diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 2d993a3fd16f7..8a43e4b54b195 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2911,7 +2911,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ( name, BorrowExplanation::MustBeValidFor { - category: ConstraintCategory::Assignment, + category: ConstraintCategory::Assignment { .. }, from_closure: false, region_name: RegionName { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index e9912c156cb49..dd06b48292df2 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -41,7 +41,7 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> { fn description(&self) -> &'static str { // Must end with a space. Allows for empty names to be provided. match self { - ConstraintCategory::Assignment => "assignment ", + ConstraintCategory::Assignment { .. } => "assignment ", ConstraintCategory::Return(_) => "returning this value ", ConstraintCategory::Yield => "yielding this value ", ConstraintCategory::UseAsConst => "using this value as a constant ", @@ -481,7 +481,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { (ConstraintCategory::Return(kind), true, false) if self.is_closure_fn_mut(fr) => { self.report_fnmut_error(&errci, kind) } - (ConstraintCategory::Assignment, true, false) + (ConstraintCategory::Assignment { .. }, true, false) | (ConstraintCategory::CallArgument(_), true, false) => { let mut db = self.report_escaping_data_error(&errci); @@ -672,7 +672,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // Revert to the normal error in these cases. // Assignments aren't "escapes" in function items. if (fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none()) - || (*category == ConstraintCategory::Assignment + || (matches!(category, ConstraintCategory::Assignment { .. }) && self.regioncx.universal_regions().defining_ty.is_fn_def()) || self.regioncx.universal_regions().defining_ty.is_const() { diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 685ad65292235..fe0d4830d3385 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -2023,6 +2023,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { | ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal | ConstraintCategory::Predicate(_) + | ConstraintCategory::Assignment { has_interesting_ty: false } ) && constraint.span.desugaring_kind().is_none_or(|kind| { // Try to avoid blaming constraints from desugarings, since they may not clearly // clearly match what users have written. As an exception, allow blaming returns diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 0c59813d124a4..10127d741d981 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1135,7 +1135,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Some(l) if !body.local_decls[l].is_user_variable() => { ConstraintCategory::Boring } - _ => ConstraintCategory::Assignment, + Some(l) => ConstraintCategory::Assignment { + has_interesting_ty: body.local_decls[l].user_ty.is_some() + || matches!( + body.local_decls[l].local_info(), + LocalInfo::User(BindingForm::Var(VarBindingForm { + opt_ty_info: Some(_), + .. + })) + ), + }, + // Assignments to projections should be considered interesting. + _ => ConstraintCategory::Assignment { has_interesting_ty: true }, }; debug!( "assignment category: {:?} {:?}", @@ -1469,7 +1480,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Some(l) if !body.local_decls[l].is_user_variable() => { ConstraintCategory::Boring } - _ => ConstraintCategory::Assignment, + // The return type of a call is interesting for diagnostics. + _ => ConstraintCategory::Assignment { has_interesting_ty: true }, }; let locations = term_location.to_locations(); diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 429be9bc725be..c2bb95a91c47e 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -250,7 +250,12 @@ pub enum ConstraintCategory<'tcx> { CallArgument(#[derive_where(skip)] Option>), CopyBound, SizedBound, - Assignment, + Assignment { + /// Whether this assignment is likely to be interesting to refer to in diagnostics. + /// Currently, this is true when it's assigning to a projection, when it's assigning from + /// the return value of a call, and when it has a user-provided type annotation. + has_interesting_ty: bool, + }, /// A constraint that came from a usage of a variable (e.g. in an ADT expression /// like `Foo { field: my_val }`) Usage, diff --git a/tests/ui/fn/fn_def_coercion.rs b/tests/ui/fn/fn_def_coercion.rs index 31c8fa41de17c..313be6f28cdcc 100644 --- a/tests/ui/fn/fn_def_coercion.rs +++ b/tests/ui/fn/fn_def_coercion.rs @@ -46,12 +46,12 @@ fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { let x = match true { - true => foo::<&'c ()>, //~ ERROR lifetime may not live long enough + true => foo::<&'c ()>, false => foo::<&'a ()>, //~ ERROR lifetime may not live long enough }; x(a); - x(b); + x(b); //~ ERROR lifetime may not live long enough x(c); } diff --git a/tests/ui/fn/fn_def_coercion.stderr b/tests/ui/fn/fn_def_coercion.stderr index c2776887b79d4..ec4a1bde7fd61 100644 --- a/tests/ui/fn/fn_def_coercion.stderr +++ b/tests/ui/fn/fn_def_coercion.stderr @@ -6,9 +6,9 @@ LL | fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | | | lifetime `'a` defined here LL | let mut x = foo::<&'a ()>; - | ^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` | - = help: consider adding the following bound: `'b: 'a` + = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -22,9 +22,9 @@ LL | fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | lifetime `'a` defined here LL | let mut x = foo::<&'a ()>; LL | x = foo::<&'b ()>; - | ^^^^^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` | - = help: consider adding the following bound: `'a: 'b` + = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -53,9 +53,9 @@ LL | fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | lifetime `'a` defined here LL | let mut x = foo::<&'c ()>; LL | x = foo::<&'b ()>; - | ^^^^^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` | - = help: consider adding the following bound: `'a: 'b` + = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -69,9 +69,9 @@ LL | fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | lifetime `'a` defined here ... LL | x = foo::<&'a ()>; - | ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` | - = help: consider adding the following bound: `'b: 'a` + = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -89,9 +89,9 @@ LL | fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | lifetime `'a` defined here LL | let x = match true { LL | true => foo::<&'b ()>, - | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | ^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` | - = help: consider adding the following bound: `'a: 'b` + = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -105,9 +105,9 @@ LL | fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | lifetime `'a` defined here ... LL | false => foo::<&'a ()>, - | ^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` | - = help: consider adding the following bound: `'b: 'a` + = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -117,15 +117,15 @@ help: `'a` and `'b` must be the same: replace one with the other = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: lifetime may not live long enough - --> $DIR/fn_def_coercion.rs:49:17 + --> $DIR/fn_def_coercion.rs:50:18 | LL | fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | -- -- lifetime `'c` defined here | | | lifetime `'a` defined here -LL | let x = match true { -LL | true => foo::<&'c ()>, - | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'c` +... +LL | false => foo::<&'a ()>, + | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'c` | = help: consider adding the following bound: `'a: 'c` = note: requirement occurs because of a function pointer to `foo` @@ -133,20 +133,17 @@ LL | true => foo::<&'c ()>, = help: see for more information about variance error: lifetime may not live long enough - --> $DIR/fn_def_coercion.rs:50:18 + --> $DIR/fn_def_coercion.rs:54:5 | LL | fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here ... -LL | false => foo::<&'a ()>, - | ^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` +LL | x(b); + | ^^^^ argument requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` - = note: requirement occurs because of a function pointer to `foo` - = note: the function `foo` is invariant over the parameter `T` - = help: see for more information about variance help: the following changes may resolve your lifetime errors | diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.rs b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.rs index 66e6eb91a22e3..09ee9accccd2f 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.rs +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.rs @@ -1,6 +1,6 @@ fn foo(&mut (ref mut v, w): &mut (&u8, &u8), x: &u8) { - //~^ ERROR lifetime may not live long enough *v = x; + //~^ ERROR lifetime may not live long enough } fn main() { } diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr index e7cab52084ddd..30083b5ef5462 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr @@ -1,15 +1,13 @@ error: lifetime may not live long enough - --> $DIR/ex3-both-anon-regions-2.rs:1:14 + --> $DIR/ex3-both-anon-regions-2.rs:2:5 | LL | fn foo(&mut (ref mut v, w): &mut (&u8, &u8), x: &u8) { - | ^^^^^^^^^ - - let's call the lifetime of this reference `'1` - | | | - | | let's call the lifetime of this reference `'2` - | assignment requires that `'1` must outlive `'2` + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | *v = x; + | ^^^^^^ assignment requires that `'1` must outlive `'2` | - = note: requirement occurs because of a mutable reference to `&u8` - = note: mutable references are invariant over their type parameter - = help: see for more information about variance help: consider introducing a named lifetime parameter | LL | fn foo<'a>(&mut (ref mut v, w): &mut (&'a u8, &u8), x: &'a u8) { diff --git a/tests/ui/match/match-ref-mut-invariance.stderr b/tests/ui/match/match-ref-mut-invariance.stderr index 93844d34b414b..b9878a1953242 100644 --- a/tests/ui/match/match-ref-mut-invariance.stderr +++ b/tests/ui/match/match-ref-mut-invariance.stderr @@ -1,12 +1,12 @@ error: lifetime may not live long enough - --> $DIR/match-ref-mut-invariance.rs:10:24 + --> $DIR/match-ref-mut-invariance.rs:10:9 | LL | impl<'b> S<'b> { | -- lifetime `'b` defined here LL | fn bar<'a>(&'a mut self) -> &'a mut &'a i32 { | -- lifetime `'a` defined here LL | match self.0 { ref mut x => x } - | ^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ method was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a mutable reference to `&i32` diff --git a/tests/ui/match/match-ref-mut-let-invariance.rs b/tests/ui/match/match-ref-mut-let-invariance.rs index 2c1f865b6d750..a33be09ac8be2 100644 --- a/tests/ui/match/match-ref-mut-let-invariance.rs +++ b/tests/ui/match/match-ref-mut-let-invariance.rs @@ -8,8 +8,8 @@ struct S<'b>(&'b i32); impl<'b> S<'b> { fn bar<'a>(&'a mut self) -> &'a mut &'a i32 { let ref mut x = self.0; - //~^ ERROR lifetime may not live long enough x + //~^ ERROR lifetime may not live long enough } } diff --git a/tests/ui/match/match-ref-mut-let-invariance.stderr b/tests/ui/match/match-ref-mut-let-invariance.stderr index 3c5d73bb4f724..27968239a8e54 100644 --- a/tests/ui/match/match-ref-mut-let-invariance.stderr +++ b/tests/ui/match/match-ref-mut-let-invariance.stderr @@ -1,12 +1,13 @@ error: lifetime may not live long enough - --> $DIR/match-ref-mut-let-invariance.rs:10:13 + --> $DIR/match-ref-mut-let-invariance.rs:11:9 | LL | impl<'b> S<'b> { | -- lifetime `'b` defined here LL | fn bar<'a>(&'a mut self) -> &'a mut &'a i32 { | -- lifetime `'a` defined here LL | let ref mut x = self.0; - | ^^^^^^^^^ assignment requires that `'a` must outlive `'b` +LL | x + | ^ method was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a mutable reference to `&i32` diff --git a/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr b/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr index 1478ad1431ba4..2084697e7e26d 100644 --- a/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr +++ b/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr @@ -4,9 +4,11 @@ error[E0597]: `c` does not live long enough LL | let c = 66; | - binding `c` declared here LL | let f = SomeStruct::<&'static u32>; - | -------------------------- assignment requires that `c` is borrowed for `'static` LL | f(&c); - | ^^ borrowed value does not live long enough + | --^^- + | | | + | | borrowed value does not live long enough + | argument requires that `c` is borrowed for `'static` LL | } | - `c` dropped here while still borrowed @@ -18,9 +20,11 @@ LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { LL | let c = 66; | - binding `c` declared here LL | let f = SomeStruct::<&'a u32>; - | --------------------- assignment requires that `c` is borrowed for `'a` LL | f(&c); - | ^^ borrowed value does not live long enough + | --^^- + | | | + | | borrowed value does not live long enough + | argument requires that `c` is borrowed for `'a` LL | } | - `c` dropped here while still borrowed @@ -33,9 +37,11 @@ LL | let _closure = || { LL | let c = 66; | - binding `c` declared here LL | let f = SomeStruct::<&'a u32>; - | --------------------- assignment requires that `c` is borrowed for `'a` LL | f(&c); - | ^^ borrowed value does not live long enough + | --^^- + | | | + | | borrowed value does not live long enough + | argument requires that `c` is borrowed for `'a` LL | }; | - `c` dropped here while still borrowed diff --git a/tests/ui/nll/user-annotations/method-ufcs-1.stderr b/tests/ui/nll/user-annotations/method-ufcs-1.stderr index 087e270c70f7d..c42ea0172cf75 100644 --- a/tests/ui/nll/user-annotations/method-ufcs-1.stderr +++ b/tests/ui/nll/user-annotations/method-ufcs-1.stderr @@ -4,10 +4,11 @@ error[E0597]: `a` does not live long enough LL | let a = 22; | - binding `a` declared here ... -LL | let x = <&'static u32 as Bazoom<_>>::method; - | ----------------------------------- assignment requires that `a` is borrowed for `'static` LL | x(&a, b, c); - | ^^ borrowed value does not live long enough + | --^^------- + | | | + | | borrowed value does not live long enough + | argument requires that `a` is borrowed for `'static` LL | } | - `a` dropped here while still borrowed diff --git a/tests/ui/nll/user-annotations/method-ufcs-2.stderr b/tests/ui/nll/user-annotations/method-ufcs-2.stderr index c89bed3b1b18f..287337c7d52d3 100644 --- a/tests/ui/nll/user-annotations/method-ufcs-2.stderr +++ b/tests/ui/nll/user-annotations/method-ufcs-2.stderr @@ -4,10 +4,11 @@ error[E0597]: `a` does not live long enough LL | let a = 22; | - binding `a` declared here ... -LL | let x = <&'static u32 as Bazoom<_>>::method; - | ----------------------------------- assignment requires that `a` is borrowed for `'static` LL | x(&a, b, c); - | ^^ borrowed value does not live long enough + | --^^------- + | | | + | | borrowed value does not live long enough + | argument requires that `a` is borrowed for `'static` LL | } | - `a` dropped here while still borrowed diff --git a/tests/ui/nll/user-annotations/promoted-annotation.stderr b/tests/ui/nll/user-annotations/promoted-annotation.stderr index ca99e53187091..39993475796f5 100644 --- a/tests/ui/nll/user-annotations/promoted-annotation.stderr +++ b/tests/ui/nll/user-annotations/promoted-annotation.stderr @@ -6,9 +6,11 @@ LL | fn foo<'a>() { LL | let x = 0; | - binding `x` declared here LL | let f = &drop::<&'a i32>; - | ---------------- assignment requires that `x` is borrowed for `'a` LL | f(&x); - | ^^ borrowed value does not live long enough + | --^^- + | | | + | | borrowed value does not live long enough + | argument requires that `x` is borrowed for `'a` LL | LL | } | - `x` dropped here while still borrowed