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