allow indexing into constant arrays
This commit is contained in:
parent
af5d9d65e7
commit
6683fa4d42
10 changed files with 190 additions and 28 deletions
|
@ -256,6 +256,8 @@ pub enum ConstVal {
|
||||||
Struct(ast::NodeId),
|
Struct(ast::NodeId),
|
||||||
Tuple(ast::NodeId),
|
Tuple(ast::NodeId),
|
||||||
Function(DefId),
|
Function(DefId),
|
||||||
|
Array(ast::NodeId, u64),
|
||||||
|
Repeat(ast::NodeId, u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl hash::Hash for ConstVal {
|
impl hash::Hash for ConstVal {
|
||||||
|
@ -270,6 +272,8 @@ impl hash::Hash for ConstVal {
|
||||||
Struct(a) => a.hash(state),
|
Struct(a) => a.hash(state),
|
||||||
Tuple(a) => a.hash(state),
|
Tuple(a) => a.hash(state),
|
||||||
Function(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,
|
(&Struct(a), &Struct(b)) => a == b,
|
||||||
(&Tuple(a), &Tuple(b)) => a == b,
|
(&Tuple(a), &Tuple(b)) => a == b,
|
||||||
(&Function(a), &Function(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,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -310,6 +316,8 @@ impl ConstVal {
|
||||||
Struct(_) => "struct",
|
Struct(_) => "struct",
|
||||||
Tuple(_) => "tuple",
|
Tuple(_) => "tuple",
|
||||||
Function(_) => "function definition",
|
Function(_) => "function definition",
|
||||||
|
Array(..) => "array",
|
||||||
|
Repeat(..) => "repeat",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -416,6 +424,12 @@ pub enum ErrKind {
|
||||||
ExpectedConstTuple,
|
ExpectedConstTuple,
|
||||||
ExpectedConstStruct,
|
ExpectedConstStruct,
|
||||||
TupleIndexOutOfBounds,
|
TupleIndexOutOfBounds,
|
||||||
|
IndexedNonVec,
|
||||||
|
IndexNegative,
|
||||||
|
IndexNotInt,
|
||||||
|
IndexOutOfBounds,
|
||||||
|
RepeatCountNotNatural,
|
||||||
|
RepeatCountNotInt,
|
||||||
|
|
||||||
MiscBinaryOp,
|
MiscBinaryOp,
|
||||||
MiscCatchAll,
|
MiscCatchAll,
|
||||||
|
@ -454,6 +468,12 @@ impl ConstEvalErr {
|
||||||
ExpectedConstTuple => "expected constant tuple".into_cow(),
|
ExpectedConstTuple => "expected constant tuple".into_cow(),
|
||||||
ExpectedConstStruct => "expected constant struct".into_cow(),
|
ExpectedConstStruct => "expected constant struct".into_cow(),
|
||||||
TupleIndexOutOfBounds => "tuple index out of bounds".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(),
|
MiscBinaryOp => "bad operands for binary".into_cow(),
|
||||||
MiscCatchAll => "unsupported constant expr".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) => {
|
hir::ExprBlock(ref block) => {
|
||||||
match block.expr {
|
match block.expr {
|
||||||
Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ty_hint, fn_args)),
|
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::ExprTup(_) => Tuple(e.id),
|
||||||
hir::ExprStruct(..) => Struct(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) => {
|
hir::ExprTupField(ref base, index) => {
|
||||||
let base_hint = if let ExprTypeChecked = ty_hint {
|
let base_hint = if let ExprTypeChecked = ty_hint {
|
||||||
ExprTypeChecked
|
ExprTypeChecked
|
||||||
|
|
|
@ -62,6 +62,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||||
ConstVal::Function(_) => {
|
ConstVal::Function(_) => {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
ConstVal::Array(..) => {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
ConstVal::Repeat(..) => {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
OperandRef {
|
OperandRef {
|
||||||
ty: ty,
|
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.
|
// except according to those terms.
|
||||||
|
|
||||||
const FOO: [u32; 3] = [1, 2, 3];
|
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() {
|
fn main() {
|
||||||
let _ = BAR;
|
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.
|
// and unsized) work properly.
|
||||||
|
|
||||||
|
|
||||||
const aa: [isize; 3] = [1, 2, 3];
|
const AA: [isize; 3] = [1, 2, 3];
|
||||||
const ab: &'static [isize; 3] = &aa;
|
const AB: &'static [isize; 3] = &AA;
|
||||||
const ac: &'static [isize] = ab;
|
const AC: &'static [isize] = AB;
|
||||||
const ad: &'static [isize] = &aa;
|
const AD: &'static [isize] = &AA;
|
||||||
const ae: &'static [isize; 3] = &[1, 2, 3];
|
const AE: &'static [isize; 3] = &[1, 2, 3];
|
||||||
const af: &'static [isize] = &[1, 2, 3];
|
const AF: &'static [isize] = &[1, 2, 3];
|
||||||
|
|
||||||
static ca: isize = aa[0];
|
static CA: isize = AA[0];
|
||||||
static cb: isize = ab[1];
|
static CB: isize = AB[1];
|
||||||
static cc: isize = ac[2];
|
static CC: isize = AC[2];
|
||||||
static cd: isize = ad[0];
|
static CD: isize = AD[0];
|
||||||
static ce: isize = ae[1];
|
static CE: isize = AE[1];
|
||||||
static cf: isize = af[2];
|
static CF: isize = AF[2];
|
||||||
|
|
||||||
|
static AG: &'static isize = &AA[2];
|
||||||
|
|
||||||
fn main () {
|
fn main () {
|
||||||
let b: &[isize] = &[1, 2, 3];
|
let b: &[isize] = &[1, 2, 3];
|
||||||
assert_eq!(ac, b);
|
assert_eq!(AC, b);
|
||||||
assert_eq!(ad, b);
|
assert_eq!(AD, b);
|
||||||
assert_eq!(af, b);
|
assert_eq!(AF, b);
|
||||||
|
assert_eq!(*AG, 3);
|
||||||
|
|
||||||
assert_eq!(ca, 1);
|
assert_eq!(CA, 1);
|
||||||
assert_eq!(cb, 2);
|
assert_eq!(CB, 2);
|
||||||
assert_eq!(cc, 3);
|
assert_eq!(CC, 3);
|
||||||
assert_eq!(cd, 1);
|
assert_eq!(CD, 1);
|
||||||
assert_eq!(ce, 2);
|
assert_eq!(CE, 2);
|
||||||
assert_eq!(cf, 3);
|
assert_eq!(CF, 3);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,14 +8,13 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
|
||||||
enum E { V1(isize), V0 }
|
enum E { V1(isize), V0 }
|
||||||
const C: &'static [E] = &[E::V0, E::V1(0xDEADBEE)];
|
const C: &'static [E] = &[E::V0, E::V1(0xDEADBEE)];
|
||||||
static C0: E = C[0];
|
static C0: E = C[0];
|
||||||
static C1: E = C[1];
|
static C1: E = C[1];
|
||||||
const D: &'static [E; 2] = &[E::V0, E::V1(0xDEADBEE)];
|
const D: &'static [E; 2] = &[E::V0, E::V1(0xDEAFBEE)];
|
||||||
static D0: E = C[0];
|
static D0: E = D[0];
|
||||||
static D1: E = C[1];
|
static D1: E = D[1];
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
match C0 {
|
match C0 {
|
||||||
|
@ -32,7 +31,7 @@ pub fn main() {
|
||||||
_ => panic!()
|
_ => panic!()
|
||||||
}
|
}
|
||||||
match D1 {
|
match D1 {
|
||||||
E::V1(n) => assert_eq!(n, 0xDEADBEE),
|
E::V1(n) => assert_eq!(n, 0xDEAFBEE),
|
||||||
_ => panic!()
|
_ => panic!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ const C: *const u8 = B as *const u8;
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let foo = &A as *const u8;
|
let foo = &A as *const u8;
|
||||||
|
assert_eq!(foo, C);
|
||||||
assert_eq!(str::from_utf8_unchecked(&A), "hi");
|
assert_eq!(str::from_utf8_unchecked(&A), "hi");
|
||||||
assert_eq!(*C, A[0]);
|
assert_eq!(*C, A[0]);
|
||||||
assert_eq!(*(&B[0] as *const u8), A[0]);
|
assert_eq!(*(&B[0] as *const u8), A[0]);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue