diff options
| author | Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> | 2018-01-31 15:06:45 +0100 |
|---|---|---|
| committer | Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> | 2018-03-08 08:34:16 +0100 |
| commit | 8500c2fab2a7e93a4a918417c4f01d136247ef89 (patch) | |
| tree | 2d092b72bd2a799d21d0d6cf7d58f8902c1f9894 | |
| parent | bd03371f711adcb7724c939ea053f4090e87c16f (diff) | |
| download | rust-8500c2fab2a7e93a4a918417c4f01d136247ef89.tar.gz rust-8500c2fab2a7e93a4a918417c4f01d136247ef89.zip | |
Const eval error refactoring
| -rw-r--r-- | src/librustc/ich/impls_ty.rs | 1 | ||||
| -rw-r--r-- | src/librustc/middle/const_val.rs | 7 | ||||
| -rw-r--r-- | src/librustc/mir/interpret/error.rs | 5 | ||||
| -rw-r--r-- | src/librustc/ty/structural_impls.rs | 1 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/const_eval.rs | 92 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/eval_context.rs | 87 |
6 files changed, 109 insertions, 84 deletions
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index a398549f359..d5476f742c8 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -531,6 +531,7 @@ for ::mir::interpret::EvalError<'gcx> { TypeckError | DerefFunctionPointer | ExecuteMemory | + ReferencedConstant | OverflowingMath => {} MachineError(ref err) => err.hash_stable(hcx, hasher), FunctionPointerTyMismatch(a, b) => { diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index d6d23c5cad8..151cc9b1ce2 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -173,6 +173,13 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { { match *self.kind { ErrKind::TypeckError | ErrKind::CheckMatchError => return, + ErrKind::Miri(ref miri, _) => { + match miri.kind { + ::mir::interpret::EvalErrorKind::TypeckError | + ::mir::interpret::EvalErrorKind::Layout(_) => return, + _ => {}, + } + } _ => {} } self.struct_error(tcx, primary_span, primary_kind).emit(); diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 90d10df1515..bb27628fa9c 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -124,6 +124,9 @@ pub enum EvalErrorKind<'tcx> { UnimplementedTraitSelection, /// Abort in case type errors are reached TypeckError, + /// Cannot compute this constant because it depends on another one + /// which already produced an error + ReferencedConstant, } pub type EvalResult<'tcx, T = ()> = Result<T, EvalError<'tcx>>; @@ -245,6 +248,8 @@ impl<'tcx> Error for EvalError<'tcx> { "there were unresolved type arguments during trait selection", TypeckError => "encountered constants with type errors, stopping evaluation", + ReferencedConstant => + "referenced constant has errors", } } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index c1a4f5ef458..243e17ee5c7 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -689,6 +689,7 @@ impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> { PathNotFound(ref v) => PathNotFound(v.clone()), UnimplementedTraitSelection => UnimplementedTraitSelection, TypeckError => TypeckError, + ReferencedConstant => ReferencedConstant, }; Some(interpret::EvalError { kind: kind, diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index b141106aa60..a4100a9d28a 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -1,7 +1,6 @@ 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}; @@ -15,6 +14,7 @@ use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory}; 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>, @@ -236,7 +236,7 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator { 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(), @@ -333,15 +333,8 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator { 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 @@ -377,52 +370,47 @@ pub fn const_val_field<'a, 'tcx>( 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>( @@ -484,7 +472,7 @@ pub fn const_eval_provider<'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, }); } @@ -496,7 +484,7 @@ pub fn const_eval_provider<'a, 'tcx>( // 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, }); } @@ -512,6 +500,8 @@ pub fn const_eval_provider<'a, 'tcx>( 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, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 676f99ea6be..483649204fb 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -10,6 +10,7 @@ use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout}; 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::{ @@ -934,17 +935,28 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M 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 } => { @@ -1496,7 +1508,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M 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); @@ -1558,9 +1570,38 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M 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(); @@ -1618,28 +1659,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M ) }; 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 { |
