rustc_middle/util/
bug.rs

1// These functions are used by macro expansion for `bug!` and `span_bug!`.
2
3use std::fmt;
4use std::panic::{Location, panic_any};
5
6use rustc_errors::MultiSpan;
7use rustc_span::Span;
8
9use crate::ty::{TyCtxt, tls};
10
11// This wrapper makes for more compact code at callsites than calling `opt_span_buf_fmt` directly.
12#[cold]
13#[inline(never)]
14#[track_caller]
15pub fn bug_fmt(args: fmt::Arguments<'_>) -> ! {
16    opt_span_bug_fmt(None::<Span>, args, Location::caller());
17}
18
19// This wrapper makes for more compact code at callsites than calling `opt_span_buf_fmt` directly.
20#[cold]
21#[inline(never)]
22#[track_caller]
23pub fn span_bug_fmt<S: Into<MultiSpan>>(span: S, args: fmt::Arguments<'_>) -> ! {
24    opt_span_bug_fmt(Some(span), args, Location::caller());
25}
26
27#[track_caller]
28fn opt_span_bug_fmt<S: Into<MultiSpan>>(
29    span: Option<S>,
30    args: fmt::Arguments<'_>,
31    location: &Location<'_>,
32) -> ! {
33    tls::with_opt(
34        #[track_caller]
35        move |tcx| {
36            let msg = format!("{location}: {args}");
37            match (tcx, span) {
38                (Some(tcx), Some(span)) => tcx.dcx().span_bug(span, msg),
39                (Some(tcx), None) => tcx.dcx().bug(msg),
40                (None, _) => panic_any(msg),
41            }
42        },
43    )
44}
45
46/// A query to trigger a delayed bug. Clearly, if one has a `tcx` one can already trigger a
47/// delayed bug, so what is the point of this? It exists to help us test the interaction of delayed
48/// bugs with the query system and incremental.
49pub fn trigger_delayed_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) {
50    tcx.dcx().span_delayed_bug(
51        tcx.def_span(key),
52        "delayed bug triggered by #[rustc_error(delayed_bug_from_inside_query)]",
53    );
54}
55
56pub fn provide(providers: &mut crate::query::Providers) {
57    *providers = crate::query::Providers { trigger_delayed_bug, ..*providers };
58}