Skip to content

Commit 6186538

Browse files
author
Jonathan Turner
committed
Replace local backtrace with def-use, repair std macro spans
1 parent d0a272b commit 6186538

20 files changed

+362
-75
lines changed

src/librustc_errors/emitter.rs

+103-41
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use self::Destination::*;
1212

1313
use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, CharPos};
1414

15-
use {Level, CodeSuggestion, DiagnosticBuilder, CodeMapper};
15+
use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapper};
1616
use RenderSpan::*;
1717
use snippet::{StyledString, Style, Annotation, Line};
1818
use styled_buffer::StyledBuffer;
@@ -30,7 +30,10 @@ pub trait Emitter {
3030

3131
impl Emitter for EmitterWriter {
3232
fn emit(&mut self, db: &DiagnosticBuilder) {
33-
self.emit_messages_default(db);
33+
let mut primary_span = db.span.clone();
34+
let mut children = db.children.clone();
35+
self.fix_multispans_in_std_macros(&mut primary_span, &mut children);
36+
self.emit_messages_default(&db.level, &db.message, &db.code, &primary_span, &children);
3437
}
3538
}
3639

@@ -381,19 +384,100 @@ impl EmitterWriter {
381384
max
382385
}
383386

384-
fn get_max_line_num(&mut self, db: &DiagnosticBuilder) -> usize {
387+
fn get_max_line_num(&mut self, span: &MultiSpan, children: &Vec<SubDiagnostic>) -> usize {
385388
let mut max = 0;
386389

387-
let primary = self.get_multispan_max_line_num(&db.span);
390+
let primary = self.get_multispan_max_line_num(span);
388391
max = if primary > max { primary } else { max };
389392

390-
for sub in &db.children {
393+
for sub in children {
391394
let sub_result = self.get_multispan_max_line_num(&sub.span);
392395
max = if sub_result > max { primary } else { max };
393396
}
394397
max
395398
}
396399

400+
// This "fixes" MultiSpans that contain Spans that are pointing to locations inside of
401+
// <*macros>. Since these locations are often difficult to read, we move these Spans from
402+
// <*macros> to their corresponding use site.
403+
fn fix_multispan_in_std_macros(&mut self, span: &mut MultiSpan) -> bool {
404+
let mut spans_updated = false;
405+
406+
if let Some(ref cm) = self.cm {
407+
let mut before_after: Vec<(Span, Span)> = vec![];
408+
let mut new_labels: Vec<(Span, String)> = vec![];
409+
410+
// First, find all the spans in <*macros> and point instead at their use site
411+
for sp in span.primary_spans() {
412+
if (*sp == COMMAND_LINE_SP) || (*sp == DUMMY_SP) {
413+
continue;
414+
}
415+
if cm.span_to_filename(sp.clone()).contains("macros>") {
416+
let v = cm.macro_backtrace(sp.clone());
417+
if let Some(use_site) = v.last() {
418+
before_after.push((sp.clone(), use_site.call_site.clone()));
419+
}
420+
}
421+
for trace in cm.macro_backtrace(sp.clone()).iter().rev() {
422+
// Only show macro locations that are local
423+
// and display them like a span_note
424+
if let Some(def_site) = trace.def_site_span {
425+
if (def_site == COMMAND_LINE_SP) || (def_site == DUMMY_SP) {
426+
continue;
427+
}
428+
// Check to make sure we're not in any <*macros>
429+
if !cm.span_to_filename(def_site).contains("macros>") {
430+
new_labels.push((trace.call_site,
431+
"in this macro invocation".to_string()));
432+
break;
433+
}
434+
}
435+
}
436+
}
437+
for (label_span, label_text) in new_labels {
438+
span.push_span_label(label_span, label_text);
439+
}
440+
for sp_label in span.span_labels() {
441+
if (sp_label.span == COMMAND_LINE_SP) || (sp_label.span == DUMMY_SP) {
442+
continue;
443+
}
444+
if cm.span_to_filename(sp_label.span.clone()).contains("macros>") {
445+
let v = cm.macro_backtrace(sp_label.span.clone());
446+
if let Some(use_site) = v.last() {
447+
before_after.push((sp_label.span.clone(), use_site.call_site.clone()));
448+
}
449+
}
450+
}
451+
// After we have them, make sure we replace these 'bad' def sites with their use sites
452+
for (before, after) in before_after {
453+
span.replace(before, after);
454+
spans_updated = true;
455+
}
456+
}
457+
458+
spans_updated
459+
}
460+
461+
// This does a small "fix" for multispans by looking to see if it can find any that
462+
// point directly at <*macros>. Since these are often difficult to read, this
463+
// will change the span to point at the use site.
464+
fn fix_multispans_in_std_macros(&mut self,
465+
span: &mut MultiSpan,
466+
children: &mut Vec<SubDiagnostic>) {
467+
let mut spans_updated = self.fix_multispan_in_std_macros(span);
468+
for child in &mut children.iter_mut() {
469+
spans_updated |= self.fix_multispan_in_std_macros(&mut child.span);
470+
}
471+
if spans_updated {
472+
children.push(SubDiagnostic {
473+
level: Level::Note,
474+
message: "this error originates in a macro from the standard library".to_string(),
475+
span: MultiSpan::new(),
476+
render_span: None
477+
});
478+
}
479+
}
480+
397481
fn emit_message_default(&mut self,
398482
msp: &MultiSpan,
399483
msg: &str,
@@ -528,10 +612,6 @@ impl EmitterWriter {
528612
}
529613
}
530614

531-
if let Some(ref primary_span) = msp.primary_span().as_ref() {
532-
self.render_macro_backtrace_old_school(primary_span, &mut buffer)?;
533-
}
534-
535615
// final step: take our styled buffer, render it, then output it
536616
emit_to_destination(&buffer.render(), level, &mut self.dst)?;
537617

@@ -578,26 +658,31 @@ impl EmitterWriter {
578658
}
579659
Ok(())
580660
}
581-
fn emit_messages_default(&mut self, db: &DiagnosticBuilder) {
582-
let max_line_num = self.get_max_line_num(db);
661+
fn emit_messages_default(&mut self,
662+
level: &Level,
663+
message: &String,
664+
code: &Option<String>,
665+
span: &MultiSpan,
666+
children: &Vec<SubDiagnostic>) {
667+
let max_line_num = self.get_max_line_num(span, children);
583668
let max_line_num_len = max_line_num.to_string().len();
584669

585-
match self.emit_message_default(&db.span,
586-
&db.message,
587-
&db.code,
588-
&db.level,
670+
match self.emit_message_default(span,
671+
message,
672+
code,
673+
level,
589674
max_line_num_len,
590675
false) {
591676
Ok(()) => {
592-
if !db.children.is_empty() {
677+
if !children.is_empty() {
593678
let mut buffer = StyledBuffer::new();
594679
draw_col_separator_no_space(&mut buffer, 0, max_line_num_len + 1);
595-
match emit_to_destination(&buffer.render(), &db.level, &mut self.dst) {
680+
match emit_to_destination(&buffer.render(), level, &mut self.dst) {
596681
Ok(()) => (),
597682
Err(e) => panic!("failed to emit error: {}", e)
598683
}
599684
}
600-
for child in &db.children {
685+
for child in children {
601686
match child.render_span {
602687
Some(FullSpan(ref msp)) => {
603688
match self.emit_message_default(msp,
@@ -640,29 +725,6 @@ impl EmitterWriter {
640725
_ => ()
641726
}
642727
}
643-
fn render_macro_backtrace_old_school(&mut self,
644-
sp: &Span,
645-
buffer: &mut StyledBuffer) -> io::Result<()> {
646-
if let Some(ref cm) = self.cm {
647-
for trace in cm.macro_backtrace(sp.clone()) {
648-
let line_offset = buffer.num_lines();
649-
650-
let mut diag_string =
651-
format!("in this expansion of {}", trace.macro_decl_name);
652-
if let Some(def_site_span) = trace.def_site_span {
653-
diag_string.push_str(
654-
&format!(" (defined in {})",
655-
cm.span_to_filename(def_site_span)));
656-
}
657-
let snippet = cm.span_to_string(trace.call_site);
658-
buffer.append(line_offset, &format!("{} ", snippet), Style::NoStyle);
659-
buffer.append(line_offset, "note", Style::Level(Level::Note));
660-
buffer.append(line_offset, ": ", Style::NoStyle);
661-
buffer.append(line_offset, &diag_string, Style::OldSchoolNoteText);
662-
}
663-
}
664-
Ok(())
665-
}
666728
}
667729

668730
fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {

src/libsyntax_pos/lib.rs

+19
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,25 @@ impl MultiSpan {
221221
&self.primary_spans
222222
}
223223

224+
/// Replaces all occurances of one Span with another. Used to move Spans in areas that don't
225+
/// display well (like std macros). Returns true if replacements occurred.
226+
pub fn replace(&mut self, before: Span, after: Span) -> bool {
227+
let mut replacements_occurred = false;
228+
for primary_span in &mut self.primary_spans {
229+
if *primary_span == before {
230+
*primary_span = after;
231+
replacements_occurred = true;
232+
}
233+
}
234+
for span_label in &mut self.span_labels {
235+
if span_label.0 == before {
236+
span_label.0 = after;
237+
replacements_occurred = true;
238+
}
239+
}
240+
replacements_occurred
241+
}
242+
224243
/// Returns the strings to highlight. We always ensure that there
225244
/// is an entry for each of the primary spans -- for each primary
226245
/// span P, if there is at least one label with span P, we return

src/test/run-fail-fulldeps/qquote.rs

+2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@ fn main() {
4040
});
4141
let cx = &mut cx;
4242

43+
println!("{}", pprust::expr_to_string(&*quote_expr!(&cx, 23)));
4344
assert_eq!(pprust::expr_to_string(&*quote_expr!(&cx, 23)), "23");
4445

4546
let expr = quote_expr!(&cx, let x isize = 20;);
47+
println!("{}", pprust::expr_to_string(&*expr));
4648
assert_eq!(pprust::expr_to_string(&*expr), "let x isize = 20;");
4749
}

src/test/compile-fail/bad-format-args.rs renamed to src/test/ui/codemap_tests/bad-format-args.rs

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

11-
// error-pattern: requires at least a format string argument
12-
// error-pattern: in this expansion
13-
14-
// error-pattern: expected token: `,`
15-
// error-pattern: in this expansion
16-
// error-pattern: in this expansion
17-
1811
fn main() {
1912
format!();
2013
format!("" 1);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error: requires at least a format string argument
2+
--> $DIR/bad-format-args.rs:12:5
3+
|
4+
12 | format!();
5+
| ^^^^^^^^^^
6+
|
7+
= note: this error originates in a macro from the standard library
8+
9+
error: expected token: `,`
10+
--> $DIR/bad-format-args.rs:13:5
11+
|
12+
13 | format!("" 1);
13+
| ^^^^^^^^^^^^^^
14+
|
15+
= note: this error originates in a macro from the standard library
16+
17+
error: expected token: `,`
18+
--> $DIR/bad-format-args.rs:14:5
19+
|
20+
14 | format!("", 1 1);
21+
| ^^^^^^^^^^^^^^^^^
22+
|
23+
= note: this error originates in a macro from the standard library
24+
25+
error: aborting due to 3 previous errors
26+

src/test/compile-fail/issue-28308.rs renamed to src/test/ui/codemap_tests/issue-28308.rs

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

11-
// this error is dispayed in `<std macros>`
12-
// error-pattern:cannot apply unary operator `!` to type `&'static str`
13-
// error-pattern:in this expansion of assert!
14-
1511
fn main() {
1612
assert!("foo");
1713
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: cannot apply unary operator `!` to type `&'static str`
2+
--> $DIR/issue-28308.rs:12:5
3+
|
4+
12 | assert!("foo");
5+
| ^^^^^^^^^^^^^^^
6+
|
7+
= note: this error originates in a macro from the standard library
8+
9+
error: aborting due to previous error
10+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let x = vec![];
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0282]: unable to infer enough type information about `_`
2+
--> $DIR/repair_span_std_macros.rs:12:13
3+
|
4+
12 | let x = vec![];
5+
| ^^^^^^ cannot infer type for `_`
6+
|
7+
= note: type annotations or generic parameter binding required
8+
= note: this error originates in a macro from the standard library
9+
10+
error: aborting due to previous error
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![crate_type = "dylib"]
12+
13+
pub fn print(_args: std::fmt::Arguments) {}
14+
15+
#[macro_export]
16+
macro_rules! myprint {
17+
($($arg:tt)*) => (print(format_args!($($arg)*)));
18+
}
19+
20+
#[macro_export]
21+
macro_rules! myprintln {
22+
($fmt:expr) => (myprint!(concat!($fmt, "\n")));
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// aux-build:extern_macro_crate.rs
12+
#[macro_use(myprintln, myprint)]
13+
extern crate extern_macro_crate;
14+
15+
fn main() {
16+
myprintln!("{}"); //~ ERROR in this macro
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: invalid reference to argument `0` (no arguments given)
2+
--> $DIR/main.rs:16:5
3+
|
4+
16 | myprintln!("{}"); //~ ERROR in this macro
5+
| ^^^^^^^^^^^^^^^^^
6+
|
7+
= note: this error originates in a macro from the standard library
8+
9+
error: aborting due to previous error
10+

src/test/ui/macros/bad_hello.rs

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
println!(3 + 4);
13+
}

0 commit comments

Comments
 (0)