diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index 51b2d0272a5..b5ec30c9212 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -4,6 +4,7 @@ use super::{ Pointer, InterpResult, AllocId, ScalarMaybeUndef, write_target_uint, read_target_uint, Scalar, }; +use super::error::UnsupportedInfo::*; use crate::ty::layout::{Size, Align}; use syntax::ast::Mutability; use std::iter; @@ -244,7 +245,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { Ok(&self.get_bytes(cx, ptr, size_with_null)?[..size]) } // This includes the case where `offset` is out-of-bounds to begin with. - None => err!(UnterminatedCString(ptr.erase_tag())), + None => err!(Unsupported(UnterminatedCString(ptr.erase_tag()))), } } @@ -446,7 +447,7 @@ impl<'tcx, Tag: Copy, Extra> Allocation { if self.relocations(cx, ptr, size).is_empty() { Ok(()) } else { - err!(ReadPointerAsBytes) + err!(Unsupported(ReadPointerAsBytes)) } } @@ -516,7 +517,7 @@ impl<'tcx, Tag, Extra> Allocation { self.undef_mask.is_range_defined( ptr.offset, ptr.offset + size, - ).or_else(|idx| err!(ReadUndefBytes(idx))) + ).or_else(|idx| err!(Unsupported(ReadUndefBytes(idx)))) } pub fn mark_definedness( diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index dd06991b46a..c28582f1ab0 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -142,7 +142,7 @@ impl<'tcx> ConstEvalErr<'tcx> { InterpError::InvalidProgram(Layout(LayoutError::Unknown(_))) | InterpError::InvalidProgram(TooGeneric) => return Err(ErrorHandled::TooGeneric), - InterpError::Layout(LayoutError::SizeOverflow(_)) | + InterpError::InvalidProgram(Layout(LayoutError::SizeOverflow(_))) | InterpError::InvalidProgram(TypeckError) => return Err(ErrorHandled::Reported), _ => {}, @@ -325,16 +325,47 @@ pub enum InvalidProgramInfo<'tcx> { Layout(layout::LayoutError<'tcx>), } +impl fmt::Debug for InvalidProgramInfo<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use InvalidProgramInfo::*; + match self { + TooGeneric => + write!(f, "encountered overly generic constant"), + ReferencedConstant => + write!(f, "referenced constant has errors"), + TypeckError => + write!(f, "encountered constants with type errors, stopping evaluation"), + Layout(ref err) => + write!(f, "rustc layout computation failed: {:?}", err), + } + } +} + #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] pub enum UndefinedBehaviourInfo { - /// Handle cases which for which we do not have a fixed variant + /// Handle cases which for which we do not have a fixed variant. Ub(String), + /// Unreachable code was executed. Unreachable, } +impl fmt::Debug for UndefinedBehaviourInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use UndefinedBehaviourInfo::*; + match self { + Ub(ref msg) => + write!(f, "{}", msg), + Unreachable => + write!(f, "entered unreachable code"), + } + } +} + #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] pub enum UnsupportedInfo<'tcx> { Unimplemented(String), + + // -- Everything below is not classified yet -- FunctionAbiMismatch(Abi, Abi), FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>), FunctionRetMismatch(Ty<'tcx>, Ty<'tcx>), @@ -400,6 +431,19 @@ pub enum ResourceExhaustionInfo { InfiniteLoop, } +impl fmt::Debug for ResourceExhaustionInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use ResourceExhaustionInfo::*; + match self { + StackFrameLimitReached => + write!(f, "reached the configured maximum number of stack frames"), + InfiniteLoop => + write!(f, "duplicate interpreter state observed here, const evaluation will never \ + terminate"), + } + } +} + #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] pub enum InterpError<'tcx> { /// The program panicked. @@ -431,139 +475,131 @@ impl fmt::Display for InterpError<'_> { impl fmt::Debug for InterpError<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use InterpError::*; + use UnsupportedInfo::*; match *self { - PointerOutOfBounds { ptr, msg, allocation_size } => { + Unsupported(PointerOutOfBounds { ptr, msg, allocation_size }) => { write!(f, "{} failed: pointer must be in-bounds at offset {}, \ but is outside bounds of allocation {} which has size {}", msg, ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes()) }, - ValidationFailure(ref err) => { + Unsupported(ValidationFailure(ref err)) => { write!(f, "type validation failed: {}", err) } - NoMirFor(ref func) => write!(f, "no mir for `{}`", func), - FunctionAbiMismatch(caller_abi, callee_abi) => + Unsupported(NoMirFor(ref func)) => write!(f, "no mir for `{}`", func), + Unsupported(FunctionAbiMismatch(caller_abi, callee_abi)) => write!(f, "tried to call a function with ABI {:?} using caller ABI {:?}", callee_abi, caller_abi), - FunctionArgMismatch(caller_ty, callee_ty) => + Unsupported(FunctionArgMismatch(caller_ty, callee_ty)) => write!(f, "tried to call a function with argument of type {:?} \ passing data of type {:?}", callee_ty, caller_ty), - FunctionRetMismatch(caller_ty, callee_ty) => + Unsupported(FunctionRetMismatch(caller_ty, callee_ty)) => write!(f, "tried to call a function with return type {:?} \ passing return place of type {:?}", callee_ty, caller_ty), - FunctionArgCountMismatch => + Unsupported(FunctionArgCountMismatch) => write!(f, "tried to call a function with incorrect number of arguments"), - ReallocatedWrongMemoryKind(ref old, ref new) => + Unsupported(ReallocatedWrongMemoryKind(ref old, ref new)) => write!(f, "tried to reallocate memory from {} to {}", old, new), - DeallocatedWrongMemoryKind(ref old, ref new) => + Unsupported(DeallocatedWrongMemoryKind(ref old, ref new)) => write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new), - InvalidChar(c) => + Unsupported(InvalidChar(c)) => write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c), - AlignmentCheckFailed { required, has } => + Unsupported(AlignmentCheckFailed { required, has }) => write!(f, "tried to access memory with alignment {}, but alignment {} is required", has.bytes(), required.bytes()), - TypeNotPrimitive(ty) => + Unsupported(TypeNotPrimitive(ty)) => write!(f, "expected primitive type, got {}", ty), - Layout(ref err) => - write!(f, "rustc layout computation failed: {:?}", err), - PathNotFound(ref path) => + Unsupported(PathNotFound(ref path)) => write!(f, "Cannot find path {:?}", path), - IncorrectAllocationInformation(size, size2, align, align2) => + Unsupported(IncorrectAllocationInformation(size, size2, align, align2)) => write!(f, "incorrect alloc info: expected size {} and align {}, \ got size {} and align {}", size.bytes(), align.bytes(), size2.bytes(), align2.bytes()), - InvalidDiscriminant(val) => + Unsupported(InvalidDiscriminant(val)) => write!(f, "encountered invalid enum discriminant {}", val), - Exit(code) => - write!(f, "exited with status code {}", code), - InvalidMemoryAccess => + Unsupported(InvalidMemoryAccess) => write!(f, "tried to access memory through an invalid pointer"), - DanglingPointerDeref => + Unsupported(DanglingPointerDeref) => write!(f, "dangling pointer was dereferenced"), - DoubleFree => + Unsupported(DoubleFree) => write!(f, "tried to deallocate dangling pointer"), - InvalidFunctionPointer => + Unsupported(InvalidFunctionPointer) => write!(f, "tried to use a function pointer after offsetting it"), - InvalidBool => + Unsupported(InvalidBool) => write!(f, "invalid boolean value read"), - InvalidNullPointerUsage => + Unsupported(InvalidNullPointerUsage) => write!(f, "invalid use of NULL pointer"), - ReadPointerAsBytes => + Unsupported(ReadPointerAsBytes) => write!(f, "a raw memory access tried to access part of a pointer value as raw \ bytes"), - ReadBytesAsPointer => + Unsupported(ReadBytesAsPointer) => write!(f, "a memory access tried to interpret some bytes as a pointer"), - ReadForeignStatic => + Unsupported(ReadForeignStatic) => write!(f, "tried to read from foreign (extern) static"), - InvalidPointerMath => + Unsupported(InvalidPointerMath) => write!(f, "attempted to do invalid arithmetic on pointers that would leak base \ addresses, e.g., comparing pointers into different allocations"), - DeadLocal => + Unsupported(DeadLocal) => write!(f, "tried to access a dead local variable"), - DerefFunctionPointer => + Unsupported(DerefFunctionPointer) => write!(f, "tried to dereference a function pointer"), - ExecuteMemory => + Unsupported(ExecuteMemory) => write!(f, "tried to treat a memory pointer as a function pointer"), - StackFrameLimitReached => - write!(f, "reached the configured maximum number of stack frames"), - OutOfTls => + Unsupported(OutOfTls) => write!(f, "reached the maximum number of representable TLS keys"), - TlsOutOfBounds => + Unsupported(TlsOutOfBounds) => write!(f, "accessed an invalid (unallocated) TLS key"), - CalledClosureAsFunction => + Unsupported(CalledClosureAsFunction) => write!(f, "tried to call a closure through a function pointer"), - VtableForArgumentlessMethod => + Unsupported(VtableForArgumentlessMethod) => write!(f, "tried to call a vtable function without arguments"), - ModifiedConstantMemory => + Unsupported(ModifiedConstantMemory) => write!(f, "tried to modify constant memory"), - ModifiedStatic => + Unsupported(ModifiedStatic) => write!(f, "tried to modify a static's initial value from another static's \ initializer"), - AssumptionNotHeld => + Unsupported(AssumptionNotHeld) => write!(f, "`assume` argument was false"), - InlineAsm => + Unsupported(InlineAsm) => write!(f, "miri does not support inline assembly"), - ReallocateNonBasePtr => + Unsupported(ReallocateNonBasePtr) => write!(f, "tried to reallocate with a pointer not to the beginning of an \ existing object"), - DeallocateNonBasePtr => + Unsupported(DeallocateNonBasePtr) => write!(f, "tried to deallocate with a pointer not to the beginning of an \ existing object"), - HeapAllocZeroBytes => + Unsupported(HeapAllocZeroBytes) => write!(f, "tried to re-, de- or allocate zero bytes on the heap"), - Unreachable => - write!(f, "entered unreachable code"), - ReadFromReturnPointer => + Unsupported(ReadFromReturnPointer) => write!(f, "tried to read from the return pointer"), - UnimplementedTraitSelection => + Unsupported(UnimplementedTraitSelection) => write!(f, "there were unresolved type arguments during trait selection"), - TypeckError => - write!(f, "encountered constants with type errors, stopping evaluation"), - TooGeneric => - write!(f, "encountered overly generic constant"), - ReferencedConstant => - write!(f, "referenced constant has errors"), - InfiniteLoop => - write!(f, "duplicate interpreter state observed here, const evaluation will never \ - terminate"), - InvalidBoolOp(_) => + Unsupported(InvalidBoolOp(_)) => write!(f, "invalid boolean operation"), - UnterminatedCString(_) => + Unsupported(UnterminatedCString(_)) => write!(f, "attempted to get length of a null terminated string, but no null \ found before end of allocation"), - ReadUndefBytes(_) => + Unsupported(ReadUndefBytes(_)) => write!(f, "attempted to read undefined bytes"), - HeapAllocNonPowerOfTwoAlignment(_) => + Unsupported(HeapAllocNonPowerOfTwoAlignment(_)) => write!(f, "tried to re-, de-, or allocate heap memory with alignment that is \ not a power of two"), - MachineError(ref msg) | - Unimplemented(ref msg) | - AbiViolation(ref msg) | - Intrinsic(ref msg) => + Unsupported(MachineError(ref msg)) | + Unsupported(Unimplemented(ref msg)) | + Unsupported(AbiViolation(ref msg)) | + Unsupported(Intrinsic(ref msg)) => write!(f, "{}", msg), + InvalidProgram(ref msg) => + write!(f, "{:?}", msg), + UndefinedBehaviour(ref msg) => + write!(f, "{:?}", msg), + ResourceExhaustion(ref msg) => + write!(f, "{:?}", msg), Panic(ref msg) => write!(f, "{:?}", msg), + Exit(code) => + write!(f, "exited with status code {}", code), } } } diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 121b6ac0ac8..ceed59885b2 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -12,7 +12,8 @@ mod pointer; pub use self::error::{ InterpErrorInfo, InterpResult, InterpError, AssertMessage, ConstEvalErr, struct_error, - FrameInfo, ConstEvalRawResult, ConstEvalResult, ErrorHandled, PanicMessage + FrameInfo, ConstEvalRawResult, ConstEvalResult, ErrorHandled, PanicMessage, UnsupportedInfo, + InvalidProgramInfo, ResourceExhaustionInfo, UndefinedBehaviourInfo, }; pub use self::value::{Scalar, ScalarMaybeUndef, RawConst, ConstValue}; diff --git a/src/librustc/mir/interpret/pointer.rs b/src/librustc/mir/interpret/pointer.rs index 0e3b8459115..afbe1ed9a93 100644 --- a/src/librustc/mir/interpret/pointer.rs +++ b/src/librustc/mir/interpret/pointer.rs @@ -1,5 +1,6 @@ use std::fmt::{self, Display}; +use super::error::UnsupportedInfo::*; use crate::mir; use crate::ty::layout::{self, HasDataLayout, Size}; use rustc_macros::HashStable; @@ -198,11 +199,11 @@ impl<'tcx, Tag> Pointer { msg: CheckInAllocMsg, ) -> InterpResult<'tcx, ()> { if self.offset > allocation_size { - err!(PointerOutOfBounds { + err!(Unsupported(PointerOutOfBounds { ptr: self.erase_tag(), msg, allocation_size, - }) + })) } else { Ok(()) } diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 4a59d845b3b..29bf94292ef 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -2,6 +2,7 @@ use std::fmt; use rustc_macros::HashStable; use rustc_apfloat::{Float, ieee::{Double, Single}}; +use super::error::UnsupportedInfo::*; use crate::ty::{Ty, InferConst, ParamConst, layout::{HasDataLayout, Size, Align}, subst::SubstsRef}; use crate::ty::PlaceholderConst; use crate::hir::def_id::DefId; @@ -360,7 +361,7 @@ impl<'tcx, Tag> Scalar { Scalar::check_data(data, size); Ok(data) } - Scalar::Ptr(_) => err!(ReadPointerAsBytes), + Scalar::Ptr(_) => err!(Unsupported(ReadPointerAsBytes)), } } @@ -373,8 +374,8 @@ impl<'tcx, Tag> Scalar { #[inline] pub fn to_ptr(self) -> InterpResult<'tcx, Pointer> { match self { - Scalar::Raw { data: 0, .. } => err!(InvalidNullPointerUsage), - Scalar::Raw { .. } => err!(ReadBytesAsPointer), + Scalar::Raw { data: 0, .. } => err!(Unsupported(InvalidNullPointerUsage)), + Scalar::Raw { .. } => err!(Unsupported(ReadBytesAsPointer)), Scalar::Ptr(p) => Ok(p), } } @@ -406,7 +407,7 @@ impl<'tcx, Tag> Scalar { match self { Scalar::Raw { data: 0, size: 1 } => Ok(false), Scalar::Raw { data: 1, size: 1 } => Ok(true), - _ => err!(InvalidBool), + _ => err!(Unsupported(InvalidBool)), } } @@ -414,7 +415,7 @@ impl<'tcx, Tag> Scalar { let val = self.to_u32()?; match ::std::char::from_u32(val) { Some(c) => Ok(c), - None => err!(InvalidChar(val as u128)), + None => err!(Unsupported(InvalidChar(val as u128))), } } @@ -537,7 +538,7 @@ impl<'tcx, Tag> ScalarMaybeUndef { pub fn not_undef(self) -> InterpResult<'static, Scalar> { match self { ScalarMaybeUndef::Scalar(scalar) => Ok(scalar), - ScalarMaybeUndef::Undef => err!(ReadUndefBytes(Size::from_bytes(0))), + ScalarMaybeUndef::Undef => err!(Unsupported(ReadUndefBytes(Size::from_bytes(0)))), } } diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 37d4c5b2f09..60381e0365f 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -24,7 +24,8 @@ use crate::interpret::{self, RawConst, ConstValue, InterpResult, InterpErrorInfo, InterpError, GlobalId, InterpCx, StackPopCleanup, Allocation, AllocId, MemoryKind, - snapshot, RefTracking, intern_const_alloc_recursive, + snapshot, RefTracking, intern_const_alloc_recursive, UnsupportedInfo::*, + InvalidProgramInfo::*, }; /// Number of steps until the detector even starts doing anything. @@ -183,7 +184,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( impl<'tcx> Into> for ConstEvalError { fn into(self) -> InterpErrorInfo<'tcx> { - InterpError::MachineError(self.to_string()).into() + InterpError::Unsupported(MachineError(self.to_string())).into() } } @@ -352,7 +353,9 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, ecx.goto_block(ret)?; // fully evaluated and done Ok(None) } else { - err!(MachineError(format!("calling non-const function `{}`", instance))) + err!(Unsupported( + MachineError(format!("calling non-const function `{}`", instance)) + )) }; } } @@ -360,7 +363,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, Ok(Some(match ecx.load_mir(instance.def) { Ok(body) => body, Err(err) => { - if let InterpError::NoMirFor(ref path) = err.kind { + if let InterpError::Unsupported(NoMirFor(ref path)) = err.kind { return Err( ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path)) .into(), @@ -412,7 +415,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, _tcx: TyCtxt<'tcx>, _def_id: DefId, ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { - err!(ReadForeignStatic) + err!(Unsupported(ReadForeignStatic)) } #[inline(always)] @@ -698,7 +701,7 @@ pub fn const_eval_raw_provider<'tcx>( // any other kind of error will be reported to the user as a deny-by-default lint _ => if let Some(p) = cid.promoted { let span = tcx.promoted_mir(def_id)[p].span; - if let InterpError::ReferencedConstant = err.error { + if let InterpError::InvalidProgram(ReferencedConstant) = err.error { err.report_as_error( tcx.at(span), "evaluation of constant expression failed", diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 980697360eb..443d264b351 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -9,7 +9,8 @@ use rustc_apfloat::{Float, FloatConvert}; use rustc::mir::interpret::{ Scalar, InterpResult, Pointer, PointerArithmetic, InterpError, }; -use rustc::mir::CastKind; +use rustc::mir::{CastKind, interpret::{UnsupportedInfo::*, InvalidProgramInfo::*}}; + use super::{InterpCx, Machine, PlaceTy, OpTy, Immediate, FnVal}; @@ -85,7 +86,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.param_env, def_id, substs, - ).ok_or_else(|| InterpError::TooGeneric.into()); + ).ok_or_else(|| InterpError::InvalidProgram(TooGeneric).into()); let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance?)); self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?; } @@ -199,7 +200,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }, // Casts to bool are not permitted by rustc, no need to handle them here. - _ => err!(Unimplemented(format!("int to {:?} cast", dest_layout.ty))), + _ => err!(Unsupported(Unimplemented(format!("int to {:?} cast", dest_layout.ty)))), } } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 007ec8cb2db..e732484b9b7 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -17,7 +17,8 @@ use rustc::mir::interpret::{ ErrorHandled, GlobalId, Scalar, Pointer, FrameInfo, AllocId, InterpResult, InterpError, - truncate, sign_extend, + truncate, sign_extend, UnsupportedInfo::*, InvalidProgramInfo::*, + ResourceExhaustionInfo::*, UndefinedBehaviourInfo::*, }; use rustc_data_structures::fx::FxHashMap; @@ -135,7 +136,7 @@ pub enum LocalValue { impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> { pub fn access(&self) -> InterpResult<'tcx, Operand> { match self.value { - LocalValue::Dead => err!(DeadLocal), + LocalValue::Dead => err!(Unsupported(DeadLocal)), LocalValue::Uninitialized => bug!("The type checker should prevent reading from a never-written local"), LocalValue::Live(val) => Ok(val), @@ -148,7 +149,7 @@ impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> { &mut self, ) -> InterpResult<'tcx, Result<&mut LocalValue, MemPlace>> { match self.value { - LocalValue::Dead => err!(DeadLocal), + LocalValue::Dead => err!(Unsupported(DeadLocal)), LocalValue::Live(Operand::Indirect(mplace)) => Ok(Err(mplace)), ref mut local @ LocalValue::Live(Operand::Immediate(_)) | ref mut local @ LocalValue::Uninitialized => { @@ -191,7 +192,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'mir, 'tcx, M> { #[inline] fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout { self.tcx.layout_of(self.param_env.and(ty)) - .map_err(|layout| InterpError::Layout(layout).into()) + .map_err(|layout| InterpError::InvalidProgram(Layout(layout)).into()) } } @@ -302,7 +303,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &substs, )), None => if substs.needs_subst() { - err!(TooGeneric).into() + err!(InvalidProgram(TooGeneric)).into() } else { Ok(substs) }, @@ -323,7 +324,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.param_env, def_id, substs, - ).ok_or_else(|| InterpError::TooGeneric.into()) + ).ok_or_else(|| InterpError::InvalidProgram(TooGeneric).into()) } pub fn load_mir( @@ -336,14 +337,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { && self.tcx.has_typeck_tables(did) && self.tcx.typeck_tables_of(did).tainted_by_errors { - return err!(TypeckError); + return err!(InvalidProgram(TypeckError)); } trace!("load mir {:?}", instance); match instance { ty::InstanceDef::Item(def_id) => if self.tcx.is_mir_available(did) { Ok(self.tcx.optimized_mir(did)) } else { - err!(NoMirFor(self.tcx.def_path_str(def_id))) + err!(Unsupported(NoMirFor(self.tcx.def_path_str(def_id)))) }, _ => Ok(self.tcx.instance_mir(instance)), } @@ -356,7 +357,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match self.stack.last() { Some(frame) => Ok(self.monomorphize_with_substs(t, frame.instance.substs)?), None => if t.needs_subst() { - err!(TooGeneric).into() + err!(InvalidProgram(TooGeneric)).into() } else { Ok(t) }, @@ -373,7 +374,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let substituted = t.subst(*self.tcx, substs); if substituted.needs_subst() { - return err!(TooGeneric); + return err!(InvalidProgram(TooGeneric)); } Ok(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted)) @@ -572,7 +573,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { info!("ENTERING({}) {}", self.cur_frame(), self.frame().instance); if self.stack.len() > self.tcx.sess.const_eval_stack_frame_limit { - err!(StackFrameLimitReached) + err!(ResourceExhaustion(StackFrameLimitReached)) } else { Ok(()) } @@ -620,7 +621,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } else { // Uh, that shouldn't happen... the function did not intend to return - return err!(Unreachable); + return err!(UndefinedBehaviour(Unreachable)); } // Jump to new block -- *after* validation so that the spans make more sense. match frame.return_to_block { @@ -694,8 +695,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles. let val = self.tcx.const_eval_raw(param_env.and(gid)).map_err(|err| { match err { - ErrorHandled::Reported => InterpError::ReferencedConstant, - ErrorHandled::TooGeneric => InterpError::TooGeneric, + ErrorHandled::Reported => InterpError::InvalidProgram(ReferencedConstant), + ErrorHandled::TooGeneric => InterpError::InvalidProgram(TooGeneric), } })?; self.raw_const_to_mplace(val) diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs index bcd36ac547c..f1e6132132c 100644 --- a/src/librustc_mir/interpret/intern.rs +++ b/src/librustc_mir/interpret/intern.rs @@ -5,7 +5,7 @@ use rustc::ty::{Ty, TyCtxt, ParamEnv, self}; use rustc::mir::interpret::{ - InterpResult, ErrorHandled, + InterpResult, ErrorHandled, UnsupportedInfo::*, }; use rustc::hir; use rustc::hir::def_id::DefId; @@ -293,7 +293,7 @@ pub fn intern_const_alloc_recursive( if let Err(error) = interned { // This can happen when e.g. the tag of an enum is not a valid discriminant. We do have // to read enum discriminants in order to find references in enum variant fields. - if let InterpError::ValidationFailure(_) = error.kind { + if let InterpError::Unsupported(ValidationFailure(_)) = error.kind { let err = crate::const_eval::error_to_const_error(&ecx, error); match err.struct_error(ecx.tcx, "it is undefined behavior to use this value") { Ok(mut diag) => { @@ -328,9 +328,9 @@ pub fn intern_const_alloc_recursive( } } else if ecx.memory().dead_alloc_map.contains_key(&alloc_id) { // dangling pointer - return err!(ValidationFailure( + return err!(Unsupported(ValidationFailure( "encountered dangling pointer in final constant".into(), - )) + ))) } } Ok(()) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 6a5b933e4a5..880984ed88c 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -7,7 +7,7 @@ use rustc::ty; use rustc::ty::layout::{LayoutOf, Primitive, Size}; use rustc::mir::BinOp; use rustc::mir::interpret::{ - InterpResult, InterpError, Scalar, PanicMessage, + InterpResult, InterpError, Scalar, PanicMessage, UnsupportedInfo::*, }; use super::{ @@ -100,11 +100,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let bits = self.read_scalar(args[0])?.to_bits(layout_of.size)?; let kind = match layout_of.abi { ty::layout::Abi::Scalar(ref scalar) => scalar.value, - _ => Err(::rustc::mir::interpret::InterpError::TypeNotPrimitive(ty))?, + _ => Err(InterpError::Unsupported(TypeNotPrimitive(ty)))?, }; let out_val = if intrinsic_name.ends_with("_nonzero") { if bits == 0 { - return err!(Intrinsic(format!("{} called on 0", intrinsic_name))); + return err!( + Unsupported(Intrinsic(format!("{} called on 0", intrinsic_name))) + ); } numeric_intrinsic(intrinsic_name.trim_end_matches("_nonzero"), bits, kind)? } else { @@ -190,9 +192,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if overflowed { let layout = self.layout_of(substs.type_at(0))?; let r_val = r.to_scalar()?.to_bits(layout.size)?; - return err!(Intrinsic( + return err!(Unsupported(Intrinsic( format!("Overflowing shift by {} in {}", r_val, intrinsic_name), - )); + ))); } self.write_scalar(val, dest)?; } diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index e3f16a3c9ea..c40f8094068 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -11,7 +11,7 @@ use rustc::ty::{self, TyCtxt}; use super::{ Allocation, AllocId, InterpResult, InterpError, Scalar, AllocationExtra, - InterpCx, PlaceTy, OpTy, ImmTy, MemoryKind, Pointer, Memory, + InterpCx, PlaceTy, OpTy, ImmTy, MemoryKind, Pointer, Memory, UnsupportedInfo::* }; /// Whether this kind of memory is allowed to leak @@ -240,9 +240,9 @@ pub trait Machine<'mir, 'tcx>: Sized { int: u64, ) -> InterpResult<'tcx, Pointer> { Err((if int == 0 { - InterpError::InvalidNullPointerUsage + InterpError::Unsupported(InvalidNullPointerUsage) } else { - InterpError::ReadBytesAsPointer + InterpError::Unsupported(ReadBytesAsPointer) }).into()) } @@ -251,6 +251,6 @@ pub trait Machine<'mir, 'tcx>: Sized { _mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer, ) -> InterpResult<'tcx, u64> { - err!(ReadPointerAsBytes) + err!(Unsupported(ReadPointerAsBytes)) } } diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 87dd7738410..74da59182c1 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -19,7 +19,8 @@ use syntax::ast::Mutability; use super::{ Pointer, AllocId, Allocation, GlobalId, AllocationExtra, InterpResult, Scalar, InterpError, GlobalAlloc, PointerArithmetic, - Machine, AllocMap, MayLeak, ErrorHandled, CheckInAllocMsg, + Machine, AllocMap, MayLeak, ErrorHandled, CheckInAllocMsg, UnsupportedInfo::*, + InvalidProgramInfo::* }; #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] @@ -66,10 +67,9 @@ impl<'tcx, Other> FnVal<'tcx, Other> { match self { FnVal::Instance(instance) => Ok(instance), - FnVal::Other(_) => - err!(MachineError( - format!("Expected instance function pointer, got 'other' pointer") - )), + FnVal::Other(_) => err!(Unsupported(MachineError(format!( + "Expected instance function pointer, got 'other' pointer" + )))), } } } @@ -203,7 +203,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { kind: MemoryKind, ) -> InterpResult<'tcx, Pointer> { if ptr.offset.bytes() != 0 { - return err!(ReallocateNonBasePtr); + return err!(Unsupported(ReallocateNonBasePtr)); } // For simplicities' sake, we implement reallocate as "alloc, copy, dealloc". @@ -244,7 +244,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { trace!("deallocating: {}", ptr.alloc_id); if ptr.offset.bytes() != 0 { - return err!(DeallocateNonBasePtr); + return err!(Unsupported(DeallocateNonBasePtr)); } let (alloc_kind, mut alloc) = match self.alloc_map.remove(&ptr.alloc_id) { @@ -252,33 +252,33 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { None => { // Deallocating static memory -- always an error return match self.tcx.alloc_map.lock().get(ptr.alloc_id) { - Some(GlobalAlloc::Function(..)) => err!(DeallocatedWrongMemoryKind( + Some(GlobalAlloc::Function(..)) => err!(Unsupported(DeallocatedWrongMemoryKind( "function".to_string(), format!("{:?}", kind), - )), + ))), Some(GlobalAlloc::Static(..)) | - Some(GlobalAlloc::Memory(..)) => err!(DeallocatedWrongMemoryKind( + Some(GlobalAlloc::Memory(..)) => err!(Unsupported(DeallocatedWrongMemoryKind( "static".to_string(), format!("{:?}", kind), - )), - None => err!(DoubleFree) + ))), + None => err!(Unsupported(DoubleFree)) } } }; if alloc_kind != kind { - return err!(DeallocatedWrongMemoryKind( + return err!(Unsupported(DeallocatedWrongMemoryKind( format!("{:?}", alloc_kind), format!("{:?}", kind), - )); + ))); } if let Some((size, align)) = old_size_and_align { if size.bytes() != alloc.bytes.len() as u64 || align != alloc.align { let bytes = Size::from_bytes(alloc.bytes.len() as u64); - return err!(IncorrectAllocationInformation(size, + return err!(Unsupported(IncorrectAllocationInformation(size, bytes, align, - alloc.align)); + alloc.align))); } } @@ -323,10 +323,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { } else { // The biggest power of two through which `offset` is divisible. let offset_pow2 = 1 << offset.trailing_zeros(); - err!(AlignmentCheckFailed { + err!(Unsupported(AlignmentCheckFailed { has: Align::from_bytes(offset_pow2).unwrap(), required: align, - }) + })) } } @@ -345,7 +345,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { assert!(size.bytes() == 0); // Must be non-NULL and aligned. if bits == 0 { - return err!(InvalidNullPointerUsage); + return err!(Unsupported(InvalidNullPointerUsage)); } check_offset_align(bits, align)?; None @@ -366,10 +366,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // got picked we might be aligned even if this check fails. // We instead have to fall back to converting to an integer and checking // the "real" alignment. - return err!(AlignmentCheckFailed { + return err!(Unsupported(AlignmentCheckFailed { has: alloc_align, required: align, - }); + })); } check_offset_align(ptr.offset.bytes(), align)?; @@ -417,9 +417,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { Some(GlobalAlloc::Memory(mem)) => Cow::Borrowed(mem), Some(GlobalAlloc::Function(..)) => - return err!(DerefFunctionPointer), + return err!(Unsupported(DerefFunctionPointer)), None => - return err!(DanglingPointerDeref), + return err!(Unsupported(DanglingPointerDeref)), Some(GlobalAlloc::Static(def_id)) => { // We got a "lazy" static that has not been computed yet. if tcx.is_foreign_item(def_id) { @@ -440,8 +440,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // for statics assert!(tcx.is_static(def_id)); match err { - ErrorHandled::Reported => InterpError::ReferencedConstant, - ErrorHandled::TooGeneric => InterpError::TooGeneric, + ErrorHandled::Reported => + InterpError::InvalidProgram(ReferencedConstant), + ErrorHandled::TooGeneric => + InterpError::InvalidProgram(TooGeneric), } })?; // Make sure we use the ID of the resolved memory, not the lazy one! @@ -505,11 +507,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // to give us a cheap reference. let alloc = Self::get_static_alloc(memory_extra, tcx, id)?; if alloc.mutability == Mutability::Immutable { - return err!(ModifiedConstantMemory); + return err!(Unsupported(ModifiedConstantMemory)); } match M::STATIC_KIND { Some(kind) => Ok((MemoryKind::Machine(kind), alloc.into_owned())), - None => err!(ModifiedStatic), + None => err!(Unsupported(ModifiedStatic)), } }); // Unpack the error type manually because type inference doesn't @@ -519,7 +521,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { Ok(a) => { let a = &mut a.1; if a.mutability == Mutability::Immutable { - return err!(ModifiedConstantMemory); + return err!(Unsupported(ModifiedConstantMemory)); } Ok(a) } @@ -591,7 +593,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { } else { match self.tcx.alloc_map.lock().get(id) { Some(GlobalAlloc::Function(instance)) => Ok(FnVal::Instance(instance)), - _ => Err(InterpError::ExecuteMemory.into()), + _ => Err(InterpError::Unsupported(ExecuteMemory).into()), } } } @@ -602,7 +604,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> { let ptr = self.force_ptr(ptr)?; // We definitely need a pointer value. if ptr.offset.bytes() != 0 { - return err!(InvalidFunctionPointer); + return err!(Unsupported(InvalidFunctionPointer)); } self.get_fn_alloc(ptr.alloc_id) } @@ -837,9 +839,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { if (src.offset <= dest.offset && src.offset + size > dest.offset) || (dest.offset <= src.offset && dest.offset + size > src.offset) { - return err!(Intrinsic( + return err!(Unsupported(Intrinsic( "copy_nonoverlapping called on overlapping ranges".to_string(), - )); + ))); } } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 1816171d7b1..3edc7748e5b 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -12,7 +12,7 @@ use rustc::mir::interpret::{ GlobalId, AllocId, ConstValue, Pointer, Scalar, InterpResult, InterpError, - sign_extend, truncate, + sign_extend, truncate, UnsupportedInfo::*, InvalidProgramInfo::* }; use super::{ InterpCx, Machine, @@ -332,7 +332,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let len = mplace.len(self)?; let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len as u64))?; let str = ::std::str::from_utf8(bytes) - .map_err(|err| InterpError::ValidationFailure(err.to_string()))?; + .map_err(|err| InterpError::Unsupported(ValidationFailure(err.to_string())))?; Ok(str) } @@ -459,7 +459,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { mir_place.iterate(|place_base, place_projection| { let mut op = match place_base { - PlaceBase::Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer), + PlaceBase::Local(mir::RETURN_PLACE) => + return err!(Unsupported(ReadFromReturnPointer)), PlaceBase::Local(local) => { // Do not use the layout passed in as argument if the base we are looking at // here is not the entire place. @@ -530,7 +531,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; // Early-return cases. match val.val { - ConstValue::Param(_) => return err!(TooGeneric), // FIXME(oli-obk): try to monomorphize + ConstValue::Param(_) => + // FIXME(oli-obk): try to monomorphize + return err!(InvalidProgram(TooGeneric)), ConstValue::Unevaluated(def_id, substs) => { let instance = self.resolve(def_id, substs)?; return Ok(OpTy::from(self.const_eval_raw(GlobalId { @@ -604,7 +607,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { layout::DiscriminantKind::Tag => { let bits_discr = match raw_discr.to_bits(discr_val.layout.size) { Ok(raw_discr) => raw_discr, - Err(_) => return err!(InvalidDiscriminant(raw_discr.erase_tag())), + Err(_) => + return err!(Unsupported(InvalidDiscriminant(raw_discr.erase_tag()))), }; let real_discr = if discr_val.layout.ty.is_signed() { // going from layout tag type to typeck discriminant type @@ -630,7 +634,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .discriminants(*def_id, self.tcx.tcx) .find(|(_, var)| var.val == real_discr), _ => bug!("tagged layout for non-adt non-generator"), - }.ok_or_else(|| InterpError::InvalidDiscriminant(raw_discr.erase_tag()))?; + }.ok_or_else( + || InterpError::Unsupported(InvalidDiscriminant(raw_discr.erase_tag())) + )?; (real_discr, index.0) }, layout::DiscriminantKind::Niche { @@ -641,14 +647,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let variants_start = niche_variants.start().as_u32() as u128; let variants_end = niche_variants.end().as_u32() as u128; let raw_discr = raw_discr.not_undef() - .map_err(|_| InterpError::InvalidDiscriminant(ScalarMaybeUndef::Undef))?; + .map_err(|_| InterpError::Unsupported(InvalidDiscriminant(ScalarMaybeUndef::Undef)))?; match raw_discr.to_bits_or_ptr(discr_val.layout.size, self) { Err(ptr) => { // The niche must be just 0 (which an inbounds pointer value never is) let ptr_valid = niche_start == 0 && variants_start == variants_end && !self.memory.ptr_may_be_null(ptr); if !ptr_valid { - return err!(InvalidDiscriminant(raw_discr.erase_tag().into())); + return err!(Unsupported(InvalidDiscriminant(raw_discr.erase_tag().into()))); } (dataful_variant.as_u32() as u128, dataful_variant) }, diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index b4edee72a4d..8af4c71299d 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -4,7 +4,7 @@ use syntax::ast::FloatTy; use rustc_apfloat::Float; use rustc::mir::interpret::{InterpResult, PanicMessage, Scalar}; -use super::{InterpCx, PlaceTy, Immediate, Machine, ImmTy}; +use super::{InterpCx, PlaceTy, Immediate, Machine, ImmTy, UnsupportedInfo::*}; impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { @@ -155,7 +155,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { r, right_layout.ty ); - return err!(Unimplemented(msg)); + return err!(Unsupported(Unimplemented(msg))); } // Operations that need special treatment for signed integers @@ -250,7 +250,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { r, right_layout.ty, ); - return err!(Unimplemented(msg)); + return err!(Unsupported(Unimplemented(msg))); } }; diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 8fe882934df..65e70b7bedc 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -14,7 +14,8 @@ use rustc::ty::TypeFoldable; use super::{ GlobalId, AllocId, Allocation, Scalar, InterpResult, Pointer, PointerArithmetic, InterpCx, Machine, AllocMap, AllocationExtra, PanicMessage, - RawConst, Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind, LocalValue + RawConst, Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind, LocalValue, + UnsupportedInfo::*, }; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -622,7 +623,7 @@ where .layout_of(self.monomorphize(self.frame().body.return_ty())?)?, } } - None => return err!(InvalidNullPointerUsage), + None => return err!(Unsupported(InvalidNullPointerUsage)), }, PlaceBase::Local(local) => PlaceTy { // This works even for dead/uninitialized locals; we check further when writing diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs index ad631793a08..112e592329f 100644 --- a/src/librustc_mir/interpret/snapshot.rs +++ b/src/librustc_mir/interpret/snapshot.rs @@ -12,7 +12,7 @@ use rustc::mir; use rustc::mir::interpret::{ AllocId, Pointer, Scalar, Relocations, Allocation, UndefMask, - InterpResult, InterpError, + InterpResult, InterpError, ResourceExhaustionInfo::*, }; use rustc::ty::{self, TyCtxt}; @@ -77,7 +77,7 @@ impl<'mir, 'tcx> InfiniteLoopDetector<'mir, 'tcx> { } // Second cycle - Err(InterpError::InfiniteLoop.into()) + Err(InterpError::ResourceExhaustion(InfiniteLoop).into()) } } diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 246c90ba48e..24aa5489e52 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -4,7 +4,7 @@ use rustc::mir; use rustc::ty::layout::LayoutOf; -use rustc::mir::interpret::{InterpResult, Scalar, PointerArithmetic}; +use rustc::mir::interpret::{InterpResult, Scalar, PointerArithmetic, UnsupportedInfo}; use super::{InterpCx, Machine}; @@ -121,7 +121,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // size of MIR constantly. Nop => {} - InlineAsm { .. } => return err!(InlineAsm), + InlineAsm { .. } => return err!(Unsupported(UnsupportedInfo::InlineAsm)), } self.stack[frame_idx].stmt += 1; diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 27bd0f88896..cfb901d380e 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -9,6 +9,7 @@ use rustc_target::spec::abi::Abi; use super::{ InterpResult, PointerArithmetic, InterpError, Scalar, InterpCx, Machine, Immediate, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal, + UndefinedBehaviourInfo, UnsupportedInfo::*, }; impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { @@ -19,7 +20,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.frame_mut().stmt = 0; Ok(()) } else { - err!(Unreachable) + err!(UndefinedBehaviour(UndefinedBehaviourInfo::Unreachable)) } } @@ -89,7 +90,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }, _ => { let msg = format!("can't handle callee of type {:?}", func.layout.ty); - return err!(Unimplemented(msg)); + return err!(Unsupported(Unimplemented(msg))); } }; let args = self.eval_operands(args)?; @@ -173,7 +174,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { `simplify_branches` mir pass"), FalseUnwind { .. } => bug!("should have been eliminated by\ `simplify_branches` mir pass"), - Unreachable => return err!(Unreachable), + Unreachable => return err!(UndefinedBehaviour(UndefinedBehaviourInfo::Unreachable)), } Ok(()) @@ -220,13 +221,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { return Ok(()); } let caller_arg = caller_arg.next() - .ok_or_else(|| InterpError::FunctionArgCountMismatch)?; + .ok_or_else(|| InterpError::Unsupported(FunctionArgCountMismatch))?; if rust_abi { debug_assert!(!caller_arg.layout.is_zst(), "ZSTs must have been already filtered out"); } // Now, check if !Self::check_argument_compat(rust_abi, caller_arg.layout, callee_arg.layout) { - return err!(FunctionArgMismatch(caller_arg.layout.ty, callee_arg.layout.ty)); + return err!( + Unsupported(FunctionArgMismatch(caller_arg.layout.ty, callee_arg.layout.ty)) + ); } // We allow some transmutes here self.copy_op_transmute(caller_arg, callee_arg) @@ -254,13 +257,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match instance.def { ty::InstanceDef::Intrinsic(..) => { if caller_abi != Abi::RustIntrinsic { - return err!(FunctionAbiMismatch(caller_abi, Abi::RustIntrinsic)); + return err!(Unsupported(FunctionAbiMismatch(caller_abi, Abi::RustIntrinsic))); } // The intrinsic itself cannot diverge, so if we got here without a return // place... (can happen e.g., for transmute returning `!`) let dest = match dest { Some(dest) => dest, - None => return err!(Unreachable) + None => return err!(UndefinedBehaviour(UndefinedBehaviourInfo::Unreachable)) }; M::call_intrinsic(self, instance, args, dest)?; // No stack frame gets pushed, the main loop will just act as if the @@ -295,7 +298,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { abi, }; if normalize_abi(caller_abi) != normalize_abi(callee_abi) { - return err!(FunctionAbiMismatch(caller_abi, callee_abi)); + return err!(Unsupported(FunctionAbiMismatch(caller_abi, callee_abi))); } } @@ -390,7 +393,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Now we should have no more caller args if caller_iter.next().is_some() { trace!("Caller has passed too many args"); - return err!(FunctionArgCountMismatch); + return err!(Unsupported(FunctionArgCountMismatch)); } // Don't forget to check the return type! if let Some(caller_ret) = dest { @@ -402,15 +405,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { caller_ret.layout, callee_ret.layout, ) { - return err!(FunctionRetMismatch( - caller_ret.layout.ty, callee_ret.layout.ty + return err!(Unsupported( + FunctionRetMismatch(caller_ret.layout.ty, callee_ret.layout.ty) )); } } else { let local = mir::RETURN_PLACE; let ty = self.frame().body.local_decls[local].ty; if !self.tcx.is_ty_uninhabited_from_any_module(ty) { - return err!(FunctionRetMismatch(self.tcx.types.never, ty)); + return err!(Unsupported(FunctionRetMismatch(self.tcx.types.never, ty))); } } Ok(()) diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index e7363f6876c..677d6c89b38 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -1,6 +1,6 @@ use rustc::ty::{self, Ty, Instance}; use rustc::ty::layout::{Size, Align, LayoutOf}; -use rustc::mir::interpret::{Scalar, Pointer, InterpResult, PointerArithmetic}; +use rustc::mir::interpret::{Scalar, Pointer, InterpResult, PointerArithmetic, InvalidProgramInfo}; use super::{InterpCx, InterpError, Machine, MemoryKind, FnVal}; @@ -83,7 +83,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.param_env, def_id, substs, - ).ok_or_else(|| InterpError::TooGeneric)?; + ).ok_or_else(|| InterpError::InvalidProgram(InvalidProgramInfo::TooGeneric))?; let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance)); let method_ptr = vtable.offset(ptr_size * (3 + i as u64), self)?; self.memory diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index da9780ac0a3..acbd2066d0e 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -11,7 +11,7 @@ use std::hash::Hash; use super::{ GlobalAlloc, InterpResult, InterpError, - OpTy, Machine, InterpCx, ValueVisitor, MPlaceTy, + OpTy, Machine, InterpCx, ValueVisitor, MPlaceTy, UnsupportedInfo::*, }; macro_rules! validation_failure { @@ -22,10 +22,10 @@ macro_rules! validation_failure { } else { format!(" at {}", where_) }; - err!(ValidationFailure(format!( + err!(Unsupported(ValidationFailure(format!( "encountered {}{}, but expected {}", $what, where_, $details, - ))) + )))) }}; ($what:expr, $where:expr) => {{ let where_ = path_format(&$where); @@ -34,10 +34,10 @@ macro_rules! validation_failure { } else { format!(" at {}", where_) }; - err!(ValidationFailure(format!( + err!(Unsupported(ValidationFailure(format!( "encountered {}{}", $what, where_, - ))) + )))) }}; } @@ -297,11 +297,11 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> match self.walk_value(op) { Ok(()) => Ok(()), Err(err) => match err.kind { - InterpError::InvalidDiscriminant(val) => + InterpError::Unsupported(InvalidDiscriminant(val)) => validation_failure!( val, self.path, "a valid enum discriminant" ), - InterpError::ReadPointerAsBytes => + InterpError::Unsupported(ReadPointerAsBytes) => validation_failure!( "a pointer", self.path, "plain (non-pointer) bytes" ), @@ -406,13 +406,13 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> ptr, size, align ); match err.kind { - InterpError::InvalidNullPointerUsage => + InterpError::Unsupported(InvalidNullPointerUsage) => return validation_failure!("NULL reference", self.path), - InterpError::AlignmentCheckFailed { required, has } => + InterpError::Unsupported(AlignmentCheckFailed { required, has }) => return validation_failure!(format!("unaligned reference \ (required {} byte alignment but found {})", required.bytes(), has.bytes()), self.path), - InterpError::ReadBytesAsPointer => + InterpError::Unsupported(ReadBytesAsPointer) => return validation_failure!( "dangling reference (created from integer)", self.path @@ -608,7 +608,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> Err(err) => { // For some errors we might be able to provide extra information match err.kind { - InterpError::ReadUndefBytes(offset) => { + InterpError::Unsupported(ReadUndefBytes(offset)) => { // Some byte was undefined, determine which // element that byte belongs to so we can // provide an index. diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 7a2d78b2e98..518489753a1 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -257,86 +257,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Err(error) => { let diagnostic = error_to_const_error(&self.ecx, error); use rustc::mir::interpret::InterpError::*; + use rustc::mir::interpret::UnsupportedInfo::*; match diagnostic.error { - // don't report these, they make no sense in a const prop context - | MachineError(_) - | Exit(_) - // at runtime these transformations might make sense - // FIXME: figure out the rules and start linting - | FunctionAbiMismatch(..) - | FunctionArgMismatch(..) - | FunctionRetMismatch(..) - | FunctionArgCountMismatch - // fine at runtime, might be a register address or sth - | ReadBytesAsPointer - // fine at runtime - | ReadForeignStatic - | Unimplemented(_) - // don't report const evaluator limits - | StackFrameLimitReached - | NoMirFor(..) - | InlineAsm - => {}, + Exit(_) => {}, - | InvalidMemoryAccess - | DanglingPointerDeref - | DoubleFree - | InvalidFunctionPointer - | InvalidBool - | InvalidDiscriminant(..) - | PointerOutOfBounds { .. } - | InvalidNullPointerUsage - | ValidationFailure(..) - | InvalidPointerMath - | ReadUndefBytes(_) - | DeadLocal - | InvalidBoolOp(_) - | DerefFunctionPointer - | ExecuteMemory - | Intrinsic(..) - | InvalidChar(..) - | AbiViolation(_) - | AlignmentCheckFailed{..} - | CalledClosureAsFunction - | VtableForArgumentlessMethod - | ModifiedConstantMemory - | ModifiedStatic - | AssumptionNotHeld - // FIXME: should probably be removed and turned into a bug! call - | TypeNotPrimitive(_) - | ReallocatedWrongMemoryKind(_, _) - | DeallocatedWrongMemoryKind(_, _) - | ReallocateNonBasePtr - | DeallocateNonBasePtr - | IncorrectAllocationInformation(..) - | UnterminatedCString(_) - | HeapAllocZeroBytes - | HeapAllocNonPowerOfTwoAlignment(_) - | Unreachable - | ReadFromReturnPointer - | ReferencedConstant - | InfiniteLoop - => { - // FIXME: report UB here - }, - - | OutOfTls - | TlsOutOfBounds - | PathNotFound(_) + | Unsupported(OutOfTls) + | Unsupported(TlsOutOfBounds) + | Unsupported(PathNotFound(_)) => bug!("these should not be in rustc, but in miri's machine errors"), - | Layout(_) - | UnimplementedTraitSelection - | TypeckError - | TooGeneric - // these are just noise - => {}, - - // non deterministic - | ReadPointerAsBytes - // FIXME: implement - => {}, - + | Unsupported(_) => {}, + | UndefinedBehaviour(_) => {}, + | InvalidProgram(_) => {}, + | ResourceExhaustion(_) => {}, + | Panic(_) => { diagnostic.report_as_lint(