Skip to content

Commit

Permalink
Rollup merge of rust-lang#69935 - davidtwco:issue-69925, r=eddyb
Browse files Browse the repository at this point in the history
codegen/mir: support polymorphic `InstanceDef`s

cc rust-lang#69925

This PR 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.

r? @eddyb
cc @nikomatsakis
  • Loading branch information
JohnTitor authored Mar 20, 2020
2 parents 3554f2d + bee1513 commit 9dc6994
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 83 deletions.
26 changes: 26 additions & 0 deletions src/librustc/ty/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,32 @@ impl<'tcx> Instance<'tcx> {
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 }
}
Expand Down
17 changes: 11 additions & 6 deletions src/librustc_codegen_ssa/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}

Expand Down
27 changes: 17 additions & 10 deletions src/librustc_mir/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,15 +335,25 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {

/// 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_current_frame_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
&self,
value: T,
) -> T {
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 {
self.tcx.subst_and_normalize_erasing_regions(
self.frame().instance.substs,
self.param_env,
&value,
)
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).
Expand Down Expand Up @@ -371,11 +381,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
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) {
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_mir/interpret/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
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)?
}
};
Expand Down
8 changes: 5 additions & 3 deletions src/librustc_mir/interpret/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -640,9 +640,11 @@ where
// 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 {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/interpret/step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}

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(),
Expand Down
102 changes: 40 additions & 62 deletions src/librustc_mir/monomorphize/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ use rustc::mir::visit::Visitor as MirVisitor;
use rustc::mir::{self, Local, Location};
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};
Expand Down Expand Up @@ -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> {
Expand All @@ -509,17 +523,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
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
Expand All @@ -540,11 +546,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
_,
) => {
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(
Expand All @@ -553,11 +555,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
_,
) => {
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(
Expand Down Expand Up @@ -593,7 +591,23 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
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);
}
Expand All @@ -605,21 +619,13 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
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 { .. }
Expand Down Expand Up @@ -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 {
Expand All @@ -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>,
Expand Down

0 comments on commit 9dc6994

Please sign in to comment.