Skip to content

Commit f3e6d31

Browse files
committed
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 ```
2 parents b1c9616 + 0be755c commit f3e6d31

6 files changed

+56
-38
lines changed

src/libsyntax/diagnostic.rs

+37-22
Original file line numberDiff line numberDiff line change
@@ -727,30 +727,45 @@ impl EmitterWriter {
727727
cm: &codemap::CodeMap,
728728
sp: Span)
729729
-> io::Result<()> {
730-
let cs = try!(cm.with_expn_info(sp.expn_id, |expn_info| -> io::Result<_> {
731-
match expn_info {
732-
Some(ei) => {
733-
let ss = ei.callee.span.map_or(String::new(),
734-
|span| cm.span_to_string(span));
735-
let (pre, post) = match ei.callee.format {
736-
codemap::MacroAttribute(..) => ("#[", "]"),
737-
codemap::MacroBang(..) => ("", "!"),
738-
codemap::CompilerExpansion(..) => ("", ""),
739-
};
740-
try!(self.print_diagnostic(&ss, Note,
741-
&format!("in expansion of {}{}{}",
742-
pre,
743-
ei.callee.name(),
744-
post),
745-
None));
746-
let ss = cm.span_to_string(ei.call_site);
747-
try!(self.print_diagnostic(&ss, Note, "expansion site", None));
748-
Ok(Some(ei.call_site))
730+
let mut last_span = codemap::DUMMY_SP;
731+
let mut sp_opt = Some(sp);
732+
733+
while let Some(sp) = sp_opt {
734+
sp_opt = try!(cm.with_expn_info(sp.expn_id, |expn_info| -> io::Result<_> {
735+
match expn_info {
736+
Some(ei) => {
737+
let (pre, post) = match ei.callee.format {
738+
codemap::MacroAttribute(..) => ("#[", "]"),
739+
codemap::MacroBang(..) => ("", "!"),
740+
codemap::CompilerExpansion(..) => ("", ""),
741+
};
742+
// Don't print recursive invocations
743+
if ei.call_site != last_span {
744+
last_span = ei.call_site;
745+
746+
let mut diag_string = format!("in this expansion of {}{}{}",
747+
pre,
748+
ei.callee.name(),
749+
post);
750+
751+
if let Some(def_site_span) = ei.callee.span {
752+
diag_string.push_str(&format!(" (defined in {})",
753+
cm.span_to_filename(def_site_span)));
754+
}
755+
756+
try!(self.print_diagnostic(&cm.span_to_string(ei.call_site),
757+
Note,
758+
&diag_string,
759+
None));
760+
}
761+
Ok(Some(ei.call_site))
762+
}
763+
None => Ok(None)
749764
}
750-
None => Ok(None)
765+
}));
751766
}
752-
}));
753-
cs.map_or(Ok(()), |call_site| self.print_macro_backtrace(cm, call_site))
767+
768+
Ok(())
754769
}
755770
}
756771

src/test/compile-fail/for-expn-2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
// Test that we get an expansion stack for `for` loops.
1212

13-
// error-pattern:in expansion of for loop expansion
13+
// error-pattern:in this expansion of for loop expansion
1414

1515
fn main() {
1616
for t in &foo {

src/test/compile-fail/macro-backtrace-invalid-internals.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,25 @@
1010

1111
// Macros in statement vs expression position handle backtraces differently.
1212

13-
macro_rules! fake_method_stmt { //~ NOTE in expansion of
13+
macro_rules! fake_method_stmt {
1414
() => {
1515
1.fake() //~ ERROR no method named `fake` found
1616
}
1717
}
1818

19-
macro_rules! fake_field_stmt { //~ NOTE in expansion of
19+
macro_rules! fake_field_stmt {
2020
() => {
2121
1.fake //~ ERROR no field with that name
2222
}
2323
}
2424

25-
macro_rules! fake_anon_field_stmt { //~ NOTE in expansion of
25+
macro_rules! fake_anon_field_stmt {
2626
() => {
2727
(1).0 //~ ERROR type was not a tuple
2828
}
2929
}
3030

31-
macro_rules! fake_method_expr { //~ NOTE in expansion of
31+
macro_rules! fake_method_expr {
3232
() => {
3333
1.fake() //~ ERROR no method named `fake` found
3434
}
@@ -47,11 +47,13 @@ macro_rules! fake_anon_field_expr {
4747
}
4848

4949
fn main() {
50-
fake_method_stmt!(); //~ NOTE expansion site
51-
fake_field_stmt!(); //~ NOTE expansion site
52-
fake_anon_field_stmt!(); //~ NOTE expansion site
50+
fake_method_stmt!(); //~ NOTE in this expansion of
51+
fake_field_stmt!(); //~ NOTE in this expansion of
52+
fake_anon_field_stmt!(); //~ NOTE in this expansion of
5353

54-
let _ = fake_method_expr!(); //~ NOTE expansion site
54+
let _ = fake_method_expr!(); //~ NOTE in this expansion of
5555
let _ = fake_field_expr!(); //~ ERROR no field with that name
56+
//~^ NOTE in this expansion of
5657
let _ = fake_anon_field_expr!(); //~ ERROR type was not a tuple
58+
//~^ NOTE in this expansion of
5759
}

src/test/compile-fail/macro-backtrace-nested.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ macro_rules! call_nested_expr {
1919
() => (nested_expr!())
2020
}
2121

22-
macro_rules! call_nested_expr_sum { //~ NOTE in expansion of
22+
macro_rules! call_nested_expr_sum {
2323
() => { 1 + nested_expr!(); } //~ ERROR unresolved name
2424
}
2525

2626
fn main() {
2727
1 + call_nested_expr!(); //~ ERROR unresolved name
28-
call_nested_expr_sum!(); //~ NOTE expansion site
28+
call_nested_expr_sum!(); //~ NOTE in this expansion of
2929
}

src/test/compile-fail/macro-backtrace-println.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@
1616

1717
fn print(_args: std::fmt::Arguments) {}
1818

19-
macro_rules! myprint { //~ NOTE in expansion of
20-
($($arg:tt)*) => (print(format_args!($($arg)*)));
19+
macro_rules! myprint {
20+
($($arg:tt)*) => (print(format_args!($($arg)*))); //~ NOTE in this expansion of
2121
}
2222

23-
macro_rules! myprintln { //~ NOTE in expansion of
23+
macro_rules! myprintln {
2424
($fmt:expr) => (myprint!(concat!($fmt, "\n"))); //~ ERROR invalid reference to argument `0`
25+
//~^ NOTE in this expansion of
2526
}
2627

2728
fn main() {
28-
myprintln!("{}"); //~ NOTE expansion site
29+
myprintln!("{}"); //~ NOTE in this expansion of
2930
}

src/test/compile-fail/method-macro-backtrace.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// forbid-output: in expansion of
11+
// forbid-output: in this expansion of
1212

1313
macro_rules! make_method {
1414
($name:ident) => ( fn $name(&self) { } )

0 commit comments

Comments
 (0)