Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 6bf600b

Browse files
committedJan 17, 2024
Auto merge of #120019 - lcnr:fn-wf, r=BoxyUwU
fix fn/const items implied bounds and wf check (rebase) A rebase of #104098, see that PR for discussion. This is pretty much entirely the work of `@aliemjay.` I received his permission for this rebase. --- These are two distinct changes (edit: actually three, see below): 1. Wf-check all fn item args. This is a soundness fix. Fixes #104005 2. Use implied bounds from impl header in borrowck of associated functions/consts. This strictly accepts more code and helps to mitigate the impact of other breaking changes. Fixes #98852 Fixes #102611 The first is a breaking change and will likely have a big impact without the the second one. See the first commit for how it breaks libstd. Landing the second one without the first will allow more incorrect code to pass. For example an exploit of #104005 would be as simple as: ```rust use core::fmt::Display; trait ExtendLt<Witness> { fn extend(self) -> Box<dyn Display>; } impl<T: Display> ExtendLt<&'static T> for T { fn extend(self) -> Box<dyn Display> { Box::new(self) } } fn main() { let val = (&String::new()).extend(); println!("{val}"); } ``` The third change is to to check WF of user type annotations before normalizing them (fixes #104764, fixes #104763). It is mutually dependent on the second change above: an attempt to land it separately in #104746 caused several crater regressions that can all be mitigated by using the implied from the impl header. It is also necessary for the soundness of associated consts that use the implied bounds of impl header. See #104763 and how the third commit fixes the soundness issue in `tests/ui/wf/wf-associated-const.rs` that was introduces by the previous commit. r? types
2 parents 6ed31ab + 66090ef commit 6bf600b

23 files changed

+425
-123
lines changed
 

‎compiler/rustc_borrowck/src/type_check/free_region_relations.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use rustc_data_structures::frozen::Frozen;
22
use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder};
3+
use rustc_hir::def::DefKind;
34
use rustc_infer::infer::canonical::QueryRegionConstraints;
45
use rustc_infer::infer::outlives;
56
use rustc_infer::infer::outlives::env::RegionBoundPairs;
@@ -195,7 +196,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
195196

196197
#[instrument(level = "debug", skip(self))]
197198
pub(crate) fn create(mut self) -> CreateResult<'tcx> {
198-
let span = self.infcx.tcx.def_span(self.universal_regions.defining_ty.def_id());
199+
let tcx = self.infcx.tcx;
200+
let defining_ty_def_id = self.universal_regions.defining_ty.def_id().expect_local();
201+
let span = tcx.def_span(defining_ty_def_id);
199202

200203
// Insert the facts we know from the predicates. Why? Why not.
201204
let param_env = self.param_env;
@@ -275,6 +278,26 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
275278
normalized_inputs_and_output.push(norm_ty);
276279
}
277280

281+
// Add implied bounds from impl header.
282+
if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst) {
283+
for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) {
284+
let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = self
285+
.param_env
286+
.and(type_op::normalize::Normalize::new(ty))
287+
.fully_perform(self.infcx, span)
288+
else {
289+
tcx.dcx().span_delayed_bug(span, format!("failed to normalize {ty:?}"));
290+
continue;
291+
};
292+
constraints.extend(c);
293+
294+
// We currently add implied bounds from the normalized ty only.
295+
// This is more conservative and matches wfcheck behavior.
296+
let c = self.add_implied_bounds(norm_ty);
297+
constraints.extend(c);
298+
}
299+
}
300+
278301
for c in constraints {
279302
self.push_region_constraints(c, span);
280303
}

‎compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,16 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
407407
instantiated_predicates,
408408
locations,
409409
);
410+
411+
assert!(!matches!(
412+
tcx.impl_of_method(def_id).map(|imp| tcx.def_kind(imp)),
413+
Some(DefKind::Impl { of_trait: true })
414+
));
415+
self.cx.prove_predicates(
416+
args.types().map(|ty| ty::ClauseKind::WellFormed(ty.into())),
417+
locations,
418+
ConstraintCategory::Boring,
419+
);
410420
}
411421
}
412422
}

