diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 0221bc6c36383..f5e70b683ad35 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -9,7 +9,7 @@ use crate::ty::fold::{FallibleTypeFolder, TypeFoldable}; use crate::ty::print::{pretty_print_const, with_no_trimmed_paths}; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::visit::TypeVisitableExt; -use crate::ty::{self, List, Ty, TyCtxt}; +use crate::ty::{self, Instance, List, Ty, TyCtxt}; use crate::ty::{AdtDef, InstanceDef, UserTypeAnnotationIndex}; use crate::ty::{GenericArg, GenericArgsRef}; @@ -375,6 +375,9 @@ pub struct Body<'tcx> { /// We hold in this field all the constants we are not able to evaluate yet. pub required_consts: Vec>, + /// Functions that need to monomorphize successfully for this MIR to be well-formed. + pub required_fns: Vec>, + /// Does this body use generic parameters. This is used for the `ConstEvaluatable` check. /// /// Note that this does not actually mean that this body is not computable right now. @@ -445,6 +448,7 @@ impl<'tcx> Body<'tcx> { var_debug_info, span, required_consts: Vec::new(), + required_fns: Vec::new(), is_polymorphic: false, injection_phase: None, tainted_by_errors, @@ -473,6 +477,7 @@ impl<'tcx> Body<'tcx> { spread_arg: None, span: DUMMY_SP, required_consts: Vec::new(), + required_fns: Vec::new(), var_debug_info: Vec::new(), is_polymorphic: false, injection_phase: None, diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs index c2bff9084c67e..3132083d0e9a5 100644 --- a/compiler/rustc_mir_build/src/build/custom/mod.rs +++ b/compiler/rustc_mir_build/src/build/custom/mod.rs @@ -56,6 +56,7 @@ pub(super) fn build_custom_mir<'tcx>( var_debug_info: Vec::new(), span, required_consts: Vec::new(), + required_fns: Vec::new(), is_polymorphic: false, tainted_by_errors: None, injection_phase: None, diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index cd9b98e4f32cd..6f6921fc0bd3f 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -344,11 +344,14 @@ fn mir_promoted( } let mut required_consts = Vec::new(); - let mut required_consts_visitor = RequiredConstsVisitor::new(&mut required_consts); + let mut required_fns = Vec::new(); + let mut required_consts_visitor = + RequiredConstsVisitor::new(tcx, &body, &mut required_consts, &mut required_fns); for (bb, bb_data) in traversal::reverse_postorder(&body) { required_consts_visitor.visit_basic_block_data(bb, bb_data); } body.required_consts = required_consts; + body.required_fns = required_fns; // What we need to run borrowck etc. let promote_pass = promote_consts::PromoteTemps::default(); diff --git a/compiler/rustc_mir_transform/src/required_consts.rs b/compiler/rustc_mir_transform/src/required_consts.rs index abde6a47e83aa..cd215d7659548 100644 --- a/compiler/rustc_mir_transform/src/required_consts.rs +++ b/compiler/rustc_mir_transform/src/required_consts.rs @@ -1,14 +1,23 @@ +use rustc_hir::LangItem; use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{Const, ConstOperand, Location}; -use rustc_middle::ty::ConstKind; +use rustc_middle::mir::{self, Const, ConstOperand, Location}; +use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, TyCtxt}; pub struct RequiredConstsVisitor<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a mir::Body<'tcx>, required_consts: &'a mut Vec>, + required_fns: &'a mut Vec>, } impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> { - pub fn new(required_consts: &'a mut Vec>) -> Self { - RequiredConstsVisitor { required_consts } + pub fn new( + tcx: TyCtxt<'tcx>, + body: &'a mir::Body<'tcx>, + required_consts: &'a mut Vec>, + required_fns: &'a mut Vec>, + ) -> Self { + RequiredConstsVisitor { tcx, body, required_consts, required_fns } } } @@ -21,7 +30,34 @@ impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> { _ => bug!("only ConstKind::Param/Value should be encountered here, got {:#?}", c), }, Const::Unevaluated(..) => self.required_consts.push(*constant), - Const::Val(..) => {} + Const::Val(_val, ty) => { + // This is how function items get referenced: via zero-sized constants of `FnDef` type + if let ty::FnDef(def_id, args) = ty.kind() { + debug!("adding to required_fns: {def_id:?}"); + // FIXME maybe we shouldn't use `Instance`? We can't use `Instance::new`, it is + // for codegen. But `Instance` feels like the right representation... Check what + // the regular collector does. + self.required_fns.push(Instance { def: InstanceDef::Item(*def_id), args }); + } + } + } + } + + fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { + self.super_terminator(terminator, location); + + match terminator.kind { + // We don't need to handle `Call` as we already handled all function type operands in + // `visit_constant`. But we do need to handle `Drop`. + mir::TerminatorKind::Drop { place, .. } => { + let ty = place.ty(self.body, self.tcx).ty; + let def_id = self.tcx.require_lang_item(LangItem::DropInPlace, None); + let args = self.tcx.mk_args(&[ty.into()]); + // FIXME: same as above (we cannot use `Instance::resolve_drop_in_place` as this is + // still generic). + self.required_fns.push(Instance { def: InstanceDef::Item(def_id), args }); + } + _ => {} } } }