},
mir_promoted,
mir_drops_elaborated_and_const_checked,
+ mir_for_ctfe,
+ mir_for_ctfe_of_const_arg,
optimized_mir,
- optimized_mir_of_const_arg,
is_mir_available,
+ is_ctfe_mir_available: |tcx, did| is_mir_available(tcx, did),
promoted_mir: |tcx, def_id| {
let def_id = def_id.expect_local();
if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
tcx.alloc_steal_mir(body)
}
+/// Compute the main MIR body and the list of MIR bodies of the promoteds.
fn mir_promoted(
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
(tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
}
+/// Compute the MIR that is used during CTFE (and thus has no optimizations run on it)
+fn mir_for_ctfe<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Body<'tcx> {
+ let did = def_id.expect_local();
+ if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) {
+ tcx.mir_for_ctfe_of_const_arg(def)
+ } else {
+ tcx.arena.alloc(inner_mir_for_ctfe(tcx, ty::WithOptConstParam::unknown(did)))
+ }
+}
+
+/// Same as `mir_for_ctfe`, but used to get the MIR of a const generic parameter.
+/// The docs on `WithOptConstParam` explain this a bit more, but the TLDR is that
+/// we'd get cycle errors with `mir_for_ctfe`, because typeck would need to typeck
+/// the const parameter while type checking the main body, which in turn would try
+/// to type check the main body again.
+fn mir_for_ctfe_of_const_arg<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ (did, param_did): (LocalDefId, DefId),
+) -> &'tcx Body<'tcx> {
+ tcx.arena.alloc(inner_mir_for_ctfe(
+ tcx,
+ ty::WithOptConstParam { did, const_param_did: Some(param_did) },
+ ))
+}
+
+fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
+ // FIXME: don't duplicate this between the optimized_mir/mir_for_ctfe queries
+ if tcx.is_constructor(def.did.to_def_id()) {
+ // There's no reason to run all of the MIR passes on constructors when
+ // we can just output the MIR we want directly. This also saves const
+ // qualification and borrow checking the trouble of special casing
+ // constructors.
+ return shim::build_adt_ctor(tcx, def.did.to_def_id());
+ }
+
+ assert_ne!(
+ tcx.hir().body_const_context(def.did),
+ None,
+ "mir_for_ctfe should not be used for runtime functions"
+ );
+
+ let mut body = tcx.mir_drops_elaborated_and_const_checked(def).borrow().clone();
+
+ #[rustfmt::skip]
+ let optimizations: &[&dyn MirPass<'_>] = &[
+ &const_prop::ConstProp,
+ ];
+
+ #[rustfmt::skip]
+ run_passes(
+ tcx,
+ &mut body,
+ MirPhase::Optimization,
+ &[
+ optimizations,
+ ],
+ );
+
+ debug_assert!(!body.has_free_regions(), "Free regions in MIR for CTFE");
+
+ body
+}
+
+/// Obtain just the main MIR (no promoteds) and run some cleanups on it. This also runs
+/// mir borrowck *before* doing so in order to ensure that borrowck can be run and doesn't
+/// end up missing the source MIR due to stealing happening.
fn mir_drops_elaborated_and_const_checked<'tcx>(
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
);
}
+/// Optimize the MIR and prepare it for codegen.
fn optimized_mir<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx Body<'tcx> {
let did = did.expect_local();
- if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) {
- tcx.optimized_mir_of_const_arg(def)
- } else {
- tcx.arena.alloc(inner_optimized_mir(tcx, ty::WithOptConstParam::unknown(did)))
- }
+ assert_eq!(ty::WithOptConstParam::try_lookup(did, tcx), None);
+ tcx.arena.alloc(inner_optimized_mir(tcx, did))
}
-fn optimized_mir_of_const_arg<'tcx>(
- tcx: TyCtxt<'tcx>,
- (did, param_did): (LocalDefId, DefId),
-) -> &'tcx Body<'tcx> {
- tcx.arena.alloc(inner_optimized_mir(
- tcx,
- ty::WithOptConstParam { did, const_param_did: Some(param_did) },
- ))
-}
-
-fn inner_optimized_mir(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
- if tcx.is_constructor(def.did.to_def_id()) {
+fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
+ if tcx.is_constructor(did.to_def_id()) {
// There's no reason to run all of the MIR passes on constructors when
// we can just output the MIR we want directly. This also saves const
// qualification and borrow checking the trouble of special casing
// constructors.
- return shim::build_adt_ctor(tcx, def.did.to_def_id());
+ return shim::build_adt_ctor(tcx, did.to_def_id());
}
- let mut body = tcx.mir_drops_elaborated_and_const_checked(def).steal();
+ match tcx.hir().body_const_context(did) {
+ // Run the `mir_for_ctfe` query, which depends on `mir_drops_elaborated_and_const_checked`
+ // which we are going to steal below. Thus we need to run `mir_for_ctfe` first, so it
+ // computes and caches its result.
+ Some(hir::ConstContext::ConstFn) => tcx.ensure().mir_for_ctfe(did),
+ None => {}
+ Some(other) => panic!("do not use `optimized_mir` for constants: {:?}", other),
+ }
+ let mut body =
+ tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did)).steal();
run_optimization_passes(tcx, &mut body);
debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR");
body
}
+/// Fetch all the promoteds of an item and prepare their MIR bodies to be ready for
+/// constant evaluation once all substitutions become known.
fn promoted_mir<'tcx>(
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
for body in &mut promoted {
run_post_borrowck_cleanup_passes(tcx, body);
- run_optimization_passes(tcx, body);
}
debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR");