rustc_span/macros.rs
1use std::fmt;
2use std::panic::{Location, panic_any};
3
4use rustc_data_structures::AtomicRef;
5
6use crate::Span;
7
8/// Signifies that the compiler died with an explicit call to `.bug` or `.span_bug` rather than a
9/// failed assertion, etc.
10pub struct ExplicitBug;
11
12/// A macro for triggering an ICE.
13/// Calling `bug` instead of panicking will result in a nicer error message and should
14/// therefore be preferred over `panic`/`unreachable` or others.
15///
16/// If you have a span available, you should use [`span_bug`] instead.
17///
18/// If the bug should only be emitted when compilation didn't fail,
19/// [`DiagCtxtHandle::span_delayed_bug`] may be useful.
20///
21/// [`DiagCtxtHandle::span_delayed_bug`]: ../../rustc_errors/struct.DiagCtxtHandle.html#method.span_delayed_bug
22/// [`span_bug`]: crate::span_bug
23pub macro bug {
24 () => (
25 bug!("impossible case reached")
26 ),
27 ($($arg:tt)+) => (
28 // Use the full path of `bug_impl` to make sure rust-analyzer can resolve it,
29 // to avoid bogus type errors about `()` versus `!`.
30 $crate::macros::bug_impl(None, std::format_args!($($arg)+), Location::caller())
31 ),
32}
33
34/// A macro for triggering an ICE with a span.
35/// Calling `span_bug!` instead of panicking will result in a nicer error message and point
36/// at the code the compiler was compiling when it ICEd. This is the preferred way to trigger
37/// ICEs.
38///
39/// If the bug should only be emitted when compilation didn't fail,
40/// [`DiagCtxtHandle::span_delayed_bug`] may be useful.
41///
42/// [`DiagCtxtHandle::span_delayed_bug`]: ../../rustc_errors/struct.DiagCtxtHandle.html#method.span_delayed_bug
43pub macro span_bug($span:expr, $($arg:tt)+){
44 // Use the full path of `bug_impl` to make sure rust-analyzer can resolve it,
45 // to avoid bogus type errors about `()` versus `!`.
46 $crate::macros::bug_impl(Some($span), std::format_args!($($arg)+), Location::caller())
47}
48
49#[cold]
50#[track_caller]
51pub fn bug_impl(
52 span: Option<Span>,
53 args: fmt::Arguments<'_>,
54 location: &'static Location<'static>,
55) -> ! {
56 // Emit the bug without aborting.
57 let emitted = (*EMIT_BUG_DIAGNOSTIC)(span, args, location);
58
59 if emitted {
60 // Panic with `ExplicitBug`, which tells `report_ice` that it's expected, e.g. originating
61 // from `bug!` or `dcx.emit_bug(..)`.
62 panic_any(ExplicitBug);
63 } else {
64 // Panic with just a string, which means it's unexpected.
65 panic_any(format!("{args}"));
66 }
67}
68
69pub static EMIT_BUG_DIAGNOSTIC: AtomicRef<
70 fn(Option<Span>, fmt::Arguments<'_>, &'static Location<'static>) -> bool,
71> = AtomicRef::new(&(default_emit_bug_diagnostic as _));
72
73fn default_emit_bug_diagnostic(
74 _: Option<Span>,
75 _args: fmt::Arguments<'_>,
76 _location: &'static Location<'static>,
77) -> bool {
78 false
79}