about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-11-21 06:42:14 +0000
committerbors <bors@rust-lang.org>2017-11-21 06:42:14 +0000
commitbac7c53bc3842b494af098dbab8723fde9c97da2 (patch)
tree215ef7bb6abc3c66adf8401d875ac04edbe56200
parent421a2113a840aa5801230e7226fc9628100072ef (diff)
parentb34a7ffb2524bbe2e8d563a846f6c9f8e2453c1a (diff)
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 https://github.com/rust-lang/rust/commit/61865384b8fa6d79d2b36cbd7c899eaf15f4aeea).

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
-rw-r--r--src/librustc/session/config.rs8
-rw-r--r--src/librustc/session/mod.rs15
-rw-r--r--src/librustc_errors/diagnostic_builder.rs2
-rw-r--r--src/librustc_errors/emitter.rs55
-rw-r--r--src/librustc_errors/lib.rs58
-rw-r--r--src/librustc_errors/snippet.rs1
-rw-r--r--src/librustdoc/test.rs4
-rw-r--r--src/libsyntax/parse/obsolete.rs2
-rw-r--r--src/test/ui/codemap_tests/bad-format-args.stderr6
-rw-r--r--src/test/ui/codemap_tests/issue-28308.stderr2
-rw-r--r--src/test/ui/cross-crate-macro-backtrace/main.stderr2
-rw-r--r--src/test/ui/fmt/format-string-error.stderr4
-rw-r--r--src/test/ui/lifetimes/borrowck-let-suggestion.stderr2
-rw-r--r--src/test/ui/macro_backtrace/auxiliary/ping.rs20
-rw-r--r--src/test/ui/macro_backtrace/main.rs25
-rw-r--r--src/test/ui/macro_backtrace/main.stderr21
-rw-r--r--src/test/ui/macros/format-foreign.stderr2
-rw-r--r--src/test/ui/macros/format-unused-lables.stderr6
-rw-r--r--src/test/ui/reachable/expr_again.stderr2
-rw-r--r--src/test/ui/reachable/expr_block.stderr2
-rw-r--r--src/test/ui/reachable/expr_if.stderr2
-rw-r--r--src/test/ui/reachable/expr_loop.stderr6
-rw-r--r--src/test/ui/reachable/expr_match.stderr4
-rw-r--r--src/test/ui/reachable/expr_while.stderr6
-rw-r--r--src/test/ui/span/coerce-suggestions.stderr2
-rw-r--r--src/test/ui/span/issue-33884.stderr2
-rw-r--r--src/test/ui/span/issue-40157.stderr2
-rw-r--r--src/test/ui/span/slice-borrow.stderr2
-rw-r--r--src/test/ui/type-check/cannot_infer_local_or_vec.stderr2
-rw-r--r--src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.stderr2
30 files changed, 211 insertions, 58 deletions
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 57fae2200e2..ee197a009f8 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -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],
@@ -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);
         }
 
         {
@@ -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);
         }
 
         {
@@ -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);
         }
     }
 
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 9f957cd7808..78015967428 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -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))
@@ -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,
diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs
index 40b5810454b..27e895164e7 100644
--- a/src/librustc_errors/diagnostic_builder.rs
+++ b/src/librustc_errors/diagnostic_builder.rs
@@ -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,
 }
 
diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs
index 57523d2c058..17ed1734fe2 100644
--- a/src/librustc_errors/emitter.rs
+++ b/src/librustc_errors/emitter.rs
@@ -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,
@@ -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,
             });
@@ -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<()> {
@@ -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)?;
 
@@ -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,
@@ -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();
@@ -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),
@@ -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) {
@@ -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))?;
diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs
index e83ac8831de..605cfc5ed12 100644
--- a/src/librustc_errors/lib.rs
+++ b/src/librustc_errors/lib.rs
@@ -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>>>,
@@ -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),
@@ -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
@@ -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
@@ -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");
         }
     }
@@ -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);
@@ -443,7 +473,7 @@ 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);
@@ -451,7 +481,7 @@ impl Handler {
         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);
@@ -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);
@@ -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);
diff --git a/src/librustc_errors/snippet.rs b/src/librustc_errors/snippet.rs
index 2e8deeee5a5..b76036b22df 100644
--- a/src/librustc_errors/snippet.rs
+++ b/src/librustc_errors/snippet.rs
@@ -213,6 +213,7 @@ pub enum Style {
     UnderlineSecondary,
     LabelPrimary,
     LabelSecondary,
+    OldSchoolNoteText,
     NoStyle,
     Level(Level),
     Highlight,
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 9bbd16355be..ea0d32e2a2d 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -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_(
diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs
index 078e86aa294..49a697edf41 100644
--- a/src/libsyntax/parse/obsolete.rs
+++ b/src/libsyntax/parse/obsolete.rs
@@ -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);
         }
