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.
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 //! See docs in build/expr/mod.rs
13 use build::{BlockAnd, BlockAndExtension, Builder};
14 use build::expr::category::Category;
18 use rustc_data_structures::indexed_vec::Idx;
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,
25 -> BlockAnd<Lvalue<'tcx>>
26 where M: Mirror<'tcx, Output=Expr<'tcx>>
28 let expr = self.hir.mirror(expr);
29 self.expr_as_lvalue(block, expr)
32 fn expr_as_lvalue(&mut self,
33 mut block: BasicBlock,
35 -> BlockAnd<Lvalue<'tcx>> {
36 debug!("expr_as_lvalue(block={:?}, expr={:?})", block, expr);
39 let expr_span = expr.span;
40 let source_info = this.source_info(expr_span);
42 ExprKind::Scope { extent, value } => {
43 this.in_scope(extent, block, |this| this.as_lvalue(block, value))
45 ExprKind::Field { lhs, name } => {
46 let lvalue = unpack!(block = this.as_lvalue(block, lhs));
47 let lvalue = lvalue.field(name, expr.ty);
50 ExprKind::Deref { arg } => {
51 let lvalue = unpack!(block = this.as_lvalue(block, arg));
52 let lvalue = lvalue.deref();
55 ExprKind::Index { lhs, index } => {
56 let (usize_ty, bool_ty) = (this.hir.usize_ty(), this.hir.bool_ty());
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
62 let idx = unpack!(block = this.as_operand(block, None, index));
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 <, Rvalue::BinaryOp(BinOp::Lt,
72 Operand::Consume(len.clone())));
74 let msg = AssertMessage::BoundsCheck {
75 len: Operand::Consume(len),
78 let success = this.assert(block, Operand::Consume(lt), true,
80 success.and(slice.index(idx))
82 ExprKind::SelfRef => {
83 block.and(Lvalue::Local(Local::new(1)))
85 ExprKind::VarRef { id } => {
86 let index = this.var_indices[&id];
87 block.and(Lvalue::Local(index))
89 ExprKind::StaticRef { id } => {
90 block.and(Lvalue::Static(Box::new(Static { def_id: id, ty: expr.ty })))
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,
127 this.as_temp(block, expr.temp_lifetime, expr)