about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs271
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--tests/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr7
-rw-r--r--tests/ui/associated-types/bound-lifetime-in-return-only.elision.stderr7
-rw-r--r--tests/ui/c-variadic/variadic-ffi-6.stderr11
-rw-r--r--tests/ui/foreign-fn-return-lifetime.fixed8
-rw-r--r--tests/ui/foreign-fn-return-lifetime.rs2
-rw-r--r--tests/ui/foreign-fn-return-lifetime.stderr9
-rw-r--r--tests/ui/generic-associated-types/issue-70304.stderr2
-rw-r--r--tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr2
-rw-r--r--tests/ui/issues/issue-13497.stderr6
-rw-r--r--tests/ui/lifetimes/issue-26638.stderr16
-rw-r--r--tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr29
-rw-r--r--tests/ui/self/elision/nested-item.stderr11
-rw-r--r--tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr66
-rw-r--r--tests/ui/suggestions/impl-trait-missing-lifetime.stderr22
-rw-r--r--tests/ui/suggestions/missing-lifetime-specifier.stderr10
-rw-r--r--tests/ui/suggestions/return-elided-lifetime.stderr22
-rw-r--r--tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr2
19 files changed, 450 insertions, 55 deletions
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index df30c185c60..61c7846ea61 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -8,7 +8,7 @@ use crate::{PathResult, PathSource, Segment};
 use rustc_hir::def::Namespace::{self, *};
 
 use rustc_ast::ptr::P;
