Match errors using the callsite of macro expansions

This commit is contained in:
Federico Poli 2018-07-19 14:15:43 +02:00
parent 3900bf8ae3
commit 8ec9d7242c
43 changed files with 137 additions and 49 deletions

View file

@ -9,7 +9,7 @@
// except according to those terms.
fn main() {
format!();
format!("" 1);
format!("", 1 1);
format!(); //~ ERROR requires at least a format string argument
format!("" 1); //~ ERROR expected token: `,`
format!("", 1 1); //~ ERROR expected token: `,`
}

View file

@ -1,7 +1,7 @@
error: requires at least a format string argument
--> $DIR/bad-format-args.rs:12:5
|
LL | format!();
LL | format!(); //~ ERROR requires at least a format string argument
| ^^^^^^^^^^
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
@ -9,7 +9,7 @@ LL | format!();
error: expected token: `,`
--> $DIR/bad-format-args.rs:13:5
|
LL | format!("" 1);
LL | format!("" 1); //~ ERROR expected token: `,`
| ^^^^^^^^^^^^^^
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
@ -17,7 +17,7 @@ LL | format!("" 1);
error: expected token: `,`
--> $DIR/bad-format-args.rs:14:5
|
LL | format!("", 1 1);
LL | format!("", 1 1); //~ ERROR expected token: `,`
| ^^^^^^^^^^^^^^^^^
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

View file

@ -8,12 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern: in format string
// aux-build:extern_macro_crate.rs
#[macro_use(myprintln, myprint)]
extern crate extern_macro_crate;
fn main() {
myprintln!("{}");
//~^ ERROR in format string
}

View file

@ -1,5 +1,5 @@
error: 1 positional argument in format string, but no arguments were given
--> $DIR/main.rs:18:5
--> $DIR/main.rs:16:5
|
LL | myprintln!("{}");
| ^^^^^^^^^^^^^^^^^

View file

@ -13,4 +13,5 @@ mod underscore;
fn main() {
underscore!();
//~^ ERROR expected expression, found reserved identifier `_`
}

View file

