Skip to content

blame the furthest statement in borrowck errors #113917

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
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
15 changes: 13 additions & 2 deletions compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2233,10 +2233,21 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// is in the same SCC or something. In that case, find what
// appears to be the most interesting point to report to the
// user via an even more ad-hoc guess.
categorized_path.sort_by_key(|p| p.category);
categorized_path.sort_by_key(|p| {
let location = p.outlives_constraint.locations.from_location();
(
location.is_none()
&& matches!(
p.category,
ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType
),
location,
std::cmp::Reverse(p.category),
)
});
debug!("sorted_path={:#?}", categorized_path);

(categorized_path.remove(0), extra_info)
(categorized_path.pop().unwrap(), extra_info)
}

pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
error: lifetime may not live long enough
--> $DIR/associated-types-project-from-hrtb-in-fn-body.rs:22:29
--> $DIR/associated-types-project-from-hrtb-in-fn-body.rs:22:40
|
LL | fn bar<'a, 'b, I : for<'x> Foo<&'x isize>>(
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
LL | let z: I::A = if cond { x } else { y };
| ^ assignment requires that `'a` must outlive `'b`
| ^ assignment requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
error: lifetime may not live long enough
--> $DIR/project-fn-ret-invariant.rs:40:13
--> $DIR/project-fn-ret-invariant.rs:41:13
|
LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | let f = foo; // <-- No consistent type can be inferred for `f` here.
LL | let a = bar(f, x);
...
LL | let b = bar(f, y);
| ^^^^^^^^^ argument requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
Expand All @@ -15,7 +15,7 @@ LL | let a = bar(f, x);
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

error: lifetime may not live long enough
--> $DIR/project-fn-ret-invariant.rs:42:13
--> $DIR/project-fn-ret-invariant.rs:41:13
|
LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
| -- -- lifetime `'b` defined here
Expand All @@ -26,8 +26,8 @@ LL | let b = bar(f, y);
| ^^^^^^^^^ argument requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
= note: requirement occurs because of the type `Type<'_>`, which makes the generic argument `'_` invariant
= note: the struct `Type<'a>` is invariant over the parameter `'a`
= note: requirement occurs because of a function pointer to `foo`
= note: the function `foo` is invariant over the parameter `'a`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

help: `'a` and `'b` must be the same: replace one with the other
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
let f = foo; // <-- No consistent type can be inferred for `f` here.
let a = bar(f, x);
//[oneuse]~^ ERROR lifetime may not live long enough
let b = bar(f, y);
//[oneuse]~^ ERROR lifetime may not live long enough
//[oneuse]~| ERROR lifetime may not live long enough
(a, b)
}

Expand Down
12 changes: 8 additions & 4 deletions tests/ui/borrowck/issue-102209.stderr
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
error: lifetime may not live long enough
--> $DIR/issue-102209.rs:10:29
--> $DIR/issue-102209.rs:10:15
|
LL | impl NfaBuilder<'_> {
| -- lifetime `'2` appears in the `impl`'s self type
LL | pub fn with<R, F: FnOnce(NfaBuilder<'_>) -> R>(f: F) -> R {
LL | Brand::with(|brand| {
| ----- has type `Brand<'1>`
LL | f(Self { brand: brand.lt })
| ^^^^^^^^ this usage requires that `'1` must outlive `'2`
| ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'1` must outlive `'2`
|
= note: requirement occurs because of the type `NfaBuilder<'_>`, which makes the generic argument `'_` invariant
= note: the struct `NfaBuilder<'brand>` is invariant over the parameter `'brand`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

error: lifetime may not live long enough
--> $DIR/issue-102209.rs:10:29
--> $DIR/issue-102209.rs:10:15
|
LL | impl NfaBuilder<'_> {
| -- lifetime `'1` appears in the `impl`'s self type
...
LL | f(Self { brand: brand.lt })
| ^^^^^^^^ this usage requires that `'1` must outlive `'static`
| ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'1` must outlive `'static`

error: aborting due to 2 previous errors

16 changes: 8 additions & 8 deletions tests/ui/borrowck/two-phase-surprise-no-conflict.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ LL | fn register_plugins<'a>(mk_reg: impl Fn() -> &'a mut Registry<'a>) {
| -- lifetime `'a` defined here
...
LL | reg.register_univ(Box::new(CapturePass::new(&reg.sess_mut)));
| ^^^^^^^^^^^^^^^^^^-----------------------------------------^
| | | |
| | | immutable borrow occurs here
| | cast requires that `reg.sess_mut` is borrowed for `'a`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^^^
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
| argument requires that `reg.sess_mut` is borrowed for `'a`

error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable
--> $DIR/two-phase-surprise-no-conflict.rs:144:5
Expand Down Expand Up @@ -114,11 +114,11 @@ LL | fn register_plugins<'a>(mk_reg: impl Fn() -> &'a mut Registry<'a>) {
| -- lifetime `'a` defined here
...
LL | reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut)));
| ^^^^^^^^^^^^^^^^^^-------------------------------------------------^
| | | |
| | | first mutable borrow occurs here
| | cast requires that `reg.sess_mut` is borrowed for `'a`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------^^^
| | |
| | first mutable borrow occurs here
| second mutable borrow occurs here
| argument requires that `reg.sess_mut` is borrowed for `'a`

