]>
Commit | Line | Data |
---|---|---|
dc9dc135 | 1 | use crate::build::scope::BreakableTarget; |
9fa01778 | 2 | use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; |
ba9703b0 XL |
3 | use rustc_middle::middle::region; |
4 | use rustc_middle::mir::*; | |
17df50a5 | 5 | use rustc_middle::thir::*; |
a7813a04 | 6 | |
dc9dc135 | 7 | impl<'a, 'tcx> Builder<'a, 'tcx> { |
3dfed10e | 8 | /// Builds a block of MIR statements to evaluate the THIR `expr`. |
9c376795 FG |
9 | /// |
10 | /// The `statement_scope` is used if a statement temporary must be dropped. | |
923072b8 | 11 | pub(crate) fn stmt_expr( |
dc9dc135 XL |
12 | &mut self, |
13 | mut block: BasicBlock, | |
17df50a5 | 14 | expr: &Expr<'tcx>, |
dc9dc135 XL |
15 | statement_scope: Option<region::Scope>, |
16 | ) -> BlockAnd<()> { | |
a7813a04 XL |
17 | let this = self; |
18 | let expr_span = expr.span; | |
3157f602 | 19 | let source_info = this.source_info(expr.span); |
a7813a04 XL |
20 | // Handle a number of expressions that don't need a destination at all. This |
21 | // avoids needing a mountain of temporary `()` variables. | |
22 | match expr.kind { | |
dfeec247 | 23 | ExprKind::Scope { region_scope, lint_level, value } => { |
dc9dc135 | 24 | this.in_scope((region_scope, source_info), lint_level, |this| { |
17df50a5 | 25 | this.stmt_expr(block, &this.thir[value], statement_scope) |
ea8adc8c | 26 | }) |
a7813a04 XL |
27 | } |
28 | ExprKind::Assign { lhs, rhs } => { | |
17df50a5 XL |
29 | let lhs = &this.thir[lhs]; |
30 | let rhs = &this.thir[rhs]; | |
a7813a04 XL |
31 | let lhs_span = lhs.span; |
32 | ||
a7813a04 XL |
33 | // Note: we evaluate assignments right-to-left. This |
34 | // is better for borrowck interaction with overloaded | |
35 | // operators like x[j] = x[i]. | |
36 | ||
6a06907d | 37 | debug!("stmt_expr Assign block_context.push(SubExpr) : {:?}", expr); |
0bf4aa26 XL |
38 | this.block_context.push(BlockFrame::SubExpr); |
39 | ||
a7813a04 XL |
40 | // Generate better code for things that don't need to be |
41 | // dropped. | |
6a06907d | 42 | if lhs.ty.needs_drop(this.tcx, this.param_env) { |
353b0b11 | 43 | let rhs = unpack!(block = this.as_local_rvalue(block, rhs)); |
ff7c6d11 | 44 | let lhs = unpack!(block = this.as_place(block, lhs)); |
b7449926 | 45 | unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs)); |
a7813a04 | 46 | } else { |
8bb4bdeb | 47 | let rhs = unpack!(block = this.as_local_rvalue(block, rhs)); |
ff7c6d11 | 48 | let lhs = unpack!(block = this.as_place(block, lhs)); |
ba9703b0 | 49 | this.cfg.push_assign(block, source_info, lhs, rhs); |
3157f602 | 50 | } |
0bf4aa26 XL |
51 | |
52 | this.block_context.pop(); | |
53 | block.unit() | |
a7813a04 XL |
54 | } |
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 | |
9c376795 | 60 | // overloaded version, which takes `&mut self`. This |
a7813a04 XL |
61 | // only affects weird things like `x += {x += 1; x}` |
62 | // -- is that equal to `x + (x + 1)` or `2*(x+1)`? | |
63 | ||
17df50a5 XL |
64 | let lhs = &this.thir[lhs]; |
65 | let rhs = &this.thir[rhs]; | |
3157f602 XL |
66 | let lhs_ty = lhs.ty; |
67 | ||
6a06907d | 68 | debug!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr); |
0bf4aa26 XL |
69 | this.block_context.push(BlockFrame::SubExpr); |
70 | ||
a7813a04 | 71 | // As above, RTL. |
8bb4bdeb | 72 | let rhs = unpack!(block = this.as_local_operand(block, rhs)); |
ff7c6d11 | 73 | let lhs = unpack!(block = this.as_place(block, lhs)); |
a7813a04 XL |
74 | |
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). | |
b7449926 | 78 | let result = unpack!( |
dfeec247 XL |
79 | block = |
80 | this.build_binary_op(block, op, expr_span, lhs_ty, Operand::Copy(lhs), rhs) | |
b7449926 | 81 | ); |
ba9703b0 | 82 | this.cfg.push_assign(block, source_info, lhs, result); |
a7813a04 | 83 | |
0bf4aa26 | 84 | this.block_context.pop(); |
a7813a04 XL |
85 | block.unit() |
86 | } | |
87 | ExprKind::Continue { label } => { | |
dc9dc135 | 88 | this.break_scope(block, None, BreakableTarget::Continue(label), source_info) |
a7813a04 | 89 | } |
6a06907d XL |
90 | ExprKind::Break { label, value } => this.break_scope( |
91 | block, | |
17df50a5 | 92 | value.map(|value| &this.thir[value]), |
6a06907d XL |
93 | BreakableTarget::Break(label), |
94 | source_info, | |
95 | ), | |
17df50a5 XL |
96 | ExprKind::Return { value } => this.break_scope( |
97 | block, | |
98 | value.map(|value| &this.thir[value]), | |
99 | BreakableTarget::Return, | |
100 | source_info, | |
101 | ), | |
a7813a04 | 102 | _ => { |
dc9dc135 XL |
103 | assert!( |
104 | statement_scope.is_some(), | |
105 | "Should not be calling `stmt_expr` on a general expression \ | |
106 | without a statement scope", | |
107 | ); | |
a1dfa0c6 XL |
108 | |
109 | // Issue #54382: When creating temp for the value of | |
110 | // expression like: | |
111 | // | |
112 | // `{ side_effects(); { let l = stuff(); the_value } }` | |
113 | // | |
114 | // it is usually better to focus on `the_value` rather | |
115 | // than the entirety of block(s) surrounding it. | |
9c376795 | 116 | let adjusted_span = |
f2b60f7d FG |
117 | if let ExprKind::Block { block } = expr.kind |
118 | && let Some(tail_ex) = this.thir[block].expr | |
119 | { | |
5e7ed085 | 120 | let mut expr = &this.thir[tail_ex]; |
f2b60f7d FG |
121 | loop { |
122 | match expr.kind { | |
123 | ExprKind::Block { block } | |
124 | if let Some(nested_expr) = this.thir[block].expr => | |
125 | { | |
126 | expr = &this.thir[nested_expr]; | |
127 | } | |
128 | ExprKind::Scope { value: nested_expr, .. } => { | |
129 | expr = &this.thir[nested_expr]; | |
130 | } | |
131 | _ => break, | |
132 | } | |
5e7ed085 FG |
133 | } |
134 | this.block_context.push(BlockFrame::TailExpr { | |
135 | tail_result_is_ignored: true, | |
136 | span: expr.span, | |
137 | }); | |
9c376795 FG |
138 | Some(expr.span) |
139 | } else { | |
140 | None | |
141 | }; | |
a1dfa0c6 | 142 | |
dfeec247 XL |
143 | let temp = |
144 | unpack!(block = this.as_temp(block, statement_scope, expr, Mutability::Not)); | |
dc9dc135 XL |
145 | |
146 | if let Some(span) = adjusted_span { | |
147 | this.local_decls[temp].source_info.span = span; | |
148 | this.block_context.pop(); | |
149 | } | |
a1dfa0c6 | 150 | |
a7813a04 XL |
151 | block.unit() |
152 | } | |
153 | } | |
154 | } | |
a7813a04 | 155 | } |