]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_mir_build/src/build/expr/stmt.rs
Remove useless references/dereferences
[rust.git] / compiler / rustc_mir_build / src / build / expr / stmt.rs
1 use crate::build::scope::BreakableTarget;
2 use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
3 use crate::thir::*;
4 use rustc_middle::middle::region;
5 use rustc_middle::mir::*;
6
7 impl<'a, 'tcx> Builder<'a, 'tcx> {
8     /// Builds a block of MIR statements to evaluate the THIR `expr`.
9     /// If the original expression was an AST statement,
10     /// (e.g., `some().code(&here());`) then `opt_stmt_span` is the
11     /// span of that statement (including its semicolon, if any).
12     /// The scope is used if a statement temporary must be dropped.
13     crate fn stmt_expr(
14         &mut self,
15         mut block: BasicBlock,
16         expr: &Expr<'_, 'tcx>,
17         statement_scope: Option<region::Scope>,
18     ) -> BlockAnd<()> {
19         let this = self;
20         let expr_span = expr.span;
21         let source_info = this.source_info(expr.span);
22         // Handle a number of expressions that don't need a destination at all. This
23         // avoids needing a mountain of temporary `()` variables.
24         match expr.kind {
25             ExprKind::Scope { region_scope, lint_level, value } => {
26                 this.in_scope((region_scope, source_info), lint_level, |this| {
27                     this.stmt_expr(block, value, statement_scope)
28                 })
29             }
30             ExprKind::Assign { lhs, rhs } => {
31                 let lhs_span = lhs.span;
32
33                 // Note: we evaluate assignments right-to-left. This
34                 // is better for borrowck interaction with overloaded
35                 // operators like x[j] = x[i].
36
37                 debug!("stmt_expr Assign block_context.push(SubExpr) : {:?}", expr);
38                 this.block_context.push(BlockFrame::SubExpr);
39
40                 // Generate better code for things that don't need to be
41                 // dropped.
42                 if lhs.ty.needs_drop(this.tcx, this.param_env) {
43                     let rhs = unpack!(block = this.as_local_operand(block, rhs));
44                     let lhs = unpack!(block = this.as_place(block, lhs));
45                     unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs));
46                 } else {
47                     let rhs = unpack!(block = this.as_local_rvalue(block, rhs));
48                     let lhs = unpack!(block = this.as_place(block, lhs));
49                     this.cfg.push_assign(block, source_info, lhs, rhs);
50                 }
51
52                 this.block_context.pop();
53                 block.unit()
54             }
55             ExprKind::AssignOp { op, lhs, rhs } => {
56                 // FIXME(#28160) there is an interesting semantics
57                 // question raised here -- should we "freeze" the
58                 // value of the lhs here?  I'm inclined to think not,
59                 // since it seems closer to the semantics of the
60                 // overloaded version, which takes `&mut self`.  This
61                 // only affects weird things like `x += {x += 1; x}`
62                 // -- is that equal to `x + (x + 1)` or `2*(x+1)`?
63
64                 let lhs_ty = lhs.ty;
65
66                 debug!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr);
67                 this.block_context.push(BlockFrame::SubExpr);
68
69                 // As above, RTL.
70                 let rhs = unpack!(block = this.as_local_operand(block, rhs));
71                 let lhs = unpack!(block = this.as_place(block, lhs));
72
73                 // we don't have to drop prior contents or anything
74                 // because AssignOp is only legal for Copy types
75                 // (overloaded ops should be desugared into a call).
76                 let result = unpack!(
77                     block =
78                         this.build_binary_op(block, op, expr_span, lhs_ty, Operand::Copy(lhs), rhs)
79                 );
80                 this.cfg.push_assign(block, source_info, lhs, result);
81
82                 this.block_context.pop();
83                 block.unit()
84             }
85             ExprKind::Continue { label } => {
86                 this.break_scope(block, None, BreakableTarget::Continue(label), source_info)
87             }
88             ExprKind::Break { label, value } => this.break_scope(
89                 block,
90                 value.as_deref(),
91                 BreakableTarget::Break(label),
92                 source_info,
93             ),
94             ExprKind::Return { value } => {
95                 this.break_scope(block, value.as_deref(), BreakableTarget::Return, source_info)
96             }
97             ExprKind::LlvmInlineAsm { asm, outputs, inputs } => {
98                 debug!("stmt_expr LlvmInlineAsm block_context.push(SubExpr) : {:?}", expr);
99                 this.block_context.push(BlockFrame::SubExpr);
100                 let outputs = outputs
101                     .into_iter()
102                     .map(|output| unpack!(block = this.as_place(block, &output)))
103                     .collect::<Vec<_>>()
104                     .into_boxed_slice();
105                 let inputs = inputs
106                     .into_iter()
107                     .map(|input| {
108                         (input.span, unpack!(block = this.as_local_operand(block, &input)))
109                     })
110                     .collect::<Vec<_>>()
111                     .into_boxed_slice();
112                 this.cfg.push(
113                     block,
114                     Statement {
115                         source_info,
116                         kind: StatementKind::LlvmInlineAsm(box LlvmInlineAsm {
117                             asm: asm.clone(),
118                             outputs,
119                             inputs,
120                         }),
121                     },
122                 );
123                 this.block_context.pop();
124                 block.unit()
125             }
126             _ => {
127                 assert!(
128                     statement_scope.is_some(),
129                     "Should not be calling `stmt_expr` on a general expression \
130                      without a statement scope",
131                 );
132
133                 // Issue #54382: When creating temp for the value of
134                 // expression like:
135                 //
136                 // `{ side_effects(); { let l = stuff(); the_value } }`
137                 //
138                 // it is usually better to focus on `the_value` rather
139                 // than the entirety of block(s) surrounding it.
140                 let adjusted_span = (|| {
141                     if let ExprKind::Block { body } = &expr.kind {
142                         if let Some(tail_expr) = &body.expr {
143                             let mut expr = &*tail_expr;
144                             while let ExprKind::Block { body: subblock } = &expr.kind {
145                                 if let Some(subtail_expr) = &subblock.expr {
146                                     expr = subtail_expr
147                                 } else {
148                                     break;
149                                 }
150                             }
151                             this.block_context.push(BlockFrame::TailExpr {
152                                 tail_result_is_ignored: true,
153                                 span: expr.span,
154                             });
155                             return Some(expr.span);
156                         }
157                     }
158                     None
159                 })();
160
161                 let temp =
162                     unpack!(block = this.as_temp(block, statement_scope, expr, Mutability::Not));
163
164                 if let Some(span) = adjusted_span {
165                     this.local_decls[temp].source_info.span = span;
166                     this.block_context.pop();
167                 }
168
169                 block.unit()
170             }
171         }
172     }
173 }