Skip to content

Commit 37c4b7f

Browse files
authored
Rollup merge of #70267 - RalfJung:const-prop-unsup, r=oli-obk,wesleywiser
get rid of ConstPropUnsupported; use ZST marker structs instead This gets rid of yet another machine-specific error variant. r? @oli-obk
2 parents ac78183 + e619b85 commit 37c4b7f

File tree

4 files changed

+56
-23
lines changed

4 files changed

+56
-23
lines changed

src/libcore/any.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ impl dyn Any {
164164
// Get `TypeId` of the type this function is instantiated with.
165165
let t = TypeId::of::<T>();
166166

167-
// Get `TypeId` of the type in the trait object.
167+
// Get `TypeId` of the type in the trait object (`self`).
168168
let concrete = self.type_id();
169169

170170
// Compare both `TypeId`s on equality.

src/librustc/mir/interpret/error.rs

+29-11
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc_hir as hir;
1414
use rustc_macros::HashStable;
1515
use rustc_session::CtfeBacktrace;
1616
use rustc_span::{def_id::DefId, Pos, Span};
17-
use std::{any::Any, fmt};
17+
use std::{any::Any, fmt, mem};
1818

1919
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable)]
2020
pub enum ErrorHandled {
@@ -449,9 +449,6 @@ impl fmt::Debug for UndefinedBehaviorInfo {
449449
pub enum UnsupportedOpInfo {
450450
/// Free-form case. Only for errors that are never caught!
451451
Unsupported(String),
452-
/// When const-prop encounters a situation it does not support, it raises this error.
453-
/// This must not allocate for performance reasons (hence `str`, not `String`).
454-
ConstPropUnsupported(&'static str),
455452
/// Accessing an unsupported foreign static.
456453
ReadForeignStatic(DefId),
457454
/// Could not find MIR for a function.
@@ -470,9 +467,6 @@ impl fmt::Debug for UnsupportedOpInfo {
470467
use UnsupportedOpInfo::*;
471468
match self {
472469
Unsupported(ref msg) => write!(f, "{}", msg),
473-
ConstPropUnsupported(ref msg) => {
474-
write!(f, "Constant propagation encountered an unsupported situation: {}", msg)
475-
}
476470
ReadForeignStatic(did) => {
477471
write!(f, "tried to read from foreign (extern) static {:?}", did)
478472
}
@@ -514,6 +508,29 @@ impl fmt::Debug for ResourceExhaustionInfo {
514508
}
515509
}
516510

511+
/// A trait to work around not having trait object upcasting.
512+
pub trait AsAny: Any {
513+
fn as_any(&self) -> &dyn Any;
514+
}
515+
516+
impl<T: Any> AsAny for T {
517+
#[inline(always)]
518+
fn as_any(&self) -> &dyn Any {
519+
self
520+
}
521+
}
522+
523+
/// A trait for machine-specific errors (or other "machine stop" conditions).
524+
pub trait MachineStopType: AsAny + fmt::Debug + Send {}
525+
impl MachineStopType for String {}
526+
527+
impl dyn MachineStopType {
528+
#[inline(always)]
529+
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
530+
self.as_any().downcast_ref()
531+
}
532+
}
533+
517534
pub enum InterpError<'tcx> {
518535
/// The program caused undefined behavior.
519536
UndefinedBehavior(UndefinedBehaviorInfo),
@@ -527,7 +544,7 @@ pub enum InterpError<'tcx> {
527544
ResourceExhaustion(ResourceExhaustionInfo),
528545
/// Stop execution for a machine-controlled reason. This is never raised by
529546
/// the core engine itself.
530-
MachineStop(Box<dyn Any + Send>),
547+
MachineStop(Box<dyn MachineStopType>),
531548
}
532549

533550
pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>;
@@ -547,7 +564,7 @@ impl fmt::Debug for InterpError<'_> {
547564
InvalidProgram(ref msg) => write!(f, "{:?}", msg),
548565
UndefinedBehavior(ref msg) => write!(f, "{:?}", msg),
549566
ResourceExhaustion(ref msg) => write!(f, "{:?}", msg),
550-
MachineStop(_) => bug!("unhandled MachineStop"),
567+
MachineStop(ref msg) => write!(f, "{:?}", msg),
551568
}
552569
}
553570
}
@@ -558,8 +575,9 @@ impl InterpError<'_> {
558575
/// waste of resources.
559576
pub fn allocates(&self) -> bool {
560577
match self {
561-
InterpError::MachineStop(_)
562-
| InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
578+
// Zero-sized boxes do not allocate.
579+
InterpError::MachineStop(b) => mem::size_of_val::<dyn MachineStopType>(&**b) > 0,
580+
InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
563581
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure(_))
564582
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) => true,
565583
_ => false,

