]> git.lizzy.rs Git - rust.git/commitdiff
Replace local backtrace with def-use, repair std macro spans
authorJonathan Turner <jturner@mozilla.com>
Wed, 17 Aug 2016 14:20:04 +0000 (07:20 -0700)
committerJonathan Turner <jturner@mozilla.com>
Wed, 17 Aug 2016 21:26:14 +0000 (14:26 -0700)
25 files changed:
src/librustc_errors/emitter.rs
src/libsyntax_pos/lib.rs
src/test/compile-fail/bad-format-args.rs [deleted file]
src/test/compile-fail/issue-28308.rs [deleted file]
src/test/compile-fail/macro-backtrace-invalid-internals.rs [deleted file]
src/test/compile-fail/macro-backtrace-nested.rs [deleted file]
src/test/compile-fail/macro-backtrace-println.rs [deleted file]
src/test/run-fail-fulldeps/qquote.rs
src/test/ui/codemap_tests/bad-format-args.rs [new file with mode: 0644]
src/test/ui/codemap_tests/bad-format-args.stderr [new file with mode: 0644]
src/test/ui/codemap_tests/issue-28308.rs [new file with mode: 0644]
src/test/ui/codemap_tests/issue-28308.stderr [new file with mode: 0644]
src/test/ui/codemap_tests/repair_span_std_macros.rs [new file with mode: 0644]
src/test/ui/codemap_tests/repair_span_std_macros.stderr [new file with mode: 0644]
src/test/ui/cross-crate-macro-backtrace/auxiliary/extern_macro_crate.rs [new file with mode: 0644]
src/test/ui/cross-crate-macro-backtrace/main.rs [new file with mode: 0644]
src/test/ui/cross-crate-macro-backtrace/main.stderr [new file with mode: 0644]
src/test/ui/macros/bad_hello.rs [new file with mode: 0644]
src/test/ui/macros/bad_hello.stderr [new file with mode: 0644]
src/test/ui/macros/macro-backtrace-invalid-internals.rs [new file with mode: 0644]
src/test/ui/macros/macro-backtrace-invalid-internals.stderr [new file with mode: 0644]
src/test/ui/macros/macro-backtrace-nested.rs [new file with mode: 0644]
src/test/ui/macros/macro-backtrace-nested.stderr [new file with mode: 0644]
src/test/ui/macros/macro-backtrace-println.rs [new file with mode: 0644]
src/test/ui/macros/macro-backtrace-println.stderr [new file with mode: 0644]

index 981729ddb839581ceecabe70f30093b388313de1..11c9c5b1d9c8dcbed536533cf9b2f664d7970d0b 100644 (file)
@@ -12,7 +12,7 @@
 
 use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, CharPos};
 
-use {Level, CodeSuggestion, DiagnosticBuilder, CodeMapper};
+use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapper};
 use RenderSpan::*;
 use snippet::{StyledString, Style, Annotation, Line};
 use styled_buffer::StyledBuffer;
