diff options
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/Cargo.toml | 24 | ||||
| -rw-r--r-- | src/libstd/backtrace.rs | 21 | ||||
| -rw-r--r-- | src/libstd/build.rs | 1 | ||||
| -rw-r--r-- | src/libstd/ffi/c_str.rs | 38 | ||||
| -rw-r--r-- | src/libstd/keyword_docs.rs | 183 | ||||
| -rw-r--r-- | src/libstd/lazy.rs | 844 | ||||
| -rw-r--r-- | src/libstd/lib.rs | 10 | ||||
| -rw-r--r-- | src/libstd/panicking.rs | 2 | ||||
| -rw-r--r-- | src/libstd/sync/once.rs | 21 | ||||
| -rw-r--r-- | src/libstd/sys_common/backtrace.rs | 3 |
10 files changed, 1117 insertions, 30 deletions
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 29893bd12f1..136db6d5d32 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -25,11 +25,15 @@ profiler_builtins = { path = "../libprofiler_builtins", optional = true } unwind = { path = "../libunwind" } hashbrown = { version = "0.6.2", default-features = false, features = ['rustc-dep-of-std'] } -[dependencies.backtrace_rs] -package = "backtrace" -version = "0.3.46" -default-features = false # without the libstd `backtrace` feature, stub out everything -features = [ "rustc-dep-of-std" ] # enable build support for integrating into libstd +# Dependencies of the `backtrace` crate +addr2line = { version = "0.13.0", optional = true, default-features = false } +rustc-demangle = { version = "0.1.4", optional = true } +miniz_oxide = { version = "0.4.0", optional = true, default-features = false } +[dependencies.object] +version = "0.20" +optional = true +default-features = false +features = ['read_core', 'elf', 'macho', 'pe'] [dev-dependencies] rand = "0.7" @@ -48,11 +52,13 @@ wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = [features] backtrace = [ - "backtrace_rs/dbghelp", # backtrace/symbolize on MSVC - "backtrace_rs/libbacktrace", # symbolize on most platforms - "backtrace_rs/libunwind", # backtrace on most platforms - "backtrace_rs/dladdr", # symbolize on platforms w/o libbacktrace + "gimli-symbolize", + 'addr2line/rustc-dep-of-std', + 'object/rustc-dep-of-std', + 'rustc-demangle/rustc-dep-of-std', + 'miniz_oxide/rustc-dep-of-std', ] +gimli-symbolize = [] panic-unwind = ["panic_unwind"] profiler = ["profiler_builtins"] diff --git a/src/libstd/backtrace.rs b/src/libstd/backtrace.rs index e10d466030f..e65775c1ced 100644 --- a/src/libstd/backtrace.rs +++ b/src/libstd/backtrace.rs @@ -91,6 +91,7 @@ // `Backtrace`, but that's a relatively small price to pay relative to capturing // a backtrace or actually symbolizing it. +use crate::backtrace_rs::{self, BytesOrWideString}; use crate::env; use crate::ffi::c_void; use crate::fmt; @@ -98,8 +99,6 @@ use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst}; use crate::sync::Mutex; use crate::sys_common::backtrace::{lock, output_filename}; use crate::vec::Vec; -use backtrace::BytesOrWideString; -use backtrace_rs as backtrace; /// A captured OS thread stack backtrace. /// @@ -150,7 +149,7 @@ struct BacktraceFrame { } enum RawFrame { - Actual(backtrace::Frame), + Actual(backtrace_rs::Frame), #[cfg(test)] Fake, } @@ -197,7 +196,7 @@ impl fmt::Debug for BacktraceSymbol { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { write!(fmt, "{{ ")?; - if let Some(fn_name) = self.name.as_ref().map(|b| backtrace::SymbolName::new(b)) { + if let Some(fn_name) = self.name.as_ref().map(|b| backtrace_rs::SymbolName::new(b)) { write!(fmt, "fn: \"{:#}\"", fn_name)?; } else { write!(fmt, "fn: <unknown>")?; @@ -223,7 +222,7 @@ impl fmt::Debug for BytesOrWide { BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w), BytesOrWide::Wide(w) => BytesOrWideString::Wide(w), }, - backtrace::PrintFmt::Short, + backtrace_rs::PrintFmt::Short, crate::env::current_dir().as_ref().ok(), ) } @@ -299,7 +298,7 @@ impl Backtrace { let mut frames = Vec::new(); let mut actual_start = None; unsafe { - backtrace::trace_unsynchronized(|frame| { + backtrace_rs::trace_unsynchronized(|frame| { frames.push(BacktraceFrame { frame: RawFrame::Actual(frame.clone()), symbols: Vec::new(), @@ -350,9 +349,9 @@ impl fmt::Display for Backtrace { let full = fmt.alternate(); let (frames, style) = if full { - (&capture.frames[..], backtrace::PrintFmt::Full) + (&capture.frames[..], backtrace_rs::PrintFmt::Full) } else { - (&capture.frames[capture.actual_start..], backtrace::PrintFmt::Short) + (&capture.frames[capture.actual_start..], backtrace_rs::PrintFmt::Short) }; // When printing paths we try to strip the cwd if it exists, otherwise @@ -364,7 +363,7 @@ impl fmt::Display for Backtrace { output_filename(fmt, path, style, cwd.as_ref().ok()) }; - let mut f = backtrace::BacktraceFmt::new(fmt, style, &mut print_path); + let mut f = backtrace_rs::BacktraceFmt::new(fmt, style, &mut print_path); f.add_context()?; for frame in frames { let mut f = f.frame(); @@ -374,7 +373,7 @@ impl fmt::Display for Backtrace { for symbol in frame.symbols.iter() { f.print_raw( frame.frame.ip(), - symbol.name.as_ref().map(|b| backtrace::SymbolName::new(b)), + symbol.name.as_ref().map(|b| backtrace_rs::SymbolName::new(b)), symbol.filename.as_ref().map(|b| match b { BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w), BytesOrWide::Wide(w) => BytesOrWideString::Wide(w), @@ -409,7 +408,7 @@ impl Capture { RawFrame::Fake => unimplemented!(), }; unsafe { - backtrace::resolve_frame_unsynchronized(frame, |symbol| { + backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { symbols.push(BacktraceSymbol { name: symbol.name().map(|m| m.as_bytes().to_vec()), filename: symbol.filename_raw().map(|b| match b { diff --git a/src/libstd/build.rs b/src/libstd/build.rs index eb2753d6245..58fb6fda19a 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -87,4 +87,5 @@ fn main() { println!("cargo:rustc-cfg=feature=\"restricted-std\""); } println!("cargo:rustc-env=STD_ENV_ARCH={}", env::var("CARGO_CFG_TARGET_ARCH").unwrap()); + println!("cargo:rustc-cfg=backtrace_in_libstd"); } diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index dca1fdde482..da25a0ede72 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -1551,6 +1551,27 @@ impl ops::Index<ops::RangeFull> for CString { } } +#[stable(feature = "cstr_range_from", since = "1.47.0")] +impl ops::Index<ops::RangeFrom<usize>> for CStr { + type Output = CStr; + + fn index(&self, index: ops::RangeFrom<usize>) -> &CStr { + let bytes = self.to_bytes_with_nul(); + // we need to manually check the starting index to account for the null + // byte, since otherwise we could get an empty string that doesn't end + // in a null. + if index.start < bytes.len() { + unsafe { CStr::from_bytes_with_nul_unchecked(&bytes[index.start..]) } + } else { + panic!( + "index out of bounds: the len is {} but the index is {}", + bytes.len(), + index.start + ); + } + } +} + #[stable(feature = "cstring_asref", since = "1.7.0")] impl AsRef<CStr> for CStr { #[inline] @@ -1747,4 +1768,21 @@ mod tests { assert_eq!(CSTR.to_str().unwrap(), "Hello, world!"); } + + #[test] + fn cstr_index_from() { + let original = b"Hello, world!\0"; + let cstr = CStr::from_bytes_with_nul(original).unwrap(); + let result = CStr::from_bytes_with_nul(&original[7..]).unwrap(); + + assert_eq!(&cstr[7..], result); + } + + #[test] + #[should_panic] + fn cstr_index_from_empty() { + let original = b"Hello, world!\0"; + let cstr = CStr::from_bytes_with_nul(original).unwrap(); + let _ = &cstr[original.len()..]; + } } diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index a53e7f5cf57..d985f10ccb4 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1497,11 +1497,188 @@ mod super_keyword {} #[doc(keyword = "trait")] // -/// A common interface for a class of types. +/// A common interface for a group of types. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// A `trait` is like an interface that data types can implement. When a type +/// implements a trait it can be treated abstractly as that trait using generics +/// or trait objects. /// -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +/// Traits can be made up of three varieties of associated items: +/// +/// - functions and methods +/// - types +/// - constants +/// +/// Traits may also contain additional type parameters. Those type parameters +/// or the trait itself can be constrained by other traits. +/// +/// Traits can serve as markers or carry other logical semantics that +/// aren't expressed through their items. When a type implements that +/// trait it is promising to uphold its contract. [`Send`] and [`Sync`] are two +/// such marker traits present in the standard library. +/// +/// See the [Reference][Ref-Traits] for a lot more information on traits. +/// +/// # Examples +/// +/// Traits are declared using the `trait` keyword. Types can implement them +/// using [`impl`] `Trait` [`for`] `Type`: +/// +/// ```rust +/// trait Zero { +/// const ZERO: Self; +/// fn is_zero(&self) -> bool; +/// } +/// +/// impl Zero for i32 { +/// const ZERO: Self = 0; +/// +/// fn is_zero(&self) -> bool { +/// *self == Self::ZERO +/// } +/// } +/// +/// assert_eq!(i32::ZERO, 0); +/// assert!(i32::ZERO.is_zero()); +/// assert!(!4.is_zero()); +/// ``` +/// +/// With an associated type: +/// +/// ```rust +/// trait Builder { +/// type Built; +/// +/// fn build(&self) -> Self::Built; +/// } +/// ``` +/// +/// Traits can be generic, with constraints or without: +/// +/// ```rust +/// trait MaybeFrom<T> { +/// fn maybe_from(value: T) -> Option<Self> +/// where +/// Self: Sized; +/// } +/// ``` +/// +/// Traits can build upon the requirements of other traits. In the example +/// below `Iterator` is a **supertrait** and `ThreeIterator` is a **subtrait**: +/// +/// ```rust +/// trait ThreeIterator: std::iter::Iterator { +/// fn next_three(&mut self) -> Option<[Self::Item; 3]>; +/// } +/// ``` +/// +/// Traits can be used in functions, as parameters: +/// +/// ```rust +/// # #![allow(dead_code)] +/// fn debug_iter<I: Iterator>(it: I) where I::Item: std::fmt::Debug { +/// for elem in it { +/// println!("{:#?}", elem); +/// } +/// } +/// +/// // u8_len_1, u8_len_2 and u8_len_3 are equivalent +/// +/// fn u8_len_1(val: impl Into<Vec<u8>>) -> usize { +/// val.into().len() +/// } +/// +/// fn u8_len_2<T: Into<Vec<u8>>>(val: T) -> usize { +/// val.into().len() +/// } +/// +/// fn u8_len_3<T>(val: T) -> usize +/// where +/// T: Into<Vec<u8>>, +/// { +/// val.into().len() +/// } +/// ``` +/// +/// Or as return types: +/// +/// ```rust +/// # #![allow(dead_code)] +/// fn from_zero_to(v: u8) -> impl Iterator<Item = u8> { +/// (0..v).into_iter() +/// } +/// ``` +/// +/// The use of the [`impl`] keyword in this position allows the function writer +/// to hide the concrete type as an implementation detail which can change +/// without breaking user's code. +/// +/// # Trait objects +/// +/// A *trait object* is an opaque value of another type that implements a set of +/// traits. A trait object implements all specified traits as well as their +/// supertraits (if any). +/// +/// The syntax is the following: `dyn BaseTrait + AutoTrait1 + ... AutoTraitN`. +/// Only one `BaseTrait` can be used so this will not compile: +/// +/// ```rust,compile_fail,E0225 +/// trait A {} +/// trait B {} +/// +/// let _: Box<dyn A + B>; +/// ``` +/// +/// Neither will this, which is a syntax error: +/// +/// ```rust,compile_fail +/// trait A {} +/// trait B {} +/// +/// let _: Box<dyn A + dyn B>; +/// ``` +/// +/// On the other hand, this is correct: +/// +/// ```rust +/// trait A {} +/// +/// let _: Box<dyn A + Send + Sync>; +/// ``` +/// +/// The [Reference][Ref-Trait-Objects] has more information about trait objects, +/// their limitations and the differences between editions. +/// +/// # Unsafe traits +/// +/// Some traits may be unsafe to implement. Using the [`unsafe`] keyword in +/// front of the trait's declaration is used to mark this: +/// +/// ```rust +/// unsafe trait UnsafeTrait {} +/// +/// unsafe impl UnsafeTrait for i32 {} +/// ``` +/// +/// # Differences between the 2015 and 2018 editions +/// +/// In the 2015 edition parameters pattern where not needed for traits: +/// +/// ```rust,edition2015 +/// trait Tr { +/// fn f(i32); +/// } +/// ``` +/// +/// This behavior is no longer valid in edition 2018. +/// +/// [`for`]: keyword.for.html +/// [`impl`]: keyword.impl.html +/// [`unsafe`]: keyword.unsafe.html +/// [`Send`]: marker/trait.Send.html +/// [`Sync`]: marker/trait.Sync.html +/// [Ref-Traits]: ../reference/items/traits.html +/// [Ref-Trait-Objects]: ../reference/types/trait-object.html mod trait_keyword {} #[doc(keyword = "true")] diff --git a/src/libstd/lazy.rs b/src/libstd/lazy.rs new file mode 100644 index 00000000000..86e1cfae582 --- /dev/null +++ b/src/libstd/lazy.rs @@ -0,0 +1,844 @@ +//! Lazy values and one-time initialization of static data. + +use crate::{ + cell::{Cell, UnsafeCell}, + fmt, + mem::{self, MaybeUninit}, + ops::{Deref, Drop}, + panic::{RefUnwindSafe, UnwindSafe}, + sync::Once, +}; + +#[doc(inline)] +#[unstable(feature = "once_cell", issue = "74465")] +pub use core::lazy::*; + +/// A synchronization primitive which can be written to only once. +/// +/// This type is a thread-safe `OnceCell`. +/// +/// # Examples +/// +/// ``` +/// #![feature(once_cell)] +/// +/// use std::lazy::SyncOnceCell; +/// +/// static CELL: SyncOnceCell<String> = SyncOnceCell::new(); +/// assert!(CELL.get().is_none()); +/// +/// std::thread::spawn(|| { +/// let value: &String = CELL.get_or_init(|| { +/// "Hello, World!".to_string() +/// }); +/// assert_eq!(value, "Hello, World!"); +/// }).join().unwrap(); +/// +/// let value: Option<&String> = CELL.get(); +/// assert!(value.is_some()); +/// assert_eq!(value.unwrap().as_str(), "Hello, World!"); +/// ``` +#[unstable(feature = "once_cell", issue = "74465")] +pub struct SyncOnceCell<T> { + once: Once, + // Whether or not the value is initialized is tracked by `state_and_queue`. + value: UnsafeCell<MaybeUninit<T>>, +} + +// Why do we need `T: Send`? +// Thread A creates a `SyncOnceCell` and shares it with +// scoped thread B, which fills the cell, which is +// then destroyed by A. That is, destructor observes +// a sent value. +#[unstable(feature = "once_cell", issue = "74465")] +unsafe impl<T: Sync + Send> Sync for SyncOnceCell<T> {} +#[unstable(feature = "once_cell", issue = "74465")] +unsafe impl<T: Send> Send for SyncOnceCell<T> {} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for SyncOnceCell<T> {} +#[unstable(feature = "once_cell", issue = "74465")] +impl<T: UnwindSafe> UnwindSafe for SyncOnceCell<T> {} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T> Default for SyncOnceCell<T> { + fn default() -> SyncOnceCell<T> { + SyncOnceCell::new() + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T: fmt::Debug> fmt::Debug for SyncOnceCell<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.get() { + Some(v) => f.debug_tuple("Once").field(v).finish(), + None => f.write_str("Once(Uninit)"), + } + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T: Clone> Clone for SyncOnceCell<T> { + fn clone(&self) -> SyncOnceCell<T> { + let cell = Self::new(); + if let Some(value) = self.get() { + match cell.set(value.clone()) { + Ok(()) => (), + Err(_) => unreachable!(), + } + } + cell + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T> From<T> for SyncOnceCell<T> { + fn from(value: T) -> Self { + let cell = Self::new(); + match cell.set(value) { + Ok(()) => cell, + Err(_) => unreachable!(), + } + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T: PartialEq> PartialEq for SyncOnceCell<T> { + fn eq(&self, other: &SyncOnceCell<T>) -> bool { + self.get() == other.get() + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T: Eq> Eq for SyncOnceCell<T> {} + +impl<T> SyncOnceCell<T> { + /// Creates a new empty cell. + #[unstable(feature = "once_cell", issue = "74465")] + pub const fn new() -> SyncOnceCell<T> { + SyncOnceCell { once: Once::new(), value: UnsafeCell::new(MaybeUninit::uninit()) } + } + + /// Gets the reference to the underlying value. + /// + /// Returns `None` if the cell is empty, or being initialized. This + /// method never blocks. + #[unstable(feature = "once_cell", issue = "74465")] + pub fn get(&self) -> Option<&T> { + if self.is_initialized() { + // Safe b/c checked is_initialized + Some(unsafe { self.get_unchecked() }) + } else { + None + } + } + + /// Gets the mutable reference to the underlying value. + /// + /// Returns `None` if the cell is empty. This method never blocks. + #[unstable(feature = "once_cell", issue = "74465")] + pub fn get_mut(&mut self) -> Option<&mut T> { + if self.is_initialized() { + // Safe b/c checked is_initialized and we have a unique access + Some(unsafe { self.get_unchecked_mut() }) + } else { + None + } + } + + /// Sets the contents of this cell to `value`. + /// + /// Returns `Ok(())` if the cell's value was updated. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::lazy::SyncOnceCell; + /// + /// static CELL: SyncOnceCell<i32> = SyncOnceCell::new(); + /// + /// fn main() { + /// assert!(CELL.get().is_none()); + /// + /// std::thread::spawn(|| { + /// assert_eq!(CELL.set(92), Ok(())); + /// }).join().unwrap(); + /// + /// assert_eq!(CELL.set(62), Err(62)); + /// assert_eq!(CELL.get(), Some(&92)); + /// } + /// ``` + #[unstable(feature = "once_cell", issue = "74465")] + pub fn set(&self, value: T) -> Result<(), T> { + let mut value = Some(value); + self.get_or_init(|| value.take().unwrap()); + match value { + None => Ok(()), + Some(value) => Err(value), + } + } + + /// Gets the contents of the cell, initializing it with `f` if the cell + /// was empty. + /// + /// Many threads may call `get_or_init` concurrently with different + /// initializing functions, but it is guaranteed that only one function + /// will be executed. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and the cell + /// remains uninitialized. + /// + /// It is an error to reentrantly initialize the cell from `f`. The + /// exact outcome is unspecified. Current implementation deadlocks, but + /// this may be changed to a panic in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::lazy::SyncOnceCell; + /// + /// let cell = SyncOnceCell::new(); + /// let value = cell.get_or_init(|| 92); + /// assert_eq!(value, &92); + /// let value = cell.get_or_init(|| unreachable!()); + /// assert_eq!(value, &92); + /// ``` + #[unstable(feature = "once_cell", issue = "74465")] + pub fn get_or_init<F>(&self, f: F) -> &T + where + F: FnOnce() -> T, + { + match self.get_or_try_init(|| Ok::<T, !>(f())) { + Ok(val) => val, + } + } + + /// Gets the contents of the cell, initializing it with `f` if + /// the cell was empty. If the cell was empty and `f` failed, an + /// error is returned. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and + /// the cell remains uninitialized. + /// + /// It is an error to reentrantly initialize the cell from `f`. + /// The exact outcome is unspecified. Current implementation + /// deadlocks, but this may be changed to a panic in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::lazy::SyncOnceCell; + /// + /// let cell = SyncOnceCell::new(); + /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); + /// assert!(cell.get().is_none()); + /// let value = cell.get_or_try_init(|| -> Result<i32, ()> { + /// Ok(92) + /// }); + /// assert_eq!(value, Ok(&92)); + /// assert_eq!(cell.get(), Some(&92)) + /// ``` + #[unstable(feature = "once_cell", issue = "74465")] + pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E> + where + F: FnOnce() -> Result<T, E>, + { + // Fast path check + // NOTE: We need to perform an acquire on the state in this method + // in order to correctly synchronize `SyncLazy::force`. This is + // currently done by calling `self.get()`, which in turn calls + // `self.is_initialized()`, which in turn performs the acquire. + if let Some(value) = self.get() { + return Ok(value); + } + self.initialize(f)?; + + debug_assert!(self.is_initialized()); + + // Safety: The inner value has been initialized + Ok(unsafe { self.get_unchecked() }) + } + + /// Consumes the `SyncOnceCell`, returning the wrapped value. Returns + /// `None` if the cell was empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::lazy::SyncOnceCell; + /// + /// let cell: SyncOnceCell<String> = SyncOnceCell::new(); + /// assert_eq!(cell.into_inner(), None); + /// + /// let cell = SyncOnceCell::new(); + /// cell.set("hello".to_string()).unwrap(); + /// assert_eq!(cell.into_inner(), Some("hello".to_string())); + /// ``` + #[unstable(feature = "once_cell", issue = "74465")] + pub fn into_inner(mut self) -> Option<T> { + // Safety: Safe because we immediately free `self` without dropping + let inner = unsafe { self.take_inner() }; + + // Don't drop this `SyncOnceCell`. We just moved out one of the fields, but didn't set + // the state to uninitialized. + mem::ManuallyDrop::new(self); + inner + } + + /// Takes the value out of this `SyncOnceCell`, moving it back to an uninitialized state. + /// + /// Has no effect and returns `None` if the `SyncOnceCell` hasn't been initialized. + /// + /// Safety is guaranteed by requiring a mutable reference. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::lazy::SyncOnceCell; + /// + /// let mut cell: SyncOnceCell<String> = SyncOnceCell::new(); + /// assert_eq!(cell.take(), None); + /// + /// let mut cell = SyncOnceCell::new(); + /// cell.set("hello".to_string()).unwrap(); + /// assert_eq!(cell.take(), Some("hello".to_string())); + /// assert_eq!(cell.get(), None); + /// ``` + #[unstable(feature = "once_cell", issue = "74465")] + pub fn take(&mut self) -> Option<T> { + mem::take(self).into_inner() + } + + /// Takes the wrapped value out of a `SyncOnceCell`. + /// Afterwards the cell is no longer initialized. + /// + /// Safety: The cell must now be free'd WITHOUT dropping. No other usages of the cell + /// are valid. Only used by `into_inner` and `drop`. + unsafe fn take_inner(&mut self) -> Option<T> { + // The mutable reference guarantees there are no other threads that can observe us + // taking out the wrapped value. + // Right after this function `self` is supposed to be freed, so it makes little sense + // to atomically set the state to uninitialized. + if self.is_initialized() { + let value = mem::replace(&mut self.value, UnsafeCell::new(MaybeUninit::uninit())); + Some(value.into_inner().assume_init()) + } else { + None + } + } + + #[inline] + fn is_initialized(&self) -> bool { + self.once.is_completed() + } + + #[cold] + fn initialize<F, E>(&self, f: F) -> Result<(), E> + where + F: FnOnce() -> Result<T, E>, + { + let mut res: Result<(), E> = Ok(()); + let slot = &self.value; + + // Ignore poisoning from other threads + // If another thread panics, then we'll be able to run our closure + self.once.call_once_force(|p| { + match f() { + Ok(value) => { + unsafe { (&mut *slot.get()).write(value) }; + } + Err(e) => { + res = Err(e); + + // Treat the underlying `Once` as poisoned since we + // failed to initialize our value. Calls + p.poison(); + } + } + }); + res + } + + /// Safety: The value must be initialized + unsafe fn get_unchecked(&self) -> &T { + debug_assert!(self.is_initialized()); + (&*self.value.get()).get_ref() + } + + /// Safety: The value must be initialized + unsafe fn get_unchecked_mut(&mut self) -> &mut T { + debug_assert!(self.is_initialized()); + (&mut *self.value.get()).get_mut() + } +} + +impl<T> Drop for SyncOnceCell<T> { + fn drop(&mut self) { + // Safety: The cell is being dropped, so it can't be accessed again + unsafe { self.take_inner() }; + } +} + +/// A value which is initialized on the first access. +/// +/// This type is a thread-safe `Lazy`, and can be used in statics. +/// +/// # Examples +/// +/// ``` +/// #![feature(once_cell)] +/// +/// use std::collections::HashMap; +/// +/// use std::lazy::SyncLazy; +/// +/// static HASHMAP: SyncLazy<HashMap<i32, String>> = SyncLazy::new(|| { +/// println!("initializing"); +/// let mut m = HashMap::new(); +/// m.insert(13, "Spica".to_string()); +/// m.insert(74, "Hoyten".to_string()); +/// m +/// }); +/// +/// fn main() { +/// println!("ready"); +/// std::thread::spawn(|| { +/// println!("{:?}", HASHMAP.get(&13)); +/// }).join().unwrap(); +/// println!("{:?}", HASHMAP.get(&74)); +/// +/// // Prints: +/// // ready +/// // initializing +/// // Some("Spica") +/// // Some("Hoyten") +/// } +/// ``` +#[unstable(feature = "once_cell", issue = "74465")] +pub struct SyncLazy<T, F = fn() -> T> { + cell: SyncOnceCell<T>, + init: Cell<Option<F>>, +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T: fmt::Debug, F> fmt::Debug for SyncLazy<T, F> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() + } +} + +// We never create a `&F` from a `&SyncLazy<T, F>` so it is fine +// to not impl `Sync` for `F` +// we do create a `&mut Option<F>` in `force`, but this is +// properly synchronized, so it only happens once +// so it also does not contribute to this impl. +#[unstable(feature = "once_cell", issue = "74465")] +unsafe impl<T, F: Send> Sync for SyncLazy<T, F> where SyncOnceCell<T>: Sync {} +// auto-derived `Send` impl is OK. + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T, F: RefUnwindSafe> RefUnwindSafe for SyncLazy<T, F> where SyncOnceCell<T>: RefUnwindSafe {} + +impl<T, F> SyncLazy<T, F> { + /// Creates a new lazy value with the given initializing + /// function. + #[unstable(feature = "once_cell", issue = "74465")] + pub const fn new(f: F) -> SyncLazy<T, F> { + SyncLazy { cell: SyncOnceCell::new(), init: Cell::new(Some(f)) } + } +} + +impl<T, F: FnOnce() -> T> SyncLazy<T, F> { + /// Forces the evaluation of this lazy value and + /// returns a reference to result. This is equivalent + /// to the `Deref` impl, but is explicit. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::lazy::SyncLazy; + /// + /// let lazy = SyncLazy::new(|| 92); + /// + /// assert_eq!(SyncLazy::force(&lazy), &92); + /// assert_eq!(&*lazy, &92); + /// ``` + #[unstable(feature = "once_cell", issue = "74465")] + pub fn force(this: &SyncLazy<T, F>) -> &T { + this.cell.get_or_init(|| match this.init.take() { + Some(f) => f(), + None => panic!("Lazy instance has previously been poisoned"), + }) + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T, F: FnOnce() -> T> Deref for SyncLazy<T, F> { + type Target = T; + fn deref(&self) -> &T { + SyncLazy::force(self) + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T: Default> Default for SyncLazy<T> { + /// Creates a new lazy value using `Default` as the initializing function. + fn default() -> SyncLazy<T> { + SyncLazy::new(T::default) + } +} + +#[cfg(test)] +mod tests { + use crate::{ + lazy::{Lazy, SyncLazy, SyncOnceCell}, + panic, + sync::{ + atomic::{AtomicUsize, Ordering::SeqCst}, + mpsc::channel, + Mutex, + }, + }; + + #[test] + fn lazy_default() { + static CALLED: AtomicUsize = AtomicUsize::new(0); + + struct Foo(u8); + impl Default for Foo { + fn default() -> Self { + CALLED.fetch_add(1, SeqCst); + Foo(42) + } + } + + let lazy: Lazy<Mutex<Foo>> = <_>::default(); + + assert_eq!(CALLED.load(SeqCst), 0); + + assert_eq!(lazy.lock().unwrap().0, 42); + assert_eq!(CALLED.load(SeqCst), 1); + + lazy.lock().unwrap().0 = 21; + + assert_eq!(lazy.lock().unwrap().0, 21); + assert_eq!(CALLED.load(SeqCst), 1); + } + + #[test] + fn lazy_poisoning() { + let x: Lazy<String> = Lazy::new(|| panic!("kaboom")); + for _ in 0..2 { + let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len())); + assert!(res.is_err()); + } + } + + // miri doesn't support threads + #[cfg(not(miri))] + fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R { + crate::thread::spawn(f).join().unwrap() + } + + #[cfg(not(miri))] + fn spawn(f: impl FnOnce() + Send + 'static) { + let _ = crate::thread::spawn(f); + } + + // "stub threads" for Miri + #[cfg(miri)] + fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R { + f(()) + } + + #[cfg(miri)] + fn spawn(f: impl FnOnce() + Send + 'static) { + f(()) + } + + #[test] + fn sync_once_cell() { + static ONCE_CELL: SyncOnceCell<i32> = SyncOnceCell::new(); + + assert!(ONCE_CELL.get().is_none()); + + spawn_and_wait(|| { + ONCE_CELL.get_or_init(|| 92); + assert_eq!(ONCE_CELL.get(), Some(&92)); + }); + + ONCE_CELL.get_or_init(|| panic!("Kabom!")); + assert_eq!(ONCE_CELL.get(), Some(&92)); + } + + #[test] + fn sync_once_cell_get_mut() { + let mut c = SyncOnceCell::new(); + assert!(c.get_mut().is_none()); + c.set(90).unwrap(); + *c.get_mut().unwrap() += 2; + assert_eq!(c.get_mut(), Some(&mut 92)); + } + + #[test] + fn sync_once_cell_get_unchecked() { + let c = SyncOnceCell::new(); + c.set(92).unwrap(); + unsafe { + assert_eq!(c.get_unchecked(), &92); + } + } + + #[test] + fn sync_once_cell_drop() { + static DROP_CNT: AtomicUsize = AtomicUsize::new(0); + struct Dropper; + impl Drop for Dropper { + fn drop(&mut self) { + DROP_CNT.fetch_add(1, SeqCst); + } + } + + let x = SyncOnceCell::new(); + spawn_and_wait(move || { + x.get_or_init(|| Dropper); + assert_eq!(DROP_CNT.load(SeqCst), 0); + drop(x); + }); + + assert_eq!(DROP_CNT.load(SeqCst), 1); + } + + #[test] + fn sync_once_cell_drop_empty() { + let x = SyncOnceCell::<String>::new(); + drop(x); + } + + #[test] + fn clone() { + let s = SyncOnceCell::new(); + let c = s.clone(); + assert!(c.get().is_none()); + + s.set("hello".to_string()).unwrap(); + let c = s.clone(); + assert_eq!(c.get().map(String::as_str), Some("hello")); + } + + #[test] + fn get_or_try_init() { + let cell: SyncOnceCell<String> = SyncOnceCell::new(); + assert!(cell.get().is_none()); + + let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() })); + assert!(res.is_err()); + assert!(!cell.is_initialized()); + assert!(cell.get().is_none()); + + assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); + + assert_eq!( + cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())), + Ok(&"hello".to_string()) + ); + assert_eq!(cell.get(), Some(&"hello".to_string())); + } + + #[test] + fn from_impl() { + assert_eq!(SyncOnceCell::from("value").get(), Some(&"value")); + assert_ne!(SyncOnceCell::from("foo").get(), Some(&"bar")); + } + + #[test] + fn partialeq_impl() { + assert!(SyncOnceCell::from("value") == SyncOnceCell::from("value")); + assert!(SyncOnceCell::from("foo") != SyncOnceCell::from("bar")); + + assert!(SyncOnceCell::<String>::new() == SyncOnceCell::new()); + assert!(SyncOnceCell::<String>::new() != SyncOnceCell::from("value".to_owned())); + } + + #[test] + fn into_inner() { + let cell: SyncOnceCell<String> = SyncOnceCell::new(); + assert_eq!(cell.into_inner(), None); + let cell = SyncOnceCell::new(); + cell.set("hello".to_string()).unwrap(); + assert_eq!(cell.into_inner(), Some("hello".to_string())); + } + + #[test] + fn sync_lazy_new() { + static CALLED: AtomicUsize = AtomicUsize::new(0); + static SYNC_LAZY: SyncLazy<i32> = SyncLazy::new(|| { + CALLED.fetch_add(1, SeqCst); + 92 + }); + + assert_eq!(CALLED.load(SeqCst), 0); + + spawn_and_wait(|| { + let y = *SYNC_LAZY - 30; + assert_eq!(y, 62); + assert_eq!(CALLED.load(SeqCst), 1); + }); + + let y = *SYNC_LAZY - 30; + assert_eq!(y, 62); + assert_eq!(CALLED.load(SeqCst), 1); + } + + #[test] + fn sync_lazy_default() { + static CALLED: AtomicUsize = AtomicUsize::new(0); + + struct Foo(u8); + impl Default for Foo { + fn default() -> Self { + CALLED.fetch_add(1, SeqCst); + Foo(42) + } + } + + let lazy: SyncLazy<Mutex<Foo>> = <_>::default(); + + assert_eq!(CALLED.load(SeqCst), 0); + + assert_eq!(lazy.lock().unwrap().0, 42); + assert_eq!(CALLED.load(SeqCst), 1); + + lazy.lock().unwrap().0 = 21; + + assert_eq!(lazy.lock().unwrap().0, 21); + assert_eq!(CALLED.load(SeqCst), 1); + } + + #[test] + #[cfg_attr(miri, ignore)] // leaks memory + fn static_sync_lazy() { + static XS: SyncLazy<Vec<i32>> = SyncLazy::new(|| { + let mut xs = Vec::new(); + xs.push(1); + xs.push(2); + xs.push(3); + xs + }); + + spawn_and_wait(|| { + assert_eq!(&*XS, &vec![1, 2, 3]); + }); + + assert_eq!(&*XS, &vec![1, 2, 3]); + } + + #[test] + #[cfg_attr(miri, ignore)] // leaks memory + fn static_sync_lazy_via_fn() { + fn xs() -> &'static Vec<i32> { + static XS: SyncOnceCell<Vec<i32>> = SyncOnceCell::new(); + XS.get_or_init(|| { + let mut xs = Vec::new(); + xs.push(1); + xs.push(2); + xs.push(3); + xs + }) + } + assert_eq!(xs(), &vec![1, 2, 3]); + } + + #[test] + fn sync_lazy_poisoning() { + let x: SyncLazy<String> = SyncLazy::new(|| panic!("kaboom")); + for _ in 0..2 { + let res = panic::catch_unwind(|| x.len()); + assert!(res.is_err()); + } + } + + #[test] + fn is_sync_send() { + fn assert_traits<T: Send + Sync>() {} + assert_traits::<SyncOnceCell<String>>(); + assert_traits::<SyncLazy<String>>(); + } + + #[test] + fn eval_once_macro() { + macro_rules! eval_once { + (|| -> $ty:ty { + $($body:tt)* + }) => {{ + static ONCE_CELL: SyncOnceCell<$ty> = SyncOnceCell::new(); + fn init() -> $ty { + $($body)* + } + ONCE_CELL.get_or_init(init) + }}; + } + + let fib: &'static Vec<i32> = eval_once! { + || -> Vec<i32> { + let mut res = vec![1, 1]; + for i in 0..10 { + let next = res[i] + res[i + 1]; + res.push(next); + } + res + } + }; + assert_eq!(fib[5], 8) + } + + #[test] + #[cfg_attr(miri, ignore)] // deadlocks without real threads + fn sync_once_cell_does_not_leak_partially_constructed_boxes() { + static ONCE_CELL: SyncOnceCell<String> = SyncOnceCell::new(); + + let n_readers = 10; + let n_writers = 3; + const MSG: &str = "Hello, World"; + + let (tx, rx) = channel(); + + for _ in 0..n_readers { + let tx = tx.clone(); + spawn(move || { + loop { + if let Some(msg) = ONCE_CELL.get() { + tx.send(msg).unwrap(); + break; + } + } + }); + } + for _ in 0..n_writers { + spawn(move || { + let _ = ONCE_CELL.set(MSG.to_owned()); + }); + } + + for _ in 0..n_readers { + let msg = rx.recv().unwrap(); + assert_eq!(msg, MSG); + } + } +} diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 54fc35b20f7..11b8f953be4 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -287,6 +287,7 @@ #![feature(linkage)] #![feature(llvm_asm)] #![feature(log_syntax)] +#![feature(maybe_uninit_extra)] #![feature(maybe_uninit_ref)] #![feature(maybe_uninit_slice)] #![feature(min_specialization)] @@ -294,6 +295,7 @@ #![feature(negative_impls)] #![feature(never_type)] #![feature(nll)] +#![feature(once_cell)] #![feature(optin_builtin_traits)] #![feature(or_patterns)] #![feature(panic_info_message)] @@ -303,6 +305,7 @@ #![feature(ptr_internals)] #![feature(raw)] #![feature(raw_ref_macros)] +#![feature(ready_macro)] #![feature(renamed_spin_loop)] #![feature(rustc_attrs)] #![feature(rustc_private)] @@ -477,6 +480,9 @@ pub mod process; pub mod sync; pub mod time; +#[unstable(feature = "once_cell", issue = "74465")] +pub mod lazy; + #[stable(feature = "futures_api", since = "1.36.0")] pub mod task { //! Types and Traits for working with asynchronous tasks. @@ -508,6 +514,10 @@ mod panicking; // compiler pub mod rt; +#[path = "../backtrace/src/lib.rs"] +#[allow(dead_code, unused_attributes)] +mod backtrace_rs; + // Pull in the `std_detect` crate directly into libstd. The contents of // `std_detect` are in a different repository: rust-lang/stdarch. // diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 9542e7209b4..ab2a6010306 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -171,7 +171,7 @@ fn default_hook(info: &PanicInfo<'_>) { // If this is a double panic, make sure that we print a backtrace // for this panic. Otherwise only print it if logging is enabled. let backtrace_env = if panic_count::get() >= 2 { - RustBacktrace::Print(backtrace_rs::PrintFmt::Full) + RustBacktrace::Print(crate::backtrace_rs::PrintFmt::Full) } else { backtrace::rust_backtrace_env() }; diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 7dc822db3d0..64260990824 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -132,6 +132,7 @@ unsafe impl Send for Once {} #[derive(Debug)] pub struct OnceState { poisoned: bool, + set_state_on_drop_to: Cell<usize>, } /// Initialization value for static [`Once`] values. @@ -321,7 +322,7 @@ impl Once { } let mut f = Some(f); - self.call_inner(true, &mut |p| f.take().unwrap()(&OnceState { poisoned: p })); + self.call_inner(true, &mut |p| f.take().unwrap()(p)); } /// Returns `true` if some `call_once` call has completed @@ -385,7 +386,7 @@ impl Once { // currently no way to take an `FnOnce` and call it via virtual dispatch // without some allocation overhead. #[cold] - fn call_inner(&self, ignore_poisoning: bool, init: &mut dyn FnMut(bool)) { + fn call_inner(&self, ignore_poisoning: bool, init: &mut dyn FnMut(&OnceState)) { let mut state_and_queue = self.state_and_queue.load(Ordering::Acquire); loop { match state_and_queue { @@ -413,8 +414,12 @@ impl Once { }; // Run the initialization function, letting it know if we're // poisoned or not. - init(state_and_queue == POISONED); - waiter_queue.set_state_on_drop_to = COMPLETE; + let init_state = OnceState { + poisoned: state_and_queue == POISONED, + set_state_on_drop_to: Cell::new(COMPLETE), + }; + init(&init_state); + waiter_queue.set_state_on_drop_to = init_state.set_state_on_drop_to.get(); break; } _ => { @@ -554,6 +559,14 @@ impl OnceState { pub fn poisoned(&self) -> bool { self.poisoned } + + /// Poison the associated [`Once`] without explicitly panicking. + /// + /// [`Once`]: struct.Once.html + // NOTE: This is currently only exposed for the `lazy` module + pub(crate) fn poison(&self) { + self.set_state_on_drop_to.set(POISONED); + } } #[cfg(all(test, not(target_os = "emscripten")))] diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index e9b1e86d7ae..d386a656e4f 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -1,3 +1,4 @@ +use crate::backtrace_rs::{self, BacktraceFmt, BytesOrWideString, PrintFmt}; use crate::borrow::Cow; /// Common code for printing the backtrace in the same way across the different /// supported platforms. @@ -9,8 +10,6 @@ use crate::path::{self, Path, PathBuf}; use crate::sync::atomic::{self, Ordering}; use crate::sys::mutex::Mutex; -use backtrace_rs::{BacktraceFmt, BytesOrWideString, PrintFmt}; - /// Max number of frames to print. const MAX_NB_FRAMES: usize = 100; |
