| //! 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(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 |
| } |
| } |