Skip to content

Commit 71f35e6

Browse files
author
Oliver 'ker' Schneider
committed
don't go through llvm for const indexing
references as first class const values
1 parent ba0e1cd commit 71f35e6

File tree

9 files changed

+261
-35
lines changed

9 files changed

+261
-35
lines changed

Diff for: 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
}

Diff for: 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 {}",

Diff for: src/librustc_trans/trans/consts.rs

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

598643
ast::ExprIndex(ref base, ref index) => {
644+
match const_eval::eval_const_expr_partial(cx.tcx(), &e, None) {
645+
Ok(val) => const_val_for_idx(cx, val, param_substs, ety, fn_args),
646+
Err(const_eval::ConstEvalErr {
647+
kind: const_eval::ErrKind::NonConstPath, ..
648+
}) | Err(const_eval::ConstEvalErr {
649+
kind: const_eval::ErrKind::MiscCatchAll, ..
650+
}) => {
599651
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")
652+
let iv = match const_eval::eval_const_index(cx.tcx(), &**index) {
653+
Ok(idx) => idx,
654+
Err(err) => {
655+
cx.sess().span_err(err.span, &*err.description());
656+
cx.sess().span_fatal(index.span, "constant evaluation of index failed");
657+
},
605658
};
606659
let (arr, len) = match bt.sty {
607660
ty::ty_vec(_, Some(u)) => (bv, C_uint(cx, u)),
@@ -638,12 +691,20 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
638691
if iv >= len {
639692
// FIXME #3170: report this earlier on in the const-eval
640693
// pass. Reporting here is a bit late.
694+
// Since some static-eval expressions aren't const-evaluable
695+
// this has to stay
641696
cx.sess().span_err(e.span,
642697
"const index-expr is out of bounds");
643698
C_undef(type_of::type_of(cx, bt).element_type())
644699
} else {
645700
const_get_elt(cx, arr, &[iv as c_uint])
646701
}
702+
},
703+
Err(err) => {
704+
cx.sess().span_err(err.span, &*err.description());
705+
cx.sess().span_fatal(e.span,"constant indexing failed");
706+
},
707+
}
647708
}
648709
ast::ExprCast(ref base, _) => {
649710
let t_cast = ety;

Diff for: src/test/compile-fail/array_const_index-0.rs

+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+
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+
}

Diff for: 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;

Diff for: src/test/run-pass/array_const_index-1.rs

+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)