]>
Commit | Line | Data |
---|---|---|
e9174d1e SL |
1 | //! See docs in build/expr/mod.rs |
2 | ||
9fa01778 | 3 | use crate::build::expr::category::{Category, RvalueFunc}; |
04454e1e | 4 | use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, NeedsTemporary}; |
3dfed10e | 5 | use rustc_ast::InlineAsmOptions; |
60c5eb7d | 6 | use rustc_data_structures::fx::FxHashMap; |
3dfed10e | 7 | use rustc_data_structures::stack::ensure_sufficient_stack; |
dfeec247 | 8 | use rustc_hir as hir; |
ba9703b0 | 9 | use rustc_middle::mir::*; |
17df50a5 | 10 | use rustc_middle::thir::*; |
5e7ed085 | 11 | use rustc_middle::ty::CanonicalUserTypeAnnotation; |
cdc7bbd5 | 12 | use std::iter; |
cc61c64b | 13 | |
dc9dc135 | 14 | impl<'a, 'tcx> Builder<'a, 'tcx> { |
e9174d1e SL |
15 | /// Compile `expr`, storing the result into `destination`, which |
16 | /// is assumed to be uninitialized. | |
2b03887a | 17 | #[instrument(level = "debug", skip(self))] |
923072b8 | 18 | pub(crate) fn expr_into_dest( |
b7449926 | 19 | &mut self, |
ba9703b0 | 20 | destination: Place<'tcx>, |
b7449926 | 21 | mut block: BasicBlock, |
17df50a5 | 22 | expr: &Expr<'tcx>, |
b7449926 | 23 | ) -> BlockAnd<()> { |
e9174d1e SL |
24 | // since we frequently have to reference `self` from within a |
25 | // closure, where `self` would be shadowed, it's easier to | |
26 | // just use the name `this` uniformly | |
27 | let this = self; | |
28 | let expr_span = expr.span; | |
3157f602 | 29 | let source_info = this.source_info(expr_span); |
e9174d1e | 30 | |
5869c6ff XL |
31 | let expr_is_block_or_scope = |
32 | matches!(expr.kind, ExprKind::Block { .. } | ExprKind::Scope { .. }); | |
0bf4aa26 XL |
33 | |
34 | if !expr_is_block_or_scope { | |
35 | this.block_context.push(BlockFrame::SubExpr); | |
36 | } | |
37 | ||
38 | let block_and = match expr.kind { | |
dfeec247 | 39 | ExprKind::Scope { region_scope, lint_level, value } => { |
ea8adc8c | 40 | let region_scope = (region_scope, source_info); |
3dfed10e XL |
41 | ensure_sufficient_stack(|| { |
42 | this.in_scope(region_scope, lint_level, |this| { | |
17df50a5 | 43 | this.expr_into_dest(destination, block, &this.thir[value]) |
3dfed10e XL |
44 | }) |
45 | }) | |
e9174d1e | 46 | } |
f2b60f7d | 47 | ExprKind::Block { block: ast_block } => { |
cc61c64b | 48 | this.ast_block(destination, block, ast_block, source_info) |
e9174d1e | 49 | } |
17df50a5 XL |
50 | ExprKind::Match { scrutinee, ref arms } => { |
51 | this.match_expr(destination, expr_span, block, &this.thir[scrutinee], arms) | |
e9174d1e | 52 | } |
94222f64 XL |
53 | ExprKind::If { cond, then, else_opt, if_then_scope } => { |
54 | let then_blk; | |
55 | let then_expr = &this.thir[then]; | |
56 | let then_source_info = this.source_info(then_expr.span); | |
57 | let condition_scope = this.local_scope(); | |
58 | ||
59 | let mut else_blk = unpack!( | |
60 | then_blk = this.in_scope( | |
61 | (if_then_scope, then_source_info), | |
62 | LintLevel::Inherited, | |
63 | |this| { | |
923072b8 FG |
64 | let source_info = if this.is_let(cond) { |
65 | let variable_scope = this.new_source_scope( | |
66 | then_expr.span, | |
67 | LintLevel::Inherited, | |
68 | None, | |
69 | ); | |
70 | this.source_scope = variable_scope; | |
71 | SourceInfo { span: then_expr.span, scope: variable_scope } | |
72 | } else { | |
73 | this.source_info(then_expr.span) | |
74 | }; | |
94222f64 | 75 | let (then_block, else_block) = |
f2b60f7d | 76 | this.in_if_then_scope(condition_scope, then_expr.span, |this| { |
94222f64 XL |
77 | let then_blk = unpack!(this.then_else_break( |
78 | block, | |
79 | &this.thir[cond], | |
80 | Some(condition_scope), | |
81 | condition_scope, | |
923072b8 | 82 | source_info |
94222f64 | 83 | )); |
923072b8 | 84 | |
94222f64 XL |
85 | this.expr_into_dest(destination, then_blk, then_expr) |
86 | }); | |
87 | then_block.and(else_block) | |
88 | }, | |
17df50a5 | 89 | ) |
5869c6ff | 90 | ); |
5869c6ff | 91 | |
94222f64 XL |
92 | else_blk = if let Some(else_opt) = else_opt { |
93 | unpack!(this.expr_into_dest(destination, else_blk, &this.thir[else_opt])) | |
5869c6ff XL |
94 | } else { |
95 | // Body of the `if` expression without an `else` clause must return `()`, thus | |
94222f64 | 96 | // we implicitly generate an `else {}` if it is not specified. |
5869c6ff | 97 | let correct_si = this.source_info(expr_span.shrink_to_hi()); |
94222f64 XL |
98 | this.cfg.push_assign_unit(else_blk, correct_si, destination, this.tcx); |
99 | else_blk | |
5869c6ff XL |
100 | }; |
101 | ||
102 | let join_block = this.cfg.start_new_block(); | |
5099ac24 FG |
103 | this.cfg.goto(then_blk, source_info, join_block); |
104 | this.cfg.goto(else_blk, source_info, join_block); | |
5869c6ff XL |
105 | join_block.unit() |
106 | } | |
94222f64 XL |
107 | ExprKind::Let { expr, ref pat } => { |
108 | let scope = this.local_scope(); | |
f2b60f7d | 109 | let (true_block, false_block) = this.in_if_then_scope(scope, expr_span, |this| { |
487cf647 | 110 | this.lower_let_expr(block, &this.thir[expr], pat, scope, None, expr_span, true) |
94222f64 XL |
111 | }); |
112 | ||
94222f64 XL |
113 | this.cfg.push_assign_constant( |
114 | true_block, | |
115 | source_info, | |
116 | destination, | |
117 | Constant { | |
118 | span: expr_span, | |
119 | user_ty: None, | |
5e7ed085 | 120 | literal: ConstantKind::from_bool(this.tcx, true), |
94222f64 XL |
121 | }, |
122 | ); | |
123 | ||
124 | this.cfg.push_assign_constant( | |
125 | false_block, | |
126 | source_info, | |
127 | destination, | |
128 | Constant { | |
129 | span: expr_span, | |
130 | user_ty: None, | |
5e7ed085 | 131 | literal: ConstantKind::from_bool(this.tcx, false), |
94222f64 XL |
132 | }, |
133 | ); | |
134 | ||
5099ac24 | 135 | let join_block = this.cfg.start_new_block(); |
94222f64 XL |
136 | this.cfg.goto(true_block, source_info, join_block); |
137 | this.cfg.goto(false_block, source_info, join_block); | |
138 | join_block.unit() | |
139 | } | |
5bcae85e | 140 | ExprKind::NeverToAny { source } => { |
17df50a5 | 141 | let source = &this.thir[source]; |
5869c6ff XL |
142 | let is_call = |
143 | matches!(source.kind, ExprKind::Call { .. } | ExprKind::InlineAsm { .. }); | |
5bcae85e | 144 | |
60c5eb7d XL |
145 | // (#66975) Source could be a const of type `!`, so has to |
146 | // exist in the generated MIR. | |
5869c6ff XL |
147 | unpack!( |
148 | block = this.as_temp(block, Some(this.local_scope()), source, Mutability::Mut,) | |
149 | ); | |
5bcae85e SL |
150 | |
151 | // This is an optimization. If the expression was a call then we already have an | |
152 | // unreachable block. Don't bother to terminate it and create a new one. | |
153 | if is_call { | |
154 | block.unit() | |
155 | } else { | |
dfeec247 | 156 | this.cfg.terminate(block, source_info, TerminatorKind::Unreachable); |
5bcae85e SL |
157 | let end_block = this.cfg.start_new_block(); |
158 | end_block.unit() | |
159 | } | |
160 | } | |
e9174d1e SL |
161 | ExprKind::LogicalOp { op, lhs, rhs } => { |
162 | // And: | |
163 | // | |
cdc7bbd5 XL |
164 | // [block: If(lhs)] -true-> [else_block: dest = (rhs)] |
165 | // | (false) | |
49aad941 | 166 | // [shortcircuit_block: dest = false] |
e9174d1e SL |
167 | // |
168 | // Or: | |
169 | // | |
cdc7bbd5 XL |
170 | // [block: If(lhs)] -false-> [else_block: dest = (rhs)] |
171 | // | (true) | |
49aad941 | 172 | // [shortcircuit_block: dest = true] |
e9174d1e | 173 | |
cdc7bbd5 | 174 | let (shortcircuit_block, mut else_block, join_block) = ( |
b7449926 XL |
175 | this.cfg.start_new_block(), |
176 | this.cfg.start_new_block(), | |
177 | this.cfg.start_new_block(), | |
178 | ); | |
e9174d1e | 179 | |
17df50a5 | 180 | let lhs = unpack!(block = this.as_local_operand(block, &this.thir[lhs])); |
e9174d1e | 181 | let blocks = match op { |
cdc7bbd5 XL |
182 | LogicalOp::And => (else_block, shortcircuit_block), |
183 | LogicalOp::Or => (shortcircuit_block, else_block), | |
e9174d1e | 184 | }; |
9c376795 | 185 | let term = TerminatorKind::if_(lhs, blocks.0, blocks.1); |
8bb4bdeb | 186 | this.cfg.terminate(block, source_info, term); |
e9174d1e | 187 | |
e9174d1e | 188 | this.cfg.push_assign_constant( |
cdc7bbd5 | 189 | shortcircuit_block, |
b7449926 XL |
190 | source_info, |
191 | destination, | |
6a06907d XL |
192 | Constant { |
193 | span: expr_span, | |
194 | user_ty: None, | |
cdc7bbd5 | 195 | literal: match op { |
5e7ed085 FG |
196 | LogicalOp::And => ConstantKind::from_bool(this.tcx, false), |
197 | LogicalOp::Or => ConstantKind::from_bool(this.tcx, true), | |
cdc7bbd5 | 198 | }, |
6a06907d | 199 | }, |
b7449926 | 200 | ); |
cdc7bbd5 | 201 | this.cfg.goto(shortcircuit_block, source_info, join_block); |
416331ca | 202 | |
17df50a5 | 203 | let rhs = unpack!(else_block = this.as_local_operand(else_block, &this.thir[rhs])); |
cdc7bbd5 XL |
204 | this.cfg.push_assign(else_block, source_info, destination, Rvalue::Use(rhs)); |
205 | this.cfg.goto(else_block, source_info, join_block); | |
e9174d1e SL |
206 | |
207 | join_block.unit() | |
208 | } | |
416331ca | 209 | ExprKind::Loop { body } => { |
2c00a5a8 XL |
210 | // [block] |
211 | // | | |
212 | // [loop_block] -> [body_block] -/eval. body/-> [body_block_end] | |
213 | // | ^ | | |
214 | // false link | | | |
215 | // | +-----------------------------------------+ | |
216 | // +-> [diverge_cleanup] | |
217 | // The false link is required to make sure borrowck considers unwinds through the | |
218 | // body, even when the exact code in the body cannot unwind | |
e9174d1e SL |
219 | |
220 | let loop_block = this.cfg.start_new_block(); | |
e9174d1e | 221 | |
dfeec247 XL |
222 | // Start the loop. |
223 | this.cfg.goto(block, source_info, loop_block); | |
e9174d1e | 224 | |
29967ef6 | 225 | this.in_breakable_scope(Some(loop_block), destination, expr_span, move |this| { |
ba9703b0 XL |
226 | // conduct the test, if necessary |
227 | let body_block = this.cfg.start_new_block(); | |
ba9703b0 XL |
228 | this.cfg.terminate( |
229 | loop_block, | |
230 | source_info, | |
353b0b11 FG |
231 | TerminatorKind::FalseUnwind { |
232 | real_target: body_block, | |
233 | unwind: UnwindAction::Continue, | |
234 | }, | |
ba9703b0 | 235 | ); |
29967ef6 | 236 | this.diverge_from(loop_block); |
ba9703b0 | 237 | |
94222f64 | 238 | // The “return” value of the loop body must always be a unit. We therefore |
ba9703b0 XL |
239 | // introduce a unit temporary as the destination for the loop body. |
240 | let tmp = this.get_unit_temp(); | |
241 | // Execute the body, branching back to the test. | |
17df50a5 XL |
242 | let body_block_end = |
243 | unpack!(this.expr_into_dest(tmp, body_block, &this.thir[body])); | |
ba9703b0 | 244 | this.cfg.goto(body_block_end, source_info, loop_block); |
29967ef6 XL |
245 | |
246 | // Loops are only exited by `break` expressions. | |
247 | None | |
248 | }) | |
e9174d1e | 249 | } |
17df50a5 XL |
250 | ExprKind::Call { ty: _, fun, ref args, from_hir_call, fn_span } => { |
251 | let fun = unpack!(block = this.as_local_operand(block, &this.thir[fun])); | |
5869c6ff XL |
252 | let args: Vec<_> = args |
253 | .into_iter() | |
17df50a5 XL |
254 | .copied() |
255 | .map(|arg| unpack!(block = this.as_local_call_operand(block, &this.thir[arg]))) | |
5869c6ff | 256 | .collect(); |
cc61c64b | 257 | |
5869c6ff | 258 | let success = this.cfg.start_new_block(); |
e1599b0c | 259 | |
5869c6ff | 260 | this.record_operands_moved(&args); |
e1599b0c | 261 | |
6a06907d | 262 | debug!("expr_into_dest: fn_span={:?}", fn_span); |
f035d41b | 263 | |
5869c6ff XL |
264 | this.cfg.terminate( |
265 | block, | |
266 | source_info, | |
267 | TerminatorKind::Call { | |
268 | func: fun, | |
269 | args, | |
353b0b11 | 270 | unwind: UnwindAction::Continue, |
923072b8 | 271 | destination, |
04454e1e FG |
272 | // The presence or absence of a return edge affects control-flow sensitive |
273 | // MIR checks and ultimately whether code is accepted or not. We can only | |
274 | // omit the return edge if a return type is visibly uninhabited to a module | |
275 | // that makes the call. | |
487cf647 FG |
276 | target: expr |
277 | .ty | |
278 | .is_inhabited_from(this.tcx, this.parent_module, this.param_env) | |
279 | .then_some(success), | |
5869c6ff XL |
280 | from_hir_call, |
281 | fn_span, | |
282 | }, | |
283 | ); | |
284 | this.diverge_from(block); | |
285 | success.unit() | |
e9174d1e | 286 | } |
17df50a5 | 287 | ExprKind::Use { source } => this.expr_into_dest(destination, block, &this.thir[source]), |
60c5eb7d | 288 | ExprKind::Borrow { arg, borrow_kind } => { |
17df50a5 | 289 | let arg = &this.thir[arg]; |
60c5eb7d XL |
290 | // We don't do this in `as_rvalue` because we use `as_place` |
291 | // for borrow expressions, so we cannot create an `RValue` that | |
292 | // remains valid across user code. `as_rvalue` is usually called | |
293 | // by this method anyway, so this shouldn't cause too many | |
294 | // unnecessary temporaries. | |
295 | let arg_place = match borrow_kind { | |
296 | BorrowKind::Shared => unpack!(block = this.as_read_only_place(block, arg)), | |
297 | _ => unpack!(block = this.as_place(block, arg)), | |
298 | }; | |
6a06907d | 299 | let borrow = Rvalue::Ref(this.tcx.lifetimes.re_erased, borrow_kind, arg_place); |
60c5eb7d XL |
300 | this.cfg.push_assign(block, source_info, destination, borrow); |
301 | block.unit() | |
302 | } | |
dfeec247 | 303 | ExprKind::AddressOf { mutability, arg } => { |
17df50a5 | 304 | let arg = &this.thir[arg]; |
dfeec247 XL |
305 | let place = match mutability { |
306 | hir::Mutability::Not => this.as_read_only_place(block, arg), | |
307 | hir::Mutability::Mut => this.as_place(block, arg), | |
308 | }; | |
309 | let address_of = Rvalue::AddressOf(mutability, unpack!(block = place)); | |
310 | this.cfg.push_assign(block, source_info, destination, address_of); | |
311 | block.unit() | |
312 | } | |
f2b60f7d | 313 | ExprKind::Adt(box AdtExpr { |
136023e0 XL |
314 | adt_def, |
315 | variant_index, | |
316 | substs, | |
f2b60f7d | 317 | ref user_ty, |
136023e0 XL |
318 | ref fields, |
319 | ref base, | |
320 | }) => { | |
60c5eb7d XL |
321 | // See the notes for `ExprKind::Array` in `as_rvalue` and for |
322 | // `ExprKind::Borrow` above. | |
323 | let is_union = adt_def.is_union(); | |
353b0b11 | 324 | let active_field_index = is_union.then(|| fields[0].name); |
60c5eb7d | 325 | |
dfeec247 | 326 | let scope = this.local_scope(); |
60c5eb7d XL |
327 | |
328 | // first process the set of fields that were provided | |
329 | // (evaluating them in order given by user) | |
330 | let fields_map: FxHashMap<_, _> = fields | |
331 | .into_iter() | |
17df50a5 XL |
332 | .map(|f| { |
333 | ( | |
334 | f.name, | |
335 | unpack!( | |
c295e0f8 XL |
336 | block = this.as_operand( |
337 | block, | |
338 | Some(scope), | |
339 | &this.thir[f.expr], | |
353b0b11 | 340 | LocalInfo::AggregateTemp, |
04454e1e | 341 | NeedsTemporary::Maybe, |
c295e0f8 | 342 | ) |
17df50a5 XL |
343 | ), |
344 | ) | |
345 | }) | |
dfeec247 | 346 | .collect(); |
60c5eb7d | 347 | |
353b0b11 | 348 | let field_names = adt_def.variant(variant_index).fields.indices(); |
60c5eb7d | 349 | |
353b0b11 | 350 | let fields = if let Some(FruInfo { base, field_types }) = base { |
17df50a5 XL |
351 | let place_builder = |
352 | unpack!(block = this.as_place_builder(block, &this.thir[*base])); | |
ba9703b0 XL |
353 | |
354 | // MIR does not natively support FRU, so for each | |
355 | // base-supplied field, generate an operand that | |
356 | // reads it from the base. | |
17df50a5 | 357 | iter::zip(field_names, &**field_types) |
ba9703b0 XL |
358 | .map(|(n, ty)| match fields_map.get(&n) { |
359 | Some(v) => v.clone(), | |
5869c6ff | 360 | None => { |
487cf647 FG |
361 | let place = place_builder.clone_project(PlaceElem::Field(n, *ty)); |
362 | this.consume_by_copy_or_move(place.to_place(this)) | |
5869c6ff | 363 | } |
ba9703b0 XL |
364 | }) |
365 | .collect() | |
366 | } else { | |
353b0b11 | 367 | field_names.filter_map(|n| fields_map.get(&n).cloned()).collect() |
ba9703b0 | 368 | }; |
60c5eb7d XL |
369 | |
370 | let inferred_ty = expr.ty; | |
f2b60f7d | 371 | let user_ty = user_ty.as_ref().map(|user_ty| { |
60c5eb7d XL |
372 | this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { |
373 | span: source_info.span, | |
f2b60f7d | 374 | user_ty: user_ty.clone(), |
60c5eb7d XL |
375 | inferred_ty, |
376 | }) | |
377 | }); | |
94222f64 | 378 | let adt = Box::new(AggregateKind::Adt( |
5e7ed085 | 379 | adt_def.did(), |
60c5eb7d XL |
380 | variant_index, |
381 | substs, | |
382 | user_ty, | |
383 | active_field_index, | |
94222f64 | 384 | )); |
60c5eb7d XL |
385 | this.cfg.push_assign( |
386 | block, | |
387 | source_info, | |
388 | destination, | |
dfeec247 | 389 | Rvalue::Aggregate(adt, fields), |
60c5eb7d XL |
390 | ); |
391 | block.unit() | |
392 | } | |
f2b60f7d FG |
393 | ExprKind::InlineAsm(box InlineAsmExpr { |
394 | template, | |
395 | ref operands, | |
396 | options, | |
397 | line_spans, | |
398 | }) => { | |
17df50a5 | 399 | use rustc_middle::{mir, thir}; |
f9f354fc XL |
400 | let operands = operands |
401 | .into_iter() | |
6a06907d | 402 | .map(|op| match *op { |
3dfed10e | 403 | thir::InlineAsmOperand::In { reg, expr } => mir::InlineAsmOperand::In { |
f9f354fc | 404 | reg, |
17df50a5 | 405 | value: unpack!(block = this.as_local_operand(block, &this.thir[expr])), |
f9f354fc | 406 | }, |
3dfed10e | 407 | thir::InlineAsmOperand::Out { reg, late, expr } => { |
f9f354fc XL |
408 | mir::InlineAsmOperand::Out { |
409 | reg, | |
410 | late, | |
17df50a5 XL |
411 | place: expr.map(|expr| { |
412 | unpack!(block = this.as_place(block, &this.thir[expr])) | |
413 | }), | |
f9f354fc XL |
414 | } |
415 | } | |
3dfed10e | 416 | thir::InlineAsmOperand::InOut { reg, late, expr } => { |
17df50a5 | 417 | let place = unpack!(block = this.as_place(block, &this.thir[expr])); |
f9f354fc XL |
418 | mir::InlineAsmOperand::InOut { |
419 | reg, | |
420 | late, | |
421 | // This works because asm operands must be Copy | |
422 | in_value: Operand::Copy(place), | |
423 | out_place: Some(place), | |
424 | } | |
425 | } | |
3dfed10e | 426 | thir::InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => { |
f9f354fc XL |
427 | mir::InlineAsmOperand::InOut { |
428 | reg, | |
429 | late, | |
17df50a5 XL |
430 | in_value: unpack!( |
431 | block = this.as_local_operand(block, &this.thir[in_expr]) | |
432 | ), | |
433 | out_place: out_expr.map(|out_expr| { | |
434 | unpack!(block = this.as_place(block, &this.thir[out_expr])) | |
f9f354fc XL |
435 | }), |
436 | } | |
437 | } | |
cdc7bbd5 XL |
438 | thir::InlineAsmOperand::Const { value, span } => { |
439 | mir::InlineAsmOperand::Const { | |
04454e1e FG |
440 | value: Box::new(Constant { span, user_ty: None, literal: value }), |
441 | } | |
442 | } | |
443 | thir::InlineAsmOperand::SymFn { value, span } => { | |
444 | mir::InlineAsmOperand::SymFn { | |
923072b8 | 445 | value: Box::new(Constant { span, user_ty: None, literal: value }), |
cdc7bbd5 XL |
446 | } |
447 | } | |
3dfed10e | 448 | thir::InlineAsmOperand::SymStatic { def_id } => { |
f035d41b | 449 | mir::InlineAsmOperand::SymStatic { def_id } |
f9f354fc XL |
450 | } |
451 | }) | |
452 | .collect(); | |
453 | ||
c295e0f8 XL |
454 | if !options.contains(InlineAsmOptions::NORETURN) { |
455 | this.cfg.push_assign_unit(block, source_info, destination, this.tcx); | |
456 | } | |
f9f354fc | 457 | |
c295e0f8 | 458 | let destination_block = this.cfg.start_new_block(); |
f9f354fc XL |
459 | this.cfg.terminate( |
460 | block, | |
461 | source_info, | |
462 | TerminatorKind::InlineAsm { | |
463 | template, | |
464 | operands, | |
465 | options, | |
466 | line_spans, | |
467 | destination: if options.contains(InlineAsmOptions::NORETURN) { | |
468 | None | |
469 | } else { | |
c295e0f8 | 470 | Some(destination_block) |
f9f354fc | 471 | }, |
353b0b11 FG |
472 | unwind: if options.contains(InlineAsmOptions::MAY_UNWIND) { |
473 | UnwindAction::Continue | |
474 | } else { | |
475 | UnwindAction::Unreachable | |
476 | }, | |
f9f354fc XL |
477 | }, |
478 | ); | |
a2a8927a XL |
479 | if options.contains(InlineAsmOptions::MAY_UNWIND) { |
480 | this.diverge_from(block); | |
481 | } | |
c295e0f8 | 482 | destination_block.unit() |
f9f354fc | 483 | } |
60c5eb7d | 484 | |
a7813a04 | 485 | // These cases don't actually need a destination |
5099ac24 | 486 | ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { |
a1dfa0c6 | 487 | unpack!(block = this.stmt_expr(block, expr, None)); |
6a06907d | 488 | this.cfg.push_assign_unit(block, source_info, destination, this.tcx); |
ff7c6d11 | 489 | block.unit() |
a7813a04 XL |
490 | } |
491 | ||
3dfed10e XL |
492 | ExprKind::Continue { .. } | ExprKind::Break { .. } | ExprKind::Return { .. } => { |
493 | unpack!(block = this.stmt_expr(block, expr, None)); | |
494 | // No assign, as these have type `!`. | |
495 | block.unit() | |
496 | } | |
497 | ||
8faf50e0 | 498 | // Avoid creating a temporary |
dfeec247 | 499 | ExprKind::VarRef { .. } |
fc512014 | 500 | | ExprKind::UpvarRef { .. } |
dfeec247 XL |
501 | | ExprKind::PlaceTypeAscription { .. } |
502 | | ExprKind::ValueTypeAscription { .. } => { | |
8faf50e0 XL |
503 | debug_assert!(Category::of(&expr.kind) == Some(Category::Place)); |
504 | ||
505 | let place = unpack!(block = this.as_place(block, expr)); | |
506 | let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place)); | |
dfeec247 | 507 | this.cfg.push_assign(block, source_info, destination, rvalue); |
8faf50e0 XL |
508 | block.unit() |
509 | } | |
b7449926 | 510 | ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Field { .. } => { |
6a06907d | 511 | debug_assert_eq!(Category::of(&expr.kind), Some(Category::Place)); |
8faf50e0 XL |
512 | |
513 | // Create a "fake" temporary variable so that we check that the | |
514 | // value is Sized. Usually, this is caught in type checking, but | |
515 | // in the case of box expr there is no such check. | |
e1599b0c | 516 | if !destination.projection.is_empty() { |
f9f354fc | 517 | this.local_decls.push(LocalDecl::new(expr.ty, expr.span)); |
8faf50e0 XL |
518 | } |
519 | ||
8faf50e0 XL |
520 | let place = unpack!(block = this.as_place(block, expr)); |
521 | let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place)); | |
dfeec247 | 522 | this.cfg.push_assign(block, source_info, destination, rvalue); |
8faf50e0 XL |
523 | block.unit() |
524 | } | |
525 | ||
74b04a01 XL |
526 | ExprKind::Yield { value } => { |
527 | let scope = this.local_scope(); | |
04454e1e FG |
528 | let value = unpack!( |
529 | block = this.as_operand( | |
530 | block, | |
531 | Some(scope), | |
532 | &this.thir[value], | |
353b0b11 | 533 | LocalInfo::Boring, |
04454e1e FG |
534 | NeedsTemporary::No |
535 | ) | |
536 | ); | |
74b04a01 | 537 | let resume = this.cfg.start_new_block(); |
74b04a01 XL |
538 | this.cfg.terminate( |
539 | block, | |
540 | source_info, | |
29967ef6 | 541 | TerminatorKind::Yield { value, resume, resume_arg: destination, drop: None }, |
74b04a01 | 542 | ); |
29967ef6 | 543 | this.generator_drop_cleanup(block); |
74b04a01 XL |
544 | resume.unit() |
545 | } | |
546 | ||
e9174d1e | 547 | // these are the cases that are more naturally handled by some other mode |
b7449926 XL |
548 | ExprKind::Unary { .. } |
549 | | ExprKind::Binary { .. } | |
550 | | ExprKind::Box { .. } | |
551 | | ExprKind::Cast { .. } | |
48663c56 | 552 | | ExprKind::Pointer { .. } |
b7449926 | 553 | | ExprKind::Repeat { .. } |
b7449926 XL |
554 | | ExprKind::Array { .. } |
555 | | ExprKind::Tuple { .. } | |
b7449926 | 556 | | ExprKind::Closure { .. } |
29967ef6 | 557 | | ExprKind::ConstBlock { .. } |
b7449926 | 558 | | ExprKind::Literal { .. } |
5e7ed085 FG |
559 | | ExprKind::NamedConst { .. } |
560 | | ExprKind::NonHirLiteral { .. } | |
064997fb | 561 | | ExprKind::ZstLiteral { .. } |
5e7ed085 | 562 | | ExprKind::ConstParam { .. } |
f9f354fc | 563 | | ExprKind::ThreadLocalRef(_) |
49aad941 FG |
564 | | ExprKind::StaticRef { .. } |
565 | | ExprKind::OffsetOf { .. } => { | |
e9174d1e | 566 | debug_assert!(match Category::of(&expr.kind).unwrap() { |
0bf4aa26 | 567 | // should be handled above |
e9174d1e | 568 | Category::Rvalue(RvalueFunc::Into) => false, |
0bf4aa26 XL |
569 | |
570 | // must be handled above or else we get an | |
571 | // infinite loop in the builder; see | |
0731742a | 572 | // e.g., `ExprKind::VarRef` above |
0bf4aa26 XL |
573 | Category::Place => false, |
574 | ||
e9174d1e SL |
575 | _ => true, |
576 | }); | |
577 | ||
8bb4bdeb | 578 | let rvalue = unpack!(block = this.as_local_rvalue(block, expr)); |
0731742a | 579 | this.cfg.push_assign(block, source_info, destination, rvalue); |
e9174d1e SL |
580 | block.unit() |
581 | } | |
0bf4aa26 XL |
582 | }; |
583 | ||
584 | if !expr_is_block_or_scope { | |
585 | let popped = this.block_context.pop(); | |
586 | assert!(popped.is_some()); | |
e9174d1e | 587 | } |
0bf4aa26 XL |
588 | |
589 | block_and | |
e9174d1e | 590 | } |
923072b8 FG |
591 | |
592 | fn is_let(&self, expr: ExprId) -> bool { | |
593 | match self.thir[expr].kind { | |
594 | ExprKind::Let { .. } => true, | |
595 | ExprKind::Scope { value, .. } => self.is_let(value), | |
596 | _ => false, | |
597 | } | |
598 | } | |
e9174d1e | 599 | } |