Skip to content

Commit

Permalink
Auto merge of #48171 - FraGag:doc-copy-clone-impls, r=nikomatsakis
Browse files Browse the repository at this point in the history
Better document the implementors of Clone and Copy

There are two parts to this change. The first part is a change to the compiler and to the standard library (specifically, libcore) to allow implementations of `Clone` and `Copy` to be written for a subset of builtin types. By adding these implementations to libcore, they now show up in the documentation. This is a [breaking-change] for users of `#![no_core]`, because they will now have to supply their own copy of the implementations of `Clone` and `Copy` that were added in libcore.

The second part is purely a documentation change to document the other implementors of `Clone` and `Copy` that cannot be described in Rust code (yet) and are thus provided by the compiler.

Fixes #25893
  • Loading branch information
bors committed Apr 4, 2018
2 parents 17fea66 + 87c08f9 commit fb44b4c
Show file tree
Hide file tree
Showing 13 changed files with 221 additions and 42 deletions.
87 changes: 82 additions & 5 deletions src/libcore/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,6 @@
/// This trait can be used with `#[derive]` if all fields are `Clone`. The `derive`d
/// implementation of [`clone`] calls [`clone`] on each field.
///
/// ## Closures
///
/// Closure types automatically implement `Clone` if they capture no value from the environment
/// or if all such captured values implement `Clone` themselves.
///
/// ## How can I implement `Clone`?
///
/// Types that are [`Copy`] should have a trivial implementation of `Clone`. More formally:
Expand All @@ -92,6 +87,23 @@
/// fn clone(&self) -> Stats { *self }
/// }
/// ```
///
/// ## Additional implementors
///
/// In addition to the [implementors listed below][impls],
/// the following types also implement `Clone`:
///
/// * Function item types (i.e. the distinct types defined for each function)
/// * Function pointer types (e.g. `fn() -> i32`)
/// * Array types, for all sizes, if the item type also implements `Clone` (e.g. `[i32; 123456]`)
/// * Tuple types, if each component also implements `Clone` (e.g. `()`, `(i32, bool)`)
/// * Closure types, if they capture no value from the environment
/// or if all such captured values implement `Clone` themselves.
/// Note that variables captured by shared reference always implement `Clone`
/// (even if the referent doesn't),
/// while variables captured by mutable reference never implement `Clone`.
///
/// [impls]: #implementors
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "clone"]
pub trait Clone : Sized {
Expand Down Expand Up @@ -135,3 +147,68 @@ pub struct AssertParamIsClone<T: Clone + ?Sized> { _field: ::marker::PhantomData
reason = "deriving hack, should not be public",
issue = "0")]
pub struct AssertParamIsCopy<T: Copy + ?Sized> { _field: ::marker::PhantomData<T> }

/// Implementations of `Clone` for primitive types.
///
/// Implementations that cannot be described in Rust
/// are implemented in `SelectionContext::copy_clone_conditions()` in librustc.
#[cfg(not(stage0))]
mod impls {

use super::Clone;

macro_rules! impl_clone {
($($t:ty)*) => {
$(
#[stable(feature = "rust1", since = "1.0.0")]
impl Clone for $t {
#[inline]
fn clone(&self) -> Self {
*self
}
}
)*
}
}

impl_clone! {
usize u8 u16 u32 u64 u128
isize i8 i16 i32 i64 i128
f32 f64
bool char
}

#[stable(feature = "never_type", since = "1.26.0")]
impl Clone for ! {
#[inline]
fn clone(&self) -> Self {
*self
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Clone for *const T {
#[inline]
fn clone(&self) -> Self {
*self
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Clone for *mut T {
#[inline]
fn clone(&self) -> Self {
*self
}
}

// Shared references can be cloned, but mutable references *cannot*!
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> Clone for &'a T {
#[inline]
fn clone(&self) -> Self {
*self
}
}

}
61 changes: 56 additions & 5 deletions src/libcore/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,6 @@ pub trait Unsize<T: ?Sized> {
/// are allowed to access `x` after the assignment. Under the hood, both a copy and a move
/// can result in bits being copied in memory, although this is sometimes optimized away.
///
/// ## Closures
///
/// Closure types automatically implement `Copy` if they capture no value from the environment
/// or if all such captured values implement `Copy` themselves.
///
/// ## How can I implement `Copy`?
///
/// There are two ways to implement `Copy` on your type. The simplest is to use `derive`:
Expand Down Expand Up @@ -265,13 +260,29 @@ pub trait Unsize<T: ?Sized> {
/// non-`Copy` in the future, it could be prudent to omit the `Copy` implementation now, to
/// avoid a breaking API change.
///
/// ## Additional implementors
///
/// In addition to the [implementors listed below][impls],
/// the following types also implement `Copy`:
///
/// * Function item types (i.e. the distinct types defined for each function)
/// * Function pointer types (e.g. `fn() -> i32`)
/// * Array types, for all sizes, if the item type also implements `Copy` (e.g. `[i32; 123456]`)
/// * Tuple types, if each component also implements `Copy` (e.g. `()`, `(i32, bool)`)
/// * Closure types, if they capture no value from the environment
/// or if all such captured values implement `Copy` themselves.
/// Note that variables captured by shared reference always implement `Copy`
/// (even if the referent doesn't),
/// while variables captured by mutable reference never implement `Copy`.
///
/// [`Vec<T>`]: ../../std/vec/struct.Vec.html
/// [`String`]: ../../std/string/struct.String.html
/// [`Drop`]: ../../std/ops/trait.Drop.html
/// [`size_of::<T>`]: ../../std/mem/fn.size_of.html
/// [`Clone`]: ../clone/trait.Clone.html
/// [`String`]: ../../std/string/struct.String.html
/// [`i32`]: ../../std/primitive.i32.html
/// [impls]: #implementors
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "copy"]
pub trait Copy : Clone {
Expand Down Expand Up @@ -593,3 +604,43 @@ unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {}
/// This trait is automatically implemented for almost every type.
#[unstable(feature = "pin", issue = "49150")]
pub unsafe auto trait Unpin {}

/// Implementations of `Copy` for primitive types.
///
/// Implementations that cannot be described in Rust
/// are implemented in `SelectionContext::copy_clone_conditions()` in librustc.
#[cfg(not(stage0))]
mod copy_impls {

use super::Copy;

macro_rules! impl_copy {
($($t:ty)*) => {
$(
#[stable(feature = "rust1", since = "1.0.0")]
impl Copy for $t {}
)*
}
}

impl_copy! {
usize u8 u16 u32 u64 u128
isize i8 i16 i32 i64 i128
f32 f64
bool char
}

#[stable(feature = "never_type", since = "1.26.0")]
impl Copy for ! {}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Copy for *const T {}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Copy for *mut T {}

// Shared references can be copied, but mutable references *cannot*!
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> Copy for &'a T {}

}
10 changes: 7 additions & 3 deletions src/librustc/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2061,11 +2061,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {

match self_ty.sty {
ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) |
ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyError => {
Where(ty::Binder(Vec::new()))
}

ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) |
ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar |
ty::TyRawPtr(..) | ty::TyError | ty::TyNever |
ty::TyChar | ty::TyRawPtr(..) | ty::TyNever |
ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
Where(ty::Binder(Vec::new()))
// Implementations provided in libcore
None
}

ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) |
Expand Down
7 changes: 7 additions & 0 deletions src/librustc/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,14 @@ impl<'tcx> ty::ParamEnv<'tcx> {
// FIXME: (@jroesch) float this code up
tcx.infer_ctxt().enter(|infcx| {
let (adt, substs) = match self_type.sty {
// These types used to have a builtin impl.
// Now libcore provides that impl.
ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) |
ty::TyChar | ty::TyRawPtr(..) | ty::TyNever |
ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => return Ok(()),

ty::TyAdt(adt, substs) => (adt, substs),

_ => return Err(CopyImplementationError::NotAnAdt),
};

Expand Down
8 changes: 4 additions & 4 deletions src/librustc_typeck/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1908,16 +1908,16 @@ differs from the behavior for `&T`, which is always `Copy`).

E0206: r##"
You can only implement `Copy` for a struct or enum. Both of the following
examples will fail, because neither `i32` (primitive type) nor `&'static Bar`
(reference to `Bar`) is a struct or enum:
examples will fail, because neither `[u8; 256]` nor `&'static mut Bar`
(mutable reference to `Bar`) is a struct or enum:
```compile_fail,E0206
type Foo = i32;
type Foo = [u8; 256];
impl Copy for Foo { } // error
#[derive(Copy, Clone)]
struct Bar;
impl Copy for &'static Bar { } // error
impl Copy for &'static mut Bar { } // error
```
"##,

Expand Down
7 changes: 6 additions & 1 deletion src/test/codegen/repeat-trusted-len.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@

use std::iter;

// CHECK: @helper([[USIZE:i[0-9]+]] %arg0)
#[no_mangle]
pub fn helper(_: usize) {
}

// CHECK-LABEL: @repeat_take_collect
#[no_mangle]
pub fn repeat_take_collect() -> Vec<u8> {
// CHECK: call void @llvm.memset.p0i8
// CHECK: call void @llvm.memset.p0i8.[[USIZE]](i8* {{(nonnull )?}}%{{[0-9]+}}, i8 42, [[USIZE]] 100000, i32 1, i1 false)
iter::repeat(42).take(100000).collect()
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ trait Copy {}
#[lang = "freeze"]
trait Freeze {}

impl<T: ?Sized> Copy for *mut T {}

#[cfg(target_has_atomic = "8")]
pub unsafe fn atomic_u8(x: *mut u8) {
atomic_xadd(x, 1);
Expand Down
3 changes: 3 additions & 0 deletions src/test/run-make-fulldeps/simd-ffi/simd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ pub trait Sized { }
#[lang = "copy"]
pub trait Copy { }

impl Copy for f32 {}
impl Copy for i32 {}

pub mod marker {
pub use Copy;
}
Expand Down
8 changes: 6 additions & 2 deletions src/test/ui/coherence-impls-copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@

use std::marker::Copy;

impl Copy for i32 {}
//~^ ERROR conflicting implementations of trait `std::marker::Copy` for type `i32`:
//~| ERROR only traits defined in the current crate can be implemented for arbitrary types

enum TestE {
A
}
Expand All @@ -35,14 +39,14 @@ impl Copy for (MyType, MyType) {}
//~| ERROR only traits defined in the current crate can be implemented for arbitrary types

impl Copy for &'static NotSync {}
//~^ ERROR the trait `Copy` may not be implemented for this type
//~^ ERROR conflicting implementations of trait `std::marker::Copy` for type `&NotSync`:

impl Copy for [MyType] {}
//~^ ERROR the trait `Copy` may not be implemented for this type
//~| ERROR only traits defined in the current crate can be implemented for arbitrary types

impl Copy for &'static [NotSync] {}
//~^ ERROR the trait `Copy` may not be implemented for this type
//~^ ERROR conflicting implementations of trait `std::marker::Copy` for type `&[NotSync]`:
//~| ERROR only traits defined in the current crate can be implemented for arbitrary types

fn main() {
Expand Down
Loading

0 comments on commit fb44b4c

Please sign in to comment.