rust-lang/rust · #162873

Adjust `bug!`/`span_bug!` emission

nnethercote · merged Sep 19, 202610 files · 124 + / 33
compiler/rustc_errors/src/diagnostic.rs6 + / 3
@@ -93,10 +93,13 @@ pub struct DiagLocation { }  impl DiagLocation {+    pub fn from_location(loc: &'static panic::Location<'static>) -> Self {+        DiagLocation { file: loc.file().into(), line: loc.line(), col: loc.column() }+    }+     #[track_caller]     pub fn caller() -> Self {-        let loc = panic::Location::caller();-        DiagLocation { file: loc.file().into(), line: loc.line(), col: loc.column() }+        Self::from_location(panic::Location::caller())     } } @@ -1294,7 +1297,7 @@ impl<'a, G> Diag<'a, G> {     }      /// Most `emit` methods use this as a starting point.-    pub fn emit_producing_nothing(mut self) {+    fn emit_producing_nothing(mut self) {         let diag = self.take_diag();         self.dcx.emit_diagnostic(diag);     }
compiler/rustc_errors/src/lib.rs1 + / 4
@@ -57,6 +57,7 @@ pub use rustc_macros::msg; use rustc_macros::{Decodable, Encodable}; pub use rustc_span::ErrorGuaranteed; pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker, catch_fatal_errors};+pub use rustc_span::macros::ExplicitBug; use rustc_span::source_map::SourceMap; use rustc_span::{DUMMY_SP, Span}; use tracing::debug;@@ -256,10 +257,6 @@ fn as_substr<'a>(original: &'a str, suggestion: &'a str) -> Option<(usize, &'a s     } } -/// Signifies that the compiler died with an explicit call to `.bug`-/// or `.span_bug` rather than a failed assertion, etc.-pub struct ExplicitBug;- /// Signifies that the compiler died due to a delayed bug rather than a failed /// assertion, etc. pub struct DelayedBugPanic;
compiler/rustc_interface/src/callbacks.rs17 + / 7
@@ -13,7 +13,7 @@ use std::fmt; use std::fmt::Arguments; use std::panic::Location; -use rustc_errors::DiagInner;+use rustc_errors::{DiagInner, DiagLocation, Level}; use rustc_middle::dep_graph::{QuerySideEffect, TaskDepsRef}; use rustc_middle::ty::tls; use rustc_span::{Span, Symbol};@@ -86,16 +86,26 @@ fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) ->     write!(f, ")") } -fn emit_bug_diagnostic(span: Option<Span>, args: Arguments<'_>, location: &Location<'_>) {+/// Returns true if it printed the diagnostic, which happens if a `tcx` is available.+fn emit_bug_diagnostic(+    span: Option<Span>,+    args: Arguments<'_>,+    location: &'static Location<'static>,+) -> bool {     tls::with_opt(move |tcx| {         if let Some(tcx) = tcx {-            let message = format!("{location}: {args}");+            let mut diag = DiagInner::new(Level::Bug, format!("{location}: {args}"));             if let Some(span) = span {-                tcx.dcx().struct_span_bug(span, message)-            } else {-                tcx.dcx().struct_bug(message)+                diag.span = span.into();             }-            .emit_producing_nothing();+            diag.emitted_at = DiagLocation::from_location(location);+            // Emit the bug without aborting. We let `bug_impl` do the abort because it has+            // `#[track_caller]` which gives a better location. (`#[track_caller]` doesn't work+            // here because this function is called via a function pointer.)+            tcx.dcx().emit_diagnostic(diag);+            true+        } else {+            false         }     }) }
compiler/rustc_span/src/macros.rs31 + / 7
@@ -1,10 +1,14 @@ use std::fmt;-use std::panic::Location;+use std::panic::{Location, panic_any};  use rustc_data_structures::AtomicRef;  use crate::Span; +/// Signifies that the compiler died with an explicit call to `.bug` or `.span_bug` rather than a+/// failed assertion, etc.+pub struct ExplicitBug;+ /// A macro for triggering an ICE. /// Calling `bug` instead of panicking will result in a nicer error message and should /// therefore be preferred over `panic`/`unreachable` or others.@@ -40,12 +44,32 @@ pub macro span_bug($span:expr, $($arg:tt)+){  #[cold] #[track_caller]-pub fn bug_impl(span: Option<Span>, args: fmt::Arguments<'_>, location: &Location<'_>) -> ! {-    (*EMIT_BUG_DIAGNOSTIC)(span, args, location);-    panic!("{args}")+pub fn bug_impl(+    span: Option<Span>,+    args: fmt::Arguments<'_>,+    location: &'static Location<'static>,+) -> ! {+    // Emit the bug without aborting.+    let emitted = (*EMIT_BUG_DIAGNOSTIC)(span, args, location);++    if emitted {+        // Panic with `ExplicitBug`, which tells `report_ice` that it's expected, e.g. originating+        // from `bug!` or `dcx.emit_bug(..)`.+        panic_any(ExplicitBug);+    } else {+        // Panic with just a string, which means it's unexpected.+        panic_any(format!("{args}"));+    } } -pub static EMIT_BUG_DIAGNOSTIC: AtomicRef<fn(Option<Span>, fmt::Arguments<'_>, &Location<'_>)> =-    AtomicRef::new(&(default_emit_diagnostic as _));+pub static EMIT_BUG_DIAGNOSTIC: AtomicRef<+    fn(Option<Span>, fmt::Arguments<'_>, &'static Location<'static>) -> bool,+> = AtomicRef::new(&(default_emit_bug_diagnostic as _)); -fn default_emit_diagnostic(_: Option<Span>, _: fmt::Arguments<'_>, _: &Location<'_>) {}+fn default_emit_bug_diagnostic(+    _: Option<Span>,+    _args: fmt::Arguments<'_>,+    _location: &'static Location<'static>,+) -> bool {+    false+}
src/tools/miri/tests/panic/mir-validation.stderr1 + / 4
@@ -7,12 +7,9 @@ LL |             *(tuple.0) = 1;   thread 'rustc' ($TID) panicked at compiler/rustc_mir_transform/src/validate.rs:LL:CC:-broken MIR in Item(DefId) (after phase change to runtime-optimized) at bb0[1]:-place (*(_2.0: *mut i32)) has deref as a later projection (it is only permitted as the first projection)+Box<dyn Any> stack backtrace: -error: the compiler unexpectedly panicked. This is a bug-   
tests/ui/intrinsics/not-overridden.stderr0 + / 2
@@ -5,8 +5,6 @@ LL |     unsafe { const_deallocate(std::ptr::null_mut(), 0, 0) }    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  -error: the compiler unexpectedly panicked. This is a bug- query stack during panic: end of query stack error: aborting due to 1 previous error
tests/ui/resolve/multiple_definitions_attribute_merging.stderr1 + / 3
@@ -17,9 +17,7 @@ LL | struct Dealigned<T>(u8, T);    |                         ^  -builtin derive created an unaligned reference-error: the compiler unexpectedly panicked. This is a bug-+Box<dyn Any> query stack during panic: #0 [mir_built] building MIR for `<impl at $DIR/multiple_definitions_attribute_merging.rs:16:10: 16:19>::eq` #1 [check_unsafety] unsafety-checking `<impl at $DIR/multiple_definitions_attribute_merging.rs:16:10: 16:19>::eq`
tests/ui/resolve/proc_macro_generated_packed.stderr1 + / 3
@@ -8,9 +8,7 @@ LL | struct Dealigned<T>(u8, T);    |                         ^  -builtin derive created an unaligned reference-error: the compiler unexpectedly panicked. This is a bug-+Box<dyn Any> query stack during panic: #0 [mir_built] building MIR for `<impl at $DIR/proc_macro_generated_packed.rs:16:10: 16:19>::eq` #1 [check_unsafety] unsafety-checking `<impl at $DIR/proc_macro_generated_packed.rs:16:10: 16:19>::eq`
tests/ui/track-diagnostics/track7.rsadded40 + / 0
@@ -0,0 +1,40 @@+// This test checks that -Ztrack-diagnostics reports the correct source locations for an ICE+// triggered with `span_bug!`.+//+//@ compile-flags: -Zvalidate-mir -Ztrack-diagnostics+//@ rustc-env:RUST_BACKTRACE=0+//@ failure-status: 101+//+// Normalize the emitted location so this doesn't need+// updating everytime someone adds or removes a line.+//@ normalize-stderr: ".rs:\d+:\d+" -> ".rs:LL:CC"+//@ normalize-stderr: "note: rustc .+ running on .+" -> "note: rustc $$VERSION running on $$TARGET"+//@ normalize-stderr: "/rustc(?:-dev)?/[a-z0-9.]+/" -> ""+//@ normalize-stderr: "track7\[....\]" -> "track7[HASH]"+// The test becomes too flaky if we care about exact args. If `-Z ui-testing`+// from compiletest and `-Z track-diagnostics` from `// compile-flags` at the+// top of this file are present, then assume all args are present.+//@ normalize-stderr: "note: compiler flags: .*-Z ui-testing.*-Z track-diagnostics" -> "note: compiler flags: ... -Z ui-testing ... -Z track-diagnostics"++#![feature(custom_mir, core_intrinsics)]+extern crate core;+use core::intrinsics::mir::*;++fn bar(_x: i32) {}++// Use of `mir!` here is just because it's an easy way to trigger a `span_bug!`.+#[custom_mir(dialect = "built")]+pub fn main() {+    mir! {+        let a: (i32, i32);+        {+            a = (1, 2);+            Call(RET = bar(Move(a.0)), ReturnTo(retblock), UnwindContinue())+            //~^ ERROR broken MIR in+            //~| ERROR encountered `Move` of a non-local, non-box place in `Call` terminator+        }+        retblock = {+            Return()+        }+    }+}
tests/ui/track-diagnostics/track7.stderradded26 + / 0
@@ -0,0 +1,26 @@+error: internal compiler error: compiler/rustc_mir_transform/src/validate.rs:LL:CC: broken MIR in Item(DefId(0:6 ~ track7[HASH]::main)) (after pass LintAndRemoveUninhabited) at bb0[1]:+                                encountered `Move` of a non-local, non-box place in `Call` terminator: _0 = bar(move (_1.0: i32)) -> [return: bb1, unwind continue]+  --> $DIR/track7.rs:LL:CC+   |+LL |             Call(RET = bar(Move(a.0)), ReturnTo(retblock), UnwindContinue())+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^+   |+   = note: -Ztrack-diagnostics: created at compiler/rustc_mir_transform/src/validate.rs:LL:CC+++thread 'rustc' ($TID) panicked at compiler/rustc_mir_transform/src/validate.rs:LL:CC:+Box<dyn Any>+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace++note: using internal features is not supported and expected to cause internal compiler errors when used incorrectly++note: rustc $VERSION running on $TARGET++note: compiler flags: ... -Z ui-testing ... -Z track-diagnostics++query stack during panic:+#0 [mir_built] building MIR for `main`+#1 [has_ffi_unwind_calls] checking if `main` contains FFI-unwind calls+... and 3 other queries... use `env RUST_BACKTRACE=1` to see the full query stack+error: aborting due to 1 previous error+