Skip to content

Point at end of macro arm when encountering EOF #55402

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Nov 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/librustc_errors/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,17 @@ impl Diagnostic {
self
}

pub fn replace_span_with(&mut self, after: Span) -> &mut Self {
let before = self.span.clone();
self.set_span(after);
for span_label in before.span_labels() {
if let Some(label) = span_label.label {
self.span_label(after, label);
}
}
self
}

pub fn note_expected_found(&mut self,
label: &dyn fmt::Display,
expected: DiagnosticStyledString,
Expand Down
24 changes: 18 additions & 6 deletions src/libsyntax/ext/tt/macro_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ pub enum ParseResult<T> {
Success(T),
/// Arm failed to match. If the second parameter is `token::Eof`, it indicates an unexpected
/// end of macro invocation. Otherwise, it indicates that no rules expected the given token.
Failure(syntax_pos::Span, Token),
Failure(syntax_pos::Span, Token, String),
/// Fatal error (malformed macro?). Abort compilation.
Error(syntax_pos::Span, String),
}
Expand Down Expand Up @@ -698,7 +698,7 @@ pub fn parse(
parser.span,
) {
Success(_) => {}
Failure(sp, tok) => return Failure(sp, tok),
Failure(sp, tok, t) => return Failure(sp, tok, t),
Error(sp, msg) => return Error(sp, msg),
}

Expand All @@ -710,7 +710,7 @@ pub fn parse(
// Error messages here could be improved with links to original rules.

// If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise,
// either the parse is ambiguous (which should never happen) or their is a syntax error.
// either the parse is ambiguous (which should never happen) or there is a syntax error.
if token_name_eq(&parser.token, &token::Eof) {
if eof_items.len() == 1 {
let matches = eof_items[0]
Expand All @@ -724,7 +724,15 @@ pub fn parse(
"ambiguity: multiple successful parses".to_string(),
);
} else {
return Failure(parser.span, token::Eof);
return Failure(
if parser.span.is_dummy() {
parser.span
} else {
sess.source_map().next_point(parser.span)
},
token::Eof,
"missing tokens in macro arguments".to_string(),
);
}
}
// Performance hack: eof_items may share matchers via Rc with other things that we want
Expand Down Expand Up @@ -757,9 +765,13 @@ pub fn parse(
);
}
// If there are no possible next positions AND we aren't waiting for the black-box parser,
// then their is a syntax error.
// then there is a syntax error.
else if bb_items.is_empty() && next_items.is_empty() {
return Failure(parser.span, parser.token);
return Failure(
parser.span,
parser.token,
"no rules expected this token in macro call".to_string(),
);
}
// Dump all possible `next_items` into `cur_items` for the next iteration.
else if !next_items.is_empty() {
Expand Down
44 changes: 36 additions & 8 deletions src/libsyntax/ext/tt/macro_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use {ast, attr};
use syntax_pos::{Span, DUMMY_SP};
use edition::Edition;
use errors::FatalError;
use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension};
use ext::base::{NormalTT, TTMacroExpander};
use ext::expand::{AstFragment, AstFragmentKind};
Expand Down Expand Up @@ -44,15 +45,34 @@ pub struct ParserAnyMacro<'a> {
/// Span of the expansion site of the macro this parser is for
site_span: Span,
/// The ident of the macro we're parsing
macro_ident: ast::Ident
macro_ident: ast::Ident,
arm_span: Span,
}