‎compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,16 @@ fn relate_mir_and_user_ty<'tcx>(
6363
user_ty: Ty<'tcx>,
6464
) -> Result<(), NoSolution> {
6565
let cause = ObligationCause::dummy_with_span(span);
66+
ocx.register_obligation(Obligation::new(
67+
ocx.infcx.tcx,
68+
cause.clone(),
69+
param_env,
70+
ty::ClauseKind::WellFormed(user_ty.into()),
71+
));
72+
6673
let user_ty = ocx.normalize(&cause, param_env, user_ty);
6774
ocx.eq(&cause, param_env, mir_ty, user_ty)?;
6875

69-
// FIXME(#104764): We should check well-formedness before normalization.
70-
let predicate =
71-
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(user_ty.into())));
72-
ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate));
7376
Ok(())
7477
}
7578

@@ -113,31 +116,38 @@ fn relate_mir_and_user_args<'tcx>(
113116
ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate));
114117
}
115118

119+
// Now prove the well-formedness of `def_id` with `substs`.
120+
// Note for some items, proving the WF of `ty` is not sufficient because the
121+
// well-formedness of an item may depend on the WF of gneneric args not present in the
122+
// item's type. Currently this is true for associated consts, e.g.:
123+
// ```rust
124+
// impl<T> MyTy<T> {
125+
// const CONST: () = { /* arbitrary code that depends on T being WF */ };
126+
// }
127+
// ```
128+
for arg in args {
129+
ocx.register_obligation(Obligation::new(
130+
tcx,
131+
cause.clone(),
132+
param_env,
133+
ty::ClauseKind::WellFormed(arg),
134+
));
135+
}
136+
116137
if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
138+
ocx.register_obligation(Obligation::new(
139+
tcx,
140+
cause.clone(),
141+
param_env,
142+
ty::ClauseKind::WellFormed(self_ty.into()),
143+
));
144+
117145
let self_ty = ocx.normalize(&cause, param_env, self_ty);
118146
let impl_self_ty = tcx.type_of(impl_def_id).instantiate(tcx, args);
119147
let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty);
120148

121149
ocx.eq(&cause, param_env, self_ty, impl_self_ty)?;
122-
let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
123-
impl_self_ty.into(),
124-
)));
125-
ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate));
126150
}
127151

128-
// In addition to proving the predicates, we have to
129-
// prove that `ty` is well-formed -- this is because
130-
// the WF of `ty` is predicated on the args being
131-
// well-formed, and we haven't proven *that*. We don't
132-
// want to prove the WF of types from `args` directly because they
133-
// haven't been normalized.
134-
//
135-
// FIXME(nmatsakis): Well, perhaps we should normalize
136-
// them? This would only be relevant if some input
137-
// type were ill-formed but did not appear in `ty`,
138-
// which...could happen with normalization...
139-
let predicate =
140-
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty.into())));
141-
ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate));
142152
Ok(())
143153
}

‎compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,23 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
3030
}
3131
}
3232

