about summary refs log tree commit diff
path: root/src/libsyntax/ext
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-11-27 12:31:45 +0000
committerbors <bors@rust-lang.org>2018-11-27 12:31:45 +0000
commit10e2c729ea2e85cb1e2a08be40564492f49e45ec (patch)
tree20a10dec78680734dbac4325e578103c88858595 /src/libsyntax/ext
parent691a7f8e2b2de984c3e0f062cbd294763af3d09a (diff)
parentd011313d843b3ddcf095db06907abffdd9cc5904 (diff)
downloadrust-10e2c729ea2e85cb1e2a08be40564492f49e45ec.tar.gz
rust-10e2c729ea2e85cb1e2a08be40564492f49e45ec.zip
Auto merge of #55402 - estebank:macro-eof-2, r=nikomatsakis
Point at end of macro arm when encountering EOF

Fix #52866.
Diffstat (limited to 'src/libsyntax/ext')
-rw-r--r--src/libsyntax/ext/tt/macro_parser.rs24
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs44
2 files changed, 54 insertions, 14 deletions
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index f31d80acbfa..8fd9590a664 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -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),
 }
@@ -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),
         }
 
@@ -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]
@@ -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
@@ -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() {
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index d526e464ba4..ff622b0c18f 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -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};
@@ -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
         }));
@@ -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 {
@@ -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)
@@ -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[..])
@@ -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");
@@ -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();