Skip to content

Commit 5aa3d2a

Browse files
committed
GCI: Imply outlives-bounds on free (generic) const items
1 parent 40daf23 commit 5aa3d2a

File tree

7 files changed

+97
-30
lines changed

7 files changed

+97
-30
lines changed

compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,13 @@ use tracing::debug;
88
use super::explicit::ExplicitPredicatesMap;
99
use super::utils::*;
1010

11-
/// Infer predicates for the items in the crate.
12-
///
13-
/// `global_inferred_outlives`: this is initially the empty map that
14-
/// was generated by walking the items in the crate. This will
15-
/// now be filled with inferred predicates.
11+
/// Infer outlives-predicates for the items in the local crate.
1612
pub(super) fn infer_predicates(
1713
tcx: TyCtxt<'_>,
1814
) -> FxIndexMap<DefId, ty::EarlyBinder<'_, RequiredPredicates<'_>>> {
1915
debug!("infer_predicates");
2016

2117
let mut explicit_map = ExplicitPredicatesMap::new();
22-
2318
let mut global_inferred_outlives = FxIndexMap::default();
2419

2520
// If new predicates were added then we need to re-calculate
@@ -70,6 +65,17 @@ pub(super) fn infer_predicates(
7065
);
7166
}
7267

68+
DefKind::Const => {
69+
insert_required_predicates_to_be_wf(
70+
tcx,
71+
tcx.type_of(item_did).instantiate_identity(),
72+
tcx.def_span(item_did),
73+
&global_inferred_outlives,
74+
&mut item_required_predicates,
75+
&mut explicit_map,
76+
);
77+
}
78+
7379
_ => {}
7480
};
7581

@@ -312,7 +318,7 @@ fn check_explicit_predicates<'tcx>(
312318
}
313319
}
314320

315-
/// Check the inferred predicates declared on the type.
321+
/// Check the inferred predicates of the type.
316322
///
317323
/// ### Example
318324
///

