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
;
16 impl<'a
, 'gcx
, 'tcx
> Builder
<'a
, 'gcx
, 'tcx
> {
18 pub fn stmt_expr(&mut self, mut block
: BasicBlock
, expr
: Expr
<'tcx
>) -> BlockAnd
<()> {
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.
25 ExprKind
::Scope { extent, value }
=> {
26 let value
= this
.hir
.mirror(value
);
27 this
.in_scope(extent
, block
, |this
| this
.stmt_expr(block
, value
))
29 ExprKind
::Assign { lhs, rhs }
=> {
30 let lhs
= this
.hir
.mirror(lhs
);
31 let rhs
= this
.hir
.mirror(rhs
);
32 let lhs_span
= lhs
.span
;
34 // Note: we evaluate assignments right-to-left. This
35 // is better for borrowck interaction with overloaded
36 // operators like x[j] = x[i].
38 // Generate better code for things that don't need to be
40 if this
.hir
.needs_drop(lhs
.ty
) {
41 let rhs
= unpack
!(block
= this
.as_operand(block
, rhs
));
42 let lhs
= unpack
!(block
= this
.as_lvalue(block
, lhs
));
43 unpack
!(block
= this
.build_drop_and_replace(
44 block
, lhs_span
, lhs
, rhs
48 let rhs
= unpack
!(block
= this
.as_rvalue(block
, rhs
));
49 let lhs
= unpack
!(block
= this
.as_lvalue(block
, lhs
));
50 this
.cfg
.push_assign(block
, source_info
, &lhs
, rhs
);
54 ExprKind
::AssignOp { op, lhs, rhs }
=> {
55 // FIXME(#28160) there is an interesting semantics
56 // question raised here -- should we "freeze" the
57 // value of the lhs here? I'm inclined to think not,
58 // since it seems closer to the semantics of the
59 // overloaded version, which takes `&mut self`. This
60 // only affects weird things like `x += {x += 1; x}`
61 // -- is that equal to `x + (x + 1)` or `2*(x+1)`?
63 let lhs
= this
.hir
.mirror(lhs
);
67 let rhs
= unpack
!(block
= this
.as_operand(block
, rhs
));
68 let lhs
= unpack
!(block
= this
.as_lvalue(block
, lhs
));
70 // we don't have to drop prior contents or anything
71 // because AssignOp is only legal for Copy types
72 // (overloaded ops should be desugared into a call).
73 let result
= unpack
!(block
= this
.build_binary_op(block
, op
, expr_span
, lhs_ty
,
74 Operand
::Consume(lhs
.clone()), rhs
));
75 this
.cfg
.push_assign(block
, source_info
, &lhs
, result
);
79 ExprKind
::Continue { label }
=> {
80 let LoopScope { continue_block, extent, .. }
=
81 *this
.find_loop_scope(expr_span
, label
);
82 this
.exit_scope(expr_span
, extent
, block
, continue_block
);
83 this
.cfg
.start_new_block().unit()
85 ExprKind
::Break { label, value }
=> {
86 let (break_block
, extent
, destination
) = {
90 ref break_destination
,
92 } = *this
.find_loop_scope(expr_span
, label
);
93 (break_block
, extent
, break_destination
.clone())
95 if let Some(value
) = value
{
96 unpack
!(block
= this
.into(&destination
, block
, value
))
98 this
.cfg
.push_assign_unit(block
, source_info
, &destination
)
100 this
.exit_scope(expr_span
, extent
, block
, break_block
);
101 this
.cfg
.start_new_block().unit()
103 ExprKind
::Return { value }
=> {
104 block
= match value
{
106 unpack
!(this
.into(&Lvalue
::Local(RETURN_POINTER
), block
, value
))
109 this
.cfg
.push_assign_unit(block
,
111 &Lvalue
::Local(RETURN_POINTER
));
115 let extent
= this
.extent_of_return_scope();
116 let return_block
= this
.return_block();
117 this
.exit_scope(expr_span
, extent
, block
, return_block
);
118 this
.cfg
.start_new_block().unit()
121 let expr_ty
= expr
.ty
;
122 let temp
= this
.temp(expr
.ty
.clone());
123 unpack
!(block
= this
.into(&temp
, block
, expr
));
124 unpack
!(block
= this
.build_drop(block
, expr_span
, temp
, expr_ty
));