diff --git a/library/alloc/src/boxed/convert.rs b/library/alloc/src/boxed/convert.rs index 45c46fb52636..73940db5d2f5 100644 --- a/library/alloc/src/boxed/convert.rs +++ b/library/alloc/src/boxed/convert.rs @@ -1,4 +1,6 @@ use core::any::Any; +#[cfg(not(no_global_oom_handling))] +use core::clone::TrivialClone; use core::error::Error; use core::mem; use core::pin::Pin; @@ -75,11 +77,13 @@ impl BoxFromSlice for Box<[T]> { } #[cfg(not(no_global_oom_handling))] -impl BoxFromSlice for Box<[T]> { +impl BoxFromSlice for Box<[T]> { #[inline] fn from_slice(slice: &[T]) -> Self { let len = slice.len(); let buf = RawVec::with_capacity(len); + // SAFETY: since `T` implements `TrivialClone`, this is sound and + // equivalent to the above. unsafe { ptr::copy_nonoverlapping(slice.as_ptr(), buf.ptr(), len); buf.into_box(slice.len()).assume_init() diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 1d4b3b558c01..78930364a926 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -7,6 +7,8 @@ #![stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(no_global_oom_handling))] +use core::clone::TrivialClone; use core::cmp::{self, Ordering}; use core::hash::{Hash, Hasher}; use core::iter::{ByRefSized, repeat_n, repeat_with}; @@ -3419,7 +3421,7 @@ impl SpecExtendFromWithin for VecDeque { } #[cfg(not(no_global_oom_handling))] -impl SpecExtendFromWithin for VecDeque { +impl SpecExtendFromWithin for VecDeque { unsafe fn spec_extend_from_within(&mut self, src: Range) { let dst = self.len(); let count = src.end - src.start; diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 73197d021f1a..666ae27fb863 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -146,6 +146,7 @@ #![feature(std_internals)] #![feature(str_internals)] #![feature(temporary_niche_types)] +#![feature(trivial_clone)] #![feature(trusted_fused)] #![feature(trusted_len)] #![feature(trusted_random_access)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index f0ce6aa03a8b..581c714998f9 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -243,9 +243,9 @@ use core::any::Any; use core::cell::{Cell, CloneFromCell}; -#[cfg(not(no_global_oom_handling))] -use core::clone::CloneToUninit; use core::clone::UseCloned; +#[cfg(not(no_global_oom_handling))] +use core::clone::{CloneToUninit, TrivialClone}; use core::cmp::Ordering; use core::hash::{Hash, Hasher}; use core::intrinsics::abort; @@ -2224,7 +2224,8 @@ impl Rc<[T]> { /// Copy elements from slice into newly allocated `Rc<[T]>` /// - /// Unsafe because the caller must either take ownership or bind `T: Copy` + /// Unsafe because the caller must either take ownership, bind `T: Copy` or + /// bind `T: TrivialClone`. #[cfg(not(no_global_oom_handling))] unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> { unsafe { @@ -2314,9 +2315,11 @@ impl RcFromSlice for Rc<[T]> { } #[cfg(not(no_global_oom_handling))] -impl RcFromSlice for Rc<[T]> { +impl RcFromSlice for Rc<[T]> { #[inline] fn from_slice(v: &[T]) -> Self { + // SAFETY: `T` implements `TrivialClone`, so this is sound and equivalent + // to the above. unsafe { Rc::copy_from_slice(v) } } } diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index ce9f967cc387..a83b51ccb60c 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -11,6 +11,8 @@ use core::borrow::{Borrow, BorrowMut}; #[cfg(not(no_global_oom_handling))] +use core::clone::TrivialClone; +#[cfg(not(no_global_oom_handling))] use core::cmp::Ordering::{self, Less}; #[cfg(not(no_global_oom_handling))] use core::mem::MaybeUninit; @@ -439,7 +441,7 @@ impl [T] { } } - impl ConvertVec for T { + impl ConvertVec for T { #[inline] fn to_vec(s: &[Self], alloc: A) -> Vec { let mut v = Vec::with_capacity_in(s.len(), alloc); @@ -822,7 +824,7 @@ impl SpecCloneIntoVec for [T] { } #[cfg(not(no_global_oom_handling))] -impl SpecCloneIntoVec for [T] { +impl SpecCloneIntoVec for [T] { fn clone_into(&self, target: &mut Vec) { target.clear(); target.extend_from_slice(self); diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index b85293973fd5..6fb8df0f8c20 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -12,6 +12,8 @@ use core::any::Any; use core::cell::CloneFromCell; #[cfg(not(no_global_oom_handling))] use core::clone::CloneToUninit; +#[cfg(not(no_global_oom_handling))] +use core::clone::TrivialClone; use core::clone::UseCloned; use core::cmp::Ordering; use core::hash::{Hash, Hasher}; @@ -2156,7 +2158,8 @@ impl Arc<[T]> { /// Copy elements from slice into newly allocated `Arc<[T]>` /// - /// Unsafe because the caller must either take ownership or bind `T: Copy`. + /// Unsafe because the caller must either take ownership, bind `T: Copy` or + /// bind `T: TrivialClone`. #[cfg(not(no_global_oom_handling))] unsafe fn copy_from_slice(v: &[T]) -> Arc<[T]> { unsafe { @@ -2248,9 +2251,11 @@ impl ArcFromSlice for Arc<[T]> { } #[cfg(not(no_global_oom_handling))] -impl ArcFromSlice for Arc<[T]> { +impl ArcFromSlice for Arc<[T]> { #[inline] fn from_slice(v: &[T]) -> Self { + // SAFETY: `T` implements `TrivialClone`, so this is sound and equivalent + // to the above. unsafe { Arc::copy_from_slice(v) } } } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index dc610d7b4674..43a68ff20373 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -73,6 +73,8 @@ #![stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(no_global_oom_handling))] +use core::clone::TrivialClone; #[cfg(not(no_global_oom_handling))] use core::cmp; use core::cmp::Ordering; @@ -3494,7 +3496,7 @@ impl ExtendFromWithinSpec for Vec { } #[cfg(not(no_global_oom_handling))] -impl ExtendFromWithinSpec for Vec { +impl ExtendFromWithinSpec for Vec { unsafe fn spec_extend_from_within(&mut self, src: Range) { let count = src.len(); { @@ -3507,8 +3509,8 @@ impl ExtendFromWithinSpec for Vec { // SAFETY: // - Both pointers are created from unique slice references (`&mut [_]`) // so they are valid and do not overlap. - // - Elements are :Copy so it's OK to copy them, without doing - // anything with the original values + // - Elements implement `TrivialClone` so this is equivalent to calling + // `clone` on every one of them. // - `count` is equal to the len of `source`, so source is valid for // `count` reads // - `.reserve(count)` guarantees that `spare.len() >= count` so spare diff --git a/library/alloc/src/vec/spec_extend.rs b/library/alloc/src/vec/spec_extend.rs index 7085bceef5ba..f5bcd3ec9d82 100644 --- a/library/alloc/src/vec/spec_extend.rs +++ b/library/alloc/src/vec/spec_extend.rs @@ -1,3 +1,4 @@ +use core::clone::TrivialClone; use core::iter::TrustedLen; use core::slice::{self}; @@ -48,7 +49,7 @@ where impl<'a, T: 'a, A: Allocator> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec where - T: Copy, + T: TrivialClone, { fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) { let slice = iterator.as_slice(); diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs index efdcb893bfee..665bc2704794 100644 --- a/library/alloctests/lib.rs +++ b/library/alloctests/lib.rs @@ -40,6 +40,7 @@ #![feature(slice_range)] #![feature(std_internals)] #![feature(temporary_niche_types)] +#![feature(trivial_clone)] #![feature(trusted_fused)] #![feature(trusted_len)] #![feature(trusted_random_access)] diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 0dc10758a856..68bc7eb6f811 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -5,10 +5,10 @@ #![stable(feature = "core_array", since = "1.35.0")] use crate::borrow::{Borrow, BorrowMut}; +use crate::clone::TrivialClone; use crate::cmp::Ordering; use crate::convert::Infallible; use crate::error::Error; -use crate::fmt; use crate::hash::{self, Hash}; use crate::intrinsics::transmute_unchecked; use crate::iter::{UncheckedIterator, repeat_n}; @@ -18,6 +18,7 @@ use crate::ops::{ }; use crate::ptr::{null, null_mut}; use crate::slice::{Iter, IterMut}; +use crate::{fmt, ptr}; mod ascii; mod drain; @@ -451,6 +452,9 @@ impl Clone for [T; N] { } } +#[unstable(feature = "trivial_clone", issue = "none")] +unsafe impl TrivialClone for [T; N] {} + trait SpecArrayClone: Clone { fn clone(array: &[Self; N]) -> [Self; N]; } @@ -462,10 +466,12 @@ impl SpecArrayClone for T { } } -impl SpecArrayClone for T { +impl SpecArrayClone for T { #[inline] fn clone(array: &[T; N]) -> [T; N] { - *array + // SAFETY: `TrivialClone` implies that this is equivalent to calling + // `Clone` on every element. + unsafe { ptr::read(array) } } } diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 06d2c93cc698..3cf8b51d50e6 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -250,6 +250,33 @@ pub const trait Clone: Sized { } } +/// Indicates that the `Clone` implementation is identical to copying the value. +/// +/// This is used for some optimizations in the standard library, which specializes +/// on this trait to select faster implementations of functions such as +/// [`clone_from_slice`](slice::clone_from_slice). It is automatically implemented +/// when using `#[derive(Clone, Copy)]`. +/// +/// Note that this trait does not imply that the type is `Copy`, because e.g. +/// `core::ops::Range` could soundly implement this trait. +/// +/// # Safety +/// `Clone::clone` must be equivalent to copying the value, otherwise calling functions +/// such as `slice::clone_from_slice` can have undefined behaviour. +#[unstable( + feature = "trivial_clone", + reason = "this isn't part of any API guarantee", + issue = "none" +)] +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] +// SAFETY: +// It is sound to specialize on this because the `clone` implementation cannot be +// lifetime-dependent. Therefore, if `TrivialClone` is implemented for any lifetime, +// its invariant holds whenever `Clone` is implemented, even if the actual +// `TrivialClone` bound would not be satisfied because of lifetime bounds. +#[rustc_unsafe_specialization_marker] +pub const unsafe trait TrivialClone: [const] Clone {} + /// Derive macro generating an impl of the trait `Clone`. #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] @@ -569,6 +596,7 @@ unsafe impl CloneToUninit for crate::bstr::ByteStr { /// are implemented in `traits::SelectionContext::copy_clone_conditions()` /// in `rustc_trait_selection`. mod impls { + use super::TrivialClone; use crate::marker::PointeeSized; macro_rules! impl_clone { @@ -582,6 +610,10 @@ mod impls { *self } } + + #[unstable(feature = "trivial_clone", issue = "none")] + #[rustc_const_unstable(feature = "const_clone", issue = "142757")] + unsafe impl const TrivialClone for $t {} )* } } @@ -602,6 +634,10 @@ mod impls { } } + #[unstable(feature = "trivial_clone", issue = "none")] + #[rustc_const_unstable(feature = "const_clone", issue = "142757")] + unsafe impl const TrivialClone for ! {} + #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_clone", issue = "142757")] impl const Clone for *const T { @@ -611,6 +647,10 @@ mod impls { } } + #[unstable(feature = "trivial_clone", issue = "none")] + #[rustc_const_unstable(feature = "const_clone", issue = "142757")] + unsafe impl const TrivialClone for *const T {} + #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_clone", issue = "142757")] impl const Clone for *mut T { @@ -620,6 +660,10 @@ mod impls { } } + #[unstable(feature = "trivial_clone", issue = "none")] + #[rustc_const_unstable(feature = "const_clone", issue = "142757")] + unsafe impl const TrivialClone for *mut T {} + /// Shared references can be cloned, but mutable references *cannot*! #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_clone", issue = "142757")] @@ -631,6 +675,10 @@ mod impls { } } + #[unstable(feature = "trivial_clone", issue = "none")] + #[rustc_const_unstable(feature = "const_clone", issue = "142757")] + unsafe impl const TrivialClone for &T {} + /// Shared references can be cloned, but mutable references *cannot*! #[stable(feature = "rust1", since = "1.0.0")] impl !Clone for &mut T {} diff --git a/library/core/src/clone/uninit.rs b/library/core/src/clone/uninit.rs index 8b738bec796d..8d1185067eb8 100644 --- a/library/core/src/clone/uninit.rs +++ b/library/core/src/clone/uninit.rs @@ -1,3 +1,4 @@ +use super::TrivialClone; use crate::mem::{self, MaybeUninit}; use crate::ptr; @@ -49,9 +50,9 @@ unsafe impl CopySpec for T { } } -// Specialized implementation for types that are [`Copy`], not just [`Clone`], +// Specialized implementation for types that are [`TrivialClone`], not just [`Clone`], // and can therefore be copied bitwise. -unsafe impl CopySpec for T { +unsafe impl CopySpec for T { #[inline] unsafe fn clone_one(src: &Self, dst: *mut Self) { // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 5fd0611a1843..64a403ce8cdb 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -14,6 +14,7 @@ pub use self::variance::{ PhantomInvariant, PhantomInvariantLifetime, Variance, variance, }; use crate::cell::UnsafeCell; +use crate::clone::TrivialClone; use crate::cmp; use crate::fmt::Debug; use crate::hash::{Hash, Hasher}; @@ -454,12 +455,8 @@ marker_impls! { /// [impls]: #implementors #[stable(feature = "rust1", since = "1.0.0")] #[lang = "copy"] -// FIXME(matthewjasper) This allows copying a type that doesn't implement -// `Copy` because of unsatisfied lifetime bounds (copying `A<'_>` when only -// `A<'static>: Copy` and `A<'_>: Clone`). -// We have this attribute here for now only because there are quite a few -// existing specializations on `Copy` that already exist in the standard -// library, and there's no way to safely have this behavior right now. +// This is unsound, but required by `hashbrown` +// FIXME(joboet): change `hashbrown` to use `TrivialClone` #[rustc_unsafe_specialization_marker] #[rustc_diagnostic_item = "Copy"] pub trait Copy: Clone { @@ -861,6 +858,9 @@ impl Clone for PhantomData { } } +#[unstable(feature = "trivial_clone", issue = "none")] +unsafe impl TrivialClone for PhantomData {} + #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_default", issue = "143894")] impl const Default for PhantomData { diff --git a/library/core/src/marker/variance.rs b/library/core/src/marker/variance.rs index 55fdacb014e6..860d28262cae 100644 --- a/library/core/src/marker/variance.rs +++ b/library/core/src/marker/variance.rs @@ -2,6 +2,7 @@ use super::PhantomData; use crate::any::type_name; +use crate::clone::TrivialClone; use crate::cmp::Ordering; use crate::fmt; use crate::hash::{Hash, Hasher}; @@ -60,6 +61,8 @@ macro_rules! phantom_type { impl Copy for $name where T: ?Sized {} + unsafe impl TrivialClone for $name where T: ?Sized {} + impl PartialEq for $name where T: ?Sized { diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 4ed914386eb8..33a6ea9ca7d1 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -1,4 +1,5 @@ use crate::any::type_name; +use crate::clone::TrivialClone; use crate::marker::Destruct; use crate::mem::ManuallyDrop; use crate::{fmt, intrinsics, ptr, slice}; @@ -356,6 +357,10 @@ impl Clone for MaybeUninit { } } +// SAFETY: the clone implementation is a copy, see above. +#[unstable(feature = "trivial_clone", issue = "none")] +unsafe impl TrivialClone for MaybeUninit where MaybeUninit: Clone {} + #[stable(feature = "maybe_uninit_debug", since = "1.41.0")] impl fmt::Debug for MaybeUninit { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -1599,8 +1604,12 @@ impl SpecFill for [MaybeUninit] { } } -impl SpecFill for [MaybeUninit] { +impl SpecFill for [MaybeUninit] { fn spec_fill(&mut self, value: T) { - self.fill(MaybeUninit::new(value)); + // SAFETY: because `T` is `TrivialClone`, this is equivalent to calling + // `T::clone` for every element. Notably, `TrivialClone` also implies + // that the `clone` implementation will not panic, so we can avoid + // initialization guards and such. + self.fill_with(|| MaybeUninit::new(unsafe { ptr::read(&value) })); } } diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 619e8a263db4..8332d6cfc028 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -6,6 +6,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::alloc::Layout; +use crate::clone::TrivialClone; use crate::marker::{Destruct, DiscriminantKind}; use crate::panic::const_assert; use crate::{clone, cmp, fmt, hash, intrinsics, ptr}; @@ -1070,6 +1071,9 @@ impl clone::Clone for Discriminant { } } +#[unstable(feature = "trivial_clone", issue = "none")] +unsafe impl TrivialClone for Discriminant {} + #[stable(feature = "discriminant_value", since = "1.21.0")] impl cmp::PartialEq for Discriminant { fn eq(&self, rhs: &Self) -> bool { diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 8cd8b0850e94..9685f521b38c 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1,7 +1,7 @@ //! Definitions of integer that is known not to equal zero. use super::{IntErrorKind, ParseIntError}; -use crate::clone::UseCloned; +use crate::clone::{TrivialClone, UseCloned}; use crate::cmp::Ordering; use crate::hash::{Hash, Hasher}; use crate::marker::{Destruct, Freeze, StructuralPartialEq}; @@ -199,6 +199,9 @@ impl UseCloned for NonZero where T: ZeroablePrimitive {} #[stable(feature = "nonzero", since = "1.28.0")] impl Copy for NonZero where T: ZeroablePrimitive {} +#[unstable(feature = "trivial_clone", issue = "none")] +unsafe impl TrivialClone for NonZero where T: ZeroablePrimitive {} + #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] impl const PartialEq for NonZero diff --git a/library/core/src/option.rs b/library/core/src/option.rs index e3c4758bc6af..3e42f954b8f4 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -581,6 +581,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use crate::clone::TrivialClone; use crate::iter::{self, FusedIterator, TrustedLen}; use crate::marker::Destruct; use crate::ops::{self, ControlFlow, Deref, DerefMut}; @@ -2215,6 +2216,10 @@ where #[unstable(feature = "ergonomic_clones", issue = "132290")] impl crate::clone::UseCloned for Option where T: crate::clone::UseCloned {} +#[unstable(feature = "trivial_clone", issue = "none")] +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] +unsafe impl const TrivialClone for Option where T: [const] TrivialClone + [const] Destruct {} + #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_default", issue = "143894")] impl const Default for Option { diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index dc3ec3fd1994..ece195c2fe4a 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -1,5 +1,6 @@ #![unstable(feature = "ptr_metadata", issue = "81513")] +use crate::clone::TrivialClone; use crate::fmt; use crate::hash::{Hash, Hasher}; use crate::intrinsics::{aggregate_raw_ptr, ptr_metadata}; @@ -231,6 +232,8 @@ impl Clone for DynMetadata { } } +unsafe impl TrivialClone for DynMetadata {} + impl Eq for DynMetadata {} impl PartialEq for DynMetadata { diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index a762e969b52d..8f4538d9c803 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1,3 +1,4 @@ +use crate::clone::TrivialClone; use crate::cmp::Ordering; use crate::marker::{Destruct, PointeeSized, Unsize}; use crate::mem::{MaybeUninit, SizedTypeProperties}; @@ -1653,6 +1654,9 @@ impl Clone for NonNull { #[stable(feature = "nonnull", since = "1.25.0")] impl Copy for NonNull {} +#[unstable(feature = "trivial_clone", issue = "none")] +unsafe impl TrivialClone for NonNull {} + #[unstable(feature = "coerce_unsized", issue = "18598")] impl CoerceUnsized> for NonNull where T: Unsize {} diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs index cdc8b6cc936d..85e006b98b8b 100644 --- a/library/core/src/ptr/unique.rs +++ b/library/core/src/ptr/unique.rs @@ -1,3 +1,4 @@ +use crate::clone::TrivialClone; use crate::fmt; use crate::marker::{PhantomData, PointeeSized, Unsize}; use crate::ops::{CoerceUnsized, DispatchFromDyn}; @@ -165,6 +166,9 @@ impl Clone for Unique { #[unstable(feature = "ptr_internals", issue = "none")] impl Copy for Unique {} +#[unstable(feature = "trivial_clone", issue = "none")] +unsafe impl TrivialClone for Unique {} + #[unstable(feature = "ptr_internals", issue = "none")] impl CoerceUnsized> for Unique where T: Unsize {} diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 1d88eb33dce1..f03f2045444d 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -6,6 +6,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use crate::clone::TrivialClone; use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::intrinsics::{exact_div, unchecked_sub}; use crate::mem::{self, MaybeUninit, SizedTypeProperties}; @@ -3890,30 +3891,8 @@ impl [T] { where T: Copy, { - // The panic code path was put into a cold function to not bloat the - // call site. - #[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] - #[cfg_attr(panic = "immediate-abort", inline)] - #[track_caller] - const fn len_mismatch_fail(dst_len: usize, src_len: usize) -> ! { - const_panic!( - "copy_from_slice: source slice length does not match destination slice length", - "copy_from_slice: source slice length ({src_len}) does not match destination slice length ({dst_len})", - src_len: usize, - dst_len: usize, - ) - } - - if self.len() != src.len() { - len_mismatch_fail(self.len(), src.len()); - } - - // SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was - // checked to have the same length. The slices cannot overlap because - // mutable references are exclusive. - unsafe { - ptr::copy_nonoverlapping(src.as_ptr(), self.as_mut_ptr(), self.len()); - } + // SAFETY: `T` implements `Copy`. + unsafe { copy_from_slice_impl(self, src) } } /// Copies elements from one part of the slice to another part of itself, @@ -5123,6 +5102,38 @@ impl [f64] { } } +/// Copies `src` to `dest`. +/// +/// # Safety +/// `T` must implement one of `Copy` or `TrivialClone`. +#[track_caller] +const unsafe fn copy_from_slice_impl(dest: &mut [T], src: &[T]) { + // The panic code path was put into a cold function to not bloat the + // call site. + #[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] + #[cfg_attr(panic = "immediate-abort", inline)] + #[track_caller] + const fn len_mismatch_fail(dst_len: usize, src_len: usize) -> ! { + const_panic!( + "copy_from_slice: source slice length does not match destination slice length", + "copy_from_slice: source slice length ({src_len}) does not match destination slice length ({dst_len})", + src_len: usize, + dst_len: usize, + ) + } + + if dest.len() != src.len() { + len_mismatch_fail(dest.len(), src.len()); + } + + // SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was + // checked to have the same length. The slices cannot overlap because + // mutable references are exclusive. + unsafe { + ptr::copy_nonoverlapping(src.as_ptr(), dest.as_mut_ptr(), dest.len()); + } +} + trait CloneFromSpec { fn spec_clone_from(&mut self, src: &[T]); } @@ -5147,11 +5158,14 @@ where impl CloneFromSpec for [T] where - T: Copy, + T: TrivialClone, { #[track_caller] fn spec_clone_from(&mut self, src: &[T]) { - self.copy_from_slice(src); + // SAFETY: `T` implements `TrivialClone`. + unsafe { + copy_from_slice_impl(self, src); + } } } diff --git a/library/core/src/slice/specialize.rs b/library/core/src/slice/specialize.rs index 17436395fee6..c44225b75364 100644 --- a/library/core/src/slice/specialize.rs +++ b/library/core/src/slice/specialize.rs @@ -1,3 +1,6 @@ +use crate::clone::TrivialClone; +use crate::ptr; + pub(super) trait SpecFill { fn spec_fill(&mut self, value: T); } @@ -14,10 +17,12 @@ impl SpecFill for [T] { } } -impl SpecFill for [T] { +impl SpecFill for [T] { default fn spec_fill(&mut self, value: T) { for item in self.iter_mut() { - *item = value; + // SAFETY: `TrivialClone` indicates that this is equivalent to + // calling `Clone::clone` + *item = unsafe { ptr::read(&value) }; } } } diff --git a/library/core/src/sync/exclusive.rs b/library/core/src/sync/exclusive.rs index f181c5514f25..7c79a191e409 100644 --- a/library/core/src/sync/exclusive.rs +++ b/library/core/src/sync/exclusive.rs @@ -1,5 +1,6 @@ //! Defines [`Exclusive`]. +use core::clone::TrivialClone; use core::cmp::Ordering; use core::fmt; use core::future::Future; @@ -261,6 +262,9 @@ where } } +#[unstable(feature = "trivial_clone", issue = "none")] +unsafe impl TrivialClone for Exclusive where T: Sync + TrivialClone {} + #[unstable(feature = "exclusive_wrapper", issue = "98407")] impl Copy for Exclusive where T: Sync + Copy {}