1
Fork 0

get rid of ConstPropUnsupported; use ZST marker structs instead

This commit is contained in:
Ralf Jung 2020-03-22 11:41:07 +01:00
parent 5574b1df57
commit 82f4a1a9b9
4 changed files with 63 additions and 24 deletions

View file

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

View file

@ -14,7 +14,10 @@ use rustc_hir as hir;
use rustc_macros::HashStable; use rustc_macros::HashStable;
use rustc_session::CtfeBacktrace; use rustc_session::CtfeBacktrace;
use rustc_span::{def_id::DefId, Pos, Span}; use rustc_span::{def_id::DefId, Pos, Span};
use std::{any::Any, fmt}; use std::{
any::{Any, TypeId},
fmt, mem,
};
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable)] #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable)]
pub enum ErrorHandled { pub enum ErrorHandled {
@ -451,9 +454,6 @@ impl fmt::Debug for UndefinedBehaviorInfo {
pub enum UnsupportedOpInfo { pub enum UnsupportedOpInfo {
/// Free-form case. Only for errors that are never caught! /// Free-form case. Only for errors that are never caught!
Unsupported(String), 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. /// Accessing an unsupported foreign static.
ReadForeignStatic(DefId), ReadForeignStatic(DefId),
/// Could not find MIR for a function. /// Could not find MIR for a function.
@ -472,9 +472,6 @@ impl fmt::Debug for UnsupportedOpInfo {
use UnsupportedOpInfo::*; use UnsupportedOpInfo::*;
match self { match self {
Unsupported(ref msg) => write!(f, "{}", msg), Unsupported(ref msg) => write!(f, "{}", msg),
ConstPropUnsupported(ref msg) => {
write!(f, "Constant propagation encountered an unsupported situation: {}", msg)
}
ReadForeignStatic(did) => { ReadForeignStatic(did) => {
write!(f, "tried to read from foreign (extern) static {:?}", did) write!(f, "tried to read from foreign (extern) static {:?}", did)
} }
@ -516,6 +513,35 @@ impl fmt::Debug for ResourceExhaustionInfo {
} }
} }
/// A trait for machine-specific errors (or other "machine stop" conditions).
pub trait MachineStopType: Any + fmt::Debug + Send {}
impl MachineStopType for String {}
// Copy-pasted from `any.rs`; there does not seem to be a way to re-use that.
impl dyn MachineStopType {
pub fn is<T: Any>(&self) -> bool {
// Get `TypeId` of the type this function is instantiated with.
let t = TypeId::of::<T>();
// Get `TypeId` of the type in the trait object (`self`).
let concrete = self.type_id();
// Compare both `TypeId`s on equality.
t == concrete
}
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
if self.is::<T>() {
// SAFETY: just checked whether we are pointing to the correct type, and we can rely on
// that check for memory safety because `Any` is implemented for all types; no other
// impls can exist as they would conflict with our impl.
unsafe { Some(&*(self as *const dyn MachineStopType as *const T)) }
} else {
None
}
}
}
pub enum InterpError<'tcx> { pub enum InterpError<'tcx> {
/// The program caused undefined behavior. /// The program caused undefined behavior.
UndefinedBehavior(UndefinedBehaviorInfo), UndefinedBehavior(UndefinedBehaviorInfo),
@ -529,7 +555,7 @@ pub enum InterpError<'tcx> {
ResourceExhaustion(ResourceExhaustionInfo), ResourceExhaustion(ResourceExhaustionInfo),
/// Stop execution for a machine-controlled reason. This is never raised by /// Stop execution for a machine-controlled reason. This is never raised by
/// the core engine itself. /// the core engine itself.
MachineStop(Box<dyn Any + Send>), MachineStop(Box<dyn MachineStopType>),
} }
pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>; pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>;
@ -549,7 +575,7 @@ impl fmt::Debug for InterpError<'_> {
InvalidProgram(ref msg) => write!(f, "{:?}", msg), InvalidProgram(ref msg) => write!(f, "{:?}", msg),
UndefinedBehavior(ref msg) => write!(f, "{:?}", msg), UndefinedBehavior(ref msg) => write!(f, "{:?}", msg),
ResourceExhaustion(ref msg) => write!(f, "{:?}", msg), ResourceExhaustion(ref msg) => write!(f, "{:?}", msg),
MachineStop(_) => bug!("unhandled MachineStop"), MachineStop(ref msg) => write!(f, "{:?}", msg),
} }
} }
} }
@ -560,8 +586,9 @@ impl InterpError<'_> {
/// waste of resources. /// waste of resources.
pub fn allocates(&self) -> bool { pub fn allocates(&self) -> bool {
match self { match self {
InterpError::MachineStop(_) // Zero-sized boxes to not allocate.
| InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_)) InterpError::MachineStop(b) => mem::size_of_val(&**b) > 0,
InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure(_)) | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure(_))
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) => true, | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) => true,

