Skip to content

Commit 6e9bbe2

Browse files
committed
(almost) get rid of the unsound #[rustc_unsafe_specialization_marker] on Copy, introduce TrivialClone
1 parent 73c0ae6 commit 6e9bbe2

File tree

14 files changed

+139
-52
lines changed

14 files changed

+139
-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
@@ -144,6 +144,7 @@
144144
#![feature(std_internals)]
145145
#![feature(str_internals)]
146146
#![feature(temporary_niche_types)]
147+
#![feature(trivial_clone)]
147148
#![feature(trusted_fused)]
148149
#![feature(trusted_len)]
149150
#![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))]
@@ -87,6 +88,7 @@ use crate::vec::Vec;
8788
// `test_permutations` test
8889
pub(crate) mod hack {
8990
use core::alloc::Allocator;
91+
use core::clone::TrivialClone;
9092

9193
use crate::boxed::Box;
9294
use crate::vec::Vec;
@@ -155,7 +157,7 @@ pub(crate) mod hack {
155157
}
156158

157159
#[cfg(not(no_global_oom_handling))]
158-
impl<T: Copy> ConvertVec for T {
160+
impl<T: TrivialClone> ConvertVec for T {
159161
#[inline]
160162
fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
161163
let mut v = Vec::with_capacity_in(s.len(), alloc);
@@ -871,7 +873,7 @@ impl<T: Clone, A: Allocator> SpecCloneIntoVec<T, A> for [T] {
871873
}
872874

873875
#[cfg(not(no_global_oom_handling))]
874-
impl<T: Copy, A: Allocator> SpecCloneIntoVec<T, A> for [T] {
876+
impl<T: TrivialClone, A: Allocator> SpecCloneIntoVec<T, A> for [T] {
875877
fn clone_into(&self, target: &mut Vec<T, A>) {
876878
target.clear();
877879
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;
@@ -3228,7 +3229,7 @@ impl<T: Clone, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
32283229
}
32293230

32303231
#[cfg(not(no_global_oom_handling))]
3231-
impl<T: Copy, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
3232+
impl<T: TrivialClone, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
32323233
unsafe fn spec_extend_from_within(&mut self, src: Range<usize>) {
32333234
let count = src.len();
32343235
{
@@ -3241,8 +3242,8 @@ impl<T: Copy, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
32413242
// SAFETY:
32423243
// - Both pointers are created from unique slice references (`&mut [_]`)
32433244
// so they are valid and do not overlap.
3244-
// - Elements are :Copy so it's OK to copy them, without doing
3245-
// anything with the original values
3245+
// - Elements implement `TrivialClone` so this is equivalent to calling
3246+
// `clone` on every one of them.
32463247
// - `count` is equal to the len of `source`, so source is valid for
32473248
// `count` reads
32483249
// - `.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;
@@ -438,10 +439,12 @@ impl<T: Clone> SpecArrayClone for T {
438439
}
439440
}
440441

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

library/core/src/clone.rs

+43
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")]
@@ -317,6 +343,8 @@ unsafe impl CloneToUninit for crate::ffi::CStr {
317343
/// are implemented in `traits::SelectionContext::copy_clone_conditions()`
318344
/// in `rustc_trait_selection`.
319345
mod impls {
346+
use super::TrivialClone;
347+
320348
macro_rules! impl_clone {
321349
($($t:ty)*) => {
322350
$(
@@ -327,6 +355,9 @@ mod impls {
327355
*self
328356
}
329357
}
358+
359+
#[unstable(feature = "trivial_clone", issue = "none")]
360+
unsafe impl TrivialClone for $t {}
330361
)*
331362
}
332363
}
@@ -346,6 +377,9 @@ mod impls {
346377
}
347378
}
348379

380+
#[unstable(feature = "trivial_clone", issue = "none")]
381+
unsafe impl TrivialClone for ! {}
382+
349383
#[stable(feature = "rust1", since = "1.0.0")]
350384
impl<T: ?Sized> Clone for *const T {
351385
#[inline(always)]
@@ -354,6 +388,9 @@ mod impls {
354388
}
355389
}
356390

391+
#[unstable(feature = "trivial_clone", issue = "none")]
392+
unsafe impl<T: ?Sized> TrivialClone for *const T {}
393+
357394
#[stable(feature = "rust1", since = "1.0.0")]
358395
impl<T: ?Sized> Clone for *mut T {
359396
#[inline(always)]
@@ -362,6 +399,9 @@ mod impls {
362399
}
363400
}
364401

402+
#[unstable(feature = "trivial_clone", issue = "none")]
403+
unsafe impl<T: ?Sized> TrivialClone for *mut T {}
404+
365405
/// Shared references can be cloned, but mutable references *cannot*!
366406
#[stable(feature = "rust1", since = "1.0.0")]
367407
impl<T: ?Sized> Clone for &T {
@@ -372,6 +412,9 @@ mod impls {
372412
}
373413
}
374414

415+
#[unstable(feature = "trivial_clone", issue = "none")]
416+
unsafe impl<T: ?Sized> TrivialClone for &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 &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
@@ -402,12 +402,8 @@ marker_impls! {
402402
/// [impls]: #implementors
403403
#[stable(feature = "rust1", since = "1.0.0")]
404404
#[lang = "copy"]
405-
// FIXME(matthewjasper) This allows copying a type that doesn't implement
406-
// `Copy` because of unsatisfied lifetime bounds (copying `A<'_>` when only
407-
// `A<'static>: Copy` and `A<'_>: Clone`).
408-
// We have this attribute here for now only because there are quite a few
409-
// existing specializations on `Copy` that already exist in the standard
410-
// library, and there's no way to safely have this behavior right now.
405+
// This is unsound, but required by `hashbrown`
406+
// FIXME(joboet): change `hashbrown` to use `TrivialClone`
411407
#[rustc_unsafe_specialization_marker]
412408
#[rustc_diagnostic_item = "Copy"]
413409
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 {
@@ -1614,8 +1619,12 @@ impl<T: Clone> SpecFill<T> for [MaybeUninit<T>] {
16141619
}
16151620
}
16161621

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

0 commit comments

Comments
 (0)