about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/outlives_bounds.rs8
-rw-r--r--tests/ui/implied-bounds/normalization-placeholder-leak.fail.stderr15
-rw-r--r--tests/ui/implied-bounds/normalization-placeholder-leak.rs56
4 files changed, 81 insertions, 3 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index c84256f8ff3..478eedc26d3 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -7,7 +7,7 @@ use rustc_infer::infer::region_constraints::GenericKind;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::traits::query::OutlivesBound;
-use rustc_middle::ty::{self, RegionVid, Ty};
+use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
 use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
 use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
 use std::rc::Rc;
@@ -321,6 +321,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
             .map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty))
             .ok()?;
         debug!(?bounds, ?constraints);
+        // Because of #109628, we may have unexpected placeholders. Ignore them!
+        // FIXME(#109628): panic in this case once the issue is fixed.
+        let bounds = bounds.into_iter().filter(|bound| !bound.has_placeholders());
         self.add_outlives_bounds(bounds);
         constraints
     }
diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
index 32bbd626d4e..1c2966bb3e5 100644
--- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
@@ -72,7 +72,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
         };
 
         let mut constraints = QueryRegionConstraints::default();
-        let Ok(InferOk { value, obligations }) = self
+        let Ok(InferOk { value: mut bounds, obligations }) = self
             .instantiate_nll_query_response_and_region_obligations(
                 &ObligationCause::dummy(),
                 param_env,
@@ -85,6 +85,10 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
         };
         assert_eq!(&obligations, &[]);
 
+        // Because of #109628, we may have unexpected placeholders. Ignore them!
+        // FIXME(#109628): panic in this case once the issue is fixed.
+        bounds.retain(|bound| !bound.has_placeholders());
+
         if !constraints.is_empty() {
             let span = self.tcx.def_span(body_id);
 
@@ -114,7 +118,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
             }
         };
 
-        value
+        bounds
     }
 
     fn implied_bounds_tys(
diff --git a/tests/ui/implied-bounds/normalization-placeholder-leak.fail.stderr b/tests/ui/implied-bounds/normalization-placeholder-leak.fail.stderr
new file mode 100644
index 00000000000..a591d0f5d4d
--- /dev/null
+++ b/tests/ui/implied-bounds/normalization-placeholder-leak.fail.stderr
@@ -0,0 +1,15 @@
+error[E0477]: the type `&'lt u8` does not fulfill the required lifetime
+  --> $DIR/normalization-placeholder-leak.rs:31:40
+   |
+LL |     fn test_lifetime<'lt, T: Trait>(_: Foo<&'lt u8>) {}
+   |                                        ^^^^^^^^^^^^
+
+error[E0477]: the type `<T as AnotherTrait>::Ty2<'lt>` does not fulfill the required lifetime
+  --> $DIR/normalization-placeholder-leak.rs:36:44
+   |
+LL |     fn test_alias<'lt, T: AnotherTrait>(_: Foo<T::Ty2::<'lt>>) {}
+   |                                            ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0477`.
diff --git a/tests/ui/implied-bounds/normalization-placeholder-leak.rs b/tests/ui/implied-bounds/normalization-placeholder-leak.rs
new file mode 100644
index 00000000000..5350dcbb233
--- /dev/null
+++ b/tests/ui/implied-bounds/normalization-placeholder-leak.rs
@@ -0,0 +1,56 @@
+// Because of #109628, when we compute the implied bounds from `Foo<X>`,
+// we incorrectly get `X: placeholder('x)`.
+// Make sure we ignore these bogus bounds and not use them for anything useful.
+//
+// revisions: fail pass
+// [fail] check-fail
+// [pass] check-pass
+
+trait Trait {
+    type Ty<'a> where Self: 'a;
+}
+
+impl<T> Trait for T {
+    type Ty<'a> = () where Self: 'a;
+}
+
+struct Foo<T: Trait>(T)
+where
+    for<'x> T::Ty<'x>: Sized;
+
+trait AnotherTrait {
+    type Ty2<'a>: 'a;
+}
+
+#[cfg(fail)]
+mod fail {
+    use super::*;
+
+    // implied_bound: `'lt: placeholder('x)`.
+    // don't use the bound to prove `'lt: 'static`.
+    fn test_lifetime<'lt, T: Trait>(_: Foo<&'lt u8>) {}
+    //[fail]~^ ERROR `&'lt u8` does not fulfill the required lifetime
+
+    // implied bound: `T::Ty2<'lt>: placeholder('x)`.
+    // don't use the bound to prove `T::Ty2<'lt>: 'static`.
+    fn test_alias<'lt, T: AnotherTrait>(_: Foo<T::Ty2::<'lt>>) {}
+    //[fail]~^ ERROR `<T as AnotherTrait>::Ty2<'lt>` does not fulfill the required lifetime
+}
+
+
+mod pass {
+    use super::*;
+
+    // implied_bound: 'static: placeholder('x).
+    // don't ice.
+    fn test_lifetime<T: Trait>(_: Foo<&'static u8>) {}
+
+    // implied bound: T::Ty2<'static>: placeholder('x).
+    // don't add the bound to the environment,
+    // otherwise we would fail to infer a value for `'_`.
+    fn test_alias<T: AnotherTrait>(_: Foo<T::Ty2::<'static>>) {
+        None::<&'static T::Ty2<'_>>;
+    }
+}
+
+fn main() {}