Skip to content

Commit 7dafad3

Browse files
authored
Rollup merge of rust-lang#75346 - davidtwco:issue-69925-polymorphic-instancedef-fnptrshim, r=nikomatsakis
shim: monomorphic `FnPtrShim`s during construction Fixes rust-lang#69925. This PR adjusts MIR shim construction so that substitutions are applied to function pointer shims during construction, rather than during codegen (as determined by `substs_for_mir_body`). r? @eddyb
2 parents f68e089 + f8376b5 commit 7dafad3

File tree

3 files changed

+58
-59
lines changed

3 files changed

+58
-59
lines changed

compiler/rustc_middle/src/ty/instance.rs

+25-28
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,6 @@ pub enum InstanceDef<'tcx> {
6262
/// `<fn() as FnTrait>::call_*` (generated `FnTrait` implementation for `fn()` pointers).
6363
///
6464
/// `DefId` is `FnTrait::call_*`.
65-
///
66-
/// NB: the (`fn` pointer) type must currently be monomorphic to avoid double substitution
67-
/// problems with the MIR shim bodies. `Instance::resolve` enforces this.
68-
// FIXME(#69925) support polymorphic MIR shim bodies properly instead.
6965
FnPtrShim(DefId, Ty<'tcx>),
7066

7167
/// Dynamic dispatch to `<dyn Trait as Trait>::fn`.
@@ -87,10 +83,6 @@ pub enum InstanceDef<'tcx> {
8783
/// The `DefId` is for `core::ptr::drop_in_place`.
8884
/// The `Option<Ty<'tcx>>` is either `Some(T)`, or `None` for empty drop
8985
/// glue.
90-
///
91-
/// NB: the type must currently be monomorphic to avoid double substitution
92-
/// problems with the MIR shim bodies. `Instance::resolve` enforces this.
93-
// FIXME(#69925) support polymorphic MIR shim bodies properly instead.
9486
DropGlue(DefId, Option<Ty<'tcx>>),
9587

9688
/// Compiler-generated `<T as Clone>::clone` implementation.
@@ -99,10 +91,6 @@ pub enum InstanceDef<'tcx> {
9991
/// Additionally, arrays, tuples, and closures get a `Clone` shim even if they aren't `Copy`.
10092
///
10193
/// The `DefId` is for `Clone::clone`, the `Ty` is the type `T` with the builtin `Clone` impl.
102-
///
103-
/// NB: the type must currently be monomorphic to avoid double substitution
104-
/// problems with the MIR shim bodies. `Instance::resolve` enforces this.
105-
// FIXME(#69925) support polymorphic MIR shim bodies properly instead.
10694
CloneShim(DefId, Ty<'tcx>),
10795
}
10896

@@ -243,6 +231,27 @@ impl<'tcx> InstanceDef<'tcx> {
243231
_ => false,
244232
}
245233
}
234+
235+
/// Returns `true` when the MIR body associated with this instance should be monomorphized
236+
/// by its users (e.g. codegen or miri) by substituting the `substs` from `Instance` (see
237+
/// `Instance::substs_for_mir_body`).
238+
///
239+
/// Otherwise, returns `false` only for some kinds of shims where the construction of the MIR
240+
/// body should perform necessary substitutions.
241+
pub fn has_polymorphic_mir_body(&self) -> bool {
242+
match *self {
243+
InstanceDef::CloneShim(..)
244+
| InstanceDef::FnPtrShim(..)
245+
| InstanceDef::DropGlue(_, Some(_)) => false,
246+
InstanceDef::ClosureOnceShim { .. }
247+
| InstanceDef::DropGlue(..)
248+
| InstanceDef::Item(_)
249+
| InstanceDef::Intrinsic(..)
250+
| InstanceDef::ReifyShim(..)
251+
| InstanceDef::Virtual(..)
252+
| InstanceDef::VtableShim(..) => true,
253+
}
254+
}
246255
}
247256

