From c6974344a5707c054ed808ea9c724dd93ec3c680 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Nov 2024 08:42:42 +0100 Subject: [PATCH] interpret: do not ICE when a promoted fails with OOM --- compiler/rustc_const_eval/src/const_eval/error.rs | 9 ++++++++- .../src/interpret/eval_context.rs | 3 +++ compiler/rustc_middle/src/mir/interpret/error.rs | 15 +++++++++++++-- tests/crashes/130687.rs | 4 ---- ...promoted_running_out_of_memory_issue-130687.rs | 12 ++++++++++++ ...oted_running_out_of_memory_issue-130687.stderr | 15 +++++++++++++++ 6 files changed, 51 insertions(+), 7 deletions(-) delete mode 100644 tests/crashes/130687.rs create mode 100644 tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs create mode 100644 tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 6686413bf0254..1271d9d2d0da6 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -152,13 +152,20 @@ where let span = span.substitute_dummy(our_span); let err = mk(span, frames); let mut err = tcx.dcx().create_err(err); + let can_be_spurious = matches!(error, InterpErrorKind::ResourceExhaustion(_)); let msg = error.diagnostic_message(); error.add_args(&mut err); // Use *our* span to label the interp error err.span_label(our_span, msg); - ErrorHandled::Reported(err.emit().into(), span) + let g = err.emit(); + let reported = if can_be_spurious { + ReportedErrorInfo::spurious(g) + } else { + ReportedErrorInfo::from(g) + }; + ErrorHandled::Reported(reported, span) } } } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index ff6d5b28b3bc4..eb574bd5f7716 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -596,6 +596,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // const-eval will return "tainted" errors if e.g. the layout cannot // be computed as the type references non-existing names. // See . + } else if reported.can_be_spurious() { + // These errors can just sometimes happen, even when the expression + // is nominally "infallible", e.g. when running out of memory. } else { // Looks like the const is not captured by `required_consts`, that's bad. span_bug!(span, "interpret const eval failure of {val:?} which is not in required_consts"); diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 8ec7e1851a51b..08afa33c6b432 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -59,22 +59,33 @@ impl ErrorHandled { pub struct ReportedErrorInfo { error: ErrorGuaranteed, is_tainted_by_errors: bool, + /// Whether this is the kind of error that can sometimes occur, and sometimes not. + /// Used for resource exhaustion errors. + can_be_spurious: bool, } impl ReportedErrorInfo { #[inline] pub fn tainted_by_errors(error: ErrorGuaranteed) -> ReportedErrorInfo { - ReportedErrorInfo { is_tainted_by_errors: true, error } + ReportedErrorInfo { is_tainted_by_errors: true, can_be_spurious: false, error } } + #[inline] + pub fn spurious(error: ErrorGuaranteed) -> ReportedErrorInfo { + ReportedErrorInfo { can_be_spurious: true, is_tainted_by_errors: false, error } + } + pub fn is_tainted_by_errors(&self) -> bool { self.is_tainted_by_errors } + pub fn can_be_spurious(&self) -> bool { + self.can_be_spurious + } } impl From for ReportedErrorInfo { #[inline] fn from(error: ErrorGuaranteed) -> ReportedErrorInfo { - ReportedErrorInfo { is_tainted_by_errors: false, error } + ReportedErrorInfo { is_tainted_by_errors: false, can_be_spurious: false, error } } } diff --git a/tests/crashes/130687.rs b/tests/crashes/130687.rs deleted file mode 100644 index 361be0905dfca..0000000000000 --- a/tests/crashes/130687.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ known-bug: #130687 -//@ only-x86_64 -pub struct Data([u8; usize::MAX >> 16]); -const _: &'static Data = &Data([0; usize::MAX >> 16]); diff --git a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs new file mode 100644 index 0000000000000..b923a768cbfe5 --- /dev/null +++ b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs @@ -0,0 +1,12 @@ +//! Ensure we do not ICE when a promoted fails to evaluate due to running out of memory. +//! Also see . + +// Needs the max type size to be much bigger than the RAM people typically have. +//@ only-64bit + +pub struct Data([u8; (1 << 47) - 1]); +const _: &'static Data = &Data([0; (1 << 47) - 1]); +//~^ERROR: evaluation of constant value failed +//~| tried to allocate more memory than available to compiler + +fn main() {} diff --git a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr new file mode 100644 index 0000000000000..50e920f05f930 --- /dev/null +++ b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr @@ -0,0 +1,15 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/promoted_running_out_of_memory_issue-130687.rs:8:32 + | +LL | const _: &'static Data = &Data([0; (1 << 47) - 1]); + | ^^^^^^^^^^^^^^^^^^ tried to allocate more memory than available to compiler + +note: erroneous constant encountered + --> $DIR/promoted_running_out_of_memory_issue-130687.rs:8:26 + | +LL | const _: &'static Data = &Data([0; (1 << 47) - 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`.