Skip to content

Commit bac7c53

Browse files
committed
Auto merge of #45545 - durka:macro-backtrace, r=nrc
show macro backtrace with -Z flag Fixes #39413 by adding a facility to restore the "old school" macro expansion backtraces (previously removed in 6186538). The restored functionality is accessed through the flag `-Z external-macro-backtrace`. Errors showing the truncated backtraces will suggest this flag. ### Example Code: <details> `a/src/lib.rs` ```rust #[macro_export] macro_rules! a { () => { a!(@) }; (@) => { a!(@@) }; (@@) => { syntax error; } } ``` `b/src/main.rs` ```rust #[macro_use] extern crate a; macro_rules! b { () => { b!(@) }; (@) => { b!(@@) }; (@@) => { syntax error; } } fn main() { a!(); b!(); } ``` </details> <br/><br/> Running without env var (note: first error is from remote macro, second from local macro): <details> ``` $ cargo +custom run Compiling b v0.1.0 error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `error` --> src/main.rs:12:5 | 12 | a!(); | ^^^^^ | | | expected one of 8 possible tokens here | unexpected token | = note: this error originates in a macro outside of the current crate (run with RUST_MACRO_BACKTRACE=1 for more info) error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `error` --> src/main.rs:7:16 | 7 | syntax error; | -^^^^^ unexpected token | | | expected one of 8 possible tokens here ... 13 | b!(); | ----- in this macro invocation error: aborting due to 2 previous errors error: Could not compile `b`. To learn more, run the command again with --verbose. ``` </details> The output is the same as today, except for an addition to the note which aids discoverability of the new environment variable. <br/><br/> Running _with_ env var: <details> ``` $ RUST_MACRO_BACKTRACE=1 cargo +custom run Compiling b v0.1.0 error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `error` --> <a macros>:1:72 | 1 | ( ) => { a ! ( @ ) } ; ( @ ) => { a ! ( @ @ ) } ; ( @ @ ) => { syntax error ; | -^^^^^ unexpected token | | | expected one of 8 possible tokens here src/main.rs:12:5: 12:10 note: in this expansion of a! (defined in <a macros>) <a macros>:1:11: 1:20 note: in this expansion of a! (defined in <a macros>) <a macros>:1:36: 1:47 note: in this expansion of a! (defined in <a macros>) error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `error` --> src/main.rs:7:16 | 7 | syntax error; | -^^^^^ unexpected token | | | expected one of 8 possible tokens here src/main.rs:12:5: 12:10 note: in this expansion of a! (defined in <a macros>) <a macros>:1:11: 1:20 note: in this expansion of a! (defined in <a macros>) <a macros>:1:36: 1:47 note: in this expansion of a! (defined in <a macros>) error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `error` --> src/main.rs:7:16 | 7 | syntax error; | -^^^^^ unexpected token | | | expected one of 8 possible tokens here src/main.rs:13:5: 13:10 note: in this expansion of b! (defined in src/main.rs) src/main.rs:4:13: 4:18 note: in this expansion of b! (defined in src/main.rs) src/main.rs:5:14: 5:20 note: in this expansion of b! (defined in src/main.rs) error: aborting due to 2 previous errors error: Could not compile `b`. To learn more, run the command again with --verbose. ``` </details> The output is hard to read, but better than nothing (and it's exactly what we used to have before the infamous `fix_multispans_in_std_macros`). <br/><br/> Wishlist: - Save the actual source of macros in crate metadata, not just AST, so the output can be improved - Hopefully this would allow line numbers in the trace as well - Show the actual macro invocations in the traces r? @nrc
2 parents 421a211 + b34a7ff commit bac7c53

30 files changed

+211
-58
lines changed

