1
Fork 0

rollup merge of #23557: aturon/rfc-909

This commit implements [RFC 909](https://github.com/rust-lang/rfcs/pull/909):

The `std::thread_local` module is now deprecated, and its contents are
available directly in `std::thread` as `LocalKey`, `LocalKeyState`, and
`ScopedKey`.

The macros remain exactly as they were, which means little if any code
should break. Nevertheless, this is technically a:

[breaking-change]

Closes #23547
This commit is contained in:
Alex Crichton 2015-03-23 15:09:09 -07:00
commit 2153c581ef
5 changed files with 133 additions and 97 deletions

View file

@ -252,30 +252,23 @@ pub mod num;
/* Runtime and platform support */ /* Runtime and platform support */
#[macro_use] #[macro_use]
pub mod thread_local; pub mod thread;
pub mod dynamic_lib;
pub mod ffi;
pub mod old_io;
pub mod io;
pub mod fs;
pub mod net;
pub mod os;
pub mod env;
pub mod path;
pub mod old_path;
pub mod process;
pub mod rand;
pub mod time;
/* Common data structures */
pub mod collections; pub mod collections;
pub mod dynamic_lib;
/* Threads and communication */ pub mod env;
pub mod ffi;
pub mod thread; pub mod fs;
pub mod io;
pub mod net;
pub mod old_io;
pub mod old_path;
pub mod os;
pub mod path;
pub mod process;
pub mod rand;
pub mod sync; pub mod sync;
pub mod time;
#[macro_use] #[macro_use]
#[path = "sys/common/mod.rs"] mod sys_common; #[path = "sys/common/mod.rs"] mod sys_common;
@ -308,7 +301,7 @@ mod std {
pub use rt; // used for panic!() pub use rt; // used for panic!()
pub use vec; // used for vec![] pub use vec; // used for vec![]
pub use cell; // used for tls! pub use cell; // used for tls!
pub use thread_local; // used for thread_local! pub use thread; // used for thread_local!
pub use marker; // used for tls! pub use marker; // used for tls!
pub use ops; // used for bitflags! pub use ops; // used for bitflags!

View file

@ -15,7 +15,7 @@ use core::prelude::*;
use cell::RefCell; use cell::RefCell;
use string::String; use string::String;
use thread::Thread; use thread::Thread;
use thread_local::State; use thread::LocalKeyState;
struct ThreadInfo { struct ThreadInfo {
stack_guard: uint, stack_guard: uint,
@ -26,7 +26,7 @@ thread_local! { static THREAD_INFO: RefCell<Option<ThreadInfo>> = RefCell::new(N
impl ThreadInfo { impl ThreadInfo {
fn with<R, F>(f: F) -> R where F: FnOnce(&mut ThreadInfo) -> R { fn with<R, F>(f: F) -> R where F: FnOnce(&mut ThreadInfo) -> R {
if THREAD_INFO.state() == State::Destroyed { if THREAD_INFO.state() == LocalKeyState::Destroyed {
panic!("Use of std::thread::current() is not possible after \ panic!("Use of std::thread::current() is not possible after \
the thread's local data has been destroyed"); the thread's local data has been destroyed");
} }

View file

@ -9,40 +9,13 @@
// except according to those terms. // except according to those terms.
//! Thread local storage //! Thread local storage
//!
//! This module provides an implementation of thread local storage for Rust
//! programs. Thread local storage is a method of storing data into a global
//! variable which each thread in the program will have its own copy of.
//! Threads do not share this data, so accesses do not need to be synchronized.
//!
//! At a high level, this module provides two variants of storage:
//!
//! * Owning thread local storage. This is a type of thread local key which
//! owns the value that it contains, and will destroy the value when the
//! thread exits. This variant is created with the `thread_local!` macro and
//! can contain any value which is `'static` (no borrowed pointers.
//!
//! * Scoped thread local storage. This type of key is used to store a reference
//! to a value into local storage temporarily for the scope of a function
//! call. There are no restrictions on what types of values can be placed
//! into this key.
//!
//! Both forms of thread local storage provide an accessor function, `with`,
//! which will yield a shared reference to the value to the specified
//! closure. Thread local keys only allow shared access to values as there is no
//! way to guarantee uniqueness if a mutable borrow was allowed. Most values
//! will want to make use of some form of **interior mutability** through the
//! `Cell` or `RefCell` types.
#![stable(feature = "rust1", since = "1.0.0")] #![unstable(feature = "thread_local_internals")]
use prelude::v1::*; use prelude::v1::*;
use cell::UnsafeCell; use cell::UnsafeCell;
#[macro_use]
pub mod scoped;
// Sure wish we had macro hygiene, no? // Sure wish we had macro hygiene, no?
#[doc(hidden)] #[doc(hidden)]
#[unstable(feature = "thread_local_internals")] #[unstable(feature = "thread_local_internals")]
@ -95,7 +68,7 @@ pub mod __impl {
/// }); /// });
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub struct Key<T> { pub struct LocalKey<T> {
// The key itself may be tagged with #[thread_local], and this `Key` is // The key itself may be tagged with #[thread_local], and this `Key` is
// stored as a `static`, and it's not valid for a static to reference the // stored as a `static`, and it's not valid for a static to reference the
// address of another thread_local static. For this reason we kinda wonkily // address of another thread_local static. For this reason we kinda wonkily
@ -114,15 +87,15 @@ pub struct Key<T> {
pub init: fn() -> T, pub init: fn() -> T,
} }
/// Declare a new thread local storage key of type `std::thread_local::Key`. /// Declare a new thread local storage key of type `std::thread::LocalKey`.
#[macro_export] #[macro_export]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable] #[allow_internal_unstable]
macro_rules! thread_local { macro_rules! thread_local {
(static $name:ident: $t:ty = $init:expr) => ( (static $name:ident: $t:ty = $init:expr) => (
static $name: ::std::thread_local::Key<$t> = { static $name: ::std::thread::LocalKey<$t> = {
use std::cell::UnsafeCell as __UnsafeCell; use std::cell::UnsafeCell as __UnsafeCell;
use std::thread_local::__impl::KeyInner as __KeyInner; use std::thread::__local::__impl::KeyInner as __KeyInner;
use std::option::Option as __Option; use std::option::Option as __Option;
use std::option::Option::None as __None; use std::option::Option::None as __None;
@ -133,13 +106,13 @@ macro_rules! thread_local {
fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> { fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
&__KEY &__KEY
} }
::std::thread_local::Key { inner: __getit, init: __init } ::std::thread::LocalKey { inner: __getit, init: __init }
}; };
); );
(pub static $name:ident: $t:ty = $init:expr) => ( (pub static $name:ident: $t:ty = $init:expr) => (
pub static $name: ::std::thread_local::Key<$t> = { pub static $name: ::std::thread::LocalKey<$t> = {
use std::cell::UnsafeCell as __UnsafeCell; use std::cell::UnsafeCell as __UnsafeCell;
use std::thread_local::__impl::KeyInner as __KeyInner; use std::thread::__local::__impl::KeyInner as __KeyInner;
use std::option::Option as __Option; use std::option::Option as __Option;
use std::option::Option::None as __None; use std::option::Option::None as __None;
@ -150,7 +123,7 @@ macro_rules! thread_local {
fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> { fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
&__KEY &__KEY
} }
::std::thread_local::Key { inner: __getit, init: __init } ::std::thread::LocalKey { inner: __getit, init: __init }
}; };
); );
} }
@ -183,20 +156,20 @@ macro_rules! __thread_local_inner {
#[cfg_attr(all(any(target_os = "macos", target_os = "linux"), #[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
not(target_arch = "aarch64")), not(target_arch = "aarch64")),
thread_local)] thread_local)]
static $name: ::std::thread_local::__impl::KeyInner<$t> = static $name: ::std::thread::__local::__impl::KeyInner<$t> =
__thread_local_inner!($init, $t); __thread_local_inner!($init, $t);
); );
(pub static $name:ident: $t:ty = $init:expr) => ( (pub static $name:ident: $t:ty = $init:expr) => (
#[cfg_attr(all(any(target_os = "macos", target_os = "linux"), #[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
not(target_arch = "aarch64")), not(target_arch = "aarch64")),
thread_local)] thread_local)]
pub static $name: ::std::thread_local::__impl::KeyInner<$t> = pub static $name: ::std::thread::__local::__impl::KeyInner<$t> =
__thread_local_inner!($init, $t); __thread_local_inner!($init, $t);
); );
($init:expr, $t:ty) => ({ ($init:expr, $t:ty) => ({
#[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))] #[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
const _INIT: ::std::thread_local::__impl::KeyInner<$t> = { const _INIT: ::std::thread::__local::__impl::KeyInner<$t> = {
::std::thread_local::__impl::KeyInner { ::std::thread::__local::__impl::KeyInner {
inner: ::std::cell::UnsafeCell { value: $init }, inner: ::std::cell::UnsafeCell { value: $init },
dtor_registered: ::std::cell::UnsafeCell { value: false }, dtor_registered: ::std::cell::UnsafeCell { value: false },
dtor_running: ::std::cell::UnsafeCell { value: false }, dtor_running: ::std::cell::UnsafeCell { value: false },
@ -204,15 +177,15 @@ macro_rules! __thread_local_inner {
}; };
#[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))] #[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))]
const _INIT: ::std::thread_local::__impl::KeyInner<$t> = { const _INIT: ::std::thread::__local::__impl::KeyInner<$t> = {
unsafe extern fn __destroy(ptr: *mut u8) { unsafe extern fn __destroy(ptr: *mut u8) {
::std::thread_local::__impl::destroy_value::<$t>(ptr); ::std::thread::__local::__impl::destroy_value::<$t>(ptr);
} }
::std::thread_local::__impl::KeyInner { ::std::thread::__local::__impl::KeyInner {
inner: ::std::cell::UnsafeCell { value: $init }, inner: ::std::cell::UnsafeCell { value: $init },
os: ::std::thread_local::__impl::OsStaticKey { os: ::std::thread::__local::__impl::OsStaticKey {
inner: ::std::thread_local::__impl::OS_INIT_INNER, inner: ::std::thread::__local::__impl::OS_INIT_INNER,
dtor: ::std::option::Option::Some(__destroy as unsafe extern fn(*mut u8)), dtor: ::std::option::Option::Some(__destroy as unsafe extern fn(*mut u8)),
}, },
} }
@ -226,7 +199,7 @@ macro_rules! __thread_local_inner {
#[unstable(feature = "std_misc", #[unstable(feature = "std_misc",
reason = "state querying was recently added")] reason = "state querying was recently added")]
#[derive(Eq, PartialEq, Copy)] #[derive(Eq, PartialEq, Copy)]
pub enum State { pub enum LocalKeyState {
/// All keys are in this state whenever a thread starts. Keys will /// All keys are in this state whenever a thread starts. Keys will
/// transition to the `Valid` state once the first call to `with` happens /// transition to the `Valid` state once the first call to `with` happens
/// and the initialization expression succeeds. /// and the initialization expression succeeds.
@ -253,7 +226,7 @@ pub enum State {
Destroyed, Destroyed,
} }
impl<T: 'static> Key<T> { impl<T: 'static> LocalKey<T> {
/// Acquire a reference to the value in this TLS key. /// Acquire a reference to the value in this TLS key.
/// ///
/// This will lazily initialize the value if this thread has not referenced /// This will lazily initialize the value if this thread has not referenced
@ -309,16 +282,16 @@ impl<T: 'static> Key<T> {
/// any call to `with`. /// any call to `with`.
#[unstable(feature = "std_misc", #[unstable(feature = "std_misc",
reason = "state querying was recently added")] reason = "state querying was recently added")]
pub fn state(&'static self) -> State { pub fn state(&'static self) -> LocalKeyState {
unsafe { unsafe {
match (self.inner)().get() { match (self.inner)().get() {
Some(cell) => { Some(cell) => {
match *cell.get() { match *cell.get() {
Some(..) => State::Valid, Some(..) => LocalKeyState::Valid,
None => State::Uninitialized, None => LocalKeyState::Uninitialized,
} }
} }
None => State::Destroyed, None => LocalKeyState::Destroyed,
} }
} }
} }
@ -327,7 +300,7 @@ impl<T: 'static> Key<T> {
#[unstable(feature = "std_misc")] #[unstable(feature = "std_misc")]
#[deprecated(since = "1.0.0", #[deprecated(since = "1.0.0",
reason = "function renamed to state() and returns more info")] reason = "function renamed to state() and returns more info")]
pub fn destroyed(&'static self) -> bool { self.state() == State::Destroyed } pub fn destroyed(&'static self) -> bool { self.state() == LocalKeyState::Destroyed }
} }
#[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))] #[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
@ -553,7 +526,7 @@ mod tests {
use sync::mpsc::{channel, Sender}; use sync::mpsc::{channel, Sender};
use cell::UnsafeCell; use cell::UnsafeCell;
use super::State; use super::LocalKeyState;
use thread; use thread;
struct Foo(Sender<()>); struct Foo(Sender<()>);
@ -592,21 +565,21 @@ mod tests {
struct Foo; struct Foo;
impl Drop for Foo { impl Drop for Foo {
fn drop(&mut self) { fn drop(&mut self) {
assert!(FOO.state() == State::Destroyed); assert!(FOO.state() == LocalKeyState::Destroyed);
} }
} }
fn foo() -> Foo { fn foo() -> Foo {
assert!(FOO.state() == State::Uninitialized); assert!(FOO.state() == LocalKeyState::Uninitialized);
Foo Foo
} }
thread_local!(static FOO: Foo = foo()); thread_local!(static FOO: Foo = foo());
thread::spawn(|| { thread::spawn(|| {
assert!(FOO.state() == State::Uninitialized); assert!(FOO.state() == LocalKeyState::Uninitialized);
FOO.with(|_| { FOO.with(|_| {
assert!(FOO.state() == State::Valid); assert!(FOO.state() == LocalKeyState::Valid);
}); });
assert!(FOO.state() == State::Valid); assert!(FOO.state() == LocalKeyState::Valid);
}).join().ok().unwrap(); }).join().ok().unwrap();
} }
@ -642,7 +615,7 @@ mod tests {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
HITS += 1; HITS += 1;
if K2.state() == State::Destroyed { if K2.state() == LocalKeyState::Destroyed {
assert_eq!(HITS, 3); assert_eq!(HITS, 3);
} else { } else {
if HITS == 1 { if HITS == 1 {
@ -658,7 +631,7 @@ mod tests {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
HITS += 1; HITS += 1;
assert!(K1.state() != State::Destroyed); assert!(K1.state() != LocalKeyState::Destroyed);
assert_eq!(HITS, 2); assert_eq!(HITS, 2);
K1.with(|s| *s.get() = Some(S1)); K1.with(|s| *s.get() = Some(S1));
} }
@ -679,7 +652,7 @@ mod tests {
impl Drop for S1 { impl Drop for S1 {
fn drop(&mut self) { fn drop(&mut self) {
assert!(K1.state() == State::Destroyed); assert!(K1.state() == LocalKeyState::Destroyed);
} }
} }
@ -702,7 +675,7 @@ mod tests {
fn drop(&mut self) { fn drop(&mut self) {
let S1(ref tx) = *self; let S1(ref tx) = *self;
unsafe { unsafe {
if K2.state() != State::Destroyed { if K2.state() != LocalKeyState::Destroyed {
K2.with(|s| *s.get() = Some(Foo(tx.clone()))); K2.with(|s| *s.get() = Some(Foo(tx.clone())));
} }
} }

View file

@ -138,9 +138,43 @@
//! synchronization primitives; the threads already provide basic blocking/signaling. //! synchronization primitives; the threads already provide basic blocking/signaling.
//! //!
//! * It can be implemented very efficiently on many platforms. //! * It can be implemented very efficiently on many platforms.
//!
//! ## Thread-local storage
//!
//! This module also provides an implementation of thread local storage for Rust
//! programs. Thread local storage is a method of storing data into a global
//! variable which each thread in the program will have its own copy of.
//! Threads do not share this data, so accesses do not need to be synchronized.
//!
//! At a high level, this module provides two variants of storage:
//!
//! * Owned thread-local storage. This is a type of thread local key which
//! owns the value that it contains, and will destroy the value when the
//! thread exits. This variant is created with the `thread_local!` macro and
//! can contain any value which is `'static` (no borrowed pointers).
//!
//! * Scoped thread-local storage. This type of key is used to store a reference
//! to a value into local storage temporarily for the scope of a function
//! call. There are no restrictions on what types of values can be placed
//! into this key.
//!
//! Both forms of thread local storage provide an accessor function, `with`,
//! which will yield a shared reference to the value to the specified
//! closure. Thread-local keys only allow shared access to values as there is no
//! way to guarantee uniqueness if a mutable borrow was allowed. Most values
//! will want to make use of some form of **interior mutability** through the
//! `Cell` or `RefCell` types.
#![stable(feature = "rust1", since = "1.0.0")] #![stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::__local::{LocalKey, LocalKeyState};
#[unstable(feature = "scoped_tls",
reason = "scoped TLS has yet to have wide enough use to fully consider \
stabilizing its interface")]
pub use self::__scoped::ScopedKey;
use prelude::v1::*; use prelude::v1::*;
use any::Any; use any::Any;
@ -157,6 +191,22 @@ use time::Duration;
#[allow(deprecated)] use old_io::Writer; #[allow(deprecated)] use old_io::Writer;
////////////////////////////////////////////////////////////////////////////////
// Thread-local storage
////////////////////////////////////////////////////////////////////////////////
#[macro_use]
#[doc(hidden)]
#[path = "local.rs"] pub mod __local;
#[macro_use]
#[doc(hidden)]
#[path = "scoped.rs"] pub mod __scoped;
////////////////////////////////////////////////////////////////////////////////
// Builder
////////////////////////////////////////////////////////////////////////////////
/// Thread configuration. Provides detailed control over the properties /// Thread configuration. Provides detailed control over the properties
/// and behavior of new threads. /// and behavior of new threads.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
@ -322,6 +372,10 @@ impl Builder {
} }
} }
////////////////////////////////////////////////////////////////////////////////
// Free functions
////////////////////////////////////////////////////////////////////////////////
/// Spawn a new thread, returning a `JoinHandle` for it. /// Spawn a new thread, returning a `JoinHandle` for it.
/// ///
/// The join handle will implicitly *detach* the child thread upon being /// The join handle will implicitly *detach* the child thread upon being
@ -433,6 +487,10 @@ pub fn park_timeout(duration: Duration) {
*guard = false; *guard = false;
} }
////////////////////////////////////////////////////////////////////////////////
// Thread
////////////////////////////////////////////////////////////////////////////////
/// The internal representation of a `Thread` handle /// The internal representation of a `Thread` handle
struct Inner { struct Inner {
name: Option<String>, name: Option<String>,
@ -557,6 +615,10 @@ impl thread_info::NewThread for Thread {
fn new(name: Option<String>) -> Thread { Thread::new(name) } fn new(name: Option<String>) -> Thread { Thread::new(name) }
} }
////////////////////////////////////////////////////////////////////////////////
// JoinHandle and JoinGuard
////////////////////////////////////////////////////////////////////////////////
/// Indicates the manner in which a thread exited. /// Indicates the manner in which a thread exited.
/// ///
/// A thread that completes without panicking is considered to exit successfully. /// A thread that completes without panicking is considered to exit successfully.
@ -689,6 +751,10 @@ impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> {
} }
} }
////////////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////////////
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use prelude::v1::*; use prelude::v1::*;

