/
as_lvalue.rs
127 lines (116 loc) · 4.91 KB
/
as_lvalue.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! See docs in build/expr/mod.rs
use build::{BlockAnd, BlockAndExtension, Builder};
use build::expr::category::Category;
use hair::*;
use rustc::mir::*;
use rustc_data_structures::indexed_vec::Idx;
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
/// Compile `expr`, yielding an lvalue that we can move from etc.
pub fn as_lvalue<M>(&mut self,
block: BasicBlock,
expr: M)
-> BlockAnd<Lvalue<'tcx>>
where M: Mirror<'tcx, Output=Expr<'tcx>>
{
let expr = self.hir.mirror(expr);
self.expr_as_lvalue(block, expr)
}
fn expr_as_lvalue(&mut self,
mut block: BasicBlock,
expr: Expr<'tcx>)
-> BlockAnd<Lvalue<'tcx>> {
debug!("expr_as_lvalue(block={:?}, expr={:?})", block, expr);
let this = self;
let expr_span = expr.span;
let source_info = this.source_info(expr_span);
match expr.kind {
ExprKind::Scope { extent, value } => {
this.in_scope(extent, block, |this| this.as_lvalue(block, value))
}
ExprKind::Field { lhs, name } => {
let lvalue = unpack!(block = this.as_lvalue(block, lhs));
let lvalue = lvalue.field(name, expr.ty);
block.and(lvalue)
}
ExprKind::Deref { arg } => {
let lvalue = unpack!(block = this.as_lvalue(block, arg));
let lvalue = lvalue.deref();
block.and(lvalue)
}
ExprKind::Index { lhs, index } => {
let (usize_ty, bool_ty) = (this.hir.usize_ty(), this.hir.bool_ty());
let slice = unpack!(block = this.as_lvalue(block, lhs));
let idx = unpack!(block = this.as_operand(block, index));
// bounds check:
let (len, lt) = (this.temp(usize_ty.clone()), this.temp(bool_ty));
this.cfg.push_assign(block, source_info, // len = len(slice)
&len, Rvalue::Len(slice.clone()));
this.cfg.push_assign(block, source_info, // lt = idx < len
<, Rvalue::BinaryOp(BinOp::Lt,
idx.clone(),
Operand::Consume(len.clone())));
let msg = AssertMessage::BoundsCheck {
len: Operand::Consume(len),
index: idx.clone()
};
let success = this.assert(block, Operand::Consume(lt), true,
msg, expr_span);
success.and(slice.index(idx))
}
ExprKind::SelfRef => {
block.and(Lvalue::Local(Local::new(1)))
}
ExprKind::VarRef { id } => {
let index = this.var_indices[&id];
block.and(Lvalue::Local(index))
}
ExprKind::StaticRef { id } => {
block.and(Lvalue::Static(id))
}
ExprKind::Array { .. } |
ExprKind::Tuple { .. } |
ExprKind::Adt { .. } |
ExprKind::Closure { .. } |
ExprKind::Unary { .. } |
ExprKind::Binary { .. } |
ExprKind::LogicalOp { .. } |
ExprKind::Box { .. } |
ExprKind::Cast { .. } |
ExprKind::Use { .. } |
ExprKind::NeverToAny { .. } |
ExprKind::ReifyFnPointer { .. } |
ExprKind::UnsafeFnPointer { .. } |
ExprKind::Unsize { .. } |
ExprKind::Repeat { .. } |
ExprKind::Borrow { .. } |
ExprKind::If { .. } |
ExprKind::Match { .. } |
ExprKind::Loop { .. } |
ExprKind::Block { .. } |
ExprKind::Assign { .. } |
ExprKind::AssignOp { .. } |
ExprKind::Break { .. } |
ExprKind::Continue { .. } |
ExprKind::Return { .. } |
ExprKind::Literal { .. } |
ExprKind::InlineAsm { .. } |
ExprKind::Call { .. } => {
// these are not lvalues, so we need to make a temporary.
debug_assert!(match Category::of(&expr.kind) {
Some(Category::Lvalue) => false,
_ => true,
});
this.as_temp(block, expr)
}
}
}
}