Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

get rid of ConstPropUnsupported; use ZST marker structs instead #70267

Merged
merged 4 commits into from
Mar 24, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/libcore/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
49 changes: 38 additions & 11 deletions src/librustc/mir/interpret/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand All @@ -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)
}
Expand Down Expand Up @@ -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.
RalfJung marked this conversation as resolved.
Show resolved Hide resolved
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),
Expand All @@ -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>>;
Expand All @@ -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),
}
}
}
Expand All @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/mir/interpret/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down
32 changes: 22 additions & 10 deletions src/librustc_mir/transform/const_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -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 {}
RalfJung marked this conversation as resolved.
Show resolved Hide resolved
throw_machine_stop!(ConstPropIntrinsic)
}

fn assert_panic(
Expand All @@ -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(
Expand All @@ -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)]
Expand All @@ -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(
Expand All @@ -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()
Expand All @@ -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(())
Expand Down