From ed5a9fb2d4a0f131334dcd77f8eec84a69b1bbfa Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 13 May 2015 15:14:25 +0200 Subject: [PATCH 1/3] don't go through llvm for const indexing closes #3170 --- src/librustc/middle/const_eval.rs | 55 +++++++++++++++++++++++- src/librustc/middle/ty.rs | 4 +- src/librustc_trans/trans/consts.rs | 51 ---------------------- src/test/run-pass/array_const_index-0.rs | 14 ++++++ src/test/run-pass/array_const_index-1.rs | 16 +++++++ 5 files changed, 87 insertions(+), 53 deletions(-) create mode 100644 src/test/run-pass/array_const_index-0.rs create mode 100644 src/test/run-pass/array_const_index-1.rs 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_index-0.rs b/src/test/run-pass/array_const_index-0.rs new file mode 100644 index 0000000000000..a9ccbb407438b --- /dev/null +++ b/src/test/run-pass/array_const_index-0.rs @@ -0,0 +1,14 @@ +// 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. + +static a: &'static [int] = &[]; +static b: int = a[1]; + +fn main() {} \ No newline at end of file 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 0000000000000..9cd85bbed99f4 --- /dev/null +++ b/src/test/run-pass/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 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]; +} From 597024979756484a7c7b55e116ab2bcd2a40a36a Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 13 May 2015 18:13:14 +0200 Subject: [PATCH 2/3] WIP --- src/librustc/middle/const_eval.rs | 28 +++++++++------ src/librustc/middle/ty.rs | 2 +- src/librustc_trans/trans/common.rs | 4 +++ src/librustc_trans/trans/consts.rs | 31 +++++++++++++++++ src/test/run-pass/check-static-slice.rs | 45 +++++++++++++------------ 5 files changed, 78 insertions(+), 32 deletions(-) diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index ae553bb5c1b96..9e8ecce9116e1 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -208,8 +208,8 @@ pub enum const_val { const_bool(bool), Struct(ast::NodeId), Tuple(ast::NodeId), - Array(Vec>), - Repeat(P, u64), + Array(ast::NodeId, u64), + Repeat(ast::NodeId, u64), } pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P { @@ -694,7 +694,7 @@ 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::Array(..) => signal!(e, NegateOnArray), const_val::Repeat(..) => signal!(e, NegateOnRepeat), } } @@ -708,7 +708,7 @@ 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::Array(..) => signal!(e, NotOnArray), const_val::Repeat(..) => signal!(e, NotOnRepeat), } } @@ -909,16 +909,24 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, _ => 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::Array(_, n) if idx >= n => signal!(e, IndexOutOfBounds), + const_val::Array(v, _) => if let ast::ExprVec(ref v) = tcx.map.expect_expr(v).node { + try!(eval_const_expr_partial(tcx, &*v[idx as usize], None)) + } else { + unreachable!() + }, const_val::Repeat(_, n) if idx >= n => signal!(e, IndexOutOfBounds), - const_val::Repeat(elem, _) => try!(eval_const_expr_partial(tcx, &*elem, None)), + const_val::Repeat(elem, _) => try!(eval_const_expr_partial( + tcx, + &*tcx.map.expect_expr(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(), + ast::ExprVec(ref v) => const_val::Array(e.id, v.len() as u64), + ast::ExprRepeat(_, ref n) => const_val::Repeat( + e.id, match try!(eval_const_expr_partial(tcx, &**n, None)) { const_int(i) if i >= 0 => i as u64, const_int(_) => signal!(e, RepeatCountNotNatural), diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 1a97127228d7a..4c0264b3a6dfa 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -6199,7 +6199,7 @@ pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> usize { const_eval::const_binary(_) => "binary array", const_eval::Struct(..) => "struct", const_eval::Tuple(_) => "tuple", - const_eval::Array(_) => "array", + const_eval::Array(..) => "array", const_eval::Repeat(..) => "repeat", }; span_err!(tcx.sess, count_expr.span, E0306, diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 03dda57e5689f..c624e16c8f04d 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -788,6 +788,10 @@ pub fn C_u64(ccx: &CrateContext, i: u64) -> ValueRef { C_integral(Type::i64(ccx), i, false) } +pub fn C_i64(ccx: &CrateContext, i: i64) -> ValueRef { + C_integral(Type::i64(ccx), i as u64, true) +} + pub fn C_int(ccx: &CrateContext, i: I) -> ValueRef { let v = i.as_i64(); diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 229dc05f40d1f..3aa22dcbb0bd2 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -38,6 +38,22 @@ use syntax::{ast, ast_util}; use syntax::parse::token; use syntax::ptr::P; +fn const_val(cx: &CrateContext, _: &ast::Expr, val: const_eval::const_val) -> ValueRef { + match val { + const_eval::const_int(i) => C_i64(cx, i), // this might be wrong + const_eval::const_uint(u) => C_u64(cx, u), // this too + const_eval::const_float(f) => C_floating(&f.to_string(), Type::f64(cx)), + const_eval::const_str(s) => C_str_slice(cx, s), + const_eval::const_binary(data) => addr_of(cx, C_bytes(cx, &data[..]), "binary"), + const_eval::const_bool(b) => C_bool(cx, b), + // split matches from const_expr_unadjusted into functions + const_eval::Struct(_) => unimplemented!(), + const_eval::Tuple(_) => unimplemented!(), + const_eval::Array(..) => unimplemented!(), + const_eval::Repeat(..) => unimplemented!(), + } +} + pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: &ast::Lit) -> ValueRef { let _icx = push_ctxt("trans_lit"); @@ -564,6 +580,21 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }) } + ast::ExprIndex(..) => { + let err = match const_eval::eval_const_expr_partial(cx.tcx(), &e, None) { + Ok(val) => return const_val(cx, &e, val), + Err(err) => err, + } + // might be a slice + let (bv, bt) = const_expr(cx, &**base, param_substs); + // WIP + cx.sess().span_bug( + e.span, + &format!("constant indexing failed: {}", err.description()), + ) + } + }, + 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/check-static-slice.rs b/src/test/run-pass/check-static-slice.rs index 8408597f35409..ac5986c6f6802 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]; +const CA: isize = AA[0]; +const CB: isize = AB[1]; +const CC: isize = AC[2]; +const CD: isize = AD[0]; +const CE: isize = AE[1]; +const CF: isize = AF[2]; + +const AG: &'static isize = &AA[2]; fn main () { let b: &[isize] = &[1, 2, 3]; - assert!(ac == b); - assert!(ad == b); - assert!(af == b); + assert!(AC == b); + assert!(AD == b); + assert!(AF == b); + assert!(*AG == 3); - assert!(ca == 1); - assert!(cb == 2); - assert!(cc == 3); - assert!(cd == 1); - assert!(ce == 2); - assert!(cf == 3); + assert!(CA == 1); + assert!(CB == 2); + assert!(CC == 3); + assert!(CD == 1); + assert!(CE == 2); + assert!(CF == 3); } From f8c7e425e496adfcf10cbf956ec9d405c77a153f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 13 May 2015 18:24:10 +0200 Subject: [PATCH 3/3] this is the way to go --- src/librustc/middle/const_eval.rs | 1 + src/librustc_trans/trans/consts.rs | 17 ++++++----------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 9e8ecce9116e1..1b7085a2884c8 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -924,6 +924,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, _ => signal!(e, IndexedNonVec), } } + ast::ExprAddrOf(ref muta, ref path) => unimplemented!(), ast::ExprVec(ref v) => const_val::Array(e.id, v.len() as u64), ast::ExprRepeat(_, ref n) => const_val::Repeat( e.id, diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 3aa22dcbb0bd2..e496d0a37b743 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -581,17 +581,12 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } ast::ExprIndex(..) => { - let err = match const_eval::eval_const_expr_partial(cx.tcx(), &e, None) { - Ok(val) => return const_val(cx, &e, val), - Err(err) => err, - } - // might be a slice - let (bv, bt) = const_expr(cx, &**base, param_substs); - // WIP - cx.sess().span_bug( - e.span, - &format!("constant indexing failed: {}", err.description()), - ) + match const_eval::eval_const_expr_partial(cx.tcx(), &e, None) { + Ok(val) => const_val(cx, &e, val), + Err(err) => cx.sess().span_bug( + e.span, + &format!("constant indexing failed: {}", err), + ), } },