]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/build/expr/as_lvalue.rs
Rollup merge of #41279 - arielb1:adjustment-composition, r=nikomatsakis
[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::*;
17
18 use rustc_data_structures::indexed_vec::Idx;
19
20 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
21     /// Compile `expr`, yielding an lvalue that we can move from etc.
22     pub fn as_lvalue<M>(&mut self,
23                         block: BasicBlock,
24                         expr: M)
25                         -> BlockAnd<Lvalue<'tcx>>
26         where M: Mirror<'tcx, Output=Expr<'tcx>>
27     {
28         let expr = self.hir.mirror(expr);
29         self.expr_as_lvalue(block, expr)
30     }
31
32     fn expr_as_lvalue(&mut self,
33                       mut block: BasicBlock,
34                       expr: Expr<'tcx>)
35                       -> BlockAnd<Lvalue<'tcx>> {
36         debug!("expr_as_lvalue(block={:?}, expr={:?})", block, expr);
37
38         let this = self;
39         let expr_span = expr.span;
40         let source_info = this.source_info(expr_span);
41         match expr.kind {
42             ExprKind::Scope { extent, value } => {
43                 this.in_scope(extent, block, |this| this.as_lvalue(block, value))
44             }
45             ExprKind::Field { lhs, name } => {
46                 let lvalue = unpack!(block = this.as_lvalue(block, lhs));
47                 let lvalue = lvalue.field(name, expr.ty);
48                 block.and(lvalue)
49             }
50             ExprKind::Deref { arg } => {
51                 let lvalue = unpack!(block = this.as_lvalue(block, arg));
52                 let lvalue = lvalue.deref();
53                 block.and(lvalue)
54             }
55             ExprKind::Index { lhs, index } => {
56                 let (usize_ty, bool_ty) = (this.hir.usize_ty(), this.hir.bool_ty());
57
58                 let slice = unpack!(block = this.as_lvalue(block, lhs));
59                 // extent=None so lvalue indexes live forever. They are scalars so they
60                 // do not need storage annotations, and they are often copied between
61                 // places.
62                 let idx = unpack!(block = this.as_operand(block, None, index));
63
64                 // bounds check:
65                 let (len, lt) = (this.temp(usize_ty.clone(), expr_span),
66                                  this.temp(bool_ty, expr_span));
67                 this.cfg.push_assign(block, source_info, // len = len(slice)
68                                      &len, Rvalue::Len(slice.clone()));
69                 this.cfg.push_assign(block, source_info, // lt = idx < len
70                                      &lt, Rvalue::BinaryOp(BinOp::Lt,
71                                                            idx.clone(),
72                                                            Operand::Consume(len.clone())));
73
74                 let msg = AssertMessage::BoundsCheck {
75                     len: Operand::Consume(len),
76                     index: idx.clone()
77                 };
78                 let success = this.assert(block, Operand::Consume(lt), true,
79                                           msg, expr_span);
80                 success.and(slice.index(idx))
81             }
82             ExprKind::SelfRef => {
83                 block.and(Lvalue::Local(Local::new(1)))
84             }
85             ExprKind::VarRef { id } => {
86                 let index = this.var_indices[&id];
87                 block.and(Lvalue::Local(index))
88             }
89             ExprKind::StaticRef { id } => {
90                 block.and(Lvalue::Static(Box::new(Static { def_id: id, ty: expr.ty })))
91             }
92
93             ExprKind::Array { .. } |
94             ExprKind::Tuple { .. } |
95             ExprKind::Adt { .. } |
96             ExprKind::Closure { .. } |
97             ExprKind::Unary { .. } |
98             ExprKind::Binary { .. } |
99             ExprKind::LogicalOp { .. } |
100             ExprKind::Box { .. } |
101             ExprKind::Cast { .. } |
102             ExprKind::Use { .. } |
103             ExprKind::NeverToAny { .. } |
104             ExprKind::ReifyFnPointer { .. } |
105             ExprKind::ClosureFnPointer { .. } |
106             ExprKind::UnsafeFnPointer { .. } |
107             ExprKind::Unsize { .. } |
108             ExprKind::Repeat { .. } |
109             ExprKind::Borrow { .. } |
110             ExprKind::If { .. } |
111             ExprKind::Match { .. } |
112             ExprKind::Loop { .. } |
113             ExprKind::Block { .. } |
114             ExprKind::Assign { .. } |
115             ExprKind::AssignOp { .. } |
116             ExprKind::Break { .. } |
117             ExprKind::Continue { .. } |
118             ExprKind::Return { .. } |
119             ExprKind::Literal { .. } |
120             ExprKind::InlineAsm { .. } |
121             ExprKind::Call { .. } => {
122                 // these are not lvalues, so we need to make a temporary.
123                 debug_assert!(match Category::of(&expr.kind) {
124                     Some(Category::Lvalue) => false,
125                     _ => true,
126                 });
127                 this.as_temp(block, expr.temp_lifetime, expr)
128             }
129         }
130     }
131 }