1111use { ast, attr} ;
1212use syntax_pos:: { Span , DUMMY_SP } ;
1313use edition:: Edition ;
14+ use errors:: FatalError ;
1415use ext:: base:: { DummyResult , ExtCtxt , MacResult , SyntaxExtension } ;
1516use ext:: base:: { NormalTT , TTMacroExpander } ;
1617use 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
5052impl < ' 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 ( ) ;
0 commit comments