33+
if let ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) =
34+
key.value.predicate.kind().skip_binder()
35+
{
36+
match arg.as_type()?.kind() {
37+
ty::Param(_)
38+
| ty::Bool
39+
| ty::Char
40+
| ty::Int(_)
41+
| ty::Float(_)
42+
| ty::Str
43+
| ty::Uint(_) => {
44+
return Some(());
45+
}
46+
_ => {}
47+
}
48+
}
49+
3350
None
3451
}
3552

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// The method `assert_static` should be callable only for static values,
2+
// because the impl has an implied bound `where T: 'static`.
3+
4+
// check-fail
5+
6+
trait AnyStatic<Witness>: Sized {
7+
fn assert_static(self) {}
8+
}
9+
10+
impl<T> AnyStatic<&'static T> for T {}
11+
12+
fn main() {
13+
(&String::new()).assert_static();
14+
//~^ ERROR temporary value dropped while borrowed
15+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0716]: temporary value dropped while borrowed
2+
--> $DIR/fn-item-check-trait-ref.rs:13:7
3+
|
4+
LL | (&String::new()).assert_static();
5+
| --^^^^^^^^^^^^^------------------ temporary value is freed at the end of this statement
6+
| | |
7+
| | creates a temporary value which is freed while still in use
8+
| argument requires that borrow lasts for `'static`
9+
10+
error: aborting due to 1 previous error
11+
12+
For more information about this error, try `rustc --explain E0716`.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Regression test for #104005.
2+
//
3+
// Previously, different borrowck implementations used to disagree here.
4+
// The status of each is documented on `fn test_*`.
5+
6+
// check-fail
7+
8+
use std::fmt::Display;
9+
10+
trait Displayable {
11+
fn display(self) -> Box<dyn Display>;
12+
}
13+
14+
impl<T: Display> Displayable for (T, Option<&'static T>) {
15+
fn display(self) -> Box<dyn Display> {
16+
Box::new(self.0)
17+
}
18+
}
19+
20+
fn extend_lt<T, U>(val: T) -> Box<dyn Display>
21+
where
22+
(T, Option<U>): Displayable,
23+
{
24+
Displayable::display((val, None))
25+
}
26+
27+
// AST: fail
28+
// HIR: pass
29+
// MIR: pass
30+
pub fn test_call<'a>(val: &'a str) {
31+
extend_lt(val);
32+
//~^ ERROR borrowed data escapes outside of function
33+
}
34+
35+
// AST: fail
36+
// HIR: fail
37+
// MIR: pass
38+
pub fn test_coercion<'a>() {
39+
let _: fn(&'a str) -> _ = extend_lt;
40+
//~^ ERROR lifetime may not live long enough
41+
}
42+
43+
// AST: fail
44+
// HIR: fail
45+
// MIR: fail
46+
pub fn test_arg() {
47+
fn want<I, O>(_: I, _: impl Fn(I) -> O) {}
48+
want(&String::new(), extend_lt);
49+
//~^ ERROR temporary value dropped while borrowed
50+
}
51+
52+
// An exploit of the unsoundness.
53+
fn main() {
54+
let val = extend_lt(&String::from("blah blah blah"));
55+
//~^ ERROR temporary value dropped while borrowed
56+
println!("{}", val);
57+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
error[E0521]: borrowed data escapes outside of function
2+
--> $DIR/fn-item-check-type-params.rs:31:5
3+
|
4+
LL | pub fn test_call<'a>(val: &'a str) {
5+
| -- --- `val` is a reference that is only valid in the function body
6+
| |
7+
| lifetime `'a` defined here
8+
LL | extend_lt(val);
9+
| ^^^^^^^^^^^^^^
10+
| |
11+
| `val` escapes the function body here
12+
| argument requires that `'a` must outlive `'static`
13+
14+
error: lifetime may not live long enough
15+
--> $DIR/fn-item-check-type-params.rs:39:12
16+
|
17+
LL | pub fn test_coercion<'a>() {
18+
| -- lifetime `'a` defined here
19+
LL | let _: fn(&'a str) -> _ = extend_lt;
20+
| ^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
21+
22+
error[E0716]: temporary value dropped while borrowed
23+
--> $DIR/fn-item-check-type-params.rs:48:11
24+
|
25+
LL | want(&String::new(), extend_lt);
26+
| ------^^^^^^^^^^^^^------------- temporary value is freed at the end of this statement
27+
| | |
28+
| | creates a temporary value which is freed while still in use
29+
| argument requires that borrow lasts for `'static`
30+
31+
error[E0716]: temporary value dropped while borrowed
32+
--> $DIR/fn-item-check-type-params.rs:54:26
33+
|
34+
LL | let val = extend_lt(&String::from("blah blah blah"));
35+
| -----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
36+
| | |
37+
| | creates a temporary value which is freed while still in use
38+
| argument requires that borrow lasts for `'static`
39+
40+
error: aborting due to 4 previous errors
41+
42+
Some errors have detailed explanations: E0521, E0716.
43+
For more information about an error, try `rustc --explain E0521`.

‎tests/ui/higher-ranked/trait-bounds/issue-59311.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ where
1717
v.t(|| {});
1818
//~^ ERROR: higher-ranked lifetime error
1919
//~| ERROR: higher-ranked lifetime error
20+
//~| ERROR: higher-ranked lifetime error
2021
}
2122

2223
fn main() {}

‎tests/ui/higher-ranked/trait-bounds/issue-59311.stderr

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ LL | v.t(|| {});
66
|
77
= note: could not prove `{closure@$DIR/issue-59311.rs:17:9: 17:11} well-formed`
88

9+
error: higher-ranked lifetime error
10+
--> $DIR/issue-59311.rs:17:5
11+
|
12+
LL | v.t(|| {});
13+
| ^^^^^^^^^^
14+
|
15+
= note: could not prove `{closure@$DIR/issue-59311.rs:17:9: 17:11} well-formed`
16+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
17+
918
error: higher-ranked lifetime error
1019
--> $DIR/issue-59311.rs:17:9
1120
|
@@ -14,5 +23,5 @@ LL | v.t(|| {});
1423
|
1524
= note: could not prove `for<'a> &'a V: 'b`
1625

17-
error: aborting due to 2 previous errors
26+
error: aborting due to 3 previous errors
1827

‎tests/ui/implied-bounds/implied-bounds-on-trait-hierarchy.rs renamed to ‎tests/ui/implied-bounds/implied-bounds-on-trait-hierarchy-1.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
// check-pass
2-
// known-bug: #84591
1+
// issue: #84591
32

4-
// Should fail. Subtrait can incorrectly extend supertrait lifetimes even when
5-
// supertrait has weaker implied bounds than subtrait. Strongly related to
6-
// issue #25860.
3+
// Subtrait was able to incorrectly extend supertrait lifetimes even when
4+
// supertrait had weaker implied bounds than subtrait.
75

86
trait Subtrait<T>: Supertrait {}
97
trait Supertrait {
@@ -34,6 +32,7 @@ fn main() {
3432
{
3533
let x = "Hello World".to_string();
3634
subs_to_soup((x.as_str(), &mut d));
35+
//~^ does not live long enough
3736
}
3837
println!("{}", d);
3938
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error[E0597]: `x` does not live long enough
2+
--> $DIR/implied-bounds-on-trait-hierarchy-1.rs:34:23
3+
|
4+
LL | let x = "Hello World".to_string();
5+
| - binding `x` declared here
6+
LL | subs_to_soup((x.as_str(), &mut d));
7+
| ^ borrowed value does not live long enough
8+
LL |
9+
LL | }
10+
| - `x` dropped here while still borrowed
11+
LL | println!("{}", d);
12+
| - borrow later used here
13+
14+
error: aborting due to 1 previous error
15+
16+
For more information about this error, try `rustc --explain E0597`.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// check-pass
2+
// known-bug: #84591
3+
4+
trait Subtrait<'a, 'b, R>: Supertrait<'a, 'b> {}
5+
trait Supertrait<'a, 'b> {
6+
fn convert<T: ?Sized>(x: &'a T) -> &'b T;
7+
}
8+
9+
fn need_hrtb_subtrait<'a_, 'b_, S, T: ?Sized>(x: &'a_ T) -> &'b_ T
10+
where
11+
S: for<'a, 'b> Subtrait<'a, 'b, &'b &'a ()>,
12+
{
13+
need_hrtb_supertrait::<S, T>(x)
14+
// This call works and drops the implied bound `'a: 'b`
15+
// of the where-bound. This means the where-bound can
16+
// now be used to transmute any two lifetimes.
17+
}
18+
19+
fn need_hrtb_supertrait<'a_, 'b_, S, T: ?Sized>(x: &'a_ T) -> &'b_ T
20+
where
21+
S: for<'a, 'b> Supertrait<'a, 'b>,
22+
{
23+
S::convert(x)
24+
}
25+
26+
struct MyStruct;
27+
impl<'a: 'b, 'b> Supertrait<'a, 'b> for MyStruct {
28+
fn convert<T: ?Sized>(x: &'a T) -> &'b T {
29+
x
30+
}
31+
}
32+
impl<'a, 'b> Subtrait<'a, 'b, &'b &'a ()> for MyStruct {}
33+
34+
fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T {
35+
need_hrtb_subtrait::<MyStruct, T>(x)
36+
}
37+
38+
fn main() {
39+
let d;
40+
{
41+
let x = "Hello World".to_string();
42+
d = extend_lifetime(&x);
43+
}
44+
println!("{}", d);
45+
}

‎tests/ui/lifetimes/lifetime-errors/issue_74400.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ fn f<T, S>(data: &[T], key: impl Fn(&T) -> S) {
1111
fn g<T>(data: &[T]) {
1212
f(data, identity)
1313
//~^ ERROR the parameter type
14+
//~| ERROR the parameter type
15+
//~| ERROR the parameter type
1416
//~| ERROR mismatched types
1517
//~| ERROR implementation of `FnOnce` is not general
1618
}

‎tests/ui/lifetimes/lifetime-errors/issue_74400.stderr

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,36 @@ help: consider adding an explicit lifetime bound
1212
LL | fn g<T: 'static>(data: &[T]) {
1313
| +++++++++
1414

15+
error[E0310]: the parameter type `T` may not live long enough
16+
--> $DIR/issue_74400.rs:12:5
17+
|
18+
LL | f(data, identity)
19+
| ^^^^^^^^^^^^^^^^^
20+
| |
21+
| the parameter type `T` must be valid for the static lifetime...
22+
| ...so that the type `T` will meet its required lifetime bounds
23+
|
24+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
25+
help: consider adding an explicit lifetime bound
26+
|
27+
LL | fn g<T: 'static>(data: &[T]) {
28+
| +++++++++
29+
30+
error[E0310]: the parameter type `T` may not live long enough
31+
--> $DIR/issue_74400.rs:12:5
32+
|
33+
LL | f(data, identity)
34+
| ^^^^^^^^^^^^^^^^^
35+
| |
36+
| the parameter type `T` must be valid for the static lifetime...
37+
| ...so that the type `T` will meet its required lifetime bounds
38+
|
39+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
40+
help: consider adding an explicit lifetime bound
41+
|
42+
LL | fn g<T: 'static>(data: &[T]) {
43+
| +++++++++
44+
1545
error[E0308]: mismatched types
1646
--> $DIR/issue_74400.rs:12:5
1747
|
@@ -35,7 +65,7 @@ LL | f(data, identity)
3565
= note: `fn(&'2 T) -> &'2 T {identity::<&'2 T>}` must implement `FnOnce<(&'1 T,)>`, for any lifetime `'1`...
3666
= note: ...but it actually implements `FnOnce<(&'2 T,)>`, for some specific lifetime `'2`
3767

38-
error: aborting due to 3 previous errors
68+
error: aborting due to 5 previous errors
3969

4070
Some errors have detailed explanations: E0308, E0310.
4171
For more information about an error, try `rustc --explain E0308`.

‎tests/ui/type-alias-impl-trait/wf-nested.fail.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0310]: the parameter type `T` may not live long enough
2-
--> $DIR/wf-nested.rs:55:27
2+
--> $DIR/wf-nested.rs:57:27
33
|
44
LL | type InnerOpaque<T> = impl Sized;
55
| ^^^^^^^^^^

‎tests/ui/type-alias-impl-trait/wf-nested.pass_sound.stderr

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,21 @@ help: consider adding an explicit lifetime bound
1212
LL | fn test<T: 'static>() {
1313
| +++++++++
1414

15-
error: aborting due to 1 previous error
15+
error[E0310]: the parameter type `T` may not live long enough
16+
--> $DIR/wf-nested.rs:46:17
17+
|
18+
LL | let _ = outer.get();
19+
| ^^^^^^^^^^^
20+
| |
21+
| the parameter type `T` must be valid for the static lifetime...
22+
| ...so that the type `T` will meet its required lifetime bounds
23+
|
24+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
25+
help: consider adding an explicit lifetime bound
26+
|
27+
LL | fn test<T: 'static>() {
28+
| +++++++++
29+
30+
error: aborting due to 2 previous errors
1631

1732
For more information about this error, try `rustc --explain E0310`.

‎tests/ui/type-alias-impl-trait/wf-nested.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ mod pass_sound {
4343

4444
fn test<T>() {
4545
let outer = define::<T>();
46-
let _ = outer.get(); //[pass_sound]~ ERROR `T` may not live long enough
46+
let _ = outer.get();
47+
//[pass_sound]~^ ERROR `T` may not live long enough
48+
//[pass_sound]~| ERROR `T` may not live long enough
4749
}
4850
}
4951

‎tests/ui/wf/wf-associated-const.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// check that associated consts can assume the impl header is well-formed.
2+
3+
trait Foo<'a, 'b, T>: Sized {
4+
const EVIL: fn(u: &'b u32) -> &'a u32;
5+
}
6+
7+
struct Evil<'a, 'b: 'a>(Option<&'a &'b ()>);
8+
9+
impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () {
10+
const EVIL: fn(&'b u32) -> &'a u32 = { |u| u };
11+
}
12+
13+
struct IndirectEvil<'a, 'b: 'a>(Option<&'a &'b ()>);
14+
15+
impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> {
16+
const EVIL: fn(&'b u32) -> &'a u32 = { |u| u };
17+
}
18+
19+
impl<'a, 'b> Evil<'a, 'b> {
20+
const INHERENT_EVIL: fn(&'b u32) -> &'a u32 = { |u| u };
21+
}
22+
23+
// while static methods can *assume* this, we should still
24+
// *check* that it holds at the use site.
25+
26+
fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
27+
<()>::EVIL(b)
28+
//~^ ERROR lifetime may not live long enough
29+
}
30+
31+
fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
32+
<IndirectEvil>::EVIL(b)
33+
//~^ ERROR lifetime may not live long enough
34+
}
35+
36+
fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
37+
<Evil>::INHERENT_EVIL(b)
38+
//~^ ERROR lifetime may not live long enough
39+
}
40+
41+
fn main() {}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
error: lifetime may not live long enough
2+
--> $DIR/wf-associated-const.rs:27:5
3+
|
4+
LL | fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
5+
| -- -- lifetime `'b` defined here
6+
| |
7+
| lifetime `'a` defined here
8+
LL | <()>::EVIL(b)
9+
| ^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
10+
|
11+
= help: consider adding the following bound: `'b: 'a`
12+
13+
error: lifetime may not live long enough
14+
--> $DIR/wf-associated-const.rs:32:5
15+
|
16+
LL | fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
17+
| -- -- lifetime `'b` defined here
18+
| |
19+
| lifetime `'a` defined here
20+
LL | <IndirectEvil>::EVIL(b)
21+
| ^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
22+
|
23+
= help: consider adding the following bound: `'b: 'a`
24+
25+
error: lifetime may not live long enough
26+
--> $DIR/wf-associated-const.rs:37:5
27+
|
28+
LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
29+
| -- -- lifetime `'b` defined here
30+
| |
31+
| lifetime `'a` defined here
32+
LL | <Evil>::INHERENT_EVIL(b)
33+
| ^^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
34+
|
35+
= help: consider adding the following bound: `'b: 'a`
36+
37+
error: aborting due to 3 previous errors
38+

‎tests/ui/wf/wf-in-fn-type-implicit.rs

Lines changed: 0 additions & 37 deletions
This file was deleted.

‎tests/ui/wf/wf-static-method.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
// check that static methods don't get to assume their trait-ref
2-
// is well-formed.
3-
// FIXME(#27579): this is just a bug. However, our checking with
4-
// static inherent methods isn't quite working - need to
5-
// fix that before removing the check.
1+
// check that static methods can assume their trait-ref is well-formed.
62

73
trait Foo<'a, 'b, T>: Sized {
84
fn make_me() -> Self { loop {} }
@@ -15,7 +11,6 @@ impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () {
1511
fn make_me() -> Self { }
1612
fn static_evil(u: &'b u32) -> &'a u32 {
1713
u
18-
//~^ ERROR lifetime may not live long enough
1914
}
2015
}
2116

@@ -25,20 +20,18 @@ impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> {
2520
fn make_me() -> Self { IndirectEvil(None) }
2621
fn static_evil(u: &'b u32) -> &'a u32 {
2722
let me = Self::make_me();
28-
//~^ ERROR lifetime may not live long enough
2923
loop {} // (`me` could be used for the lifetime transmute).
3024
}
3125
}
3226

3327
impl<'a, 'b> Evil<'a, 'b> {
3428
fn inherent_evil(u: &'b u32) -> &'a u32 {
3529
u
36-
//~^ ERROR lifetime may not live long enough
3730
}
3831
}
3932

40-
// while static methods don't get to *assume* this, we still
41-
// *check* that they hold.
33+
// while static methods can *assume* this, we should still
34+
// *check* that it holds at the use site.
4235

4336
fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
4437
<()>::static_evil(b)

‎tests/ui/wf/wf-static-method.stderr

Lines changed: 4 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,5 @@
11
error: lifetime may not live long enough
2-
--> $DIR/wf-static-method.rs:17:9
3-
|
4-
LL | impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () {
5-
| -- -- lifetime `'b` defined here
6-
| |
7-
| lifetime `'a` defined here
8-
...
9-
LL | u
10-
| ^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
11-
|
12-
= help: consider adding the following bound: `'b: 'a`
13-
14-
error: lifetime may not live long enough
15-
--> $DIR/wf-static-method.rs:27:18
16-
|
17-
LL | impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> {
18-
| -- -- lifetime `'b` defined here
19-
| |
20-
| lifetime `'a` defined here
21-
...
22-
LL | let me = Self::make_me();
23-
| ^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
24-
|
25-
= help: consider adding the following bound: `'b: 'a`
26-
27-
error: lifetime may not live long enough
28-
--> $DIR/wf-static-method.rs:35:9
29-
|
30-
LL | impl<'a, 'b> Evil<'a, 'b> {
31-
| -- -- lifetime `'b` defined here
32-
| |
33-
| lifetime `'a` defined here
34-
LL | fn inherent_evil(u: &'b u32) -> &'a u32 {
35-
LL | u
36-
| ^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
37-
|
38-
= help: consider adding the following bound: `'b: 'a`
39-
40-
error: lifetime may not live long enough
41-
--> $DIR/wf-static-method.rs:44:5
2+
--> $DIR/wf-static-method.rs:37:5
423
|
434
LL | fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
445
| -- -- lifetime `'b` defined here
@@ -50,7 +11,7 @@ LL | <()>::static_evil(b)
5011
= help: consider adding the following bound: `'b: 'a`
5112

5213
error: lifetime may not live long enough
53-
--> $DIR/wf-static-method.rs:49:5
14+
--> $DIR/wf-static-method.rs:42:5
5415
|
5516
LL | fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
5617
| -- -- lifetime `'b` defined here
@@ -62,7 +23,7 @@ LL | <IndirectEvil>::static_evil(b)
6223
= help: consider adding the following bound: `'b: 'a`
6324

6425
error: lifetime may not live long enough
65-
--> $DIR/wf-static-method.rs:54:5
26+
--> $DIR/wf-static-method.rs:47:5
6627
|
6728
LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
6829
| -- -- lifetime `'b` defined here
@@ -73,5 +34,5 @@ LL | <Evil>::inherent_evil(b)
7334
|
7435
= help: consider adding the following bound: `'b: 'a`
7536

76-
error: aborting due to 6 previous errors
37+
error: aborting due to 3 previous errors
7738

0 commit comments

Comments
 (0)
Please sign in to comment.