about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeSeulArtichaut <leseulartichaut@gmail.com>2021-04-03 19:58:46 +0200
committerLeSeulArtichaut <leseulartichaut@gmail.com>2021-05-19 16:03:35 +0200
commitdc3eabd48700863075bd986a497fbe4f227aa33b (patch)
treee22ae7664cc500b49027e13737314c8d91f6208d
parente78bccfbc01526808c4222ee49c1b6a2f7d8ab5b (diff)
downloadrust-dc3eabd48700863075bd986a497fbe4f227aa33b.tar.gz
rust-dc3eabd48700863075bd986a497fbe4f227aa33b.zip
Store THIR in `IndexVec`s instead of an `Arena`
-rw-r--r--compiler/rustc_driver/src/pretty.rs16
-rw-r--r--compiler/rustc_mir_build/src/build/block.rs33
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_constant.rs6
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_operand.rs19
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs40
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs47
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_temp.rs6
-rw-r--r--compiler/rustc_mir_build/src/build/expr/category.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs84
-rw-r--r--compiler/rustc_mir_build/src/build/expr/stmt.rs34
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs35
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs79
-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.rs125
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs443
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs26
-rw-r--r--compiler/rustc_mir_build/src/thir/mod.rs212
18 files changed, 681 insertions, 628 deletions
diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs
index e0c140b143b..a8b6a16ed12 100644
--- a/compiler/rustc_driver/src/pretty.rs
+++ b/compiler/rustc_driver/src/pretty.rs
@@ -9,14 +9,12 @@ use rustc_hir_pretty as pprust_hir;
 use rustc_middle::hir::map as hir_map;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_mir::util::{write_mir_graphviz, write_mir_pretty};
-use rustc_mir_build::thir;
 use rustc_session::config::{Input, PpAstTreeMode, PpHirMode, PpMode, PpSourceMode};
 use rustc_session::Session;
 use rustc_span::symbol::Ident;
 use rustc_span::FileName;
 
 use std::cell::Cell;
-use std::fmt::Write;
 use std::path::Path;
 
 pub use self::PpMode::*;
@@ -491,18 +489,8 @@ fn print_with_analysis(
         }
 
         ThirTree => {
-            let mut out = String::new();
-            abort_on_err(rustc_typeck::check_crate(tcx), tcx.sess);
-            debug!("pretty printing THIR tree");
-            for did in tcx.body_owners() {
-                let hir = tcx.hir();
-                let body = hir.body(hir.body_owned_by(hir.local_def_id_to_hir_id(did)));
-                let arena = thir::Arena::default();
-                let thir =
-                    thir::build_thir(tcx, ty::WithOptConstParam::unknown(did), &arena, &body.value);
-                let _ = writeln!(out, "{:?}:\n{:#?}\n", did, thir);
-            }
-            out
+            // FIXME(rust-lang/project-thir-unsafeck#8)
+            todo!()
         }
 
         _ => unreachable!(),
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index 808c6e3ff64..ea3a5174fd8 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -12,18 +12,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         destination: Place<'tcx>,
         block: BasicBlock,
-        ast_block: &Block<'_, 'tcx>,
+        ast_block: &Block,
         source_info: SourceInfo,
     ) -> BlockAnd<()> {
         let Block {
             region_scope,
             opt_destruction_scope,
             span,
-            stmts,
+            ref stmts,
             expr,
             targeted_by_break,
             safety_mode,
         } = *ast_block;
+        let expr = expr.map(|expr| &self.thir[expr]);
         self.in_opt_scope(opt_destruction_scope.map(|de| (de, source_info)), move |this| {
             this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
                 if targeted_by_break {
@@ -32,13 +33,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             destination,
                             block,
                             span,
-                            stmts,
+                            &stmts,
                             expr,
                             safety_mode,
                         ))
                     })
                 } else {
-                    this.ast_block_stmts(destination, block, span, stmts, expr, safety_mode)
+                    this.ast_block_stmts(destination, block, span, &stmts, expr, safety_mode)
                 }
             })
         })
@@ -49,8 +50,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         destination: Place<'tcx>,
         mut block: BasicBlock,
         span: Span,
-        stmts: &[Stmt<'_, 'tcx>],
-        expr: Option<&Expr<'_, 'tcx>>,
+        stmts: &[StmtId],
+        expr: Option<&Expr<'tcx>>,
         safety_mode: BlockSafety,
     ) -> BlockAnd<()> {
         let this = self;
@@ -78,23 +79,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         this.update_source_scope_for_safety_mode(span, safety_mode);
 
         let source_info = this.source_info(span);
-        for Stmt { kind, opt_destruction_scope } in stmts {
+        for stmt in stmts {
+            let Stmt { ref kind, opt_destruction_scope } = this.thir[*stmt];
             match kind {
-                &StmtKind::Expr { scope, expr } => {
+                StmtKind::Expr { scope, expr } => {
                     this.block_context.push(BlockFrame::Statement { ignores_expr_result: true });
                     unpack!(
                         block = this.in_opt_scope(
                             opt_destruction_scope.map(|de| (de, source_info)),
                             |this| {
-                                let si = (scope, source_info);
+                                let si = (*scope, source_info);
                                 this.in_scope(si, LintLevel::Inherited, |this| {
-                                    this.stmt_expr(block, expr, Some(scope))
+                                    this.stmt_expr(block, &this.thir[*expr], Some(*scope))
                                 })
                             }
                         )
                     );
                 }
-                StmtKind::Let { remainder_scope, init_scope, pattern, initializer, lint_level } => {
+                StmtKind::Let {
+                    remainder_scope,
+                    init_scope,
+                    ref pattern,
+                    initializer,
+                    lint_level,
+                } => {
                     let ignores_expr_result = matches!(*pattern.kind, PatKind::Wild);
                     this.block_context.push(BlockFrame::Statement { ignores_expr_result });
 
@@ -110,6 +118,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                     // Evaluate the initializer, if present.
                     if let Some(init) = initializer {
+                        let init = &this.thir[*init];
                         let initializer_span = init.span;
 
                         unpack!(
@@ -145,7 +154,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                         debug!("ast_block_stmts: pattern={:?}", pattern);
                         this.visit_primary_bindings(
-                            &pattern,
+                            pattern,
                             UserTypeProjections::none(),
                             &mut |this, _, _, _, node, span, _, _| {
                                 this.storage_live_binding(block, node, span, OutsideGuard, true);
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 57f56e2d092..796a90713ba 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -8,11 +8,13 @@ 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, ref kind } = *expr;
         match *kind {
-            ExprKind::Scope { region_scope: _, lint_level: _, value } => this.as_constant(value),
+            ExprKind::Scope { region_scope: _, lint_level: _, value } => {
+                this.as_constant(&this.thir[value])
+            }
             ExprKind::Literal { literal, user_ty, const_id: _ } => {
                 let user_ty = user_ty.map(|user_ty| {
                     this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
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 c393878e0b9..1c439aad394 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;
@@ -101,8 +101,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
             let source_info = this.source_info(expr.span);
             let region_scope = (region_scope, source_info);
-            return this
-                .in_scope(region_scope, lint_level, |this| this.as_operand(block, scope, value));
+            return this.in_scope(region_scope, lint_level, |this| {
+                this.as_operand(block, scope, &this.thir[value])
+            });
         }
 
         let category = Category::of(&expr.kind).unwrap();
@@ -123,7 +124,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;
@@ -132,7 +133,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             let source_info = this.source_info(expr.span);
             let region_scope = (region_scope, source_info);
             return this.in_scope(region_scope, lint_level, |this| {
-                this.as_call_operand(block, scope, value)
+                this.as_call_operand(block, scope, &this.thir[value])
             });
         }
 
@@ -151,7 +152,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // type, and that value is coming from the deref of a box.
                 if let ExprKind::Deref { arg } = expr.kind {
                     // Generate let tmp0 = arg0
-                    let operand = unpack!(block = this.as_temp(block, scope, arg, Mutability::Mut));
+                    let operand = unpack!(
+                        block = this.as_temp(block, scope, &this.thir[arg], Mutability::Mut)
+                    );
 
                     // Return the operand *tmp0 to be used as the call argument
                     let place = Place {
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 1053890e618..96df77a65da 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -381,7 +381,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))
@@ -392,7 +392,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)
     }
@@ -405,7 +405,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))
@@ -420,7 +420,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)
     }
@@ -428,7 +428,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>> {
@@ -440,23 +440,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         match expr.kind {
             ExprKind::Scope { region_scope, lint_level, value } => {
                 this.in_scope((region_scope, source_info), lint_level, |this| {
-                    this.expr_as_place(block, value, mutability, fake_borrow_temps)
+                    this.expr_as_place(block, &this.thir[value], mutability, fake_borrow_temps)
                 })
             }
             ExprKind::Field { lhs, name } => {
-                let place_builder =
-                    unpack!(block = this.expr_as_place(block, lhs, mutability, fake_borrow_temps,));
+                let place_builder = unpack!(
+                    block =
+                        this.expr_as_place(block, &this.thir[lhs], mutability, fake_borrow_temps,)
+                );
                 block.and(place_builder.field(name, expr.ty))
             }
             ExprKind::Deref { arg } => {
-                let place_builder =
-                    unpack!(block = this.expr_as_place(block, arg, mutability, fake_borrow_temps,));
+                let place_builder = unpack!(
+                    block =
+                        this.expr_as_place(block, &this.thir[arg], mutability, fake_borrow_temps,)
+                );
                 block.and(place_builder.deref())
             }
             ExprKind::Index { lhs, index } => this.lower_index_expression(
                 block,
-                lhs,
-                index,
+                &this.thir[lhs],
+                &this.thir[index],
                 mutability,
                 fake_borrow_temps,
                 expr.temp_lifetime,
@@ -481,7 +485,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
             ExprKind::PlaceTypeAscription { source, user_ty } => {
                 let place_builder = unpack!(
-                    block = this.expr_as_place(block, source, mutability, fake_borrow_temps,)
+                    block = this.expr_as_place(
+                        block,
+                        &this.thir[source],
+                        mutability,
+                        fake_borrow_temps,
+                    )
                 );
                 if let Some(user_ty) = user_ty {
                     let annotation_index =
@@ -509,6 +518,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 block.and(place_builder)
             }
             ExprKind::ValueTypeAscription { source, user_ty } => {
+                let source = &this.thir[source];
                 let temp =
                     unpack!(block = this.as_temp(block, source.temp_lifetime, source, mutability));
                 if let Some(user_ty) = user_ty {
@@ -613,8 +623,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 822fbd91c94..92a2a7bc17a 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -23,7 +23,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)
@@ -34,7 +34,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);
 
@@ -46,19 +46,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             ExprKind::ThreadLocalRef(did) => block.and(Rvalue::ThreadLocalRef(did)),
             ExprKind::Scope { region_scope, lint_level, value } => {
                 let region_scope = (region_scope, source_info);
-                this.in_scope(region_scope, lint_level, |this| this.as_rvalue(block, scope, value))
+                this.in_scope(region_scope, lint_level, |this| {
+                    this.as_rvalue(block, scope, &this.thir[value])
+                })
             }
             ExprKind::Repeat { value, count } => {
-                let value_operand = unpack!(block = this.as_operand(block, scope, value));
+                let value_operand =
+                    unpack!(block = this.as_operand(block, scope, &this.thir[value]));
                 block.and(Rvalue::Repeat(value_operand, count))
             }
             ExprKind::Binary { op, lhs, rhs } => {
-                let lhs = unpack!(block = this.as_operand(block, scope, lhs));
-                let rhs = unpack!(block = this.as_operand(block, scope, rhs));
+                let lhs = unpack!(block = this.as_operand(block, scope, &this.thir[lhs]));
+                let rhs = unpack!(block = this.as_operand(block, scope, &this.thir[rhs]));
                 this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs)
             }
             ExprKind::Unary { op, arg } => {
-                let arg = unpack!(block = this.as_operand(block, scope, arg));
+                let arg = unpack!(block = this.as_operand(block, scope, &this.thir[arg]));
                 // Check for -MIN on signed integers
                 if this.check_overflow && op == UnOp::Neg && expr.ty.is_signed() {
                     let bool_ty = this.tcx.types.bool;
@@ -84,6 +87,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 block.and(Rvalue::UnaryOp(op, arg))
             }
             ExprKind::Box { value } => {
+                let value = &this.thir[value];
                 // The `Box<T>` temporary created here is not a part of the HIR,
                 // and therefore is not considered during generator auto-trait
                 // determination. See the comment about `box` at `yield_in_scope`.
@@ -112,14 +116,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 block.and(Rvalue::Use(Operand::Move(Place::from(result))))
             }
             ExprKind::Cast { source } => {
-                let source = unpack!(block = this.as_operand(block, scope, source));
+                let source = unpack!(block = this.as_operand(block, scope, &this.thir[source]));
                 block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
             }
             ExprKind::Pointer { cast, source } => {
-                let source = unpack!(block = this.as_operand(block, scope, source));
+                let source = unpack!(block = this.as_operand(block, scope, &this.thir[source]));
                 block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty))
             }
-            ExprKind::Array { fields } => {
+            ExprKind::Array { ref fields } => {
                 // (*) We would (maybe) be closer to codegen if we
                 // handled this and other aggregate cases via
                 // `into()`, not `as_rvalue` -- in that case, instead
@@ -150,22 +154,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let el_ty = expr.ty.sequence_element_type(this.tcx);
                 let fields: Vec<_> = fields
                     .into_iter()
-                    .map(|f| unpack!(block = this.as_operand(block, scope, f)))
+                    .copied()
+                    .map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f])))
                     .collect();
 
                 block.and(Rvalue::Aggregate(box AggregateKind::Array(el_ty), fields))
             }
-            ExprKind::Tuple { fields } => {
+            ExprKind::Tuple { ref fields } => {
                 // see (*) above
                 // first process the set of fields
                 let fields: Vec<_> = fields
                     .into_iter()
-                    .map(|f| unpack!(block = this.as_operand(block, scope, f)))
+                    .copied()
+                    .map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f])))
                     .collect();
 
                 block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields))
             }
