summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-09-15 03:21:30 +0000
committerbors <bors@rust-lang.org>2015-09-15 03:21:30 +0000
commitf3e6d315386cebdd6679055d9350c258f2a51689 (patch)
treec368a43c199c178e9e51766611197bebe4143eab
parentb1c96168821d70992157f55ee9f06190bf299ba4 (diff)
parent0be755c24a81f3c7c07dcd50406c9f17bee0d6ac (diff)
downloadrust-f3e6d315386cebdd6679055d9350c258f2a51689.tar.gz
rust-f3e6d315386cebdd6679055d9350c258f2a51689.zip
Auto merge of #28351 - jonas-schievink:macro-bt, r=nrc
The second commit in this PR will stop printing the macro definition site in backtraces, which cuts their length in half and increases readability (the definition site was only correct for local macros).

The third commit will not print an invocation if the last one printed occurred at the same place (span). This will make backtraces caused by a self-recursive macro much shorter.

(A possible alternative would be to capture the backtrace first, then limit it to a few frames at the start and end of the chain and print `...` inbetween. This would also work with multiple macros calling each other, which is not addressed by this PR - although the backtrace will still be halved)

Example:
```rust
macro_rules! m {
 ( 0 $($t:tt)* ) => ( m!($($t)*); );
 () => ( fn main() {0} );
}

m!(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0);
```

On a semi-recent nightly, this yields:
```
test.rs:3:21: 3:22 error: mismatched types:
 expected `()`,
    found `_`
(expected (),
    found integral variable) [E0308]
test.rs:3  () => ( fn main() {0} );
                              ^
test.rs:1:1: 4:2 note: in expansion of m!
test.rs:2:23: 2:34 note: expansion site
test.rs:1:1: 4:2 note: in expansion of m!
test.rs:2:23: 2:34 note: expansion site
test.rs:1:1: 4:2 note: in expansion of m!
test.rs:2:23: 2:34 note: expansion site
test.rs:1:1: 4:2 note: in expansion of m!
test.rs:2:23: 2:34 note: expansion site
test.rs:1:1: 4:2 note: in expansion of m!
test.rs:2:23: 2:34 note: expansion site
test.rs:1:1: 4:2 note: in expansion of m!
test.rs:2:23: 2:34 note: expansion site
test.rs:1:1: 4:2 note: in expansion of m!
test.rs:2:23: 2:34 note: expansion site
test.rs:1:1: 4:2 note: in expansion of m!
test.rs:2:23: 2:34 note: expansion site
test.rs:1:1: 4:2 note: in expansion of m!
test.rs:2:23: 2:34 note: expansion site
test.rs:1:1: 4:2 note: in expansion of m!
test.rs:2:23: 2:34 note: expansion site
test.rs:1:1: 4:2 note: in expansion of m!
test.rs:2:23: 2:34 note: expansion site
test.rs:1:1: 4:2 note: in expansion of m!
test.rs:2:23: 2:34 note: expansion site
test.rs:1:1: 4:2 note: in expansion of m!
test.rs:2:23: 2:34 note: expansion site
test.rs:1:1: 4:2 note: in expansion of m!
test.rs:2:23: 2:34 note: expansion site
test.rs:1:1: 4:2 note: in expansion of m!
test.rs:2:23: 2:34 note: expansion site
test.rs:1:1: 4:2 note: in expansion of m!
test.rs:6:1: 6:35 note: expansion site
test.rs:3:21: 3:22 help: run `rustc --explain E0308` to see a detailed explanation
error: aborting due to previous error
```

