Skip to content

Commit d91e63b

Browse files
authored
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
2 parents 75fd413 + 5d23518 commit d91e63b

File tree

2 files changed

+38
-14
lines changed

2 files changed

+38
-14
lines changed

src/librustc/mir/interpret/error.rs

+13-7
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@ CloneTypeFoldableImpls! {
4444
pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>;
4545
pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>;
4646

47-
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
47+
#[derive(Clone, Debug)]
4848
pub struct ConstEvalErr<'tcx> {
4949
pub span: Span,
5050
pub error: crate::mir::interpret::InterpError<'tcx>,
5151
pub stacktrace: Vec<FrameInfo<'tcx>>,
5252
}
5353

54-
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
54+
#[derive(Clone, Debug)]
5555
pub struct FrameInfo<'tcx> {
5656
/// This span is in the caller.
5757
pub call_site: Span,
@@ -331,7 +331,7 @@ impl<O: fmt::Debug> fmt::Debug for PanicInfo<O> {
331331
/// Error information for when the program we executed turned out not to actually be a valid
332332
/// program. This cannot happen in stand-alone Miri, but it can happen during CTFE/ConstProp
333333
/// where we work on generic code or execution does not have all information available.
334-
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
334+
#[derive(Clone, HashStable)]
335335
pub enum InvalidProgramInfo<'tcx> {
336336
/// Resolution can fail if we are in a too generic context.
337337
TooGeneric,
@@ -361,7 +361,7 @@ impl fmt::Debug for InvalidProgramInfo<'tcx> {
361361
}
362362

363363
/// Error information for when the program caused Undefined Behavior.
364-
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
364+
#[derive(Clone, HashStable)]
365365
pub enum UndefinedBehaviorInfo {
366366
/// Free-form case. Only for errors that are never caught!
367367
Ub(String),
@@ -394,11 +394,15 @@ impl fmt::Debug for UndefinedBehaviorInfo {
394394
///
395395
/// Currently, we also use this as fall-back error kind for errors that have not been
396396
/// categorized yet.
397-
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
397+
#[derive(Clone, HashStable)]
398398
pub enum UnsupportedOpInfo<'tcx> {
399399
/// Free-form case. Only for errors that are never caught!
400400
Unsupported(String),
401401

402+
/// When const-prop encounters a situation it does not support, it raises this error.
403+
/// This must not allocate for performance reasons.
404+
ConstPropUnsupported(&'tcx str),
405+
402406
// -- Everything below is not categorized yet --
403407
FunctionAbiMismatch(Abi, Abi),
404408
FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>),
@@ -559,13 +563,15 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> {
559563
not a power of two"),
560564
Unsupported(ref msg) =>
561565
write!(f, "{}", msg),
566+
ConstPropUnsupported(ref msg) =>
567+
write!(f, "Constant propagation encountered an unsupported situation: {}", msg),
562568
}
563569
}
564570
}
565571

566572
/// Error information for when the program exhausted the resources granted to it
567573
/// by the interpreter.
568-
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
574+
#[derive(Clone, HashStable)]
569575
pub enum ResourceExhaustionInfo {
570576
/// The stack grew too big.
571577
StackFrameLimitReached,
@@ -586,7 +592,7 @@ impl fmt::Debug for ResourceExhaustionInfo {
586592
}
587593
}
588594

589-
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
595+
#[derive(Clone, HashStable)]
590596
pub enum InterpError<'tcx> {
591597
/// The program panicked.
592598
Panic(PanicInfo<u64>),

src/librustc_mir/transform/const_prop.rs

+25-7
Original file line numberDiff line numberDiff line change
@@ -168,14 +168,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
168168
_ret: Option<(PlaceTy<'tcx>, BasicBlock)>,
169169
_unwind: Option<BasicBlock>
170170
) -> InterpResult<'tcx> {
171-
throw_unsup_format!("calling intrinsics isn't supported in ConstProp");
171+
throw_unsup!(ConstPropUnsupported("calling intrinsics isn't supported in ConstProp"));
172172
}
173173

174174
fn ptr_to_int(
175175
_mem: &Memory<'mir, 'tcx, Self>,
176176
_ptr: Pointer,
177177
) -> InterpResult<'tcx, u64> {
178-
throw_unsup_format!("ptr-to-int casts aren't supported in ConstProp");
178+
throw_unsup!(ConstPropUnsupported("ptr-to-int casts aren't supported in ConstProp"));
179179
}
180180

181181
fn binary_ptr_op(
@@ -185,7 +185,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
185185
_right: ImmTy<'tcx>,
186186
) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
187187
// We can't do this because aliasing of memory can differ between const eval and llvm
188-
throw_unsup_format!("pointer arithmetic or comparisons aren't supported in ConstProp");
188+
throw_unsup!(ConstPropUnsupported("pointer arithmetic or comparisons aren't supported \
189+
in ConstProp"));
189190
}
190191

191192
fn find_foreign_static(
@@ -218,7 +219,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
218219
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
219220
_dest: PlaceTy<'tcx>,
220221
) -> InterpResult<'tcx> {
221-
throw_unsup_format!("can't const prop `box` keyword");
222+
throw_unsup!(ConstPropUnsupported("can't const prop `box` keyword"));
222223
}
223224

224225
fn access_local(
@@ -229,7 +230,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
229230
let l = &frame.locals[local];
230231

231232
if l.value == LocalValue::Uninitialized {
232-
throw_unsup_format!("tried to access an uninitialized local");
233+
throw_unsup!(ConstPropUnsupported("tried to access an uninitialized local"));
233234
}
234235

235236
l.access()
@@ -241,7 +242,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
241242
// if the static allocation is mutable or if it has relocations (it may be legal to mutate
242243
// the memory behind that in the future), then we can't const prop it
243244
if allocation.mutability == Mutability::Mutable || allocation.relocations().len() > 0 {
244-
throw_unsup_format!("can't eval mutable statics in ConstProp");
245+
throw_unsup!(ConstPropUnsupported("can't eval mutable statics in ConstProp"));
245246
}
246247

247248
Ok(())
@@ -389,9 +390,26 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
389390
let r = match f(self) {
390391
Ok(val) => Some(val),
391392
Err(error) => {
392-
use rustc::mir::interpret::InterpError::*;
393+
use rustc::mir::interpret::{
394+
UnsupportedOpInfo,
395+
UndefinedBehaviorInfo,
396+
InterpError::*
397+
};
393398
match error.kind {
394399
Exit(_) => bug!("the CTFE program cannot exit"),
400+
401+
// Some error shouldn't come up because creating them causes
402+
// an allocation, which we should avoid. When that happens,
403+
// dedicated error variants should be introduced instead.
404+
// Only test this in debug builds though to avoid disruptions.
405+
Unsupported(UnsupportedOpInfo::Unsupported(_))
406+
| Unsupported(UnsupportedOpInfo::ValidationFailure(_))
407+
| UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
408+
| UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_))
409+
if cfg!(debug_assertions) => {
410+
bug!("const-prop encountered allocating error: {:?}", error.kind);
411+
}
412+
395413
Unsupported(_)
396414
| UndefinedBehavior(_)
397415
| InvalidProgram(_)

0 commit comments

Comments
 (0)