about summary refs log tree commit diff
path: root/compiler/rustc_public_bridge/src/builder.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_public_bridge/src/builder.rs')
-rw-r--r--compiler/rustc_public_bridge/src/builder.rs77
1 files changed, 77 insertions, 0 deletions
diff --git a/compiler/rustc_public_bridge/src/builder.rs b/compiler/rustc_public_bridge/src/builder.rs
new file mode 100644
index 00000000000..2141053d09a
--- /dev/null
+++ b/compiler/rustc_public_bridge/src/builder.rs
@@ -0,0 +1,77 @@
+//! 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};
+
+/// 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 stable 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
+    }
+}