@ -17,7 +17,7 @@
extern crate edition_kw_macro_2018;
mod one_async {
produces_async! {} // ERROR expected identifier, found reserved keyword
produces_async! {} //~ ERROR expected identifier, found reserved keyword
}
mod two_async {
produces_async_raw! {} // OK

View file

@ -1,7 +1,7 @@
error: expected identifier, found reserved keyword `async`
--> $DIR/edition-keywords-2015-2018-expansion.rs:20:5
|
LL | produces_async! {} // ERROR expected identifier, found reserved keyword
LL | produces_async! {} //~ ERROR expected identifier, found reserved keyword
| ^^^^^^^^^^^^^^^^^^ expected identifier, found reserved keyword
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

View file

@ -17,7 +17,7 @@
extern crate edition_kw_macro_2018;
mod one_async {
produces_async! {} // ERROR expected identifier, found reserved keyword `async`
produces_async! {} //~ ERROR expected identifier, found reserved keyword `async`
}
mod two_async {
produces_async_raw! {} // OK

View file

@ -1,7 +1,7 @@
error: expected identifier, found reserved keyword `async`
--> $DIR/edition-keywords-2018-2018-expansion.rs:20:5
|
LL | produces_async! {} // ERROR expected identifier, found reserved keyword `async`
LL | produces_async! {} //~ ERROR expected identifier, found reserved keyword `async`
| ^^^^^^^^^^^^^^^^^^ expected identifier, found reserved keyword
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

View file

@ -12,12 +12,11 @@
// aux-build:intercrate.rs
// error-pattern:type `fn() -> u32 {intercrate::foo::bar::f}` is private
#![feature(decl_macro)]
extern crate intercrate;
fn main() {
assert_eq!(intercrate::foo::m!(), 1);
//~^ ERROR type `fn() -> u32 {intercrate::foo::bar::f}` is private
}

View file

@ -1,5 +1,5 @@
error: type `fn() -> u32 {intercrate::foo::bar::f}` is private
--> $DIR/intercrate.rs:22:16
--> $DIR/intercrate.rs:20:16
|
LL | assert_eq!(intercrate::foo::m!(), 1);
| ^^^^^^^^^^^^^^^^^^^^^

View file

@ -11,11 +11,10 @@
// `local_inner_macros` has no effect if `feature(use_extern_macros)` is not enabled
// aux-build:local_inner_macros.rs
// error-pattern: cannot find macro `helper2!` in this scope
#[macro_use(public_macro)]
extern crate local_inner_macros;
public_macro!();
public_macro!(); //~ ERROR cannot find macro `helper2!` in this scope
fn main() {}

View file

@ -1,7 +1,7 @@
error: cannot find macro `helper2!` in this scope
--> $DIR/local_inner_macros_disabled.rs:19:1
--> $DIR/local_inner_macros_disabled.rs:18:1
|
LL | public_macro!();
LL | public_macro!(); //~ ERROR cannot find macro `helper2!` in this scope
| ^^^^^^^^^^^^^^^^
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

View file

@ -11,8 +11,7 @@
// Used to cause ICE
// error-pattern: mismatched types
static VEC: [u32; 256] = vec![];
//~^ ERROR mismatched types
fn main() {}

View file

@ -1,5 +1,5 @@
error[E0308]: mismatched types
--> $DIR/issue-13446.rs:16:26
--> $DIR/issue-13446.rs:14:26
|
LL | static VEC: [u32; 256] = vec![];
| ^^^^^^ expected array of 256 elements, found struct `std::vec::Vec`

View file

@ -8,9 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern:type annotations needed
fn main() {
panic!(
std::default::Default::default()
);
panic!(std::default::Default::default());
//~^ ERROR type annotations needed
}

View file

@ -1,10 +1,8 @@
error[E0282]: type annotations needed
--> $DIR/issue-16966.rs:13:5
--> $DIR/issue-16966.rs:12:5
|
LL | / panic!(
LL | | std::default::Default::default()
LL | | );
| |______^ cannot infer type for `M`
LL | panic!(std::default::Default::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for `M`
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

View file

@ -8,9 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern: calls in statics are limited
static S : u64 = { { panic!("foo"); 0 } };
//~^ ERROR calls in statics are limited
fn main() {
println!("{:?}", S);

View file

@ -1,5 +1,5 @@
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
--> $DIR/issue-32829.rs:13:22
--> $DIR/issue-32829.rs:11:22
|
LL | static S : u64 = { { panic!("foo"); 0 } };
| ^^^^^^^^^^^^^^

View file

@ -11,5 +11,6 @@
fn main() {
enum Foo {
Drop = assert_eq!(1, 1)
//~^ ERROR if may be missing an else clause
}
}

View file

@ -0,0 +1,30 @@
// Copyright 2014 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 case of macro expansion, the errors should be matched using the deepest callsite in the
// macro call stack whose span is in the current file
macro_rules! macro_with_error {
( ) => {
println!("{"); //~ ERROR invalid
};
}
fn foo() {
}
fn main() {
macro_with_error!();
//^ In case of a local macro we want the error to be matched in the macro definition, not here
println!("}"); //~ ERROR invalid
//^ In case of an external macro we want the error to be matched here
}

View file

@ -0,0 +1,21 @@
error: invalid format string: expected `'}'` but string was terminated
--> $DIR/issue-51848.rs:16:20
|
LL | println!("{"); //~ ERROR invalid
| ^ expected `'}'` in format string
...
LL | macro_with_error!();
| -------------------- in this macro invocation
|
= note: if you intended to print `{`, you can escape it using `{{`
error: invalid format string: unmatched `}` found
--> $DIR/issue-51848.rs:28:15
|
LL | println!("}"); //~ ERROR invalid
| ^ unmatched `}` in format string
|
= note: if you intended to print `}`, you can escape it using `}}`
error: aborting due to 2 previous errors

View file

@ -5,6 +5,7 @@ LL | let mut x = vec![1].iter();
| ^^^^^^^ - temporary value only lives until here
| |
| temporary value does not live long enough
LL | //~^ ERROR borrowed value does not live long enough
LL | x.use_mut();
| - borrow later used here
|

View file

@ -10,6 +10,7 @@
fn f() {
let mut x = vec![1].iter();
//~^ ERROR borrowed value does not live long enough
x.use_mut();
}

View file

@ -5,7 +5,7 @@ LL | let mut x = vec![1].iter();
| ^^^^^^^ - temporary value dropped here while still borrowed
| |
| temporary value does not live long enough
LL | x.use_mut();
...
LL | }
| - temporary value needs to live until here
|

View file

@ -16,5 +16,6 @@ fn main() {
let x = loop {
continue;
println!("hi");
//~^ ERROR unreachable statement
};
}

View file

@ -33,6 +33,7 @@ fn c() {
let x = {
return;
println!("foo");
//~^ ERROR unreachable statement
22
};
}

View file

@ -35,6 +35,7 @@ fn baz() {
// As the next action to be taken after the if arms, we should
// report the `println!` as unreachable:
println!("But I am.");
//~^ ERROR unreachable statement
}
fn main() { }

View file

@ -16,6 +16,7 @@
fn a() {
loop { return; }
println!("I am dead.");
//~^ ERROR unreachable statement
}
fn b() {
@ -28,6 +29,7 @@ fn b() {
fn c() {
loop { return; }
println!("I am dead.");
//~^ ERROR unreachable statement
}
fn d() {
@ -38,6 +40,7 @@ fn d() {
fn e() {
loop { 'middle: loop { loop { break 'middle; } } }
println!("I am dead.");
//~^ ERROR unreachable statement
}
fn main() { }

View file

@ -12,7 +12,7 @@ LL | #![deny(unreachable_code)]
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error: unreachable statement
--> $DIR/expr_loop.rs:30:5
--> $DIR/expr_loop.rs:31:5
|
LL | println!("I am dead.");
| ^^^^^^^^^^^^^^^^^^^^^^^
@ -20,7 +20,7 @@ LL | println!("I am dead.");
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error: unreachable statement
--> $DIR/expr_loop.rs:40:5
--> $DIR/expr_loop.rs:42:5
|
LL | println!("I am dead.");
| ^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -22,6 +22,7 @@ fn a() {
fn b() {
match () { () => return }
println!("I am dead");
//~^ ERROR unreachable statement
}
fn c() {
@ -32,6 +33,7 @@ fn c() {
fn d() {
match () { () if false => return, () => return }
println!("I am dead");
//~^ ERROR unreachable statement
}
fn e() {

View file

@ -19,7 +19,7 @@ LL | println!("I am dead");
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error: unreachable statement
--> $DIR/expr_match.rs:34:5
--> $DIR/expr_match.rs:35:5
|
LL | println!("I am dead");
| ^^^^^^^^^^^^^^^^^^^^^^

View file

@ -16,6 +16,7 @@
fn foo() {
while {return} {
println!("Hello, world!");
//~^ ERROR unreachable
}
}
@ -30,8 +31,10 @@ fn baz() {
// Here, we cite the `while` loop as dead.
while {return} {
println!("I am dead.");
//~^ ERROR unreachable
}
println!("I am, too.");
//~^ ERROR unreachable
}
fn main() { }

View file

@ -12,7 +12,7 @@ LL | #![deny(unreachable_code)]
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error: unreachable statement
--> $DIR/expr_while.rs:32:9
--> $DIR/expr_while.rs:33:9
|
LL | println!("I am dead.");
| ^^^^^^^^^^^^^^^^^^^^^^^
@ -20,7 +20,7 @@ LL | println!("I am dead.");
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error: unreachable statement
--> $DIR/expr_while.rs:34:5
--> $DIR/expr_while.rs:36:5
|
LL | println!("I am, too.");
| ^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -29,4 +29,5 @@ fn main() {
let s = &mut String::new();
s = format!("foo");
//~^ ERROR E0308
}

View file

@ -16,6 +16,7 @@ use std::io::{self, Read, Write};
fn handle_client(stream: TcpStream) -> io::Result<()> {
stream.write_fmt(format!("message received"))
//~^ ERROR mismatched types
}
fn main() {

View file

@ -3,7 +3,7 @@ error[E0597]: borrowed value does not live long enough
|
LL | let x: &[isize] = &vec![1, 2, 3, 4, 5];
| ^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
LL | y = &x[1..];
...
LL | }
| - temporary value only lives until here
LL | y.use_ref();

View file

@ -14,6 +14,7 @@ fn main() {
let y;
{
let x: &[isize] = &vec![1, 2, 3, 4, 5];
//~^ ERROR borrowed value does not live long enough
y = &x[1..];
}
y.use_ref();

View file

@ -3,7 +3,7 @@ error[E0597]: borrowed value does not live long enough
|
LL | let x: &[isize] = &vec![1, 2, 3, 4, 5];
| ^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
LL | y = &x[1..];
...
LL | }
| - temporary value dropped here while still borrowed
LL | y.use_ref();

View file

@ -10,4 +10,5 @@
fn main() {
let x = vec![];
//~^ ERROR type annotations needed
}

View file

@ -10,4 +10,5 @@
fn main() {
let (x, ) = (vec![], );
//~^ ERROR type annotations needed
}

View file

@ -40,6 +40,21 @@ struct DiagnosticSpan {
expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
}
impl DiagnosticSpan {
/// Returns the deepest source span in the macro call stack with a given file name.
/// This is either the supplied span, or the span for some macro callsite that expanded to it.
fn first_callsite_in_file(&self, file_name: &str) -> &DiagnosticSpan {
if self.file_name == file_name {
self
} else {
self.expansion
.as_ref()
.map(|origin| origin.span.first_callsite_in_file(file_name))
.unwrap_or(self)
}
}
}
#[derive(Deserialize, Clone)]
struct DiagnosticSpanMacroExpansion {
/// span where macro was applied to generate this code
@ -115,16 +130,23 @@ fn push_expected_errors(
default_spans: &[&DiagnosticSpan],
file_name: &str,
) {
let spans_in_this_file: Vec<_> = diagnostic
// In case of macro expansions, we need to get the span of the callsite
let spans_info_in_this_file: Vec<_> = diagnostic
.spans
.iter()
.filter(|span| Path::new(&span.file_name) == Path::new(&file_name))
.map(|span| (span.is_primary, span.first_callsite_in_file(file_name)))
.filter(|(_, span)| Path::new(&span.file_name) == Path::new(&file_name))
.collect();
let primary_spans: Vec<_> = spans_in_this_file.iter()
.cloned()
.filter(|span| span.is_primary)
let spans_in_this_file: Vec<_> = spans_info_in_this_file.iter()
.map(|(_, span)| span)
.collect();
let primary_spans: Vec<_> = spans_info_in_this_file.iter()
.filter(|(is_primary, _)| *is_primary)
.map(|(_, span)| span)
.take(1) // sometimes we have more than one showing up in the json; pick first
.cloned()
.collect();
let primary_spans = if primary_spans.is_empty() {
// subdiagnostics often don't have a span of their own;

View file

@ -1194,6 +1194,10 @@ impl<'test> TestCx<'test> {
self.fatal_proc_rec("process did not return an error status", proc_res);
}
// On Windows, keep all '\' path separators to match the paths reported in the JSON output
// from the compiler
let os_file_name = self.testpaths.file.display().to_string();
// on windows, translate all '\' path separators to '/'
let file_name = format!("{}", self.testpaths.file.display()).replace(r"\", "/");
@ -1209,7 +1213,7 @@ impl<'test> TestCx<'test> {
.any(|ee| ee.kind == Some(ErrorKind::Note));
// Parse the JSON output from the compiler and extract out the messages.
let actual_errors = json::parse_output(&file_name, &proc_res.stderr, proc_res);
let actual_errors = json::parse_output(&os_file_name, &proc_res.stderr, proc_res);
let mut unexpected = Vec::new();
let mut found = vec![false; expected_errors.len()];
for actual_error in &actual_errors {