about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-08-31 03:19:05 +0000
committerbors <bors@rust-lang.org>2020-08-31 03:19:05 +0000
commite98f0632bbec24b196dbd6fc820537f6f3724807 (patch)
tree52494c35f981ca033b005c364b5adda9ccd40cc9
parent92290d1631c0c0d87610cee842cc0d03fb95d6d0 (diff)
parentd9208665b5eef883c025f44717f8c76afa871a94 (diff)
downloadrust-e98f0632bbec24b196dbd6fc820537f6f3724807.tar.gz
rust-e98f0632bbec24b196dbd6fc820537f6f3724807.zip
Auto merge of #75082 - Aaron1011:feature/proc-macro-backtrace, r=petrochenkov
Add `-Z proc-macro-backtrace` to allow showing proc-macro panics

Fixes #75050

Previously, we would unconditionally suppress the panic hook during
proc-macro execution. This commit adds a new flag
`-Z proc-macro-backtrace`, which allows running the panic hook for
easier debugging.
-rw-r--r--compiler/rustc_expand/src/expand.rs2
-rw-r--r--compiler/rustc_expand/src/proc_macro.rs41
-rw-r--r--compiler/rustc_interface/src/passes.rs1
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--library/proc_macro/src/bridge/client.rs10
-rw-r--r--library/proc_macro/src/bridge/mod.rs3
-rw-r--r--library/proc_macro/src/bridge/server.rs34
-rw-r--r--src/test/ui/proc-macro/load-panic-backtrace.rs21
-rw-r--r--src/test/ui/proc-macro/load-panic-backtrace.stderr11
10 files changed, 99 insertions, 27 deletions
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<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));
@@ -48,14 +48,16 @@ impl base::AttrProcMacro for AttrProcMacro {
         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
+            })
     }
 }
 
@@ -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<PathBuf> = (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<u8>, Buffer<u8>>,
+
+    /// 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<u8>,
         run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
         client_data: D,
+        force_show_panics: bool,
     ) -> Buffer<u8>;
 }
 
@@ -147,10 +148,14 @@ impl ExecutionStrategy for SameThread {
         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,
+        )
     }
 }
 
@@ -166,6 +171,7 @@ impl ExecutionStrategy for CrossThread1 {
         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;
 
@@ -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<u8>,
         run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
         client_data: D,
+        force_show_panics: bool,
     ) -> Buffer<u8> {
         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<u8>,
     client_data: D,
+    force_show_panics: bool,
 ) -> Result<O, PanicMessage> {
     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<fn(crate::TokenStream) -> crate::TokenStream> {
         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(
@@ -292,6 +315,7 @@ impl client::Client<fn(crate::TokenStream) -> crate::TokenStream> {
             <MarkedTypes<S> as Types>::TokenStream::mark(input),
             run,
             f,
+            force_show_panics,
         )
         .map(<MarkedTypes<S> as Types>::TokenStream::unmark)
     }
@@ -304,6 +328,7 @@ impl client::Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenSt
         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(
@@ -316,6 +341,7 @@ impl client::Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenSt
             ),
             run,
             f,
+            force_show_panics,
         )
         .map(<MarkedTypes<S> 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
+