diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-12-01 04:49:27 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-12-01 04:49:27 +0100 |
| commit | d91e63b7a2b92a66e6dd34dd76485fd906447111 (patch) | |
| tree | 997fabe151f83fd3eb4325e1bfe8cd9adb60655e | |
| parent | 75fd413e7b5eefacfc85b8c313fe3dfbc149ed1e (diff) | |
| parent | 5d23518a12548fdbbca74fcc3171fdc2f3888334 (diff) | |
| download | rust-d91e63b7a2b92a66e6dd34dd76485fd906447111.tar.gz rust-d91e63b7a2b92a66e6dd34dd76485fd906447111.zip | |
Rollup merge of #66832 - RalfJung:const-prop-no-alloc, r=oli-obk
const_prop: detect and avoid catching Miri errors that require allocation r? @wesleywiser @oli-obk
| -rw-r--r-- | src/librustc/mir/interpret/error.rs | 20 | ||||
| -rw-r--r-- | src/librustc_mir/transform/const_prop.rs | 32 |
2 files changed, 38 insertions, 14 deletions
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 98e6770c70d..9f133597ab4 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -44,14 +44,14 @@ CloneTypeFoldableImpls! { pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>; pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>; -#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug)] pub struct ConstEvalErr<'tcx> { pub span: Span, pub error: crate::mir::interpret::InterpError<'tcx>, pub stacktrace: Vec<FrameInfo<'tcx>>, } -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Clone, Debug)] pub struct FrameInfo<'tcx> { /// This span is in the caller. pub call_site: Span, @@ -331,7 +331,7 @@ impl<O: fmt::Debug> fmt::Debug for PanicInfo<O> { /// Error information for when the program we executed turned out not to actually be a valid /// program. This cannot happen in stand-alone Miri, but it can happen during CTFE/ConstProp /// where we work on generic code or execution does not have all information available. -#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Clone, HashStable)] pub enum InvalidProgramInfo<'tcx> { /// Resolution can fail if we are in a too generic context. TooGeneric, @@ -361,7 +361,7 @@ impl fmt::Debug for InvalidProgramInfo<'tcx> { } /// Error information for when the program caused Undefined Behavior. -#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Clone, HashStable)] pub enum UndefinedBehaviorInfo { /// Free-form case. Only for errors that are never caught! Ub(String), @@ -394,11 +394,15 @@ impl fmt::Debug for UndefinedBehaviorInfo { /// /// Currently, we also use this as fall-back error kind for errors that have not been /// categorized yet. -#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Clone, HashStable)] pub enum UnsupportedOpInfo<'tcx> { /// 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. + ConstPropUnsupported(&'tcx str), + // -- Everything below is not categorized yet -- FunctionAbiMismatch(Abi, Abi), FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>), @@ -559,13 +563,15 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> { not a power of two"), Unsupported(ref msg) => write!(f, "{}", msg), + ConstPropUnsupported(ref msg) => + write!(f, "Constant propagation encountered an unsupported situation: {}", msg), } } } /// Error information for when the program exhausted the resources granted to it /// by the interpreter. -#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Clone, HashStable)] pub enum ResourceExhaustionInfo { /// The stack grew too big. StackFrameLimitReached, @@ -586,7 +592,7 @@ impl fmt::Debug for ResourceExhaustionInfo { } } -#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Clone, HashStable)] pub enum InterpError<'tcx> { /// The program panicked. Panic(PanicInfo<u64>), diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index d2740cf3771..0fe75301fc1 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -168,14 +168,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { _ret: Option<(PlaceTy<'tcx>, BasicBlock)>, _unwind: Option<BasicBlock> ) -> InterpResult<'tcx> { - throw_unsup_format!("calling intrinsics isn't supported in ConstProp"); + throw_unsup!(ConstPropUnsupported("calling intrinsics isn't supported in ConstProp")); } fn ptr_to_int( _mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer, ) -> InterpResult<'tcx, u64> { - throw_unsup_format!("ptr-to-int casts aren't supported in ConstProp"); + throw_unsup!(ConstPropUnsupported("ptr-to-int casts aren't supported in ConstProp")); } fn binary_ptr_op( @@ -185,7 +185,8 @@ 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_format!("pointer arithmetic or comparisons aren't supported in ConstProp"); + throw_unsup!(ConstPropUnsupported("pointer arithmetic or comparisons aren't supported \ + in ConstProp")); } fn find_foreign_static( @@ -218,7 +219,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { _ecx: &mut InterpCx<'mir, 'tcx, Self>, _dest: PlaceTy<'tcx>, ) -> InterpResult<'tcx> { - throw_unsup_format!("can't const prop `box` keyword"); + throw_unsup!(ConstPropUnsupported("can't const prop `box` keyword")); } fn access_local( @@ -229,7 +230,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { let l = &frame.locals[local]; if l.value == LocalValue::Uninitialized { - throw_unsup_format!("tried to access an uninitialized local"); + throw_unsup!(ConstPropUnsupported("tried to access an uninitialized local")); } l.access() @@ -241,7 +242,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::Mutable || allocation.relocations().len() > 0 { - throw_unsup_format!("can't eval mutable statics in ConstProp"); + throw_unsup!(ConstPropUnsupported("can't eval mutable statics in ConstProp")); } Ok(()) @@ -389,9 +390,26 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let r = match f(self) { Ok(val) => Some(val), Err(error) => { - use rustc::mir::interpret::InterpError::*; + use rustc::mir::interpret::{ + UnsupportedOpInfo, + UndefinedBehaviorInfo, + InterpError::* + }; match error.kind { Exit(_) => bug!("the CTFE program cannot exit"), + + // Some error shouldn't come up because creating them causes + // an allocation, which we should avoid. When that happens, + // dedicated error variants should be introduced instead. + // Only test this in debug builds though to avoid disruptions. + Unsupported(UnsupportedOpInfo::Unsupported(_)) + | Unsupported(UnsupportedOpInfo::ValidationFailure(_)) + | UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) + | UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) + if cfg!(debug_assertions) => { + bug!("const-prop encountered allocating error: {:?}", error.kind); + } + Unsupported(_) | UndefinedBehavior(_) | InvalidProgram(_) |
