From a2b4ef7384c68eaa34ab6ad9246bf98ebe2c1575 Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 11 Jan 2025 21:22:01 +0100 Subject: [PATCH 1/6] (almost) get rid of the unsound `#[rustc_unsafe_specialization_marker]` on `Copy`, introduce `TrivialClone` --- library/alloc/src/boxed/convert.rs | 6 ++- library/alloc/src/lib.rs | 1 + library/alloc/src/rc.rs | 11 +++-- library/alloc/src/slice.rs | 6 ++- library/alloc/src/sync.rs | 9 +++- library/alloc/src/vec/mod.rs | 8 ++-- library/alloc/src/vec/spec_extend.rs | 3 +- library/core/src/array/mod.rs | 12 +++-- library/core/src/clone.rs | 46 +++++++++++++++++++ library/core/src/clone/uninit.rs | 5 ++- library/core/src/marker.rs | 12 ++--- library/core/src/marker/variance.rs | 3 ++ library/core/src/mem/maybe_uninit.rs | 13 +++++- library/core/src/mem/mod.rs | 4 ++ library/core/src/num/nonzero.rs | 5 ++- library/core/src/option.rs | 4 ++ library/core/src/ptr/metadata.rs | 3 ++ library/core/src/ptr/non_null.rs | 4 ++ library/core/src/ptr/unique.rs | 4 ++ library/core/src/slice/mod.rs | 66 +++++++++++++++++----------- library/core/src/slice/specialize.rs | 9 +++- 21 files changed, 179 insertions(+), 55 deletions(-) diff --git a/library/alloc/src/boxed/convert.rs b/library/alloc/src/boxed/convert.rs index 8062658020239..a7765a89a7417 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/lib.rs b/library/alloc/src/lib.rs index f0cdb1e4e0f78..c4234e5f03ec2 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -147,6 +147,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 619d9f258e342..fd1e87aa3fe09 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; -#[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; @@ -2150,7 +2150,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 { @@ -2240,9 +2241,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 7c5d22e1ee9be..f9c2b60793a5e 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; @@ -440,7 +442,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); @@ -825,7 +827,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 104cb35c23b65..e85b17f373ff7 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -11,6 +11,8 @@ use core::any::Any; #[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}; @@ -2057,7 +2059,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 { @@ -2149,9 +2152,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 3782f9e95194c..715d3bce67f57 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -53,6 +53,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; @@ -3250,7 +3252,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(); { @@ -3263,8 +3265,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 b98db669059f9..f0faabd2b9509 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}; @@ -53,7 +54,7 @@ where impl<'a, T: 'a, A: Allocator> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec where - T: Copy, + T: TrivialClone, { #[track_caller] fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) { diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 28329bb090845..d0914848853a4 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; @@ -426,6 +427,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]; } @@ -437,10 +441,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 e0ac0bfc5289f..b3d74029fc026 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -176,6 +176,32 @@ pub 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" +)] +// 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 unsafe trait TrivialClone: Clone {} + /// Derive macro generating an impl of the trait `Clone`. #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] @@ -495,6 +521,8 @@ unsafe impl CloneToUninit for crate::bstr::ByteStr { /// are implemented in `traits::SelectionContext::copy_clone_conditions()` /// in `rustc_trait_selection`. mod impls { + use super::TrivialClone; + macro_rules! impl_clone { ($($t:ty)*) => { $( @@ -505,6 +533,9 @@ mod impls { *self } } + + #[unstable(feature = "trivial_clone", issue = "none")] + unsafe impl TrivialClone for $t {} )* } } @@ -524,6 +555,12 @@ mod impls { } } + #[unstable(feature = "trivial_clone", issue = "none")] + unsafe impl TrivialClone for ! {} + + #[unstable(feature = "trivial_clone", issue = "none")] + unsafe impl TrivialClone for () {} + #[stable(feature = "rust1", since = "1.0.0")] impl Clone for *const T { #[inline(always)] @@ -532,6 +569,9 @@ mod impls { } } + #[unstable(feature = "trivial_clone", issue = "none")] + unsafe impl TrivialClone for *const T {} + #[stable(feature = "rust1", since = "1.0.0")] impl Clone for *mut T { #[inline(always)] @@ -540,6 +580,9 @@ mod impls { } } + #[unstable(feature = "trivial_clone", issue = "none")] + unsafe impl TrivialClone for *mut T {} + /// Shared references can be cloned, but mutable references *cannot*! #[stable(feature = "rust1", since = "1.0.0")] impl Clone for &T { @@ -550,6 +593,9 @@ mod impls { } } + #[unstable(feature = "trivial_clone", issue = "none")] + unsafe impl 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 8b738bec796de..8d1185067eb88 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 68011310d2cad..91f578a7ac9d9 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}; @@ -409,12 +410,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 { @@ -816,6 +813,9 @@ impl Clone for PhantomData { } } +#[unstable(feature = "trivial_clone", issue = "none")] +unsafe impl TrivialClone for PhantomData {} + #[stable(feature = "rust1", since = "1.0.0")] impl Default for PhantomData { fn default() -> Self { diff --git a/library/core/src/marker/variance.rs b/library/core/src/marker/variance.rs index 235f8a3bb79f2..cbc19116671a0 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 ce84f105e5c50..5f84170fcbaa3 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::mem::ManuallyDrop; use crate::{fmt, intrinsics, ptr, slice}; @@ -272,6 +273,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 { @@ -1574,8 +1579,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 27387754633d1..6b0722e7e9355 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::DiscriminantKind; use crate::{clone, cmp, fmt, hash, intrinsics, ptr}; @@ -1038,6 +1039,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 7585ec140e31e..e07ddf168c80c 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::{Freeze, StructuralPartialEq}; @@ -189,6 +189,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")] impl PartialEq for NonZero where diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 7ec0ac7127142..d6f7cb6ff3b73 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -556,6 +556,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use crate::clone::TrivialClone; use crate::iter::{self, FusedIterator, TrustedLen}; use crate::ops::{self, ControlFlow, Deref, DerefMut}; use crate::panicking::{panic, panic_display}; @@ -2053,6 +2054,9 @@ where #[unstable(feature = "ergonomic_clones", issue = "132290")] impl crate::clone::UseCloned for Option where T: crate::clone::UseCloned {} +#[unstable(feature = "trivial_clone", issue = "none")] +unsafe impl TrivialClone for Option {} + #[stable(feature = "rust1", since = "1.0.0")] impl Default for Option { /// Returns [`None`][Option::None]. diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 9c5da306e27a7..c23bbf520692f 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}; @@ -228,6 +229,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 c769ba673c61e..03855a3748679 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::Unsize; use crate::mem::{MaybeUninit, SizedTypeProperties}; @@ -1582,6 +1583,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 4810ebe01f9bb..fbe78c67786a2 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, Unsize}; use crate::ops::{CoerceUnsized, DispatchFromDyn}; @@ -161,6 +162,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 2c699ee9fdd4c..959f14040d053 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, SizedTypeProperties}; @@ -3737,30 +3738,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(feature = "panic_immediate_abort"), inline(never), cold)] - #[cfg_attr(feature = "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, @@ -4899,6 +4878,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(feature = "panic_immediate_abort"), inline(never), cold)] + #[cfg_attr(feature = "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]); } @@ -4923,11 +4934,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 80eb590587f99..5ff529168c041 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] { 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) }; } } } From e7af76c2b400e7d5416f68da4480dc389e52b811 Mon Sep 17 00:00:00 2001 From: joboet Date: Fri, 17 Jan 2025 16:19:10 +0100 Subject: [PATCH 2/6] add a `TrivialClone` implementation when deriving both `Clone` and `Copy` --- .../src/deriving/bounds.rs | 6 ++++- .../src/deriving/clone.rs | 24 +++++++++++++++++-- .../src/deriving/cmp/eq.rs | 3 ++- .../src/deriving/cmp/ord.rs | 3 ++- .../src/deriving/cmp/partial_eq.rs | 4 +++- .../src/deriving/cmp/partial_ord.rs | 3 ++- .../src/deriving/debug.rs | 3 ++- .../src/deriving/default.rs | 4 ++-- .../src/deriving/generic/mod.rs | 7 ++++-- .../rustc_builtin_macros/src/deriving/hash.rs | 3 ++- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/clone.rs | 2 +- ...duplicate-derive-copy-clone-diagnostics.rs | 1 + ...icate-derive-copy-clone-diagnostics.stderr | 12 +++++++++- tests/ui/deriving/deriving-all-codegen.stdout | 16 +++++++++++++ 15 files changed, 77 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index a98e9c6d1c7fc..ca0b46da98462 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -1,4 +1,4 @@ -use rustc_ast::MetaItem; +use rustc_ast::{MetaItem, Safety}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::Span; @@ -23,6 +23,7 @@ pub(crate) fn expand_deriving_copy( methods: Vec::new(), associated_types: Vec::new(), is_const, + safety: Safety::Default, }; trait_def.expand(cx, mitem, item, push); @@ -46,6 +47,7 @@ pub(crate) fn expand_deriving_const_param_ty( methods: Vec::new(), associated_types: Vec::new(), is_const, + safety: Safety::Default, }; trait_def.expand(cx, mitem, item, push); @@ -60,6 +62,7 @@ pub(crate) fn expand_deriving_const_param_ty( methods: Vec::new(), associated_types: Vec::new(), is_const, + safety: Safety::Default, }; trait_def.expand(cx, mitem, item, push); @@ -83,6 +86,7 @@ pub(crate) fn expand_deriving_unsized_const_param_ty( methods: Vec::new(), associated_types: Vec::new(), is_const, + safety: Safety::Default, }; trait_def.expand(cx, mitem, item, push); diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index c3656e8244fe0..06951adef3726 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -1,7 +1,7 @@ -use rustc_ast::{self as ast, Generics, ItemKind, MetaItem, VariantData}; +use rustc_ast::{self as ast, Generics, ItemKind, MetaItem, Safety, VariantData}; use rustc_data_structures::fx::FxHashSet; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::{Ident, Span, kw, sym}; +use rustc_span::{DUMMY_SP, Ident, Span, kw, sym}; use thin_vec::{ThinVec, thin_vec}; use crate::deriving::generic::ty::*; @@ -68,6 +68,25 @@ pub(crate) fn expand_deriving_clone( _ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on trait item or impl item"), } + // If the clone method is just copying the value, also mark the type as + // `TrivialClone` to allow some library optimizations. + if is_simple { + let trivial_def = TraitDef { + span, + path: path_std!(clone::TrivialClone), + skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, + additional_bounds: bounds.clone(), + supports_unions: true, + methods: Vec::new(), + associated_types: Vec::new(), + is_const, + safety: Safety::Unsafe(DUMMY_SP), + }; + + trivial_def.expand_ext(cx, mitem, item, push, true); + } + let trait_def = TraitDef { span, path: path_std!(clone::Clone), @@ -87,6 +106,7 @@ pub(crate) fn expand_deriving_clone( }], associated_types: Vec::new(), is_const, + safety: Safety::Default, }; trait_def.expand_ext(cx, mitem, item, push, is_simple) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index eca79e4dc4897..046be78e4567c 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -1,4 +1,4 @@ -use rustc_ast::{self as ast, MetaItem}; +use rustc_ast::{self as ast, MetaItem, Safety}; use rustc_data_structures::fx::FxHashSet; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::{Span, sym}; @@ -43,6 +43,7 @@ pub(crate) fn expand_deriving_eq( }], associated_types: Vec::new(), is_const, + safety: Safety::Default, }; trait_def.expand_ext(cx, mitem, item, push, true) } diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index 1ed44c20bc61e..e0c836c7f3378 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -1,4 +1,4 @@ -use rustc_ast::MetaItem; +use rustc_ast::{MetaItem, Safety}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::{Ident, Span, sym}; use thin_vec::thin_vec; @@ -34,6 +34,7 @@ pub(crate) fn expand_deriving_ord( }], associated_types: Vec::new(), is_const, + safety: Safety::Default, }; trait_def.expand(cx, mitem, item, push) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index 4b93b3414c76b..d9988fc1b55ea 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -1,5 +1,5 @@ use rustc_ast::ptr::P; -use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability}; +use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability, Safety}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::{Span, sym}; use thin_vec::thin_vec; @@ -84,6 +84,7 @@ pub(crate) fn expand_deriving_partial_eq( methods: Vec::new(), associated_types: Vec::new(), is_const: false, + safety: Safety::Default, }; structural_trait_def.expand(cx, mitem, item, push); @@ -110,6 +111,7 @@ pub(crate) fn expand_deriving_partial_eq( methods, associated_types: Vec::new(), is_const, + safety: Safety::Default, }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index 7958e037555d5..ef0a81910dcd9 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -1,4 +1,4 @@ -use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind}; +use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind, Safety}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::{Ident, Span, sym}; use thin_vec::thin_vec; @@ -64,6 +64,7 @@ pub(crate) fn expand_deriving_partial_ord( methods: vec![partial_cmp_def], associated_types: Vec::new(), is_const, + safety: Safety::Default, }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 8ab21986e68a0..385e516f83e17 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -1,4 +1,4 @@ -use rustc_ast::{self as ast, EnumDef, MetaItem}; +use rustc_ast::{self as ast, EnumDef, MetaItem, Safety}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_session::config::FmtDebug; use rustc_span::{Ident, Span, Symbol, sym}; @@ -41,6 +41,7 @@ pub(crate) fn expand_deriving_debug( }], associated_types: Vec::new(), is_const, + safety: Safety::Default, }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 1fe567e23f455..6b85836b476e2 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -1,8 +1,7 @@ use core::ops::ControlFlow; -use rustc_ast as ast; use rustc_ast::visit::visit_opt; -use rustc_ast::{EnumDef, VariantData, attr}; +use rustc_ast::{self as ast, EnumDef, Safety, VariantData, attr}; use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt}; use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym}; use smallvec::SmallVec; @@ -51,6 +50,7 @@ pub(crate) fn expand_deriving_default( }], associated_types: Vec::new(), is_const, + safety: Safety::Default, }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 03ee59de70e12..75b825214e9af 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -183,7 +183,7 @@ pub(crate) use SubstructureFields::*; use rustc_ast::ptr::P; use rustc_ast::{ self as ast, AnonConst, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, - Generics, Mutability, PatKind, VariantData, + Generics, Mutability, PatKind, Safety, VariantData, }; use rustc_attr_parsing::{AttributeKind, AttributeParser, ReprPacked}; use rustc_expand::base::{Annotatable, ExtCtxt}; @@ -221,6 +221,9 @@ pub(crate) struct TraitDef<'a> { pub associated_types: Vec<(Ident, Ty)>, pub is_const: bool, + + /// The safety of the `impl`. + pub safety: Safety, } pub(crate) struct MethodDef<'a> { @@ -792,7 +795,7 @@ impl<'a> TraitDef<'a> { Ident::empty(), attrs, ast::ItemKind::Impl(Box::new(ast::Impl { - safety: ast::Safety::Default, + safety: self.safety, polarity: ast::ImplPolarity::Positive, defaultness: ast::Defaultness::Final, constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No }, diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index 6e6dbe19e4d1a..54f82d5ce96de 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -1,4 +1,4 @@ -use rustc_ast::{MetaItem, Mutability}; +use rustc_ast::{MetaItem, Mutability, Safety}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::{Span, sym}; use thin_vec::thin_vec; @@ -41,6 +41,7 @@ pub(crate) fn expand_deriving_hash( }], associated_types: Vec::new(), is_const, + safety: Safety::Default, }; hash_trait_def.expand(cx, mitem, item, push); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8a8bec35d8194..232270660a265 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -364,6 +364,7 @@ symbols! { ToString, TokenStream, Trait, + TrivialClone, Try, TryCaptureGeneric, TryCapturePrintable, diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index b3d74029fc026..d680227fa0b38 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -205,7 +205,7 @@ pub unsafe trait TrivialClone: Clone {} /// Derive macro generating an impl of the trait `Clone`. #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[allow_internal_unstable(core_intrinsics, derive_clone_copy)] +#[allow_internal_unstable(core_intrinsics, derive_clone_copy, trivial_clone)] pub macro Clone($item:item) { /* compiler built-in */ } diff --git a/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs b/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs index c4fb620fea4f3..bc88a0e131a8e 100644 --- a/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs +++ b/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs @@ -6,6 +6,7 @@ #[derive(Copy, Clone)] //~^ ERROR conflicting implementations of trait `Clone` for type `E` //~| ERROR conflicting implementations of trait `Copy` for type `E` +//~| ERROR conflicting implementations of trait `TrivialClone` for type `E` enum E {} fn main() {} diff --git a/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr b/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr index b9eb6194f6c4c..a0274222e78c6 100644 --- a/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr +++ b/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr @@ -6,6 +6,16 @@ LL | #[derive(Copy, Clone)] LL | #[derive(Copy, Clone)] | ^^^^ conflicting implementation for `E` +error[E0119]: conflicting implementations of trait `TrivialClone` for type `E` + --> $DIR/duplicate-derive-copy-clone-diagnostics.rs:6:16 + | +LL | #[derive(Copy, Clone)] + | ----- first implementation here +LL | #[derive(Copy, Clone)] + | ^^^^^ conflicting implementation for `E` + | + = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0119]: conflicting implementations of trait `Clone` for type `E` --> $DIR/duplicate-derive-copy-clone-diagnostics.rs:6:16 | @@ -14,6 +24,6 @@ LL | #[derive(Copy, Clone)] LL | #[derive(Copy, Clone)] | ^^^^^ conflicting implementation for `E` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout index 6503c87099040..35ea8503be9d7 100644 --- a/tests/ui/deriving/deriving-all-codegen.stdout +++ b/tests/ui/deriving/deriving-all-codegen.stdout @@ -25,6 +25,8 @@ extern crate std; // Empty struct. struct Empty; #[automatically_derived] +unsafe impl ::core::clone::TrivialClone for Empty { } +#[automatically_derived] impl ::core::clone::Clone for Empty { #[inline] fn clone(&self) -> Empty { *self } @@ -85,6 +87,8 @@ struct Point { y: u32, } #[automatically_derived] +unsafe impl ::core::clone::TrivialClone for Point { } +#[automatically_derived] impl ::core::clone::Clone for Point { #[inline] fn clone(&self) -> Point { @@ -170,6 +174,8 @@ struct PackedPoint { y: u32, } #[automatically_derived] +unsafe impl ::core::clone::TrivialClone for PackedPoint { } +#[automatically_derived] impl ::core::clone::Clone for PackedPoint { #[inline] fn clone(&self) -> PackedPoint { @@ -262,6 +268,8 @@ struct Big { b8: u32, } #[automatically_derived] +unsafe impl ::core::clone::TrivialClone for Big { } +#[automatically_derived] impl ::core::clone::Clone for Big { #[inline] fn clone(&self) -> Big { @@ -763,6 +771,8 @@ impl Enum0 { *self } @@ -958,6 +968,8 @@ enum Fieldless { C, } #[automatically_derived] +unsafe impl ::core::clone::TrivialClone for Fieldless { } +#[automatically_derived] impl ::core::clone::Clone for Fieldless { #[inline] fn clone(&self) -> Fieldless { *self } @@ -1040,6 +1052,8 @@ enum Mixed { }, } #[automatically_derived] +unsafe impl ::core::clone::TrivialClone for Mixed { } +#[automatically_derived] impl ::core::clone::Clone for Mixed { #[inline] fn clone(&self) -> Mixed { @@ -1437,6 +1451,8 @@ pub union Union { pub i: i32, } #[automatically_derived] +unsafe impl ::core::clone::TrivialClone for Union { } +#[automatically_derived] impl ::core::clone::Clone for Union { #[inline] fn clone(&self) -> Union { From 431ee821f8ea63fe5cf80877e4ae267563cd1708 Mon Sep 17 00:00:00 2001 From: joboet Date: Tue, 11 Feb 2025 11:16:45 +0100 Subject: [PATCH 3/6] alloc: remove test of unsound specialization behaviour --- library/alloctests/tests/vec.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index f430d979fa848..2deeff77e719b 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -2345,20 +2345,6 @@ fn test_vec_swap() { assert_eq!(n, 0); } -#[test] -fn test_extend_from_within_spec() { - #[derive(Copy)] - struct CopyOnly; - - impl Clone for CopyOnly { - fn clone(&self) -> Self { - panic!("extend_from_within must use specialization on copy"); - } - } - - vec![CopyOnly, CopyOnly].extend_from_within(..); -} - #[test] fn test_extend_from_within_clone() { let mut v = vec![String::from("sssss"), String::from("12334567890"), String::from("c")]; From ba97294bc6bbf31dc4443db23364251b2fce267f Mon Sep 17 00:00:00 2001 From: joboet Date: Tue, 11 Feb 2025 11:42:22 +0100 Subject: [PATCH 4/6] make `TrivialClone` a `#[marker]`-trait to keep it from appearing in error messages --- library/core/src/clone.rs | 4 ++++ .../duplicate-derive-copy-clone-diagnostics.rs | 1 - .../duplicate-derive-copy-clone-diagnostics.stderr | 12 +----------- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index d680227fa0b38..481fe232df347 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -200,6 +200,10 @@ pub trait Clone: Sized { // 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] +// If `#[derive(Clone, Clone, Copy)]` is written, there will be multiple +// implementations of `TrivialClone`. To keep it from appearing in error +// messages, make it a `#[marker]` trait. +#[marker] pub unsafe trait TrivialClone: Clone {} /// Derive macro generating an impl of the trait `Clone`. diff --git a/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs b/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs index bc88a0e131a8e..c4fb620fea4f3 100644 --- a/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs +++ b/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs @@ -6,7 +6,6 @@ #[derive(Copy, Clone)] //~^ ERROR conflicting implementations of trait `Clone` for type `E` //~| ERROR conflicting implementations of trait `Copy` for type `E` -//~| ERROR conflicting implementations of trait `TrivialClone` for type `E` enum E {} fn main() {} diff --git a/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr b/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr index a0274222e78c6..b9eb6194f6c4c 100644 --- a/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr +++ b/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr @@ -6,16 +6,6 @@ LL | #[derive(Copy, Clone)] LL | #[derive(Copy, Clone)] | ^^^^ conflicting implementation for `E` -error[E0119]: conflicting implementations of trait `TrivialClone` for type `E` - --> $DIR/duplicate-derive-copy-clone-diagnostics.rs:6:16 - | -LL | #[derive(Copy, Clone)] - | ----- first implementation here -LL | #[derive(Copy, Clone)] - | ^^^^^ conflicting implementation for `E` - | - = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0119]: conflicting implementations of trait `Clone` for type `E` --> $DIR/duplicate-derive-copy-clone-diagnostics.rs:6:16 | @@ -24,6 +14,6 @@ LL | #[derive(Copy, Clone)] LL | #[derive(Copy, Clone)] | ^^^^^ conflicting implementation for `E` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0119`. From c5e262c374827e9d468d9f5fd9aa3400dc91285f Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 17 Mar 2025 13:11:41 +0100 Subject: [PATCH 5/6] automatically implement `TrivialClone` for closures and tuples If each of the component types is `TrivialClone`, the closure/tuple itself can be trivially cloned. --- compiler/rustc_hir/src/lang_items.rs | 1 + compiler/rustc_middle/src/ty/context.rs | 1 + .../src/solve/assembly/mod.rs | 8 +++++--- compiler/rustc_span/src/symbol.rs | 1 + .../src/traits/select/candidate_assembly.rs | 4 +++- .../src/traits/select/confirmation.rs | 2 ++ compiler/rustc_type_ir/src/lang_items.rs | 1 + library/core/src/clone.rs | 1 + .../ui/functions-closures/trivial-clone-closure.rs | 13 +++++++++++++ 9 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 tests/ui/functions-closures/trivial-clone-closure.rs diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 29f4d5b807699..b5ea5526ec57e 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -172,6 +172,7 @@ language_item_table! { Clone, sym::clone, clone_trait, Target::Trait, GenericRequirement::None; CloneFn, sym::clone_fn, clone_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; UseCloned, sym::use_cloned, use_cloned_trait, Target::Trait, GenericRequirement::None; + TrivialClone, sym::trivial_clone, trivial_clone_trait, Target::Trait, GenericRequirement::None; Sync, sym::sync, sync_trait, Target::Trait, GenericRequirement::Exact(0); DiscriminantKind, sym::discriminant_kind, discriminant_kind_trait, Target::Trait, GenericRequirement::None; /// The associated item of the `DiscriminantKind` trait. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f54dd2b0040ae..90bcd4924c492 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -719,6 +719,7 @@ bidirectional_lang_item_map! { Poll, Sized, TransmuteTrait, + TrivialClone, Tuple, Unpin, Unsize, diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 384a304c4a9d6..8bb642355caad 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -397,9 +397,11 @@ where } else { match cx.as_lang_item(trait_def_id) { Some(TraitSolverLangItem::Sized) => G::consider_builtin_sized_candidate(self, goal), - Some(TraitSolverLangItem::Copy | TraitSolverLangItem::Clone) => { - G::consider_builtin_copy_clone_candidate(self, goal) - } + Some( + TraitSolverLangItem::Copy + | TraitSolverLangItem::Clone + | TraitSolverLangItem::TrivialClone, + ) => G::consider_builtin_copy_clone_candidate(self, goal), Some(TraitSolverLangItem::Fn) => { G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::Fn) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 232270660a265..f808407bc859f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2082,6 +2082,7 @@ symbols! { transparent_enums, transparent_unions, trivial_bounds, + trivial_clone, truncf128, truncf16, truncf32, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index a8d8003ead6ea..4fa469988a0cd 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -108,7 +108,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut candidates, ); } else { - if tcx.is_lang_item(def_id, LangItem::Clone) { + if tcx.is_lang_item(def_id, LangItem::Clone) + || tcx.is_lang_item(def_id, LangItem::TrivialClone) + { // Same builtin conditions as `Copy`, i.e., every type which has builtin support // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone` // types have builtin support for `Clone`. diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 4cd6781ab8905..2af6b353bb0c2 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -261,6 +261,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.copy_clone_conditions(obligation) } else if tcx.is_lang_item(trait_def, LangItem::Clone) { self.copy_clone_conditions(obligation) + } else if tcx.is_lang_item(trait_def, LangItem::TrivialClone) { + self.copy_clone_conditions(obligation) } else if tcx.is_lang_item(trait_def, LangItem::FusedIterator) { self.fused_iterator_conditions(obligation) } else { diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index 65f7cdf8f922b..de4fd55f3f731 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -36,6 +36,7 @@ pub enum TraitSolverLangItem { Poll, Sized, TransmuteTrait, + TrivialClone, Tuple, Unpin, Unsize, diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 481fe232df347..08f3ff0392166 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -194,6 +194,7 @@ pub trait Clone: Sized { reason = "this isn't part of any API guarantee", issue = "none" )] +#[cfg_attr(not(bootstrap), lang = "trivial_clone")] // SAFETY: // It is sound to specialize on this because the `clone` implementation cannot be // lifetime-dependent. Therefore, if `TrivialClone` is implemented for any lifetime, diff --git a/tests/ui/functions-closures/trivial-clone-closure.rs b/tests/ui/functions-closures/trivial-clone-closure.rs new file mode 100644 index 0000000000000..5f45d500543ae --- /dev/null +++ b/tests/ui/functions-closures/trivial-clone-closure.rs @@ -0,0 +1,13 @@ +//@ run-pass +// Check that closures implement `TrivialClone`. + +#![feature(trivial_clone)] + +use std::clone::TrivialClone; + +fn require_trivial_clone(_t: T) {} + +fn main() { + let some_trivial_clone_value = 42i32; + require_trivial_clone(move || some_trivial_clone_value); +} From 1509254482c72eb005f0b8f04f6f7661c4b47f25 Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 24 Mar 2025 18:47:49 +0100 Subject: [PATCH 6/6] prevent `TrivialClone` implementations from appearing in rustdoc output --- compiler/rustc_builtin_macros/src/deriving/bounds.rs | 4 ++++ compiler/rustc_builtin_macros/src/deriving/clone.rs | 4 ++++ compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs | 1 + compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs | 1 + .../rustc_builtin_macros/src/deriving/cmp/partial_eq.rs | 2 ++ .../rustc_builtin_macros/src/deriving/cmp/partial_ord.rs | 1 + compiler/rustc_builtin_macros/src/deriving/debug.rs | 1 + compiler/rustc_builtin_macros/src/deriving/default.rs | 1 + .../rustc_builtin_macros/src/deriving/generic/mod.rs | 9 ++++++++- compiler/rustc_builtin_macros/src/deriving/hash.rs | 1 + library/core/src/array/mod.rs | 1 + library/core/src/clone.rs | 6 ++++++ library/core/src/marker.rs | 1 + library/core/src/marker/variance.rs | 1 + library/core/src/mem/maybe_uninit.rs | 1 + library/core/src/mem/mod.rs | 1 + library/core/src/num/nonzero.rs | 1 + library/core/src/option.rs | 1 + library/core/src/ptr/metadata.rs | 1 + library/core/src/ptr/non_null.rs | 1 + library/core/src/ptr/unique.rs | 1 + tests/ui/deriving/deriving-all-codegen.stdout | 8 ++++++++ 22 files changed, 48 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index ca0b46da98462..63e5fed37ac25 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -24,6 +24,7 @@ pub(crate) fn expand_deriving_copy( associated_types: Vec::new(), is_const, safety: Safety::Default, + document: true, }; trait_def.expand(cx, mitem, item, push); @@ -48,6 +49,7 @@ pub(crate) fn expand_deriving_const_param_ty( associated_types: Vec::new(), is_const, safety: Safety::Default, + document: true, }; trait_def.expand(cx, mitem, item, push); @@ -63,6 +65,7 @@ pub(crate) fn expand_deriving_const_param_ty( associated_types: Vec::new(), is_const, safety: Safety::Default, + document: true, }; trait_def.expand(cx, mitem, item, push); @@ -87,6 +90,7 @@ pub(crate) fn expand_deriving_unsized_const_param_ty( associated_types: Vec::new(), is_const, safety: Safety::Default, + document: true, }; trait_def.expand(cx, mitem, item, push); diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 06951adef3726..7b81da8571bab 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -82,6 +82,9 @@ pub(crate) fn expand_deriving_clone( associated_types: Vec::new(), is_const, safety: Safety::Unsafe(DUMMY_SP), + // `TrivialClone` is not part of an API guarantee, so it shouldn't + // appear in rustdoc output. + document: false, }; trivial_def.expand_ext(cx, mitem, item, push, true); @@ -107,6 +110,7 @@ pub(crate) fn expand_deriving_clone( associated_types: Vec::new(), is_const, safety: Safety::Default, + document: true, }; trait_def.expand_ext(cx, mitem, item, push, is_simple) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 046be78e4567c..50ae7e19164a3 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -44,6 +44,7 @@ pub(crate) fn expand_deriving_eq( associated_types: Vec::new(), is_const, safety: Safety::Default, + document: true, }; trait_def.expand_ext(cx, mitem, item, push, true) } diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index e0c836c7f3378..49e4b1dd691f9 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -35,6 +35,7 @@ pub(crate) fn expand_deriving_ord( associated_types: Vec::new(), is_const, safety: Safety::Default, + document: true, }; trait_def.expand(cx, mitem, item, push) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index d9988fc1b55ea..1257f20af4e0c 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -85,6 +85,7 @@ pub(crate) fn expand_deriving_partial_eq( associated_types: Vec::new(), is_const: false, safety: Safety::Default, + document: true, }; structural_trait_def.expand(cx, mitem, item, push); @@ -112,6 +113,7 @@ pub(crate) fn expand_deriving_partial_eq( associated_types: Vec::new(), is_const, safety: Safety::Default, + document: true, }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index ef0a81910dcd9..4d9310b2718f4 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -65,6 +65,7 @@ pub(crate) fn expand_deriving_partial_ord( associated_types: Vec::new(), is_const, safety: Safety::Default, + document: true, }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 385e516f83e17..d0d1294818632 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -42,6 +42,7 @@ pub(crate) fn expand_deriving_debug( associated_types: Vec::new(), is_const, safety: Safety::Default, + document: true, }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 6b85836b476e2..9af1c5edbe975 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -51,6 +51,7 @@ pub(crate) fn expand_deriving_default( associated_types: Vec::new(), is_const, safety: Safety::Default, + document: true, }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 75b825214e9af..93d58545c0078 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -224,6 +224,9 @@ pub(crate) struct TraitDef<'a> { /// The safety of the `impl`. pub safety: Safety, + + /// Whether the added `impl` should appear in rustdoc output. + pub document: bool, } pub(crate) struct MethodDef<'a> { @@ -787,7 +790,11 @@ impl<'a> TraitDef<'a> { let path = cx.path_all(self.span, false, vec![type_ident], self_params); let self_type = cx.ty_path(path); - let attrs = thin_vec![cx.attr_word(sym::automatically_derived, self.span),]; + let mut attrs = thin_vec![cx.attr_word(sym::automatically_derived, self.span),]; + if !self.document { + attrs.push(cx.attr_nested_word(sym::doc, sym::hidden, self.span)); + } + let opt_trait_ref = Some(trait_ref); cx.item( diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index 54f82d5ce96de..e196f6ee6ce08 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -42,6 +42,7 @@ pub(crate) fn expand_deriving_hash( associated_types: Vec::new(), is_const, safety: Safety::Default, + document: true, }; hash_trait_def.expand(cx, mitem, item, push); diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index d0914848853a4..4d6b392d63606 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -427,6 +427,7 @@ impl Clone for [T; N] { } } +#[doc(hidden)] #[unstable(feature = "trivial_clone", issue = "none")] unsafe impl TrivialClone for [T; N] {} diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 08f3ff0392166..170bdb42e10fc 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -539,6 +539,7 @@ mod impls { } } + #[doc(hidden)] #[unstable(feature = "trivial_clone", issue = "none")] unsafe impl TrivialClone for $t {} )* @@ -560,9 +561,11 @@ mod impls { } } + #[doc(hidden)] #[unstable(feature = "trivial_clone", issue = "none")] unsafe impl TrivialClone for ! {} + #[doc(hidden)] #[unstable(feature = "trivial_clone", issue = "none")] unsafe impl TrivialClone for () {} @@ -574,6 +577,7 @@ mod impls { } } + #[doc(hidden)] #[unstable(feature = "trivial_clone", issue = "none")] unsafe impl TrivialClone for *const T {} @@ -585,6 +589,7 @@ mod impls { } } + #[doc(hidden)] #[unstable(feature = "trivial_clone", issue = "none")] unsafe impl TrivialClone for *mut T {} @@ -598,6 +603,7 @@ mod impls { } } + #[doc(hidden)] #[unstable(feature = "trivial_clone", issue = "none")] unsafe impl TrivialClone for &T {} diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 91f578a7ac9d9..ba5340cc2d34d 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -813,6 +813,7 @@ impl Clone for PhantomData { } } +#[doc(hidden)] #[unstable(feature = "trivial_clone", issue = "none")] unsafe impl TrivialClone for PhantomData {} diff --git a/library/core/src/marker/variance.rs b/library/core/src/marker/variance.rs index cbc19116671a0..032db9506e4ee 100644 --- a/library/core/src/marker/variance.rs +++ b/library/core/src/marker/variance.rs @@ -61,6 +61,7 @@ macro_rules! phantom_type { impl Copy for $name where T: ?Sized {} + #[doc(hidden)] unsafe impl TrivialClone for $name where T: ?Sized {} impl PartialEq for $name diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 5f84170fcbaa3..913aa52db817b 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -274,6 +274,7 @@ impl Clone for MaybeUninit { } // SAFETY: the clone implementation is a copy, see above. +#[doc(hidden)] #[unstable(feature = "trivial_clone", issue = "none")] unsafe impl TrivialClone for MaybeUninit where MaybeUninit: Clone {} diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 6b0722e7e9355..dbfb5b2fb51f4 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1039,6 +1039,7 @@ impl clone::Clone for Discriminant { } } +#[doc(hidden)] #[unstable(feature = "trivial_clone", issue = "none")] unsafe impl TrivialClone for Discriminant {} diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index e07ddf168c80c..adcc9721e45d7 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -189,6 +189,7 @@ impl UseCloned for NonZero where T: ZeroablePrimitive {} #[stable(feature = "nonzero", since = "1.28.0")] impl Copy for NonZero where T: ZeroablePrimitive {} +#[doc(hidden)] #[unstable(feature = "trivial_clone", issue = "none")] unsafe impl TrivialClone for NonZero where T: ZeroablePrimitive {} diff --git a/library/core/src/option.rs b/library/core/src/option.rs index d6f7cb6ff3b73..260b4a3f58057 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -2054,6 +2054,7 @@ where #[unstable(feature = "ergonomic_clones", issue = "132290")] impl crate::clone::UseCloned for Option where T: crate::clone::UseCloned {} +#[doc(hidden)] #[unstable(feature = "trivial_clone", issue = "none")] unsafe impl TrivialClone for Option {} diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index c23bbf520692f..936577a6f358a 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -229,6 +229,7 @@ impl Clone for DynMetadata { } } +#[doc(hidden)] unsafe impl TrivialClone for DynMetadata {} impl Eq for DynMetadata {} diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 03855a3748679..e6e406445dc8b 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1583,6 +1583,7 @@ impl Clone for NonNull { #[stable(feature = "nonnull", since = "1.25.0")] impl Copy for NonNull {} +#[doc(hidden)] #[unstable(feature = "trivial_clone", issue = "none")] unsafe impl TrivialClone for NonNull {} diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs index fbe78c67786a2..422a6322dc9cf 100644 --- a/library/core/src/ptr/unique.rs +++ b/library/core/src/ptr/unique.rs @@ -162,6 +162,7 @@ impl Clone for Unique { #[unstable(feature = "ptr_internals", issue = "none")] impl Copy for Unique {} +#[doc(hidden)] #[unstable(feature = "trivial_clone", issue = "none")] unsafe impl TrivialClone for Unique {} diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout index 35ea8503be9d7..8d6d785c44fbf 100644 --- a/tests/ui/deriving/deriving-all-codegen.stdout +++ b/tests/ui/deriving/deriving-all-codegen.stdout @@ -25,6 +25,7 @@ extern crate std; // Empty struct. struct Empty; #[automatically_derived] +#[doc(hidden)] unsafe impl ::core::clone::TrivialClone for Empty { } #[automatically_derived] impl ::core::clone::Clone for Empty { @@ -87,6 +88,7 @@ struct Point { y: u32, } #[automatically_derived] +#[doc(hidden)] unsafe impl ::core::clone::TrivialClone for Point { } #[automatically_derived] impl ::core::clone::Clone for Point { @@ -174,6 +176,7 @@ struct PackedPoint { y: u32, } #[automatically_derived] +#[doc(hidden)] unsafe impl ::core::clone::TrivialClone for PackedPoint { } #[automatically_derived] impl ::core::clone::Clone for PackedPoint { @@ -268,6 +271,7 @@ struct Big { b8: u32, } #[automatically_derived] +#[doc(hidden)] unsafe impl ::core::clone::TrivialClone for Big { } #[automatically_derived] impl ::core::clone::Clone for Big { @@ -771,6 +775,7 @@ impl