Skip to content

Commit

Permalink
Move some implementations of Clone and Copy to libcore
Browse files Browse the repository at this point in the history
Add implementations of `Clone` and `Copy` for some primitive types to
libcore so that they show up in the documentation. The concerned types
are the following:

* All primitive signed and unsigned integer types (`usize`, `u8`, `u16`,
  `u32`, `u64`, `u128`, `isize`, `i8`, `i16`, `i32`, `i64`, `i128`);
* All primitive floating point types (`f32`, `f64`)
* `bool`
* `char`
* `!`
* Raw pointers (`*const T` and `*mut T`)
* Shared references (`&'a T`)

These types already implemented `Clone` and `Copy`, but the
implementation was provided by the compiler. The compiler no longer
provides these implementations and instead tries to look them up as
normal trait implementations. The goal of this change is to make the
implementations appear in the generated documentation.

For `Copy` specifically, the compiler would reject an attempt to write
an `impl` for the primitive types listed above with error `E0206`; this
error no longer occurs for these types, but it will still occur for the
other types that used to raise that error.

The trait implementations are guarded with `#[cfg(not(stage0))]` because
they are invalid according to the stage0 compiler. When the stage0
compiler is updated to a revision that includes this change, the
attribute will have to be removed, otherwise the stage0 build will fail
because the types mentioned above no longer implement `Clone` or `Copy`.

For type variants that are variadic, such as tuples and function
pointers, and for array types, the `Clone` and `Copy` implementations
are still provided by the compiler, because the language is not
expressive enough yet to be able to write the appropriate
implementations in Rust.

The initial plan was to add `impl` blocks guarded by `#[cfg(dox)]` to
make them apply only when generating documentation, without having to
touch the compiler. However, rustdoc's usage of the compiler still
rejected those `impl` blocks.

This is a [breaking-change] for users of `#![no_core]`, because they
will now have to supply their own implementations of `Clone` and `Copy`
for the primitive types listed above. The easiest way to do that is to
simply copy the implementations from `src/libcore/clone.rs` and
`src/libcore/marker.rs`.

Fixes #25893
  • Loading branch information
FraGag committed Mar 27, 2018
1 parent 989b257 commit 27164fa
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 30 deletions.
60 changes: 60 additions & 0 deletions src/libcore/clone.rs
Expand Up @@ -135,3 +135,63 @@ 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 {
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 ! {
fn clone(&self) -> Self {
*self
}
}

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

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

}
40 changes: 40 additions & 0 deletions src/libcore/marker.rs
Expand Up @@ -593,3 +593,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
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
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
Expand Up @@ -1918,16 +1918,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
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
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
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
60 changes: 43 additions & 17 deletions src/test/ui/coherence-impls-copy.stderr
@@ -1,35 +1,61 @@
error[E0206]: the trait `Copy` may not be implemented for this type
--> $DIR/coherence-impls-copy.rs:29:15
error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `i32`:
--> $DIR/coherence-impls-copy.rs:15:1
|
LL | impl Copy for &'static mut MyType {}
| ^^^^^^^^^^^^^^^^^^^ type is not a structure or enumeration
LL | impl Copy for i32 {}
| ^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl std::marker::Copy for i32;

error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `&NotSync`:
--> $DIR/coherence-impls-copy.rs:41:1
|
LL | impl Copy for &'static NotSync {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<'a, T> std::marker::Copy for &'a T
where T: ?Sized;

error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `&[NotSync]`:
--> $DIR/coherence-impls-copy.rs:48:1
|
LL | impl Copy for &'static [NotSync] {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<'a, T> std::marker::Copy for &'a T
where T: ?Sized;

error[E0206]: the trait `Copy` may not be implemented for this type
--> $DIR/coherence-impls-copy.rs:33:15
|
LL | impl Copy for (MyType, MyType) {}
| ^^^^^^^^^^^^^^^^ type is not a structure or enumeration
LL | impl Copy for &'static mut MyType {}
| ^^^^^^^^^^^^^^^^^^^ type is not a structure or enumeration

error[E0206]: the trait `Copy` may not be implemented for this type
--> $DIR/coherence-impls-copy.rs:37:15
|
LL | impl Copy for &'static NotSync {}
LL | impl Copy for (MyType, MyType) {}
| ^^^^^^^^^^^^^^^^ type is not a structure or enumeration

error[E0206]: the trait `Copy` may not be implemented for this type
--> $DIR/coherence-impls-copy.rs:40:15
--> $DIR/coherence-impls-copy.rs:44:15
|
LL | impl Copy for [MyType] {}
| ^^^^^^^^ type is not a structure or enumeration

error[E0206]: the trait `Copy` may not be implemented for this type
--> $DIR/coherence-impls-copy.rs:44:15
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/coherence-impls-copy.rs:15:1
|
LL | impl Copy for &'static [NotSync] {}
| ^^^^^^^^^^^^^^^^^^ type is not a structure or enumeration
LL | impl Copy for i32 {}
| ^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
|
= note: the impl does not reference any types defined in this crate
= note: define and implement a trait or new type instead

error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/coherence-impls-copy.rs:33:1
--> $DIR/coherence-impls-copy.rs:37:1
|
LL | impl Copy for (MyType, MyType) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
Expand All @@ -38,7 +64,7 @@ LL | impl Copy for (MyType, MyType) {}
= note: define and implement a trait or new type instead

error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/coherence-impls-copy.rs:40:1
--> $DIR/coherence-impls-copy.rs:44:1
|
LL | impl Copy for [MyType] {}
| ^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
Expand All @@ -47,15 +73,15 @@ LL | impl Copy for [MyType] {}
= note: define and implement a trait or new type instead

error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/coherence-impls-copy.rs:44:1
--> $DIR/coherence-impls-copy.rs:48:1
|
LL | impl Copy for &'static [NotSync] {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
|
= note: the impl does not reference any types defined in this crate
= note: define and implement a trait or new type instead

error: aborting due to 8 previous errors
error: aborting due to 10 previous errors

Some errors occurred: E0117, E0206.
Some errors occurred: E0117, E0119, E0206.
For more information about an error, try `rustc --explain E0117`.
4 changes: 2 additions & 2 deletions src/test/ui/error-codes/E0206.rs
Expand Up @@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

type Foo = i32;
type Foo = [u8; 256];

impl Copy for Foo { }
//~^ ERROR the trait `Copy` may not be implemented for this type
Expand All @@ -17,7 +17,7 @@ impl Copy for Foo { }
#[derive(Copy, Clone)]
struct Bar;

impl Copy for &'static Bar { }
impl Copy for &'static mut Bar { }
//~^ ERROR the trait `Copy` may not be implemented for this type

fn main() {
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/error-codes/E0206.stderr
Expand Up @@ -7,8 +7,8 @@ LL | impl Copy for Foo { }
error[E0206]: the trait `Copy` may not be implemented for this type
--> $DIR/E0206.rs:20:15
|
LL | impl Copy for &'static Bar { }
| ^^^^^^^^^^^^ type is not a structure or enumeration
LL | impl Copy for &'static mut Bar { }
| ^^^^^^^^^^^^^^^^ type is not a structure or enumeration

error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/E0206.rs:13:1
Expand Down

0 comments on commit 27164fa

Please sign in to comment.