]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/build/expr/as_lvalue.rs
fa864625f7f32e1baf86f2d1e1f8a547f20c1272
[rust.git] / src / librustc_mir / build / expr / as_lvalue.rs
1 // Copyright 2015 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 //! See docs in build/expr/mod.rs
12
13 use build::{BlockAnd, BlockAndExtension, Builder};
14 use build::expr::category::Category;
15 use hair::*;
16 use rustc::mir::repr::*;
17
18 impl<'a,'tcx> Builder<'a,'tcx> {
19     /// Compile `expr`, yielding an lvalue that we can move from etc.
20     pub fn as_lvalue<M>(&mut self,
21                         block: BasicBlock,
22                         expr: M)
23                         -> BlockAnd<Lvalue<'tcx>>
24         where M: Mirror<'tcx, Output=Expr<'tcx>>
25     {
26         let expr = self.hir.mirror(expr);
27         self.expr_as_lvalue(block, expr)
28     }
29
30     fn expr_as_lvalue(&mut self,
31                       mut block: BasicBlock,
32                       expr: Expr<'tcx>)
33                       -> BlockAnd<Lvalue<'tcx>> {
34         debug!("expr_as_lvalue(block={:?}, expr={:?})", block, expr);
35
36         let this = self;
37         let scope_id = this.innermost_scope_id();
38         let expr_span = expr.span;
39         match expr.kind {
40             ExprKind::Scope { extent, value } => {
41                 this.in_scope(extent, block, |this, _| this.as_lvalue(block, value))
42             }
43             ExprKind::Field { lhs, name } => {
44                 let lvalue = unpack!(block = this.as_lvalue(block, lhs));
45                 let lvalue = lvalue.field(name, expr.ty);
46                 block.and(lvalue)
47             }
48             ExprKind::Deref { arg } => {
49                 let lvalue = unpack!(block = this.as_lvalue(block, arg));
50                 let lvalue = lvalue.deref();
51                 block.and(lvalue)
52             }
53             ExprKind::Index { lhs, index } => {
54                 let (usize_ty, bool_ty) = (this.hir.usize_ty(), this.hir.bool_ty());
55
56                 let slice = unpack!(block = this.as_lvalue(block, lhs));
57
58                 let idx = unpack!(block = this.as_operand(block, index));
59
60                 // bounds check:
61                 let (len, lt) = (this.temp(usize_ty.clone()), this.temp(bool_ty));
62                 this.cfg.push_assign(block, scope_id, expr_span, // len = len(slice)
63                                      &len, Rvalue::Len(slice.clone()));
64                 this.cfg.push_assign(block, scope_id, expr_span, // lt = idx < len
65                                      &lt, Rvalue::BinaryOp(BinOp::Lt,
66                                                            idx.clone(),
67                                                            Operand::Consume(len.clone())));
68
69                 let (success, failure) = (this.cfg.start_new_block(), this.cfg.start_new_block());
70                 this.cfg.terminate(block,
71                                    TerminatorKind::If {
72                                        cond: Operand::Consume(lt),
73                                        targets: (success, failure),
74                                    });
75                 this.panic_bounds_check(failure, idx.clone(), Operand::Consume(len), expr_span);
76                 success.and(slice.index(idx))
77             }
78             ExprKind::SelfRef => {
79                 block.and(Lvalue::Arg(0))
80             }
81             ExprKind::VarRef { id } => {
82                 let index = this.var_indices[&id];
83                 block.and(Lvalue::Var(index))
84             }
85             ExprKind::StaticRef { id } => {
86                 block.and(Lvalue::Static(id))
87             }
88
89             ExprKind::Vec { .. } |
90             ExprKind::Tuple { .. } |
91             ExprKind::Adt { .. } |
92             ExprKind::Closure { .. } |
93             ExprKind::Unary { .. } |
94             ExprKind::Binary { .. } |
95             ExprKind::LogicalOp { .. } |
96             ExprKind::Box { .. } |
97             ExprKind::Cast { .. } |
98             ExprKind::ReifyFnPointer { .. } |
99             ExprKind::UnsafeFnPointer { .. } |
100             ExprKind::Unsize { .. } |
101             ExprKind::Repeat { .. } |
102             ExprKind::Borrow { .. } |
103             ExprKind::If { .. } |
104             ExprKind::Match { .. } |
105             ExprKind::Loop { .. } |
106             ExprKind::Block { .. } |
107             ExprKind::Assign { .. } |
108             ExprKind::AssignOp { .. } |
109             ExprKind::Break { .. } |
110             ExprKind::Continue { .. } |
111             ExprKind::Return { .. } |
112             ExprKind::Literal { .. } |
113             ExprKind::InlineAsm { .. } |
114             ExprKind::Call { .. } => {
115                 // these are not lvalues, so we need to make a temporary.
116                 debug_assert!(match Category::of(&expr.kind) {
117                     Some(Category::Lvalue) => false,
118                     _ => true,
119                 });
120                 this.as_temp(block, expr)
121             }
122         }
123     }
124 }