error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
--> $DIR/two-phase-surprise-no-conflict.rs:158:53
Expand Down
8 changes: 4 additions & 4 deletions tests/ui/c-variadic/variadic-ffi-4.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -120,28 +120,28 @@ LL | }
| - `ap1` dropped here while still borrowed

error: lifetime may not live long enough
--> $DIR/variadic-ffi-4.rs:35:12
--> $DIR/variadic-ffi-4.rs:35:5
|
LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
| ------- ------- has type `VaListImpl<'2>`
| |
| has type `&mut VaListImpl<'1>`
LL | *ap0 = ap1.clone();
| ^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
| ^^^^ assignment requires that `'1` must outlive `'2`
|
= note: requirement occurs because of the type `VaListImpl<'_>`, which makes the generic argument `'_` invariant
= note: the struct `VaListImpl<'f>` is invariant over the parameter `'f`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

error: lifetime may not live long enough
--> $DIR/variadic-ffi-4.rs:35:12
--> $DIR/variadic-ffi-4.rs:35:5
|
LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
| ------- ------- has type `VaListImpl<'2>`
| |
| has type `&mut VaListImpl<'1>`
LL | *ap0 = ap1.clone();
| ^^^^^^^^^^^ argument requires that `'2` must outlive `'1`
| ^^^^ assignment requires that `'2` must outlive `'1`
|
= note: requirement occurs because of the type `VaListImpl<'_>`, which makes the generic argument `'_` invariant
= note: the struct `VaListImpl<'f>` is invariant over the parameter `'f`
Expand Down
38 changes: 28 additions & 10 deletions tests/ui/dropck/dropck_trait_cycle_checked.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,42 @@ error[E0597]: `o2` does not live long enough
--> $DIR/dropck_trait_cycle_checked.rs:111:13
|
LL | let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
| -- binding `o2` declared here -------- cast requires that `o2` is borrowed for `'static`
| -- binding `o2` declared here
LL | o1.set0(&o2);
| ^^^ borrowed value does not live long enough
...
LL | o3.set0(&o1);
| ------------ argument requires that `o2` is borrowed for `'static`
LL | o3.set1(&o2);
LL | }
| - `o2` dropped here while still borrowed

error[E0597]: `o3` does not live long enough
--> $DIR/dropck_trait_cycle_checked.rs:112:13
|
LL | let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
| -- binding `o3` declared here -------- cast requires that `o3` is borrowed for `'static`
| -- binding `o3` declared here
LL | o1.set0(&o2);
LL | o1.set1(&o3);
| ^^^ borrowed value does not live long enough
...
LL | o3.set0(&o1);
| ------------ argument requires that `o3` is borrowed for `'static`
LL | o3.set1(&o2);
LL | }
| - `o3` dropped here while still borrowed

