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
This commit is contained in:
commit
d91e63b7a2
|
@ -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>),
|
||||
|
|
|
@ -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(_)
|
||||
|
|
Loading…
Reference in New Issue