diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs index f41b68bb1f7ed..072338540140c 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -49,7 +49,8 @@ impl HasStaticRootDefId for DummyMachine { impl<'tcx> interpret::Machine<'tcx> for DummyMachine { interpret::compile_time_machine!(<'tcx>); - const PANIC_ON_ALLOC_FAIL: bool = true; + const ALLOC_FAILURE_REPORTING: interpret::AllocFailureReporting = + interpret::AllocFailureReporting::Suppress; // We want to just eval random consts in the program, so `eval_mir_const` can fail. const ALL_CONSTS_ARE_PRECHECKED: bool = false; diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index e88123334dd52..57f4b6b715b30 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -396,7 +396,8 @@ impl<'tcx> CompileTimeMachine<'tcx> { impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { compile_time_machine!(<'tcx>); - const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error + const ALLOC_FAILURE_REPORTING: interpret::AllocFailureReporting = + interpret::AllocFailureReporting::Emit; #[inline(always)] fn enforce_alignment(ecx: &InterpCx<'tcx, Self>) -> bool { diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 62ca47d23b4ce..1021377486f19 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -45,6 +45,11 @@ pub trait MayLeak: Copy { fn may_leak(self) -> bool; } +pub enum AllocFailureReporting { + Emit, + Suppress, +} + /// The functionality needed by memory to manage its allocations pub trait AllocMap { /// Tests if the map contains the given key. @@ -139,8 +144,8 @@ pub trait Machine<'tcx>: Sized { /// that is added to the memory so that the work is not done twice. const GLOBAL_KIND: Option; - /// Should the machine panic on allocation failures? - const PANIC_ON_ALLOC_FAIL: bool; + /// How should allocation failures be surfaced? + const ALLOC_FAILURE_REPORTING: AllocFailureReporting = AllocFailureReporting::Emit; /// Determines whether `eval_mir_constant` can never fail because all required consts have /// already been checked before. diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 7b67d3acd555e..4f15278de9cb5 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -22,10 +22,10 @@ use rustc_middle::{bug, throw_ub_format}; use tracing::{debug, instrument, trace}; use super::{ - AllocBytes, AllocId, AllocInit, AllocMap, AllocRange, Allocation, CheckAlignMsg, - CheckInAllocMsg, CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine, - MayLeak, Misalignment, Pointer, PointerArithmetic, Provenance, Scalar, alloc_range, err_ub, - err_ub_custom, interp_ok, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format, + AllocBytes, AllocFailureReporting, AllocId, AllocInit, AllocMap, AllocRange, Allocation, + CheckAlignMsg, CheckInAllocMsg, CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, + Machine, MayLeak, Misalignment, Pointer, PointerArithmetic, Provenance, Scalar, alloc_range, + err_ub, err_ub_custom, interp_ok, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format, }; use crate::const_eval::ConstEvalErrKind; @@ -258,10 +258,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { init: AllocInit, ) -> InterpResult<'tcx, Pointer> { let params = self.machine.get_default_alloc_params(); - let alloc = if M::PANIC_ON_ALLOC_FAIL { - Allocation::new(size, align, init, params) - } else { - Allocation::try_new(size, align, init, params)? + let alloc = match M::ALLOC_FAILURE_REPORTING { + AllocFailureReporting::Emit => Allocation::try_new(size, align, init, params)?, + AllocFailureReporting::Suppress => { + Allocation::try_new_silent(size, align, init, params)? + } }; self.insert_allocation(alloc, kind) } diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index c1d32e0f7bfbe..3b5234687cb9c 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -29,7 +29,9 @@ pub use self::intern::{ HasStaticRootDefId, InternError, InternKind, intern_const_alloc_for_constprop, intern_const_alloc_recursive, }; -pub use self::machine::{AllocMap, Machine, MayLeak, ReturnAction, compile_time_machine}; +pub use self::machine::{ + AllocFailureReporting, AllocMap, Machine, MayLeak, ReturnAction, compile_time_machine, +}; pub use self::memory::{AllocInfo, AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind}; use self::operand::Operand; pub use self::operand::{ImmTy, Immediate, OpTy}; diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 1cfe5219997b1..f0aa00be1ca60 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -468,6 +468,20 @@ impl Allocation { .into() } + /// Try to create an Allocation of `size` bytes, failing if there is not enough memory + /// available to the compiler to do so, without emitting a bug. + pub fn try_new_silent<'tcx>( + size: Size, + align: Align, + init: AllocInit, + params: ::AllocParams, + ) -> InterpResult<'tcx, Self> { + Self::new_inner(size, align, init, params, || { + InterpErrorKind::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted) + }) + .into() + } + /// Try to create an Allocation of `size` bytes, panics if there is not enough memory /// available to the compiler to do so. /// diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 7883673cdd6a2..d2fdf79f2403d 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1108,7 +1108,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { const GLOBAL_KIND: Option = Some(MiriMemoryKind::Global); - const PANIC_ON_ALLOC_FAIL: bool = false; + const ALLOC_FAILURE_REPORTING: interpret::AllocFailureReporting = + interpret::AllocFailureReporting::Emit; #[inline(always)] fn enforce_alignment(ecx: &MiriInterpCx<'tcx>) -> bool { diff --git a/tests/ui/mir/gvn-memory-exhausted-no-ice.rs b/tests/ui/mir/gvn-memory-exhausted-no-ice.rs new file mode 100644 index 0000000000000..5840b323462b5 --- /dev/null +++ b/tests/ui/mir/gvn-memory-exhausted-no-ice.rs @@ -0,0 +1,24 @@ +//@ compile-flags: -Zmir-opt-level=5 +//@ check-pass +//@ only-64bit + +#![feature(maybe_uninit_as_bytes)] + +use std::mem::MaybeUninit; +use std::ptr::from_ref; + +const N: usize = 0x0000_7ff0_0000_0000; + +#[inline(never)] +pub fn g(n: &u8) { + let mut xs = MaybeUninit::<[u8; N]>::uninit(); + let base = from_ref(&xs.as_bytes()[0]).addr(); + let index = from_ref(n).addr() - base; + xs.as_bytes_mut()[index].write(42); +} + +pub fn main() { + let n = Box::new(27); + g(&n); + std::process::exit(*n as i32); +}