codegen/mir: support polymorphic InstanceDef
s
This commit modifies the use of `subst_and_normalize_erasing_regions` on parts of the MIR bodies returned from `instance_mir`, so that `InstanceDef::CloneShim` and `InstanceDef::DropGlue` (where there is a type) do not perform substitutions. This avoids double substitutions and enables polymorphic `InstanceDef`s. Signed-off-by: David Wood <david@davidtw.co>
This commit is contained in:
parent
303d8aff60
commit
bee151308d
@ -369,6 +369,32 @@ pub fn fn_once_adapter_instance(
|
||||
Instance { def, substs }
|
||||
}
|
||||
|
||||
/// FIXME(#69925) Depending on the kind of `InstanceDef`, the MIR body associated with an
|
||||
/// instance is expressed in terms of the generic parameters of `self.def_id()`, and in other
|
||||
/// cases the MIR body is expressed in terms of the types found in the substitution array.
|
||||
/// In the former case, we want to substitute those generic types and replace them with the
|
||||
/// values from the substs when monomorphizing the function body. But in the latter case, we
|
||||
/// don't want to do that substitution, since it has already been done effectively.
|
||||
///
|
||||
/// This function returns `Some(substs)` in the former case and None otherwise -- i.e., if
|
||||
/// this function returns `None`, then the MIR body does not require substitution during
|
||||
/// monomorphization.
|
||||
pub fn substs_for_mir_body(&self) -> Option<SubstsRef<'tcx>> {
|
||||
match self.def {
|
||||
InstanceDef::CloneShim(..)
|
||||
| InstanceDef::DropGlue(_, Some(_)) => None,
|
||||
InstanceDef::ClosureOnceShim { .. }
|
||||
| InstanceDef::DropGlue(..)
|
||||
// FIXME(#69925): `FnPtrShim` should be in the other branch.
|
||||
| InstanceDef::FnPtrShim(..)
|
||||
| InstanceDef::Item(_)
|
||||
| InstanceDef::Intrinsic(..)
|
||||
| InstanceDef::ReifyShim(..)
|
||||
| InstanceDef::Virtual(..)
|
||||
| InstanceDef::VtableShim(..) => Some(self.substs),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_vtable_shim(&self) -> bool {
|
||||
if let InstanceDef::VtableShim(..) = self.def { true } else { false }
|
||||
}
|
||||
|
@ -86,13 +86,18 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
|
||||
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
pub fn monomorphize<T>(&self, value: &T) -> T
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
T: Copy + TypeFoldable<'tcx>,
|
||||
{
|
||||
self.cx.tcx().subst_and_normalize_erasing_regions(
|
||||
self.instance.substs,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
value,
|
||||
)
|
||||
debug!("monomorphize: self.instance={:?}", self.instance);
|
||||
if let Some(substs) = self.instance.substs_for_mir_body() {
|
||||
self.cx.tcx().subst_and_normalize_erasing_regions(
|
||||
substs,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
&value,
|
||||
)
|
||||
} else {
|
||||
self.cx.tcx().normalize_erasing_regions(ty::ParamEnv::reveal_all(), *value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,15 +335,25 @@ pub fn load_mir(
|
||||
|
||||
/// Call this on things you got out of the MIR (so it is as generic as the current
|
||||
/// stack frame), to bring it into the proper environment for this interpreter.
|
||||
pub(super) fn subst_from_frame_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
|
||||
pub(super) fn subst_from_current_frame_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
|
||||
&self,
|
||||
value: T,
|
||||
) -> T {
|
||||
self.tcx.subst_and_normalize_erasing_regions(
|
||||
self.frame().instance.substs,
|
||||
self.param_env,
|
||||
&value,
|
||||
)
|
||||
self.subst_from_frame_and_normalize_erasing_regions(self.frame(), value)
|
||||
}
|
||||
|
||||
/// Call this on things you got out of the MIR (so it is as generic as the provided
|
||||
/// stack frame), to bring it into the proper environment for this interpreter.
|
||||
pub(super) fn subst_from_frame_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
|
||||
&self,
|
||||
frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
|
||||
value: T,
|
||||
) -> T {
|
||||
if let Some(substs) = frame.instance.substs_for_mir_body() {
|
||||
self.tcx.subst_and_normalize_erasing_regions(substs, self.param_env, &value)
|
||||
} else {
|
||||
self.tcx.normalize_erasing_regions(self.param_env, value)
|
||||
}
|
||||
}
|
||||
|
||||
/// The `substs` are assumed to already be in our interpreter "universe" (param_env).
|
||||
@ -371,11 +381,8 @@ pub fn layout_of_local(
|
||||
None => {
|
||||
let layout = crate::interpret::operand::from_known_layout(layout, || {
|
||||
let local_ty = frame.body.local_decls[local].ty;
|
||||
let local_ty = self.tcx.subst_and_normalize_erasing_regions(
|
||||
frame.instance.substs,
|
||||
self.param_env,
|
||||
&local_ty,
|
||||
);
|
||||
let local_ty =
|
||||
self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty);
|
||||
self.layout_of(local_ty)
|
||||
})?;
|
||||
if let Some(state) = frame.locals.get(local) {
|
||||
|
@ -491,7 +491,8 @@ pub fn eval_operand(
|
||||
Copy(ref place) | Move(ref place) => self.eval_place_to_op(place, layout)?,
|
||||
|
||||
Constant(ref constant) => {
|
||||
let val = self.subst_from_frame_and_normalize_erasing_regions(constant.literal);
|
||||
let val =
|
||||
self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal);
|
||||
self.eval_const_to_op(val, layout)?
|
||||
}
|
||||
};
|
||||
|
@ -648,9 +648,11 @@ pub fn eval_place(
|
||||
// bail out.
|
||||
None => Place::null(&*self),
|
||||
},
|
||||
layout: self.layout_of(self.subst_from_frame_and_normalize_erasing_regions(
|
||||
self.frame().body.return_ty(),
|
||||
))?,
|
||||
layout: self.layout_of(
|
||||
self.subst_from_current_frame_and_normalize_erasing_regions(
|
||||
self.frame().body.return_ty(),
|
||||
),
|
||||
)?,
|
||||
}
|
||||
}
|
||||
local => PlaceTy {
|
||||
|
@ -248,7 +248,7 @@ pub fn eval_rvalue_into_place(
|
||||
}
|
||||
|
||||
NullaryOp(mir::NullOp::SizeOf, ty) => {
|
||||
let ty = self.subst_from_frame_and_normalize_erasing_regions(ty);
|
||||
let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty);
|
||||
let layout = self.layout_of(ty)?;
|
||||
assert!(
|
||||
!layout.is_unsized(),
|
||||
|
@ -186,7 +186,7 @@
|
||||
use rustc::session::config::EntryFnType;
|
||||
use rustc::ty::adjustment::{CustomCoerceUnsized, PointerCast};
|
||||
use rustc::ty::print::obsolete::DefPathBasedNames;
|
||||
use rustc::ty::subst::{InternalSubsts, SubstsRef};
|
||||
use rustc::ty::subst::InternalSubsts;
|
||||
use rustc::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator};
|
||||
@ -493,7 +493,21 @@ struct MirNeighborCollector<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &'a mir::Body<'tcx>,
|
||||
output: &'a mut Vec<MonoItem<'tcx>>,
|
||||
param_substs: SubstsRef<'tcx>,
|
||||
instance: Instance<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> MirNeighborCollector<'a, 'tcx> {
|
||||
pub fn monomorphize<T>(&self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
debug!("monomorphize: self.instance={:?}", self.instance);
|
||||
if let Some(substs) = self.instance.substs_for_mir_body() {
|
||||
self.tcx.subst_and_normalize_erasing_regions(substs, ty::ParamEnv::reveal_all(), &value)
|
||||
} else {
|
||||
self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
|
||||
@ -509,17 +523,9 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
|
||||
ref operand,
|
||||
target_ty,
|
||||
) => {
|
||||
let target_ty = self.tcx.subst_and_normalize_erasing_regions(
|
||||
self.param_substs,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
&target_ty,
|
||||
);
|
||||
let target_ty = self.monomorphize(target_ty);
|
||||
let source_ty = operand.ty(self.body, self.tcx);
|
||||
let source_ty = self.tcx.subst_and_normalize_erasing_regions(
|
||||
self.param_substs,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
&source_ty,
|
||||
);
|
||||
let source_ty = self.monomorphize(source_ty);
|
||||
let (source_ty, target_ty) =
|
||||
find_vtable_types_for_unsizing(self.tcx, source_ty, target_ty);
|
||||
// This could also be a different Unsize instruction, like
|
||||
@ -540,11 +546,7 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
|
||||
_,
|
||||
) => {
|
||||
let fn_ty = operand.ty(self.body, self.tcx);
|
||||
let fn_ty = self.tcx.subst_and_normalize_erasing_regions(
|
||||
self.param_substs,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
&fn_ty,
|
||||
);
|
||||
let fn_ty = self.monomorphize(fn_ty);
|
||||
visit_fn_use(self.tcx, fn_ty, false, &mut self.output);
|
||||
}
|
||||
mir::Rvalue::Cast(
|
||||
@ -553,11 +555,7 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
|
||||
_,
|
||||
) => {
|
||||
let source_ty = operand.ty(self.body, self.tcx);
|
||||
let source_ty = self.tcx.subst_and_normalize_erasing_regions(
|
||||
self.param_substs,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
&source_ty,
|
||||
);
|
||||
let source_ty = self.monomorphize(source_ty);
|
||||
match source_ty.kind {
|
||||
ty::Closure(def_id, substs) => {
|
||||
let instance = Instance::resolve_closure(
|
||||
@ -593,7 +591,23 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
|
||||
fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) {
|
||||
debug!("visiting const {:?} @ {:?}", *constant, location);
|
||||
|
||||
collect_const(self.tcx, *constant, self.param_substs, self.output);
|
||||
let substituted_constant = self.monomorphize(*constant);
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
|
||||
match substituted_constant.val {
|
||||
ty::ConstKind::Value(val) => collect_const_value(self.tcx, val, self.output),
|
||||
ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
|
||||
match self.tcx.const_eval_resolve(param_env, def_id, substs, promoted, None) {
|
||||
Ok(val) => collect_const_value(self.tcx, val, self.output),
|
||||
Err(ErrorHandled::Reported) => {}
|
||||
Err(ErrorHandled::TooGeneric) => span_bug!(
|
||||
self.tcx.def_span(def_id),
|
||||
"collection encountered polymorphic constant",
|
||||
),
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.super_const(constant);
|
||||
}
|
||||
@ -605,21 +619,13 @@ fn visit_terminator_kind(&mut self, kind: &mir::TerminatorKind<'tcx>, location:
|
||||
match *kind {
|
||||
mir::TerminatorKind::Call { ref func, .. } => {
|
||||
let callee_ty = func.ty(self.body, tcx);
|
||||
let callee_ty = tcx.subst_and_normalize_erasing_regions(
|
||||
self.param_substs,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
&callee_ty,
|
||||
);
|
||||
let callee_ty = self.monomorphize(callee_ty);
|
||||
visit_fn_use(self.tcx, callee_ty, true, &mut self.output);
|
||||
}
|
||||
mir::TerminatorKind::Drop { ref location, .. }
|
||||
| mir::TerminatorKind::DropAndReplace { ref location, .. } => {
|
||||
let ty = location.ty(self.body, self.tcx).ty;
|
||||
let ty = tcx.subst_and_normalize_erasing_regions(
|
||||
self.param_substs,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
&ty,
|
||||
);
|
||||
let ty = self.monomorphize(ty);
|
||||
visit_drop_use(self.tcx, ty, true, self.output);
|
||||
}
|
||||
mir::TerminatorKind::Goto { .. }
|
||||
@ -1156,8 +1162,7 @@ fn collect_neighbours<'tcx>(
|
||||
debug!("collect_neighbours: {:?}", instance.def_id());
|
||||
let body = tcx.instance_mir(instance.def);
|
||||
|
||||
MirNeighborCollector { tcx, body: &body, output, param_substs: instance.substs }
|
||||
.visit_body(body);
|
||||
MirNeighborCollector { tcx, body: &body, output, instance }.visit_body(body);
|
||||
}
|
||||
|
||||
fn def_id_to_string(tcx: TyCtxt<'_>, def_id: DefId) -> String {
|
||||
@ -1167,33 +1172,6 @@ fn def_id_to_string(tcx: TyCtxt<'_>, def_id: DefId) -> String {
|
||||
output
|
||||
}
|
||||
|
||||
fn collect_const<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
constant: &'tcx ty::Const<'tcx>,
|
||||
param_substs: SubstsRef<'tcx>,
|
||||
output: &mut Vec<MonoItem<'tcx>>,
|
||||
) {
|
||||
debug!("visiting const {:?}", constant);
|
||||
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
let substituted_constant =
|
||||
tcx.subst_and_normalize_erasing_regions(param_substs, param_env, &constant);
|
||||
|
||||
match substituted_constant.val {
|
||||
ty::ConstKind::Value(val) => collect_const_value(tcx, val, output),
|
||||
ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
|
||||
match tcx.const_eval_resolve(param_env, def_id, substs, promoted, None) {
|
||||
Ok(val) => collect_const_value(tcx, val, output),
|
||||
Err(ErrorHandled::Reported) => {}
|
||||
Err(ErrorHandled::TooGeneric) => {
|
||||
span_bug!(tcx.def_span(def_id), "collection encountered polymorphic constant",)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_const_value<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
value: ConstValue<'tcx>,
|
||||
|
Loading…
Reference in New Issue
Block a user