Skip to content

Commit e98f063

Browse files
committed
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.
2 parents 92290d1 + d920866 commit e98f063

File tree

10 files changed

+99
-27
lines changed

10 files changed

+99
-27
lines changed

compiler/rustc_expand/src/expand.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1788,6 +1788,7 @@ pub struct ExpansionConfig<'feat> {
17881788
pub should_test: bool, // If false, strip `#[test]` nodes
17891789
pub keep_macs: bool,
17901790
pub span_debug: bool, // If true, use verbose debugging for `proc_macro::Span`
1791+
pub proc_macro_backtrace: bool, // If true, show backtraces for proc-macro panics
17911792
}
17921793

17931794
impl<'feat> ExpansionConfig<'feat> {
@@ -1800,6 +1801,7 @@ impl<'feat> ExpansionConfig<'feat> {
18001801
should_test: false,
18011802
keep_macs: false,
18021803
span_debug: false,
1804+
proc_macro_backtrace: false,
18031805
}
18041806
}
18051807

compiler/rustc_expand/src/proc_macro.rs

+22-19
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ impl base::ProcMacro for BangProcMacro {
2424
input: TokenStream,
2525
) -> Result<TokenStream, ErrorReported> {
2626
let server = proc_macro_server::Rustc::new(ecx);
27-
self.client.run(&EXEC_STRATEGY, server, input).map_err(|e| {
27+
self.client.run(&EXEC_STRATEGY, server, input, ecx.ecfg.proc_macro_backtrace).map_err(|e| {
2828
let mut err = ecx.struct_span_err(span, "proc macro panicked");
2929
if let Some(s) = e.as_str() {
3030
err.help(&format!("message: {}", s));
@@ -48,14 +48,16 @@ impl base::AttrProcMacro for AttrProcMacro {
4848
annotated: TokenStream,
4949
) -> Result<TokenStream, ErrorReported> {
5050
let server = proc_macro_server::Rustc::new(ecx);
51-
self.client.run(&EXEC_STRATEGY, server, annotation, annotated).map_err(|e| {
52-
let mut err = ecx.struct_span_err(span, "custom attribute panicked");
53-
if let Some(s) = e.as_str() {
54-
err.help(&format!("message: {}", s));
55-
}
56-
err.emit();
57-
ErrorReported
58-
})
51+
self.client
52+
.run(&EXEC_STRATEGY, server, annotation, annotated, ecx.ecfg.proc_macro_backtrace)
53+
.map_err(|e| {
54+
let mut err = ecx.struct_span_err(span, "custom attribute panicked");
55+
if let Some(s) = e.as_str() {
56+
err.help(&format!("message: {}", s));
57+
}
58+
err.emit();
59+
ErrorReported
60+
})
5961
}
6062
}
6163

@@ -111,17 +113,18 @@ impl MultiItemModifier for ProcMacroDerive {
111113
};
112114

113115
let server = proc_macro_server::Rustc::new(ecx);
114-
let stream = match self.client.run(&EXEC_STRATEGY, server, input) {
115-
Ok(stream) => stream,
116-
Err(e) => {
117-
let mut err = ecx.struct_span_err(span, "proc-macro derive panicked");
118-
if let Some(s) = e.as_str() {
119-
err.help(&format!("message: {}", s));
116+
let stream =
117+
match self.client.run(&EXEC_STRATEGY, server, input, ecx.ecfg.proc_macro_backtrace) {
118+
Ok(stream) => stream,
119+
Err(e) => {
120+
let mut err = ecx.struct_span_err(span, "proc-macro derive panicked");
121+
if let Some(s) = e.as_str() {
122+
err.help(&format!("message: {}", s));
123+
}
124+
err.emit();
125+
return ExpandResult::Ready(vec![]);
120126
}
121-
err.emit();
122-
return ExpandResult::Ready(vec![]);
123-
}
124-
};
127+
};
125128

126129
let error_count_before = ecx.sess.parse_sess.span_diagnostic.err_count();
127130
let mut parser =

compiler/rustc_interface/src/passes.rs

+1
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ fn configure_and_expand_inner<'a>(
291291
trace_mac: sess.opts.debugging_opts.trace_macros,
292292
should_test: sess.opts.test,
293293
span_debug: sess.opts.debugging_opts.span_debug,
294+
proc_macro_backtrace: sess.opts.debugging_opts.proc_macro_backtrace,
294295
..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string())
295296
};
296297

compiler/rustc_interface/src/tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,7 @@ fn test_debugging_options_tracking_hash() {
502502
untracked!(print_llvm_passes, true);
503503
untracked!(print_mono_items, Some(String::from("abc")));
504504
untracked!(print_type_sizes, true);
505+
untracked!(proc_macro_backtrace, true);
505506
untracked!(query_dep_graph, true);
506507
untracked!(query_stats, true);
507508
untracked!(save_analysis, true);

compiler/rustc_session/src/options.rs

+2
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
967967
"print the result of the monomorphization collection pass"),
968968
print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
969969
"print layout information for each type encountered (default: no)"),
970+
proc_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
971+
"show backtraces for panics during proc-macro execution (default: no)"),
970972
profile: bool = (false, parse_bool, [TRACKED],
971973
"insert profiling code (default: no)"),
972974
profile_emit: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],

library/proc_macro/src/bridge/client.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -311,11 +311,13 @@ impl Bridge<'_> {
311311
HIDE_PANICS_DURING_EXPANSION.call_once(|| {
312312
let prev = panic::take_hook();
313313
panic::set_hook(Box::new(move |info| {
314-
let hide = BridgeState::with(|state| match state {
315-
BridgeState::NotConnected => false,
316-
BridgeState::Connected(_) | BridgeState::InUse => true,
314+
let show = BridgeState::with(|state| match state {
315+
BridgeState::NotConnected => true,
316+
// Something weird is going on, so don't suppress any backtraces
317+
BridgeState::InUse => true,
318+
BridgeState::Connected(bridge) => bridge.force_show_panics,
317319
});
318-
if !hide {
320+
if show {
319321
prev(info)
320322
}
321323
}));

library/proc_macro/src/bridge/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,9 @@ pub struct Bridge<'a> {
220220

221221
/// Server-side function that the client uses to make requests.
222222
dispatch: closure::Closure<'a, Buffer<u8>, Buffer<u8>>,
223+
224+
/// If 'true', always invoke the default panic hook
225+
force_show_panics: bool,
223226
}
224227

225228
impl<'a> !Sync for Bridge<'a> {}

library/proc_macro/src/bridge/server.rs

+30-4
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ pub trait ExecutionStrategy {
135135
input: Buffer<u8>,
136136
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
137137
client_data: D,
138+
force_show_panics: bool,
138139
) -> Buffer<u8>;
139140
}
140141

@@ -147,10 +148,14 @@ impl ExecutionStrategy for SameThread {
147148
input: Buffer<u8>,
148149
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
149150
client_data: D,
151+
force_show_panics: bool,
150152
) -> Buffer<u8> {
151153
let mut dispatch = |b| dispatcher.dispatch(b);
152154

153-
run_client(Bridge { cached_buffer: input, dispatch: (&mut dispatch).into() }, client_data)
155+
run_client(
156+
Bridge { cached_buffer: input, dispatch: (&mut dispatch).into(), force_show_panics },
157+
client_data,
158+
)
154159
}
155160
}
156161

@@ -166,6 +171,7 @@ impl ExecutionStrategy for CrossThread1 {
166171
input: Buffer<u8>,
167172
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
168173
client_data: D,
174+
force_show_panics: bool,
169175
) -> Buffer<u8> {
170176
use std::sync::mpsc::channel;
171177

@@ -179,7 +185,11 @@ impl ExecutionStrategy for CrossThread1 {
179185
};
180186

181187
run_client(
182-
Bridge { cached_buffer: input, dispatch: (&mut dispatch).into() },
188+
Bridge {
189+
cached_buffer: input,
190+
dispatch: (&mut dispatch).into(),
191+
force_show_panics,
192+
},
183193
client_data,
184194
)
185195
});
@@ -201,6 +211,7 @@ impl ExecutionStrategy for CrossThread2 {
201211
input: Buffer<u8>,
202212
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
203213
client_data: D,
214+
force_show_panics: bool,
204215
) -> Buffer<u8> {
205216
use std::sync::{Arc, Mutex};
206217

@@ -226,7 +237,11 @@ impl ExecutionStrategy for CrossThread2 {
226237
};
227238

228239
let r = run_client(
229-
Bridge { cached_buffer: input, dispatch: (&mut dispatch).into() },
240+
Bridge {
241+
cached_buffer: input,
242+
dispatch: (&mut dispatch).into(),
243+
force_show_panics,
244+
},
230245
client_data,
231246
);
232247

@@ -265,14 +280,21 @@ fn run_server<
265280
input: I,
266281
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
267282
client_data: D,
283+
force_show_panics: bool,
268284
) -> Result<O, PanicMessage> {
269285
let mut dispatcher =
270286
Dispatcher { handle_store: HandleStore::new(handle_counters), server: MarkedTypes(server) };
271287

272288
let mut b = Buffer::new();
273289
input.encode(&mut b, &mut dispatcher.handle_store);
274290

275-
b = strategy.run_bridge_and_client(&mut dispatcher, b, run_client, client_data);
291+
b = strategy.run_bridge_and_client(
292+
&mut dispatcher,
293+
b,
294+
run_client,
295+
client_data,
296+
force_show_panics,
297+
);
276298

277299
Result::decode(&mut &b[..], &mut dispatcher.handle_store)
278300
}
@@ -283,6 +305,7 @@ impl client::Client<fn(crate::TokenStream) -> crate::TokenStream> {
283305
strategy: &impl ExecutionStrategy,
284306
server: S,
285307
input: S::TokenStream,
308+
force_show_panics: bool,
286309
) -> Result<S::TokenStream, PanicMessage> {
287310
let client::Client { get_handle_counters, run, f } = *self;
288311
run_server(
@@ -292,6 +315,7 @@ impl client::Client<fn(crate::TokenStream) -> crate::TokenStream> {
292315
<MarkedTypes<S> as Types>::TokenStream::mark(input),
293316
run,
294317
f,
318+
force_show_panics,
295319
)
296320
.map(<MarkedTypes<S> as Types>::TokenStream::unmark)
297321
}
@@ -304,6 +328,7 @@ impl client::Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenSt
304328
server: S,
305329
input: S::TokenStream,
306330
input2: S::TokenStream,
331+
force_show_panics: bool,
307332
) -> Result<S::TokenStream, PanicMessage> {
308333
let client::Client { get_handle_counters, run, f } = *self;
309334
run_server(
@@ -316,6 +341,7 @@ impl client::Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenSt
316341
),
317342
run,
318343
f,
344+
force_show_panics,
319345
)
320346
.map(<MarkedTypes<S> as Types>::TokenStream::unmark)
321347
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// aux-build:test-macros.rs
2+
// compile-flags: -Z proc-macro-backtrace
3+
// rustc-env:RUST_BACKTRACE=0
4+
5+
// FIXME https://github.com/rust-lang/rust/issues/59998
6+
// normalize-stderr-test "thread '.*' panicked " -> ""
7+
// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
8+
// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
9+
// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
10+
// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
11+
// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
12+
// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
13+
14+
#[macro_use]
15+
extern crate test_macros;
16+
17+
#[derive(Panic)]
18+
//~^ ERROR: proc-macro derive panicked
19+
struct Foo;
20+
21+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
at 'panic-derive', $DIR/auxiliary/test-macros.rs:43:5
2+
error: proc-macro derive panicked
3+
--> $DIR/load-panic-backtrace.rs:17:10
4+
|
5+
LL | #[derive(Panic)]
6+
| ^^^^^
7+
|
8+
= help: message: panic-derive
9+
10+
error: aborting due to previous error
11+

0 commit comments

Comments
 (0)