View file

@ -38,9 +38,7 @@
//! }); //! });
//! ``` //! ```
#![unstable(feature = "std_misc", #![unstable(feature = "thread_local_internals")]
reason = "scoped TLS has yet to have wide enough use to fully consider \
stabilizing its interface")]
use prelude::v1::*; use prelude::v1::*;
@ -58,7 +56,10 @@ pub mod __impl {
/// type `T` scoped to a particular lifetime. Keys provides two methods, `set` /// type `T` scoped to a particular lifetime. Keys provides two methods, `set`
/// and `with`, both of which currently use closures to control the scope of /// and `with`, both of which currently use closures to control the scope of
/// their contents. /// their contents.
pub struct Key<T> { #[doc(hidden)] pub inner: __impl::KeyInner<T> } #[unstable(feature = "scoped_tls",
reason = "scoped TLS has yet to have wide enough use to fully consider \
stabilizing its interface")]
pub struct ScopedKey<T> { #[doc(hidden)] pub inner: __impl::KeyInner<T> }
/// Declare a new scoped thread local storage key. /// Declare a new scoped thread local storage key.
/// ///
@ -86,7 +87,7 @@ macro_rules! __scoped_thread_local_inner {
target_os = "openbsd", target_os = "openbsd",
target_arch = "aarch64")), target_arch = "aarch64")),
thread_local)] thread_local)]
static $name: ::std::thread_local::scoped::Key<$t> = static $name: ::std::thread::ScopedKey<$t> =
__scoped_thread_local_inner!($t); __scoped_thread_local_inner!($t);
); );
(pub static $name:ident: $t:ty) => ( (pub static $name:ident: $t:ty) => (
@ -96,11 +97,11 @@ macro_rules! __scoped_thread_local_inner {
target_os = "openbsd", target_os = "openbsd",
target_arch = "aarch64")), target_arch = "aarch64")),
thread_local)] thread_local)]
pub static $name: ::std::thread_local::scoped::Key<$t> = pub static $name: ::std::thread::ScopedKey<$t> =
__scoped_thread_local_inner!($t); __scoped_thread_local_inner!($t);
); );
($t:ty) => ({ ($t:ty) => ({
use std::thread_local::scoped::Key as __Key; use std::thread::ScopedKey as __Key;
#[cfg(not(any(windows, #[cfg(not(any(windows,
target_os = "android", target_os = "android",
@ -108,7 +109,7 @@ macro_rules! __scoped_thread_local_inner {
target_os = "openbsd", target_os = "openbsd",
target_arch = "aarch64")))] target_arch = "aarch64")))]
const _INIT: __Key<$t> = __Key { const _INIT: __Key<$t> = __Key {
inner: ::std::thread_local::scoped::__impl::KeyInner { inner: ::std::thread::__scoped::__impl::KeyInner {
inner: ::std::cell::UnsafeCell { value: 0 as *mut _ }, inner: ::std::cell::UnsafeCell { value: 0 as *mut _ },
} }
}; };
@ -119,8 +120,8 @@ macro_rules! __scoped_thread_local_inner {
target_os = "openbsd", target_os = "openbsd",
target_arch = "aarch64"))] target_arch = "aarch64"))]
const _INIT: __Key<$t> = __Key { const _INIT: __Key<$t> = __Key {
inner: ::std::thread_local::scoped::__impl::KeyInner { inner: ::std::thread::__scoped::__impl::KeyInner {
inner: ::std::thread_local::scoped::__impl::OS_INIT, inner: ::std::thread::__scoped::__impl::OS_INIT,
marker: ::std::marker::PhantomData::<::std::cell::Cell<$t>>, marker: ::std::marker::PhantomData::<::std::cell::Cell<$t>>,
} }
}; };
@ -129,7 +130,10 @@ macro_rules! __scoped_thread_local_inner {
}) })
} }
impl<T> Key<T> { #[unstable(feature = "scoped_tls",
reason = "scoped TLS has yet to have wide enough use to fully consider \
stabilizing its interface")]
impl<T> ScopedKey<T> {
/// Insert a value into this scoped thread local storage slot for a /// Insert a value into this scoped thread local storage slot for a
/// duration of a closure. /// duration of a closure.
/// ///