compiler/rustc_hir_analysis/src/outlives/mod.rs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub(crate) fn provide(providers: &mut Providers) {
1515

1616
fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clause<'_>, Span)] {
1717
match tcx.def_kind(item_def_id) {
18-
DefKind::Struct | DefKind::Enum | DefKind::Union => {
18+
DefKind::Struct | DefKind::Enum | DefKind::Union | DefKind::Const => {
1919
let crate_map = tcx.inferred_outlives_crate(());
2020
crate_map.predicates.get(&item_def_id.to_def_id()).copied().unwrap_or(&[])
2121
}
@@ -48,15 +48,8 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clau
4848
}
4949
}
5050

51+
/// Compute a map from each applicable item in the local crate to its inferred/implied outlives-predicates.
5152
fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> {
52-
// Compute a map from each ADT (struct/enum/union) and lazy type alias to
53-
// the **explicit** outlives predicates (`T: 'a`, `'a: 'b`) that the user wrote.
54-
// Typically there won't be many of these, except in older code where
55-
// they were mandatory. Nonetheless, we have to ensure that every such
56-
// predicate is satisfied, so they form a kind of base set of requirements
57-
// for the type.
58-
59-
// Compute the inferred predicates
6053
let global_inferred_outlives = implicit_infer::infer_predicates(tcx);
6154

6255
// Convert the inferred predicates into the "collected" form the

src/doc/rustc-dev-guide/src/traits/implied-bounds.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ handled... well... implicitly.
99

1010
## explicit implied bounds
1111

12-
The explicit implied bounds are computed in [`fn inferred_outlives_of`]. Only ADTs and
13-
lazy type aliases have explicit implied bounds which are computed via a fixpoint algorithm
14-
in the [`fn inferred_outlives_crate`] query.
12+
The explicit implied bounds are computed in [`fn inferred_outlives_of`]. Only ADTs,
13+
[lazy type aliases][lta] and [free (generic) const items][gci] have explicit implied bounds
14+
which are computed via a fixpoint algorithm in the [`fn inferred_outlives_crate`] query.
1515

1616
We use [`fn insert_required_predicates_to_be_wf`] on all fields of all ADTs in the crate.
1717
This function computes the outlives bounds for each component of the field using a
@@ -31,6 +31,8 @@ if the outlived region is a region parameter. [It does not add `'static` require
3131
[`fn check_explicit_predicates`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs#L238
3232
[`fn insert_outlives_predicate`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_hir_analysis/src/outlives/utils.rs#L15
3333
[nostatic]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_hir_analysis/src/outlives/utils.rs#L159-L165
34+
[lta]: https://github.com/rust-lang/rust/issues/112792
35+
[gci]: https://github.com/rust-lang/rust/issues/113521
3436

3537
## implicit implied bounds
3638

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error: lifetime may not live long enough
2+
--> $DIR/implied-outlives-bounds.rs:20:9
3+
|
4+
LL | fn env0<'any>() {
5+
| ---- lifetime `'any` defined here
6+
LL | _ = TYPE_OUTLIVES_0::<'static, &'any ()>;
7+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'any` must outlive `'static`
8+
9+
error: lifetime may not live long enough
10+
--> $DIR/implied-outlives-bounds.rs:25:9
11+
|
12+
LL | fn env1<'any>() {
13+
| ---- lifetime `'any` defined here
14+
LL | _ = REGION_OUTLIVES_0::<'static, 'any>;
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'any` must outlive `'static`
16+
17+
error: aborting due to 2 previous errors
18+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Check that we imply outlives-bounds on free const items.
2+
//@ revisions: pos neg
3+
//@[pos] check-pass
4+
#![feature(generic_const_items)]
5+
#![feature(freeze)] // only used in the test case `TYPE_OUTLIVES_1`
6+
#![expect(incomplete_features)]
7+
8+
const REGION_OUTLIVES_0<'a, 'b>: Option<&'a &'b ()> = None; // we imply `'a: 'b`
9+
const REGION_OUTLIVES_1<'a, 'b>: &'a &'b () = &&(); // we imply `'a: 'b`
10+
11+
const TYPE_OUTLIVES_0<'a, T>: Option<&'a T> = None; // we imply `T: 'a`
12+
13+
const TYPE_OUTLIVES_1<'a, T: Def>: &'a T = &T::DEF; // we imply `T: 'a`
14+
trait Def: std::marker::Freeze { const DEF: Self; }
15+
16+
// Ensure that we actually enforce these implied bounds at usage sites:
17+
18+
#[cfg(neg)]
19+
fn env0<'any>() {
20+
_ = TYPE_OUTLIVES_0::<'static, &'any ()>; //[neg]~ ERROR lifetime may not live long enough
21+
}
22+
23+
#[cfg(neg)]
24+
fn env1<'any>() {
25+
_ = REGION_OUTLIVES_0::<'static, 'any>; //[neg]~ ERROR lifetime may not live long enough
26+
}
27+
28+
fn main() {}

tests/ui/generic-const-items/reference-outlives-referent.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,16 @@
22
// successfully emit a diagnostic. Regression test for issue #114714.
33

44
#![feature(generic_const_items)]
5-
#![allow(incomplete_features)]
5+
#![expect(incomplete_features)]
66

7-
const Q<'a, 'b>: &'a &'b () = &&(); //~ ERROR reference has a longer lifetime than the data it references
7+
struct S<'a>(&'a ());
8+
9+
impl<'a> S<'a> {
10+
const K<'b>: &'a &'b () = &&(); //~ ERROR reference has a longer lifetime than the data it references
11+
}
12+
13+
const Q<'a, 'b>: () = {
14+
let _: &'a &'b () = &&(); //~ ERROR lifetime may not live long enough
15+
};
816

917
fn main() {}
Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,32 @@
11
error[E0491]: in type `&'a &'b ()`, reference has a longer lifetime than the data it references
2-
--> $DIR/reference-outlives-referent.rs:7:18
2+
--> $DIR/reference-outlives-referent.rs:10:5
33
|
4-
LL | const Q<'a, 'b>: &'a &'b () = &&();
5-
| ^^^^^^^^^^
4+
LL | const K<'b>: &'a &'b () = &&();
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
77
note: the pointer is valid for the lifetime `'a` as defined here
8-
--> $DIR/reference-outlives-referent.rs:7:9
8+
--> $DIR/reference-outlives-referent.rs:9:6
99
|
10-
LL | const Q<'a, 'b>: &'a &'b () = &&();
11-
| ^^
10+
LL | impl<'a> S<'a> {
11+
| ^^
1212
note: but the referenced data is only valid for the lifetime `'b` as defined here
13-
--> $DIR/reference-outlives-referent.rs:7:13
13+
--> $DIR/reference-outlives-referent.rs:10:13
1414
|
15-
LL | const Q<'a, 'b>: &'a &'b () = &&();
15+
LL | const K<'b>: &'a &'b () = &&();
1616
| ^^
1717

18-
error: aborting due to 1 previous error
18+
error: lifetime may not live long enough
19+
--> $DIR/reference-outlives-referent.rs:14:12
20+
|
21+
LL | const Q<'a, 'b>: () = {
22+
| -- -- lifetime `'b` defined here
23+
| |
24+
| lifetime `'a` defined here
25+
LL | let _: &'a &'b () = &&();
26+
| ^^^^^^^^^^ requires that `'b` must outlive `'a`
27+
|
28+
= help: consider adding the following bound: `'b: 'a`
29+
30+
error: aborting due to 2 previous errors
1931

2032
For more information about this error, try `rustc --explain E0491`.

0 commit comments

Comments
 (0)