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