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