From 88338ff820a2e7f6330309349dd4fd6bd178a3bf Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 28 Mar 2024 14:30:32 +0000 Subject: [PATCH 01/19] Add `size_of`, `size_of_val`, `align_of`, and `align_of_val` to the prelude Many, many projects use `size_of` to get the size of a type. However, it's also often equally easy to hardcode a size (e.g. `8` instead of `size_of::()`). Minimizing friction in the use of `size_of` helps ensure that people use it and make code more self-documenting. The name `size_of` is unambiguous: the name alone, without any prefix or path, is self-explanatory and unmistakeable for any other functionality. Adding it to the prelude cannot produce any name conflicts, as any local definition will silently shadow the one from the prelude. Thus, we don't need to wait for a new edition prelude to add it. Add `size_of_val`, `align_of`, and `align_of_val` as well, with similar justification: widely useful, self-explanatory, unmistakeable for anything else, won't produce conflicts. --- alloc/src/rc.rs | 2 -- alloc/src/sync.rs | 2 -- core/src/cell.rs | 2 +- core/src/intrinsics.rs | 1 - core/src/prelude/common.rs | 3 +++ core/src/ptr/mod.rs | 2 +- core/src/slice/raw.rs | 1 - core/src/sync/atomic.rs | 3 --- portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs | 2 +- portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs | 2 +- proc_macro/src/bridge/fxhash.rs | 1 - std/src/io/error/repr_bitpacked.rs | 1 - std/src/os/unix/net/ancillary.rs | 2 +- std/src/prelude/common.rs | 3 +++ std/src/prelude/mod.rs | 4 ++++ 15 files changed, 15 insertions(+), 16 deletions(-) diff --git a/alloc/src/rc.rs b/alloc/src/rc.rs index 45b205356758f..52b91c5ac8879 100644 --- a/alloc/src/rc.rs +++ b/alloc/src/rc.rs @@ -257,8 +257,6 @@ use core::intrinsics::abort; #[cfg(not(no_global_oom_handling))] use core::iter; use core::marker::{PhantomData, Unsize}; -#[cfg(not(no_global_oom_handling))] -use core::mem::size_of_val; use core::mem::{self, align_of_val_raw, forget, ManuallyDrop}; use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; diff --git a/alloc/src/sync.rs b/alloc/src/sync.rs index a35c99849b343..d7c3a261fe405 100644 --- a/alloc/src/sync.rs +++ b/alloc/src/sync.rs @@ -18,8 +18,6 @@ use core::intrinsics::abort; #[cfg(not(no_global_oom_handling))] use core::iter; use core::marker::{PhantomData, Unsize}; -#[cfg(not(no_global_oom_handling))] -use core::mem::size_of_val; use core::mem::{self, align_of_val_raw}; use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, Receiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; diff --git a/core/src/cell.rs b/core/src/cell.rs index 4b491ffdafa70..dd6466d6285ba 100644 --- a/core/src/cell.rs +++ b/core/src/cell.rs @@ -238,7 +238,7 @@ use crate::cmp::Ordering; use crate::fmt::{self, Debug, Display}; use crate::marker::{PhantomData, Unsize}; -use crate::mem::{self, size_of}; +use crate::mem; use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn}; use crate::ptr::{self, NonNull}; diff --git a/core/src/intrinsics.rs b/core/src/intrinsics.rs index d1450bf12ce72..56c998d99f258 100644 --- a/core/src/intrinsics.rs +++ b/core/src/intrinsics.rs @@ -65,7 +65,6 @@ use crate::marker::DiscriminantKind; use crate::marker::Tuple; -use crate::mem::align_of; use crate::ptr; use crate::ub_checks; diff --git a/core/src/prelude/common.rs b/core/src/prelude/common.rs index afc6817aa1d24..2a0331ef7b274 100644 --- a/core/src/prelude/common.rs +++ b/core/src/prelude/common.rs @@ -14,6 +14,9 @@ pub use crate::ops::{Drop, Fn, FnMut, FnOnce}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use crate::mem::drop; +#[stable(feature = "size_of_prelude", since = "CURRENT_RUSTC_VERSION")] +#[doc(no_inline)] +pub use crate::mem::{align_of, align_of_val, size_of, size_of_val}; // Re-exported types and traits #[stable(feature = "core_prelude", since = "1.4.0")] diff --git a/core/src/ptr/mod.rs b/core/src/ptr/mod.rs index 8d7192c1b0fd1..3258e338e837c 100644 --- a/core/src/ptr/mod.rs +++ b/core/src/ptr/mod.rs @@ -392,7 +392,7 @@ use crate::intrinsics; use crate::marker::FnPtr; use crate::ub_checks; -use crate::mem::{self, align_of, size_of, MaybeUninit}; +use crate::mem::{self, MaybeUninit}; mod alignment; #[unstable(feature = "ptr_alignment_type", issue = "102070")] diff --git a/core/src/slice/raw.rs b/core/src/slice/raw.rs index 29a12f106c5ed..3f4305866e688 100644 --- a/core/src/slice/raw.rs +++ b/core/src/slice/raw.rs @@ -1,7 +1,6 @@ //! Free functions to create `&[T]` and `&mut [T]`. use crate::array; -use crate::mem::{align_of, size_of}; use crate::ops::Range; use crate::ptr; use crate::ub_checks; diff --git a/core/src/sync/atomic.rs b/core/src/sync/atomic.rs index 232ec589093d3..482bd19705c2f 100644 --- a/core/src/sync/atomic.rs +++ b/core/src/sync/atomic.rs @@ -1296,7 +1296,6 @@ impl AtomicPtr { #[cfg(target_has_atomic_equal_alignment = "ptr")] #[unstable(feature = "atomic_from_mut", issue = "76314")] pub fn from_mut(v: &mut *mut T) -> &mut Self { - use crate::mem::align_of; let [] = [(); align_of::>() - align_of::<*mut ()>()]; // SAFETY: // - the mutable reference guarantees unique ownership. @@ -2286,7 +2285,6 @@ macro_rules! atomic_int { #[$cfg_align] #[unstable(feature = "atomic_from_mut", issue = "76314")] pub fn from_mut(v: &mut $int_type) -> &mut Self { - use crate::mem::align_of; let [] = [(); align_of::() - align_of::<$int_type>()]; // SAFETY: // - the mutable reference guarantees unique ownership. @@ -2354,7 +2352,6 @@ macro_rules! atomic_int { #[$cfg_align] #[unstable(feature = "atomic_from_mut", issue = "76314")] pub fn from_mut_slice(v: &mut [$int_type]) -> &mut [Self] { - use crate::mem::align_of; let [] = [(); align_of::() - align_of::<$int_type>()]; // SAFETY: // - the mutable reference guarantees unique ownership. diff --git a/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs b/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs index 0f1719206c9ce..cbffbc564cfed 100644 --- a/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs +++ b/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs @@ -96,7 +96,7 @@ where fn cast(self) -> Self::CastPtr { // SimdElement currently requires zero-sized metadata, so this should never fail. // If this ever changes, `simd_cast_ptr` should produce a post-mono error. - use core::{mem::size_of, ptr::Pointee}; + use core::ptr::Pointee; assert_eq!(size_of::<::Metadata>(), 0); assert_eq!(size_of::<::Metadata>(), 0); diff --git a/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs b/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs index 7ba996d149c0c..6bc6ca3ac42dc 100644 --- a/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs +++ b/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs @@ -93,7 +93,7 @@ where fn cast(self) -> Self::CastPtr { // SimdElement currently requires zero-sized metadata, so this should never fail. // If this ever changes, `simd_cast_ptr` should produce a post-mono error. - use core::{mem::size_of, ptr::Pointee}; + use core::ptr::Pointee; assert_eq!(size_of::<::Metadata>(), 0); assert_eq!(size_of::<::Metadata>(), 0); diff --git a/proc_macro/src/bridge/fxhash.rs b/proc_macro/src/bridge/fxhash.rs index f4e9054419721..0923493d06c7c 100644 --- a/proc_macro/src/bridge/fxhash.rs +++ b/proc_macro/src/bridge/fxhash.rs @@ -7,7 +7,6 @@ use std::collections::HashMap; use std::hash::BuildHasherDefault; use std::hash::Hasher; -use std::mem::size_of; use std::ops::BitXor; /// Type alias for a hashmap using the `fx` hash algorithm. diff --git a/std/src/io/error/repr_bitpacked.rs b/std/src/io/error/repr_bitpacked.rs index 6f8d5e3777568..c9d3934ad70ce 100644 --- a/std/src/io/error/repr_bitpacked.rs +++ b/std/src/io/error/repr_bitpacked.rs @@ -104,7 +104,6 @@ use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage}; use core::marker::PhantomData; -use core::mem::{align_of, size_of}; use core::ptr::{self, NonNull}; // The 2 least-significant bits are used as tag. diff --git a/std/src/os/unix/net/ancillary.rs b/std/src/os/unix/net/ancillary.rs index 0597fdcbd7289..fe8e2be93724e 100644 --- a/std/src/os/unix/net/ancillary.rs +++ b/std/src/os/unix/net/ancillary.rs @@ -3,7 +3,7 @@ use super::{sockaddr_un, SocketAddr}; use crate::io::{self, IoSlice, IoSliceMut}; use crate::marker::PhantomData; -use crate::mem::{size_of, zeroed}; +use crate::mem::zeroed; use crate::os::unix::io::RawFd; use crate::path::Path; use crate::ptr::{eq, read_unaligned}; diff --git a/std/src/prelude/common.rs b/std/src/prelude/common.rs index 01936734d7548..ceee3e33c3ef0 100644 --- a/std/src/prelude/common.rs +++ b/std/src/prelude/common.rs @@ -14,6 +14,9 @@ pub use crate::ops::{Drop, Fn, FnMut, FnOnce}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use crate::mem::drop; +#[stable(feature = "size_of_prelude", since = "CURRENT_RUSTC_VERSION")] +#[doc(no_inline)] +pub use crate::mem::{align_of, align_of_val, size_of, size_of_val}; // Re-exported types and traits #[stable(feature = "rust1", since = "1.0.0")] diff --git a/std/src/prelude/mod.rs b/std/src/prelude/mod.rs index 0bdbab716adb4..2d4639342bf85 100644 --- a/std/src/prelude/mod.rs +++ b/std/src/prelude/mod.rs @@ -36,6 +36,10 @@ //! operations for both destructors and overloading `()`. //! * [std::mem]::[drop], a convenience function for explicitly //! dropping a value. +//! * [std::mem]::{[size_of], [size_of_val]}, to get the size of +//! a type or value. +//! * [std::mem]::{[align_of], [align_of_val]}, to get the +//! alignment of a type or value. //! * [std::boxed]::[Box], a way to allocate values on the heap. //! * [std::borrow]::[ToOwned], the conversion trait that defines //! [`to_owned`], the generic method for creating an owned type from a From 894310362d525c973703a155cec7b5dc08bc6b74 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Wed, 29 May 2024 14:19:09 +0200 Subject: [PATCH 02/19] Avoid `mut` and simplify initialization of `TASK_QUEUE` --- std/src/sys/pal/sgx/thread.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/std/src/sys/pal/sgx/thread.rs b/std/src/sys/pal/sgx/thread.rs index 7d271e6d2b65d..d70c6e31fb73b 100644 --- a/std/src/sys/pal/sgx/thread.rs +++ b/std/src/sys/pal/sgx/thread.rs @@ -15,7 +15,7 @@ pub use self::task_queue::JoinNotifier; mod task_queue { use super::wait_notify; - use crate::sync::{Mutex, MutexGuard, Once}; + use crate::sync::{Mutex, MutexGuard}; pub type JoinHandle = wait_notify::Waiter; @@ -32,6 +32,8 @@ mod task_queue { done: JoinNotifier, } + unsafe impl Send for Task {} + impl Task { pub(super) fn new(p: Box) -> (Task, JoinHandle) { let (done, recv) = wait_notify::new(); @@ -45,18 +47,12 @@ mod task_queue { } } - #[cfg_attr(test, linkage = "available_externally")] - #[export_name = "_ZN16__rust_internals3std3sys3sgx6thread15TASK_QUEUE_INITE"] - static TASK_QUEUE_INIT: Once = Once::new(); #[cfg_attr(test, linkage = "available_externally")] #[export_name = "_ZN16__rust_internals3std3sys3sgx6thread10TASK_QUEUEE"] - static mut TASK_QUEUE: Option>> = None; + static TASK_QUEUE: Mutex> = Mutex::new(Vec::new()); pub(super) fn lock() -> MutexGuard<'static, Vec> { - unsafe { - TASK_QUEUE_INIT.call_once(|| TASK_QUEUE = Some(Default::default())); - TASK_QUEUE.as_ref().unwrap().lock().unwrap() - } + TASK_QUEUE.lock().unwrap() } } From a198721997cd3b425d30286880086298a2bab0cd Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Mon, 27 May 2024 10:03:54 -0700 Subject: [PATCH 03/19] Explain LazyCell in core::cell overview --- core/src/cell.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/core/src/cell.rs b/core/src/cell.rs index ac026de95da12..6cdc1e00f4790 100644 --- a/core/src/cell.rs +++ b/core/src/cell.rs @@ -82,6 +82,20 @@ //! //! The corresponding [`Sync`] version of `OnceCell` is [`OnceLock`]. //! +//! ## `LazyCell` +//! +//! A common pattern with OnceCell is, for a given OnceCell, to use the same function on every +//! call to [`OnceCell::get_or_init`] with that cell. This is what is offered by [`LazyCell`], +//! which pairs cells of `T` with functions of `F`, and always calls `F` before it yields `&T`. +//! This happens implicitly by simply attempting to dereference the LazyCell to get its contents, +//! so its use is much more transparent with a place which has been initialized by a constant. +//! +//! More complicated patterns that don't fit this description can be built on `OnceCell` instead. +//! +//! `LazyCell` works by providing an implementation of `impl Deref` that calls the function, +//! so you can just use it by dereference (e.g. `*lazy_cell` or `lazy_cell.deref()`). +//! +//! The corresponding [`Sync`] version of `LazyCell` is [`LazyLock`]. //! //! # When to choose interior mutability //! @@ -230,6 +244,7 @@ //! [`RwLock`]: ../../std/sync/struct.RwLock.html //! [`Mutex`]: ../../std/sync/struct.Mutex.html //! [`OnceLock`]: ../../std/sync/struct.OnceLock.html +//! [`LazyLock`]: ../../std/sync/struct.LazyLock.html //! [`Sync`]: ../../std/marker/trait.Sync.html //! [`atomic`]: crate::sync::atomic From 7e47256ddbf4c2c44989a27b6a76168e2091c383 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Mon, 27 May 2024 10:24:28 -0700 Subject: [PATCH 04/19] Differ LazyLock vs. OnceLock in std::sync overview --- std/src/sync/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/std/src/sync/mod.rs b/std/src/sync/mod.rs index fb7d601b09478..70e8f5f90c61e 100644 --- a/std/src/sync/mod.rs +++ b/std/src/sync/mod.rs @@ -136,7 +136,10 @@ //! - [`Once`]: Used for a thread-safe, one-time global initialization routine //! //! - [`OnceLock`]: Used for thread-safe, one-time initialization of a -//! global variable. +//! variable, with potentially different initializers based on the caller. +//! +//! - [`LazyLock`]: Used for thread-safe, one-time initialization of a +//! variable, using one nullary initializer function provided at creation. //! //! - [`RwLock`]: Provides a mutual exclusion mechanism which allows //! multiple readers at the same time, while allowing only one From 6d001c57db61feb34596d0e8c5d9ee9c870a9e7d Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Mon, 27 May 2024 13:02:39 -0700 Subject: [PATCH 05/19] Move first OnceLock example to LazyLock This example is spiritually an example of LazyLock, as it computes a variable at runtime but accepts no inputs into that process. It is also slightly simpler and thus easier to understand. Change it to an even-more concise version and move it to LazyLock. The example now editorializes slightly more. This may be unnecessary, but it can be educational for the reader. --- std/src/sync/lazy_lock.rs | 36 ++++++++++++++---------------------- std/src/sync/once_lock.rs | 36 ------------------------------------ 2 files changed, 14 insertions(+), 58 deletions(-) diff --git a/std/src/sync/lazy_lock.rs b/std/src/sync/lazy_lock.rs index d3bb3bfdff92a..7a2eed93dd4f8 100644 --- a/std/src/sync/lazy_lock.rs +++ b/std/src/sync/lazy_lock.rs @@ -29,34 +29,26 @@ union Data { /// # Examples /// /// Initialize static variables with `LazyLock`. -/// /// ``` -/// use std::collections::HashMap; -/// /// use std::sync::LazyLock; /// -/// static HASHMAP: LazyLock> = LazyLock::new(|| { -/// println!("initializing"); -/// let mut m = HashMap::new(); -/// m.insert(13, "Spica".to_string()); -/// m.insert(74, "Hoyten".to_string()); -/// m +/// // n.b. static items do not call [`Drop`] on program termination, so this won't be deallocated. +/// // this is fine, as the OS can deallocate the terminated program faster than we can free memory +/// // but tools like valgrind might report "memory leaks" as it isn't obvious this is intentional. +/// static DEEP_THOUGHT: LazyLock = LazyLock::new(|| { +/// # mod another_crate { +/// # pub fn great_question() -> String { "42".to_string() } +/// # } +/// // M3 Ultra takes about 16 million years in --release config +/// another_crate::great_question() /// }); /// -/// fn main() { -/// println!("ready"); -/// std::thread::spawn(|| { -/// println!("{:?}", HASHMAP.get(&13)); -/// }).join().unwrap(); -/// println!("{:?}", HASHMAP.get(&74)); -/// -/// // Prints: -/// // ready -/// // initializing -/// // Some("Spica") -/// // Some("Hoyten") -/// } +/// // The `String` is built, stored in the `LazyLock`, and returned as `&String`. +/// let _ = &*DEEP_THOUGHT; +/// // The `String` is retrieved from the `LazyLock` and returned as `&String`. +/// let _ = &*DEEP_THOUGHT; /// ``` +/// /// Initialize fields with `LazyLock`. /// ``` /// use std::sync::LazyLock; diff --git a/std/src/sync/once_lock.rs b/std/src/sync/once_lock.rs index fc830baccedd2..d52f610c1f456 100644 --- a/std/src/sync/once_lock.rs +++ b/std/src/sync/once_lock.rs @@ -13,42 +13,6 @@ use crate::sync::Once; /// /// # Examples /// -/// Using `OnceLock` to store a function’s previously computed value (a.k.a. -/// ‘lazy static’ or ‘memoizing’): -/// -/// ``` -/// use std::sync::OnceLock; -/// -/// struct DeepThought { -/// answer: String, -/// } -/// -/// impl DeepThought { -/// # fn great_question() -> String { -/// # "42".to_string() -/// # } -/// # -/// fn new() -> Self { -/// Self { -/// // M3 Ultra takes about 16 million years in --release config -/// answer: Self::great_question(), -/// } -/// } -/// } -/// -/// fn computation() -> &'static DeepThought { -/// // n.b. static items do not call [`Drop`] on program termination, so if -/// // [`DeepThought`] impls Drop, that will not be used for this instance. -/// static COMPUTATION: OnceLock = OnceLock::new(); -/// COMPUTATION.get_or_init(|| DeepThought::new()) -/// } -/// -/// // The `DeepThought` is built, stored in the `OnceLock`, and returned. -/// let _ = computation().answer; -/// // The `DeepThought` is retrieved from the `OnceLock` and returned. -/// let _ = computation().answer; -/// ``` -/// /// Writing to a `OnceLock` from a separate thread: /// /// ``` From 06d9b0e9397272ef0ea35a80339082f607c54fd3 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Mon, 27 May 2024 13:21:38 -0700 Subject: [PATCH 06/19] Add "OnceList" example to motivate OnceLock While slightly verbose, it helps explain "why bother with OnceLock?" This is a point of confusion that has been raised multiple times shortly before and after the stabilization of LazyLock. --- std/src/sync/once_lock.rs | 55 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/std/src/sync/once_lock.rs b/std/src/sync/once_lock.rs index d52f610c1f456..22083bc293330 100644 --- a/std/src/sync/once_lock.rs +++ b/std/src/sync/once_lock.rs @@ -8,8 +8,14 @@ use crate::sync::Once; /// A synchronization primitive which can be written to only once. /// /// This type is a thread-safe [`OnceCell`], and can be used in statics. +/// In many simple cases, you can use [`LazyLock`] instead to get the benefits of this type +/// with less effort: `LazyLock` "looks like" `&T` because it initializes with `F` on deref! +/// Where OnceLock shines is when LazyLock is too simple to support a given case, as LazyLock +/// doesn't allow additional inputs to its function after you call [`LazyLock::new(|| ...)`]. /// /// [`OnceCell`]: crate::cell::OnceCell +/// [`LazyLock`]: crate::sync::LazyLock +/// [`LazyLock::new(|| ...)`]: crate::sync::LazyLock::new /// /// # Examples /// @@ -37,6 +43,55 @@ use crate::sync::Once; /// Some(&12345), /// ); /// ``` +/// +/// You can use `OnceLock` to implement a type that requires "append-only" logic: +/// +/// ``` +/// use std::sync::{OnceLock, atomic::{AtomicU32, Ordering}}; +/// use std::thread; +/// +/// struct OnceList { +/// data: OnceLock, +/// next: OnceLock>>, +/// } +/// impl OnceList { +/// const fn new() -> OnceList { +/// OnceList { data: OnceLock::new(), next: OnceLock::new() } +/// } +/// fn push(&self, value: T) { +/// // FIXME: this impl is concise, but is also slow for long lists or many threads. +/// // as an exercise, consider how you might improve on it while preserving the behavior +/// if let Err(value) = self.data.set(value) { +/// let next = self.next.get_or_init(|| Box::new(OnceList::new())); +/// next.push(value) +/// }; +/// } +/// fn contains(&self, example: &T) -> bool +/// where +/// T: PartialEq, +/// { +/// self.data.get().map(|item| item == example).filter(|v| *v).unwrap_or_else(|| { +/// self.next.get().map(|next| next.contains(example)).unwrap_or(false) +/// }) +/// } +/// } +/// +/// // Let's exercise this new Sync append-only list by doing a little counting +/// static LIST: OnceList = OnceList::new(); +/// static COUNTER: AtomicU32 = AtomicU32::new(0); +/// +/// let vec = (0..thread::available_parallelism().unwrap().get()).map(|_| thread::spawn(|| { +/// while let i @ 0..=1000 = COUNTER.fetch_add(1, Ordering::Relaxed) { +/// LIST.push(i); +/// } +/// })).collect::>>(); +/// vec.into_iter().for_each(|handle| handle.join().unwrap()); +/// +/// for i in 0..=1000 { +/// assert!(LIST.contains(&i)); +/// } +/// +/// ``` #[stable(feature = "once_cell", since = "1.70.0")] pub struct OnceLock { once: Once, From fcc07af4e3abf1cfefbc60a0ce4458ef7cdadfb8 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 3 Jun 2024 13:46:56 +0200 Subject: [PATCH 07/19] Ignore `vec_deque_alloc_error::test_shrink_to_unwind` test on non-unwind targets --- alloc/tests/vec_deque_alloc_error.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/alloc/tests/vec_deque_alloc_error.rs b/alloc/tests/vec_deque_alloc_error.rs index c11f4556da9a6..8b516ddbc5c55 100644 --- a/alloc/tests/vec_deque_alloc_error.rs +++ b/alloc/tests/vec_deque_alloc_error.rs @@ -8,6 +8,7 @@ use std::{ }; #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_shrink_to_unwind() { // This tests that `shrink_to` leaves the deque in a consistent state when // the call to `RawVec::shrink_to_fit` unwinds. The code is adapted from #123369 From 82e24ad44cdce9112fad8d299ffc81b4a239ff12 Mon Sep 17 00:00:00 2001 From: Tim Kurdov Date: Mon, 3 Jun 2024 17:35:58 +0100 Subject: [PATCH 08/19] Fix typo in the docs of `HashMap::raw_entry_mut` --- std/src/collections/hash/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/src/collections/hash/map.rs b/std/src/collections/hash/map.rs index 5039f0b6bb289..fcd1c307b5af6 100644 --- a/std/src/collections/hash/map.rs +++ b/std/src/collections/hash/map.rs @@ -1218,7 +1218,7 @@ where /// will cause the map to produce seemingly random results. Higher-level and /// more foolproof APIs like `entry` should be preferred when possible. /// - /// In particular, the hash used to initialized the raw entry must still be + /// In particular, the hash used to initialize the raw entry must still be /// consistent with the hash of the key that is ultimately stored in the entry. /// This is because implementations of HashMap may need to recompute hashes /// when resizing, at which point only the keys are available. From 31e0022e8f2394cdb23774b9a9a858b926922bad Mon Sep 17 00:00:00 2001 From: David Carlier Date: Mon, 3 Jun 2024 19:01:35 +0000 Subject: [PATCH 09/19] std::unix::fs::get_path: using fcntl codepath for netbsd instead. on netbsd, procfs is not as central as on linux/solaris thus can be perfectly not mounted. Thus using fcntl with F_GETPATH, the kernel deals with MAXPATHLEN internally too. --- std/src/sys/pal/unix/fs.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/std/src/sys/pal/unix/fs.rs b/std/src/sys/pal/unix/fs.rs index fbbd40bfb796a..3d4452e73a640 100644 --- a/std/src/sys/pal/unix/fs.rs +++ b/std/src/sys/pal/unix/fs.rs @@ -1481,29 +1481,33 @@ impl FromRawFd for File { impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[cfg(any( - target_os = "linux", - target_os = "netbsd", - target_os = "illumos", - target_os = "solaris" - ))] + #[cfg(any(target_os = "linux", target_os = "illumos", target_os = "solaris"))] fn get_path(fd: c_int) -> Option { let mut p = PathBuf::from("/proc/self/fd"); p.push(&fd.to_string()); readlink(&p).ok() } - #[cfg(target_vendor = "apple")] + #[cfg(any(target_vendor = "apple", target_os = "netbsd"))] fn get_path(fd: c_int) -> Option { // FIXME: The use of PATH_MAX is generally not encouraged, but it - // is inevitable in this case because Apple targets define `fcntl` + // is inevitable in this case because Apple targets and NetBSD define `fcntl` // with `F_GETPATH` in terms of `MAXPATHLEN`, and there are no // alternatives. If a better method is invented, it should be used // instead. let mut buf = vec![0; libc::PATH_MAX as usize]; let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr()) }; if n == -1 { - return None; + cfg_if::cfg_if! { + if #[cfg(target_os = "netbsd")] { + // fallback to procfs as last resort + let mut p = PathBuf::from("/proc/self/fd"); + p.push(&fd.to_string()); + return readlink(&p).ok(); + } else { + return None; + } + } } let l = buf.iter().position(|&c| c == 0).unwrap(); buf.truncate(l as usize); From 92b604f475fe3667a208f3f869146dbc6c63f3ae Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Thu, 30 May 2024 15:22:12 +0200 Subject: [PATCH 10/19] Pass function for `Thread` as `Send` to `Thread::imp` --- std/src/thread/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/std/src/thread/mod.rs b/std/src/thread/mod.rs index 22215873933d6..83e27dfb746c2 100644 --- a/std/src/thread/mod.rs +++ b/std/src/thread/mod.rs @@ -561,7 +561,8 @@ impl Builder { let main = Box::new(main); // SAFETY: dynamic size and alignment of the Box remain the same. See below for why the // lifetime change is justified. - let main = unsafe { Box::from_raw(Box::into_raw(main) as *mut (dyn FnOnce() + 'static)) }; + let main = + unsafe { Box::from_raw(Box::into_raw(main) as *mut (dyn FnOnce() + Send + 'static)) }; Ok(JoinInner { // SAFETY: @@ -1544,7 +1545,7 @@ struct Packet<'scope, T> { // The type `T` should already always be Send (otherwise the thread could not // have been created) and the Packet is Sync because all access to the // `UnsafeCell` synchronized (by the `join()` boundary), and `ScopeData` is Sync. -unsafe impl<'scope, T: Sync> Sync for Packet<'scope, T> {} +unsafe impl<'scope, T: Send> Sync for Packet<'scope, T> {} impl<'scope, T> Drop for Packet<'scope, T> { fn drop(&mut self) { From 55f3d10071cc5038b7bfc6642c837aa5dafbf335 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Thu, 30 May 2024 15:50:44 +0200 Subject: [PATCH 11/19] Store `Task::p` as `dyn FnOnce() + Send` --- std/src/sys/pal/sgx/thread.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/std/src/sys/pal/sgx/thread.rs b/std/src/sys/pal/sgx/thread.rs index d70c6e31fb73b..2d936b09c708f 100644 --- a/std/src/sys/pal/sgx/thread.rs +++ b/std/src/sys/pal/sgx/thread.rs @@ -28,14 +28,14 @@ mod task_queue { } pub(super) struct Task { - p: Box, + p: Box, done: JoinNotifier, } unsafe impl Send for Task {} impl Task { - pub(super) fn new(p: Box) -> (Task, JoinHandle) { + pub(super) fn new(p: Box) -> (Task, JoinHandle) { let (done, recv) = wait_notify::new(); let done = JoinNotifier(Some(done)); (Task { p, done }, recv) @@ -97,7 +97,7 @@ pub mod wait_notify { impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(_stack: usize, p: Box) -> io::Result { + pub unsafe fn new(_stack: usize, p: Box) -> io::Result { let mut queue_lock = task_queue::lock(); unsafe { usercalls::launch_thread()? }; let (task, handle) = task_queue::Task::new(p); From ea7e91c635772c8259d94ff2d1a1bc54df7b5917 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Thu, 30 May 2024 15:50:59 +0200 Subject: [PATCH 12/19] Let compiler auto impl `Send` for `Task` --- std/src/sys/pal/sgx/thread.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/std/src/sys/pal/sgx/thread.rs b/std/src/sys/pal/sgx/thread.rs index 2d936b09c708f..446cdd18b7e42 100644 --- a/std/src/sys/pal/sgx/thread.rs +++ b/std/src/sys/pal/sgx/thread.rs @@ -32,8 +32,6 @@ mod task_queue { done: JoinNotifier, } - unsafe impl Send for Task {} - impl Task { pub(super) fn new(p: Box) -> (Task, JoinHandle) { let (done, recv) = wait_notify::new(); From b19dd145ea9d5ecd1f0af3d12a5a0dc5e7555dd1 Mon Sep 17 00:00:00 2001 From: Ross MacArthur Date: Tue, 4 Jun 2024 10:51:05 +0200 Subject: [PATCH 13/19] Add function `core::iter::chain` The addition of `core::iter::zip` (#82917) set a precedent for adding plain functions for iterator adaptors. Adding `chain` makes it a little easier to `chain` two iterators. ``` for (x, y) in chain(xs, ys) {} // vs. for (x, y) in xs.into_iter().chain(ys) {} ``` --- core/src/iter/adapters/chain.rs | 37 +++++++++++++++++++++++++++++-- core/src/iter/adapters/mod.rs | 3 +++ core/src/iter/mod.rs | 2 ++ core/tests/iter/adapters/chain.rs | 8 +++++++ core/tests/lib.rs | 1 + 5 files changed, 49 insertions(+), 2 deletions(-) diff --git a/core/src/iter/adapters/chain.rs b/core/src/iter/adapters/chain.rs index bcaac2f42cf04..dad3d79acb183 100644 --- a/core/src/iter/adapters/chain.rs +++ b/core/src/iter/adapters/chain.rs @@ -4,8 +4,8 @@ use crate::ops::Try; /// An iterator that links two iterators together, in a chain. /// -/// This `struct` is created by [`Iterator::chain`]. See its documentation -/// for more. +/// This `struct` is created by [`chain`] or [`Iterator::chain`]. See their +/// documentation for more. /// /// # Examples /// @@ -38,6 +38,39 @@ impl Chain { } } +/// Converts the arguments to iterators and links them together, in a chain. +/// +/// See the documentation of [`Iterator::chain`] for more. +/// +/// # Examples +/// +/// ``` +/// #![feature(iter_chain)] +/// +/// use std::iter::chain; +/// +/// let a = [1, 2, 3]; +/// let b = [4, 5, 6]; +/// +/// let mut iter = chain(a, b); +/// +/// assert_eq!(iter.next(), Some(1)); +/// assert_eq!(iter.next(), Some(2)); +/// assert_eq!(iter.next(), Some(3)); +/// assert_eq!(iter.next(), Some(4)); +/// assert_eq!(iter.next(), Some(5)); +/// assert_eq!(iter.next(), Some(6)); +/// assert_eq!(iter.next(), None); +/// ``` +#[unstable(feature = "iter_chain", reason = "recently added", issue = "125964")] +pub fn chain(a: A, b: B) -> Chain +where + A: IntoIterator, + B: IntoIterator, +{ + Chain::new(a.into_iter(), b.into_iter()) +} + #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for Chain where diff --git a/core/src/iter/adapters/mod.rs b/core/src/iter/adapters/mod.rs index cc514bd914f14..05a5f2689056b 100644 --- a/core/src/iter/adapters/mod.rs +++ b/core/src/iter/adapters/mod.rs @@ -41,6 +41,9 @@ pub use self::array_chunks::ArrayChunks; #[unstable(feature = "std_internals", issue = "none")] pub use self::by_ref_sized::ByRefSized; +#[unstable(feature = "iter_chain", reason = "recently added", issue = "125964")] +pub use self::chain::chain; + #[stable(feature = "iter_cloned", since = "1.1.0")] pub use self::cloned::Cloned; diff --git a/core/src/iter/mod.rs b/core/src/iter/mod.rs index 44fef3e145b78..921c75c85f161 100644 --- a/core/src/iter/mod.rs +++ b/core/src/iter/mod.rs @@ -428,6 +428,8 @@ pub use self::traits::{ DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator, IntoIterator, Product, Sum, }; +#[unstable(feature = "iter_chain", reason = "recently added", issue = "125964")] +pub use self::adapters::chain; #[stable(feature = "iter_zip", since = "1.59.0")] pub use self::adapters::zip; #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] diff --git a/core/tests/iter/adapters/chain.rs b/core/tests/iter/adapters/chain.rs index b2429588de12b..c93510df524cf 100644 --- a/core/tests/iter/adapters/chain.rs +++ b/core/tests/iter/adapters/chain.rs @@ -2,6 +2,14 @@ use super::*; use core::iter::*; use core::num::NonZero; +#[test] +fn test_chain() { + let xs = [0, 1, 2, 3, 4, 5]; + let ys = [30, 40, 50, 60]; + let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; + assert_eq!(Vec::from_iter(chain(xs, ys)), expected); +} + #[test] fn test_iterator_chain() { let xs = [0, 1, 2, 3, 4, 5]; diff --git a/core/tests/lib.rs b/core/tests/lib.rs index e0f82c916635e..20ff6fd7687fe 100644 --- a/core/tests/lib.rs +++ b/core/tests/lib.rs @@ -75,6 +75,7 @@ #![feature(ip)] #![feature(iter_advance_by)] #![feature(iter_array_chunks)] +#![feature(iter_chain)] #![feature(iter_collect_into)] #![feature(iter_partition_in_place)] #![feature(iter_intersperse)] From fbb5246b92c4c41e24ba44a6dc935587f41a17aa Mon Sep 17 00:00:00 2001 From: Andrei Damian Date: Tue, 4 Jun 2024 18:49:13 +0300 Subject: [PATCH 14/19] Make deleting on LinkedList aware of the allocator --- alloc/src/collections/linked_list.rs | 4 +-- alloc/src/collections/linked_list/tests.rs | 39 ++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/alloc/src/collections/linked_list.rs b/alloc/src/collections/linked_list.rs index 1c90c171a155b..01510a6140512 100644 --- a/alloc/src/collections/linked_list.rs +++ b/alloc/src/collections/linked_list.rs @@ -1705,7 +1705,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { unsafe { self.current = unlinked_node.as_ref().next; self.list.unlink_node(unlinked_node); - let unlinked_node = Box::from_raw(unlinked_node.as_ptr()); + let unlinked_node = Box::from_raw_in(unlinked_node.as_ptr(), &self.list.alloc); Some(unlinked_node.element) } } @@ -1946,7 +1946,7 @@ where if (self.pred)(&mut node.as_mut().element) { // `unlink_node` is okay with aliasing `element` references. self.list.unlink_node(node); - return Some(Box::from_raw(node.as_ptr()).element); + return Some(Box::from_raw_in(node.as_ptr(), &self.list.alloc).element); } } } diff --git a/alloc/src/collections/linked_list/tests.rs b/alloc/src/collections/linked_list/tests.rs index 8dcd59d12d927..d3744c5a9d0c9 100644 --- a/alloc/src/collections/linked_list/tests.rs +++ b/alloc/src/collections/linked_list/tests.rs @@ -1164,3 +1164,42 @@ fn test_drop_panic() { assert_eq!(unsafe { DROPS }, 8); } + +#[test] +fn test_allocator() { + use core::alloc::AllocError; + use core::alloc::Allocator; + use core::alloc::Layout; + use core::cell::Cell; + + struct A { + has_allocated: Cell, + has_deallocated: Cell, + } + + unsafe impl Allocator for A { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + assert!(!self.has_allocated.get()); + self.has_allocated.set(true); + + Global.allocate(layout) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + assert!(!self.has_deallocated.get()); + self.has_deallocated.set(true); + + unsafe { Global.deallocate(ptr, layout) } + } + } + + let alloc = &A { has_allocated: Cell::new(false), has_deallocated: Cell::new(false) }; + { + let mut list = LinkedList::new_in(alloc); + list.push_back(5u32); + list.remove(0); + } + + assert!(alloc.has_allocated.get()); + assert!(alloc.has_deallocated.get()); +} From a2c3406e6262e9bae68c9a14694953c8d67b7060 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Sun, 12 May 2024 21:31:13 -0700 Subject: [PATCH 15/19] Use inline const instead of unsafe to construct arrays in `MaybeUninit` examples. --- core/src/mem/maybe_uninit.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/core/src/mem/maybe_uninit.rs b/core/src/mem/maybe_uninit.rs index 026e21586d403..56af7fa9c89c2 100644 --- a/core/src/mem/maybe_uninit.rs +++ b/core/src/mem/maybe_uninit.rs @@ -120,12 +120,8 @@ use crate::slice; /// use std::mem::{self, MaybeUninit}; /// /// let data = { -/// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is -/// // safe because the type we are claiming to have initialized here is a -/// // bunch of `MaybeUninit`s, which do not require initialization. -/// let mut data: [MaybeUninit>; 1000] = unsafe { -/// MaybeUninit::uninit().assume_init() -/// }; +/// // Create an uninitialized array of `MaybeUninit`. +/// let mut data: [MaybeUninit>; 1000] = [const { MaybeUninit::uninit() }; 1000]; /// /// // Dropping a `MaybeUninit` does nothing, so if there is a panic during this loop, /// // we have a memory leak, but there is no memory safety issue. @@ -147,10 +143,8 @@ use crate::slice; /// ``` /// use std::mem::MaybeUninit; /// -/// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is -/// // safe because the type we are claiming to have initialized here is a -/// // bunch of `MaybeUninit`s, which do not require initialization. -/// let mut data: [MaybeUninit; 1000] = unsafe { MaybeUninit::uninit().assume_init() }; +/// // Create an uninitialized array of `MaybeUninit`. +/// let mut data: [MaybeUninit; 1000] = [const { MaybeUninit::uninit() }; 1000]; /// // Count the number of elements we have assigned. /// let mut data_len: usize = 0; /// From 14a6f295bcdb6464c8e8687a60b877d6d1ac001a Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Sun, 12 May 2024 21:36:09 -0700 Subject: [PATCH 16/19] Use inline const instead of unsafe to implement `MaybeUninit::uninit_array()`. --- core/src/mem/maybe_uninit.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/mem/maybe_uninit.rs b/core/src/mem/maybe_uninit.rs index 56af7fa9c89c2..4175d4a33294b 100644 --- a/core/src/mem/maybe_uninit.rs +++ b/core/src/mem/maybe_uninit.rs @@ -342,8 +342,7 @@ impl MaybeUninit { #[must_use] #[inline(always)] pub const fn uninit_array() -> [Self; N] { - // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid. - unsafe { MaybeUninit::<[MaybeUninit; N]>::uninit().assume_init() } + [const { MaybeUninit::uninit() }; N] } /// Creates a new `MaybeUninit` in an uninitialized state, with the memory being From bf7430fdc683f5d1efb590b5480aec8c318ce0be Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 5 Jun 2024 14:28:42 +0000 Subject: [PATCH 17/19] Update description of the `IsTerminal` example --- std/src/io/stdio.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/std/src/io/stdio.rs b/std/src/io/stdio.rs index c8968b74b12d1..9aee2bb5e1c5c 100644 --- a/std/src/io/stdio.rs +++ b/std/src/io/stdio.rs @@ -1190,9 +1190,8 @@ pub trait IsTerminal: crate::sealed::Sealed { /// /// - If you run this example by piping some text to it, e.g. `echo "foo" | path/to/executable` /// it will print: `Hello foo`. - /// - If you instead run the example interactively by running the executable directly, it will - /// panic with the message "Expected input to be piped to the process". - /// + /// - If you instead run the example interactively by running `path/to/executable` directly, it will + /// prompt for input. /// /// [changes]: io#platform-specific-behavior /// [`Stdin`]: crate::io::Stdin From 051c6c609775adfa361fc7b41b28b3bfee79a2ae Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Wed, 5 Jun 2024 23:06:15 -0700 Subject: [PATCH 18/19] Raise `DEFAULT_MIN_STACK_SIZE` to at least 64KiB Prevent copy-paste errors from producing new starved-for-resources threaded platforms by raising `DEFAULT_MIN_STACK_SIZE` from 4096 bytes to at least 64KiB. Two platforms "affected" by this have no actual threads: - UEFI - "unsupported" Platforms that this actually affects: - wasm32-wasi with "atomics" enabled - wasm32-wasi-p1-threads Two exceptions: - SGX: a "secure code execution" platform, stays at 4096B - TEEOS: also a "secure code execution" platform, stays at 8192B I believe either of these may have sufficiently "interesting" semantics around threads, or significant external library support. Either would mean making any choices here for them is suspect. --- std/src/sys/pal/uefi/thread.rs | 2 +- std/src/sys/pal/unsupported/thread.rs | 2 +- std/src/sys/pal/wasi/thread.rs | 2 +- std/src/sys/pal/wasm/atomics/thread.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/std/src/sys/pal/uefi/thread.rs b/std/src/sys/pal/uefi/thread.rs index edc736978a123..7d4006ff4b2f7 100644 --- a/std/src/sys/pal/uefi/thread.rs +++ b/std/src/sys/pal/uefi/thread.rs @@ -7,7 +7,7 @@ use crate::time::Duration; pub struct Thread(!); -pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; +pub const DEFAULT_MIN_STACK_SIZE: usize = 64 * 1024; impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements diff --git a/std/src/sys/pal/unsupported/thread.rs b/std/src/sys/pal/unsupported/thread.rs index ea939247199c2..89f8bad7026ee 100644 --- a/std/src/sys/pal/unsupported/thread.rs +++ b/std/src/sys/pal/unsupported/thread.rs @@ -6,7 +6,7 @@ use crate::time::Duration; pub struct Thread(!); -pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; +pub const DEFAULT_MIN_STACK_SIZE: usize = 64 * 1024; impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements diff --git a/std/src/sys/pal/wasi/thread.rs b/std/src/sys/pal/wasi/thread.rs index d45fb28b67e63..975eef2451f4c 100644 --- a/std/src/sys/pal/wasi/thread.rs +++ b/std/src/sys/pal/wasi/thread.rs @@ -66,7 +66,7 @@ cfg_if::cfg_if! { } } -pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; +pub const DEFAULT_MIN_STACK_SIZE: usize = 64 * 1024; impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements diff --git a/std/src/sys/pal/wasm/atomics/thread.rs b/std/src/sys/pal/wasm/atomics/thread.rs index 49f936f14498c..484bd08495eef 100644 --- a/std/src/sys/pal/wasm/atomics/thread.rs +++ b/std/src/sys/pal/wasm/atomics/thread.rs @@ -6,7 +6,7 @@ use crate::time::Duration; pub struct Thread(!); -pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; +pub const DEFAULT_MIN_STACK_SIZE: usize = 64 * 1024; impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements From 57369442f0d212b90444ce253e45d2dd3a807676 Mon Sep 17 00:00:00 2001 From: Caio Date: Thu, 6 Jun 2024 16:30:05 -0300 Subject: [PATCH 19/19] [RFC-2011] Allow `core_intrinsics` when activated --- core/src/macros/mod.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/src/macros/mod.rs b/core/src/macros/mod.rs index 9bbaf62a5caaf..395e04cf26e95 100644 --- a/core/src/macros/mod.rs +++ b/core/src/macros/mod.rs @@ -1534,7 +1534,12 @@ pub(crate) mod builtin { #[rustc_builtin_macro] #[macro_export] #[rustc_diagnostic_item = "assert_macro"] - #[allow_internal_unstable(panic_internals, edition_panic, generic_assert_internals)] + #[allow_internal_unstable( + core_intrinsics, + panic_internals, + edition_panic, + generic_assert_internals + )] macro_rules! assert { ($cond:expr $(,)?) => {{ /* compiler built-in */ }}; ($cond:expr, $($arg:tt)+) => {{ /* compiler built-in */ }};