allow indexing into constant arrays
This commit is contained in:
parent
af5d9d65e7
commit
6683fa4d42
@ -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
|
||||
|
@ -62,6 +62,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
ConstVal::Function(_) => {
|
||||
unimplemented!()
|
||||
}
|
||||
ConstVal::Array(..) => {
|
||||
unimplemented!()
|
||||
}
|
||||
ConstVal::Repeat(..) => {
|
||||
unimplemented!()
|
||||
}
|
||||
};
|
||||
OperandRef {
|
||||
ty: ty,
|
||||
|
16
src/test/compile-fail/array_const_index-0.rs
Normal file
16
src/test/compile-fail/array_const_index-0.rs
Normal file
@ -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;
|
||||
}
|
16
src/test/compile-fail/array_const_index-1.rs
Normal file
16
src/test/compile-fail/array_const_index-1.rs
Normal file
@ -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;
|
||||
}
|
20
src/test/compile-fail/const-array-oob-arith.rs
Normal file
20
src/test/compile-fail/const-array-oob-arith.rs
Normal file
@ -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;
|
||||
}
|
@ -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;
|
||||
|
17
src/test/run-pass/array_const_index-1.rs
Normal file
17
src/test/run-pass/array_const_index-1.rs
Normal file
@ -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];
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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!()
|
||||
}
|
||||
}
|
||||
|
@ -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]);
|
||||
|
Loading…
x
Reference in New Issue
Block a user