1 use crate::build
::scope
::BreakableTarget
;
2 use crate::build
::{BlockAnd, BlockAndExtension, BlockFrame, Builder}
;
3 use rustc_middle
::middle
::region
;
4 use rustc_middle
::mir
::*;
5 use rustc_middle
::thir
::*;
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.
13 pub(crate) fn stmt_expr(
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.
25 ExprKind
::Scope { region_scope, lint_level, value }
=> {
26 this
.in_scope((region_scope
, source_info
), lint_level
, |this
| {
27 this
.stmt_expr(block
, &this
.thir
[value
], statement_scope
)
30 ExprKind
::Assign { lhs, rhs }
=> {
31 let lhs
= &this
.thir
[lhs
];
32 let rhs
= &this
.thir
[rhs
];
33 let lhs_span
= lhs
.span
;
35 // Note: we evaluate assignments right-to-left. This
36 // is better for borrowck interaction with overloaded
37 // operators like x[j] = x[i].
39 debug
!("stmt_expr Assign block_context.push(SubExpr) : {:?}", expr
);
40 this
.block_context
.push(BlockFrame
::SubExpr
);
42 // Generate better code for things that don't need to be
44 if lhs
.ty
.needs_drop(this
.tcx
, this
.param_env
) {
45 let rhs
= unpack
!(block
= this
.as_local_operand(block
, rhs
));
46 let lhs
= unpack
!(block
= this
.as_place(block
, lhs
));
47 unpack
!(block
= this
.build_drop_and_replace(block
, lhs_span
, lhs
, rhs
));
49 let rhs
= unpack
!(block
= this
.as_local_rvalue(block
, rhs
));
50 let lhs
= unpack
!(block
= this
.as_place(block
, lhs
));
51 this
.cfg
.push_assign(block
, source_info
, lhs
, rhs
);
54 this
.block_context
.pop();
57 ExprKind
::AssignOp { op, lhs, rhs }
=> {
58 // FIXME(#28160) there is an interesting semantics
59 // question raised here -- should we "freeze" the
60 // value of the lhs here? I'm inclined to think not,
61 // since it seems closer to the semantics of the
62 // overloaded version, which takes `&mut self`. This
63 // only affects weird things like `x += {x += 1; x}`
64 // -- is that equal to `x + (x + 1)` or `2*(x+1)`?
66 let lhs
= &this
.thir
[lhs
];
67 let rhs
= &this
.thir
[rhs
];
70 debug
!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr
);
71 this
.block_context
.push(BlockFrame
::SubExpr
);
74 let rhs
= unpack
!(block
= this
.as_local_operand(block
, rhs
));
75 let lhs
= unpack
!(block
= this
.as_place(block
, lhs
));
77 // we don't have to drop prior contents or anything
78 // because AssignOp is only legal for Copy types
79 // (overloaded ops should be desugared into a call).
82 this
.build_binary_op(block
, op
, expr_span
, lhs_ty
, Operand
::Copy(lhs
), rhs
)
84 this
.cfg
.push_assign(block
, source_info
, lhs
, result
);
86 this
.block_context
.pop();
89 ExprKind
::Continue { label }
=> {
90 this
.break_scope(block
, None
, BreakableTarget
::Continue(label
), source_info
)
92 ExprKind
::Break { label, value }
=> this
.break_scope(
94 value
.map(|value
| &this
.thir
[value
]),
95 BreakableTarget
::Break(label
),
98 ExprKind
::Return { value }
=> this
.break_scope(
100 value
.map(|value
| &this
.thir
[value
]),
101 BreakableTarget
::Return
,
106 statement_scope
.is_some(),
107 "Should not be calling `stmt_expr` on a general expression \
108 without a statement scope",
111 // Issue #54382: When creating temp for the value of
114 // `{ side_effects(); { let l = stuff(); the_value } }`
116 // it is usually better to focus on `the_value` rather
117 // than the entirety of block(s) surrounding it.
118 let adjusted_span
= (|| {
119 if let ExprKind
::Block { block }
= expr
.kind
120 && let Some(tail_ex
) = this
.thir
[block
].expr
122 let mut expr
= &this
.thir
[tail_ex
];
125 ExprKind
::Block { block }
126 if let Some(nested_expr
) = this
.thir
[block
].expr
=>
128 expr
= &this
.thir
[nested_expr
];
130 ExprKind
::Scope { value: nested_expr, .. }
=> {
131 expr
= &this
.thir
[nested_expr
];
136 this
.block_context
.push(BlockFrame
::TailExpr
{
137 tail_result_is_ignored
: true,
140 return Some(expr
.span
);
146 unpack
!(block
= this
.as_temp(block
, statement_scope
, expr
, Mutability
::Not
));
148 if let Some(span
) = adjusted_span
{
149 this
.local_decls
[temp
].source_info
.span
= span
;
150 this
.block_context
.pop();