diff options
| author | Graydon Hoare <graydon@mozilla.com> | 2012-08-09 16:05:34 -0700 |
|---|---|---|
| committer | Graydon Hoare <graydon@mozilla.com> | 2012-08-09 16:05:34 -0700 |
| commit | f0775d7bfe99617892e90e956be65cc80a28e070 (patch) | |
| tree | 9f5cf432377aa5f5a97a2b19fe2b55f4a98c2dd7 /src | |
| parent | 22a14dd700338ed26f78143dfad4325566a3f4ed (diff) | |
Finish translating const indexing. Close #1417, close #570, close #571, close #1272, close #2317.
Diffstat (limited to 'src')
| -rw-r--r-- | src/rustc/middle/trans/base.rs | 1 | ||||
| -rw-r--r-- | src/rustc/middle/trans/common.rs | 4 | ||||
| -rw-r--r-- | src/rustc/middle/trans/consts.rs | 68 | ||||
| -rw-r--r-- | src/test/run-pass/const-fields-and-indexing.rs | 14 |
4 files changed, 64 insertions, 23 deletions
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 354b368897a..07aba04ca0e 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -5717,6 +5717,7 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt, type_use_cache: ast_util::new_def_hash(), vtables: map::hashmap(hash_mono_id, sys::shape_eq), const_cstr_cache: map::str_hash(), + const_globals: int_hash::<ValueRef>(), module_data: str_hash::<ValueRef>(), lltypes: ty::new_ty_hash(), names: new_namegen(), diff --git a/src/rustc/middle/trans/common.rs b/src/rustc/middle/trans/common.rs index 1d8c4686c55..363f725b5fc 100644 --- a/src/rustc/middle/trans/common.rs +++ b/src/rustc/middle/trans/common.rs @@ -107,6 +107,10 @@ type crate_ctxt = { vtables: hashmap<mono_id, ValueRef>, // Cache of constant strings, const_cstr_cache: hashmap<~str, ValueRef>, + // Reverse-direction for const ptrs cast from globals, + // since the ptr -> init association is lost any + // time a GlobalValue is cast. + const_globals: hashmap<int, ValueRef>, module_data: hashmap<~str, ValueRef>, lltypes: hashmap<ty::t, TypeRef>, names: namegen, diff --git a/src/rustc/middle/trans/consts.rs b/src/rustc/middle/trans/consts.rs index e7f281c461f..732d02928c4 100644 --- a/src/rustc/middle/trans/consts.rs +++ b/src/rustc/middle/trans/consts.rs @@ -32,6 +32,12 @@ fn const_lit(cx: @crate_ctxt, e: @ast::expr, lit: ast::lit) // duplicate constants. I think. Maybe LLVM has a magical mode that does so // later on? +fn const_ptrcast(cx: @crate_ctxt, a: ValueRef, t: TypeRef) -> ValueRef { + let b = llvm::LLVMConstPointerCast(a, T_ptr(t)); + assert cx.const_globals.insert(b as int, a); + b +} + fn const_vec(cx: @crate_ctxt, e: @ast::expr, es: &[@ast::expr]) -> (ValueRef, ValueRef, TypeRef) { let vec_ty = ty::expr_ty(cx.tcx, e); @@ -43,9 +49,14 @@ fn const_vec(cx: @crate_ctxt, e: @ast::expr, es: &[@ast::expr]) return (v, sz, llunitty); } -fn const_deref(v: ValueRef) -> ValueRef { +fn const_deref(cx: @crate_ctxt, v: ValueRef) -> ValueRef { + let v = match cx.const_globals.find(v as int) { + some(v) => v, + none => v + }; assert llvm::LLVMIsGlobalConstant(v) == True; - llvm::LLVMGetInitializer(v) + let v = llvm::LLVMGetInitializer(v); + v } fn const_get_elt(v: ValueRef, u: uint) -> ValueRef { @@ -53,7 +64,7 @@ fn const_get_elt(v: ValueRef, u: uint) -> ValueRef { llvm::LLVMConstExtractValue(v, ptr::addr_of(u), 1 as c_uint) } -fn const_autoderef(ty: ty::t, v: ValueRef) +fn const_autoderef(cx: @crate_ctxt, ty: ty::t, v: ValueRef) -> (ty::t, ValueRef) { let mut t1 = ty; let mut v1 = v; @@ -62,7 +73,7 @@ fn const_autoderef(ty: ty::t, v: ValueRef) match ty::get(ty).struct { ty::ty_rptr(_, mt) => { t1 = mt.ty; - v1 = const_deref(v1); + v1 = const_deref(cx, v1); } _ => return (t1,v1) } @@ -133,7 +144,7 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { return match u { ast::box(_) | ast::uniq(_) | - ast::deref => const_deref(te), + ast::deref => const_deref(cx, te), ast::not => llvm::LLVMConstNot(te), ast::neg => { if is_float { llvm::LLVMConstFNeg(te) } @@ -144,7 +155,7 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { ast::expr_field(base, field, _) => { let bt = ty::expr_ty(cx.tcx, base); let bv = const_expr(cx, base); - let (bt, bv) = const_autoderef(bt, bv); + let (bt, bv) = const_autoderef(cx, bt, bv); let fields = match ty::get(bt).struct { ty::ty_rec(fs) => fs, ty::ty_class(did, substs) => @@ -159,7 +170,7 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { ast::expr_index(base, index) => { let bt = ty::expr_ty(cx.tcx, base); let bv = const_expr(cx, base); - let (bt, bv) = const_autoderef(bt, bv); + let (bt, bv) = const_autoderef(cx, bt, bv); let iv = match const_eval::eval_const_expr(cx.tcx, index) { const_eval::const_int(i) => i as u64, const_eval::const_uint(u) => u, @@ -167,7 +178,7 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { ~"index is not an integer-constant \ expression") }; - let (arr,len) = match ty::get(bt).struct { + let (arr, _len) = match ty::get(bt).struct { ty::ty_evec(_, vstore) | ty::ty_estr(vstore) => match vstore { ty::vstore_fixed(u) => @@ -177,9 +188,10 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { let unit_ty = ty::sequence_element_type(cx.tcx, bt); let llunitty = type_of::type_of(cx, unit_ty); let unit_sz = shape::llsize_of(cx, llunitty); - (const_deref(const_get_elt(bv, 0)), + + (const_deref(cx, const_get_elt(bv, 0)), llvm::LLVMConstUDiv(const_get_elt(bv, 1), - unit_sz)) + unit_sz)) }, _ => cx.sess.span_bug(base.span, ~"index-expr base must be \ @@ -189,13 +201,42 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { ~"index-expr base must be \ a vector or string type") }; - let len = llvm::LLVMConstIntGetZExtValue(len) as u64; + + // FIXME #3169: This is a little odd but it arises due to a weird + // wrinkle in LLVM: it doesn't appear willing to let us call + // LLVMConstIntGetZExtValue on the size element of the slice, or + // seemingly any integer-const involving a sizeof() call. Despite + // that being "a const", it's not the kind of const you can ask + // for the integer-value of, evidently. This might be an LLVM + // bug, not sure. In any case, to work around this we drop down + // to the array-type level here and just ask how long the + // array-type itself is, ignoring the length we pulled out of the + // slice. This in turn only works because we picked out the + // original globalvar via const_deref and so can recover the + // array-size of the underlying array, and all this will hold + // together exactly as long as we _don't_ support const + // sub-slices (that is, slices that represent something other + // than a whole array). At that point we'll have more and uglier + // work to do here, but for now this should work. + // + // In the future, what we should be doing here is the + // moral equivalent of: + // + // let len = llvm::LLVMConstIntGetZExtValue(len) as u64; + // + // but we might have to do substantially more magic to + // make it work. Or figure out what is causing LLVM to + // not want to consider sizeof() a constant expression + // we can get the value (as a number) out of. + + let len = llvm::LLVMGetArrayLength(val_ty(arr)) as u64; let len = match ty::get(bt).struct { ty::ty_estr(*) => {assert len > 0; len - 1}, _ => len }; if iv >= len { - // Better late than never for reporting this? + // FIXME #3170: report this earlier on in the const-eval + // pass. Reporting here is a bit late. cx.sess.span_err(e.span, ~"const index-expr is out of bounds"); } @@ -292,8 +333,7 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { }; llvm::LLVMSetInitializer(gv, cv); llvm::LLVMSetGlobalConstant(gv, True); - let p = llvm::LLVMConstPointerCast(gv, T_ptr(llunitty)); - + let p = const_ptrcast(cx, gv, llunitty); C_struct(~[p, sz]) } _ => cx.sess.span_bug(e.span, diff --git a/src/test/run-pass/const-fields-and-indexing.rs b/src/test/run-pass/const-fields-and-indexing.rs index 6190053df7a..8a02ea13186 100644 --- a/src/test/run-pass/const-fields-and-indexing.rs +++ b/src/test/run-pass/const-fields-and-indexing.rs @@ -1,20 +1,16 @@ -// Not quite working on the indexing part yet. -/* const x : [int]/4 = [1,2,3,4]; -const y : &[int] = &[1,2,3,4]; const p : int = x[2]; +const y : &[int] = &[1,2,3,4]; const q : int = y[2]; -*/ const s : {a: int, b: int} = {a: 10, b: 20}; const t : int = s.b; fn main() { - -// io::println(fmt!("%?", p)); -// io::println(fmt!("%?", q)); + io::println(fmt!("%?", p)); + io::println(fmt!("%?", q)); io::println(fmt!("%?", t)); -// assert p == 3; -// assert q == 3; + assert p == 3; + assert q == 3; assert t == 20; } \ No newline at end of file |
