Skip to content

Commit 8ce7fdb

Browse files
author
Oliver Schneider
committed
undo hack and pure const eval of indices
1 parent ff25291 commit 8ce7fdb

File tree

2 files changed

+67
-48
lines changed

2 files changed

+67
-48
lines changed

src/librustc/middle/const_eval.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,15 @@ fn const_uint_not(a: u64, opt_ety: Option<UintTy>) -> const_val {
522522
const_uint(!a & mask)
523523
}
524524

525+
pub fn eval_const_index(tcx: &ty::ctxt, idx: &Expr) -> Result<u64, ConstEvalErr> {
526+
match try!(eval_const_expr_partial(tcx, idx, None)) {
527+
const_int(i) if i >= 0 => Ok(i as u64),
528+
const_int(_) => signal!(idx, IndexNotNatural),
529+
const_uint(i) => Ok(i),
530+
_ => signal!(idx, IndexNotInt),
531+
}
532+
}
533+
525534
macro_rules! overflow_checking_body {
526535
($a:ident, $b:ident, $ety:ident, $overflowing_op:ident,
527536
lhs: $to_8_lhs:ident $to_16_lhs:ident $to_32_lhs:ident,
@@ -964,13 +973,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
964973
while let const_val::Ref(inner) = arr {
965974
arr = *inner;
966975
}
967-
let idx = try!(eval_const_expr_partial(tcx, idx, None));
968-
let idx = match idx {
969-
const_int(i) if i >= 0 => i as u64,
970-
const_int(_) => signal!(e, IndexNotNatural),
971-
const_uint(i) => i,
972-
_ => signal!(e, IndexNotInt),
973-
};
976+
let idx = try!(eval_const_index(tcx, idx));
974977
match arr {
975978
const_val::Array(_, n) if idx >= n => signal!(e, IndexOutOfBounds),
976979
const_val::Array(v, _) => if let ast::ExprVec(ref v) = tcx.map.expect_expr(v).node {

src/librustc_trans/trans/consts.rs

+57-41
Original file line numberDiff line numberDiff line change
@@ -609,14 +609,56 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
609609
})
610610
}
611611

612-
ast::ExprIndex(..) => {
613-
match const_eval::eval_const_expr_partial(cx.tcx(), &e, None) {
614-
Ok(val) => const_val_for_idx(cx, val, param_substs, ety),
615-
Err(err) => cx.sess().span_fatal(
616-
e.span,
617-
&format!("constant indexing failed: {}", err.description()),
618-
),
619-
}
612+
ast::ExprIndex(ref base, ref index) => {
613+
if let Ok(val) = const_eval::eval_const_expr_partial(cx.tcx(), &e, None) {
614+
const_val_for_idx(cx, val, param_substs, ety)
615+
} else {
616+
let (bv, bt) = const_expr(cx, &**base, param_substs);
617+
let iv = try!(eval_const_index(tcx, idx));
618+
let (arr, len) = match bt.sty {
619+
ty::ty_vec(_, Some(u)) => (bv, C_uint(cx, u)),
620+
ty::ty_vec(_, None) | ty::ty_str => {
621+
let e1 = const_get_elt(cx, bv, &[0]);
622+
(const_deref_ptr(cx, e1), const_get_elt(cx, bv, &[1]))
623+
}
624+
ty::ty_rptr(_, mt) => match mt.ty.sty {
625+
ty::ty_vec(_, Some(u)) => {
626+
(const_deref_ptr(cx, bv), C_uint(cx, u))
627+
},
628+
_ => cx.sess().span_bug(base.span,
629+
&format!("index-expr base must be a vector \
630+
or string type, found {}",
631+
ty_to_string(cx.tcx(), bt)))
632+
},
633+
_ => cx.sess().span_bug(base.span,
634+
&format!("index-expr base must be a vector \
635+
or string type, found {}",
636+
ty_to_string(cx.tcx(), bt)))
637+
};
638+
639+
let len = llvm::LLVMConstIntGetZExtValue(len) as u64;
640+
let len = match bt.sty {
641+
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty.sty {
642+
ty::ty_str => {
643+
assert!(len > 0);
644+
len - 1
645+
}
646+
_ => len
647+
},
648+
_ => len
649+
};
650+
if iv >= len {
651+
// FIXME #3170: report this earlier on in the const-eval
652+
// pass. Reporting here is a bit late.
653+
// Since some static-eval expressions aren't const-evaluable
654+
// this has to stay
655+
cx.sess().span_err(e.span,
656+
"const index-expr is out of bounds");
657+
C_undef(type_of::type_of(cx, bt).element_type())
658+
} else {
659+
const_get_elt(cx, arr, &[iv as c_uint])
660+
}
661+
}
620662
},
621663

622664
ast::ExprCast(ref base, _) => {
@@ -693,40 +735,14 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
693735
_ => break,
694736
}
695737
}
696-
if let ast::ExprIndex(ref base, ref index) = cur.node {
697-
let (bv, bt) = const_expr(cx, &**base, param_substs);
698-
let iv = match const_eval::eval_const_expr_partial(cx.tcx(), &**index, None) {
699-
Ok(const_eval::const_int(i)) => i as u64,
700-
Ok(const_eval::const_uint(u)) => u,
701-
_ => unreachable!(),
702-
};
703-
let arr = match bt.sty {
704-
ty::ty_vec(_, Some(_)) => bv,
705-
ty::ty_vec(_, None) | ty::ty_str => {
706-
let e1 = const_get_elt(cx, bv, &[0]);
707-
const_deref_ptr(cx, e1)
708-
},
709-
ty::ty_rptr(_, mt) => if let ty::ty_vec(_, Some(_)) = mt.ty.sty {
710-
const_deref_ptr(cx,bv)
711-
} else {
712-
unreachable!()
713-
},
714-
_ => unreachable!(),
715-
};
716-
// UB if const_eval wasn't called on this
717-
// since no len check happening here
718-
let v = const_get_elt(cx, arr, &[iv as c_uint]);
719-
addr_of(cx, v, "ref")
738+
let opt_def = cx.tcx().def_map.borrow().get(&cur.id).map(|d| d.full_def());
739+
if let Some(def::DefStatic(def_id, _)) = opt_def {
740+
get_static_val(cx, def_id, ety)
720741
} else {
721-
let opt_def = cx.tcx().def_map.borrow().get(&cur.id).map(|d| d.full_def());
722-
if let Some(def::DefStatic(def_id, _)) = opt_def {
723-
get_static_val(cx, def_id, ety)
724-
} else {
725-
// If this isn't the address of a static, then keep going through
726-
// normal constant evaluation.
727-
let (v, _) = const_expr(cx, &**sub, param_substs);
728-
addr_of(cx, v, "ref")
729-
}
742+
// If this isn't the address of a static, then keep going through
743+
// normal constant evaluation.
744+
let (v, _) = const_expr(cx, &**sub, param_substs);
745+
addr_of(cx, v, "ref")
730746
}
731747
}
732748
ast::ExprAddrOf(ast::MutMutable, ref sub) => {

0 commit comments

Comments
 (0)