src/librustc/mir/interpret/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ mod value;
9797

9898
pub use self::error::{
9999
struct_error, ConstEvalErr, ConstEvalRawResult, ConstEvalResult, ErrorHandled, FrameInfo,
100-
InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, ResourceExhaustionInfo,
101-
UndefinedBehaviorInfo, UnsupportedOpInfo,
100+
InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType,
101+
ResourceExhaustionInfo, UndefinedBehaviorInfo, UnsupportedOpInfo,
102102
};
103103

104104
pub use self::value::{get_slice_bytes, ConstValue, RawConst, Scalar, ScalarMaybeUndef};

src/librustc_mir/transform/const_prop.rs

+24-9
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,24 @@ use crate::transform::{MirPass, MirSource};
3939
/// The maximum number of bytes that we'll allocate space for a return value.
4040
const MAX_ALLOC_LIMIT: u64 = 1024;
4141

42+
/// Macro for machine-specific `InterpError` without allocation.
43+
/// (These will never be shown to the user, but they help diagnose ICEs.)
44+
macro_rules! throw_machine_stop_str {
45+
($($tt:tt)*) => {{
46+
// We make a new local type for it. The type itself does not carry any information,
47+
// but its vtable (for the `MachineStopType` trait) does.
48+
struct Zst;
49+
// Debug-printing this type shows the desired string.
50+
impl std::fmt::Debug for Zst {
51+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52+
write!(f, $($tt)*)
53+
}
54+
}
55+
impl rustc::mir::interpret::MachineStopType for Zst {}
56+
throw_machine_stop!(Zst)
57+
}};
58+
}
59+
4260
pub struct ConstProp;
4361

4462
impl<'tcx> MirPass<'tcx> for ConstProp {
@@ -192,7 +210,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
192210
_ret: Option<(PlaceTy<'tcx>, BasicBlock)>,
193211
_unwind: Option<BasicBlock>,
194212
) -> InterpResult<'tcx> {
195-
throw_unsup!(ConstPropUnsupported("calling intrinsics isn't supported in ConstProp"))
213+
throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
196214
}
197215

198216
fn assert_panic(
@@ -204,7 +222,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
204222
}
205223

206224
fn ptr_to_int(_mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx, u64> {
207-
throw_unsup!(ConstPropUnsupported("ptr-to-int casts aren't supported in ConstProp"))
225+
throw_unsup!(ReadPointerAsBytes)
208226
}
209227

210228
fn binary_ptr_op(
@@ -214,10 +232,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
214232
_right: ImmTy<'tcx>,
215233
) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
216234
// We can't do this because aliasing of memory can differ between const eval and llvm
217-
throw_unsup!(ConstPropUnsupported(
218-
"pointer arithmetic or comparisons aren't supported \
219-
in ConstProp"
220-
))
235+
throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp")
221236
}
222237

223238
#[inline(always)]
@@ -238,7 +253,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
238253
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
239254
_dest: PlaceTy<'tcx>,
240255
) -> InterpResult<'tcx> {
241-
throw_unsup!(ConstPropUnsupported("can't const prop `box` keyword"))
256+
throw_machine_stop_str!("can't const prop heap allocations")
242257
}
243258

244259
fn access_local(
@@ -249,7 +264,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
249264
let l = &frame.locals[local];
250265

251266
if l.value == LocalValue::Uninitialized {
252-
throw_unsup!(ConstPropUnsupported("tried to access an uninitialized local"));
267+
throw_machine_stop_str!("tried to access an uninitialized local")
253268
}
254269

255270
l.access()
@@ -262,7 +277,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
262277
// if the static allocation is mutable or if it has relocations (it may be legal to mutate
263278
// the memory behind that in the future), then we can't const prop it
264279
if allocation.mutability == Mutability::Mut || allocation.relocations().len() > 0 {
265-
throw_unsup!(ConstPropUnsupported("can't eval mutable statics in ConstProp"));
280+
throw_machine_stop_str!("can't eval mutable statics in ConstProp")
266281
}
267282

268283
Ok(())

0 commit comments

Comments
 (0)