pub should_test: bool, // If false, strip `#[test]` nodes
pub keep_macs: bool,
pub span_debug: bool, // If true, use verbose debugging for `proc_macro::Span`
+ pub proc_macro_backtrace: bool, // If true, show backtraces for proc-macro panics
}
impl<'feat> ExpansionConfig<'feat> {
should_test: false,
keep_macs: false,
span_debug: false,
+ proc_macro_backtrace: false,
}
}
input: TokenStream,
) -> Result<TokenStream, ErrorReported> {
let server = proc_macro_server::Rustc::new(ecx);
- self.client.run(&EXEC_STRATEGY, server, input).map_err(|e| {
+ self.client.run(&EXEC_STRATEGY, server, input, ecx.ecfg.proc_macro_backtrace).map_err(|e| {
let mut err = ecx.struct_span_err(span, "proc macro panicked");
if let Some(s) = e.as_str() {
err.help(&format!("message: {}", s));
annotated: TokenStream,
) -> Result<TokenStream, ErrorReported> {
let server = proc_macro_server::Rustc::new(ecx);
- self.client.run(&EXEC_STRATEGY, server, annotation, annotated).map_err(|e| {
- let mut err = ecx.struct_span_err(span, "custom attribute panicked");
- if let Some(s) = e.as_str() {
- err.help(&format!("message: {}", s));
- }
- err.emit();
- ErrorReported
- })
+ self.client
+ .run(&EXEC_STRATEGY, server, annotation, annotated, ecx.ecfg.proc_macro_backtrace)
+ .map_err(|e| {
+ let mut err = ecx.struct_span_err(span, "custom attribute panicked");
+ if let Some(s) = e.as_str() {
+ err.help(&format!("message: {}", s));
+ }
+ err.emit();
+ ErrorReported
+ })
}
}
};
let server = proc_macro_server::Rustc::new(ecx);
- let stream = match self.client.run(&EXEC_STRATEGY, server, input) {
- Ok(stream) => stream,
- Err(e) => {
- let mut err = ecx.struct_span_err(span, "proc-macro derive panicked");
- if let Some(s) = e.as_str() {
- err.help(&format!("message: {}", s));
+ let stream =
+ match self.client.run(&EXEC_STRATEGY, server, input, ecx.ecfg.proc_macro_backtrace) {
+ Ok(stream) => stream,
+ Err(e) => {
+ let mut err = ecx.struct_span_err(span, "proc-macro derive panicked");
+ if let Some(s) = e.as_str() {
+ err.help(&format!("message: {}", s));
+ }
+ err.emit();
+ return ExpandResult::Ready(vec![]);
}
- err.emit();
- return ExpandResult::Ready(vec![]);
- }
- };
+ };
let error_count_before = ecx.sess.parse_sess.span_diagnostic.err_count();
let mut parser =
trace_mac: sess.opts.debugging_opts.trace_macros,
should_test: sess.opts.test,
span_debug: sess.opts.debugging_opts.span_debug,
+ proc_macro_backtrace: sess.opts.debugging_opts.proc_macro_backtrace,
..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string())
};
untracked!(print_llvm_passes, true);
untracked!(print_mono_items, Some(String::from("abc")));
untracked!(print_type_sizes, true);
+ untracked!(proc_macro_backtrace, true);
untracked!(query_dep_graph, true);
untracked!(query_stats, true);
untracked!(save_analysis, true);
"print the result of the monomorphization collection pass"),
print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
"print layout information for each type encountered (default: no)"),
+ proc_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
+ "show backtraces for panics during proc-macro execution (default: no)"),
profile: bool = (false, parse_bool, [TRACKED],
"insert profiling code (default: no)"),
profile_emit: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
HIDE_PANICS_DURING_EXPANSION.call_once(|| {
let prev = panic::take_hook();
panic::set_hook(Box::new(move |info| {
- let hide = BridgeState::with(|state| match state {
- BridgeState::NotConnected => false,
- BridgeState::Connected(_) | BridgeState::InUse => true,
+ let show = BridgeState::with(|state| match state {
+ BridgeState::NotConnected => true,
+ // Something weird is going on, so don't suppress any backtraces
+ BridgeState::InUse => true,
+ BridgeState::Connected(bridge) => bridge.force_show_panics,
});
- if !hide {
+ if show {
prev(info)
}
}));
/// Server-side function that the client uses to make requests.
dispatch: closure::Closure<'a, Buffer<u8>, Buffer<u8>>,
+
+ /// If 'true', always invoke the default panic hook
+ force_show_panics: bool,
}
impl<'a> !Sync for Bridge<'a> {}
input: Buffer<u8>,
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
client_data: D,
+ force_show_panics: bool,
) -> Buffer<u8>;
}
input: Buffer<u8>,
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
client_data: D,
+ force_show_panics: bool,
) -> Buffer<u8> {
let mut dispatch = |b| dispatcher.dispatch(b);
- run_client(Bridge { cached_buffer: input, dispatch: (&mut dispatch).into() }, client_data)
+ run_client(
+ Bridge { cached_buffer: input, dispatch: (&mut dispatch).into(), force_show_panics },
+ client_data,
+ )
}
}
input: Buffer<u8>,
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
client_data: D,
+ force_show_panics: bool,
) -> Buffer<u8> {
use std::sync::mpsc::channel;
};
run_client(
- Bridge { cached_buffer: input, dispatch: (&mut dispatch).into() },
+ Bridge {
+ cached_buffer: input,
+ dispatch: (&mut dispatch).into(),
+ force_show_panics,
+ },
client_data,
)
});
input: Buffer<u8>,
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
client_data: D,
+ force_show_panics: bool,
) -> Buffer<u8> {
use std::sync::{Arc, Mutex};
};
let r = run_client(
- Bridge { cached_buffer: input, dispatch: (&mut dispatch).into() },
+ Bridge {
+ cached_buffer: input,
+ dispatch: (&mut dispatch).into(),
+ force_show_panics,
+ },
client_data,
);
input: I,
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
client_data: D,
+ force_show_panics: bool,
) -> Result<O, PanicMessage> {
let mut dispatcher =
Dispatcher { handle_store: HandleStore::new(handle_counters), server: MarkedTypes(server) };
let mut b = Buffer::new();
input.encode(&mut b, &mut dispatcher.handle_store);
- b = strategy.run_bridge_and_client(&mut dispatcher, b, run_client, client_data);
+ b = strategy.run_bridge_and_client(
+ &mut dispatcher,
+ b,
+ run_client,
+ client_data,
+ force_show_panics,
+ );
Result::decode(&mut &b[..], &mut dispatcher.handle_store)
}
strategy: &impl ExecutionStrategy,
server: S,
input: S::TokenStream,
+ force_show_panics: bool,
) -> Result<S::TokenStream, PanicMessage> {
let client::Client { get_handle_counters, run, f } = *self;
run_server(
<MarkedTypes<S> as Types>::TokenStream::mark(input),
run,
f,
+ force_show_panics,
)
.map(<MarkedTypes<S> as Types>::TokenStream::unmark)
}
server: S,
input: S::TokenStream,
input2: S::TokenStream,
+ force_show_panics: bool,
) -> Result<S::TokenStream, PanicMessage> {
let client::Client { get_handle_counters, run, f } = *self;
run_server(
),
run,
f,
+ force_show_panics,
)
.map(<MarkedTypes<S> as Types>::TokenStream::unmark)
}
--- /dev/null
+// aux-build:test-macros.rs
+// compile-flags: -Z proc-macro-backtrace
+// rustc-env:RUST_BACKTRACE=0
+
+// FIXME https://github.com/rust-lang/rust/issues/59998
+// normalize-stderr-test "thread '.*' panicked " -> ""
+// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
+// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
+// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
+// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
+// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
+// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
+
+#[macro_use]
+extern crate test_macros;
+
+#[derive(Panic)]
+//~^ ERROR: proc-macro derive panicked
+struct Foo;
+
+fn main() {}
--- /dev/null
+at 'panic-derive', $DIR/auxiliary/test-macros.rs:43:5
+error: proc-macro derive panicked
+ --> $DIR/load-panic-backtrace.rs:17:10
+ |
+LL | #[derive(Panic)]
+ | ^^^^^
+ |
+ = help: message: panic-derive
+
+error: aborting due to previous error
+