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