Skip to content

Commit

Permalink
Auto merge of #45545 - durka:macro-backtrace, r=nrc
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Nov 21, 2017
2 parents 421a211 + b34a7ff commit bac7c53
Show file tree
Hide file tree
Showing 30 changed files with 211 additions and 58 deletions.
8 changes: 5 additions & 3 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1036,6 +1036,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"run all passes except translation; no output"),
treat_err_as_bug: bool = (false, parse_bool, [TRACKED],
"treat all errors that occur as bugs"),
external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
"show macro backtraces even for non-local macros"),
continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
"attempt to recover from parse errors (experimental)"),
incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
Expand Down Expand Up @@ -2100,7 +2102,7 @@ mod tests {
let registry = errors::registry::Registry::new(&[]);
let (sessopts, _) = build_session_options_and_crate_config(&matches);
let sess = build_session(sessopts, None, registry);
assert!(!sess.diagnostic().can_emit_warnings);
assert!(!sess.diagnostic().flags.can_emit_warnings);
}

{
Expand All @@ -2111,7 +2113,7 @@ mod tests {
let registry = errors::registry::Registry::new(&[]);
let (sessopts, _) = build_session_options_and_crate_config(&matches);
let sess = build_session(sessopts, None, registry);
assert!(sess.diagnostic().can_emit_warnings);
assert!(sess.diagnostic().flags.can_emit_warnings);
}

{
Expand All @@ -2121,7 +2123,7 @@ mod tests {
let registry = errors::registry::Registry::new(&[]);
let (sessopts, _) = build_session_options_and_crate_config(&matches);
let sess = build_session(sessopts, None, registry);
assert!(sess.diagnostic().can_emit_warnings);
assert!(sess.diagnostic().flags.can_emit_warnings);
}
}

Expand Down
15 changes: 11 additions & 4 deletions src/librustc/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -727,10 +727,12 @@ pub fn build_session_with_codemap(sopts: config::Options,
.unwrap_or(false);
let cap_lints_allow = sopts.lint_cap.map_or(false, |cap| cap == lint::Allow);

let can_print_warnings = !(warnings_allow || cap_lints_allow);
let can_emit_warnings = !(warnings_allow || cap_lints_allow);

let treat_err_as_bug = sopts.debugging_opts.treat_err_as_bug;

let external_macro_backtrace = sopts.debugging_opts.external_macro_backtrace;

let emitter: Box<Emitter> = match (sopts.error_format, emitter_dest) {
(config::ErrorOutputType::HumanReadable(color_config), None) => {
Box::new(EmitterWriter::stderr(color_config, Some(codemap.clone()), false))
Expand All @@ -753,9 +755,14 @@ pub fn build_session_with_codemap(sopts: config::Options,
};

let diagnostic_handler =
errors::Handler::with_emitter(can_print_warnings,
treat_err_as_bug,
emitter);
errors::Handler::with_emitter_and_flags(
emitter,
errors::HandlerFlags {
can_emit_warnings,
treat_err_as_bug,
external_macro_backtrace,
.. Default::default()
});

build_session_(sopts,
local_crate_source_file,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_errors/diagnostic_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use syntax_pos::{MultiSpan, Span};
#[must_use]
#[derive(Clone)]
pub struct DiagnosticBuilder<'a> {
handler: &'a Handler,
pub handler: &'a Handler,
diagnostic: Diagnostic,
}

Expand Down
55 changes: 50 additions & 5 deletions src/librustc_errors/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,11 @@ impl Emitter for EmitterWriter {
}
}

self.fix_multispans_in_std_macros(&mut primary_span, &mut children);
if !db.handler.flags.external_macro_backtrace {
self.fix_multispans_in_std_macros(&mut primary_span, &mut children);
}
self.emit_messages_default(&db.level,
db.handler.flags.external_macro_backtrace,
&db.styled_message(),
&db.code,
&primary_span,
Expand Down Expand Up @@ -793,8 +796,11 @@ impl EmitterWriter {
if spans_updated {
children.push(SubDiagnostic {
level: Level::Note,
message: vec![("this error originates in a macro outside of the current crate"
.to_string(), Style::NoStyle)],
message: vec![
(["this error originates in a macro outside of the current crate",
"(run with -Z external-macro-backtrace for more info)"].join(" "),
Style::NoStyle),
],
span: MultiSpan::new(),
render_span: None,
});
Expand Down Expand Up @@ -882,6 +888,7 @@ impl EmitterWriter {
msg: &Vec<(String, Style)>,
code: &Option<DiagnosticId>,
level: &Level,
external_macro_backtrace: bool,
max_line_num_len: usize,
is_secondary: bool)
-> io::Result<()> {
Expand Down Expand Up @@ -1079,6 +1086,12 @@ impl EmitterWriter {
}
}

if external_macro_backtrace {
if let Some(ref primary_span) = msp.primary_span().as_ref() {
self.render_macro_backtrace_old_school(primary_span, &mut buffer)?;
}
}

// final step: take our styled buffer, render it, then output it
emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;

Expand Down Expand Up @@ -1170,6 +1183,7 @@ impl EmitterWriter {
}
fn emit_messages_default(&mut self,
level: &Level,
external_macro_backtrace: bool,
message: &Vec<(String, Style)>,
code: &Option<DiagnosticId>,
span: &MultiSpan,
Expand All @@ -1178,7 +1192,13 @@ impl EmitterWriter {
let max_line_num = self.get_max_line_num(span, children);
let max_line_num_len = max_line_num.to_string().len();

match self.emit_message_default(span, message, code, level, max_line_num_len, false) {
match self.emit_message_default(span,
message,
code,
level,
external_macro_backtrace,
max_line_num_len,
false) {
Ok(()) => {
if !children.is_empty() {
let mut buffer = StyledBuffer::new();
Expand All @@ -1198,6 +1218,7 @@ impl EmitterWriter {
&child.styled_message(),
&None,
&child.level,
external_macro_backtrace,
max_line_num_len,
true) {
Err(e) => panic!("failed to emit error: {}", e),
Expand Down Expand Up @@ -1226,6 +1247,30 @@ impl EmitterWriter {
}
}
}

fn render_macro_backtrace_old_school(&self,
sp: &Span,
buffer: &mut StyledBuffer) -> io::Result<()> {
if let Some(ref cm) = self.cm {
for trace in sp.macro_backtrace().iter().rev() {
let line_offset = buffer.num_lines();

let mut diag_string =
format!("in this expansion of {}", trace.macro_decl_name);
if let Some(def_site_span) = trace.def_site_span {
diag_string.push_str(
&format!(" (defined in {})",
cm.span_to_filename(def_site_span)));
}
let snippet = cm.span_to_string(trace.call_site);
buffer.append(line_offset, &format!("{} ", snippet), Style::NoStyle);
buffer.append(line_offset, "note", Style::Level(Level::Note));
buffer.append(line_offset, ": ", Style::NoStyle);
buffer.append(line_offset, &diag_string, Style::OldSchoolNoteText);
}
}
Ok(())
}
}

fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
Expand Down Expand Up @@ -1415,7 +1460,7 @@ impl Destination {
}
}
Style::Quotation => {}
Style::HeaderMsg => {
Style::OldSchoolNoteText | Style::HeaderMsg => {
self.start_attr(term::Attr::Bold)?;
if cfg!(windows) {
self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_WHITE))?;
Expand Down
58 changes: 44 additions & 14 deletions src/librustc_errors/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,10 @@ pub use diagnostic_builder::DiagnosticBuilder;
/// (fatal, bug, unimpl) may cause immediate exit,
/// others log errors for later reporting.
pub struct Handler {
pub flags: HandlerFlags,

err_count: Cell<usize>,
emitter: RefCell<Box<Emitter>>,
pub can_emit_warnings: bool,
treat_err_as_bug: bool,
continue_after_error: Cell<bool>,
delayed_span_bug: RefCell<Option<Diagnostic>>,
tracked_diagnostics: RefCell<Option<Vec<Diagnostic>>>,
Expand All @@ -247,25 +247,55 @@ pub struct Handler {
emitted_diagnostics: RefCell<FxHashSet<u128>>,
}

#[derive(Default)]
pub struct HandlerFlags {
pub can_emit_warnings: bool,
pub treat_err_as_bug: bool,
pub external_macro_backtrace: bool,
}

impl Handler {
pub fn with_tty_emitter(color_config: ColorConfig,
can_emit_warnings: bool,
treat_err_as_bug: bool,
cm: Option<Rc<CodeMapper>>)
-> Handler {
Handler::with_tty_emitter_and_flags(
color_config,
cm,
HandlerFlags {
can_emit_warnings,
treat_err_as_bug,
.. Default::default()
})
}

pub fn with_tty_emitter_and_flags(color_config: ColorConfig,
cm: Option<Rc<CodeMapper>>,
flags: HandlerFlags)
-> Handler {
let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false));
Handler::with_emitter(can_emit_warnings, treat_err_as_bug, emitter)
Handler::with_emitter_and_flags(emitter, flags)
}

pub fn with_emitter(can_emit_warnings: bool,
treat_err_as_bug: bool,
e: Box<Emitter>)
-> Handler {
Handler::with_emitter_and_flags(
e,
HandlerFlags {
can_emit_warnings,
treat_err_as_bug,
.. Default::default()
})
}

pub fn with_emitter_and_flags(e: Box<Emitter>, flags: HandlerFlags) -> Handler {
Handler {
flags,
err_count: Cell::new(0),
emitter: RefCell::new(e),
can_emit_warnings,
treat_err_as_bug,
continue_after_error: Cell::new(true),
delayed_span_bug: RefCell::new(None),
tracked_diagnostics: RefCell::new(None),
Expand Down Expand Up @@ -293,7 +323,7 @@ impl Handler {
-> DiagnosticBuilder<'a> {
let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
result.set_span(sp);
if !self.can_emit_warnings {
if !self.flags.can_emit_warnings {
result.cancel();
}
result
Expand All @@ -306,14 +336,14 @@ impl Handler {
let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
result.set_span(sp);
result.code(code);
if !self.can_emit_warnings {
if !self.flags.can_emit_warnings {
result.cancel();
}
result
}
pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
if !self.can_emit_warnings {
if !self.flags.can_emit_warnings {
result.cancel();
}
result
Expand Down Expand Up @@ -376,7 +406,7 @@ impl Handler {
}

fn panic_if_treat_err_as_bug(&self) {
if self.treat_err_as_bug {
if self.flags.treat_err_as_bug {
panic!("encountered error with `-Z treat_err_as_bug");
}
}
Expand Down Expand Up @@ -418,7 +448,7 @@ impl Handler {
panic!(ExplicitBug);
}
pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
if self.treat_err_as_bug {
if self.flags.treat_err_as_bug {
self.span_bug(sp, msg);
}
let mut diagnostic = Diagnostic::new(Level::Bug, msg);
Expand All @@ -443,15 +473,15 @@ impl Handler {
self.span_bug(sp, &format!("unimplemented {}", msg));
}
pub fn fatal(&self, msg: &str) -> FatalError {
if self.treat_err_as_bug {
if self.flags.treat_err_as_bug {
self.bug(msg);
}
let mut db = DiagnosticBuilder::new(self, Fatal, msg);
db.emit();
FatalError
}
pub fn err(&self, msg: &str) {
if self.treat_err_as_bug {
if self.flags.treat_err_as_bug {
self.bug(msg);
}
let mut db = DiagnosticBuilder::new(self, Error, msg);
Expand Down Expand Up @@ -504,7 +534,7 @@ impl Handler {
panic!(self.fatal(&s));
}
pub fn emit(&self, msp: &MultiSpan, msg: &str, lvl: Level) {
if lvl == Warning && !self.can_emit_warnings {
if lvl == Warning && !self.flags.can_emit_warnings {
return;
}
let mut db = DiagnosticBuilder::new(self, lvl, msg);
Expand All @@ -515,7 +545,7 @@ impl Handler {
}
}
pub fn emit_with_code(&self, msp: &MultiSpan, msg: &str, code: DiagnosticId, lvl: Level) {
if lvl == Warning && !self.can_emit_warnings {
if lvl == Warning && !self.flags.can_emit_warnings {
return;
}
let mut db = DiagnosticBuilder::new_with_code(self, lvl, Some(code), msg);
Expand Down
1 change: 1 addition & 0 deletions src/librustc_errors/snippet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ pub enum Style {
UnderlineSecondary,
LabelPrimary,
LabelSecondary,
OldSchoolNoteText,
NoStyle,
Level(Level),
Highlight,
Expand Down
4 changes: 3 additions & 1 deletion src/librustdoc/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ pub fn run(input: &str,

let codemap = Rc::new(CodeMap::new(sessopts.file_path_mapping()));
let handler =
errors::Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(codemap.clone()));
errors::Handler::with_tty_emitter(ColorConfig::Auto,
true, false,
Some(codemap.clone()));

let cstore = Rc::new(CStore::new(box rustc_trans::LlvmMetadataLoader));
let mut sess = session::build_session_(
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/parse/obsolete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> {
};

if !self.obsolete_set.contains(&kind) &&
(error || self.sess.span_diagnostic.can_emit_warnings) {
(error || self.sess.span_diagnostic.flags.can_emit_warnings) {
err.note(desc);
self.obsolete_set.insert(kind);
}
Expand Down
Loading

0 comments on commit bac7c53

Please sign in to comment.