Skip to content

thread_local! has some shadowing issues #147006

@Jules-Bertholet

Description

@Jules-Bertholet

I tried this code:

fn __init() -> u32 {
    17
}
const __INIT: u32 = 17;
const VAL: usize = 0;

thread_local! {
    static FOO: u32 = __init();
    static BAR: u32 = const { __INIT };
    static BAZ: [u32; VAL] = const { [] };
}

fn main() {
    FOO.with(|&s| assert_eq!(s, 17));
    BAR.with(|&s| assert_eq!(s, 17));
    BAZ.with(|&s| assert_eq!(s, []));
}

I expected to see this happen: It compiles and runs successfully

Instead, this happened: A bunch of compile errors. If BAR and BAZ are commented out, initializing FOO triggers a stack overflow.

The cause of these issues is shadowing inside thread_local_inner!. rustc_macro_transparency = "opaque" should fix it, but is blocked on fixing #146993.

Meta

rustc --version:

1.92.0-nightly (2025-09-23 975e6c8fec280816d24f)
Backtrace

error[E0391]: cycle detected when computing type of `BAZ::{constant#1}::{closure#0}::VAL`
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
   |
note: ...which requires evaluating type-level constant...
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
note: ...which requires const-evaluating + checking `BAZ::{constant#1}::{closure#0}::VAL::{constant#0}`...
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
note: ...which requires caching mir of `BAZ::{constant#1}::{closure#0}::VAL::{constant#0}` for CTFE...
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
note: ...which requires elaborating drops for `BAZ::{constant#1}::{closure#0}::VAL::{constant#0}`...
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
note: ...which requires borrow-checking `BAZ::{constant#1}::{closure#0}::VAL::{constant#0}`...
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
note: ...which requires promoting constants in MIR for `BAZ::{constant#1}::{closure#0}::VAL::{constant#0}`...
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
note: ...which requires const checking `BAZ::{constant#1}::{closure#0}::VAL::{constant#0}`...
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
note: ...which requires building MIR for `BAZ::{constant#1}::{closure#0}::VAL::{constant#0}`...
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
note: ...which requires match-checking `BAZ::{constant#1}::{closure#0}::VAL::{constant#0}`...
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
note: ...which requires type-checking `BAZ::{constant#1}::{closure#0}::VAL::{constant#0}`...
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
   = note: ...which again requires computing type of `BAZ::{constant#1}::{closure#0}::VAL`, completing the cycle
note: cycle used when checking that `BAZ::{constant#1}::{closure#0}::VAL` is well-formed
  --> src/main.rs:7:1
   |
 7 | / thread_local! {
 8 | |     static FOO: u32 = __init();
 9 | |     static BAR: u32 = const { __INIT };
10 | |     static BAZ: [u32; VAL] = const { [] };
11 | | }
   | |_^
   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
   = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0391]: cycle detected when computing type of `BAZ::{constant#1}::{closure#1}::VAL`
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
   |
note: ...which requires evaluating type-level constant...
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
note: ...which requires const-evaluating + checking `BAZ::{constant#1}::{closure#1}::VAL::{constant#0}`...
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
note: ...which requires caching mir of `BAZ::{constant#1}::{closure#1}::VAL::{constant#0}` for CTFE...
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
note: ...which requires elaborating drops for `BAZ::{constant#1}::{closure#1}::VAL::{constant#0}`...
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
note: ...which requires borrow-checking `BAZ::{constant#1}::{closure#1}::VAL::{constant#0}`...
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
note: ...which requires promoting constants in MIR for `BAZ::{constant#1}::{closure#1}::VAL::{constant#0}`...
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
note: ...which requires const checking `BAZ::{constant#1}::{closure#1}::VAL::{constant#0}`...
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
note: ...which requires building MIR for `BAZ::{constant#1}::{closure#1}::VAL::{constant#0}`...
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
note: ...which requires match-checking `BAZ::{constant#1}::{closure#1}::VAL::{constant#0}`...
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
note: ...which requires type-checking `BAZ::{constant#1}::{closure#1}::VAL::{constant#0}`...
  --> src/main.rs:10:23
   |
10 |     static BAZ: [u32; VAL] = const { [] };
   |                       ^^^
   = note: ...which again requires computing type of `BAZ::{constant#1}::{closure#1}::VAL`, completing the cycle
note: cycle used when checking that `BAZ::{constant#1}::{closure#1}::VAL` is well-formed
  --> src/main.rs:7:1
   |
 7 | / thread_local! {
 8 | |     static FOO: u32 = __init();
 9 | |     static BAR: u32 = const { __INIT };
10 | |     static BAZ: [u32; VAL] = const { [] };
11 | | }
   | |_^
   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
   = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0391]: cycle detected when simplifying constant for the type system `BAR::__INIT`
  --> src/main.rs:7:1
   |
 7 | / thread_local! {
 8 | |     static FOO: u32 = __init();
 9 | |     static BAR: u32 = const { __INIT };
10 | |     static BAZ: [u32; VAL] = const { [] };
11 | | }
   | |_^
   |
note: ...which requires const-evaluating + checking `BAR::__INIT`...
  --> src/main.rs:9:31
   |
 9 |     static BAR: u32 = const { __INIT };
   |                               ^^^^^^
   = note: ...which again requires simplifying constant for the type system `BAR::__INIT`, completing the cycle
   = note: cycle used when running analysis passes on this crate
   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
   = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)

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

@rustbot label T-libs A-macros A-thread-locals A-hygiene

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-hygieneArea: Macro hygieneA-macrosArea: All kinds of macros (custom derive, macro_rules!, proc macros, ..)A-thread-localsArea: Thread local storage (TLS)C-bugCategory: This is a bug.T-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions