Skip to main content

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(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}", args))
    })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}