From e190f0d974bc0cc43cc41b2d9c9f963b6af2ec50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sun, 14 Feb 2021 00:00:00 +0000 Subject: [PATCH 1/2] Reduce size of InterpErrorInfo to 8 bytes --- .../rustc_middle/src/mir/interpret/error.rs | 28 +++++++++++++++---- compiler/rustc_mir/src/const_eval/error.rs | 6 +++- .../rustc_mir/src/const_eval/eval_queries.rs | 2 +- compiler/rustc_mir/src/const_eval/machine.rs | 4 +-- compiler/rustc_mir/src/interpret/intern.rs | 2 +- compiler/rustc_mir/src/interpret/validity.rs | 27 ++++++++++-------- .../rustc_mir/src/transform/const_prop.rs | 2 +- 7 files changed, 47 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index cf931ece712b0..26ce3c2c3db8a 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -40,29 +40,45 @@ pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<' struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg) } +#[cfg(target_arch = "x86_64")] +static_assert_size!(InterpErrorInfo<'_>, 8); + /// Packages the kind of error we got from the const code interpreter /// up with a Rust-level backtrace of where the error occurred. /// Thsese should always be constructed by calling `.into()` on /// a `InterpError`. In `librustc_mir::interpret`, we have `throw_err_*` /// macros for this. #[derive(Debug)] -pub struct InterpErrorInfo<'tcx> { - pub kind: InterpError<'tcx>, +pub struct InterpErrorInfo<'tcx>(Box>); + +#[derive(Debug)] +struct InterpErrorInfoInner<'tcx> { + kind: InterpError<'tcx>, backtrace: Option>, } impl fmt::Display for InterpErrorInfo<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.kind) + write!(f, "{}", self.0.kind) } } -impl InterpErrorInfo<'_> { +impl InterpErrorInfo<'tcx> { pub fn print_backtrace(&self) { - if let Some(backtrace) = self.backtrace.as_ref() { + if let Some(backtrace) = self.0.backtrace.as_ref() { print_backtrace(backtrace); } } + + pub fn into_kind(self) -> InterpError<'tcx> { + let InterpErrorInfo(box InterpErrorInfoInner { kind, .. }) = self; + kind + } + + #[inline] + pub fn kind(&self) -> &InterpError<'tcx> { + &self.0.kind + } } fn print_backtrace(backtrace: &Backtrace) { @@ -108,7 +124,7 @@ impl<'tcx> From> for InterpErrorInfo<'tcx> { } }; - InterpErrorInfo { kind, backtrace } + InterpErrorInfo(Box::new(InterpErrorInfoInner { kind, backtrace })) } } diff --git a/compiler/rustc_mir/src/const_eval/error.rs b/compiler/rustc_mir/src/const_eval/error.rs index 88af9391cadfe..754ed0bea8494 100644 --- a/compiler/rustc_mir/src/const_eval/error.rs +++ b/compiler/rustc_mir/src/const_eval/error.rs @@ -84,7 +84,11 @@ impl<'tcx> ConstEvalErr<'tcx> { { error.print_backtrace(); let stacktrace = ecx.generate_stacktrace(); - ConstEvalErr { error: error.kind, stacktrace, span: span.unwrap_or_else(|| ecx.cur_span()) } + ConstEvalErr { + error: error.into_kind(), + stacktrace, + span: span.unwrap_or_else(|| ecx.cur_span()), + } } pub fn struct_error( diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index ed450c0c2a056..0f1c2b87426b5 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -230,7 +230,7 @@ pub fn eval_to_const_value_raw_provider<'tcx>( }; return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs).map_err(|error| { let span = tcx.def_span(def_id); - let error = ConstEvalErr { error: error.kind, stacktrace: vec![], span }; + let error = ConstEvalErr { error: error.into_kind(), stacktrace: vec![], span }; error.report_as_error(tcx.at(span), "could not evaluate nullary intrinsic") }); } diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index f6b950c08c78e..8e75481e323c5 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -245,8 +245,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, Ok(Some(match ecx.load_mir(instance.def, None) { Ok(body) => body, Err(err) => { - if let err_unsup!(NoMirFor(did)) = err.kind { - let path = ecx.tcx.def_path_str(did); + if let err_unsup!(NoMirFor(did)) = err.kind() { + let path = ecx.tcx.def_path_str(*did); return Err(ConstEvalErrKind::NeedsRfc(format!( "calling extern function `{}`", path diff --git a/compiler/rustc_mir/src/interpret/intern.rs b/compiler/rustc_mir/src/interpret/intern.rs index 6904ea5b77d16..7993d4847a744 100644 --- a/compiler/rustc_mir/src/interpret/intern.rs +++ b/compiler/rustc_mir/src/interpret/intern.rs @@ -356,7 +356,7 @@ where // an allocation, which we should avoid. When that happens, // dedicated error variants should be introduced instead. assert!( - !error.kind.allocates(), + !error.kind().allocates(), "interning encountered allocating error: {}", error ); diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs index 64e7a4d9ca758..ce803c0d485f1 100644 --- a/compiler/rustc_mir/src/interpret/validity.rs +++ b/compiler/rustc_mir/src/interpret/validity.rs @@ -11,7 +11,7 @@ use std::ops::RangeInclusive; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; -use rustc_middle::mir::interpret::{InterpError, InterpErrorInfo}; +use rustc_middle::mir::interpret::InterpError; use rustc_middle::ty; use rustc_middle::ty::layout::TyAndLayout; use rustc_span::symbol::{sym, Symbol}; @@ -83,14 +83,17 @@ macro_rules! try_validation { Ok(x) => x, // We catch the error and turn it into a validation failure. We are okay with // allocation here as this can only slow down builds that fail anyway. - $( $( Err(InterpErrorInfo { kind: $p, .. }) )|+ => - throw_validation_failure!( - $where, - { $( $what_fmt ),+ } $( expected { $( $expected_fmt ),+ } )? - ), - )+ - #[allow(unreachable_patterns)] - Err(e) => Err::(e)?, + Err(e) => match e.kind() { + $( + $($p)|+ => + throw_validation_failure!( + $where, + { $( $what_fmt ),+ } $( expected { $( $expected_fmt ),+ } )? + ) + ),+, + #[allow(unreachable_patterns)] + _ => Err::(e)?, + } } }}; } @@ -877,7 +880,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> Err(err) => { // For some errors we might be able to provide extra information. // (This custom logic does not fit the `try_validation!` macro.) - match err.kind { + match err.kind() { err_ub!(InvalidUninitBytes(Some(access))) => { // Some byte was uninitialized, determine which // element that byte belongs to so we can @@ -935,10 +938,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match visitor.visit_value(op) { Ok(()) => Ok(()), // Pass through validation failures. - Err(err) if matches!(err.kind, err_ub!(ValidationFailure { .. })) => Err(err), + Err(err) if matches!(err.kind(), err_ub!(ValidationFailure { .. })) => Err(err), // Also pass through InvalidProgram, those just indicate that we could not // validate and each caller will know best what to do with them. - Err(err) if matches!(err.kind, InterpError::InvalidProgram(_)) => Err(err), + Err(err) if matches!(err.kind(), InterpError::InvalidProgram(_)) => Err(err), // Avoid other errors as those do not show *where* in the value the issue lies. Err(err) => { err.print_backtrace(); diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index fd5c2236902a2..d0a23e1359c70 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -466,7 +466,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // an allocation, which we should avoid. When that happens, // dedicated error variants should be introduced instead. assert!( - !error.kind.allocates(), + !error.kind().allocates(), "const-prop encountered allocating error: {}", error ); From 614b0cccfeb3f08aea0fdd90ca2d4b961f846a1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 17 Feb 2021 00:00:00 +0000 Subject: [PATCH 2/2] Use -Ccodegen-units=1 to make issue-23458 test deterministic The test case fails with either one error or two errors. Use a single code generation unit to avoid nondeterminism. --- src/test/ui/issues/issue-23458.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/issues/issue-23458.rs b/src/test/ui/issues/issue-23458.rs index 423b19c3ebd09..1762d21832848 100644 --- a/src/test/ui/issues/issue-23458.rs +++ b/src/test/ui/issues/issue-23458.rs @@ -1,5 +1,5 @@ #![feature(llvm_asm)] - +// compile-flags: -Ccodegen-units=1 // build-fail // only-x86_64