about summary refs log tree commit diff
path: root/src/rustc
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2012-08-08 19:41:50 -0700
committerGraydon Hoare <graydon@mozilla.com>2012-08-08 19:59:30 -0700
commita0e3a2ae8e2dc78b520b0bc42eb51a491bda38b0 (patch)
treebc971e23da42acc3c6a43853871aa9e50e8c1a68 /src/rustc
parent5c9c9a6a9fb81ea909da227752bec3dd9e5b3caf (diff)
Const field access (working) and vec indexing (almost). More for #2317.
Diffstat (limited to 'src/rustc')
-rw-r--r--src/rustc/middle/check_const.rs2
-rw-r--r--src/rustc/middle/trans/consts.rs90
2 files changed, 90 insertions, 2 deletions
diff --git a/src/rustc/middle/check_const.rs b/src/rustc/middle/check_const.rs
index 67e5d9cd6a1..545cc049f48 100644
--- a/src/rustc/middle/check_const.rs
+++ b/src/rustc/middle/check_const.rs
@@ -102,6 +102,8 @@ fn check_expr(sess: session, def_map: resolve3::DefMap,
           expr_vstore(_, vstore_fixed(_)) |
           expr_vec(_, m_imm) |
           expr_addr_of(m_imm, _) |
+          expr_field(*) |
+          expr_index(*) |
           expr_tup(*) |
           expr_struct(*) |
           expr_rec(*) => { }
diff --git a/src/rustc/middle/trans/consts.rs b/src/rustc/middle/trans/consts.rs
index f4c67efdd77..e7f281c461f 100644
--- a/src/rustc/middle/trans/consts.rs
+++ b/src/rustc/middle/trans/consts.rs
@@ -43,6 +43,33 @@ fn const_vec(cx: @crate_ctxt, e: @ast::expr, es: &[@ast::expr])
     return (v, sz, llunitty);
 }
 
+fn const_deref(v: ValueRef) -> ValueRef {
+    assert llvm::LLVMIsGlobalConstant(v) == True;
+    llvm::LLVMGetInitializer(v)
+}
+
+fn const_get_elt(v: ValueRef, u: uint) -> ValueRef {
+    let u = u;
+    llvm::LLVMConstExtractValue(v, ptr::addr_of(u), 1 as c_uint)
+}
+
+fn const_autoderef(ty: ty::t, v: ValueRef)
+    -> (ty::t, ValueRef) {
+    let mut t1 = ty;
+    let mut v1 = v;
+    loop {
+        // Only rptrs can be autoderef'ed in a const context.
+        match ty::get(ty).struct {
+            ty::ty_rptr(_, mt) => {
+                t1 = mt.ty;
+                v1 = const_deref(v1);
+            }
+            _ => return (t1,v1)
+        }
+    }
+}
+
+
 fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
     let _icx = cx.insn_ctxt(~"const_expr");
     match e.node {
@@ -106,8 +133,7 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
         return match u {
           ast::box(_)  |
           ast::uniq(_) |
-          ast::deref   => cx.sess.span_bug(e.span,
-                                           ~"bad unop type in const_expr"),
+          ast::deref  => const_deref(te),
           ast::not    => llvm::LLVMConstNot(te),
           ast::neg    => {
             if is_float { llvm::LLVMConstFNeg(te) }
@@ -115,6 +141,66 @@ 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 fields = match ty::get(bt).struct {
+              ty::ty_rec(fs) => fs,
+              ty::ty_class(did, substs) =>
+                  ty::class_items_as_mutable_fields(cx.tcx, did, substs),
+              _ => cx.sess.span_bug(e.span,
+                                    ~"field access on unknown type in const"),
+          };
+          let ix = field_idx_strict(cx.tcx, e.span, field, fields);
+          const_get_elt(bv, ix)
+      }
+
+      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 iv = match const_eval::eval_const_expr(cx.tcx, index) {
+              const_eval::const_int(i) => i as u64,
+              const_eval::const_uint(u) => u,
+              _ => cx.sess.span_bug(index.span,
+                                    ~"index is not an integer-constant \
+                                      expression")
+          };
+          let (arr,len) = match ty::get(bt).struct {
+              ty::ty_evec(_, vstore) | ty::ty_estr(vstore) =>
+                  match vstore {
+                  ty::vstore_fixed(u) =>
+                      (bv, C_uint(cx, u)),
+
+                  ty::vstore_slice(_) => {
+                      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)),
+                       llvm::LLVMConstUDiv(const_get_elt(bv, 1),
+                                            unit_sz))
+                  },
+                  _ => cx.sess.span_bug(base.span,
+                                        ~"index-expr base must be \
+                                          fixed-size or slice")
+              },
+              _ =>  cx.sess.span_bug(base.span,
+                                     ~"index-expr base must be \
+                                       a vector or string type")
+          };
+          let len = llvm::LLVMConstIntGetZExtValue(len) 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?
+              cx.sess.span_err(e.span,
+                               ~"const index-expr is out of bounds");
+          }
+          const_get_elt(arr, iv as uint)
+      }
       ast::expr_cast(base, tp) => {
         let ety = ty::expr_ty(cx.tcx, e), llty = type_of::type_of(cx, ety);
         let basety = ty::expr_ty(cx.tcx, base);