Rollup merge of #69036 - eddyb:monoshim, r=nikomatsakis

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
This commit is contained in:
Mazdak Farrokhzad 2020-03-19 06:57:28 +01:00 committed by GitHub
commit ffb3c2cb3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 83 additions and 32 deletions

View File

@ -39,6 +39,10 @@ pub enum InstanceDef<'tcx> {
/// `<fn() as FnTrait>::call_*`
/// `DefId` is `FnTrait::call_*`.
///
/// NB: the (`fn` pointer) 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.
FnPtrShim(DefId, Ty<'tcx>),
/// `<dyn Trait as Trait>::fn`, "direct calls" of which are implicitly
@ -57,9 +61,17 @@ pub enum InstanceDef<'tcx> {
/// The `DefId` is for `core::ptr::drop_in_place`.
/// The `Option<Ty<'tcx>>` is either `Some(T)`, or `None` for empty drop
/// glue.
///
/// 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.
DropGlue(DefId, Option<Ty<'tcx>>),
///`<T as Clone>::clone` shim.
///
/// 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>),
}

View File

@ -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;
@ -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.fn_trait_kind_from_lang_item(trait_) {
Some(ty::ClosureKind::FnOnce) => Adjustment::Identity,
@ -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)

View File

@ -1,6 +1,7 @@
use rustc::ty::subst::SubstsRef;
use rustc::ty::{self, Instance, TyCtxt, TypeFoldable};
use rustc_hir::def_id::DefId;
use rustc_span::sym;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits;
@ -31,21 +32,26 @@ pub fn resolve_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, param_env.with_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, substs })
};
@ -113,20 +119,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
}