about summary refs log tree commit diff
diff options
context:
space:
mode:
authordianne <diannes.gm@gmail.com>2024-12-19 23:19:24 -0800
committerdianne <diannes.gm@gmail.com>2025-01-06 16:12:11 -0800
commit6421d4cf801491bb4bf3f796ec45a3f65c1a0364 (patch)
tree9b82b14ee3c21678ada575b1eca61dd352b5714b
parent45b2ae935dbc9feb18e9cb9f87ae04d5978e1669 (diff)
downloadrust-6421d4cf801491bb4bf3f796ec45a3f65c1a0364.tar.gz
rust-6421d4cf801491bb4bf3f796ec45a3f65c1a0364.zip
`best_blame_constraint`: prioritize blaming interesting-seeming constraints
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs159
-rw-r--r--compiler/rustc_middle/Cargo.toml1
-rw-r--r--compiler/rustc_middle/src/mir/query.rs7
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.stderr2
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr20
-rw-r--r--tests/ui/fn/fn_def_coercion.rs4
-rw-r--r--tests/ui/fn/fn_def_coercion.stderr32
-rw-r--r--tests/ui/issues/issue-15034.stderr4
-rw-r--r--tests/ui/lifetimes/copy_modulo_regions.stderr6
-rw-r--r--tests/ui/nll/issue-54779-anon-static-lifetime.rs2
-rw-r--r--tests/ui/nll/issue-54779-anon-static-lifetime.stderr14
-rw-r--r--tests/ui/nll/issue-98589-closures-relate-named-regions.stderr4
-rw-r--r--tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr35
-rw-r--r--tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr35
-rw-r--r--tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.rs4
-rw-r--r--tests/ui/nll/type-check-pointer-comparisons.stderr24
-rw-r--r--tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs2
-rw-r--r--tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr25
-rw-r--r--tests/ui/variance/variance-contravariant-arg-object.stderr2
-rw-r--r--tests/ui/variance/variance-covariant-arg-object.stderr2
-rw-r--r--tests/ui/variance/variance-invariant-arg-object.stderr2
22 files changed, 210 insertions, 177 deletions
diff --git a/Cargo.lock b/Cargo.lock
index fca4469803b..c525901869b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4118,7 +4118,6 @@ name = "rustc_middle"
 version = "0.0.0"
 dependencies = [
  "bitflags",
- "derive-where",
  "either",
  "field-offset",
  "gsgdt",
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 7e8fad8698a..7b4e82fa310 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -2026,87 +2026,102 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             | NllRegionVariableOrigin::Existential { from_forall: true } => false,
         };
 
