Skip to content

Commit 3e20129

Browse files
committed
Delay ICE on evaluation fail
1 parent 12a8d10 commit 3e20129

File tree

2 files changed

+20
-68
lines changed

2 files changed

+20
-68
lines changed

compiler/rustc_middle/src/mir/interpret/allocation.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ use std::ptr;
88

99
use rustc_ast::Mutability;
1010
use rustc_data_structures::sorted_map::SortedMap;
11+
use rustc_span::DUMMY_SP;
1112
use rustc_target::abi::{Align, HasDataLayout, Size};
1213

1314
use super::{
1415
read_target_uint, write_target_uint, AllocId, InterpError, InterpResult, Pointer,
1516
ResourceExhaustionInfo, Scalar, ScalarMaybeUninit, UndefinedBehaviorInfo, UninitBytesAccess,
1617
UnsupportedOpInfo,
1718
};
19+
use crate::ty;
1820

1921
/// This type represents an Allocation in the Miri/CTFE core engine.
2022
///
@@ -132,6 +134,9 @@ impl<Tag> Allocation<Tag> {
132134
// deterministic. However, we can be non-determinstic here because all uses of const
133135
// evaluation (including ConstProp!) will make compilation fail (via hard error
134136
// or ICE) upon encountering a `MemoryExhausted` error.
137+
ty::tls::with(|tcx| {
138+
tcx.sess.delay_span_bug(DUMMY_SP, "exhausted memory during interpreation")
139+
});
135140
InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted)
136141
})?;
137142
bytes.resize(size.bytes_usize(), 0);

compiler/rustc_mir/src/transform/const_prop.rs

Lines changed: 15 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ use rustc_trait_selection::traits;
3131
use crate::const_eval::ConstEvalErr;
3232
use crate::interpret::{
3333
self, compile_time_machine, AllocId, Allocation, ConstValue, CtfeValidationMode, Frame, ImmTy,
34-
Immediate, InterpCx, InterpError, InterpResult, LocalState, LocalValue, MemPlace, Memory,
35-
MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer, ResourceExhaustionInfo, Scalar,
36-
ScalarMaybeUninit, StackPopCleanup, StackPopUnwind,
34+
Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, Memory, MemoryKind, OpTy,
35+
Operand as InterpOperand, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, StackPopCleanup,
36+
StackPopUnwind,
3737
};
3838
use crate::transform::MirPass;
3939

@@ -393,12 +393,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
393393
.filter(|ret_layout| {
394394
!ret_layout.is_zst() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)
395395
})
396-
.and_then(|ret_layout| {
397-
let alloc = ecx.allocate(ret_layout, MemoryKind::Stack);
398-
Self::check_interpresult(tcx, &alloc);
399-
alloc.ok()
400-
})
401-
.map(Into::into);
396+
.map(|ret_layout| {
397+
ecx.allocate(ret_layout, MemoryKind::Stack)
398+
.expect("couldn't perform small allocation")
399+
.into()
400+
});
402401

403402
ecx.push_stack_frame(
404403
Instance::new(def_id, substs),
@@ -421,27 +420,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
421420
}
422421
}
423422