@@ -30,7 +30,10 @@ pub trait Emitter {
 
 impl Emitter for EmitterWriter {
     fn emit(&mut self, db: &DiagnosticBuilder) {
-        self.emit_messages_default(db);
+        let mut primary_span = db.span.clone();
+        let mut children = db.children.clone();
+        self.fix_multispans_in_std_macros(&mut primary_span, &mut children);
+        self.emit_messages_default(&db.level, &db.message, &db.code, &primary_span, &children);
     }
 }
 
@@ -381,19 +384,100 @@ fn get_multispan_max_line_num(&mut self, msp: &MultiSpan) -> usize {
         max
     }
 
-    fn get_max_line_num(&mut self, db: &DiagnosticBuilder) -> usize {
+    fn get_max_line_num(&mut self, span: &MultiSpan, children: &Vec<SubDiagnostic>) -> usize {
         let mut max = 0;
 
-        let primary = self.get_multispan_max_line_num(&db.span);
+        let primary = self.get_multispan_max_line_num(span);
         max = if primary > max { primary } else { max };
 
-        for sub in &db.children {
+        for sub in children {
             let sub_result = self.get_multispan_max_line_num(&sub.span);
             max = if sub_result > max { primary } else { max };
         }
         max
     }
 
+    // This "fixes" MultiSpans that contain Spans that are pointing to locations inside of
+    // <*macros>. Since these locations are often difficult to read, we move these Spans from
+    // <*macros> to their corresponding use site.
+    fn fix_multispan_in_std_macros(&mut self, span: &mut MultiSpan) -> bool {
+        let mut spans_updated = false;
+
+        if let Some(ref cm) = self.cm {
+            let mut before_after: Vec<(Span, Span)> = vec![];
+            let mut new_labels: Vec<(Span, String)> = vec![];
+
+            // First, find all the spans in <*macros> and point instead at their use site
+            for sp in span.primary_spans() {
+                if (*sp == COMMAND_LINE_SP) || (*sp == DUMMY_SP) {
+                    continue;
+                }
+                if cm.span_to_filename(sp.clone()).contains("macros>") {
+                    let v = cm.macro_backtrace(sp.clone());
+                    if let Some(use_site) = v.last() {
+                        before_after.push((sp.clone(), use_site.call_site.clone()));
+                    }
+                }
+                for trace in cm.macro_backtrace(sp.clone()).iter().rev() {
+                    // Only show macro locations that are local
+                    // and display them like a span_note
+                    if let Some(def_site) = trace.def_site_span {
+                        if (def_site == COMMAND_LINE_SP) || (def_site == DUMMY_SP) {
+                            continue;
+                        }
+                        // Check to make sure we're not in any <*macros>
+                        if !cm.span_to_filename(def_site).contains("macros>") {
+                            new_labels.push((trace.call_site,
+                                             "in this macro invocation".to_string()));
+                            break;
+                        }
+                    }
+                }
+            }
+            for (label_span, label_text) in new_labels {
+                span.push_span_label(label_span, label_text);
+            }
+            for sp_label in span.span_labels() {
+                if (sp_label.span == COMMAND_LINE_SP) || (sp_label.span == DUMMY_SP) {
+                    continue;
+                }
+                if cm.span_to_filename(sp_label.span.clone()).contains("macros>") {
+                    let v = cm.macro_backtrace(sp_label.span.clone());
+                    if let Some(use_site) = v.last() {
+                        before_after.push((sp_label.span.clone(), use_site.call_site.clone()));
+                    }
+                }
+            }
+            // After we have them, make sure we replace these 'bad' def sites with their use sites
+            for (before, after) in before_after {
+                span.replace(before, after);
+                spans_updated = true;
+            }
+        }
+
+        spans_updated
+    }
+
+    // This does a small "fix" for multispans by looking to see if it can find any that
+    // point directly at <*macros>. Since these are often difficult to read, this
+    // will change the span to point at the use site.
+    fn fix_multispans_in_std_macros(&mut self,
+                                    span: &mut MultiSpan,
+                                    children: &mut Vec<SubDiagnostic>) {
+        let mut spans_updated = self.fix_multispan_in_std_macros(span);
+        for child in &mut children.iter_mut() {
+            spans_updated |= self.fix_multispan_in_std_macros(&mut child.span);
+        }
+        if spans_updated {
+            children.push(SubDiagnostic {
+                level: Level::Note,
+                message: "this error originates in a macro from the standard library".to_string(),
+                span: MultiSpan::new(),
+                render_span: None
+            });
+        }
+    }
+
     fn emit_message_default(&mut self,
                             msp: &MultiSpan,
                             msg: &str,
@@ -528,10 +612,6 @@ fn emit_message_default(&mut self,
             }
         }
 
-        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)?;
 
@@ -578,26 +658,31 @@ fn emit_suggestion_default(&mut self,
         }
         Ok(())
     }
-    fn emit_messages_default(&mut self, db: &DiagnosticBuilder) {
-        let max_line_num = self.get_max_line_num(db);
+    fn emit_messages_default(&mut self,
+                             level: &Level,
+                             message: &String,
+                             code: &Option<String>,
+                             span: &MultiSpan,
+                             children: &Vec<SubDiagnostic>) {
+        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(&db.span,
-                                        &db.message,
-                                        &db.code,
-                                        &db.level,
+        match self.emit_message_default(span,
+                                        message,
+                                        code,
+                                        level,
                                         max_line_num_len,
                                         false) {
             Ok(()) => {
-                if !db.children.is_empty() {
+                if !children.is_empty() {
                     let mut buffer = StyledBuffer::new();
                     draw_col_separator_no_space(&mut buffer, 0, max_line_num_len + 1);
-                    match emit_to_destination(&buffer.render(), &db.level, &mut self.dst) {
+                    match emit_to_destination(&buffer.render(), level, &mut self.dst) {
                         Ok(()) => (),
                         Err(e) => panic!("failed to emit error: {}", e)
                     }
                 }
-                for child in &db.children {
+                for child in children {
                     match child.render_span {
                         Some(FullSpan(ref msp)) => {
                             match self.emit_message_default(msp,
@@ -640,29 +725,6 @@ fn emit_messages_default(&mut self, db: &DiagnosticBuilder) {
             _ => ()
         }
     }
-    fn render_macro_backtrace_old_school(&mut self,
-                                         sp: &Span,
-                                         buffer: &mut StyledBuffer) -> io::Result<()> {
-        if let Some(ref cm) = self.cm {
-            for trace in cm.macro_backtrace(sp.clone()) {
-                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) {
index 0f171805bb0a988fb95853932fa3619b46b37627..b11bbea84abcedfa3e77f15cd85347a3e26e7087 100644 (file)
@@ -221,6 +221,25 @@ pub fn primary_spans(&self) -> &[Span] {
         &self.primary_spans
     }
 
+    /// Replaces all occurances of one Span with another. Used to move Spans in areas that don't
+    /// display well (like std macros). Returns true if replacements occurred.
+    pub fn replace(&mut self, before: Span, after: Span) -> bool {
+        let mut replacements_occurred = false;
+        for primary_span in &mut self.primary_spans {
+            if *primary_span == before {
+                *primary_span = after;
+                replacements_occurred = true;
+            }
+        }
+        for span_label in &mut self.span_labels {
+            if span_label.0 == before {
+                span_label.0 = after;
+                replacements_occurred = true;
+            }
+        }
+        replacements_occurred
+    }
+
     /// Returns the strings to highlight. We always ensure that there
     /// is an entry for each of the primary spans -- for each primary
     /// span P, if there is at least one label with span P, we return
diff --git a/src/test/compile-fail/bad-format-args.rs b/src/test/compile-fail/bad-format-args.rs
deleted file mode 100644 (file)
index 8c58c8c..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2016 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.
-
-// error-pattern: requires at least a format string argument
-// error-pattern: in this expansion
-
-// error-pattern: expected token: `,`
-// error-pattern: in this expansion
-// error-pattern: in this expansion
-
-fn main() {
-    format!();
-    format!("" 1);
-    format!("", 1 1);
-}
diff --git a/src/test/compile-fail/issue-28308.rs b/src/test/compile-fail/issue-28308.rs
deleted file mode 100644 (file)
index b0c44b5..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2016 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.
-
-// this error is dispayed in `<std macros>`
-// error-pattern:cannot apply unary operator `!` to type `&'static str`
-// error-pattern:in this expansion of assert!
-
-fn main() {
-    assert!("foo");
-}
diff --git a/src/test/compile-fail/macro-backtrace-invalid-internals.rs b/src/test/compile-fail/macro-backtrace-invalid-internals.rs
deleted file mode 100644 (file)
index ebec204..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2015 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.
-
-// Macros in statement vs expression position handle backtraces differently.
-
-macro_rules! fake_method_stmt {
-     () => {
-          1.fake() //~ ERROR no method named `fake` found
-     }
-}
-
-macro_rules! fake_field_stmt {
-     () => {
-          1.fake //~ ERROR no field with that name
-     }
-}
-
-macro_rules! fake_anon_field_stmt {
-     () => {
-          (1).0 //~ ERROR type was not a tuple
-     }
-}
-
-macro_rules! fake_method_expr {
-     () => {
-          1.fake() //~ ERROR no method named `fake` found
-     }
-}
-
-macro_rules! fake_field_expr {
-     () => {
-          1.fake //~ ERROR no field with that name
-     }
-}
-
-macro_rules! fake_anon_field_expr {
-     () => {
-          (1).0 //~ ERROR type was not a tuple
-     }
-}
-
-fn main() {
-    fake_method_stmt!(); //~ NOTE in this expansion of
-    fake_field_stmt!(); //~ NOTE in this expansion of
-    fake_anon_field_stmt!(); //~ NOTE in this expansion of
-
-    let _ = fake_method_expr!(); //~ NOTE in this expansion of
-    let _ = fake_field_expr!(); //~ NOTE in this expansion of
-    let _ = fake_anon_field_expr!(); //~ NOTE in this expansion of
-}
diff --git a/src/test/compile-fail/macro-backtrace-nested.rs b/src/test/compile-fail/macro-backtrace-nested.rs
deleted file mode 100644 (file)
index c2a270e..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2015 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.
-
-// In expression position, but not statement position, when we expand a macro,
-// we replace the span of the expanded expression with that of the call site.
-
-macro_rules! nested_expr {
-    () => (fake) //~ ERROR unresolved name
-                 //~^ ERROR unresolved name
-}
-
-macro_rules! call_nested_expr {
-    () => (nested_expr!()) //~ NOTE in this expansion of nested_expr!
-}
-
-macro_rules! call_nested_expr_sum {
-    () => { 1 + nested_expr!(); } //~ NOTE in this expansion of nested_expr!
-}
-
-fn main() {
-    1 + call_nested_expr!(); //~ NOTE in this expansion of call_nested_expr!
-    call_nested_expr_sum!(); //~ NOTE in this expansion of
-}
diff --git a/src/test/compile-fail/macro-backtrace-println.rs b/src/test/compile-fail/macro-backtrace-println.rs
deleted file mode 100644 (file)
index 9d6da2a..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2015 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.
-
-// The `format_args!` syntax extension issues errors before code expansion
-// has completed, but we still need a backtrace.
-
-// This test includes stripped-down versions of `print!` and `println!`,
-// because we can't otherwise verify the lines of the backtrace.
-
-fn print(_args: std::fmt::Arguments) {}
-
-macro_rules! myprint {
-    ($($arg:tt)*) => (print(format_args!($($arg)*)));   //~ NOTE in this expansion of
-}
-
-macro_rules! myprintln {
-    ($fmt:expr) => (myprint!(concat!($fmt, "\n"))); //~ ERROR invalid reference to argument `0`
-                                                    //~| NOTE in this expansion of concat!
-                                                    //~| NOTE in this expansion of myprint!
-}
-
-fn main() {
-    myprintln!("{}"); //~ NOTE in this expansion of
-}
index e1461c7847e4ca5050cc33ad598533cce26096da..47e97abbbaa47ef441ed1344e170279f0412f236 100644 (file)
@@ -40,8 +40,10 @@ fn main() {
     });
     let cx = &mut cx;
 
+    println!("{}", pprust::expr_to_string(&*quote_expr!(&cx, 23)));
     assert_eq!(pprust::expr_to_string(&*quote_expr!(&cx, 23)), "23");
 
     let expr = quote_expr!(&cx, let x isize = 20;);
+    println!("{}", pprust::expr_to_string(&*expr));
     assert_eq!(pprust::expr_to_string(&*expr), "let x isize = 20;");
 }
diff --git a/src/test/ui/codemap_tests/bad-format-args.rs b/src/test/ui/codemap_tests/bad-format-args.rs
new file mode 100644 (file)
index 0000000..de7bc88
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2016 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.
+
+fn main() {
+    format!();
+    format!("" 1);
+    format!("", 1 1);
+}
diff --git a/src/test/ui/codemap_tests/bad-format-args.stderr b/src/test/ui/codemap_tests/bad-format-args.stderr
new file mode 100644 (file)
index 0000000..fab8e2c
--- /dev/null
@@ -0,0 +1,26 @@
+error: requires at least a format string argument
+  --> $DIR/bad-format-args.rs:12:5
+   |
+12 |     format!();
+   |     ^^^^^^^^^^
+   |
+   = note: this error originates in a macro from the standard library
+
+error: expected token: `,`
+  --> $DIR/bad-format-args.rs:13:5
+   |
+13 |     format!("" 1);
+   |     ^^^^^^^^^^^^^^
+   |
+   = note: this error originates in a macro from the standard library
+
+error: expected token: `,`
+  --> $DIR/bad-format-args.rs:14:5
+   |
+14 |     format!("", 1 1);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in a macro from the standard library
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/codemap_tests/issue-28308.rs b/src/test/ui/codemap_tests/issue-28308.rs
new file mode 100644 (file)
index 0000000..e3a4920
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2016 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.
+
+fn main() {
+    assert!("foo");
+}
diff --git a/src/test/ui/codemap_tests/issue-28308.stderr b/src/test/ui/codemap_tests/issue-28308.stderr
new file mode 100644 (file)
index 0000000..0d51a3f
--- /dev/null
@@ -0,0 +1,10 @@
+error: cannot apply unary operator `!` to type `&'static str`
+  --> $DIR/issue-28308.rs:12:5
+   |
+12 |     assert!("foo");
+   |     ^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in a macro from the standard library
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/codemap_tests/repair_span_std_macros.rs b/src/test/ui/codemap_tests/repair_span_std_macros.rs
new file mode 100644 (file)
index 0000000..3abc91d
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2016 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.
+
+fn main() {
+    let x = vec![];
+}
diff --git a/src/test/ui/codemap_tests/repair_span_std_macros.stderr b/src/test/ui/codemap_tests/repair_span_std_macros.stderr
new file mode 100644 (file)
index 0000000..1c9cbd6
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0282]: unable to infer enough type information about `_`
+  --> $DIR/repair_span_std_macros.rs:12:13
+   |
+12 |     let x = vec![];
+   |             ^^^^^^ cannot infer type for `_`
+   |
+   = note: type annotations or generic parameter binding required
+   = note: this error originates in a macro from the standard library
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/cross-crate-macro-backtrace/auxiliary/extern_macro_crate.rs b/src/test/ui/cross-crate-macro-backtrace/auxiliary/extern_macro_crate.rs
new file mode 100644 (file)
index 0000000..598e9f0
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2015 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.
+
+#![crate_type = "dylib"]
+
+pub fn print(_args: std::fmt::Arguments) {}
+
+#[macro_export]
+macro_rules! myprint {
+    ($($arg:tt)*) => (print(format_args!($($arg)*)));
+}
+
+#[macro_export]
+macro_rules! myprintln {
+    ($fmt:expr) => (myprint!(concat!($fmt, "\n")));
+}
diff --git a/src/test/ui/cross-crate-macro-backtrace/main.rs b/src/test/ui/cross-crate-macro-backtrace/main.rs
new file mode 100644 (file)
index 0000000..f8bb84a
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2012 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.
+
+// aux-build:extern_macro_crate.rs
+#[macro_use(myprintln, myprint)]
+extern crate extern_macro_crate;
+
+fn main() {
+    myprintln!("{}"); //~ ERROR in this macro
+}
diff --git a/src/test/ui/cross-crate-macro-backtrace/main.stderr b/src/test/ui/cross-crate-macro-backtrace/main.stderr
new file mode 100644 (file)
index 0000000..fceaa70
--- /dev/null
@@ -0,0 +1,10 @@
+error: invalid reference to argument `0` (no arguments given)
+  --> $DIR/main.rs:16:5
+   |
+16 |     myprintln!("{}"); //~ ERROR in this macro
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in a macro from the standard library
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/macros/bad_hello.rs b/src/test/ui/macros/bad_hello.rs
new file mode 100644 (file)
index 0000000..a18771d
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2016 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.
+
+fn main() {
+    println!(3 + 4);
+}
diff --git a/src/test/ui/macros/bad_hello.stderr b/src/test/ui/macros/bad_hello.stderr
new file mode 100644 (file)
index 0000000..bffb33f
--- /dev/null
@@ -0,0 +1,8 @@
+error: expected a literal
+  --> $DIR/bad_hello.rs:12:14
+   |
+12 |     println!(3 + 4);
+   |              ^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.rs b/src/test/ui/macros/macro-backtrace-invalid-internals.rs
new file mode 100644 (file)
index 0000000..546e06b
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2015 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.
+
+// Macros in statement vs expression position handle backtraces differently.
+
+macro_rules! fake_method_stmt {
+     () => {
+          1.fake()
+     }
+}
+
+macro_rules! fake_field_stmt {
+     () => {
+          1.fake
+     }
+}
+
+macro_rules! fake_anon_field_stmt {
+     () => {
+          (1).0
+     }
+}
+
+macro_rules! fake_method_expr {
+     () => {
+          1.fake()
+     }
+}
+
+macro_rules! fake_field_expr {
+     () => {
+          1.fake
+     }
+}
+
+macro_rules! fake_anon_field_expr {
+     () => {
+          (1).0
+     }
+}
+
+fn main() {
+    fake_method_stmt!();
+    fake_field_stmt!();
+    fake_anon_field_stmt!();
+
+    let _ = fake_method_expr!();
+    let _ = fake_field_expr!();
+    let _ = fake_anon_field_expr!();
+}
diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr
new file mode 100644 (file)
index 0000000..82000a5
--- /dev/null
@@ -0,0 +1,56 @@
+error: no method named `fake` found for type `{integer}` in the current scope
+  --> $DIR/macro-backtrace-invalid-internals.rs:15:13
+   |
+15 |           1.fake()
+   |             ^^^^
+...
+50 |     fake_method_stmt!();
+   |     -------------------- in this macro invocation
+
+error: attempted access of field `fake` on type `{integer}`, but no field with that name was found
+  --> $DIR/macro-backtrace-invalid-internals.rs:21:11
+   |
+21 |           1.fake
+   |           ^^^^^^
+...
+51 |     fake_field_stmt!();
+   |     ------------------- in this macro invocation
+
+error: attempted tuple index `0` on type `{integer}`, but the type was not a tuple or tuple struct
+  --> $DIR/macro-backtrace-invalid-internals.rs:27:11
+   |
+27 |           (1).0
+   |           ^^^^^
+...
+52 |     fake_anon_field_stmt!();
+   |     ------------------------ in this macro invocation
+
+error: no method named `fake` found for type `{integer}` in the current scope
+  --> $DIR/macro-backtrace-invalid-internals.rs:33:13
+   |
+33 |           1.fake()
+   |             ^^^^
+...
+54 |     let _ = fake_method_expr!();
+   |             ------------------- in this macro invocation
+
+error: attempted access of field `fake` on type `{integer}`, but no field with that name was found
+  --> $DIR/macro-backtrace-invalid-internals.rs:39:11
+   |
+39 |           1.fake
+   |           ^^^^^^
+...
+55 |     let _ = fake_field_expr!();
+   |             ------------------ in this macro invocation
+
+error: attempted tuple index `0` on type `{integer}`, but the type was not a tuple or tuple struct
+  --> $DIR/macro-backtrace-invalid-internals.rs:45:11
+   |
+45 |           (1).0
+   |           ^^^^^
+...
+56 |     let _ = fake_anon_field_expr!();
+   |             ----------------------- in this macro invocation
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/macros/macro-backtrace-nested.rs b/src/test/ui/macros/macro-backtrace-nested.rs
new file mode 100644 (file)
index 0000000..d8bf622
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2015 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.
+
+// In expression position, but not statement position, when we expand a macro,
+// we replace the span of the expanded expression with that of the call site.
+
+macro_rules! nested_expr {
+    () => (fake)
+}
+
+macro_rules! call_nested_expr {
+    () => (nested_expr!())
+}
+
+macro_rules! call_nested_expr_sum {
+    () => { 1 + nested_expr!(); }
+}
+
+fn main() {
+    1 + call_nested_expr!();
+    call_nested_expr_sum!();
+}
diff --git a/src/test/ui/macros/macro-backtrace-nested.stderr b/src/test/ui/macros/macro-backtrace-nested.stderr
new file mode 100644 (file)
index 0000000..e452e8d
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0425]: unresolved name `fake`
+  --> $DIR/macro-backtrace-nested.rs:15:12
+   |
+15 |     () => (fake)
+   |            ^^^^
+...
+27 |     1 + call_nested_expr!();
+   |         ------------------- in this macro invocation
+
+error[E0425]: unresolved name `fake`
+  --> $DIR/macro-backtrace-nested.rs:15:12
+   |
+15 |     () => (fake)
+   |            ^^^^
+...
+28 |     call_nested_expr_sum!();
+   |     ------------------------ in this macro invocation
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/macros/macro-backtrace-println.rs b/src/test/ui/macros/macro-backtrace-println.rs
new file mode 100644 (file)
index 0000000..baf2769
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2015 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.
+
+// The `format_args!` syntax extension issues errors before code expansion
+// has completed, but we still need a backtrace.
+
+// This test includes stripped-down versions of `print!` and `println!`,
+// because we can't otherwise verify the lines of the backtrace.
+
+fn print(_args: std::fmt::Arguments) {}
+
+macro_rules! myprint {
+    ($($arg:tt)*) => (print(format_args!($($arg)*)));
+}
+
+macro_rules! myprintln {
+    ($fmt:expr) => (myprint!(concat!($fmt, "\n")));
+}
+
+fn main() {
+    myprintln!("{}");
+}
diff --git a/src/test/ui/macros/macro-backtrace-println.stderr b/src/test/ui/macros/macro-backtrace-println.stderr
new file mode 100644 (file)
index 0000000..f21253b
--- /dev/null
@@ -0,0 +1,11 @@
+error: invalid reference to argument `0` (no arguments given)
+  --> $DIR/macro-backtrace-println.rs:24:30
+   |
+24 |     ($fmt:expr) => (myprint!(concat!($fmt, "/n")));
+   |                              ^^^^^^^^^^^^^^^^^^^
+...
+28 |     myprintln!("{}");
+   |     ----------------- in this macro invocation
+
+error: aborting due to previous error
+