Skip to content

Commit

Permalink
remove Panic variant from InterpError
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Feb 13, 2020
1 parent 2e6eace commit 0633a0e
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 123 deletions.
22 changes: 15 additions & 7 deletions src/librustc/mir/interpret/error.rs
Expand Up @@ -139,7 +139,6 @@ impl<'tcx> ConstEvalErr<'tcx> {
lint_root: Option<hir::HirId>,
) -> Result<(), ErrorHandled> {
let must_error = match self.error {
InterpError::MachineStop(_) => bug!("CTFE does not stop"),
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
return Err(ErrorHandled::TooGeneric);
}
Expand All @@ -149,9 +148,18 @@ impl<'tcx> ConstEvalErr<'tcx> {
};
trace!("reporting const eval failure at {:?}", self.span);

let err_msg = match &self.error {
InterpError::MachineStop(msg) => {
// A custom error (`ConstEvalErrKind` in `librustc_mir/interp/const_eval/error.rs`).
// Should be turned into a string by now.
msg.downcast_ref::<String>().expect("invalid MachineStop payload").clone()
}
err => err.to_string(),
};

let add_span_labels = |err: &mut DiagnosticBuilder<'_>| {
if !must_error {
err.span_label(self.span, self.error.to_string());
err.span_label(self.span, err_msg.clone());
}
// Skip the last, which is just the environment of the constant. The stacktrace
// is sometimes empty because we create "fake" eval contexts in CTFE to do work
Expand Down Expand Up @@ -183,7 +191,7 @@ impl<'tcx> ConstEvalErr<'tcx> {
);
} else {
let mut err = if must_error {
struct_error(tcx, &self.error.to_string())
struct_error(tcx, &err_msg)
} else {
struct_error(tcx, message)
};
Expand Down Expand Up @@ -259,6 +267,9 @@ impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
}
}

/// Information about a panic.
///
/// FIXME: this is not actually an InterpError, and should probably be moved to another module.
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)]
pub enum PanicInfo<O> {
Panic { msg: Symbol, line: u32, col: u32, file: Symbol },
Expand Down Expand Up @@ -616,8 +627,6 @@ impl fmt::Debug for ResourceExhaustionInfo {
}

pub enum InterpError<'tcx> {
/// The program panicked.
Panic(PanicInfo<u64>),
/// The program caused undefined behavior.
UndefinedBehavior(UndefinedBehaviorInfo),
/// The program did something the interpreter does not support (some of these *might* be UB
Expand Down Expand Up @@ -650,8 +659,7 @@ impl fmt::Debug for InterpError<'_> {
InvalidProgram(ref msg) => write!(f, "{:?}", msg),
UndefinedBehavior(ref msg) => write!(f, "{:?}", msg),
ResourceExhaustion(ref msg) => write!(f, "{:?}", msg),
Panic(ref msg) => write!(f, "{:?}", msg),
MachineStop(_) => write!(f, "machine caused execution to stop"),
MachineStop(_) => bug!("unhandled MachineStop"),
}
}
}
14 changes: 0 additions & 14 deletions src/librustc/mir/interpret/mod.rs
Expand Up @@ -37,15 +37,6 @@ macro_rules! err_ub_format {
($($tt:tt)*) => { err_ub!(Ub(format!($($tt)*))) };
}

#[macro_export]
macro_rules! err_panic {
($($tt:tt)*) => {
$crate::mir::interpret::InterpError::Panic(
$crate::mir::interpret::PanicInfo::$($tt)*
)
};
}

