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`.
10 /// The `statement_scope` is used if a statement temporary must be dropped.
11 pub(crate) fn stmt_expr(
13 mut block
: BasicBlock
,
15 statement_scope
: Option
<region
::Scope
>,
18 let expr_span
= expr
.span
;
19 let source_info
= this
.source_info(expr
.span
);
20 // Handle a number of expressions that don't need a destination at all. This
21 // avoids needing a mountain of temporary `()` variables.
23 ExprKind
::Scope { region_scope, lint_level, value }
=> {
24 this
.in_scope((region_scope
, source_info
), lint_level
, |this
| {
25 this
.stmt_expr(block
, &this
.thir
[value
], statement_scope
)
28 ExprKind
::Assign { lhs, rhs }
=> {
29 let lhs
= &this
.thir
[lhs
];
30 let rhs
= &this
.thir
[rhs
];
31 let lhs_span
= lhs
.span
;
33 // Note: we evaluate assignments right-to-left. This
34 // is better for borrowck interaction with overloaded
35 // operators like x[j] = x[i].
37 debug
!("stmt_expr Assign block_context.push(SubExpr) : {:?}", expr
);
38 this
.block_context
.push(BlockFrame
::SubExpr
);
40 // Generate better code for things that don't need to be
42 if lhs
.ty
.needs_drop(this
.tcx
, this
.param_env
) {
43 let rhs
= unpack
!(block
= this
.as_local_operand(block
, rhs
));
44 let lhs
= unpack
!(block
= this
.as_place(block
, lhs
));
45 unpack
!(block
= this
.build_drop_and_replace(block
, lhs_span
, lhs
, rhs
));
47 let rhs
= unpack
!(block
= this
.as_local_rvalue(block
, rhs
));
48 let lhs
= unpack
!(block
= this
.as_place(block
, lhs
));
49 this
.cfg
.push_assign(block
, source_info
, lhs
, rhs
);
52 this
.block_context
.pop();
55 ExprKind
::AssignOp { op, lhs, rhs }
=> {
56 // FIXME(#28160) there is an interesting semantics
57 // question raised here -- should we "freeze" the
58 // value of the lhs here? I'm inclined to think not,
59 // since it seems closer to the semantics of the
60 // overloaded version, which takes `&mut self`. This
61 // only affects weird things like `x += {x += 1; x}`
62 // -- is that equal to `x + (x + 1)` or `2*(x+1)`?
64 let lhs
= &this
.thir
[lhs
];
65 let rhs
= &this
.thir
[rhs
];
68 debug
!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr
);
69 this
.block_context
.push(BlockFrame
::SubExpr
);
72 let rhs
= unpack
!(block
= this
.as_local_operand(block
, rhs
));
73 let lhs
= unpack
!(block
= this
.as_place(block
, lhs
));
75 // we don't have to drop prior contents or anything
76 // because AssignOp is only legal for Copy types
77 // (overloaded ops should be desugared into a call).
80 this
.build_binary_op(block
, op
, expr_span
, lhs_ty
, Operand
::Copy(lhs
), rhs
)
82 this
.cfg
.push_assign(block
, source_info
, lhs
, result
);
84 this
.block_context
.pop();
87 ExprKind
::Continue { label }
=> {
88 this
.break_scope(block
, None
, BreakableTarget
::Continue(label
), source_info
)
90 ExprKind
::Break { label, value }
=> this
.break_scope(
92 value
.map(|value
| &this
.thir
[value
]),
93 BreakableTarget
::Break(label
),
96 ExprKind
::Return { value }
=> this
.break_scope(
98 value
.map(|value
| &this
.thir
[value
]),
99 BreakableTarget
::Return
,
104 statement_scope
.is_some(),
105 "Should not be calling `stmt_expr` on a general expression \
106 without a statement scope",
109 // Issue #54382: When creating temp for the value of
112 // `{ side_effects(); { let l = stuff(); the_value } }`
114 // it is usually better to focus on `the_value` rather
115 // than the entirety of block(s) surrounding it.
117 if let ExprKind
::Block { block }
= expr
.kind
118 && let Some(tail_ex
) = this
.thir
[block
].expr
120 let mut expr
= &this
.thir
[tail_ex
];
123 ExprKind
::Block { block }
124 if let Some(nested_expr
) = this
.thir
[block
].expr
=>
126 expr
= &this
.thir
[nested_expr
];
128 ExprKind
::Scope { value: nested_expr, .. }
=> {
129 expr
= &this
.thir
[nested_expr
];
134 this
.block_context
.push(BlockFrame
::TailExpr
{
135 tail_result_is_ignored
: true,
144 unpack
!(block
= this
.as_temp(block
, statement_scope
, expr
, Mutability
::Not
));
146 if let Some(span
) = adjusted_span
{
147 this
.local_decls
[temp
].source_info
.span
= span
;
148 this
.block_context
.pop();