Skip to content

Commit a2b4ef7

Browse files
committed
(almost) get rid of the unsound #[rustc_unsafe_specialization_marker] on Copy, introduce TrivialClone
1 parent 9bad8ac commit a2b4ef7

21 files changed

+179
-55
lines changed

library/alloc/src/boxed/convert.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use core::any::Any;
2+
#[cfg(not(no_global_oom_handling))]
3+
use core::clone::TrivialClone;
24
use core::error::Error;
35
use core::mem;
46
use core::pin::Pin;
@@ -75,11 +77,13 @@ impl<T: Clone> BoxFromSlice<T> for Box<[T]> {
7577
}
7678

7779
#[cfg(not(no_global_oom_handling))]
78-
impl<T: Copy> BoxFromSlice<T> for Box<[T]> {
80+
impl<T: TrivialClone> BoxFromSlice<T> for Box<[T]> {
7981
#[inline]
8082
fn from_slice(slice: &[T]) -> Self {
8183
let len = slice.len();
8284
let buf = RawVec::with_capacity(len);
85+
// SAFETY: since `T` implements `TrivialClone`, this is sound and
86+
// equivalent to the above.
8387
unsafe {
8488
ptr::copy_nonoverlapping(slice.as_ptr(), buf.ptr(), len);
8589
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

+7-4
Original file line numberDiff line numberDiff line change
@@ -243,9 +243,9 @@
243243

244244
use core::any::Any;
245245
use core::cell::Cell;
246-
#[cfg(not(no_global_oom_handling))]
247-
use core::clone::CloneToUninit;
248246
use core::clone::UseCloned;
247+
#[cfg(not(no_global_oom_handling))]
248+
use core::clone::{CloneToUninit, TrivialClone};
249249
use core::cmp::Ordering;
250250
use core::hash::{Hash, Hasher};
251251
use core::intrinsics::abort;
@@ -2150,7 +2150,8 @@ impl<T> Rc<[T]> {
21502150

21512151
/// Copy elements from slice into newly allocated `Rc<[T]>`
21522152
///
2153-
/// Unsafe because the caller must either take ownership or bind `T: Copy`
2153+
/// Unsafe because the caller must either take ownership, bind `T: Copy` or
2154+
/// bind `T: TrivialClone`.
21542155
#[cfg(not(no_global_oom_handling))]
21552156
unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> {
21562157
unsafe {
@@ -2240,9 +2241,11 @@ impl<T: Clone> RcFromSlice<T> for Rc<[T]> {
22402241
}
22412242

22422243
#[cfg(not(no_global_oom_handling))]
2243-
impl<T: Copy> RcFromSlice<T> for Rc<[T]> {
2244+
impl<T: TrivialClone> RcFromSlice<T> for Rc<[T]> {
22442245
#[inline]
22452246
fn from_slice(v: &[T]) -> Self {
2247+
// SAFETY: `T` implements `TrivialClone`, so this is sound and equivalent
2248+
// to the above.
22462249
unsafe { Rc::copy_from_slice(v) }
22472250
}
22482251
}

library/alloc/src/slice.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
use core::borrow::{Borrow, BorrowMut};
1313
#[cfg(not(no_global_oom_handling))]
14+
use core::clone::TrivialClone;
15+
#[cfg(not(no_global_oom_handling))]
1416
use core::cmp::Ordering::{self, Less};
1517
#[cfg(not(no_global_oom_handling))]
1618
use core::mem::MaybeUninit;
@@ -440,7 +442,7 @@ impl<T> [T] {
440442
}
441443
}
442444

443-
impl<T: Copy> ConvertVec for T {
445+
impl<T: TrivialClone> ConvertVec for T {
444446
#[inline]
445447
fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
446448
let mut v = Vec::with_capacity_in(s.len(), alloc);
@@ -825,7 +827,7 @@ impl<T: Clone, A: Allocator> SpecCloneIntoVec<T, A> for [T] {
825827
}
826828

827829
#[cfg(not(no_global_oom_handling))]
828-
impl<T: Copy, A: Allocator> SpecCloneIntoVec<T, A> for [T] {
830+
impl<T: TrivialClone, A: Allocator> SpecCloneIntoVec<T, A> for [T] {
829831
fn clone_into(&self, target: &mut Vec<T, A>) {
830832
target.clear();
831833
target.extend_from_slice(self);

library/alloc/src/sync.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
use core::any::Any;
1212
#[cfg(not(no_global_oom_handling))]
1313
use core::clone::CloneToUninit;
14+
#[cfg(not(no_global_oom_handling))]
15+
use core::clone::TrivialClone;
1416
use core::clone::UseCloned;
1517
use core::cmp::Ordering;
1618
use core::hash::{Hash, Hasher};
@@ -2057,7 +2059,8 @@ impl<T> Arc<[T]> {
20572059

20582060
/// Copy elements from slice into newly allocated `Arc<[T]>`
20592061
///
2060-
/// Unsafe because the caller must either take ownership or bind `T: Copy`.
2062+
/// Unsafe because the caller must either take ownership, bind `T: Copy` or
2063+
/// bind `T: TrivialClone`.
20612064
#[cfg(not(no_global_oom_handling))]
20622065
unsafe fn copy_from_slice(v: &[T]) -> Arc<[T]> {
20632066
unsafe {
@@ -2149,9 +2152,11 @@ impl<T: Clone> ArcFromSlice<T> for Arc<[T]> {
21492152
}
21502153

21512154
#[cfg(not(no_global_oom_handling))]
2152-
impl<T: Copy> ArcFromSlice<T> for Arc<[T]> {
2155+
impl<T: TrivialClone> ArcFromSlice<T> for Arc<[T]> {
21532156
#[inline]
21542157
fn from_slice(v: &[T]) -> Self {
2158+
// SAFETY: `T` implements `TrivialClone`, so this is sound and equivalent
2159+
// to the above.
21552160
unsafe { Arc::copy_from_slice(v) }
21562161
}
21572162
}

library/alloc/src/vec/mod.rs

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

56+
#[cfg(not(no_global_oom_handling))]
57+
use core::clone::TrivialClone;
5658
#[cfg(not(no_global_oom_handling))]
5759
use core::cmp;
5860
use core::cmp::Ordering;
@@ -3250,7 +3252,7 @@ impl<T: Clone, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
32503252
}
32513253

32523254
#[cfg(not(no_global_oom_handling))]
3253-
impl<T: Copy, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
3255+
impl<T: TrivialClone, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
32543256
unsafe fn spec_extend_from_within(&mut self, src: Range<usize>) {
32553257
let count = src.len();
32563258
{
@@ -3263,8 +3265,8 @@ impl<T: Copy, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
32633265
// SAFETY:
32643266
// - Both pointers are created from unique slice references (`&mut [_]`)
32653267
// so they are valid and do not overlap.
3266-
// - Elements are :Copy so it's OK to copy them, without doing
3267-
// anything with the original values
3268+
// - Elements implement `TrivialClone` so this is equivalent to calling
3269+
// `clone` on every one of them.
32683270
// - `count` is equal to the len of `source`, so source is valid for
32693271
// `count` reads
32703272
// - `.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

+9-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;
@@ -426,6 +427,9 @@ impl<T: Clone, const N: usize> Clone for [T; N] {
426427
}
427428
}
428429

430+
#[unstable(feature = "trivial_clone", issue = "none")]
431+
unsafe impl<T: TrivialClone, const N: usize> TrivialClone for [T; N] {}
432+
429433
trait SpecArrayClone: Clone {
430434
fn clone<const N: usize>(array: &[Self; N]) -> [Self; N];
431435
}
@@ -437,10 +441,12 @@ impl<T: Clone> SpecArrayClone for T {
437441
}
438442
}
439443

440-
impl<T: Copy> SpecArrayClone for T {
444+
impl<T: TrivialClone> SpecArrayClone for T {
441445
#[inline]
442446
fn clone<const N: usize>(array: &[T; N]) -> [T; N] {
443-
*array
447+
// SAFETY: `TrivialClone` implies that this is equivalent to calling
448+
// `Clone` on every element.
449+
unsafe { ptr::read(array) }
444450
}
445451
}
446452

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")]
@@ -495,6 +521,8 @@ unsafe impl CloneToUninit for crate::bstr::ByteStr {
495521
/// are implemented in `traits::SelectionContext::copy_clone_conditions()`
496522
/// in `rustc_trait_selection`.
497523
mod impls {
524+
use super::TrivialClone;
525+
498526
macro_rules! impl_clone {
499527
($($t:ty)*) => {
500528
$(
@@ -505,6 +533,9 @@ mod impls {
505533
*self
506534
}
507535
}
536+
537+
#[unstable(feature = "trivial_clone", issue = "none")]
538+
unsafe impl TrivialClone for $t {}
508539
)*
509540
}
510541
}
@@ -524,6 +555,12 @@ mod impls {
524555
}
525556
}
526557

558+
#[unstable(feature = "trivial_clone", issue = "none")]
559+
unsafe impl TrivialClone for ! {}
560+
561+
#[unstable(feature = "trivial_clone", issue = "none")]
562+
unsafe impl TrivialClone for () {}
563+
527564
#[stable(feature = "rust1", since = "1.0.0")]
528565
impl<T: ?Sized> Clone for *const T {
529566
#[inline(always)]
@@ -532,6 +569,9 @@ mod impls {
532569
}
533570
}
534571

572+
#[unstable(feature = "trivial_clone", issue = "none")]
573+
unsafe impl<T: ?Sized> TrivialClone for *const T {}
574+
535575
#[stable(feature = "rust1", since = "1.0.0")]
536576
impl<T: ?Sized> Clone for *mut T {
537577
#[inline(always)]
@@ -540,6 +580,9 @@ mod impls {
540580
}
541581
}
542582

583+
#[unstable(feature = "trivial_clone", issue = "none")]
584+
unsafe impl<T: ?Sized> TrivialClone for *mut T {}
585+
543586
/// Shared references can be cloned, but mutable references *cannot*!
544587
#[stable(feature = "rust1", since = "1.0.0")]
545588
impl<T: ?Sized> Clone for &T {
@@ -550,6 +593,9 @@ mod impls {
550593
}
551594
}
552595

596+
#[unstable(feature = "trivial_clone", issue = "none")]
597+
unsafe impl<T: ?Sized> TrivialClone for &T {}
598+
553599
/// Shared references can be cloned, but mutable references *cannot*!
554600
#[stable(feature = "rust1", since = "1.0.0")]
555601
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

+6-6
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub use self::variance::{
1414
PhantomInvariant, PhantomInvariantLifetime, Variance, variance,
1515
};
1616
use crate::cell::UnsafeCell;
17+
use crate::clone::TrivialClone;
1718
use crate::cmp;
1819
use crate::fmt::Debug;
1920
use crate::hash::{Hash, Hasher};
@@ -409,12 +410,8 @@ marker_impls! {
409410
/// [impls]: #implementors
410411
#[stable(feature = "rust1", since = "1.0.0")]
411412
#[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.
413+
// This is unsound, but required by `hashbrown`
414+
// FIXME(joboet): change `hashbrown` to use `TrivialClone`
418415
#[rustc_unsafe_specialization_marker]
419416
#[rustc_diagnostic_item = "Copy"]
420417
pub trait Copy: Clone {
@@ -816,6 +813,9 @@ impl<T: ?Sized> Clone for PhantomData<T> {
816813
}
817814
}
818815

816+
#[unstable(feature = "trivial_clone", issue = "none")]
817+
unsafe impl<T: ?Sized> TrivialClone for PhantomData<T> {}
818+
819819
#[stable(feature = "rust1", since = "1.0.0")]
820820
impl<T: ?Sized> Default for PhantomData<T> {
821821
fn default() -> Self {

library/core/src/marker/variance.rs

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use super::PhantomData;
44
use crate::any::type_name;
5+
use crate::clone::TrivialClone;
56
use crate::cmp::Ordering;
67
use crate::fmt;
78
use crate::hash::{Hash, Hasher};
@@ -60,6 +61,8 @@ macro_rules! phantom_type {
6061

6162
impl<T> Copy for $name<T> where T: ?Sized {}
6263

64+
unsafe impl<T> TrivialClone for $name<T> where T: ?Sized {}
65+
6366
impl<T> PartialEq for $name<T>
6467
where T: ?Sized
6568
{

0 commit comments

Comments
 (0)