rust-lang/rust · #162873
Adjust `bug!`/`span_bug!` emission
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 errortests/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+