about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>2015-11-18 10:57:52 +0100
committerOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>2015-11-18 10:57:52 +0100
commit6683fa4d425d3ca2f2ba6b5a48dc073956ad0f13 (patch)
tree62082ca485aeffc36b46ac5a54af7b92ab849342
parentaf5d9d65e781d587414b266fb2e5815ed85f0bd3 (diff)
downloadrust-6683fa4d425d3ca2f2ba6b5a48dc073956ad0f13.tar.gz
rust-6683fa4d425d3ca2f2ba6b5a48dc073956ad0f13.zip
allow indexing into constant arrays
-rw-r--r--src/librustc/middle/const_eval.rs83
-rw-r--r--src/librustc_trans/trans/mir/constant.rs6
-rw-r--r--src/test/compile-fail/array_const_index-0.rs16
-rw-r--r--src/test/compile-fail/array_const_index-1.rs16
-rw-r--r--src/test/compile-fail/const-array-oob-arith.rs20
-rw-r--r--src/test/compile-fail/const-array-oob.rs5
-rw-r--r--src/test/run-pass/array_const_index-1.rs17
-rw-r--r--src/test/run-pass/check-static-slice.rs45
-rw-r--r--src/test/run-pass/const-enum-vec-index.rs9
-rw-r--r--src/test/run-pass/const-str-ptr.rs1
10 files changed, 190 insertions, 28 deletions
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index 34d002d3342..f90fdd1d4b3 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -256,6 +256,8 @@ pub enum ConstVal {
     Struct(ast::NodeId),
     Tuple(ast::NodeId),
     Function(DefId),
+    Array(ast::NodeId, u64),
+    Repeat(ast::NodeId, u64),
 }
 
 impl hash::Hash for ConstVal {
@@ -270,6 +272,8 @@ impl hash::Hash for ConstVal {
             Struct(a) => a.hash(state),
             Tuple(a) => a.hash(state),
             Function(a) => a.hash(state),
+            Array(a, n) => { a.hash(state); n.hash(state) },
+            Repeat(a, n) => { a.hash(state); n.hash(state) },
         }
     }
 }
@@ -290,6 +294,8 @@ impl PartialEq for ConstVal {
             (&Struct(a), &Struct(b)) => a == b,
             (&Tuple(a), &Tuple(b)) => a == b,
             (&Function(a), &Function(b)) => a == b,
+            (&Array(a, an), &Array(b, bn)) => (a == b) && (an == bn),
+            (&Repeat(a, an), &Repeat(b, bn)) => (a == b) && (an == bn),
             _ => false,
         }
     }
@@ -310,6 +316,8 @@ impl ConstVal {
             Struct(_) => "struct",
             Tuple(_) => "tuple",
             Function(_) => "function definition",
+            Array(..) => "array",
+            Repeat(..) => "repeat",
         }
     }
 }
@@ -416,6 +424,12 @@ pub enum ErrKind {
     ExpectedConstTuple,
     ExpectedConstStruct,
     TupleIndexOutOfBounds,
+    IndexedNonVec,
+    IndexNegative,
+    IndexNotInt,
+    IndexOutOfBounds,
+    RepeatCountNotNatural,
+    RepeatCountNotInt,
 
     MiscBinaryOp,
     MiscCatchAll,
@@ -454,6 +468,12 @@ impl ConstEvalErr {
             ExpectedConstTuple => "expected constant tuple".into_cow(),
             ExpectedConstStruct => "expected constant struct".into_cow(),
             TupleIndexOutOfBounds => "tuple index out of bounds".into_cow(),
+            IndexedNonVec => "indexing is only supported for arrays".into_cow(),
+            IndexNegative => "indices must be non-negative integers".into_cow(),
+            IndexNotInt => "indices must be integers".into_cow(),
+            IndexOutOfBounds => "array index out of bounds".into_cow(),
+            RepeatCountNotNatural => "repeat count must be a natural number".into_cow(),
+            RepeatCountNotInt => "repeat count must be integers".into_cow(),
 
             MiscBinaryOp => "bad operands for binary".into_cow(),
             MiscCatchAll => "unsupported constant expr".into_cow(),
@@ -1111,11 +1131,72 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
       hir::ExprBlock(ref block) => {
         match block.expr {
             Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ty_hint, fn_args)),
-            None => Int(0)
+            None => unreachable!(),
         }
       }
       hir::ExprTup(_) => Tuple(e.id),
       hir::ExprStruct(..) => Struct(e.id),