-        let interesting_to_blame = |constraint: &OutlivesConstraint<'tcx>| {
-            !matches!(
-                constraint.category,
-                ConstraintCategory::OpaqueType
-                    | ConstraintCategory::Boring
-                    | 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
-                // generated by `?` desugaring, since the correspondence is fairly clear.
-                kind == DesugaringKind::QuestionMark
-                    && matches!(constraint.category, ConstraintCategory::Return(_))
-            })
+        // To pick a constraint to blame, we organize constraints by how interesting we expect them
+        // to be in diagnostics, then pick the most interesting one closest to either the source or
+        // the target on our constraint path.
+        let constraint_interest = |constraint: &OutlivesConstraint<'tcx>| {
+            // Try to avoid blaming constraints from desugarings, since they may not clearly match
+            // match what users have written. As an exception, allow blaming returns generated by
+            // `?` desugaring, since the correspondence is fairly clear.
+            let category = if let Some(kind) = constraint.span.desugaring_kind()
+                && (kind != DesugaringKind::QuestionMark
+                    || !matches!(constraint.category, ConstraintCategory::Return(_)))
+            {
+                ConstraintCategory::Boring
+            } else {
+                constraint.category
+            };
+
+            match category {
+                // Returns usually provide a type to blame and have specially written diagnostics,
+                // so prioritize them.
+                ConstraintCategory::Return(_) => 0,
+                // Unsizing coercions are interesting, since we have a note for that:
+                // `BorrowExplanation::add_object_lifetime_default_note`.
+                // FIXME(dianne): That note shouldn't depend on a coercion being blamed; see issue
+                // #131008 for an example of where we currently don't emit it but should.
+                // Once the note is handled properly, this case should be removed. Until then, it
+                // should be as limited as possible; the note is prone to false positives and this
+                // constraint usually isn't best to blame.
+                ConstraintCategory::Cast {
+                    unsize_to: Some(unsize_ty),
+                    is_implicit_coercion: true,
+                } if target_region == self.universal_regions().fr_static
+                    // Mirror the note's condition, to minimize how often this diverts blame.
+                    && let ty::Adt(_, args) = unsize_ty.kind()
+                    && args.iter().any(|arg| arg.as_type().is_some_and(|ty| ty.is_trait()))
+                    // Mimic old logic for this, to minimize false positives in tests.
+                    && !path
+                        .iter()
+                        .any(|c| matches!(c.category, ConstraintCategory::TypeAnnotation)) =>
+                {
+                    1
+                }
+                // Between other interesting constraints, order by their position on the `path`.
+                ConstraintCategory::Yield
+                | ConstraintCategory::UseAsConst
+                | ConstraintCategory::UseAsStatic
+                | ConstraintCategory::TypeAnnotation
+                | ConstraintCategory::Cast { .. }
+                | ConstraintCategory::CallArgument(_)
+                | ConstraintCategory::CopyBound
+                | ConstraintCategory::SizedBound
+                | ConstraintCategory::Assignment { has_interesting_ty: true }
+                | ConstraintCategory::Usage
+                | ConstraintCategory::ClosureUpvar(_) => 2,
+                // Give assignments a lower priority when flagged as less likely to be interesting.
+                // In particular, de-prioritize MIR assignments lowered from argument patterns.
+                ConstraintCategory::Assignment { has_interesting_ty: false } => 3,
+                // We handle predicates and opaque types specially; don't prioritize them here.
+                ConstraintCategory::Predicate(_) | ConstraintCategory::OpaqueType => 4,
+                // `Boring` constraints can correspond to user-written code and have useful spans,
+                // but don't provide any other useful information for diagnostics.
+                ConstraintCategory::Boring => 5,
+                // `BoringNoLocation` constraints can point to user-written code, but are less
+                // specific, and are not used for relations that would make sense to blame.
+                ConstraintCategory::BoringNoLocation => 6,
+                // Do not blame internal constraints.
+                ConstraintCategory::Internal => 7,
+                ConstraintCategory::IllegalUniverse => 8,
+            }
         };
 
         let best_choice = if blame_source {
-            path.iter().rposition(interesting_to_blame)
+            path.iter().enumerate().rev().min_by_key(|(_, c)| constraint_interest(c)).unwrap().0
         } else {
-            path.iter().position(interesting_to_blame)
+            path.iter().enumerate().min_by_key(|(_, c)| constraint_interest(c)).unwrap().0
         };
 
         debug!(?best_choice, ?blame_source);
 
-        let best_constraint = match best_choice {
-            Some(i)
-                if let Some(next) = path.get(i + 1)
-                    && matches!(path[i].category, ConstraintCategory::Return(_))
-                    && next.category == ConstraintCategory::OpaqueType =>
-            {
-                // The return expression is being influenced by the return type being
-                // impl Trait, point at the return type and not the return expr.
-                *next
-            }
-
-            Some(i)
-                if path[i].category == ConstraintCategory::Return(ReturnConstraint::Normal)
-                    && let Some(field) = path.iter().find_map(|p| {
-                        if let ConstraintCategory::ClosureUpvar(f) = p.category {
-                            Some(f)
-                        } else {
-                            None
-                        }
-                    }) =>
-            {
-                OutlivesConstraint {
-                    category: ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field)),
-                    ..path[i]
-                }
-            }
-
-            Some(_)
-                if target_region == self.universal_regions().fr_static
-                    && let Some(old_best) = path.iter().min_by_key(|p| p.category)
-                    && matches!(old_best.category, ConstraintCategory::Cast {
-                        is_implicit_coercion: true,
-                        unsize_to: Some(_)
-                    }) =>
-            {
-                // FIXME(dianne): This is a hack in order to emit the subdiagnostic
-                // `BorrowExplanation::add_object_lifetime_default_note` more often, e.g. on
-                // `tests/ui/traits/trait-object-lifetime-default-note.rs`. The subdiagnostic
-                // depends on a coercion being blamed, so we fall back to an earlier version of this
-                // function's blaming logic to keep the test result the same. A proper fix will
-                // require rewriting the subdiagnostic not to rely on a coercion being blamed.
-                // For examples of where notes are missing, see #131008 and
-                // `tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs`.
-                // As part of fixing those, this case should be removed.
-                *old_best
-            }
-
-            Some(i) => path[i],
-
-            None => {
-                // If that search fails, the only constraints on the path are those that we try not
-                // to blame. In that case, find what appears to be the most interesting point to
-                // report to the user via an even more ad-hoc guess.
-                *path.iter().min_by_key(|p| p.category).unwrap()
+        let best_constraint = if let Some(next) = path.get(best_choice + 1)
+            && matches!(path[best_choice].category, ConstraintCategory::Return(_))
+            && next.category == ConstraintCategory::OpaqueType
+        {
+            // The return expression is being influenced by the return type being
+            // impl Trait, point at the return type and not the return expr.
+            *next
+        } else if path[best_choice].category == ConstraintCategory::Return(ReturnConstraint::Normal)
+            && let Some(field) = path.iter().find_map(|p| {
+                if let ConstraintCategory::ClosureUpvar(f) = p.category { Some(f) } else { None }
+            })
+        {
+            OutlivesConstraint {
+                category: ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field)),
+                ..path[best_choice]
             }
