about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_mir_build/src/build/custom/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse.rs25
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse/instruction.rs47
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_constant.rs137
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs2
-rw-r--r--library/core/src/intrinsics/mir.rs174
-rw-r--r--src/test/mir-opt/building/custom/arbitrary_let.arbitrary_let.built.after.mir22
-rw-r--r--src/test/mir-opt/building/custom/arbitrary_let.rs28
-rw-r--r--src/test/mir-opt/building/custom/consts.consts.built.after.mir22
-rw-r--r--src/test/mir-opt/building/custom/consts.rs36
-rw-r--r--src/test/mir-opt/building/custom/consts.statics.built.after.mir27
-rw-r--r--src/test/mir-opt/building/custom/references.immut_ref.built.after.mir10
-rw-r--r--src/test/mir-opt/building/custom/references.mut_ref.built.after.mir10
-rw-r--r--src/test/mir-opt/building/custom/simple_assign.simple.built.after.mir10
-rw-r--r--src/test/mir-opt/building/custom/simple_assign.simple_ref.built.after.mir4
15 files changed, 454 insertions, 104 deletions
diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs
index 68d8766c907..2412824efeb 100644
--- a/compiler/rustc_mir_build/src/build/custom/mod.rs
+++ b/compiler/rustc_mir_build/src/build/custom/mod.rs
@@ -74,7 +74,7 @@ pub(super) fn build_custom_mir<'tcx>(
     let mut pctxt = ParseCtxt {
         tcx,
         thir,
-        source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE },
+        source_scope: OUTERMOST_SOURCE_SCOPE,
         body: &mut body,
         local_map: FxHashMap::default(),
         block_map: FxHashMap::default(),