-            ExprKind::Closure { closure_id, substs, upvars, movability, ref fake_reads } => {
+            ExprKind::Closure { closure_id, substs, ref upvars, movability, ref fake_reads } => {
                 // Convert the closure fake reads, if any, from `ExprRef` to mir `Place`
                 // and push the fake reads.
                 // This must come before creating the operands. This is required in case
@@ -180,7 +186,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // };
                 // ```
                 for (thir_place, cause, hir_id) in fake_reads.into_iter() {
-                    let place_builder = unpack!(block = this.as_place_builder(block, thir_place));
+                    let place_builder =
+                        unpack!(block = this.as_place_builder(block, &this.thir[*thir_place]));
 
                     if let Ok(place_builder_resolved) =
                         place_builder.try_upvars_resolved(this.tcx, this.typeck_results)
@@ -199,7 +206,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // see (*) above
                 let operands: Vec<_> = upvars
                     .into_iter()
+                    .copied()
                     .map(|upvar| {
+                        let upvar = &this.thir[upvar];
                         match Category::of(&upvar.kind) {
                             // Use as_place to avoid creating a temporary when
                             // moving a variable into a closure, so that
@@ -225,7 +234,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                         arg,
                                     } => unpack!(
                                         block = this.limit_capture_mutability(
-                                            upvar.span, upvar.ty, scope, block, arg,
+                                            upvar.span,
+                                            upvar.ty,
+                                            scope,
+                                            block,
+                                            &this.thir[arg],
                                         )
                                     ),
                                     _ => unpack!(block = this.as_operand(block, scope, upvar)),
@@ -398,7 +411,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 98b910ab21c..96bf3e6d69d 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!(
@@ -40,7 +40,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let source_info = this.source_info(expr_span);
         if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
             return this.in_scope((region_scope, source_info), lint_level, |this| {
-                this.as_temp(block, temp_lifetime, value, mutability)
+                this.as_temp(block, temp_lifetime, &this.thir[value], mutability)
             });
         }
 
diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs
index 0cadfa2f0a1..9320b5810e3 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 1e7ed3d95d2..d7c8a07103e 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -19,7 +19,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);
 
@@ -42,19 +42,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let region_scope = (region_scope, source_info);
                 ensure_sufficient_stack(|| {
                     this.in_scope(region_scope, lint_level, |this| {
-                        this.expr_into_dest(destination, block, value)
+                        this.expr_into_dest(destination, block, &this.thir[value])
                     })
                 })
             }
             ExprKind::Block { body: ref ast_block } => {
                 this.ast_block(destination, block, ast_block, source_info)
             }
-            ExprKind::Match { scrutinee, arms } => {
-                this.match_expr(destination, expr_span, block, scrutinee, arms)
+            ExprKind::Match { scrutinee, ref arms } => {
+                this.match_expr(destination, expr_span, block, &this.thir[scrutinee], arms)
             }
             ExprKind::If { cond, then, else_opt } => {
                 let place = unpack!(
-                    block = this.as_temp(block, Some(this.local_scope()), cond, Mutability::Mut)
+                    block = this.as_temp(
+                        block,
+                        Some(this.local_scope()),
+                        &this.thir[cond],
+                        Mutability::Mut
+                    )
                 );
                 let operand = Operand::Move(Place::from(place));
 
@@ -63,9 +68,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let term = TerminatorKind::if_(this.tcx, operand, then_block, else_block);
                 this.cfg.terminate(block, source_info, term);
 
-                unpack!(then_block = this.expr_into_dest(destination, then_block, then));
+                unpack!(
+                    then_block = this.expr_into_dest(destination, then_block, &this.thir[then])
+                );
                 else_block = if let Some(else_opt) = else_opt {
-                    unpack!(this.expr_into_dest(destination, else_block, else_opt))
+                    unpack!(this.expr_into_dest(destination, else_block, &this.thir[else_opt]))
                 } else {
                     // Body of the `if` expression without an `else` clause must return `()`, thus
                     // we implicitly generate a `else {}` if it is not specified.
@@ -89,6 +96,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 join_block.unit()
             }
             ExprKind::NeverToAny { source } => {
+                let source = &this.thir[source];
                 let is_call =
                     matches!(source.kind, ExprKind::Call { .. } | ExprKind::InlineAsm { .. });
 
@@ -127,7 +135,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     this.cfg.start_new_block(),
                 );
 
-                let lhs = unpack!(block = this.as_local_operand(block, lhs));
+                let lhs = unpack!(block = this.as_local_operand(block, &this.thir[lhs]));
                 let blocks = match op {
                     LogicalOp::And => (else_block, shortcircuit_block),
                     LogicalOp::Or => (shortcircuit_block, else_block),
@@ -150,7 +158,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 );
                 this.cfg.goto(shortcircuit_block, source_info, join_block);
 
-                let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs));
+                let rhs = unpack!(else_block = this.as_local_operand(else_block, &this.thir[rhs]));
                 this.cfg.push_assign(else_block, source_info, destination, Rvalue::Use(rhs));
                 this.cfg.goto(else_block, source_info, join_block);
 
@@ -186,18 +194,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     // introduce a unit temporary as the destination for the loop body.
                     let tmp = this.get_unit_temp();
                     // Execute the body, branching back to the test.
-                    let body_block_end = unpack!(this.expr_into_dest(tmp, body_block, body));
+                    let body_block_end =
+                        unpack!(this.expr_into_dest(tmp, body_block, &this.thir[body]));
                     this.cfg.goto(body_block_end, source_info, loop_block);
 
                     // Loops are only exited by `break` expressions.
                     None
                 })
             }
