Skip to content

Commit 85063aa

Browse files
committed
ADT implied bounds: consider 'static + elaborate
1 parent e999d8b commit 85063aa

14 files changed

+121
-137
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use rustc_data_structures::fx::FxHashMap;
22
use rustc_hir::def_id::DefId;
33
use rustc_middle::ty::{self, OutlivesPredicate, TyCtxt};
4+
use rustc_trait_selection::traits::elaborate;
45

56
use super::utils::*;
67

@@ -18,46 +19,54 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
1819
&mut self,
1920
tcx: TyCtxt<'tcx>,
2021
def_id: DefId,
21-
) -> &ty::EarlyBinder<RequiredPredicates<'tcx>> {
22-
self.map.entry(def_id).or_insert_with(|| {
23-
let predicates = if def_id.is_local() {
24-
tcx.explicit_predicates_of(def_id)
25-
} else {
26-
tcx.predicates_of(def_id)
27-
};
28-
let mut required_predicates = RequiredPredicates::default();
29-
30-
// process predicates and convert to `RequiredPredicates` entry, see below
31-
for &(predicate, span) in predicates.predicates {
32-
match predicate.kind().skip_binder() {
33-
ty::ClauseKind::TypeOutlives(OutlivesPredicate(ty, reg)) => {
34-
insert_outlives_predicate(
35-
tcx,
36-
ty.into(),
37-
reg,
38-
span,
39-
&mut required_predicates,
40-
)
41-
}
22+
) -> ty::EarlyBinder<&RequiredPredicates<'tcx>> {
23+
self.map
24+
.entry(def_id)
25+
.or_insert_with(|| {
26+
let predicates = if def_id.is_local() {
27+
tcx.explicit_predicates_of(def_id)
28+
} else {
29+
tcx.predicates_of(def_id)
30+
};
31+
32+
let mut required_predicates = RequiredPredicates::default();
33+
34+
// process predicates and convert to `RequiredPredicates` entry, see below
35+
let predicates = predicates
36+
.predicates
37+
.into_iter()
38+
.flat_map(|&(p, span)| elaborate(tcx, [p]).map(move |p| (p, span)));
39+
for (predicate, span) in predicates {
40+
match predicate.kind().skip_binder() {
41+
ty::ClauseKind::TypeOutlives(OutlivesPredicate(ty, reg)) => {
42+
insert_outlives_predicate(
43+
tcx,
44+
ty.into(),
45+
reg,
46+
span,
47+
&mut required_predicates,
48+
)
49+
}
4250

43-
ty::ClauseKind::RegionOutlives(OutlivesPredicate(reg1, reg2)) => {
44-
insert_outlives_predicate(
45-
tcx,
46-
reg1.into(),
47-
reg2,
48-
span,
49-
&mut required_predicates,
50-
)
51+
ty::ClauseKind::RegionOutlives(OutlivesPredicate(reg1, reg2)) => {
52+
insert_outlives_predicate(
53+
tcx,
54+
reg1.into(),
55+
reg2,
56+
span,
57+
&mut required_predicates,
58+
)
59+
}
60+
ty::ClauseKind::Trait(_)
61+
| ty::ClauseKind::Projection(_)
62+
| ty::ClauseKind::ConstArgHasType(_, _)
63+
| ty::ClauseKind::WellFormed(_)
64+
| ty::ClauseKind::ConstEvaluatable(_) => {}
5165
}
52-
ty::ClauseKind::Trait(_)
53-
| ty::ClauseKind::Projection(_)
54-
| ty::ClauseKind::ConstArgHasType(_, _)
55-
| ty::ClauseKind::WellFormed(_)
56-
| ty::ClauseKind::ConstEvaluatable(_) => {}
5766
}
58-
}
5967

60-
ty::EarlyBinder::bind(required_predicates)
61-
})
68+
ty::EarlyBinder::bind(required_predicates)
69+
})
70+
.as_ref()
6271
}
6372
}

compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ fn check_explicit_predicates<'tcx>(
253253
);
254254
let explicit_predicates = explicit_map.explicit_predicates_of(tcx, def_id);
255255

