From 8c66aab9ca78bc1a619f137f0c8aa38f29d2bb95 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Fri, 31 Oct 2025 15:36:41 +0100 Subject: [PATCH 1/9] Do not propogate unnecessary closure constraints + tests. --- .../rustc_borrowck/src/region_infer/mod.rs | 47 +++++++++++++++---- .../closure-prop-issue-104477-case1.rs | 11 +++++ tests/ui/regions/closure-prop-issue-148289.rs | 22 +++++++++ 3 files changed, 70 insertions(+), 10 deletions(-) create mode 100644 tests/ui/regions/closure-prop-issue-104477-case1.rs create mode 100644 tests/ui/regions/closure-prop-issue-148289.rs diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index e98c60e633805..3728ecc4400be 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1290,17 +1290,44 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Grow `shorter_fr` until we find some non-local regions. (We // always will.) We'll call them `shorter_fr+` -- they're ever // so slightly larger than `shorter_fr`. - let shorter_fr_plus = + let shorter_fr_plusses = self.universal_region_relations.non_local_upper_bounds(shorter_fr); - debug!("try_propagate_universal_region_error: shorter_fr_plus={:?}", shorter_fr_plus); - for fr in shorter_fr_plus { - // Push the constraint `fr-: shorter_fr+` - propagated_outlives_requirements.push(ClosureOutlivesRequirement { - subject: ClosureOutlivesSubject::Region(fr_minus), - outlived_free_region: fr, - blame_span: blame_constraint.cause.span, - category: blame_constraint.category, - }); + debug!( + "try_propagate_universal_region_error: shorter_fr_plus={:?}", + shorter_fr_plusses + ); + + let fr_static = self.universal_regions().fr_static; + let single_region = shorter_fr_plusses.len() == 1; + + for shorter_fr_plus in shorter_fr_plusses { + // Don't propagate every `fr-: shorter_fr+`. + // A smaller "optimal subset" exists, since full propagation is overly conservative + // and can reject valid code. Consider this small example (`'b: 'a` == `a -> b`) + // were we try to propagate region error `'d: 'a`: + // a --> b --> d + // \ + // \-> c + // Here `shorter_fr_plusses` == `['b, 'c]`. + // Propagating `'d: 'b` is correct and should happen; `'d: 'c` is redundant and can reject valid code. + // We can come closer to this "optimal subset" by checking if the `shorter_fr+` should be outlived by `fr-`. + // NOTE: [] is *not* a valid subset, so we check for that as well. + if single_region + || shorter_fr_plus == fr_static // `fr-: 'static` should be propagated + || self.eval_outlives(fr_minus, shorter_fr_plus) + { + debug!( + "try_propagate_universal_region_error: propagating {:?}: {:?}", + fr_minus, shorter_fr_plus, + ); + // If that's the case, push the constraint `fr-: shorter_fr+` + propagated_outlives_requirements.push(ClosureOutlivesRequirement { + subject: ClosureOutlivesSubject::Region(fr_minus), + outlived_free_region: shorter_fr_plus, + blame_span: blame_constraint.cause.span, + category: blame_constraint.category, + }); + } } return RegionRelationCheckResult::Propagated; } diff --git a/tests/ui/regions/closure-prop-issue-104477-case1.rs b/tests/ui/regions/closure-prop-issue-104477-case1.rs new file mode 100644 index 0000000000000..c51dea4335599 --- /dev/null +++ b/tests/ui/regions/closure-prop-issue-104477-case1.rs @@ -0,0 +1,11 @@ +//@ check-pass + + +struct MyTy<'x, 'a, 'b>(std::cell::Cell<(&'x &'a u8, &'x &'b u8)>); +fn wf(_: T) {} +fn test<'a, 'b>() { + |_: &'a u8, x: MyTy<'_, 'a, 'b>| wf(x); + |x: MyTy<'_, 'a, 'b>, _: &'a u8| wf(x); +} + +fn main(){} diff --git a/tests/ui/regions/closure-prop-issue-148289.rs b/tests/ui/regions/closure-prop-issue-148289.rs new file mode 100644 index 0000000000000..b6acf5655c99d --- /dev/null +++ b/tests/ui/regions/closure-prop-issue-148289.rs @@ -0,0 +1,22 @@ +//@ check-pass + +#[derive(Clone, Copy)] +struct Inv<'a>(*mut &'a ()); +impl<'a> Inv<'a> { + fn outlived_by<'b: 'a>(self, _: Inv<'b>) {} +} +struct OutlivedBy<'a, 'b: 'a>(Inv<'a>, Inv<'b>); + +fn closure_arg<'b, 'c, 'd>( + _: impl for<'a> FnOnce(Inv<'a>, OutlivedBy<'a, 'b>, OutlivedBy<'a, 'c>, Inv<'d>), +) { +} +fn foo<'b, 'c, 'd: 'b>() { + closure_arg::<'b, 'c, 'd>(|a, b, c, d| { + a.outlived_by(b.1); + a.outlived_by(c.1); + b.1.outlived_by(d); + }); +} + +fn main() {} From a36dc084177e6d554a8496d395ee319442ab3e79 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Mon, 3 Nov 2025 17:03:47 +0100 Subject: [PATCH 2/9] correct filtering of regions + update comment --- .../rustc_borrowck/src/region_infer/mod.rs | 65 +++++++++---------- 1 file changed, 29 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 3728ecc4400be..61a6d6d5b79d9 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1290,44 +1290,37 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Grow `shorter_fr` until we find some non-local regions. (We // always will.) We'll call them `shorter_fr+` -- they're ever // so slightly larger than `shorter_fr`. - let shorter_fr_plusses = + let shorter_fr_plus = self.universal_region_relations.non_local_upper_bounds(shorter_fr); - debug!( - "try_propagate_universal_region_error: shorter_fr_plus={:?}", - shorter_fr_plusses - ); - let fr_static = self.universal_regions().fr_static; - let single_region = shorter_fr_plusses.len() == 1; - - for shorter_fr_plus in shorter_fr_plusses { - // Don't propagate every `fr-: shorter_fr+`. - // A smaller "optimal subset" exists, since full propagation is overly conservative - // and can reject valid code. Consider this small example (`'b: 'a` == `a -> b`) - // were we try to propagate region error `'d: 'a`: - // a --> b --> d - // \ - // \-> c - // Here `shorter_fr_plusses` == `['b, 'c]`. - // Propagating `'d: 'b` is correct and should happen; `'d: 'c` is redundant and can reject valid code. - // We can come closer to this "optimal subset" by checking if the `shorter_fr+` should be outlived by `fr-`. - // NOTE: [] is *not* a valid subset, so we check for that as well. - if single_region - || shorter_fr_plus == fr_static // `fr-: 'static` should be propagated - || self.eval_outlives(fr_minus, shorter_fr_plus) - { - debug!( - "try_propagate_universal_region_error: propagating {:?}: {:?}", - fr_minus, shorter_fr_plus, - ); - // If that's the case, push the constraint `fr-: shorter_fr+` - propagated_outlives_requirements.push(ClosureOutlivesRequirement { - subject: ClosureOutlivesSubject::Region(fr_minus), - outlived_free_region: shorter_fr_plus, - blame_span: blame_constraint.cause.span, - category: blame_constraint.category, - }); - } + // If any of the `shorter_fr+` regions are already outlived by `fr-`, we propagate only those. + // Otherwise, we might incorrectly reject valid code. + // + // Consider this example (`'b: 'a` == `a -> b`), where we try to propagate `'d: 'a`: + // a --> b --> d + // \ + // \-> c + // Here, `shorter_fr+` of `'a` == `['b, 'c]`. + // Propagating `'d: 'b` is correct and should occur; `'d: 'c` is redundant because of `'d: 'b` + // and could reject valid code. + // + // So we filter `shorter_fr+` to regions already outlived by `fr-`, but if the filter yields an empty set, + // we fall back to the original one. + let subset: Vec<_> = shorter_fr_plus + .iter() + .filter(|&&fr_plus| self.eval_outlives(fr_minus, fr_plus)) + .copied() + .collect(); + let shorter_fr_plus = if subset.is_empty() { shorter_fr_plus } else { subset }; + debug!("try_propagate_universal_region_error: shorter_fr_plus={:?}", shorter_fr_plus); + for fr in shorter_fr_plus { + // Push the constraint `fr-: shorter_fr+` + propagated_outlives_requirements.push(ClosureOutlivesRequirement { + subject: ClosureOutlivesSubject::Region(fr_minus), + outlived_free_region: fr, + blame_span: blame_constraint.cause.span, + category: blame_constraint.category, + }); } return RegionRelationCheckResult::Propagated; } From a2e305dcc85cecddf94b8fb00b318fa932185065 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Fri, 7 Nov 2025 12:16:11 +0100 Subject: [PATCH 3/9] address review: add explanation for tests --- tests/ui/regions/closure-prop-issue-104477-case1.rs | 5 ++++- tests/ui/regions/closure-prop-issue-148289.rs | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/ui/regions/closure-prop-issue-104477-case1.rs b/tests/ui/regions/closure-prop-issue-104477-case1.rs index c51dea4335599..307ca930baea7 100644 --- a/tests/ui/regions/closure-prop-issue-104477-case1.rs +++ b/tests/ui/regions/closure-prop-issue-104477-case1.rs @@ -1,5 +1,8 @@ //@ check-pass - +// This checks that the compiler does not require that 'a: 'b. '_ has 'a and 'b as non-local +// upper bounds, but the compiler should not propagate 'a: 'b OR 'b: 'a when checking +// the closures. If it did, this would fail to compile, eventhough it's a valid program. +// PR #148329 explains this in detail. struct MyTy<'x, 'a, 'b>(std::cell::Cell<(&'x &'a u8, &'x &'b u8)>); fn wf(_: T) {} diff --git a/tests/ui/regions/closure-prop-issue-148289.rs b/tests/ui/regions/closure-prop-issue-148289.rs index b6acf5655c99d..fcaa6d970ad91 100644 --- a/tests/ui/regions/closure-prop-issue-148289.rs +++ b/tests/ui/regions/closure-prop-issue-148289.rs @@ -1,4 +1,8 @@ //@ check-pass +// This test checks that the compiler does not propagate 'd: 'c when propagating region errors +// for the closure argument. If it did, this would fail to compile, eventhough it's a valid program. +// It should only propagate 'd: 'c. +// PR #148329 explains this in detail. #[derive(Clone, Copy)] struct Inv<'a>(*mut &'a ()); From 477a82012397147d3ddeb9311ff6c3046fdb88d9 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Tue, 11 Nov 2025 12:45:59 +0100 Subject: [PATCH 4/9] fix typo in test explanation --- tests/ui/regions/closure-prop-issue-148289.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/regions/closure-prop-issue-148289.rs b/tests/ui/regions/closure-prop-issue-148289.rs index fcaa6d970ad91..7f89927a76e03 100644 --- a/tests/ui/regions/closure-prop-issue-148289.rs +++ b/tests/ui/regions/closure-prop-issue-148289.rs @@ -1,7 +1,7 @@ //@ check-pass // This test checks that the compiler does not propagate 'd: 'c when propagating region errors // for the closure argument. If it did, this would fail to compile, eventhough it's a valid program. -// It should only propagate 'd: 'c. +// It should only propagate 'd: 'b. // PR #148329 explains this in detail. #[derive(Clone, Copy)] From b7f5bcaf77358ce2df1aa25c310b0242c222016a Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Tue, 11 Nov 2025 22:16:13 +0100 Subject: [PATCH 5/9] propagate region error for every non-local lower bound --- .../rustc_borrowck/src/region_infer/mod.rs | 51 +++++++++++++------ .../src/type_check/free_region_relations.rs | 24 ++------- 2 files changed, 39 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 61a6d6d5b79d9..1b634e5a3d589 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1275,13 +1275,19 @@ impl<'tcx> RegionInferenceContext<'tcx> { shorter_fr: RegionVid, propagated_outlives_requirements: &mut Option<&mut Vec>>, ) -> RegionRelationCheckResult { - if let Some(propagated_outlives_requirements) = propagated_outlives_requirements - // Shrink `longer_fr` until we find a non-local region (if we do). - // We'll call it `fr-` -- it's ever so slightly smaller than + if let Some(propagated_outlives_requirements) = propagated_outlives_requirements { + // Shrink `longer_fr` until we find some non-local regions. + // We'll call them `longer_fr-` -- they are ever so slightly smaller than // `longer_fr`. - && let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr) - { - debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus); + let longer_fr_minus = self.universal_region_relations.non_local_lower_bounds(longer_fr); + + debug!("try_propagate_universal_region_error: fr_minus={:?}", longer_fr_minus); + + // If we don't find a any non-local regions, we should error out as there is nothing + // to propagate. + if longer_fr_minus.is_empty() { + return RegionRelationCheckResult::Error; + } let blame_constraint = self .best_blame_constraint(longer_fr, NllRegionVariableOrigin::FreeRegion, shorter_fr) @@ -1292,8 +1298,17 @@ impl<'tcx> RegionInferenceContext<'tcx> { // so slightly larger than `shorter_fr`. let shorter_fr_plus = self.universal_region_relations.non_local_upper_bounds(shorter_fr); + debug!("try_propagate_universal_region_error: shorter_fr_plus={:?}", shorter_fr_plus); - // If any of the `shorter_fr+` regions are already outlived by `fr-`, we propagate only those. + // We then create constraints `longer_fr-: shorter_fr+` that may or may not be propagated (see below). + let mut constraints = vec![]; + for fr_minus in longer_fr_minus { + for shorter_fr_plus in &shorter_fr_plus { + constraints.push((fr_minus, *shorter_fr_plus)); + } + } + + // If any of the `shorter_fr+` regions are already outlived by `longer_fr-`, we propagate only those. // Otherwise, we might incorrectly reject valid code. // // Consider this example (`'b: 'a` == `a -> b`), where we try to propagate `'d: 'a`: @@ -1304,20 +1319,26 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Propagating `'d: 'b` is correct and should occur; `'d: 'c` is redundant because of `'d: 'b` // and could reject valid code. // - // So we filter `shorter_fr+` to regions already outlived by `fr-`, but if the filter yields an empty set, + // So we filter the constraints to regions already outlived by `longer_fr-`, but if the filter yields an empty set, // we fall back to the original one. - let subset: Vec<_> = shorter_fr_plus + let subset: Vec<_> = constraints .iter() - .filter(|&&fr_plus| self.eval_outlives(fr_minus, fr_plus)) + .filter(|&&(fr_minus, shorter_fr_plus)| { + self.eval_outlives(fr_minus, shorter_fr_plus) + }) .copied() .collect(); - let shorter_fr_plus = if subset.is_empty() { shorter_fr_plus } else { subset }; - debug!("try_propagate_universal_region_error: shorter_fr_plus={:?}", shorter_fr_plus); - for fr in shorter_fr_plus { - // Push the constraint `fr-: shorter_fr+` + let propagated_constraints = if subset.is_empty() { constraints } else { subset }; + debug!( + "try_propagate_universal_region_error: constraints={:?}", + propagated_constraints + ); + + for (fr_minus, fr_plus) in propagated_constraints { + // Push the constraint `long_fr-: shorter_fr+` propagated_outlives_requirements.push(ClosureOutlivesRequirement { subject: ClosureOutlivesSubject::Region(fr_minus), - outlived_free_region: fr, + outlived_free_region: fr_plus, blame_span: blame_constraint.cause.span, category: blame_constraint.category, }); diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index d27a73535bab0..279625cb87c9c 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -94,28 +94,10 @@ impl UniversalRegionRelations<'_> { /// words, returns the largest (*) known region `fr1` that (a) is /// outlived by `fr` and (b) is not local. /// - /// (*) If there are multiple competing choices, we pick the "postdominating" - /// one. See `TransitiveRelation::postdom_upper_bound` for details. - pub(crate) fn non_local_lower_bound(&self, fr: RegionVid) -> Option { + /// (*) If there are multiple competing choices, we return all of them. + pub(crate) fn non_local_lower_bounds(&self, fr: RegionVid) -> Vec { debug!("non_local_lower_bound(fr={:?})", fr); - let lower_bounds = self.non_local_bounds(&self.outlives, fr); - - // In case we find more than one, reduce to one for - // convenience. This is to prevent us from generating more - // complex constraints, but it will cause spurious errors. - let post_dom = self.outlives.mutual_immediate_postdominator(lower_bounds); - - debug!("non_local_bound: post_dom={:?}", post_dom); - - post_dom.and_then(|post_dom| { - // If the mutual immediate postdom is not local, then - // there is no non-local result we can return. - if !self.universal_regions.is_local_free_region(post_dom) { - Some(post_dom) - } else { - None - } - }) + self.non_local_bounds(&self.outlives, fr) } /// Helper for `non_local_upper_bounds` and `non_local_lower_bounds`. From 3071a81eb8f53fb92b650a487846447836553cd6 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Tue, 11 Nov 2025 22:17:11 +0100 Subject: [PATCH 6/9] test case2 --- tests/ui/regions/closure-prop-issue-104477-case2.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/ui/regions/closure-prop-issue-104477-case2.rs diff --git a/tests/ui/regions/closure-prop-issue-104477-case2.rs b/tests/ui/regions/closure-prop-issue-104477-case2.rs new file mode 100644 index 0000000000000..99a5d1c6c3ada --- /dev/null +++ b/tests/ui/regions/closure-prop-issue-104477-case2.rs @@ -0,0 +1,10 @@ +//@ check-pass +// FIXME: add explanation. + +struct MyTy<'a, 'b, 'x>(std::cell::Cell<(&'a &'x str, &'b &'x str)>); +fn wf(_: T) {} +fn test<'a, 'b, 'x>() { + |x: MyTy<'a, 'b, '_>| wf(x); +} + +fn main() {} From 967e963d3ae30d1aaf05b9a73797796e53e7b120 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Wed, 12 Nov 2025 00:20:38 +0100 Subject: [PATCH 7/9] bless test about post dominating lower bounds --- .../propagate-approximated-fail-no-postdom.rs | 13 ++-- ...pagate-approximated-fail-no-postdom.stderr | 69 ++++++++++++++----- 2 files changed, 60 insertions(+), 22 deletions(-) diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs index 5d21fa100a432..3ff5e1ca93634 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs +++ b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs @@ -1,5 +1,5 @@ -// Test where we fail to approximate due to demanding a postdom -// relationship between our upper bounds. +// Test that we can propagate multiple region errors by propagating all +// non-local lower bounds of `fr_longer`. //@ compile-flags:-Zverbose-internals @@ -13,9 +13,8 @@ use std::cell::Cell; // 'x: 'b // 'c: 'y // -// we have to prove that `'x: 'y`. We currently can only approximate -// via a postdominator -- hence we fail to choose between `'a` and -// `'b` here and report the error in the closure. +// we have to prove that `'x: 'y`. We find non-local lower bounds of 'x to be 'a and 'b and +// non-local upper bound of 'y to be 'c. So we propagate `'b: 'c` and `'a: 'c`. fn establish_relationships<'a, 'b, 'c, F>( _cell_a: Cell<&'a u32>, _cell_b: Cell<&'b u32>, @@ -36,6 +35,8 @@ fn demand_y<'x, 'y>(_cell_x: Cell<&'x u32>, _cell_y: Cell<&'y u32>, _y: &'y u32) #[rustc_regions] fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell<&'c u32>) { + //~vv ERROR lifetime may not live long enough + //~v ERROR lifetime may not live long enough establish_relationships( cell_a, cell_b, @@ -43,7 +44,7 @@ fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell |_outlives1, _outlives2, _outlives3, x, y| { // Only works if 'x: 'y: let p = x.get(); - demand_y(x, y, p) //~ ERROR + demand_y(x, y, p) }, ); } diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr index 134ce99014d8a..e49c9ab75d38b 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr +++ b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr @@ -1,5 +1,5 @@ -note: no external requirements - --> $DIR/propagate-approximated-fail-no-postdom.rs:43:9 +note: external requirements + --> $DIR/propagate-approximated-fail-no-postdom.rs:44:9 | LL | |_outlives1, _outlives2, _outlives3, x, y| { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -14,29 +14,66 @@ LL | |_outlives1, _outlives2, _outlives3, x, y| { = note: late-bound region is '?4 = note: late-bound region is '?5 = note: late-bound region is '?6 + = note: number of external vids: 7 + = note: where '?2: '?3 + = note: where '?1: '?3 + +note: no external requirements + --> $DIR/propagate-approximated-fail-no-postdom.rs:37:1 + | +LL | fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell<&'c u32>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: supply error: lifetime may not live long enough - --> $DIR/propagate-approximated-fail-no-postdom.rs:46:13 + --> $DIR/propagate-approximated-fail-no-postdom.rs:40:5 | -LL | |_outlives1, _outlives2, _outlives3, x, y| { - | ---------- ---------- has type `Cell<&'2 &'?3 u32>` - | | - | has type `Cell<&'?1 &'1 u32>` +LL | fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell<&'c u32>) { + | -- -- lifetime `'c` defined here + | | + | lifetime `'a` defined here ... -LL | demand_y(x, y, p) - | ^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` +LL | / establish_relationships( +LL | | cell_a, +LL | | cell_b, +LL | | cell_c, +... | +LL | | }, +LL | | ); + | |_____^ argument requires that `'a` must outlive `'c` | - = note: requirement occurs because of the type `Cell<&'?34 u32>`, which makes the generic argument `&'?34 u32` invariant + = help: consider adding the following bound: `'a: 'c` + = note: requirement occurs because of the type `Cell<&'?10 u32>`, which makes the generic argument `&'?10 u32` invariant = note: the struct `Cell` is invariant over the parameter `T` = help: see for more information about variance -note: no external requirements - --> $DIR/propagate-approximated-fail-no-postdom.rs:38:1 +error: lifetime may not live long enough + --> $DIR/propagate-approximated-fail-no-postdom.rs:40:5 | -LL | fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell<&'c u32>) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell<&'c u32>) { + | -- -- lifetime `'c` defined here + | | + | lifetime `'b` defined here +... +LL | / establish_relationships( +LL | | cell_a, +LL | | cell_b, +LL | | cell_c, +... | +LL | | }, +LL | | ); + | |_____^ argument requires that `'b` must outlive `'c` | - = note: defining type: supply + = help: consider adding the following bound: `'b: 'c` + = note: requirement occurs because of the type `Cell<&'?10 u32>`, which makes the generic argument `&'?10 u32` invariant + = note: the struct `Cell` is invariant over the parameter `T` + = help: see for more information about variance + +help: the following changes may resolve your lifetime errors + | + = help: add bound `'a: 'c` + = help: add bound `'b: 'c` -error: aborting due to 1 previous error +error: aborting due to 2 previous errors From 44fcd463ceb5d070adbba3ad9aef693a2d0925ea Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Mon, 17 Nov 2025 10:22:08 +0100 Subject: [PATCH 8/9] add explanation to postdom test --- .../propagate-approximated-fail-no-postdom.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs index 3ff5e1ca93634..020e53f0ce7a4 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs +++ b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs @@ -1,7 +1,5 @@ -// Test that we can propagate multiple region errors by propagating all -// non-local lower bounds of `fr_longer`. - -//@ compile-flags:-Zverbose-internals +// Test that we can propagate multiple region errors for closure constraints +// where the longer region has multiple non-local lower bounds without any postdominating one. #![feature(rustc_attrs)] From d1674cb571343e912ccb1b33e75f39d46cd95116 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Mon, 17 Nov 2025 11:33:17 +0100 Subject: [PATCH 9/9] oops --- .../propagate-approximated-fail-no-postdom.rs | 1 + .../propagate-approximated-fail-no-postdom.stderr | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs index 020e53f0ce7a4..addfc7b913911 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs +++ b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs @@ -1,5 +1,6 @@ // Test that we can propagate multiple region errors for closure constraints // where the longer region has multiple non-local lower bounds without any postdominating one. +//@ compile-flags:-Zverbose-internals #![feature(rustc_attrs)] diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr index e49c9ab75d38b..73a6d111725a3 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr +++ b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr @@ -1,5 +1,5 @@ note: external requirements - --> $DIR/propagate-approximated-fail-no-postdom.rs:44:9 + --> $DIR/propagate-approximated-fail-no-postdom.rs:43:9 | LL | |_outlives1, _outlives2, _outlives3, x, y| { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | |_outlives1, _outlives2, _outlives3, x, y| { = note: where '?1: '?3 note: no external requirements - --> $DIR/propagate-approximated-fail-no-postdom.rs:37:1 + --> $DIR/propagate-approximated-fail-no-postdom.rs:36:1 | LL | fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell<&'c u32>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: = note: defining type: supply error: lifetime may not live long enough - --> $DIR/propagate-approximated-fail-no-postdom.rs:40:5 + --> $DIR/propagate-approximated-fail-no-postdom.rs:39:5 | LL | fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell<&'c u32>) { | -- -- lifetime `'c` defined here @@ -49,7 +49,7 @@ LL | | ); = help: see for more information about variance error: lifetime may not live long enough - --> $DIR/propagate-approximated-fail-no-postdom.rs:40:5 + --> $DIR/propagate-approximated-fail-no-postdom.rs:39:5 | LL | fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell<&'c u32>) { | -- -- lifetime `'c` defined here