diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 7a21caf255a..6243e9676de 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1788,6 +1788,7 @@ pub struct ExpansionConfig<'feat> { 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> { @@ -1800,6 +1801,7 @@ impl<'feat> ExpansionConfig<'feat> { should_test: false, keep_macs: false, span_debug: false, + proc_macro_backtrace: false, } } diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 4e865c20d6f..94b3fcf2850 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -24,7 +24,7 @@ impl base::ProcMacro for BangProcMacro { input: TokenStream, ) -> Result { 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)); @@ -48,14 +48,16 @@ impl base::AttrProcMacro for AttrProcMacro { annotated: TokenStream, ) -> Result { 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 + }) } } @@ -111,17 +113,18 @@ impl MultiItemModifier for ProcMacroDerive { }; 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 = diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 403aea8b304..f33dcec8ba7 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -291,6 +291,7 @@ fn configure_and_expand_inner<'a>( 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()) }; diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index e94745519a4..cb906b3d911 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -502,6 +502,7 @@ fn test_debugging_options_tracking_hash() { 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); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index d05f1a3f34b..82330d9a533 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -967,6 +967,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "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 = (None, parse_opt_pathbuf, [TRACKED], diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index c00e07388b8..3d9016293b8 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -311,11 +311,13 @@ impl Bridge<'_> { 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) } })); diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 324be9f4701..c898d483a8b 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -220,6 +220,9 @@ pub struct Bridge<'a> { /// Server-side function that the client uses to make requests. dispatch: closure::Closure<'a, Buffer, Buffer>, + + /// If 'true', always invoke the default panic hook + force_show_panics: bool, } impl<'a> !Sync for Bridge<'a> {} diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index eb39025e4c2..1b3ccf4c18e 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -135,6 +135,7 @@ pub trait ExecutionStrategy { input: Buffer, run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, + force_show_panics: bool, ) -> Buffer; } @@ -147,10 +148,14 @@ impl ExecutionStrategy for SameThread { input: Buffer, run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, + force_show_panics: bool, ) -> Buffer { 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, + ) } } @@ -166,6 +171,7 @@ impl ExecutionStrategy for CrossThread1 { input: Buffer, run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, + force_show_panics: bool, ) -> Buffer { use std::sync::mpsc::channel; @@ -179,7 +185,11 @@ impl ExecutionStrategy for CrossThread1 { }; run_client( - Bridge { cached_buffer: input, dispatch: (&mut dispatch).into() }, + Bridge { + cached_buffer: input, + dispatch: (&mut dispatch).into(), + force_show_panics, + }, client_data, ) }); @@ -201,6 +211,7 @@ impl ExecutionStrategy for CrossThread2 { input: Buffer, run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, + force_show_panics: bool, ) -> Buffer { use std::sync::{Arc, Mutex}; @@ -226,7 +237,11 @@ impl ExecutionStrategy for CrossThread2 { }; 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, ); @@ -265,6 +280,7 @@ fn run_server< input: I, run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, + force_show_panics: bool, ) -> Result { let mut dispatcher = Dispatcher { handle_store: HandleStore::new(handle_counters), server: MarkedTypes(server) }; @@ -272,7 +288,13 @@ fn run_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) } @@ -283,6 +305,7 @@ impl client::Client crate::TokenStream> { strategy: &impl ExecutionStrategy, server: S, input: S::TokenStream, + force_show_panics: bool, ) -> Result { let client::Client { get_handle_counters, run, f } = *self; run_server( @@ -292,6 +315,7 @@ impl client::Client crate::TokenStream> { as Types>::TokenStream::mark(input), run, f, + force_show_panics, ) .map( as Types>::TokenStream::unmark) } @@ -304,6 +328,7 @@ impl client::Client crate::TokenSt server: S, input: S::TokenStream, input2: S::TokenStream, + force_show_panics: bool, ) -> Result { let client::Client { get_handle_counters, run, f } = *self; run_server( @@ -316,6 +341,7 @@ impl client::Client crate::TokenSt ), run, f, + force_show_panics, ) .map( as Types>::TokenStream::unmark) } diff --git a/src/test/ui/proc-macro/load-panic-backtrace.rs b/src/test/ui/proc-macro/load-panic-backtrace.rs new file mode 100644 index 00000000000..90fe109abb8 --- /dev/null +++ b/src/test/ui/proc-macro/load-panic-backtrace.rs @@ -0,0 +1,21 @@ +// 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() {} diff --git a/src/test/ui/proc-macro/load-panic-backtrace.stderr b/src/test/ui/proc-macro/load-panic-backtrace.stderr new file mode 100644 index 00000000000..63378b5735a --- /dev/null +++ b/src/test/ui/proc-macro/load-panic-backtrace.stderr @@ -0,0 +1,11 @@ +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 +