@@ -128,7 +128,7 @@ fn parse_attribute(attr: &Attribute) -> MirPhase {
 struct ParseCtxt<'tcx, 'body> {
     tcx: TyCtxt<'tcx>,
     thir: &'body Thir<'tcx>,
-    source_info: SourceInfo,
+    source_scope: SourceScope,
 
     body: &'body mut Body<'tcx>,
     local_map: FxHashMap<LocalVarId, Local>,
diff --git a/compiler/rustc_mir_build/src/build/custom/parse.rs b/compiler/rustc_mir_build/src/build/custom/parse.rs
index 52cb0a4826d..d72770e70c7 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse.rs
@@ -23,6 +23,7 @@ macro_rules! parse_by_kind {
     (
         $self:ident,
         $expr_id:expr,
+        $expr_name:pat,
         $expected:literal,
         $(
             @call($name:literal, $args:ident) => $call_expr:expr,
@@ -33,6 +34,8 @@ macro_rules! parse_by_kind {
     ) => {{
         let expr_id = $self.preparse($expr_id);
         let expr = &$self.thir[expr_id];
+        debug!("Trying to parse {:?} as {}", expr.kind, $expected);
+        let $expr_name = expr;
         match &expr.kind {
             $(
                 ExprKind::Call { ty, fun: _, args: $args, .. } if {
@@ -137,10 +140,10 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
     /// This allows us to easily parse the basic blocks declarations, local declarations, and
     /// basic block definitions in order.
     pub fn parse_body(&mut self, expr_id: ExprId) -> PResult<()> {
-        let body = parse_by_kind!(self, expr_id, "whole body",
+        let body = parse_by_kind!(self, expr_id, _, "whole body",
             ExprKind::Block { block } => self.thir[*block].expr.unwrap(),
         );
-        let (block_decls, rest) = parse_by_kind!(self, body, "body with block decls",
+        let (block_decls, rest) = parse_by_kind!(self, body, _, "body with block decls",
             ExprKind::Block { block } => {
                 let block = &self.thir[*block];
                 (&block.stmts, block.expr.unwrap())
@@ -148,7 +151,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
         );
         self.parse_block_decls(block_decls.iter().copied())?;
 
-        let (local_decls, rest) = parse_by_kind!(self, rest, "body with local decls",
+        let (local_decls, rest) = parse_by_kind!(self, rest, _, "body with local decls",
             ExprKind::Block { block } => {
                 let block = &self.thir[*block];
                 (&block.stmts, block.expr.unwrap())
@@ -156,7 +159,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
         );
         self.parse_local_decls(local_decls.iter().copied())?;
 
-        let block_defs = parse_by_kind!(self, rest, "body with block defs",
+        let block_defs = parse_by_kind!(self, rest, _, "body with block defs",
             ExprKind::Block { block } => &self.thir[*block].stmts,
         );
         for (i, block_def) in block_defs.iter().enumerate() {
@@ -223,22 +226,30 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
     }
 
     fn parse_block_def(&self, expr_id: ExprId) -> PResult<BasicBlockData<'tcx>> {
-        let block = parse_by_kind!(self, expr_id, "basic block",
+        let block = parse_by_kind!(self, expr_id, _, "basic block",
             ExprKind::Block { block } => &self.thir[*block],
         );
 
         let mut data = BasicBlockData::new(None);
         for stmt_id in &*block.stmts {
             let stmt = self.statement_as_expr(*stmt_id)?;
+            let span = self.thir[stmt].span;
             let statement = self.parse_statement(stmt)?;
-            data.statements.push(Statement { source_info: self.source_info, kind: statement });
+            data.statements.push(Statement {
+                source_info: SourceInfo { span, scope: self.source_scope },
+                kind: statement,
+            });
         }
 
         let Some(trailing) = block.expr else {
             return Err(self.expr_error(expr_id, "terminator"))
         };
+        let span = self.thir[trailing].span;
         let terminator = self.parse_terminator(trailing)?;
-        data.terminator = Some(Terminator { source_info: self.source_info, kind: terminator });
+        data.terminator = Some(Terminator {
+            source_info: SourceInfo { span, scope: self.source_scope },
+            kind: terminator,
+        });
 
         Ok(data)
     }
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index 6d6176584f5..03206af33bf 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -1,10 +1,11 @@
+use rustc_middle::mir::interpret::{ConstValue, Scalar};
 use rustc_middle::{mir::*, thir::*, ty};
 
 use super::{parse_by_kind, PResult, ParseCtxt};
 
 impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
     pub fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> {
-        parse_by_kind!(self, expr_id, "statement",
+        parse_by_kind!(self, expr_id, _, "statement",
             @call("mir_retag", args) => {
                 Ok(StatementKind::Retag(RetagKind::Default, Box::new(self.parse_place(args[0])?)))
             },
@@ -20,7 +21,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
     }
 
     pub fn parse_terminator(&self, expr_id: ExprId) -> PResult<TerminatorKind<'tcx>> {
-        parse_by_kind!(self, expr_id, "terminator",
+        parse_by_kind!(self, expr_id, _, "terminator",
             @call("mir_return", _args) => {
                 Ok(TerminatorKind::Return)
             },
@@ -31,7 +32,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
     }
 
     fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
-        parse_by_kind!(self, expr_id, "rvalue",
+        parse_by_kind!(self, expr_id, _, "rvalue",
             ExprKind::Borrow { borrow_kind, arg } => Ok(
                 Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
             ),
@@ -43,14 +44,26 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
     }
 
     fn parse_operand(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
-        parse_by_kind!(self, expr_id, "operand",
+        parse_by_kind!(self, expr_id, expr, "operand",
             @call("mir_move", args) => self.parse_place(args[0]).map(Operand::Move),
+            @call("mir_static", args) => self.parse_static(args[0]),
+            @call("mir_static_mut", args) => self.parse_static(args[0]),
+            ExprKind::Literal { .. }
+            | ExprKind::NamedConst { .. }
+            | ExprKind::NonHirLiteral { .. }
+            | ExprKind::ZstLiteral { .. }
+            | ExprKind::ConstParam { .. }
+            | ExprKind::ConstBlock { .. } => {
+                Ok(Operand::Constant(Box::new(
+                    crate::build::expr::as_constant::as_constant_inner(expr, |_| None, self.tcx)
+                )))
+            },
             _ => self.parse_place(expr_id).map(Operand::Copy),
         )
     }
 
     fn parse_place(&self, expr_id: ExprId) -> PResult<Place<'tcx>> {
-        parse_by_kind!(self, expr_id, "place",
+        parse_by_kind!(self, expr_id, _, "place",
             ExprKind::Deref { arg } => Ok(
                 self.parse_place(*arg)?.project_deeper(&[PlaceElem::Deref], self.tcx)
             ),
@@ -59,14 +72,34 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
     }
 
     fn parse_local(&self, expr_id: ExprId) -> PResult<Local> {
-        parse_by_kind!(self, expr_id, "local",
+        parse_by_kind!(self, expr_id, _, "local",
             ExprKind::VarRef { id } => Ok(self.local_map[id]),
         )
     }
 
     fn parse_block(&self, expr_id: ExprId) -> PResult<BasicBlock> {
-        parse_by_kind!(self, expr_id, "basic block",
+        parse_by_kind!(self, expr_id, _, "basic block",
             ExprKind::VarRef { id } => Ok(self.block_map[id]),
         )
     }
+
+    fn parse_static(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
+        let expr_id = parse_by_kind!(self, expr_id, _, "static",
+            ExprKind::Deref { arg } => *arg,
+        );
+
+        parse_by_kind!(self, expr_id, expr, "static",
+            ExprKind::StaticRef { alloc_id, ty, .. } => {
+                let const_val =
+                    ConstValue::Scalar(Scalar::from_pointer((*alloc_id).into(), &self.tcx));
+                let literal = ConstantKind::Val(const_val, *ty);
+
+                Ok(Operand::Constant(Box::new(Constant {
+                    span: expr.span,
+                    user_ty: None,
+                    literal
+                })))
+            },
+        )
+    }
 }
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index 32c0207cb68..717c6231574 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -8,7 +8,9 @@ use rustc_middle::mir::interpret::{
 };
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
-use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, TyCtxt};
+use rustc_middle::ty::{
+    self, CanonicalUserType, CanonicalUserTypeAnnotation, TyCtxt, UserTypeAnnotationIndex,
+};
 use rustc_span::DUMMY_SP;
 use rustc_target::abi::Size;
 
@@ -19,84 +21,87 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let this = self;
         let tcx = this.tcx;
         let Expr { ty, temp_lifetime: _, span, ref kind } = *expr;
-        match *kind {
+        match kind {
             ExprKind::Scope { region_scope: _, lint_level: _, value } => {
-                this.as_constant(&this.thir[value])
-            }
-            ExprKind::Literal { lit, neg } => {
-                let literal =
-                    match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) {
-                        Ok(c) => c,
-                        Err(LitToConstError::Reported(guar)) => {
-                            ConstantKind::Ty(tcx.const_error_with_guaranteed(ty, guar))
-                        }
-                        Err(LitToConstError::TypeError) => {
-                            bug!("encountered type error in `lit_to_mir_constant")
-                        }
-                    };
-
-                Constant { span, user_ty: None, literal }
+                this.as_constant(&this.thir[*value])
             }
-            ExprKind::NonHirLiteral { lit, ref user_ty } => {
-                let user_ty = user_ty.as_ref().map(|user_ty| {
-                    this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
+            _ => as_constant_inner(
+                expr,
+                |user_ty| {
+                    Some(this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
                         span,
                         user_ty: user_ty.clone(),
                         inferred_ty: ty,
-                    })
-                });
-                let literal = ConstantKind::Val(ConstValue::Scalar(Scalar::Int(lit)), ty);
+                    }))
+                },
+                tcx,
+            ),
+        }
+    }
+}
 
-                Constant { span, user_ty: user_ty, literal }
-            }
-            ExprKind::ZstLiteral { ref user_ty } => {
-                let user_ty = user_ty.as_ref().map(|user_ty| {
-                    this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
-                        span,
-                        user_ty: user_ty.clone(),
-                        inferred_ty: ty,
-                    })
-                });
-                let literal = ConstantKind::Val(ConstValue::ZeroSized, ty);
+pub fn as_constant_inner<'tcx>(
+    expr: &Expr<'tcx>,
+    push_cuta: impl FnMut(&Box<CanonicalUserType<'tcx>>) -> Option<UserTypeAnnotationIndex>,
+    tcx: TyCtxt<'tcx>,
+) -> Constant<'tcx> {
+    let Expr { ty, temp_lifetime: _, span, ref kind } = *expr;
+    match *kind {
+        ExprKind::Literal { lit, neg } => {
+            let literal =
+                match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) {
+                    Ok(c) => c,
+                    Err(LitToConstError::Reported(guar)) => {
+                        ConstantKind::Ty(tcx.const_error_with_guaranteed(ty, guar))
+                    }
+                    Err(LitToConstError::TypeError) => {
+                        bug!("encountered type error in `lit_to_mir_constant")
+                    }
+                };
 
-                Constant { span, user_ty: user_ty, literal }
-            }
-            ExprKind::NamedConst { def_id, substs, ref user_ty } => {
-                let user_ty = user_ty.as_ref().map(|user_ty| {
-                    this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
-                        span,
-                        user_ty: user_ty.clone(),
-                        inferred_ty: ty,
-                    })
-                });
+            Constant { span, user_ty: None, literal }
+        }
+        ExprKind::NonHirLiteral { lit, ref user_ty } => {
+            let user_ty = user_ty.as_ref().map(push_cuta).flatten();
 
-                let uneval =
-                    mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs);
-                let literal = ConstantKind::Unevaluated(uneval, ty);
+            let literal = ConstantKind::Val(ConstValue::Scalar(Scalar::Int(lit)), ty);
 
-                Constant { user_ty, span, literal }
-            }
-            ExprKind::ConstParam { param, def_id: _ } => {
-                let const_param = tcx.mk_const(param, expr.ty);
-                let literal = ConstantKind::Ty(const_param);
+            Constant { span, user_ty: user_ty, literal }
+        }
+        ExprKind::ZstLiteral { ref user_ty } => {
+            let user_ty = user_ty.as_ref().map(push_cuta).flatten();
 
-                Constant { user_ty: None, span, literal }
-            }
-            ExprKind::ConstBlock { did: def_id, substs } => {
-                let uneval =
-                    mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs);
-                let literal = ConstantKind::Unevaluated(uneval, ty);
+            let literal = ConstantKind::Val(ConstValue::ZeroSized, ty);
 
-                Constant { user_ty: None, span, literal }
-            }
-            ExprKind::StaticRef { alloc_id, ty, .. } => {
-                let const_val = ConstValue::Scalar(Scalar::from_pointer(alloc_id.into(), &tcx));
-                let literal = ConstantKind::Val(const_val, ty);
+            Constant { span, user_ty: user_ty, literal }
+        }
+        ExprKind::NamedConst { def_id, substs, ref user_ty } => {
+            let user_ty = user_ty.as_ref().map(push_cuta).flatten();
 
-                Constant { span, user_ty: None, literal }
-            }
-            _ => span_bug!(span, "expression is not a valid constant {:?}", kind),
+            let uneval = mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs);
+            let literal = ConstantKind::Unevaluated(uneval, ty);
+
+            Constant { user_ty, span, literal }
+        }
+        ExprKind::ConstParam { param, def_id: _ } => {
+            let const_param = tcx.mk_const(ty::ConstKind::Param(param), expr.ty);
+            let literal = ConstantKind::Ty(const_param);
+
+            Constant { user_ty: None, span, literal }
+        }
+        ExprKind::ConstBlock { did: def_id, substs } => {
+            let uneval = mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs);
+            let literal = ConstantKind::Unevaluated(uneval, ty);
+
+            Constant { user_ty: None, span, literal }
+        }
+        ExprKind::StaticRef { alloc_id, ty, .. } => {
+            let const_val = ConstValue::Scalar(Scalar::from_pointer(alloc_id.into(), &tcx));
+            let literal = ConstantKind::Val(const_val, ty);
+
+            Constant { span, user_ty: None, literal }
         }
+        _ => span_bug!(span, "expression is not a valid constant {:?}", kind),
     }
 }
 
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 0b76122913e..b456e2aa37a 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -492,7 +492,7 @@ fn construct_fn<'tcx>(
             arguments,
             return_ty,
             return_ty_span,
-            span,
+            span_with_body,
             custom_mir_attr,
         );
     }
diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs
index 1bacdc39148..8ba1c122884 100644
--- a/library/core/src/intrinsics/mir.rs
+++ b/library/core/src/intrinsics/mir.rs
@@ -80,6 +80,8 @@ define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock);
 define!("mir_retag", fn Retag<T>(place: T));
 define!("mir_retag_raw", fn RetagRaw<T>(place: T));
 define!("mir_move", fn Move<T>(place: T) -> T);
+define!("mir_static", fn Static<T>(s: T) -> &'static T);
+define!("mir_static_mut", fn StaticMut<T>(s: T) -> *mut T);
 
 /// Convenience macro for generating custom MIR.
 ///
@@ -90,10 +92,14 @@ pub macro mir {
     (
         $(let $local_decl:ident $(: $local_decl_ty:ty)? ;)*
 
-        $entry_block:block
+        {
+            $($entry:tt)*
+        }
 
         $(
-            $block_name:ident = $block:block
+            $block_name:ident = {
+                $($block:tt)*
+            }
         )*
     ) => {{
         // First, we declare all basic blocks.
@@ -109,11 +115,22 @@ pub macro mir {
                 let $local_decl $(: $local_decl_ty)? ;
             )*
 
+            ::core::intrinsics::mir::__internal_extract_let!($($entry)*);
+            $(
+                ::core::intrinsics::mir::__internal_extract_let!($($block)*);
+            )*
+
             {
                 // Finally, the contents of the basic blocks
-                $entry_block;
+                ::core::intrinsics::mir::__internal_remove_let!({
+                    {}
+                    { $($entry)* }
+                });
                 $(
-                    $block;
+                    ::core::intrinsics::mir::__internal_remove_let!({
+                        {}
+                        { $($block)* }
+                    });
                 )*
 
                 RET
@@ -121,3 +138,152 @@ pub macro mir {
         }
     }}
 }
+
+/// Helper macro that extracts the `let` declarations out of a bunch of statements.
+///
+/// This macro is written using the "statement muncher" strategy. Each invocation parses the first
+/// statement out of the input, does the appropriate thing with it, and then recursively calls the
+/// same macro on the remainder of the input.
+#[doc(hidden)]
+pub macro __internal_extract_let {
+    // If it's a `let` like statement, keep the `let`
+    (
+        let $var:ident $(: $ty:ty)? = $expr:expr; $($rest:tt)*
+    ) => {
+        let $var $(: $ty)?;
+        ::core::intrinsics::mir::__internal_extract_let!($($rest)*);
+    },
+    // Due to #86730, we have to handle const blocks separately
+    (
+        let $var:ident $(: $ty:ty)? = const $block:block; $($rest:tt)*
+    ) => {
+        let $var $(: $ty)?;
+        ::core::intrinsics::mir::__internal_extract_let!($($rest)*);
+    },
+    // Otherwise, output nothing
+    (
+        $stmt:stmt; $($rest:tt)*
+    ) => {
+        ::core::intrinsics::mir::__internal_extract_let!($($rest)*);
+    },
+    (
+        $expr:expr
+    ) => {}
+}
+
+/// Helper macro that removes the `let` declarations from a bunch of statements.
+///
+/// Because expression position macros cannot expand to statements + expressions, we need to be
+/// slightly creative here. The general strategy is also statement munching as above, but the output
+/// of the macro is "stored" in the subsequent macro invocation. Easiest understood via example:
+/// ```text
+/// invoke!(
+///     {
+///         {
+///             x = 5;
+///         }
+///         {
+///             let d = e;
+///             Call()
+///         }
+///     }
+/// )
+/// ```
+/// becomes
+/// ```text
+/// invoke!(
+///     {
+///         {
+///             x = 5;
+///             d = e;
+///         }
+///         {
+///             Call()
+///         }
+///     }
+/// )
+/// ```
+#[doc(hidden)]
+pub macro __internal_remove_let {
+    // If it's a `let` like statement, remove the `let`
+    (
+        {
+            {
+                $($already_parsed:tt)*
+            }
+            {
+                let $var:ident $(: $ty:ty)? = $expr:expr;
+                $($rest:tt)*
+            }
+        }
+    ) => { ::core::intrinsics::mir::__internal_remove_let!(
+        {
+            {
+                $($already_parsed)*
+                $var = $expr;
+            }
+            {
+                $($rest)*
+            }
+        }
+    )},
+    // Due to #86730 , we have to handle const blocks separately
+    (
+        {
+            {
+                $($already_parsed:tt)*
+            }
+            {
+                let $var:ident $(: $ty:ty)? = const $block:block;
+                $($rest:tt)*
+            }
+        }
+    ) => { ::core::intrinsics::mir::__internal_remove_let!(
+        {
+            {
+                $($already_parsed)*
+                $var = const $block;
+            }
+            {
+                $($rest)*
+            }
+        }
+    )},
+    // Otherwise, keep going
+    (
+        {
+            {
+                $($already_parsed:tt)*
+            }
+            {
+                $stmt:stmt;
+                $($rest:tt)*
+            }
+        }
+    ) => { ::core::intrinsics::mir::__internal_remove_let!(
+        {
+            {
+                $($already_parsed)*
+                $stmt;
+            }
+            {
+                $($rest)*
+            }
+        }
+    )},
+    (
+        {
+            {
+                $($already_parsed:tt)*
+            }
+            {
+                $expr:expr
+            }
+        }
+    ) => {
+        {
+            $($already_parsed)*
+            $expr
+        }
+    },
+}
diff --git a/src/test/mir-opt/building/custom/arbitrary_let.arbitrary_let.built.after.mir b/src/test/mir-opt/building/custom/arbitrary_let.arbitrary_let.built.after.mir
new file mode 100644
index 00000000000..20dd251e7e3
--- /dev/null
+++ b/src/test/mir-opt/building/custom/arbitrary_let.arbitrary_let.built.after.mir
@@ -0,0 +1,22 @@
+// MIR for `arbitrary_let` after built
+
+fn arbitrary_let(_1: i32) -> i32 {
+    let mut _0: i32;                     // return place in scope 0 at $DIR/arbitrary_let.rs:+0:29: +0:32
+    let mut _2: i32;                     // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+    let mut _3: i32;                     // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        _2 = _1;                         // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+        goto -> bb2;                     // scope 0 at $DIR/arbitrary_let.rs:+4:13: +4:25
+    }
+
+    bb1: {
+        _0 = _3;                         // scope 0 at $DIR/arbitrary_let.rs:+7:13: +7:20
+        return;                          // scope 0 at $DIR/arbitrary_let.rs:+8:13: +8:21
+    }
+
+    bb2: {
+        _3 = _2;                         // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+        goto -> bb1;                     // scope 0 at $DIR/arbitrary_let.rs:+12:13: +12:24
+    }
+}
diff --git a/src/test/mir-opt/building/custom/arbitrary_let.rs b/src/test/mir-opt/building/custom/arbitrary_let.rs
new file mode 100644
index 00000000000..776df3151ff
--- /dev/null
+++ b/src/test/mir-opt/building/custom/arbitrary_let.rs
@@ -0,0 +1,28 @@
+#![feature(custom_mir, core_intrinsics)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+use core::ptr::{addr_of, addr_of_mut};
+
+// EMIT_MIR arbitrary_let.arbitrary_let.built.after.mir
+#[custom_mir(dialect = "built")]
+fn arbitrary_let(x: i32) -> i32 {
+    mir!(
+        {
+            let y = x;
+            Goto(second)
+        }
+        third = {
+            RET = z;
+            Return()
+        }
+        second = {
+            let z = y;
+            Goto(third)
+        }
+    )
+}
+
+fn main() {
+    assert_eq!(arbitrary_let(5), 5);
+}
diff --git a/src/test/mir-opt/building/custom/consts.consts.built.after.mir b/src/test/mir-opt/building/custom/consts.consts.built.after.mir
new file mode 100644
index 00000000000..ba753cfc20c
--- /dev/null
+++ b/src/test/mir-opt/building/custom/consts.consts.built.after.mir
@@ -0,0 +1,22 @@
+// MIR for `consts` after built
+
+fn consts() -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/consts.rs:+0:27: +0:27
+    let mut _1: u8;                      // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+    let mut _2: i8;                      // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+    let mut _3: u32;                     // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+    let mut _4: i32;                     // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+    let mut _5: fn() {consts::<10>};     // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        _1 = const 5_u8;                 // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+        _2 = const _;                    // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+        _3 = const C;                    // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+        _4 = const _;                    // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+        _5 = consts::<10>;               // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+                                         // mir::Constant
+                                         // + span: $DIR/consts.rs:16:18: 16:30
+                                         // + literal: Const { ty: fn() {consts::<10>}, val: Value(<ZST>) }
+        return;                          // scope 0 at $DIR/consts.rs:+7:9: +7:17
+    }
+}
diff --git a/src/test/mir-opt/building/custom/consts.rs b/src/test/mir-opt/building/custom/consts.rs
new file mode 100644
index 00000000000..ff4fe1a9324
--- /dev/null
+++ b/src/test/mir-opt/building/custom/consts.rs
@@ -0,0 +1,36 @@
+#![feature(custom_mir, core_intrinsics, inline_const)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+
+const D: i32 = 5;
+
+// EMIT_MIR consts.consts.built.after.mir
+#[custom_mir(dialect = "built")]
+fn consts<const C: u32>() {
+    mir!({
+        let _a = 5_u8;
+        let _b = const { 5_i8 };
+        let _c = C;
+        let _d = D;
+        let _e = consts::<10>;
+        Return()
+    })
+}
+
+static S: i32 = 5;
+static mut T: i32 = 10;
+// EMIT_MIR consts.statics.built.after.mir
+#[custom_mir(dialect = "built")]
+fn statics() {
+    mir!({
+        let _a: &i32 = Static(S);
+        let _b: *mut i32 = StaticMut(T);
+        Return()
+    })
+}
+
+fn main() {
+    consts::<5>();
+    statics();
+}
diff --git a/src/test/mir-opt/building/custom/consts.statics.built.after.mir b/src/test/mir-opt/building/custom/consts.statics.built.after.mir
new file mode 100644
index 00000000000..ee768e263ec
--- /dev/null
+++ b/src/test/mir-opt/building/custom/consts.statics.built.after.mir
@@ -0,0 +1,27 @@
+// MIR for `statics` after built
+
+fn statics() -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/consts.rs:+0:14: +0:14
+    let mut _1: &i32;                    // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+    let mut _2: *mut i32;                // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        _1 = const {alloc1: &i32};       // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+                                         // mir::Constant
+                                         // + span: $DIR/consts.rs:27:31: 27:32
+                                         // + literal: Const { ty: &i32, val: Value(Scalar(alloc1)) }
+        _2 = const {alloc2: *mut i32};   // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+                                         // mir::Constant
+                                         // + span: $DIR/consts.rs:28:38: 28:39
+                                         // + literal: Const { ty: *mut i32, val: Value(Scalar(alloc2)) }
+        return;                          // scope 0 at $DIR/consts.rs:+4:9: +4:17
+    }
+}
+
+alloc2 (static: T, size: 4, align: 4) {
+    0a 00 00 00                                     │ ....
+}
+
+alloc1 (static: S, size: 4, align: 4) {
+    05 00 00 00                                     │ ....
+}
diff --git a/src/test/mir-opt/building/custom/references.immut_ref.built.after.mir b/src/test/mir-opt/building/custom/references.immut_ref.built.after.mir
index 4a5ddde4081..4d38d45c0f4 100644
--- a/src/test/mir-opt/building/custom/references.immut_ref.built.after.mir
+++ b/src/test/mir-opt/building/custom/references.immut_ref.built.after.mir
@@ -5,10 +5,10 @@ fn immut_ref(_1: &i32) -> &i32 {
     let mut _2: *const i32;              // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
 
     bb0: {
-        _2 = &raw const (*_1);           // scope 0 at $DIR/references.rs:+0:1: +0:34
-        Retag([raw] _2);                 // scope 0 at $DIR/references.rs:+0:1: +0:34
-        _0 = &(*_2);                     // scope 0 at $DIR/references.rs:+0:1: +0:34
-        Retag(_0);                       // scope 0 at $DIR/references.rs:+0:1: +0:34
-        return;                          // scope 0 at $DIR/references.rs:+0:1: +0:34
+        _2 = &raw const (*_1);           // scope 0 at $DIR/references.rs:+5:13: +5:29
+        Retag([raw] _2);                 // scope 0 at $DIR/references.rs:+6:13: +6:24
+        _0 = &(*_2);                     // scope 0 at $DIR/references.rs:+7:13: +7:23
+        Retag(_0);                       // scope 0 at $DIR/references.rs:+8:13: +8:23
+        return;                          // scope 0 at $DIR/references.rs:+9:13: +9:21
     }
 }
diff --git a/src/test/mir-opt/building/custom/references.mut_ref.built.after.mir b/src/test/mir-opt/building/custom/references.mut_ref.built.after.mir
index ec8509f69d1..01bc8a9cd35 100644
--- a/src/test/mir-opt/building/custom/references.mut_ref.built.after.mir
+++ b/src/test/mir-opt/building/custom/references.mut_ref.built.after.mir
@@ -5,10 +5,10 @@ fn mut_ref(_1: &mut i32) -> &mut i32 {
     let mut _2: *mut i32;                // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
 
     bb0: {
-        _2 = &raw mut (*_1);             // scope 0 at $DIR/references.rs:+0:1: +0:40
-        Retag([raw] _2);                 // scope 0 at $DIR/references.rs:+0:1: +0:40
-        _0 = &mut (*_2);                 // scope 0 at $DIR/references.rs:+0:1: +0:40
-        Retag(_0);                       // scope 0 at $DIR/references.rs:+0:1: +0:40
-        return;                          // scope 0 at $DIR/references.rs:+0:1: +0:40
+        _2 = &raw mut (*_1);             // scope 0 at $DIR/references.rs:+5:13: +5:33
+        Retag([raw] _2);                 // scope 0 at $DIR/references.rs:+6:13: +6:24
+        _0 = &mut (*_2);                 // scope 0 at $DIR/references.rs:+7:13: +7:26
+        Retag(_0);                       // scope 0 at $DIR/references.rs:+8:13: +8:23
+        return;                          // scope 0 at $DIR/references.rs:+9:13: +9:21
     }
 }
diff --git a/src/test/mir-opt/building/custom/simple_assign.simple.built.after.mir b/src/test/mir-opt/building/custom/simple_assign.simple.built.after.mir
index a5a2834c2e1..d7560fde69c 100644
--- a/src/test/mir-opt/building/custom/simple_assign.simple.built.after.mir
+++ b/src/test/mir-opt/building/custom/simple_assign.simple.built.after.mir
@@ -6,13 +6,13 @@ fn simple(_1: i32) -> i32 {
     let mut _3: i32;                     // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
 
     bb0: {
-        _2 = _1;                         // scope 0 at $DIR/simple_assign.rs:+0:1: +0:29
-        goto -> bb1;                     // scope 0 at $DIR/simple_assign.rs:+0:1: +0:29
+        _2 = _1;                         // scope 0 at $DIR/simple_assign.rs:+6:13: +6:22
+        goto -> bb1;                     // scope 0 at $DIR/simple_assign.rs:+7:13: +7:23
     }
 
     bb1: {
-        _3 = move _2;                    // scope 0 at $DIR/simple_assign.rs:+0:1: +0:29
-        _0 = _3;                         // scope 0 at $DIR/simple_assign.rs:+0:1: +0:29
-        return;                          // scope 0 at $DIR/simple_assign.rs:+0:1: +0:29
+        _3 = move _2;                    // scope 0 at $DIR/simple_assign.rs:+11:13: +11:32
+        _0 = _3;                         // scope 0 at $DIR/simple_assign.rs:+12:13: +12:24
+        return;                          // scope 0 at $DIR/simple_assign.rs:+13:13: +13:21
     }
 }
diff --git a/src/test/mir-opt/building/custom/simple_assign.simple_ref.built.after.mir b/src/test/mir-opt/building/custom/simple_assign.simple_ref.built.after.mir
index 6c90f0130a2..2b0e8f1047b 100644
--- a/src/test/mir-opt/building/custom/simple_assign.simple_ref.built.after.mir
+++ b/src/test/mir-opt/building/custom/simple_assign.simple_ref.built.after.mir
@@ -4,7 +4,7 @@ fn simple_ref(_1: &mut i32) -> &mut i32 {
     let mut _0: &mut i32;                // return place in scope 0 at $DIR/simple_assign.rs:+0:35: +0:43
 
     bb0: {
-        _0 = move _1;                    // scope 0 at $DIR/simple_assign.rs:+0:1: +0:43
-        return;                          // scope 0 at $DIR/simple_assign.rs:+0:1: +0:43
+        _0 = move _1;                    // scope 0 at $DIR/simple_assign.rs:+2:9: +2:22
+        return;                          // scope 0 at $DIR/simple_assign.rs:+3:9: +3:17
     }
 }