From 0c3ac648f85cca1e8dd89dfff727a422bc1897a6 Mon Sep 17 00:00:00 2001 From: scalexm Date: Fri, 4 Aug 2017 14:44:12 +0200 Subject: [PATCH] Make `Clone` a lang item and generate builtin impls. Fixes #28229. Fixes #24000. --- src/libcore/array.rs | 1 + src/libcore/clone.rs | 3 + src/libcore/ptr.rs | 3 + src/libcore/tuple.rs | 1 + src/librustc/ich/impls_ty.rs | 4 + src/librustc/middle/lang_items.rs | 4 + src/librustc/traits/mod.rs | 7 +- src/librustc/traits/select.rs | 27 +++- src/librustc/traits/structural_impls.rs | 16 +- src/librustc/ty/instance.rs | 26 +++- src/librustc/ty/mod.rs | 3 +- src/librustc_mir/shim.rs | 179 +++++++++++++++++++++- src/librustc_trans/collector.rs | 6 +- src/librustc_trans/monomorphize.rs | 6 + src/librustc_trans/partitioning.rs | 6 +- src/librustc_typeck/check/method/probe.rs | 45 ++++++ src/test/run-pass/issue-37725.rs | 8 +- 17 files changed, 313 insertions(+), 32 deletions(-) diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 37bd57034a7b6..0d9f9d16d82e7 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -124,6 +124,7 @@ macro_rules! array_impls { } #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] impl Clone for [T; $N] { fn clone(&self) -> [T; $N] { *self diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 8856d0b8cb9de..2dc51718b97b2 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -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. /// @@ -131,6 +132,7 @@ pub struct AssertParamIsClone { _field: ::marker::PhantomData pub struct AssertParamIsCopy { _field: ::marker::PhantomData } #[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] @@ -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] diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index e35777d222c06..63e9373e93606 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -876,6 +876,7 @@ pub fn eq(a: *const T, b: *const T) -> bool { } #[stable(feature = "rust1", since = "1.0.0")] +#[cfg(stage0)] impl Clone for *const T { #[inline] fn clone(&self) -> *const T { @@ -884,6 +885,7 @@ impl Clone for *const T { } #[stable(feature = "rust1", since = "1.0.0")] +#[cfg(stage0)] impl Clone for *mut T { #[inline] fn clone(&self) -> *mut T { @@ -895,6 +897,7 @@ impl Clone for *mut T { macro_rules! fnptr_impls_safety_abi { ($FnTy: ty, $($Arg: ident),*) => { #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] impl Clone for $FnTy { #[inline] fn clone(&self) -> Self { diff --git a/src/libcore/tuple.rs b/src/libcore/tuple.rs index 47e9c7c903880..555843dba418e 100644 --- a/src/libcore/tuple.rs +++ b/src/libcore/tuple.rs @@ -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(),)+) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 8a37d7bab4445..5b75ce7864f8d 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -721,6 +721,10 @@ impl<'a, 'gcx, 'tcx> HashStable> 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); + } } } } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 01ed79096b101..8cee88bd39b7f 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -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; @@ -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. diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index d1938197e6529..1c6d75ace52e6 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -301,7 +301,7 @@ pub enum Vtable<'tcx, N> { VtableObject(VtableObjectData<'tcx, N>), /// Successful resolution for a builtin trait. - VtableBuiltin(VtableBuiltinData), + 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 @@ -345,7 +345,9 @@ pub struct VtableDefaultImplData { } #[derive(Clone)] -pub struct VtableBuiltinData { +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 } @@ -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 { diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 3e39d5921351f..88cca70993e9a 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -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)?; @@ -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) => { @@ -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> + -> VtableBuiltinData<'tcx, PredicateObligation<'tcx>> { debug!("confirm_builtin_candidate({:?}, {:?})", obligation, has_nested); @@ -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 { @@ -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. @@ -2598,8 +2611,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn confirm_builtin_unsize_candidate(&mut self, obligation: &TraitObligation<'tcx>,) - -> Result>, - SelectionError<'tcx>> { + -> Result>, SelectionError<'tcx>> + { let tcx = self.tcx(); // assemble_candidates_for_unsizing should ensure there are no late bound @@ -2801,7 +2814,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { _ => bug!() }; - Ok(VtableBuiltinData { nested: nested }) + Ok(VtableBuiltinData { ty: source, nested: nested }) } /////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index f1c176561ea48..a83849898f587 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -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 { +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) } } @@ -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, @@ -378,9 +385,10 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableDefaultIm } } -impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableBuiltinData { +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), } } diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 32063a2dda603..e8daf7c09f4f2 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -24,15 +24,22 @@ pub struct Instance<'tcx> { pub enum InstanceDef<'tcx> { Item(DefId), Intrinsic(DefId), - // ::call_* - // def-id is FnTrait::call_* + + /// ::call_* + /// def-id is FnTrait::call_* FnPtrShim(DefId, Ty<'tcx>), - // ::fn + + /// ::fn Virtual(DefId, usize), - // <[mut closure] as FnOnce>::call_once + + /// <[mut closure] as FnOnce>::call_once ClosureOnceShim { call_once: DefId }, - // drop_in_place::; None for empty drop glue. + + /// drop_in_place::; None for empty drop glue. DropGlue(DefId, Option>), + + /// Builtin method implementation, e.g. `Clone::clone`. + BuiltinShim(DefId, Ty<'tcx>), } impl<'tcx> InstanceDef<'tcx> { @@ -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 } } @@ -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) + } } } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 28a73f4a4d387..81a0af63942ed 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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) } } diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 62e762be93a71..cb1a2f6b1077e 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -17,6 +17,7 @@ use rustc::mir::transform::MirSource; use rustc::ty::{self, Ty}; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::ty::maps::Providers; +use rustc_const_math::{ConstInt, ConstUsize}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -98,14 +99,26 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, ty::InstanceDef::DropGlue(def_id, ty) => { build_drop_shim(tcx, def_id, ty) } + ty::InstanceDef::BuiltinShim(def_id, ty) => { + let name = tcx.item_name(def_id).as_str(); + let trait_id = tcx.trait_of_item(def_id); + if trait_id == tcx.lang_items.clone_trait() && name == "clone" { + build_clone_shim(tcx, def_id, ty) + } else if trait_id == tcx.lang_items.clone_trait() && name == "clone_from" { + debug!("make_shim({:?}: using default trait implementation", instance); + return tcx.optimized_mir(def_id); + } else { + bug!("builtin shim {:?} not supported", instance) + } + } ty::InstanceDef::Intrinsic(_) => { bug!("creating shims from intrinsics ({:?}) is unsupported", instance) } }; - debug!("make_shim({:?}) = untransformed {:?}", instance, result); - no_landing_pads::no_landing_pads(tcx, &mut result); - simplify::simplify_cfg(&mut result); - add_call_guards::CriticalCallEdges.add_call_guards(&mut result); + debug!("make_shim({:?}) = untransformed {:?}", instance, result); + no_landing_pads::no_landing_pads(tcx, &mut result); + simplify::simplify_cfg(&mut result); + add_call_guards::CriticalCallEdges.add_call_guards(&mut result); debug!("make_shim({:?}) = {:?}", instance, result); tcx.alloc_mir(result) @@ -259,6 +272,164 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> { } } +/// Build a `Clone::clone` shim for `recvr_ty`. Here, `def_id` is `Clone::clone`. +fn build_clone_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + recvr_ty: ty::Ty<'tcx>) + -> Mir<'tcx> +{ + let sig = tcx.fn_sig(def_id); + let sig = tcx.erase_late_bound_regions(&sig); + let span = tcx.def_span(def_id); + + debug!("build_clone_shim(def_id={:?})", def_id); + + let mut local_decls = local_decls_for_sig(&sig, span); + let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE }; + + let mut blocks = IndexVec::new(); + let block = |blocks: &mut IndexVec<_, _>, statement, kind| { + blocks.push(BasicBlockData { + statements: vec![statement], + terminator: Some(Terminator { source_info, kind }), + is_cleanup: false + }) + }; + + let rcvr = Lvalue::Local(Local::new(1+0)).deref(); + + let call_clone = |i, ty, rcvr_field, blocks: &mut _, local_decls: &mut IndexVec<_, _>| { + // `func == Clone::clone(&ty) -> ty` + let substs = Substs::for_item(tcx, def_id, |_, _| tcx.types.re_erased, |_, _| ty); + let func = Operand::Constant(box Constant { + span: span, + ty: tcx.mk_fn_def(def_id, substs), + literal: Literal::Value { + value: ConstVal::Function(def_id, substs), + }, + }); + + let ref_loc = Lvalue::Local( + local_decls.push(temp_decl( + Mutability::Not, + tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut { + ty, + mutbl: hir::Mutability::MutImmutable, + }), + span + )) + ); + + let loc = Lvalue::Local( + local_decls.push(temp_decl( + Mutability::Not, + ty, + span + )) + ); + + // `let ref_loc: &ty = &rcvr_field;` + let statement = Statement { + source_info: source_info, + kind: StatementKind::Assign( + ref_loc.clone(), + Rvalue::Ref(tcx.types.re_erased, BorrowKind::Shared, rcvr_field) + ) + }; + + // `let loc = Clone::clone(ref_loc);` + block(blocks, statement, TerminatorKind::Call { + func, + args: vec![Operand::Consume(ref_loc)], + destination: Some((loc.clone(), BasicBlock::new(i + 1))), + cleanup: None, + }); + + loc + }; + + match recvr_ty.sty { + ty::TyArray(ty, len) => { + let mut returns = Vec::new(); + for i in 0..len { + let index = ConstUsize::new(i as u64, tcx.sess.target.uint_type).unwrap(); + let rcvr_field = rcvr.clone().index( + Operand::Constant(box Constant { + span, + ty: tcx.types.usize, + literal: Literal::Value { + value: ConstVal::Integral(ConstInt::Usize(index)) + } + }) + ); + + // `returns[i] = Clone::clone(&rcvr[i]);` + returns.push(call_clone(i, ty, rcvr_field, &mut blocks, &mut local_decls)); + } + + // `return [returns[0], returns[1], ..., returns[len - 1]];` + let statement = Statement { + source_info: source_info, + kind: StatementKind::Assign( + Lvalue::Local(RETURN_POINTER), + Rvalue::Aggregate( + box AggregateKind::Array(ty), + returns.into_iter().map(|loc| Operand::Consume(loc)).collect() + ) + ) + }; + block(&mut blocks, statement, TerminatorKind::Return); + } + ty::TyTuple(tys, _) => { + let mut returns = Vec::new(); + for (i, ity) in tys.iter().enumerate() { + let rcvr_field = rcvr.clone().field(Field::new(i), *ity); + + // `returns[i] = Clone::clone(&rcvr.i);` + returns.push(call_clone(i, *ity, rcvr_field, &mut blocks, &mut local_decls)); + } + + // `return (returns[0], returns[1], ..., returns[tys.len() - 1]);` + let statement = Statement { + source_info: source_info, + kind: StatementKind::Assign( + Lvalue::Local(RETURN_POINTER), + Rvalue::Aggregate( + box AggregateKind::Tuple, + returns.into_iter().map(|loc| Operand::Consume(loc)).collect() + ) + ) + }; + block(&mut blocks, statement, TerminatorKind::Return); + } + _ => { + // `return *self;` + let statement = Statement { + source_info: source_info, + kind: StatementKind::Assign( + Lvalue::Local(RETURN_POINTER), + Rvalue::Use(Operand::Consume(rcvr)) + ) + }; + block(&mut blocks, statement, TerminatorKind::Return); + } + }; + + let mir = Mir::new( + blocks, + IndexVec::from_elem_n( + VisibilityScopeData { span: span, parent_scope: None }, 1 + ), + IndexVec::new(), + sig.output(), + local_decls, + sig.inputs().len(), + vec![], + span + ); + mir +} + /// Build a "call" shim for `def_id`. The shim calls the /// function specified by `call_kind`, first adjusting its first /// argument according to `rcvr_adjustment`. diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index b31295f4022ed..4e02810b040ca 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -699,7 +699,8 @@ fn visit_instance_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::Item(..) | - ty::InstanceDef::FnPtrShim(..) => { + ty::InstanceDef::FnPtrShim(..) | + ty::InstanceDef::BuiltinShim(..) => { output.push(create_fn_trans_item(instance)); } } @@ -716,7 +717,8 @@ fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &Instan ty::InstanceDef::Virtual(..) | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::DropGlue(..) | - ty::InstanceDef::Intrinsic(_) => return true + ty::InstanceDef::Intrinsic(_) | + ty::InstanceDef::BuiltinShim(..) => return true }; match tcx.hir.get_if_local(def_id) { Some(hir_map::NodeForeignItem(..)) => { diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 1f6a262162d39..1936775df0ab3 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -143,6 +143,12 @@ fn resolve_associated_item<'a, 'tcx>( substs: rcvr_substs } } + traits::VtableBuiltin(ref data) => { + Instance { + def: ty::InstanceDef::BuiltinShim(def_id, data.ty), + substs: rcvr_substs + } + } _ => { bug!("static call to invalid vtable: {:?}", vtbl) } diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 63c7b18e8d290..0149714d0b799 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -361,7 +361,8 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, InstanceDef::Virtual(..) | InstanceDef::Intrinsic(..) | InstanceDef::ClosureOnceShim { .. } | - InstanceDef::DropGlue(..) => { + InstanceDef::DropGlue(..) | + InstanceDef::BuiltinShim(..) => { bug!("partitioning: Encountered unexpected root translation item: {:?}", trans_item) @@ -603,7 +604,8 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 't ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::DropGlue(..) | - ty::InstanceDef::Virtual(..) => return None + ty::InstanceDef::Virtual(..) | + ty::InstanceDef::BuiltinShim(..) => return None }; // If this is a method, we want to put it into the same module as diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 7bf671d5e9f93..a0985102f1ccb 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -719,6 +719,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { continue; } + self.assemble_builtin_candidates(import_id, trait_def_id, item.clone()); + self.assemble_extension_candidates_for_trait_impls(import_id, trait_def_id, item.clone()); @@ -732,6 +734,49 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { Ok(()) } + fn assemble_builtin_candidates(&mut self, + import_id: Option, + trait_def_id: DefId, + item: ty::AssociatedItem) { + if Some(trait_def_id) == self.tcx.lang_items.clone_trait() { + self.assemble_builtin_clone_candidates(import_id, trait_def_id, item); + } + } + + fn assemble_builtin_clone_candidates(&mut self, + import_id: Option, + trait_def_id: DefId, + item: ty::AssociatedItem) { + for step in Rc::clone(&self.steps).iter() { + match step.self_ty.sty { + ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) | + ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) | + ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar | + ty::TyRawPtr(..) | ty::TyError | ty::TyNever | + ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) | + ty::TyArray(..) | ty::TyTuple(..) => { + () + } + + _ => continue, + }; + + let substs = Substs::for_item(self.tcx, + trait_def_id, + |def, _| self.region_var_for_def(self.span, def), + |def, substs| { + if def.index == 0 { + step.self_ty + } else { + self.type_var_for_def(self.span, def, substs) + } + }); + + let xform_self_ty = self.xform_self_ty(&item, step.self_ty, substs); + self.push_inherent_candidate(xform_self_ty, item, TraitCandidate, import_id); + } + } + fn assemble_extension_candidates_for_trait_impls(&mut self, import_id: Option, trait_def_id: DefId, diff --git a/src/test/run-pass/issue-37725.rs b/src/test/run-pass/issue-37725.rs index 5ed1295c85c76..a8fb11f9c62bd 100644 --- a/src/test/run-pass/issue-37725.rs +++ b/src/test/run-pass/issue-37725.rs @@ -8,7 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone { - s.clone(); +trait Foo { + fn foo(&self); +} + +fn foo<'a>(s: &'a mut ()) where &'a mut (): Foo { + s.foo(); } fn main() {}