Skip to content

Commit

Permalink
Unify MIR assert messages and const eval errors
Browse files Browse the repository at this point in the history
  • Loading branch information
oli-obk committed Apr 30, 2018
1 parent 5f46e5c commit 01158ea
Show file tree
Hide file tree
Showing 16 changed files with 111 additions and 147 deletions.
21 changes: 0 additions & 21 deletions src/librustc/ich/impls_mir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,27 +227,6 @@ for mir::TerminatorKind<'gcx> {
}
}

impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
for mir::AssertMessage<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher);

match *self {
mir::AssertMessage::BoundsCheck { ref len, ref index } => {
len.hash_stable(hcx, hasher);
index.hash_stable(hcx, hasher);
}
mir::AssertMessage::Math(ref const_math_err) => {
const_math_err.hash_stable(hcx, hasher);
}
mir::AssertMessage::GeneratorResumedAfterReturn => (),
mir::AssertMessage::GeneratorResumedAfterPanic => (),
}
}
}

impl_stable_hash_for!(struct mir::Statement<'tcx> { source_info, kind });

impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
Expand Down
13 changes: 7 additions & 6 deletions src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -535,8 +535,8 @@ for ::mir::interpret::EvalError<'gcx> {
}
}

impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
for ::mir::interpret::EvalErrorKind<'gcx> {
impl<'a, 'gcx, O: HashStable<StableHashingContext<'a>>> HashStable<StableHashingContext<'a>>
for ::mir::interpret::EvalErrorKind<'gcx, O> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
Expand Down Expand Up @@ -578,6 +578,8 @@ for ::mir::interpret::EvalErrorKind<'gcx> {
OverflowNeg |
RemainderByZero |
DivisionByZero |
GeneratorResumedAfterReturn |
GeneratorResumedAfterPanic |
ReferencedConstant => {}
MachineError(ref err) => err.hash_stable(hcx, hasher),
FunctionPointerTyMismatch(a, b) => {
Expand All @@ -597,10 +599,9 @@ for ::mir::interpret::EvalErrorKind<'gcx> {
},
InvalidBoolOp(bop) => bop.hash_stable(hcx, hasher),
Unimplemented(ref s) => s.hash_stable(hcx, hasher),
ArrayIndexOutOfBounds(sp, a, b) => {
sp.hash_stable(hcx, hasher);
a.hash_stable(hcx, hasher);
b.hash_stable(hcx, hasher)
BoundsCheck { ref len, ref index } => {
len.hash_stable(hcx, hasher);
index.hash_stable(hcx, hasher)
},
Intrinsic(ref s) => s.hash_stable(hcx, hasher),
InvalidChar(c) => c.hash_stable(hcx, hasher),
Expand Down
39 changes: 25 additions & 14 deletions src/librustc/mir/interpret/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,16 @@ use super::{
MemoryPointer, Lock, AccessKind
};

use syntax::codemap::Span;
use backtrace::Backtrace;

#[derive(Debug, Clone)]
pub struct EvalError<'tcx> {
pub kind: EvalErrorKind<'tcx>,
pub kind: EvalErrorKind<'tcx, u64>,
pub backtrace: Option<Backtrace>,
}