diff --git a/src/test/ui/codemap_tests/bad-format-args.stderr b/src/test/ui/codemap_tests/bad-format-args.stderr
index 87255dfe774..7faabc6b3a6 100644
--- a/src/test/ui/codemap_tests/bad-format-args.stderr
+++ b/src/test/ui/codemap_tests/bad-format-args.stderr
@@ -4,7 +4,7 @@ error: requires at least a format string argument
 12 |     format!();
    |     ^^^^^^^^^^
    |
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: expected token: `,`
   --> $DIR/bad-format-args.rs:13:5
@@ -12,7 +12,7 @@ error: expected token: `,`
 13 |     format!("" 1);
    |     ^^^^^^^^^^^^^^
    |
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: expected token: `,`
   --> $DIR/bad-format-args.rs:14:5
@@ -20,7 +20,7 @@ error: expected token: `,`
 14 |     format!("", 1 1);
    |     ^^^^^^^^^^^^^^^^^
    |
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/codemap_tests/issue-28308.stderr b/src/test/ui/codemap_tests/issue-28308.stderr
index 7a1478104fd..bb91bbbc9e3 100644
--- a/src/test/ui/codemap_tests/issue-28308.stderr
+++ b/src/test/ui/codemap_tests/issue-28308.stderr
@@ -4,7 +4,7 @@ error[E0600]: cannot apply unary operator `!` to type `&'static str`
 12 |     assert!("foo");
    |     ^^^^^^^^^^^^^^^
    |
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/cross-crate-macro-backtrace/main.stderr b/src/test/ui/cross-crate-macro-backtrace/main.stderr
index 4dad6d60b40..7d5055deb89 100644
--- a/src/test/ui/cross-crate-macro-backtrace/main.stderr
+++ b/src/test/ui/cross-crate-macro-backtrace/main.stderr
@@ -4,7 +4,7 @@ error: 1 positional argument in format string, but no arguments were given
 16 |     myprintln!("{}"); //~ ERROR in this macro
    |     ^^^^^^^^^^^^^^^^^
    |
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/fmt/format-string-error.stderr b/src/test/ui/fmt/format-string-error.stderr
index 58b392f0b8d..1da8833e0f8 100644
--- a/src/test/ui/fmt/format-string-error.stderr
+++ b/src/test/ui/fmt/format-string-error.stderr
@@ -5,7 +5,7 @@ error: invalid format string: expected `'}'` but string was terminated
    |     ^^^^^^^^^^^^^^
    |
    = note: if you intended to print `{`, you can escape it using `{{`
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: invalid format string: unmatched `}` found
   --> $DIR/format-string-error.rs:14:5
