Skip to content

Commit 10e2c72

Browse files
committed
Auto merge of #55402 - estebank:macro-eof-2, r=nikomatsakis
Point at end of macro arm when encountering EOF Fix #52866.
2 parents 691a7f8 + d011313 commit 10e2c72

25 files changed

+130
-65
lines changed

src/librustc_errors/diagnostic.rs

+11
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,17 @@ impl Diagnostic {
139139
self
140140
}
141141

142+
pub fn replace_span_with(&mut self, after: Span) -> &mut Self {
143+
let before = self.span.clone();
144+
self.set_span(after);
145+
for span_label in before.span_labels() {
146+
if let Some(label) = span_label.label {
147+
self.span_label(after, label);
148+
}
149+
}
150+
self
151+
}
152+
142153
pub fn note_expected_found(&mut self,
143154
label: &dyn fmt::Display,
144155
expected: DiagnosticStyledString,

src/libsyntax/ext/tt/macro_parser.rs

+18-6
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ pub enum ParseResult<T> {
281281
Success(T),
282282
/// Arm failed to match. If the second parameter is `token::Eof`, it indicates an unexpected
283283
/// end of macro invocation. Otherwise, it indicates that no rules expected the given token.
284-
Failure(syntax_pos::Span, Token),
284+
Failure(syntax_pos::Span, Token, String),
285285
/// Fatal error (malformed macro?). Abort compilation.
286286
Error(syntax_pos::Span, String),
287287
}
@@ -698,7 +698,7 @@ pub fn parse(
698698
parser.span,
699699
) {
700700
Success(_) => {}
701-
Failure(sp, tok) => return Failure(sp, tok),
701+
Failure(sp, tok, t) => return Failure(sp, tok, t),
702702
Error(sp, msg) => return Error(sp, msg),
703703
}
704704

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

712712
// If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise,
713-
// either the parse is ambiguous (which should never happen) or their is a syntax error.
713+
// either the parse is ambiguous (which should never happen) or there is a syntax error.
714714
if token_name_eq(&parser.token, &token::Eof) {
715715
if eof_items.len() == 1 {
716716
let matches = eof_items[0]
@@ -724,7 +724,15 @@ pub fn parse(
724724
"ambiguity: multiple successful parses".to_string(),
725725
);
726726
} else {
727-
return Failure(parser.span, token::Eof);
727+
return Failure(
728+
if parser.span.is_dummy() {
729+
parser.span
730+
} else {
731+
sess.source_map().next_point(parser.span)
732+
},
733+
token::Eof,
734+
"missing tokens in macro arguments".to_string(),
735+
);
728736
}
729737
}
730738
// Performance hack: eof_items may share matchers via Rc with other things that we want
@@ -757,9 +765,13 @@ pub fn parse(
757765
);
758766
}
759767
// If there are no possible next positions AND we aren't waiting for the black-box parser,
760-
// then their is a syntax error.
768+
// then there is a syntax error.
761769
else if bb_items.is_empty() && next_items.is_empty() {
762-
return Failure(parser.span, parser.token);
770+
return Failure(
771+
parser.span,
772+
parser.token,
773+
"no rules expected this token in macro call".to_string(),
774+
);
763775
}
764776
// Dump all possible `next_items` into `cur_items` for the next iteration.
765777
else if !next_items.is_empty() {

src/libsyntax/ext/tt/macro_rules.rs

+36-8
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use {ast, attr};
1212
use syntax_pos::{Span, DUMMY_SP};
1313
use edition::Edition;
14+
use errors::FatalError;
1415
use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension};
1516
use ext::base::{NormalTT, TTMacroExpander};
1617
use ext::expand::{AstFragment, AstFragmentKind};
@@ -44,15 +45,34 @@ pub struct ParserAnyMacro<'a> {
4445
/// Span of the expansion site of the macro this parser is for
4546
site_span: Span,
4647
/// The ident of the macro we're parsing
47-
macro_ident: ast::Ident
48+
macro_ident: ast::Ident,
49+
arm_span: Span,
4850
}
4951

