diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index e99a757b76305..c922d1a9f0f86 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -144,7 +144,31 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> { variance, ty, )?; - Ok(infcx.resolve_vars_if_possible(Ty::new_infer(infcx.tcx, ty::TyVar(ty_vid)))) + let new_var = + infcx.resolve_vars_if_possible(Ty::new_infer(infcx.tcx, ty::TyVar(ty_vid))); + + // Any regions in this new type must be live everywhere, so we mark them as such. + // (It may be that it only needs to be live where the opaque type itself is - which + // includes defining use sites, but we'll be conservative and mark all points as live). + // This is needed for Polonius, which doesn't propagate constraints + // through dead regions. See issue #160669. + // + // We only do this in the root universe. Inside a binder these regions live in a higher + // universe and their values contain placeholders; marking them live at every point + // leaks those placeholders, turning the higher-ranked check into an error which then + // suppresses the deferred opaque type diagnostics. + if infcx.universe() == ty::UniverseIndex::ROOT { + let tcx = infcx.tcx; + let liveness = &mut self.type_checker.constraints.liveness_constraints; + ty::fold_regions(tcx, new_var, |r, _| { + if let ty::ReVar(vid) = r.kind() { + liveness.add_all_points(vid); + } + r + }); + } + + Ok(new_var) }; let (a, b) = match (a.kind(), b.kind()) { diff --git a/tests/ui/nll/polonius/opaque-multiple-defining-uses-160669.next.stderr b/tests/ui/nll/polonius/opaque-multiple-defining-uses-160669.next.stderr new file mode 100644 index 0000000000000..36443de770ebf --- /dev/null +++ b/tests/ui/nll/polonius/opaque-multiple-defining-uses-160669.next.stderr @@ -0,0 +1,69 @@ +error[E0597]: `local` does not live long enough + --> $DIR/opaque-multiple-defining-uses-160669.rs:31:16 + | +LL | let local = String::from("dangling"); + | ----- binding `local` declared here +LL | return &local; + | ^^^^^^ borrowed value does not live long enough +LL | } + | - `local` dropped here while still borrowed +LL | s +LL | } + | - borrow later used here + +error[E0597]: `local` does not live long enough + --> $DIR/opaque-multiple-defining-uses-160669.rs:41:16 + | +LL | let local = String::from("dangling0"); + | ----- binding `local` declared here +LL | return &local; + | ^^^^^^ borrowed value does not live long enough +LL | } + | - `local` dropped here while still borrowed +... +LL | } + | - borrow later used here + +error[E0597]: `local` does not live long enough + --> $DIR/opaque-multiple-defining-uses-160669.rs:45:16 + | +LL | let local = String::from("dangling1"); + | ----- binding `local` declared here +LL | return &local; + | ^^^^^^ borrowed value does not live long enough +LL | } + | - `local` dropped here while still borrowed +LL | s +LL | } + | - borrow later used here + +error[E0597]: `local` does not live long enough + --> $DIR/opaque-multiple-defining-uses-160669.rs:57:5 + | +LL | let local = String::from("dangling"); + | ----- binding `local` declared here +LL | &local + | ^^^^^^ borrowed value does not live long enough +LL | } + | -- borrow later used here + | | + | `local` dropped here while still borrowed + +error[E0597]: `short` does not live long enough + --> $DIR/opaque-multiple-defining-uses-160669.rs:64:16 + | +LL | fn minimal(short: (), out: &'static ()) -> impl Sized { + | ----- binding `short` declared here +LL | if true { +LL | return &short; + | ^^^^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | `short` dropped here while still borrowed + | borrow later used here + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/nll/polonius/opaque-multiple-defining-uses-160669.nll.stderr b/tests/ui/nll/polonius/opaque-multiple-defining-uses-160669.nll.stderr new file mode 100644 index 0000000000000..37458833ddfc2 --- /dev/null +++ b/tests/ui/nll/polonius/opaque-multiple-defining-uses-160669.nll.stderr @@ -0,0 +1,80 @@ +error[E0597]: `local` does not live long enough + --> $DIR/opaque-multiple-defining-uses-160669.rs:31:16 + | +LL | fn two_uses<'a>(s: &'a String, flag: bool) -> impl Display + use<'a> { + | -- lifetime `'a` defined here +LL | if flag { +LL | let local = String::from("dangling"); + | ----- binding `local` declared here +LL | return &local; + | ^^^^^^ borrowed value does not live long enough +LL | } + | - `local` dropped here while still borrowed +LL | s + | - opaque type requires that `local` is borrowed for `'a` + +error[E0597]: `local` does not live long enough + --> $DIR/opaque-multiple-defining-uses-160669.rs:41:16 + | +LL | fn three_uses<'a>(s: &'a String, flag: u8) -> impl Display + use<'a> { + | -- lifetime `'a` defined here +LL | if flag == 0 { +LL | let local = String::from("dangling0"); + | ----- binding `local` declared here +LL | return &local; + | ^^^^^^ borrowed value does not live long enough +LL | } + | - `local` dropped here while still borrowed +... +LL | return &local; + | ------ opaque type requires that `local` is borrowed for `'a` + +error[E0597]: `local` does not live long enough + --> $DIR/opaque-multiple-defining-uses-160669.rs:45:16 + | +LL | fn three_uses<'a>(s: &'a String, flag: u8) -> impl Display + use<'a> { + | -- lifetime `'a` defined here +... +LL | let local = String::from("dangling1"); + | ----- binding `local` declared here +LL | return &local; + | ^^^^^^ + | | + | borrowed value does not live long enough + | opaque type requires that `local` is borrowed for `'a` +LL | } + | - `local` dropped here while still borrowed + +error[E0597]: `local` does not live long enough + --> $DIR/opaque-multiple-defining-uses-160669.rs:57:5 + | +LL | fn reversed_order<'a>(s: &'a String, flag: bool) -> impl Display + use<'a> { + | -- lifetime `'a` defined here +... +LL | let local = String::from("dangling"); + | ----- binding `local` declared here +LL | &local + | ^^^^^^ + | | + | borrowed value does not live long enough + | opaque type requires that `local` is borrowed for `'a` +LL | } + | - `local` dropped here while still borrowed + +error[E0597]: `short` does not live long enough + --> $DIR/opaque-multiple-defining-uses-160669.rs:64:16 + | +LL | fn minimal(short: (), out: &'static ()) -> impl Sized { + | ----- binding `short` declared here +LL | if true { +LL | return &short; + | ^^^^^^ borrowed value does not live long enough +LL | } +LL | out + | --- opaque type requires that `short` is borrowed for `'static` +LL | } + | - `short` dropped here while still borrowed + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/nll/polonius/opaque-multiple-defining-uses-160669.polonius.stderr b/tests/ui/nll/polonius/opaque-multiple-defining-uses-160669.polonius.stderr new file mode 100644 index 0000000000000..37458833ddfc2 --- /dev/null +++ b/tests/ui/nll/polonius/opaque-multiple-defining-uses-160669.polonius.stderr @@ -0,0 +1,80 @@ +error[E0597]: `local` does not live long enough + --> $DIR/opaque-multiple-defining-uses-160669.rs:31:16 + | +LL | fn two_uses<'a>(s: &'a String, flag: bool) -> impl Display + use<'a> { + | -- lifetime `'a` defined here +LL | if flag { +LL | let local = String::from("dangling"); + | ----- binding `local` declared here +LL | return &local; + | ^^^^^^ borrowed value does not live long enough +LL | } + | - `local` dropped here while still borrowed +LL | s + | - opaque type requires that `local` is borrowed for `'a` + +error[E0597]: `local` does not live long enough + --> $DIR/opaque-multiple-defining-uses-160669.rs:41:16 + | +LL | fn three_uses<'a>(s: &'a String, flag: u8) -> impl Display + use<'a> { + | -- lifetime `'a` defined here +LL | if flag == 0 { +LL | let local = String::from("dangling0"); + | ----- binding `local` declared here +LL | return &local; + | ^^^^^^ borrowed value does not live long enough +LL | } + | - `local` dropped here while still borrowed +... +LL | return &local; + | ------ opaque type requires that `local` is borrowed for `'a` + +error[E0597]: `local` does not live long enough + --> $DIR/opaque-multiple-defining-uses-160669.rs:45:16 + | +LL | fn three_uses<'a>(s: &'a String, flag: u8) -> impl Display + use<'a> { + | -- lifetime `'a` defined here +... +LL | let local = String::from("dangling1"); + | ----- binding `local` declared here +LL | return &local; + | ^^^^^^ + | | + | borrowed value does not live long enough + | opaque type requires that `local` is borrowed for `'a` +LL | } + | - `local` dropped here while still borrowed + +error[E0597]: `local` does not live long enough + --> $DIR/opaque-multiple-defining-uses-160669.rs:57:5 + | +LL | fn reversed_order<'a>(s: &'a String, flag: bool) -> impl Display + use<'a> { + | -- lifetime `'a` defined here +... +LL | let local = String::from("dangling"); + | ----- binding `local` declared here +LL | &local + | ^^^^^^ + | | + | borrowed value does not live long enough + | opaque type requires that `local` is borrowed for `'a` +LL | } + | - `local` dropped here while still borrowed + +error[E0597]: `short` does not live long enough + --> $DIR/opaque-multiple-defining-uses-160669.rs:64:16 + | +LL | fn minimal(short: (), out: &'static ()) -> impl Sized { + | ----- binding `short` declared here +LL | if true { +LL | return &short; + | ^^^^^^ borrowed value does not live long enough +LL | } +LL | out + | --- opaque type requires that `short` is borrowed for `'static` +LL | } + | - `short` dropped here while still borrowed + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/nll/polonius/opaque-multiple-defining-uses-160669.rs b/tests/ui/nll/polonius/opaque-multiple-defining-uses-160669.rs new file mode 100644 index 0000000000000..e1aa23749fb62 --- /dev/null +++ b/tests/ui/nll/polonius/opaque-multiple-defining-uses-160669.rs @@ -0,0 +1,69 @@ +// An opaque type has a single hidden type, and the opaque type storage only keeps a +// single hidden type per key. So, a second defining use replaces the first. +// +// In the old solver, MIR is built with unnormalized opaques; and, a defining use +// is generalized prior to being registered as the hidden type, to allow for +// subtyping. +// +// During this generalization, any regions created were previously not +// considered live, which means that under Polonius Alpha, outlives constraints +// were not propogated between a previous hidden type and a new one. +// +// We now consider all these lifetimes live at all points. +// +// In the new solver, this is all moot, because MIR has *normalized* opaques, +// and so there is no special subtyping code. +// +// Regression test for #160669. + +//@ ignore-compare-mode-polonius (explicit revisions) +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ revisions: nll polonius next +//@ [nll] compile-flags: -Z polonius=off +//@ [polonius] compile-flags: -Z polonius=next +//@ [next] compile-flags: -Z next-solver -Z polonius=next + +use std::fmt::Display; + +fn two_uses<'a>(s: &'a String, flag: bool) -> impl Display + use<'a> { + if flag { + let local = String::from("dangling"); + return &local; //~ ERROR `local` does not live long enough + } + s +} + +// The same, with a borrow of a local in multiple branchs, to check that we +// don't only report the defining use which happens to be last in MIR order. +fn three_uses<'a>(s: &'a String, flag: u8) -> impl Display + use<'a> { + if flag == 0 { + let local = String::from("dangling0"); + return &local; //~ ERROR `local` does not live long enough + } + if flag == 1 { + let local = String::from("dangling1"); + return &local; //~ ERROR `local` does not live long enough + } + s +} + +// Control for the order dependence: here the bad defining use is the last one in MIR order, +// so it stayed anchored and was caught even before the fix. +fn reversed_order<'a>(s: &'a String, flag: bool) -> impl Display + use<'a> { + if flag { + return s; + } + let local = String::from("dangling"); + &local //~ ERROR `local` does not live long enough +} + +// This is a much more minimal MIR representation of the same bug. Useful for +// debugging. +fn minimal(short: (), out: &'static ()) -> impl Sized { + if true { + return &short; //~ ERROR `short` does not live long enough + } + out +} + +fn main() {} diff --git a/tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.rs b/tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.rs index 2011d4e01205e..05653667ac758 100644 --- a/tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.rs +++ b/tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.rs @@ -8,6 +8,7 @@ fn bar(src: &crate::Foo) -> impl Iterator { [0].into_iter() //~^ ERROR hidden type for `impl Iterator` captures lifetime that does not appear in bounds .filter_map(|_| foo(src)) + //~^ ERROR `src` does not live long enough } struct Foo<'a>(&'a str); diff --git a/tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.stderr b/tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.stderr index e7751de6f51ab..441adf4856b5d 100644 --- a/tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.stderr +++ b/tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.stderr @@ -10,6 +10,21 @@ LL | | .filter_map(|_| foo(src)) | = note: hidden type `FilterMap, {closure@...}>` captures lifetime `'_` -error: aborting due to 1 previous error +error[E0597]: `src` does not live long enough + --> $DIR/explicit-lifetime-suggestion-in-proper-span-issue-121267.rs:10:29 + | +LL | fn bar(src: &crate::Foo) -> impl Iterator { + | --- binding `src` declared here +... +LL | .filter_map(|_| foo(src)) + | --- ^^^ borrowed value does not live long enough + | | + | value captured here +LL | +LL | } + | - `src` dropped here while still borrowed + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0700`. +Some errors have detailed explanations: E0597, E0700. +For more information about an error, try `rustc --explain E0597`.