Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion compiler/rustc_borrowck/src/type_check/relate_tys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -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`.
69 changes: 69 additions & 0 deletions tests/ui/nll/polonius/opaque-multiple-defining-uses-160669.rs
Comment thread
jackh726 marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ fn bar(src: &crate::Foo) -> impl Iterator<Item = i32> {
[0].into_iter()
//~^ ERROR hidden type for `impl Iterator<Item = i32>` captures lifetime that does not appear in bounds
.filter_map(|_| foo(src))
//~^ ERROR `src` does not live long enough
}

struct Foo<'a>(&'a str);
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,21 @@ LL | | .filter_map(|_| foo(src))
|
= note: hidden type `FilterMap<Iter<'_, i32>, {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<Item = i32> {
| --- 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`.
Loading