@@ -14,7 +14,7 @@ error: invalid format string: unmatched `}` found
    |     ^^^^^^^^^^^^^^
    |
    = note: if you intended to print `}`, you can escape it using `}}`
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/lifetimes/borrowck-let-suggestion.stderr b/src/test/ui/lifetimes/borrowck-let-suggestion.stderr
index 6316c066660..ea8aafadc8e 100644
--- a/src/test/ui/lifetimes/borrowck-let-suggestion.stderr
+++ b/src/test/ui/lifetimes/borrowck-let-suggestion.stderr
@@ -9,7 +9,7 @@ error[E0597]: borrowed value does not live long enough
    | - temporary value needs to live until here
    |
    = note: consider using a `let` binding to increase its lifetime
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/macro_backtrace/auxiliary/ping.rs b/src/test/ui/macro_backtrace/auxiliary/ping.rs
new file mode 100644
index 00000000000..eeed0d78158
--- /dev/null
+++ b/src/test/ui/macro_backtrace/auxiliary/ping.rs
@@ -0,0 +1,20 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the macro backtrace facility works (supporting file)
+
+// a non-local macro
+#[macro_export]
+macro_rules! ping {
+    () => {
+        pong!();
+    }
+}
+
diff --git a/src/test/ui/macro_backtrace/main.rs b/src/test/ui/macro_backtrace/main.rs
new file mode 100644
index 00000000000..488aeddbf54
--- /dev/null
+++ b/src/test/ui/macro_backtrace/main.rs
@@ -0,0 +1,25 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the macro backtrace facility works
+// aux-build:ping.rs
+// compile-flags: -Z external-macro-backtrace
+
+#[macro_use] extern crate ping;
+
+// a local macro
+macro_rules! pong {
+    () => { syntax error };
+}
+
+fn main() {
+    pong!();
+    ping!();
+}
diff --git a/src/test/ui/macro_backtrace/main.stderr b/src/test/ui/macro_backtrace/main.stderr
new file mode 100644
index 00000000000..37f3d450215
--- /dev/null
+++ b/src/test/ui/macro_backtrace/main.stderr
@@ -0,0 +1,21 @@
+error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `error`
+  --> $DIR/main.rs:19:20
+   |
+19 |     () => { syntax error };
+   |                   -^^^^^ unexpected token
+   |                   |
+   |                   expected one of 8 possible tokens here
+$DIR/main.rs:23:5: 23:13 note: in this expansion of pong! (defined in $DIR/main.rs)
+
+error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `error`
+  --> $DIR/main.rs:19:20
+   |
+19 |     () => { syntax error };
+   |                   -^^^^^ unexpected token
+   |                   |
+   |                   expected one of 8 possible tokens here
+$DIR/main.rs:24:5: 24:13 note: in this expansion of ping! (defined in <ping macros>)
+<ping macros>:1:11: 1:24 note: in this expansion of pong! (defined in $DIR/main.rs)
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/macros/format-foreign.stderr b/src/test/ui/macros/format-foreign.stderr
index 00469b5f799..cb27bb2281d 100644
--- a/src/test/ui/macros/format-foreign.stderr
+++ b/src/test/ui/macros/format-foreign.stderr
@@ -11,7 +11,7 @@ error: multiple unused formatting arguments
    = help: `%.*3$s` should be written as `{:.2$}`
    = help: `%s` should be written as `{}`
    = note: printf formatting not supported; see the documentation for `std::fmt`
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: argument never used
   --> $DIR/format-foreign.rs:13:29
diff --git a/src/test/ui/macros/format-unused-lables.stderr b/src/test/ui/macros/format-unused-lables.stderr
index bd6d38ccb0a..0205e9a9bfc 100644
--- a/src/test/ui/macros/format-unused-lables.stderr
+++ b/src/test/ui/macros/format-unused-lables.stderr
@@ -8,7 +8,7 @@ error: multiple unused formatting arguments
    |                      |    unused
    |                      unused
    |
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: multiple unused formatting arguments
   --> $DIR/format-unused-lables.rs:14:5
@@ -23,7 +23,7 @@ error: multiple unused formatting arguments
 18 | |     );
    | |______^
    |
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: named argument never used
   --> $DIR/format-unused-lables.rs:20:35
@@ -47,7 +47,7 @@ error: multiple unused formatting arguments
    |
    = help: `$STUFF` should be written as `{STUFF}`
    = note: shell formatting not supported; see the documentation for `std::fmt`
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/reachable/expr_again.stderr b/src/test/ui/reachable/expr_again.stderr
index bf4e4dc4711..54b1d47710c 100644
--- a/src/test/ui/reachable/expr_again.stderr
+++ b/src/test/ui/reachable/expr_again.stderr
@@ -9,7 +9,7 @@ note: lint level defined here
    |
 13 | #![deny(unreachable_code)]
    |         ^^^^^^^^^^^^^^^^
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/reachable/expr_block.stderr b/src/test/ui/reachable/expr_block.stderr
index 542ce1c3fd9..8a17d4e6278 100644
--- a/src/test/ui/reachable/expr_block.stderr
+++ b/src/test/ui/reachable/expr_block.stderr
@@ -16,7 +16,7 @@ error: unreachable statement
 36 |         println!("foo");
    |         ^^^^^^^^^^^^^^^^
    |
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/reachable/expr_if.stderr b/src/test/ui/reachable/expr_if.stderr
index 2cf17474f6e..2b77f5bb3ca 100644
--- a/src/test/ui/reachable/expr_if.stderr
+++ b/src/test/ui/reachable/expr_if.stderr
@@ -9,7 +9,7 @@ note: lint level defined here
    |
 14 | #![deny(unreachable_code)]
    |         ^^^^^^^^^^^^^^^^
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/reachable/expr_loop.stderr b/src/test/ui/reachable/expr_loop.stderr
index 6e98e754c54..bcfe2c5bd63 100644
--- a/src/test/ui/reachable/expr_loop.stderr
+++ b/src/test/ui/reachable/expr_loop.stderr
@@ -9,7 +9,7 @@ note: lint level defined here
    |
 14 | #![deny(unreachable_code)]
    |         ^^^^^^^^^^^^^^^^
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: unreachable statement
   --> $DIR/expr_loop.rs:31:5