error[E0597]: `o2` does not live long enough
--> $DIR/dropck_trait_cycle_checked.rs:113:13
|
LL | let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
| -- binding `o2` declared here -------- cast requires that `o2` is borrowed for `'static`
| -- binding `o2` declared here
...
LL | o2.set0(&o2);
| ^^^ borrowed value does not live long enough
| --------^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `o2` is borrowed for `'static`
...
LL | }
| - `o2` dropped here while still borrowed
Expand All @@ -37,10 +46,13 @@ error[E0597]: `o3` does not live long enough
--> $DIR/dropck_trait_cycle_checked.rs:114:13
|
LL | let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
| -- binding `o3` declared here -------- cast requires that `o3` is borrowed for `'static`
| -- binding `o3` declared here
...
LL | o2.set1(&o3);
| ^^^ borrowed value does not live long enough
| --------^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `o3` is borrowed for `'static`
...
LL | }
| - `o3` dropped here while still borrowed
Expand All @@ -49,10 +61,13 @@ error[E0597]: `o1` does not live long enough
--> $DIR/dropck_trait_cycle_checked.rs:115:13
|
LL | let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
| -- binding `o1` declared here -------- cast requires that `o1` is borrowed for `'static`
| -- binding `o1` declared here
...
LL | o3.set0(&o1);
| ^^^ borrowed value does not live long enough
| --------^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `o1` is borrowed for `'static`
LL | o3.set1(&o2);
LL | }
| - `o1` dropped here while still borrowed
Expand All @@ -61,10 +76,13 @@ error[E0597]: `o2` does not live long enough
--> $DIR/dropck_trait_cycle_checked.rs:116:13
|
LL | let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
| -- binding `o2` declared here -------- cast requires that `o2` is borrowed for `'static`
| -- binding `o2` declared here
...
LL | o3.set1(&o2);
| ^^^ borrowed value does not live long enough
| --------^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `o2` is borrowed for `'static`
LL | }
| - `o2` dropped here while still borrowed

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/lifetimes/issue-69314.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ LL | let mut buf = [0; 512];
LL | let m2 = &buf[..];
| ^^^ borrowed value does not live long enough
LL | let m = Self::g(m2).await;
| ----------- argument requires that `buf` is borrowed for `'static`
LL | Self::f2(m).await;
| ----------- argument requires that `buf` is borrowed for `'static`
LL | }
| - `buf` dropped here while still borrowed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ fn inner(mut foo: &[u8]) {
let refcell = RefCell::new(&mut foo);
//~^ ERROR `foo` does not live long enough
let read = &refcell as &RefCell<dyn Read>;
//~^ ERROR lifetime may not live long enough

read_thing(read);
//~^ ERROR borrowed data escapes outside of function [E0521]
}

fn read_thing(refcell: &RefCell<dyn Read>) {}
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,32 @@ LL | fn inner(mut foo: &[u8]) {
| ------- binding `foo` declared here
LL | let refcell = RefCell::new(&mut foo);
| ^^^^^^^^ borrowed value does not live long enough
LL |
LL | let read = &refcell as &RefCell<dyn Read>;
| -------- cast requires that `foo` is borrowed for `'static`
...
LL | read_thing(read);
| ---------------- argument requires that `foo` is borrowed for `'static`
LL |
LL | }
| - `foo` dropped here while still borrowed

error: lifetime may not live long enough
--> $DIR/issue-90600-expected-return-static-indirect.rs:9:16
error[E0521]: borrowed data escapes outside of function
--> $DIR/issue-90600-expected-return-static-indirect.rs:11:5
|
LL | fn inner(mut foo: &[u8]) {
| - let's call the lifetime of this reference `'1`
| ------- - let's call the lifetime of this reference `'1`
| |
| `foo` is a reference that is only valid in the function body
...
LL | let read = &refcell as &RefCell<dyn Read>;
| ^^^^^^^^ cast requires that `'1` must outlive `'static`
LL | read_thing(read);
| ^^^^^^^^^^^^^^^^
| |
| `foo` escapes the function body here
| argument requires that `'1` must outlive `'static`
|
= note: requirement occurs because of the type `RefCell<(dyn std::io::Read + 'static)>`, which makes the generic argument `(dyn std::io::Read + 'static)` invariant
= note: the struct `RefCell<T>` is invariant over the parameter `T`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0597`.
Some errors have detailed explanations: E0521, E0597.
For more information about an error, try `rustc --explain E0521`.
48 changes: 48 additions & 0 deletions tests/ui/nll/blame-furthest-statement.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Make sure we blame the furthest statment in lifetime errors.

fn id<X>(x: X) -> X { x }
fn relate<X>(_: &X, _: &X) {}
struct Inv<'a>(*mut &'a u8);

fn test_static(a: Inv<'_>, b: Inv<'static>) {
let a = id(a);
let b = id(b);
relate(&a, &b);
//~^ ERROR
}

fn test1(a: Inv<'_>, b: Inv<'_>) {
let a = id(a);
let b = id(b);
relate(&a, &b);
//~^ ERROR
//~| ERROR
}

fn test2(cond: bool, a: Inv<'_>, b: Inv<'_>) {
let mut x = None::<Inv<'_>>;
let mut y = None::<Inv<'_>>;
if cond {
relate(&x, &y);
} else {
x.replace(a);
y.replace(b);
//~^ ERROR
//~| ERROR
}
}

fn test3(cond: bool, a: Inv<'_>, b: Inv<'_>) {
let mut x = None::<Inv<'_>>;
let mut y = None::<Inv<'_>>;
if cond {
x.replace(a);
y.replace(b);
} else {
relate(&x, &y);
//~^ ERROR
//~| ERROR
}
}

fn main() {}
Loading