From 1ac5d7dcde57c3f4baa975d79dbdb57dfdb2489c Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Wed, 10 Nov 2021 10:55:30 -0800
Subject: [PATCH] std: Tweak expansion of thread-local const

This commit tweaks the expansion of `thread_local!` when combined with a
`const { ... }` value to help ensure that the rules which apply to
`const { ... }` blocks will be the same as when they're stabilized.
Previously with this invocation:

    thread_local!(static NAME: Type = const { init_expr });

this would generate (on supporting platforms):

    #[thread_local]
    static NAME: Type = init_expr;

instead the macro now expands to:

    const INIT_EXPR: Type = init_expr;
    #[thread_local]
    static NAME: Type = INIT_EXPR;

with the hope that because `init_expr` is defined as a `const` item then
it's not accidentally allowing more behavior than if it were put into a
`static`. For example on the stabilization issue [this example][ex] now
gives the same error both ways.

[ex]: https://github.com/rust-lang/rust/issues/84223#issuecomment-953384298
---
 library/std/src/thread/local.rs | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index c53290ec0c7..b27db876176 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -165,6 +165,7 @@ macro_rules! __thread_local_inner {
         #[cfg_attr(not(windows), inline)] // see comments below
         unsafe fn __getit() -> $crate::option::Option<&'static $t> {
             const _REQUIRE_UNSTABLE: () = $crate::thread::require_unstable_const_init_thread_local();
+            const INIT_EXPR: $t = $init;
 
             // wasm without atomics maps directly to `static mut`, and dtors
             // aren't implemented because thread dtors aren't really a thing
@@ -174,7 +175,7 @@ macro_rules! __thread_local_inner {
             // block.
             #[cfg(all(target_arch = "wasm32", not(target_feature = "atomics")))]
             {
-                static mut VAL: $t = $init;
+                static mut VAL: $t = INIT_EXPR;
                 Some(&VAL)
             }
 
@@ -184,18 +185,17 @@ macro_rules! __thread_local_inner {
                 not(all(target_arch = "wasm32", not(target_feature = "atomics"))),
             ))]
             {
+                #[thread_local]
+                static mut VAL: $t = INIT_EXPR;
+
                 // If a dtor isn't needed we can do something "very raw" and
                 // just get going.
                 if !$crate::mem::needs_drop::<$t>() {
-                    #[thread_local]
-                    static mut VAL: $t = $init;
                     unsafe {
                         return Some(&VAL)
                     }
                 }
 
-                #[thread_local]
-                static mut VAL: $t = $init;
                 // 0 == dtor not registered
                 // 1 == dtor registered, dtor not run
                 // 2 == dtor registered and is running or has run
@@ -242,7 +242,7 @@ macro_rules! __thread_local_inner {
             ))]
             {
                 #[inline]
-                const fn __init() -> $t { $init }
+                const fn __init() -> $t { INIT_EXPR }
                 static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
                     $crate::thread::__OsLocalKeyInner::new();
                 #[allow(unused_unsafe)]