View file

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

View file

@ -4,7 +4,7 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::cell::Cell; use std::cell::Cell;
use rustc::mir::interpret::{InterpResult, Scalar}; use rustc::mir::interpret::{InterpResult, MachineStopType, Scalar};
use rustc::mir::visit::{ use rustc::mir::visit::{
MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor, MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor,
}; };
@ -192,7 +192,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
_ret: Option<(PlaceTy<'tcx>, BasicBlock)>, _ret: Option<(PlaceTy<'tcx>, BasicBlock)>,
_unwind: Option<BasicBlock>, _unwind: Option<BasicBlock>,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
throw_unsup!(ConstPropUnsupported("calling intrinsics isn't supported in ConstProp")) #[derive(Debug)]
struct ConstPropIntrinsic;
impl MachineStopType for ConstPropIntrinsic {}
throw_machine_stop!(ConstPropIntrinsic)
} }
fn assert_panic( fn assert_panic(
@ -204,7 +207,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
} }
fn ptr_to_int(_mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx, u64> { 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( fn binary_ptr_op(
@ -213,11 +216,11 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
_left: ImmTy<'tcx>, _left: ImmTy<'tcx>,
_right: ImmTy<'tcx>, _right: ImmTy<'tcx>,
) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
#[derive(Debug)]
struct ConstPropPtrOp;
impl MachineStopType for ConstPropPtrOp {}
// We can't do this because aliasing of memory can differ between const eval and llvm // We can't do this because aliasing of memory can differ between const eval and llvm
throw_unsup!(ConstPropUnsupported( throw_machine_stop!(ConstPropPtrOp)
"pointer arithmetic or comparisons aren't supported \
in ConstProp"
))
} }
#[inline(always)] #[inline(always)]
@ -240,7 +243,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
_ecx: &mut InterpCx<'mir, 'tcx, Self>, _ecx: &mut InterpCx<'mir, 'tcx, Self>,
_dest: PlaceTy<'tcx>, _dest: PlaceTy<'tcx>,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
throw_unsup!(ConstPropUnsupported("can't const prop `box` keyword")) #[derive(Debug)]
struct ConstPropBox;
impl MachineStopType for ConstPropBox {}
throw_machine_stop!(ConstPropBox)
} }
fn access_local( fn access_local(
@ -251,7 +257,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
let l = &frame.locals[local]; let l = &frame.locals[local];
if l.value == LocalValue::Uninitialized { if l.value == LocalValue::Uninitialized {
throw_unsup!(ConstPropUnsupported("tried to access an uninitialized local")); #[derive(Debug)]
struct ConstPropUninitLocal;
impl MachineStopType for ConstPropUninitLocal {}
throw_machine_stop!(ConstPropUninitLocal)
} }
l.access() l.access()
@ -261,10 +270,13 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
_memory_extra: &(), _memory_extra: &(),
allocation: &Allocation<Self::PointerTag, Self::AllocExtra>, allocation: &Allocation<Self::PointerTag, Self::AllocExtra>,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
#[derive(Debug)]
struct ConstPropGlobalMem;
impl MachineStopType for ConstPropGlobalMem {}
// if the static allocation is mutable or if it has relocations (it may be legal to mutate // 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 // the memory behind that in the future), then we can't const prop it
if allocation.mutability == Mutability::Mut || allocation.relocations().len() > 0 { if allocation.mutability == Mutability::Mut || allocation.relocations().len() > 0 {
throw_unsup!(ConstPropUnsupported("can't eval mutable statics in ConstProp")); throw_machine_stop!(ConstPropGlobalMem)
} }
Ok(()) Ok(())