5052
impl<'a> ParserAnyMacro<'a> {
5153
pub fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment {
52-
let ParserAnyMacro { site_span, macro_ident, ref mut parser } = *self;
54+
let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self;
5355
let fragment = panictry!(parser.parse_ast_fragment(kind, true).map_err(|mut e| {
56+
if parser.token == token::Eof && e.message().ends_with(", found `<eof>`") {
57+
if !e.span.is_dummy() { // early end of macro arm (#52866)
58+
e.replace_span_with(parser.sess.source_map().next_point(parser.span));
59+
}
60+
let msg = &e.message[0];
61+
e.message[0] = (
62+
format!(
63+
"macro expansion ends with an incomplete expression: {}",
64+
msg.0.replace(", found `<eof>`", ""),
65+
),
66+
msg.1,
67+
);
68+
}
5469
if e.span.is_dummy() { // Get around lack of span in error (#30128)
55-
e.set_span(site_span);
70+
e.replace_span_with(site_span);
71+
if parser.sess.source_map().span_to_filename(arm_span).is_real() {
72+
e.span_label(arm_span, "in this macro arm");
73+
}
74+
} else if !parser.sess.source_map().span_to_filename(parser.span).is_real() {
75+
e.span_label(site_span, "in this macro invocation");
5676
}
5777
e
5878
}));
@@ -120,6 +140,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
120140
// Which arm's failure should we report? (the one furthest along)
121141
let mut best_fail_spot = DUMMY_SP;
122142
let mut best_fail_tok = None;
143+
let mut best_fail_text = None;
123144

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

138160
let rhs_spans = rhs.iter().map(|t| t.span()).collect::<Vec<_>>();
139161
// rhs has holes ( `$id` and `$(...)` that need filled)
@@ -172,12 +194,14 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
172194
// so we can print a useful error message if the parse of the expanded
173195
// macro leaves unparsed tokens.
174196
site_span: sp,
175-
macro_ident: name
197+
macro_ident: name,
198+
arm_span,
176199
})
177200
}
178-
Failure(sp, tok) => if sp.lo() >= best_fail_spot.lo() {
201+
Failure(sp, tok, t) => if sp.lo() >= best_fail_spot.lo() {
179202
best_fail_spot = sp;
180203
best_fail_tok = Some(tok);
204+
best_fail_text = Some(t);
181205
},
182206
Error(err_sp, ref msg) => {
183207
cx.span_fatal(err_sp.substitute_dummy(sp), &msg[..])
@@ -188,7 +212,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
188212
let best_fail_msg = parse_failure_msg(best_fail_tok.expect("ran no matchers"));
189213
let span = best_fail_spot.substitute_dummy(sp);
190214
let mut err = cx.struct_span_err(span, &best_fail_msg);
191-
err.span_label(span, best_fail_msg);
215+
err.span_label(span, best_fail_text.unwrap_or(best_fail_msg));
192216
if let Some(sp) = def_span {
193217
if cx.source_map().span_to_filename(sp).is_real() && !sp.is_dummy() {
194218
err.span_label(cx.source_map().def_span(sp), "when calling this macro");
@@ -268,9 +292,13 @@ pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item, edition:
268292

269293
let argument_map = match parse(sess, body.stream(), &argument_gram, None, true) {
270294
Success(m) => m,
271-
Failure(sp, tok) => {
295+
Failure(sp, tok, t) => {
272296
let s = parse_failure_msg(tok);
273-
sess.span_diagnostic.span_fatal(sp.substitute_dummy(def.span), &s).raise();
297+
let sp = sp.substitute_dummy(def.span);
298+
let mut err = sess.span_diagnostic.struct_span_fatal(sp, &s);
299+
err.span_label(sp, t);
300+
err.emit();
301+
FatalError.raise();
274302
}
275303
Error(sp, s) => {
276304
sess.span_diagnostic.span_fatal(sp.substitute_dummy(def.span), &s).raise();

src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ fn expand_mbe_matches(cx: &mut ExtCtxt, _: Span, args: &[TokenTree])
4646
NodeId::from_u32(0));
4747
let map = match TokenTree::parse(cx, &mbe_matcher, args.iter().cloned().collect()) {
4848
Success(map) => map,
49-
Failure(_, tok) => {
50-
panic!("expected Success, but got Failure: {}", parse_failure_msg(tok));
49+
Failure(_, tok, msg) => {
50+
panic!("expected Success, but got Failure: {} - {}", parse_failure_msg(tok), msg);
5151
}
5252
Error(_, s) => {
5353
panic!("expected Success, but got Error: {}", s);

src/test/ui/directory_ownership/macro-expanded-mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@ mod macro_expanded_mod_helper {
1919
}
2020

2121
fn main() {
22-
mod_decl!(foo); //~ ERROR Cannot declare a non-inline module inside a block
22+
mod_decl!(foo);
23+
//~^ ERROR Cannot declare a non-inline module inside a block
2324
}

src/test/ui/directory_ownership/macro-expanded-mod.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
error: Cannot declare a non-inline module inside a block unless it has a path attribute
22
--> $DIR/macro-expanded-mod.rs:22:15
33
|
4-
LL | mod_decl!(foo); //~ ERROR Cannot declare a non-inline module inside a block
4+
LL | mod_decl!(foo);
55
| ^^^
66

77
error: aborting due to previous error

src/test/ui/editions/edition-keywords-2015-2015-parsing.stderr

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

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

1313
error: aborting due to 2 previous errors
1414

src/test/ui/editions/edition-keywords-2015-2018-parsing.stderr

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

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

1313
error: aborting due to 2 previous errors
1414

src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr

+10-5
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,24 @@ error: no rules expected the token `r#async`
1414
--> $DIR/edition-keywords-2018-2015-parsing.rs:22:31
1515
|
1616
LL | r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
17-
| ^^^^^^^ no rules expected the token `r#async`
17+
| ^^^^^^^ no rules expected this token in macro call
1818

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

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

3136
error: aborting due to 5 previous errors
3237

src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr

+10-5
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,24 @@ error: no rules expected the token `r#async`
1414
--> $DIR/edition-keywords-2018-2018-parsing.rs:22:31
1515
|
1616
LL | r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
17-
| ^^^^^^^ no rules expected the token `r#async`
17+
| ^^^^^^^ no rules expected this token in macro call
1818

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

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

3136
error: aborting due to 5 previous errors
3237

src/test/ui/empty/empty-comment.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | macro_rules! one_arg_macro {
55
| -------------------------- when calling this macro
66
...
77
LL | one_arg_macro!(/**/); //~ ERROR unexpected end
8-
| ^^^^^^^^^^^^^^^^^^^^^ unexpected end of macro invocation
8+
| ^^^^^^^^^^^^^^^^^^^^^ missing tokens in macro arguments
99

1010
error: aborting due to previous error
1111

src/test/ui/fail-simple.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error: no rules expected the token `@`
22
--> $DIR/fail-simple.rs:12:12
33
|
44
LL | panic!(@); //~ ERROR no rules expected the token `@`
5-
| ^ no rules expected the token `@`
5+
| ^ no rules expected this token in macro call
66

77
error: aborting due to previous error
88

src/test/ui/issues/issue-7970a.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | macro_rules! one_arg_macro {
55
| -------------------------- when calling this macro
66
...
77
LL | one_arg_macro!();
8-
| ^^^^^^^^^^^^^^^^^ unexpected end of macro invocation
8+
| ^^^^^^^^^^^^^^^^^ missing tokens in macro arguments
99

1010
error: aborting due to previous error
1111

src/test/ui/issues/issue-7970b.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error: unexpected end of macro invocation
22
--> $DIR/issue-7970b.rs:13:1
33
|
44
LL | macro_rules! test {}
5-
| ^^^^^^^^^^^^^^^^^^^^
5+
| ^^^^^^^^^^^^^^^^^^^^ missing tokens in macro arguments
66

77
error: aborting due to previous error
88

src/test/ui/macros/macro-at-most-once-rep-2018-feature-gate.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ LL | macro_rules! foo {
5555
| ---------------- when calling this macro
5656
...
5757
LL | foo!(a?); //~ ERROR no rules expected the token `?`
58-
| ^ no rules expected the token `?`
58+
| ^ no rules expected this token in macro call
5959

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

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

7878
error: aborting due to 10 previous errors
7979

0 commit comments

Comments
 (0)