]> git.proxmox.com Git - rustc.git/blob - src/librustc_mir/build/expr/stmt.rs
Imported Upstream version 1.11.0+dfsg1
[rustc.git] / src / librustc_mir / build / expr / stmt.rs
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.
4 //
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.
10
11 use build::{BlockAnd, BlockAndExtension, Builder};
12 use build::scope::LoopScope;
13 use hair::*;
14 use rustc::middle::region::CodeExtent;
15 use rustc::mir::repr::*;
16 use syntax_pos::Span;
17
18 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
19
20 pub fn stmt_expr(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd<()> {
21 let this = self;
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.
26 match expr.kind {
27 ExprKind::Scope { extent, value } => {
28 let value = this.hir.mirror(value);
29 this.in_scope(extent, block, |this| this.stmt_expr(block, value))
30 }
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;
35
36 // Note: we evaluate assignments right-to-left. This
37 // is better for borrowck interaction with overloaded
38 // operators like x[j] = x[i].
39
40 // Generate better code for things that don't need to be
41 // dropped.
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
47 ));
48 block.unit()
49 } else {
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);
53 block.unit()
54 }
55 }
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)`?
64
65 let lhs = this.hir.mirror(lhs);
66 let lhs_ty = lhs.ty;
67
68 // As above, RTL.
69 let rhs = unpack!(block = this.as_operand(block, rhs));
70 let lhs = unpack!(block = this.as_lvalue(block, lhs));
71
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);
78
79 block.unit()
80 }
81 ExprKind::Continue { label } => {
82 this.break_or_continue(expr_span, label, block,
83 |loop_scope| loop_scope.continue_block)
84 }
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
89 })
90 }
91 ExprKind::Return { value } => {
92 block = match value {
93 Some(value) => unpack!(this.into(&Lvalue::ReturnPointer, block, value)),
94 None => {
95 this.cfg.push_assign_unit(block, source_info, &Lvalue::ReturnPointer);
96 block
97 }
98 };
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()
103 }
104 _ => {
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));
109 block.unit()
110 }
111 }
112 }
113
114 fn break_or_continue<F>(&mut self,
115 span: Span,
116 label: Option<CodeExtent>,
117 block: BasicBlock,
118 exit_selector: F)
119 -> BlockAnd<()>
120 where F: FnOnce(&mut LoopScope) -> BasicBlock
121 {
122 let (exit_block, extent) = {
123 let loop_scope = self.find_loop_scope(span, label);
124 (exit_selector(loop_scope), loop_scope.extent)
125 };
126 self.exit_scope(span, extent, block, exit_block);
127 self.cfg.start_new_block().unit()
128 }
129
130 }