424-
/// Some `InterpError`s could be ignored but must not be to ensure that queries are stable.
425-
fn check_interpresult<T>(tcx: TyCtxt<'tcx>, error: &InterpResult<'tcx, T>) {
426-
if let Err(e) = error {
427-
if matches!(
428-
e.kind(),
429-
InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted)
430-
) {
431-
// Memory errors can't be ignored since otherwise the amount of available
432-
// memory influences the result of optimization and the build. The error
433-
// doesn't need to be fatal since no code will actually be generated anyways.
434-
tcx.sess.fatal("memory exhausted during optimization");
435-
}
436-
}
437-
}
438-
439423
fn get_const(&self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
440424
let op = match self.ecx.eval_place_to_op(place, None) {
441425
Ok(op) => op,
442426
Err(e) => {
443427
trace!("get_const failed: {}", e);
444-
Self::check_interpresult::<()>(self.tcx, &Err(e));
445428
return None;
446429
}
447430
};
@@ -513,19 +496,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
513496
},
514497
ConstantKind::Val(_, ty) => ty.needs_subst(),
515498
};
516-
// Memory errors can't be ignored since otherwise the amount of available
517-
// memory influences the result of optimization and the build. The error
518-
// doesn't need to be fatal since no code will actually be generated anyways.
519-
// FIXME(#86255): use err.error.is_hard_err(), but beware of backwards
520-
// compatibility and interactions with promoteds
521-
if lint_only
522-
&& !matches!(
523-
err.error,
524-
InterpError::ResourceExhaustion(
525-
ResourceExhaustionInfo::MemoryExhausted,
526-
),
527-
)
528-
{
499+
if lint_only {
529500
// Out of backwards compatibility we cannot report hard errors in unused
530501
// generic functions using associated constants of the generic parameters.
531502
err.report_as_lint(tcx, "erroneous constant used", lint_root, Some(c.span));
@@ -543,12 +514,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
543514
/// Returns the value, if any, of evaluating `place`.
544515
fn eval_place(&mut self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
545516
trace!("eval_place(place={:?})", place);
546-
let tcx = self.tcx;
547-
self.use_ecx(|this| {
548-
let val = this.ecx.eval_place_to_op(place, None);
549-
Self::check_interpresult(tcx, &val);
550-
val
551-
})
517+
self.use_ecx(|this| this.ecx.eval_place_to_op(place, None))
552518
}
553519

554520
/// Returns the value, if any, of evaluating `op`. Calls upon `eval_constant`
@@ -609,17 +575,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
609575
right: &Operand<'tcx>,
610576
source_info: SourceInfo,
611577
) -> Option<()> {
612-
let tcx = self.tcx;
613-
let r = self.use_ecx(|this| {
614-
let val = this.ecx.read_immediate(&this.ecx.eval_operand(right, None)?);
615-
Self::check_interpresult(tcx, &val);
616-
val
617-
});
618-
let l = self.use_ecx(|this| {
619-
let val = this.ecx.read_immediate(&this.ecx.eval_operand(left, None)?);
620-
Self::check_interpresult(tcx, &val);
621-
val
622-
});
578+
let r = self.use_ecx(|this| this.ecx.read_immediate(&this.ecx.eval_operand(right, None)?));
579+
let l = self.use_ecx(|this| this.ecx.read_immediate(&this.ecx.eval_operand(left, None)?));
623580
// Check for exceeding shifts *even if* we cannot evaluate the LHS.
624581
if op == BinOp::Shr || op == BinOp::Shl {
625582
let r = r?;
@@ -785,24 +742,18 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
785742
rvalue: &Rvalue<'tcx>,
786743
place: Place<'tcx>,
787744
) -> Option<()> {
788-
let tcx = self.tcx;
789745
self.use_ecx(|this| {
790746
match rvalue {
791747
Rvalue::BinaryOp(op, box (left, right))
792748
| Rvalue::CheckedBinaryOp(op, box (left, right)) => {
793749
let l = this.ecx.eval_operand(left, None);
794750
let r = this.ecx.eval_operand(right, None);
795-
Self::check_interpresult(tcx, &l);
796-
Self::check_interpresult(tcx, &r);
797751

798752
let const_arg = match (l, r) {
799753
(Ok(ref x), Err(_)) | (Err(_), Ok(ref x)) => this.ecx.read_immediate(x)?,
800754
(Err(e), Err(_)) => return Err(e),
801755
(Ok(_), Ok(_)) => {
802-
Self::check_interpresult(
803-
tcx,
804-
&this.ecx.eval_rvalue_into_place(rvalue, place),
805-
);
756+
this.ecx.eval_rvalue_into_place(rvalue, place)?;
806757
return Ok(());
807758
}
808759
};
@@ -838,16 +789,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
838789
}
839790
}
840791
_ => {
841-
let res = this.ecx.eval_rvalue_into_place(rvalue, place);
842-
Self::check_interpresult(tcx, &res);
843-
res?
792+
this.ecx.eval_rvalue_into_place(rvalue, place)?;
844793
}
845794
}
846795
}
847796
_ => {
848-
let res = this.ecx.eval_rvalue_into_place(rvalue, place);
849-
Self::check_interpresult(tcx, &res);
850-
res?
797+
this.ecx.eval_rvalue_into_place(rvalue, place)?;
851798
}
852799
}
853800

0 commit comments

Comments
 (0)