Skip to content

Commit 5eb7d70

Browse files
author
Oliver Schneider
committed
don't go through llvm for const indexing
references as first class const values
1 parent 84b1e08 commit 5eb7d70

File tree

7 files changed

+212
-74
lines changed

7 files changed

+212
-74
lines changed

src/librustc/middle/const_eval.rs

Lines changed: 116 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,10 @@ pub enum const_val {
207207
const_binary(Rc<Vec<u8>>),
208208
const_bool(bool),
209209
Struct(ast::NodeId),
210-
Tuple(ast::NodeId)
210+
Tuple(ast::NodeId),
211+
Array(ast::NodeId, u64),
212+
Repeat(ast::NodeId, u64),
213+
Ref(Box<const_val>),
211214
}
212215

213216
pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P<ast::Pat> {
@@ -294,11 +297,28 @@ pub enum ErrKind {
294297
NegateOnBinary,
295298
NegateOnStruct,
296299
NegateOnTuple,
300+
NegateOnArray,
301+
NegateOnRepeat,
302+
NegateOnRef,
297303
NotOnFloat,
298304
NotOnString,
299305
NotOnBinary,
300306
NotOnStruct,
301307
NotOnTuple,
308+
NotOnArray,
309+
NotOnRepeat,
310+
NotOnRef,
311+
312+
DerefInt,
313+
DerefUInt,
314+
DerefBool,
315+
DerefString,
316+
DerefFloat,
317+
DerefBinary,
318+
DerefTuple,
319+
DerefStruct,
320+
DerefArray,
321+
DerefRepeat,
302322

303323
NegateWithOverflow(i64),
304324
AddiWithOverflow(i64, i64),
@@ -318,6 +338,13 @@ pub enum ErrKind {
318338
ExpectedConstTuple,
319339
ExpectedConstStruct,
320340
TupleIndexOutOfBounds,
341+
IndexedNonVec,
342+
IndexNotNatural,
343+
IndexNotInt,
344+
IndexOutOfBounds,
345+
RepeatCountNotNatural,
346+
RepeatCountNotInt,
347+
MutableRef,
321348

322349
MiscBinaryOp,
323350
MiscCatchAll,
@@ -339,11 +366,28 @@ impl ConstEvalErr {
339366
NegateOnBinary => "negate on binary literal".into_cow(),
340367
NegateOnStruct => "negate on struct".into_cow(),
341368
NegateOnTuple => "negate on tuple".into_cow(),
369+
NegateOnArray => "negate on array".into_cow(),
370+
NegateOnRepeat => "negate on repeat".into_cow(),
371+
NegateOnRef => "negate on ref".into_cow(),
342372
NotOnFloat => "not on float or string".into_cow(),
343373
NotOnString => "not on float or string".into_cow(),
344374
NotOnBinary => "not on binary literal".into_cow(),
345375
NotOnStruct => "not on struct".into_cow(),
346376
NotOnTuple => "not on tuple".into_cow(),
377+
NotOnArray => "not on array".into_cow(),
378+
NotOnRepeat => "not on repeat".into_cow(),
379+
NotOnRef => "not on ref".into_cow(),
380+
381+
DerefInt => "deref on int".into_cow(),
382+
DerefUInt => "deref on unsigned int".into_cow(),
383+
DerefBool => "deref on float".into_cow(),
384+
DerefFloat => "deref on float".into_cow(),
385+
DerefString => "deref on string".into_cow(),
386+
DerefBinary => "deref on binary literal".into_cow(),
387+
DerefStruct => "deref on struct".into_cow(),
388+
DerefTuple => "deref on tuple".into_cow(),
389+
DerefArray => "deref on array".into_cow(),
390+
DerefRepeat => "deref on repeat".into_cow(),
347391

348392
NegateWithOverflow(..) => "attempted to negate with overflow".into_cow(),
349393
AddiWithOverflow(..) => "attempted to add with overflow".into_cow(),
@@ -363,6 +407,13 @@ impl ConstEvalErr {
363407
ExpectedConstTuple => "expected constant tuple".into_cow(),
364408
ExpectedConstStruct => "expected constant struct".into_cow(),
365409
TupleIndexOutOfBounds => "tuple index out of bounds".into_cow(),
410+
IndexedNonVec => "indexing is only supported for arrays".into_cow(),
411+
IndexNotNatural => "indices must be a natural number".into_cow(),
412+
IndexNotInt => "indices must be integers".into_cow(),
413+
IndexOutOfBounds => "array index out of bounds".into_cow(),
414+
RepeatCountNotNatural => "repeat count must be a natural number".into_cow(),
415+
RepeatCountNotInt => "repeat count must be integers".into_cow(),
416+
MutableRef => "cannot get a mutable reference to a constant".into_cow(),
366417

367418
MiscBinaryOp => "bad operands for binary".into_cow(),
368419
MiscCatchAll => "unsupported constant expr".into_cow(),
@@ -682,6 +733,9 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
682733
const_binary(_) => signal!(e, NegateOnBinary),
683734
const_val::Tuple(_) => signal!(e, NegateOnTuple),
684735
const_val::Struct(..) => signal!(e, NegateOnStruct),
736+
const_val::Array(..) => signal!(e, NegateOnArray),
737+
const_val::Repeat(..) => signal!(e, NegateOnRepeat),
738+
const_val::Ref(_) => signal!(e, NegateOnRef),
685739
}
686740
}
687741
ast::ExprUnary(ast::UnNot, ref inner) => {
@@ -694,6 +748,24 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
694748
const_binary(_) => signal!(e, NotOnBinary),
695749
const_val::Tuple(_) => signal!(e, NotOnTuple),
696750
const_val::Struct(..) => signal!(e, NotOnStruct),
751+
const_val::Array(..) => signal!(e, NotOnArray),
752+
const_val::Repeat(..) => signal!(e, NotOnRepeat),
753+
const_val::Ref(_) => signal!(e, NotOnRef),
754+
}
755+
}
756+
ast::ExprUnary(ast::UnDeref, ref inner) => {
757+
match try!(eval_const_expr_partial(tcx, &**inner, ety)) {
758+
const_int(_) => signal!(e, DerefInt),
759+
const_uint(_) => signal!(e, DerefUInt),
760+
const_bool(_) => signal!(e, DerefBool),
761+
const_str(_) => signal!(e, DerefString),
762+
const_float(_) => signal!(e, DerefFloat),
763+
const_binary(_) => signal!(e, DerefBinary),
764+
const_val::Tuple(_) => signal!(e, DerefTuple),
765+
const_val::Struct(..) => signal!(e, DerefStruct),
766+
const_val::Array(..) => signal!(e, DerefArray),
767+
const_val::Repeat(..) => signal!(e, DerefRepeat),
768+
const_val::Ref(inner) => *inner,
697769
}
698770
}
699771
ast::ExprBinary(op, ref a, ref b) => {
@@ -877,12 +949,54 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
877949
ast::ExprBlock(ref block) => {
878950
match block.expr {
879951
Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ety)),
880-
None => const_int(0)
952+
None => const_int(0) // huh???
881953
}
882954
}
883955
ast::ExprTup(_) => {
884956
const_val::Tuple(e.id)
885957
}
958+
ast::ExprIndex(ref arr, ref idx) => {
959+
let mut arr = try!(eval_const_expr_partial(tcx, arr, None));
960+
while let const_val::Ref(inner) = arr {
961+
arr = *inner;
962+
}
963+
let idx = try!(eval_const_expr_partial(tcx, idx, None));
964+
let idx = match idx {
965+
const_int(i) if i >= 0 => i as u64,
966+
const_int(_) => signal!(e, IndexNotNatural),
967+
const_uint(i) => i,
968+
_ => signal!(e, IndexNotInt),
969+
};
970+
match arr {
971+
const_val::Array(_, n) if idx >= n => signal!(e, IndexOutOfBounds),
972+
const_val::Array(v, _) => if let ast::ExprVec(ref v) = tcx.map.expect_expr(v).node {
973+
try!(eval_const_expr_partial(tcx, &*v[idx as usize], None))
974+
} else {
975+
unreachable!()
976+
},
977+
const_val::Repeat(_, n) if idx >= n => signal!(e, IndexOutOfBounds),
978+
const_val::Repeat(elem, _) => try!(eval_const_expr_partial(
979+
tcx,
980+
&*tcx.map.expect_expr(elem),
981+
None,
982+
)),
983+
_ => signal!(e, IndexedNonVec),
984+
}
985+
}
986+
ast::ExprAddrOf(ast::Mutability::MutMutable, _) => signal!(e, MutableRef),
987+
ast::ExprAddrOf(ast::Mutability::MutImmutable, ref expr) => {
988+
const_val::Ref(Box::new(try!(eval_const_expr_partial(tcx, &**expr, None))))
989+
},
990+
ast::ExprVec(ref v) => const_val::Array(e.id, v.len() as u64),
991+
ast::ExprRepeat(_, ref n) => const_val::Repeat(
992+
e.id,
993+
match try!(eval_const_expr_partial(tcx, &**n, None)) {
994+
const_int(i) if i >= 0 => i as u64,
995+
const_int(_) => signal!(e, RepeatCountNotNatural),
996+
const_uint(i) => i,
997+
_ => signal!(e, RepeatCountNotInt),
998+
},
999+
),
8861000
ast::ExprStruct(..) => {
8871001
const_val::Struct(e.id)
8881002
}

src/librustc/middle/ty.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6235,7 +6235,10 @@ pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> usize {
62356235
const_eval::const_bool(_) => "boolean",
62366236
const_eval::const_binary(_) => "binary array",
62376237
const_eval::Struct(..) => "struct",
6238-
const_eval::Tuple(_) => "tuple"
6238+
const_eval::Tuple(_) => "tuple",
6239+
const_eval::Array(..) => "array",
6240+
const_eval::Repeat(..) => "repeat",
6241+
const_eval::Ref(_) => "ref",
62396242
};
62406243
span_err!(tcx.sess, count_expr.span, E0306,
62416244
"expected positive integer for repeat count, found {}",

src/librustc_trans/trans/common.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,10 @@ pub fn C_u64(ccx: &CrateContext, i: u64) -> ValueRef {
788788
C_integral(Type::i64(ccx), i, false)
789789
}
790790

791+
pub fn C_i64(ccx: &CrateContext, i: i64) -> ValueRef {
792+
C_integral(Type::i64(ccx), i as u64, true)
793+
}
794+
791795
pub fn C_int<I: AsI64>(ccx: &CrateContext, i: I) -> ValueRef {
792796
let v = i.as_i64();
793797

src/librustc_trans/trans/consts.rs

Lines changed: 34 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,35 @@ use middle::ty::{self, Ty};
3434
use util::ppaux::{Repr, ty_to_string};
3535

3636
use std::iter::repeat;
37-
use libc::c_uint;
3837
use syntax::{ast, ast_util};
3938
use syntax::parse::token;
4039
use syntax::ptr::P;
4140

41+
fn const_val_for_idx<'a, 'tcx>(
42+
cx: &CrateContext<'a, 'tcx>,
43+
val: const_eval::const_val,
44+
param_substs: &'tcx Substs<'tcx>,
45+
) -> ValueRef
46+
{
47+
let id2val = |id| {
48+
let expr = cx.tcx().map.expect_expr(id);
49+
const_expr(cx, expr, param_substs).0
50+
};
51+
match val {
52+
const_eval::const_int(i) => C_i64(cx, i), // this might be wrong
53+
const_eval::const_uint(u) => C_u64(cx, u), // this too
54+
const_eval::const_float(f) => C_floating(&f.to_string(), Type::f64(cx)),
55+
const_eval::const_str(s) => C_str_slice(cx, s),
56+
const_eval::const_binary(data) => addr_of(cx, C_bytes(cx, &data[..]), "binary"),
57+
const_eval::const_bool(b) => C_bool(cx, b),
58+
const_eval::Struct(id) => id2val(id),
59+
const_eval::Tuple(id) => id2val(id),
60+
const_eval::Array(id, _) => id2val(id),
61+
const_eval::Repeat(id, _) => id2val(id),
62+
const_eval::Ref(inner) => const_val_for_idx(cx, *inner, param_substs),
63+
}
64+
}
65+
4266
pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: &ast::Lit)
4367
-> ValueRef {
4468
let _icx = push_ctxt("trans_lit");
@@ -565,56 +589,16 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
565589
})
566590
}
567591

568-
ast::ExprIndex(ref base, ref index) => {
569-
let (bv, bt) = const_expr(cx, &**base, param_substs);
570-
let iv = match const_eval::eval_const_expr_partial(cx.tcx(), &**index, None) {
571-
Ok(const_eval::const_int(i)) => i as u64,
572-
Ok(const_eval::const_uint(u)) => u,
573-
_ => cx.sess().span_bug(index.span,
574-
"index is not an integer-constant expression")
575-
};
576-
let (arr, len) = match bt.sty {
577-
ty::ty_vec(_, Some(u)) => (bv, C_uint(cx, u)),
578-
ty::ty_vec(_, None) | ty::ty_str => {
579-
let e1 = const_get_elt(cx, bv, &[0]);
580-
(const_deref_ptr(cx, e1), const_get_elt(cx, bv, &[1]))
581-
}
582-
ty::ty_rptr(_, mt) => match mt.ty.sty {
583-
ty::ty_vec(_, Some(u)) => {
584-
(const_deref_ptr(cx, bv), C_uint(cx, u))
585-
},
586-
_ => cx.sess().span_bug(base.span,
587-
&format!("index-expr base must be a vector \
588-
or string type, found {}",
589-
ty_to_string(cx.tcx(), bt)))
590-
},
591-
_ => cx.sess().span_bug(base.span,
592-
&format!("index-expr base must be a vector \
593-
or string type, found {}",
594-
ty_to_string(cx.tcx(), bt)))
595-
};
592+
ast::ExprIndex(..) => {
593+
match const_eval::eval_const_expr_partial(cx.tcx(), &e, None) {
594+
Ok(val) => const_val_for_idx(cx, val, param_substs),
595+
Err(err) => cx.sess().span_fatal(
596+
e.span,
597+
&format!("constant indexing failed: {}", err.description()),
598+
),
599+
}
600+
},
596601

597-
let len = llvm::LLVMConstIntGetZExtValue(len) as u64;
598-
let len = match bt.sty {
599-
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty.sty {
600-
ty::ty_str => {
601-
assert!(len > 0);
602-
len - 1
603-
}
604-
_ => len
605-
},
606-
_ => len
607-
};
608-
if iv >= len {
609-
// FIXME #3170: report this earlier on in the const-eval
610-
// pass. Reporting here is a bit late.
611-
cx.sess().span_err(e.span,
612-
"const index-expr is out of bounds");
613-
C_undef(type_of::type_of(cx, bt).element_type())
614-
} else {
615-
const_get_elt(cx, arr, &[iv as c_uint])
616-
}
617-
}
618602
ast::ExprCast(ref base, _) => {
619603
let llty = type_of::type_of(cx, ety);
620604
let (v, basety) = const_expr(cx, &**base, param_substs);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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];
13+
14+
fn main() {}
Lines changed: 16 additions & 0 deletions
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)