Skip to content

Commit 85e52d0

Browse files
Oliver SchneiderOliver 'ker' Schneider
Oliver Schneider
authored and
Oliver 'ker' Schneider
committed
don't go through llvm for const indexing
references as first class const values
1 parent ba0e1cd commit 85e52d0

File tree

9 files changed

+260
-35
lines changed

9 files changed

+260
-35
lines changed

src/librustc/middle/const_eval.rs

+128-2
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,10 @@ pub enum const_val {
266266
const_binary(Rc<Vec<u8>>),
267267
const_bool(bool),
268268
Struct(ast::NodeId),
269-
Tuple(ast::NodeId)
269+
Tuple(ast::NodeId),
270+
Array(ast::NodeId, u64),
271+
Repeat(ast::NodeId, u64),
272+
Ref(Box<const_val>),
270273
}
271274

272275
pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P<ast::Pat> {
@@ -353,11 +356,28 @@ pub enum ErrKind {
353356
NegateOnBinary,
354357
NegateOnStruct,
355358
NegateOnTuple,
359+
NegateOnArray,
360+
NegateOnRepeat,
361+
NegateOnRef,
356362
NotOnFloat,
357363
NotOnString,
358364
NotOnBinary,
359365
NotOnStruct,
360366
NotOnTuple,
367+
NotOnArray,
368+
NotOnRepeat,
369+
NotOnRef,
370+
371+
DerefInt,
372+
DerefUInt,
373+
DerefBool,
374+
DerefString,
375+
DerefFloat,
376+
DerefBinary,
377+
DerefTuple,
378+
DerefStruct,
379+
DerefArray,
380+
DerefRepeat,
361381

362382
NegateWithOverflow(i64),
363383
AddiWithOverflow(i64, i64),
@@ -377,6 +397,13 @@ pub enum ErrKind {
377397
ExpectedConstTuple,
378398
ExpectedConstStruct,
379399
TupleIndexOutOfBounds,
400+
IndexedNonVec,
401+
IndexNotNatural,
402+
IndexNotInt,
403+
IndexOutOfBounds,
404+
RepeatCountNotNatural,
405+
RepeatCountNotInt,
406+
MutableRef,
380407

381408
MiscBinaryOp,
382409
MiscCatchAll,
@@ -398,11 +425,28 @@ impl ConstEvalErr {
398425
NegateOnBinary => "negate on binary literal".into_cow(),
399426
NegateOnStruct => "negate on struct".into_cow(),
400427
NegateOnTuple => "negate on tuple".into_cow(),
428+
NegateOnArray => "negate on array".into_cow(),
429+
NegateOnRepeat => "negate on repeat".into_cow(),
430+
NegateOnRef => "negate on ref".into_cow(),
401431
NotOnFloat => "not on float or string".into_cow(),
402432
NotOnString => "not on float or string".into_cow(),
403433
NotOnBinary => "not on binary literal".into_cow(),
404434
NotOnStruct => "not on struct".into_cow(),
405435
NotOnTuple => "not on tuple".into_cow(),
436+
NotOnArray => "not on array".into_cow(),
437+
NotOnRepeat => "not on repeat".into_cow(),
438+
NotOnRef => "not on ref".into_cow(),
439+
440+
DerefInt => "deref on int".into_cow(),
441+
DerefUInt => "deref on unsigned int".into_cow(),
442+
DerefBool => "deref on float".into_cow(),
443+
DerefFloat => "deref on float".into_cow(),
444+
DerefString => "deref on string".into_cow(),
445+
DerefBinary => "deref on binary literal".into_cow(),
446+
DerefStruct => "deref on struct".into_cow(),
447+
DerefTuple => "deref on tuple".into_cow(),
448+
DerefArray => "deref on array".into_cow(),
449+
DerefRepeat => "deref on repeat".into_cow(),
406450

407451
NegateWithOverflow(..) => "attempted to negate with overflow".into_cow(),
408452
AddiWithOverflow(..) => "attempted to add with overflow".into_cow(),
@@ -422,6 +466,13 @@ impl ConstEvalErr {
422466
ExpectedConstTuple => "expected constant tuple".into_cow(),
423467
ExpectedConstStruct => "expected constant struct".into_cow(),
424468
TupleIndexOutOfBounds => "tuple index out of bounds".into_cow(),
469+
IndexedNonVec => "indexing is only supported for arrays".into_cow(),
470+
IndexNotNatural => "indices must be a natural number".into_cow(),
471+
IndexNotInt => "indices must be integers".into_cow(),
472+
IndexOutOfBounds => "array index out of bounds".into_cow(),
473+
RepeatCountNotNatural => "repeat count must be a natural number".into_cow(),
474+
RepeatCountNotInt => "repeat count must be integers".into_cow(),
475+
MutableRef => "cannot get a mutable reference to a constant".into_cow(),
425476

426477
MiscBinaryOp => "bad operands for binary".into_cow(),
427478
MiscCatchAll => "unsupported constant expr".into_cow(),
@@ -530,6 +581,15 @@ fn const_uint_not(a: u64, opt_ety: Option<UintTy>) -> const_val {
530581
const_uint(!a & mask)
531582
}
532583

584+
pub fn eval_const_index(tcx: &ty::ctxt, idx: &Expr) -> Result<u64, ConstEvalErr> {
585+
match try!(eval_const_expr_partial(tcx, idx, None)) {
586+
const_int(i) if i >= 0 => Ok(i as u64),
587+
const_int(_) => signal!(idx, IndexNotNatural),
588+
const_uint(i) => Ok(i),
589+
_ => signal!(idx, IndexNotInt),
590+
}
591+
}
592+
533593
macro_rules! overflow_checking_body {
534594
($a:ident, $b:ident, $ety:ident, $overflowing_op:ident,
535595
lhs: $to_8_lhs:ident $to_16_lhs:ident $to_32_lhs:ident,
@@ -741,6 +801,9 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
741801
const_binary(_) => signal!(e, NegateOnBinary),
742802
const_val::Tuple(_) => signal!(e, NegateOnTuple),
743803
const_val::Struct(..) => signal!(e, NegateOnStruct),
804+
const_val::Array(..) => signal!(e, NegateOnArray),
805+
const_val::Repeat(..) => signal!(e, NegateOnRepeat),
806+
const_val::Ref(_) => signal!(e, NegateOnRef),
744807
}
745808
}
746809
ast::ExprUnary(ast::UnNot, ref inner) => {
@@ -753,6 +816,24 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
753816
const_binary(_) => signal!(e, NotOnBinary),
754817
const_val::Tuple(_) => signal!(e, NotOnTuple),
755818
const_val::Struct(..) => signal!(e, NotOnStruct),
819+
const_val::Array(..) => signal!(e, NotOnArray),
820+
const_val::Repeat(..) => signal!(e, NotOnRepeat),
821+
const_val::Ref(_) => signal!(e, NotOnRef),
822+
}
823+
}
824+
ast::ExprUnary(ast::UnDeref, ref inner) => {
825+
match try!(eval_const_expr_partial(tcx, &**inner, ety)) {
826+
const_int(_) => signal!(e, DerefInt),
827+
const_uint(_) => signal!(e, DerefUInt),
828+
const_bool(_) => signal!(e, DerefBool),
829+
const_str(_) => signal!(e, DerefString),
830+
const_float(_) => signal!(e, DerefFloat),
831+
const_binary(_) => signal!(e, DerefBinary),
832+
const_val::Tuple(_) => signal!(e, DerefTuple),
833+
const_val::Struct(..) => signal!(e, DerefStruct),
834+
const_val::Array(..) => signal!(e, DerefArray),
835+
const_val::Repeat(..) => signal!(e, DerefRepeat),
836+
const_val::Ref(inner) => *inner,
756837
}
757838
}
758839
ast::ExprBinary(op, ref a, ref b) => {
@@ -936,12 +1017,57 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
9361017
ast::ExprBlock(ref block) => {
9371018
match block.expr {
9381019
Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ety)),
939-
None => const_int(0)
1020+
None => unreachable!(),
9401021
}
9411022
}
9421023
ast::ExprTup(_) => {
9431024
const_val::Tuple(e.id)
9441025
}
1026+
ast::ExprIndex(ref arr, ref idx) => {
1027+
let mut arr = try!(eval_const_expr_partial(tcx, arr, None));
1028+
while let const_val::Ref(inner) = arr {
1029+
arr = *inner;
1030+
}
1031+
let idx = try!(eval_const_index(tcx, idx));
1032+
match arr {
1033+
const_val::Array(_, n) if idx >= n => signal!(e, IndexOutOfBounds),
1034+
const_val::Array(v, _) => if let ast::ExprVec(ref v) = tcx.map.expect_expr(v).node {
1035+
try!(eval_const_expr_partial(tcx, &*v[idx as usize], None))
1036+
} else {
1037+
unreachable!()
1038+
},
1039+
1040+
const_val::Repeat(_, n) if idx >= n => signal!(e, IndexOutOfBounds),
1041+
const_val::Repeat(elem, _) => try!(eval_const_expr_partial(
1042+
tcx,
1043+
&*tcx.map.expect_expr(elem),
1044+
None,
1045+
)),
1046+
1047+
const_val::const_binary(ref data) if idx as usize >= data.len()
1048+
=> signal!(e, IndexOutOfBounds),
1049+
const_val::const_binary(data) => const_val::const_uint(data[idx as usize] as u64),
1050+
1051+
const_val::const_str(ref s) if idx as usize >= s.len()
1052+
=> signal!(e, IndexOutOfBounds),
1053+
const_val::const_str(_) => unimplemented!(), // there's no const_char type
1054+
_ => signal!(e, IndexedNonVec),
1055+
}
1056+
}
1057+
ast::ExprAddrOf(ast::Mutability::MutMutable, _) => signal!(e, MutableRef),
1058+
ast::ExprAddrOf(ast::Mutability::MutImmutable, ref expr) => {
1059+
const_val::Ref(Box::new(try!(eval_const_expr_partial(tcx, &**expr, None))))
1060+
},
1061+
ast::ExprVec(ref v) => const_val::Array(e.id, v.len() as u64),
1062+
ast::ExprRepeat(_, ref n) => const_val::Repeat(
1063+
e.id,
1064+
match try!(eval_const_expr_partial(tcx, &**n, None)) {
1065+
const_int(i) if i >= 0 => i as u64,
1066+
const_int(_) => signal!(e, RepeatCountNotNatural),
1067+
const_uint(i) => i,
1068+
_ => signal!(e, RepeatCountNotInt),
1069+
},
1070+
),
9451071
ast::ExprStruct(..) => {
9461072
const_val::Struct(e.id)
9471073
}

src/librustc/middle/ty.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -6242,7 +6242,10 @@ pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> usize {
62426242
const_eval::const_bool(_) => "boolean",
62436243
const_eval::const_binary(_) => "binary array",
62446244
const_eval::Struct(..) => "struct",
6245-
const_eval::Tuple(_) => "tuple"
6245+
const_eval::Tuple(_) => "tuple",
6246+
const_eval::Array(..) => "array",
6247+
const_eval::Repeat(..) => "repeat",
6248+
const_eval::Ref(_) => "ref",
62466249
};
62476250
span_err!(tcx.sess, count_expr.span, E0306,
62486251
"expected positive integer for repeat count, found {}",

src/librustc_trans/trans/consts.rs

+65-5
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,50 @@ use syntax::ptr::P;
4343

4444
pub type FnArgMap<'a> = Option<&'a NodeMap<ValueRef>>;
4545

46+
fn const_val_for_idx<'a, 'tcx>(
47+
cx: &CrateContext<'a, 'tcx>,
48+
val: const_eval::const_val,
49+
param_substs: &'tcx Substs<'tcx>,
50+
ety: Ty<'tcx>,
51+
) -> ValueRef
52+
{
53+
let id2val = |id| {
54+
let expr = cx.tcx().map.expect_expr(id);
55+
const_expr(cx, expr, param_substs).0
56+
};
57+
match val {
58+
const_eval::const_int(i) => if let ty::ty_int(t) = ety.sty {
59+
C_integral(Type::int_from_ty(cx, t), i as u64, true)
60+
} else {
61+
cx.sess().bug(
62+
&format!(
63+
"integer literal has type {}",
64+
ty_to_string(cx.tcx(), ety),
65+
)
66+
)
67+
},
68+
const_eval::const_uint(u) => if let ty::ty_uint(t) = ety.sty {
69+
C_integral(Type::uint_from_ty(cx, t), u as u64, false)
70+
} else {
71+
cx.sess().bug(
72+
&format!(
73+
"unsigned integer literal has type {}",
74+
ty_to_string(cx.tcx(), ety),
75+
)
76+
)
77+
},
78+
const_eval::const_float(f) => C_floating(&f.to_string(), Type::f64(cx)),
79+
const_eval::const_str(s) => C_str_slice(cx, s),
80+
const_eval::const_binary(data) => addr_of(cx, C_bytes(cx, &data[..]), "binary"),
81+
const_eval::const_bool(b) => C_bool(cx, b),
82+
const_eval::Struct(id) => id2val(id),
83+
const_eval::Tuple(id) => id2val(id),
84+
const_eval::Array(id, _) => id2val(id),
85+
const_eval::Repeat(id, _) => id2val(id),
86+
const_eval::Ref(inner) => const_val_for_idx(cx, *inner, param_substs, ety),
87+
}
88+
}
89+
4690
pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: &ast::Lit)
4791
-> ValueRef {
4892
let _icx = push_ctxt("trans_lit");
@@ -596,12 +640,20 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
596640
}
597641

598642
ast::ExprIndex(ref base, ref index) => {
643+
match const_eval::eval_const_expr_partial(cx.tcx(), &e, None) {
644+
Ok(val) => const_val_for_idx(cx, val, param_substs, ety),
645+
Err(const_eval::ConstEvalErr {
646+
kind: const_eval::ErrKind::NonConstPath, ..
647+
}) | Err(const_eval::ConstEvalErr {
648+
kind: const_eval::ErrKind::MiscCatchAll, ..
649+
}) => {
599650
let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args);
600-
let iv = match const_eval::eval_const_expr_partial(cx.tcx(), &**index, None) {
601-
Ok(const_eval::const_int(i)) => i as u64,
602-
Ok(const_eval::const_uint(u)) => u,
603-
_ => cx.sess().span_bug(index.span,
604-
"index is not an integer-constant expression")
651+
let iv = match const_eval::eval_const_index(cx.tcx(), &**index) {
652+
Ok(idx) => idx,
653+
Err(err) => {
654+
cx.sess().span_err(err.span, &*err.description());
655+
cx.sess().span_fatal(index.span, "constant evaluation of index failed");
656+
},
605657
};
606658
let (arr, len) = match bt.sty {
607659
ty::ty_vec(_, Some(u)) => (bv, C_uint(cx, u)),
@@ -638,12 +690,20 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
638690
if iv >= len {
639691
// FIXME #3170: report this earlier on in the const-eval
640692
// pass. Reporting here is a bit late.
693+
// Since some static-eval expressions aren't const-evaluable
694+
// this has to stay
641695
cx.sess().span_err(e.span,
642696
"const index-expr is out of bounds");
643697
C_undef(type_of::type_of(cx, bt).element_type())
644698
} else {
645699
const_get_elt(cx, arr, &[iv as c_uint])
646700
}
701+
},
702+
Err(err) => {
703+
cx.sess().span_err(err.span, &*err.description());
704+
cx.sess().span_fatal(e.span,"constant indexing failed");
705+
},
706+
}
647707
}
648708
ast::ExprCast(ref base, _) => {
649709
let t_cast = ety;
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+
}

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
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]; //~ ERROR array index out of bounds
13+
//~^ ERROR constant indexing failed
1314

1415
fn main() {
1516
let _ = BAR;
+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+
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+
}

0 commit comments

Comments
 (0)