Skip to content

Commit 10564b7

Browse files
committed
(almost) get rid of the unsound #[rustc_unsafe_specialization_marker] on Copy, introduce TrivialClone
1 parent c182ce9 commit 10564b7

File tree

14 files changed

+142
-52
lines changed

14 files changed

+142
-52
lines changed

library/alloc/src/boxed/convert.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use core::any::Any;
2+
use core::clone::TrivialClone;
23
use core::error::Error;
34
use core::mem;
45
use core::pin::Pin;
@@ -75,11 +76,13 @@ impl<T: Clone> BoxFromSlice<T> for Box<[T]> {
7576
}
7677

7778
#[cfg(not(no_global_oom_handling))]
78-
impl<T: Copy> BoxFromSlice<T> for Box<[T]> {
79+
impl<T: TrivialClone> BoxFromSlice<T> for Box<[T]> {
7980
#[inline]
8081
fn from_slice(slice: &[T]) -> Self {
8182
let len = slice.len();
8283
let buf = RawVec::with_capacity(len);
84+
// SAFETY: since `T` implements `TrivialClone`, this is sound and
85+
// equivalent to the above.
8386
unsafe {
8487
ptr::copy_nonoverlapping(slice.as_ptr(), buf.ptr(), len);
8588
buf.into_box(slice.len()).assume_init()

library/alloc/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@
147147
#![feature(std_internals)]
148148
#![feature(str_internals)]
149149
#![feature(temporary_niche_types)]
150+
#![feature(trivial_clone)]
150151
#![feature(trusted_fused)]
151152
#![feature(trusted_len)]
152153
#![feature(trusted_random_access)]

library/alloc/src/rc.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ use core::any::Any;
245245
use core::cell::Cell;
246246
#[cfg(not(no_global_oom_handling))]
247247
use core::clone::CloneToUninit;
248+
use core::clone::TrivialClone;
248249
use core::cmp::Ordering;
249250
use core::hash::{Hash, Hasher};
250251
use core::intrinsics::abort;
@@ -2143,7 +2144,8 @@ impl<T> Rc<[T]> {
21432144

21442145
/// Copy elements from slice into newly allocated `Rc<[T]>`
21452146
///
2146-
/// Unsafe because the caller must either take ownership or bind `T: Copy`
2147+
/// Unsafe because the caller must either take ownership, bind `T: Copy` or
2148+
/// bind `T: TrivialClone`.
21472149
#[cfg(not(no_global_oom_handling))]
21482150
unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> {
21492151
unsafe {
@@ -2233,9 +2235,11 @@ impl<T: Clone> RcFromSlice<T> for Rc<[T]> {
22332235
}
22342236

22352237
#[cfg(not(no_global_oom_handling))]
2236-
impl<T: Copy> RcFromSlice<T> for Rc<[T]> {
2238+
impl<T: TrivialClone> RcFromSlice<T> for Rc<[T]> {
22372239
#[inline]
22382240
fn from_slice(v: &[T]) -> Self {
2241+
// SAFETY: `T` implements `TrivialClone`, so this is sound and equivalent
2242+
// to the above.
22392243
unsafe { Rc::copy_from_slice(v) }
22402244
}
22412245
}

library/alloc/src/slice.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#![cfg_attr(test, allow(unused_imports, dead_code))]
1414

1515
use core::borrow::{Borrow, BorrowMut};
16+
use core::clone::TrivialClone;
1617
#[cfg(not(no_global_oom_handling))]
1718
use core::cmp::Ordering::{self, Less};
1819
#[cfg(not(no_global_oom_handling))]
@@ -88,6 +89,7 @@ use crate::vec::Vec;
8889
#[allow(unreachable_pub)] // cfg(test) pub above
8990
pub(crate) mod hack {
9091
use core::alloc::Allocator;
92+
use core::clone::TrivialClone;
9193

9294
use crate::boxed::Box;
9395
use crate::vec::Vec;
@@ -156,7 +158,7 @@ pub(crate) mod hack {
156158
}
157159

158160
#[cfg(not(no_global_oom_handling))]
159-
impl<T: Copy> ConvertVec for T {
161+
impl<T: TrivialClone> ConvertVec for T {
160162
#[inline]
161163
fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
162164
let mut v = Vec::with_capacity_in(s.len(), alloc);
@@ -872,7 +874,7 @@ impl<T: Clone, A: Allocator> SpecCloneIntoVec<T, A> for [T] {
872874
}
873875

874876
#[cfg(not(no_global_oom_handling))]
875-
impl<T: Copy, A: Allocator> SpecCloneIntoVec<T, A> for [T] {
877+
impl<T: TrivialClone, A: Allocator> SpecCloneIntoVec<T, A> for [T] {
876878
fn clone_into(&self, target: &mut Vec<T, A>) {
877879
target.clear();
878880
target.extend_from_slice(self);

library/alloc/src/sync.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use core::any::Any;
1212
#[cfg(not(no_global_oom_handling))]
1313
use core::clone::CloneToUninit;
14+
use core::clone::TrivialClone;
1415
use core::cmp::Ordering;
1516
use core::hash::{Hash, Hasher};
1617
use core::intrinsics::abort;
@@ -2044,7 +2045,8 @@ impl<T> Arc<[T]> {
20442045

20452046
/// Copy elements from slice into newly allocated `Arc<[T]>`
20462047
///
2047-
/// Unsafe because the caller must either take ownership or bind `T: Copy`.
2048+
/// Unsafe because the caller must either take ownership, bind `T: Copy` or
2049+
/// bind `T: TrivialClone`.
20482050
#[cfg(not(no_global_oom_handling))]
20492051
unsafe fn copy_from_slice(v: &[T]) -> Arc<[T]> {
20502052
unsafe {
@@ -2136,9 +2138,11 @@ impl<T: Clone> ArcFromSlice<T> for Arc<[T]> {
21362138
}
21372139

21382140
#[cfg(not(no_global_oom_handling))]
2139-
impl<T: Copy> ArcFromSlice<T> for Arc<[T]> {
2141+
impl<T: TrivialClone> ArcFromSlice<T> for Arc<[T]> {
21402142
#[inline]
21412143
fn from_slice(v: &[T]) -> Self {
2144+
// SAFETY: `T` implements `TrivialClone`, so this is sound and equivalent
2145+
// to the above.
21422146
unsafe { Arc::copy_from_slice(v) }
21432147
}
21442148
}

library/alloc/src/vec/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
5454
#![stable(feature = "rust1", since = "1.0.0")]
5555

56+
use core::clone::TrivialClone;
5657
#[cfg(not(no_global_oom_handling))]
5758
use core::cmp;
5859
use core::cmp::Ordering;
@@ -3225,7 +3226,7 @@ impl<T: Clone, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
32253226
}
32263227

32273228
#[cfg(not(no_global_oom_handling))]
3228-
impl<T: Copy, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
3229+
impl<T: TrivialClone, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
32293230
unsafe fn spec_extend_from_within(&mut self, src: Range<usize>) {
32303231
let count = src.len();
32313232
{
@@ -3238,8 +3239,8 @@ impl<T: Copy, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
32383239
// SAFETY:
32393240
// - Both pointers are created from unique slice references (`&mut [_]`)
32403241
// so they are valid and do not overlap.
3241-
// - Elements are :Copy so it's OK to copy them, without doing
3242-
// anything with the original values
3242+
// - Elements implement `TrivialClone` so this is equivalent to calling
3243+
// `clone` on every one of them.
32433244
// - `count` is equal to the len of `source`, so source is valid for
32443245
// `count` reads
32453246
// - `.reserve(count)` guarantees that `spare.len() >= count` so spare

library/alloc/src/vec/spec_extend.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use core::clone::TrivialClone;
12
use core::iter::TrustedLen;
23
use core::slice::{self};
34

@@ -53,7 +54,7 @@ where
5354

5455
impl<'a, T: 'a, A: Allocator> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
5556
where
56-
T: Copy,
57+
T: TrivialClone,
5758
{
5859
#[track_caller]
5960
fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) {

library/core/src/array/mod.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
#![stable(feature = "core_array", since = "1.35.0")]
66

77
use crate::borrow::{Borrow, BorrowMut};
8+
use crate::clone::TrivialClone;
89
use crate::cmp::Ordering;
910
use crate::convert::Infallible;
1011
use crate::error::Error;
11-
use crate::fmt;
1212
use crate::hash::{self, Hash};
1313
use crate::intrinsics::transmute_unchecked;
1414
use crate::iter::{UncheckedIterator, repeat_n};
@@ -18,6 +18,7 @@ use crate::ops::{
1818
};
1919
use crate::ptr::{null, null_mut};
2020
use crate::slice::{Iter, IterMut};
21+
use crate::{fmt, ptr};
2122

2223
mod ascii;
2324
mod drain;
@@ -437,10 +438,12 @@ impl<T: Clone> SpecArrayClone for T {
437438
}
438439
}
439440

440-
impl<T: Copy> SpecArrayClone for T {
441+
impl<T: TrivialClone> SpecArrayClone for T {
441442
#[inline]
442443
fn clone<const N: usize>(array: &[T; N]) -> [T; N] {
443-
*array
444+
// SAFETY: `TrivialClone` implies that this is equivalent to calling
445+
// `Clone` on every element.
446+
unsafe { ptr::read(array) }
444447
}
445448
}
446449

library/core/src/clone.rs

+46
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,32 @@ pub trait Clone: Sized {
176176
}
177177
}
178178

179+
/// Indicates that the `Clone` implementation is identical to copying the value.
180+
///
181+
/// This is used for some optimizations in the standard library, which specializes
182+
/// on this trait to select faster implementations of functions such as
183+
/// [`clone_from_slice`](slice::clone_from_slice). It is automatically implemented
184+
/// when using `#[derive(Clone, Copy)]`.
185+
///
186+
/// Note that this trait does not imply that the type is `Copy`, because e.g.
187+
/// `core::ops::Range<i32>` could soundly implement this trait.
188+
///
189+
/// # Safety
190+
/// `Clone::clone` must be equivalent to copying the value, otherwise calling functions
191+
/// such as `slice::clone_from_slice` can have undefined behaviour.
192+
#[unstable(
193+
feature = "trivial_clone",
194+
reason = "this isn't part of any API guarantee",
195+
issue = "none"
196+
)]
197+
// SAFETY:
198+
// It is sound to specialize on this because the `clone` implementation cannot be
199+
// lifetime-dependent. Therefore, if `TrivialClone` is implemented for any lifetime,
200+
// its invariant holds whenever `Clone` is implemented, even if the actual
201+
// `TrivialClone` bound would not be satisfied because of lifetime bounds.
202+
#[rustc_unsafe_specialization_marker]
203+
pub unsafe trait TrivialClone: Clone {}
204+
179205
/// Derive macro generating an impl of the trait `Clone`.
180206
#[rustc_builtin_macro]
181207
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
@@ -327,6 +353,8 @@ unsafe impl CloneToUninit for crate::bstr::ByteStr {
327353
/// are implemented in `traits::SelectionContext::copy_clone_conditions()`
328354
/// in `rustc_trait_selection`.
329355
mod impls {
356+
use super::TrivialClone;
357+
330358
macro_rules! impl_clone {
331359
($($t:ty)*) => {
332360
$(
@@ -337,6 +365,9 @@ mod impls {
337365
*self
338366
}
339367
}
368+
369+
#[unstable(feature = "trivial_clone", issue = "none")]
370+
unsafe impl TrivialClone for $t {}
340371
)*
341372
}
342373
}
@@ -356,6 +387,12 @@ mod impls {
356387
}
357388
}
358389

390+
#[unstable(feature = "trivial_clone", issue = "none")]
391+
unsafe impl TrivialClone for ! {}
392+
393+
#[unstable(feature = "trivial_clone", issue = "none")]
394+
unsafe impl TrivialClone for () {}
395+
359396
#[stable(feature = "rust1", since = "1.0.0")]
360397
impl<T: ?Sized> Clone for *const T {
361398
#[inline(always)]
@@ -364,6 +401,9 @@ mod impls {
364401
}
365402
}
366403

404+
#[unstable(feature = "trivial_clone", issue = "none")]
405+
unsafe impl<T: ?Sized> TrivialClone for *const T {}
406+
367407
#[stable(feature = "rust1", since = "1.0.0")]
368408
impl<T: ?Sized> Clone for *mut T {
369409
#[inline(always)]
@@ -372,6 +412,9 @@ mod impls {
372412
}
373413
}
374414

415+
#[unstable(feature = "trivial_clone", issue = "none")]
416+
unsafe impl<T: ?Sized> TrivialClone for *mut T {}
417+
375418
/// Shared references can be cloned, but mutable references *cannot*!
376419
#[stable(feature = "rust1", since = "1.0.0")]
377420
impl<T: ?Sized> Clone for &T {
@@ -382,6 +425,9 @@ mod impls {
382425
}
383426
}
384427

428+
#[unstable(feature = "trivial_clone", issue = "none")]
429+
unsafe impl<T: ?Sized> TrivialClone for &T {}
430+
385431
/// Shared references can be cloned, but mutable references *cannot*!
386432
#[stable(feature = "rust1", since = "1.0.0")]
387433
impl<T: ?Sized> !Clone for &mut T {}

library/core/src/clone/uninit.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::TrivialClone;
12
use crate::mem::{self, MaybeUninit};
23
use crate::ptr;
34

@@ -49,9 +50,9 @@ unsafe impl<T: Clone> CopySpec for T {
4950
}
5051
}
5152

52-
// Specialized implementation for types that are [`Copy`], not just [`Clone`],
53+
// Specialized implementation for types that are [`TrivialClone`], not just [`Clone`],
5354
// and can therefore be copied bitwise.
54-
unsafe impl<T: Copy> CopySpec for T {
55+
unsafe impl<T: TrivialClone> CopySpec for T {
5556
#[inline]
5657
unsafe fn clone_one(src: &Self, dst: *mut Self) {
5758
// SAFETY: The safety conditions of clone_to_uninit() are a superset of those of

library/core/src/marker.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -409,12 +409,8 @@ marker_impls! {
409409
/// [impls]: #implementors
410410
#[stable(feature = "rust1", since = "1.0.0")]
411411
#[lang = "copy"]
412-
// FIXME(matthewjasper) This allows copying a type that doesn't implement
413-
// `Copy` because of unsatisfied lifetime bounds (copying `A<'_>` when only
414-
// `A<'static>: Copy` and `A<'_>: Clone`).
415-
// We have this attribute here for now only because there are quite a few
416-
// existing specializations on `Copy` that already exist in the standard
417-
// library, and there's no way to safely have this behavior right now.
412+
// This is unsound, but required by `hashbrown`
413+
// FIXME(joboet): change `hashbrown` to use `TrivialClone`
418414
#[rustc_unsafe_specialization_marker]
419415
#[rustc_diagnostic_item = "Copy"]
420416
pub trait Copy: Clone {

library/core/src/mem/maybe_uninit.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::any::type_name;
2+
use crate::clone::TrivialClone;
23
use crate::mem::ManuallyDrop;
34
use crate::{fmt, intrinsics, ptr, slice};
45

@@ -272,6 +273,10 @@ impl<T: Copy> Clone for MaybeUninit<T> {
272273
}
273274
}
274275

276+
// SAFETY: the clone implementation is a copy, see above.
277+
#[unstable(feature = "trivial_clone", issue = "none")]
278+
unsafe impl<T> TrivialClone for MaybeUninit<T> where MaybeUninit<T>: Clone {}
279+
275280
#[stable(feature = "maybe_uninit_debug", since = "1.41.0")]
276281
impl<T> fmt::Debug for MaybeUninit<T> {
277282
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -1613,8 +1618,12 @@ impl<T: Clone> SpecFill<T> for [MaybeUninit<T>] {
16131618
}
16141619
}
16151620

1616-
impl<T: Copy> SpecFill<T> for [MaybeUninit<T>] {
1621+
impl<T: TrivialClone> SpecFill<T> for [MaybeUninit<T>] {
16171622
fn spec_fill(&mut self, value: T) {
1618-
self.fill(MaybeUninit::new(value));
1623+
// SAFETY: because `T` is `TrivialClone`, this is equivalent to calling
1624+
// `T::clone` for every element. Notably, `TrivialClone` also implies
1625+
// that the `clone` implementation will not panic, so we can avoid
1626+
// initialization guards and such.
1627+
self.fill_with(|| MaybeUninit::new(unsafe { ptr::read(&value) }));
16191628
}
16201629
}

0 commit comments

Comments
 (0)