rust-lang / rust-lang/rust

Inconsistent lifetime elision for `thread_local!`

Open
#159,640 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-lifetimes A-macros A-thread-locals C-bug T-lang T-libs
Dominant language
Rust
Stars
119k
Forks
16.2k
PR merge metrics
PR metrics pending

Description

I tried this code:

thread_local! {
    static WORKS: &i32 = const { &1 };
}

thread_local! {
    static FAILS: &i32 = &1;
}

I expected the thread-locals to either both compile or both fail to compile. Instead, only WORKS compiles, and FAILS doesn't:

error[E0106]: missing lifetime specifier
 --> src/lib.rs:6:19
  |
6 |     static FAILS: &i32 = &1;
  |                   ^ 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, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
  |
6 |     static FAILS: &'static i32 = &1;
  |                    +++++++
help: instead, you are more likely to want to return an owned value
  |
6 -     static FAILS: &i32 = &1;
6 +     static FAILS: i32 = &1;
  |

For more information about this error, try `rustc --explain E0106`.

The difference is that the WORKS expands into a const item of type &i32, while FAILS expands into a function item that returns type &i32. The former is legal lifetime elision, but the latter is not.

Meta

Reproducible on the playground with version 1.99.0-nightly (2026-07-20 87e5904f5eb6398af6b2)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the expansion of the thread_local! macro, comparing the generated const item and function item that handle &i32. Reproduce the mismatch and add coverage establishing consistent lifetime-elision behavior for both forms; done means the supplied example no longer has divergent results.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.