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;
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);
}
}
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,
}
}
- 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)?;
}
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,
_ => ()
}
}
- 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) {
&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
+++ /dev/null
-// 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);
-}
+++ /dev/null
-// 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");
-}
+++ /dev/null
-// 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
-}
+++ /dev/null
-// 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
-}
+++ /dev/null
-// 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
-}
});
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;");
}
--- /dev/null
+// 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);
+}
--- /dev/null
+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
+
--- /dev/null
+// 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");
+}
--- /dev/null
+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
+
--- /dev/null
+// 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![];
+}
--- /dev/null
+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
+
--- /dev/null
+// 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")));
+}
--- /dev/null
+// 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
+}
--- /dev/null
+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
+
--- /dev/null
+// 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);
+}
--- /dev/null
+error: expected a literal
+ --> $DIR/bad_hello.rs:12:14
+ |
+12 | println!(3 + 4);
+ | ^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// 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!();
+}
--- /dev/null
+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
+
--- /dev/null
+// 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!();
+}
--- /dev/null
+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
+
--- /dev/null
+// 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!("{}");
+}
--- /dev/null
+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
+