Skip to content

[WIP] Implement shim for types that transitively derive Clone #72409

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/libcore/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ pub trait Clone: Sized {
/// Derive macro generating an impl of the trait `Clone`.
#[rustc_builtin_macro]
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
#[allow_internal_unstable(core_intrinsics, derive_clone_copy)]
#[allow_internal_unstable(core_intrinsics, derive_clone_copy, structural_match)]
pub macro Clone($item:item) {
/* compiler built-in */
}
Expand Down
6 changes: 6 additions & 0 deletions src/libcore/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,12 @@ pub trait StructuralEq {
// Empty.
}

/// Temp
#[cfg(not(bootstrap))]
#[unstable(feature = "structural_match", issue = "31434")]
#[lang = "derived_clone"]
pub trait DerivedClone {}

/// Types whose values can be duplicated simply by copying bits.
///
/// By default, variable bindings have 'move semantics.' In other
Expand Down
8 changes: 8 additions & 0 deletions src/librustc_builtin_macros/deriving/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ pub fn expand_deriving_clone(
_ => cx.span_bug(span, "`#[derive(Clone)]` on trait item or impl item"),
}

super::inject_impl_of_structural_trait(
cx,
span,
item,
path_std!(cx, marker::DerivedClone),
push,
);

let inline = cx.meta_word(span, sym::inline);
let attrs = vec![cx.attribute(inline)];
let trait_def = TraitDef {
Expand Down
1 change: 1 addition & 0 deletions src/librustc_hir/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ language_item_table! {
StructuralPeqTraitLangItem, "structural_peq", structural_peq_trait, Target::Trait;
// trait injected by #[derive(Eq)], (i.e. "Total EQ"; no, I will not apologize).
StructuralTeqTraitLangItem, "structural_teq", structural_teq_trait, Target::Trait;
DerivedClone, "derived_clone", derived_clone_trait, Target::Trait;
CopyTraitLangItem, "copy", copy_trait, Target::Trait;
CloneTraitLangItem, "clone", clone_trait, Target::Trait;
SyncTraitLangItem, "sync", sync_trait, Target::Trait;
Expand Down
4 changes: 4 additions & 0 deletions src/librustc_middle/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1296,5 +1296,9 @@ rustc_queries! {
) -> Result<Option<ty::Instance<'tcx>>, ErrorReported> {
desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) }
}

query is_transitive_derive_clone(key: Ty<'tcx>) -> bool {
desc { "determining if item {:?} transitively derives Clone", key }
}
}
}
7 changes: 4 additions & 3 deletions src/librustc_middle/ty/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ pub enum InstanceDef<'tcx> {
/// NB: the type must currently be monomorphic to avoid double substitution
/// problems with the MIR shim bodies. `Instance::resolve` enforces this.
// FIXME(#69925) support polymorphic MIR shim bodies properly instead.
CloneShim(DefId, Ty<'tcx>),
CloneShim(DefId, Ty<'tcx>, bool),
}

impl<'tcx> Instance<'tcx> {
Expand Down Expand Up @@ -151,7 +151,7 @@ impl<'tcx> InstanceDef<'tcx> {
| InstanceDef::Intrinsic(def_id)
| InstanceDef::ClosureOnceShim { call_once: def_id }
| InstanceDef::DropGlue(def_id, _)
| InstanceDef::CloneShim(def_id, _) => def_id,
| InstanceDef::CloneShim(def_id, _, _) => def_id,
}
}

Expand Down Expand Up @@ -240,7 +240,8 @@ impl<'tcx> fmt::Display for Instance<'tcx> {
InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({:?})", ty),
InstanceDef::ClosureOnceShim { .. } => write!(f, " - shim"),
InstanceDef::DropGlue(_, ty) => write!(f, " - shim({:?})", ty),
InstanceDef::CloneShim(_, ty) => write!(f, " - shim({:?})", ty),
InstanceDef::CloneShim(_, ty, from_derive) => write!(f, " - shim({:?}, from_derive={:?})", ty,
from_derive),
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_middle/ty/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -676,8 +676,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> {
ty::InstanceDef::DropGlue(def_id, ref ty) => {
Some(ty::InstanceDef::DropGlue(def_id, tcx.lift(ty)?))
}
ty::InstanceDef::CloneShim(def_id, ref ty) => {
Some(ty::InstanceDef::CloneShim(def_id, tcx.lift(ty)?))
ty::InstanceDef::CloneShim(def_id, ref ty, from_derive) => {
Some(ty::InstanceDef::CloneShim(def_id, tcx.lift(ty)?, from_derive))
}
}
}
Expand Down Expand Up @@ -844,7 +844,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
ClosureOnceShim { call_once: call_once.fold_with(folder) }
}
DropGlue(did, ty) => DropGlue(did.fold_with(folder), ty.fold_with(folder)),
CloneShim(did, ty) => CloneShim(did.fold_with(folder), ty.fold_with(folder)),
CloneShim(did, ty, from_derive) => CloneShim(did.fold_with(folder), ty.fold_with(folder), from_derive),
},
}
}
Expand All @@ -856,7 +856,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
Item(did) | VtableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => {
did.visit_with(visitor)
}
FnPtrShim(did, ty) | CloneShim(did, ty) => {
FnPtrShim(did, ty) | CloneShim(did, ty, _) => {
did.visit_with(visitor) || ty.visit_with(visitor)
}
DropGlue(did, ty) => did.visit_with(visitor) || ty.visit_with(visitor),
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_mir/shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,13 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'

build_drop_shim(tcx, def_id, ty)
}
ty::InstanceDef::CloneShim(def_id, ty) => {
ty::InstanceDef::CloneShim(def_id, ty, from_derive) => {
// FIXME(eddyb) support generating shims for a "shallow type",
// e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic
// `Foo<Bar>` or `[String]` etc.
assert!(!ty.needs_subst());

build_clone_shim(tcx, def_id, ty)
build_clone_shim(tcx, def_id, ty, from_derive)
}
ty::InstanceDef::Virtual(..) => {
bug!("InstanceDef::Virtual ({:?}) is for direct calls only", instance)
Expand Down Expand Up @@ -312,7 +312,7 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
}

/// Builds a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`.
fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>, from_derive: bool) -> Body<'tcx> {
debug!("build_clone_shim(def_id={:?})", def_id);

