diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index e98c60e633805..61a6d6d5b79d9 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1292,6 +1292,26 @@ impl<'tcx> RegionInferenceContext<'tcx> { // so slightly larger than `shorter_fr`. let shorter_fr_plus = self.universal_region_relations.non_local_upper_bounds(shorter_fr); + + // 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+` 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() {}