@@ -17,7 +17,7 @@ error: unreachable statement
 31 |     println!("I am dead.");
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: unreachable statement
   --> $DIR/expr_loop.rs:41:5
@@ -25,7 +25,7 @@ error: unreachable statement
 41 |     println!("I am dead.");
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/reachable/expr_match.stderr b/src/test/ui/reachable/expr_match.stderr
index f5857a5b345..dcfefe109c3 100644
--- a/src/test/ui/reachable/expr_match.stderr
+++ b/src/test/ui/reachable/expr_match.stderr
@@ -16,7 +16,7 @@ error: unreachable statement
 25 |     println!("I am dead");
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: unreachable statement
   --> $DIR/expr_match.rs:35:5
@@ -24,7 +24,7 @@ error: unreachable statement
 35 |     println!("I am dead");
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/reachable/expr_while.stderr b/src/test/ui/reachable/expr_while.stderr
index 066cfc86c64..31e63c324d2 100644
--- a/src/test/ui/reachable/expr_while.stderr
+++ b/src/test/ui/reachable/expr_while.stderr
@@ -9,7 +9,7 @@ note: lint level defined here
    |
 14 | #![deny(unreachable_code)]
    |         ^^^^^^^^^^^^^^^^
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: unreachable statement
   --> $DIR/expr_while.rs:33:9
@@ -17,7 +17,7 @@ error: unreachable statement
 33 |         println!("I am dead.");
    |         ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: unreachable statement
   --> $DIR/expr_while.rs:35:5
@@ -25,7 +25,7 @@ error: unreachable statement
 35 |     println!("I am, too.");
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/span/coerce-suggestions.stderr b/src/test/ui/span/coerce-suggestions.stderr
index b703632bf90..07f49d999a4 100644
--- a/src/test/ui/span/coerce-suggestions.stderr
+++ b/src/test/ui/span/coerce-suggestions.stderr
@@ -56,7 +56,7 @@ error[E0308]: mismatched types
    = note: expected type `&mut std::string::String`
               found type `std::string::String`
    = help: try with `&mut format!("foo")`
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/span/issue-33884.stderr b/src/test/ui/span/issue-33884.stderr
index 2a874181c7a..22eecb9d882 100644
--- a/src/test/ui/span/issue-33884.stderr
+++ b/src/test/ui/span/issue-33884.stderr
@@ -6,7 +6,7 @@ error[E0308]: mismatched types
    |
    = note: expected type `std::fmt::Arguments<'_>`
               found type `std::string::String`
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/span/issue-40157.stderr b/src/test/ui/span/issue-40157.stderr
index b689bef63f1..0879cb5fac2 100644
--- a/src/test/ui/span/issue-40157.stderr
+++ b/src/test/ui/span/issue-40157.stderr
@@ -8,7 +8,7 @@ error[E0597]: `foo` does not live long enough
    |      |                                              borrow occurs here
    |      borrowed value needs to live until here
    |
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/span/slice-borrow.stderr b/src/test/ui/span/slice-borrow.stderr
index 5e8edf80df6..f9dbddd226f 100644
--- a/src/test/ui/span/slice-borrow.stderr
+++ b/src/test/ui/span/slice-borrow.stderr
@@ -9,7 +9,7 @@ error[E0597]: borrowed value does not live long enough
 19 | }
    | - temporary value needs to live until here
    |
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-check/cannot_infer_local_or_vec.stderr b/src/test/ui/type-check/cannot_infer_local_or_vec.stderr
index 4788fad2088..923dcd01070 100644
--- a/src/test/ui/type-check/cannot_infer_local_or_vec.stderr
+++ b/src/test/ui/type-check/cannot_infer_local_or_vec.stderr
@@ -6,7 +6,7 @@ error[E0282]: type annotations needed
    |         |
    |         consider giving `x` a type
    |
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.stderr b/src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.stderr
index ccffadebe9e..24f2cef4a6c 100644
--- a/src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.stderr
+++ b/src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.stderr
@@ -6,7 +6,7 @@ error[E0282]: type annotations needed
    |         |
    |         consider giving the pattern a type
    |
-   = note: this error originates in a macro outside of the current crate
+   = note: this error originates in a macro outside of the current crate (run with -Z external-macro-backtrace for more info)
 
 error: aborting due to previous error