impl<'tcx> From<EvalErrorKind<'tcx>> for EvalError<'tcx> {
fn from(kind: EvalErrorKind<'tcx>) -> Self {
impl<'tcx> From<EvalErrorKind<'tcx, u64>> for EvalError<'tcx> {
fn from(kind: EvalErrorKind<'tcx, u64>) -> Self {
let backtrace = match env::var("MIRI_BACKTRACE") {
Ok(ref val) if !val.is_empty() => Some(Backtrace::new_unresolved()),
_ => None
Expand All @@ -29,8 +28,10 @@ impl<'tcx> From<EvalErrorKind<'tcx>> for EvalError<'tcx> {
}
}

#[derive(Debug, Clone, RustcEncodable, RustcDecodable)]
pub enum EvalErrorKind<'tcx> {
pub type AssertMessage<'tcx> = EvalErrorKind<'tcx, mir::Operand<'tcx>>;

#[derive(Clone, RustcEncodable, RustcDecodable)]
pub enum EvalErrorKind<'tcx, O> {
/// This variant is used by machines to signal their own errors that do not
/// match an existing variant
MachineError(String),
Expand Down Expand Up @@ -58,7 +59,7 @@ pub enum EvalErrorKind<'tcx> {
Unimplemented(String),
DerefFunctionPointer,
ExecuteMemory,
ArrayIndexOutOfBounds(Span, u64, u64),
BoundsCheck { len: O, index: O },
Overflow(mir::BinOp),
OverflowNeg,
DivisionByZero,
Expand Down Expand Up @@ -121,11 +122,13 @@ pub enum EvalErrorKind<'tcx> {
/// Cannot compute this constant because it depends on another one
/// which already produced an error
ReferencedConstant,
GeneratorResumedAfterReturn,
GeneratorResumedAfterPanic,
}

pub type EvalResult<'tcx, T = ()> = Result<T, EvalError<'tcx>>;