After this patch:
```
test.rs:3:21: 3:22 error: mismatched types:
 expected `()`,
    found `_`
(expected (),
    found integral variable) [E0308]
test.rs:3  () => ( fn main() {0} );
                              ^
test.rs:2:23: 2:34 note: in this expansion of m!
test.rs:6:1: 6:35 note: in this expansion of m!
test.rs:3:21: 3:22 help: run `rustc --explain E0308` to see a detailed explanation
error: aborting due to previous error
```
-rw-r--r--src/libsyntax/diagnostic.rs59
-rw-r--r--src/test/compile-fail/for-expn-2.rs2
-rw-r--r--src/test/compile-fail/macro-backtrace-invalid-internals.rs18
-rw-r--r--src/test/compile-fail/macro-backtrace-nested.rs4
-rw-r--r--src/test/compile-fail/macro-backtrace-println.rs9
-rw-r--r--src/test/compile-fail/method-macro-backtrace.rs2
6 files changed, 56 insertions, 38 deletions
diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs
index 067e3fff3eb..c177eb1f00b 100644
--- a/src/libsyntax/diagnostic.rs
+++ b/src/libsyntax/diagnostic.rs
@@ -727,30 +727,45 @@ impl EmitterWriter {
                              cm: &codemap::CodeMap,
                              sp: Span)
                              -> io::Result<()> {
-        let cs = try!(cm.with_expn_info(sp.expn_id, |expn_info| -> io::Result<_> {
-            match expn_info {
-                Some(ei) => {
-                    let ss = ei.callee.span.map_or(String::new(),
-                                                   |span| cm.span_to_string(span));
-                    let (pre, post) = match ei.callee.format {
-                        codemap::MacroAttribute(..) => ("#[", "]"),
-                        codemap::MacroBang(..) => ("", "!"),
-                        codemap::CompilerExpansion(..) => ("", ""),
-                    };
-                    try!(self.print_diagnostic(&ss, Note,
-                                               &format!("in expansion of {}{}{}",
-                                                        pre,
-                                                        ei.callee.name(),
-                                                        post),
-                                               None));
-                    let ss = cm.span_to_string(ei.call_site);
-                    try!(self.print_diagnostic(&ss, Note, "expansion site", None));
-                    Ok(Some(ei.call_site))
+        let mut last_span = codemap::DUMMY_SP;
+        let mut sp_opt = Some(sp);
+
+        while let Some(sp) = sp_opt {
+            sp_opt = try!(cm.with_expn_info(sp.expn_id, |expn_info| -> io::Result<_> {
+                match expn_info {
+                    Some(ei) => {
+                        let (pre, post) = match ei.callee.format {
+                            codemap::MacroAttribute(..) => ("#[", "]"),
+                            codemap::MacroBang(..) => ("", "!"),
+                            codemap::CompilerExpansion(..) => ("", ""),
+                        };
+                        // Don't print recursive invocations
+                        if ei.call_site != last_span {
+                            last_span = ei.call_site;
+
+                            let mut diag_string = format!("in this expansion of {}{}{}",
+                                                          pre,
+                                                          ei.callee.name(),
+                                                          post);
+
+                            if let Some(def_site_span) = ei.callee.span {
+                                diag_string.push_str(&format!(" (defined in {})",
+                                                              cm.span_to_filename(def_site_span)));
+                            }
+
+                            try!(self.print_diagnostic(&cm.span_to_string(ei.call_site),
+                                                       Note,
+                                                       &diag_string,
+                                                       None));
+                        }
+                        Ok(Some(ei.call_site))
+                    }
+                    None => Ok(None)
                 }
-                None => Ok(None)
+            }));
         }
-        }));
-        cs.map_or(Ok(()), |call_site| self.print_macro_backtrace(cm, call_site))
+
+        Ok(())
     }
 }
 
diff --git a/src/test/compile-fail/for-expn-2.rs b/src/test/compile-fail/for-expn-2.rs
index 6b1dbf9d2d0..ce2315f3a38 100644
--- a/src/test/compile-fail/for-expn-2.rs
+++ b/src/test/compile-fail/for-expn-2.rs
@@ -10,7 +10,7 @@
 
 // Test that we get an expansion stack for `for` loops.
 
-// error-pattern:in expansion of for loop expansion
+// error-pattern:in this expansion of for loop expansion
 
 fn main() {
     for t in &foo {
diff --git a/src/test/compile-fail/macro-backtrace-invalid-internals.rs b/src/test/compile-fail/macro-backtrace-invalid-internals.rs
index 34aa1c75872..5069ec7d284 100644
--- a/src/test/compile-fail/macro-backtrace-invalid-internals.rs
+++ b/src/test/compile-fail/macro-backtrace-invalid-internals.rs
@@ -10,25 +10,25 @@
 
 // Macros in statement vs expression position handle backtraces differently.
 
-macro_rules! fake_method_stmt { //~ NOTE in expansion of
+macro_rules! fake_method_stmt {
      () => {
           1.fake() //~ ERROR no method named `fake` found
      }
 }
 
-macro_rules! fake_field_stmt { //~ NOTE in expansion of
+macro_rules! fake_field_stmt {
      () => {
           1.fake //~ ERROR no field with that name
      }
 }
 
-macro_rules! fake_anon_field_stmt { //~ NOTE in expansion of
+macro_rules! fake_anon_field_stmt {
      () => {
           (1).0 //~ ERROR type was not a tuple
      }
 }
 
-macro_rules! fake_method_expr { //~ NOTE in expansion of
+macro_rules! fake_method_expr {
      () => {
           1.fake() //~ ERROR no method named `fake` found
      }
@@ -47,11 +47,13 @@ macro_rules! fake_anon_field_expr {
 }
 
 fn main() {
-    fake_method_stmt!(); //~ NOTE expansion site
-    fake_field_stmt!(); //~ NOTE expansion site
-    fake_anon_field_stmt!(); //~ NOTE expansion site
+    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 expansion site
+    let _ = fake_method_expr!(); //~ NOTE in this expansion of
     let _ = fake_field_expr!(); //~ ERROR no field with that name
+                                //~^ NOTE in this expansion of
     let _ = fake_anon_field_expr!(); //~ ERROR type was not a tuple
+                                     //~^ 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
index 7c1dc1a468c..a429681bb21 100644
--- a/src/test/compile-fail/macro-backtrace-nested.rs
+++ b/src/test/compile-fail/macro-backtrace-nested.rs
@@ -19,11 +19,11 @@ macro_rules! call_nested_expr {
     () => (nested_expr!())
 }
 
-macro_rules! call_nested_expr_sum { //~ NOTE in expansion of
+macro_rules! call_nested_expr_sum {
     () => { 1 + nested_expr!(); } //~ ERROR unresolved name
 }
 
 fn main() {
     1 + call_nested_expr!(); //~ ERROR unresolved name
-    call_nested_expr_sum!(); //~ NOTE expansion site
+    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
index 0c66bbfcf04..294892662d4 100644
--- a/src/test/compile-fail/macro-backtrace-println.rs
+++ b/src/test/compile-fail/macro-backtrace-println.rs
@@ -16,14 +16,15 @@
 
 fn print(_args: std::fmt::Arguments) {}
 
-macro_rules! myprint { //~ NOTE in expansion of
-    ($($arg:tt)*) => (print(format_args!($($arg)*)));
+macro_rules! myprint {
+    ($($arg:tt)*) => (print(format_args!($($arg)*)));   //~ NOTE in this expansion of
 }
 
-macro_rules! myprintln { //~ NOTE in expansion of
+macro_rules! myprintln {
     ($fmt:expr) => (myprint!(concat!($fmt, "\n"))); //~ ERROR invalid reference to argument `0`
+                                                    //~^ NOTE in this expansion of
 }
 
 fn main() {
-    myprintln!("{}"); //~ NOTE expansion site
+    myprintln!("{}"); //~ NOTE in this expansion of
 }
diff --git a/src/test/compile-fail/method-macro-backtrace.rs b/src/test/compile-fail/method-macro-backtrace.rs
index c9ef2df8e13..967a8531b2c 100644
--- a/src/test/compile-fail/method-macro-backtrace.rs
+++ b/src/test/compile-fail/method-macro-backtrace.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// forbid-output: in expansion of
+// forbid-output: in this expansion of
 
 macro_rules! make_method {
     ($name:ident) => ( fn $name(&self) { } )