Skip to content

Commit 4d7f952

Browse files
committed
Auto merge of rust-lang#112422 - aliemjay:implied-bounds-placeholders, r=lcnr
ignore implied bounds with placeholders given the following code: ```rust 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; ``` when computing the implied bounds from `Foo<X>` we incorrectly get the bound `X: !x` from the normalization of ` for<'x> <X as Trait>::Ty::<'x>: Sized`. This is a a known bug! we shouldn't use the constraints that arise from normalization as implied bounds. See rust-lang#109628. Ignore these bounds for now. This should prevent later ICEs. Fixes rust-lang#112250 Fixes rust-lang#107409
2 parents 78efca8 + af79fd1 commit 4d7f952

File tree

4 files changed

+81
-3
lines changed

4 files changed

+81
-3
lines changed

compiler/rustc_borrowck/src/type_check/free_region_relations.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_infer::infer::region_constraints::GenericKind;
77
use rustc_infer::infer::InferCtxt;
88
use rustc_middle::mir::ConstraintCategory;
99
use rustc_middle::traits::query::OutlivesBound;
10-
use rustc_middle::ty::{self, RegionVid, Ty};
10+
use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
1111
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
1212
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
1313
use std::rc::Rc;
@@ -321,6 +321,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
321321
.map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty))
322322
.ok()?;
323323
debug!(?bounds, ?constraints);
324+
// Because of #109628, we may have unexpected placeholders. Ignore them!
325+
// FIXME(#109628): panic in this case once the issue is fixed.
326+
let bounds = bounds.into_iter().filter(|bound| !bound.has_placeholders());
324327
self.add_outlives_bounds(bounds);
325328
constraints
326329
}

compiler/rustc_trait_selection/src/traits/outlives_bounds.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
7272
};
7373

7474
let mut constraints = QueryRegionConstraints::default();
75-
let Ok(InferOk { value, obligations }) = self
75+
let Ok(InferOk { value: mut bounds, obligations }) = self
7676
.instantiate_nll_query_response_and_region_obligations(
7777
&ObligationCause::dummy(),
7878
param_env,
@@ -85,6 +85,10 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
8585
};
8686
assert_eq!(&obligations, &[]);
8787

88+
// Because of #109628, we may have unexpected placeholders. Ignore them!
89+
// FIXME(#109628): panic in this case once the issue is fixed.
90+
bounds.retain(|bound| !bound.has_placeholders());
91+
8892
if !constraints.is_empty() {
8993
let span = self.tcx.def_span(body_id);
9094

@@ -114,7 +118,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
114118
}
115119
};
116120

117-
value
121+
bounds
118122
}
119123

120124
fn implied_bounds_tys(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0477]: the type `&'lt u8` does not fulfill the required lifetime
2+
--> $DIR/normalization-placeholder-leak.rs:31:40
3+
|
4+
LL | fn test_lifetime<'lt, T: Trait>(_: Foo<&'lt u8>) {}
5+
| ^^^^^^^^^^^^
6+
7+
error[E0477]: the type `<T as AnotherTrait>::Ty2<'lt>` does not fulfill the required lifetime
8+
--> $DIR/normalization-placeholder-leak.rs:36:44
9+
|
10+
LL | fn test_alias<'lt, T: AnotherTrait>(_: Foo<T::Ty2::<'lt>>) {}
11+
| ^^^^^^^^^^^^^^^^^^
12+
13+
error: aborting due to 2 previous errors
14+
15+
For more information about this error, try `rustc --explain E0477`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Because of #109628, when we compute the implied bounds from `Foo<X>`,
2+
// we incorrectly get `X: placeholder('x)`.
3+
// Make sure we ignore these bogus bounds and not use them for anything useful.
4+
//
5+
// revisions: fail pass
6+
// [fail] check-fail
7+
// [pass] check-pass
8+
9+
trait Trait {
10+
type Ty<'a> where Self: 'a;
11+
}
12+
13+
impl<T> Trait for T {
14+
type Ty<'a> = () where Self: 'a;
15+
}
16+
17+
struct Foo<T: Trait>(T)
18+
where
19+
for<'x> T::Ty<'x>: Sized;
20+
21+
trait AnotherTrait {
22+
type Ty2<'a>: 'a;
23+
}
24+
25+
#[cfg(fail)]
26+
mod fail {
27+
use super::*;
28+
29+
// implied_bound: `'lt: placeholder('x)`.
30+
// don't use the bound to prove `'lt: 'static`.
31+
fn test_lifetime<'lt, T: Trait>(_: Foo<&'lt u8>) {}
32+
//[fail]~^ ERROR `&'lt u8` does not fulfill the required lifetime
33+
34+
// implied bound: `T::Ty2<'lt>: placeholder('x)`.
35+
// don't use the bound to prove `T::Ty2<'lt>: 'static`.
36+
fn test_alias<'lt, T: AnotherTrait>(_: Foo<T::Ty2::<'lt>>) {}
37+
//[fail]~^ ERROR `<T as AnotherTrait>::Ty2<'lt>` does not fulfill the required lifetime
38+
}
39+
40+
41+
mod pass {
42+
use super::*;
43+
44+
// implied_bound: 'static: placeholder('x).
45+
// don't ice.
46+
fn test_lifetime<T: Trait>(_: Foo<&'static u8>) {}
47+
48+
// implied bound: T::Ty2<'static>: placeholder('x).
49+
// don't add the bound to the environment,
50+
// otherwise we would fail to infer a value for `'_`.
51+
fn test_alias<T: AnotherTrait>(_: Foo<T::Ty2::<'static>>) {
52+
None::<&'static T::Ty2<'_>>;
53+
}
54+
}
55+
56+
fn main() {}

0 commit comments

Comments
 (0)