#[macro_export]
macro_rules! err_exhaust {
($($tt:tt)*) => {
Expand Down Expand Up @@ -80,11 +71,6 @@ macro_rules! throw_ub_format {
($($tt:tt)*) => { throw_ub!(Ub(format!($($tt)*))) };
}

#[macro_export]
macro_rules! throw_panic {
($($tt:tt)*) => { return Err(err_panic!($($tt)*).into()) };
}

#[macro_export]
macro_rules! throw_exhaust {
($($tt:tt)*) => { return Err(err_exhaust!($($tt)*).into()) };
Expand Down
21 changes: 14 additions & 7 deletions src/librustc_mir/const_eval/error.rs
Expand Up @@ -2,32 +2,39 @@ use std::error::Error;
use std::fmt;

use super::InterpCx;
use crate::interpret::{ConstEvalErr, InterpErrorInfo, Machine};
use crate::interpret::{ConstEvalErr, InterpError, InterpErrorInfo, Machine, PanicInfo};

/// The CTFE machine has some custom error kinds.
#[derive(Clone, Debug)]
pub enum ConstEvalError {
pub enum ConstEvalErrKind {
NeedsRfc(String),
ConstAccessesStatic,
Panic(PanicInfo<u64>),
}

impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalError {
// The errors become `MachineStop` with plain strings when being raised.
// `ConstEvalErr` (in `librustc/mir/interpret/error.rs`) knows to
// handle these.
impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalErrKind {
fn into(self) -> InterpErrorInfo<'tcx> {
err_unsup!(Unsupported(self.to_string())).into()
InterpError::MachineStop(Box::new(self.to_string())).into()
}
}

impl fmt::Display for ConstEvalError {
impl fmt::Display for ConstEvalErrKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use self::ConstEvalError::*;
use self::ConstEvalErrKind::*;
match *self {
NeedsRfc(ref msg) => {
write!(f, "\"{}\" needs an rfc before being allowed inside constants", msg)
}
ConstAccessesStatic => write!(f, "constant accesses static"),
Panic(ref msg) => write!(f, "{:?}", msg),
}
}
}

impl Error for ConstEvalError {}
impl Error for ConstEvalErrKind {}

/// Turn an interpreter error into something to report to the user.
/// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace.
Expand Down
62 changes: 45 additions & 17 deletions src/librustc_mir/const_eval/machine.rs
Expand Up @@ -9,10 +9,11 @@ use std::hash::Hash;
use rustc_data_structures::fx::FxHashMap;

use rustc_span::source_map::Span;
use rustc_span::symbol::Symbol;

use crate::interpret::{
self, snapshot, AllocId, Allocation, AssertMessage, GlobalId, ImmTy, InterpCx, InterpResult,
Memory, MemoryKind, OpTy, PlaceTy, Pointer, Scalar,
Memory, MemoryKind, OpTy, PanicInfo, PlaceTy, Pointer, Scalar,
};

use super::error::*;
Expand Down Expand Up @@ -56,6 +57,32 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> {
self.dump_place(*dest);
return Ok(true);
}

/// "Intercept" a function call to a panic-related function
/// because we have something special to do for it.
/// Returns `true` if an intercept happened.
pub fn hook_panic_fn(
&mut self,
span: Span,
instance: ty::Instance<'tcx>,
args: &[OpTy<'tcx>],
) -> InterpResult<'tcx, bool> {
let def_id = instance.def_id();
if Some(def_id) == self.tcx.lang_items().panic_fn()
|| Some(def_id) == self.tcx.lang_items().begin_panic_fn()
{
// &'static str
assert!(args.len() == 1);

let msg_place = self.deref_operand(args[0])?;
let msg = Symbol::intern(self.read_str(msg_place)?);
let span = self.find_closest_untracked_caller_location().unwrap_or(span);
let (file, line, col) = self.location_triple_for_span(span);
Err(ConstEvalErrKind::Panic(PanicInfo::Panic { msg, file, line, col }).into())
} else {
Ok(false)
}
}
}

/// Number of steps until the detector even starts doing anything.
Expand Down Expand Up @@ -212,7 +239,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
Ok(body) => *body,
Err(err) => {
if let err_unsup!(NoMirFor(ref path)) = err.kind {
return Err(ConstEvalError::NeedsRfc(format!(
return Err(ConstEvalErrKind::NeedsRfc(format!(
"calling extern function `{}`",
path
))
Expand Down Expand Up @@ -246,7 +273,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
}
// An intrinsic that we do not support
let intrinsic_name = ecx.tcx.item_name(instance.def_id());
Err(ConstEvalError::NeedsRfc(format!("calling intrinsic `{}`", intrinsic_name)).into())
Err(ConstEvalErrKind::NeedsRfc(format!("calling intrinsic `{}`", intrinsic_name)).into())
}

fn assert_panic(
Expand All @@ -256,7 +283,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
_unwind: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
use rustc::mir::interpret::PanicInfo::*;
Err(match msg {
// Convert `PanicInfo<Operand>` to `PanicInfo<u64>`.
let err = match msg {
BoundsCheck { ref len, ref index } => {
let len = ecx
.read_immediate(ecx.eval_operand(len, None)?)
Expand All @@ -268,21 +296,21 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
.expect("can't eval index")
.to_scalar()?
.to_machine_usize(&*ecx)?;
err_panic!(BoundsCheck { len, index })
BoundsCheck { len, index }
}
Overflow(op) => err_panic!(Overflow(*op)),
OverflowNeg => err_panic!(OverflowNeg),
DivisionByZero => err_panic!(DivisionByZero),
RemainderByZero => err_panic!(RemainderByZero),
ResumedAfterReturn(generator_kind) => err_panic!(ResumedAfterReturn(*generator_kind)),
ResumedAfterPanic(generator_kind) => err_panic!(ResumedAfterPanic(*generator_kind)),
Overflow(op) => Overflow(*op),
OverflowNeg => OverflowNeg,
DivisionByZero => DivisionByZero,
RemainderByZero => RemainderByZero,
ResumedAfterReturn(generator_kind) => ResumedAfterReturn(*generator_kind),
ResumedAfterPanic(generator_kind) => ResumedAfterPanic(*generator_kind),
Panic { .. } => bug!("`Panic` variant cannot occur in MIR"),
}
.into())
};
Err(ConstEvalErrKind::Panic(err).into())
}

fn ptr_to_int(_mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx, u64> {
Err(ConstEvalError::NeedsRfc("pointer-to-integer cast".to_string()).into())
Err(ConstEvalErrKind::NeedsRfc("pointer-to-integer cast".to_string()).into())
}

fn binary_ptr_op(
Expand All @@ -291,7 +319,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
_left: ImmTy<'tcx>,
_right: ImmTy<'tcx>,
) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
Err(ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into())
Err(ConstEvalErrKind::NeedsRfc("pointer arithmetic or comparison".to_string()).into())
}

fn find_foreign_static(
Expand Down Expand Up @@ -321,7 +349,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
_dest: PlaceTy<'tcx>,
) -> InterpResult<'tcx> {
Err(ConstEvalError::NeedsRfc("heap allocations via `box` keyword".to_string()).into())
Err(ConstEvalErrKind::NeedsRfc("heap allocations via `box` keyword".to_string()).into())
}

fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
Expand Down Expand Up @@ -355,7 +383,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
if memory_extra.can_access_statics {
Ok(())
} else {
Err(ConstEvalError::ConstAccessesStatic.into())
Err(ConstEvalErrKind::ConstAccessesStatic.into())
}
}
}
Expand Down
26 changes: 0 additions & 26 deletions src/librustc_mir/interpret/intrinsics.rs
Expand Up @@ -376,32 +376,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Ok(true)
}

/// "Intercept" a function call to a panic-related function
/// because we have something special to do for it.
/// Returns `true` if an intercept happened.
pub fn hook_panic_fn(
&mut self,
span: Span,
instance: ty::Instance<'tcx>,
args: &[OpTy<'tcx, M::PointerTag>],
) -> InterpResult<'tcx, bool> {
let def_id = instance.def_id();
if Some(def_id) == self.tcx.lang_items().panic_fn()
|| Some(def_id) == self.tcx.lang_items().begin_panic_fn()
{
// &'static str
assert!(args.len() == 1);

let msg_place = self.deref_operand(args[0])?;
let msg = Symbol::intern(self.read_str(msg_place)?);
let span = self.find_closest_untracked_caller_location().unwrap_or(span);
let (file, line, col) = self.location_triple_for_span(span);
throw_panic!(Panic { msg, file, line, col })
} else {
return Ok(false);
}
}

pub fn exact_div(
&mut self,
a: ImmTy<'tcx, M::PointerTag>,
Expand Down
12 changes: 6 additions & 6 deletions src/librustc_mir/interpret/intrinsics/caller_location.rs
Expand Up @@ -54,12 +54,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
location
}

pub fn alloc_caller_location_for_span(&mut self, span: Span) -> MPlaceTy<'tcx, M::PointerTag> {
let (file, line, column) = self.location_triple_for_span(span);
self.alloc_caller_location(file, line, column)
}

pub(super) fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) {
crate fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) {
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo());
(
Expand All @@ -68,4 +63,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
caller.col_display as u32 + 1,
)
}

pub fn alloc_caller_location_for_span(&mut self, span: Span) -> MPlaceTy<'tcx, M::PointerTag> {
let (file, line, column) = self.location_triple_for_span(span);
self.alloc_caller_location(file, line, column)
}
}

0 comments on commit 0633a0e

Please sign in to comment.