Skip to content

Commit

Permalink
Auto merge of rust-lang#43690 - scalexm:issue-28229, r=nikomatsakis
Browse files Browse the repository at this point in the history
Generate builtin impls for `Clone`

This fixes a long-standing ICE and limitation where some builtin types implement `Copy` but not `Clone` (whereas `Clone` is a super trait of `Copy`).

However, this PR has a few side-effects:
* `Clone` is now marked as a lang item.
* `[T; N]` is now `Clone` if `T: Clone` (currently, only if `T: Copy` and for `N <= 32`).
* `fn foo<'a>() where &'a mut (): Clone { }` won't compile anymore because of how bounds for builtin traits are handled (e.g. same thing currently if you replace `Clone` by `Copy` in this example). Of course this function is unusable anyway, an error would pop as soon as it is called.

Hence, I'm wondering wether this PR would need an RFC...
Also, cc-ing @nikomatsakis, @arielb1.

Related issues: rust-lang#28229, rust-lang#24000.
  • Loading branch information
bors committed Aug 22, 2017
2 parents 8df670b + d58b40e commit 942711e
Show file tree
Hide file tree
Showing 18 changed files with 618 additions and 24 deletions.
1 change: 1 addition & 0 deletions src/libcore/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ macro_rules! array_impls {
}

