@@ -291,17 +291,16 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
291291 let lhses = match * * argument_map. get ( & lhs_nm. name ) . unwrap ( ) {
292292 MatchedSeq ( ref s, _) => {
293293 s. iter ( ) . map ( |m| match * * m {
294- MatchedNonterminal ( NtTT ( ref tt) ) => ( * * tt) . clone ( ) ,
294+ MatchedNonterminal ( NtTT ( ref tt) ) => {
295+ valid &= check_lhs_nt_follows ( cx, tt) ;
296+ ( * * tt) . clone ( )
297+ }
295298 _ => cx. span_bug ( def. span , "wrong-structured lhs" )
296299 } ) . collect ( )
297300 }
298301 _ => cx. span_bug ( def. span , "wrong-structured lhs" )
299302 } ;
300303
301- for lhs in & lhses {
302- check_lhs_nt_follows ( cx, lhs, def. span ) ;
303- }
304-
305304 let rhses = match * * argument_map. get ( & rhs_nm. name ) . unwrap ( ) {
306305 MatchedSeq ( ref s, _) => {
307306 s. iter ( ) . map ( |m| match * * m {
@@ -330,19 +329,19 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
330329// why is this here? because of https://github.com/rust-lang/rust/issues/27774
331330fn ref_slice < A > ( s : & A ) -> & [ A ] { use std:: slice:: from_raw_parts; unsafe { from_raw_parts ( s, 1 ) } }
332331
333- fn check_lhs_nt_follows ( cx : & mut ExtCtxt , lhs : & TokenTree , sp : Span ) {
332+ fn check_lhs_nt_follows ( cx : & mut ExtCtxt , lhs : & TokenTree ) -> bool {
334333 // lhs is going to be like TokenTree::Delimited(...), where the
335334 // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
336335 match lhs {
337- & TokenTree :: Delimited ( _, ref tts) => {
338- check_matcher ( cx, & tts . tts ) ;
339- } ,
340- tt @ & TokenTree :: Sequence ( .. ) => {
341- check_matcher ( cx , ref_slice ( tt ) ) ;
342- } ,
343- _ => cx . span_err ( sp , "invalid macro matcher; matchers must be contained \
344- in balanced delimiters or a repetition indicator" )
345- } ;
336+ & TokenTree :: Delimited ( _, ref tts) => check_matcher ( cx , & tts . tts ) ,
337+ tt @ & TokenTree :: Sequence ( .. ) => check_matcher ( cx, ref_slice ( tt ) ) ,
338+ _ => {
339+ cx . span_err ( lhs . get_span ( ) ,
340+ "invalid macro matcher; matchers must be contained \
341+ in balanced delimiters or a repetition indicator" ) ;
342+ false
343+ }
344+ }
346345 // we don't abort on errors on rejection, the driver will do that for us
347346 // after parsing/expansion. we can report every error in every macro this way.
348347}
@@ -364,28 +363,33 @@ struct OnFail {
364363 action : OnFailAction ,
365364}
366365
367- #[ derive( Copy , Clone , Debug ) ]
366+ #[ derive( Copy , Clone , Debug , PartialEq ) ]
368367enum OnFailAction { Warn , Error , DoNothing }
369368
370369impl OnFail {
371370 fn warn ( ) -> OnFail { OnFail { saw_failure : false , action : OnFailAction :: Warn } }
372371 fn error ( ) -> OnFail { OnFail { saw_failure : false , action : OnFailAction :: Error } }
373372 fn do_nothing ( ) -> OnFail { OnFail { saw_failure : false , action : OnFailAction :: DoNothing } }
374- fn react ( & mut self , cx : & mut ExtCtxt , sp : Span , msg : & str ) {
373+ fn react ( & mut self , cx : & mut ExtCtxt , sp : Span , msg : & str , help : Option < & str > ) {
375374 match self . action {
376375 OnFailAction :: DoNothing => { }
377- OnFailAction :: Error => cx. span_err ( sp, msg) ,
376+ OnFailAction :: Error => {
377+ let mut err = cx. struct_span_err ( sp, msg) ;
378+ if let Some ( msg) = help { err. span_help ( sp, msg) ; }
379+ err. emit ( ) ;
380+ }
378381 OnFailAction :: Warn => {
379- cx. struct_span_warn ( sp, msg)
380- . span_note ( sp, "The above warning will be a hard error in the next release." )
382+ let mut warn = cx. struct_span_warn ( sp, msg) ;
383+ if let Some ( msg) = help { warn. span_help ( sp, msg) ; }
384+ warn. span_note ( sp, "The above warning will be a hard error in the next release." )
381385 . emit ( ) ;
382386 }
383387 } ;
384388 self . saw_failure = true ;
385389 }
386390}
387391
388- fn check_matcher ( cx : & mut ExtCtxt , matcher : & [ TokenTree ] ) {
392+ fn check_matcher ( cx : & mut ExtCtxt , matcher : & [ TokenTree ] ) -> bool {
389393 // Issue 30450: when we are through a warning cycle, we can just
390394 // error on all failure conditions (and remove check_matcher_old).
391395
@@ -400,6 +404,9 @@ fn check_matcher(cx: &mut ExtCtxt, matcher: &[TokenTree]) {
400404 OnFail :: warn ( )
401405 } ;
402406 check_matcher_new ( cx, matcher, & mut on_fail) ;
407+ // matcher is valid if the new pass didn't see any error,
408+ // or if errors were considered warnings
409+ on_fail. action != OnFailAction :: Error || !on_fail. saw_failure
403410}
404411
405412// returns the last token that was checked, for TokenTree::Sequence.
@@ -435,11 +442,11 @@ fn check_matcher_old<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token, on_fai
435442 // sequence, which may itself be a sequence,
436443 // and so on).
437444 on_fail. react ( cx, sp,
438- & format ! ( "`${0}:{1}` is followed by a \
439- sequence repetition, which is not \
440- allowed for `{1}` fragments",
441- name, frag_spec)
442- ) ;
445+ & format ! ( "`${0}:{1}` is followed by a \
446+ sequence repetition, which is not \
447+ allowed for `{1}` fragments",
448+ name, frag_spec) ,
449+ None ) ;
443450 Eof
444451 } ,
445452 // die next iteration
@@ -456,8 +463,10 @@ fn check_matcher_old<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token, on_fai
456463
457464 // If T' is in the set FOLLOW(NT), continue. Else, reject.
458465 match ( & next_token, is_in_follow ( cx, & next_token, & frag_spec. name . as_str ( ) ) ) {
459- ( _, Err ( msg) ) => {
460- on_fail. react ( cx, sp, & msg) ;
466+ ( _, Err ( ( msg, _) ) ) => {
467+ // no need for help message, those messages
468+ // are never emitted anyway...
469+ on_fail. react ( cx, sp, & msg, None ) ;
461470 continue
462471 }
463472 ( & Eof , _) => return Some ( ( sp, tok. clone ( ) ) ) ,
@@ -466,7 +475,7 @@ fn check_matcher_old<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token, on_fai
466475 on_fail. react ( cx, sp, & format ! ( "`${0}:{1}` is followed by `{2}`, which \
467476 is not allowed for `{1}` fragments",
468477 name, frag_spec,
469- token_to_string( next) ) ) ;
478+ token_to_string( next) ) , None ) ;
470479 continue
471480 } ,
472481 }
@@ -494,7 +503,8 @@ fn check_matcher_old<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token, on_fai
494503 delim. close_token ( ) ,
495504 Some ( _) => {
496505 on_fail. react ( cx, sp, "sequence repetition followed by \
497- another sequence repetition, which is not allowed") ;
506+ another sequence repetition, which is not allowed",
507+ None ) ;
498508 Eof
499509 } ,
500510 None => Eof
@@ -514,7 +524,7 @@ fn check_matcher_old<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token, on_fai
514524 Some ( & & TokenTree :: Delimited ( _, ref delim) ) => delim. close_token ( ) ,
515525 Some ( _) => {
516526 on_fail. react ( cx, sp, "sequence repetition followed by another \
517- sequence repetition, which is not allowed") ;
527+ sequence repetition, which is not allowed", None ) ;
518528 Eof
519529 } ,
520530 None => Eof
@@ -810,7 +820,11 @@ fn check_matcher_core(cx: &mut ExtCtxt,
810820 TokenTree :: Token ( sp, ref tok) => {
811821 let can_be_followed_by_any;
812822 if let Err ( bad_frag) = has_legal_fragment_specifier ( tok) {
813- on_fail. react ( cx, sp, & format ! ( "invalid fragment specifier `{}`" , bad_frag) ) ;
823+ on_fail. react ( cx, sp,
824+ & format ! ( "invalid fragment specifier `{}`" , bad_frag) ,
825+ Some ( "valid fragment specifiers are `ident`, `block`, \
826+ `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \
827+ and `item`") ) ;
814828 // (This eliminates false positives and duplicates
815829 // from error messages.)
816830 can_be_followed_by_any = true ;
@@ -884,8 +898,8 @@ fn check_matcher_core(cx: &mut ExtCtxt,
884898 if let MatchNt ( ref name, ref frag_spec) = * t {
885899 for & ( sp, ref next_token) in & suffix_first. tokens {
886900 match is_in_follow ( cx, next_token, & frag_spec. name . as_str ( ) ) {
887- Err ( msg) => {
888- on_fail. react ( cx, sp, & msg) ;
901+ Err ( ( msg, help ) ) => {
902+ on_fail. react ( cx, sp, & msg, Some ( help ) ) ;
889903 // don't bother reporting every source of
890904 // conflict for a particular element of `last`.
891905 continue ' each_last;
@@ -907,7 +921,9 @@ fn check_matcher_core(cx: &mut ExtCtxt,
907921 name=name,
908922 frag=frag_spec,
909923 next=token_to_string( next_token) ,
910- may_be=may_be) ) ;
924+ may_be=may_be) ,
925+ None
926+ ) ;
911927 }
912928 }
913929 }
@@ -978,7 +994,7 @@ fn can_be_followed_by_any(frag: &str) -> bool {
978994/// break macros that were relying on that binary operator as a
979995/// separator.
980996// when changing this do not forget to update doc/book/macros.md!
981- fn is_in_follow ( _: & ExtCtxt , tok : & Token , frag : & str ) -> Result < bool , String > {
997+ fn is_in_follow ( _: & ExtCtxt , tok : & Token , frag : & str ) -> Result < bool , ( String , & ' static str ) > {
982998 if let & CloseDelim ( _) = tok {
983999 // closing a token tree can never be matched by any fragment;
9841000 // iow, we always require that `(` and `)` match, etc.
@@ -1027,7 +1043,10 @@ fn is_in_follow(_: &ExtCtxt, tok: &Token, frag: &str) -> Result<bool, String> {
10271043 // harmless
10281044 Ok ( true )
10291045 } ,
1030- _ => Err ( format ! ( "invalid fragment specifier `{}`" , frag) )
1046+ _ => Err ( ( format ! ( "invalid fragment specifier `{}`" , frag) ,
1047+ "valid fragment specifiers are `ident`, `block`, \
1048+ `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \
1049+ and `item`") )
10311050 }
10321051 }
10331052}
0 commit comments