1
Fork 0

[WIP] Eagerly construct bodies of THIR

This commit is contained in:
LeSeulArtichaut 2021-02-24 21:29:09 +01:00
parent 3a5d45f68c
commit 60def4de5e
18 changed files with 1379 additions and 1618 deletions

View file

@ -2,7 +2,6 @@ use crate::build::matches::ArmHasGuard;
use crate::build::ForGuard::OutsideGuard; use crate::build::ForGuard::OutsideGuard;
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
use crate::thir::*; use crate::thir::*;
use rustc_hir as hir;
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN; use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN;
use rustc_session::lint::Level; use rustc_session::lint::Level;
@ -13,7 +12,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&mut self, &mut self,
destination: Place<'tcx>, destination: Place<'tcx>,
block: BasicBlock, block: BasicBlock,
ast_block: &'tcx hir::Block<'tcx>, ast_block: &Block<'tcx>,
source_info: SourceInfo, source_info: SourceInfo,
) -> BlockAnd<()> { ) -> BlockAnd<()> {
let Block { let Block {
@ -24,22 +23,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
expr, expr,
targeted_by_break, targeted_by_break,
safety_mode, safety_mode,
} = self.hir.mirror(ast_block); } = ast_block;
self.in_opt_scope(opt_destruction_scope.map(|de| (de, source_info)), move |this| { 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| { this.in_scope((*region_scope, source_info), LintLevel::Inherited, move |this| {
if targeted_by_break { if *targeted_by_break {
this.in_breakable_scope(None, destination, span, |this| { this.in_breakable_scope(None, destination, *span, |this| {
Some(this.ast_block_stmts( Some(this.ast_block_stmts(
destination, destination,
block, block,
span, *span,
stmts, &stmts,
expr, expr.as_deref(),
safety_mode, *safety_mode,
)) ))
}) })
} else { } else {
this.ast_block_stmts(destination, block, span, stmts, expr, safety_mode) this.ast_block_stmts(
destination,
block,
*span,
&stmts,
expr.as_deref(),
*safety_mode,
)
} }
}) })
}) })
@ -50,8 +56,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
destination: Place<'tcx>, destination: Place<'tcx>,
mut block: BasicBlock, mut block: BasicBlock,
span: Span, span: Span,
stmts: Vec<StmtRef<'tcx>>, stmts: &[Stmt<'tcx>],
expr: Option<ExprRef<'tcx>>, expr: Option<&Expr<'tcx>>,
safety_mode: BlockSafety, safety_mode: BlockSafety,
) -> BlockAnd<()> { ) -> BlockAnd<()> {
let this = self; let this = self;
@ -79,8 +85,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
this.update_source_scope_for_safety_mode(span, safety_mode); this.update_source_scope_for_safety_mode(span, safety_mode);
let source_info = this.source_info(span); let source_info = this.source_info(span);
for stmt in stmts { for Stmt { kind, opt_destruction_scope } in stmts {
let Stmt { kind, opt_destruction_scope } = this.hir.mirror(stmt);
match kind { match kind {
StmtKind::Expr { scope, expr } => { StmtKind::Expr { scope, expr } => {
this.block_context.push(BlockFrame::Statement { ignores_expr_result: true }); this.block_context.push(BlockFrame::Statement { ignores_expr_result: true });
@ -88,10 +93,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block = this.in_opt_scope( block = this.in_opt_scope(
opt_destruction_scope.map(|de| (de, source_info)), opt_destruction_scope.map(|de| (de, source_info)),
|this| { |this| {
let si = (scope, source_info); let si = (*scope, source_info);
this.in_scope(si, LintLevel::Inherited, |this| { this.in_scope(si, LintLevel::Inherited, |this| {
let expr = this.hir.mirror(expr); this.stmt_expr(block, &expr, Some(*scope))
this.stmt_expr(block, expr, Some(scope))
}) })
} }
) )
@ -102,7 +106,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
this.block_context.push(BlockFrame::Statement { ignores_expr_result }); this.block_context.push(BlockFrame::Statement { ignores_expr_result });
// Enter the remainder scope, i.e., the bindings' destruction scope. // Enter the remainder scope, i.e., the bindings' destruction scope.
this.push_scope((remainder_scope, source_info)); this.push_scope((*remainder_scope, source_info));
let_scope_stack.push(remainder_scope); let_scope_stack.push(remainder_scope);
// Declare the bindings, which may create a source scope. // Declare the bindings, which may create a source scope.
@ -114,14 +118,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Evaluate the initializer, if present. // Evaluate the initializer, if present.
if let Some(init) = initializer { if let Some(init) = initializer {
let initializer_span = init.span(); let initializer_span = init.span;
unpack!( unpack!(
block = this.in_opt_scope( block = this.in_opt_scope(
opt_destruction_scope.map(|de| (de, source_info)), opt_destruction_scope.map(|de| (de, source_info)),
|this| { |this| {
let scope = (init_scope, source_info); let scope = (*init_scope, source_info);
this.in_scope(scope, lint_level, |this| { this.in_scope(scope, *lint_level, |this| {
this.declare_bindings( this.declare_bindings(
visibility_scope, visibility_scope,
remainder_span, remainder_span,
@ -129,14 +133,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ArmHasGuard(false), ArmHasGuard(false),
Some((None, initializer_span)), Some((None, initializer_span)),
); );
this.expr_into_pattern(block, pattern, init) this.expr_into_pattern(block, pattern.clone(), &init)
}) })
} }
) )
); );
} else { } else {
let scope = (init_scope, source_info); let scope = (*init_scope, source_info);
unpack!(this.in_scope(scope, lint_level, |this| { unpack!(this.in_scope(scope, *lint_level, |this| {
this.declare_bindings( this.declare_bindings(
visibility_scope, visibility_scope,
remainder_span, remainder_span,
@ -176,13 +180,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
if let Some(expr) = expr { if let Some(expr) = expr {
let tail_result_is_ignored = let tail_result_is_ignored =
destination_ty.is_unit() || this.block_context.currently_ignores_tail_results(); destination_ty.is_unit() || this.block_context.currently_ignores_tail_results();
let span = match expr { this.block_context
ExprRef::Thir(expr) => expr.span, .push(BlockFrame::TailExpr { tail_result_is_ignored, span: expr.span });
ExprRef::Mirror(ref expr) => expr.span,
};
this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored, span });
unpack!(block = this.into(destination, block, expr)); unpack!(block = this.expr_into_dest(destination, block, expr));
let popped = this.block_context.pop(); let popped = this.block_context.pop();
assert!(popped.map_or(false, |bf| bf.is_tail_expr())); assert!(popped.map_or(false, |bf| bf.is_tail_expr()));
@ -200,7 +201,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Finally, we pop all the let scopes before exiting out from the scope of block // Finally, we pop all the let scopes before exiting out from the scope of block
// itself. // itself.
for scope in let_scope_stack.into_iter().rev() { for scope in let_scope_stack.into_iter().rev() {
unpack!(block = this.pop_scope((scope, source_info), block)); unpack!(block = this.pop_scope((*scope, source_info), block));
} }
// Restore the original source scope. // Restore the original source scope.
this.source_scope = outer_source_scope; this.source_scope = outer_source_scope;

View file

@ -8,33 +8,27 @@ use rustc_middle::ty::CanonicalUserTypeAnnotation;
impl<'a, 'tcx> Builder<'a, 'tcx> { impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Compile `expr`, yielding a compile-time constant. Assumes that /// Compile `expr`, yielding a compile-time constant. Assumes that
/// `expr` is a valid compile-time constant! /// `expr` is a valid compile-time constant!
crate fn as_constant<M>(&mut self, expr: M) -> Constant<'tcx> crate fn as_constant(&mut self, expr: &Expr<'tcx>) -> Constant<'tcx> {
where
M: Mirror<'tcx, Output = Expr<'tcx>>,
{
let expr = self.hir.mirror(expr);
self.expr_as_constant(expr)
}
fn expr_as_constant(&mut self, expr: Expr<'tcx>) -> Constant<'tcx> {
let this = self; let this = self;
let Expr { ty, temp_lifetime: _, span, kind } = expr; let Expr { ty, temp_lifetime: _, span, kind } = expr;
match kind { match kind {
ExprKind::Scope { region_scope: _, lint_level: _, value } => this.as_constant(value), ExprKind::Scope { region_scope: _, lint_level: _, value } => this.as_constant(&value),
ExprKind::Literal { literal, user_ty, const_id: _ } => { ExprKind::Literal { literal, user_ty, const_id: _ } => {
let user_ty = user_ty.map(|user_ty| { let user_ty = user_ty.map(|user_ty| {
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
span, span: *span,
user_ty, user_ty,
inferred_ty: ty, inferred_ty: ty,
}) })
}); });
assert_eq!(literal.ty, ty); assert_eq!(literal.ty, *ty);
Constant { span, user_ty, literal } Constant { span: *span, user_ty, literal }
} }
ExprKind::StaticRef { literal, .. } => Constant { span, user_ty: None, literal }, ExprKind::StaticRef { literal, .. } => Constant { span: *span, user_ty: None, literal },
ExprKind::ConstBlock { value } => Constant { span, user_ty: None, literal: value }, ExprKind::ConstBlock { value } => {
_ => span_bug!(span, "expression is not a valid constant {:?}", kind), Constant { span: *span, user_ty: None, literal: value }
}
_ => span_bug!(*span, "expression is not a valid constant {:?}", kind),
} }
} }
} }

View file

@ -14,10 +14,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// after the current enclosing `ExprKind::Scope` has ended, so /// after the current enclosing `ExprKind::Scope` has ended, so
/// please do *not* return it from functions to avoid bad /// please do *not* return it from functions to avoid bad
/// miscompiles. /// miscompiles.
crate fn as_local_operand<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Operand<'tcx>> crate fn as_local_operand(
where &mut self,
M: Mirror<'tcx, Output = Expr<'tcx>>, block: BasicBlock,
{ expr: &Expr<'tcx>,
) -> BlockAnd<Operand<'tcx>> {
let local_scope = self.local_scope(); let local_scope = self.local_scope();
self.as_operand(block, Some(local_scope), expr) self.as_operand(block, Some(local_scope), expr)
} }
@ -70,14 +71,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// value to the stack. /// value to the stack.
/// ///
/// See #68034 for more details. /// See #68034 for more details.
crate fn as_local_call_operand<M>( crate fn as_local_call_operand(
&mut self, &mut self,
block: BasicBlock, block: BasicBlock,
expr: M, expr: &Expr<'tcx>,
) -> BlockAnd<Operand<'tcx>> ) -> BlockAnd<Operand<'tcx>> {
where
M: Mirror<'tcx, Output = Expr<'tcx>>,
{
let local_scope = self.local_scope(); let local_scope = self.local_scope();
self.as_call_operand(block, Some(local_scope), expr) self.as_call_operand(block, Some(local_scope), expr)
} }
@ -88,52 +86,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// this time. /// this time.
/// ///
/// The operand is known to be live until the end of `scope`. /// The operand is known to be live until the end of `scope`.
crate fn as_operand<M>( ///
&mut self,
block: BasicBlock,
scope: Option<region::Scope>,
expr: M,
) -> BlockAnd<Operand<'tcx>>
where
M: Mirror<'tcx, Output = Expr<'tcx>>,
{
let expr = self.hir.mirror(expr);
self.expr_as_operand(block, scope, expr)
}
/// Like `as_local_call_operand`, except that the argument will /// Like `as_local_call_operand`, except that the argument will
/// not be valid once `scope` ends. /// not be valid once `scope` ends.
fn as_call_operand<M>( crate fn as_operand(
&mut self,
block: BasicBlock,
scope: Option<region::Scope>,
expr: M,
) -> BlockAnd<Operand<'tcx>>
where
M: Mirror<'tcx, Output = Expr<'tcx>>,
{
let expr = self.hir.mirror(expr);
self.expr_as_call_operand(block, scope, expr)
}
fn expr_as_operand(
&mut self, &mut self,
mut block: BasicBlock, mut block: BasicBlock,
scope: Option<region::Scope>, scope: Option<region::Scope>,
expr: Expr<'tcx>, expr: &Expr<'tcx>,
) -> BlockAnd<Operand<'tcx>> { ) -> BlockAnd<Operand<'tcx>> {
debug!("expr_as_operand(block={:?}, expr={:?})", block, expr); debug!("as_operand(block={:?}, expr={:?})", block, expr);
let this = self; let this = self;
if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind { if let ExprKind::Scope { region_scope, lint_level, value } = &expr.kind {
let source_info = this.source_info(expr.span); let source_info = this.source_info(expr.span);
let region_scope = (region_scope, source_info); let region_scope = (*region_scope, source_info);
return this return this
.in_scope(region_scope, lint_level, |this| this.as_operand(block, scope, value)); .in_scope(region_scope, *lint_level, |this| this.as_operand(block, scope, &value));
} }
let category = Category::of(&expr.kind).unwrap(); let category = Category::of(&expr.kind).unwrap();
debug!("expr_as_operand: category={:?} for={:?}", category, expr.kind); debug!("as_operand: category={:?} for={:?}", category, expr.kind);
match category { match category {
Category::Constant => { Category::Constant => {
let constant = this.as_constant(expr); let constant = this.as_constant(expr);
@ -146,20 +119,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
} }
fn expr_as_call_operand( crate fn as_call_operand(
&mut self, &mut self,
mut block: BasicBlock, mut block: BasicBlock,
scope: Option<region::Scope>, scope: Option<region::Scope>,
expr: Expr<'tcx>, expr: &Expr<'tcx>,
) -> BlockAnd<Operand<'tcx>> { ) -> BlockAnd<Operand<'tcx>> {
debug!("expr_as_call_operand(block={:?}, expr={:?})", block, expr); debug!("as_call_operand(block={:?}, expr={:?})", block, expr);
let this = self; let this = self;
if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind { if let ExprKind::Scope { region_scope, lint_level, value } = &expr.kind {
let source_info = this.source_info(expr.span); let source_info = this.source_info(expr.span);
let region_scope = (region_scope, source_info); let region_scope = (*region_scope, source_info);
return this.in_scope(region_scope, lint_level, |this| { return this.in_scope(region_scope, *lint_level, |this| {
this.as_call_operand(block, scope, value) this.as_call_operand(block, scope, &value)
}); });
} }
@ -177,8 +150,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// As described above, detect the case where we are passing a value of unsized // As described above, detect the case where we are passing a value of unsized
// type, and that value is coming from the deref of a box. // type, and that value is coming from the deref of a box.
if let ExprKind::Deref { ref arg } = expr.kind { if let ExprKind::Deref { ref arg } = expr.kind {
let arg = this.hir.mirror(arg.clone());
// Generate let tmp0 = arg0 // 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, arg, Mutability::Mut));
@ -193,6 +164,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
} }
this.expr_as_operand(block, scope, expr) this.as_operand(block, scope, expr)
} }
} }

View file

@ -347,25 +347,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Extra care is needed if any user code is allowed to run between calling /// Extra care is needed if any user code is allowed to run between calling
/// this method and using it, as is the case for `match` and index /// this method and using it, as is the case for `match` and index
/// expressions. /// expressions.
crate fn as_place<M>(&mut self, mut block: BasicBlock, expr: M) -> BlockAnd<Place<'tcx>> crate fn as_place(
where &mut self,
M: Mirror<'tcx, Output = Expr<'tcx>>, mut block: BasicBlock,
{ expr: &Expr<'tcx>,
) -> BlockAnd<Place<'tcx>> {
let place_builder = unpack!(block = self.as_place_builder(block, expr)); let place_builder = unpack!(block = self.as_place_builder(block, expr));
block.and(place_builder.into_place(self.hir.tcx(), self.hir.typeck_results())) block.and(place_builder.into_place(self.hir.tcx(), self.hir.typeck_results()))
} }
/// This is used when constructing a compound `Place`, so that we can avoid creating /// This is used when constructing a compound `Place`, so that we can avoid creating
/// intermediate `Place` values until we know the full set of projections. /// intermediate `Place` values until we know the full set of projections.
crate fn as_place_builder<M>( crate fn as_place_builder(
&mut self, &mut self,
block: BasicBlock, block: BasicBlock,
expr: M, expr: &Expr<'tcx>,
) -> BlockAnd<PlaceBuilder<'tcx>> ) -> BlockAnd<PlaceBuilder<'tcx>> {
where
M: Mirror<'tcx, Output = Expr<'tcx>>,
{
let expr = self.hir.mirror(expr);
self.expr_as_place(block, expr, Mutability::Mut, None) self.expr_as_place(block, expr, Mutability::Mut, None)
} }
@ -374,14 +371,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// place. The place itself may or may not be mutable: /// place. The place itself may or may not be mutable:
/// * If this expr is a place expr like a.b, then we will return that place. /// * If this expr is a place expr like a.b, then we will return that place.
/// * Otherwise, a temporary is created: in that event, it will be an immutable temporary. /// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
crate fn as_read_only_place<M>( crate fn as_read_only_place(
&mut self, &mut self,
mut block: BasicBlock, mut block: BasicBlock,
expr: M, expr: &Expr<'tcx>,
) -> BlockAnd<Place<'tcx>> ) -> BlockAnd<Place<'tcx>> {
where
M: Mirror<'tcx, Output = Expr<'tcx>>,
{
let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr)); let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
block.and(place_builder.into_place(self.hir.tcx(), self.hir.typeck_results())) block.and(place_builder.into_place(self.hir.tcx(), self.hir.typeck_results()))
} }
@ -392,22 +386,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// place. The place itself may or may not be mutable: /// place. The place itself may or may not be mutable:
/// * If this expr is a place expr like a.b, then we will return that place. /// * If this expr is a place expr like a.b, then we will return that place.
/// * Otherwise, a temporary is created: in that event, it will be an immutable temporary. /// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
fn as_read_only_place_builder<M>( fn as_read_only_place_builder(
&mut self, &mut self,
block: BasicBlock, block: BasicBlock,
expr: M, expr: &Expr<'tcx>,
) -> BlockAnd<PlaceBuilder<'tcx>> ) -> BlockAnd<PlaceBuilder<'tcx>> {
where
M: Mirror<'tcx, Output = Expr<'tcx>>,
{
let expr = self.hir.mirror(expr);
self.expr_as_place(block, expr, Mutability::Not, None) self.expr_as_place(block, expr, Mutability::Not, None)
} }
fn expr_as_place( fn expr_as_place(
&mut self, &mut self,
mut block: BasicBlock, mut block: BasicBlock,
expr: Expr<'tcx>, expr: &Expr<'tcx>,
mutability: Mutability, mutability: Mutability,
fake_borrow_temps: Option<&mut Vec<Local>>, fake_borrow_temps: Option<&mut Vec<Local>>,
) -> BlockAnd<PlaceBuilder<'tcx>> { ) -> BlockAnd<PlaceBuilder<'tcx>> {
@ -416,29 +406,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let this = self; let this = self;
let expr_span = expr.span; let expr_span = expr.span;
let source_info = this.source_info(expr_span); let source_info = this.source_info(expr_span);
match expr.kind { match &expr.kind {
ExprKind::Scope { region_scope, lint_level, value } => { ExprKind::Scope { region_scope, lint_level, value } => {
this.in_scope((region_scope, source_info), lint_level, |this| { this.in_scope((*region_scope, source_info), *lint_level, |this| {
let value = this.hir.mirror(value); this.expr_as_place(block, &value, mutability, fake_borrow_temps)
this.expr_as_place(block, value, mutability, fake_borrow_temps)
}) })
} }
ExprKind::Field { lhs, name } => { ExprKind::Field { lhs, name } => {
let lhs = this.hir.mirror(lhs); let place_builder = unpack!(
let place_builder = block = this.expr_as_place(block, &lhs, mutability, fake_borrow_temps,)
unpack!(block = this.expr_as_place(block, lhs, mutability, fake_borrow_temps,)); );
block.and(place_builder.field(name, expr.ty)) block.and(place_builder.field(*name, expr.ty))
} }
ExprKind::Deref { arg } => { ExprKind::Deref { arg } => {
let arg = this.hir.mirror(arg); let place_builder = unpack!(
let place_builder = block = this.expr_as_place(block, &arg, mutability, fake_borrow_temps,)
unpack!(block = this.expr_as_place(block, arg, mutability, fake_borrow_temps,)); );
block.and(place_builder.deref()) block.and(place_builder.deref())
} }
ExprKind::Index { lhs, index } => this.lower_index_expression( ExprKind::Index { lhs, index } => this.lower_index_expression(
block, block,
lhs, &lhs,
index, &index,
mutability, mutability,
fake_borrow_temps, fake_borrow_temps,
expr.temp_lifetime, expr.temp_lifetime,
@ -446,31 +435,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
source_info, source_info,
), ),
ExprKind::UpvarRef { closure_def_id, var_hir_id } => { ExprKind::UpvarRef { closure_def_id, var_hir_id } => {
let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id.expect_local()); let upvar_id = ty::UpvarId::new(*var_hir_id, closure_def_id.expect_local());
this.lower_captured_upvar(block, upvar_id) this.lower_captured_upvar(block, upvar_id)
} }
ExprKind::VarRef { id } => { ExprKind::VarRef { id } => {
let place_builder = if this.is_bound_var_in_guard(id) { let place_builder = if this.is_bound_var_in_guard(*id) {
let index = this.var_local_id(id, RefWithinGuard); let index = this.var_local_id(*id, RefWithinGuard);
PlaceBuilder::from(index).deref() PlaceBuilder::from(index).deref()
} else { } else {
let index = this.var_local_id(id, OutsideGuard); let index = this.var_local_id(*id, OutsideGuard);
PlaceBuilder::from(index) PlaceBuilder::from(index)
}; };
block.and(place_builder) block.and(place_builder)
} }
ExprKind::PlaceTypeAscription { source, user_ty } => { ExprKind::PlaceTypeAscription { source, user_ty } => {
let source = this.hir.mirror(source);
let place_builder = unpack!( let place_builder = unpack!(
block = this.expr_as_place(block, source, mutability, fake_borrow_temps,) block = this.expr_as_place(block, &source, mutability, fake_borrow_temps,)
); );
if let Some(user_ty) = user_ty { if let Some(user_ty) = user_ty {
let annotation_index = let annotation_index =
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
span: source_info.span, span: source_info.span,
user_ty, user_ty: *user_ty,
inferred_ty: expr.ty, inferred_ty: expr.ty,
}); });
@ -493,14 +481,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block.and(place_builder) block.and(place_builder)
} }
ExprKind::ValueTypeAscription { source, user_ty } => { ExprKind::ValueTypeAscription { source, user_ty } => {
let source = this.hir.mirror(source);
let temp = let temp =
unpack!(block = this.as_temp(block, source.temp_lifetime, source, mutability)); unpack!(block = this.as_temp(block, source.temp_lifetime, &source, mutability));
if let Some(user_ty) = user_ty { if let Some(user_ty) = user_ty {
let annotation_index = let annotation_index =
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
span: source_info.span, span: source_info.span,
user_ty, user_ty: *user_ty,
inferred_ty: expr.ty, inferred_ty: expr.ty,
}); });
this.cfg.push( this.cfg.push(
@ -599,22 +586,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fn lower_index_expression( fn lower_index_expression(
&mut self, &mut self,
mut block: BasicBlock, mut block: BasicBlock,
base: ExprRef<'tcx>, base: &Expr<'tcx>,
index: ExprRef<'tcx>, index: &Expr<'tcx>,
mutability: Mutability, mutability: Mutability,
fake_borrow_temps: Option<&mut Vec<Local>>, fake_borrow_temps: Option<&mut Vec<Local>>,
temp_lifetime: Option<region::Scope>, temp_lifetime: Option<region::Scope>,
expr_span: Span, expr_span: Span,
source_info: SourceInfo, source_info: SourceInfo,
) -> BlockAnd<PlaceBuilder<'tcx>> { ) -> BlockAnd<PlaceBuilder<'tcx>> {
let lhs = self.hir.mirror(base);
let base_fake_borrow_temps = &mut Vec::new(); let base_fake_borrow_temps = &mut Vec::new();
let is_outermost_index = fake_borrow_temps.is_none(); let is_outermost_index = fake_borrow_temps.is_none();
let fake_borrow_temps = fake_borrow_temps.unwrap_or(base_fake_borrow_temps); let fake_borrow_temps = fake_borrow_temps.unwrap_or(base_fake_borrow_temps);
let mut base_place = let mut base_place =
unpack!(block = self.expr_as_place(block, lhs, mutability, Some(fake_borrow_temps),)); unpack!(block = self.expr_as_place(block, base, mutability, Some(fake_borrow_temps),));
// Making this a *fresh* temporary means we do not have to worry about // Making this a *fresh* temporary means we do not have to worry about
// the index changing later: Nothing will ever change this temporary. // the index changing later: Nothing will ever change this temporary.

View file

@ -19,33 +19,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// The operand returned from this function will *not be valid* after /// The operand returned from this function will *not be valid* after
/// an ExprKind::Scope is passed, so please do *not* return it from /// an ExprKind::Scope is passed, so please do *not* return it from
/// functions to avoid bad miscompiles. /// functions to avoid bad miscompiles.
crate fn as_local_rvalue<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Rvalue<'tcx>> crate fn as_local_rvalue(
where &mut self,
M: Mirror<'tcx, Output = Expr<'tcx>>, block: BasicBlock,
{ expr: &Expr<'tcx>,
) -> BlockAnd<Rvalue<'tcx>> {
let local_scope = self.local_scope(); let local_scope = self.local_scope();
self.as_rvalue(block, Some(local_scope), expr) self.as_rvalue(block, Some(local_scope), expr)
} }
/// Compile `expr`, yielding an rvalue. /// Compile `expr`, yielding an rvalue.
fn as_rvalue<M>( crate fn as_rvalue(
&mut self,
block: BasicBlock,
scope: Option<region::Scope>,
expr: M,
) -> BlockAnd<Rvalue<'tcx>>
where
M: Mirror<'tcx, Output = Expr<'tcx>>,
{
let expr = self.hir.mirror(expr);
self.expr_as_rvalue(block, scope, expr)
}
fn expr_as_rvalue(
&mut self, &mut self,
mut block: BasicBlock, mut block: BasicBlock,
scope: Option<region::Scope>, scope: Option<region::Scope>,
expr: Expr<'tcx>, expr: &Expr<'tcx>,
) -> BlockAnd<Rvalue<'tcx>> { ) -> BlockAnd<Rvalue<'tcx>> {
debug!("expr_as_rvalue(block={:?}, scope={:?}, expr={:?})", block, scope, expr); debug!("expr_as_rvalue(block={:?}, scope={:?}, expr={:?})", block, scope, expr);
@ -53,25 +41,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let expr_span = expr.span; let expr_span = expr.span;
let source_info = this.source_info(expr_span); let source_info = this.source_info(expr_span);
match expr.kind { match &expr.kind {
ExprKind::ThreadLocalRef(did) => block.and(Rvalue::ThreadLocalRef(did)), ExprKind::ThreadLocalRef(did) => block.and(Rvalue::ThreadLocalRef(*did)),
ExprKind::Scope { region_scope, lint_level, value } => { ExprKind::Scope { region_scope, lint_level, value } => {
let region_scope = (region_scope, source_info); 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, &value)
})
} }
ExprKind::Repeat { value, count } => { 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, &value));
block.and(Rvalue::Repeat(value_operand, count)) block.and(Rvalue::Repeat(value_operand, count))
} }
ExprKind::Binary { op, lhs, rhs } => { ExprKind::Binary { op, lhs, rhs } => {
let lhs = unpack!(block = this.as_operand(block, scope, lhs)); let lhs = unpack!(block = this.as_operand(block, scope, &lhs));
let rhs = unpack!(block = this.as_operand(block, scope, rhs)); let rhs = unpack!(block = this.as_operand(block, scope, &rhs));
this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs) this.build_binary_op(block, *op, expr_span, expr.ty, lhs, rhs)
} }
ExprKind::Unary { op, arg } => { ExprKind::Unary { op, arg } => {
let arg = unpack!(block = this.as_operand(block, scope, arg)); let arg = unpack!(block = this.as_operand(block, scope, &arg));
// Check for -MIN on signed integers // Check for -MIN on signed integers
if this.hir.check_overflow() && op == UnOp::Neg && expr.ty.is_signed() { if this.hir.check_overflow() && *op == UnOp::Neg && expr.ty.is_signed() {
let bool_ty = this.hir.bool_ty(); let bool_ty = this.hir.bool_ty();
let minval = this.minval_literal(expr_span, expr.ty); let minval = this.minval_literal(expr_span, expr.ty);
@ -92,10 +82,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
expr_span, expr_span,
); );
} }
block.and(Rvalue::UnaryOp(op, arg)) block.and(Rvalue::UnaryOp(*op, arg))
} }
ExprKind::Box { value } => { ExprKind::Box { value } => {
let value = this.hir.mirror(value);
// The `Box<T>` temporary created here is not a part of the HIR, // The `Box<T>` temporary created here is not a part of the HIR,
// and therefore is not considered during generator auto-trait // and therefore is not considered during generator auto-trait
// determination. See the comment about `box` at `yield_in_scope`. // determination. See the comment about `box` at `yield_in_scope`.
@ -115,18 +104,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// initialize the box contents: // initialize the box contents:
unpack!( unpack!(
block = block = this.expr_into_dest(
this.into(this.hir.tcx().mk_place_deref(Place::from(result)), block, value) this.hir.tcx().mk_place_deref(Place::from(result)),
block,
&value
)
); );
block.and(Rvalue::Use(Operand::Move(Place::from(result)))) block.and(Rvalue::Use(Operand::Move(Place::from(result))))
} }
ExprKind::Cast { source } => { ExprKind::Cast { source } => {
let source = unpack!(block = this.as_operand(block, scope, source)); let source = unpack!(block = this.as_operand(block, scope, &source));
block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty)) block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
} }
ExprKind::Pointer { cast, source } => { ExprKind::Pointer { cast, source } => {
let source = unpack!(block = this.as_operand(block, scope, source)); let source = unpack!(block = this.as_operand(block, scope, &source));
block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty)) block.and(Rvalue::Cast(CastKind::Pointer(*cast), source, expr.ty))
} }
ExprKind::Array { fields } => { ExprKind::Array { fields } => {
// (*) We would (maybe) be closer to codegen if we // (*) We would (maybe) be closer to codegen if we
@ -159,7 +151,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let el_ty = expr.ty.sequence_element_type(this.hir.tcx()); let el_ty = expr.ty.sequence_element_type(this.hir.tcx());
let fields: Vec<_> = fields let fields: Vec<_> = fields
.into_iter() .into_iter()
.map(|f| unpack!(block = this.as_operand(block, scope, f))) .map(|f| unpack!(block = this.as_operand(block, scope, &f)))
.collect(); .collect();
block.and(Rvalue::Aggregate(box AggregateKind::Array(el_ty), fields)) block.and(Rvalue::Aggregate(box AggregateKind::Array(el_ty), fields))
@ -169,7 +161,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// first process the set of fields // first process the set of fields
let fields: Vec<_> = fields let fields: Vec<_> = fields
.into_iter() .into_iter()
.map(|f| unpack!(block = this.as_operand(block, scope, f))) .map(|f| unpack!(block = this.as_operand(block, scope, &f)))
.collect(); .collect();
block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields)) block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields))
@ -179,7 +171,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let operands: Vec<_> = upvars let operands: Vec<_> = upvars
.into_iter() .into_iter()
.map(|upvar| { .map(|upvar| {
let upvar = this.hir.mirror(upvar);
match Category::of(&upvar.kind) { match Category::of(&upvar.kind) {
// Use as_place to avoid creating a temporary when // Use as_place to avoid creating a temporary when
// moving a variable into a closure, so that // moving a variable into a closure, so that
@ -190,7 +181,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// This occurs when capturing by copy/move, while // This occurs when capturing by copy/move, while
// by reference captures use as_operand // by reference captures use as_operand
Some(Category::Place) => { Some(Category::Place) => {
let place = unpack!(block = this.as_place(block, upvar)); let place = unpack!(block = this.as_place(block, &upvar));
this.consume_by_copy_or_move(place) this.consume_by_copy_or_move(place)
} }
_ => { _ => {
@ -198,17 +189,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// borrow captures when capturing an immutable // borrow captures when capturing an immutable
// variable. This is sound because the mutation // variable. This is sound because the mutation
// that caused the capture will cause an error. // that caused the capture will cause an error.
match upvar.kind { match &upvar.kind {
ExprKind::Borrow { ExprKind::Borrow {
borrow_kind: borrow_kind:
BorrowKind::Mut { allow_two_phase_borrow: false }, BorrowKind::Mut { allow_two_phase_borrow: false },
arg, arg,
} => unpack!( } => unpack!(
block = this.limit_capture_mutability( block = this.limit_capture_mutability(
upvar.span, upvar.ty, scope, block, arg, upvar.span, upvar.ty, scope, block, &arg,
) )
), ),
_ => unpack!(block = this.as_operand(block, scope, upvar)), _ => unpack!(block = this.as_operand(block, scope, &upvar)),
} }
} }
} }
@ -219,9 +210,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// We implicitly set the discriminant to 0. See // We implicitly set the discriminant to 0. See
// librustc_mir/transform/deaggregator.rs for details. // librustc_mir/transform/deaggregator.rs for details.
let movability = movability.unwrap(); let movability = movability.unwrap();
box AggregateKind::Generator(closure_id, substs, movability) box AggregateKind::Generator(*closure_id, substs, movability)
} }
UpvarSubsts::Closure(substs) => box AggregateKind::Closure(closure_id, substs), UpvarSubsts::Closure(substs) => box AggregateKind::Closure(*closure_id, substs),
}; };
block.and(Rvalue::Aggregate(result, operands)) block.and(Rvalue::Aggregate(result, operands))
} }
@ -377,7 +368,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
upvar_ty: Ty<'tcx>, upvar_ty: Ty<'tcx>,
temp_lifetime: Option<region::Scope>, temp_lifetime: Option<region::Scope>,
mut block: BasicBlock, mut block: BasicBlock,
arg: ExprRef<'tcx>, arg: &Expr<'tcx>,
) -> BlockAnd<Operand<'tcx>> { ) -> BlockAnd<Operand<'tcx>> {
let this = self; let this = self;

View file

@ -4,48 +4,42 @@ use crate::build::scope::DropKind;
use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::build::{BlockAnd, BlockAndExtension, Builder};
use crate::thir::*; use crate::thir::*;
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir;
use rustc_middle::middle::region; use rustc_middle::middle::region;
use rustc_middle::mir::*; use rustc_middle::mir::*;
impl<'a, 'tcx> Builder<'a, 'tcx> { impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Compile `expr` into a fresh temporary. This is used when building /// Compile `expr` into a fresh temporary. This is used when building
/// up rvalues so as to freeze the value that will be consumed. /// up rvalues so as to freeze the value that will be consumed.
crate fn as_temp<M>( crate fn as_temp(
&mut self, &mut self,
block: BasicBlock, block: BasicBlock,
temp_lifetime: Option<region::Scope>, temp_lifetime: Option<region::Scope>,
expr: M, expr: &Expr<'tcx>,
mutability: Mutability, mutability: Mutability,
) -> BlockAnd<Local> ) -> BlockAnd<Local> {
where
M: Mirror<'tcx, Output = Expr<'tcx>>,
{
let expr = self.hir.mirror(expr);
//
// this is the only place in mir building that we need to truly need to worry about // this is the only place in mir building that we need to truly need to worry about
// infinite recursion. Everything else does recurse, too, but it always gets broken up // infinite recursion. Everything else does recurse, too, but it always gets broken up
// at some point by inserting an intermediate temporary // at some point by inserting an intermediate temporary
ensure_sufficient_stack(|| self.expr_as_temp(block, temp_lifetime, expr, mutability)) ensure_sufficient_stack(|| self.as_temp_inner(block, temp_lifetime, expr, mutability))
} }
fn expr_as_temp( fn as_temp_inner(
&mut self, &mut self,
mut block: BasicBlock, mut block: BasicBlock,
temp_lifetime: Option<region::Scope>, temp_lifetime: Option<region::Scope>,
expr: Expr<'tcx>, expr: &Expr<'tcx>,
mutability: Mutability, mutability: Mutability,
) -> BlockAnd<Local> { ) -> BlockAnd<Local> {
debug!( debug!(
"expr_as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})", "as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})",
block, temp_lifetime, expr, mutability block, temp_lifetime, expr, mutability
); );
let this = self; let this = self;
let expr_span = expr.span; let expr_span = expr.span;
let source_info = this.source_info(expr_span); let source_info = this.source_info(expr_span);
if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind { if let ExprKind::Scope { region_scope, lint_level, value } = &expr.kind {
return this.in_scope((region_scope, source_info), lint_level, |this| { 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, value, mutability)
}); });
} }
@ -89,7 +83,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Don't bother with StorageLive and Dead for these temporaries, // Don't bother with StorageLive and Dead for these temporaries,
// they are never assigned. // they are never assigned.
ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::Return { .. } => (), ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::Return { .. } => (),
ExprKind::Block { body: hir::Block { expr: None, targeted_by_break: false, .. } } ExprKind::Block { body: Block { expr: None, targeted_by_break: false, .. } }
if expr_ty.is_never() => {} if expr_ty.is_never() => {}
_ => { _ => {
this.cfg this.cfg
@ -114,7 +108,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
} }
unpack!(block = this.into(temp_place, block, expr)); unpack!(block = this.expr_into_dest(temp_place, block, expr));
if let Some(temp_lifetime) = temp_lifetime { if let Some(temp_lifetime) = temp_lifetime {
this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value); this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value);

View file

@ -13,13 +13,13 @@ use rustc_middle::ty::CanonicalUserTypeAnnotation;
impl<'a, 'tcx> Builder<'a, 'tcx> { impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Compile `expr`, storing the result into `destination`, which /// Compile `expr`, storing the result into `destination`, which
/// is assumed to be uninitialized. /// is assumed to be uninitialized.
crate fn into_expr( crate fn expr_into_dest(
&mut self, &mut self,
destination: Place<'tcx>, destination: Place<'tcx>,
mut block: BasicBlock, mut block: BasicBlock,
expr: Expr<'tcx>, expr: &Expr<'tcx>,
) -> BlockAnd<()> { ) -> BlockAnd<()> {
debug!("into_expr(destination={:?}, block={:?}, expr={:?})", destination, block, expr); debug!("expr_into_dest(destination={:?}, block={:?}, expr={:?})", destination, block, expr);
// since we frequently have to reference `self` from within a // since we frequently have to reference `self` from within a
// closure, where `self` would be shadowed, it's easier to // closure, where `self` would be shadowed, it's easier to
@ -35,24 +35,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
this.block_context.push(BlockFrame::SubExpr); this.block_context.push(BlockFrame::SubExpr);
} }
let block_and = match expr.kind { let block_and = match &expr.kind {
ExprKind::Scope { region_scope, lint_level, value } => { ExprKind::Scope { region_scope, lint_level, value } => {
let region_scope = (region_scope, source_info); let region_scope = (*region_scope, source_info);
ensure_sufficient_stack(|| { ensure_sufficient_stack(|| {
this.in_scope(region_scope, lint_level, |this| { this.in_scope(region_scope, *lint_level, |this| {
this.into(destination, block, value) this.expr_into_dest(destination, block, &value)
}) })
}) })
} }
ExprKind::Block { body: ast_block } => { ExprKind::Block { body: ast_block } => {
this.ast_block(destination, block, ast_block, source_info) this.ast_block(destination, block, &ast_block, source_info)
} }
ExprKind::Match { scrutinee, arms } => { ExprKind::Match { scrutinee, arms } => {
this.match_expr(destination, expr_span, block, scrutinee, arms) this.match_expr(destination, expr_span, block, &scrutinee, &arms)
} }
ExprKind::If { cond, then, else_opt } => { ExprKind::If { cond, then, else_opt } => {
let place = unpack!( let place = unpack!(
block = this.as_temp(block, Some(this.local_scope()), cond, Mutability::Mut) block = this.as_temp(block, Some(this.local_scope()), &cond, Mutability::Mut)
); );
let operand = Operand::Move(Place::from(place)); let operand = Operand::Move(Place::from(place));
@ -61,9 +61,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let term = TerminatorKind::if_(this.hir.tcx(), operand, then_block, else_block); let term = TerminatorKind::if_(this.hir.tcx(), operand, then_block, else_block);
this.cfg.terminate(block, source_info, term); this.cfg.terminate(block, source_info, term);
unpack!(then_block = this.into(destination, then_block, then)); unpack!(then_block = this.expr_into_dest(destination, then_block, &then));
else_block = if let Some(else_opt) = else_opt { else_block = if let Some(else_opt) = else_opt {
unpack!(this.into(destination, else_block, else_opt)) unpack!(this.expr_into_dest(destination, else_block, &else_opt))
} else { } else {
// Body of the `if` expression without an `else` clause must return `()`, thus // Body of the `if` expression without an `else` clause must return `()`, thus
// we implicitly generate a `else {}` if it is not specified. // we implicitly generate a `else {}` if it is not specified.
@ -87,14 +87,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
join_block.unit() join_block.unit()
} }
ExprKind::NeverToAny { source } => { ExprKind::NeverToAny { source } => {
let source = this.hir.mirror(source);
let is_call = let is_call =
matches!(source.kind, ExprKind::Call { .. } | ExprKind::InlineAsm { .. }); matches!(source.kind, ExprKind::Call { .. } | ExprKind::InlineAsm { .. });
// (#66975) Source could be a const of type `!`, so has to // (#66975) Source could be a const of type `!`, so has to
// exist in the generated MIR. // exist in the generated MIR.
unpack!( unpack!(
block = this.as_temp(block, Some(this.local_scope()), source, Mutability::Mut,) block =
this.as_temp(block, Some(this.local_scope()), &source, Mutability::Mut,)
); );
// This is an optimization. If the expression was a call then we already have an // This is an optimization. If the expression was a call then we already have an
@ -127,7 +127,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
this.cfg.start_new_block(), this.cfg.start_new_block(),
); );
let lhs = unpack!(block = this.as_local_operand(block, lhs)); let lhs = unpack!(block = this.as_local_operand(block, &lhs));
let blocks = match op { let blocks = match op {
LogicalOp::And => (else_block, false_block), LogicalOp::And => (else_block, false_block),
LogicalOp::Or => (true_block, else_block), LogicalOp::Or => (true_block, else_block),
@ -135,7 +135,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1); let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1);
this.cfg.terminate(block, source_info, term); this.cfg.terminate(block, source_info, term);
let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs)); let rhs = unpack!(else_block = this.as_local_operand(else_block, &rhs));
let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block); let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block);
this.cfg.terminate(else_block, source_info, term); this.cfg.terminate(else_block, source_info, term);
@ -188,7 +188,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// introduce a unit temporary as the destination for the loop body. // introduce a unit temporary as the destination for the loop body.
let tmp = this.get_unit_temp(); let tmp = this.get_unit_temp();
// Execute the body, branching back to the test. // Execute the body, branching back to the test.
let body_block_end = unpack!(this.into(tmp, body_block, body)); let body_block_end = unpack!(this.expr_into_dest(tmp, body_block, &body));
this.cfg.goto(body_block_end, source_info, loop_block); this.cfg.goto(body_block_end, source_info, loop_block);
// Loops are only exited by `break` expressions. // Loops are only exited by `break` expressions.
@ -196,17 +196,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}) })
} }
ExprKind::Call { ty: _, fun, args, from_hir_call, fn_span } => { ExprKind::Call { ty: _, fun, args, from_hir_call, fn_span } => {
let fun = unpack!(block = this.as_local_operand(block, fun)); let fun = unpack!(block = this.as_local_operand(block, &fun));
let args: Vec<_> = args let args: Vec<_> = args
.into_iter() .into_iter()
.map(|arg| unpack!(block = this.as_local_call_operand(block, arg))) .map(|arg| unpack!(block = this.as_local_call_operand(block, &arg)))
.collect(); .collect();
let success = this.cfg.start_new_block(); let success = this.cfg.start_new_block();
this.record_operands_moved(&args); this.record_operands_moved(&args);
debug!("into_expr: fn_span={:?}", fn_span); debug!("expr_into_dest: fn_span={:?}", fn_span);
this.cfg.terminate( this.cfg.terminate(
block, block,
@ -223,14 +223,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} else { } else {
Some((destination, success)) Some((destination, success))
}, },
from_hir_call, from_hir_call: *from_hir_call,
fn_span, fn_span: *fn_span,
}, },
); );
this.diverge_from(block); this.diverge_from(block);
success.unit() success.unit()
} }
ExprKind::Use { source } => this.into(destination, block, source), ExprKind::Use { source } => this.expr_into_dest(destination, block, &source),
ExprKind::Borrow { arg, borrow_kind } => { ExprKind::Borrow { arg, borrow_kind } => {
// We don't do this in `as_rvalue` because we use `as_place` // We don't do this in `as_rvalue` because we use `as_place`
// for borrow expressions, so we cannot create an `RValue` that // for borrow expressions, so we cannot create an `RValue` that
@ -238,20 +238,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// by this method anyway, so this shouldn't cause too many // by this method anyway, so this shouldn't cause too many
// unnecessary temporaries. // unnecessary temporaries.
let arg_place = match borrow_kind { let arg_place = match borrow_kind {
BorrowKind::Shared => unpack!(block = this.as_read_only_place(block, arg)), BorrowKind::Shared => unpack!(block = this.as_read_only_place(block, &arg)),
_ => unpack!(block = this.as_place(block, arg)), _ => unpack!(block = this.as_place(block, &arg)),
}; };
let borrow = let borrow =
Rvalue::Ref(this.hir.tcx().lifetimes.re_erased, borrow_kind, arg_place); Rvalue::Ref(this.hir.tcx().lifetimes.re_erased, *borrow_kind, arg_place);
this.cfg.push_assign(block, source_info, destination, borrow); this.cfg.push_assign(block, source_info, destination, borrow);
block.unit() block.unit()
} }
ExprKind::AddressOf { mutability, arg } => { ExprKind::AddressOf { mutability, arg } => {
let place = match mutability { let place = match mutability {
hir::Mutability::Not => this.as_read_only_place(block, arg), hir::Mutability::Not => this.as_read_only_place(block, &arg),
hir::Mutability::Mut => this.as_place(block, arg), hir::Mutability::Mut => this.as_place(block, &arg),
}; };
let address_of = Rvalue::AddressOf(mutability, unpack!(block = place)); let address_of = Rvalue::AddressOf(*mutability, unpack!(block = place));
this.cfg.push_assign(block, source_info, destination, address_of); this.cfg.push_assign(block, source_info, destination, address_of);
block.unit() block.unit()
} }
@ -267,13 +267,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// (evaluating them in order given by user) // (evaluating them in order given by user)
let fields_map: FxHashMap<_, _> = fields let fields_map: FxHashMap<_, _> = fields
.into_iter() .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), &f.expr)))
})
.collect(); .collect();
let field_names = this.hir.all_fields(adt_def, variant_index); let field_names = this.hir.all_fields(adt_def, *variant_index);
let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base { 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, &base));
// MIR does not natively support FRU, so for each // MIR does not natively support FRU, so for each
// base-supplied field, generate an operand that // base-supplied field, generate an operand that
@ -307,7 +309,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}); });
let adt = box AggregateKind::Adt( let adt = box AggregateKind::Adt(
adt_def, adt_def,
variant_index, *variant_index,
substs, substs,
user_ty, user_ty,
active_field_index, active_field_index,
@ -327,21 +329,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
.into_iter() .into_iter()
.map(|op| match op { .map(|op| match op {
thir::InlineAsmOperand::In { reg, expr } => mir::InlineAsmOperand::In { thir::InlineAsmOperand::In { reg, expr } => mir::InlineAsmOperand::In {
reg, reg: *reg,
value: unpack!(block = this.as_local_operand(block, expr)), value: unpack!(block = this.as_local_operand(block, &expr)),
}, },
thir::InlineAsmOperand::Out { reg, late, expr } => { thir::InlineAsmOperand::Out { reg, late, expr } => {
mir::InlineAsmOperand::Out { mir::InlineAsmOperand::Out {
reg, reg: *reg,
late, late: *late,
place: expr.map(|expr| unpack!(block = this.as_place(block, expr))), place: expr
.as_ref()
.map(|expr| unpack!(block = this.as_place(block, expr))),
} }
} }
thir::InlineAsmOperand::InOut { reg, late, expr } => { thir::InlineAsmOperand::InOut { reg, late, expr } => {
let place = unpack!(block = this.as_place(block, expr)); let place = unpack!(block = this.as_place(block, &expr));
mir::InlineAsmOperand::InOut { mir::InlineAsmOperand::InOut {
reg, reg: *reg,
late, late: *late,
// This works because asm operands must be Copy // This works because asm operands must be Copy
in_value: Operand::Copy(place), in_value: Operand::Copy(place),
out_place: Some(place), out_place: Some(place),
@ -349,22 +353,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
thir::InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => { thir::InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => {
mir::InlineAsmOperand::InOut { mir::InlineAsmOperand::InOut {
reg, reg: *reg,
late, late: *late,
in_value: unpack!(block = this.as_local_operand(block, in_expr)), in_value: unpack!(block = this.as_local_operand(block, &in_expr)),
out_place: out_expr.map(|out_expr| { out_place: out_expr.as_ref().map(|out_expr| {
unpack!(block = this.as_place(block, out_expr)) unpack!(block = this.as_place(block, out_expr))
}), }),
} }
} }
thir::InlineAsmOperand::Const { expr } => mir::InlineAsmOperand::Const { thir::InlineAsmOperand::Const { expr } => mir::InlineAsmOperand::Const {
value: unpack!(block = this.as_local_operand(block, expr)), value: unpack!(block = this.as_local_operand(block, &expr)),
}, },
thir::InlineAsmOperand::SymFn { expr } => { thir::InlineAsmOperand::SymFn { expr } => {
mir::InlineAsmOperand::SymFn { value: box this.as_constant(expr) } mir::InlineAsmOperand::SymFn { value: box this.as_constant(&expr) }
} }
thir::InlineAsmOperand::SymStatic { def_id } => { thir::InlineAsmOperand::SymStatic { def_id } => {
mir::InlineAsmOperand::SymStatic { def_id } mir::InlineAsmOperand::SymStatic { def_id: *def_id }
} }
}) })
.collect(); .collect();
@ -377,7 +381,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
TerminatorKind::InlineAsm { TerminatorKind::InlineAsm {
template, template,
operands, operands,
options, options: *options,
line_spans, line_spans,
destination: if options.contains(InlineAsmOptions::NORETURN) { destination: if options.contains(InlineAsmOptions::NORETURN) {
None None
@ -436,7 +440,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ExprKind::Yield { value } => { ExprKind::Yield { value } => {
let scope = this.local_scope(); 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), &value));
let resume = this.cfg.start_new_block(); let resume = this.cfg.start_new_block();
this.cfg.terminate( this.cfg.terminate(
block, block,

View file

@ -9,7 +9,7 @@
//! a type that is not `Copy`, then using any of these functions will //! a type that is not `Copy`, then using any of these functions will
//! "move" the value out of its current home (if any). //! "move" the value out of its current home (if any).
//! //!
//! - `into` -- writes the value into a specific location, which //! - `expr_into_dest` -- writes the value into a specific location, which
//! should be uninitialized //! should be uninitialized
//! - `as_operand` -- evaluates the value and yields an `Operand`, //! - `as_operand` -- evaluates the value and yields an `Operand`,
//! suitable for use as an argument to an `Rvalue` //! suitable for use as an argument to an `Rvalue`

View file

@ -13,7 +13,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
crate fn stmt_expr( crate fn stmt_expr(
&mut self, &mut self,
mut block: BasicBlock, mut block: BasicBlock,
expr: Expr<'tcx>, expr: &Expr<'tcx>,
statement_scope: Option<region::Scope>, statement_scope: Option<region::Scope>,
) -> BlockAnd<()> { ) -> BlockAnd<()> {
let this = self; let this = self;
@ -22,16 +22,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Handle a number of expressions that don't need a destination at all. This // Handle a number of expressions that don't need a destination at all. This
// avoids needing a mountain of temporary `()` variables. // avoids needing a mountain of temporary `()` variables.
let expr2 = expr.clone(); let expr2 = expr.clone();
match expr.kind { match &expr.kind {
ExprKind::Scope { region_scope, lint_level, value } => { ExprKind::Scope { region_scope, lint_level, value } => {
let value = this.hir.mirror(value); this.in_scope((*region_scope, source_info), *lint_level, |this| {
this.in_scope((region_scope, source_info), lint_level, |this| { this.stmt_expr(block, &value, statement_scope)
this.stmt_expr(block, value, statement_scope)
}) })
} }
ExprKind::Assign { lhs, rhs } => { ExprKind::Assign { lhs, rhs } => {
let lhs = this.hir.mirror(lhs);
let rhs = this.hir.mirror(rhs);
let lhs_span = lhs.span; let lhs_span = lhs.span;
// Note: we evaluate assignments right-to-left. This // Note: we evaluate assignments right-to-left. This
@ -44,12 +41,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Generate better code for things that don't need to be // Generate better code for things that don't need to be
// dropped. // dropped.
if this.hir.needs_drop(lhs.ty) { if this.hir.needs_drop(lhs.ty) {
let rhs = unpack!(block = this.as_local_operand(block, rhs)); let rhs = unpack!(block = this.as_local_operand(block, &rhs));
let lhs = unpack!(block = this.as_place(block, lhs)); let lhs = unpack!(block = this.as_place(block, &lhs));
unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs)); unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs));
} else { } else {
let rhs = unpack!(block = this.as_local_rvalue(block, rhs)); let rhs = unpack!(block = this.as_local_rvalue(block, &rhs));
let lhs = unpack!(block = this.as_place(block, lhs)); let lhs = unpack!(block = this.as_place(block, &lhs));
this.cfg.push_assign(block, source_info, lhs, rhs); this.cfg.push_assign(block, source_info, lhs, rhs);
} }
@ -65,22 +62,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// only affects weird things like `x += {x += 1; x}` // only affects weird things like `x += {x += 1; x}`
// -- is that equal to `x + (x + 1)` or `2*(x+1)`? // -- is that equal to `x + (x + 1)` or `2*(x+1)`?
let lhs = this.hir.mirror(lhs);
let lhs_ty = lhs.ty; let lhs_ty = lhs.ty;
debug!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr2); debug!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr2);
this.block_context.push(BlockFrame::SubExpr); this.block_context.push(BlockFrame::SubExpr);
// As above, RTL. // As above, RTL.
let rhs = unpack!(block = this.as_local_operand(block, rhs)); let rhs = unpack!(block = this.as_local_operand(block, &rhs));
let lhs = unpack!(block = this.as_place(block, lhs)); let lhs = unpack!(block = this.as_place(block, &lhs));
// we don't have to drop prior contents or anything // we don't have to drop prior contents or anything
// because AssignOp is only legal for Copy types // because AssignOp is only legal for Copy types
// (overloaded ops should be desugared into a call). // (overloaded ops should be desugared into a call).
let result = unpack!( let result = unpack!(
block = block = this.build_binary_op(
this.build_binary_op(block, op, expr_span, lhs_ty, Operand::Copy(lhs), rhs) block,
*op,
expr_span,
lhs_ty,
Operand::Copy(lhs),
rhs
)
); );
this.cfg.push_assign(block, source_info, lhs, result); this.cfg.push_assign(block, source_info, lhs, result);
@ -88,26 +90,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block.unit() block.unit()
} }
ExprKind::Continue { label } => { ExprKind::Continue { label } => {
this.break_scope(block, None, BreakableTarget::Continue(label), source_info) this.break_scope(block, None, BreakableTarget::Continue(*label), source_info)
}
ExprKind::Break { label, value } => {
this.break_scope(block, value, BreakableTarget::Break(label), source_info)
} }
ExprKind::Break { label, value } => this.break_scope(
block,
value.as_deref(),
BreakableTarget::Break(*label),
source_info,
),
ExprKind::Return { value } => { ExprKind::Return { value } => {
this.break_scope(block, value, BreakableTarget::Return, source_info) this.break_scope(block, value.as_deref(), BreakableTarget::Return, source_info)
} }
ExprKind::LlvmInlineAsm { asm, outputs, inputs } => { ExprKind::LlvmInlineAsm { asm, outputs, inputs } => {
debug!("stmt_expr LlvmInlineAsm block_context.push(SubExpr) : {:?}", expr2); debug!("stmt_expr LlvmInlineAsm block_context.push(SubExpr) : {:?}", expr2);
this.block_context.push(BlockFrame::SubExpr); this.block_context.push(BlockFrame::SubExpr);
let outputs = outputs let outputs = outputs
.into_iter() .into_iter()
.map(|output| unpack!(block = this.as_place(block, output))) .map(|output| unpack!(block = this.as_place(block, &output)))
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into_boxed_slice(); .into_boxed_slice();
let inputs = inputs let inputs = inputs
.into_iter() .into_iter()
.map(|input| { .map(|input| {
(input.span(), unpack!(block = this.as_local_operand(block, input))) (input.span, unpack!(block = this.as_local_operand(block, &input)))
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into_boxed_slice(); .into_boxed_slice();
@ -116,7 +121,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Statement { Statement {
source_info, source_info,
kind: StatementKind::LlvmInlineAsm(box LlvmInlineAsm { kind: StatementKind::LlvmInlineAsm(box LlvmInlineAsm {
asm: asm.clone(), asm: (*asm).clone(),
outputs, outputs,
inputs, inputs,
}), }),
@ -140,10 +145,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// it is usually better to focus on `the_value` rather // it is usually better to focus on `the_value` rather
// than the entirety of block(s) surrounding it. // than the entirety of block(s) surrounding it.
let adjusted_span = (|| { let adjusted_span = (|| {
if let ExprKind::Block { body } = expr.kind { if let ExprKind::Block { body } = &expr.kind {
if let Some(tail_expr) = &body.expr { if let Some(tail_expr) = &body.expr {
let mut expr = tail_expr; let mut expr = &*tail_expr;
while let rustc_hir::ExprKind::Block(subblock, _label) = &expr.kind { while let ExprKind::Block { body: subblock } = &expr.kind {
if let Some(subtail_expr) = &subblock.expr { if let Some(subtail_expr) = &subblock.expr {
expr = subtail_expr expr = subtail_expr
} else { } else {

View file

@ -1,55 +0,0 @@
//! In general, there are a number of things for which it's convenient
//! to just call `builder.into` and have it emit its result into a
//! given location. This is basically for expressions or things that can be
//! wrapped up as expressions (e.g., blocks). To make this ergonomic, we use this
//! latter `EvalInto` trait.
use crate::build::{BlockAnd, Builder};
use crate::thir::*;
use rustc_middle::mir::*;
pub(in crate::build) trait EvalInto<'tcx> {
fn eval_into(
self,
builder: &mut Builder<'_, 'tcx>,
destination: Place<'tcx>,
block: BasicBlock,
) -> BlockAnd<()>;
}
impl<'a, 'tcx> Builder<'a, 'tcx> {
crate fn into<E>(
&mut self,
destination: Place<'tcx>,
block: BasicBlock,
expr: E,
) -> BlockAnd<()>
where
E: EvalInto<'tcx>,
{
expr.eval_into(self, destination, block)
}
}
impl<'tcx> EvalInto<'tcx> for ExprRef<'tcx> {
fn eval_into(
self,
builder: &mut Builder<'_, 'tcx>,
destination: Place<'tcx>,
block: BasicBlock,
) -> BlockAnd<()> {
let expr = builder.hir.mirror(self);
builder.into_expr(destination, block, expr)
}
}
impl<'tcx> EvalInto<'tcx> for Expr<'tcx> {
fn eval_into(
self,
builder: &mut Builder<'_, 'tcx>,
destination: Place<'tcx>,
block: BasicBlock,
) -> BlockAnd<()> {
builder.into_expr(destination, block, self)
}
}

View file

@ -89,10 +89,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
destination: Place<'tcx>, destination: Place<'tcx>,
span: Span, span: Span,
mut block: BasicBlock, mut block: BasicBlock,
scrutinee: ExprRef<'tcx>, scrutinee: &Expr<'tcx>,
arms: Vec<Arm<'tcx>>, arms: &[Arm<'tcx>],
) -> BlockAnd<()> { ) -> BlockAnd<()> {
let scrutinee_span = scrutinee.span(); let scrutinee_span = scrutinee.span;
let scrutinee_place = let scrutinee_place =
unpack!(block = self.lower_scrutinee(block, scrutinee, scrutinee_span,)); unpack!(block = self.lower_scrutinee(block, scrutinee, scrutinee_span,));
@ -119,7 +119,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fn lower_scrutinee( fn lower_scrutinee(
&mut self, &mut self,
mut block: BasicBlock, mut block: BasicBlock,
scrutinee: ExprRef<'tcx>, scrutinee: &Expr<'tcx>,
scrutinee_span: Span, scrutinee_span: Span,
) -> BlockAnd<Place<'tcx>> { ) -> BlockAnd<Place<'tcx>> {
let scrutinee_place = unpack!(block = self.as_place(block, scrutinee)); let scrutinee_place = unpack!(block = self.as_place(block, scrutinee));
@ -236,7 +236,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let arm_source_info = self.source_info(arm.span); let arm_source_info = self.source_info(arm.span);
let arm_scope = (arm.scope, arm_source_info); let arm_scope = (arm.scope, arm_source_info);
self.in_scope(arm_scope, arm.lint_level, |this| { self.in_scope(arm_scope, arm.lint_level, |this| {
let body = this.hir.mirror(arm.body.clone());
let scope = this.declare_bindings( let scope = this.declare_bindings(
None, None,
arm.span, arm.span,
@ -259,7 +258,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
this.source_scope = source_scope; this.source_scope = source_scope;
} }
this.into(destination, arm_block, body) this.expr_into_dest(destination, arm_block, &arm.body)
}) })
}) })
.collect(); .collect();
@ -362,14 +361,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&mut self, &mut self,
mut block: BasicBlock, mut block: BasicBlock,
irrefutable_pat: Pat<'tcx>, irrefutable_pat: Pat<'tcx>,
initializer: ExprRef<'tcx>, initializer: &Expr<'tcx>,
) -> BlockAnd<()> { ) -> BlockAnd<()> {
match *irrefutable_pat.kind { match *irrefutable_pat.kind {
// Optimize the case of `let x = ...` to write directly into `x` // Optimize the case of `let x = ...` to write directly into `x`
PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => { PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => {
let place = let place =
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
unpack!(block = self.into(place, block, initializer)); unpack!(block = self.expr_into_dest(place, block, initializer));
// Inject a fake read, see comments on `FakeReadCause::ForLet`. // Inject a fake read, see comments on `FakeReadCause::ForLet`.
let source_info = self.source_info(irrefutable_pat.span); let source_info = self.source_info(irrefutable_pat.span);
@ -404,7 +403,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} => { } => {
let place = let place =
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
unpack!(block = self.into(place, block, initializer)); unpack!(block = self.expr_into_dest(place, block, initializer));
// Inject a fake read, see comments on `FakeReadCause::ForLet`. // Inject a fake read, see comments on `FakeReadCause::ForLet`.
let pattern_source_info = self.source_info(irrefutable_pat.span); let pattern_source_info = self.source_info(irrefutable_pat.span);
@ -1749,15 +1748,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
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) => { Guard::If(e) => {
let e = self.hir.mirror(e.clone());
let source_info = self.source_info(e.span); let source_info = self.source_info(e.span);
(e.span, self.test_bool(block, e, source_info)) (e.span, self.test_bool(block, e, source_info))
} }
Guard::IfLet(pat, scrutinee) => { Guard::IfLet(pat, scrutinee) => {
let scrutinee_span = scrutinee.span(); let scrutinee_span = scrutinee.span;
let scrutinee_place = unpack!( let scrutinee_place =
block = self.lower_scrutinee(block, scrutinee.clone(), scrutinee_span) unpack!(block = self.lower_scrutinee(block, &scrutinee, scrutinee_span));
);
let mut guard_candidate = Candidate::new(scrutinee_place, &pat, false); let mut guard_candidate = Candidate::new(scrutinee_place, &pat, false);
let wildcard = Pat::wildcard_from_ty(pat.ty); let wildcard = Pat::wildcard_from_ty(pat.ty);
let mut otherwise_candidate = Candidate::new(scrutinee_place, &wildcard, false); let mut otherwise_candidate = Candidate::new(scrutinee_place, &wildcard, false);
@ -1772,14 +1769,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
pat.span.to(arm_span.unwrap()), pat.span.to(arm_span.unwrap()),
pat, pat,
ArmHasGuard(false), ArmHasGuard(false),
Some((Some(&scrutinee_place), scrutinee.span())), Some((Some(&scrutinee_place), scrutinee.span)),
); );
let post_guard_block = self.bind_pattern( let post_guard_block = self.bind_pattern(
self.source_info(pat.span), self.source_info(pat.span),
guard_candidate, guard_candidate,
None, None,
&fake_borrow_temps, &fake_borrow_temps,
scrutinee.span(), scrutinee.span,
None, None,
None, None,
); );

View file

@ -667,8 +667,8 @@ fn construct_const<'a, 'tcx>(
let mut block = START_BLOCK; let mut block = START_BLOCK;
let ast_expr = &tcx.hir().body(body_id).value; let ast_expr = &tcx.hir().body(body_id).value;
let expr = builder.hir.mirror(ast_expr); let expr = builder.hir.mirror_expr(ast_expr);
unpack!(block = builder.into_expr(Place::return_place(), block, expr)); unpack!(block = builder.expr_into_dest(Place::return_place(), block, &expr));
let source_info = builder.source_info(span); let source_info = builder.source_info(span);
builder.cfg.terminate(block, source_info, TerminatorKind::Return); builder.cfg.terminate(block, source_info, TerminatorKind::Return);
@ -953,8 +953,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.source_scope = source_scope; self.source_scope = source_scope;
} }
let body = self.hir.mirror(ast_body); let body = self.hir.mirror_expr(ast_body);
self.into(Place::return_place(), block, body) self.expr_into_dest(Place::return_place(), block, &body)
} }
fn set_correct_source_scope_for_arg( fn set_correct_source_scope_for_arg(
@ -1001,7 +1001,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
mod block; mod block;
mod cfg; mod cfg;
mod expr; mod expr;
mod into;
mod matches; mod matches;
mod misc; mod misc;
mod scope; mod scope;

View file

@ -82,7 +82,7 @@ that contains only loops and breakable blocks. It tracks where a `break`,
*/ */
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG}; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
use crate::thir::{Expr, ExprRef, LintLevel}; use crate::thir::{Expr, LintLevel};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_index::vec::IndexVec; use rustc_index::vec::IndexVec;
use rustc_middle::middle::region; use rustc_middle::middle::region;
@ -575,7 +575,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
crate fn break_scope( crate fn break_scope(
&mut self, &mut self,
mut block: BasicBlock, mut block: BasicBlock,
value: Option<ExprRef<'tcx>>, value: Option<&Expr<'tcx>>,
target: BreakableTarget, target: BreakableTarget,
source_info: SourceInfo, source_info: SourceInfo,
) -> BlockAnd<()> { ) -> BlockAnd<()> {
@ -612,7 +612,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
if let Some(value) = value { if let Some(value) = value {
debug!("stmt_expr Break val block_context.push(SubExpr)"); debug!("stmt_expr Break val block_context.push(SubExpr)");
self.block_context.push(BlockFrame::SubExpr); self.block_context.push(BlockFrame::SubExpr);
unpack!(block = self.into(destination, block, value)); unpack!(block = self.expr_into_dest(destination, block, value));
self.block_context.pop(); self.block_context.pop();
} else { } else {
self.cfg.push_assign_unit(block, source_info, destination, self.hir.tcx()) self.cfg.push_assign_unit(block, source_info, destination, self.hir.tcx())
@ -920,7 +920,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
crate fn test_bool( crate fn test_bool(
&mut self, &mut self,
mut block: BasicBlock, mut block: BasicBlock,
condition: Expr<'tcx>, condition: &Expr<'tcx>,
source_info: SourceInfo, source_info: SourceInfo,
) -> (BasicBlock, BasicBlock) { ) -> (BasicBlock, BasicBlock) {
let cond = unpack!(block = self.as_local_operand(block, condition)); let cond = unpack!(block = self.as_local_operand(block, condition));

View file

@ -1,4 +1,3 @@
use crate::thir::cx::to_ref::ToRef;
use crate::thir::cx::Cx; use crate::thir::cx::Cx;
use crate::thir::{self, *}; use crate::thir::{self, *};
@ -8,110 +7,101 @@ use rustc_middle::ty;
use rustc_index::vec::Idx; use rustc_index::vec::Idx;
impl<'tcx> Mirror<'tcx> for &'tcx hir::Block<'tcx> { impl<'a, 'tcx> Cx<'a, 'tcx> {
type Output = Block<'tcx>; crate fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block<'tcx> {
fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Block<'tcx> {
// We have to eagerly lower the "spine" of the statements // We have to eagerly lower the "spine" of the statements
// in order to get the lexical scoping correctly. // in order to get the lexical scoping correctly.
let stmts = mirror_stmts(cx, self.hir_id.local_id, &*self.stmts); let stmts = self.mirror_stmts(block.hir_id.local_id, &*block.stmts);
let opt_destruction_scope = let opt_destruction_scope =
cx.region_scope_tree.opt_destruction_scope(self.hir_id.local_id); self.region_scope_tree.opt_destruction_scope(block.hir_id.local_id);
Block { Block {
targeted_by_break: self.targeted_by_break, targeted_by_break: block.targeted_by_break,
region_scope: region::Scope { id: self.hir_id.local_id, data: region::ScopeData::Node }, region_scope: region::Scope {
id: block.hir_id.local_id,
data: region::ScopeData::Node,
},
opt_destruction_scope, opt_destruction_scope,
span: self.span, span: block.span,
stmts, stmts,
expr: self.expr.to_ref(), expr: block.expr.as_ref().map(|expr| self.mirror_expr_boxed(expr)),
safety_mode: match self.rules { safety_mode: match block.rules {
hir::BlockCheckMode::DefaultBlock => BlockSafety::Safe, hir::BlockCheckMode::DefaultBlock => BlockSafety::Safe,
hir::BlockCheckMode::UnsafeBlock(..) => BlockSafety::ExplicitUnsafe(self.hir_id), hir::BlockCheckMode::UnsafeBlock(..) => BlockSafety::ExplicitUnsafe(block.hir_id),
hir::BlockCheckMode::PushUnsafeBlock(..) => BlockSafety::PushUnsafe, hir::BlockCheckMode::PushUnsafeBlock(..) => BlockSafety::PushUnsafe,
hir::BlockCheckMode::PopUnsafeBlock(..) => BlockSafety::PopUnsafe, hir::BlockCheckMode::PopUnsafeBlock(..) => BlockSafety::PopUnsafe,
}, },
} }
} }
}
fn mirror_stmts<'a, 'tcx>( fn mirror_stmts(
cx: &mut Cx<'a, 'tcx>, &mut self,
block_id: hir::ItemLocalId, block_id: hir::ItemLocalId,
stmts: &'tcx [hir::Stmt<'tcx>], stmts: &'tcx [hir::Stmt<'tcx>],
) -> Vec<StmtRef<'tcx>> { ) -> Vec<Stmt<'tcx>> {
let mut result = vec![]; let mut result = vec![];
for (index, stmt) in stmts.iter().enumerate() { for (index, stmt) in stmts.iter().enumerate() {
let hir_id = stmt.hir_id; let hir_id = stmt.hir_id;
let opt_dxn_ext = cx.region_scope_tree.opt_destruction_scope(hir_id.local_id); let opt_dxn_ext = self.region_scope_tree.opt_destruction_scope(hir_id.local_id);
match stmt.kind { match stmt.kind {
hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => { hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => {
result.push(StmtRef::Mirror(Box::new(Stmt { result.push(Stmt {
kind: StmtKind::Expr { kind: StmtKind::Expr {
scope: region::Scope { id: hir_id.local_id, data: region::ScopeData::Node }, scope: region::Scope {
expr: expr.to_ref(), id: hir_id.local_id,
}, data: region::ScopeData::Node,
opt_destruction_scope: opt_dxn_ext, },
}))) expr: self.mirror_expr_boxed(expr),
}
hir::StmtKind::Item(..) => {
// ignore for purposes of the MIR
}
hir::StmtKind::Local(ref local) => {
let remainder_scope = region::Scope {
id: block_id,
data: region::ScopeData::Remainder(region::FirstStatementIndex::new(index)),
};
let mut pattern = cx.pattern_from_hir(&local.pat);
if let Some(ty) = &local.ty {
if let Some(&user_ty) = cx.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,
}),
};
}
}
result.push(StmtRef::Mirror(Box::new(Stmt {
kind: StmtKind::Let {
remainder_scope,
init_scope: region::Scope {
id: hir_id.local_id,
data: region::ScopeData::Node,
}, },
pattern, opt_destruction_scope: opt_dxn_ext,
initializer: local.init.to_ref(), })
lint_level: LintLevel::Explicit(local.hir_id), }
}, hir::StmtKind::Item(..) => {
opt_destruction_scope: opt_dxn_ext, // ignore for purposes of the MIR
}))); }
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);
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,
}),
};
}
}
result.push(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_boxed(init)),
lint_level: LintLevel::Explicit(local.hir_id),
},
opt_destruction_scope: opt_dxn_ext,
});
}
} }
} }
result
} }
result
}
crate fn to_expr_ref<'a, 'tcx>(
cx: &mut Cx<'a, 'tcx>,
block: &'tcx hir::Block<'tcx>,
) -> ExprRef<'tcx> {
let block_ty = cx.typeck_results().node_type(block.hir_id);
let temp_lifetime = cx.region_scope_tree.temporary_scope(block.hir_id.local_id);
let expr = Expr {
ty: block_ty,
temp_lifetime,
span: block.span,
kind: ExprKind::Block { body: block },
};
expr.to_ref()
} }

File diff suppressed because it is too large Load diff

View file

@ -93,11 +93,6 @@ impl<'a, 'tcx> Cx<'a, 'tcx> {
} }
impl<'a, 'tcx> Cx<'a, 'tcx> { impl<'a, 'tcx> Cx<'a, 'tcx> {
/// Normalizes `ast` into the appropriate "mirror" type.
crate fn mirror<M: Mirror<'tcx>>(&mut self, ast: M) -> M::Output {
ast.make_mirror(self)
}
crate fn usize_ty(&mut self) -> Ty<'tcx> { crate fn usize_ty(&mut self) -> Ty<'tcx> {
self.tcx.types.usize self.tcx.types.usize
} }
@ -219,4 +214,3 @@ impl<'tcx> UserAnnotatedTyHelpers<'tcx> for Cx<'_, 'tcx> {
mod block; mod block;
mod expr; mod expr;
mod to_ref;

View file

@ -1,65 +0,0 @@
use crate::thir::*;
use rustc_hir as hir;
crate trait ToRef {
type Output;
fn to_ref(self) -> Self::Output;
}
impl<'tcx> ToRef for &'tcx hir::Expr<'tcx> {
type Output = ExprRef<'tcx>;
fn to_ref(self) -> ExprRef<'tcx> {
ExprRef::Thir(self)
}
}
impl<'tcx> ToRef for &'tcx &'tcx hir::Expr<'tcx> {
type Output = ExprRef<'tcx>;
fn to_ref(self) -> ExprRef<'tcx> {
ExprRef::Thir(&**self)
}
}
impl<'tcx> ToRef for Expr<'tcx> {
type Output = ExprRef<'tcx>;
fn to_ref(self) -> ExprRef<'tcx> {
ExprRef::Mirror(Box::new(self))
}
}
impl<'tcx, T, U> ToRef for &'tcx Option<T>
where
&'tcx T: ToRef<Output = U>,
{
type Output = Option<U>;
fn to_ref(self) -> Option<U> {
self.as_ref().map(|expr| expr.to_ref())
}
}
impl<'tcx, T, U> ToRef for &'tcx Vec<T>
where
&'tcx T: ToRef<Output = U>,
{
type Output = Vec<U>;
fn to_ref(self) -> Vec<U> {
self.iter().map(|expr| expr.to_ref()).collect()
}
}
impl<'tcx, T, U> ToRef for &'tcx [T]
where
&'tcx T: ToRef<Output = U>,
{
type Output = Vec<U>;
fn to_ref(self) -> Vec<U> {
self.iter().map(|expr| expr.to_ref()).collect()
}
}

View file

@ -4,7 +4,6 @@
//! unit-tested and separated from the Rust source and compiler data //! unit-tested and separated from the Rust source and compiler data
//! structures. //! structures.
use self::cx::Cx;
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
@ -39,8 +38,8 @@ crate struct Block<'tcx> {
crate region_scope: region::Scope, crate region_scope: region::Scope,
crate opt_destruction_scope: Option<region::Scope>, crate opt_destruction_scope: Option<region::Scope>,
crate span: Span, crate span: Span,
crate stmts: Vec<StmtRef<'tcx>>, crate stmts: Vec<Stmt<'tcx>>,
crate expr: Option<ExprRef<'tcx>>, crate expr: Option<Box<Expr<'tcx>>>,
crate safety_mode: BlockSafety, crate safety_mode: BlockSafety,
} }
@ -52,11 +51,6 @@ crate enum BlockSafety {
PopUnsafe, PopUnsafe,
} }
#[derive(Clone, Debug)]
crate enum StmtRef<'tcx> {
Mirror(Box<Stmt<'tcx>>),
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
crate struct Stmt<'tcx> { crate struct Stmt<'tcx> {
crate kind: StmtKind<'tcx>, crate kind: StmtKind<'tcx>,
@ -70,7 +64,7 @@ crate enum StmtKind<'tcx> {
scope: region::Scope, scope: region::Scope,
/// expression being evaluated in this statement /// expression being evaluated in this statement
expr: ExprRef<'tcx>, expr: Box<Expr<'tcx>>,
}, },
Let { Let {
@ -88,7 +82,7 @@ crate enum StmtKind<'tcx> {
pattern: Pat<'tcx>, pattern: Pat<'tcx>,
/// let pat: ty = <INIT> ... /// let pat: ty = <INIT> ...
initializer: Option<ExprRef<'tcx>>, initializer: Option<Box<Expr<'tcx>>>,
/// the lint level for this let-statement /// the lint level for this let-statement
lint_level: LintLevel, lint_level: LintLevel,
@ -97,12 +91,12 @@ crate enum StmtKind<'tcx> {
// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger. // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(Expr<'_>, 168); rustc_data_structures::static_assert_size!(Expr<'_>, 160);
/// The Thir trait implementor lowers their expressions (`&'tcx H::Expr`) /// The Thir trait implementor lowers their expressions (`&'tcx H::Expr`)
/// into instances of this `Expr` enum. This lowering can be done /// into instances of this `Expr` enum. This lowering can be done
/// basically as lazily or as eagerly as desired: every recursive /// basically as lazily or as eagerly as desired: every recursive
/// reference to an expression in this enum is an `ExprRef<'tcx>`, which /// reference to an expression in this enum is an `Box<Expr<'tcx>>`, which
/// may in turn be another instance of this enum (boxed), or else an /// may in turn be another instance of this enum (boxed), or else an
/// unlowered `&'tcx H::Expr`. Note that instances of `Expr` are very /// unlowered `&'tcx H::Expr`. Note that instances of `Expr` are very
/// short-lived. They are created by `Thir::to_expr`, analyzed and /// short-lived. They are created by `Thir::to_expr`, analyzed and
@ -134,84 +128,84 @@ crate enum ExprKind<'tcx> {
Scope { Scope {
region_scope: region::Scope, region_scope: region::Scope,
lint_level: LintLevel, lint_level: LintLevel,
value: ExprRef<'tcx>, value: Box<Expr<'tcx>>,
}, },
Box { Box {
value: ExprRef<'tcx>, value: Box<Expr<'tcx>>,
}, },
If { If {
cond: ExprRef<'tcx>, cond: Box<Expr<'tcx>>,
then: ExprRef<'tcx>, then: Box<Expr<'tcx>>,
else_opt: Option<ExprRef<'tcx>>, else_opt: Option<Box<Expr<'tcx>>>,
}, },
Call { Call {
ty: Ty<'tcx>, ty: Ty<'tcx>,
fun: ExprRef<'tcx>, fun: Box<Expr<'tcx>>,
args: Vec<ExprRef<'tcx>>, args: Vec<Expr<'tcx>>,
// Whether this is from a call in HIR, rather than from an overloaded /// Whether this is from a call in HIR, rather than from an overloaded
// operator. True for overloaded function call. /// operator. `true` for overloaded function call.
from_hir_call: bool, from_hir_call: bool,
/// This `Span` is the span of the function, without the dot and receiver /// This `Span` is the span of the function, without the dot and receiver
/// (e.g. `foo(a, b)` in `x.foo(a, b)` /// (e.g. `foo(a, b)` in `x.foo(a, b)`
fn_span: Span, fn_span: Span,
}, },
Deref { Deref {
arg: ExprRef<'tcx>, arg: Box<Expr<'tcx>>,
}, // NOT overloaded! }, // NOT overloaded!
Binary { Binary {
op: BinOp, op: BinOp,
lhs: ExprRef<'tcx>, lhs: Box<Expr<'tcx>>,
rhs: ExprRef<'tcx>, rhs: Box<Expr<'tcx>>,
}, // NOT overloaded! }, // NOT overloaded!
LogicalOp { LogicalOp {
op: LogicalOp, op: LogicalOp,
lhs: ExprRef<'tcx>, lhs: Box<Expr<'tcx>>,
rhs: ExprRef<'tcx>, rhs: Box<Expr<'tcx>>,
}, // NOT overloaded! }, // NOT overloaded!
// LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands. // LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands.
Unary { Unary {
op: UnOp, op: UnOp,
arg: ExprRef<'tcx>, arg: Box<Expr<'tcx>>,
}, // NOT overloaded! }, // NOT overloaded!
Cast { Cast {
source: ExprRef<'tcx>, source: Box<Expr<'tcx>>,
}, },
Use { Use {
source: ExprRef<'tcx>, source: Box<Expr<'tcx>>,
}, // Use a lexpr to get a vexpr. }, // Use a lexpr to get a vexpr.
NeverToAny { NeverToAny {
source: ExprRef<'tcx>, source: Box<Expr<'tcx>>,
}, },
Pointer { Pointer {
cast: PointerCast, cast: PointerCast,
source: ExprRef<'tcx>, source: Box<Expr<'tcx>>,
}, },
Loop { Loop {
body: ExprRef<'tcx>, body: Box<Expr<'tcx>>,
}, },
Match { Match {
scrutinee: ExprRef<'tcx>, scrutinee: Box<Expr<'tcx>>,
arms: Vec<Arm<'tcx>>, arms: Vec<Arm<'tcx>>,
}, },
Block { Block {
body: &'tcx hir::Block<'tcx>, body: Block<'tcx>,
}, },
Assign { Assign {
lhs: ExprRef<'tcx>, lhs: Box<Expr<'tcx>>,
rhs: ExprRef<'tcx>, rhs: Box<Expr<'tcx>>,
}, },
AssignOp { AssignOp {
op: BinOp, op: BinOp,
lhs: ExprRef<'tcx>, lhs: Box<Expr<'tcx>>,
rhs: ExprRef<'tcx>, rhs: Box<Expr<'tcx>>,
}, },
Field { Field {
lhs: ExprRef<'tcx>, lhs: Box<Expr<'tcx>>,
name: Field, name: Field,
}, },
Index { Index {
lhs: ExprRef<'tcx>, lhs: Box<Expr<'tcx>>,
index: ExprRef<'tcx>, index: Box<Expr<'tcx>>,
}, },
VarRef { VarRef {
id: hir::HirId, id: hir::HirId,
@ -226,35 +220,35 @@ crate enum ExprKind<'tcx> {
}, },
Borrow { Borrow {
borrow_kind: BorrowKind, borrow_kind: BorrowKind,
arg: ExprRef<'tcx>, arg: Box<Expr<'tcx>>,
}, },
/// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`. /// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`.
AddressOf { AddressOf {
mutability: hir::Mutability, mutability: hir::Mutability,
arg: ExprRef<'tcx>, arg: Box<Expr<'tcx>>,
}, },
Break { Break {
label: region::Scope, label: region::Scope,
value: Option<ExprRef<'tcx>>, value: Option<Box<Expr<'tcx>>>,
}, },
Continue { Continue {
label: region::Scope, label: region::Scope,
}, },
Return { Return {
value: Option<ExprRef<'tcx>>, value: Option<Box<Expr<'tcx>>>,
}, },
ConstBlock { ConstBlock {
value: &'tcx Const<'tcx>, value: &'tcx Const<'tcx>,
}, },
Repeat { Repeat {
value: ExprRef<'tcx>, value: Box<Expr<'tcx>>,
count: &'tcx Const<'tcx>, count: &'tcx Const<'tcx>,
}, },
Array { Array {
fields: Vec<ExprRef<'tcx>>, fields: Vec<Expr<'tcx>>,
}, },
Tuple { Tuple {
fields: Vec<ExprRef<'tcx>>, fields: Vec<Expr<'tcx>>,
}, },
Adt { Adt {
adt_def: &'tcx AdtDef, adt_def: &'tcx AdtDef,
@ -265,23 +259,23 @@ crate enum ExprKind<'tcx> {
/// Bar::<T> { ... }`. /// Bar::<T> { ... }`.
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>, user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
fields: Vec<FieldExprRef<'tcx>>, fields: Vec<FieldExpr<'tcx>>,
base: Option<FruInfo<'tcx>>, base: Option<FruInfo<'tcx>>,
}, },
PlaceTypeAscription { PlaceTypeAscription {
source: ExprRef<'tcx>, source: Box<Expr<'tcx>>,
/// Type that the user gave to this expression /// Type that the user gave to this expression
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>, user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
}, },
ValueTypeAscription { ValueTypeAscription {
source: ExprRef<'tcx>, source: Box<Expr<'tcx>>,
/// Type that the user gave to this expression /// Type that the user gave to this expression
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>, user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
}, },
Closure { Closure {
closure_id: DefId, closure_id: DefId,
substs: UpvarSubsts<'tcx>, substs: UpvarSubsts<'tcx>,
upvars: Vec<ExprRef<'tcx>>, upvars: Vec<Expr<'tcx>>,
movability: Option<hir::Movability>, movability: Option<hir::Movability>,
}, },
Literal { Literal {
@ -310,29 +304,23 @@ crate enum ExprKind<'tcx> {
ThreadLocalRef(DefId), ThreadLocalRef(DefId),
LlvmInlineAsm { LlvmInlineAsm {
asm: &'tcx hir::LlvmInlineAsmInner, asm: &'tcx hir::LlvmInlineAsmInner,
outputs: Vec<ExprRef<'tcx>>, outputs: Vec<Expr<'tcx>>,
inputs: Vec<ExprRef<'tcx>>, inputs: Vec<Expr<'tcx>>,
}, },
Yield { Yield {
value: ExprRef<'tcx>, value: Box<Expr<'tcx>>,
}, },
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
crate enum ExprRef<'tcx> { crate struct FieldExpr<'tcx> {
Thir(&'tcx hir::Expr<'tcx>),
Mirror(Box<Expr<'tcx>>),
}
#[derive(Clone, Debug)]
crate struct FieldExprRef<'tcx> {
crate name: Field, crate name: Field,
crate expr: ExprRef<'tcx>, crate expr: Expr<'tcx>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
crate struct FruInfo<'tcx> { crate struct FruInfo<'tcx> {
crate base: ExprRef<'tcx>, crate base: Box<Expr<'tcx>>,
crate field_types: Vec<Ty<'tcx>>, crate field_types: Vec<Ty<'tcx>>,
} }
@ -340,7 +328,7 @@ crate struct FruInfo<'tcx> {
crate struct Arm<'tcx> { crate struct Arm<'tcx> {
crate pattern: Pat<'tcx>, crate pattern: Pat<'tcx>,
crate guard: Option<Guard<'tcx>>, crate guard: Option<Guard<'tcx>>,
crate body: ExprRef<'tcx>, crate body: Expr<'tcx>,
crate lint_level: LintLevel, crate lint_level: LintLevel,
crate scope: region::Scope, crate scope: region::Scope,
crate span: Span, crate span: Span,
@ -348,8 +336,8 @@ crate struct Arm<'tcx> {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
crate enum Guard<'tcx> { crate enum Guard<'tcx> {
If(ExprRef<'tcx>), If(Box<Expr<'tcx>>),
IfLet(Pat<'tcx>, ExprRef<'tcx>), IfLet(Pat<'tcx>, Box<Expr<'tcx>>),
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
@ -358,110 +346,35 @@ crate enum LogicalOp {
Or, Or,
} }
impl<'tcx> ExprRef<'tcx> {
crate fn span(&self) -> Span {
match self {
ExprRef::Thir(expr) => expr.span,
ExprRef::Mirror(expr) => expr.span,
}
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
crate enum InlineAsmOperand<'tcx> { crate enum InlineAsmOperand<'tcx> {
In { In {
reg: InlineAsmRegOrRegClass, reg: InlineAsmRegOrRegClass,
expr: ExprRef<'tcx>, expr: Expr<'tcx>,
}, },
Out { Out {
reg: InlineAsmRegOrRegClass, reg: InlineAsmRegOrRegClass,
late: bool, late: bool,
expr: Option<ExprRef<'tcx>>, expr: Option<Expr<'tcx>>,
}, },
InOut { InOut {
reg: InlineAsmRegOrRegClass, reg: InlineAsmRegOrRegClass,
late: bool, late: bool,
expr: ExprRef<'tcx>, expr: Expr<'tcx>,
}, },
SplitInOut { SplitInOut {
reg: InlineAsmRegOrRegClass, reg: InlineAsmRegOrRegClass,
late: bool, late: bool,
in_expr: ExprRef<'tcx>, in_expr: Expr<'tcx>,
out_expr: Option<ExprRef<'tcx>>, out_expr: Option<Expr<'tcx>>,
}, },
Const { Const {
expr: ExprRef<'tcx>, expr: Expr<'tcx>,
}, },
SymFn { SymFn {
expr: ExprRef<'tcx>, expr: Expr<'tcx>,
}, },
SymStatic { SymStatic {
def_id: DefId, def_id: DefId,
}, },
} }
///////////////////////////////////////////////////////////////////////////
// The Mirror trait
/// "Mirroring" is the process of converting from a HIR type into one
/// of the THIR types defined in this file. This is basically a "on
/// the fly" desugaring step that hides a lot of the messiness in the
/// tcx. For example, the mirror of a `&'tcx hir::Expr` is an
/// `Expr<'tcx>`.
///
/// Mirroring is gradual: when you mirror an outer expression like `e1
/// + e2`, the references to the inner expressions `e1` and `e2` are
/// `ExprRef<'tcx>` instances, and they may or may not be eagerly
/// mirrored. This allows a single AST node from the compiler to
/// expand into one or more Thir nodes, which lets the Thir nodes be
/// simpler.
crate trait Mirror<'tcx> {
type Output;
fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Self::Output;
}
impl<'tcx> Mirror<'tcx> for Expr<'tcx> {
type Output = Expr<'tcx>;
fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Expr<'tcx> {
self
}
}
impl<'tcx> Mirror<'tcx> for ExprRef<'tcx> {
type Output = Expr<'tcx>;
fn make_mirror(self, hir: &mut Cx<'_, 'tcx>) -> Expr<'tcx> {
match self {
ExprRef::Thir(h) => h.make_mirror(hir),
ExprRef::Mirror(m) => *m,
}
}
}
impl<'tcx> Mirror<'tcx> for Stmt<'tcx> {
type Output = Stmt<'tcx>;
fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Stmt<'tcx> {
self
}
}
impl<'tcx> Mirror<'tcx> for StmtRef<'tcx> {
type Output = Stmt<'tcx>;
fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Stmt<'tcx> {
match self {
StmtRef::Mirror(m) => *m,
}
}
}
impl<'tcx> Mirror<'tcx> for Block<'tcx> {
type Output = Block<'tcx>;
fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Block<'tcx> {
self
}
}