src/librustc/session/config.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
10361036
"run all passes except translation; no output"),
10371037
treat_err_as_bug: bool = (false, parse_bool, [TRACKED],
10381038
"treat all errors that occur as bugs"),
1039+
external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
1040+
"show macro backtraces even for non-local macros"),
10391041
continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
10401042
"attempt to recover from parse errors (experimental)"),
10411043
incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
@@ -2100,7 +2102,7 @@ mod tests {
21002102
let registry = errors::registry::Registry::new(&[]);
21012103
let (sessopts, _) = build_session_options_and_crate_config(&matches);
21022104
let sess = build_session(sessopts, None, registry);
2103-
assert!(!sess.diagnostic().can_emit_warnings);
2105+
assert!(!sess.diagnostic().flags.can_emit_warnings);
21042106
}
21052107

21062108
{
@@ -2111,7 +2113,7 @@ mod tests {
21112113
let registry = errors::registry::Registry::new(&[]);
21122114
let (sessopts, _) = build_session_options_and_crate_config(&matches);
21132115
let sess = build_session(sessopts, None, registry);
2114-
assert!(sess.diagnostic().can_emit_warnings);
2116+
assert!(sess.diagnostic().flags.can_emit_warnings);
21152117
}
21162118

21172119
{
@@ -2121,7 +2123,7 @@ mod tests {
21212123
let registry = errors::registry::Registry::new(&[]);
21222124
let (sessopts, _) = build_session_options_and_crate_config(&matches);
21232125
let sess = build_session(sessopts, None, registry);
2124-
assert!(sess.diagnostic().can_emit_warnings);
2126+
assert!(sess.diagnostic().flags.can_emit_warnings);
21252127
}
21262128
}
21272129

src/librustc/session/mod.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -727,10 +727,12 @@ pub fn build_session_with_codemap(sopts: config::Options,
727727
.unwrap_or(false);
728728
let cap_lints_allow = sopts.lint_cap.map_or(false, |cap| cap == lint::Allow);
729729

730-
let can_print_warnings = !(warnings_allow || cap_lints_allow);
730+
let can_emit_warnings = !(warnings_allow || cap_lints_allow);
731731

732732
let treat_err_as_bug = sopts.debugging_opts.treat_err_as_bug;
733733

734+
let external_macro_backtrace = sopts.debugging_opts.external_macro_backtrace;
735+
734736
let emitter: Box<Emitter> = match (sopts.error_format, emitter_dest) {
735737
(config::ErrorOutputType::HumanReadable(color_config), None) => {
736738
Box::new(EmitterWriter::stderr(color_config, Some(codemap.clone()), false))
@@ -753,9 +755,14 @@ pub fn build_session_with_codemap(sopts: config::Options,
753755
};
754756

755757
let diagnostic_handler =
756-
errors::Handler::with_emitter(can_print_warnings,
757-
treat_err_as_bug,
758-
emitter);
758+
errors::Handler::with_emitter_and_flags(
759+
emitter,
760+
errors::HandlerFlags {
761+
can_emit_warnings,
762+
treat_err_as_bug,
763+
external_macro_backtrace,
764+
.. Default::default()
765+
});
759766

760767
build_session_(sopts,
761768
local_crate_source_file,

src/librustc_errors/diagnostic_builder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use syntax_pos::{MultiSpan, Span};
2323
#[must_use]
2424
#[derive(Clone)]
2525
pub struct DiagnosticBuilder<'a> {
26-
handler: &'a Handler,
26+
pub handler: &'a Handler,
2727
diagnostic: Diagnostic,
2828
}
2929

src/librustc_errors/emitter.rs

+50-5
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,11 @@ impl Emitter for EmitterWriter {
6464
}
6565
}
6666

67-
self.fix_multispans_in_std_macros(&mut primary_span, &mut children);
67+
if !db.handler.flags.external_macro_backtrace {
68+
self.fix_multispans_in_std_macros(&mut primary_span, &mut children);
69+
}
6870
self.emit_messages_default(&db.level,
71+
db.handler.flags.external_macro_backtrace,
6972
&db.styled_message(),
7073
&db.code,
7174
&primary_span,
@@ -793,8 +796,11 @@ impl EmitterWriter {
793796
if spans_updated {
794797
children.push(SubDiagnostic {
795798
level: Level::Note,
796-
message: vec![("this error originates in a macro outside of the current crate"
797-
.to_string(), Style::NoStyle)],
799+
message: vec![
800+
(["this error originates in a macro outside of the current crate",
801+
"(run with -Z external-macro-backtrace for more info)"].join(" "),
802+
Style::NoStyle),
803+
],
798804
span: MultiSpan::new(),
799805
render_span: None,
800806
});
@@ -882,6 +888,7 @@ impl EmitterWriter {
882888
msg: &Vec<(String, Style)>,
883889
code: &Option<DiagnosticId>,
884890
level: &Level,
891+
external_macro_backtrace: bool,
885892
max_line_num_len: usize,
886893
is_secondary: bool)
887894
-> io::Result<()> {
@@ -1079,6 +1086,12 @@ impl EmitterWriter {
10791086
}
10801087
}
10811088

1089+
if external_macro_backtrace {
1090+
if let Some(ref primary_span) = msp.primary_span().as_ref() {
1091+
self.render_macro_backtrace_old_school(primary_span, &mut buffer)?;
1092+
}
1093+
}
1094+
10821095
// final step: take our styled buffer, render it, then output it
10831096
emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
10841097

@@ -1170,6 +1183,7 @@ impl EmitterWriter {
11701183
}
11711184
fn emit_messages_default(&mut self,
11721185
level: &Level,
1186+
external_macro_backtrace: bool,
11731187
message: &Vec<(String, Style)>,
11741188
code: &Option<DiagnosticId>,
11751189
span: &MultiSpan,
@@ -1178,7 +1192,13 @@ impl EmitterWriter {
11781192
let max_line_num = self.get_max_line_num(span, children);
11791193
let max_line_num_len = max_line_num.to_string().len();
11801194

1181-
match self.emit_message_default(span, message, code, level, max_line_num_len, false) {
1195+
match self.emit_message_default(span,
1196+
message,
1197+
code,
1198+
level,
1199+
external_macro_backtrace,
1200+
max_line_num_len,
1201+
false) {
11821202
Ok(()) => {
11831203
if !children.is_empty() {
11841204
let mut buffer = StyledBuffer::new();
@@ -1198,6 +1218,7 @@ impl EmitterWriter {
11981218
&child.styled_message(),
11991219
&None,
12001220
&child.level,
1221+
external_macro_backtrace,
12011222
max_line_num_len,
12021223
true) {
12031224
Err(e) => panic!("failed to emit error: {}", e),
@@ -1226,6 +1247,30 @@ impl EmitterWriter {
12261247
}
12271248
}
12281249
}
1250+
1251+
fn render_macro_backtrace_old_school(&self,
1252+
sp: &Span,
1253+
buffer: &mut StyledBuffer) -> io::Result<()> {
1254+
if let Some(ref cm) = self.cm {
1255+
for trace in sp.macro_backtrace().iter().rev() {
1256+
let line_offset = buffer.num_lines();
1257+
1258+
let mut diag_string =
1259+
format!("in this expansion of {}", trace.macro_decl_name);
1260+
if let Some(def_site_span) = trace.def_site_span {
1261+
diag_string.push_str(
1262+
&format!(" (defined in {})",
1263+
cm.span_to_filename(def_site_span)));
1264+
}
1265+
let snippet = cm.span_to_string(trace.call_site);
1266+
buffer.append(line_offset, &format!("{} ", snippet), Style::NoStyle);
1267+
buffer.append(line_offset, "note", Style::Level(Level::Note));
1268+
buffer.append(line_offset, ": ", Style::NoStyle);
1269+
buffer.append(line_offset, &diag_string, Style::OldSchoolNoteText);
1270+
}
1271+
}
1272+
Ok(())
1273+
}
12291274
}
12301275

12311276
fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
@@ -1415,7 +1460,7 @@ impl Destination {
14151460
}
14161461
}
14171462
Style::Quotation => {}
1418-
Style::HeaderMsg => {
1463+
Style::OldSchoolNoteText | Style::HeaderMsg => {
14191464
self.start_attr(term::Attr::Bold)?;
14201465
if cfg!(windows) {
14211466
self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_WHITE))?;

src/librustc_errors/lib.rs

+44-14
Original file line numberDiff line numberDiff line change
@@ -233,10 +233,10 @@ pub use diagnostic_builder::DiagnosticBuilder;
233233
/// (fatal, bug, unimpl) may cause immediate exit,
234234
/// others log errors for later reporting.
235235
pub struct Handler {
236+
pub flags: HandlerFlags,
237+
236238
err_count: Cell<usize>,
237239
emitter: RefCell<Box<Emitter>>,
238-
pub can_emit_warnings: bool,
239-
treat_err_as_bug: bool,
240240
continue_after_error: Cell<bool>,
241241
delayed_span_bug: RefCell<Option<Diagnostic>>,
242242
tracked_diagnostics: RefCell<Option<Vec<Diagnostic>>>,
@@ -247,25 +247,55 @@ pub struct Handler {
247247
emitted_diagnostics: RefCell<FxHashSet<u128>>,
248248
}
249249

250+
#[derive(Default)]
251+
pub struct HandlerFlags {
252+
pub can_emit_warnings: bool,
253+
pub treat_err_as_bug: bool,
254+
pub external_macro_backtrace: bool,
255+
}
256+
250257
impl Handler {
251258
pub fn with_tty_emitter(color_config: ColorConfig,
252259
can_emit_warnings: bool,
253260
treat_err_as_bug: bool,
254261
cm: Option<Rc<CodeMapper>>)
255262
-> Handler {
263+
Handler::with_tty_emitter_and_flags(
264+
color_config,
265+
cm,
266+
HandlerFlags {
267+
can_emit_warnings,
268+
treat_err_as_bug,
269+
.. Default::default()
270+
})
271+
}
272+
273+
pub fn with_tty_emitter_and_flags(color_config: ColorConfig,
274+
cm: Option<Rc<CodeMapper>>,
275+
flags: HandlerFlags)
276+
-> Handler {
256277
let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false));
257-
Handler::with_emitter(can_emit_warnings, treat_err_as_bug, emitter)
278+
Handler::with_emitter_and_flags(emitter, flags)
258279
}
259280

260281
pub fn with_emitter(can_emit_warnings: bool,
261282
treat_err_as_bug: bool,
262283
e: Box<Emitter>)
263284
-> Handler {
285+
Handler::with_emitter_and_flags(
286+
e,
287+
HandlerFlags {
288+
can_emit_warnings,
289+
treat_err_as_bug,
290+
.. Default::default()
291+
})
292+
}
293+
294+
pub fn with_emitter_and_flags(e: Box<Emitter>, flags: HandlerFlags) -> Handler {
264295
Handler {
296+
flags,
265297
err_count: Cell::new(0),
266298
emitter: RefCell::new(e),
267-
can_emit_warnings,
268-
treat_err_as_bug,
269299
continue_after_error: Cell::new(true),
270300
delayed_span_bug: RefCell::new(None),
271301
tracked_diagnostics: RefCell::new(None),
@@ -293,7 +323,7 @@ impl Handler {
293323
-> DiagnosticBuilder<'a> {
294324
let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
295325
result.set_span(sp);
296-
if !self.can_emit_warnings {
326+
if !self.flags.can_emit_warnings {
297327
result.cancel();
298328
}
299329
result
@@ -306,14 +336,14 @@ impl Handler {
306336
let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
307337
result.set_span(sp);
308338
result.code(code);
309-
if !self.can_emit_warnings {
339+
if !self.flags.can_emit_warnings {
310340
result.cancel();
311341
}
312342
result
313343
}
314344
pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
315345
let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
316-
if !self.can_emit_warnings {
346+
if !self.flags.can_emit_warnings {
317347
result.cancel();
318348
}
319349
result
@@ -376,7 +406,7 @@ impl Handler {
376406
}
377407

378408
fn panic_if_treat_err_as_bug(&self) {
379-
if self.treat_err_as_bug {
409+
if self.flags.treat_err_as_bug {
380410
panic!("encountered error with `-Z treat_err_as_bug");
381411
}
382412
}
@@ -418,7 +448,7 @@ impl Handler {
418448
panic!(ExplicitBug);
419449
}
420450
pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
421-
if self.treat_err_as_bug {
451+
if self.flags.treat_err_as_bug {
422452
self.span_bug(sp, msg);
423453
}
424454
let mut diagnostic = Diagnostic::new(Level::Bug, msg);
@@ -443,15 +473,15 @@ impl Handler {
443473
self.span_bug(sp, &format!("unimplemented {}", msg));
444474
}
445475
pub fn fatal(&self, msg: &str) -> FatalError {
446-
if self.treat_err_as_bug {
476+
if self.flags.treat_err_as_bug {
447477
self.bug(msg);
448478
}
449479
let mut db = DiagnosticBuilder::new(self, Fatal, msg);
450480
db.emit();
451481
FatalError
452482
}
453483
pub fn err(&self, msg: &str) {
454-
if self.treat_err_as_bug {
484+
if self.flags.treat_err_as_bug {
455485
self.bug(msg);
456486
}
457487
let mut db = DiagnosticBuilder::new(self, Error, msg);
@@ -504,7 +534,7 @@ impl Handler {
504534
panic!(self.fatal(&s));
505535
}
506536
pub fn emit(&self, msp: &MultiSpan, msg: &str, lvl: Level) {
507-
if lvl == Warning && !self.can_emit_warnings {
537+
if lvl == Warning && !self.flags.can_emit_warnings {
508538
return;
509539
}
510540
let mut db = DiagnosticBuilder::new(self, lvl, msg);
@@ -515,7 +545,7 @@ impl Handler {
515545
}
516546
}
517547
pub fn emit_with_code(&self, msp: &MultiSpan, msg: &str, code: DiagnosticId, lvl: Level) {
518-
if lvl == Warning && !self.can_emit_warnings {
548+
if lvl == Warning && !self.flags.can_emit_warnings {
519549
return;
520550
}
521551
let mut db = DiagnosticBuilder::new_with_code(self, lvl, Some(code), msg);

src/librustc_errors/snippet.rs

+1
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ pub enum Style {
213213
UnderlineSecondary,
214214
LabelPrimary,
215215
LabelSecondary,
216+
OldSchoolNoteText,
216217
NoStyle,
217218
Level(Level),
218219
Highlight,

src/librustdoc/test.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ pub fn run(input: &str,
8181

8282
let codemap = Rc::new(CodeMap::new(sessopts.file_path_mapping()));
8383
let handler =
84-
errors::Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(codemap.clone()));
84+
errors::Handler::with_tty_emitter(ColorConfig::Auto,
85+
true, false,
86+
Some(codemap.clone()));
8587

8688
let cstore = Rc::new(CStore::new(box rustc_trans::LlvmMetadataLoader));
8789
let mut sess = session::build_session_(

src/libsyntax/parse/obsolete.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> {
5858
};
5959

6060
if !self.obsolete_set.contains(&kind) &&
61-
(error || self.sess.span_diagnostic.can_emit_warnings) {
61+
(error || self.sess.span_diagnostic.flags.can_emit_warnings) {
6262
err.note(desc);
6363
self.obsolete_set.insert(kind);
6464
}

0 commit comments

Comments
 (0)