Unify MIR assert messages and const eval errors
This commit is contained in:
parent
5f46e5cc7e
commit
01158eaec6
16 changed files with 111 additions and 147 deletions
|
@ -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>>
|
||||
|
|
|
@ -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>) {
|
||||
|
@ -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) => {
|
||||
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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" },
|
||||
|
@ -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) =>
|
||||
|
@ -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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -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, ")")
|
||||
},
|
||||
|
@ -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
|
||||
|
||||
|
@ -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),
|
||||
}
|
||||
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)?,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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};
|
||||
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ use build::{BlockAnd, BlockAndExtension, Builder};
|
|||
use build::expr::category::Category;
|
||||
use hair::*;
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
|
||||
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
||||
|
@ -73,7 +74,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
Operand::Copy(Place::Local(idx)),
|
||||
Operand::Copy(len.clone())));
|
||||
|
||||
let msg = AssertMessage::BoundsCheck {
|
||||
let msg = BoundsCheck {
|
||||
len: Operand::Move(len),
|
||||
index: Operand::Copy(Place::Local(idx))
|
||||
};
|
||||
|
|
|
@ -85,9 +85,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
this.cfg.push_assign(block, source_info, &is_min,
|
||||
Rvalue::BinaryOp(BinOp::Eq, arg.to_copy(), minval));
|
||||
|
||||
let err = EvalErrorKind::OverflowNeg;
|
||||
block = this.assert(block, Operand::Move(is_min), false,
|
||||
AssertMessage::Math(err), expr_span);
|
||||
EvalErrorKind::OverflowNeg, expr_span);
|
||||
}
|
||||
block.and(Rvalue::UnaryOp(op, arg))
|
||||
}
|
||||
|
@ -313,7 +312,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
let err = EvalErrorKind::Overflow(op);
|
||||
|
||||
block = self.assert(block, Operand::Move(of), false,
|
||||
AssertMessage::Math(err), span);
|
||||
err, span);
|
||||
|
||||
block.and(Rvalue::Use(Operand::Move(val)))
|
||||
} else {
|
||||
|
@ -336,7 +335,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
Rvalue::BinaryOp(BinOp::Eq, rhs.to_copy(), zero));
|
||||
|
||||
block = self.assert(block, Operand::Move(is_zero), false,
|
||||
AssertMessage::Math(zero_err), span);
|
||||
zero_err, span);
|
||||
|
||||
// We only need to check for the overflow in one case:
|
||||
// MIN / -1, and only for signed values.
|
||||
|
@ -361,7 +360,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
Rvalue::BinaryOp(BinOp::BitAnd, is_neg_1, is_min));
|
||||
|
||||
block = self.assert(block, Operand::Move(of), false,
|
||||
AssertMessage::Math(overflow_err), span);
|
||||
overflow_err, span);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -148,21 +148,22 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
if expected == cond_val {
|
||||
self.goto_block(target);
|
||||
} else {
|
||||
use rustc::mir::AssertMessage::*;
|
||||
use rustc::mir::interpret::EvalErrorKind::*;
|
||||
return match *msg {
|
||||
BoundsCheck { ref len, ref index } => {
|
||||
let span = terminator.source_info.span;
|
||||
let len = self.eval_operand_to_primval(len)
|
||||
.expect("can't eval len")
|
||||
.to_u64()?;
|
||||
let index = self.eval_operand_to_primval(index)
|
||||
.expect("can't eval index")
|
||||
.to_u64()?;
|
||||
err!(ArrayIndexOutOfBounds(span, len, index))
|
||||
err!(BoundsCheck { len, index })
|
||||
}
|
||||
Math(ref err) => Err(err.clone().into()),
|
||||
Overflow(op) => Err(Overflow(op).into()),
|
||||
OverflowNeg => Err(OverflowNeg.into()),
|
||||
GeneratorResumedAfterReturn |
|
||||
GeneratorResumedAfterPanic => unimplemented!(),
|
||||
_ => bug!(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -478,12 +478,12 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
|
|||
.hir
|
||||
.as_local_node_id(self.source.def_id)
|
||||
.expect("some part of a failing const eval must be local");
|
||||
use rustc::mir::AssertMessage::*;
|
||||
use rustc::mir::interpret::EvalErrorKind::*;
|
||||
let msg = match msg {
|
||||
// Need proper const propagator for these
|
||||
GeneratorResumedAfterReturn |
|
||||
GeneratorResumedAfterPanic => return,
|
||||
Math(ref err) => err.description().to_owned(),
|
||||
Overflow(_) |
|
||||
OverflowNeg |
|
||||
DivisionByZero |
|
||||
RemainderByZero => msg.description().to_owned(),
|
||||
BoundsCheck { ref len, ref index } => {
|
||||
let len = self.eval_operand(len).expect("len must be const");
|
||||
let len = match len.0 {
|
||||
|
@ -504,6 +504,8 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
|
|||
index,
|
||||
)
|
||||
},
|
||||
// Need proper const propagator for these
|
||||
_ => return,
|
||||
};
|
||||
self.tcx.lint_node(
|
||||
::rustc::lint::builtin::CONST_ERR,
|
||||
|
|
|
@ -738,12 +738,17 @@ fn create_generator_resume_function<'a, 'tcx>(
|
|||
|
||||
let mut cases = create_cases(mir, &transform, |point| Some(point.resume));
|
||||
|
||||
use rustc::mir::interpret::EvalErrorKind::{
|
||||
GeneratorResumedAfterPanic,
|
||||
GeneratorResumedAfterReturn,
|
||||
};
|
||||
|
||||
// Jump to the entry point on the 0 state
|
||||
cases.insert(0, (0, BasicBlock::new(0)));
|
||||
// Panic when resumed on the returned (1) state
|
||||
cases.insert(1, (1, insert_panic_block(tcx, mir, AssertMessage::GeneratorResumedAfterReturn)));
|
||||
cases.insert(1, (1, insert_panic_block(tcx, mir, GeneratorResumedAfterReturn)));
|
||||
// Panic when resumed on the poisoned (2) state
|
||||
cases.insert(2, (2, insert_panic_block(tcx, mir, AssertMessage::GeneratorResumedAfterPanic)));
|
||||
cases.insert(2, (2, insert_panic_block(tcx, mir, GeneratorResumedAfterPanic)));
|
||||
|
||||
insert_switch(tcx, mir, cases, &transform, TerminatorKind::Unreachable);
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ use rustc::mir::{Place, PlaceElem, PlaceProjection};
|
|||
use rustc::mir::{Mir, Operand, ProjectionElem};
|
||||
use rustc::mir::{Rvalue, SourceInfo, Statement, StatementKind};
|
||||
use rustc::mir::{Terminator, TerminatorKind, VisibilityScope, VisibilityScopeData};
|
||||
use rustc::mir::interpret::EvalErrorKind;
|
||||
use rustc::mir::visit as mir_visit;
|
||||
use rustc::ty::{self, ClosureSubsts, TyCtxt};
|
||||
use rustc::util::nodemap::{FxHashMap};
|
||||
|
@ -133,14 +134,18 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
|
|||
location: Location) {
|
||||
self.record("AssertMessage", msg);
|
||||
self.record(match *msg {
|
||||
AssertMessage::BoundsCheck { .. } => "AssertMessage::BoundsCheck",
|
||||
AssertMessage::Math(..) => "AssertMessage::Math",
|
||||
AssertMessage::GeneratorResumedAfterReturn => {
|
||||
EvalErrorKind::BoundsCheck { .. } => "AssertMessage::BoundsCheck",
|
||||
EvalErrorKind::Overflow(..) => "AssertMessage::Overflow",
|
||||
EvalErrorKind::OverflowNeg => "AssertMessage::OverflowNeg",
|
||||
EvalErrorKind::DivisionByZero => "AssertMessage::DivisionByZero",
|
||||
EvalErrorKind::RemainderByZero => "AssertMessage::RemainderByZero",
|
||||
EvalErrorKind::GeneratorResumedAfterReturn => {
|
||||
"AssertMessage::GeneratorResumedAfterReturn"
|
||||
}
|
||||
AssertMessage::GeneratorResumedAfterPanic => {
|
||||
EvalErrorKind::GeneratorResumedAfterPanic => {
|
||||
"AssertMessage::GeneratorResumedAfterPanic"
|
||||
}
|
||||
_ => bug!(),
|
||||
}, msg);
|
||||
self.super_assert_message(msg, location);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ use rustc::middle::lang_items;
|
|||
use rustc::ty::{self, Ty, TypeFoldable};
|
||||
use rustc::ty::layout::{self, LayoutOf};
|
||||
use rustc::mir;
|
||||
use rustc::mir::interpret::EvalErrorKind;
|
||||
use abi::{Abi, ArgType, ArgTypeExt, FnType, FnTypeExt, LlvmType, PassMode};
|
||||
use base;
|
||||
use callee;
|
||||
|
@ -311,9 +312,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
|||
// checked operation, just a comparison with the minimum
|
||||
// value, so we have to check for the assert message.
|
||||
if !bx.cx.check_overflow {
|
||||
use rustc::mir::interpret::EvalErrorKind::OverflowNeg;
|
||||
|
||||
if let mir::AssertMessage::Math(OverflowNeg) = *msg {
|
||||
if let mir::interpret::EvalErrorKind::OverflowNeg = *msg {
|
||||
const_cond = Some(expected);
|
||||
}
|
||||
}
|
||||
|
@ -353,7 +352,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
|||
|
||||
// Put together the arguments to the panic entry point.
|
||||
let (lang_item, args) = match *msg {
|
||||
mir::AssertMessage::BoundsCheck { ref len, ref index } => {
|
||||
EvalErrorKind::BoundsCheck { ref len, ref index } => {
|
||||
let len = self.trans_operand(&mut bx, len).immediate();
|
||||
let index = self.trans_operand(&mut bx, index).immediate();
|
||||
|
||||
|
@ -365,26 +364,8 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
|||
(lang_items::PanicBoundsCheckFnLangItem,
|
||||
vec![file_line_col, index, len])
|
||||
}
|
||||
mir::AssertMessage::Math(ref err) => {
|
||||
let msg_str = Symbol::intern(err.description()).as_str();
|
||||
let msg_str = C_str_slice(bx.cx, msg_str);
|
||||
let msg_file_line_col = C_struct(bx.cx,
|
||||
&[msg_str, filename, line, col],
|
||||
false);
|
||||
let msg_file_line_col = consts::addr_of(bx.cx,
|
||||
msg_file_line_col,
|
||||
align,
|
||||
"panic_loc");
|
||||
(lang_items::PanicFnLangItem,
|
||||
vec![msg_file_line_col])
|
||||
}
|
||||
mir::AssertMessage::GeneratorResumedAfterReturn |
|
||||
mir::AssertMessage::GeneratorResumedAfterPanic => {
|
||||
let str = if let mir::AssertMessage::GeneratorResumedAfterReturn = *msg {
|
||||
"generator resumed after completion"
|
||||
} else {
|
||||
"generator resumed after panicking"
|
||||
};
|
||||
_ => {
|
||||
let str = msg.description();
|
||||
let msg_str = Symbol::intern(str).as_str();
|
||||
let msg_str = C_str_slice(bx.cx, msg_str);
|
||||
let msg_file_line_col = C_struct(bx.cx,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue