about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeSeulArtichaut <leseulartichaut@gmail.com>2021-03-05 21:56:02 +0100
committerLeSeulArtichaut <leseulartichaut@gmail.com>2021-03-09 20:14:42 +0100
commitc2c432289195eaf65e42566ed0b95f82a913bcb3 (patch)
treea8d921e446d3572864bd7709dbb7291c7e3cece4
parenta9f4dfc8fa90420548bb96d2df4b0d76eea9c862 (diff)
downloadrust-c2c432289195eaf65e42566ed0b95f82a913bcb3.tar.gz
rust-c2c432289195eaf65e42566ed0b95f82a913bcb3.zip
Make arena allocation for the THIR work
-rw-r--r--compiler/rustc_mir_build/src/build/block.rs6
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_constant.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_operand.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs14
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs6
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_temp.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/expr/category.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/expr/stmt.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs18
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs27
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/arena.rs98
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/block.rs40
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs494
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs27
-rw-r--r--compiler/rustc_mir_build/src/thir/mod.rs155
17 files changed, 526 insertions, 383 deletions
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index 7bb141058d2..e93c796c970 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -12,7 +12,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         destination: Place<'tcx>,
         block: BasicBlock,
-        ast_block: &Block<'tcx>,
+        ast_block: &Block<'_, 'tcx>,
         source_info: SourceInfo,
     ) -> BlockAnd<()> {
         let Block {
@@ -56,8 +56,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         destination: Place<'tcx>,
         mut block: BasicBlock,
         span: Span,
-        stmts: &[Stmt<'tcx>],
-        expr: Option<&Expr<'tcx>>,
+        stmts: &[Stmt<'_, 'tcx>],
+        expr: Option<&Expr<'_, 'tcx>>,
         safety_mode: BlockSafety,
     ) -> BlockAnd<()> {
         let this = self;
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 1096d2eedfe..ce341c0c06c 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,7 @@ use rustc_middle::ty::CanonicalUserTypeAnnotation;
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Compile `expr`, yielding a compile-time constant. Assumes that
     /// `expr` is a valid compile-time constant!
-    crate fn as_constant(&mut self, expr: &Expr<'tcx>) -> Constant<'tcx> {
+    crate fn as_constant(&mut self, expr: &Expr<'_, 'tcx>) -> Constant<'tcx> {
         let this = self;
         let Expr { ty, temp_lifetime: _, span, kind } = expr;
         match kind {
diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
index 81428e09869..28262287b63 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
@@ -17,7 +17,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn as_local_operand(
         &mut self,
         block: BasicBlock,
-        expr: &Expr<'tcx>,
+        expr: &Expr<'_, 'tcx>,
     ) -> BlockAnd<Operand<'tcx>> {
         let local_scope = self.local_scope();
         self.as_operand(block, Some(local_scope), expr)
@@ -74,7 +74,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn as_local_call_operand(
         &mut self,
         block: BasicBlock,
-        expr: &Expr<'tcx>,
+        expr: &Expr<'_, 'tcx>,
     ) -> BlockAnd<Operand<'tcx>> {
         let local_scope = self.local_scope();
         self.as_call_operand(block, Some(local_scope), expr)
@@ -93,7 +93,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         mut block: BasicBlock,
         scope: Option<region::Scope>,
-        expr: &Expr<'tcx>,
+        expr: &Expr<'_, 'tcx>,
     ) -> BlockAnd<Operand<'tcx>> {
         debug!("as_operand(block={:?}, expr={:?})", block, expr);
         let this = self;
@@ -123,7 +123,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         mut block: BasicBlock,
         scope: Option<region::Scope>,
-        expr: &Expr<'tcx>,
+        expr: &Expr<'_, 'tcx>,
     ) -> BlockAnd<Operand<'tcx>> {
         debug!("as_call_operand(block={:?}, expr={:?})", block, expr);
         let this = self;
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index 3581ca1ee5b..30262e16420 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -350,7 +350,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn as_place(
         &mut self,
         mut block: BasicBlock,
-        expr: &Expr<'tcx>,
+        expr: &Expr<'_, 'tcx>,
     ) -> BlockAnd<Place<'tcx>> {
         let place_builder = unpack!(block = self.as_place_builder(block, expr));
         block.and(place_builder.into_place(self.tcx, self.typeck_results))
@@ -361,7 +361,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn as_place_builder(
         &mut self,
         block: BasicBlock,
-        expr: &Expr<'tcx>,
+        expr: &Expr<'_, 'tcx>,
     ) -> BlockAnd<PlaceBuilder<'tcx>> {
         self.expr_as_place(block, expr, Mutability::Mut, None)
     }
@@ -374,7 +374,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn as_read_only_place(
         &mut self,
         mut block: BasicBlock,
-        expr: &Expr<'tcx>,
+        expr: &Expr<'_, 'tcx>,
     ) -> BlockAnd<Place<'tcx>> {
         let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
         block.and(place_builder.into_place(self.tcx, self.typeck_results))
@@ -389,7 +389,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn as_read_only_place_builder(
         &mut self,
         block: BasicBlock,
-        expr: &Expr<'tcx>,
+        expr: &Expr<'_, 'tcx>,
     ) -> BlockAnd<PlaceBuilder<'tcx>> {
         self.expr_as_place(block, expr, Mutability::Not, None)
     }
@@ -397,7 +397,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn expr_as_place(
         &mut self,
         mut block: BasicBlock,
-        expr: &Expr<'tcx>,
+        expr: &Expr<'_, 'tcx>,
         mutability: Mutability,
         fake_borrow_temps: Option<&mut Vec<Local>>,
     ) -> BlockAnd<PlaceBuilder<'tcx>> {
@@ -584,8 +584,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn lower_index_expression(
         &mut self,
         mut block: BasicBlock,
-        base: &Expr<'tcx>,
-        index: &Expr<'tcx>,
+        base: &Expr<'_, 'tcx>,
+        index: &Expr<'_, 'tcx>,
         mutability: Mutability,
         fake_borrow_temps: Option<&mut Vec<Local>>,
         temp_lifetime: Option<region::Scope>,
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 89a179bd451..335ea4dca60 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -22,7 +22,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn as_local_rvalue(
         &mut self,
         block: BasicBlock,
-        expr: &Expr<'tcx>,
+        expr: &Expr<'_, 'tcx>,
     ) -> BlockAnd<Rvalue<'tcx>> {
         let local_scope = self.local_scope();
         self.as_rvalue(block, Some(local_scope), expr)
@@ -33,7 +33,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         mut block: BasicBlock,
         scope: Option<region::Scope>,
-        expr: &Expr<'tcx>,
+        expr: &Expr<'_, 'tcx>,
     ) -> BlockAnd<Rvalue<'tcx>> {
         debug!("expr_as_rvalue(block={:?}, scope={:?}, expr={:?})", block, scope, expr);
 
@@ -368,7 +368,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         upvar_ty: Ty<'tcx>,
         temp_lifetime: Option<region::Scope>,
         mut block: BasicBlock,
-        arg: &Expr<'tcx>,
+        arg: &Expr<'_, 'tcx>,
     ) -> BlockAnd<Operand<'tcx>> {
         let this = self;
 
diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
index 8b032032bfc..12029b04a08 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
@@ -14,7 +14,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         block: BasicBlock,
         temp_lifetime: Option<region::Scope>,
-        expr: &Expr<'tcx>,
+        expr: &Expr<'_, 'tcx>,
         mutability: Mutability,
     ) -> BlockAnd<Local> {
         // this is the only place in mir building that we need to truly need to worry about
@@ -27,7 +27,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         mut block: BasicBlock,
         temp_lifetime: Option<region::Scope>,
-        expr: &Expr<'tcx>,
+        expr: &Expr<'_, 'tcx>,
         mutability: Mutability,
     ) -> BlockAnd<Local> {
         debug!(
diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs
index 9320b5810e3..0cadfa2f0a1 100644
--- a/compiler/rustc_mir_build/src/build/expr/category.rs
+++ b/compiler/rustc_mir_build/src/build/expr/category.rs
@@ -31,7 +31,7 @@ crate enum RvalueFunc {
 /// Determines the category for a given expression. Note that scope
 /// and paren expressions have no category.
 impl Category {
-    crate fn of(ek: &ExprKind<'_>) -> Option<Category> {
+    crate fn of(ek: &ExprKind<'_, '_>) -> Option<Category> {
         match *ek {
             ExprKind::Scope { .. } => None,
 
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 83a09a00508..4baf26dce6a 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -18,7 +18,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         destination: Place<'tcx>,
         mut block: BasicBlock,
-        expr: &Expr<'tcx>,
+        expr: &Expr<'_, 'tcx>,
     ) -> BlockAnd<()> {
         debug!("expr_into_dest(destination={:?}, block={:?}, expr={:?})", destination, block, expr);
 
diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs
index 470a3eaaa3c..23e23f0885b 100644
--- a/compiler/rustc_mir_build/src/build/expr/stmt.rs
+++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs
@@ -13,7 +13,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn stmt_expr(
         &mut self,
         mut block: BasicBlock,
-        expr: &Expr<'tcx>,
+        expr: &Expr<'_, 'tcx>,
         statement_scope: Option<region::Scope>,
     ) -> BlockAnd<()> {
         let this = self;
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index d93fc6149c2..098ed8b3eb8 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -89,8 +89,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         destination: Place<'tcx>,
         span: Span,
         mut block: BasicBlock,
-        scrutinee: &Expr<'tcx>,
-        arms: &[Arm<'tcx>],
+        scrutinee: &Expr<'_, 'tcx>,
+        arms: &[Arm<'_, 'tcx>],
     ) -> BlockAnd<()> {
         let scrutinee_span = scrutinee.span;
         let scrutinee_place =
@@ -119,7 +119,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn lower_scrutinee(
         &mut self,
         mut block: BasicBlock,
-        scrutinee: &Expr<'tcx>,
+        scrutinee: &Expr<'_, 'tcx>,
         scrutinee_span: Span,
     ) -> BlockAnd<Place<'tcx>> {
         let scrutinee_place = unpack!(block = self.as_place(block, scrutinee));
@@ -149,8 +149,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn create_match_candidates<'pat>(
         &mut self,
         scrutinee: Place<'tcx>,
-        arms: &'pat [Arm<'tcx>],
-    ) -> Vec<(&'pat Arm<'tcx>, Candidate<'pat, 'tcx>)> {
+        arms: &'pat [Arm<'pat, 'tcx>],
+    ) -> Vec<(&'pat Arm<'pat, 'tcx>, Candidate<'pat, 'tcx>)> {
         // Assemble a list of candidates: there is one candidate per pattern,
         // which means there may be more than one candidate *per arm*.
         arms.iter()
@@ -224,7 +224,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         destination: Place<'tcx>,
         scrutinee_place: Place<'tcx>,
         scrutinee_span: Span,
-        arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>,
+        arm_candidates: Vec<(&'_ Arm<'_, 'tcx>, Candidate<'_, 'tcx>)>,
         outer_source_info: SourceInfo,
         fake_borrow_temps: Vec<(Place<'tcx>, Local)>,
     ) -> BlockAnd<()> {
@@ -285,7 +285,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         outer_source_info: SourceInfo,
         candidate: Candidate<'_, 'tcx>,
-        guard: Option<&Guard<'tcx>>,
+        guard: Option<&Guard<'_, 'tcx>>,
         fake_borrow_temps: &Vec<(Place<'tcx>, Local)>,
         scrutinee_span: Span,
         arm_span: Option<Span>,
@@ -361,7 +361,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         mut block: BasicBlock,
         irrefutable_pat: Pat<'tcx>,
-        initializer: &Expr<'tcx>,
+        initializer: &Expr<'_, 'tcx>,
     ) -> BlockAnd<()> {
         match *irrefutable_pat.kind {
             // Optimize the case of `let x = ...` to write directly into `x`
@@ -1612,7 +1612,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         candidate: Candidate<'pat, 'tcx>,
         parent_bindings: &[(Vec<Binding<'tcx>>, Vec<Ascription<'tcx>>)],
-        guard: Option<&Guard<'tcx>>,
+        guard: Option<&Guard<'_, 'tcx>>,
         fake_borrows: &Vec<(Place<'tcx>, Local)>,
         scrutinee_span: Span,
         arm_span: Option<Span>,
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index ecc5f2f260e..ef531a23921 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -1,7 +1,7 @@
 use crate::build;
 use crate::build::scope::DropKind;
-use crate::thir::cx::Cx;
-use crate::thir::{BindingMode, Expr, LintLevel, Pat, PatKind};
+use crate::thir::cx::build_thir;
+use crate::thir::{Arena, BindingMode, Expr, LintLevel, Pat, PatKind};
 use rustc_attr::{self as attr, UnwindAttr};
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
@@ -43,6 +43,7 @@ crate fn mir_built<'tcx>(
 fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
     let id = tcx.hir().local_def_id_to_hir_id(def.did);
     let body_owner_kind = tcx.hir().body_owner_kind(id);
+    let typeck_results = tcx.typeck_opt_const_arg(def);
 
     // Figure out what primary body this item has.
     let (body_id, return_ty_span, span_with_body) = match tcx.hir().get(id) {
@@ -87,15 +88,15 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
     // If we don't have a specialized span for the body, just use the
     // normal def span.
     let span_with_body = span_with_body.unwrap_or_else(|| tcx.hir().span(id));
+    let arena = Arena::default();
 
     tcx.infer_ctxt().enter(|infcx| {
-        let mut cx = Cx::new(tcx, def);
-        let body = if let Some(ErrorReported) = cx.typeck_results.tainted_by_errors {
+        let body = if let Some(ErrorReported) = typeck_results.tainted_by_errors {
             build::construct_error(&infcx, def, id, body_id, body_owner_kind)
         } else if body_owner_kind.is_fn_or_closure() {
             // fetch the fully liberated fn signature (that is, all bound
             // types/lifetimes replaced)
-            let fn_sig = cx.typeck_results.liberated_fn_sigs()[id];
+            let fn_sig = typeck_results.liberated_fn_sigs()[id];
             let fn_def_id = tcx.hir().local_def_id(id);
 
             let safety = match fn_sig.unsafety {
@@ -104,7 +105,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
             };
 
             let body = tcx.hir().body(body_id);
-            let expr = cx.mirror_expr(&body.value);
+            let thir = build_thir(tcx, def, &arena, &body.value);
             let ty = tcx.type_of(fn_def_id);
             let mut abi = fn_sig.abi;
             let implicit_argument = match ty.kind() {
@@ -189,7 +190,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
                 return_ty,
                 return_ty_span,
                 body,
-                expr,
+                thir,
                 span_with_body,
             );
             if yield_ty.is_some() {
@@ -209,12 +210,12 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
             // place to be the type of the constant because NLL typeck will
             // equate them.
 
-            let return_ty = cx.typeck_results.node_type(id);
+            let return_ty = typeck_results.node_type(id);
 
             let ast_expr = &tcx.hir().body(body_id).value;
-            let expr = cx.mirror_expr(ast_expr);
+            let thir = build_thir(tcx, def, &arena, ast_expr);
 
-            build::construct_const(&infcx, expr, def, id, return_ty, return_ty_span)
+            build::construct_const(&infcx, thir, def, id, return_ty, return_ty_span)
         };
 
         lints::check(tcx, &body);
@@ -601,7 +602,7 @@ fn construct_fn<'tcx, A>(
     return_ty: Ty<'tcx>,
     return_ty_span: Span,
     body: &'tcx hir::Body<'tcx>,
-    expr: Expr<'tcx>,
+    expr: &Expr<'_, 'tcx>,
     span_with_body: Span,
 ) -> Body<'tcx>
 where
@@ -668,7 +669,7 @@ where
 
 fn construct_const<'a, 'tcx>(
     infcx: &'a InferCtxt<'a, 'tcx>,
-    expr: Expr<'tcx>,
+    expr: &Expr<'_, 'tcx>,
     def: ty::WithOptConstParam<LocalDefId>,
     hir_id: hir::HirId,
     const_ty: Ty<'tcx>,
@@ -825,7 +826,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         fn_def_id: DefId,
         arguments: &[ArgInfo<'tcx>],
         argument_scope: region::Scope,
-        expr: &Expr<'tcx>,
+        expr: &Expr<'_, 'tcx>,
     ) -> BlockAnd<()> {
         // Allocate locals for the function arguments
         for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() {
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index 6c58528a3c5..b637b9b70bd 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -574,7 +574,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn break_scope(
         &mut self,
         mut block: BasicBlock,
-        value: Option<&Expr<'tcx>>,
+        value: Option<&Expr<'_, 'tcx>>,
         target: BreakableTarget,
         source_info: SourceInfo,
     ) -> BlockAnd<()> {
@@ -918,7 +918,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn test_bool(
         &mut self,
         mut block: BasicBlock,
-        condition: &Expr<'tcx>,
+        condition: &Expr<'_, 'tcx>,
         source_info: SourceInfo,
     ) -> (BasicBlock, BasicBlock) {
         let cond = unpack!(block = self.as_local_operand(block, condition));
diff --git a/compiler/rustc_mir_build/src/thir/arena.rs b/compiler/rustc_mir_build/src/thir/arena.rs
new file mode 100644
index 00000000000..aacc7b12a42
--- /dev/null
+++ b/compiler/rustc_mir_build/src/thir/arena.rs
@@ -0,0 +1,98 @@
+use crate::thir::*;
+
+macro_rules! declare_arena {
+    ([], [$($a:tt $name:ident: $ty:ty,)*]) => {
+        #[derive(Default)]
+        pub struct Arena<'thir, 'tcx> {
+            pub dropless: rustc_arena::DroplessArena,
+            drop: rustc_arena::DropArena,
+            $($name: rustc_arena::arena_for_type!($a[$ty]),)*
+        }
+
+        pub trait ArenaAllocatable<'thir, 'tcx, T = Self>: Sized {
+            fn allocate_on(self, arena: &'thir Arena<'thir, 'tcx>) -> &'thir mut Self;
+            fn allocate_from_iter(
+                arena: &'thir Arena<'thir, 'tcx>,
+                iter: impl ::std::iter::IntoIterator<Item = Self>,
+            ) -> &'thir mut [Self];
+        }
+
+        impl<'thir, 'tcx, T: Copy> ArenaAllocatable<'thir, 'tcx, ()> for T {
+            #[inline]
+            fn allocate_on(self, arena: &'thir Arena<'thir, 'tcx>) -> &'thir mut Self {
+                arena.dropless.alloc(self)
+            }
+            #[inline]
+            fn allocate_from_iter(
+                arena: &'thir Arena<'thir, 'tcx>,
+                iter: impl ::std::iter::IntoIterator<Item = Self>,
+            ) -> &'thir mut [Self] {
+                arena.dropless.alloc_from_iter(iter)
+            }
+
+        }
+        $(
+            impl<'thir, 'tcx> ArenaAllocatable<'thir, 'tcx, $ty> for $ty {
+                #[inline]
+                fn allocate_on(self, arena: &'thir Arena<'thir, 'tcx>) -> &'thir mut Self {
+                    if !::std::mem::needs_drop::<Self>() {
+                        return arena.dropless.alloc(self);
+                    }
+                    match rustc_arena::which_arena_for_type!($a[&arena.$name]) {
+                        ::std::option::Option::<&rustc_arena::TypedArena<Self>>::Some(ty_arena) => {
+                            ty_arena.alloc(self)
+                        }
+                        ::std::option::Option::None => unsafe { arena.drop.alloc(self) },
+                    }
+                }
+
+                #[inline]
+                fn allocate_from_iter(
+                    arena: &'thir Arena<'thir, 'tcx>,
+                    iter: impl ::std::iter::IntoIterator<Item = Self>,
+                ) -> &'thir mut [Self] {
+                    if !::std::mem::needs_drop::<Self>() {
+                        return arena.dropless.alloc_from_iter(iter);
+                    }
+                    match rustc_arena::which_arena_for_type!($a[&arena.$name]) {
+                        ::std::option::Option::<&rustc_arena::TypedArena<Self>>::Some(ty_arena) => {
+                            ty_arena.alloc_from_iter(iter)
+                        }
+                        ::std::option::Option::None => unsafe { arena.drop.alloc_from_iter(iter) },
+                    }
+                }
+            }
+        )*
+
+        impl<'thir, 'tcx> Arena<'thir, 'tcx> {
+            #[inline]
+            pub fn alloc<T: ArenaAllocatable<'thir, 'tcx, U>, U>(&'thir self, value: T) -> &'thir mut T {
+                value.allocate_on(self)
+            }
+
+            #[allow(dead_code)] // function is never used
+            #[inline]
+            pub fn alloc_slice<T: ::std::marker::Copy>(&'thir self, value: &[T]) -> &'thir mut [T] {
+                if value.is_empty() {
+                    return &mut [];
+                }
+                self.dropless.alloc_slice(value)
+            }
+
+            pub fn alloc_from_iter<T: ArenaAllocatable<'thir, 'tcx, U>, U>(
+                &'thir self,
+                iter: impl ::std::iter::IntoIterator<Item = T>,
+            ) -> &'thir mut [T] {
+                T::allocate_from_iter(self, iter)
+            }
+        }
+    }
+}
+
+declare_arena!([], [
+    [] arm: Arm<'thir, 'tcx>,
+    [] expr: Expr<'thir, 'tcx>,
+    [] field_expr: FieldExpr<'thir, 'tcx>,
+    [few] inline_asm_operand: InlineAsmOperand<'thir, 'tcx>,
+    [] stmt: Stmt<'thir, 'tcx>,
+]);
diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs
index 25af65d1c65..2ec102282c2 100644
--- a/compiler/rustc_mir_build/src/thir/cx/block.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/block.rs
@@ -7,8 +7,8 @@ use rustc_middle::ty;
 
 use rustc_index::vec::Idx;
 
-impl<'tcx> Cx<'tcx> {
-    crate fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block<'tcx> {
+impl<'thir, 'tcx> Cx<'thir, 'tcx> {
+    crate fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block<'thir, 'tcx> {
         // We have to eagerly lower the "spine" of the statements
         // in order to get the lexical scoping correctly.
         let stmts = self.mirror_stmts(block.hir_id.local_id, &*block.stmts);
@@ -23,7 +23,7 @@ impl<'tcx> Cx<'tcx> {
             opt_destruction_scope,
             span: block.span,
             stmts,
-            expr: block.expr.as_ref().map(|expr| self.mirror_expr_boxed(expr)),
+            expr: block.expr.as_ref().map(|expr| self.mirror_expr(expr)),
             safety_mode: match block.rules {
                 hir::BlockCheckMode::DefaultBlock => BlockSafety::Safe,
                 hir::BlockCheckMode::UnsafeBlock(..) => BlockSafety::ExplicitUnsafe(block.hir_id),
@@ -37,26 +37,21 @@ impl<'tcx> Cx<'tcx> {
         &mut self,
         block_id: hir::ItemLocalId,
         stmts: &'tcx [hir::Stmt<'tcx>],
-    ) -> Vec<Stmt<'tcx>> {
-        let mut result = vec![];
-        for (index, stmt) in stmts.iter().enumerate() {
+    ) -> &'thir [Stmt<'thir, 'tcx>] {
+        self.arena.alloc_from_iter(stmts.iter().enumerate().filter_map(|(index, stmt)| {
             let hir_id = stmt.hir_id;
             let opt_dxn_ext = self.region_scope_tree.opt_destruction_scope(hir_id.local_id);
             match stmt.kind {
-                hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => {
-                    result.push(Stmt {
-                        kind: StmtKind::Expr {
-                            scope: region::Scope {
-                                id: hir_id.local_id,
-                                data: region::ScopeData::Node,
-                            },
-                            expr: self.mirror_expr_boxed(expr),
-                        },
-                        opt_destruction_scope: opt_dxn_ext,
-                    })
-                }
+                hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => Some(Stmt {
+                    kind: StmtKind::Expr {
+                        scope: region::Scope { id: hir_id.local_id, data: region::ScopeData::Node },
+                        expr: self.mirror_expr(expr),
+                    },
+                    opt_destruction_scope: opt_dxn_ext,
+                }),
                 hir::StmtKind::Item(..) => {
                     // ignore for purposes of the MIR
+                    None
                 }
                 hir::StmtKind::Local(ref local) => {
                     let remainder_scope = region::Scope {
@@ -86,7 +81,7 @@ impl<'tcx> Cx<'tcx> {
                         }
                     }
 
-                    result.push(Stmt {
+                    Some(Stmt {
                         kind: StmtKind::Let {
                             remainder_scope,
                             init_scope: region::Scope {
@@ -94,14 +89,13 @@ impl<'tcx> Cx<'tcx> {
                                 data: region::ScopeData::Node,
                             },
                             pattern,
-                            initializer: local.init.map(|init| self.mirror_expr_boxed(init)),
+                            initializer: local.init.map(|init| self.mirror_expr(init)),
                             lint_level: LintLevel::Explicit(local.hir_id),
                         },
                         opt_destruction_scope: opt_dxn_ext,
-                    });
+                    })
                 }
             }
-        }
-        result
+        }))
     }
 }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 2d1170ca3a8..73ec9ac4dcf 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -15,8 +15,33 @@ use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
 use rustc_middle::ty::{self, AdtKind, Ty};
 use rustc_span::Span;
 
-impl<'tcx> Cx<'tcx> {
-    crate fn mirror_expr(&mut self, hir_expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> {
+use std::iter;
+
+impl<'thir, 'tcx> Cx<'thir, 'tcx> {
+    /// Mirrors and allocates a single [`hir::Expr`]. If you need to mirror a whole slice
+    /// of expressions, prefer using [`mirror_exprs`].
+    ///
+    /// [`mirror_exprs`]: Self::mirror_exprs
+    crate fn mirror_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> &'thir Expr<'thir, 'tcx> {
+        self.arena.alloc(self.mirror_expr_inner(expr))
+    }
+
+    /// Mirrors and allocates a slice of [`hir::Expr`]s. They will be allocated as a
+    /// contiguous sequence in memory.
+    crate fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> &'thir [Expr<'thir, 'tcx>] {
+        self.arena.alloc_from_iter(exprs.iter().map(|expr| self.mirror_expr_inner(expr)))
+    }
+
+    /// Mirrors a [`hir::Expr`] without allocating it into the arena.
+    /// This is a separate, private function so that [`mirror_expr`] and [`mirror_exprs`] can
+    /// decide how to allocate this expression (alone or within a slice).
+    ///
+    /// [`mirror_expr`]: Self::mirror_expr
+    /// [`mirror_exprs`]: Self::mirror_exprs
+    pub(super) fn mirror_expr_inner(
+        &mut self,
+        hir_expr: &'tcx hir::Expr<'tcx>,
+    ) -> Expr<'thir, 'tcx> {
         let temp_lifetime = self.region_scope_tree.temporary_scope(hir_expr.hir_id.local_id);
         let expr_scope =
             region::Scope { id: hir_expr.hir_id.local_id, data: region::ScopeData::Node };
@@ -38,7 +63,7 @@ impl<'tcx> Cx<'tcx> {
             span: hir_expr.span,
             kind: ExprKind::Scope {
                 region_scope: expr_scope,
-                value: Box::new(expr),
+                value: self.arena.alloc(expr),
                 lint_level: LintLevel::Explicit(hir_expr.hir_id),
             },
         };
@@ -53,7 +78,7 @@ impl<'tcx> Cx<'tcx> {
                 span: hir_expr.span,
                 kind: ExprKind::Scope {
                     region_scope,
-                    value: Box::new(expr),
+                    value: self.arena.alloc(expr),
                     lint_level: LintLevel::Inherited,
                 },
             };
@@ -63,20 +88,12 @@ impl<'tcx> Cx<'tcx> {
         expr
     }
 
-    crate fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> Vec<Expr<'tcx>> {
-        exprs.iter().map(|expr| self.mirror_expr(expr)).collect()
-    }
-
-    crate fn mirror_expr_boxed(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Box<Expr<'tcx>> {
-        Box::new(self.mirror_expr(expr))
-    }
-
     fn apply_adjustment(
         &mut self,
         hir_expr: &'tcx hir::Expr<'tcx>,
-        mut expr: Expr<'tcx>,
+        mut expr: Expr<'thir, 'tcx>,
         adjustment: &Adjustment<'tcx>,
-    ) -> Expr<'tcx> {
+    ) -> Expr<'thir, 'tcx> {
         let Expr { temp_lifetime, mut span, .. } = expr;
 
         // Adjust the span from the block, to the last expression of the
@@ -89,7 +106,7 @@ impl<'tcx> Cx<'tcx> {
         //      x
         //   // ^ error message points at this expression.
         // }
-        let mut adjust_span = |expr: &mut Expr<'tcx>| {
+        let mut adjust_span = |expr: &mut Expr<'thir, 'tcx>| {
             if let ExprKind::Block { body } = &expr.kind {
                 if let Some(ref last_expr) = body.expr {
                     span = last_expr.span;
@@ -101,13 +118,13 @@ impl<'tcx> Cx<'tcx> {
         let kind = match adjustment.kind {
             Adjust::Pointer(PointerCast::Unsize) => {
                 adjust_span(&mut expr);
-                ExprKind::Pointer { cast: PointerCast::Unsize, source: Box::new(expr) }
+                ExprKind::Pointer { cast: PointerCast::Unsize, source: self.arena.alloc(expr) }
             }
-            Adjust::Pointer(cast) => ExprKind::Pointer { cast, source: Box::new(expr) },
-            Adjust::NeverToAny => ExprKind::NeverToAny { source: Box::new(expr) },
+            Adjust::Pointer(cast) => ExprKind::Pointer { cast, source: self.arena.alloc(expr) },
+            Adjust::NeverToAny => ExprKind::NeverToAny { source: self.arena.alloc(expr) },
             Adjust::Deref(None) => {
                 adjust_span(&mut expr);
-                ExprKind::Deref { arg: Box::new(expr) }
+                ExprKind::Deref { arg: self.arena.alloc(expr) }
             }
             Adjust::Deref(Some(deref)) => {
                 // We don't need to do call adjust_span here since
@@ -122,7 +139,7 @@ impl<'tcx> Cx<'tcx> {
                     span,
                     kind: ExprKind::Borrow {
                         borrow_kind: deref.mutbl.to_borrow_kind(),
-                        arg: Box::new(expr),
+                        arg: self.arena.alloc(expr),
                     },
                 };
 
@@ -130,22 +147,22 @@ impl<'tcx> Cx<'tcx> {
                     hir_expr,
                     adjustment.target,
                     Some(call),
-                    vec![expr],
+                    self.arena.alloc_from_iter(iter::once(expr)),
                     deref.span,
                 )
             }
             Adjust::Borrow(AutoBorrow::Ref(_, m)) => {
-                ExprKind::Borrow { borrow_kind: m.to_borrow_kind(), arg: Box::new(expr) }
+                ExprKind::Borrow { borrow_kind: m.to_borrow_kind(), arg: self.arena.alloc(expr) }
             }
             Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => {
-                ExprKind::AddressOf { mutability, arg: Box::new(expr) }
+                ExprKind::AddressOf { mutability, arg: self.arena.alloc(expr) }
             }
         };
 
         Expr { temp_lifetime, ty: adjustment.target, span, kind }
     }
 
-    fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> {
+    fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'thir, 'tcx> {
         let expr_ty = self.typeck_results().expr_ty(expr);
         let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
 
@@ -157,7 +174,7 @@ impl<'tcx> Cx<'tcx> {
                 let args = self.mirror_exprs(args);
                 ExprKind::Call {
                     ty: expr.ty,
-                    fun: Box::new(expr),
+                    fun: self.arena.alloc(expr),
                     args,
                     from_hir_call: true,
                     fn_span,
@@ -185,8 +202,10 @@ impl<'tcx> Cx<'tcx> {
 
                     ExprKind::Call {
                         ty: method.ty,
-                        fun: Box::new(method),
-                        args: vec![self.mirror_expr(fun), tupled_args],
+                        fun: self.arena.alloc(method),
+                        args: &*self
+                            .arena
+                            .alloc_from_iter(vec![self.mirror_expr_inner(fun), tupled_args]),
                         from_hir_call: true,
                         fn_span: expr.span,
                     }
@@ -216,26 +235,22 @@ impl<'tcx> Cx<'tcx> {
                             });
                         debug!("make_mirror_unadjusted: (call) user_ty={:?}", user_ty);
 
-                        let field_refs = args
-                            .iter()
-                            .enumerate()
-                            .map(|(idx, e)| FieldExpr {
-                                name: Field::new(idx),
-                                expr: self.mirror_expr(e),
-                            })
-                            .collect();
+                        let field_refs =
+                            self.arena.alloc_from_iter(args.iter().enumerate().map(|(idx, e)| {
+                                FieldExpr { name: Field::new(idx), expr: self.mirror_expr(e) }
+                            }));
                         ExprKind::Adt {
                             adt_def,
                             substs,
                             variant_index: index,
-                            fields: field_refs,
+                            fields: &*field_refs,
                             user_ty,
                             base: None,
                         }
                     } else {
                         ExprKind::Call {
                             ty: self.typeck_results().node_type(fun.hir_id),
-                            fun: self.mirror_expr_boxed(fun),
+                            fun: self.mirror_expr(fun),
                             args: self.mirror_exprs(args),
                             from_hir_call: true,
                             fn_span: expr.span,
@@ -244,32 +259,30 @@ impl<'tcx> Cx<'tcx> {
                 }
             }
 
-            hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, ref arg) => ExprKind::Borrow {
-                borrow_kind: mutbl.to_borrow_kind(),
-                arg: self.mirror_expr_boxed(arg),
-            },
+            hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, ref arg) => {
+                ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg: self.mirror_expr(arg) }
+            }
 
             hir::ExprKind::AddrOf(hir::BorrowKind::Raw, mutability, ref arg) => {
-                ExprKind::AddressOf { mutability, arg: self.mirror_expr_boxed(arg) }
+                ExprKind::AddressOf { mutability, arg: self.mirror_expr(arg) }
             }
 
             hir::ExprKind::Block(ref blk, _) => ExprKind::Block { body: self.mirror_block(blk) },
 
-            hir::ExprKind::Assign(ref lhs, ref rhs, _) => ExprKind::Assign {
-                lhs: self.mirror_expr_boxed(lhs),
-                rhs: self.mirror_expr_boxed(rhs),
-            },
+            hir::ExprKind::Assign(ref lhs, ref rhs, _) => {
+                ExprKind::Assign { lhs: self.mirror_expr(lhs), rhs: self.mirror_expr(rhs) }
+            }
 
             hir::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
                 if self.typeck_results().is_method_call(expr) {
-                    let lhs = self.mirror_expr(lhs);
-                    let rhs = self.mirror_expr(rhs);
-                    self.overloaded_operator(expr, vec![lhs, rhs])
+                    let lhs = self.mirror_expr_inner(lhs);
+                    let rhs = self.mirror_expr_inner(rhs);
+                    self.overloaded_operator(expr, &*self.arena.alloc_from_iter(vec![lhs, rhs]))
                 } else {
                     ExprKind::AssignOp {
                         op: bin_op(op.node),
-                        lhs: self.mirror_expr_boxed(lhs),
-                        rhs: self.mirror_expr_boxed(rhs),
+                        lhs: self.mirror_expr(lhs),
+                        rhs: self.mirror_expr(rhs),
                     }
                 }
             }
@@ -282,29 +295,29 @@ impl<'tcx> Cx<'tcx> {
 
             hir::ExprKind::Binary(op, ref lhs, ref rhs) => {
                 if self.typeck_results().is_method_call(expr) {
-                    let lhs = self.mirror_expr(lhs);
-                    let rhs = self.mirror_expr(rhs);
-                    self.overloaded_operator(expr, vec![lhs, rhs])
+                    let lhs = self.mirror_expr_inner(lhs);
+                    let rhs = self.mirror_expr_inner(rhs);
+                    self.overloaded_operator(expr, &*self.arena.alloc_from_iter(vec![lhs, rhs]))
                 } else {
                     // FIXME overflow
                     match op.node {
                         hir::BinOpKind::And => ExprKind::LogicalOp {
                             op: LogicalOp::And,
-                            lhs: self.mirror_expr_boxed(lhs),
-                            rhs: self.mirror_expr_boxed(rhs),
+                            lhs: self.mirror_expr(lhs),
+                            rhs: self.mirror_expr(rhs),
                         },
                         hir::BinOpKind::Or => ExprKind::LogicalOp {
                             op: LogicalOp::Or,
-                            lhs: self.mirror_expr_boxed(lhs),
-                            rhs: self.mirror_expr_boxed(rhs),
+                            lhs: self.mirror_expr(lhs),
+                            rhs: self.mirror_expr(rhs),
                         },
 
                         _ => {
                             let op = bin_op(op.node);
                             ExprKind::Binary {
                                 op,
-                                lhs: self.mirror_expr_boxed(lhs),
-                                rhs: self.mirror_expr_boxed(rhs),
+                                lhs: self.mirror_expr(lhs),
+                                rhs: self.mirror_expr(rhs),
                             }
                         }
                     }
@@ -313,39 +326,48 @@ impl<'tcx> Cx<'tcx> {
 
             hir::ExprKind::Index(ref lhs, ref index) => {
                 if self.typeck_results().is_method_call(expr) {
-                    let lhs = self.mirror_expr(lhs);
-                    let index = self.mirror_expr(index);
-                    self.overloaded_place(expr, expr_ty, None, vec![lhs, index], expr.span)
+                    let lhs = self.mirror_expr_inner(lhs);
+                    let index = self.mirror_expr_inner(index);
+                    self.overloaded_place(
+                        expr,
+                        expr_ty,
+                        None,
+                        &*self.arena.alloc_from_iter(vec![lhs, index]),
+                        expr.span,
+                    )
                 } else {
-                    ExprKind::Index {
-                        lhs: self.mirror_expr_boxed(lhs),
-                        index: self.mirror_expr_boxed(index),
-                    }
+                    ExprKind::Index { lhs: self.mirror_expr(lhs), index: self.mirror_expr(index) }
                 }
             }
 
             hir::ExprKind::Unary(hir::UnOp::Deref, ref arg) => {
                 if self.typeck_results().is_method_call(expr) {
-                    let arg = self.mirror_expr(arg);
-                    self.overloaded_place(expr, expr_ty, None, vec![arg], expr.span)
+                    let arg = self.mirror_expr_inner(arg);
+                    self.overloaded_place(
+                        expr,
+                        expr_ty,
+                        None,
+                        &*self.arena.alloc_from_iter(iter::once(arg)),
+                        expr.span,
+                    )
                 } else {
-                    ExprKind::Deref { arg: self.mirror_expr_boxed(arg) }
+                    ExprKind::Deref { arg: self.mirror_expr(arg) }
                 }
             }
 
             hir::ExprKind::Unary(hir::UnOp::Not, ref arg) => {
                 if self.typeck_results().is_method_call(expr) {
-                    let arg = self.mirror_expr(arg);
-                    self.overloaded_operator(expr, vec![arg])
+                    let arg = self.mirror_expr_inner(arg);
+                    self.overloaded_operator(expr, &*self.arena.alloc_from_iter(iter::once(arg)))
                 } else {
-                    ExprKind::Unary { op: UnOp::Not, arg: self.mirror_expr_boxed(arg) }
+                    ExprKind::Unary { op: UnOp::Not, arg: self.mirror_expr(arg) }
                 }
             }
 
             hir::ExprKind::Unary(hir::UnOp::Neg, ref arg) => {
                 if self.typeck_results().is_method_call(expr) {
-                    let arg = self.mirror_expr(arg);
-                    self.overloaded_operator(expr, vec![arg])
+                    let arg = self.mirror_expr_inner(arg);
+                    self.overloaded_operator(expr, &*self.arena.alloc_from_iter(iter::once(arg)))
                 } else if let hir::ExprKind::Lit(ref lit) = arg.kind {
                     ExprKind::Literal {
                         literal: self.const_eval_literal(&lit.node, expr_ty, lit.span, true),
@@ -353,7 +375,7 @@ impl<'tcx> Cx<'tcx> {
                         const_id: None,
                     }
                 } else {
-                    ExprKind::Unary { op: UnOp::Neg, arg: self.mirror_expr_boxed(arg) }
+                    ExprKind::Unary { op: UnOp::Neg, arg: self.mirror_expr(arg) }
                 }
             }
 
@@ -370,9 +392,12 @@ impl<'tcx> Cx<'tcx> {
                             user_ty,
                             fields: self.field_refs(fields),
                             base: base.as_ref().map(|base| FruInfo {
-                                base: self.mirror_expr_boxed(base),
-                                field_types: self.typeck_results().fru_field_types()[expr.hir_id]
-                                    .clone(),
+                                base: self.mirror_expr(base),
+                                field_types: self.arena.alloc_from_iter(
+                                    self.typeck_results().fru_field_types()[expr.hir_id]
+                                        .iter()
+                                        .cloned(),
+                                ),
                             }),
                         }
                     }
@@ -419,12 +444,12 @@ impl<'tcx> Cx<'tcx> {
                     }
                 };
 
-                let upvars = self
-                    .typeck_results
-                    .closure_min_captures_flattened(def_id)
-                    .zip(substs.upvar_tys())
-                    .map(|(captured_place, ty)| self.capture_upvar(expr, captured_place, ty))
-                    .collect();
+                let upvars = self.arena.alloc_from_iter(
+                    self.typeck_results
+                        .closure_min_captures_flattened(def_id)
+                        .zip(substs.upvar_tys())
+                        .map(|(captured_place, ty)| self.capture_upvar(expr, captured_place, ty)),
+                );
                 ExprKind::Closure { closure_id: def_id, substs, upvars, movability }
             }
 
@@ -435,100 +460,95 @@ impl<'tcx> Cx<'tcx> {
 
             hir::ExprKind::InlineAsm(ref asm) => ExprKind::InlineAsm {
                 template: asm.template,
-                operands: asm
-                    .operands
-                    .iter()
-                    .map(|(op, _op_sp)| {
-                        match *op {
-                            hir::InlineAsmOperand::In { reg, ref expr } => {
-                                InlineAsmOperand::In { reg, expr: self.mirror_expr(expr) }
-                            }
-                            hir::InlineAsmOperand::Out { reg, late, ref expr } => {
-                                InlineAsmOperand::Out {
-                                    reg,
-                                    late,
-                                    expr: expr.as_ref().map(|expr| self.mirror_expr(expr)),
-                                }
-                            }
-                            hir::InlineAsmOperand::InOut { reg, late, ref expr } => {
-                                InlineAsmOperand::InOut { reg, late, expr: self.mirror_expr(expr) }
-                            }
-                            hir::InlineAsmOperand::SplitInOut {
-                                reg,
-                                late,
-                                ref in_expr,
-                                ref out_expr,
-                            } => InlineAsmOperand::SplitInOut {
+                operands: self.arena.alloc_from_iter(asm.operands.iter().map(|(op, _op_sp)| {
+                    match *op {
+                        hir::InlineAsmOperand::In { reg, ref expr } => {
+                            InlineAsmOperand::In { reg, expr: self.mirror_expr(expr) }
+                        }
+                        hir::InlineAsmOperand::Out { reg, late, ref expr } => {
+                            InlineAsmOperand::Out {
                                 reg,
                                 late,
-                                in_expr: self.mirror_expr(in_expr),
-                                out_expr: out_expr.as_ref().map(|expr| self.mirror_expr(expr)),
-                            },
-                            hir::InlineAsmOperand::Const { ref expr } => {
-                                InlineAsmOperand::Const { expr: self.mirror_expr(expr) }
+                                expr: expr.as_ref().map(|expr| self.mirror_expr(expr)),
                             }
-                            hir::InlineAsmOperand::Sym { ref expr } => {
-                                let qpath = match expr.kind {
-                                    hir::ExprKind::Path(ref qpath) => qpath,
-                                    _ => span_bug!(
-                                        expr.span,
-                                        "asm `sym` operand should be a path, found {:?}",
-                                        expr.kind
-                                    ),
-                                };
-                                let temp_lifetime =
-                                    self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
-                                let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
-                                let ty;
-                                match res {
-                                    Res::Def(DefKind::Fn, _) | Res::Def(DefKind::AssocFn, _) => {
-                                        ty = self.typeck_results().node_type(expr.hir_id);
-                                        let user_ty =
-                                            self.user_substs_applied_to_res(expr.hir_id, res);
-                                        InlineAsmOperand::SymFn {
-                                            expr: Expr {
-                                                ty,
-                                                temp_lifetime,
-                                                span: expr.span,
-                                                kind: ExprKind::Literal {
-                                                    literal: ty::Const::zero_sized(self.tcx, ty),
-                                                    user_ty,
-                                                    const_id: None,
-                                                },
+                        }
+                        hir::InlineAsmOperand::InOut { reg, late, ref expr } => {
+                            InlineAsmOperand::InOut { reg, late, expr: self.mirror_expr(expr) }
+                        }
+                        hir::InlineAsmOperand::SplitInOut {
+                            reg,
+                            late,
+                            ref in_expr,
+                            ref out_expr,
+                        } => InlineAsmOperand::SplitInOut {
+                            reg,
+                            late,
+                            in_expr: self.mirror_expr(in_expr),
+                            out_expr: out_expr.as_ref().map(|expr| self.mirror_expr(expr)),
+                        },
+                        hir::InlineAsmOperand::Const { ref expr } => {
+                            InlineAsmOperand::Const { expr: self.mirror_expr(expr) }
+                        }
+                        hir::InlineAsmOperand::Sym { ref expr } => {
+                            let qpath = match expr.kind {
+                                hir::ExprKind::Path(ref qpath) => qpath,
+                                _ => span_bug!(
+                                    expr.span,
+                                    "asm `sym` operand should be a path, found {:?}",
+                                    expr.kind
+                                ),
+                            };
+                            let temp_lifetime =
+                                self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+                            let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
+                            let ty;
+                            match res {
+                                Res::Def(DefKind::Fn, _) | Res::Def(DefKind::AssocFn, _) => {
+                                    ty = self.typeck_results().node_type(expr.hir_id);
+                                    let user_ty = self.user_substs_applied_to_res(expr.hir_id, res);
+                                    InlineAsmOperand::SymFn {
+                                        expr: self.arena.alloc(Expr {
+                                            ty,
+                                            temp_lifetime,
+                                            span: expr.span,
+                                            kind: ExprKind::Literal {
+                                                literal: ty::Const::zero_sized(self.tcx, ty),
+                                                user_ty,
+                                                const_id: None,
                                             },
-                                        }
+                                        }),
                                     }
+                                }
 
-                                    Res::Def(DefKind::Static, def_id) => {
-                                        InlineAsmOperand::SymStatic { def_id }
-                                    }
+                                Res::Def(DefKind::Static, def_id) => {
+                                    InlineAsmOperand::SymStatic { def_id }
+                                }
 
-                                    _ => {
-                                        self.tcx.sess.span_err(
-                                            expr.span,
-                                            "asm `sym` operand must point to a fn or static",
-                                        );
-
-                                        // Not a real fn, but we're not reaching codegen anyways...
-                                        ty = self.tcx.ty_error();
-                                        InlineAsmOperand::SymFn {
-                                            expr: Expr {
-                                                ty,
-                                                temp_lifetime,
-                                                span: expr.span,
-                                                kind: ExprKind::Literal {
-                                                    literal: ty::Const::zero_sized(self.tcx, ty),
-                                                    user_ty: None,
-                                                    const_id: None,
-                                                },
+                                _ => {
+                                    self.tcx.sess.span_err(
+                                        expr.span,
+                                        "asm `sym` operand must point to a fn or static",
+                                    );
+
+                                    // Not a real fn, but we're not reaching codegen anyways...
+                                    ty = self.tcx.ty_error();
+                                    InlineAsmOperand::SymFn {
+                                        expr: self.arena.alloc(Expr {
+                                            ty,
+                                            temp_lifetime,
+                                            span: expr.span,
+                                            kind: ExprKind::Literal {
+                                                literal: ty::Const::zero_sized(self.tcx, ty),
+                                                user_ty: None,
+                                                const_id: None,
                                             },
-                                        }
+                                        }),
                                     }
                                 }
                             }
                         }
-                    })
-                    .collect(),
+                    }
+                })),
                 options: asm.options,
                 line_spans: asm.line_spans,
             },
@@ -550,15 +570,15 @@ impl<'tcx> Cx<'tcx> {
                 let count_def_id = self.tcx.hir().local_def_id(count.hir_id);
                 let count = ty::Const::from_anon_const(self.tcx, count_def_id);
 
-                ExprKind::Repeat { value: self.mirror_expr_boxed(v), count }
+                ExprKind::Repeat { value: self.mirror_expr(v), count }
             }
             hir::ExprKind::Ret(ref v) => {
-                ExprKind::Return { value: v.as_ref().map(|v| self.mirror_expr_boxed(v)) }
+                ExprKind::Return { value: v.as_ref().map(|v| self.mirror_expr(v)) }
             }
             hir::ExprKind::Break(dest, ref value) => match dest.target_id {
                 Ok(target_id) => ExprKind::Break {
                     label: region::Scope { id: target_id.local_id, data: region::ScopeData::Node },
-                    value: value.as_ref().map(|value| self.mirror_expr_boxed(value)),
+                    value: value.as_ref().map(|value| self.mirror_expr(value)),
                 },
                 Err(err) => bug!("invalid loop id for break: {}", err),
             },
@@ -569,19 +589,19 @@ impl<'tcx> Cx<'tcx> {
                 Err(err) => bug!("invalid loop id for continue: {}", err),
             },
             hir::ExprKind::If(cond, then, else_opt) => ExprKind::If {
-                cond: self.mirror_expr_boxed(cond),
-                then: self.mirror_expr_boxed(then),
-                else_opt: else_opt.map(|el| self.mirror_expr_boxed(el)),
+                cond: self.mirror_expr(cond),
+                then: self.mirror_expr(then),
+                else_opt: else_opt.map(|el| self.mirror_expr(el)),
             },
             hir::ExprKind::Match(ref discr, ref arms, _) => ExprKind::Match {
-                scrutinee: self.mirror_expr_boxed(discr),
-                arms: arms.iter().map(|a| self.convert_arm(a)).collect(),
+                scrutinee: self.mirror_expr(discr),
+                arms: self.arena.alloc_from_iter(arms.iter().map(|a| self.convert_arm(a))),
             },
             hir::ExprKind::Loop(ref body, ..) => {
                 let block_ty = self.typeck_results().node_type(body.hir_id);
                 let temp_lifetime = self.region_scope_tree.temporary_scope(body.hir_id.local_id);
                 let block = self.mirror_block(body);
-                let body = Box::new(Expr {
+                let body = self.arena.alloc(Expr {
                     ty: block_ty,
                     temp_lifetime,
                     span: block.span,
@@ -590,7 +610,7 @@ impl<'tcx> Cx<'tcx> {
                 ExprKind::Loop { body }
             }
             hir::ExprKind::Field(ref source, ..) => ExprKind::Field {
-                lhs: self.mirror_expr_boxed(source),
+                lhs: self.mirror_expr(source),
                 name: Field::new(self.tcx.field_index(expr.hir_id, self.typeck_results)),
             },
             hir::ExprKind::Cast(ref source, ref cast_ty) => {
@@ -607,13 +627,13 @@ impl<'tcx> Cx<'tcx> {
                 // using a coercion (or is a no-op).
                 let cast = if self.typeck_results().is_coercion_cast(source.hir_id) {
                     // Convert the lexpr to a vexpr.
-                    ExprKind::Use { source: self.mirror_expr_boxed(source) }
+                    ExprKind::Use { source: self.mirror_expr(source) }
                 } else if self.typeck_results().expr_ty(source).is_region_ptr() {
                     // Special cased so that we can type check that the element
                     // type of the source matches the pointed to type of the
                     // destination.
                     ExprKind::Pointer {
-                        source: self.mirror_expr_boxed(source),
+                        source: self.mirror_expr(source),
                         cast: PointerCast::ArrayToPointer,
                     }
                 } else {
@@ -651,11 +671,13 @@ impl<'tcx> Cx<'tcx> {
                     };
 
                     let source = if let Some((did, offset, var_ty)) = var {
-                        let mk_const = |literal| Expr {
-                            temp_lifetime,
-                            ty: var_ty,
-                            span: expr.span,
-                            kind: ExprKind::Literal { literal, user_ty: None, const_id: None },
+                        let mk_const = |literal| {
+                            self.arena.alloc(Expr {
+                                temp_lifetime,
+                                ty: var_ty,
+                                span: expr.span,
+                                kind: ExprKind::Literal { literal, user_ty: None, const_id: None },
+                            })
                         };
                         let offset = mk_const(ty::Const::from_bits(
                             self.tcx,
@@ -675,12 +697,14 @@ impl<'tcx> Cx<'tcx> {
                                     ),
                                     ty: var_ty,
                                 }));
-                                let bin = ExprKind::Binary {
-                                    op: BinOp::Add,
-                                    lhs: Box::new(lhs),
-                                    rhs: Box::new(offset),
-                                };
-                                Expr { temp_lifetime, ty: var_ty, span: expr.span, kind: bin }
+                                let bin =
+                                    ExprKind::Binary { op: BinOp::Add, lhs: lhs, rhs: offset };
+                                self.arena.alloc(Expr {
+                                    temp_lifetime,
+                                    ty: var_ty,
+                                    span: expr.span,
+                                    kind: bin,
+                                })
                             }
                             None => offset,
                         }
@@ -688,14 +712,18 @@ impl<'tcx> Cx<'tcx> {
                         self.mirror_expr(source)
                     };
 
-                    ExprKind::Cast { source: Box::new(source) }
+                    ExprKind::Cast { source: source }
                 };
 
                 if let Some(user_ty) = user_ty {
                     // NOTE: Creating a new Expr and wrapping a Cast inside of it may be
                     //       inefficient, revisit this when performance becomes an issue.
-                    let cast_expr =
-                        Box::new(Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind: cast });
+                    let cast_expr = self.arena.alloc(Expr {
+                        temp_lifetime,
+                        ty: expr_ty,
+                        span: expr.span,
+                        kind: cast,
+                    });
                     debug!("make_mirror_unadjusted: (cast) user_ty={:?}", user_ty);
 
                     ExprKind::ValueTypeAscription { source: cast_expr, user_ty: Some(*user_ty) }
@@ -707,7 +735,7 @@ impl<'tcx> Cx<'tcx> {
                 let user_provided_types = self.typeck_results.user_provided_types();
                 let user_ty = user_provided_types.get(ty.hir_id).copied();
                 debug!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty);
-                let mirrored = self.mirror_expr_boxed(source);
+                let mirrored = self.mirror_expr(source);
                 if source.is_syntactic_place_expr() {
                     ExprKind::PlaceTypeAscription { source: mirrored, user_ty }
                 } else {
@@ -715,17 +743,15 @@ impl<'tcx> Cx<'tcx> {
                 }
             }
             hir::ExprKind::DropTemps(ref source) => {
-                ExprKind::Use { source: self.mirror_expr_boxed(source) }
+                ExprKind::Use { source: self.mirror_expr(source) }
             }
-            hir::ExprKind::Box(ref value) => ExprKind::Box { value: self.mirror_expr_boxed(value) },
-            hir::ExprKind::Array(ref fields) => ExprKind::Array {
-                fields: fields.iter().map(|field| self.mirror_expr(field)).collect(),
-            },
-            hir::ExprKind::Tup(ref fields) => ExprKind::Tuple {
-                fields: fields.iter().map(|field| self.mirror_expr(field)).collect(),
-            },
+            hir::ExprKind::Box(ref value) => ExprKind::Box { value: self.mirror_expr(value) },
+            hir::ExprKind::Array(ref fields) => {
+                ExprKind::Array { fields: self.mirror_exprs(fields) }
+            }
+            hir::ExprKind::Tup(ref fields) => ExprKind::Tuple { fields: self.mirror_exprs(fields) },
 
-            hir::ExprKind::Yield(ref v, _) => ExprKind::Yield { value: self.mirror_expr_boxed(v) },
+            hir::ExprKind::Yield(ref v, _) => ExprKind::Yield { value: self.mirror_expr(v) },
             hir::ExprKind::Err => unreachable!(),
         };
 
@@ -772,7 +798,7 @@ impl<'tcx> Cx<'tcx> {
         expr: &hir::Expr<'_>,
         span: Span,
         overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
-    ) -> Expr<'tcx> {
+    ) -> Expr<'thir, 'tcx> {
         let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
         let (def_id, substs, user_ty) = match overloaded_callee {
             Some((def_id, substs)) => (def_id, substs, None),
@@ -799,13 +825,13 @@ impl<'tcx> Cx<'tcx> {
         }
     }
 
-    fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> Arm<'tcx> {
+    fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> Arm<'thir, 'tcx> {
         Arm {
             pattern: self.pattern_from_hir(&arm.pat),
             guard: arm.guard.as_ref().map(|g| match g {
-                hir::Guard::If(ref e) => Guard::If(self.mirror_expr_boxed(e)),
+                hir::Guard::If(ref e) => Guard::If(self.mirror_expr(e)),
                 hir::Guard::IfLet(ref pat, ref e) => {
-                    Guard::IfLet(self.pattern_from_hir(pat), self.mirror_expr_boxed(e))
+                    Guard::IfLet(self.pattern_from_hir(pat), self.mirror_expr(e))
                 }
             }),
             body: self.mirror_expr(arm.body),
@@ -815,7 +841,11 @@ impl<'tcx> Cx<'tcx> {
         }
     }
 
-    fn convert_path_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, res: Res) -> ExprKind<'tcx> {
+    fn convert_path_expr(
+        &mut self,
+        expr: &'tcx hir::Expr<'tcx>,
+        res: Res,
+    ) -> ExprKind<'thir, 'tcx> {
         let substs = self.typeck_results().node_substs(expr.hir_id);
         match res {
             // A regular function, constructor function or a constant.
@@ -883,7 +913,7 @@ impl<'tcx> Cx<'tcx> {
                         variant_index: adt_def.variant_index_with_ctor_id(def_id),
                         substs,
                         user_ty: user_provided_type,
-                        fields: vec![],
+                        fields: self.arena.alloc_from_iter(iter::empty()),
                         base: None,
                     },
                     _ => bug!("unexpected ty: {:?}", ty),
@@ -904,7 +934,9 @@ impl<'tcx> Cx<'tcx> {
                         def_id: id,
                     }
                 };
-                ExprKind::Deref { arg: Box::new(Expr { ty, temp_lifetime, span: expr.span, kind }) }
+                ExprKind::Deref {
+                    arg: self.arena.alloc(Expr { ty, temp_lifetime, span: expr.span, kind }),
+                }
             }
 
             Res::Local(var_hir_id) => self.convert_var(var_hir_id),
@@ -913,7 +945,7 @@ impl<'tcx> Cx<'tcx> {
         }
     }
 
-    fn convert_var(&mut self, var_hir_id: hir::HirId) -> ExprKind<'tcx> {
+    fn convert_var(&mut self, var_hir_id: hir::HirId) -> ExprKind<'thir, 'tcx> {
         // We want upvars here not captures.
         // Captures will be handled in MIR.
         let is_upvar = self
@@ -936,9 +968,9 @@ impl<'tcx> Cx<'tcx> {
     fn overloaded_operator(
         &mut self,
         expr: &'tcx hir::Expr<'tcx>,
-        args: Vec<Expr<'tcx>>,
-    ) -> ExprKind<'tcx> {
-        let fun = Box::new(self.method_callee(expr, expr.span, None));
+        args: &'thir [Expr<'thir, 'tcx>],
+    ) -> ExprKind<'thir, 'tcx> {
+        let fun = self.arena.alloc(self.method_callee(expr, expr.span, None));
         ExprKind::Call { ty: fun.ty, fun, args, from_hir_call: false, fn_span: expr.span }
     }
 
@@ -947,9 +979,9 @@ impl<'tcx> Cx<'tcx> {
         expr: &'tcx hir::Expr<'tcx>,
         place_ty: Ty<'tcx>,
         overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
-        args: Vec<Expr<'tcx>>,
+        args: &'thir [Expr<'thir, 'tcx>],
         span: Span,
-    ) -> ExprKind<'tcx> {
+    ) -> ExprKind<'thir, 'tcx> {
         // For an overloaded *x or x[y] expression of type T, the method
         // call returns an &T and we must add the deref so that the types
         // line up (this is because `*x` and `x[y]` represent places):
@@ -966,8 +998,8 @@ impl<'tcx> Cx<'tcx> {
         // construct the complete expression `foo()` for the overloaded call,
         // which will yield the &T type
         let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
-        let fun = Box::new(self.method_callee(expr, span, overloaded_callee));
-        let ref_expr = Box::new(Expr {
+        let fun = self.arena.alloc(self.method_callee(expr, span, overloaded_callee));
+        let ref_expr = self.arena.alloc(Expr {
             temp_lifetime,
             ty: ref_ty,
             span,
@@ -983,7 +1015,7 @@ impl<'tcx> Cx<'tcx> {
         closure_expr: &'tcx hir::Expr<'tcx>,
         captured_place: &'tcx ty::CapturedPlace<'tcx>,
         upvar_ty: Ty<'tcx>,
-    ) -> Expr<'tcx> {
+    ) -> Expr<'thir, 'tcx> {
         let upvar_capture = captured_place.info.capture_kind;
         let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
         let var_ty = captured_place.place.base_ty;
@@ -1007,12 +1039,14 @@ impl<'tcx> Cx<'tcx> {
 
         for proj in captured_place.place.projections.iter() {
             let kind = match proj.kind {
-                HirProjectionKind::Deref => ExprKind::Deref { arg: Box::new(captured_place_expr) },
+                HirProjectionKind::Deref => {
+                    ExprKind::Deref { arg: self.arena.alloc(captured_place_expr) }
+                }
                 HirProjectionKind::Field(field, ..) => {
                     // Variant index will always be 0, because for multi-variant
                     // enums, we capture the enum entirely.
                     ExprKind::Field {
-                        lhs: Box::new(captured_place_expr),
+                        lhs: self.arena.alloc(captured_place_expr),
                         name: Field::new(field as usize),
                     }
                 }
@@ -1038,21 +1072,21 @@ impl<'tcx> Cx<'tcx> {
                     temp_lifetime,
                     ty: upvar_ty,
                     span: closure_expr.span,
-                    kind: ExprKind::Borrow { borrow_kind, arg: Box::new(captured_place_expr) },
+                    kind: ExprKind::Borrow {
+                        borrow_kind,
+                        arg: self.arena.alloc(captured_place_expr),
+                    },
                 }
             }
         }
     }
 
     /// Converts a list of named fields (i.e., for struct-like struct/enum ADTs) into FieldExpr.
-    fn field_refs(&mut self, fields: &'tcx [hir::Field<'tcx>]) -> Vec<FieldExpr<'tcx>> {
-        fields
-            .iter()
-            .map(|field| FieldExpr {
-                name: Field::new(self.tcx.field_index(field.hir_id, self.typeck_results)),
-                expr: self.mirror_expr(field.expr),
-            })
-            .collect()
+    fn field_refs(&mut self, fields: &'tcx [hir::Field<'tcx>]) -> &'thir [FieldExpr<'thir, 'tcx>] {
+        self.arena.alloc_from_iter(fields.iter().map(|field| FieldExpr {
+            name: Field::new(self.tcx.field_index(field.hir_id, self.typeck_results)),
+            expr: self.mirror_expr(field.expr),
+        }))
     }
 }
 
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index c00e9ff8dd9..66c11ea9528 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -2,6 +2,7 @@
 //! structures into the THIR. The `builder` is generally ignorant of the tcx,
 //! etc., and instead goes through the `Cx` for most of its work.
 
+use crate::thir::arena::Arena;
 use crate::thir::util::UserAnnotatedTyHelpers;
 use crate::thir::*;
 
@@ -13,9 +14,18 @@ use rustc_middle::middle::region;
 use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
-#[derive(Clone)]
-crate struct Cx<'tcx> {
+crate fn build_thir<'thir, 'tcx>(
     tcx: TyCtxt<'tcx>,
+    owner_def: ty::WithOptConstParam<LocalDefId>,
+    arena: &'thir Arena<'thir, 'tcx>,
+    expr: &'tcx hir::Expr<'tcx>,
+) -> &'thir Expr<'thir, 'tcx> {
+    Cx::new(tcx, owner_def, &arena).mirror_expr(expr)
+}
+
+struct Cx<'thir, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    arena: &'thir Arena<'thir, 'tcx>,
 
     crate param_env: ty::ParamEnv<'tcx>,
 
@@ -26,20 +36,23 @@ crate struct Cx<'tcx> {
     body_owner: DefId,
 }
 
-impl<'tcx> Cx<'tcx> {
-    crate fn new(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) -> Cx<'tcx> {
+impl<'thir, 'tcx> Cx<'thir, 'tcx> {
+    fn new(
+        tcx: TyCtxt<'tcx>,
+        def: ty::WithOptConstParam<LocalDefId>,
+        arena: &'thir Arena<'thir, 'tcx>,
+    ) -> Cx<'thir, 'tcx> {
         let typeck_results = tcx.typeck_opt_const_arg(def);
         Cx {
             tcx,
+            arena,
             param_env: tcx.param_env(def.did),
             region_scope_tree: tcx.region_scope_tree(def.did),
             typeck_results,
             body_owner: def.did.to_def_id(),
         }
     }
-}
 
-impl<'tcx> Cx<'tcx> {
     crate fn const_eval_literal(
         &mut self,
         lit: &'tcx ast::LitKind,
@@ -74,7 +87,7 @@ impl<'tcx> Cx<'tcx> {
     }
 }
 
-impl<'tcx> UserAnnotatedTyHelpers<'tcx> for Cx<'tcx> {
+impl<'tcx> UserAnnotatedTyHelpers<'tcx> for Cx<'_, 'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs
index 6e7094307b1..27a7e99951c 100644
--- a/compiler/rustc_mir_build/src/thir/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/mod.rs
@@ -24,6 +24,9 @@ crate mod pattern;
 crate use self::pattern::PatTyProj;
 crate use self::pattern::{BindingMode, FieldPat, Pat, PatKind, PatRange};
 
+mod arena;
+crate use arena::Arena;
+
 mod util;
 
 #[derive(Copy, Clone, Debug)]
@@ -33,13 +36,13 @@ crate enum LintLevel {
 }
 
 #[derive(Debug)]
-crate struct Block<'tcx> {
+crate struct Block<'thir, 'tcx> {
     crate targeted_by_break: bool,
     crate region_scope: region::Scope,
     crate opt_destruction_scope: Option<region::Scope>,
     crate span: Span,
-    crate stmts: Vec<Stmt<'tcx>>,
-    crate expr: Option<Box<Expr<'tcx>>>,
+    crate stmts: &'thir [Stmt<'thir, 'tcx>],
+    crate expr: Option<&'thir Expr<'thir, 'tcx>>,
     crate safety_mode: BlockSafety,
 }
 
@@ -52,19 +55,19 @@ crate enum BlockSafety {
 }
 
 #[derive(Debug)]
-crate struct Stmt<'tcx> {
-    crate kind: StmtKind<'tcx>,
+crate struct Stmt<'thir, 'tcx> {
+    crate kind: StmtKind<'thir, 'tcx>,
     crate opt_destruction_scope: Option<region::Scope>,
 }
 
 #[derive(Debug)]
-crate enum StmtKind<'tcx> {
+crate enum StmtKind<'thir, 'tcx> {
     Expr {
         /// scope for this statement; may be used as lifetime of temporaries
         scope: region::Scope,
 
         /// expression being evaluated in this statement
-        expr: Box<Expr<'tcx>>,
+        expr: &'thir Expr<'thir, 'tcx>,
     },
 
     Let {
@@ -82,7 +85,7 @@ crate enum StmtKind<'tcx> {
         pattern: Pat<'tcx>,
 
         /// let pat: ty = <INIT> ...
-        initializer: Option<Box<Expr<'tcx>>>,
+        initializer: Option<&'thir Expr<'thir, 'tcx>>,
 
         /// the lint level for this let-statement
         lint_level: LintLevel,
@@ -91,12 +94,12 @@ crate enum StmtKind<'tcx> {
 
 // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Expr<'_>, 160);
+rustc_data_structures::static_assert_size!(Expr<'_, '_>, 144);
 
 /// The Thir trait implementor lowers their expressions (`&'tcx H::Expr`)
 /// into instances of this `Expr` enum. This lowering can be done
 /// basically as lazily or as eagerly as desired: every recursive
-/// reference to an expression in this enum is an `Box<Expr<'tcx>>`, which
+/// reference to an expression in this enum is an `&'thir Expr<'thir, 'tcx>`, which
 /// may in turn be another instance of this enum (boxed), or else an
 /// unlowered `&'tcx H::Expr`. Note that instances of `Expr` are very
 /// short-lived. They are created by `Thir::to_expr`, analyzed and
@@ -108,7 +111,7 @@ rustc_data_structures::static_assert_size!(Expr<'_>, 160);
 /// example, method calls and overloaded operators are absent: they are
 /// expected to be converted into `Expr::Call` instances.
 #[derive(Debug)]
-crate struct Expr<'tcx> {
+crate struct Expr<'thir, 'tcx> {
     /// type of this expression
     crate ty: Ty<'tcx>,
 
@@ -120,28 +123,28 @@ crate struct Expr<'tcx> {
     crate span: Span,
 
     /// kind of expression
-    crate kind: ExprKind<'tcx>,
+    crate kind: ExprKind<'thir, 'tcx>,
 }
 
 #[derive(Debug)]
-crate enum ExprKind<'tcx> {
+crate enum ExprKind<'thir, 'tcx> {
     Scope {
         region_scope: region::Scope,
         lint_level: LintLevel,
-        value: Box<Expr<'tcx>>,
+        value: &'thir Expr<'thir, 'tcx>,
     },
     Box {
-        value: Box<Expr<'tcx>>,
+        value: &'thir Expr<'thir, 'tcx>,
     },
     If {
-        cond: Box<Expr<'tcx>>,
-        then: Box<Expr<'tcx>>,
-        else_opt: Option<Box<Expr<'tcx>>>,
+        cond: &'thir Expr<'thir, 'tcx>,
+        then: &'thir Expr<'thir, 'tcx>,
+        else_opt: Option<&'thir Expr<'thir, 'tcx>>,
     },
     Call {
         ty: Ty<'tcx>,
-        fun: Box<Expr<'tcx>>,
-        args: Vec<Expr<'tcx>>,
+        fun: &'thir Expr<'thir, 'tcx>,
+        args: &'thir [Expr<'thir, 'tcx>],
         /// Whether this is from a call in HIR, rather than from an overloaded
         /// operator. `true` for overloaded function call.
         from_hir_call: bool,
@@ -150,62 +153,62 @@ crate enum ExprKind<'tcx> {
         fn_span: Span,
     },
     Deref {
-        arg: Box<Expr<'tcx>>,
+        arg: &'thir Expr<'thir, 'tcx>,
     }, // NOT overloaded!
     Binary {
         op: BinOp,
-        lhs: Box<Expr<'tcx>>,
-        rhs: Box<Expr<'tcx>>,
+        lhs: &'thir Expr<'thir, 'tcx>,
+        rhs: &'thir Expr<'thir, 'tcx>,
     }, // NOT overloaded!
     LogicalOp {
         op: LogicalOp,
-        lhs: Box<Expr<'tcx>>,
-        rhs: Box<Expr<'tcx>>,
+        lhs: &'thir Expr<'thir, 'tcx>,
+        rhs: &'thir Expr<'thir, 'tcx>,
     }, // NOT overloaded!
     // LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands.
     Unary {
         op: UnOp,
-        arg: Box<Expr<'tcx>>,
+        arg: &'thir Expr<'thir, 'tcx>,
     }, // NOT overloaded!
     Cast {
-        source: Box<Expr<'tcx>>,
+        source: &'thir Expr<'thir, 'tcx>,
     },
     Use {
-        source: Box<Expr<'tcx>>,
+        source: &'thir Expr<'thir, 'tcx>,
     }, // Use a lexpr to get a vexpr.
     NeverToAny {
-        source: Box<Expr<'tcx>>,
+        source: &'thir Expr<'thir, 'tcx>,
     },
     Pointer {
         cast: PointerCast,
-        source: Box<Expr<'tcx>>,
+        source: &'thir Expr<'thir, 'tcx>,
     },
     Loop {
-        body: Box<Expr<'tcx>>,
+        body: &'thir Expr<'thir, 'tcx>,
     },
     Match {
-        scrutinee: Box<Expr<'tcx>>,
-        arms: Vec<Arm<'tcx>>,
+        scrutinee: &'thir Expr<'thir, 'tcx>,
+        arms: &'thir [Arm<'thir, 'tcx>],
     },
     Block {
-        body: Block<'tcx>,
+        body: Block<'thir, 'tcx>,
     },
     Assign {
-        lhs: Box<Expr<'tcx>>,
-        rhs: Box<Expr<'tcx>>,
+        lhs: &'thir Expr<'thir, 'tcx>,
+        rhs: &'thir Expr<'thir, 'tcx>,
     },
     AssignOp {
         op: BinOp,
-        lhs: Box<Expr<'tcx>>,
-        rhs: Box<Expr<'tcx>>,
+        lhs: &'thir Expr<'thir, 'tcx>,
+        rhs: &'thir Expr<'thir, 'tcx>,
     },
     Field {
-        lhs: Box<Expr<'tcx>>,
+        lhs: &'thir Expr<'thir, 'tcx>,
         name: Field,
     },
     Index {
-        lhs: Box<Expr<'tcx>>,
-        index: Box<Expr<'tcx>>,
+        lhs: &'thir Expr<'thir, 'tcx>,
+        index: &'thir Expr<'thir, 'tcx>,
     },
     VarRef {
         id: hir::HirId,
@@ -220,35 +223,35 @@ crate enum ExprKind<'tcx> {
     },
     Borrow {
         borrow_kind: BorrowKind,
-        arg: Box<Expr<'tcx>>,
+        arg: &'thir Expr<'thir, 'tcx>,
     },
     /// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`.
     AddressOf {
         mutability: hir::Mutability,
-        arg: Box<Expr<'tcx>>,
+        arg: &'thir Expr<'thir, 'tcx>,
     },
     Break {
         label: region::Scope,
-        value: Option<Box<Expr<'tcx>>>,
+        value: Option<&'thir Expr<'thir, 'tcx>>,
     },
     Continue {
         label: region::Scope,
     },
     Return {
-        value: Option<Box<Expr<'tcx>>>,
+        value: Option<&'thir Expr<'thir, 'tcx>>,
     },
     ConstBlock {
         value: &'tcx Const<'tcx>,
     },
     Repeat {
-        value: Box<Expr<'tcx>>,
+        value: &'thir Expr<'thir, 'tcx>,
         count: &'tcx Const<'tcx>,
     },
     Array {
-        fields: Vec<Expr<'tcx>>,
+        fields: &'thir [Expr<'thir, 'tcx>],
     },
     Tuple {
-        fields: Vec<Expr<'tcx>>,
+        fields: &'thir [Expr<'thir, 'tcx>],
     },
     Adt {
         adt_def: &'tcx AdtDef,
@@ -259,23 +262,23 @@ crate enum ExprKind<'tcx> {
         /// Bar::<T> { ... }`.
         user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
 
-        fields: Vec<FieldExpr<'tcx>>,
-        base: Option<FruInfo<'tcx>>,
+        fields: &'thir [FieldExpr<'thir, 'tcx>],
+        base: Option<FruInfo<'thir, 'tcx>>,
     },
     PlaceTypeAscription {
-        source: Box<Expr<'tcx>>,
+        source: &'thir Expr<'thir, 'tcx>,
         /// Type that the user gave to this expression
         user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
     },
     ValueTypeAscription {
-        source: Box<Expr<'tcx>>,
+        source: &'thir Expr<'thir, 'tcx>,
         /// Type that the user gave to this expression
         user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
     },
     Closure {
         closure_id: DefId,
         substs: UpvarSubsts<'tcx>,
-        upvars: Vec<Expr<'tcx>>,
+        upvars: &'thir [Expr<'thir, 'tcx>],
         movability: Option<hir::Movability>,
     },
     Literal {
@@ -296,7 +299,7 @@ crate enum ExprKind<'tcx> {
     },
     InlineAsm {
         template: &'tcx [InlineAsmTemplatePiece],
-        operands: Vec<InlineAsmOperand<'tcx>>,
+        operands: &'thir [InlineAsmOperand<'thir, 'tcx>],
         options: InlineAsmOptions,
         line_spans: &'tcx [Span],
     },
@@ -304,40 +307,40 @@ crate enum ExprKind<'tcx> {
     ThreadLocalRef(DefId),
     LlvmInlineAsm {
         asm: &'tcx hir::LlvmInlineAsmInner,
-        outputs: Vec<Expr<'tcx>>,
-        inputs: Vec<Expr<'tcx>>,
+        outputs: &'thir [Expr<'thir, 'tcx>],
+        inputs: &'thir [Expr<'thir, 'tcx>],
     },
     Yield {
-        value: Box<Expr<'tcx>>,
+        value: &'thir Expr<'thir, 'tcx>,
     },
 }
 
 #[derive(Debug)]
-crate struct FieldExpr<'tcx> {
+crate struct FieldExpr<'thir, 'tcx> {
     crate name: Field,
-    crate expr: Expr<'tcx>,
+    crate expr: &'thir Expr<'thir, 'tcx>,
 }
 
 #[derive(Debug)]
-crate struct FruInfo<'tcx> {
-    crate base: Box<Expr<'tcx>>,
-    crate field_types: Vec<Ty<'tcx>>,
+crate struct FruInfo<'thir, 'tcx> {
+    crate base: &'thir Expr<'thir, 'tcx>,
+    crate field_types: &'thir [Ty<'tcx>],
 }
 
 #[derive(Debug)]
-crate struct Arm<'tcx> {
+crate struct Arm<'thir, 'tcx> {
     crate pattern: Pat<'tcx>,
-    crate guard: Option<Guard<'tcx>>,
-    crate body: Expr<'tcx>,
+    crate guard: Option<Guard<'thir, 'tcx>>,
+    crate body: &'thir Expr<'thir, 'tcx>,
     crate lint_level: LintLevel,
     crate scope: region::Scope,
     crate span: Span,
 }
 
 #[derive(Debug)]
-crate enum Guard<'tcx> {
-    If(Box<Expr<'tcx>>),
-    IfLet(Pat<'tcx>, Box<Expr<'tcx>>),
+crate enum Guard<'thir, 'tcx> {
+    If(&'thir Expr<'thir, 'tcx>),
+    IfLet(Pat<'tcx>, &'thir Expr<'thir, 'tcx>),
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -347,32 +350,32 @@ crate enum LogicalOp {
 }
 
 #[derive(Debug)]
-crate enum InlineAsmOperand<'tcx> {
+crate enum InlineAsmOperand<'thir, 'tcx> {
     In {
         reg: InlineAsmRegOrRegClass,
-        expr: Expr<'tcx>,
+        expr: &'thir Expr<'thir, 'tcx>,
     },
     Out {
         reg: InlineAsmRegOrRegClass,
         late: bool,
-        expr: Option<Expr<'tcx>>,
+        expr: Option<&'thir Expr<'thir, 'tcx>>,
     },
     InOut {
         reg: InlineAsmRegOrRegClass,
         late: bool,
-        expr: Expr<'tcx>,
+        expr: &'thir Expr<'thir, 'tcx>,
     },
     SplitInOut {
         reg: InlineAsmRegOrRegClass,
         late: bool,
-        in_expr: Expr<'tcx>,
-        out_expr: Option<Expr<'tcx>>,
+        in_expr: &'thir Expr<'thir, 'tcx>,
+        out_expr: Option<&'thir Expr<'thir, 'tcx>>,
     },
     Const {
-        expr: Expr<'tcx>,
+        expr: &'thir Expr<'thir, 'tcx>,
     },
     SymFn {
-        expr: Expr<'tcx>,
+        expr: &'thir Expr<'thir, 'tcx>,
     },
     SymStatic {
         def_id: DefId,