]> git.lizzy.rs Git - rust.git/commitdiff
Add `-Z proc-macro-backtrace` to allow showing proc-macro panics
authorAaron Hill <aa1ronham@gmail.com>
Mon, 31 Aug 2020 02:17:24 +0000 (22:17 -0400)
committerAaron Hill <aa1ronham@gmail.com>
Mon, 31 Aug 2020 02:17:24 +0000 (22:17 -0400)
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.

compiler/rustc_expand/src/expand.rs
compiler/rustc_expand/src/proc_macro.rs
compiler/rustc_interface/src/passes.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_session/src/options.rs
library/proc_macro/src/bridge/client.rs
library/proc_macro/src/bridge/mod.rs
library/proc_macro/src/bridge/server.rs
src/test/ui/proc-macro/load-panic-backtrace.rs [new file with mode: 0644]
src/test/ui/proc-macro/load-panic-backtrace.stderr [new file with mode: 0644]

index 7a21caf255a3ce1f548004335c0cdcf2c5553351..6243e9676de0cceb6133234574fa39c9623b99e6 100644 (file)
@@ -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 @@ pub fn default(crate_name: String) -> ExpansionConfig<'static> {
             should_test: false,
             keep_macs: false,
             span_debug: false,
+            proc_macro_backtrace: false,
         }
     }
 
index 4e865c20d6f4a12f74f7a6fe656fdbc21aa028a4..94b3fcf2850d23670cf90636d3ee66ef6a2ca1f7 100644 (file)
@@ -24,7 +24,7 @@ fn expand<'cx>(
         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 @@ fn expand<'cx>(
         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 @@ fn expand(
         };
 
         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 =
index 403aea8b304eb9252f74e6447dbcd3dd81842080..f33dcec8ba70063829ee9c87cde14f8ed7b6fdb3 100644 (file)
@@ -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())
         };
 
index e94745519a496608e1c85e21c31ed0a7eb440ed6..cb906b3d911640bbe01605a3c5f1fab9698ecd50 100644 (file)
@@ -502,6 +502,7 @@ macro_rules! untracked {
     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);
index d05f1a3f34b78337d924ba78ca9e22880331517e..82330d9a5331ab579646280a8584c60ebe6e69fa 100644 (file)
@@ -967,6 +967,8 @@ fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
         "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],
index c00e07388b882908d2adfc18096fa4c08bce1f3c..3d9016293b80d673004fd34c88b9ed22165bb439 100644 (file)
@@ -311,11 +311,13 @@ fn enter<R>(self, f: impl FnOnce() -> R) -> R {
         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)
                 }
             }));
index 324be9f47010882d3ae900e6a0ad55b5e2e92444..c898d483a8ba2e84ccea7ab324796eb49c11d425 100644 (file)
@@ -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> {}
index eb39025e4c228ac2cab05fd58ff2117c4a69ef1c..1b3ccf4c18e702bf20be3c0624c417618c4b128a 100644 (file)
@@ -135,6 +135,7 @@ fn run_bridge_and_client<D: Copy + Send + 'static>(
         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 @@ fn run_bridge_and_client<D: Copy + Send + 'static>(
         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 @@ fn run_bridge_and_client<D: Copy + Send + 'static>(
         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 @@ fn run_bridge_and_client<D: Copy + Send + 'static>(
             };
 
             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 @@ fn run_bridge_and_client<D: Copy + Send + 'static>(
         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 @@ enum State<T> {
             };
 
             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 @@ pub fn run<S: Server>(
         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 @@ pub fn run<S: Server>(
             <MarkedTypes<S> as Types>::TokenStream::mark(input),
             run,
             f,
+            force_show_panics,
         )
         .map(<MarkedTypes<S> as Types>::TokenStream::unmark)
     }
@@ -304,6 +328,7 @@ pub fn run<S: Server>(
         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 @@ pub fn run<S: Server>(
             ),
             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 (file)
index 0000000..90fe109
--- /dev/null
@@ -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 (file)
index 0000000..63378b5
--- /dev/null
@@ -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
+