-            ExprKind::Call { ty: _, fun, args, from_hir_call, fn_span } => {
-                let fun = unpack!(block = this.as_local_operand(block, fun));
+            ExprKind::Call { ty: _, fun, ref args, from_hir_call, fn_span } => {
+                let fun = unpack!(block = this.as_local_operand(block, &this.thir[fun]));
                 let args: Vec<_> = args
                     .into_iter()
-                    .map(|arg| unpack!(block = this.as_local_call_operand(block, arg)))
+                    .copied()
+                    .map(|arg| unpack!(block = this.as_local_call_operand(block, &this.thir[arg])))
                     .collect();
 
                 let success = this.cfg.start_new_block();
@@ -228,8 +238,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 this.diverge_from(block);
                 success.unit()
             }
-            ExprKind::Use { source } => this.expr_into_dest(destination, block, source),
+            ExprKind::Use { source } => this.expr_into_dest(destination, block, &this.thir[source]),
             ExprKind::Borrow { arg, borrow_kind } => {
+                let arg = &this.thir[arg];
                 // We don't do this in `as_rvalue` because we use `as_place`
                 // for borrow expressions, so we cannot create an `RValue` that
                 // remains valid across user code. `as_rvalue` is usually called
@@ -244,6 +255,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 block.unit()
             }
             ExprKind::AddressOf { mutability, arg } => {
+                let arg = &this.thir[arg];
                 let place = match mutability {
                     hir::Mutability::Not => this.as_read_only_place(block, arg),
                     hir::Mutability::Mut => this.as_place(block, arg),
@@ -252,7 +264,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 this.cfg.push_assign(block, source_info, destination, address_of);
                 block.unit()
             }
-            ExprKind::Adt { adt_def, variant_index, substs, user_ty, fields, ref base } => {
+            ExprKind::Adt { adt_def, variant_index, substs, user_ty, ref fields, ref base } => {
                 // See the notes for `ExprKind::Array` in `as_rvalue` and for
                 // `ExprKind::Borrow` above.
                 let is_union = adt_def.is_union();
@@ -264,19 +276,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // (evaluating them in order given by user)
                 let fields_map: FxHashMap<_, _> = fields
                     .into_iter()
-                    .map(|f| (f.name, unpack!(block = this.as_operand(block, Some(scope), f.expr))))
+                    .map(|f| {
+                        (
+                            f.name,
+                            unpack!(
+                                block = this.as_operand(block, Some(scope), &this.thir[f.expr])
+                            ),
+                        )
+                    })
                     .collect();
 
                 let field_names: Vec<_> =
                     (0..adt_def.variants[variant_index].fields.len()).map(Field::new).collect();
 
                 let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base {
-                    let place_builder = unpack!(block = this.as_place_builder(block, base));
+                    let place_builder =
+                        unpack!(block = this.as_place_builder(block, &this.thir[*base]));
 
                     // MIR does not natively support FRU, so for each
                     // base-supplied field, generate an operand that
                     // reads it from the base.
-                    iter::zip(field_names, *field_types)
+                    iter::zip(field_names, &**field_types)
                         .map(|(n, ty)| match fields_map.get(&n) {
                             Some(v) => v.clone(),
                             None => {
@@ -316,7 +336,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 );
                 block.unit()
             }
-            ExprKind::InlineAsm { template, operands, options, line_spans } => {
+            ExprKind::InlineAsm { template, ref operands, options, line_spans } => {
                 use crate::thir;
                 use rustc_middle::mir;
                 let operands = operands
@@ -324,19 +344,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     .map(|op| match *op {
                         thir::InlineAsmOperand::In { reg, expr } => mir::InlineAsmOperand::In {
                             reg,
-                            value: unpack!(block = this.as_local_operand(block, expr)),
+                            value: unpack!(block = this.as_local_operand(block, &this.thir[expr])),
                         },
                         thir::InlineAsmOperand::Out { reg, late, expr } => {
                             mir::InlineAsmOperand::Out {
                                 reg,
                                 late,
-                                place: expr
-                                    .as_ref()
-                                    .map(|expr| unpack!(block = this.as_place(block, expr))),
+                                place: expr.map(|expr| {
+                                    unpack!(block = this.as_place(block, &this.thir[expr]))
+                                }),
                             }
                         }
                         thir::InlineAsmOperand::InOut { reg, late, expr } => {
-                            let place = unpack!(block = this.as_place(block, expr));
+                            let place = unpack!(block = this.as_place(block, &this.thir[expr]));
                             mir::InlineAsmOperand::InOut {
                                 reg,
                                 late,
@@ -349,9 +369,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             mir::InlineAsmOperand::InOut {
                                 reg,
                                 late,
-                                in_value: unpack!(block = this.as_local_operand(block, in_expr)),
-                                out_place: out_expr.as_ref().map(|out_expr| {
-                                    unpack!(block = this.as_place(block, out_expr))
+                                in_value: unpack!(
+                                    block = this.as_local_operand(block, &this.thir[in_expr])
+                                ),
+                                out_place: out_expr.map(|out_expr| {
+                                    unpack!(block = this.as_place(block, &this.thir[out_expr]))
                                 }),
                             }
                         }
@@ -360,9 +382,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                 value: box Constant { span, user_ty: None, literal: value.into() },
                             }
                         }
-                        thir::InlineAsmOperand::SymFn { expr } => {
-                            mir::InlineAsmOperand::SymFn { value: box this.as_constant(expr) }
-                        }
+                        thir::InlineAsmOperand::SymFn { expr } => mir::InlineAsmOperand::SymFn {
+                            value: box this.as_constant(&this.thir[expr]),
+                        },
                         thir::InlineAsmOperand::SymStatic { def_id } => {
                             mir::InlineAsmOperand::SymStatic { def_id }
                         }
@@ -434,7 +456,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
             ExprKind::Yield { value } => {
                 let scope = this.local_scope();
-                let value = unpack!(block = this.as_operand(block, Some(scope), value));
+                let value = unpack!(block = this.as_operand(block, Some(scope), &this.thir[value]));
                 let resume = this.cfg.start_new_block();
                 this.cfg.terminate(
                     block,
diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs
index f01315fc5db..d2442f33b0c 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;
@@ -24,10 +24,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         match expr.kind {
             ExprKind::Scope { region_scope, lint_level, value } => {
                 this.in_scope((region_scope, source_info), lint_level, |this| {
-                    this.stmt_expr(block, value, statement_scope)
+                    this.stmt_expr(block, &this.thir[value], statement_scope)
                 })
             }
             ExprKind::Assign { lhs, rhs } => {
+                let lhs = &this.thir[lhs];
+                let rhs = &this.thir[rhs];
                 let lhs_span = lhs.span;
 
                 // Note: we evaluate assignments right-to-left. This
@@ -61,6 +63,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // only affects weird things like `x += {x += 1; x}`
                 // -- is that equal to `x + (x + 1)` or `2*(x+1)`?
 
+                let lhs = &this.thir[lhs];
+                let rhs = &this.thir[rhs];
                 let lhs_ty = lhs.ty;
 
                 debug!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr);
@@ -87,24 +91,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
             ExprKind::Break { label, value } => this.break_scope(
                 block,
-                value.as_deref(),
+                value.map(|value| &this.thir[value]),
                 BreakableTarget::Break(label),
                 source_info,
             ),
-            ExprKind::Return { value } => {
-                this.break_scope(block, value.as_deref(), BreakableTarget::Return, source_info)
-            }
-            ExprKind::LlvmInlineAsm { asm, outputs, inputs } => {
+            ExprKind::Return { value } => this.break_scope(
+                block,
+                value.map(|value| &this.thir[value]),
+                BreakableTarget::Return,
+                source_info,
+            ),
+            ExprKind::LlvmInlineAsm { asm, ref outputs, ref inputs } => {
                 debug!("stmt_expr LlvmInlineAsm block_context.push(SubExpr) : {:?}", expr);
                 this.block_context.push(BlockFrame::SubExpr);
                 let outputs = outputs
                     .into_iter()
-                    .map(|output| unpack!(block = this.as_place(block, &output)))
+                    .copied()
+                    .map(|output| unpack!(block = this.as_place(block, &this.thir[output])))
                     .collect::<Vec<_>>()
                     .into_boxed_slice();
                 let inputs = inputs
                     .into_iter()
+                    .copied()
                     .map(|input| {
+                        let input = &this.thir[input];
                         (input.span, unpack!(block = this.as_local_operand(block, &input)))
                     })
                     .collect::<Vec<_>>()
@@ -139,14 +149,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // than the entirety of block(s) surrounding it.
                 let adjusted_span = (|| {
                     if let ExprKind::Block { body } = &expr.kind {
-                        if let Some(tail_expr) = &body.expr {
-                            let mut expr = &*tail_expr;
+                        if let Some(tail_expr) = body.expr {
+                            let mut expr = &this.thir[tail_expr];
                             while let ExprKind::Block {
                                 body: Block { expr: Some(nested_expr), .. },
                             }
-                            | ExprKind::Scope { value: nested_expr, .. } = &expr.kind
+                            | ExprKind::Scope { value: nested_expr, .. } = expr.kind
                             {
-                                expr = nested_expr;
+                                expr = &this.thir[nested_expr];
                             }
                             this.block_context.push(BlockFrame::TailExpr {
                                 tail_result_is_ignored: true,
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 0e422dc3c63..c30193b5a5a 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -90,8 +90,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: &[ArmId],
     ) -> BlockAnd<()> {
         let scrutinee_span = scrutinee.span;
         let scrutinee_place =
@@ -99,7 +99,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         let mut arm_candidates = self.create_match_candidates(scrutinee_place.clone(), &arms);
 
-        let match_has_guard = arms.iter().any(|arm| arm.guard.is_some());
+        let match_has_guard = arms.iter().copied().any(|arm| self.thir[arm].guard.is_some());
         let mut candidates =
             arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::<Vec<_>>();
 
@@ -120,7 +120,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<PlaceBuilder<'tcx>> {
         let scrutinee_place_builder = unpack!(block = self.as_place_builder(block, scrutinee));
@@ -156,12 +156,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn create_match_candidates<'pat>(
         &mut self,
         scrutinee: PlaceBuilder<'tcx>,
-        arms: &'pat [Arm<'pat, 'tcx>],
-    ) -> Vec<(&'pat Arm<'pat, 'tcx>, Candidate<'pat, 'tcx>)> {
+        arms: &'pat [ArmId],
+    ) -> Vec<(&'pat Arm<'tcx>, Candidate<'pat, 'tcx>)>
+    where
+        'a: 'pat,
+    {
         // Assemble a list of candidates: there is one candidate per pattern,
         // which means there may be more than one candidate *per arm*.
         arms.iter()
+            .copied()
             .map(|arm| {
+                let arm = &self.thir[arm];
                 let arm_has_guard = arm.guard.is_some();
                 let arm_candidate = Candidate::new(scrutinee.clone(), &arm.pattern, arm_has_guard);
                 (arm, arm_candidate)
@@ -231,7 +236,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         destination: Place<'tcx>,
         scrutinee_place_builder: PlaceBuilder<'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<()> {
@@ -286,7 +291,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         this.source_scope = source_scope;
                     }
 
-                    this.expr_into_dest(destination, arm_block, &arm.body)
+                    this.expr_into_dest(destination, arm_block, &&this.thir[arm.body])
                 })
             })
             .collect();
@@ -313,7 +318,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>,
@@ -389,7 +394,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`
@@ -1665,7 +1670,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>,
@@ -1799,12 +1804,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 self.cfg.push_assign(block, scrutinee_source_info, Place::from(temp), borrow);
             }
 
-            let (guard_span, (post_guard_block, otherwise_post_guard_block)) = match guard {
+            let (guard_span, (post_guard_block, otherwise_post_guard_block)) = match *guard {
                 Guard::If(e) => {
+                    let e = &self.thir[e];
                     let source_info = self.source_info(e.span);
                     (e.span, self.test_bool(block, e, source_info))
                 }
-                Guard::IfLet(pat, scrutinee) => {
+                Guard::IfLet(ref pat, scrutinee) => {
+                    let scrutinee = &self.thir[scrutinee];
                     let scrutinee_span = scrutinee.span;
                     let scrutinee_place_builder =
                         unpack!(block = self.lower_scrutinee(block, scrutinee, scrutinee_span));
@@ -1840,7 +1847,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         guard_candidate,
                         None,
                         &fake_borrow_temps,
-                        scrutinee.span,
+                        scrutinee_span,
                         None,
                         None,
                     );
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index f944e5f8f04..4f6c57be2da 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::expr::as_place::PlaceBuilder;
 use crate::build::scope::DropKind;
-use crate::thir::{build_thir, Arena, BindingMode, Expr, LintLevel, Pat, PatKind};
+use crate::thir::{build_thir, BindingMode, Expr, ExprId, LintLevel, Pat, PatKind, Thir};
 use rustc_attr::{self as attr, UnwindAttr};
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
@@ -88,7 +88,6 @@ 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 body = if let Some(ErrorReported) = typeck_results.tainted_by_errors {
@@ -105,7 +104,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
             };
 
             let body = tcx.hir().body(body_id);
-            let thir = build_thir(tcx, def, &arena, &body.value);
+            let (thir, expr) = build_thir(tcx, def, &body.value);
             let ty = tcx.type_of(fn_def_id);
             let mut abi = fn_sig.abi;
             let implicit_argument = match ty.kind() {
@@ -181,6 +180,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
             };
 
             let mut mir = build::construct_fn(
+                &thir,
                 &infcx,
                 def,
                 id,
@@ -190,7 +190,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
                 return_ty,
                 return_ty_span,
                 body,
-                thir,
+                expr,
                 span_with_body,
             );
             if yield_ty.is_some() {
@@ -213,9 +213,9 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
             let return_ty = typeck_results.node_type(id);
 
             let ast_expr = &tcx.hir().body(body_id).value;
-            let thir = build_thir(tcx, def, &arena, ast_expr);
+            let (thir, expr) = build_thir(tcx, def, ast_expr);
 
-            build::construct_const(&infcx, thir, def, id, return_ty, return_ty_span)
+            build::construct_const(&thir, &infcx, expr, def, id, return_ty, return_ty_span)
         };
 
         lints::check(tcx, &body);
@@ -323,6 +323,7 @@ struct Builder<'a, 'tcx> {
     region_scope_tree: &'tcx region::ScopeTree,
     param_env: ty::ParamEnv<'tcx>,
 
+    thir: &'a Thir<'tcx>,
     cfg: CFG<'tcx>,
 
     def_id: DefId,
@@ -633,6 +634,7 @@ struct ArgInfo<'tcx>(
 );
 
 fn construct_fn<'tcx, A>(
+    thir: &Thir<'tcx>,
     infcx: &InferCtxt<'_, 'tcx>,
     fn_def: ty::WithOptConstParam<LocalDefId>,
     fn_id: hir::HirId,
@@ -642,7 +644,7 @@ fn construct_fn<'tcx, A>(
     return_ty: Ty<'tcx>,
     return_ty_span: Span,
     body: &'tcx hir::Body<'tcx>,
-    expr: &Expr<'_, 'tcx>,
+    expr: ExprId,
     span_with_body: Span,
 ) -> Body<'tcx>
 where
@@ -654,6 +656,7 @@ where
     let span = tcx.hir().span(fn_id);
 
     let mut builder = Builder::new(
+        thir,
         infcx,
         fn_def,
         fn_id,
@@ -683,7 +686,7 @@ where
                         fn_def.did.to_def_id(),
                         &arguments,
                         arg_scope,
-                        expr,
+                        &thir[expr],
                     )
                 }))
             }));
@@ -708,8 +711,9 @@ where
 }
 
 fn construct_const<'a, 'tcx>(
+    thir: &'a Thir<'tcx>,
     infcx: &'a InferCtxt<'a, 'tcx>,
-    expr: &Expr<'_, 'tcx>,
+    expr: ExprId,
     def: ty::WithOptConstParam<LocalDefId>,
     hir_id: hir::HirId,
     const_ty: Ty<'tcx>,
@@ -717,11 +721,21 @@ fn construct_const<'a, 'tcx>(
 ) -> Body<'tcx> {
     let tcx = infcx.tcx;
     let span = tcx.hir().span(hir_id);
-    let mut builder =
-        Builder::new(infcx, def, hir_id, span, 0, Safety::Safe, const_ty, const_ty_span, None);
+    let mut builder = Builder::new(
+        thir,
+        infcx,
+        def,
+        hir_id,
+        span,
+        0,
+        Safety::Safe,
+        const_ty,
+        const_ty_span,
+        None,
+    );
 
     let mut block = START_BLOCK;
-    unpack!(block = builder.expr_into_dest(Place::return_place(), block, &expr));
+    unpack!(block = builder.expr_into_dest(Place::return_place(), block, &thir[expr]));
 
     let source_info = builder.source_info(span);
     builder.cfg.terminate(block, source_info, TerminatorKind::Return);
@@ -761,22 +775,48 @@ fn construct_error<'a, 'tcx>(
         hir::BodyOwnerKind::Const => 0,
         hir::BodyOwnerKind::Static(_) => 0,
     };
-    let mut builder =
-        Builder::new(infcx, def, hir_id, span, num_params, Safety::Safe, ty, span, generator_kind);
-    let source_info = builder.source_info(span);
+    let mut cfg = CFG { basic_blocks: IndexVec::new() };
+    let mut source_scopes = IndexVec::new();
+    let mut local_decls = IndexVec::from_elem_n(LocalDecl::new(ty, span), 1);
+
+    cfg.start_new_block();
+    source_scopes.push(SourceScopeData {
+        span,
+        parent_scope: None,
+        inlined: None,
+        inlined_parent_scope: None,
+        local_data: ClearCrossCrate::Set(SourceScopeLocalData {
+            lint_root: hir_id,
+            safety: Safety::Safe,
+        }),
+    });
+    let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE };
+
     // Some MIR passes will expect the number of parameters to match the
     // function declaration.
     for _ in 0..num_params {
-        builder.local_decls.push(LocalDecl::with_source_info(ty, source_info));
+        local_decls.push(LocalDecl::with_source_info(ty, source_info));
     }
-    builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
-    let mut body = builder.finish();
+    cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
+
+    let mut body = Body::new(
+        MirSource::item(def.did.to_def_id()),
+        cfg.basic_blocks,
+        source_scopes,
+        local_decls,
+        IndexVec::new(),
+        num_params,
+        vec![],
+        span,
+        generator_kind,
+    );
     body.generator.as_mut().map(|gen| gen.yield_ty = Some(ty));
     body
 }
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn new(
+        thir: &'a Thir<'tcx>,
         infcx: &'a InferCtxt<'a, 'tcx>,
         def: ty::WithOptConstParam<LocalDefId>,
         hir_id: hir::HirId,
@@ -803,6 +843,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         let lint_level = LintLevel::Explicit(hir_id);
         let mut builder = Builder {
+            thir,
             tcx,
             infcx,
             typeck_results: tcx.typeck_opt_const_arg(def),
@@ -866,7 +907,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 41fc925c049..e79a19d57ac 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<()> {
@@ -933,7 +933,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
deleted file mode 100644
index aacc7b12a42..00000000000
--- a/compiler/rustc_mir_build/src/thir/arena.rs
+++ /dev/null
@@ -1,98 +0,0 @@
-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 d450f8a265d..b90f9abe33a 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<'thir, 'tcx> Cx<'thir, 'tcx> {
-    crate fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block<'thir, 'tcx> {
+impl<'tcx> Cx<'tcx> {
+    crate fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block {
         // 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);
@@ -37,65 +37,78 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         &mut self,
         block_id: hir::ItemLocalId,
         stmts: &'tcx [hir::Stmt<'tcx>],
-    ) -> &'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) => 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 {
-                        id: block_id,
-                        data: region::ScopeData::Remainder(region::FirstStatementIndex::new(index)),
-                    };
+    ) -> Box<[StmtId]> {
+        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) => {
+                        let stmt = 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,
+                        };
+                        Some(self.thir.stmts.push(stmt))
+                    }
+                    hir::StmtKind::Item(..) => {
+                        // ignore for purposes of the MIR
+                        None
+                    }
+                    hir::StmtKind::Local(ref local) => {
+                        let remainder_scope = region::Scope {
+                            id: block_id,
+                            data: region::ScopeData::Remainder(region::FirstStatementIndex::new(
+                                index,
+                            )),
+                        };
 
-                    let mut pattern = self.pattern_from_hir(local.pat);
+                        let mut pattern = self.pattern_from_hir(local.pat);
 
-                    if let Some(ty) = &local.ty {
-                        if let Some(&user_ty) =
-                            self.typeck_results.user_provided_types().get(ty.hir_id)
-                        {
-                            debug!("mirror_stmts: user_ty={:?}", user_ty);
-                            pattern = Pat {
-                                ty: pattern.ty,
-                                span: pattern.span,
-                                kind: Box::new(PatKind::AscribeUserType {
-                                    ascription: thir::pattern::Ascription {
-                                        user_ty: PatTyProj::from_user_type(user_ty),
-                                        user_ty_span: ty.span,
-                                        variance: ty::Variance::Covariant,
-                                    },
-                                    subpattern: pattern,
-                                }),
-                            };
+                        if let Some(ty) = &local.ty {
+                            if let Some(&user_ty) =
+                                self.typeck_results.user_provided_types().get(ty.hir_id)
+                            {
+                                debug!("mirror_stmts: user_ty={:?}", user_ty);
+                                pattern = Pat {
+                                    ty: pattern.ty,
+                                    span: pattern.span,
+                                    kind: Box::new(PatKind::AscribeUserType {
+                                        ascription: thir::pattern::Ascription {
+                                            user_ty: PatTyProj::from_user_type(user_ty),
+                                            user_ty_span: ty.span,
+                                            variance: ty::Variance::Covariant,
+                                        },
+                                        subpattern: pattern,
+                                    }),
+                                };
+                            }
                         }
-                    }
 
-                    Some(Stmt {
-                        kind: StmtKind::Let {
-                            remainder_scope,
-                            init_scope: region::Scope {
-                                id: hir_id.local_id,
-                                data: region::ScopeData::Node,
+                        let stmt = Stmt {
+                            kind: StmtKind::Let {
+                                remainder_scope,
+                                init_scope: region::Scope {
+                                    id: hir_id.local_id,
+                                    data: region::ScopeData::Node,
+                                },
+                                pattern,
+                                initializer: local.init.map(|init| self.mirror_expr(init)),
+                                lint_level: LintLevel::Explicit(local.hir_id),
                             },
-                            pattern,
-                            initializer: local.init.map(|init| self.mirror_expr(init)),
-                            lint_level: LintLevel::Explicit(local.hir_id),
-                        },
-                        opt_destruction_scope: opt_dxn_ext,
-                    })
+                            opt_destruction_scope: opt_dxn_ext,
+                        };
+                        Some(self.thir.stmts.push(stmt))
+                    }
                 }
-            }
-        }))
+            })
+            .collect()
     }
 }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 924278e1a7f..9cc7fbdf824 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -17,34 +17,17 @@ use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
 use rustc_middle::ty::{self, AdtKind, Ty};
 use rustc_span::Span;
 
-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> {
+impl<'tcx> Cx<'tcx> {
+    crate fn mirror_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ExprId {
         // `mirror_expr` is recursing very deep. Make sure the stack doesn't overflow.
-        ensure_sufficient_stack(|| self.arena.alloc(self.mirror_expr_inner(expr)))
+        ensure_sufficient_stack(|| 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)))
+    crate fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> Box<[ExprId]> {
+        exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect()
     }
 
-    /// 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> {
+    pub(super) fn mirror_expr_inner(&mut self, hir_expr: &'tcx hir::Expr<'tcx>) -> ExprId {
         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 };
@@ -66,7 +49,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
             span: hir_expr.span,
             kind: ExprKind::Scope {
                 region_scope: expr_scope,
-                value: self.arena.alloc(expr),
+                value: self.thir.exprs.push(expr),
                 lint_level: LintLevel::Explicit(hir_expr.hir_id),
             },
         };
@@ -81,22 +64,22 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                 span: hir_expr.span,
                 kind: ExprKind::Scope {
                     region_scope,
-                    value: self.arena.alloc(expr),
+                    value: self.thir.exprs.push(expr),
                     lint_level: LintLevel::Inherited,
                 },
             };
         }
 
         // OK, all done!
-        expr
+        self.thir.exprs.push(expr)
     }
 
     fn apply_adjustment(
         &mut self,
         hir_expr: &'tcx hir::Expr<'tcx>,
-        mut expr: Expr<'thir, 'tcx>,
+        mut expr: Expr<'tcx>,
         adjustment: &Adjustment<'tcx>,
-    ) -> Expr<'thir, 'tcx> {
+    ) -> Expr<'tcx> {
         let Expr { temp_lifetime, mut span, .. } = expr;
 
         // Adjust the span from the block, to the last expression of the
@@ -109,10 +92,10 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         //      x
         //   // ^ error message points at this expression.
         // }
-        let mut adjust_span = |expr: &mut Expr<'thir, 'tcx>| {
+        let mut adjust_span = |expr: &mut Expr<'tcx>| {
             if let ExprKind::Block { body } = &expr.kind {
-                if let Some(ref last_expr) = body.expr {
-                    span = last_expr.span;
+                if let Some(last_expr) = body.expr {
+                    span = self.thir[last_expr].span;
                     expr.span = span;
                 }
             }
@@ -121,13 +104,13 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         let kind = match adjustment.kind {
             Adjust::Pointer(PointerCast::Unsize) => {
                 adjust_span(&mut expr);
-                ExprKind::Pointer { cast: PointerCast::Unsize, source: self.arena.alloc(expr) }
+                ExprKind::Pointer { cast: PointerCast::Unsize, source: self.thir.exprs.push(expr) }
             }
-            Adjust::Pointer(cast) => ExprKind::Pointer { cast, source: self.arena.alloc(expr) },
-            Adjust::NeverToAny => ExprKind::NeverToAny { source: self.arena.alloc(expr) },
+            Adjust::Pointer(cast) => ExprKind::Pointer { cast, source: self.thir.exprs.push(expr) },
+            Adjust::NeverToAny => ExprKind::NeverToAny { source: self.thir.exprs.push(expr) },
             Adjust::Deref(None) => {
                 adjust_span(&mut expr);
-                ExprKind::Deref { arg: self.arena.alloc(expr) }
+                ExprKind::Deref { arg: self.thir.exprs.push(expr) }
             }
             Adjust::Deref(Some(deref)) => {
                 // We don't need to do call adjust_span here since
@@ -142,30 +125,27 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                     span,
                     kind: ExprKind::Borrow {
                         borrow_kind: deref.mutbl.to_borrow_kind(),
-                        arg: self.arena.alloc(expr),
+                        arg: self.thir.exprs.push(expr),
                     },
                 };
 
-                self.overloaded_place(
-                    hir_expr,
-                    adjustment.target,
-                    Some(call),
-                    self.arena.alloc_from_iter(iter::once(expr)),
-                    deref.span,
-                )
-            }
-            Adjust::Borrow(AutoBorrow::Ref(_, m)) => {
-                ExprKind::Borrow { borrow_kind: m.to_borrow_kind(), arg: self.arena.alloc(expr) }
+                let expr = box [self.thir.exprs.push(expr)];
+
+                self.overloaded_place(hir_expr, adjustment.target, Some(call), expr, deref.span)
             }
+            Adjust::Borrow(AutoBorrow::Ref(_, m)) => ExprKind::Borrow {
+                borrow_kind: m.to_borrow_kind(),
+                arg: self.thir.exprs.push(expr),
+            },
             Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => {
-                ExprKind::AddressOf { mutability, arg: self.arena.alloc(expr) }
+                ExprKind::AddressOf { mutability, arg: self.thir.exprs.push(expr) }
             }
         };
 
         Expr { temp_lifetime, ty: adjustment.target, span, kind }
     }
 
-    fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'thir, 'tcx> {
+    fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> {
         let expr_ty = self.typeck_results().expr_ty(expr);
         let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
 
@@ -177,7 +157,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                 let args = self.mirror_exprs(args);
                 ExprKind::Call {
                     ty: expr.ty,
-                    fun: self.arena.alloc(expr),
+                    fun: self.thir.exprs.push(expr),
                     args,
                     from_hir_call: true,
                     fn_span,
@@ -202,13 +182,12 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                         span: expr.span,
                         kind: ExprKind::Tuple { fields: self.mirror_exprs(args) },
                     };
+                    let tupled_args = self.thir.exprs.push(tupled_args);
 
                     ExprKind::Call {
                         ty: method.ty,
-                        fun: self.arena.alloc(method),
-                        args: self
-                            .arena
-                            .alloc_from_iter(vec![self.mirror_expr_inner(fun), tupled_args]),
+                        fun: self.thir.exprs.push(method),
+                        args: box [self.mirror_expr(fun), tupled_args],
                         from_hir_call: true,
                         fn_span: expr.span,
                     }
@@ -238,10 +217,14 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                             });
                         debug!("make_mirror_unadjusted: (call) user_ty={:?}", user_ty);
 
-                        let field_refs =
-                            self.arena.alloc_from_iter(args.iter().enumerate().map(|(idx, e)| {
-                                FieldExpr { name: Field::new(idx), expr: self.mirror_expr(e) }
-                            }));
+                        let field_refs = args
+                            .iter()
+                            .enumerate()
+                            .map(|(idx, e)| FieldExpr {
+                                name: Field::new(idx),
+                                expr: self.mirror_expr(e),
+                            })
+                            .collect();
                         ExprKind::Adt {
                             adt_def,
                             substs,
@@ -278,9 +261,9 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
 
             hir::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
                 if self.typeck_results().is_method_call(expr) {
-                    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]))
+                    let lhs = self.mirror_expr(lhs);
+                    let rhs = self.mirror_expr(rhs);
+                    self.overloaded_operator(expr, box [lhs, rhs])
                 } else {
                     ExprKind::AssignOp {
                         op: bin_op(op.node),
@@ -298,9 +281,9 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
 
             hir::ExprKind::Binary(op, ref lhs, ref rhs) => {
                 if self.typeck_results().is_method_call(expr) {
-                    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]))
+                    let lhs = self.mirror_expr(lhs);
+                    let rhs = self.mirror_expr(rhs);
+                    self.overloaded_operator(expr, box [lhs, rhs])
                 } else {
                     // FIXME overflow
                     match op.node {
@@ -329,15 +312,9 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
 
             hir::ExprKind::Index(ref lhs, ref index) => {
                 if self.typeck_results().is_method_call(expr) {
-                    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,
-                    )
+                    let lhs = self.mirror_expr(lhs);
+                    let index = self.mirror_expr(index);
+                    self.overloaded_place(expr, expr_ty, None, box [lhs, index], expr.span)
                 } else {
                     ExprKind::Index { lhs: self.mirror_expr(lhs), index: self.mirror_expr(index) }
                 }
@@ -345,14 +322,8 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
 
             hir::ExprKind::Unary(hir::UnOp::Deref, ref arg) => {
                 if self.typeck_results().is_method_call(expr) {
-                    let arg = self.mirror_expr_inner(arg);
-                    self.overloaded_place(
-                        expr,
-                        expr_ty,
-                        None,
-                        self.arena.alloc_from_iter(iter::once(arg)),
-                        expr.span,
-                    )
+                    let arg = self.mirror_expr(arg);
+                    self.overloaded_place(expr, expr_ty, None, box [arg], expr.span)
                 } else {
                     ExprKind::Deref { arg: self.mirror_expr(arg) }
                 }
@@ -360,8 +331,8 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
 
             hir::ExprKind::Unary(hir::UnOp::Not, ref arg) => {
                 if self.typeck_results().is_method_call(expr) {
-                    let arg = self.mirror_expr_inner(arg);
-                    self.overloaded_operator(expr, self.arena.alloc_from_iter(iter::once(arg)))
+                    let arg = self.mirror_expr(arg);
+                    self.overloaded_operator(expr, box [arg])
                 } else {
                     ExprKind::Unary { op: UnOp::Not, arg: self.mirror_expr(arg) }
                 }
@@ -369,8 +340,8 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
 
             hir::ExprKind::Unary(hir::UnOp::Neg, ref arg) => {
                 if self.typeck_results().is_method_call(expr) {
-                    let arg = self.mirror_expr_inner(arg);
-                    self.overloaded_operator(expr, self.arena.alloc_from_iter(iter::once(arg)))
+                    let arg = self.mirror_expr(arg);
+                    self.overloaded_operator(expr, box [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),
@@ -396,11 +367,10 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                             fields: self.field_refs(fields),
                             base: base.as_ref().map(|base| FruInfo {
                                 base: self.mirror_expr(base),
-                                field_types: self.arena.alloc_from_iter(
-                                    self.typeck_results().fru_field_types()[expr.hir_id]
-                                        .iter()
-                                        .cloned(),
-                                ),
+                                field_types: self.typeck_results().fru_field_types()[expr.hir_id]
+                                    .iter()
+                                    .copied()
+                                    .collect(),
                             }),
                         }
                     }
@@ -447,12 +417,15 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                     }
                 };
 
-                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)),
-                );
+                let upvars = self
+                    .typeck_results
+                    .closure_min_captures_flattened(def_id)
+                    .zip(substs.upvar_tys())
+                    .map(|(captured_place, ty)| {
+                        let upvars = self.capture_upvar(expr, captured_place, ty);
+                        self.thir.exprs.push(upvars)
+                    })
+                    .collect();
 
                 // Convert the closure fake reads, if any, from hir `Place` to ExprRef
                 let fake_reads = match self.typeck_results.closure_fake_reads.get(&def_id) {
@@ -460,8 +433,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                         .iter()
                         .map(|(place, cause, hir_id)| {
                             let expr = self.convert_captured_hir_place(expr, place.clone());
-                            let expr_ref: &'thir Expr<'thir, 'tcx> = self.arena.alloc(expr);
-                            (expr_ref, *cause, *hir_id)
+                            (self.thir.exprs.push(expr), *cause, *hir_id)
                         })
                         .collect(),
                     None => Vec::new(),
@@ -477,99 +449,105 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
 
             hir::ExprKind::InlineAsm(ref asm) => ExprKind::InlineAsm {
                 template: asm.template,
-                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 {
+                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,
-                                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 {
-                            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 anon_const } => {
-                            let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
-                            let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
-                            let span = self.tcx.hir().span(anon_const.hir_id);
+                                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 anon_const } => {
+                                let anon_const_def_id =
+                                    self.tcx.hir().local_def_id(anon_const.hir_id);
+                                let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
+                                let span = self.tcx.hir().span(anon_const.hir_id);
 
-                            InlineAsmOperand::Const { value, span }
-                        }
-                        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,
-                                            },
-                                        }),
+                                InlineAsmOperand::Const { value, span }
+                            }
+                            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.thir.exprs.push(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: 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,
-                                            },
-                                        }),
+                                    _ => {
+                                        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.thir.exprs.push(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,
             },
@@ -616,13 +594,13 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
             },
             hir::ExprKind::Match(ref discr, ref arms, _) => ExprKind::Match {
                 scrutinee: self.mirror_expr(discr),
-                arms: self.arena.alloc_from_iter(arms.iter().map(|a| self.convert_arm(a))),
+                arms: arms.iter().map(|a| self.convert_arm(a)).collect(),
             },
             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 = self.arena.alloc(Expr {
+                let body = self.thir.exprs.push(Expr {
                     ty: block_ty,
                     temp_lifetime,
                     span: block.span,
@@ -692,35 +670,34 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                     };
 
                     let source = if let Some((did, offset, var_ty)) = var {
-                        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 mk_const = |literal| 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(
+                        let offset = self.thir.exprs.push(mk_const(ty::Const::from_bits(
                             self.tcx,
                             offset as u128,
                             self.param_env.and(var_ty),
-                        ));
+                        )));
                         match did {
                             Some(did) => {
                                 // in case we are offsetting from a computed discriminant
                                 // and not the beginning of discriminants (which is always `0`)
                                 let substs = InternalSubsts::identity_for_item(self.tcx(), did);
-                                let lhs = mk_const(self.tcx().mk_const(ty::Const {
+                                let lhs = ty::Const {
                                     val: ty::ConstKind::Unevaluated(ty::Unevaluated {
                                         def: ty::WithOptConstParam::unknown(did),
                                         substs,
                                         promoted: None,
                                     }),
                                     ty: var_ty,
-                                }));
+                                };
+                                let lhs = self.thir.exprs.push(mk_const(self.tcx().mk_const(lhs)));
                                 let bin =
                                     ExprKind::Binary { op: BinOp::Add, lhs: lhs, rhs: offset };
-                                self.arena.alloc(Expr {
+                                self.thir.exprs.push(Expr {
                                     temp_lifetime,
                                     ty: var_ty,
                                     span: expr.span,
@@ -739,7 +716,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                 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 = self.arena.alloc(Expr {
+                    let cast_expr = self.thir.exprs.push(Expr {
                         temp_lifetime,
                         ty: expr_ty,
                         span: expr.span,
@@ -819,7 +796,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         expr: &hir::Expr<'_>,
         span: Span,
         overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
-    ) -> Expr<'thir, 'tcx> {
+    ) -> Expr<'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),
@@ -846,8 +823,8 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         }
     }
 
-    fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> Arm<'thir, 'tcx> {
-        Arm {
+    fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ArmId {
+        let arm = 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(e)),
@@ -859,14 +836,11 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
             lint_level: LintLevel::Explicit(arm.hir_id),
             scope: region::Scope { id: arm.hir_id.local_id, data: region::ScopeData::Node },
             span: arm.span,
-        }
+        };
+        self.thir.arms.push(arm)
     }
 
-    fn convert_path_expr(
-        &mut self,
-        expr: &'tcx hir::Expr<'tcx>,
-        res: Res,
-    ) -> ExprKind<'thir, 'tcx> {
+    fn convert_path_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, res: Res) -> ExprKind<'tcx> {
         let substs = self.typeck_results().node_substs(expr.hir_id);
         match res {
             // A regular function, constructor function or a constant.
@@ -934,7 +908,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                         variant_index: adt_def.variant_index_with_ctor_id(def_id),
                         substs,
                         user_ty: user_provided_type,
-                        fields: self.arena.alloc_from_iter(iter::empty()),
+                        fields: box [],
                         base: None,
                     },
                     _ => bug!("unexpected ty: {:?}", ty),
@@ -956,7 +930,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                     }
                 };
                 ExprKind::Deref {
-                    arg: self.arena.alloc(Expr { ty, temp_lifetime, span: expr.span, kind }),
+                    arg: self.thir.exprs.push(Expr { ty, temp_lifetime, span: expr.span, kind }),
                 }
             }
 
@@ -966,7 +940,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         }
     }
 
-    fn convert_var(&mut self, var_hir_id: hir::HirId) -> ExprKind<'thir, 'tcx> {
+    fn convert_var(&mut self, var_hir_id: hir::HirId) -> ExprKind<'tcx> {
         // We want upvars here not captures.
         // Captures will be handled in MIR.
         let is_upvar = self
@@ -989,10 +963,17 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
     fn overloaded_operator(
         &mut self,
         expr: &'tcx hir::Expr<'tcx>,
-        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 }
+        args: Box<[ExprId]>,
+    ) -> ExprKind<'tcx> {
+        let fun = self.method_callee(expr, expr.span, None);
+        let fun = self.thir.exprs.push(fun);
+        ExprKind::Call {
+            ty: self.thir[fun].ty,
+            fun,
+            args,
+            from_hir_call: false,
+            fn_span: expr.span,
+        }
     }
 
     fn overloaded_place(
@@ -1000,9 +981,9 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         expr: &'tcx hir::Expr<'tcx>,
         place_ty: Ty<'tcx>,
         overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
-        args: &'thir [Expr<'thir, 'tcx>],
+        args: Box<[ExprId]>,
         span: Span,
-    ) -> ExprKind<'thir, 'tcx> {
+    ) -> ExprKind<'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):
@@ -1010,7 +991,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         // Reconstruct the output assuming it's a reference with the
         // same region and mutability as the receiver. This holds for
         // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
-        let (region, mutbl) = match *args[0].ty.kind() {
+        let (region, mutbl) = match *self.thir[args[0]].ty.kind() {
             ty::Ref(region, _, mutbl) => (region, mutbl),
             _ => span_bug!(span, "overloaded_place: receiver is not a reference"),
         };
@@ -1019,12 +1000,14 @@ impl<'thir, 'tcx> Cx<'thir, '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 = self.arena.alloc(self.method_callee(expr, span, overloaded_callee));
-        let ref_expr = self.arena.alloc(Expr {
+        let fun = self.method_callee(expr, span, overloaded_callee);
+        let fun = self.thir.exprs.push(fun);
+        let fun_ty = self.thir[fun].ty;
+        let ref_expr = self.thir.exprs.push(Expr {
             temp_lifetime,
             ty: ref_ty,
             span,
-            kind: ExprKind::Call { ty: fun.ty, fun, args, from_hir_call: false, fn_span: span },
+            kind: ExprKind::Call { ty: fun_ty, fun, args, from_hir_call: false, fn_span: span },
         });
 
         // construct and return a deref wrapper `*foo()`
@@ -1035,7 +1018,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         &mut self,
         closure_expr: &'tcx hir::Expr<'tcx>,
         place: HirPlace<'tcx>,
-    ) -> Expr<'thir, 'tcx> {
+    ) -> Expr<'tcx> {
         let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
         let var_ty = place.base_ty;
 
@@ -1059,13 +1042,13 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         for proj in place.projections.iter() {
             let kind = match proj.kind {
                 HirProjectionKind::Deref => {
-                    ExprKind::Deref { arg: self.arena.alloc(captured_place_expr) }
+                    ExprKind::Deref { arg: self.thir.exprs.push(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: self.arena.alloc(captured_place_expr),
+                        lhs: self.thir.exprs.push(captured_place_expr),
                         name: Field::new(field as usize),
                     }
                 }
@@ -1087,7 +1070,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         closure_expr: &'tcx hir::Expr<'tcx>,
         captured_place: &'tcx ty::CapturedPlace<'tcx>,
         upvar_ty: Ty<'tcx>,
-    ) -> Expr<'thir, 'tcx> {
+    ) -> Expr<'tcx> {
         let upvar_capture = captured_place.info.capture_kind;
         let captured_place_expr =
             self.convert_captured_hir_place(closure_expr, captured_place.place.clone());
@@ -1107,7 +1090,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                     span: closure_expr.span,
                     kind: ExprKind::Borrow {
                         borrow_kind,
-                        arg: self.arena.alloc(captured_place_expr),
+                        arg: self.thir.exprs.push(captured_place_expr),
                     },
                 }
             }
@@ -1115,14 +1098,14 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
     }
 
     /// Converts a list of named fields (i.e., for struct-like struct/enum ADTs) into FieldExpr.
-    fn field_refs(
-        &mut self,
-        fields: &'tcx [hir::ExprField<'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),
-        }))
+    fn field_refs(&mut self, fields: &'tcx [hir::ExprField<'tcx>]) -> Box<[FieldExpr]> {
+        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()
     }
 }
 
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index c0433604f8c..aad6319e404 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -2,7 +2,6 @@
 //! 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::*;
 
@@ -14,18 +13,19 @@ use rustc_middle::middle::region;
 use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
-pub fn build_thir<'thir, 'tcx>(
+pub fn build_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)
+) -> (Thir<'tcx>, ExprId) {
+    let mut cx = Cx::new(tcx, owner_def);
+    let expr = cx.mirror_expr(expr);
+    (cx.thir, expr)
 }
 
-struct Cx<'thir, 'tcx> {
+struct Cx<'tcx> {
     tcx: TyCtxt<'tcx>,
-    arena: &'thir Arena<'thir, 'tcx>,
+    thir: Thir<'tcx>,
 
     crate param_env: ty::ParamEnv<'tcx>,
 
@@ -36,16 +36,12 @@ struct Cx<'thir, 'tcx> {
     body_owner: DefId,
 }
 
-impl<'thir, 'tcx> Cx<'thir, 'tcx> {
-    fn new(
-        tcx: TyCtxt<'tcx>,
-        def: ty::WithOptConstParam<LocalDefId>,
-        arena: &'thir Arena<'thir, 'tcx>,
-    ) -> Cx<'thir, 'tcx> {
+impl<'tcx> Cx<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) -> Cx<'tcx> {
         let typeck_results = tcx.typeck_opt_const_arg(def);
         Cx {
             tcx,
-            arena,
+            thir: Thir::new(),
             param_env: tcx.param_env(def.did),
             region_scope_tree: tcx.region_scope_tree(def.did),
             typeck_results,
@@ -87,7 +83,7 @@ impl<'thir, 'tcx> Cx<'thir, '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 9bcb000920c..d188d17dd56 100644
--- a/compiler/rustc_mir_build/src/thir/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/mod.rs
@@ -7,6 +7,8 @@
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_index::newtype_index;
+use rustc_index::vec::IndexVec;
 use rustc_middle::infer::canonical::Canonical;
 use rustc_middle::middle::region;
 use rustc_middle::mir::{BinOp, BorrowKind, FakeReadCause, Field, UnOp};
@@ -17,6 +19,8 @@ use rustc_span::Span;
 use rustc_target::abi::VariantIdx;
 use rustc_target::asm::InlineAsmRegOrRegClass;
 
+use std::ops::Index;
+
 crate mod constant;
 
 crate mod cx;
@@ -25,12 +29,62 @@ pub use cx::build_thir;
 crate mod pattern;
 pub use self::pattern::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange, PatTyProj};
 
-mod arena;
-pub use arena::Arena;
-
 mod util;
 pub mod visit;
 
+newtype_index! {
+    pub struct ArmId {
+        DEBUG_FORMAT = "a{}"
+    }
+}
+
+newtype_index! {
+    pub struct ExprId {
+        DEBUG_FORMAT = "e{}"
+    }
+}
+
+newtype_index! {
+    pub struct StmtId {
+        DEBUG_FORMAT = "s{}"
+    }
+}
+
+macro_rules! thir_with_elements {
+    ($($name:ident: $id:ty => $value:ty,)*) => {
+        pub struct Thir<'tcx> {
+            $(
+                $name: IndexVec<$id, $value>,
+            )*
+        }
+
+        impl<'tcx> Thir<'tcx> {
+            fn new() -> Thir<'tcx> {
+                Thir {
+                    $(
+                        $name: IndexVec::new(),
+                    )*
+                }
+            }
+        }
+
+        $(
+            impl<'tcx> Index<$id> for Thir<'tcx> {
+                type Output = $value;
+                fn index(&self, index: $id) -> &Self::Output {
+                    &self.$name[index]
+                }
+            }
+        )*
+    }
+}
+
+thir_with_elements! {
+    arms: ArmId => Arm<'tcx>,
+    exprs: ExprId => Expr<'tcx>,
+    stmts: StmtId => Stmt<'tcx>,
+}
+
 #[derive(Copy, Clone, Debug)]
 pub enum LintLevel {
     Inherited,
@@ -38,13 +92,13 @@ pub enum LintLevel {
 }
 
 #[derive(Debug)]
-pub struct Block<'thir, 'tcx> {
+pub struct Block {
     pub targeted_by_break: bool,
     pub region_scope: region::Scope,
     pub opt_destruction_scope: Option<region::Scope>,
     pub span: Span,
-    pub stmts: &'thir [Stmt<'thir, 'tcx>],
-    pub expr: Option<&'thir Expr<'thir, 'tcx>>,
+    pub stmts: Box<[StmtId]>,
+    pub expr: Option<ExprId>,
     pub safety_mode: BlockSafety,
 }
 
@@ -57,19 +111,19 @@ pub enum BlockSafety {
 }
 
 #[derive(Debug)]
-pub struct Stmt<'thir, 'tcx> {
-    pub kind: StmtKind<'thir, 'tcx>,
+pub struct Stmt<'tcx> {
+    pub kind: StmtKind<'tcx>,
     pub opt_destruction_scope: Option<region::Scope>,
 }
 
 #[derive(Debug)]
-pub enum StmtKind<'thir, 'tcx> {
+pub enum StmtKind<'tcx> {
     Expr {
         /// scope for this statement; may be used as lifetime of temporaries
         scope: region::Scope,
 
         /// expression being evaluated in this statement
-        expr: &'thir Expr<'thir, 'tcx>,
+        expr: ExprId,
     },
 
     Let {
@@ -87,7 +141,7 @@ pub enum StmtKind<'thir, 'tcx> {
         pattern: Pat<'tcx>,
 
         /// let pat: ty = <INIT> ...
-        initializer: Option<&'thir Expr<'thir, 'tcx>>,
+        initializer: Option<ExprId>,
 
         /// the lint level for this let-statement
         lint_level: LintLevel,
@@ -96,12 +150,12 @@ pub enum StmtKind<'thir, '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<'_, '_>, 144);
+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 `&'thir Expr<'thir, 'tcx>`, which
+/// reference to an expression in this enum is an `ExprId`, 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
@@ -113,7 +167,7 @@ rustc_data_structures::static_assert_size!(Expr<'_, '_>, 144);
 /// example, method calls and overloaded operators are absent: they are
 /// expected to be converted into `Expr::Call` instances.
 #[derive(Debug)]
-pub struct Expr<'thir, 'tcx> {
+pub struct Expr<'tcx> {
     /// type of this expression
     pub ty: Ty<'tcx>,
 
@@ -125,28 +179,28 @@ pub struct Expr<'thir, 'tcx> {
     pub span: Span,
 
     /// kind of expression
-    pub kind: ExprKind<'thir, 'tcx>,
+    pub kind: ExprKind<'tcx>,
 }
 
 #[derive(Debug)]
-pub enum ExprKind<'thir, 'tcx> {
+pub enum ExprKind<'tcx> {
     Scope {
         region_scope: region::Scope,
         lint_level: LintLevel,
-        value: &'thir Expr<'thir, 'tcx>,
+        value: ExprId,
     },
     Box {
-        value: &'thir Expr<'thir, 'tcx>,
+        value: ExprId,
     },
     If {
-        cond: &'thir Expr<'thir, 'tcx>,
-        then: &'thir Expr<'thir, 'tcx>,
-        else_opt: Option<&'thir Expr<'thir, 'tcx>>,
+        cond: ExprId,
+        then: ExprId,
+        else_opt: Option<ExprId>,
     },
     Call {
         ty: Ty<'tcx>,
-        fun: &'thir Expr<'thir, 'tcx>,
-        args: &'thir [Expr<'thir, 'tcx>],
+        fun: ExprId,
+        args: Box<[ExprId]>,
         /// Whether this is from a call in HIR, rather than from an overloaded
         /// operator. `true` for overloaded function call.
         from_hir_call: bool,
@@ -155,62 +209,62 @@ pub enum ExprKind<'thir, 'tcx> {
         fn_span: Span,
     },
     Deref {
-        arg: &'thir Expr<'thir, 'tcx>,
+        arg: ExprId,
     }, // NOT overloaded!
     Binary {
         op: BinOp,
-        lhs: &'thir Expr<'thir, 'tcx>,
-        rhs: &'thir Expr<'thir, 'tcx>,
+        lhs: ExprId,
+        rhs: ExprId,
     }, // NOT overloaded!
     LogicalOp {
         op: LogicalOp,
-        lhs: &'thir Expr<'thir, 'tcx>,
-        rhs: &'thir Expr<'thir, 'tcx>,
+        lhs: ExprId,
+        rhs: ExprId,
     }, // NOT overloaded!
     // LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands.
     Unary {
         op: UnOp,
-        arg: &'thir Expr<'thir, 'tcx>,
+        arg: ExprId,
     }, // NOT overloaded!
     Cast {
-        source: &'thir Expr<'thir, 'tcx>,
+        source: ExprId,
     },
     Use {
-        source: &'thir Expr<'thir, 'tcx>,
+        source: ExprId,
     }, // Use a lexpr to get a vexpr.
     NeverToAny {
-        source: &'thir Expr<'thir, 'tcx>,
+        source: ExprId,
     },
     Pointer {
         cast: PointerCast,
-        source: &'thir Expr<'thir, 'tcx>,
+        source: ExprId,
     },
     Loop {
-        body: &'thir Expr<'thir, 'tcx>,
+        body: ExprId,
     },
     Match {
-        scrutinee: &'thir Expr<'thir, 'tcx>,
-        arms: &'thir [Arm<'thir, 'tcx>],
+        scrutinee: ExprId,
+        arms: Box<[ArmId]>,
     },
     Block {
-        body: Block<'thir, 'tcx>,
+        body: Block,
     },
     Assign {
-        lhs: &'thir Expr<'thir, 'tcx>,
-        rhs: &'thir Expr<'thir, 'tcx>,
+        lhs: ExprId,
+        rhs: ExprId,
     },
     AssignOp {
         op: BinOp,
-        lhs: &'thir Expr<'thir, 'tcx>,
-        rhs: &'thir Expr<'thir, 'tcx>,
+        lhs: ExprId,
+        rhs: ExprId,
     },
     Field {
-        lhs: &'thir Expr<'thir, 'tcx>,
+        lhs: ExprId,
         name: Field,
     },
     Index {
-        lhs: &'thir Expr<'thir, 'tcx>,
-        index: &'thir Expr<'thir, 'tcx>,
+        lhs: ExprId,
+        index: ExprId,
     },
     VarRef {
         id: hir::HirId,
@@ -225,35 +279,35 @@ pub enum ExprKind<'thir, 'tcx> {
     },
     Borrow {
         borrow_kind: BorrowKind,
-        arg: &'thir Expr<'thir, 'tcx>,
+        arg: ExprId,
     },
     /// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`.
     AddressOf {
         mutability: hir::Mutability,
-        arg: &'thir Expr<'thir, 'tcx>,
+        arg: ExprId,
     },
     Break {
         label: region::Scope,
-        value: Option<&'thir Expr<'thir, 'tcx>>,
+        value: Option<ExprId>,
     },
     Continue {
         label: region::Scope,
     },
     Return {
-        value: Option<&'thir Expr<'thir, 'tcx>>,
+        value: Option<ExprId>,
     },
     ConstBlock {
         value: &'tcx Const<'tcx>,
     },
     Repeat {
-        value: &'thir Expr<'thir, 'tcx>,
+        value: ExprId,
         count: &'tcx Const<'tcx>,
     },
     Array {
-        fields: &'thir [Expr<'thir, 'tcx>],
+        fields: Box<[ExprId]>,
     },
     Tuple {
-        fields: &'thir [Expr<'thir, 'tcx>],
+        fields: Box<[ExprId]>,
     },
     Adt {
         adt_def: &'tcx AdtDef,
@@ -264,25 +318,25 @@ pub enum ExprKind<'thir, 'tcx> {
         /// Bar::<T> { ... }`.
         user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
 
-        fields: &'thir [FieldExpr<'thir, 'tcx>],
-        base: Option<FruInfo<'thir, 'tcx>>,
+        fields: Box<[FieldExpr]>,
+        base: Option<FruInfo<'tcx>>,
     },
     PlaceTypeAscription {
-        source: &'thir Expr<'thir, 'tcx>,
+        source: ExprId,
         /// Type that the user gave to this expression
         user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
     },
     ValueTypeAscription {
-        source: &'thir Expr<'thir, 'tcx>,
+        source: ExprId,
         /// Type that the user gave to this expression
         user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
     },
     Closure {
         closure_id: DefId,
         substs: UpvarSubsts<'tcx>,
-        upvars: &'thir [Expr<'thir, 'tcx>],
+        upvars: Box<[ExprId]>,
         movability: Option<hir::Movability>,
-        fake_reads: Vec<(&'thir Expr<'thir, 'tcx>, FakeReadCause, hir::HirId)>,
+        fake_reads: Vec<(ExprId, FakeReadCause, hir::HirId)>,
     },
     Literal {
         literal: &'tcx Const<'tcx>,
@@ -302,7 +356,7 @@ pub enum ExprKind<'thir, 'tcx> {
     },
     InlineAsm {
         template: &'tcx [InlineAsmTemplatePiece],
-        operands: &'thir [InlineAsmOperand<'thir, 'tcx>],
+        operands: Box<[InlineAsmOperand<'tcx>]>,
         options: InlineAsmOptions,
         line_spans: &'tcx [Span],
     },
@@ -310,40 +364,40 @@ pub enum ExprKind<'thir, 'tcx> {
     ThreadLocalRef(DefId),
     LlvmInlineAsm {
         asm: &'tcx hir::LlvmInlineAsmInner,
-        outputs: &'thir [Expr<'thir, 'tcx>],
-        inputs: &'thir [Expr<'thir, 'tcx>],
+        outputs: Box<[ExprId]>,
+        inputs: Box<[ExprId]>,
     },
     Yield {
-        value: &'thir Expr<'thir, 'tcx>,
+        value: ExprId,
     },
 }
 
 #[derive(Debug)]
-pub struct FieldExpr<'thir, 'tcx> {
+pub struct FieldExpr {
     pub name: Field,
-    pub expr: &'thir Expr<'thir, 'tcx>,
+    pub expr: ExprId,
 }
 
 #[derive(Debug)]
-pub struct FruInfo<'thir, 'tcx> {
-    pub base: &'thir Expr<'thir, 'tcx>,
-    pub field_types: &'thir [Ty<'tcx>],
+pub struct FruInfo<'tcx> {
+    pub base: ExprId,
+    pub field_types: Box<[Ty<'tcx>]>,
 }
 
 #[derive(Debug)]
-pub struct Arm<'thir, 'tcx> {
+pub struct Arm<'tcx> {
     pub pattern: Pat<'tcx>,
-    pub guard: Option<Guard<'thir, 'tcx>>,
-    pub body: &'thir Expr<'thir, 'tcx>,
+    pub guard: Option<Guard<'tcx>>,
+    pub body: ExprId,
     pub lint_level: LintLevel,
     pub scope: region::Scope,
     pub span: Span,
 }
 
 #[derive(Debug)]
-pub enum Guard<'thir, 'tcx> {
-    If(&'thir Expr<'thir, 'tcx>),
-    IfLet(Pat<'tcx>, &'thir Expr<'thir, 'tcx>),
+pub enum Guard<'tcx> {
+    If(ExprId),
+    IfLet(Pat<'tcx>, ExprId),
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -353,33 +407,33 @@ pub enum LogicalOp {
 }
 
 #[derive(Debug)]
-pub enum InlineAsmOperand<'thir, 'tcx> {
+pub enum InlineAsmOperand<'tcx> {
     In {
         reg: InlineAsmRegOrRegClass,
-        expr: &'thir Expr<'thir, 'tcx>,
+        expr: ExprId,
     },
     Out {
         reg: InlineAsmRegOrRegClass,
         late: bool,
-        expr: Option<&'thir Expr<'thir, 'tcx>>,
+        expr: Option<ExprId>,
     },
     InOut {
         reg: InlineAsmRegOrRegClass,
         late: bool,
-        expr: &'thir Expr<'thir, 'tcx>,
+        expr: ExprId,
     },
     SplitInOut {
         reg: InlineAsmRegOrRegClass,
         late: bool,
-        in_expr: &'thir Expr<'thir, 'tcx>,
-        out_expr: Option<&'thir Expr<'thir, 'tcx>>,
+        in_expr: ExprId,
+        out_expr: Option<ExprId>,
     },
     Const {
         value: &'tcx Const<'tcx>,
         span: Span,
     },
     SymFn {
-        expr: &'thir Expr<'thir, 'tcx>,
+        expr: ExprId,
     },
     SymStatic {
         def_id: DefId,