diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 067e3fff3eb29..c177eb1f00bbd 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 6b1dbf9d2d0ba..ce2315f3a38d4 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 34aa1c75872f3..5069ec7d2846a 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 7c1dc1a468c76..a429681bb2181 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 0c66bbfcf044a..294892662d464 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 c9ef2df8e1326..967a8531b2c0a 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) { } )