Skip to content
20 changes: 20 additions & 0 deletions compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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+`
Expand Down
11 changes: 11 additions & 0 deletions tests/ui/regions/closure-prop-issue-104477-case1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//@ check-pass


struct MyTy<'x, 'a, 'b>(std::cell::Cell<(&'x &'a u8, &'x &'b u8)>);
fn wf<T>(_: T) {}
fn test<'a, 'b>() {
|_: &'a u8, x: MyTy<'_, 'a, 'b>| wf(x);
|x: MyTy<'_, 'a, 'b>, _: &'a u8| wf(x);
}

fn main(){}
22 changes: 22 additions & 0 deletions tests/ui/regions/closure-prop-issue-148289.rs
Original file line number Diff line number Diff line change
@@ -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() {}
Loading