+        } else {
+            path[best_choice]
         };
 
         let blame_constraint = BlameConstraint {
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index e64500f812a..2c34df6ea61 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -6,7 +6,6 @@ edition = "2021"
 [dependencies]
 # tidy-alphabetical-start
 bitflags = "2.4.1"
-derive-where = "1.2.7"
 either = "1.5.0"
 field-offset = "0.3.5"
 gsgdt = "0.1.2"
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 9943914628e..8ab994a2dad 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -3,7 +3,6 @@
 use std::cell::Cell;
 use std::fmt::{self, Debug};
 
-use derive_where::derive_where;
 use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::ErrorGuaranteed;
@@ -225,7 +224,6 @@ rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
 /// See also `rustc_const_eval::borrow_check::constraints`.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
 #[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)]
-#[derive_where(PartialOrd, Ord)]
 pub enum ConstraintCategory<'tcx> {
     Return(ReturnConstraint),
     Yield,
@@ -237,12 +235,11 @@ pub enum ConstraintCategory<'tcx> {
         is_implicit_coercion: bool,
         /// Whether this is an unsizing coercion and if yes, this contains the target type.
         /// Region variables are erased to ReErased.
-        #[derive_where(skip)]
         unsize_to: Option<Ty<'tcx>>,
     },
 
     /// Contains the function type if available.
