rustc_mir_build/builder/expr/
stmt.rs1use rustc_middle::middle::region;
2use rustc_middle::mir::*;
3use rustc_middle::span_bug;
4use rustc_middle::thir::*;
5use rustc_span::source_map::Spanned;
6use tracing::debug;
7
8use crate::builder::scope::BreakableTarget;
9use crate::builder::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
10
11impl<'a, 'tcx> Builder<'a, 'tcx> {
12 pub(crate) fn stmt_expr(
16 &mut self,
17 mut block: BasicBlock,
18 expr_id: ExprId,
19 statement_scope: Option<region::Scope>,
20 ) -> BlockAnd<()> {
21 let this = self;
22 let expr = &this.thir[expr_id];
23 let expr_span = expr.span;
24 let source_info = this.source_info(expr.span);
25 match expr.kind {
28 ExprKind::Scope { region_scope, lint_level, value } => {
29 this.in_scope((region_scope, source_info), lint_level, |this| {
30 this.stmt_expr(block, value, statement_scope)
31 })
32 }
33 ExprKind::Assign { lhs, rhs } => {
34 let lhs_expr = &this.thir[lhs];
35
36 debug!("stmt_expr Assign block_context.push(SubExpr) : {:?}", expr);
41 this.block_context.push(BlockFrame::SubExpr);
42
43 if lhs_expr.ty.needs_drop(this.tcx, this.typing_env()) {
46 let rhs = unpack!(block = this.as_local_rvalue(block, rhs));
47 let lhs = unpack!(block = this.as_place(block, lhs));
48 block =
49 this.build_drop_and_replace(block, lhs_expr.span, lhs, rhs).into_block();
50 } else {
51 let rhs = unpack!(block = this.as_local_rvalue(block, rhs));
52 let lhs = unpack!(block = this.as_place(block, lhs));
53 this.cfg.push_assign(block, source_info, lhs, rhs);
54 }
55
56 this.block_context.pop();
57 block.unit()
58 }
59 ExprKind::AssignOp { op, lhs, rhs } => {
60 let lhs_ty = this.thir[lhs].ty;
69
70 debug!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr);
71 this.block_context.push(BlockFrame::SubExpr);
72
73 let rhs = unpack!(block = this.as_local_operand(block, rhs));
75 let lhs = unpack!(block = this.as_place(block, lhs));
76
77 let result = unpack!(
81 block = this.build_binary_op(
82 block,
83 op.into(),
84 expr_span,
85 lhs_ty,
86 Operand::Copy(lhs),
87 rhs
88 )
89 );
90 this.cfg.push_assign(block, source_info, lhs, result);
91
92 this.block_context.pop();
93 block.unit()
94 }
95 ExprKind::Continue { label } => {
96 this.break_scope(block, None, BreakableTarget::Continue(label), source_info)
97 }
98 ExprKind::Break { label, value } => {
99 this.break_scope(block, value, BreakableTarget::Break(label), source_info)
100 }
101 ExprKind::ConstContinue { label, value } => {
102 this.break_const_continuable_scope(block, value, label, source_info)
103 }
104 ExprKind::Return { value } => {
105 this.break_scope(block, value, BreakableTarget::Return, source_info)
106 }
107 ExprKind::Become { value } => {
108 let v = &this.thir[value];
109 let ExprKind::Scope { value, lint_level, region_scope } = v.kind else {
110 span_bug!(v.span, "`thir_check_tail_calls` should have disallowed this {v:?}")
111 };
112
113 let v = &this.thir[value];
114 let ExprKind::Call { ref args, fun, fn_span, .. } = v.kind else {
115 span_bug!(v.span, "`thir_check_tail_calls` should have disallowed this {v:?}")
116 };
117
118 this.in_scope((region_scope, source_info), lint_level, |this| {
119 let fun = unpack!(block = this.as_local_operand(block, fun));
120 let args: Box<[_]> = args
121 .into_iter()
122 .copied()
123 .map(|arg| Spanned {
124 node: unpack!(block = this.as_local_call_operand(block, arg)),
125 span: this.thir.exprs[arg].span,
126 })
127 .collect();
128
129 this.record_operands_moved(&args);
130
131 debug!("expr_into_dest: fn_span={:?}", fn_span);
132
133 unpack!(block = this.break_for_tail_call(block, &args, source_info));
134
135 this.cfg.terminate(
136 block,
137 source_info,
138 TerminatorKind::TailCall { func: fun, args, fn_span },
139 );
140
141 this.cfg.start_new_block().unit()
142 })
143 }
144 _ => {
145 assert!(
146 statement_scope.is_some(),
147 "Should not be calling `stmt_expr` on a general expression \
148 without a statement scope",
149 );
150
151 let adjusted_span = if let ExprKind::Block { block } = expr.kind
159 && let Some(tail_ex) = this.thir[block].expr
160 {
161 let mut expr = &this.thir[tail_ex];
162 loop {
163 match expr.kind {
164 ExprKind::Block { block }
165 if let Some(nested_expr) = this.thir[block].expr =>
166 {
167 expr = &this.thir[nested_expr];
168 }
169 ExprKind::Scope { value: nested_expr, .. } => {
170 expr = &this.thir[nested_expr];
171 }
172 _ => break,
173 }
174 }
175 this.block_context.push(BlockFrame::TailExpr {
176 info: BlockTailInfo { tail_result_is_ignored: true, span: expr.span },
177 });
178 Some(expr.span)
179 } else {
180 None
181 };
182
183 let temp = unpack!(
184 block = this.as_temp(
185 block,
186 TempLifetime {
187 temp_lifetime: statement_scope,
188 backwards_incompatible: None
189 },
190 expr_id,
191 Mutability::Not
192 )
193 );
194
195 if let Some(span) = adjusted_span {
196 this.local_decls[temp].source_info.span = span;
197 this.block_context.pop();
198 }
199
200 block.unit()
201 }
202 }
203 }
204}