]>
Commit | Line | Data |
---|---|---|
dc9dc135 | 1 | use crate::build::scope::BreakableTarget; |
9fa01778 | 2 | use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; |
3dfed10e | 3 | use crate::thir::*; |
ba9703b0 XL |
4 | use rustc_middle::middle::region; |
5 | use rustc_middle::mir::*; | |
a7813a04 | 6 | |
dc9dc135 | 7 | impl<'a, 'tcx> Builder<'a, 'tcx> { |
3dfed10e | 8 | /// Builds a block of MIR statements to evaluate the THIR `expr`. |
a1dfa0c6 | 9 | /// If the original expression was an AST statement, |
0731742a | 10 | /// (e.g., `some().code(&here());`) then `opt_stmt_span` is the |
a1dfa0c6 | 11 | /// span of that statement (including its semicolon, if any). |
dc9dc135 | 12 | /// The scope is used if a statement temporary must be dropped. |
dfeec247 | 13 | crate fn stmt_expr( |
dc9dc135 XL |
14 | &mut self, |
15 | mut block: BasicBlock, | |
6a06907d | 16 | expr: &Expr<'_, 'tcx>, |
dc9dc135 XL |
17 | statement_scope: Option<region::Scope>, |
18 | ) -> BlockAnd<()> { | |
a7813a04 XL |
19 | let this = self; |
20 | let expr_span = expr.span; | |
3157f602 | 21 | let source_info = this.source_info(expr.span); |
a7813a04 XL |
22 | // Handle a number of expressions that don't need a destination at all. This |
23 | // avoids needing a mountain of temporary `()` variables. | |
24 | match expr.kind { | |
dfeec247 | 25 | ExprKind::Scope { region_scope, lint_level, value } => { |
dc9dc135 XL |
26 | this.in_scope((region_scope, source_info), lint_level, |this| { |
27 | this.stmt_expr(block, value, statement_scope) | |
ea8adc8c | 28 | }) |
a7813a04 XL |
29 | } |
30 | ExprKind::Assign { lhs, 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) { |
8bb4bdeb | 43 | let rhs = unpack!(block = this.as_local_operand(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 | |
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)`? | |
63 | ||
3157f602 XL |
64 | let lhs_ty = lhs.ty; |
65 | ||
6a06907d | 66 | debug!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr); |
0bf4aa26 XL |
67 | this.block_context.push(BlockFrame::SubExpr); |
68 | ||
a7813a04 | 69 | // As above, RTL. |
8bb4bdeb | 70 | let rhs = unpack!(block = this.as_local_operand(block, rhs)); |
ff7c6d11 | 71 | let lhs = unpack!(block = this.as_place(block, lhs)); |
a7813a04 XL |
72 | |
73 | // we don't have to drop prior contents or anything | |
74 | // because AssignOp is only legal for Copy types | |
75 | // (overloaded ops should be desugared into a call). | |
b7449926 | 76 | let result = unpack!( |
dfeec247 XL |
77 | block = |
78 | this.build_binary_op(block, op, expr_span, lhs_ty, Operand::Copy(lhs), rhs) | |
b7449926 | 79 | ); |
ba9703b0 | 80 | this.cfg.push_assign(block, source_info, lhs, result); |
a7813a04 | 81 | |
0bf4aa26 | 82 | this.block_context.pop(); |
a7813a04 XL |
83 | block.unit() |
84 | } | |
85 | ExprKind::Continue { label } => { | |
dc9dc135 | 86 | this.break_scope(block, None, BreakableTarget::Continue(label), source_info) |
a7813a04 | 87 | } |
6a06907d XL |
88 | ExprKind::Break { label, value } => this.break_scope( |
89 | block, | |
90 | value.as_deref(), | |
91 | BreakableTarget::Break(label), | |
92 | source_info, | |
93 | ), | |
a7813a04 | 94 | ExprKind::Return { value } => { |
6a06907d | 95 | this.break_scope(block, value.as_deref(), BreakableTarget::Return, source_info) |
a7813a04 | 96 | } |
ba9703b0 | 97 | ExprKind::LlvmInlineAsm { asm, outputs, inputs } => { |
6a06907d | 98 | debug!("stmt_expr LlvmInlineAsm block_context.push(SubExpr) : {:?}", expr); |
0bf4aa26 | 99 | this.block_context.push(BlockFrame::SubExpr); |
b7449926 XL |
100 | let outputs = outputs |
101 | .into_iter() | |
6a06907d | 102 | .map(|output| unpack!(block = this.as_place(block, &output))) |
0bf4aa26 XL |
103 | .collect::<Vec<_>>() |
104 | .into_boxed_slice(); | |
b7449926 XL |
105 | let inputs = inputs |
106 | .into_iter() | |
a1dfa0c6 | 107 | .map(|input| { |
6a06907d | 108 | (input.span, unpack!(block = this.as_local_operand(block, &input))) |
dfeec247 XL |
109 | }) |
110 | .collect::<Vec<_>>() | |
0bf4aa26 | 111 | .into_boxed_slice(); |
b7449926 XL |
112 | this.cfg.push( |
113 | block, | |
114 | Statement { | |
115 | source_info, | |
ba9703b0 | 116 | kind: StatementKind::LlvmInlineAsm(box LlvmInlineAsm { |
532ac7d7 | 117 | asm: asm.clone(), |
b7449926 XL |
118 | outputs, |
119 | inputs, | |
532ac7d7 | 120 | }), |
8bb4bdeb | 121 | }, |
b7449926 | 122 | ); |
0bf4aa26 | 123 | this.block_context.pop(); |
8bb4bdeb XL |
124 | block.unit() |
125 | } | |
a7813a04 | 126 | _ => { |
dc9dc135 XL |
127 | assert!( |
128 | statement_scope.is_some(), | |
129 | "Should not be calling `stmt_expr` on a general expression \ | |
130 | without a statement scope", | |
131 | ); | |
a1dfa0c6 XL |
132 | |
133 | // Issue #54382: When creating temp for the value of | |
134 | // expression like: | |
135 | // | |
136 | // `{ side_effects(); { let l = stuff(); the_value } }` | |
137 | // | |
138 | // it is usually better to focus on `the_value` rather | |
139 | // than the entirety of block(s) surrounding it. | |
dc9dc135 | 140 | let adjusted_span = (|| { |
6a06907d | 141 | if let ExprKind::Block { body } = &expr.kind { |
dc9dc135 | 142 | if let Some(tail_expr) = &body.expr { |
6a06907d XL |
143 | let mut expr = &*tail_expr; |
144 | while let ExprKind::Block { | |
145 | body: Block { expr: Some(nested_expr), .. }, | |
146 | } | |
147 | | ExprKind::Scope { value: nested_expr, .. } = &expr.kind | |
148 | { | |
149 | expr = nested_expr; | |
a1dfa0c6 | 150 | } |
3dfed10e XL |
151 | this.block_context.push(BlockFrame::TailExpr { |
152 | tail_result_is_ignored: true, | |
153 | span: expr.span, | |
154 | }); | |
dc9dc135 | 155 | return Some(expr.span); |
a1dfa0c6 XL |
156 | } |
157 | } | |
dc9dc135 XL |
158 | None |
159 | })(); | |
a1dfa0c6 | 160 | |
dfeec247 XL |
161 | let temp = |
162 | unpack!(block = this.as_temp(block, statement_scope, expr, Mutability::Not)); | |
dc9dc135 XL |
163 | |
164 | if let Some(span) = adjusted_span { | |
165 | this.local_decls[temp].source_info.span = span; | |
166 | this.block_context.pop(); | |
167 | } | |
a1dfa0c6 | 168 | |
a7813a04 XL |
169 | block.unit() |
170 | } | |
171 | } | |
172 | } | |
a7813a04 | 173 | } |