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