Auto merge of #92123 - m-ou-se:thread-local-cell-methods, r=joshtriplett
Implement RFC 3184 - thread local cell methods This implements [RFC 3184](https://github.com/rust-lang/rfcs/pull/3184), with `@danielhenrymantilla's` [suggestion](https://github.com/rust-lang/rfcs/pull/3184#issuecomment-965773616) for the `with_` method names. Tracking issue: https://github.com/rust-lang/rust/issues/92122
This commit is contained in:
commit
ab2bd41ce0
7 changed files with 490 additions and 71 deletions
|
|
@ -249,6 +249,7 @@
|
|||
#![feature(const_ip)]
|
||||
#![feature(const_ipv4)]
|
||||
#![feature(const_ipv6)]
|
||||
#![feature(const_mut_refs)]
|
||||
#![feature(const_option)]
|
||||
#![feature(const_socketaddr)]
|
||||
#![feature(const_trait_impl)]
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ mod tests;
|
|||
#[cfg(test)]
|
||||
mod dynamic_tests;
|
||||
|
||||
use crate::cell::{Cell, RefCell};
|
||||
use crate::error::Error;
|
||||
use crate::fmt;
|
||||
|
||||
|
|
@ -108,7 +109,7 @@ pub struct LocalKey<T: 'static> {
|
|||
// trivially devirtualizable by LLVM because the value of `inner` never
|
||||
// changes and the constant should be readonly within a crate. This mainly
|
||||
// only runs into problems when TLS statics are exported across crates.
|
||||
inner: unsafe fn() -> Option<&'static T>,
|
||||
inner: unsafe fn(Option<&mut Option<T>>) -> Option<&'static T>,
|
||||
}
|
||||
|
||||
#[stable(feature = "std_debug", since = "1.16.0")]
|
||||
|
|
@ -178,7 +179,9 @@ macro_rules! __thread_local_inner {
|
|||
// used to generate the `LocalKey` value for const-initialized thread locals
|
||||
(@key $t:ty, const $init:expr) => {{
|
||||
#[cfg_attr(not(windows), inline(always))] // see comments below
|
||||
unsafe fn __getit() -> $crate::option::Option<&'static $t> {
|
||||
unsafe fn __getit(
|
||||
_init: $crate::option::Option<&mut $crate::option::Option<$t>>,
|
||||
) -> $crate::option::Option<&'static $t> {
|
||||
const INIT_EXPR: $t = $init;
|
||||
|
||||
// wasm without atomics maps directly to `static mut`, and dtors
|
||||
|
|
@ -260,7 +263,18 @@ macro_rules! __thread_local_inner {
|
|||
static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
|
||||
$crate::thread::__OsLocalKeyInner::new();
|
||||
#[allow(unused_unsafe)]
|
||||
unsafe { __KEY.get(__init) }
|
||||
unsafe {
|
||||
__KEY.get(move || {
|
||||
if let $crate::option::Option::Some(init) = _init {
|
||||
if let $crate::option::Option::Some(value) = init.take() {
|
||||
return value;
|
||||
} else if $crate::cfg!(debug_assertions) {
|
||||
unreachable!("missing initial value");
|
||||
}
|
||||
}
|
||||
__init()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -298,7 +312,9 @@ macro_rules! __thread_local_inner {
|
|||
//
|
||||
// The issue of "should enable on Windows sometimes" is #84933
|
||||
#[cfg_attr(not(windows), inline(always))]
|
||||
unsafe fn __getit() -> $crate::option::Option<&'static $t> {
|
||||
unsafe fn __getit(
|
||||
init: $crate::option::Option<&mut $crate::option::Option<$t>>,
|
||||
) -> $crate::option::Option<&'static $t> {
|
||||
#[cfg(all(target_family = "wasm", not(target_feature = "atomics")))]
|
||||
static __KEY: $crate::thread::__StaticLocalKeyInner<$t> =
|
||||
$crate::thread::__StaticLocalKeyInner::new();
|
||||
|
|
@ -322,7 +338,18 @@ macro_rules! __thread_local_inner {
|
|||
// raise warning for missing/extraneous unsafe blocks anymore.
|
||||
// See https://github.com/rust-lang/rust/issues/74838.
|
||||
#[allow(unused_unsafe)]
|
||||
unsafe { __KEY.get(__init) }
|
||||
unsafe {
|
||||
__KEY.get(move || {
|
||||
if let $crate::option::Option::Some(init) = init {
|
||||
if let $crate::option::Option::Some(value) = init.take() {
|
||||
return value;
|
||||
} else if $crate::cfg!(debug_assertions) {
|
||||
unreachable!("missing default value");
|
||||
}
|
||||
}
|
||||
__init()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
|
|
@ -367,7 +394,9 @@ impl<T: 'static> LocalKey<T> {
|
|||
issue = "none"
|
||||
)]
|
||||
#[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
|
||||
pub const unsafe fn new(inner: unsafe fn() -> Option<&'static T>) -> LocalKey<T> {
|
||||
pub const unsafe fn new(
|
||||
inner: unsafe fn(Option<&mut Option<T>>) -> Option<&'static T>,
|
||||
) -> LocalKey<T> {
|
||||
LocalKey { inner }
|
||||
}
|
||||
|
||||
|
|
@ -409,10 +438,342 @@ impl<T: 'static> LocalKey<T> {
|
|||
F: FnOnce(&T) -> R,
|
||||
{
|
||||
unsafe {
|
||||
let thread_local = (self.inner)().ok_or(AccessError)?;
|
||||
let thread_local = (self.inner)(None).ok_or(AccessError)?;
|
||||
Ok(f(thread_local))
|
||||
}
|
||||
}
|
||||
|
||||
/// Acquires a reference to the value in this TLS key, initializing it with
|
||||
/// `init` if it wasn't already initialized on this thread.
|
||||
///
|
||||
/// If `init` was used to initialize the thread local variable, `None` is
|
||||
/// passed as the first argument to `f`. If it was already initialized,
|
||||
/// `Some(init)` is passed to `f`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if the key currently has its destructor
|
||||
/// running, and it **may** panic if the destructor has previously been run
|
||||
/// for this thread.
|
||||
fn initialize_with<F, R>(&'static self, init: T, f: F) -> R
|
||||
where
|
||||
F: FnOnce(Option<T>, &T) -> R,
|
||||
{
|
||||
unsafe {
|
||||
let mut init = Some(init);
|
||||
let reference = (self.inner)(Some(&mut init)).expect(
|
||||
"cannot access a Thread Local Storage value \
|
||||
during or after destruction",
|
||||
);
|
||||
f(init, reference)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> LocalKey<Cell<T>> {
|
||||
/// Sets or initializes the contained value.
|
||||
///
|
||||
/// Unlike the other methods, this will *not* run the lazy initializer of
|
||||
/// the thread local. Instead, it will be directly initialized with the
|
||||
/// given value if it wasn't initialized yet.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the key currently has its destructor running,
|
||||
/// and it **may** panic if the destructor has previously been run for this thread.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(local_key_cell_methods)]
|
||||
/// use std::cell::Cell;
|
||||
///
|
||||
/// thread_local! {
|
||||
/// static X: Cell<i32> = panic!("!");
|
||||
/// }
|
||||
///
|
||||
/// // Calling X.get() here would result in a panic.
|
||||
///
|
||||
/// X.set(123); // But X.set() is fine, as it skips the initializer above.
|
||||
///
|
||||
/// assert_eq!(X.get(), 123);
|
||||
/// ```
|
||||
#[unstable(feature = "local_key_cell_methods", issue = "92122")]
|
||||
pub fn set(&'static self, value: T) {
|
||||
self.initialize_with(Cell::new(value), |value, cell| {
|
||||
if let Some(value) = value {
|
||||
// The cell was already initialized, so `value` wasn't used to
|
||||
// initialize it. So we overwrite the current value with the
|
||||
// new one instead.
|
||||
cell.set(value.into_inner());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns a copy of the contained value.
|
||||
///
|
||||
/// This will lazily initialize the value if this thread has not referenced
|
||||
/// this key yet.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the key currently has its destructor running,
|
||||
/// and it **may** panic if the destructor has previously been run for this thread.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(local_key_cell_methods)]
|
||||
/// use std::cell::Cell;
|
||||
///
|
||||
/// thread_local! {
|
||||
/// static X: Cell<i32> = Cell::new(1);
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(X.get(), 1);
|
||||
/// ```
|
||||
#[unstable(feature = "local_key_cell_methods", issue = "92122")]
|
||||
pub fn get(&'static self) -> T
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
self.with(|cell| cell.get())
|
||||
}
|
||||
|
||||
/// Takes the contained value, leaving `Default::default()` in its place.
|
||||
///
|
||||
/// This will lazily initialize the value if this thread has not referenced
|
||||
/// this key yet.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the key currently has its destructor running,
|
||||
/// and it **may** panic if the destructor has previously been run for this thread.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(local_key_cell_methods)]
|
||||
/// use std::cell::Cell;
|
||||
///
|
||||
/// thread_local! {
|
||||
/// static X: Cell<Option<i32>> = Cell::new(Some(1));
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(X.take(), Some(1));
|
||||
/// assert_eq!(X.take(), None);
|
||||
/// ```
|
||||
#[unstable(feature = "local_key_cell_methods", issue = "92122")]
|
||||
pub fn take(&'static self) -> T
|
||||
where
|
||||
T: Default,
|
||||
{
|
||||
self.with(|cell| cell.take())
|
||||
}
|
||||
|
||||
/// Replaces the contained value, returning the old value.
|
||||
///
|
||||
/// This will lazily initialize the value if this thread has not referenced
|
||||
/// this key yet.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the key currently has its destructor running,
|
||||
/// and it **may** panic if the destructor has previously been run for this thread.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(local_key_cell_methods)]
|
||||
/// use std::cell::Cell;
|
||||
///
|
||||
/// thread_local! {
|
||||
/// static X: Cell<i32> = Cell::new(1);
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(X.replace(2), 1);
|
||||
/// assert_eq!(X.replace(3), 2);
|
||||
/// ```
|
||||
#[unstable(feature = "local_key_cell_methods", issue = "92122")]
|
||||
pub fn replace(&'static self, value: T) -> T {
|
||||
self.with(|cell| cell.replace(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> LocalKey<RefCell<T>> {
|
||||
/// Acquires a reference to the contained value.
|
||||
///
|
||||
/// This will lazily initialize the value if this thread has not referenced
|
||||
/// this key yet.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the value is currently mutably borrowed.
|
||||
///
|
||||
/// Panics if the key currently has its destructor running,
|
||||
/// and it **may** panic if the destructor has previously been run for this thread.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(local_key_cell_methods)]
|
||||
/// use std::cell::RefCell;
|
||||
///
|
||||
/// thread_local! {
|
||||
/// static X: RefCell<Vec<i32>> = RefCell::new(Vec::new());
|
||||
/// }
|
||||
///
|
||||
/// X.with_borrow(|v| assert!(v.is_empty()));
|
||||
/// ```
|
||||
#[unstable(feature = "local_key_cell_methods", issue = "92122")]
|
||||
pub fn with_borrow<F, R>(&'static self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&T) -> R,
|
||||
{
|
||||
self.with(|cell| f(&cell.borrow()))
|
||||
}
|
||||
|
||||
/// Acquires a mutable reference to the contained value.
|
||||
///
|
||||
/// This will lazily initialize the value if this thread has not referenced
|
||||
/// this key yet.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the value is currently borrowed.
|
||||
///
|
||||
/// Panics if the key currently has its destructor running,
|
||||
/// and it **may** panic if the destructor has previously been run for this thread.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(local_key_cell_methods)]
|
||||
/// use std::cell::RefCell;
|
||||
///
|
||||
/// thread_local! {
|
||||
/// static X: RefCell<Vec<i32>> = RefCell::new(Vec::new());
|
||||
/// }
|
||||
///
|
||||
/// X.with_borrow_mut(|v| v.push(1));
|
||||
///
|
||||
/// X.with_borrow(|v| assert_eq!(*v, vec![1]));
|
||||
/// ```
|
||||
#[unstable(feature = "local_key_cell_methods", issue = "92122")]
|
||||
pub fn with_borrow_mut<F, R>(&'static self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut T) -> R,
|
||||
{
|
||||
self.with(|cell| f(&mut cell.borrow_mut()))
|
||||
}
|
||||
|
||||
/// Sets or initializes the contained value.
|
||||
///
|
||||
/// Unlike the other methods, this will *not* run the lazy initializer of
|
||||
/// the thread local. Instead, it will be directly initialized with the
|
||||
/// given value if it wasn't initialized yet.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the value is currently borrowed.
|
||||
///
|
||||
/// Panics if the key currently has its destructor running,
|
||||
/// and it **may** panic if the destructor has previously been run for this thread.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(local_key_cell_methods)]
|
||||
/// use std::cell::RefCell;
|
||||
///
|
||||
/// thread_local! {
|
||||
/// static X: RefCell<Vec<i32>> = panic!("!");
|
||||
/// }
|
||||
///
|
||||
/// // Calling X.with() here would result in a panic.
|
||||
///
|
||||
/// X.set(vec![1, 2, 3]); // But X.set() is fine, as it skips the initializer above.
|
||||
///
|
||||
/// X.with_borrow(|v| assert_eq!(*v, vec![1, 2, 3]));
|
||||
/// ```
|
||||
#[unstable(feature = "local_key_cell_methods", issue = "92122")]
|
||||
pub fn set(&'static self, value: T) {
|
||||
self.initialize_with(RefCell::new(value), |value, cell| {
|
||||
if let Some(value) = value {
|
||||
// The cell was already initialized, so `value` wasn't used to
|
||||
// initialize it. So we overwrite the current value with the
|
||||
// new one instead.
|
||||
*cell.borrow_mut() = value.into_inner();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Takes the contained value, leaving `Default::default()` in its place.
|
||||
///
|
||||
/// This will lazily initialize the value if this thread has not referenced
|
||||
/// this key yet.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the value is currently borrowed.
|
||||
///
|
||||
/// Panics if the key currently has its destructor running,
|
||||
/// and it **may** panic if the destructor has previously been run for this thread.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(local_key_cell_methods)]
|
||||
/// use std::cell::RefCell;
|
||||
///
|
||||
/// thread_local! {
|
||||
/// static X: RefCell<Vec<i32>> = RefCell::new(Vec::new());
|
||||
/// }
|
||||
///
|
||||
/// X.with_borrow_mut(|v| v.push(1));
|
||||
///
|
||||
/// let a = X.take();
|
||||
///
|
||||
/// assert_eq!(a, vec![1]);
|
||||
///
|
||||
/// X.with_borrow(|v| assert!(v.is_empty()));
|
||||
/// ```
|
||||
#[unstable(feature = "local_key_cell_methods", issue = "92122")]
|
||||
pub fn take(&'static self) -> T
|
||||
where
|
||||
T: Default,
|
||||
{
|
||||
self.with(|cell| cell.take())
|
||||
}
|
||||
|
||||
/// Replaces the contained value, returning the old value.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the value is currently borrowed.
|
||||
///
|
||||
/// Panics if the key currently has its destructor running,
|
||||
/// and it **may** panic if the destructor has previously been run for this thread.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(local_key_cell_methods)]
|
||||
/// use std::cell::RefCell;
|
||||
///
|
||||
/// thread_local! {
|
||||
/// static X: RefCell<Vec<i32>> = RefCell::new(Vec::new());
|
||||
/// }
|
||||
///
|
||||
/// let prev = X.replace(vec![1, 2, 3]);
|
||||
/// assert!(prev.is_empty());
|
||||
///
|
||||
/// X.with_borrow(|v| assert_eq!(*v, vec![1, 2, 3]));
|
||||
/// ```
|
||||
#[unstable(feature = "local_key_cell_methods", issue = "92122")]
|
||||
pub fn replace(&'static self, value: T) -> T {
|
||||
self.with(|cell| cell.replace(value))
|
||||
}
|
||||
}
|
||||
|
||||
mod lazy {
|
||||
|
|
@ -518,7 +879,7 @@ pub mod statik {
|
|||
Key { inner: LazyKeyInner::new() }
|
||||
}
|
||||
|
||||
pub unsafe fn get(&self, init: fn() -> T) -> Option<&'static T> {
|
||||
pub unsafe fn get(&self, init: impl FnOnce() -> T) -> Option<&'static T> {
|
||||
// SAFETY: The caller must ensure no reference is ever handed out to
|
||||
// the inner cell nor mutable reference to the Option<T> inside said
|
||||
// cell. This make it safe to hand a reference, though the lifetime
|
||||
|
|
@ -707,7 +1068,7 @@ pub mod os {
|
|||
|
||||
/// It is a requirement for the caller to ensure that no mutable
|
||||
/// reference is active when this method is called.
|
||||
pub unsafe fn get(&'static self, init: fn() -> T) -> Option<&'static T> {
|
||||
pub unsafe fn get(&'static self, init: impl FnOnce() -> T) -> Option<&'static T> {
|
||||
// SAFETY: See the documentation for this method.
|
||||
let ptr = unsafe { self.os.get() as *mut Value<T> };
|
||||
if ptr as usize > 1 {
|
||||
|
|
@ -725,7 +1086,7 @@ pub mod os {
|
|||
// `try_initialize` is only called once per os thread local variable,
|
||||
// except in corner cases where thread_local dtors reference other
|
||||
// thread_local's, or it is being recursively initialized.
|
||||
unsafe fn try_initialize(&'static self, init: fn() -> T) -> Option<&'static T> {
|
||||
unsafe fn try_initialize(&'static self, init: impl FnOnce() -> T) -> Option<&'static T> {
|
||||
// SAFETY: No mutable references are ever handed out meaning getting
|
||||
// the value is ok.
|
||||
let ptr = unsafe { self.os.get() as *mut Value<T> };
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ thread_local! {
|
|||
//~| ERROR this union takes 2 lifetime arguments but 1 lifetime argument was supplied
|
||||
//~| ERROR this union takes 2 lifetime arguments but 1 lifetime argument was supplied
|
||||
//~| ERROR this union takes 2 lifetime arguments but 1 lifetime argument was supplied
|
||||
//~| ERROR this union takes 2 lifetime arguments but 1 lifetime argument was supplied
|
||||
}
|
||||
thread_local! {
|
||||
static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
|
||||
|
|
@ -52,6 +53,7 @@ thread_local! {
|
|||
//~| ERROR this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
|
||||
//~| ERROR this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
|
||||
//~| ERROR this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
|
||||
//~| ERROR this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
|
||||
//~| ERROR missing lifetime
|
||||
//~| ERROR missing lifetime
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,14 +13,15 @@ LL | static a: RefCell<HashMap<i32, Vec<Vec<Foo<'static, 'static>>>>> = RefC
|
|||
error[E0106]: missing lifetime specifiers
|
||||
--> $DIR/missing-lifetime-specifier.rs:18:44
|
||||
|
|
||||
LL | static a: RefCell<HashMap<i32, Vec<Vec<Foo>>>> = RefCell::new(HashMap::new());
|
||||
| ^^^ expected 2 lifetime parameters
|
||||
LL | / thread_local! {
|
||||
LL | | static a: RefCell<HashMap<i32, Vec<Vec<Foo>>>> = RefCell::new(HashMap::new());
|
||||
| | ^^^ expected 2 lifetime parameters
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_-
|
||||
|
|
||||
= 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
|
||||
|
|
||||
LL | static a: RefCell<HashMap<i32, Vec<Vec<Foo<'static, 'static>>>>> = RefCell::new(HashMap::new());
|
||||
| ~~~~~~~~~~~~~~~~~~~~~
|
||||
= help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/missing-lifetime-specifier.rs:23:44
|
||||
|
|
@ -49,26 +50,32 @@ LL | static b: RefCell<HashMap<i32, Vec<Vec<&Bar<'static, 'static>>>>> = Ref
|
|||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/missing-lifetime-specifier.rs:23:44
|
||||
|
|
||||
LL | static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
|
||||
| ^ expected named lifetime parameter
|
||||
LL | / thread_local! {
|
||||
LL | | static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
|
||||
| | ^ expected named lifetime parameter
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_-
|
||||
|
|
||||
= 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
|
||||
|
|
||||
LL | static b: RefCell<HashMap<i32, Vec<Vec<&'static Bar>>>> = RefCell::new(HashMap::new());
|
||||
| ~~~~~~~~
|
||||
= help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
|
||||
|
||||
error[E0106]: missing lifetime specifiers
|
||||
--> $DIR/missing-lifetime-specifier.rs:23:45
|
||||
|
|
||||
LL | static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
|
||||
| ^^^ expected 2 lifetime parameters
|
||||
LL | / thread_local! {
|
||||
LL | | static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
|
||||
| | ^^^ expected 2 lifetime parameters
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_-
|
||||
|
|
||||
= 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
|
||||
|
|
||||
LL | static b: RefCell<HashMap<i32, Vec<Vec<&Bar<'static, 'static>>>>> = RefCell::new(HashMap::new());
|
||||
| ~~~~~~~~~~~~~~~~~~~~~
|
||||
= help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
|
||||
|
||||
error[E0106]: missing lifetime specifiers
|
||||
--> $DIR/missing-lifetime-specifier.rs:30:48
|
||||
|
|
@ -85,14 +92,15 @@ LL | static c: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> =
|
|||
error[E0106]: missing lifetime specifiers
|
||||
--> $DIR/missing-lifetime-specifier.rs:30:48
|
||||
|
|
||||
LL | static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
|
||||
| ^ expected 2 lifetime parameters
|
||||
LL | / thread_local! {
|
||||
LL | | static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
|
||||
| | ^ expected 2 lifetime parameters
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_-
|
||||
|
|
||||
= 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
|
||||
|
|
||||
LL | static c: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| +++++++++++++++++
|
||||
= help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/missing-lifetime-specifier.rs:35:44
|
||||
|
|
@ -121,26 +129,32 @@ LL | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>>
|
|||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/missing-lifetime-specifier.rs:35:44
|
||||
|
|
||||
LL | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
|
||||
| ^ expected named lifetime parameter
|
||||
LL | / thread_local! {
|
||||
LL | | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
|
||||
| | ^ expected named lifetime parameter
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_-
|
||||
|
|
||||
= 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
|
||||
|
|
||||
LL | static d: RefCell<HashMap<i32, Vec<Vec<&'static Tar<i32>>>>> = RefCell::new(HashMap::new());
|
||||
| ~~~~~~~~
|
||||
= help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
|
||||
|
||||
error[E0106]: missing lifetime specifiers
|
||||
--> $DIR/missing-lifetime-specifier.rs:35:49
|
||||
|
|
||||
LL | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
|
||||
| ^ expected 2 lifetime parameters
|
||||
LL | / thread_local! {
|
||||
LL | | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
|
||||
| | ^ expected 2 lifetime parameters
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_-
|
||||
|
|
||||
= 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
|
||||
|
|
||||
LL | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| +++++++++++++++++
|
||||
= help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
|
||||
|
||||
error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
|
||||
--> $DIR/missing-lifetime-specifier.rs:43:44
|
||||
|
|
@ -196,6 +210,24 @@ help: add missing lifetime argument
|
|||
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'k, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| ++++
|
||||
|
||||
error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
|
||||
--> $DIR/missing-lifetime-specifier.rs:43:44
|
||||
|
|
||||
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| ^^^ ------- supplied 1 lifetime argument
|
||||
| |
|
||||
| expected 2 lifetime arguments
|
||||
|
|
||||
note: union defined here, with 2 lifetime parameters: `'t`, `'k`
|
||||
--> $DIR/missing-lifetime-specifier.rs:11:11
|
||||
|
|
||||
LL | pub union Qux<'t, 'k, I> {
|
||||
| ^^^ -- --
|
||||
help: add missing lifetime argument
|
||||
|
|
||||
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'k, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| ++++
|
||||
|
||||
error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
|
||||
--> $DIR/missing-lifetime-specifier.rs:43:44
|
||||
|
|
||||
|
|
@ -215,7 +247,7 @@ LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, '_, i32>>>>> = RefC
|
|||
| ++++
|
||||
|
||||
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
|
||||
--> $DIR/missing-lifetime-specifier.rs:50:45
|
||||
--> $DIR/missing-lifetime-specifier.rs:51:45
|
||||
|
|
||||
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| ^^^ ------- supplied 1 lifetime argument
|
||||
|
|
@ -233,7 +265,7 @@ LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, '_, i32>>>>> = Ref
|
|||
| ++++
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/missing-lifetime-specifier.rs:50:44
|
||||
--> $DIR/missing-lifetime-specifier.rs:51:44
|
||||
|
|
||||
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| ^ expected named lifetime parameter
|
||||
|
|
@ -245,7 +277,7 @@ LL | static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> =
|
|||
| ~~~~~~~~
|
||||
|
||||
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
|
||||
--> $DIR/missing-lifetime-specifier.rs:50:45
|
||||
--> $DIR/missing-lifetime-specifier.rs:51:45
|
||||
|
|
||||
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| ^^^ ------- supplied 1 lifetime argument
|
||||
|
|
@ -263,19 +295,22 @@ LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'k, i32>>>>> = Ref
|
|||
| ++++
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/missing-lifetime-specifier.rs:50:44
|
||||
--> $DIR/missing-lifetime-specifier.rs:51:44
|
||||
|
|
||||
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| ^ expected named lifetime parameter
|
||||
LL | / thread_local! {
|
||||
LL | | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| | ^ expected named lifetime parameter
|
||||
LL | |
|
||||
LL | |
|
||||
... |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_-
|
||||
|
|
||||
= 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
|
||||
|
|
||||
LL | static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| ~~~~~~~~
|
||||
= help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
|
||||
|
||||
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
|
||||
--> $DIR/missing-lifetime-specifier.rs:50:45
|
||||
--> $DIR/missing-lifetime-specifier.rs:51:45
|
||||
|
|
||||
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| ^^^ ------- supplied 1 lifetime argument
|
||||
|
|
@ -293,7 +328,25 @@ LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'k, i32>>>>> = Ref
|
|||
| ++++
|
||||
|
||||
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
|
||||
--> $DIR/missing-lifetime-specifier.rs:50:45
|
||||
--> $DIR/missing-lifetime-specifier.rs:51:45
|
||||
|
|
||||
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| ^^^ ------- supplied 1 lifetime argument
|
||||
| |
|
||||
| expected 2 lifetime arguments
|
||||
|
|
||||
note: trait defined here, with 2 lifetime parameters: `'t`, `'k`
|
||||
--> $DIR/missing-lifetime-specifier.rs:15:7
|
||||
|
|
||||
LL | trait Tar<'t, 'k, I> {}
|
||||
| ^^^ -- --
|
||||
help: add missing lifetime argument
|
||||
|
|
||||
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'k, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| ++++
|
||||
|
||||
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
|
||||
--> $DIR/missing-lifetime-specifier.rs:51:45
|
||||
|
|
||||
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| ^^^ ------- supplied 1 lifetime argument
|
||||
|
|
@ -310,7 +363,7 @@ help: add missing lifetime argument
|
|||
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, '_, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| ++++
|
||||
|
||||
error: aborting due to 22 previous errors
|
||||
error: aborting due to 24 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0106, E0107.
|
||||
For more information about an error, try `rustc --explain E0106`.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
|
||||
--> $DIR/issue-43733.rs:17:5
|
||||
--> $DIR/issue-43733.rs:19:5
|
||||
|
|
||||
LL | __KEY.get(Default::default)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
||||
|
|
@ -7,7 +7,7 @@ LL | __KEY.get(Default::default)
|
|||
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||
|
||||
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
|
||||
--> $DIR/issue-43733.rs:20:42
|
||||
--> $DIR/issue-43733.rs:22:42
|
||||
|
|
||||
LL | static FOO: std::thread::LocalKey<Foo> = std::thread::LocalKey::new(__getit);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
#![feature(thread_local)]
|
||||
#![feature(cfg_target_thread_local, thread_local_internals)]
|
||||
|
||||
use std::cell::RefCell;
|
||||
|
||||
type Foo = std::cell::RefCell<String>;
|
||||
|
||||
#[cfg(target_thread_local)]
|
||||
|
|
@ -13,7 +15,7 @@ static __KEY: std::thread::__FastLocalKeyInner<Foo> = std::thread::__FastLocalKe
|
|||
#[cfg(not(target_thread_local))]
|
||||
static __KEY: std::thread::__OsLocalKeyInner<Foo> = std::thread::__OsLocalKeyInner::new();
|
||||
|
||||
fn __getit() -> std::option::Option<&'static Foo> {
|
||||
fn __getit(_: Option<&mut Option<RefCell<String>>>) -> std::option::Option<&'static Foo> {
|
||||
__KEY.get(Default::default) //~ ERROR call to unsafe function is unsafe
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
|
||||
--> $DIR/issue-43733.rs:17:5
|
||||
--> $DIR/issue-43733.rs:19:5
|
||||
|
|
||||
LL | __KEY.get(Default::default)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
||||
|
|
@ -7,7 +7,7 @@ LL | __KEY.get(Default::default)
|
|||
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||
|
||||
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
|
||||
--> $DIR/issue-43733.rs:20:42
|
||||
--> $DIR/issue-43733.rs:22:42
|
||||
|
|
||||
LL | static FOO: std::thread::LocalKey<Foo> = std::thread::LocalKey::new(__getit);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue