diff options
| author | bors <bors@rust-lang.org> | 2024-06-04 05:03:52 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-06-04 05:03:52 +0000 |
| commit | 27529d5c2526eab5aa03d765426c44ea55c5d269 (patch) | |
| tree | 5fdf6463de4aabd0023eaf2507a64e90f6e4886b | |
| parent | 90d6255d82dcfd0b73dbaa4f172a7f9886dcc2c1 (diff) | |
| parent | 6df8d0dd4e05cd96fbc299fa5fc32f37ad936db0 (diff) | |
| download | rust-27529d5c2526eab5aa03d765426c44ea55c5d269.tar.gz rust-27529d5c2526eab5aa03d765426c44ea55c5d269.zip | |
Auto merge of #125525 - joboet:tls_accessor, r=cuviper
Make TLS accessors closures that return pointers The current TLS macros generate a function that returns an `Option<&'static T>`. This is both risky as we lie about lifetimes, and necessitates that those functions are `unsafe`. By returning a `*const T` instead, the accessor function do not have safety requirements any longer and can be made closures without hassle. This PR does exactly that! For native TLS, the closure approach makes it trivial to select the right accessor function at compile-time, which could result in a slight speed-up (I have the hope that the accessors are now simple enough for the MIR-inliner to kick in).
| -rw-r--r-- | library/std/src/sys/thread_local/fast_local/eager.rs | 34 | ||||
| -rw-r--r-- | library/std/src/sys/thread_local/fast_local/lazy.rs | 46 | ||||
| -rw-r--r-- | library/std/src/sys/thread_local/fast_local/mod.rs | 79 | ||||
| -rw-r--r-- | library/std/src/sys/thread_local/os_local.rs | 63 | ||||
| -rw-r--r-- | library/std/src/sys/thread_local/static_local.rs | 53 | ||||
| -rw-r--r-- | library/std/src/thread/local.rs | 12 | ||||
| -rw-r--r-- | tests/ui/suggestions/missing-lifetime-specifier.rs | 22 | ||||
| -rw-r--r-- | tests/ui/suggestions/missing-lifetime-specifier.stderr | 90 |
8 files changed, 128 insertions, 271 deletions
diff --git a/library/std/src/sys/thread_local/fast_local/eager.rs b/library/std/src/sys/thread_local/fast_local/eager.rs index c2bc580530b..b97bd9cc88c 100644 --- a/library/std/src/sys/thread_local/fast_local/eager.rs +++ b/library/std/src/sys/thread_local/fast_local/eager.rs @@ -21,43 +21,35 @@ impl<T> Storage<T> { Storage { state: Cell::new(State::Initial), val: UnsafeCell::new(val) } } - /// Get a reference to the TLS value. If the TLS variable has been destroyed, - /// `None` is returned. + /// Get a pointer to the TLS value. If the TLS variable has been destroyed, + /// a null pointer is returned. /// - /// # Safety - /// * The `self` reference must remain valid until the TLS destructor has been - /// run. - /// * The returned reference may only be used until thread destruction occurs - /// and may not be used after reentrant initialization has occurred. + /// The resulting pointer may not be used after thread destruction has + /// occurred. /// - // FIXME(#110897): return NonNull instead of lying about the lifetime. + /// # Safety + /// The `self` reference must remain valid until the TLS destructor is run. #[inline] - pub unsafe fn get(&self) -> Option<&'static T> { + pub unsafe fn get(&self) -> *const T { match self.state.get() { - // SAFETY: as the state is not `Destroyed`, the value cannot have - // been destroyed yet. The reference fulfills the terms outlined - // above. - State::Alive => unsafe { Some(&*self.val.get()) }, - State::Destroyed => None, + State::Alive => self.val.get(), + State::Destroyed => ptr::null(), State::Initial => unsafe { self.initialize() }, } } #[cold] - unsafe fn initialize(&self) -> Option<&'static T> { + unsafe fn initialize(&self) -> *const T { // Register the destructor // SAFETY: - // * the destructor will be called at thread destruction. - // * the caller guarantees that `self` will be valid until that time. + // The caller guarantees that `self` will be valid until thread destruction. unsafe { register_dtor(ptr::from_ref(self).cast_mut().cast(), destroy::<T>); } + self.state.set(State::Alive); - // SAFETY: as the state is not `Destroyed`, the value cannot have - // been destroyed yet. The reference fulfills the terms outlined - // above. - unsafe { Some(&*self.val.get()) } + self.val.get() } } diff --git a/library/std/src/sys/thread_local/fast_local/lazy.rs b/library/std/src/sys/thread_local/fast_local/lazy.rs index c2e9a171454..c1ada35d484 100644 --- a/library/std/src/sys/thread_local/fast_local/lazy.rs +++ b/library/std/src/sys/thread_local/fast_local/lazy.rs @@ -39,49 +39,31 @@ where Storage { state: UnsafeCell::new(State::Initial) } } - /// Get a reference to the TLS value, potentially initializing it with the - /// provided parameters. If the TLS variable has been destroyed, `None` is - /// returned. + /// Get a pointer to the TLS value, potentially initializing it with the + /// provided parameters. If the TLS variable has been destroyed, a null + /// pointer is returned. /// - /// # Safety - /// * The `self` reference must remain valid until the TLS destructor is run, - /// at which point the returned reference is invalidated. - /// * The returned reference may only be used until thread destruction occurs - /// and may not be used after reentrant initialization has occurred. + /// The resulting pointer may not be used after reentrant inialialization + /// or thread destruction has occurred. /// - // FIXME(#110897): return NonNull instead of lying about the lifetime. + /// # Safety + /// The `self` reference must remain valid until the TLS destructor is run. #[inline] - pub unsafe fn get_or_init( - &self, - i: Option<&mut Option<T>>, - f: impl FnOnce() -> T, - ) -> Option<&'static T> { - // SAFETY: - // No mutable reference to the inner value exists outside the calls to - // `replace`. The lifetime of the returned reference fulfills the terms - // outlined above. + pub unsafe fn get_or_init(&self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T { let state = unsafe { &*self.state.get() }; match state { - State::Alive(v) => Some(v), - State::Destroyed(_) => None, + State::Alive(v) => v, + State::Destroyed(_) => ptr::null(), State::Initial => unsafe { self.initialize(i, f) }, } } #[cold] - unsafe fn initialize( - &self, - i: Option<&mut Option<T>>, - f: impl FnOnce() -> T, - ) -> Option<&'static T> { + unsafe fn initialize(&self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T { // Perform initialization let v = i.and_then(Option::take).unwrap_or_else(f); - // SAFETY: - // If references to the inner value exist, they were created in `f` - // and are invalidated here. The caller promises to never use them - // after this. let old = unsafe { self.state.get().replace(State::Alive(v)) }; match old { // If the variable is not being recursively initialized, register @@ -92,12 +74,10 @@ where val => drop(val), } - // SAFETY: - // Initialization was completed and the state was set to `Alive`, so the - // reference fulfills the terms outlined above. + // SAFETY: the state was just set to `Alive` unsafe { let State::Alive(v) = &*self.state.get() else { unreachable_unchecked() }; - Some(v) + v } } } diff --git a/library/std/src/sys/thread_local/fast_local/mod.rs b/library/std/src/sys/thread_local/fast_local/mod.rs index 152137d9270..575d60de4ee 100644 --- a/library/std/src/sys/thread_local/fast_local/mod.rs +++ b/library/std/src/sys/thread_local/fast_local/mod.rs @@ -52,32 +52,26 @@ pub macro thread_local_inner { (@key $t:ty, const $init:expr) => {{ const __INIT: $t = $init; - #[inline] - #[deny(unsafe_op_in_unsafe_fn)] - unsafe fn __getit( - _init: $crate::option::Option<&mut $crate::option::Option<$t>>, - ) -> $crate::option::Option<&'static $t> { - use $crate::thread::local_impl::EagerStorage; + unsafe { use $crate::mem::needs_drop; - use $crate::ptr::addr_of; + use $crate::thread::LocalKey; + use $crate::thread::local_impl::EagerStorage; - if needs_drop::<$t>() { - #[thread_local] - static VAL: EagerStorage<$t> = EagerStorage::new(__INIT); - unsafe { - VAL.get() + LocalKey::new(const { + if needs_drop::<$t>() { + |_| { + #[thread_local] + static VAL: EagerStorage<$t> = EagerStorage::new(__INIT); + VAL.get() + } + } else { + |_| { + #[thread_local] + static VAL: $t = __INIT; + &VAL + } } - } else { - #[thread_local] - static VAL: $t = __INIT; - unsafe { - $crate::option::Option::Some(&*addr_of!(VAL)) - } - } - } - - unsafe { - $crate::thread::LocalKey::new(__getit) + }) } }}, @@ -88,31 +82,26 @@ pub macro thread_local_inner { $init } - #[inline] - #[deny(unsafe_op_in_unsafe_fn)] - unsafe fn __getit( - init: $crate::option::Option<&mut $crate::option::Option<$t>>, - ) -> $crate::option::Option<&'static $t> { - use $crate::thread::local_impl::LazyStorage; + unsafe { use $crate::mem::needs_drop; + use $crate::thread::LocalKey; + use $crate::thread::local_impl::LazyStorage; - if needs_drop::<$t>() { - #[thread_local] - static VAL: LazyStorage<$t, ()> = LazyStorage::new(); - unsafe { - VAL.get_or_init(init, __init) + LocalKey::new(const { + if needs_drop::<$t>() { + |init| { + #[thread_local] + static VAL: LazyStorage<$t, ()> = LazyStorage::new(); + VAL.get_or_init(init, __init) + } + } else { + |init| { + #[thread_local] + static VAL: LazyStorage<$t, !> = LazyStorage::new(); + VAL.get_or_init(init, __init) + } } - } else { - #[thread_local] - static VAL: LazyStorage<$t, !> = LazyStorage::new(); - unsafe { - VAL.get_or_init(init, __init) - } - } - } - - unsafe { - $crate::thread::LocalKey::new(__getit) + }) } }}, ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => { diff --git a/library/std/src/sys/thread_local/os_local.rs b/library/std/src/sys/thread_local/os_local.rs index d6ddbb78a9c..ee5adef66ea 100644 --- a/library/std/src/sys/thread_local/os_local.rs +++ b/library/std/src/sys/thread_local/os_local.rs @@ -16,30 +16,22 @@ pub macro thread_local_inner { }, // used to generate the `LocalKey` value for `thread_local!` - (@key $t:ty, $init:expr) => { - { - #[inline] - fn __init() -> $t { $init } + (@key $t:ty, $init:expr) => {{ + #[inline] + fn __init() -> $t { $init } - // `#[inline] does not work on windows-gnu due to linking errors around dllimports. - // See https://github.com/rust-lang/rust/issues/109797. - #[cfg_attr(not(windows), inline)] - unsafe fn __getit( - init: $crate::option::Option<&mut $crate::option::Option<$t>>, - ) -> $crate::option::Option<&'static $t> { - use $crate::thread::local_impl::Key; - - static __KEY: Key<$t> = Key::new(); - unsafe { - __KEY.get(init, __init) - } - } + unsafe { + use $crate::thread::LocalKey; + use $crate::thread::local_impl::Key; - unsafe { - $crate::thread::LocalKey::new(__getit) - } + // Inlining does not work on windows-gnu due to linking errors around + // dllimports. See https://github.com/rust-lang/rust/issues/109797. + LocalKey::new(#[cfg_attr(windows, inline(never))] |init| { + static VAL: Key<$t> = Key::new(); + VAL.get(init, __init) + }) } - }, + }}, ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => { $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> = $crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*); @@ -67,38 +59,33 @@ impl<T: 'static> Key<T> { Key { os: OsKey::new(Some(destroy_value::<T>)), marker: PhantomData } } - /// Get the value associated with this key, initializating it if necessary. + /// Get a pointer to the TLS value, potentially initializing it with the + /// provided parameters. If the TLS variable has been destroyed, a null + /// pointer is returned. /// - /// # Safety - /// * the returned reference must not be used after recursive initialization - /// or thread destruction occurs. - pub unsafe fn get( - &'static self, - i: Option<&mut Option<T>>, - f: impl FnOnce() -> T, - ) -> Option<&'static T> { + /// The resulting pointer may not be used after reentrant inialialization + /// or thread destruction has occurred. + pub fn get(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T { // SAFETY: (FIXME: get should actually be safe) let ptr = unsafe { self.os.get() as *mut Value<T> }; if ptr.addr() > 1 { // SAFETY: the check ensured the pointer is safe (its destructor // is not running) + it is coming from a trusted source (self). - unsafe { Some(&(*ptr).value) } + unsafe { &(*ptr).value } } else { - // SAFETY: At this point we are sure we have no value and so - // initializing (or trying to) is safe. - unsafe { self.try_initialize(ptr, i, f) } + self.try_initialize(ptr, i, f) } } - unsafe fn try_initialize( + fn try_initialize( &'static self, ptr: *mut Value<T>, i: Option<&mut Option<T>>, f: impl FnOnce() -> T, - ) -> Option<&'static T> { + ) -> *const T { if ptr.addr() == 1 { // destructor is running - return None; + return ptr::null(); } let value = i.and_then(Option::take).unwrap_or_else(f); @@ -119,7 +106,7 @@ impl<T: 'static> Key<T> { } // SAFETY: We just created this value above. - unsafe { Some(&(*ptr).value) } + unsafe { &(*ptr).value } } } diff --git a/library/std/src/sys/thread_local/static_local.rs b/library/std/src/sys/thread_local/static_local.rs index 6beda2e7188..0f08cab1ae4 100644 --- a/library/std/src/sys/thread_local/static_local.rs +++ b/library/std/src/sys/thread_local/static_local.rs @@ -13,19 +13,14 @@ pub macro thread_local_inner { (@key $t:ty, const $init:expr) => {{ const __INIT: $t = $init; - #[inline] - #[deny(unsafe_op_in_unsafe_fn)] - unsafe fn __getit( - _init: $crate::option::Option<&mut $crate::option::Option<$t>>, - ) -> $crate::option::Option<&'static $t> { + unsafe { + use $crate::thread::LocalKey; use $crate::thread::local_impl::EagerStorage; - static VAL: EagerStorage<$t> = EagerStorage { value: __INIT }; - $crate::option::Option::Some(&VAL.value) - } - - unsafe { - $crate::thread::LocalKey::new(__getit) + LocalKey::new(|_| { + static VAL: EagerStorage<$t> = EagerStorage { value: __INIT }; + &VAL.value + }) } }}, @@ -34,19 +29,14 @@ pub macro thread_local_inner { #[inline] fn __init() -> $t { $init } - #[inline] - #[deny(unsafe_op_in_unsafe_fn)] - unsafe fn __getit( - init: $crate::option::Option<&mut $crate::option::Option<$t>>, - ) -> $crate::option::Option<&'static $t> { + unsafe { + use $crate::thread::LocalKey; use $crate::thread::local_impl::LazyStorage; - static VAL: LazyStorage<$t> = LazyStorage::new(); - unsafe { $crate::option::Option::Some(VAL.get(init, __init)) } - } - - unsafe { - $crate::thread::LocalKey::new(__getit) + LocalKey::new(|init| { + static VAL: LazyStorage<$t> = LazyStorage::new(); + VAL.get(init, __init) + }) } }}, ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => { @@ -73,16 +63,13 @@ impl<T> LazyStorage<T> { LazyStorage { value: UnsafeCell::new(None) } } - /// Gets a reference to the contained value, initializing it if necessary. + /// Get a pointer to the TLS value, potentially initializing it with the + /// provided parameters. /// - /// # Safety - /// The returned reference may not be used after reentrant initialization has occurred. + /// The resulting pointer may not be used after reentrant inialialization + /// has occurred. #[inline] - pub unsafe fn get( - &'static self, - i: Option<&mut Option<T>>, - f: impl FnOnce() -> T, - ) -> &'static T { + pub fn get(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T { let value = unsafe { &*self.value.get() }; match value { Some(v) => v, @@ -91,11 +78,7 @@ impl<T> LazyStorage<T> { } #[cold] - unsafe fn initialize( - &'static self, - i: Option<&mut Option<T>>, - f: impl FnOnce() -> T, - ) -> &'static T { + fn initialize(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T { let value = i.and_then(Option::take).unwrap_or_else(f); // Destroy the old value, after updating the TLS variable as the // destructor might reference it. diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index c1b4440e560..aed185637fd 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -123,7 +123,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<&mut Option<T>>) -> Option<&'static T>, + inner: fn(Option<&mut Option<T>>) -> *const T, } #[stable(feature = "std_debug", since = "1.16.0")] @@ -238,9 +238,7 @@ 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<&mut Option<T>>) -> Option<&'static T>, - ) -> LocalKey<T> { + pub const unsafe fn new(inner: fn(Option<&mut Option<T>>) -> *const T) -> LocalKey<T> { LocalKey { inner } } @@ -281,8 +279,7 @@ impl<T: 'static> LocalKey<T> { where F: FnOnce(&T) -> R, { - // SAFETY: `inner` is safe to call within the lifetime of the thread - let thread_local = unsafe { (self.inner)(None).ok_or(AccessError)? }; + let thread_local = unsafe { (self.inner)(None).as_ref().ok_or(AccessError)? }; Ok(f(thread_local)) } @@ -304,9 +301,8 @@ impl<T: 'static> LocalKey<T> { { let mut init = Some(init); - // SAFETY: `inner` is safe to call within the lifetime of the thread let reference = unsafe { - (self.inner)(Some(&mut init)).expect( + (self.inner)(Some(&mut init)).as_ref().expect( "cannot access a Thread Local Storage value \ during or after destruction", ) diff --git a/tests/ui/suggestions/missing-lifetime-specifier.rs b/tests/ui/suggestions/missing-lifetime-specifier.rs index cd7fa0c1d85..dd437fc0c0b 100644 --- a/tests/ui/suggestions/missing-lifetime-specifier.rs +++ b/tests/ui/suggestions/missing-lifetime-specifier.rs @@ -1,6 +1,11 @@ -// different number of duplicated diagnostics on different targets -//@ only-x86_64 -//@ only-linux +// The specific errors produced depend the thread-local implementation. +// Run only on platforms with "fast" TLS. +//@ ignore-windows FIXME(#84933) +//@ ignore-wasm globals are used instead of thread locals +//@ ignore-emscripten globals are used instead of thread locals +//@ ignore-android does not use #[thread_local] +//@ ignore-nto does not use #[thread_local] +// Different number of duplicated diagnostics on different targets //@ compile-flags: -Zdeduplicate-diagnostics=yes #![allow(bare_trait_objects)] @@ -21,23 +26,19 @@ trait Tar<'t, 'k, I> {} thread_local! { static a: RefCell<HashMap<i32, Vec<Vec<Foo>>>> = RefCell::new(HashMap::new()); - //~^ ERROR missing lifetime specifiers - //~| ERROR missing lifetime specifiers + //~^ ERROR missing lifetime specifiers } thread_local! { static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new()); - //~^ ERROR missing lifetime specifiers - //~| ERROR missing lifetime specifiers + //~^ ERROR missing lifetime specifiers } thread_local! { static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new()); //~^ ERROR missing lifetime specifiers - //~| ERROR missing lifetime specifiers } thread_local! { static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new()); //~^ ERROR missing lifetime specifiers - //~| ERROR missing lifetime specifiers } thread_local! { @@ -47,8 +48,7 @@ thread_local! { thread_local! { static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new()); //~^ ERROR trait takes 2 lifetime arguments but 1 lifetime argument was supplied - //~| ERROR missing lifetime - //~| ERROR missing lifetime + //~| ERROR missing lifetime specifier } fn main() {} diff --git a/tests/ui/suggestions/missing-lifetime-specifier.stderr b/tests/ui/suggestions/missing-lifetime-specifier.stderr index 2b85cfde7b6..e0b6bb872b5 100644 --- a/tests/ui/suggestions/missing-lifetime-specifier.stderr +++ b/tests/ui/suggestions/missing-lifetime-specifier.stderr @@ -1,5 +1,5 @@ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:23:44 + --> $DIR/missing-lifetime-specifier.rs:28:44 | LL | static a: RefCell<HashMap<i32, Vec<Vec<Foo>>>> = RefCell::new(HashMap::new()); | ^^^ expected 2 lifetime parameters @@ -11,20 +11,7 @@ LL | static a: RefCell<HashMap<i32, Vec<Vec<Foo<'static, 'static>>>>> = RefC | ++++++++++++++++++ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:23:44 - | -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 the signature does not say which one of `init`'s 3 lifetimes it is borrowed from - -error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:28:44 + --> $DIR/missing-lifetime-specifier.rs:32:44 | LL | static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new()); | ^^^^ expected 2 lifetime parameters @@ -38,22 +25,7 @@ LL | static b: RefCell<HashMap<i32, Vec<Vec<&'static Bar<'static, 'static>>> | +++++++ ++++++++++++++++++ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:28:44 - | -LL | / thread_local! { -LL | | static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new()); - | | ^^^^ expected 2 lifetime parameters - | | | - | | expected named lifetime parameter -LL | | -LL | | -LL | | } - | |_- - | - = 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:33:47 + --> $DIR/missing-lifetime-specifier.rs:36:47 | LL | static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new()); | ^ expected 2 lifetime parameters @@ -65,20 +37,7 @@ LL | static c: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = | +++++++++++++++++ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:33:47 - | -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 the signature does not say which one of `init`'s 3 lifetimes it is borrowed from - -error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:38:44 + --> $DIR/missing-lifetime-specifier.rs:40:44 | LL | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new()); | ^ ^ expected 2 lifetime parameters @@ -91,23 +50,8 @@ help: consider using the `'static` lifetime, but this is uncommon unless you're LL | static d: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new()); | +++++++ +++++++++++++++++ -error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:38:44 - | -LL | / thread_local! { -LL | | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new()); - | | ^ ^ expected 2 lifetime parameters - | | | - | | expected named lifetime parameter -LL | | -LL | | -LL | | } - | |_- - | - = 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 specifier - --> $DIR/missing-lifetime-specifier.rs:48:44 + --> $DIR/missing-lifetime-specifier.rs:49:44 | LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new()); | ^ expected named lifetime parameter @@ -118,22 +62,8 @@ help: consider using the `'static` lifetime, but this is uncommon unless you're LL | static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> = RefCell::new(HashMap::new()); | +++++++ -error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-specifier.rs:48:44 - | -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 the signature does not say which one of `init`'s 3 lifetimes it is borrowed from - error[E0107]: union takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:44:44 + --> $DIR/missing-lifetime-specifier.rs:45:44 | LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -141,7 +71,7 @@ LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell: | expected 2 lifetime arguments | note: union defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:16:11 + --> $DIR/missing-lifetime-specifier.rs:21:11 | LL | pub union Qux<'t, 'k, I> { | ^^^ -- -- @@ -151,7 +81,7 @@ LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = | +++++++++ error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:48:45 + --> $DIR/missing-lifetime-specifier.rs:49:45 | LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -159,7 +89,7 @@ LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell | expected 2 lifetime arguments | note: trait defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:20:7 + --> $DIR/missing-lifetime-specifier.rs:25:7 | LL | trait Tar<'t, 'k, I> {} | ^^^ -- -- @@ -168,7 +98,7 @@ help: add missing lifetime argument LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new()); | +++++++++ -error: aborting due to 12 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0106, E0107. For more information about an error, try `rustc --explain E0106`. |