let param_env = tcx.param_env(def_id);
Expand All @@ -324,7 +324,7 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -
let src = tcx.mk_place_deref(Place::from(Local::new(1 + 0)));

match self_ty.kind {
_ if is_copy => builder.copy_shim(),
_ if is_copy || from_derive => builder.copy_shim(),
ty::Array(ty, len) => {
let len = len.eval_usize(tcx, param_env);
builder.array_shim(dest, src, ty, len)
Expand Down
15 changes: 15 additions & 0 deletions src/librustc_trait_selection/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::DerivedClone;
use rustc_middle::middle::region;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
Expand Down Expand Up @@ -562,6 +563,19 @@ fn type_implements_trait<'tcx>(
tcx.infer_ctxt().enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation))
}

fn is_transitive_derive_clone(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
match ty.kind {
ty::Adt(adt_def, substs) => {
let derived_clone = tcx.require_lang_item(DerivedClone, None);
let is_derived_clone = tcx.type_implements_trait((derived_clone, ty, InternalSubsts::empty(), ParamEnv::empty()));
is_derived_clone && adt_def.all_fields().all(|field| {
tcx.is_transitive_derive_clone(field.ty(tcx, substs))
})
}
_ => true
}
}

pub fn provide(providers: &mut ty::query::Providers<'_>) {
object_safety::provide(providers);
*providers = ty::query::Providers {
Expand All @@ -571,6 +585,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
vtable_methods,
substitute_normalize_and_test_predicates,
type_implements_trait,
is_transitive_derive_clone,
..*providers
};
}
18 changes: 17 additions & 1 deletion src/librustc_ty/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,22 @@ fn resolve_associated_item<'tcx>(
assert!(!rcvr_substs.needs_infer());
assert!(!trait_ref.needs_infer());

if Some(trait_ref.def_id) == tcx.lang_items().clone_trait() {
let name = tcx.item_name(def_id);
let self_ty = trait_ref.self_ty();
if name == sym::clone {
if tcx.is_transitive_derive_clone(self_ty) {
debug!("Using CloneShim for transitive Clone derive on {:?}",
self_ty);
return Ok(Some(Instance {
def: ty::InstanceDef::CloneShim(def_id, self_ty, true),
substs: rcvr_substs,
}))
}
}
}


let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap();
let trait_def = tcx.trait_def(trait_def_id);
let leaf_def = trait_def
Expand Down Expand Up @@ -222,7 +238,7 @@ fn resolve_associated_item<'tcx>(
}

Some(Instance {
def: ty::InstanceDef::CloneShim(def_id, self_ty),
def: ty::InstanceDef::CloneShim(def_id, self_ty, false),
substs: rcvr_substs,
})
} else {
Expand Down