1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use build
::{BlockAnd, BlockAndExtension, Builder}
;
12 use build
::scope
::LoopScope
;
14 use rustc
::middle
::region
::CodeExtent
;
15 use rustc
::mir
::repr
::*;
18 impl<'a
, 'gcx
, 'tcx
> Builder
<'a
, 'gcx
, 'tcx
> {
20 pub fn stmt_expr(&mut self, mut block
: BasicBlock
, expr
: Expr
<'tcx
>) -> BlockAnd
<()> {
22 let expr_span
= expr
.span
;
23 let source_info
= this
.source_info(expr
.span
);
24 // Handle a number of expressions that don't need a destination at all. This
25 // avoids needing a mountain of temporary `()` variables.
27 ExprKind
::Scope { extent, value }
=> {
28 let value
= this
.hir
.mirror(value
);
29 this
.in_scope(extent
, block
, |this
| this
.stmt_expr(block
, value
))
31 ExprKind
::Assign { lhs, rhs }
=> {
32 let lhs
= this
.hir
.mirror(lhs
);
33 let rhs
= this
.hir
.mirror(rhs
);
34 let lhs_span
= lhs
.span
;
36 // Note: we evaluate assignments right-to-left. This
37 // is better for borrowck interaction with overloaded
38 // operators like x[j] = x[i].
40 // Generate better code for things that don't need to be
42 if this
.hir
.needs_drop(lhs
.ty
) {
43 let rhs
= unpack
!(block
= this
.as_operand(block
, rhs
));
44 let lhs
= unpack
!(block
= this
.as_lvalue(block
, lhs
));
45 unpack
!(block
= this
.build_drop_and_replace(
46 block
, lhs_span
, lhs
, rhs
50 let rhs
= unpack
!(block
= this
.as_rvalue(block
, rhs
));
51 let lhs
= unpack
!(block
= this
.as_lvalue(block
, lhs
));
52 this
.cfg
.push_assign(block
, source_info
, &lhs
, rhs
);
56 ExprKind
::AssignOp { op, lhs, rhs }
=> {
57 // FIXME(#28160) there is an interesting semantics
58 // question raised here -- should we "freeze" the
59 // value of the lhs here? I'm inclined to think not,
60 // since it seems closer to the semantics of the
61 // overloaded version, which takes `&mut self`. This
62 // only affects weird things like `x += {x += 1; x}`
63 // -- is that equal to `x + (x + 1)` or `2*(x+1)`?
65 let lhs
= this
.hir
.mirror(lhs
);
69 let rhs
= unpack
!(block
= this
.as_operand(block
, rhs
));
70 let lhs
= unpack
!(block
= this
.as_lvalue(block
, lhs
));
72 // we don't have to drop prior contents or anything
73 // because AssignOp is only legal for Copy types
74 // (overloaded ops should be desugared into a call).
75 let result
= unpack
!(block
= this
.build_binary_op(block
, op
, expr_span
, lhs_ty
,
76 Operand
::Consume(lhs
.clone()), rhs
));
77 this
.cfg
.push_assign(block
, source_info
, &lhs
, result
);
81 ExprKind
::Continue { label }
=> {
82 this
.break_or_continue(expr_span
, label
, block
,
83 |loop_scope
| loop_scope
.continue_block
)
85 ExprKind
::Break { label }
=> {
86 this
.break_or_continue(expr_span
, label
, block
, |loop_scope
| {
87 loop_scope
.might_break
= true;
88 loop_scope
.break_block
91 ExprKind
::Return { value }
=> {
93 Some(value
) => unpack
!(this
.into(&Lvalue
::ReturnPointer
, block
, value
)),
95 this
.cfg
.push_assign_unit(block
, source_info
, &Lvalue
::ReturnPointer
);
99 let extent
= this
.extent_of_return_scope();
100 let return_block
= this
.return_block();
101 this
.exit_scope(expr_span
, extent
, block
, return_block
);
102 this
.cfg
.start_new_block().unit()
105 let expr_ty
= expr
.ty
;
106 let temp
= this
.temp(expr
.ty
.clone());
107 unpack
!(block
= this
.into(&temp
, block
, expr
));
108 unpack
!(block
= this
.build_drop(block
, expr_span
, temp
, expr_ty
));
114 fn break_or_continue
<F
>(&mut self,
116 label
: Option
<CodeExtent
>,
120 where F
: FnOnce(&mut LoopScope
) -> BasicBlock
122 let (exit_block
, extent
) = {
123 let loop_scope
= self.find_loop_scope(span
, label
);
124 (exit_selector(loop_scope
), loop_scope
.extent
)
126 self.exit_scope(span
, extent
, block
, exit_block
);
127 self.cfg
.start_new_block().unit()