diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 091092e3b6079..ae553bb5c1b96 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -207,7 +207,9 @@ pub enum const_val { const_binary(Rc>), const_bool(bool), Struct(ast::NodeId), - Tuple(ast::NodeId) + Tuple(ast::NodeId), + Array(Vec>), + Repeat(P, u64), } pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P { @@ -294,11 +296,15 @@ pub enum ErrKind { NegateOnBinary, NegateOnStruct, NegateOnTuple, + NegateOnArray, + NegateOnRepeat, NotOnFloat, NotOnString, NotOnBinary, NotOnStruct, NotOnTuple, + NotOnArray, + NotOnRepeat, NegateWithOverflow(i64), AddiWithOverflow(i64, i64), @@ -318,6 +324,12 @@ pub enum ErrKind { ExpectedConstTuple, ExpectedConstStruct, TupleIndexOutOfBounds, + IndexedNonVec, + IndexNotNatural, + IndexNotInt, + IndexOutOfBounds, + RepeatCountNotNatural, + RepeatCountNotInt, MiscBinaryOp, MiscCatchAll, @@ -339,11 +351,15 @@ impl ConstEvalErr { NegateOnBinary => "negate on binary literal".into_cow(), NegateOnStruct => "negate on struct".into_cow(), NegateOnTuple => "negate on tuple".into_cow(), + NegateOnArray => "negate on array".into_cow(), + NegateOnRepeat => "negate on repeat".into_cow(), NotOnFloat => "not on float or string".into_cow(), NotOnString => "not on float or string".into_cow(), NotOnBinary => "not on binary literal".into_cow(), NotOnStruct => "not on struct".into_cow(), NotOnTuple => "not on tuple".into_cow(), + NotOnArray => "not on array".into_cow(), + NotOnRepeat => "not on repeat".into_cow(), NegateWithOverflow(..) => "attempted to negate with overflow".into_cow(), AddiWithOverflow(..) => "attempted to add with overflow".into_cow(), @@ -363,6 +379,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(), + IndexNotNatural => "indices must be a natural number".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(), @@ -672,6 +694,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, const_binary(_) => signal!(e, NegateOnBinary), const_val::Tuple(_) => signal!(e, NegateOnTuple), const_val::Struct(..) => signal!(e, NegateOnStruct), + const_val::Array(_) => signal!(e, NegateOnArray), + const_val::Repeat(..) => signal!(e, NegateOnRepeat), } } ast::ExprUnary(ast::UnNot, ref inner) => { @@ -684,6 +708,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, const_binary(_) => signal!(e, NotOnBinary), const_val::Tuple(_) => signal!(e, NotOnTuple), const_val::Struct(..) => signal!(e, NotOnStruct), + const_val::Array(_) => signal!(e, NotOnArray), + const_val::Repeat(..) => signal!(e, NotOnRepeat), } } ast::ExprBinary(op, ref a, ref b) => { @@ -873,6 +899,33 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, ast::ExprTup(_) => { const_val::Tuple(e.id) } + ast::ExprIndex(ref arr, ref idx) => { + let arr = try!(eval_const_expr_partial(tcx, arr, None)); + let idx = try!(eval_const_expr_partial(tcx, idx, None)); + let idx = match idx { + const_int(i) if i >= 0 => i as u64, + const_int(_) => signal!(e, IndexNotNatural), + const_uint(i) => i, + _ => signal!(e, IndexNotInt), + }; + match arr { + const_val::Array(ref v) if idx as usize >= v.len() => signal!(e, IndexOutOfBounds), + const_val::Array(v) => try!(eval_const_expr_partial(tcx, &*v[idx as usize], None)), + const_val::Repeat(_, n) if idx >= n => signal!(e, IndexOutOfBounds), + const_val::Repeat(elem, _) => try!(eval_const_expr_partial(tcx, &*elem, None)), + _ => signal!(e, IndexedNonVec), + } + } + ast::ExprVec(ref arr) => const_val::Array(arr.clone()), // FIXME: eval elements? + ast::ExprRepeat(ref elem, ref n) => const_val::Repeat( + elem.clone(), + match try!(eval_const_expr_partial(tcx, &**n, None)) { + const_int(i) if i >= 0 => i as u64, + const_int(_) => signal!(e, RepeatCountNotNatural), + const_uint(i) => i, + _ => signal!(e, RepeatCountNotInt), + }, + ), ast::ExprStruct(..) => { const_val::Struct(e.id) } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index e445b6bb300e3..1a97127228d7a 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -6198,7 +6198,9 @@ pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> usize { const_eval::const_bool(_) => "boolean", const_eval::const_binary(_) => "binary array", const_eval::Struct(..) => "struct", - const_eval::Tuple(_) => "tuple" + const_eval::Tuple(_) => "tuple", + const_eval::Array(_) => "array", + const_eval::Repeat(..) => "repeat", }; span_err!(tcx.sess, count_expr.span, E0306, "expected positive integer for repeat count, found {}", diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 503bdf8dadb94..229dc05f40d1f 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -34,7 +34,6 @@ use middle::ty::{self, Ty}; use util::ppaux::{Repr, ty_to_string}; use std::iter::repeat; -use libc::c_uint; use syntax::{ast, ast_util}; use syntax::parse::token; use syntax::ptr::P; @@ -565,56 +564,6 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }) } - ast::ExprIndex(ref base, ref index) => { - let (bv, bt) = const_expr(cx, &**base, param_substs); - let iv = match const_eval::eval_const_expr_partial(cx.tcx(), &**index, None) { - Ok(const_eval::const_int(i)) => i as u64, - Ok(const_eval::const_uint(u)) => u, - _ => cx.sess().span_bug(index.span, - "index is not an integer-constant expression") - }; - let (arr, len) = match bt.sty { - ty::ty_vec(_, Some(u)) => (bv, C_uint(cx, u)), - ty::ty_vec(_, None) | ty::ty_str => { - let e1 = const_get_elt(cx, bv, &[0]); - (const_deref_ptr(cx, e1), const_get_elt(cx, bv, &[1])) - } - ty::ty_rptr(_, mt) => match mt.ty.sty { - ty::ty_vec(_, Some(u)) => { - (const_deref_ptr(cx, bv), C_uint(cx, u)) - }, - _ => cx.sess().span_bug(base.span, - &format!("index-expr base must be a vector \ - or string type, found {}", - ty_to_string(cx.tcx(), bt))) - }, - _ => cx.sess().span_bug(base.span, - &format!("index-expr base must be a vector \ - or string type, found {}", - ty_to_string(cx.tcx(), bt))) - }; - - let len = llvm::LLVMConstIntGetZExtValue(len) as u64; - let len = match bt.sty { - ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty.sty { - ty::ty_str => { - assert!(len > 0); - len - 1 - } - _ => len - }, - _ => len - }; - if iv >= len { - // FIXME #3170: report this earlier on in the const-eval - // pass. Reporting here is a bit late. - cx.sess().span_err(e.span, - "const index-expr is out of bounds"); - C_undef(type_of::type_of(cx, bt).element_type()) - } else { - const_get_elt(cx, arr, &[iv as c_uint]) - } - } ast::ExprCast(ref base, _) => { let llty = type_of::type_of(cx, ety); let (v, basety) = const_expr(cx, &**base, param_substs); diff --git a/src/test/run-pass/array_const_slice.rs b/src/test/run-pass/array_const_slice.rs new file mode 100644 index 0000000000000..9cd85bbed99f4 --- /dev/null +++ b/src/test/run-pass/array_const_slice.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 or the MIT license +// , 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]; +}