impl<'tcx> EvalErrorKind<'tcx> {
impl<'tcx, O> EvalErrorKind<'tcx, O> {
pub fn description(&self) -> &str {
use self::EvalErrorKind::*;
match *self {
Expand Down Expand Up @@ -175,7 +178,7 @@ impl<'tcx> EvalErrorKind<'tcx> {
"tried to dereference a function pointer",
ExecuteMemory =>
"tried to treat a memory pointer as a function pointer",
ArrayIndexOutOfBounds(..) =>
BoundsCheck{..} =>
"array index out of bounds",
Intrinsic(..) =>
"intrinsic failed",
Expand Down Expand Up @@ -228,7 +231,7 @@ impl<'tcx> EvalErrorKind<'tcx> {
"the evaluated program panicked",
ReadFromReturnPointer =>
"tried to read from the return pointer",
EvalErrorKind::PathNotFound(_) =>
PathNotFound(_) =>
"a path could not be resolved, maybe the crate is not loaded",
UnimplementedTraitSelection =>
"there were unresolved type arguments during trait selection",
Expand All @@ -247,14 +250,22 @@ impl<'tcx> EvalErrorKind<'tcx> {
Overflow(op) => bug!("{:?} cannot overflow", op),
DivisionByZero => "attempt to divide by zero",
RemainderByZero => "attempt to calculate the remainder with a divisor of zero",
GeneratorResumedAfterReturn => "generator resumed after completion",
GeneratorResumedAfterPanic => "generator resumed after panicking",
}
}
}

impl<'tcx> fmt::Display for EvalError<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self.kind)
}
}

impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::EvalErrorKind::*;
match self.kind {
match *self {
PointerOutOfBounds { ptr, access, allocation_size } => {
write!(f, "{} at offset {}, outside bounds of allocation {} which has size {}",
if access { "memory access" } else { "pointer computed" },
Expand Down Expand Up @@ -282,8 +293,8 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
NoMirFor(ref func) => write!(f, "no mir for `{}`", func),
FunctionPointerTyMismatch(sig, got) =>
write!(f, "tried to call a function with sig {} through a function pointer of type {}", sig, got),
ArrayIndexOutOfBounds(span, len, index) =>
write!(f, "index out of bounds: the len is {} but the index is {} at {:?}", len, index, span),
BoundsCheck { ref len, ref index } =>
write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index),
ReallocatedWrongMemoryKind(ref old, ref new) =>
write!(f, "tried to reallocate memory from {} to {}", old, new),
DeallocatedWrongMemoryKind(ref old, ref new) =>
Expand All @@ -305,7 +316,7 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
write!(f, "{}", inner),
IncorrectAllocationInformation(size, size2, align, align2) =>
write!(f, "incorrect alloc info: expected size {} and align {}, got size {} and align {}", size, align, size2, align2),
_ => write!(f, "{}", self.kind.description()),
_ => write!(f, "{}", self.description()),
}
}
}
2 changes: 1 addition & 1 deletion src/librustc/mir/interpret/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ macro_rules! err {
mod error;
mod value;

pub use self::error::{EvalError, EvalResult, EvalErrorKind};
pub use self::error::{EvalError, EvalResult, EvalErrorKind, AssertMessage};

pub use self::value::{PrimVal, PrimValKind, Value, Pointer};

Expand Down
37 changes: 6 additions & 31 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ use syntax_pos::{Span, DUMMY_SP};
use rustc_apfloat::ieee::{Single, Double};
use rustc_apfloat::Float;

pub use mir::interpret::AssertMessage;

mod cache;
pub mod tcx;
pub mod visit;
Expand Down Expand Up @@ -1132,23 +1134,7 @@ impl<'tcx> TerminatorKind<'tcx> {
write!(fmt, "!")?;
}
write!(fmt, "{:?}, ", cond)?;

match *msg {
AssertMessage::BoundsCheck { ref len, ref index } => {
write!(fmt, "{:?}, {:?}, {:?}",
"index out of bounds: the len is {} but the index is {}",
len, index)?;
}
AssertMessage::Math(ref err) => {
write!(fmt, "{:?}", err.description())?;
}
AssertMessage::GeneratorResumedAfterReturn => {
write!(fmt, "{:?}", "generator resumed after completion")?;
}
AssertMessage::GeneratorResumedAfterPanic => {
write!(fmt, "{:?}", "generator resumed after panicking")?;
}
}
write!(fmt, "{:?}", msg)?;

write!(fmt, ")")
},
Expand Down Expand Up @@ -1205,17 +1191,6 @@ impl<'tcx> TerminatorKind<'tcx> {
}
}

#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum AssertMessage<'tcx> {
BoundsCheck {
len: Operand<'tcx>,
index: Operand<'tcx>
},
Math(EvalErrorKind<'tcx>),
GeneratorResumedAfterReturn,
GeneratorResumedAfterPanic,
}

///////////////////////////////////////////////////////////////////////////
// Statements

Expand Down Expand Up @@ -2281,8 +2256,8 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
}
},
Assert { ref cond, expected, ref msg, target, cleanup } => {
let msg = if let AssertMessage::BoundsCheck { ref len, ref index } = *msg {
AssertMessage::BoundsCheck {
let msg = if let EvalErrorKind::BoundsCheck { ref len, ref index } = *msg {
EvalErrorKind::BoundsCheck {
len: len.fold_with(folder),
index: index.fold_with(folder),
}
Expand Down Expand Up @@ -2331,7 +2306,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
},
Assert { ref cond, ref msg, .. } => {
if cond.visit_with(visitor) {
if let AssertMessage::BoundsCheck { ref len, ref index } = *msg {
if let EvalErrorKind::BoundsCheck { ref len, ref index } = *msg {
len.visit_with(visitor) || index.visit_with(visitor)
} else {
false
Expand Down
14 changes: 5 additions & 9 deletions src/librustc/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,17 +511,13 @@ macro_rules! make_mir_visitor {
fn super_assert_message(&mut self,
msg: & $($mutability)* AssertMessage<'tcx>,
location: Location) {
match *msg {
AssertMessage::BoundsCheck {
use mir::interpret::EvalErrorKind::*;
if let BoundsCheck {
ref $($mutability)* len,
ref $($mutability)* index
} => {
self.visit_operand(len, location);
self.visit_operand(index, location);
}
AssertMessage::Math(_) => {},
AssertMessage::GeneratorResumedAfterReturn => {},
AssertMessage::GeneratorResumedAfterPanic => {},
} = *msg {
self.visit_operand(len, location);
self.visit_operand(index, location);
}
}

Expand Down
23 changes: 17 additions & 6 deletions src/librustc/ty/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,9 +473,19 @@ impl<'a, 'tcx> Lift<'tcx> for ConstEvalErr<'a> {

impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> {
type Lifted = interpret::EvalError<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
Some(interpret::EvalError {
kind: tcx.lift(&self.kind)?,
backtrace: self.backtrace.clone(),
})
}
}

impl<'a, 'tcx, O: Lift<'tcx>> Lift<'tcx> for interpret::EvalErrorKind<'a, O> {
type Lifted = interpret::EvalErrorKind<'tcx, <O as Lift<'tcx>>::Lifted>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
use ::mir::interpret::EvalErrorKind::*;
let kind = match self.kind {
Some(match *self {
MachineError(ref err) => MachineError(err.clone()),
FunctionPointerTyMismatch(a, b) => FunctionPointerTyMismatch(
tcx.lift(&a)?,
Expand Down Expand Up @@ -504,7 +514,10 @@ impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> {
Unimplemented(ref s) => Unimplemented(s.clone()),
DerefFunctionPointer => DerefFunctionPointer,
ExecuteMemory => ExecuteMemory,
ArrayIndexOutOfBounds(sp, a, b) => ArrayIndexOutOfBounds(sp, a, b),
BoundsCheck { ref len, ref index } => BoundsCheck {
len: tcx.lift(len)?,
index: tcx.lift(index)?,
},
Intrinsic(ref s) => Intrinsic(s.clone()),
InvalidChar(c) => InvalidChar(c),
StackFrameLimitReached => StackFrameLimitReached,
Expand Down Expand Up @@ -570,10 +583,8 @@ impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> {
Overflow(op) => Overflow(op),
DivisionByZero => DivisionByZero,
RemainderByZero => RemainderByZero,
};
Some(interpret::EvalError {
kind: kind,
backtrace: self.backtrace.clone(),
GeneratorResumedAfterReturn => GeneratorResumedAfterReturn,
GeneratorResumedAfterPanic => GeneratorResumedAfterPanic,
})
}
}
Expand Down
22 changes: 9 additions & 13 deletions src/librustc_mir/borrow_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use rustc::infer::InferCtxt;
use rustc::ty::{self, ParamEnv, TyCtxt};
use rustc::ty::maps::Providers;
use rustc::lint::builtin::UNUSED_MUT;
use rustc::mir::{AssertMessage, AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
use rustc::mir::{ClearCrossCrate, Local, Location, Place, Mir, Mutability, Operand};
use rustc::mir::{Projection, ProjectionElem, Rvalue, Field, Statement, StatementKind};
use rustc::mir::{Terminator, TerminatorKind};
Expand Down Expand Up @@ -586,18 +586,14 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
cleanup: _,
} => {
self.consume_operand(ContextKind::Assert.new(loc), (cond, span), flow_state);
match *msg {
AssertMessage::BoundsCheck { ref len, ref index } => {
self.consume_operand(ContextKind::Assert.new(loc), (len, span), flow_state);
self.consume_operand(
ContextKind::Assert.new(loc),
(index, span),
flow_state,
);
}
AssertMessage::Math(_ /*const_math_err*/) => {}
AssertMessage::GeneratorResumedAfterReturn => {}
AssertMessage::GeneratorResumedAfterPanic => {}
use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
if let BoundsCheck { ref len, ref index } = *msg {
self.consume_operand(ContextKind::Assert.new(loc), (len, span), flow_state);
self.consume_operand(
ContextKind::Assert.new(loc),
(index, span),
flow_state,
);
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/librustc_mir/borrow_check/nll/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use rustc::infer::region_constraints::{GenericKind, RegionConstraintData};
use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
use rustc::mir::tcx::PlaceTy;
use rustc::mir::visit::{PlaceContext, Visitor};
use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
use rustc::mir::*;
use rustc::traits::query::NoSolution;
use rustc::traits::{self, Normalized, TraitEngine};
Expand Down Expand Up @@ -928,7 +929,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
}

if let AssertMessage::BoundsCheck { ref len, ref index } = *msg {
if let BoundsCheck { ref len, ref index } = *msg {
if len.ty(mir, tcx) != tcx.types.usize {
span_mirbug!(self, len, "bounds-check length non-usize {:?}", len)
}
Expand Down
Loading

0 comments on commit 01158ea

Please sign in to comment.