256-
for (outlives_predicate, &span) in explicit_predicates.as_ref().skip_binder() {
256+
for (outlives_predicate, &span) in explicit_predicates.skip_binder() {
257257
debug!("outlives_predicate = {:?}", &outlives_predicate);
258258

259259
// Careful: If we are inferring the effects of a `dyn Trait<..>`

compiler/rustc_hir_analysis/src/outlives/utils.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
2121
) {
2222
// If the `'a` region is bound within the field type itself, we
2323
// don't want to propagate this constraint to the header.
24-
if !is_free_region(outlived_region) {
24+
let valid_outlived_region = is_free_region(outlived_region) || outlived_region.is_static();
25+
if !valid_outlived_region {
2526
return;
2627
}
2728

tests/ui/lifetimes/lifetime-doesnt-live-long-enough.rs

-5
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,6 @@ impl<'a, T: ListItem<'a>> Collection for List<'a, T> {
1515
}
1616
}
1717

18-
struct Foo<T> {
19-
foo: &'static T
20-
//~^ ERROR may not live long enough
21-
}
22-
2318
trait X<K>: Sized {
2419
fn foo<'a, L: X<&'a Nested<K>>>();
2520
//~^ ERROR may not live long enough

tests/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr

+7-22
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,5 @@
1-
error[E0310]: the parameter type `T` may not live long enough
2-
--> $DIR/lifetime-doesnt-live-long-enough.rs:19:10
3-
|
4-
LL | foo: &'static T
5-
| ^^^^^^^^^^
6-
| |
7-
| the parameter type `T` must be valid for the static lifetime...
8-
| ...so that the reference type `&'static T` does not outlive the data it points at
9-
|
10-
help: consider adding an explicit lifetime bound
11-
|
12-
LL | struct Foo<T: 'static> {
13-
| +++++++++
14-
151
error[E0309]: the parameter type `K` may not live long enough
16-
--> $DIR/lifetime-doesnt-live-long-enough.rs:41:33
2+
--> $DIR/lifetime-doesnt-live-long-enough.rs:36:33
173
|
184
LL | fn generic_in_parent<'a, L: X<&'a Nested<K>>>() {
195
| -- ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<K>` does not outlive the data it points at
@@ -26,7 +12,7 @@ LL | fn generic_in_parent<'a, L: X<&'a Nested<K>>>() where K: 'a {
2612
| +++++++++++
2713

2814
error[E0309]: the parameter type `M` may not live long enough
29-
--> $DIR/lifetime-doesnt-live-long-enough.rs:44:36
15+
--> $DIR/lifetime-doesnt-live-long-enough.rs:39:36
3016
|
3117
LL | fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b>() {
3218
| -- ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<M>` does not outlive the data it points at
@@ -39,7 +25,7 @@ LL | fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b + 'a>() {
3925
| ++++
4026

4127
error[E0309]: the parameter type `K` may not live long enough
42-
--> $DIR/lifetime-doesnt-live-long-enough.rs:24:19
28+
--> $DIR/lifetime-doesnt-live-long-enough.rs:19:19
4329
|
4430
LL | fn foo<'a, L: X<&'a Nested<K>>>();
4531
| -- ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<K>` does not outlive the data it points at
@@ -52,7 +38,7 @@ LL | fn foo<'a, L: X<&'a Nested<K>>>() where K: 'a;
5238
| +++++++++++
5339

5440
error[E0309]: the parameter type `Self` may not live long enough
55-
--> $DIR/lifetime-doesnt-live-long-enough.rs:28:19
41+
--> $DIR/lifetime-doesnt-live-long-enough.rs:23:19
5642
|
5743
LL | fn bar<'a, L: X<&'a Nested<Self>>>();
5844
| -- ^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<Self>` does not outlive the data it points at
@@ -65,7 +51,7 @@ LL | fn bar<'a, L: X<&'a Nested<Self>>>() where Self: 'a;
6551
| ++++++++++++++
6652

6753
error[E0309]: the parameter type `L` may not live long enough
68-
--> $DIR/lifetime-doesnt-live-long-enough.rs:32:22
54+
--> $DIR/lifetime-doesnt-live-long-enough.rs:27:22
6955
|
7056
LL | fn baz<'a, L, M: X<&'a Nested<L>>>() {
7157
| -- ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<L>` does not outlive the data it points at
@@ -77,7 +63,6 @@ help: consider adding an explicit lifetime bound
7763
LL | fn baz<'a, L: 'a, M: X<&'a Nested<L>>>() {
7864
| ++++
7965

80-
error: aborting due to 6 previous errors
66+
error: aborting due to 5 previous errors
8167

82-
Some errors have detailed explanations: E0309, E0310.
83-
For more information about an error, try `rustc --explain E0309`.
68+
For more information about this error, try `rustc --explain E0309`.

tests/ui/rfcs/rfc-2093-infer-outlives/dont-infer-static.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
/*
2-
* We don't infer `T: 'static` outlives relationships.
3-
*/
1+
// We don't infer `T: 'static` outlives relationships.
2+
3+
// check-pass
44

55
struct Foo<U> {
6-
bar: Bar<U> //~ ERROR the parameter type `U` may not live long enough [E0310]
6+
bar: Bar<U>,
77
}
88
struct Bar<T: 'static> {
99
x: T,

tests/ui/rfcs/rfc-2093-infer-outlives/dont-infer-static.stderr

-22
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Check that we rely on super trait bounds when computing implied bounds for ADTs.
2+
//
3+
// check-pass
4+
struct Foo<U> {
5+
bar: Bar<U>,
6+
}
7+
8+
trait Trait: 'static {}
9+
impl<T: 'static> Trait for T {}
10+
struct Bar<T: Trait> {
11+
x: T,
12+
}
13+
14+
fn main() {}

tests/ui/wf/wf-in-obj-type-static.rs renamed to tests/ui/rfcs/rfc-2093-infer-outlives/object-infer-static.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Check that we enforce WF conditions also for types in fns.
2-
2+
//
3+
// check-pass
34

45
#![allow(dead_code)]
56

@@ -10,8 +11,7 @@ struct MustBeCopy<T:Copy> {
1011
}
1112

1213
struct Foo<T> {
13-
// needs T: 'static
14-
x: dyn Object<&'static T> //~ ERROR E0310
14+
x: dyn Object<&'static T>
1515
}
1616

1717

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
struct Foo<T> { t: &'static T }
2+
3+
fn main() {
4+
let x = 3;
5+
let _ = Foo { t: &x }; //~ ERROR `x` does not live long enough
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error[E0597]: `x` does not live long enough
2+
--> $DIR/unexpected-error.rs:5:22
3+
|
4+
LL | let x = 3;
5+
| - binding `x` declared here
6+
LL | let _ = Foo { t: &x };
7+
| ^^
8+
| |
9+
| borrowed value does not live long enough
10+
| this usage requires that `x` is borrowed for `'static`
11+
LL | }
12+
| - `x` dropped here while still borrowed
13+
14+
error: aborting due to 1 previous error
15+
16+
For more information about this error, try `rustc --explain E0597`.

tests/ui/wf/wf-in-fn-type-static.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,17 @@
33

44
#![allow(dead_code)]
55

6-
7-
struct MustBeCopy<T:Copy> {
8-
t: T
9-
}
10-
116
struct Foo<T> {
12-
// needs T: 'static
13-
x: fn() -> &'static T //~ ERROR E0310
7+
x: fn() -> &'static T,
148
}
159

1610
struct Bar<T> {
17-
// needs T: Copy
18-
x: fn(&'static T) //~ ERROR E0310
11+
x: fn(&'static T),
1912
}
2013

14+
fn not_static<T>() {
15+
let _: Foo<T>; //~ ERROR E0310
16+
let _: Bar<T>; //~ ERROR E0310
17+
}
2118

2219
fn main() { }

tests/ui/wf/wf-in-fn-type-static.stderr

+16-16
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
error[E0310]: the parameter type `T` may not live long enough
2-
--> $DIR/wf-in-fn-type-static.rs:13:8
2+
--> $DIR/wf-in-fn-type-static.rs:15:12
33
|
4-
LL | x: fn() -> &'static T
5-
| ^^^^^^^^^^^^^^^^^^
6-
| |
7-
| the parameter type `T` must be valid for the static lifetime...
8-
| ...so that the reference type `&'static T` does not outlive the data it points at
4+
LL | let _: Foo<T>;
5+
| ^^^^^^
6+
| |
7+
| the parameter type `T` must be valid for the static lifetime...
8+
| ...so that the type `T` will meet its required lifetime bounds
99
|
1010
help: consider adding an explicit lifetime bound
1111
|
12-
LL | struct Foo<T: 'static> {
13-
| +++++++++
12+
LL | fn not_static<T: 'static>() {
13+
| +++++++++
1414

1515
error[E0310]: the parameter type `T` may not live long enough
16-
--> $DIR/wf-in-fn-type-static.rs:18:8
16+
--> $DIR/wf-in-fn-type-static.rs:16:12
1717
|
18-
LL | x: fn(&'static T)
19-
| ^^^^^^^^^^^^^^
20-
| |
21-
| the parameter type `T` must be valid for the static lifetime...
22-
| ...so that the reference type `&'static T` does not outlive the data it points at
18+
LL | let _: Bar<T>;
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
2323
|
2424
help: consider adding an explicit lifetime bound
2525
|
26-
LL | struct Bar<T: 'static> {
27-
| +++++++++
26+
LL | fn not_static<T: 'static>() {
27+
| +++++++++
2828

2929
error: aborting due to 2 previous errors
3030

tests/ui/wf/wf-in-obj-type-static.stderr

-17
This file was deleted.

0 commit comments

Comments
 (0)