rustc_smir/rustc_smir/
builder.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
//! Logic required to produce a monomorphic stable body.
//!
//! We first retrieve and monomorphize the rustc body representation, i.e., we generate a
//! monomorphic body using internal representation.
//! After that, we convert the internal representation into a stable one.

use rustc_hir::def::DefKind;
use rustc_middle::mir;
use rustc_middle::mir::visit::MutVisitor;
use rustc_middle::ty::{self, TyCtxt};

use crate::rustc_smir::{Stable, Tables};

/// 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(def_id, instance.args),
            _ => instance,
        };
        BodyBuilder { tcx, instance }
    }

    /// Build a stable monomorphic body for a given instance based on the MIR body.
    ///
    /// All constants are also evaluated.
    pub(crate) fn build(mut self, tables: &mut Tables<'tcx>) -> stable_mir::mir::Body {
        let body = tables.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(
                tables.tcx,
                ty::TypingEnv::fully_monomorphized(),
                ty::EarlyBinder::bind(body),
            );
            self.visit_body(&mut mono_body);
            mono_body
        } else {
            // Already monomorphic.
            body
        };
        mono_body.stable(tables)
    }
}

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
    }
}