about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs36
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs24
-rw-r--r--tests/ui/lifetimes/anonymize-unnamed-bound-vars-in-binders.rs27
3 files changed, 72 insertions, 15 deletions
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 3cafd9a8da9..231635c086e 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -34,6 +34,26 @@ impl FlagComputation {
         result.flags
     }
 
+    pub fn bound_var_flags(vars: &ty::List<ty::BoundVariableKind>) -> FlagComputation {
+        let mut computation = FlagComputation::new();
+
+        for bv in vars {
+            match bv {
+                ty::BoundVariableKind::Ty(_) => {
+                    computation.flags |= TypeFlags::HAS_TY_LATE_BOUND;
+                }
+                ty::BoundVariableKind::Region(_) => {
+                    computation.flags |= TypeFlags::HAS_RE_LATE_BOUND;
+                }
+                ty::BoundVariableKind::Const => {
+                    computation.flags |= TypeFlags::HAS_CT_LATE_BOUND;
+                }
+            }
+        }
+
+        computation
+    }
+
     fn add_flags(&mut self, flags: TypeFlags) {
         self.flags = self.flags | flags;
     }
@@ -57,21 +77,7 @@ impl FlagComputation {
     where
         F: FnOnce(&mut Self, T),
     {
-        let mut computation = FlagComputation::new();
-
-        for bv in value.bound_vars() {
-            match bv {
-                ty::BoundVariableKind::Ty(_) => {
-                    computation.flags |= TypeFlags::HAS_TY_LATE_BOUND;
-                }
-                ty::BoundVariableKind::Region(_) => {
-                    computation.flags |= TypeFlags::HAS_RE_LATE_BOUND;
-                }
-                ty::BoundVariableKind::Const => {
-                    computation.flags |= TypeFlags::HAS_CT_LATE_BOUND;
-                }
-            }
-        }
+        let mut computation = FlagComputation::bound_var_flags(value.bound_vars());
 
         f(&mut computation, value.skip_binder());
 
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index fb760654ea7..5deb5bfb19e 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -481,9 +481,33 @@ impl std::fmt::Debug for HasTypeFlagsVisitor {
 // `Ty`/`Const`/`Predicate`, but not within those types. This is because the
 // type flags at the outer layer are enough. So it's faster than it first
 // looks, particular for `Ty`/`Predicate` where it's just a field access.
+//
+// N.B. The only case where this isn't totally true is binders, which also
+// add `HAS_{RE,TY,CT}_LATE_BOUND` flag depending on the *bound variables* that
+// are present, regardless of whether those bound variables are used. This
+// is important for anonymization of binders in `TyCtxt::erase_regions`. We
+// specifically detect this case in `visit_binder`.
 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasTypeFlagsVisitor {
     type BreakTy = FoundFlags;
 
+    fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
+        &mut self,
+        t: &Binder<'tcx, T>,
+    ) -> ControlFlow<Self::BreakTy> {
+        // If we're looking for any of the HAS_*_LATE_BOUND flags, we need to
+        // additionally consider the bound vars on the binder itself, even if
+        // the contents of a the binder (e.g. a `TraitRef`) doesn't reference
+        // the bound vars.
+        if self.flags.intersects(TypeFlags::HAS_LATE_BOUND) {
+            let bound_var_flags = FlagComputation::bound_var_flags(t.bound_vars());
+            if bound_var_flags.flags.intersects(self.flags) {
+                return ControlFlow::Break(FoundFlags);
+            }
+        }
+
+        t.super_visit_with(self)
+    }
+
     #[inline]
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         // Note: no `super_visit_with` call.
diff --git a/tests/ui/lifetimes/anonymize-unnamed-bound-vars-in-binders.rs b/tests/ui/lifetimes/anonymize-unnamed-bound-vars-in-binders.rs
new file mode 100644
index 00000000000..05e3763e9d1
--- /dev/null
+++ b/tests/ui/lifetimes/anonymize-unnamed-bound-vars-in-binders.rs
@@ -0,0 +1,27 @@
+// build-pass
+// issue: #115807
+
+trait Chip: for<'a> TraitWithLifetime<'a> + SomeMarker {
+    fn compute(&self);
+}
+
+trait SomeMarker {}
+
+trait TraitWithLifetime<'a>: SomeMarker {}
+
+trait Machine {
+    fn run();
+}
+
+struct BasicMachine;
+
+impl Machine for BasicMachine {
+    fn run() {
+        let chips: [&dyn Chip; 0] = [];
+        let _ = chips.map(|chip| chip.compute());
+    }
+}
+
+fn main() {
+    BasicMachine::run();
+}