#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct ConstEvalErr<'tcx> {
pub span: Span,
- pub error: crate::mir::interpret::InterpError<'tcx, u64>,
+ pub error: crate::mir::interpret::InterpError<'tcx>,
pub stacktrace: Vec<FrameInfo<'tcx>>,
}
/// macro for this.
#[derive(Debug, Clone)]
pub struct InterpErrorInfo<'tcx> {
- pub kind: InterpError<'tcx, u64>,
+ pub kind: InterpError<'tcx>,
backtrace: Option<Box<Backtrace>>,
}
+
+impl<'tcx> fmt::Display for InterpErrorInfo<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", self.kind)
+ }
+}
+
impl<'tcx> InterpErrorInfo<'tcx> {
pub fn print_backtrace(&mut self) {
if let Some(ref mut backtrace) = self.backtrace {
eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace);
}
-impl<'tcx> From<InterpError<'tcx, u64>> for InterpErrorInfo<'tcx> {
- fn from(kind: InterpError<'tcx, u64>) -> Self {
+impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
+ fn from(kind: InterpError<'tcx>) -> Self {
let backtrace = match env::var("RUST_CTFE_BACKTRACE") {
// Matching `RUST_BACKTRACE` -- we treat "0" the same as "not present".
Ok(ref val) if val != "0" => {
}
}
-pub type AssertMessage<'tcx> = InterpError<'tcx, mir::Operand<'tcx>>;
-
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
pub enum PanicMessage<O> {
Panic {
OverflowNeg,
DivisionByZero,
RemainderByZero,
+ GeneratorResumedAfterReturn,
+ GeneratorResumedAfterPanic,
+}
+
+/// Type for MIR `Assert` terminator error messages.
+pub type AssertMessage<'tcx> = PanicMessage<mir::Operand<'tcx>>;
+
+impl<O> PanicMessage<O> {
+ /// Getting a description does not require `O` to be printable, and does not
+ /// require allocation.
+ /// The caller is expected to handle `Panic` and `BoundsCheck` separately.
+ pub fn description(&self) -> &'static str {
+ use PanicMessage::*;
+ match self {
+ Overflow(mir::BinOp::Add) =>
+ "attempt to add with overflow",
+ Overflow(mir::BinOp::Sub) =>
+ "attempt to subtract with overflow",
+ Overflow(mir::BinOp::Mul) =>
+ "attempt to multiply with overflow",
+ Overflow(mir::BinOp::Div) =>
+ "attempt to divide with overflow",
+ Overflow(mir::BinOp::Rem) =>
+ "attempt to calculate the remainder with overflow",
+ OverflowNeg =>
+ "attempt to negate with overflow",
+ Overflow(mir::BinOp::Shr) =>
+ "attempt to shift right with overflow",
+ Overflow(mir::BinOp::Shl) =>
+ "attempt to shift left with overflow",
+ 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",
+ Panic { .. } | BoundsCheck { .. } =>
+ bug!("Unexpected PanicMessage"),
+ }
+ }
+}
+
+impl<O: fmt::Debug> fmt::Debug for PanicMessage<O> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ use PanicMessage::*;
+ match self {
+ Panic { ref msg, line, col, ref file } =>
+ write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
+ BoundsCheck { ref len, ref index } =>
+ write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index),
+ _ =>
+ write!(f, "{}", self.description()),
+ }
+ }
}
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
-pub enum InterpError<'tcx, O> {
+pub enum InterpError<'tcx> {
/// This variant is used by machines to signal their own errors that do not
/// match an existing variant.
MachineError(String),
HeapAllocZeroBytes,
HeapAllocNonPowerOfTwoAlignment(u64),
Unreachable,
- Panic(PanicMessage<O>),
+ Panic(PanicMessage<u64>),
ReadFromReturnPointer,
PathNotFound(Vec<String>),
UnimplementedTraitSelection,
/// Cannot compute this constant because it depends on another one
/// which already produced an error
ReferencedConstant,
- GeneratorResumedAfterReturn,
- GeneratorResumedAfterPanic,
InfiniteLoop,
}
pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>;
-impl<'tcx> fmt::Display for InterpErrorInfo<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{}", self.kind)
- }
-}
-
-impl<'tcx> fmt::Display for InterpError<'tcx, u64> {
+impl<'tcx> fmt::Display for InterpError<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // Forward `Display` to `Debug`
write!(f, "{:?}", self)
}
}
-impl<'tcx, O: fmt::Debug> fmt::Debug for InterpError<'tcx, O> {
+impl<'tcx> fmt::Debug for InterpError<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- use self::InterpError::*;
+ use InterpError::*;
match *self {
PointerOutOfBounds { ptr, msg, allocation_size } => {
write!(f, "{} failed: pointer must be in-bounds at offset {}, \
write!(f, "encountered overly generic constant"),
ReferencedConstant =>
write!(f, "referenced constant has errors"),
- GeneratorResumedAfterReturn =>
- write!(f, "generator resumed after completion"),
- GeneratorResumedAfterPanic =>
- write!(f, "generator resumed after panicking"),
InfiniteLoop =>
write!(f, "duplicate interpreter state observed here, const evaluation will never \
terminate"),
AbiViolation(ref msg) |
Intrinsic(ref msg) =>
write!(f, "{}", msg),
-
- Panic(PanicMessage::Panic { ref msg, line, col, ref file }) =>
- write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
- Panic(PanicMessage::BoundsCheck { ref len, ref index }) =>
- write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index),
- Panic(PanicMessage::Overflow(mir::BinOp::Add)) =>
- write!(f, "attempt to add with overflow"),
- Panic(PanicMessage::Overflow(mir::BinOp::Sub)) =>
- write!(f, "attempt to subtract with overflow"),
- Panic(PanicMessage::Overflow(mir::BinOp::Mul)) =>
- write!(f, "attempt to multiply with overflow"),
- Panic(PanicMessage::Overflow(mir::BinOp::Div)) =>
- write!(f, "attempt to divide with overflow"),
- Panic(PanicMessage::Overflow(mir::BinOp::Rem)) =>
- write!(f, "attempt to calculate the remainder with overflow"),
- Panic(PanicMessage::OverflowNeg) =>
- write!(f, "attempt to negate with overflow"),
- Panic(PanicMessage::Overflow(mir::BinOp::Shr)) =>
- write!(f, "attempt to shift right with overflow"),
- Panic(PanicMessage::Overflow(mir::BinOp::Shl)) =>
- write!(f, "attempt to shift left with overflow"),
- Panic(PanicMessage::Overflow(op)) =>
- bug!("{:?} cannot overflow", op),
- Panic(PanicMessage::DivisionByZero) =>
- write!(f, "attempt to divide by zero"),
- Panic(PanicMessage::RemainderByZero) =>
- write!(f, "attempt to calculate the remainder with a divisor of zero"),
+ Panic(ref msg) =>
+ write!(f, "{:?}", msg),
}
}
}
use crate::hir::def::{CtorKind, Namespace};
use crate::hir::def_id::DefId;
use crate::hir::{self, InlineAsm as HirInlineAsm};
-use crate::mir::interpret::{ConstValue, PanicMessage, InterpError::Panic, Scalar};
+use crate::mir::interpret::{ConstValue, PanicMessage, Scalar};
use crate::mir::visit::MirVisitable;
use crate::rustc_serialize as serialize;
use crate::ty::adjustment::PointerCast;
}
}
Assert { ref cond, expected, ref msg, target, cleanup } => {
- let msg = if let Panic(PanicMessage::BoundsCheck { ref len, ref index }) = *msg {
- Panic(PanicMessage::BoundsCheck {
- len: len.fold_with(folder),
- index: index.fold_with(folder),
- })
- } else {
- msg.clone()
+ use PanicMessage::*;
+ let msg = match msg {
+ BoundsCheck { ref len, ref index } =>
+ BoundsCheck {
+ len: len.fold_with(folder),
+ index: index.fold_with(folder),
+ },
+ Panic { .. } | Overflow(_) | OverflowNeg | DivisionByZero | RemainderByZero |
+ GeneratorResumedAfterReturn | GeneratorResumedAfterPanic =>
+ msg.clone(),
};
Assert { cond: cond.fold_with(folder), expected, msg, target, cleanup }
}
}
Assert { ref cond, ref msg, .. } => {
if cond.visit_with(visitor) {
- if let Panic(PanicMessage::BoundsCheck { ref len, ref index }) = *msg {
- len.visit_with(visitor) || index.visit_with(visitor)
- } else {
- false
+ use PanicMessage::*;
+ match msg {
+ BoundsCheck { ref len, ref index } =>
+ len.visit_with(visitor) || index.visit_with(visitor),
+ Panic { .. } | Overflow(_) | OverflowNeg |
+ DivisionByZero | RemainderByZero |
+ GeneratorResumedAfterReturn | GeneratorResumedAfterPanic =>
+ false
}
} else {
false
fn super_assert_message(&mut self,
msg: & $($mutability)? AssertMessage<'tcx>,
location: Location) {
- use crate::mir::interpret::InterpError::*;
- use crate::mir::interpret::PanicMessage::BoundsCheck;
- if let Panic(BoundsCheck { len, index }) = msg {
- self.visit_operand(len, location);
- self.visit_operand(index, location);
+ use crate::mir::interpret::PanicMessage::*;
+ match msg {
+ BoundsCheck { len, index } => {
+ self.visit_operand(len, location);
+ self.visit_operand(index, location);
+ }
+ Panic { .. } | Overflow(_) | OverflowNeg | DivisionByZero | RemainderByZero |
+ GeneratorResumedAfterReturn | GeneratorResumedAfterPanic => {
+ // Nothing to visit
+ }
}
}
// checked operation, just a comparison with the minimum
// value, so we have to check for the assert message.
if !bx.check_overflow() {
- if let InterpError::Panic(PanicMessage::OverflowNeg) = *msg {
+ if let PanicMessage::OverflowNeg = *msg {
const_cond = Some(expected);
}
}
let col = bx.const_u32(loc.col.to_usize() as u32 + 1);
// Put together the arguments to the panic entry point.
- let (lang_item, args) = match *msg {
- InterpError::Panic(PanicMessage::BoundsCheck { ref len, ref index }) => {
+ let (lang_item, args) = match msg {
+ PanicMessage::BoundsCheck { ref len, ref index } => {
let len = self.codegen_operand(&mut bx, len).immediate();
let index = self.codegen_operand(&mut bx, index).immediate();
vec![file_line_col, index, len])
}
_ => {
- let str = format!("{:?}", msg);
- let msg_str = LocalInternedString::intern(&str);
+ let str = msg.description();
+ let msg_str = LocalInternedString::intern(str);
let msg_file_line_col = bx.static_panic_msg(
Some(msg_str),
filename,
cleanup: _,
} => {
self.consume_operand(loc, (cond, span), flow_state);
- use rustc::mir::interpret::{InterpError::Panic, PanicMessage};
- if let Panic(PanicMessage::BoundsCheck { ref len, ref index }) = *msg {
+ use rustc::mir::interpret::PanicMessage;
+ if let PanicMessage::BoundsCheck { ref len, ref index } = *msg {
self.consume_operand(loc, (len, span), flow_state);
self.consume_operand(loc, (index, span), flow_state);
}
cleanup: _,
} => {
self.consume_operand(location, cond);
- use rustc::mir::interpret::{InterpError::Panic, PanicMessage::BoundsCheck};
- if let Panic(BoundsCheck { ref len, ref index }) = *msg {
+ use rustc::mir::interpret::PanicMessage;
+ if let PanicMessage::BoundsCheck { ref len, ref index } = *msg {
self.consume_operand(location, len);
self.consume_operand(location, index);
}
use rustc::infer::outlives::env::RegionBoundPairs;
use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin};
use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc::mir::interpret::{InterpError::Panic, ConstValue, PanicMessage};
+use rustc::mir::interpret::{ConstValue, PanicMessage};
use rustc::mir::tcx::PlaceTy;
use rustc::mir::visit::{PlaceContext, Visitor, NonMutatingUseContext};
use rustc::mir::*;
span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
}
- if let Panic(PanicMessage::BoundsCheck { ref len, ref index }) = *msg {
+ if let PanicMessage::BoundsCheck { ref len, ref index } = *msg {
if len.ty(body, tcx) != tcx.types.usize {
span_mirbug!(self, len, "bounds-check length non-usize {:?}", len)
}
use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
use crate::build::{BlockAnd, BlockAndExtension, Builder};
use crate::hair::*;
-use rustc::mir::interpret::{InterpError::Panic, PanicMessage::BoundsCheck};
+use rustc::mir::interpret::{PanicMessage::BoundsCheck};
use rustc::mir::*;
use rustc::ty::{CanonicalUserTypeAnnotation, Variance};
),
);
- let msg = Panic(BoundsCheck {
+ let msg = BoundsCheck {
len: Operand::Move(len),
index: Operand::Copy(Place::from(idx)),
- });
+ };
let success = this.assert(block, Operand::Move(lt), true, msg, expr_span);
success.and(slice.index(idx))
}
use crate::build::{BlockAnd, BlockAndExtension, Builder};
use crate::hair::*;
use rustc::middle::region;
-use rustc::mir::interpret::{InterpError::Panic, PanicMessage};
+use rustc::mir::interpret::PanicMessage;
use rustc::mir::*;
use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty, UpvarSubsts};
use syntax_pos::Span;
block,
Operand::Move(is_min),
false,
- Panic(PanicMessage::OverflowNeg),
+ PanicMessage::OverflowNeg,
expr_span,
);
}
let val = result_value.clone().field(val_fld, ty);
let of = result_value.field(of_fld, bool_ty);
- let err = Panic(PanicMessage::Overflow(op));
+ let err = PanicMessage::Overflow(op);
block = self.assert(block, Operand::Move(of), false, err, span);
// Checking division and remainder is more complex, since we 1. always check
// and 2. there are two possible failure cases, divide-by-zero and overflow.
- let (zero_err, overflow_err) = if op == BinOp::Div {
- (Panic(PanicMessage::DivisionByZero), Panic(PanicMessage::Overflow(op)))
+ let zero_err = if op == BinOp::Div {
+ PanicMessage::DivisionByZero
} else {
- (Panic(PanicMessage::RemainderByZero), Panic(PanicMessage::Overflow(op)))
+ PanicMessage::RemainderByZero
};
+ let overflow_err = PanicMessage::Overflow(op);
// Check for / 0
let is_zero = self.temp(bool_ty, span);
use rustc_target::spec::abi::Abi;
use super::{
- InterpResult, PointerArithmetic, InterpError, Scalar, PanicMessage,
+ InterpResult, PointerArithmetic, InterpError, Scalar,
InterpCx, Machine, Immediate, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal,
};
self.goto_block(Some(target))?;
} else {
// Compute error message
- use rustc::mir::interpret::InterpError::*;
- return match *msg {
- Panic(PanicMessage::BoundsCheck { ref len, ref index }) => {
+ use rustc::mir::interpret::PanicMessage::*;
+ return match msg {
+ BoundsCheck { ref len, ref index } => {
let len = self.read_immediate(self.eval_operand(len, None)?)
.expect("can't eval len").to_scalar()?
.to_bits(self.memory().pointer_size())? as u64;
let index = self.read_immediate(self.eval_operand(index, None)?)
.expect("can't eval index").to_scalar()?
.to_bits(self.memory().pointer_size())? as u64;
- err!(Panic(PanicMessage::BoundsCheck { len, index }))
+ err!(Panic(BoundsCheck { len, index }))
}
- Panic(PanicMessage::Overflow(op)) =>
- Err(Panic(PanicMessage::Overflow(op)).into()),
- Panic(PanicMessage::OverflowNeg) =>
- Err(Panic(PanicMessage::OverflowNeg).into()),
- Panic(PanicMessage::DivisionByZero) =>
- Err(Panic(PanicMessage::DivisionByZero).into()),
- Panic(PanicMessage::RemainderByZero) =>
- Err(Panic(PanicMessage::RemainderByZero).into()),
- GeneratorResumedAfterReturn |
- GeneratorResumedAfterPanic => unimplemented!(),
- _ => bug!(),
+ Overflow(op) =>
+ err!(Panic(Overflow(*op))),
+ OverflowNeg =>
+ err!(Panic(OverflowNeg)),
+ DivisionByZero =>
+ err!(Panic(DivisionByZero)),
+ RemainderByZero =>
+ err!(Panic(RemainderByZero)),
+ GeneratorResumedAfterReturn =>
+ err!(Panic(GeneratorResumedAfterReturn)),
+ GeneratorResumedAfterPanic =>
+ err!(Panic(GeneratorResumedAfterPanic)),
+ Panic { .. } =>
+ bug!("`Panic` variant cannot occur in MIR"),
};
}
}
use rustc::mir::visit::{
Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext,
};
-use rustc::mir::interpret::{InterpError::Panic, Scalar, GlobalId, InterpResult, PanicMessage};
+use rustc::mir::interpret::{Scalar, GlobalId, InterpResult, InterpError, PanicMessage};
use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
use syntax_pos::{Span, DUMMY_SP};
use rustc::ty::subst::InternalSubsts;
| HeapAllocNonPowerOfTwoAlignment(_)
| Unreachable
| ReadFromReturnPointer
- | GeneratorResumedAfterReturn
- | GeneratorResumedAfterPanic
| ReferencedConstant
| InfiniteLoop
=> {
)
} else {
if overflow {
- let err = Panic(PanicMessage::Overflow(op)).into();
+ let err = InterpError::Panic(PanicMessage::Overflow(op)).into();
let _: Option<()> = self.use_ecx(source_info, |_| Err(err));
return None;
}
.hir()
.as_local_hir_id(self.source.def_id())
.expect("some part of a failing const eval must be local");
- use rustc::mir::interpret::InterpError::*;
let msg = match msg {
- Panic(PanicMessage::Overflow(_)) |
- Panic(PanicMessage::OverflowNeg) |
- Panic(PanicMessage::DivisionByZero) |
- Panic(PanicMessage::RemainderByZero) =>
- format!("{:?}", msg),
- Panic(PanicMessage::BoundsCheck { ref len, ref index }) => {
+ PanicMessage::Overflow(_) |
+ PanicMessage::OverflowNeg |
+ PanicMessage::DivisionByZero |
+ PanicMessage::RemainderByZero =>
+ msg.description().to_owned(),
+ PanicMessage::BoundsCheck { ref len, ref index } => {
let len = self
.eval_operand(len, source_info)
.expect("len must be const");
let mut cases = create_cases(body, &transform, |point| Some(point.resume));
- use rustc::mir::interpret::InterpError::{
+ use rustc::mir::interpret::PanicMessage::{
GeneratorResumedAfterPanic,
GeneratorResumedAfterReturn,
};