1 use crate::build
::scope
::BreakableTarget
;
2 use crate::build
::{BlockAnd, BlockAndExtension, BlockFrame, Builder}
;
4 use rustc_middle
::middle
::region
;
5 use rustc_middle
::mir
::*;
7 impl<'a
, 'tcx
> Builder
<'a
, 'tcx
> {
8 /// Builds a block of MIR statements to evaluate the HAIR `expr`.
9 /// If the original expression was an AST statement,
10 /// (e.g., `some().code(&here());`) then `opt_stmt_span` is the
11 /// span of that statement (including its semicolon, if any).
12 /// The scope is used if a statement temporary must be dropped.
15 mut block
: BasicBlock
,
17 statement_scope
: Option
<region
::Scope
>,
20 let expr_span
= expr
.span
;
21 let source_info
= this
.source_info(expr
.span
);
22 // Handle a number of expressions that don't need a destination at all. This
23 // avoids needing a mountain of temporary `()` variables.
24 let expr2
= expr
.clone();
26 ExprKind
::Scope { region_scope, lint_level, value }
=> {
27 let value
= this
.hir
.mirror(value
);
28 this
.in_scope((region_scope
, source_info
), lint_level
, |this
| {
29 this
.stmt_expr(block
, value
, statement_scope
)
32 ExprKind
::Assign { lhs, rhs }
=> {
33 let lhs
= this
.hir
.mirror(lhs
);
34 let rhs
= this
.hir
.mirror(rhs
);
35 let lhs_span
= lhs
.span
;
37 // Note: we evaluate assignments right-to-left. This
38 // is better for borrowck interaction with overloaded
39 // operators like x[j] = x[i].
41 debug
!("stmt_expr Assign block_context.push(SubExpr) : {:?}", expr2
);
42 this
.block_context
.push(BlockFrame
::SubExpr
);
44 // Generate better code for things that don't need to be
46 if this
.hir
.needs_drop(lhs
.ty
) {
47 let rhs
= unpack
!(block
= this
.as_local_operand(block
, rhs
));
48 let lhs
= unpack
!(block
= this
.as_place(block
, lhs
));
49 unpack
!(block
= this
.build_drop_and_replace(block
, lhs_span
, lhs
, rhs
));
51 let rhs
= unpack
!(block
= this
.as_local_rvalue(block
, rhs
));
52 let lhs
= unpack
!(block
= this
.as_place(block
, lhs
));
53 this
.cfg
.push_assign(block
, source_info
, lhs
, rhs
);
56 this
.block_context
.pop();
59 ExprKind
::AssignOp { op, lhs, rhs }
=> {
60 // FIXME(#28160) there is an interesting semantics
61 // question raised here -- should we "freeze" the
62 // value of the lhs here? I'm inclined to think not,
63 // since it seems closer to the semantics of the
64 // overloaded version, which takes `&mut self`. This
65 // only affects weird things like `x += {x += 1; x}`
66 // -- is that equal to `x + (x + 1)` or `2*(x+1)`?
68 let lhs
= this
.hir
.mirror(lhs
);
71 debug
!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr2
);
72 this
.block_context
.push(BlockFrame
::SubExpr
);
75 let rhs
= unpack
!(block
= this
.as_local_operand(block
, rhs
));
76 let lhs
= unpack
!(block
= this
.as_place(block
, lhs
));
78 // we don't have to drop prior contents or anything
79 // because AssignOp is only legal for Copy types
80 // (overloaded ops should be desugared into a call).
83 this
.build_binary_op(block
, op
, expr_span
, lhs_ty
, Operand
::Copy(lhs
), rhs
)
85 this
.cfg
.push_assign(block
, source_info
, lhs
, result
);
87 this
.block_context
.pop();
90 ExprKind
::Continue { label }
=> {
91 this
.break_scope(block
, None
, BreakableTarget
::Continue(label
), source_info
)
93 ExprKind
::Break { label, value }
=> {
94 this
.break_scope(block
, value
, BreakableTarget
::Break(label
), source_info
)
96 ExprKind
::Return { value }
=> {
97 this
.break_scope(block
, value
, BreakableTarget
::Return
, source_info
)
99 ExprKind
::LlvmInlineAsm { asm, outputs, inputs }
=> {
100 debug
!("stmt_expr LlvmInlineAsm block_context.push(SubExpr) : {:?}", expr2
);
101 this
.block_context
.push(BlockFrame
::SubExpr
);
102 let outputs
= outputs
104 .map(|output
| unpack
!(block
= this
.as_place(block
, output
)))
110 (input
.span(), unpack
!(block
= this
.as_local_operand(block
, input
)))
118 kind
: StatementKind
::LlvmInlineAsm(box LlvmInlineAsm
{
125 this
.block_context
.pop();
130 statement_scope
.is_some(),
131 "Should not be calling `stmt_expr` on a general expression \
132 without a statement scope",
135 // Issue #54382: When creating temp for the value of
138 // `{ side_effects(); { let l = stuff(); the_value } }`
140 // it is usually better to focus on `the_value` rather
141 // than the entirety of block(s) surrounding it.
142 let adjusted_span
= (|| {
143 if let ExprKind
::Block { body }
= expr
.kind
{
144 if let Some(tail_expr
) = &body
.expr
{
145 let mut expr
= tail_expr
;
146 while let rustc_hir
::ExprKind
::Block(subblock
, _label
) = &expr
.kind
{
147 if let Some(subtail_expr
) = &subblock
.expr
{
154 .push(BlockFrame
::TailExpr { tail_result_is_ignored: true }
);
155 return Some(expr
.span
);
162 unpack
!(block
= this
.as_temp(block
, statement_scope
, expr
, Mutability
::Not
));
164 if let Some(span
) = adjusted_span
{
165 this
.local_decls
[temp
].source_info
.span
= span
;
166 this
.block_context
.pop();