248257
impl<'tcx> fmt::Display for Instance<'tcx> {
@@ -440,30 +449,18 @@ impl<'tcx> Instance<'tcx> {
440449
Instance { def, substs }
441450
}
442451

443-
/// FIXME(#69925) Depending on the kind of `InstanceDef`, the MIR body associated with an
452+
/// Depending on the kind of `InstanceDef`, the MIR body associated with an
444453
/// instance is expressed in terms of the generic parameters of `self.def_id()`, and in other
445454
/// cases the MIR body is expressed in terms of the types found in the substitution array.
446455
/// In the former case, we want to substitute those generic types and replace them with the
447456
/// values from the substs when monomorphizing the function body. But in the latter case, we
448457
/// don't want to do that substitution, since it has already been done effectively.
449458
///
450-
/// This function returns `Some(substs)` in the former case and None otherwise -- i.e., if
459+
/// This function returns `Some(substs)` in the former case and `None` otherwise -- i.e., if
451460
/// this function returns `None`, then the MIR body does not require substitution during
452-
/// monomorphization.
461+
/// codegen.
453462
pub fn substs_for_mir_body(&self) -> Option<SubstsRef<'tcx>> {
454-
match self.def {
455-
InstanceDef::CloneShim(..)
456-
| InstanceDef::DropGlue(_, Some(_)) => None,
457-
InstanceDef::ClosureOnceShim { .. }
458-
| InstanceDef::DropGlue(..)
459-
// FIXME(#69925): `FnPtrShim` should be in the other branch.
460-
| InstanceDef::FnPtrShim(..)
461-
| InstanceDef::Item(_)
462-
| InstanceDef::Intrinsic(..)
463-
| InstanceDef::ReifyShim(..)
464-
| InstanceDef::Virtual(..)
465-
| InstanceDef::VtableShim(..) => Some(self.substs),
466-
}
463+
if self.def.has_polymorphic_mir_body() { Some(self.substs) } else { None }
467464
}
468465

469466
/// Returns a new `Instance` where generic parameters in `instance.substs` are replaced by

compiler/rustc_mir/src/shim.rs

+31-29
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
3333
let mut result = match instance {
3434
ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance),
3535
ty::InstanceDef::VtableShim(def_id) => {
36-
build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id), None)
36+
build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id))
3737
}
3838
ty::InstanceDef::FnPtrShim(def_id, ty) => {
3939
let trait_ = tcx.trait_of_item(def_id).unwrap();
@@ -42,24 +42,16 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
4242
Some(ty::ClosureKind::FnMut | ty::ClosureKind::Fn) => Adjustment::Deref,
4343
None => bug!("fn pointer {:?} is not an fn", ty),
4444
};
45-
// HACK: we need the "real" argument types for the MIR,
46-
// but because our substs are (Self, Args), where Args
47-
// is a tuple, we must include the *concrete* argument
48-
// types in the MIR. They will be substituted again with
49-
// the param-substs, but because they are concrete, this
50-
// will not do any harm.
51-
let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx));
52-
let arg_tys = sig.inputs();
53-
54-
build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect(ty), Some(arg_tys))
45+
46+
build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect(ty))
5547
}
5648
// We are generating a call back to our def-id, which the
5749
// codegen backend knows to turn to an actual call, be it
5850
// a virtual call, or a direct call to a function for which
5951
// indirect calls must be codegen'd differently than direct ones
6052
// (such as `#[track_caller]`).
6153
ty::InstanceDef::ReifyShim(def_id) => {
62-
build_call_shim(tcx, instance, None, CallKind::Direct(def_id), None)
54+
build_call_shim(tcx, instance, None, CallKind::Direct(def_id))
6355
}
6456
ty::InstanceDef::ClosureOnceShim { call_once: _ } => {
6557
let fn_mut = tcx.require_lang_item(LangItem::FnMut, None);
@@ -70,13 +62,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
7062
.unwrap()
7163
.def_id;
7264

73-
build_call_shim(
74-
tcx,
75-
instance,
76-
Some(Adjustment::RefMut),
77-
CallKind::Direct(call_mut),
78-
None,
79-
)
65+
build_call_shim(tcx, instance, Some(Adjustment::RefMut), CallKind::Direct(call_mut))
8066
}
8167
ty::InstanceDef::DropGlue(def_id, ty) => build_drop_shim(tcx, def_id, ty),
8268
ty::InstanceDef::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty),
@@ -641,29 +627,45 @@ impl CloneShimBuilder<'tcx> {
641627
}
642628
}
643629

644-
/// Builds a "call" shim for `instance`. The shim calls the
645-
/// function specified by `call_kind`, first adjusting its first
646-
/// argument according to `rcvr_adjustment`.
647-
///
648-
/// If `untuple_args` is a vec of types, the second argument of the
649-
/// function will be untupled as these types.
630+
/// Builds a "call" shim for `instance`. The shim calls the function specified by `call_kind`,
631+
/// first adjusting its first argument according to `rcvr_adjustment`.
650632
fn build_call_shim<'tcx>(
651633
tcx: TyCtxt<'tcx>,
652634
instance: ty::InstanceDef<'tcx>,
653635
rcvr_adjustment: Option<Adjustment>,
654636
call_kind: CallKind<'tcx>,
655-
untuple_args: Option<&[Ty<'tcx>]>,
656637
) -> Body<'tcx> {
657638
debug!(
658-
"build_call_shim(instance={:?}, rcvr_adjustment={:?}, \
659-
call_kind={:?}, untuple_args={:?})",
660-
instance, rcvr_adjustment, call_kind, untuple_args
639+
"build_call_shim(instance={:?}, rcvr_adjustment={:?}, call_kind={:?})",
640+
instance, rcvr_adjustment, call_kind
661641
);
662642

643+
// `FnPtrShim` contains the fn pointer type that a call shim is being built for - this is used
644+
// to substitute into the signature of the shim. It is not necessary for users of this
645+
// MIR body to perform further substitutions (see `InstanceDef::has_polymorphic_mir_body`).
646+
let (sig_substs, untuple_args) = if let ty::InstanceDef::FnPtrShim(_, ty) = instance {
647+
let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx));
648+
649+
let untuple_args = sig.inputs();
650+
651+
// Create substitutions for the `Self` and `Args` generic parameters of the shim body.
652+
let arg_tup = tcx.mk_tup(untuple_args.iter());
653+
let sig_substs = tcx.mk_substs_trait(ty, &[ty::subst::GenericArg::from(arg_tup)]);
654+
655+
(Some(sig_substs), Some(untuple_args))
656+
} else {
657+
(None, None)
658+
};
659+
663660
let def_id = instance.def_id();
664661
let sig = tcx.fn_sig(def_id);
665662
let mut sig = tcx.erase_late_bound_regions(&sig);
666663

664+
assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body());
665+
if let Some(sig_substs) = sig_substs {
666+
sig = sig.subst(tcx, sig_substs);
667+
}
668+
667669
if let CallKind::Indirect(fnty) = call_kind {
668670
// `sig` determines our local decls, and thus the callee type in the `Call` terminator. This
669671
// can only be an `FnDef` or `FnPtr`, but currently will be `Self` since the types come from

src/test/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// MIR for `std::ops::Fn::call` before AddMovesForPackedDrops
22

3-
fn std::ops::Fn::call(_1: *const fn(), _2: Args) -> <Self as FnOnce<Args>>::Output {
4-
let mut _0: <Self as std::ops::FnOnce<Args>>::Output; // return place in scope 0 at $SRC_DIR/core/src/ops/function.rs:LL:COL
3+
fn std::ops::Fn::call(_1: *const fn(), _2: ()) -> <fn() as FnOnce<()>>::Output {
4+
let mut _0: <fn() as std::ops::FnOnce<()>>::Output; // return place in scope 0 at $SRC_DIR/core/src/ops/function.rs:LL:COL
55

66
bb0: {
77
_0 = move (*_1)() -> bb1; // scope 0 at $SRC_DIR/core/src/ops/function.rs:LL:COL

0 commit comments

Comments
 (0)