Skip to content

Commit

Permalink
Make Clone a lang item and generate builtin impls.
Browse files Browse the repository at this point in the history
Fixes #28229.
Fixes #24000.
  • Loading branch information
scalexm committed Aug 14, 2017
1 parent b1ff235 commit 0c3ac64
Show file tree
Hide file tree
Showing 17 changed files with 313 additions and 32 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 @@ -721,6 +721,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::BuiltinShim(def_id, t) => {
def_id.hash_stable(hcx, hasher);
t.hash_stable(hcx, hasher);
}
}
}
}
Expand Down
4 changes: 4 additions & 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 Expand Up @@ -320,6 +321,9 @@ language_item_table! {

StrEqFnLangItem, "str_eq", str_eq_fn;

CloneMethodLangItem, "clone_method", clone_method;
CloneFromMethodLangItem, "clone_from_method", clone_from_method;

// A number of panic-related lang items. The `panic` item corresponds to
// divide-by-zero and various panic cases with `match`. The
// `panic_bounds_check` item is for indexing arrays.
Expand Down
7 changes: 5 additions & 2 deletions src/librustc/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ pub enum Vtable<'tcx, N> {
VtableObject(VtableObjectData<'tcx, N>),

/// Successful resolution for a builtin trait.
VtableBuiltin(VtableBuiltinData<N>),
VtableBuiltin(VtableBuiltinData<'tcx, N>),

/// Vtable automatically generated for a closure. The def ID is the ID
/// of the closure expression. This is a `VtableImpl` in spirit, but the
Expand Down Expand Up @@ -345,7 +345,9 @@ pub struct VtableDefaultImplData<N> {
}

#[derive(Clone)]
pub struct VtableBuiltinData<N> {
pub struct VtableBuiltinData<'tcx, N> {
/// `ty` can be used for generating shim for builtin implementations like `Clone::clone`.
pub ty: ty::Ty<'tcx>,
pub nested: Vec<N>
}

Expand Down Expand Up @@ -769,6 +771,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
}),
VtableParam(n) => VtableParam(n.into_iter().map(f).collect()),
VtableBuiltin(i) => VtableBuiltin(VtableBuiltinData {
ty: i.ty,
nested: i.nested.into_iter().map(f).collect(),
}),
VtableObject(o) => VtableObject(VtableObjectData {
Expand Down
27 changes: 20 additions & 7 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 @@ -2257,7 +2265,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
fn confirm_builtin_candidate(&mut self,
obligation: &TraitObligation<'tcx>,
has_nested: bool)
-> VtableBuiltinData<PredicateObligation<'tcx>>
-> VtableBuiltinData<'tcx, PredicateObligation<'tcx>>
{
debug!("confirm_builtin_candidate({:?}, {:?})",
obligation, has_nested);
Expand All @@ -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,7 +2302,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {

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

let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty());
VtableBuiltinData { ty: self_ty, nested: obligations }
}

/// This handles the case where a `impl Foo for ..` impl is being used.
Expand Down Expand Up @@ -2598,8 +2611,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<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
{
let tcx = self.tcx();

// assemble_candidates_for_unsizing should ensure there are no late bound
Expand Down Expand Up @@ -2801,7 +2814,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
_ => bug!()
};

Ok(VtableBuiltinData { nested: nested })
Ok(VtableBuiltinData { ty: source, nested: nested })
}

///////////////////////////////////////////////////////////////////////////
Expand Down
16 changes: 12 additions & 4 deletions src/librustc/traits/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableClosureData<'tcx, N> {
}
}

impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableBuiltinData<N> {
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableBuiltinData<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "VtableBuiltin(nested={:?})", self.nested)
write!(f, "VtableBuiltin(ty={:?}, nested={:?})", self.ty, self.nested)
}
}

Expand Down Expand Up @@ -300,7 +300,14 @@ 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(traits::VtableBuiltinData { ty, nested }) => {
tcx.lift(&ty).map(|ty| {
traits::VtableBuiltin(traits::VtableBuiltinData {
ty,
nested,
})
})
}
traits::VtableObject(traits::VtableObjectData {
upcast_trait_ref,
vtable_base,
Expand Down Expand Up @@ -378,9 +385,10 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableDefaultIm
}
}

impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableBuiltinData<N> {
impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableBuiltinData<'tcx, N> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
traits::VtableBuiltinData {
ty: self.ty.fold_with(folder),
nested: self.nested.fold_with(folder),
}
}
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`.
BuiltinShim(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::BuiltinShim(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::BuiltinShim(_, 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 @@ -2227,7 +2227,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::BuiltinShim(..) => {
self.mir_shims(instance)
}
}
Expand Down
Loading

0 comments on commit 0c3ac64

Please sign in to comment.