From d04da1125d8583e7ae85491eb764c19564b2ab19 Mon Sep 17 00:00:00 2001 From: Smitty Date: Tue, 29 Jun 2021 20:22:32 -0400 Subject: [PATCH] Properly handle const prop failures --- .../rustc_middle/src/mir/interpret/allocation.rs | 13 ++++++++----- compiler/rustc_middle/src/mir/interpret/error.rs | 6 ++++++ compiler/rustc_middle/src/ty/vtable.rs | 2 +- compiler/rustc_mir/src/transform/const_prop.rs | 13 +++++++++++++ 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 550eb84fc87..9bc41da1b46 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -131,11 +131,14 @@ impl Allocation { // available to the compiler can change between runs. Normally queries are always // deterministic. However, we can be non-determinstic here because all uses of const // evaluation do one of: - // - cause a fatal compiler error when they see this error as the result of const - // evaluation - // - panic on evaluation failure - // - always evaluate very small constants that are practically unlikely to result in - // memory exhaustion + // - error on failure + // - used for static initalizer evalution + // - used for const value evaluation + // - const prop errors on this since otherwise it would generate different code based + // on available memory + // - panic on failure to allocate very small sizes + // - actually panicking won't happen since there wouldn't be enough memory to panic + // - used for caller location evaluation InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted) })?; bytes.resize(size.bytes_usize(), 0); diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index ab9239585c4..2e461015b62 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -535,4 +535,10 @@ impl InterpError<'_> { _ => false, } } + + /// Did the error originate from volatile conditons such as the memory available to the + /// interpreter? + pub fn is_spurious(&self) -> bool { + matches!(self, InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted)) + } } diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index 61c146d03a3..0230e05c12e 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -1,6 +1,6 @@ use std::convert::TryFrom; -use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar, InterpResult}; +use crate::mir::interpret::{alloc_range, AllocId, Allocation, InterpResult, Pointer, Scalar}; use crate::ty::fold::TypeFoldable; use crate::ty::{self, DefId, SubstsRef, Ty, TyCtxt}; use rustc_ast::Mutability; diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index a660b145b3f..3264f16eccd 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -478,6 +478,19 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Ok(op) => Some(op), Err(error) => { let tcx = self.ecx.tcx.at(c.span); + if error.kind().is_spurious() { + // Spurious errors can't be ignored since otherwise the amount of available + // memory influences the result of optimization and the build. The error + // doesn't need to be fatal since no code will actually be generated anyways. + self.ecx + .tcx + .tcx + .sess + .struct_err("memory exhausted during optimization") + .help("try increasing the amount of memory available to the compiler") + .emit(); + return None; + } let err = ConstEvalErr::new(&self.ecx, error, Some(c.span)); if let Some(lint_root) = self.lint_root(source_info) { let lint_only = match c.literal {