Yep! Which in turn matters when you have (ultimately) multiple lifetime parameters.

Notably, if we have 'a : 'i, and 'b : 'i, then Type<'a, 'b> : 'i, and vice versa.
This, in turn, applies to this -> impl …, with, say, the following signature:
fn f<'a, 'b, 'i>(a: &'a (), b: &'b ()) -> impl …
where
'a : 'i,
'b : 'i,
// thus: `…<'a, 'b> : 'i`
{
(a, b)
}
Here we have:
: 'i
type Ret<'a, 'b> = (&'a (), &'b ()) = impl …
+ use<'a, 'b> + 'i;
That is, we have both:
-
type Ret<'a, 'b> = impl use<'a, 'b> + …
-
type Ret<'a, 'b> = impl 'i + …
Thence, intuitively :
The important intuition connecting use<'lts, '..> with + 'usability

impl use<'a, 'b> ≈ impl 'i (when 'a : 'i, 'b : 'i)
With that having been said, or that "nerd"/intellectual curiosity having explored, let's take a step back, and focus on:
use<'lts, '..> vs. + 'usability in practice

This whole discussion is about their usage in fn return type:
-> impl … + use<…>
-> impl … + 'usability
As of current Rust, there is no other place where + use<…> can be used, making this whole comparison pointless or irrelevant then.
The main points are the following:
-

When using -> impl …, favor + use<…> over + 'usability
To get an intuition as to why, going back to our f() example above, notice how using + 'usability required us to introduce an extra, otherwise unused, lifetime parameter, and to "artificially" constrain it to be "smaller than" every other lifetime (or type) parameter present. Indeed, (&'a (), &'b ()) is neither : 'a nor : 'b (when 'a and 'b are both arbitrary, and thus, potentially unrelated / with no ordering property between them).
So using + 'usability may sometimes require "thinking of" / "coming up with" this "trick", which is not as easy as merely listing every generic parameter used in the return type (a rather mechanical and intuitive operation), which is what using + use<…> is about.
-

When the package.edition is ≥"2024", eliding use<…> is equivalent to a hidden, automagically inserted by the compiler, + use<'every, 'single, Param, In, Scope>.
So unless you're doing something a bit specific, favor using neither use<…> nor + 'usability: things will Just Work™ this way.
-

+ use<…> cannot be used with -> PtrTo<dyn …>. So you have to use + 'usability in that case.
And this is, as a matter of fact, the main reason I've been writing this post: whilst it would have been great being able to say "-> … + 'usability is an artifact from the past, to be superseded by the more intuitive -> … + use<…>", it turns out not to be true, because of → PtrTo<dyn … + 'usability>, which "brings us back" to pre-use<…> Rust questions.
Why the need for these use<…> vs. + 'usability annotations to begin with?
This is, in general, the "whole point", or at least, the "main point" of this annotation to begin with:
- the return type is some type-erased or opaque type whose details we do not wish to expose;
- but there is an important "detail" that we cannot overlook nor hide, no matter how much it may displease us: the "effective region/lifetime of safe usability of (instances of) our type"
Indeed, consider:
fn foo(s: &str) -> Box<…> { Box::new("some static str") }
fn bar(s: &str) -> Box<…> { Box::new(s) }
Given the fn bodies, we know the following call-site to be safe and sound:
let ret = {
let local = String::from("local");
foo(&local)
};
stuff(ret);
But the following one should very much be rejected!
let ret = {
let local = String::from("local");
bar(&local) // return type still borrows from `local`
}; // <- `local` is dropped here
stuff(ret); // <- Uh-oh…
Of course, if we see the fn bodies, or rather, if the Rust compiler/borrow-checker sees the fn bodies, it should be able to reject this for us, no matter what we write for … in our -> Box<…> return type, right? We may just want to mention we're returning "some Display" type (granted, inside a Box), whatever that may be.
- using
dyn(amic dispatch and unifying-type-erasure): -> Box<dyn Display>,
- using
impl ("opaque" type): -> Box<impl Display>.
Well, papering over the technical feasability challenges of such an approach regarding an all-seeing compiler, if this were to work, it would mean that changing the fn body of, say, foo(), to match that of bar(), without any syntactical change to its function signature, would make our example call-site cease to compile. That is, a change of fn body/implementation with no syntactical change of the fn signature would be a breaking change 
This would be catastrophic for the ecosystem, and does, in fact, go against the very ethos of Rust's non-SemVer-footgunny API design philosophy.
So we want:
- a function such as
foo to be definable, and in a way that allows our example callsite to compile;
- a function such as
bar to be definable, and in a way that prevents our example callsite from compiling;
- some syntactical marker in the
fn signature to signify, within the API contract, whether our fn body implementation is more like bar(), i.e., borrowing from the input (or rather potentially borrowing from the input), or more like foo(), i.e., not borrowing from the input (guaranteed not to).
We could envision several possible ways to make this annotation (we could have imagined, initially, some #[borrowing(true)] and #[borrowing(false)] lang-magical annotation or whatnot, but eventually, as the number of borrowing args increases, we'd need to say which args we may be borrowing from, and as a matter of fact, which parts of which args we may be "borrowing". Eventually, we need to be talking of lifetimes, so yes, we do end up needing some lifetime annotations. Or, back to our original "type-erasure/opaquification" goal, generally, we cannot really erase or be opaque over lifetime usage.
Now, the reason for the two use<…> + 'usability approaches for this very annotation comes rather naturally if we rewrite our situation using a trait API:
fn f(s: &str) -> Box<… '_ …>;
// is sugar for:
fn f<'s>(s: &'s str) -> Box<… 's …>;
So, with a trait, we could have:
trait OurFn : 'static {
fn call<'s>(s: &'s str) -> Box<Self::Ret<'s>>;
// where:
type Ret<'s> : Display; // Option A
// or:
type Ret<'s> : 'static + Display; // Option B
}
// or:
trait OurFn : 'static {
fn call<'s>(s: &'s str) -> Box<Self::Ret>;
type Ret : Display;
// Note: `type Ret :` can also be spelled out as:
// type Ret<> : Display; // Option C
// ^
// no 's!
}
alongside our callsite:
fn callsite<F: OurFn>() {
let ret = {
let local = String::from("local");
F::call(&local)
}; // <- `drop(local);`
println!("{ret}");
}
It turns out these three "Option"s I've listed are valid ways to describe this "family" of APIs, and that if we do so, our:
-
callsite() fails to compile in the Option A case,
which is the least restrictive for the implementor, and thus, the less powerful / most restrictive for the user/caller/callsite;
-
callsite() does compile in the Option B case,
which does have a : 'static restriction on Ret<'s>; thus, a : 'static property which the user/caller/callsite can make use of (for their function to compile);
-
callsite() does compile in the Option C case,
which does have a non-<'s>-using restriction on type Ret; thus, a "non-'s-infected property" which the user/caller/callsite can make use of (for their function to compile).
If you stare at the three type Ret … definitions, and you sed/strip the type Ret "common prefix" on all them (and the : and ;), and instead, write -> impl, you end up with:
// Option A: type Ret<'s>: Display;
-> impl<'s>: Display;
// Option B: type Ret<'s>: 'static + Display;
-> impl<'s>: 'static + Display;
// Option C: type Ret<>: Display;
-> impl<>: Display;
If we replace <…>: with use<…> +, we end up with:
-> impl /* may */use<'s> + Display
-> impl /* may */use<'s> + 'static + Display
-> impl /* may */use<> + Display
Which is exactly the three kinds of annotations we can use for our -> impl … types!
But how do these differ in semantics with one another? Which ones are more restrictive for the callee/implementation/fn body, and which for the caller/callsite?
The exact meaning/difference in semantics between use<..> and + 'usability
- IOW, using
use<…> vs. + 'usability as restrictions (for the callee), or properties (for the caller).
For this, we need to focus on use<'lt> vs. + 'usability. Or, equivalently, given some unknown/arbitrary or we daresay adversarial choice of F: OurFn, what can we say about:
F::Ret<'lt, ...> vs.
F::Ret<...> : 'usability ?
Well, remember the golden rule:

Notably, if we have 'a : 'i, and 'b : 'i, then Type<'a, 'b> : 'i, and vice versa.
Which we can generalize:

Type<'a, 'b, ...> : 'i ⇔ 'a : 'i, 'b : 'i, ...
'a : 'i, 'b : 'i, ... can be written as:
'a ⊇ 'i, 'b ⊇ 'i, ... i.e.,
('a ∩ 'b ∩ ...) ⊇ 'i
There is another important property, related to this, at least as far as intuition is concerned:

If T : 'u, then (any instance of type) T is guaranteed not "to dangle", i.e., not to contain any dangling/expired references anywhere inside it.
It is thus safe to use (any instance of type) T for the "duration"/region/lifetime 'u (notably, "for the lifetime 'static" means "forever").
We could even say that (any instance of type) T is safely usable within/for 'u.
Hence my calling this "the lifetime of usability of T"; I even strive to name a lifetime in this position 'usability.
From all this stems an important, and in our case, meaningful, corollary:
Type<'a, ...> : 'u ⇒ 'a : 'u ('a ⊇ 'u)
"Thus", use<'a, ...> : 'u ⇒ 'a : 'u... Kind of. It's a decent intuition, but the devil here is in the details.
There is a difference between Type<'a, ...> when it is a concrete type (e.g., &'a str, Box<&'a str>, Box<dyn 'a + Display>, Cow<'a, str>, BorrowedFd<'a>), when the 'a : 'usability entailment does hold, and when you have some "abstract", or somehow overly generic, or outright opaque type that happens to "mention 'a".
- Note:
dyn is deemed a "concrete" type in this regard: it "definitely uses 'a". It is impl which is "opaque": it only may use 'a.
For instance, let's focus on some F: OurFn + 'static (notice how F itself, in this example, is not allowed to "know" of any lifetime other than 'static): what could F::Ret<'s> possibly be? As in, for every possible choice of F, or, equivalently, for a masterfully clever adversary providing some F with the purpose to annoy us.
Well, they could write, notably, the two following impls, and provide us either of the implementors:
enum A {}
impl OurFn for A {
type Ret<'s> = &'s str;
...
}
enum B {}
impl OurFn for B {
type Ret<'s> = &'static str; // Allowed!
...
}
That is, with a GAT (as well as with a trait's own generic parameters), an associated type is not forced to be infected with / mentioning each and every one of these parameters in scope: we are allowed to "ignore" 's!
So we have both:
A::Ret<'s> = &'s str :! 'static,
B::Ret<'s> = &'static str : 'static,
i.e.,
So, which is it? Well, whilst the implementor is not forced to use 's, a user/caller/callsite of such an abstract / generic / "adversarially chosen" / opaque type cannot assume this to be the case. Quite the contrary!
Barring any extra information, they must assume the worst: that F::Ret<'s> may start dangling once 's expires 

impl /* may */use<'a, ...> + NoOtherLifetimeInfo : 'u ⇒ 'a : 'u ('a ⊇ 'u)
So back to our original, practical question. Given:
fn a<'s>(s: &'s str) -> impl /* may */use<'s> + Display;
fn b<'s>(s: &'s str) -> impl /* may */use<'s> + 'static + Display;
fn c<'s>(s: &'s str) -> impl /* may */use<> + Display;
fn d<'s>(s: &'s str) -> impl /* may */use<> + 'static + Display;
which return types can be used for 'static (no matter how small 's be)?
To illustrate, if we had f be some function ranging over a, b, c, d, the question is whether the following snippet would compile:
// a, b, c, or d.
use ... as f;
fn callsite() -> impl 'static + Display {
let local = String::from("...");
let s: &'_ str = &local;
/* return */ f(s)
}
-
Well, d() obviously can; as a matter of fact, I'll skip mentioning this one in the future, since there is no subtlety whatsoever about this one.
-
As it turns out, so can c(): whilst it does not strictly stipulate that it be : 'static, it does stipulate that the exhaustive list of generic parameters it /* may */use is empy. With no non-'static info at its disposal, it has no other choice than to be 'static.
-
We have seen case a() in our previous
:

impl /* may */use<'a, ...> + NoOtherLifetimeInfo : 'u ⇒ 'a : 'u
Our a() function is indeed a case of impl /* may */use<'s> + NoOtherLifetimeInfo. Thus, in order for it to be : 'static, we'd need for 's to be : 'static, which we're assuming not to hold.
Thus, a() will not be callable/usable in our callsite().
-
Remains b(): here, we have something which may be using 's, but which also stipulates it is : 'static. The latter "takes precedence", and our resulting type is indeed : 'static
Hence:

-> impl use<'s> + Bounds...; // ❌ not `: 'static`, just `: 's`
-> impl use<'s> + Bounds... + 'static; // ✅ `: 'static`
-> impl use<> + Bounds...; // ✅ `: 'static`
More generally, going back to the use<...>-with-2-or-more-lifetimes case (when use<> is truly useful and/or meaningful vs. using bare + 'lifetime), and naming this 'intersection lifetime of 'x and 'y (so impl use<'x, 'y> ≈ impl 'i), we have:
//! Given `fn<'x, 'y, 'i>(...) where 'x : 'i, 'y : 'i`
-> impl use<'x, 'y> + Bounds...; // `: 'i`
-> impl use<'x, /*no 'y*/> + Bounds...; // `: 'x`
// Reminder:
-> impl use<'x, 'y> + Bounds... + 'x; // `: 'x`. And so on and so forth.
Practical example: 3-1 lifetimes being use<..>d
This can get trickier (and use<...> can get especially handier) when you get to 3 or more lifetimes, and some of which are not use<..>d (and you intend to let the caller/callsite take advantage of that fact):
fn f_impl<'a, 'b, 'c, /* 'i */>(
a: &'a str,
_b: &'b str,
c: &'c str,
) -> Box<impl use<'a, /*no 'b,*/ 'c> + Debug>
where
// ... : 'i, ...
{
Box::new((a, c)) // : Box<(&'a str, &'c str)>
}
fn callsite() -> impl 'static + Debug {
let local = String::from("b");
/* return */ f_impl("a", &local, "c") // OK because `'b` not `use<..>`d.
}
This last snippet compiles fine, courtesy of impl use<...> managing to:
- intuitively describe the fact that
b is not being used in the return type,
- so the caller/callsite can take advantage of that fact for a snippet such as
fn callsite() to be allowed.
But what about when use<..> is not available? Notably, when returning dyn, rather than impl?
fn f_dyn<'a, 'b, 'c, /* 'i */>(
a: &'a str,
_b: &'b str,
c: &'c str,
) -> Box<dyn use<'a, /*no 'b,*/ 'c> + '_ + Debug>
where
// ... : 'i, ...
{
Box::new((a, c)) // : Box<(&'a str, &'c str)>
}
fn callsite() -> impl 'static + Debug {
let local = String::from("b");
/* return */ f_dyn("a", &local, "c") // OK because `'b` not `use<..>`d.
}
Well, le me hint you that the answer, which as you may have guessed, will involve:
-
adding some kind of 'intersection lifetime, i.e., some <'i>-introduced lifetime,
-
Using this extra 'i lifetime as the one lifetime annotation inside the returned dyn, in the form of -> Ptr<dyn 'i + ...>
-
And finally, adding the approprisate where ... : 'i kind of bounds. You can either try to come up with the right bounds straight away, or "fail on purpose", e.g., not writing down any bounds, and then letting the compiler suggestions lead you towards the solution
.
For instance, the following snippet yields the following diagnostics:
Click to show the intermediary step
fn f_dyn<'a, 'b, 'c, 'i>(
a: &'a str,
_b: &'b str,
c: &'c str,
) -> Box<dyn 'i + Debug>
where
// ... : 'i, ...
{
Box::new((a, c)) // : Box<(&'a str, &'c str)>
}
yielding:
error: lifetime may not live long enough
--> src/lib.rs:11:5
|
3 | fn f_dyn<'a, 'b, 'c, 'i>(
| -- -- lifetime `'i` defined here
| |
| lifetime `'a` defined here
...
11 | Box::new((a, c)) // : Box<(&'a str, &'c str)>
| ^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'i` but it is returning data with lifetime `'a`
|
= help: consider adding the following bound: `'a: 'i`
error: lifetime may not live long enough
--> src/lib.rs:11:5
|
3 | fn f_dyn<'a, 'b, 'c, 'i>(
| -- -- lifetime `'i` defined here
| |
| lifetime `'c` defined here
...
11 | Box::new((a, c)) // : Box<(&'a str, &'c str)>
| ^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'i` but it is returning data with lifetime `'c`
|
= help: consider adding the following bound: `'c: 'i`
help: the following changes may resolve your lifetime errors
|
= help: add bound `'a: 'i`
= help: add bound `'c: 'i`
Hence the answer:
Spoiler: click here to reveal the answer!
fn f_dyn<'a, 'b, 'c, 'i>(
a: &'a str,
_b: &'b str,
c: &'c str,
) -> Box<dyn 'i + Debug>
where
'a : 'i,
// 'b : 'i not written!
'c : 'i,
{
Box::new((a, c)) // : Box<(&'a str, &'c str)>
}
fn callsite() -> impl 'static + Debug {
let local = String::from("b");
/* return */ f_dyn("a", &local, "c") // OK because `'b` not bounded by `'i`.
}
Going further: quirks of use<...> and how variance interacts with it
TODO