Rollup merge of #70267 - RalfJung:const-prop-unsup, r=oli-obk,wesleywiser

get rid of ConstPropUnsupported; use ZST marker structs instead

This gets rid of yet another machine-specific error variant.

r? @oli-obk
This commit is contained in:
Mazdak Farrokhzad 2020-03-24 00:49:46 +01:00 committed by GitHub
commit 31845068cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 56 additions and 23 deletions

View File

@ -164,7 +164,7 @@ impl dyn Any {
// Get `TypeId` of the type this function is instantiated with.
let t = TypeId::of::<T>();
// Get `TypeId` of the type in the trait object.
// Get `TypeId` of the type in the trait object (`self`).
let concrete = self.type_id();
// Compare both `TypeId`s on equality.

View File

@ -14,7 +14,7 @@ use rustc_hir as hir;
use rustc_macros::HashStable;
use rustc_session::CtfeBacktrace;
use rustc_span::{def_id::DefId, Pos, Span};
use std::{any::Any, fmt};
use std::{any::Any, fmt, mem};
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable)]
pub enum ErrorHandled {
@ -449,9 +449,6 @@ impl fmt::Debug for UndefinedBehaviorInfo {
pub enum UnsupportedOpInfo {
/// Free-form case. Only for errors that are never caught!
Unsupported(String),
/// When const-prop encounters a situation it does not support, it raises this error.
/// This must not allocate for performance reasons (hence `str`, not `String`).
ConstPropUnsupported(&'static str),
/// Accessing an unsupported foreign static.
ReadForeignStatic(DefId),
/// Could not find MIR for a function.
@ -470,9 +467,6 @@ impl fmt::Debug for UnsupportedOpInfo {
use UnsupportedOpInfo::*;
match self {
Unsupported(ref msg) => write!(f, "{}", msg),
ConstPropUnsupported(ref msg) => {
write!(f, "Constant propagation encountered an unsupported situation: {}", msg)
}
ReadForeignStatic(did) => {
write!(f, "tried to read from foreign (extern) static {:?}", did)
}
@ -514,6 +508,29 @@ impl fmt::Debug for ResourceExhaustionInfo {
}
}
/// A trait to work around not having trait object upcasting.
pub trait AsAny: Any {
fn as_any(&self) -> &dyn Any;
}
impl<T: Any> AsAny for T {
#[inline(always)]
fn as_any(&self) -> &dyn Any {
self
}
}
/// A trait for machine-specific errors (or other "machine stop" conditions).
pub trait MachineStopType: AsAny + fmt::Debug + Send {}
impl MachineStopType for String {}
impl dyn MachineStopType {
#[inline(always)]
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
self.as_any().downcast_ref()
}
}
pub enum InterpError<'tcx> {
/// The program caused undefined behavior.
UndefinedBehavior(UndefinedBehaviorInfo),
@ -527,7 +544,7 @@ pub enum InterpError<'tcx> {
ResourceExhaustion(ResourceExhaustionInfo),
/// Stop execution for a machine-controlled reason. This is never raised by
/// the core engine itself.
MachineStop(Box<dyn Any + Send>),
MachineStop(Box<dyn MachineStopType>),
}
pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>;
@ -547,7 +564,7 @@ impl fmt::Debug for InterpError<'_> {
InvalidProgram(ref msg) => write!(f, "{:?}", msg),
UndefinedBehavior(ref msg) => write!(f, "{:?}", msg),
ResourceExhaustion(ref msg) => write!(f, "{:?}", msg),
MachineStop(_) => bug!("unhandled MachineStop"),
MachineStop(ref msg) => write!(f, "{:?}", msg),
}
}
}
@ -558,8 +575,9 @@ impl InterpError<'_> {
/// waste of resources.
pub fn allocates(&self) -> bool {
match self {
InterpError::MachineStop(_)
| InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
// Zero-sized boxes do not allocate.
InterpError::MachineStop(b) => mem::size_of_val::<dyn MachineStopType>(&**b) > 0,
InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure(_))
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) => true,
_ => false,

View File

@ -97,8 +97,8 @@ mod value;
pub use self::error::{
struct_error, ConstEvalErr, ConstEvalRawResult, ConstEvalResult, ErrorHandled, FrameInfo,
InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, ResourceExhaustionInfo,
UndefinedBehaviorInfo, UnsupportedOpInfo,
InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType,
ResourceExhaustionInfo, UndefinedBehaviorInfo, UnsupportedOpInfo,
};
pub use self::value::{get_slice_bytes, ConstValue, RawConst, Scalar, ScalarMaybeUndef};

View File

@ -39,6 +39,24 @@ use crate::transform::{MirPass, MirSource};
/// The maximum number of bytes that we'll allocate space for a return value.
const MAX_ALLOC_LIMIT: u64 = 1024;
/// Macro for machine-specific `InterpError` without allocation.
/// (These will never be shown to the user, but they help diagnose ICEs.)
macro_rules! throw_machine_stop_str {
($($tt:tt)*) => {{
// We make a new local type for it. The type itself does not carry any information,
// but its vtable (for the `MachineStopType` trait) does.
struct Zst;
// Debug-printing this type shows the desired string.
impl std::fmt::Debug for Zst {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, $($tt)*)
}
}
impl rustc::mir::interpret::MachineStopType for Zst {}
throw_machine_stop!(Zst)
}};
}
pub struct ConstProp;
impl<'tcx> MirPass<'tcx> for ConstProp {
@ -192,7 +210,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
_ret: Option<(PlaceTy<'tcx>, BasicBlock)>,
_unwind: Option<BasicBlock>,
) -> InterpResult<'tcx> {
throw_unsup!(ConstPropUnsupported("calling intrinsics isn't supported in ConstProp"))
throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
}
fn assert_panic(
@ -204,7 +222,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
}
fn ptr_to_int(_mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx, u64> {
throw_unsup!(ConstPropUnsupported("ptr-to-int casts aren't supported in ConstProp"))
throw_unsup!(ReadPointerAsBytes)
}
fn binary_ptr_op(
@ -214,10 +232,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
_right: ImmTy<'tcx>,
) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
// We can't do this because aliasing of memory can differ between const eval and llvm
throw_unsup!(ConstPropUnsupported(
"pointer arithmetic or comparisons aren't supported \
in ConstProp"
))
throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp")
}
#[inline(always)]
@ -238,7 +253,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
_dest: PlaceTy<'tcx>,
) -> InterpResult<'tcx> {
throw_unsup!(ConstPropUnsupported("can't const prop `box` keyword"))
throw_machine_stop_str!("can't const prop heap allocations")
}
fn access_local(
@ -249,7 +264,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
let l = &frame.locals[local];
if l.value == LocalValue::Uninitialized {
throw_unsup!(ConstPropUnsupported("tried to access an uninitialized local"));
throw_machine_stop_str!("tried to access an uninitialized local")
}
l.access()
@ -262,7 +277,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
// if the static allocation is mutable or if it has relocations (it may be legal to mutate
// the memory behind that in the future), then we can't const prop it
if allocation.mutability == Mutability::Mut || allocation.relocations().len() > 0 {
throw_unsup!(ConstPropUnsupported("can't eval mutable statics in ConstProp"));
throw_machine_stop_str!("can't eval mutable statics in ConstProp")
}
Ok(())