| //! Logic required to produce a monomorphic body. | |
| //! | |
| //! We retrieve and monomorphize the rustc body representation, i.e., we generate a | |
| //! monomorphic body using internal representation. | |
| use rustc_hir::def::DefKind; | |
| use rustc_middle::mir; | |
| use rustc_middle::mir::visit::MutVisitor; | |
| use rustc_middle::ty::{self, TyCtxt}; | |
| /// Builds a monomorphic body for a given instance. | |
| pub(crate) struct BodyBuilder<'tcx> { | |
| tcx: TyCtxt<'tcx>, | |
| instance: ty::Instance<'tcx>, | |
| } | |
| impl<'tcx> BodyBuilder<'tcx> { | |
| pub(crate) fn new(tcx: TyCtxt<'tcx>, instance: ty::Instance<'tcx>) -> Self { | |
| let instance = match instance.def { | |
| // To get the fallback body of an intrinsic, we need to convert it to an item. | |
| ty::InstanceKind::Intrinsic(def_id) => ty::Instance::new_raw(def_id, instance.args), | |
| _ => instance, | |
| }; | |
| BodyBuilder { tcx, instance } | |
| } | |
| /// Build a monomorphic body for a given instance based on the MIR body. | |
| /// | |
| /// All constants are also evaluated. | |
| pub(crate) fn build(mut self) -> mir::Body<'tcx> { | |
| let body = self.tcx.instance_mir(self.instance.def).clone(); | |
| let mono_body = if !self.instance.args.is_empty() | |
| // Without the `generic_const_exprs` feature gate, anon consts in signatures do not | |
| // get generic parameters. Which is wrong, but also not a problem without | |
| // generic_const_exprs | |
| || self.tcx.def_kind(self.instance.def_id()) != DefKind::AnonConst | |
| { | |
| let mut mono_body = self.instance.instantiate_mir_and_normalize_erasing_regions( | |
| self.tcx, | |
| ty::TypingEnv::fully_monomorphized(), | |
| ty::EarlyBinder::bind(self.tcx, body), | |
| ); | |
| self.visit_body(&mut mono_body); | |
| mono_body | |
| } else { | |
| // Already monomorphic. | |
| body | |
| }; | |
| mono_body | |
| } | |
| } | |
| impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> { | |
| fn visit_const_operand( | |
| &mut self, | |
| constant: &mut mir::ConstOperand<'tcx>, | |
| location: mir::Location, | |
| ) { | |
| let const_ = constant.const_; | |
| let val = match const_.eval(self.tcx, ty::TypingEnv::fully_monomorphized(), constant.span) { | |
| Ok(v) => v, | |
| Err(mir::interpret::ErrorHandled::Reported(..)) => return, | |
| Err(mir::interpret::ErrorHandled::TooGeneric(..)) => { | |
| unreachable!("Failed to evaluate instance constant: {:?}", const_) | |
| } | |
| }; | |
| let ty = constant.ty(); | |
| constant.const_ = mir::Const::Val(val, ty); | |
| self.super_const_operand(constant, location); | |
| } | |
| fn tcx(&self) -> TyCtxt<'tcx> { | |
| self.tcx | |
| } | |
| } |