Skip to content

Tracking issue for future-incompatibility lint elided_lifetimes_in_associated_constant #115010

Closed

Description

@compiler-errors

This is a tracking issue for the elided_lifetimes_in_associated_constant future-incompatibility lint.

The goal of this page is describe why this change was made and how you can fix code that is affected by it. It also provides a place to ask questions or register a complaint if you feel the change should not be made. For more information on the policy around future-compatibility warnings, see our breaking change policy guidelines.

What

The elided_lifetimes_in_associated_constant lint detects elided lifetimes that became erroneously allowed in associated constants after #97313.

struct Foo<'f>(&'f ());
impl Foo<'_> {
    const STR: &str = "hello, world";
}

They current desugar to fresh early-bound lifetimes on the parent impl, like:

struct Foo<'f>(&'f ());
impl<'__a> Foo<'_> {
    const STR: &'__a str = "hello, world";
}

This is in contrast to the way that elided lifetimes are treated in item-level consts (where elided lifetimes are resolved to 'static), and this behavior was also never formally decided -- static-in-const lifetime rules do not apply to associated consts (rust-lang/rfcs#1623 (comment), #38831 (comment)).

Why

It was never decided what to do with elided lifetimes in consts, and it is not clear that the current behavior is optimal here. This is to stop the leaking by making sure existing elided lifetimes are fixed back to using 'static as they were required to before version 1.64, and that new usages of elided lifetimes in consts are not introduced.

How to fix

Replace the elided lifetimes with 'static (or manually introduce or reference another lifetime):

struct Foo;
impl Foo {
    const STR: &'static str = "hello, world";
}

Tracking

Activity

  1. added
    C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFC
    on Aug 19, 2023
  2. jonathanstrong commented on Aug 23, 2023

    @jonathanstrong

    I'm old enough to remember when clippy used to nag me to change &'static str to &str for consts. Ugh.

  3. tgross35 commented on Aug 24, 2023

    @tgross35
    Member

    Is it possible to loosen the implicit lifetime to 'static lifetime for literals at least? This change is kind of churny and doesn't really seem to align with expected behavior.

  4. compiler-errors commented on Aug 24, 2023

    @compiler-errors
    ContributorAuthor

    @tgross35: that's behavior that @rust-lang/lang needs to stabilize separately. I'll nominate this issue to see if opinions have changed since #38831, but this lint is specifically aimed at making sure people are not relying on behavior that was never formally stabilized.

    Question for T-lang: What should we do here?

    • A. Continue with this lint, accepting churn, with the possibility of relaxing this (i.e. resolving '_ to 'static in associated consts) in the future
    • B. Fast-track stabilization of this extension to static-lifetimes-in-const (RFC 1623), and revert this lint before it makes its way to stable (1.74, so we have approx. 12 weeks to decide as of 2023/08/24)
    • C. Some other compromise in the middle, e.g. stabilizing the static-lifetime elision rule when some other condition is true (i.e. the self type has no other lifetimes)
    • D. Something else :^)
  5. repi commented on Aug 29, 2023

    @repi

    The clippy warn-by-default lint redundant_static_lifetimes conflicts with this warning with latest nightly, so users would have to disable one or the other which is unfortunate.

  6. compiler-errors commented on Aug 29, 2023

    @compiler-errors
    ContributorAuthor

    @repi: The redundant_static_lifetimes lint does not trigger on associated consts:

    if let ItemKind::Const(box ConstItem { ty: ref var_type, .. }) = item.kind {
    Self::visit_type(var_type, cx, "constants have by default a `'static` lifetime");
    // Don't check associated consts because `'static` cannot be elided on those (issue
    // #2438)
    }
    (and should have been fixed since rust-lang/rust-clippy#2443)

    https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=a3f5fbfff746ad971f4ca458633990e6

    Can you share code where you encountered a conflict between this future-compat warning and the clippy lint?

  7. repi commented on Aug 29, 2023

    @repi

    dug a bit deeper and I was wrong, this clippy lint indeed doesn't trigger on associated consts. sorry.

    was able to resolve all of our lint warnings on this without clippy::redundant_static_lifetimes triggering.

  8. compiler-errors commented on Aug 31, 2023

    @compiler-errors
    ContributorAuthor

    Lang team consensus is that we should go with (A.) above:

    A. Continue with this lint, accepting churn, with the possibility of relaxing this (i.e. resolving '_ to 'static in associated consts) in the future

    Since this was inadvertently stabilized and a separate RFC would need to be authored if it's desired to make elision work in associated consts.

    See notes here: https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Triage.20meeting.202023-08-29/near/388257641

  9. QuineDot commented on Sep 1, 2023

    @QuineDot

    Heads up: This lint as currently written accepts code that is not accepted in Rust 1.72 (nor 1.63).

    From 1.64 to current stable, anonymous lifetimes were allowed, but they weren't specifically 'static; instead, each one was independent. The independent-ness caused things like nested elided lifetimes and ambiguous trait bounds for trait objects to fail.

    Under the change which accompanied this lint, elided lifetimes are no longer independent, they are specifically 'static. This allows more things to compile.

    Example (Rust 1.63 fails; Rust 1.72 fails; nightly succeeds):

    struct S;
    impl S {
        const C: &&str = &"";
    }

    Perhaps this will be considered fine since the lint is supposedly going to be deny, but I thought I should mention it. If the lint doesn't go the way you anticipate, you may be unwittingly opting into a specific behavior ('static).

    The change also means that contravariant cases that worked from 1.64-1.72 fail on nightly:

    struct Contra<'a>(PhantomData<fn(&'a str)>);
    
    struct S;
    impl S {
        const C: Contra<'_> = Contra(PhantomData);
    }
    
    fn f<'a>() {
        let _: Contra<'a> = S::C;
    }

    But probably that's not ecosystem-breaking like the covariant case is.


    More examples that probably add nothing

    The last three examples in this section (before "impl Headers") don't compile in Rust 1.63 (prior to #97313 landing) due to the use of '_. The first example compiles from 1.64 to current stable, but the second two examples did not. All three compile on nightly (with this lint).


    This example fails on 1.63 due to the '_ in dyn Single<'_>. It compiles on 1.72.

    use core::marker::PhantomData;
    trait Single<'a>: 'a + Send + Sync {}
    struct L<'l, 'm>(&'l str, &'m str);
    impl<'a, 'b> L<'a, 'b> {
        const ECS: PhantomData<Box<dyn Single<'_>>> = PhantomData;
        const SCS: PhantomData<Box<dyn Single<'static>>> = PhantomData;
    
        const S_ECS: PhantomData<Box<dyn Single<'static> + 'static>> = Self::ECS;
        const S_SCS: PhantomData<Box<dyn Single<'static> + 'static>> = Self::SCS;
    }

    This example fails on 1.63 due to the '_ in dyn Double<'a, '_>. It fails on 1.72 because it considers the elided trait object lifetime ambiguous in the face of two independent lifetimes.

    use core::marker::PhantomData;
    trait Double<'a, 'b>: 'a + 'b + Send + Sync {}
    struct L<'l, 'm>(&'l str, &'m str);
    impl<'a, 'b> L<'a, 'b> {
        const EBCD: PhantomData<Box<dyn Double<'a, '_>>> = PhantomData;
    }

    This example fails on 1.63 due to the use of '_ and eliding & lifetimes. It fails on 1.72 because some of the anonymous lifetimes aren't considered to be implicitly longer than the reference lifetime. (N.b. the spans are also broken in the error. Comment out the ECS case to see better spans on the RECS case.)

    use core::marker::PhantomData;
    trait Single<'a>: 'a + Send + Sync {}
    struct R<'l, 'm, 'r>(&'l str, &'m str, &'r ());
    impl<'a, 'b, 'r> R<'a, 'b, 'r> where 'a: 'r, 'b: 'r {
        const ECS: PhantomData<&dyn Single<'_>> = PhantomData;
        const RECS: PhantomData<&'r dyn Single<'_>> = PhantomData;
    }
  10. compiler-errors commented on Sep 1, 2023

    @compiler-errors
    ContributorAuthor

    @QuineDot: thanks for the comment.

    Yeah, I'm aware of this, and chose to lower to 'static to avoid additional errors like #114706, but yeah, perhaps we shouldn't allow this. I'll modify the warning code to continue to lower to fresh lifetimes to preserve 1.64-1.73 behavior behind the warning.

  11. added a commit that references this issue on Sep 2, 2023
  12. 62 remaining items

  13. added
    A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.
    and removed
    A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.
    on Dec 21, 2024
  14. ensc commented on Jan 20, 2025

    @ensc

    What is the state of this issue? rust stopped to warn about it somewhere between 1.80 and 1.84, and afair there were clippy warnings in some nightly versions which caused me to remove all the 'static annotations.

  15. dtolnay commented on Jan 20, 2025

    @dtolnay
    Member

    This code stopped triggering the future incompatibility lint after #125258:

    struct Struct;
    impl Struct {
        const S: &str = "";
    }

    It continues to be triggered for this code:

    struct Struct<'a>(&'a ());
    impl Struct<'_> {
        const S: &str = "";
    }

    As well as this code:

    struct Struct;
    impl<'a> Struct {
        const S: &str = "";
    }
  16. added 2 commits that reference this issue on Jul 9, 2026
    c793d50
    ca03087
  17. added 2 commits that reference this issue on Jul 9, 2026
    61c40bb
    fa275b1
  18. added a commit that references this issue on Jul 10, 2026
    eebb7ed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-associated-itemsArea: Associated items (types, constants & functions)A-lifetimesArea: Lifetimes / regionsA-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.C-future-incompatibilityCategory: Future-incompatibility lintsC-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions