use rustc::hir;
use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind};
use rustc::middle::const_val::ErrKind::{TypeckError, CheckMatchError};
-use rustc::traits;
use rustc::mir;
use rustc::ty::{self, TyCtxt, Ty, Instance};
use rustc::ty::layout::{self, LayoutOf};
use std::fmt;
use std::error::Error;
+use std::rc::Rc;
pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
let mir = match ecx.load_mir(instance.def) {
Ok(mir) => mir,
Err(err) => {
- if let EvalErrorKind::NoMirFor(ref path) = *err.kind {
+ if let EvalErrorKind::NoMirFor(ref path) = err.kind {
return Err(
ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path))
.into(),
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
cid: GlobalId<'tcx>,
) -> EvalResult<'tcx, AllocId> {
- let param_env = ty::ParamEnv::empty(traits::Reveal::All);
// ensure the static is computed
- if let Err(err) = ecx.tcx.const_eval(param_env.and(cid)) {
- match err.kind {
- ErrKind::Miri(miri) => return Err(miri),
- ErrKind::TypeckError => return err!(TypeckError),
- other => bug!("const eval returned {:?}", other),
- }
- };
+ ecx.const_eval(cid)?;
Ok(ecx
.tcx
.interpret_interner
span: Span,
variant: Option<usize>,
field: mir::Field,
- val: Value,
+ value: Value,
ty: Ty<'tcx>,
) -> ::rustc::middle::const_val::EvalResult<'tcx> {
- match const_val_field_inner(tcx, param_env, instance, variant, field, val, ty) {
+ trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty);
+ let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
+ let result = (|| {
+ let (mut field, ty) = match value {
+ Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"),
+ Value::ByRef(ptr, align) => {
+ let place = Place::Ptr {
+ ptr,
+ align,
+ extra: variant.map_or(PlaceExtra::None, PlaceExtra::DowncastVariant),
+ };
+ let layout = ecx.layout_of(ty)?;
+ let (place, layout) = ecx.place_field(place, field, layout)?;
+ let (ptr, align) = place.to_ptr_align();
+ (Value::ByRef(ptr, align), layout.ty)
+ }
+ };
+ if let Value::ByRef(ptr, align) = field {
+ if let Some(val) = ecx.try_read_value(ptr, align, ty)? {
+ field = val;
+ }
+ }
+ Ok((field, ty))
+ })();
+ match result {
Ok((field, ty)) => Ok(tcx.mk_const(ty::Const {
val: ConstVal::Value(field),
ty,
})),
- Err(err) => Err(ConstEvalErr {
- span,
- kind: err.into(),
- }),
- }
-}
-
-fn const_val_field_inner<'a, 'tcx>(
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- instance: ty::Instance<'tcx>,
- variant: Option<usize>,
- field: mir::Field,
- value: Value,
- ty: Ty<'tcx>,
-) -> EvalResult<'tcx, (Value, Ty<'tcx>)> {
- trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty);
- let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
- let (mut field, ty) = match value {
- Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"),
- Value::ByRef(ptr, align) => {
- let place = Place::Ptr {
- ptr,
- align,
- extra: variant.map_or(PlaceExtra::None, PlaceExtra::DowncastVariant),
- };
- let layout = ecx.layout_of(ty)?;
- let (place, layout) = ecx.place_field(place, field, layout)?;
- let (ptr, align) = place.to_ptr_align();
- (Value::ByRef(ptr, align), layout.ty)
- }
- };
- if let Value::ByRef(ptr, align) = field {
- if let Some(val) = ecx.try_read_value(ptr, align, ty)? {
- field = val;
- }
+ Err(err) => {
+ let trace = ecx.generate_stacktrace(None);
+ let err = ErrKind::Miri(err, trace);
+ Err(ConstEvalErr {
+ kind: err.into(),
+ span,
+ })
+ },
}
- Ok((field, ty))
}
pub fn const_discr<'a, 'tcx>(
// Do match-check before building MIR
if tcx.check_match(def_id).is_err() {
return Err(ConstEvalErr {
- kind: CheckMatchError,
+ kind: Rc::new(CheckMatchError),
span,
});
}
// Do not continue into miri if typeck errors occurred; it will fail horribly
if tables.tainted_by_errors {
return Err(ConstEvalErr {
- kind: TypeckError,
+ kind: Rc::new(TypeckError),
span,
});
}
if tcx.is_static(def_id).is_some() {
ecx.report(&mut err, true, None);
}
+ let trace = ecx.generate_stacktrace(None);
+ let err = ErrKind::Miri(err, trace);
ConstEvalErr {
kind: err.into(),
span,
use rustc::ty::subst::{Subst, Substs};
use rustc::ty::{self, Ty, TyCtxt};
use rustc_data_structures::indexed_vec::Idx;
+use rustc::middle::const_val::FrameInfo;
use syntax::codemap::{self, DUMMY_SP, Span};
use syntax::ast::Mutability;
use rustc::mir::interpret::{
return Ok(Value::ByRef(ptr.into(), layout.align))
}
}
- let cv = match self.tcx.const_eval(self.param_env.and(gid)) {
- Ok(val) => val,
- Err(err) => match err.kind {
- ErrKind::Miri(miri) => return Err(miri),
- ErrKind::TypeckError => return err!(TypeckError),
- other => bug!("const eval returned {:?}", other),
- },
- };
+ let cv = self.const_eval(gid)?;
self.const_to_value(&cv.val, ty)
}
+ pub fn const_eval(&self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, &'tcx ty::Const<'tcx>> {
+ let param_env = if self.tcx.is_static(gid.instance.def_id()).is_some() {
+ use rustc::traits;
+ ty::ParamEnv::empty(traits::Reveal::All)
+ } else {
+ self.param_env
+ };
+ self.tcx.const_eval(param_env.and(gid)).map_err(|err| match *err.kind {
+ ErrKind::Miri(ref err, _) => match err.kind {
+ EvalErrorKind::TypeckError |
+ EvalErrorKind::Layout(_) => EvalErrorKind::TypeckError.into(),
+ _ => EvalErrorKind::ReferencedConstant.into(),
+ },
+ ErrKind::TypeckError => EvalErrorKind::TypeckError.into(),
+ ref other => bug!("const eval returned {:?}", other),
+ })
+ }
+
pub fn force_allocation(&mut self, place: Place) -> EvalResult<'tcx, Place> {
let new_place = match place {
Place::Local { frame, local } => {
match self.stack[frame].get_local(local) {
Err(err) => {
- if let EvalErrorKind::DeadLocal = *err.kind {
+ if let EvalErrorKind::DeadLocal = err.kind {
write!(msg, " is dead").unwrap();
} else {
panic!("Failed to access local: {:?}", err);
Ok(())
}
+ pub fn generate_stacktrace(&self, explicit_span: Option<Span>) -> Vec<FrameInfo> {
+ let mut last_span = None;
+ let mut frames = Vec::new();
+ // skip 1 because the last frame is just the environment of the constant
+ for &Frame { instance, span, .. } in self.stack().iter().skip(1).rev() {
+ // make sure we don't emit frames that are duplicates of the previous
+ if explicit_span == Some(span) {
+ last_span = Some(span);
+ continue;
+ }
+ if let Some(last) = last_span {
+ if last == span {
+ continue;
+ }
+ } else {
+ last_span = Some(span);
+ }
+ let location = if self.tcx.def_key(instance.def_id()).disambiguated_data.data == DefPathData::ClosureExpr {
+ "closure".to_owned()
+ } else {
+ instance.to_string()
+ };
+ frames.push(FrameInfo { span, location });
+ }
+ frames
+ }
+
pub fn report(&self, e: &mut EvalError, as_err: bool, explicit_span: Option<Span>) {
- if let EvalErrorKind::TypeckError = *e.kind {
- return;
+ match e.kind {
+ EvalErrorKind::Layout(_) |
+ EvalErrorKind::TypeckError => return,
+ _ => {},
}
if let Some(ref mut backtrace) = e.backtrace {
let mut trace_text = "\n\nAn error occurred in miri:\n".to_string();
)
};
err.span_label(span, e.to_string());
- let mut last_span = None;
- // skip 1 because the last frame is just the environment of the constant
- for &Frame { instance, span, .. } in self.stack().iter().skip(1).rev() {
- // make sure we don't emit frames that are duplicates of the previous
- if explicit_span == Some(span) {
- last_span = Some(span);
- continue;
- }
- if let Some(last) = last_span {
- if last == span {
- continue;
- }
- } else {
- last_span = Some(span);
- }
- if self.tcx.def_key(instance.def_id()).disambiguated_data.data ==
- DefPathData::ClosureExpr
- {
- err.span_note(span, "inside call to closure");
- continue;
- }
- err.span_note(span, &format!("inside call to {}", instance));
+ for FrameInfo { span, location } in self.generate_stacktrace(explicit_span) {
+ err.span_note(span, &format!("inside call to {}", location));
}
err.emit();
} else {