Skip to content

Commit 6683fa4

Browse files
committed
allow indexing into constant arrays
1 parent af5d9d6 commit 6683fa4

10 files changed

+190
-28
lines changed

src/librustc/middle/const_eval.rs

+82-1
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ pub enum ConstVal {
256256
Struct(ast::NodeId),
257257
Tuple(ast::NodeId),
258258
Function(DefId),
259+
Array(ast::NodeId, u64),
260+
Repeat(ast::NodeId, u64),
259261
}
260262

261263
impl hash::Hash for ConstVal {
@@ -270,6 +272,8 @@ impl hash::Hash for ConstVal {
270272
Struct(a) => a.hash(state),
271273
Tuple(a) => a.hash(state),
272274
Function(a) => a.hash(state),
275+
Array(a, n) => { a.hash(state); n.hash(state) },
276+
Repeat(a, n) => { a.hash(state); n.hash(state) },
273277
}
274278
}
275279
}
@@ -290,6 +294,8 @@ impl PartialEq for ConstVal {
290294
(&Struct(a), &Struct(b)) => a == b,
291295
(&Tuple(a), &Tuple(b)) => a == b,
292296
(&Function(a), &Function(b)) => a == b,
297+
(&Array(a, an), &Array(b, bn)) => (a == b) && (an == bn),
298+
(&Repeat(a, an), &Repeat(b, bn)) => (a == b) && (an == bn),
293299
_ => false,
294300
}
295301
}
@@ -310,6 +316,8 @@ impl ConstVal {
310316
Struct(_) => "struct",
311317
Tuple(_) => "tuple",
312318
Function(_) => "function definition",
319+
Array(..) => "array",
320+
Repeat(..) => "repeat",
313321
}
314322
}
315323
}
@@ -416,6 +424,12 @@ pub enum ErrKind {
416424
ExpectedConstTuple,
417425
ExpectedConstStruct,
418426
TupleIndexOutOfBounds,
427+
IndexedNonVec,
428+
IndexNegative,
429+
IndexNotInt,
430+
IndexOutOfBounds,
431+
RepeatCountNotNatural,
432+
RepeatCountNotInt,
419433

420434
MiscBinaryOp,
421435
MiscCatchAll,
@@ -454,6 +468,12 @@ impl ConstEvalErr {
454468
ExpectedConstTuple => "expected constant tuple".into_cow(),
455469
ExpectedConstStruct => "expected constant struct".into_cow(),
456470
TupleIndexOutOfBounds => "tuple index out of bounds".into_cow(),
471+
IndexedNonVec => "indexing is only supported for arrays".into_cow(),
472+
IndexNegative => "indices must be non-negative integers".into_cow(),
473+
IndexNotInt => "indices must be integers".into_cow(),
474+
IndexOutOfBounds => "array index out of bounds".into_cow(),
475+
RepeatCountNotNatural => "repeat count must be a natural number".into_cow(),
476+
RepeatCountNotInt => "repeat count must be integers".into_cow(),
457477

458478
MiscBinaryOp => "bad operands for binary".into_cow(),
459479
MiscCatchAll => "unsupported constant expr".into_cow(),
@@ -1111,11 +1131,72 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
11111131
hir::ExprBlock(ref block) => {
11121132
match block.expr {
11131133
Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ty_hint, fn_args)),
1114-
None => Int(0)
1134+
None => unreachable!(),
11151135
}
11161136
}
11171137
hir::ExprTup(_) => Tuple(e.id),
11181138
hir::ExprStruct(..) => Struct(e.id),
1139+
hir::ExprIndex(ref arr, ref idx) => {
1140+
let arr_hint = if let ExprTypeChecked = ty_hint {
1141+
ExprTypeChecked
1142+
} else {
1143+
UncheckedExprNoHint
1144+
};
1145+
let arr = try!(eval_const_expr_partial(tcx, arr, arr_hint, fn_args));
1146+
let idx_hint = if let ExprTypeChecked = ty_hint {
1147+
ExprTypeChecked
1148+
} else {
1149+
UncheckedExprHint(tcx.types.usize)
1150+
};
1151+
let idx = match try!(eval_const_expr_partial(tcx, idx, idx_hint, fn_args)) {
1152+
Int(i) if i >= 0 => i as u64,
1153+
Int(_) => signal!(idx, IndexNegative),
1154+
Uint(i) => i,
1155+
_ => signal!(idx, IndexNotInt),
1156+
};
1157+
match arr {
1158+
Array(_, n) if idx >= n => signal!(e, IndexOutOfBounds),
1159+
Array(v, _) => if let hir::ExprVec(ref v) = tcx.map.expect_expr(v).node {
1160+
try!(eval_const_expr_partial(tcx, &*v[idx as usize], ty_hint, fn_args))
1161+
} else {
1162+
unreachable!()
1163+
},
1164+
1165+
Repeat(_, n) if idx >= n => signal!(e, IndexOutOfBounds),
1166+
Repeat(elem, _) => try!(eval_const_expr_partial(
1167+
tcx,
1168+
&*tcx.map.expect_expr(elem),
1169+
ty_hint,
1170+
fn_args,
1171+
)),
1172+
1173+
ByteStr(ref data) if idx as usize >= data.len()
1174+
=> signal!(e, IndexOutOfBounds),
1175+
ByteStr(data) => Uint(data[idx as usize] as u64),
1176+
1177+
Str(ref s) if idx as usize >= s.len()
1178+
=> signal!(e, IndexOutOfBounds),
1179+
Str(_) => unimplemented!(), // there's no const_char type
1180+
_ => signal!(e, IndexedNonVec),
1181+
}
1182+
}
1183+
hir::ExprVec(ref v) => Array(e.id, v.len() as u64),
1184+
hir::ExprRepeat(_, ref n) => {
1185+
let len_hint = if let ExprTypeChecked = ty_hint {
1186+
ExprTypeChecked
1187+
} else {
1188+
UncheckedExprHint(tcx.types.usize)
1189+
};
1190+
Repeat(
1191+
e.id,
1192+
match try!(eval_const_expr_partial(tcx, &**n, len_hint, fn_args)) {
1193+
Int(i) if i >= 0 => i as u64,
1194+
Int(_) => signal!(e, RepeatCountNotNatural),
1195+
Uint(i) => i,
1196+
_ => signal!(e, RepeatCountNotInt),
1197+
},
1198+
)
1199+
},
11191200
hir::ExprTupField(ref base, index) => {
11201201
let base_hint = if let ExprTypeChecked = ty_hint {
11211202
ExprTypeChecked

src/librustc_trans/trans/mir/constant.rs

+6
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
6262
ConstVal::Function(_) => {
6363
unimplemented!()
6464
}
65+
ConstVal::Array(..) => {
66+
unimplemented!()
67+
}
68+
ConstVal::Repeat(..) => {
69+
unimplemented!()
70+
}
6571
};
6672
OperandRef {
6773
ty: ty,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
static A: &'static [i32] = &[];
12+
static B: i32 = (&A)[1]; //~ ERROR: const index-expr is out of bounds
13+
14+
fn main() {
15+
let _ = B;
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
const A: [i32; 0] = [];
12+
const B: i32 = A[1]; //~ ERROR: const index-expr is out of bounds
13+
14+
fn main() {
15+
let _ = B;
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
const ARR: [i32; 6] = [42, 43, 44, 45, 46, 47];
12+
const IDX: usize = 3;
13+
const VAL: i32 = ARR[IDX];
14+
const BONG: [i32; (ARR[0] - 41) as usize] = [5];
15+
const BLUB: [i32; (ARR[0] - 40) as usize] = [5]; //~ ERROR: mismatched types
16+
const BOO: [i32; (ARR[0] - 41) as usize] = [5, 99]; //~ ERROR: mismatched types
17+
18+
fn main() {
19+
let _ = VAL;
20+
}

src/test/compile-fail/const-array-oob.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
// except according to those terms.
1010

1111
const FOO: [u32; 3] = [1, 2, 3];
12-
const BAR: u32 = FOO[5]; //~ ERROR const index-expr is out of bounds
12+
const BAR: u32 = FOO[5]; // no error, because the error below occurs before regular const eval
13+
14+
const BLUB: [u32; FOO[4]] = [5, 6];
15+
//~^ ERROR array length constant evaluation error: array index out of bounds [E0250]
1316

1417
fn main() {
1518
let _ = BAR;
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
12+
fn main() {
13+
const ARR: [i32; 6] = [42, 43, 44, 45, 46, 47];
14+
const IDX: usize = 3;
15+
const VAL: i32 = ARR[IDX];
16+
const BLUB: [i32; (ARR[0] - 41) as usize] = [5];
17+
}

src/test/run-pass/check-static-slice.rs

+24-21
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,33 @@
1212
// and unsized) work properly.
1313

1414

15-
const aa: [isize; 3] = [1, 2, 3];
16-
const ab: &'static [isize; 3] = &aa;
17-
const ac: &'static [isize] = ab;
18-
const ad: &'static [isize] = &aa;
19-
const ae: &'static [isize; 3] = &[1, 2, 3];
20-
const af: &'static [isize] = &[1, 2, 3];
15+
const AA: [isize; 3] = [1, 2, 3];
16+
const AB: &'static [isize; 3] = &AA;
17+
const AC: &'static [isize] = AB;
18+
const AD: &'static [isize] = &AA;
19+
const AE: &'static [isize; 3] = &[1, 2, 3];
20+
const AF: &'static [isize] = &[1, 2, 3];
2121

22-
static ca: isize = aa[0];
23-
static cb: isize = ab[1];
24-
static cc: isize = ac[2];
25-
static cd: isize = ad[0];
26-
static ce: isize = ae[1];
27-
static cf: isize = af[2];
22+
static CA: isize = AA[0];
23+
static CB: isize = AB[1];
24+
static CC: isize = AC[2];
25+
static CD: isize = AD[0];
26+
static CE: isize = AE[1];
27+
static CF: isize = AF[2];
28+
29+
static AG: &'static isize = &AA[2];
2830

2931
fn main () {
3032
let b: &[isize] = &[1, 2, 3];
31-
assert_eq!(ac, b);
32-
assert_eq!(ad, b);
33-
assert_eq!(af, b);
33+
assert_eq!(AC, b);
34+
assert_eq!(AD, b);
35+
assert_eq!(AF, b);
36+
assert_eq!(*AG, 3);
3437

35-
assert_eq!(ca, 1);
36-
assert_eq!(cb, 2);
37-
assert_eq!(cc, 3);
38-
assert_eq!(cd, 1);
39-
assert_eq!(ce, 2);
40-
assert_eq!(cf, 3);
38+
assert_eq!(CA, 1);
39+
assert_eq!(CB, 2);
40+
assert_eq!(CC, 3);
41+
assert_eq!(CD, 1);
42+
assert_eq!(CE, 2);
43+
assert_eq!(CF, 3);
4144
}

src/test/run-pass/const-enum-vec-index.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
1211
enum E { V1(isize), V0 }
1312
const C: &'static [E] = &[E::V0, E::V1(0xDEADBEE)];
1413
static C0: E = C[0];
1514
static C1: E = C[1];
16-
const D: &'static [E; 2] = &[E::V0, E::V1(0xDEADBEE)];
17-
static D0: E = C[0];
18-
static D1: E = C[1];
15+
const D: &'static [E; 2] = &[E::V0, E::V1(0xDEAFBEE)];
16+
static D0: E = D[0];
17+
static D1: E = D[1];
1918

2019
pub fn main() {
2120
match C0 {
@@ -32,7 +31,7 @@ pub fn main() {
3231
_ => panic!()
3332
}
3433
match D1 {
35-
E::V1(n) => assert_eq!(n, 0xDEADBEE),
34+
E::V1(n) => assert_eq!(n, 0xDEAFBEE),
3635
_ => panic!()
3736
}
3837
}

src/test/run-pass/const-str-ptr.rs

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const C: *const u8 = B as *const u8;
1818
pub fn main() {
1919
unsafe {
2020
let foo = &A as *const u8;
21+
assert_eq!(foo, C);
2122
assert_eq!(str::from_utf8_unchecked(&A), "hi");
2223
assert_eq!(*C, A[0]);
2324
assert_eq!(*(&B[0] as *const u8), A[0]);

0 commit comments

Comments
 (0)