diff options
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ext/tt/macro_parser.rs | 24 | ||||
| -rw-r--r-- | src/libsyntax/ext/tt/macro_rules.rs | 44 |
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(); |