-    CallArgument(#[derive_where(skip)] Option<Ty<'tcx>>),
+    CallArgument(Option<Ty<'tcx>>),
     CopyBound,
     SizedBound,
     Assignment {
@@ -276,7 +273,7 @@ pub enum ConstraintCategory<'tcx> {
     IllegalUniverse,
 }
 
-#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
 #[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)]
 pub enum ReturnConstraint {
     Normal,
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.stderr
index ed9ebce4832..b7319e3356b 100644
--- a/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.stderr
+++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.stderr
@@ -4,7 +4,7 @@ error: lifetime may not live long enough
 LL | fn bad_cast<'a>(x: *const dyn Static<'static>) -> *const dyn Static<'a> {
    |             -- lifetime `'a` defined here
 LL |     x as _
-   |     ^^^^^^ cast requires that `'a` must outlive `'static`
+   |     ^^^^^^ returning this value requires that `'a` must outlive `'static`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr
index 6eeaeb120a7..faaa6325f34 100644
--- a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr
+++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr
@@ -6,9 +6,12 @@ LL | fn change_lt<'a, 'b>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
    |              |
    |              lifetime `'a` defined here
 LL |     x as _
-   |     ^^^^^^ cast requires that `'b` must outlive `'a`
+   |     ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable pointer to `dyn Trait<'_>`
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:6:5
@@ -35,9 +38,12 @@ LL | fn change_lt_ab<'a: 'b, 'b>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
    |                 |
    |                 lifetime `'a` defined here
 LL |     x as _
-   |     ^^^^^^ cast requires that `'b` must outlive `'a`
+   |     ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable pointer to `dyn Trait<'_>`
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:15:5
@@ -85,9 +91,12 @@ LL | fn change_assoc_0<'a, 'b>(
    |                   lifetime `'a` defined here
 ...
 LL |     x as _
-   |     ^^^^^^ cast requires that `'b` must outlive `'a`
+   |     ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable pointer to `dyn Assocked<Assoc = dyn Send>`
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:31:5
@@ -118,9 +127,12 @@ LL | fn change_assoc_1<'a, 'b>(
    |                   lifetime `'a` defined here
 ...
 LL |     x as _
-   |     ^^^^^^ cast requires that `'b` must outlive `'a`
+   |     ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable pointer to `dyn Assocked<Assoc = dyn Trait<'_>>`
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:38:5
diff --git a/tests/ui/fn/fn_def_coercion.rs b/tests/ui/fn/fn_def_coercion.rs
index 313be6f28cd..eea9e480827 100644
--- a/tests/ui/fn/fn_def_coercion.rs
+++ b/tests/ui/fn/fn_def_coercion.rs
@@ -46,8 +46,8 @@ 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 ()>,
-        false => foo::<&'a ()>, //~ ERROR lifetime may not live long enough
+        true => foo::<&'c ()>, //~ ERROR lifetime may not live long enough
+        false => foo::<&'a ()>,
     };
 
     x(a);
diff --git a/tests/ui/fn/fn_def_coercion.stderr b/tests/ui/fn/fn_def_coercion.stderr
index ec4a1bde7fd..a4dc7231081 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 `'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 <https://doc.rust-lang.org/nomicon/subtyping.html> 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 `'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 <https://doc.rust-lang.org/nomicon/subtyping.html> 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 `'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 <https://doc.rust-lang.org/nomicon/subtyping.html> 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 `'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 <https://doc.rust-lang.org/nomicon/subtyping.html> 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 `'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 <https://doc.rust-lang.org/nomicon/subtyping.html> 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 `'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 <https://doc.rust-lang.org/nomicon/subtyping.html> 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:50:18
+  --> $DIR/fn_def_coercion.rs:49:17
    |
 LL | fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
    |      --      -- lifetime `'c` defined here
    |      |
    |      lifetime `'a` defined here
-...
-LL |         false => foo::<&'a ()>,
-   |                  ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'c`
+LL |     let x = match true {
+LL |         true => foo::<&'c ()>,
+   |                 ^^^^^^^^^^^^^ 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`
diff --git a/tests/ui/issues/issue-15034.stderr b/tests/ui/issues/issue-15034.stderr
index c5bc31f94d9..587a5c85e92 100644
--- a/tests/ui/issues/issue-15034.stderr
+++ b/tests/ui/issues/issue-15034.stderr
@@ -1,10 +1,10 @@
 error[E0621]: explicit lifetime required in the type of `lexer`
-  --> $DIR/issue-15034.rs:17:25
+  --> $DIR/issue-15034.rs:17:9
    |
 LL |     pub fn new(lexer: &'a mut Lexer) -> Parser<'a> {
    |                       ------------- help: add explicit lifetime `'a` to the type of `lexer`: `&'a mut Lexer<'a>`
 LL |         Parser { lexer: lexer }
-   |                         ^^^^^ lifetime `'a` required
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/copy_modulo_regions.stderr b/tests/ui/lifetimes/copy_modulo_regions.stderr
index 920fec09103..310ddb21647 100644
--- a/tests/ui/lifetimes/copy_modulo_regions.stderr
+++ b/tests/ui/lifetimes/copy_modulo_regions.stderr
@@ -4,7 +4,11 @@ error: lifetime may not live long enough
 LL | fn foo<'a>() -> [Foo<'a>; 100] {
    |        -- lifetime `'a` defined here
 LL |     [mk_foo::<'a>(); 100]
-   |     ^^^^^^^^^^^^^^^^^^^^^ copying this value requires that `'a` must outlive `'static`
+   |     ^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+   |
+   = note: requirement occurs because of the type `Foo<'_>`, which makes the generic argument `'_` invariant
+   = note: the struct `Foo<'a>` is invariant over the parameter `'a`
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/nll/issue-54779-anon-static-lifetime.rs b/tests/ui/nll/issue-54779-anon-static-lifetime.rs
index 1dab7c1712a..6b8fa608ebb 100644
--- a/tests/ui/nll/issue-54779-anon-static-lifetime.rs
+++ b/tests/ui/nll/issue-54779-anon-static-lifetime.rs
@@ -29,7 +29,7 @@ impl DebugWith<dyn DebugContext> for Foo {
         fmt: &mut std::fmt::Formatter<'_>,
     ) -> std::fmt::Result {
         let Foo { bar } = self;
-        bar.debug_with(cx); //~ lifetime may not live long enough
+        bar.debug_with(cx); //~ borrowed data escapes outside of method
         Ok(())
     }
 }
diff --git a/tests/ui/nll/issue-54779-anon-static-lifetime.stderr b/tests/ui/nll/issue-54779-anon-static-lifetime.stderr
index a454ed26568..03a55906614 100644
--- a/tests/ui/nll/issue-54779-anon-static-lifetime.stderr
+++ b/tests/ui/nll/issue-54779-anon-static-lifetime.stderr
@@ -1,11 +1,17 @@
-error: lifetime may not live long enough
-  --> $DIR/issue-54779-anon-static-lifetime.rs:32:24
+error[E0521]: borrowed data escapes outside of method
+  --> $DIR/issue-54779-anon-static-lifetime.rs:32:9
    |
 LL |         cx: &dyn DebugContext,
-   |             - let's call the lifetime of this reference `'1`
+   |         --  - let's call the lifetime of this reference `'1`
+   |         |
+   |         `cx` is a reference that is only valid in the method body
 ...
 LL |         bar.debug_with(cx);
-   |                        ^^ coercion requires that `'1` must outlive `'static`
+   |         ^^^^^^^^^^^^^^^^^^
+   |         |
+   |         `cx` escapes the method body here
+   |         argument requires that `'1` must outlive `'static`
 
 error: aborting due to 1 previous error
 
+For more information about this error, try `rustc --explain E0521`.
diff --git a/tests/ui/nll/issue-98589-closures-relate-named-regions.stderr b/tests/ui/nll/issue-98589-closures-relate-named-regions.stderr
index 4e741abc2dc..4f244b54bd0 100644
--- a/tests/ui/nll/issue-98589-closures-relate-named-regions.stderr
+++ b/tests/ui/nll/issue-98589-closures-relate-named-regions.stderr
@@ -11,14 +11,14 @@ LL |     || { None::<&'a &'b ()>; };
    = help: consider adding the following bound: `'b: 'a`
 
 error: lifetime may not live long enough
-  --> $DIR/issue-98589-closures-relate-named-regions.rs:15:10
+  --> $DIR/issue-98589-closures-relate-named-regions.rs:15:5
    |
 LL | fn test_early_late<'a: 'a, 'b>() {
    |                    --      -- lifetime `'b` defined here
    |                    |
    |                    lifetime `'a` defined here
 LL |     || { None::<&'a &'b ()>; };
-   |          ^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
 
diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr
index e4b323bc2b6..1d086c658df 100644
--- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr
+++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr
@@ -1,20 +1,23 @@
-error[E0373]: closure may outlive the current function, but it borrows `a`, which is owned by the current function
-  --> $DIR/location-insensitive-scopes-issue-117146.rs:10:13
+error[E0597]: `a` does not live long enough
+  --> $DIR/location-insensitive-scopes-issue-117146.rs:10:18
    |
+LL |     let a = ();
+   |         - binding `a` declared here
 LL |     let b = |_| &a;
-   |             ^^^  - `a` is borrowed here
-   |             |
-   |             may outlive borrowed value `a`
-   |
-note: function requires argument type to outlive `'static`
-  --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5
-   |
-LL |     bad(&b);
-   |     ^^^^^^^
-help: to force the closure to take ownership of `a` (and any other referenced variables), use the `move` keyword
-   |
-LL |     let b = move |_| &a;
-   |             ++++
+   |             --- -^
+   |             |   ||
+   |             |   |borrowed value does not live long enough
+   |             |   returning this value requires that `a` is borrowed for `'static`
+   |             value captured here
+...
+LL | }
+   | - `a` dropped here while still borrowed
+   |
+note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+  --> $DIR/location-insensitive-scopes-issue-117146.rs:20:22
+   |
+LL | fn bad<F: Fn(&()) -> &()>(_: F) {}
+   |                      ^^^
 
 error: implementation of `Fn` is not general enough
   --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5
@@ -36,4 +39,4 @@ LL |     bad(&b);
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0373`.
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr
index e4b323bc2b6..1d086c658df 100644
--- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr
+++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr
@@ -1,20 +1,23 @@
-error[E0373]: closure may outlive the current function, but it borrows `a`, which is owned by the current function
-  --> $DIR/location-insensitive-scopes-issue-117146.rs:10:13
+error[E0597]: `a` does not live long enough
+  --> $DIR/location-insensitive-scopes-issue-117146.rs:10:18
    |
+LL |     let a = ();
+   |         - binding `a` declared here
 LL |     let b = |_| &a;
-   |             ^^^  - `a` is borrowed here
-   |             |
-   |             may outlive borrowed value `a`
-   |
-note: function requires argument type to outlive `'static`
-  --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5
-   |
-LL |     bad(&b);
-   |     ^^^^^^^
-help: to force the closure to take ownership of `a` (and any other referenced variables), use the `move` keyword
-   |
-LL |     let b = move |_| &a;
-   |             ++++
+   |             --- -^
+   |             |   ||
+   |             |   |borrowed value does not live long enough
+   |             |   returning this value requires that `a` is borrowed for `'static`
+   |             value captured here
+...
+LL | }
+   | - `a` dropped here while still borrowed
+   |
+note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+  --> $DIR/location-insensitive-scopes-issue-117146.rs:20:22
+   |
+LL | fn bad<F: Fn(&()) -> &()>(_: F) {}
+   |                      ^^^
 
 error: implementation of `Fn` is not general enough
   --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5
@@ -36,4 +39,4 @@ LL |     bad(&b);
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0373`.
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.rs b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.rs
index bd26af5bee2..c828a37521e 100644
--- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.rs
+++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.rs
@@ -8,8 +8,8 @@
 fn main() {
     let a = ();
     let b = |_| &a;
-    //[nll]~^ ERROR closure may outlive the current function, but it borrows `a`
-    //[polonius]~^^ ERROR closure may outlive the current function, but it borrows `a`
+    //[nll]~^ ERROR `a` does not live long enough
+    //[polonius]~^^ ERROR `a` does not live long enough
     bad(&b);
     //[nll]~^ ERROR implementation of `Fn`
     //[nll]~| ERROR implementation of `FnOnce`
diff --git a/tests/ui/nll/type-check-pointer-comparisons.stderr b/tests/ui/nll/type-check-pointer-comparisons.stderr
index 37098b585df..90cdb92e81b 100644
--- a/tests/ui/nll/type-check-pointer-comparisons.stderr
+++ b/tests/ui/nll/type-check-pointer-comparisons.stderr
@@ -6,9 +6,9 @@ LL | fn compare_const<'a, 'b>(x: *const &mut &'a i32, y: *const &mut &'b i32) {
    |                  |
    |                  lifetime `'a` defined here
 LL |     x == y;
-   |     ^ requires that `'a` must outlive `'b`
+   |     ^ 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 mutable reference to `&i32`
    = note: mutable references are invariant over their type parameter
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
@@ -21,9 +21,9 @@ LL | fn compare_const<'a, 'b>(x: *const &mut &'a i32, y: *const &mut &'b i32) {
    |                  |
    |                  lifetime `'a` defined here
 LL |     x == y;
-   |          ^ requires that `'b` must outlive `'a`
+   |          ^ 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 mutable reference to `&i32`
    = note: mutable references are invariant over their type parameter
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
@@ -38,9 +38,9 @@ LL | fn compare_mut<'a, 'b>(x: *mut &'a i32, y: *mut &'b i32) {
    |                |
    |                lifetime `'a` defined here
 LL |     x == y;
-   |     ^ requires that `'a` must outlive `'b`
+   |     ^ 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 mutable pointer to `&i32`
    = note: mutable pointers are invariant over their type parameter
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
@@ -53,9 +53,9 @@ LL | fn compare_mut<'a, 'b>(x: *mut &'a i32, y: *mut &'b i32) {
    |                |
    |                lifetime `'a` defined here
 LL |     x == y;
-   |          ^ requires that `'b` must outlive `'a`
+   |          ^ 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 mutable pointer to `&i32`
    = note: mutable pointers are invariant over their type parameter
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
@@ -72,9 +72,9 @@ LL | fn compare_fn_ptr<'a, 'b, 'c>(f: fn(&'c mut &'a i32), g: fn(&'c mut &'b i32
    |                   |
    |                   lifetime `'a` defined here
 LL |     f == g;
-   |     ^ requires that `'a` must outlive `'b`
+   |     ^ 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 mutable reference to `&i32`
    = note: mutable references are invariant over their type parameter
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
@@ -87,9 +87,9 @@ LL | fn compare_fn_ptr<'a, 'b, 'c>(f: fn(&'c mut &'a i32), g: fn(&'c mut &'b i32
    |                   |
    |                   lifetime `'a` defined here
 LL |     f == g;
-   |          ^ requires that `'b` must outlive `'a`
+   |          ^ 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 mutable reference to `&i32`
    = note: mutable references are invariant over their type parameter
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
diff --git a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs
index 8f3171222bb..c24672816ac 100644
--- a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs
+++ b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs
@@ -64,7 +64,7 @@ mod bay {
 
     fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32> + 'a>) -> &'a () {
         val.use_self()
-        //~^ ERROR: `val` does not live long enough
+        //~^ ERROR: cannot return value referencing function parameter `val`
         //~| ERROR: borrowed data escapes outside of function
     }
 }
diff --git a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr
index a8a854220b4..505765d2b41 100644
--- a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr
+++ b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr
@@ -25,20 +25,6 @@ LL |         val.use_self()
    |         returns a value referencing data owned by the current function
    |         `val` is borrowed here
 
-error[E0597]: `val` does not live long enough
-  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:66:9
-   |
-LL |     fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32> + 'a>) -> &'a () {
-   |                   --- binding `val` declared here
-LL |         val.use_self()
-   |         ^^^-----------
-   |         |
-   |         borrowed value does not live long enough
-   |         argument requires that `val` is borrowed for `'static`
-...
-LL |     }
-   |     - `val` dropped here while still borrowed
-
 error[E0521]: borrowed data escapes outside of function
   --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:66:9
    |
@@ -65,6 +51,15 @@ LL |     impl MyTrait for Box<dyn ObjectTrait<Assoc = i32> + '_> {
    |                                                       ++++
 
 error[E0515]: cannot return value referencing function parameter `val`
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:66:9
+   |
+LL |         val.use_self()
+   |         ---^^^^^^^^^^^
+   |         |
+   |         returns a value referencing data owned by the current function
+   |         `val` is borrowed here
+
+error[E0515]: cannot return value referencing function parameter `val`
   --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:90:9
    |
 LL |         val.use_self()
@@ -75,5 +70,5 @@ LL |         val.use_self()
 
 error: aborting due to 6 previous errors
 
-Some errors have detailed explanations: E0515, E0521, E0597.
+Some errors have detailed explanations: E0515, E0521.
 For more information about an error, try `rustc --explain E0515`.
diff --git a/tests/ui/variance/variance-contravariant-arg-object.stderr b/tests/ui/variance/variance-contravariant-arg-object.stderr
index 7d7c6cb28cd..ab28315e11e 100644
--- a/tests/ui/variance/variance-contravariant-arg-object.stderr
+++ b/tests/ui/variance/variance-contravariant-arg-object.stderr
@@ -7,7 +7,7 @@ LL | fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>)
    |                     lifetime `'min` defined here
 ...
 LL |     v
-   |     ^ coercion requires that `'min` must outlive `'max`
+   |     ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
    |
    = help: consider adding the following bound: `'min: 'max`
 
diff --git a/tests/ui/variance/variance-covariant-arg-object.stderr b/tests/ui/variance/variance-covariant-arg-object.stderr
index 4e82c8e8e1b..51f8cb3ec75 100644
--- a/tests/ui/variance/variance-covariant-arg-object.stderr
+++ b/tests/ui/variance/variance-covariant-arg-object.stderr
@@ -7,7 +7,7 @@ LL | fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>)
    |                     lifetime `'min` defined here
 ...
 LL |     v
-   |     ^ coercion requires that `'min` must outlive `'max`
+   |     ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
    |
    = help: consider adding the following bound: `'min: 'max`
 
diff --git a/tests/ui/variance/variance-invariant-arg-object.stderr b/tests/ui/variance/variance-invariant-arg-object.stderr
index e3969ebebce..9793a36be06 100644
--- a/tests/ui/variance/variance-invariant-arg-object.stderr
+++ b/tests/ui/variance/variance-invariant-arg-object.stderr
@@ -7,7 +7,7 @@ LL | fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>)
    |                     lifetime `'min` defined here
 ...
 LL |     v
-   |     ^ coercion requires that `'min` must outlive `'max`
+   |     ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
    |
    = help: consider adding the following bound: `'min: 'max`