impl<'a> ParserAnyMacro<'a> {
pub fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment {
let ParserAnyMacro { site_span, macro_ident, ref mut parser } = *self;
let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self;
let fragment = panictry!(parser.parse_ast_fragment(kind, true).map_err(|mut e| {
if parser.token == token::Eof && e.message().ends_with(", found `<eof>`") {
if !e.span.is_dummy() { // early end of macro arm (#52866)
e.replace_span_with(parser.sess.source_map().next_point(parser.span));
}
let msg = &e.message[0];
e.message[0] = (
format!(
"macro expansion ends with an incomplete expression: {}",
msg.0.replace(", found `<eof>`", ""),
),
msg.1,
);
}
if e.span.is_dummy() { // Get around lack of span in error (#30128)
e.set_span(site_span);
e.replace_span_with(site_span);
if parser.sess.source_map().span_to_filename(arm_span).is_real() {
e.span_label(arm_span, "in this macro arm");
}
} else if !parser.sess.source_map().span_to_filename(parser.span).is_real() {
e.span_label(site_span, "in this macro invocation");
}
e
}));
Expand Down Expand Up @@ -120,6 +140,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
// Which arm's failure should we report? (the one furthest along)
let mut best_fail_spot = DUMMY_SP;
let mut best_fail_tok = None;
let mut best_fail_text = None;

for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers
let lhs_tt = match *lhs {
Expand All @@ -134,6 +155,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
quoted::TokenTree::Delimited(_, ref delimed) => delimed.tts.clone(),
_ => cx.span_bug(sp, "malformed macro rhs"),
};
let arm_span = rhses[i].span();

let rhs_spans = rhs.iter().map(|t| t.span()).collect::<Vec<_>>();
// rhs has holes ( `$id` and `$(...)` that need filled)
Expand Down Expand Up @@ -172,12 +194,14 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
// so we can print a useful error message if the parse of the expanded
// macro leaves unparsed tokens.
site_span: sp,
macro_ident: name
macro_ident: name,
arm_span,
})
}
Failure(sp, tok) => if sp.lo() >= best_fail_spot.lo() {
Failure(sp, tok, t) => if sp.lo() >= best_fail_spot.lo() {
best_fail_spot = sp;
best_fail_tok = Some(tok);
best_fail_text = Some(t);
},
Error(err_sp, ref msg) => {
cx.span_fatal(err_sp.substitute_dummy(sp), &msg[..])
Expand All @@ -188,7 +212,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
let best_fail_msg = parse_failure_msg(best_fail_tok.expect("ran no matchers"));
let span = best_fail_spot.substitute_dummy(sp);
let mut err = cx.struct_span_err(span, &best_fail_msg);
err.span_label(span, best_fail_msg);
err.span_label(span, best_fail_text.unwrap_or(best_fail_msg));
if let Some(sp) = def_span {
if cx.source_map().span_to_filename(sp).is_real() && !sp.is_dummy() {
err.span_label(cx.source_map().def_span(sp), "when calling this macro");
Expand Down Expand Up @@ -268,9 +292,13 @@ pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item, edition:

let argument_map = match parse(sess, body.stream(), &argument_gram, None, true) {
Success(m) => m,
Failure(sp, tok) => {
Failure(sp, tok, t) => {
let s = parse_failure_msg(tok);
sess.span_diagnostic.span_fatal(sp.substitute_dummy(def.span), &s).raise();
let sp = sp.substitute_dummy(def.span);
let mut err = sess.span_diagnostic.struct_span_fatal(sp, &s);
err.span_label(sp, t);
err.emit();
FatalError.raise();
}
Error(sp, s) => {
sess.span_diagnostic.span_fatal(sp.substitute_dummy(def.span), &s).raise();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ fn expand_mbe_matches(cx: &mut ExtCtxt, _: Span, args: &[TokenTree])
NodeId::from_u32(0));
let map = match TokenTree::parse(cx, &mbe_matcher, args.iter().cloned().collect()) {
Success(map) => map,
Failure(_, tok) => {
panic!("expected Success, but got Failure: {}", parse_failure_msg(tok));
Failure(_, tok, msg) => {
panic!("expected Success, but got Failure: {} - {}", parse_failure_msg(tok), msg);
}
Error(_, s) => {
panic!("expected Success, but got Error: {}", s);
Expand Down
3 changes: 2 additions & 1 deletion src/test/ui/directory_ownership/macro-expanded-mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ mod macro_expanded_mod_helper {
}

fn main() {
mod_decl!(foo); //~ ERROR Cannot declare a non-inline module inside a block
mod_decl!(foo);
//~^ ERROR Cannot declare a non-inline module inside a block
}
2 changes: 1 addition & 1 deletion src/test/ui/directory_ownership/macro-expanded-mod.stderr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
error: Cannot declare a non-inline module inside a block unless it has a path attribute
--> $DIR/macro-expanded-mod.rs:22:15
|
LL | mod_decl!(foo); //~ ERROR Cannot declare a non-inline module inside a block
LL | mod_decl!(foo);
| ^^^

error: aborting due to previous error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ error: no rules expected the token `r#async`
--> $DIR/edition-keywords-2015-2015-parsing.rs:22:31
|
LL | r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
| ^^^^^^^ no rules expected the token `r#async`
| ^^^^^^^ no rules expected this token in macro call

error: no rules expected the token `async`
--> $DIR/edition-keywords-2015-2015-parsing.rs:23:35
|
LL | r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
| ^^^^^ no rules expected the token `async`
| ^^^^^ no rules expected this token in macro call

error: aborting due to 2 previous errors

Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ error: no rules expected the token `r#async`
--> $DIR/edition-keywords-2015-2018-parsing.rs:22:31
|
LL | r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
| ^^^^^^^ no rules expected the token `r#async`
| ^^^^^^^ no rules expected this token in macro call

error: no rules expected the token `async`
--> $DIR/edition-keywords-2015-2018-parsing.rs:23:35
|
LL | r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
| ^^^^^ no rules expected the token `async`
| ^^^^^ no rules expected this token in macro call

error: aborting due to 2 previous errors

15 changes: 10 additions & 5 deletions src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,24 @@ error: no rules expected the token `r#async`
--> $DIR/edition-keywords-2018-2015-parsing.rs:22:31
|
LL | r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
| ^^^^^^^ no rules expected the token `r#async`
| ^^^^^^^ no rules expected this token in macro call

error: no rules expected the token `async`
--> $DIR/edition-keywords-2018-2015-parsing.rs:23:35
|
LL | r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
| ^^^^^ no rules expected the token `async`
| ^^^^^ no rules expected this token in macro call

error: expected one of `move`, `|`, or `||`, found `<eof>`
--> <::edition_kw_macro_2015::passes_ident macros>:1:22
error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
--> <::edition_kw_macro_2015::passes_ident macros>:1:25
|
LL | ( $ i : ident ) => ( $ i )
| ^^^ expected one of `move`, `|`, or `||` here
| ^ expected one of `move`, `|`, or `||` here
|
::: $DIR/edition-keywords-2018-2015-parsing.rs:26:8
|
LL | if passes_ident!(async) == 1 {}
| -------------------- in this macro invocation

error: aborting due to 5 previous errors

15 changes: 10 additions & 5 deletions src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,24 @@ error: no rules expected the token `r#async`
--> $DIR/edition-keywords-2018-2018-parsing.rs:22:31
|
LL | r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
| ^^^^^^^ no rules expected the token `r#async`
| ^^^^^^^ no rules expected this token in macro call

error: no rules expected the token `async`
--> $DIR/edition-keywords-2018-2018-parsing.rs:23:35
|
LL | r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
| ^^^^^ no rules expected the token `async`
| ^^^^^ no rules expected this token in macro call

error: expected one of `move`, `|`, or `||`, found `<eof>`
--> <::edition_kw_macro_2018::passes_ident macros>:1:22
error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
--> <::edition_kw_macro_2018::passes_ident macros>:1:25
|
LL | ( $ i : ident ) => ( $ i )
| ^^^ expected one of `move`, `|`, or `||` here
| ^ expected one of `move`, `|`, or `||` here
|
::: $DIR/edition-keywords-2018-2018-parsing.rs:26:8
|
LL | if passes_ident!(async) == 1 {}
| -------------------- in this macro invocation

error: aborting due to 5 previous errors

2 changes: 1 addition & 1 deletion src/test/ui/empty/empty-comment.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ LL | macro_rules! one_arg_macro {
| -------------------------- when calling this macro
...
LL | one_arg_macro!(/**/); //~ ERROR unexpected end
| ^^^^^^^^^^^^^^^^^^^^^ unexpected end of macro invocation
| ^^^^^^^^^^^^^^^^^^^^^ missing tokens in macro arguments

error: aborting due to previous error

2 changes: 1 addition & 1 deletion src/test/ui/fail-simple.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error: no rules expected the token `@`
--> $DIR/fail-simple.rs:12:12
|
LL | panic!(@); //~ ERROR no rules expected the token `@`
| ^ no rules expected the token `@`
| ^ no rules expected this token in macro call

error: aborting due to previous error

2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-7970a.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ LL | macro_rules! one_arg_macro {
| -------------------------- when calling this macro
...
LL | one_arg_macro!();
| ^^^^^^^^^^^^^^^^^ unexpected end of macro invocation
| ^^^^^^^^^^^^^^^^^ missing tokens in macro arguments

error: aborting due to previous error

2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-7970b.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error: unexpected end of macro invocation
--> $DIR/issue-7970b.rs:13:1
|
LL | macro_rules! test {}
| ^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^ missing tokens in macro arguments

error: aborting due to previous error

Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ LL | macro_rules! foo {
| ---------------- when calling this macro
...
LL | foo!(a?); //~ ERROR no rules expected the token `?`
| ^ no rules expected the token `?`
| ^ no rules expected this token in macro call

error: no rules expected the token `?`
--> $DIR/macro-at-most-once-rep-2018-feature-gate.rs:42:11
Expand All @@ -64,7 +64,7 @@ LL | macro_rules! foo {
| ---------------- when calling this macro
...
LL | foo!(a?a); //~ ERROR no rules expected the token `?`
| ^ no rules expected the token `?`
| ^ no rules expected this token in macro call

error: no rules expected the token `?`
--> $DIR/macro-at-most-once-rep-2018-feature-gate.rs:43:11
Expand All @@ -73,7 +73,7 @@ LL | macro_rules! foo {
| ---------------- when calling this macro
...
LL | foo!(a?a?a); //~ ERROR no rules expected the token `?`
| ^ no rules expected the token `?`
| ^ no rules expected this token in macro call

error: aborting due to 10 previous errors

Expand Down
Loading