diff options
| -rw-r--r-- | src/libcore/any.rs | 2 | ||||
| -rw-r--r-- | src/librustc/mir/interpret/error.rs | 49 | ||||
| -rw-r--r-- | src/librustc/mir/interpret/mod.rs | 4 | ||||
| -rw-r--r-- | src/librustc_mir/transform/const_prop.rs | 32 |
4 files changed, 63 insertions, 24 deletions
diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 97ef513cbcc..39df803bbea 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -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. diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index ff107a5f1e2..fd7f5361214 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -14,7 +14,10 @@ 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, TypeId}, + fmt, mem, +}; #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable)] pub enum ErrorHandled { @@ -451,9 +454,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. @@ -472,9 +472,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) } @@ -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> { /// The program caused undefined behavior. UndefinedBehavior(UndefinedBehaviorInfo), @@ -529,7 +555,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>>; @@ -549,7 +575,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), } } } @@ -560,8 +586,9 @@ impl InterpError<'_> { /// waste of resources. pub fn allocates(&self) -> bool { match self { - InterpError::MachineStop(_) - | InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_)) + // Zero-sized boxes to not allocate. + InterpError::MachineStop(b) => mem::size_of_val(&**b) > 0, + InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_)) | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure(_)) | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) => true, diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index dfe5adb1bbf..35876c8e95a 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -92,8 +92,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}; diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 8d7cafc34b3..687bacfdc1b 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -4,7 +4,7 @@ use std::borrow::Cow; use std::cell::Cell; -use rustc::mir::interpret::{InterpResult, Scalar}; +use rustc::mir::interpret::{InterpResult, MachineStopType, Scalar}; use rustc::mir::visit::{ MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor, }; @@ -192,7 +192,10 @@ 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")) + #[derive(Debug)] + struct ConstPropIntrinsic; + impl MachineStopType for ConstPropIntrinsic {} + throw_machine_stop!(ConstPropIntrinsic) } 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> { - throw_unsup!(ConstPropUnsupported("ptr-to-int casts aren't supported in ConstProp")) + throw_unsup!(ReadPointerAsBytes) } fn binary_ptr_op( @@ -213,11 +216,11 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { _left: ImmTy<'tcx>, _right: ImmTy<'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 - throw_unsup!(ConstPropUnsupported( - "pointer arithmetic or comparisons aren't supported \ - in ConstProp" - )) + throw_machine_stop!(ConstPropPtrOp) } #[inline(always)] @@ -240,7 +243,10 @@ 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")) + #[derive(Debug)] + struct ConstPropBox; + impl MachineStopType for ConstPropBox {} + throw_machine_stop!(ConstPropBox) } fn access_local( @@ -251,7 +257,10 @@ 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")); + #[derive(Debug)] + struct ConstPropUninitLocal; + impl MachineStopType for ConstPropUninitLocal {} + throw_machine_stop!(ConstPropUninitLocal) } l.access() @@ -261,10 +270,13 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { _memory_extra: &(), allocation: &Allocation<Self::PointerTag, Self::AllocExtra>, ) -> 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 // 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!(ConstPropGlobalMem) } Ok(()) |
