(almost) get rid of the unsound #[rustc_unsafe_specialization_marker] on Copy, introduce TrivialClone

This commit is contained in:
joboet 2025-01-11 21:22:01 +01:00
parent acda5e9f9a
commit 5fb5861765
No known key found for this signature in database
GPG key ID: 704E0149B0194B3C
24 changed files with 190 additions and 56 deletions

View file

@ -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<T: Clone> BoxFromSlice<T> for Box<[T]> {
}
#[cfg(not(no_global_oom_handling))]
impl<T: Copy> BoxFromSlice<T> for Box<[T]> {
impl<T: TrivialClone> BoxFromSlice<T> 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()

View file

@ -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<T: Clone, A: Allocator> SpecExtendFromWithin for VecDeque<T, A> {
}
#[cfg(not(no_global_oom_handling))]
impl<T: Copy, A: Allocator> SpecExtendFromWithin for VecDeque<T, A> {
impl<T: TrivialClone, A: Allocator> SpecExtendFromWithin for VecDeque<T, A> {
unsafe fn spec_extend_from_within(&mut self, src: Range<usize>) {
let dst = self.len();
let count = src.end - src.start;

View file

@ -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)]

View file

@ -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<T> 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<T: Clone> RcFromSlice<T> for Rc<[T]> {
}
#[cfg(not(no_global_oom_handling))]
impl<T: Copy> RcFromSlice<T> for Rc<[T]> {
impl<T: TrivialClone> RcFromSlice<T> 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) }
}
}

View file

@ -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> [T] {
}
}
impl<T: Copy> ConvertVec for T {
impl<T: TrivialClone> ConvertVec for T {
#[inline]
fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
let mut v = Vec::with_capacity_in(s.len(), alloc);
@ -822,7 +824,7 @@ impl<T: Clone, A: Allocator> SpecCloneIntoVec<T, A> for [T] {
}
#[cfg(not(no_global_oom_handling))]
impl<T: Copy, A: Allocator> SpecCloneIntoVec<T, A> for [T] {
impl<T: TrivialClone, A: Allocator> SpecCloneIntoVec<T, A> for [T] {
fn clone_into(&self, target: &mut Vec<T, A>) {
target.clear();
target.extend_from_slice(self);

View file

@ -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<T> 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<T: Clone> ArcFromSlice<T> for Arc<[T]> {
}
#[cfg(not(no_global_oom_handling))]
impl<T: Copy> ArcFromSlice<T> for Arc<[T]> {
impl<T: TrivialClone> ArcFromSlice<T> 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) }
}
}

View file

@ -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<T: Clone, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
}
#[cfg(not(no_global_oom_handling))]
impl<T: Copy, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
impl<T: TrivialClone, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
unsafe fn spec_extend_from_within(&mut self, src: Range<usize>) {
let count = src.len();
{
@ -3507,8 +3509,8 @@ impl<T: Copy, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
// 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

View file

@ -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<T, A>
where
T: Copy,
T: TrivialClone,
{
fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) {
let slice = iterator.as_slice();

View file

@ -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)]

View file

@ -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<T: Clone, const N: usize> Clone for [T; N] {
}
}
#[unstable(feature = "trivial_clone", issue = "none")]
unsafe impl<T: TrivialClone, const N: usize> TrivialClone for [T; N] {}
trait SpecArrayClone: Clone {
fn clone<const N: usize>(array: &[Self; N]) -> [Self; N];
}
@ -462,10 +466,12 @@ impl<T: Clone> SpecArrayClone for T {
}
}
impl<T: Copy> SpecArrayClone for T {
impl<T: TrivialClone> SpecArrayClone for T {
#[inline]
fn clone<const N: usize>(array: &[T; N]) -> [T; N] {
*array
// SAFETY: `TrivialClone` implies that this is equivalent to calling
// `Clone` on every element.
unsafe { ptr::read(array) }
}
}

View file

@ -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<i32>` 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<T: PointeeSized> 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<T: PointeeSized> const TrivialClone for *const T {}
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_clone", issue = "142757")]
impl<T: PointeeSized> 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<T: PointeeSized> 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<T: PointeeSized> const TrivialClone for &T {}
/// Shared references can be cloned, but mutable references *cannot*!
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: PointeeSized> !Clone for &mut T {}

View file

@ -1,3 +1,4 @@
use super::TrivialClone;
use crate::mem::{self, MaybeUninit};
use crate::ptr;
@ -49,9 +50,9 @@ unsafe impl<T: Clone> 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<T: Copy> CopySpec for T {
unsafe impl<T: TrivialClone> 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

View file

@ -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<T: PointeeSized> Clone for PhantomData<T> {
}
}
#[unstable(feature = "trivial_clone", issue = "none")]
unsafe impl<T: ?Sized> TrivialClone for PhantomData<T> {}
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_default", issue = "143894")]
impl<T: PointeeSized> const Default for PhantomData<T> {

View file

@ -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<T> Copy for $name<T> where T: ?Sized {}
unsafe impl<T> TrivialClone for $name<T> where T: ?Sized {}
impl<T> PartialEq for $name<T>
where T: ?Sized
{

View file

@ -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<T: Copy> Clone for MaybeUninit<T> {
}
}
// SAFETY: the clone implementation is a copy, see above.
#[unstable(feature = "trivial_clone", issue = "none")]
unsafe impl<T> TrivialClone for MaybeUninit<T> where MaybeUninit<T>: Clone {}
#[stable(feature = "maybe_uninit_debug", since = "1.41.0")]
impl<T> fmt::Debug for MaybeUninit<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@ -1599,8 +1604,12 @@ impl<T: Clone> SpecFill<T> for [MaybeUninit<T>] {
}
}
impl<T: Copy> SpecFill<T> for [MaybeUninit<T>] {
impl<T: TrivialClone> SpecFill<T> for [MaybeUninit<T>] {
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) }));
}
}

View file

@ -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<T> clone::Clone for Discriminant<T> {
}
}
#[unstable(feature = "trivial_clone", issue = "none")]
unsafe impl<T> TrivialClone for Discriminant<T> {}
#[stable(feature = "discriminant_value", since = "1.21.0")]
impl<T> cmp::PartialEq for Discriminant<T> {
fn eq(&self, rhs: &Self) -> bool {

View file

@ -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<T> UseCloned for NonZero<T> where T: ZeroablePrimitive {}
#[stable(feature = "nonzero", since = "1.28.0")]
impl<T> Copy for NonZero<T> where T: ZeroablePrimitive {}
#[unstable(feature = "trivial_clone", issue = "none")]
unsafe impl<T> TrivialClone for NonZero<T> where T: ZeroablePrimitive {}
#[stable(feature = "nonzero", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
impl<T> const PartialEq for NonZero<T>

View file

@ -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<T> crate::clone::UseCloned for Option<T> where T: crate::clone::UseCloned {}
#[unstable(feature = "trivial_clone", issue = "none")]
#[rustc_const_unstable(feature = "const_clone", issue = "142757")]
unsafe impl<T> const TrivialClone for Option<T> where T: [const] TrivialClone + [const] Destruct {}
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_default", issue = "143894")]
impl<T> const Default for Option<T> {

View file

@ -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<Dyn: PointeeSized> Clone for DynMetadata<Dyn> {
}
}
unsafe impl<Dyn: ?Sized> TrivialClone for DynMetadata<Dyn> {}
impl<Dyn: PointeeSized> Eq for DynMetadata<Dyn> {}
impl<Dyn: PointeeSized> PartialEq for DynMetadata<Dyn> {

View file

@ -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<T: PointeeSized> Clone for NonNull<T> {
#[stable(feature = "nonnull", since = "1.25.0")]
impl<T: PointeeSized> Copy for NonNull<T> {}
#[unstable(feature = "trivial_clone", issue = "none")]
unsafe impl<T: ?Sized> TrivialClone for NonNull<T> {}
#[unstable(feature = "coerce_unsized", issue = "18598")]
impl<T: PointeeSized, U: PointeeSized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> {}

View file

@ -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<T: PointeeSized> Clone for Unique<T> {
#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: PointeeSized> Copy for Unique<T> {}
#[unstable(feature = "trivial_clone", issue = "none")]
unsafe impl<T: ?Sized> TrivialClone for Unique<T> {}
#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: PointeeSized, U: PointeeSized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}

View file

@ -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> [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<T: Clone>(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<T> {
fn spec_clone_from(&mut self, src: &[T]);
}
@ -5147,11 +5158,14 @@ where
impl<T> CloneFromSpec<T> 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);
}
}
}

View file

@ -1,3 +1,6 @@
use crate::clone::TrivialClone;
use crate::ptr;
pub(super) trait SpecFill<T> {
fn spec_fill(&mut self, value: T);
}
@ -14,10 +17,12 @@ impl<T: Clone> SpecFill<T> for [T] {
}
}
impl<T: Copy> SpecFill<T> for [T] {
impl<T: TrivialClone> SpecFill<T> 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) };
}
}
}

View file

@ -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<T> TrivialClone for Exclusive<T> where T: Sync + TrivialClone {}
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
impl<T> Copy for Exclusive<T> where T: Sync + Copy {}