#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(stage0)]
impl<T:Copy> Clone for [T; $N] {
fn clone(&self) -> [T; $N] {
*self
Expand Down
3 changes: 3 additions & 0 deletions src/libcore/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(stage0), lang = "clone")]
pub trait Clone : Sized {
/// Returns a copy of the value.
///
Expand Down Expand Up @@ -131,6 +132,7 @@ pub struct AssertParamIsClone<T: Clone + ?Sized> { _field: ::marker::PhantomData
pub struct AssertParamIsCopy<T: Copy + ?Sized> { _field: ::marker::PhantomData<T> }

#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(stage0)]
impl<'a, T: ?Sized> Clone for &'a T {
/// Returns a shallow copy of the reference.
#[inline]
Expand All @@ -140,6 +142,7 @@ impl<'a, T: ?Sized> Clone for &'a T {
macro_rules! clone_impl {
($t:ty) => {
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(stage0)]
impl Clone for $t {
/// Returns a deep copy of the value.
#[inline]
Expand Down
3 changes: 3 additions & 0 deletions src/libcore/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,7 @@ pub fn eq<T: ?Sized>(a: *const T, b: *const T) -> bool {
}

#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(stage0)]
impl<T: ?Sized> Clone for *const T {
#[inline]
fn clone(&self) -> *const T {
Expand All @@ -884,6 +885,7 @@ impl<T: ?Sized> Clone for *const T {
}

#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(stage0)]
impl<T: ?Sized> Clone for *mut T {
#[inline]
fn clone(&self) -> *mut T {
Expand All @@ -895,6 +897,7 @@ impl<T: ?Sized> Clone for *mut T {
macro_rules! fnptr_impls_safety_abi {
($FnTy: ty, $($Arg: ident),*) => {
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(stage0)]
impl<Ret, $($Arg),*> Clone for $FnTy {
#[inline]
fn clone(&self) -> Self {
Expand Down
1 change: 1 addition & 0 deletions src/libcore/tuple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ macro_rules! tuple_impls {
)+) => {
$(
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(stage0)]
impl<$($T:Clone),+> Clone for ($($T,)+) {
fn clone(&self) -> ($($T,)+) {
($(self.$idx.clone(),)+)
Expand Down
4 changes: 4 additions & 0 deletions src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,10 @@ impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::In
def_id.hash_stable(hcx, hasher);
t.hash_stable(hcx, hasher);
}
ty::InstanceDef::CloneShim(def_id, t) => {
def_id.hash_stable(hcx, hasher);
t.hash_stable(hcx, hasher);
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ language_item_table! {
SizedTraitLangItem, "sized", sized_trait;
UnsizeTraitLangItem, "unsize", unsize_trait;
CopyTraitLangItem, "copy", copy_trait;
CloneTraitLangItem, "clone", clone_trait;
SyncTraitLangItem, "sync", sync_trait;
FreezeTraitLangItem, "freeze", freeze_trait;

Expand Down
20 changes: 16 additions & 4 deletions src/librustc/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1296,6 +1296,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
} else if self.tcx().lang_items.unsize_trait() == Some(def_id) {
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
} else {
if self.tcx().lang_items.clone_trait() == Some(def_id) {
// Same builtin conditions as `Copy`, i.e. every type which has builtin support
// for `Copy` also has builtin support for `Clone`, + tuples and arrays of `Clone`
// types have builtin support for `Clone`.
let clone_conditions = self.copy_conditions(obligation);
self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?;
}

self.assemble_closure_candidates(obligation, &mut candidates)?;
self.assemble_fn_pointer_candidates(obligation, &mut candidates)?;
self.assemble_candidates_from_impls(obligation, &mut candidates)?;
Expand Down Expand Up @@ -2164,8 +2172,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {

match candidate {
BuiltinCandidate { has_nested } => {
Ok(VtableBuiltin(
self.confirm_builtin_candidate(obligation, has_nested)))
let data = self.confirm_builtin_candidate(obligation, has_nested);
Ok(VtableBuiltin(data))
}

ParamCandidate(param) => {
Expand Down Expand Up @@ -2271,6 +2279,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
_ if Some(trait_def) == self.tcx().lang_items.copy_trait() => {
self.copy_conditions(obligation)
}
_ if Some(trait_def) == self.tcx().lang_items.clone_trait() => {
self.copy_conditions(obligation)
}
_ => bug!("unexpected builtin trait {:?}", trait_def)
};
let nested = match conditions {
Expand All @@ -2291,6 +2302,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {

debug!("confirm_builtin_candidate: obligations={:?}",
obligations);

VtableBuiltinData { nested: obligations }
}

Expand Down Expand Up @@ -2598,8 +2610,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {

fn confirm_builtin_unsize_candidate(&mut self,
obligation: &TraitObligation<'tcx>,)
-> Result<VtableBuiltinData<PredicateObligation<'tcx>>,
SelectionError<'tcx>> {
-> Result<VtableBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>>
{
let tcx = self.tcx();

// assemble_candidates_for_unsizing should ensure there are no late bound
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/traits/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> {
})
}
traits::VtableParam(n) => Some(traits::VtableParam(n)),
traits::VtableBuiltin(d) => Some(traits::VtableBuiltin(d)),
traits::VtableBuiltin(n) => Some(traits::VtableBuiltin(n)),
traits::VtableObject(traits::VtableObjectData {
upcast_trait_ref,
vtable_base,
Expand Down
26 changes: 18 additions & 8 deletions src/librustc/ty/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,22 @@ pub struct Instance<'tcx> {
pub enum InstanceDef<'tcx> {
Item(DefId),
Intrinsic(DefId),
// <fn() as FnTrait>::call_*
// def-id is FnTrait::call_*

/// <fn() as FnTrait>::call_*
/// def-id is FnTrait::call_*
FnPtrShim(DefId, Ty<'tcx>),
// <Trait as Trait>::fn

/// <Trait as Trait>::fn
Virtual(DefId, usize),
// <[mut closure] as FnOnce>::call_once

/// <[mut closure] as FnOnce>::call_once
ClosureOnceShim { call_once: DefId },
// drop_in_place::<T>; None for empty drop glue.

/// drop_in_place::<T>; None for empty drop glue.
DropGlue(DefId, Option<Ty<'tcx>>),

/// Builtin method implementation, e.g. `Clone::clone`.
CloneShim(DefId, Ty<'tcx>),
}

impl<'tcx> InstanceDef<'tcx> {
Expand All @@ -43,9 +50,9 @@ impl<'tcx> InstanceDef<'tcx> {
InstanceDef::FnPtrShim(def_id, _) |
InstanceDef::Virtual(def_id, _) |
InstanceDef::Intrinsic(def_id, ) |
InstanceDef::ClosureOnceShim { call_once: def_id }
=> def_id,
InstanceDef::DropGlue(def_id, _) => def_id
InstanceDef::ClosureOnceShim { call_once: def_id } |
InstanceDef::DropGlue(def_id, _) |
InstanceDef::CloneShim(def_id, _) => def_id
}
}

Expand Down Expand Up @@ -80,6 +87,9 @@ impl<'tcx> fmt::Display for Instance<'tcx> {
InstanceDef::DropGlue(_, ty) => {
write!(f, " - shim({:?})", ty)
}
InstanceDef::CloneShim(_, ty) => {
write!(f, " - shim({:?})", ty)
}
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2232,7 +2232,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
ty::InstanceDef::FnPtrShim(..) |
ty::InstanceDef::Virtual(..) |
ty::InstanceDef::ClosureOnceShim { .. } |
ty::InstanceDef::DropGlue(..) => {
ty::InstanceDef::DropGlue(..) |
ty::InstanceDef::CloneShim(..) => {
self.mir_shims(instance)
}
}
Expand Down
Loading

0 comments on commit 942711e

Please sign in to comment.