+      hir::ExprIndex(ref arr, ref idx) => {
+        let arr_hint = if let ExprTypeChecked = ty_hint {
+            ExprTypeChecked
+        } else {
+            UncheckedExprNoHint
+        };
+        let arr = try!(eval_const_expr_partial(tcx, arr, arr_hint, fn_args));
+        let idx_hint = if let ExprTypeChecked = ty_hint {
+            ExprTypeChecked
+        } else {
+            UncheckedExprHint(tcx.types.usize)
+        };
+        let idx = match try!(eval_const_expr_partial(tcx, idx, idx_hint, fn_args)) {
+            Int(i) if i >= 0 => i as u64,
+            Int(_) => signal!(idx, IndexNegative),
+            Uint(i) => i,
+            _ => signal!(idx, IndexNotInt),
+        };
+        match arr {
+            Array(_, n) if idx >= n => signal!(e, IndexOutOfBounds),
+            Array(v, _) => if let hir::ExprVec(ref v) = tcx.map.expect_expr(v).node {
+                try!(eval_const_expr_partial(tcx, &*v[idx as usize], ty_hint, fn_args))
+            } else {
+                unreachable!()
+            },
+
+            Repeat(_, n) if idx >= n => signal!(e, IndexOutOfBounds),
+            Repeat(elem, _) => try!(eval_const_expr_partial(
+                tcx,
+                &*tcx.map.expect_expr(elem),
+                ty_hint,
+                fn_args,
+            )),
+
+            ByteStr(ref data) if idx as usize >= data.len()
+                => signal!(e, IndexOutOfBounds),
+            ByteStr(data) => Uint(data[idx as usize] as u64),
+
+            Str(ref s) if idx as usize >= s.len()
+                => signal!(e, IndexOutOfBounds),
+            Str(_) => unimplemented!(), // there's no const_char type
+            _ => signal!(e, IndexedNonVec),
+        }
+      }
+      hir::ExprVec(ref v) => Array(e.id, v.len() as u64),
+      hir::ExprRepeat(_, ref n) => {
+          let len_hint = if let ExprTypeChecked = ty_hint {
+              ExprTypeChecked
+          } else {
+              UncheckedExprHint(tcx.types.usize)
+          };
+          Repeat(
+              e.id,
+              match try!(eval_const_expr_partial(tcx, &**n, len_hint, fn_args)) {
+                  Int(i) if i >= 0 => i as u64,
+                  Int(_) => signal!(e, RepeatCountNotNatural),
+                  Uint(i) => i,
+                  _ => signal!(e, RepeatCountNotInt),
+              },
+          )
+      },
       hir::ExprTupField(ref base, index) => {
         let base_hint = if let ExprTypeChecked = ty_hint {
             ExprTypeChecked
diff --git a/src/librustc_trans/trans/mir/constant.rs b/src/librustc_trans/trans/mir/constant.rs
index 8c0d8b10bfe..9a374a3484b 100644
--- a/src/librustc_trans/trans/mir/constant.rs
+++ b/src/librustc_trans/trans/mir/constant.rs
@@ -62,6 +62,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
             ConstVal::Function(_) => {
                 unimplemented!()
             }
+            ConstVal::Array(..) => {
+                unimplemented!()
+            }
+            ConstVal::Repeat(..) => {
+                unimplemented!()
+            }
         };
         OperandRef {
             ty: ty,
diff --git a/src/test/compile-fail/array_const_index-0.rs b/src/test/compile-fail/array_const_index-0.rs
new file mode 100644
index 00000000000..63a5cf65e36
--- /dev/null
+++ b/src/test/compile-fail/array_const_index-0.rs
@@ -0,0 +1,16 @@
+// 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.
+
+static A: &'static [i32] = &[];
+static B: i32 = (&A)[1]; //~ ERROR: const index-expr is out of bounds
+
+fn main() {
+    let _ = B;
+}
diff --git a/src/test/compile-fail/array_const_index-1.rs b/src/test/compile-fail/array_const_index-1.rs
new file mode 100644
index 00000000000..1f56cd8e875
--- /dev/null
+++ b/src/test/compile-fail/array_const_index-1.rs
@@ -0,0 +1,16 @@
+// 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.
+
+const A: [i32; 0] = [];
+const B: i32 = A[1]; //~ ERROR: const index-expr is out of bounds
+
+fn main() {
+    let _ = B;
+}
diff --git a/src/test/compile-fail/const-array-oob-arith.rs b/src/test/compile-fail/const-array-oob-arith.rs
new file mode 100644
index 00000000000..bca3cd74d24
--- /dev/null
+++ b/src/test/compile-fail/const-array-oob-arith.rs
@@ -0,0 +1,20 @@
+// 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.
+
+const ARR: [i32; 6] = [42, 43, 44, 45, 46, 47];
+const IDX: usize = 3;
+const VAL: i32 = ARR[IDX];
+const BONG: [i32; (ARR[0] - 41) as usize] = [5];
+const BLUB: [i32; (ARR[0] - 40) as usize] = [5]; //~ ERROR: mismatched types
+const BOO: [i32; (ARR[0] - 41) as usize] = [5, 99]; //~ ERROR: mismatched types
+
+fn main() {
+    let _ = VAL;
+}
diff --git a/src/test/compile-fail/const-array-oob.rs b/src/test/compile-fail/const-array-oob.rs
index 84d35292608..da9f6bd247e 100644
--- a/src/test/compile-fail/const-array-oob.rs
+++ b/src/test/compile-fail/const-array-oob.rs
@@ -9,7 +9,10 @@
 // except according to those terms.
 
 const FOO: [u32; 3] = [1, 2, 3];
-const BAR: u32 = FOO[5]; //~ ERROR const index-expr is out of bounds
+const BAR: u32 = FOO[5]; // no error, because the error below occurs before regular const eval
+
+const BLUB: [u32; FOO[4]] = [5, 6];
+//~^ ERROR array length constant evaluation error: array index out of bounds [E0250]
 
 fn main() {
     let _ = BAR;
diff --git a/src/test/run-pass/array_const_index-1.rs b/src/test/run-pass/array_const_index-1.rs
new file mode 100644
index 00000000000..63f0a844880
--- /dev/null
+++ b/src/test/run-pass/array_const_index-1.rs
@@ -0,0 +1,17 @@
+// 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.
+
+
+fn main() {
+    const ARR: [i32; 6] = [42, 43, 44, 45, 46, 47];
+    const IDX: usize = 3;
+    const VAL: i32 = ARR[IDX];
+    const BLUB: [i32; (ARR[0] - 41) as usize] = [5];
+}
diff --git a/src/test/run-pass/check-static-slice.rs b/src/test/run-pass/check-static-slice.rs
index 9286991a4a3..b5f2bea5a38 100644
--- a/src/test/run-pass/check-static-slice.rs
+++ b/src/test/run-pass/check-static-slice.rs
@@ -12,30 +12,33 @@
 // and unsized) work properly.
 
 
-const aa: [isize; 3] = [1, 2, 3];
-const ab: &'static [isize; 3] = &aa;
-const ac: &'static [isize] = ab;
-const ad: &'static [isize] = &aa;
-const ae: &'static [isize; 3] = &[1, 2, 3];
-const af: &'static [isize] = &[1, 2, 3];
+const AA: [isize; 3] = [1, 2, 3];
+const AB: &'static [isize; 3] = &AA;
+const AC: &'static [isize] = AB;
+const AD: &'static [isize] = &AA;
+const AE: &'static [isize; 3] = &[1, 2, 3];
+const AF: &'static [isize] = &[1, 2, 3];
 
-static ca: isize = aa[0];
-static cb: isize = ab[1];
-static cc: isize = ac[2];
-static cd: isize = ad[0];
-static ce: isize = ae[1];
-static cf: isize = af[2];
+static CA: isize = AA[0];
+static CB: isize = AB[1];
+static CC: isize = AC[2];
+static CD: isize = AD[0];
+static CE: isize = AE[1];
+static CF: isize = AF[2];
+
+static AG: &'static isize = &AA[2];
 
 fn main () {
     let b: &[isize] = &[1, 2, 3];
-    assert_eq!(ac, b);
-    assert_eq!(ad, b);
-    assert_eq!(af, b);
+    assert_eq!(AC, b);
+    assert_eq!(AD, b);
+    assert_eq!(AF, b);
+    assert_eq!(*AG, 3);
 
-    assert_eq!(ca, 1);
-    assert_eq!(cb, 2);
-    assert_eq!(cc, 3);
-    assert_eq!(cd, 1);
-    assert_eq!(ce, 2);
-    assert_eq!(cf, 3);
+    assert_eq!(CA, 1);
+    assert_eq!(CB, 2);
+    assert_eq!(CC, 3);
+    assert_eq!(CD, 1);
+    assert_eq!(CE, 2);
+    assert_eq!(CF, 3);
 }
diff --git a/src/test/run-pass/const-enum-vec-index.rs b/src/test/run-pass/const-enum-vec-index.rs
index 56aec867f9d..4af6a6d10d5 100644
--- a/src/test/run-pass/const-enum-vec-index.rs
+++ b/src/test/run-pass/const-enum-vec-index.rs
@@ -8,14 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
 enum E { V1(isize), V0 }
 const C: &'static [E] = &[E::V0, E::V1(0xDEADBEE)];
 static C0: E = C[0];
 static C1: E = C[1];
-const D: &'static [E; 2] = &[E::V0, E::V1(0xDEADBEE)];
-static D0: E = C[0];
-static D1: E = C[1];
+const D: &'static [E; 2] = &[E::V0, E::V1(0xDEAFBEE)];
+static D0: E = D[0];
+static D1: E = D[1];
 
 pub fn main() {
     match C0 {
@@ -32,7 +31,7 @@ pub fn main() {
         _ => panic!()
     }
     match D1 {
-        E::V1(n) => assert_eq!(n, 0xDEADBEE),
+        E::V1(n) => assert_eq!(n, 0xDEAFBEE),
         _ => panic!()
     }
 }
diff --git a/src/test/run-pass/const-str-ptr.rs b/src/test/run-pass/const-str-ptr.rs
index 93cae04a933..4c5152ff90f 100644
--- a/src/test/run-pass/const-str-ptr.rs
+++ b/src/test/run-pass/const-str-ptr.rs
@@ -18,6 +18,7 @@ const C: *const u8 = B as *const u8;
 pub fn main() {
     unsafe {
         let foo = &A as *const u8;
+        assert_eq!(foo, C);
         assert_eq!(str::from_utf8_unchecked(&A), "hi");
         assert_eq!(*C, A[0]);
         assert_eq!(*(&B[0] as *const u8), A[0]);