Skip to content

Commit f0775d7

Browse files
committed
Finish translating const indexing. Close #1417, close #570, close #571, close #1272, close #2317.
1 parent 22a14dd commit f0775d7

File tree

4 files changed

+64
-23
lines changed

4 files changed

+64
-23
lines changed

Diff for: src/rustc/middle/trans/base.rs

+1
Original file line numberDiff line numberDiff line change
@@ -5717,6 +5717,7 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
57175717
type_use_cache: ast_util::new_def_hash(),
57185718
vtables: map::hashmap(hash_mono_id, sys::shape_eq),
57195719
const_cstr_cache: map::str_hash(),
5720+
const_globals: int_hash::<ValueRef>(),
57205721
module_data: str_hash::<ValueRef>(),
57215722
lltypes: ty::new_ty_hash(),
57225723
names: new_namegen(),

Diff for: src/rustc/middle/trans/common.rs

+4
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ type crate_ctxt = {
107107
vtables: hashmap<mono_id, ValueRef>,
108108
// Cache of constant strings,
109109
const_cstr_cache: hashmap<~str, ValueRef>,
110+
// Reverse-direction for const ptrs cast from globals,
111+
// since the ptr -> init association is lost any
112+
// time a GlobalValue is cast.
113+
const_globals: hashmap<int, ValueRef>,
110114
module_data: hashmap<~str, ValueRef>,
111115
lltypes: hashmap<ty::t, TypeRef>,
112116
names: namegen,

Diff for: src/rustc/middle/trans/consts.rs

+54-14
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ fn const_lit(cx: @crate_ctxt, e: @ast::expr, lit: ast::lit)
3232
// duplicate constants. I think. Maybe LLVM has a magical mode that does so
3333
// later on?
3434

35+
fn const_ptrcast(cx: @crate_ctxt, a: ValueRef, t: TypeRef) -> ValueRef {
36+
let b = llvm::LLVMConstPointerCast(a, T_ptr(t));
37+
assert cx.const_globals.insert(b as int, a);
38+
b
39+
}
40+
3541
fn const_vec(cx: @crate_ctxt, e: @ast::expr, es: &[@ast::expr])
3642
-> (ValueRef, ValueRef, TypeRef) {
3743
let vec_ty = ty::expr_ty(cx.tcx, e);
@@ -43,17 +49,22 @@ fn const_vec(cx: @crate_ctxt, e: @ast::expr, es: &[@ast::expr])
4349
return (v, sz, llunitty);
4450
}
4551

46-
fn const_deref(v: ValueRef) -> ValueRef {
52+
fn const_deref(cx: @crate_ctxt, v: ValueRef) -> ValueRef {
53+
let v = match cx.const_globals.find(v as int) {
54+
some(v) => v,
55+
none => v
56+
};
4757
assert llvm::LLVMIsGlobalConstant(v) == True;
48-
llvm::LLVMGetInitializer(v)
58+
let v = llvm::LLVMGetInitializer(v);
59+
v
4960
}
5061

5162
fn const_get_elt(v: ValueRef, u: uint) -> ValueRef {
5263
let u = u;
5364
llvm::LLVMConstExtractValue(v, ptr::addr_of(u), 1 as c_uint)
5465
}
5566

56-
fn const_autoderef(ty: ty::t, v: ValueRef)
67+
fn const_autoderef(cx: @crate_ctxt, ty: ty::t, v: ValueRef)
5768
-> (ty::t, ValueRef) {
5869
let mut t1 = ty;
5970
let mut v1 = v;
@@ -62,7 +73,7 @@ fn const_autoderef(ty: ty::t, v: ValueRef)
6273
match ty::get(ty).struct {
6374
ty::ty_rptr(_, mt) => {
6475
t1 = mt.ty;
65-
v1 = const_deref(v1);
76+
v1 = const_deref(cx, v1);
6677
}
6778
_ => return (t1,v1)
6879
}
@@ -133,7 +144,7 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
133144
return match u {
134145
ast::box(_) |
135146
ast::uniq(_) |
136-
ast::deref => const_deref(te),
147+
ast::deref => const_deref(cx, te),
137148
ast::not => llvm::LLVMConstNot(te),
138149
ast::neg => {
139150
if is_float { llvm::LLVMConstFNeg(te) }
@@ -144,7 +155,7 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
144155
ast::expr_field(base, field, _) => {
145156
let bt = ty::expr_ty(cx.tcx, base);
146157
let bv = const_expr(cx, base);
147-
let (bt, bv) = const_autoderef(bt, bv);
158+
let (bt, bv) = const_autoderef(cx, bt, bv);
148159
let fields = match ty::get(bt).struct {
149160
ty::ty_rec(fs) => fs,
150161
ty::ty_class(did, substs) =>
@@ -159,15 +170,15 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
159170
ast::expr_index(base, index) => {
160171
let bt = ty::expr_ty(cx.tcx, base);
161172
let bv = const_expr(cx, base);
162-
let (bt, bv) = const_autoderef(bt, bv);
173+
let (bt, bv) = const_autoderef(cx, bt, bv);
163174
let iv = match const_eval::eval_const_expr(cx.tcx, index) {
164175
const_eval::const_int(i) => i as u64,
165176
const_eval::const_uint(u) => u,
166177
_ => cx.sess.span_bug(index.span,
167178
~"index is not an integer-constant \
168179
expression")
169180
};
170-
let (arr,len) = match ty::get(bt).struct {
181+
let (arr, _len) = match ty::get(bt).struct {
171182
ty::ty_evec(_, vstore) | ty::ty_estr(vstore) =>
172183
match vstore {
173184
ty::vstore_fixed(u) =>
@@ -177,9 +188,10 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
177188
let unit_ty = ty::sequence_element_type(cx.tcx, bt);
178189
let llunitty = type_of::type_of(cx, unit_ty);
179190
let unit_sz = shape::llsize_of(cx, llunitty);
180-
(const_deref(const_get_elt(bv, 0)),
191+
192+
(const_deref(cx, const_get_elt(bv, 0)),
181193
llvm::LLVMConstUDiv(const_get_elt(bv, 1),
182-
unit_sz))
194+
unit_sz))
183195
},
184196
_ => cx.sess.span_bug(base.span,
185197
~"index-expr base must be \
@@ -189,13 +201,42 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
189201
~"index-expr base must be \
190202
a vector or string type")
191203
};
192-
let len = llvm::LLVMConstIntGetZExtValue(len) as u64;
204+
205+
// FIXME #3169: This is a little odd but it arises due to a weird
206+
// wrinkle in LLVM: it doesn't appear willing to let us call
207+
// LLVMConstIntGetZExtValue on the size element of the slice, or
208+
// seemingly any integer-const involving a sizeof() call. Despite
209+
// that being "a const", it's not the kind of const you can ask
210+
// for the integer-value of, evidently. This might be an LLVM
211+
// bug, not sure. In any case, to work around this we drop down
212+
// to the array-type level here and just ask how long the
213+
// array-type itself is, ignoring the length we pulled out of the
214+
// slice. This in turn only works because we picked out the
215+
// original globalvar via const_deref and so can recover the
216+
// array-size of the underlying array, and all this will hold
217+
// together exactly as long as we _don't_ support const
218+
// sub-slices (that is, slices that represent something other
219+
// than a whole array). At that point we'll have more and uglier
220+
// work to do here, but for now this should work.
221+
//
222+
// In the future, what we should be doing here is the
223+
// moral equivalent of:
224+
//
225+
// let len = llvm::LLVMConstIntGetZExtValue(len) as u64;
226+
//
227+
// but we might have to do substantially more magic to
228+
// make it work. Or figure out what is causing LLVM to
229+
// not want to consider sizeof() a constant expression
230+
// we can get the value (as a number) out of.
231+
232+
let len = llvm::LLVMGetArrayLength(val_ty(arr)) as u64;
193233
let len = match ty::get(bt).struct {
194234
ty::ty_estr(*) => {assert len > 0; len - 1},
195235
_ => len
196236
};
197237
if iv >= len {
198-
// Better late than never for reporting this?
238+
// FIXME #3170: report this earlier on in the const-eval
239+
// pass. Reporting here is a bit late.
199240
cx.sess.span_err(e.span,
200241
~"const index-expr is out of bounds");
201242
}
@@ -292,8 +333,7 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
292333
};
293334
llvm::LLVMSetInitializer(gv, cv);
294335
llvm::LLVMSetGlobalConstant(gv, True);
295-
let p = llvm::LLVMConstPointerCast(gv, T_ptr(llunitty));
296-
336+
let p = const_ptrcast(cx, gv, llunitty);
297337
C_struct(~[p, sz])
298338
}
299339
_ => cx.sess.span_bug(e.span,

Diff for: src/test/run-pass/const-fields-and-indexing.rs

+5-9
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
1-
// Not quite working on the indexing part yet.
2-
/*
31
const x : [int]/4 = [1,2,3,4];
4-
const y : &[int] = &[1,2,3,4];
52
const p : int = x[2];
3+
const y : &[int] = &[1,2,3,4];
64
const q : int = y[2];
7-
*/
85

96
const s : {a: int, b: int} = {a: 10, b: 20};
107
const t : int = s.b;
118

129
fn main() {
13-
14-
// io::println(fmt!("%?", p));
15-
// io::println(fmt!("%?", q));
10+
io::println(fmt!("%?", p));
11+
io::println(fmt!("%?", q));
1612
io::println(fmt!("%?", t));
17-
// assert p == 3;
18-
// assert q == 3;
13+
assert p == 3;
14+
assert q == 3;
1915
assert t == 20;
2016
}

0 commit comments

Comments
 (0)