Skip to content

Commit

Permalink
Auto merge of #69036 - eddyb:monoshim, r=<try>
Browse files Browse the repository at this point in the history
rustc: don't resolve Instances which would produce malformed shims.

There are some `InstanceDef` variants (shims and drop "glue") which contain a `Ty`, and that `Ty` is used in generating the shim MIR. But if that `Ty` mentions any generic parameters, the generated shim would refer to them (but they won't match the `Substs` of the `Instance`), or worse, generating the shim would fail because not enough of the type is known.

Ideally we would always produce a "skeleton" of the type, e.g. `(_, _)` for dropping any tuples with two elements, or `Vec<_>` for dropping any `Vec` value, but that's a lot of work, and they would still not match the `Substs` of the `Instance` as it exists today, so `Instance` would probably need to change.

By making `Instance::resolve` return `None` in the still-generic cases, we get behavior similar to specialization, where a default can only be used if there are no more generic parameters which would allow a more specialized `impl` to match.

<hr/>

This was found while testing the MIR inliner with #68965, because it was trying to inline shims.

cc @rust-lang/wg-mir-opt
  • Loading branch information
bors committed Feb 10, 2020
2 parents 4d1241f + 2d03e10 commit e369f6b
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 32 deletions.
87 changes: 67 additions & 20 deletions src/librustc/ty/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeFoldable};
use rustc_hir::def::Namespace;
use rustc_hir::def_id::{CrateNum, DefId};
use rustc_macros::HashStable;
use rustc_span::sym;
use rustc_target::spec::abi::Abi;

use std::fmt;
Expand Down Expand Up @@ -40,6 +41,11 @@ pub enum InstanceDef<'tcx> {

/// `<fn() as FnTrait>::call_*`
/// `DefId` is `FnTrait::call_*`.
///
/// NB: the (`fn` pointer) type must be monomorphic for MIR shims to work.
// FIXME(eddyb) support generating shims for a "shallow type",
// e.g. `fn(_, _) -> _` instead of requiring a fully monomorphic
// `fn(Foo, Bar) -> Baz` etc.
FnPtrShim(DefId, Ty<'tcx>),

/// `<dyn Trait as Trait>::fn`, "direct calls" of which are implicitly
Expand All @@ -55,9 +61,19 @@ pub enum InstanceDef<'tcx> {
},

/// `drop_in_place::<T>; None` for empty drop glue.
///
/// NB: the type must be monomorphic for MIR shims to work.
// FIXME(eddyb) support generating shims for a "shallow type",
// e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic
// `Foo<Bar>` or `[String]` etc.
DropGlue(DefId, Option<Ty<'tcx>>),

///`<T as Clone>::clone` shim.
///
/// NB: the type must be monomorphic for MIR shims to work.
// FIXME(eddyb) support generating shims for a "shallow type",
// e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic
// `Foo<Bar>` or `[String]` etc.
CloneShim(DefId, Ty<'tcx>),
}

Expand Down Expand Up @@ -282,21 +298,28 @@ impl<'tcx> Instance<'tcx> {
debug!(" => intrinsic");
ty::InstanceDef::Intrinsic(def_id)
}
_ => {
if Some(def_id) == tcx.lang_items().drop_in_place_fn() {
let ty = substs.type_at(0);
if ty.needs_drop(tcx, ty::ParamEnv::reveal_all()) {
debug!(" => nontrivial drop glue");
ty::InstanceDef::DropGlue(def_id, Some(ty))
} else {
debug!(" => trivial drop glue");
ty::InstanceDef::DropGlue(def_id, None)
ty::FnDef(def_id, substs)
if Some(def_id) == tcx.lang_items().drop_in_place_fn() =>
{
let ty = substs.type_at(0);

if ty.needs_drop(tcx, param_env) {
// `DropGlue` requires a monomorphic aka concrete type.
if ty.needs_subst() {
return None;
}

debug!(" => nontrivial drop glue");
ty::InstanceDef::DropGlue(def_id, Some(ty))
} else {
debug!(" => free item");
ty::InstanceDef::Item(def_id)
debug!(" => trivial drop glue");
ty::InstanceDef::DropGlue(def_id, None)
}
}
_ => {
debug!(" => free item");
ty::InstanceDef::Item(def_id)
}
};
Some(Instance { def: def, substs: substs })
};
Expand Down Expand Up @@ -458,20 +481,44 @@ fn resolve_associated_item<'tcx>(
trait_closure_kind,
))
}
traits::VtableFnPointer(ref data) => Some(Instance {
def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty),
substs: rcvr_substs,
}),
traits::VtableFnPointer(ref data) => {
// `FnPtrShim` requires a monomorphic aka concrete type.
if data.fn_ty.needs_subst() {
return None;
}

Some(Instance {
def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty),
substs: rcvr_substs,
})
}
traits::VtableObject(ref data) => {
let index = traits::get_vtable_index_of_object_method(tcx, data, def_id);
Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs })
}
traits::VtableBuiltin(..) => {
if tcx.lang_items().clone_trait().is_some() {
Some(Instance {
def: ty::InstanceDef::CloneShim(def_id, trait_ref.self_ty()),
substs: rcvr_substs,
})
if Some(trait_ref.def_id) == tcx.lang_items().clone_trait() {
// FIXME(eddyb) use lang items for methods instead of names.
let name = tcx.item_name(def_id);
if name == sym::clone {
let self_ty = trait_ref.self_ty();

// `CloneShim` requires a monomorphic aka concrete type.
if self_ty.needs_subst() {
return None;
}

Some(Instance {
def: ty::InstanceDef::CloneShim(def_id, self_ty),
substs: rcvr_substs,
})
} else {
assert_eq!(name, sym::clone_from);

// Use the default `fn clone_from` from `trait Clone`.
let substs = tcx.erase_regions(&rcvr_substs);
Some(ty::Instance::new(def_id, substs))
}
} else {
None
}
Expand Down
33 changes: 21 additions & 12 deletions src/librustc_mir/shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ use rustc::mir::*;
use rustc::ty::layout::VariantIdx;
use rustc::ty::query::Providers;
use rustc::ty::subst::{InternalSubsts, Subst};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;

use rustc_index::vec::{Idx, IndexVec};

use rustc_span::{sym, Span};
use rustc_span::Span;
use rustc_target::spec::abi::Abi;

use std::fmt;
Expand Down Expand Up @@ -39,6 +39,11 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx
None,
),
ty::InstanceDef::FnPtrShim(def_id, ty) => {
// 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());

let trait_ = tcx.trait_of_item(def_id).unwrap();
let adjustment = match tcx.lang_items().fn_trait_kind(trait_) {
Some(ty::ClosureKind::FnOnce) => Adjustment::Identity,
Expand Down Expand Up @@ -81,17 +86,21 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx
None,
)
}
ty::InstanceDef::DropGlue(def_id, ty) => build_drop_shim(tcx, def_id, ty),
ty::InstanceDef::DropGlue(def_id, ty) => {
// 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_drop_shim(tcx, def_id, ty)
}
ty::InstanceDef::CloneShim(def_id, ty) => {
let name = tcx.item_name(def_id);
if name == sym::clone {
build_clone_shim(tcx, def_id, ty)
} else if name == sym::clone_from {
debug!("make_shim({:?}: using default trait implementation", instance);
return tcx.optimized_mir(def_id);
} else {
bug!("builtin clone shim {:?} not supported", instance)
}
// 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)
}
ty::InstanceDef::Virtual(..) => {
bug!("InstanceDef::Virtual ({:?}) is for direct calls only", instance)
Expand Down

0 comments on commit e369f6b

Please sign in to comment.