rustc_smir/rustc_smir/
builder.rs

1//! Logic required to produce a monomorphic stable body.
2//!
3//! We first retrieve and monomorphize the rustc body representation, i.e., we generate a
4//! monomorphic body using internal representation.
5//! After that, we convert the internal representation into a stable one.
6
7use rustc_hir::def::DefKind;
8use rustc_middle::mir;
9use rustc_middle::mir::visit::MutVisitor;
10use rustc_middle::ty::{self, TyCtxt};
11
12use crate::rustc_smir::{Stable, Tables};
13use crate::stable_mir;
14
15/// Builds a monomorphic body for a given instance.
16pub(crate) struct BodyBuilder<'tcx> {
17    tcx: TyCtxt<'tcx>,
18    instance: ty::Instance<'tcx>,
19}
20
21impl<'tcx> BodyBuilder<'tcx> {
22    pub(crate) fn new(tcx: TyCtxt<'tcx>, instance: ty::Instance<'tcx>) -> Self {
23        let instance = match instance.def {
24            // To get the fallback body of an intrinsic, we need to convert it to an item.
25            ty::InstanceKind::Intrinsic(def_id) => ty::Instance::new_raw(def_id, instance.args),
26            _ => instance,
27        };
28        BodyBuilder { tcx, instance }
29    }
30
31    /// Build a stable monomorphic body for a given instance based on the MIR body.
32    ///
33    /// All constants are also evaluated.
34    pub(crate) fn build(mut self, tables: &mut Tables<'tcx>) -> stable_mir::mir::Body {
35        let body = tables.tcx.instance_mir(self.instance.def).clone();
36        let mono_body = if !self.instance.args.is_empty()
37            // Without the `generic_const_exprs` feature gate, anon consts in signatures do not
38            // get generic parameters. Which is wrong, but also not a problem without
39            // generic_const_exprs
40            || self.tcx.def_kind(self.instance.def_id()) != DefKind::AnonConst
41        {
42            let mut mono_body = self.instance.instantiate_mir_and_normalize_erasing_regions(
43                tables.tcx,
44                ty::TypingEnv::fully_monomorphized(),
45                ty::EarlyBinder::bind(body),
46            );
47            self.visit_body(&mut mono_body);
48            mono_body
49        } else {
50            // Already monomorphic.
51            body
52        };
53        mono_body.stable(tables)
54    }
55}
56
57impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> {
58    fn visit_const_operand(
59        &mut self,
60        constant: &mut mir::ConstOperand<'tcx>,
61        location: mir::Location,
62    ) {
63        let const_ = constant.const_;
64        let val = match const_.eval(self.tcx, ty::TypingEnv::fully_monomorphized(), constant.span) {
65            Ok(v) => v,
66            Err(mir::interpret::ErrorHandled::Reported(..)) => return,
67            Err(mir::interpret::ErrorHandled::TooGeneric(..)) => {
68                unreachable!("Failed to evaluate instance constant: {:?}", const_)
69            }
70        };
71        let ty = constant.ty();
72        constant.const_ = mir::Const::Val(val, ty);
73        self.super_const_operand(constant, location);
74    }
75
76    fn tcx(&self) -> TyCtxt<'tcx> {
77        self.tcx
78    }
79}