From 63c959dea9e0a92579918fa9f791a6e90270acc9 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 12 Jan 2024 09:42:41 +0100 Subject: [PATCH] ADT implied bounds: consider 'static + elaborate --- .../src/outlives/explicit.rs | 83 ++++++++++--------- .../src/outlives/implicit_infer.rs | 2 +- .../rustc_hir_analysis/src/outlives/utils.rs | 3 +- .../lifetime-doesnt-live-long-enough.rs | 5 -- .../lifetime-doesnt-live-long-enough.stderr | 29 ++----- .../dont-infer-static.rs | 8 +- .../dont-infer-static.stderr | 22 ----- .../infer-static-from-trait-bound.rs | 14 ++++ .../object-infer-static.rs} | 6 +- .../unexpected-error.rs | 6 ++ .../unexpected-error.stderr | 16 ++++ tests/ui/wf/wf-in-fn-type-static.rs | 15 ++-- tests/ui/wf/wf-in-fn-type-static.stderr | 32 +++---- tests/ui/wf/wf-in-obj-type-static.stderr | 17 ---- 14 files changed, 121 insertions(+), 137 deletions(-) delete mode 100644 tests/ui/rfcs/rfc-2093-infer-outlives/dont-infer-static.stderr create mode 100644 tests/ui/rfcs/rfc-2093-infer-outlives/infer-static-from-trait-bound.rs rename tests/ui/{wf/wf-in-obj-type-static.rs => rfcs/rfc-2093-infer-outlives/object-infer-static.rs} (71%) create mode 100644 tests/ui/rfcs/rfc-2093-infer-outlives/unexpected-error.rs create mode 100644 tests/ui/rfcs/rfc-2093-infer-outlives/unexpected-error.stderr delete mode 100644 tests/ui/wf/wf-in-obj-type-static.stderr diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index a7fca41f86ac..d33a66d3eb3b 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -1,6 +1,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, OutlivesPredicate, TyCtxt}; +use rustc_trait_selection::traits::elaborate; use super::utils::*; @@ -18,46 +19,54 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { &mut self, tcx: TyCtxt<'tcx>, def_id: DefId, - ) -> &ty::EarlyBinder> { - self.map.entry(def_id).or_insert_with(|| { - let predicates = if def_id.is_local() { - tcx.explicit_predicates_of(def_id) - } else { - tcx.predicates_of(def_id) - }; - let mut required_predicates = RequiredPredicates::default(); - - // process predicates and convert to `RequiredPredicates` entry, see below - for &(predicate, span) in predicates.predicates { - match predicate.kind().skip_binder() { - ty::ClauseKind::TypeOutlives(OutlivesPredicate(ty, reg)) => { - insert_outlives_predicate( - tcx, - ty.into(), - reg, - span, - &mut required_predicates, - ) - } + ) -> ty::EarlyBinder<&RequiredPredicates<'tcx>> { + self.map + .entry(def_id) + .or_insert_with(|| { + let predicates = if def_id.is_local() { + tcx.explicit_predicates_of(def_id) + } else { + tcx.predicates_of(def_id) + }; + + let mut required_predicates = RequiredPredicates::default(); + + // process predicates and convert to `RequiredPredicates` entry, see below + let predicates = predicates + .predicates + .into_iter() + .flat_map(|&(p, span)| elaborate(tcx, [p]).map(move |p| (p, span))); + for (predicate, span) in predicates { + match predicate.kind().skip_binder() { + ty::ClauseKind::TypeOutlives(OutlivesPredicate(ty, reg)) => { + insert_outlives_predicate( + tcx, + ty.into(), + reg, + span, + &mut required_predicates, + ) + } - ty::ClauseKind::RegionOutlives(OutlivesPredicate(reg1, reg2)) => { - insert_outlives_predicate( - tcx, - reg1.into(), - reg2, - span, - &mut required_predicates, - ) + ty::ClauseKind::RegionOutlives(OutlivesPredicate(reg1, reg2)) => { + insert_outlives_predicate( + tcx, + reg1.into(), + reg2, + span, + &mut required_predicates, + ) + } + ty::ClauseKind::Trait(_) + | ty::ClauseKind::Projection(_) + | ty::ClauseKind::ConstArgHasType(_, _) + | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::ConstEvaluatable(_) => {} } - ty::ClauseKind::Trait(_) - | ty::ClauseKind::Projection(_) - | ty::ClauseKind::ConstArgHasType(_, _) - | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) => {} } - } - ty::EarlyBinder::bind(required_predicates) - }) + ty::EarlyBinder::bind(required_predicates) + }) + .as_ref() } } diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index c17925471d98..820b73bd9f05 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -253,7 +253,7 @@ fn check_explicit_predicates<'tcx>( ); let explicit_predicates = explicit_map.explicit_predicates_of(tcx, def_id); - for (outlives_predicate, &span) in explicit_predicates.as_ref().skip_binder() { + for (outlives_predicate, &span) in explicit_predicates.skip_binder() { debug!("outlives_predicate = {:?}", &outlives_predicate); // Careful: If we are inferring the effects of a `dyn Trait<..>` diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs index 8077acea52e4..a0c0c9a78645 100644 --- a/compiler/rustc_hir_analysis/src/outlives/utils.rs +++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs @@ -21,7 +21,8 @@ pub(crate) fn insert_outlives_predicate<'tcx>( ) { // If the `'a` region is bound within the field type itself, we // don't want to propagate this constraint to the header. - if !is_free_region(outlived_region) { + let valid_outlived_region = is_free_region(outlived_region) || outlived_region.is_static(); + if !valid_outlived_region { return; } diff --git a/tests/ui/lifetimes/lifetime-doesnt-live-long-enough.rs b/tests/ui/lifetimes/lifetime-doesnt-live-long-enough.rs index d2b782c92f3d..6ddc191a6ebc 100644 --- a/tests/ui/lifetimes/lifetime-doesnt-live-long-enough.rs +++ b/tests/ui/lifetimes/lifetime-doesnt-live-long-enough.rs @@ -15,11 +15,6 @@ impl<'a, T: ListItem<'a>> Collection for List<'a, T> { } } -struct Foo { - foo: &'static T - //~^ ERROR may not live long enough -} - trait X: Sized { fn foo<'a, L: X<&'a Nested>>(); //~^ ERROR may not live long enough diff --git a/tests/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr b/tests/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr index 235092e24634..0a73bef88c1c 100644 --- a/tests/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr +++ b/tests/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr @@ -1,19 +1,5 @@ -error[E0310]: the parameter type `T` may not live long enough - --> $DIR/lifetime-doesnt-live-long-enough.rs:19:10 - | -LL | foo: &'static T - | ^^^^^^^^^^ - | | - | the parameter type `T` must be valid for the static lifetime... - | ...so that the reference type `&'static T` does not outlive the data it points at - | -help: consider adding an explicit lifetime bound - | -LL | struct Foo { - | +++++++++ - error[E0309]: the parameter type `K` may not live long enough - --> $DIR/lifetime-doesnt-live-long-enough.rs:41:33 + --> $DIR/lifetime-doesnt-live-long-enough.rs:36:33 | LL | fn generic_in_parent<'a, L: X<&'a Nested>>() { | -- ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested` does not outlive the data it points at @@ -26,7 +12,7 @@ LL | fn generic_in_parent<'a, L: X<&'a Nested>>() where K: 'a { | +++++++++++ error[E0309]: the parameter type `M` may not live long enough - --> $DIR/lifetime-doesnt-live-long-enough.rs:44:36 + --> $DIR/lifetime-doesnt-live-long-enough.rs:39:36 | LL | fn generic_in_child<'a, 'b, L: X<&'a Nested>, M: 'b>() { | -- ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested` does not outlive the data it points at @@ -39,7 +25,7 @@ LL | fn generic_in_child<'a, 'b, L: X<&'a Nested>, M: 'b + 'a>() { | ++++ error[E0309]: the parameter type `K` may not live long enough - --> $DIR/lifetime-doesnt-live-long-enough.rs:24:19 + --> $DIR/lifetime-doesnt-live-long-enough.rs:19:19 | LL | fn foo<'a, L: X<&'a Nested>>(); | -- ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested` does not outlive the data it points at @@ -52,7 +38,7 @@ LL | fn foo<'a, L: X<&'a Nested>>() where K: 'a; | +++++++++++ error[E0309]: the parameter type `Self` may not live long enough - --> $DIR/lifetime-doesnt-live-long-enough.rs:28:19 + --> $DIR/lifetime-doesnt-live-long-enough.rs:23:19 | LL | fn bar<'a, L: X<&'a Nested>>(); | -- ^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested` does not outlive the data it points at @@ -65,7 +51,7 @@ LL | fn bar<'a, L: X<&'a Nested>>() where Self: 'a; | ++++++++++++++ error[E0309]: the parameter type `L` may not live long enough - --> $DIR/lifetime-doesnt-live-long-enough.rs:32:22 + --> $DIR/lifetime-doesnt-live-long-enough.rs:27:22 | LL | fn baz<'a, L, M: X<&'a Nested>>() { | -- ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested` does not outlive the data it points at @@ -77,7 +63,6 @@ help: consider adding an explicit lifetime bound LL | fn baz<'a, L: 'a, M: X<&'a Nested>>() { | ++++ -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0309, E0310. -For more information about an error, try `rustc --explain E0309`. +For more information about this error, try `rustc --explain E0309`. diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/dont-infer-static.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/dont-infer-static.rs index d3940b13b11a..60a19e6deea3 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/dont-infer-static.rs +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/dont-infer-static.rs @@ -1,9 +1,9 @@ -/* - * We don't infer `T: 'static` outlives relationships. - */ +// We don't infer `T: 'static` outlives relationships. + +// check-pass struct Foo { - bar: Bar //~ ERROR the parameter type `U` may not live long enough [E0310] + bar: Bar, } struct Bar { x: T, diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/dont-infer-static.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/dont-infer-static.stderr deleted file mode 100644 index b0f1d7b33e40..000000000000 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/dont-infer-static.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0310]: the parameter type `U` may not live long enough - --> $DIR/dont-infer-static.rs:6:10 - | -LL | bar: Bar - | ^^^^^^ - | | - | the parameter type `U` must be valid for the static lifetime... - | ...so that the type `U` will meet its required lifetime bounds... - | -note: ...that is required by this bound - --> $DIR/dont-infer-static.rs:8:15 - | -LL | struct Bar { - | ^^^^^^^ -help: consider adding an explicit lifetime bound - | -LL | struct Foo { - | +++++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/infer-static-from-trait-bound.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/infer-static-from-trait-bound.rs new file mode 100644 index 000000000000..194882603e1c --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/infer-static-from-trait-bound.rs @@ -0,0 +1,14 @@ +// Check that we rely on super trait bounds when computing implied bounds for ADTs. +// +// check-pass +struct Foo { + bar: Bar, +} + +trait Trait: 'static {} +impl Trait for T {} +struct Bar { + x: T, +} + +fn main() {} diff --git a/tests/ui/wf/wf-in-obj-type-static.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/object-infer-static.rs similarity index 71% rename from tests/ui/wf/wf-in-obj-type-static.rs rename to tests/ui/rfcs/rfc-2093-infer-outlives/object-infer-static.rs index 1ad2fd1edb3b..63f5914358e3 100644 --- a/tests/ui/wf/wf-in-obj-type-static.rs +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/object-infer-static.rs @@ -1,5 +1,6 @@ // Check that we enforce WF conditions also for types in fns. - +// +// check-pass #![allow(dead_code)] @@ -10,8 +11,7 @@ struct MustBeCopy { } struct Foo { - // needs T: 'static - x: dyn Object<&'static T> //~ ERROR E0310 + x: dyn Object<&'static T> } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/unexpected-error.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/unexpected-error.rs new file mode 100644 index 000000000000..00393eb5602b --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/unexpected-error.rs @@ -0,0 +1,6 @@ +struct Foo { t: &'static T } + +fn main() { + let x = 3; + let _ = Foo { t: &x }; //~ ERROR `x` does not live long enough +} diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/unexpected-error.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/unexpected-error.stderr new file mode 100644 index 000000000000..de6dedd3e14c --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/unexpected-error.stderr @@ -0,0 +1,16 @@ +error[E0597]: `x` does not live long enough + --> $DIR/unexpected-error.rs:5:22 + | +LL | let x = 3; + | - binding `x` declared here +LL | let _ = Foo { t: &x }; + | ^^ + | | + | borrowed value does not live long enough + | this usage requires that `x` is borrowed for `'static` +LL | } + | - `x` dropped here while still borrowed + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/wf/wf-in-fn-type-static.rs b/tests/ui/wf/wf-in-fn-type-static.rs index 73071dd23ad7..c9980db5fd4f 100644 --- a/tests/ui/wf/wf-in-fn-type-static.rs +++ b/tests/ui/wf/wf-in-fn-type-static.rs @@ -3,20 +3,17 @@ #![allow(dead_code)] - -struct MustBeCopy { - t: T -} - struct Foo { - // needs T: 'static - x: fn() -> &'static T //~ ERROR E0310 + x: fn() -> &'static T, } struct Bar { - // needs T: Copy - x: fn(&'static T) //~ ERROR E0310 + x: fn(&'static T), } +fn not_static() { + let _: Foo; //~ ERROR E0310 + let _: Bar; //~ ERROR E0310 +} fn main() { } diff --git a/tests/ui/wf/wf-in-fn-type-static.stderr b/tests/ui/wf/wf-in-fn-type-static.stderr index 45ad9fba0ce7..a355dfe20842 100644 --- a/tests/ui/wf/wf-in-fn-type-static.stderr +++ b/tests/ui/wf/wf-in-fn-type-static.stderr @@ -1,30 +1,30 @@ error[E0310]: the parameter type `T` may not live long enough - --> $DIR/wf-in-fn-type-static.rs:13:8 + --> $DIR/wf-in-fn-type-static.rs:15:12 | -LL | x: fn() -> &'static T - | ^^^^^^^^^^^^^^^^^^ - | | - | the parameter type `T` must be valid for the static lifetime... - | ...so that the reference type `&'static T` does not outlive the data it points at +LL | let _: Foo; + | ^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds | help: consider adding an explicit lifetime bound | -LL | struct Foo { - | +++++++++ +LL | fn not_static() { + | +++++++++ error[E0310]: the parameter type `T` may not live long enough - --> $DIR/wf-in-fn-type-static.rs:18:8 + --> $DIR/wf-in-fn-type-static.rs:16:12 | -LL | x: fn(&'static T) - | ^^^^^^^^^^^^^^ - | | - | the parameter type `T` must be valid for the static lifetime... - | ...so that the reference type `&'static T` does not outlive the data it points at +LL | let _: Bar; + | ^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds | help: consider adding an explicit lifetime bound | -LL | struct Bar { - | +++++++++ +LL | fn not_static() { + | +++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/wf/wf-in-obj-type-static.stderr b/tests/ui/wf/wf-in-obj-type-static.stderr deleted file mode 100644 index 9e837b10e284..000000000000 --- a/tests/ui/wf/wf-in-obj-type-static.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0310]: the parameter type `T` may not live long enough - --> $DIR/wf-in-obj-type-static.rs:14:8 - | -LL | x: dyn Object<&'static T> - | ^^^^^^^^^^^^^^^^^^^^^^ - | | - | the parameter type `T` must be valid for the static lifetime... - | ...so that the reference type `&'static T` does not outlive the data it points at - | -help: consider adding an explicit lifetime bound - | -LL | struct Foo { - | +++++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0310`.