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 THIR `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 this.in_scope((*region_scope, source_info), *lint_level, |this| {
28 this.stmt_expr(block, &value, statement_scope)
31 ExprKind::Assign { lhs, rhs } => {
32 let lhs_span = lhs.span;
34 // Note: we evaluate assignments right-to-left. This
35 // is better for borrowck interaction with overloaded
36 // operators like x[j] = x[i].
38 debug!("stmt_expr Assign block_context.push(SubExpr) : {:?}", expr2);
39 this.block_context.push(BlockFrame::SubExpr);
41 // Generate better code for things that don't need to be
43 if lhs.ty.needs_drop(this.tcx, this.param_env) {
44 let rhs = unpack!(block = this.as_local_operand(block, &rhs));
45 let lhs = unpack!(block = this.as_place(block, &lhs));
46 unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs));
48 let rhs = unpack!(block = this.as_local_rvalue(block, &rhs));
49 let lhs = unpack!(block = this.as_place(block, &lhs));
50 this.cfg.push_assign(block, source_info, lhs, rhs);
53 this.block_context.pop();
56 ExprKind::AssignOp { op, lhs, rhs } => {
57 // FIXME(#28160) there is an interesting semantics
58 // question raised here -- should we "freeze" the
59 // value of the lhs here? I'm inclined to think not,
60 // since it seems closer to the semantics of the
61 // overloaded version, which takes `&mut self`. This
62 // only affects weird things like `x += {x += 1; x}`
63 // -- is that equal to `x + (x + 1)` or `2*(x+1)`?
67 debug!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr2);
68 this.block_context.push(BlockFrame::SubExpr);
71 let rhs = unpack!(block = this.as_local_operand(block, &rhs));
72 let lhs = unpack!(block = this.as_place(block, &lhs));
74 // we don't have to drop prior contents or anything
75 // because AssignOp is only legal for Copy types
76 // (overloaded ops should be desugared into a call).
78 block = this.build_binary_op(
87 this.cfg.push_assign(block, source_info, lhs, result);
89 this.block_context.pop();
92 ExprKind::Continue { label } => {
93 this.break_scope(block, None, BreakableTarget::Continue(*label), source_info)
95 ExprKind::Break { label, value } => this.break_scope(
98 BreakableTarget::Break(*label),
101 ExprKind::Return { value } => {
102 this.break_scope(block, value.as_deref(), BreakableTarget::Return, source_info)
104 ExprKind::LlvmInlineAsm { asm, outputs, inputs } => {
105 debug!("stmt_expr LlvmInlineAsm block_context.push(SubExpr) : {:?}", expr2);
106 this.block_context.push(BlockFrame::SubExpr);
107 let outputs = outputs
109 .map(|output| unpack!(block = this.as_place(block, &output)))
115 (input.span, unpack!(block = this.as_local_operand(block, &input)))
123 kind: StatementKind::LlvmInlineAsm(box LlvmInlineAsm {
130 this.block_context.pop();
135 statement_scope.is_some(),
136 "Should not be calling `stmt_expr` on a general expression \
137 without a statement scope",
140 // Issue #54382: When creating temp for the value of
143 // `{ side_effects(); { let l = stuff(); the_value } }`
145 // it is usually better to focus on `the_value` rather
146 // than the entirety of block(s) surrounding it.
147 let adjusted_span = (|| {
148 if let ExprKind::Block { body } = &expr.kind {
149 if let Some(tail_expr) = &body.expr {
150 let mut expr = &*tail_expr;
151 while let ExprKind::Block { body: subblock } = &expr.kind {
152 if let Some(subtail_expr) = &subblock.expr {
158 this.block_context.push(BlockFrame::TailExpr {
159 tail_result_is_ignored: true,
162 return Some(expr.span);
169 unpack!(block = this.as_temp(block, statement_scope, expr, Mutability::Not));
171 if let Some(span) = adjusted_span {
172 this.local_decls[temp].source_info.span = span;
173 this.block_context.pop();