Skip to content

Commit a0e3a2a

Browse files
committed
Const field access (working) and vec indexing (almost). More for #2317.
1 parent 5c9c9a6 commit a0e3a2a

File tree

3 files changed

+110
-2
lines changed

3 files changed

+110
-2
lines changed

src/rustc/middle/check_const.rs

+2
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ fn check_expr(sess: session, def_map: resolve3::DefMap,
102102
expr_vstore(_, vstore_fixed(_)) |
103103
expr_vec(_, m_imm) |
104104
expr_addr_of(m_imm, _) |
105+
expr_field(*) |
106+
expr_index(*) |
105107
expr_tup(*) |
106108
expr_struct(*) |
107109
expr_rec(*) => { }

src/rustc/middle/trans/consts.rs

+88-2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,33 @@ fn const_vec(cx: @crate_ctxt, e: @ast::expr, es: &[@ast::expr])
4343
return (v, sz, llunitty);
4444
}
4545

46+
fn const_deref(v: ValueRef) -> ValueRef {
47+
assert llvm::LLVMIsGlobalConstant(v) == True;
48+
llvm::LLVMGetInitializer(v)
49+
}
50+
51+
fn const_get_elt(v: ValueRef, u: uint) -> ValueRef {
52+
let u = u;
53+
llvm::LLVMConstExtractValue(v, ptr::addr_of(u), 1 as c_uint)
54+
}
55+
56+
fn const_autoderef(ty: ty::t, v: ValueRef)
57+
-> (ty::t, ValueRef) {
58+
let mut t1 = ty;
59+
let mut v1 = v;
60+
loop {
61+
// Only rptrs can be autoderef'ed in a const context.
62+
match ty::get(ty).struct {
63+
ty::ty_rptr(_, mt) => {
64+
t1 = mt.ty;
65+
v1 = const_deref(v1);
66+
}
67+
_ => return (t1,v1)
68+
}
69+
}
70+
}
71+
72+
4673
fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
4774
let _icx = cx.insn_ctxt(~"const_expr");
4875
match e.node {
@@ -106,15 +133,74 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
106133
return match u {
107134
ast::box(_) |
108135
ast::uniq(_) |
109-
ast::deref => cx.sess.span_bug(e.span,
110-
~"bad unop type in const_expr"),
136+
ast::deref => const_deref(te),
111137
ast::not => llvm::LLVMConstNot(te),
112138
ast::neg => {
113139
if is_float { llvm::LLVMConstFNeg(te) }
114140
else { llvm::LLVMConstNeg(te) }
115141
}
116142
}
117143
}
144+
ast::expr_field(base, field, _) => {
145+
let bt = ty::expr_ty(cx.tcx, base);
146+
let bv = const_expr(cx, base);
147+
let (bt, bv) = const_autoderef(bt, bv);
148+
let fields = match ty::get(bt).struct {
149+
ty::ty_rec(fs) => fs,
150+
ty::ty_class(did, substs) =>
151+
ty::class_items_as_mutable_fields(cx.tcx, did, substs),
152+
_ => cx.sess.span_bug(e.span,
153+
~"field access on unknown type in const"),
154+
};
155+
let ix = field_idx_strict(cx.tcx, e.span, field, fields);
156+
const_get_elt(bv, ix)
157+
}
158+
159+
ast::expr_index(base, index) => {
160+
let bt = ty::expr_ty(cx.tcx, base);
161+
let bv = const_expr(cx, base);
162+
let (bt, bv) = const_autoderef(bt, bv);
163+
let iv = match const_eval::eval_const_expr(cx.tcx, index) {
164+
const_eval::const_int(i) => i as u64,
165+
const_eval::const_uint(u) => u,
166+
_ => cx.sess.span_bug(index.span,
167+
~"index is not an integer-constant \
168+
expression")
169+
};
170+
let (arr,len) = match ty::get(bt).struct {
171+
ty::ty_evec(_, vstore) | ty::ty_estr(vstore) =>
172+
match vstore {
173+
ty::vstore_fixed(u) =>
174+
(bv, C_uint(cx, u)),
175+
176+
ty::vstore_slice(_) => {
177+
let unit_ty = ty::sequence_element_type(cx.tcx, bt);
178+
let llunitty = type_of::type_of(cx, unit_ty);
179+
let unit_sz = shape::llsize_of(cx, llunitty);
180+
(const_deref(const_get_elt(bv, 0)),
181+
llvm::LLVMConstUDiv(const_get_elt(bv, 1),
182+
unit_sz))
183+
},
184+
_ => cx.sess.span_bug(base.span,
185+
~"index-expr base must be \
186+
fixed-size or slice")
187+
},
188+
_ => cx.sess.span_bug(base.span,
189+
~"index-expr base must be \
190+
a vector or string type")
191+
};
192+
let len = llvm::LLVMConstIntGetZExtValue(len) as u64;
193+
let len = match ty::get(bt).struct {
194+
ty::ty_estr(*) => {assert len > 0; len - 1},
195+
_ => len
196+
};
197+
if iv >= len {
198+
// Better late than never for reporting this?
199+
cx.sess.span_err(e.span,
200+
~"const index-expr is out of bounds");
201+
}
202+
const_get_elt(arr, iv as uint)
203+
}
118204
ast::expr_cast(base, tp) => {
119205
let ety = ty::expr_ty(cx.tcx, e), llty = type_of::type_of(cx, ety);
120206
let basety = ty::expr_ty(cx.tcx, base);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Not quite working on the indexing part yet.
2+
/*
3+
const x : [int]/4 = [1,2,3,4];
4+
const y : &[int] = &[1,2,3,4];
5+
const p : int = x[2];
6+
const q : int = y[2];
7+
*/
8+
9+
const s : {a: int, b: int} = {a: 10, b: 20};
10+
const t : int = s.b;
11+
12+
fn main() {
13+
14+
// io::println(fmt!("%?", p));
15+
// io::println(fmt!("%?", q));
16+
io::println(fmt!("%?", t));
17+
// assert p == 3;
18+
// assert q == 3;
19+
assert t == 20;
20+
}

0 commit comments

Comments
 (0)