-use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt};
+use rustc_ast::visit::{walk_ty, FnCtxt, FnKind, LifetimeCtxt, Visitor};
 use rustc_ast::{
     self as ast, AssocItemKind, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind,
     MethodCall, NodeId, Path, Ty, TyKind, DUMMY_NODE_ID,
@@ -2830,6 +2830,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             .collect();
         debug!(?in_scope_lifetimes);
 
+        let mut maybe_static = false;
         debug!(?function_param_lifetimes);
         if let Some((param_lifetimes, params)) = &function_param_lifetimes {
             let elided_len = param_lifetimes.len();
@@ -2868,10 +2869,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
 
             if num_params == 0 {
                 err.help(
-                    "this function's return type contains a borrowed value, \
-                 but there is no value for it to be borrowed from",
+                    "this function's return type contains a borrowed value, but there is no value \
+                     for it to be borrowed from",
                 );
                 if in_scope_lifetimes.is_empty() {
+                    maybe_static = true;
                     in_scope_lifetimes = vec![(
                         Ident::with_dummy_span(kw::StaticLifetime),
                         (DUMMY_NODE_ID, LifetimeRes::Static),
@@ -2879,11 +2881,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 }
             } else if elided_len == 0 {
                 err.help(
-                    "this function's return type contains a borrowed value with \
-                 an elided lifetime, but the lifetime cannot be derived from \
-                 the arguments",
+                    "this function's return type contains a borrowed value with an elided \
+                     lifetime, but the lifetime cannot be derived from the arguments",
                 );
                 if in_scope_lifetimes.is_empty() {
+                    maybe_static = true;
                     in_scope_lifetimes = vec![(
                         Ident::with_dummy_span(kw::StaticLifetime),
                         (DUMMY_NODE_ID, LifetimeRes::Static),
@@ -2891,13 +2893,13 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 }
             } else if num_params == 1 {
                 err.help(format!(
-                    "this function's return type contains a borrowed value, \
-                 but the signature does not say which {m} it is borrowed from"
+                    "this function's return type contains a borrowed value, but the signature does \
+                     not say which {m} it is borrowed from",
                 ));
             } else {
                 err.help(format!(
-                    "this function's return type contains a borrowed value, \
-                 but the signature does not say whether it is borrowed from {m}"
+                    "this function's return type contains a borrowed value, but the signature does \
+                     not say whether it is borrowed from {m}",
                 ));
             }
         }
@@ -2962,11 +2964,238 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 );
             }
             1 => {
+                let post = if maybe_static {
+                    let owned = if let [lt] = &lifetime_refs[..]
+                        && lt.kind != MissingLifetimeKind::Ampersand
+                    {
+                        ", or if you will only have owned values"
+                    } else {
+                        ""
+                    };
+                    format!(
+                        ", but this is uncommon unless you're returning a borrowed value from a \
+                         `const` or a `static`{owned}",
+                    )
+                } else {
+                    String::new()
+                };
                 err.multipart_suggestion_verbose(
-                    format!("consider using the `{existing_name}` lifetime"),
+                    format!("consider using the `{existing_name}` lifetime{post}"),
                     spans_suggs,
                     Applicability::MaybeIncorrect,
                 );
+                if maybe_static {
+                    // FIXME: what follows are general suggestions, but we'd want to perform some
+                    // minimal flow analysis to provide more accurate suggestions. For example, if
+                    // we identified that the return expression references only one argument, we
+                    // would suggest borrowing only that argument, and we'd skip the prior
+                    // "use `'static`" suggestion entirely.
+                    if let [lt] = &lifetime_refs[..]
+                        && (lt.kind == MissingLifetimeKind::Ampersand
+                            || lt.kind == MissingLifetimeKind::Underscore)
+                    {
+                        let pre = if lt.kind == MissingLifetimeKind::Ampersand
+                            && let Some((kind, _span)) = self.diagnostic_metadata.current_function
+                            && let FnKind::Fn(_, _, sig, _, _, _) = kind
+                            && !sig.decl.inputs.is_empty()
+                            && let sugg = sig
+                                .decl
+                                .inputs
+                                .iter()
+                                .filter_map(|param| {
+                                    if param.ty.span.contains(lt.span) {
+                                        // We don't want to suggest `fn elision(_: &fn() -> &i32)`
+                                        // when we have `fn elision(_: fn() -> &i32)`
+                                        None
+                                    } else if let TyKind::CVarArgs = param.ty.kind {
+                                        // Don't suggest `&...` for ffi fn with varargs
+                                        None
+                                    } else if let TyKind::ImplTrait(..) = &param.ty.kind {
+                                        // We handle these in the next `else if` branch.
+                                        None
+                                    } else {
+                                        Some((param.ty.span.shrink_to_lo(), "&".to_string()))
+                                    }
+                                })
+                                .collect::<Vec<_>>()
+                            && !sugg.is_empty()
+                        {
+                            let (the, s) = if sig.decl.inputs.len() == 1 {
+                                ("the", "")
+                            } else {
+                                ("one of the", "s")
+                            };
+                            err.multipart_suggestion_verbose(
+                                format!(
+                                    "instead, you are more likely to want to change {the} \
+                                     argument{s} to be borrowed...",
+                                ),
+                                sugg,
+                                Applicability::MaybeIncorrect,
+                            );
+                            "...or alternatively, you might want"
+                        } else if (lt.kind == MissingLifetimeKind::Ampersand
+                            || lt.kind == MissingLifetimeKind::Underscore)
+                            && let Some((kind, _span)) = self.diagnostic_metadata.current_function
+                            && let FnKind::Fn(_, _, sig, _, _, _) = kind
+                            && let ast::FnRetTy::Ty(ret_ty) = &sig.decl.output
+                            && !sig.decl.inputs.is_empty()
+                            && let arg_refs = sig
+                                .decl
+                                .inputs
+                                .iter()
+                                .filter_map(|param| match &param.ty.kind {
+                                    TyKind::ImplTrait(_, bounds) => Some(bounds),
+                                    _ => None,
+                                })
+                                .flat_map(|bounds| bounds.into_iter())
+                                .collect::<Vec<_>>()
+                            && !arg_refs.is_empty()
+                        {
+                            // We have a situation like
+                            // fn g(mut x: impl Iterator<Item = &()>) -> Option<&()>
+                            // So we look at every ref in the trait bound. If there's any, we
+                            // suggest
+                            // fn g<'a>(mut x: impl Iterator<Item = &'a ()>) -> Option<&'a ()>
+                            let mut lt_finder =
+                                LifetimeFinder { lifetime: lt.span, found: None, seen: vec![] };
+                            for bound in arg_refs {
+                                if let ast::GenericBound::Trait(trait_ref, _) = bound {
+                                    lt_finder.visit_trait_ref(&trait_ref.trait_ref);
+                                }
+                            }
+                            lt_finder.visit_ty(ret_ty);
+                            let spans_suggs: Vec<_> = lt_finder
+                                .seen
+                                .iter()
+                                .filter_map(|ty| match &ty.kind {
+                                    TyKind::Ref(_, mut_ty) => {
+                                        let span = ty.span.with_hi(mut_ty.ty.span.lo());
+                                        Some((span, "&'a ".to_string()))
+                                    }
+                                    _ => None,
+                                })
+                                .collect();
+                            self.suggest_introducing_lifetime(
+                                err,
+                                None,
+                                |err, higher_ranked, span, message, intro_sugg| {
+                                    err.multipart_suggestion_verbose(
+                                        message,
+                                        std::iter::once((span, intro_sugg))
+                                            .chain(spans_suggs.iter().cloned())
+                                            .collect(),
+                                        Applicability::MaybeIncorrect,
+                                    );
+                                    higher_ranked
+                                },
+                            );
+                            "alternatively, you might want"
+                        } else {
+                            "instead, you are more likely to want"
+                        };
+                        let mut owned_sugg = lt.kind == MissingLifetimeKind::Ampersand;
+                        let mut sugg = vec![(lt.span, String::new())];
+                        if let Some((kind, _span)) = self.diagnostic_metadata.current_function
+                            && let FnKind::Fn(_, _, sig, _, _, _) = kind
+                            && let ast::FnRetTy::Ty(ty) = &sig.decl.output
+                        {
+                            let mut lt_finder =
+                                LifetimeFinder { lifetime: lt.span, found: None, seen: vec![] };
+                            lt_finder.visit_ty(&ty);
+
+                            if let [Ty { span, kind: TyKind::Ref(_, mut_ty), .. }] =
+                                &lt_finder.seen[..]
+                            {
+                                // We might have a situation like
+                                // fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()>
+                                // but `lt.span` only points at `'_`, so to suggest `-> Option<()>`
+                                // we need to find a more accurate span to end up with
+                                // fn g<'a>(mut x: impl Iterator<Item = &'_ ()>) -> Option<()>
+                                sugg = vec![(span.with_hi(mut_ty.ty.span.lo()), String::new())];
+                                owned_sugg = true;
+                            }
+                            if let Some(ty) = lt_finder.found {
+                                if let TyKind::Path(None, path) = &ty.kind {
+                                    // Check if the path being borrowed is likely to be owned.
+                                    let path: Vec<_> = Segment::from_path(path);
+                                    match self.resolve_path(&path, Some(TypeNS), None) {
+                                        PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
+                                            match module.res() {
+                                                Some(Res::PrimTy(PrimTy::Str)) => {
+                                                    // Don't suggest `-> str`, suggest `-> String`.
+                                                    sugg = vec![(
+                                                        lt.span.with_hi(ty.span.hi()),
+                                                        "String".to_string(),
+                                                    )];
+                                                }
+                                                Some(Res::PrimTy(..)) => {}
+                                                Some(Res::Def(
+                                                    DefKind::Struct
+                                                    | DefKind::Union
+                                                    | DefKind::Enum
+                                                    | DefKind::ForeignTy
+                                                    | DefKind::AssocTy
+                                                    | DefKind::OpaqueTy
+                                                    | DefKind::TyParam,
+                                                    _,
+                                                )) => {}
+                                                _ => {
+                                                    // Do not suggest in all other cases.
+                                                    owned_sugg = false;
+                                                }
+                                            }
+                                        }
+                                        PathResult::NonModule(res) => {
+                                            match res.base_res() {
+                                                Res::PrimTy(PrimTy::Str) => {
+                                                    // Don't suggest `-> str`, suggest `-> String`.
+                                                    sugg = vec![(
+                                                        lt.span.with_hi(ty.span.hi()),
+                                                        "String".to_string(),
+                                                    )];
+                                                }
+                                                Res::PrimTy(..) => {}
+                                                Res::Def(
+                                                    DefKind::Struct
+                                                    | DefKind::Union
+                                                    | DefKind::Enum
+                                                    | DefKind::ForeignTy
+                                                    | DefKind::AssocTy
+                                                    | DefKind::OpaqueTy
+                                                    | DefKind::TyParam,
+                                                    _,
+                                                ) => {}
+                                                _ => {
+                                                    // Do not suggest in all other cases.
+                                                    owned_sugg = false;
+                                                }
+                                            }
+                                        }
+                                        _ => {
+                                            // Do not suggest in all other cases.
+                                            owned_sugg = false;
+                                        }
+                                    }
+                                }
+                                if let TyKind::Slice(inner_ty) = &ty.kind {
+                                    // Don't suggest `-> [T]`, suggest `-> Vec<T>`.
+                                    sugg = vec![
+                                        (lt.span.with_hi(inner_ty.span.lo()), "Vec<".to_string()),
+                                        (ty.span.with_lo(inner_ty.span.hi()), ">".to_string()),
+                                    ];
+                                }
+                            }
+                        }
+                        if owned_sugg {
+                            err.multipart_suggestion_verbose(
+                                format!("{pre} to return an owned value"),
+                                sugg,
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                    }
+                }
 
                 // Record as using the suggested resolution.
                 let (_, (_, res)) = in_scope_lifetimes[0];
@@ -2996,7 +3225,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
 fn mk_where_bound_predicate(
     path: &Path,
     poly_trait_ref: &ast::PolyTraitRef,
-    ty: &ast::Ty,
+    ty: &Ty,
 ) -> Option<ast::WhereBoundPredicate> {
     use rustc_span::DUMMY_SP;
     let modified_segments = {
@@ -3073,6 +3302,24 @@ pub(super) fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: I
     err.emit();
 }
 
+struct LifetimeFinder<'ast> {
+    lifetime: Span,
+    found: Option<&'ast Ty>,
+    seen: Vec<&'ast Ty>,
+}
+
+impl<'ast> Visitor<'ast> for LifetimeFinder<'ast> {
+    fn visit_ty(&mut self, t: &'ast Ty) {
+        if let TyKind::Ref(_, mut_ty) = &t.kind {
+            self.seen.push(t);
+            if t.span.lo() == self.lifetime.lo() {
+                self.found = Some(&mut_ty.ty);
+            }
+        }
+        walk_ty(self, t)
+    }
+}
+
 /// Shadowing involving a label is only a warning for historical reasons.
 //FIXME: make this a proper lint.
 pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index dfa386b49de..40149f8f1c3 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -11,7 +11,7 @@ use std::path::{Path, PathBuf};
 const ENTRY_LIMIT: usize = 900;
 // FIXME: The following limits should be reduced eventually.
 const ISSUES_ENTRY_LIMIT: usize = 1852;
-const ROOT_ENTRY_LIMIT: usize = 867;
+const ROOT_ENTRY_LIMIT: usize = 866;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
diff --git a/tests/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr b/tests/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr
index 8ccfb212216..24fd38f31ad 100644
--- a/tests/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr
+++ b/tests/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr
@@ -5,10 +5,15 @@ LL | fn elision<T: Fn() -> &i32>() {
    |                       ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL | fn elision<T: Fn() -> &'static i32>() {
    |                        +++++++
+help: instead, you are more likely to want to return an owned value
+   |
+LL - fn elision<T: Fn() -> &i32>() {
+LL + fn elision<T: Fn() -> i32>() {
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/associated-types/bound-lifetime-in-return-only.elision.stderr b/tests/ui/associated-types/bound-lifetime-in-return-only.elision.stderr
index 0593a62a750..d24378487e7 100644
--- a/tests/ui/associated-types/bound-lifetime-in-return-only.elision.stderr
+++ b/tests/ui/associated-types/bound-lifetime-in-return-only.elision.stderr
@@ -5,10 +5,15 @@ LL | fn elision(_: fn() -> &i32) {
    |                       ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL | fn elision(_: fn() -> &'static i32) {
    |                        +++++++
+help: instead, you are more likely to want to return an owned value
+   |
+LL - fn elision(_: fn() -> &i32) {
+LL + fn elision(_: fn() -> i32) {
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/c-variadic/variadic-ffi-6.stderr b/tests/ui/c-variadic/variadic-ffi-6.stderr
index 1ceff570478..344bfed4b42 100644
--- a/tests/ui/c-variadic/variadic-ffi-6.stderr
+++ b/tests/ui/c-variadic/variadic-ffi-6.stderr
@@ -5,10 +5,19 @@ LL | ) -> &usize {
    |      ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL | ) -> &'static usize {
    |       +++++++
+help: instead, you are more likely to want to change one of the arguments to be borrowed...
+   |
+LL |     x: &usize,
+   |        +
+help: ...or alternatively, you might want to return an owned value
+   |
+LL - ) -> &usize {
+LL + ) -> usize {
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/foreign-fn-return-lifetime.fixed b/tests/ui/foreign-fn-return-lifetime.fixed
deleted file mode 100644
index 143d6343d26..00000000000
--- a/tests/ui/foreign-fn-return-lifetime.fixed
+++ /dev/null
@@ -1,8 +0,0 @@
-// run-rustfix
-
-extern "C" {
-    pub fn g(_: &u8) -> &u8; // OK
-    pub fn f() -> &'static u8; //~ ERROR missing lifetime specifier
-}
-
-fn main() {}
diff --git a/tests/ui/foreign-fn-return-lifetime.rs b/tests/ui/foreign-fn-return-lifetime.rs
index 76fe50a340a..35595bab36d 100644
--- a/tests/ui/foreign-fn-return-lifetime.rs
+++ b/tests/ui/foreign-fn-return-lifetime.rs
@@ -1,5 +1,3 @@
-// run-rustfix
-
 extern "C" {
     pub fn g(_: &u8) -> &u8; // OK
     pub fn f() -> &u8; //~ ERROR missing lifetime specifier
diff --git a/tests/ui/foreign-fn-return-lifetime.stderr b/tests/ui/foreign-fn-return-lifetime.stderr
index 43edcbde35c..e24c0f23c35 100644
--- a/tests/ui/foreign-fn-return-lifetime.stderr
+++ b/tests/ui/foreign-fn-return-lifetime.stderr
@@ -1,14 +1,19 @@
 error[E0106]: missing lifetime specifier
-  --> $DIR/foreign-fn-return-lifetime.rs:5:19
+  --> $DIR/foreign-fn-return-lifetime.rs:3:19
    |
 LL |     pub fn f() -> &u8;
    |                   ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL |     pub fn f() -> &'static u8;
    |                    +++++++
+help: instead, you are more likely to want to return an owned value
+   |
+LL -     pub fn f() -> &u8;
+LL +     pub fn f() -> u8;
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/generic-associated-types/issue-70304.stderr b/tests/ui/generic-associated-types/issue-70304.stderr
index 99339e96859..9b02c1b0768 100644
--- a/tests/ui/generic-associated-types/issue-70304.stderr
+++ b/tests/ui/generic-associated-types/issue-70304.stderr
@@ -11,7 +11,7 @@ LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> {
    |                                                             ^^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values
    |
 LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'static>> {
    |                                                             ~~~~~~~
diff --git a/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr b/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr
index 443ffeb55cd..a5982a5542a 100644
--- a/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr
+++ b/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr
@@ -5,7 +5,7 @@ LL | fn d() -> impl Fn() -> (impl Debug + '_) {
    |                                      ^^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values
    |
 LL | fn d() -> impl Fn() -> (impl Debug + 'static) {
    |                                      ~~~~~~~
diff --git a/tests/ui/issues/issue-13497.stderr b/tests/ui/issues/issue-13497.stderr
index 236e6b48607..fb3de637a79 100644
--- a/tests/ui/issues/issue-13497.stderr
+++ b/tests/ui/issues/issue-13497.stderr
@@ -5,10 +5,14 @@ LL |     &str
    |     ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL |     &'static str
    |      +++++++
+help: instead, you are more likely to want to return an owned value
+   |
+LL |     String
+   |     ~~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/issue-26638.stderr b/tests/ui/lifetimes/issue-26638.stderr
index e61158a5d4d..ee958686259 100644
--- a/tests/ui/lifetimes/issue-26638.stderr
+++ b/tests/ui/lifetimes/issue-26638.stderr
@@ -17,10 +17,18 @@ LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
    |                                        ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &'static str { iter() }
    |                                         +++++++
+help: instead, you are more likely to want to change the argument to be borrowed...
+   |
+LL | fn parse_type_2(iter: &fn(&u8)->&u8) -> &str { iter() }
+   |                       +
+help: ...or alternatively, you might want to return an owned value
+   |
+LL | fn parse_type_2(iter: fn(&u8)->&u8) -> String { iter() }
+   |                                        ~~~~~~
 
 error[E0106]: missing lifetime specifier
   --> $DIR/issue-26638.rs:10:22
@@ -29,10 +37,14 @@ LL | fn parse_type_3() -> &str { unimplemented!() }
    |                      ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL | fn parse_type_3() -> &'static str { unimplemented!() }
    |                       +++++++
+help: instead, you are more likely to want to return an owned value
+   |
+LL | fn parse_type_3() -> String { unimplemented!() }
+   |                      ~~~~~~
 
 error[E0308]: mismatched types
   --> $DIR/issue-26638.rs:1:69
diff --git a/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr b/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr
index 5eee953ef18..23ef36888f0 100644
--- a/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr
+++ b/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr
@@ -5,10 +5,15 @@ LL | fn f() -> &isize {
    |           ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL | fn f() -> &'static isize {
    |            +++++++
+help: instead, you are more likely to want to return an owned value
+   |
+LL - fn f() -> &isize {
+LL + fn f() -> isize {
+   |
 
 error[E0106]: missing lifetime specifier
   --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:7:33
@@ -41,10 +46,19 @@ LL | fn i(_x: isize) -> &isize {
    |                    ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL | fn i(_x: isize) -> &'static isize {
    |                     +++++++
+help: instead, you are more likely to want to change the argument to be borrowed...
+   |
+LL | fn i(_x: &isize) -> &isize {
+   |          +
+help: ...or alternatively, you might want to return an owned value
+   |
+LL - fn i(_x: isize) -> &isize {
+LL + fn i(_x: isize) -> isize {
+   |
 
 error[E0106]: missing lifetime specifier
   --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:34:24
@@ -53,10 +67,19 @@ LL | fn j(_x: StaticStr) -> &isize {
    |                        ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL | fn j(_x: StaticStr) -> &'static isize {
    |                         +++++++
+help: instead, you are more likely to want to change the argument to be borrowed...
+   |
+LL | fn j(_x: &StaticStr) -> &isize {
+   |          +
+help: ...or alternatively, you might want to return an owned value
+   |
+LL - fn j(_x: StaticStr) -> &isize {
+LL + fn j(_x: StaticStr) -> isize {
+   |
 
 error[E0106]: missing lifetime specifier
   --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:40:49
diff --git a/tests/ui/self/elision/nested-item.stderr b/tests/ui/self/elision/nested-item.stderr
index 752fd82332c..7bad26fa133 100644
--- a/tests/ui/self/elision/nested-item.stderr
+++ b/tests/ui/self/elision/nested-item.stderr
@@ -21,10 +21,19 @@ LL | fn wrap(self: Wrap<{ fn bar(&self) {} }>) -> &() {
    |                                              ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL | fn wrap(self: Wrap<{ fn bar(&self) {} }>) -> &'static () {
    |                                               +++++++
+help: instead, you are more likely to want to change the argument to be borrowed...
+   |
+LL | fn wrap(self: &Wrap<{ fn bar(&self) {} }>) -> &() {
+   |               +
+help: ...or alternatively, you might want to return an owned value
+   |
+LL - fn wrap(self: Wrap<{ fn bar(&self) {} }>) -> &() {
+LL + fn wrap(self: Wrap<{ fn bar(&self) {} }>) -> () {
+   |
 
 error[E0412]: cannot find type `Wrap` in this scope
   --> $DIR/nested-item.rs:5:15
diff --git a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr
index 50806a67255..2dfaa731194 100644
--- a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr
+++ b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr
@@ -5,10 +5,19 @@ LL |     fn g(mut x: impl Iterator<Item = &()>) -> Option<&()> { x.next() }
    |                                                      ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL |     fn g(mut x: impl Iterator<Item = &()>) -> Option<&'static ()> { x.next() }
    |                                                       +++++++
+help: consider introducing a named lifetime parameter
+   |
+LL |     fn g<'a>(mut x: impl Iterator<Item = &'a ()>) -> Option<&'a ()> { x.next() }
+   |         ++++                             ~~~                ~~~
+help: alternatively, you might want to return an owned value
+   |
+LL -     fn g(mut x: impl Iterator<Item = &()>) -> Option<&()> { x.next() }
+LL +     fn g(mut x: impl Iterator<Item = &()>) -> Option<()> { x.next() }
+   |
 
 error[E0106]: missing lifetime specifier
   --> $DIR/impl-trait-missing-lifetime-gated.rs:19:60
@@ -17,10 +26,19 @@ LL |     async fn i(mut x: impl Iterator<Item = &()>) -> Option<&()> { x.next()
    |                                                            ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL |     async fn i(mut x: impl Iterator<Item = &()>) -> Option<&'static ()> { x.next() }
    |                                                             +++++++
+help: consider introducing a named lifetime parameter
+   |
+LL |     async fn i<'a>(mut x: impl Iterator<Item = &'a ()>) -> Option<&'a ()> { x.next() }
+   |               ++++                             ~~~                ~~~
+help: alternatively, you might want to return an owned value
+   |
+LL -     async fn i(mut x: impl Iterator<Item = &()>) -> Option<&()> { x.next() }
+LL +     async fn i(mut x: impl Iterator<Item = &()>) -> Option<()> { x.next() }
+   |
 
 error[E0106]: missing lifetime specifier
   --> $DIR/impl-trait-missing-lifetime-gated.rs:27:58
@@ -29,10 +47,19 @@ LL |     fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next()
    |                                                          ^^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values
    |
 LL |     fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
    |                                                          ~~~~~~~
+help: consider introducing a named lifetime parameter
+   |
+LL |     fn g<'a>(mut x: impl Iterator<Item = &'a ()>) -> Option<&'a ()> { x.next() }
+   |         ++++                             ~~~                ~~~
+help: alternatively, you might want to return an owned value
+   |
+LL -     fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+LL +     fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<()> { x.next() }
+   |
 
 error[E0106]: missing lifetime specifier
   --> $DIR/impl-trait-missing-lifetime-gated.rs:37:64
@@ -41,10 +68,19 @@ LL |     async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.n
    |                                                                ^^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values
    |
 LL |     async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
    |                                                                ~~~~~~~
+help: consider introducing a named lifetime parameter
+   |
+LL |     async fn i<'a>(mut x: impl Iterator<Item = &'a ()>) -> Option<&'a ()> { x.next() }
+   |               ++++                             ~~~                ~~~
+help: alternatively, you might want to return an owned value
+   |
+LL -     async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+LL +     async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<()> { x.next() }
+   |
 
 error[E0106]: missing lifetime specifier
   --> $DIR/impl-trait-missing-lifetime-gated.rs:47:37
@@ -53,10 +89,19 @@ LL |     fn g(mut x: impl Foo) -> Option<&()> { x.next() }
    |                                     ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL |     fn g(mut x: impl Foo) -> Option<&'static ()> { x.next() }
    |                                      +++++++
+help: consider introducing a named lifetime parameter
+   |
+LL |     fn g<'a>(mut x: impl Foo) -> Option<&'a ()> { x.next() }
+   |         ++++                            ~~~
+help: alternatively, you might want to return an owned value
+   |
+LL -     fn g(mut x: impl Foo) -> Option<&()> { x.next() }
+LL +     fn g(mut x: impl Foo) -> Option<()> { x.next() }
+   |
 
 error[E0106]: missing lifetime specifier
   --> $DIR/impl-trait-missing-lifetime-gated.rs:58:41
@@ -65,10 +110,19 @@ LL |     fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() }
    |                                         ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL |     fn g(mut x: impl Foo<()>) -> Option<&'static ()> { x.next() }
    |                                          +++++++
+help: consider introducing a named lifetime parameter
+   |
+LL |     fn g<'a>(mut x: impl Foo<()>) -> Option<&'a ()> { x.next() }
+   |         ++++                                ~~~
+help: alternatively, you might want to return an owned value
+   |
+LL -     fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() }
+LL +     fn g(mut x: impl Foo<()>) -> Option<()> { x.next() }
+   |
 
 error[E0658]: anonymous lifetimes in `impl Trait` are unstable
   --> $DIR/impl-trait-missing-lifetime-gated.rs:6:35
diff --git a/tests/ui/suggestions/impl-trait-missing-lifetime.stderr b/tests/ui/suggestions/impl-trait-missing-lifetime.stderr
index 2c29cfa0b91..c1dbaae0649 100644
--- a/tests/ui/suggestions/impl-trait-missing-lifetime.stderr
+++ b/tests/ui/suggestions/impl-trait-missing-lifetime.stderr
@@ -5,10 +5,19 @@ LL | fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
    |                                                      ^^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values
    |
 LL | fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
    |                                                      ~~~~~~~
+help: consider introducing a named lifetime parameter
+   |
+LL | fn g<'a>(mut x: impl Iterator<Item = &'a ()>) -> Option<&'a ()> { x.next() }
+   |     ++++                             ~~~                ~~~
+help: alternatively, you might want to return an owned value
+   |
+LL - fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+LL + fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<()> { x.next() }
+   |
 
 error[E0106]: missing lifetime specifier
   --> $DIR/impl-trait-missing-lifetime.rs:16:60
@@ -17,10 +26,19 @@ LL | async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next(
    |                                                            ^^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values
    |
 LL | async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
    |                                                            ~~~~~~~
+help: consider introducing a named lifetime parameter
+   |
+LL | async fn i<'a>(mut x: impl Iterator<Item = &'a ()>) -> Option<&'a ()> { x.next() }
+   |           ++++                             ~~~                ~~~
+help: alternatively, you might want to return an owned value
+   |
+LL - async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+LL + async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<()> { x.next() }
+   |
 
 error: lifetime may not live long enough
   --> $DIR/impl-trait-missing-lifetime.rs:16:69
diff --git a/tests/ui/suggestions/missing-lifetime-specifier.stderr b/tests/ui/suggestions/missing-lifetime-specifier.stderr
index fa4bc2fa79d..e41f547ce9b 100644
--- a/tests/ui/suggestions/missing-lifetime-specifier.stderr
+++ b/tests/ui/suggestions/missing-lifetime-specifier.stderr
@@ -5,7 +5,7 @@ LL |     static a: RefCell<HashMap<i32, Vec<Vec<Foo>>>> = RefCell::new(HashMap::
    |                                            ^^^ expected 2 lifetime parameters
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values
    |
 LL |     static a: RefCell<HashMap<i32, Vec<Vec<Foo<'static, 'static>>>>> = RefCell::new(HashMap::new());
    |                                               ++++++++++++++++++
@@ -32,7 +32,7 @@ LL |     static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap:
    |                                            expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL |     static b: RefCell<HashMap<i32, Vec<Vec<&'static Bar<'static, 'static>>>>> = RefCell::new(HashMap::new());
    |                                             +++++++    ++++++++++++++++++
@@ -59,7 +59,7 @@ LL |     static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(Hash
    |                                               ^ expected 2 lifetime parameters
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values
    |
 LL |     static c: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                                +++++++++++++++++
@@ -86,7 +86,7 @@ LL |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(Has
    |                                            expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL |     static d: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                             +++++++     +++++++++++++++++
@@ -113,7 +113,7 @@ LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell
    |                                            ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                             +++++++
diff --git a/tests/ui/suggestions/return-elided-lifetime.stderr b/tests/ui/suggestions/return-elided-lifetime.stderr
index 273d95bc747..7bfffd30184 100644
--- a/tests/ui/suggestions/return-elided-lifetime.stderr
+++ b/tests/ui/suggestions/return-elided-lifetime.stderr
@@ -5,10 +5,15 @@ LL | fn f1() -> &i32 { loop {} }
    |            ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL | fn f1() -> &'static i32 { loop {} }
    |             +++++++
+help: instead, you are more likely to want to return an owned value
+   |
+LL - fn f1() -> &i32 { loop {} }
+LL + fn f1() -> i32 { loop {} }
+   |
 
 error[E0106]: missing lifetime specifiers
   --> $DIR/return-elided-lifetime.rs:8:14
@@ -19,7 +24,7 @@ LL | fn f1_() -> (&i32, &i32) { loop {} }
    |              expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL | fn f1_() -> (&'static i32, &'static i32) { loop {} }
    |               +++++++       +++++++
@@ -31,10 +36,19 @@ LL | fn f2(a: i32, b: i32) -> &i32 { loop {} }
    |                          ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL | fn f2(a: i32, b: i32) -> &'static i32 { loop {} }
    |                           +++++++
+help: instead, you are more likely to want to change one of the arguments to be borrowed...
+   |
+LL | fn f2(a: &i32, b: &i32) -> &i32 { loop {} }
+   |          +        +
+help: ...or alternatively, you might want to return an owned value
+   |
+LL - fn f2(a: i32, b: i32) -> &i32 { loop {} }
+LL + fn f2(a: i32, b: i32) -> i32 { loop {} }
+   |
 
 error[E0106]: missing lifetime specifiers
   --> $DIR/return-elided-lifetime.rs:13:28
@@ -45,7 +59,7 @@ LL | fn f2_(a: i32, b: i32) -> (&i32, &i32) { loop {} }
    |                            expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
 LL | fn f2_(a: i32, b: i32) -> (&'static i32, &'static i32) { loop {} }
    |                             +++++++       +++++++
diff --git a/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr
index 50401791eff..cd74d27dcb5 100644
--- a/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr
+++ b/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr
@@ -28,7 +28,7 @@ LL | fn meh() -> Box<dyn for<'_> Meh<'_>>
    |                                 ^^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values
    |
 LL | fn meh() -> Box<dyn for<'_> Meh<'static>>
    |                                 ~~~~~~~