@@ -354,203 +354,12 @@ fn check_rhs(cx: &mut ExtCtxt, rhs: &TokenTree) -> bool {
354354 false
355355}
356356
357- // Issue 30450: when we are through a warning cycle, we can just error
358- // on all failure conditions and remove this struct and enum.
359-
360- #[ derive( Debug ) ]
361- struct OnFail {
362- saw_failure : bool ,
363- action : OnFailAction ,
364- }
365-
366- #[ derive( Copy , Clone , Debug , PartialEq ) ]
367- enum OnFailAction { Warn , Error , DoNothing }
368-
369- impl OnFail {
370- fn warn ( ) -> OnFail { OnFail { saw_failure : false , action : OnFailAction :: Warn } }
371- fn error ( ) -> OnFail { OnFail { saw_failure : false , action : OnFailAction :: Error } }
372- fn do_nothing ( ) -> OnFail { OnFail { saw_failure : false , action : OnFailAction :: DoNothing } }
373- fn react ( & mut self , cx : & mut ExtCtxt , sp : Span , msg : & str , help : Option < & str > ) {
374- match self . action {
375- OnFailAction :: DoNothing => { }
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- }
381- OnFailAction :: Warn => {
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." )
385- . emit ( ) ;
386- }
387- } ;
388- self . saw_failure = true ;
389- }
390- }
391-
392357fn check_matcher ( cx : & mut ExtCtxt , matcher : & [ TokenTree ] ) -> bool {
393- // Issue 30450: when we are through a warning cycle, we can just
394- // error on all failure conditions (and remove check_matcher_old).
395-
396- // First run the old-pass, but *only* to find out if it would have failed.
397- let mut on_fail = OnFail :: do_nothing ( ) ;
398- check_matcher_old ( cx, matcher. iter ( ) , & Eof , & mut on_fail) ;
399- // Then run the new pass, but merely warn if the old pass accepts and new pass rejects.
400- // (Note this silently accepts code if new pass accepts.)
401- let mut on_fail = if on_fail. saw_failure {
402- OnFail :: error ( )
403- } else {
404- OnFail :: warn ( )
405- } ;
406- 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
410- }
411-
412- // returns the last token that was checked, for TokenTree::Sequence.
413- // return value is used by recursive calls.
414- fn check_matcher_old < ' a , I > ( cx : & mut ExtCtxt , matcher : I , follow : & Token , on_fail : & mut OnFail )
415- -> Option < ( Span , Token ) > where I : Iterator < Item =& ' a TokenTree > {
416- use print:: pprust:: token_to_string;
417- use std:: iter:: once;
418-
419- let mut last = None ;
420-
421- // 2. For each token T in M:
422- let mut tokens = matcher. peekable ( ) ;
423- while let Some ( token) = tokens. next ( ) {
424- last = match * token {
425- TokenTree :: Token ( sp, MatchNt ( ref name, ref frag_spec) ) => {
426- // ii. If T is a simple NT, look ahead to the next token T' in
427- // M. If T' is in the set FOLLOW(NT), continue. Else; reject.
428- if can_be_followed_by_any ( & frag_spec. name . as_str ( ) ) {
429- continue
430- } else {
431- let next_token = match tokens. peek ( ) {
432- // If T' closes a complex NT, replace T' with F
433- Some ( & & TokenTree :: Token ( _, CloseDelim ( _) ) ) => follow. clone ( ) ,
434- Some ( & & TokenTree :: Token ( _, ref tok) ) => tok. clone ( ) ,
435- Some ( & & TokenTree :: Sequence ( sp, _) ) => {
436- // Be conservative around sequences: to be
437- // more specific, we would need to
438- // consider FIRST sets, but also the
439- // possibility that the sequence occurred
440- // zero times (in which case we need to
441- // look at the token that follows the
442- // sequence, which may itself be a sequence,
443- // and so on).
444- on_fail. react ( cx, sp,
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 ) ;
450- Eof
451- } ,
452- // die next iteration
453- Some ( & & TokenTree :: Delimited ( _, ref delim) ) => delim. close_token ( ) ,
454- // else, we're at the end of the macro or sequence
455- None => follow. clone ( )
456- } ;
457-
458- let tok = if let TokenTree :: Token ( _, ref tok) = * token {
459- tok
460- } else {
461- unreachable ! ( )
462- } ;
463-
464- // If T' is in the set FOLLOW(NT), continue. Else, reject.
465- match ( & next_token, is_in_follow ( cx, & next_token, & frag_spec. name . as_str ( ) ) ) {
466- ( _, Err ( ( msg, _) ) ) => {
467- // no need for help message, those messages
468- // are never emitted anyway...
469- on_fail. react ( cx, sp, & msg, None ) ;
470- continue
471- }
472- ( & Eof , _) => return Some ( ( sp, tok. clone ( ) ) ) ,
473- ( _, Ok ( true ) ) => continue ,
474- ( next, Ok ( false ) ) => {
475- on_fail. react ( cx, sp, & format ! ( "`${0}:{1}` is followed by `{2}`, which \
476- is not allowed for `{1}` fragments",
477- name, frag_spec,
478- token_to_string( next) ) , None ) ;
479- continue
480- } ,
481- }
482- }
483- } ,
484- TokenTree :: Sequence ( sp, ref seq) => {
485- // iii. Else, T is a complex NT.
486- match seq. separator {
487- // If T has the form $(...)U+ or $(...)U* for some token U,
488- // run the algorithm on the contents with F set to U. If it
489- // accepts, continue, else, reject.
490- Some ( ref u) => {
491- let last = check_matcher_old ( cx, seq. tts . iter ( ) , u, on_fail) ;
492- match last {
493- // Since the delimiter isn't required after the last
494- // repetition, make sure that the *next* token is
495- // sane. This doesn't actually compute the FIRST of
496- // the rest of the matcher yet, it only considers
497- // single tokens and simple NTs. This is imprecise,
498- // but conservatively correct.
499- Some ( ( span, tok) ) => {
500- let fol = match tokens. peek ( ) {
501- Some ( & & TokenTree :: Token ( _, ref tok) ) => tok. clone ( ) ,
502- Some ( & & TokenTree :: Delimited ( _, ref delim) ) =>
503- delim. close_token ( ) ,
504- Some ( _) => {
505- on_fail. react ( cx, sp, "sequence repetition followed by \
506- another sequence repetition, which is not allowed",
507- None ) ;
508- Eof
509- } ,
510- None => Eof
511- } ;
512- check_matcher_old ( cx, once ( & TokenTree :: Token ( span, tok. clone ( ) ) ) ,
513- & fol, on_fail)
514- } ,
515- None => last,
516- }
517- } ,
518- // If T has the form $(...)+ or $(...)*, run the algorithm
519- // on the contents with F set to the token following the
520- // sequence. If it accepts, continue, else, reject.
521- None => {
522- let fol = match tokens. peek ( ) {
523- Some ( & & TokenTree :: Token ( _, ref tok) ) => tok. clone ( ) ,
524- Some ( & & TokenTree :: Delimited ( _, ref delim) ) => delim. close_token ( ) ,
525- Some ( _) => {
526- on_fail. react ( cx, sp, "sequence repetition followed by another \
527- sequence repetition, which is not allowed", None ) ;
528- Eof
529- } ,
530- None => Eof
531- } ;
532- check_matcher_old ( cx, seq. tts . iter ( ) , & fol, on_fail)
533- }
534- }
535- } ,
536- TokenTree :: Token ( ..) => {
537- // i. If T is not an NT, continue.
538- continue
539- } ,
540- TokenTree :: Delimited ( _, ref tts) => {
541- // if we don't pass in that close delimiter, we'll incorrectly consider the matcher
542- // `{ $foo:ty }` as having a follow that isn't `RBrace`
543- check_matcher_old ( cx, tts. tts . iter ( ) , & tts. close_token ( ) , on_fail)
544- }
545- }
546- }
547- last
548- }
549-
550- fn check_matcher_new ( cx : & mut ExtCtxt , matcher : & [ TokenTree ] , on_fail : & mut OnFail ) {
551358 let first_sets = FirstSets :: new ( matcher) ;
552359 let empty_suffix = TokenSet :: empty ( ) ;
553- check_matcher_core ( cx, & first_sets, matcher, & empty_suffix, on_fail) ;
360+ let err = cx. parse_sess . span_diagnostic . err_count ( ) ;
361+ check_matcher_core ( cx, & first_sets, matcher, & empty_suffix) ;
362+ err == cx. parse_sess . span_diagnostic . err_count ( )
554363}
555364
556365// The FirstSets for a matcher is a mapping from subsequences in the
@@ -790,8 +599,7 @@ impl TokenSet {
790599fn check_matcher_core ( cx : & mut ExtCtxt ,
791600 first_sets : & FirstSets ,
792601 matcher : & [ TokenTree ] ,
793- follow : & TokenSet ,
794- on_fail : & mut OnFail ) -> TokenSet {
602+ follow : & TokenSet ) -> TokenSet {
795603 use print:: pprust:: token_to_string;
796604
797605 let mut last = TokenSet :: empty ( ) ;
@@ -820,11 +628,11 @@ fn check_matcher_core(cx: &mut ExtCtxt,
820628 TokenTree :: Token ( sp, ref tok) => {
821629 let can_be_followed_by_any;
822630 if let Err ( bad_frag) = has_legal_fragment_specifier ( tok) {
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`" ) ) ;
631+ cx . struct_span_err ( sp , & format ! ( "invalid fragment specifier `{}`" , bad_frag ) )
632+ . help ( "valid fragment specifiers are `ident`, `block`, \
633+ `stmt`, `expr`, `pat`, `ty`, `path `, `meta`, `tt` \
634+ and `item`" )
635+ . emit ( ) ;
828636 // (This eliminates false positives and duplicates
829637 // from error messages.)
830638 can_be_followed_by_any = true ;
@@ -845,7 +653,7 @@ fn check_matcher_core(cx: &mut ExtCtxt,
845653 }
846654 TokenTree :: Delimited ( _, ref d) => {
847655 let my_suffix = TokenSet :: singleton ( ( d. close_span , Token :: CloseDelim ( d. delim ) ) ) ;
848- check_matcher_core ( cx, first_sets, & d. tts , & my_suffix, on_fail ) ;
656+ check_matcher_core ( cx, first_sets, & d. tts , & my_suffix) ;
849657 // don't track non NT tokens
850658 last. replace_with_irrelevant ( ) ;
851659
@@ -877,7 +685,7 @@ fn check_matcher_core(cx: &mut ExtCtxt,
877685 // At this point, `suffix_first` is built, and
878686 // `my_suffix` is some TokenSet that we can use
879687 // for checking the interior of `seq_rep`.
880- let next = check_matcher_core ( cx, first_sets, & seq_rep. tts , my_suffix, on_fail ) ;
688+ let next = check_matcher_core ( cx, first_sets, & seq_rep. tts , my_suffix) ;
881689 if next. maybe_empty {
882690 last. add_all ( & next) ;
883691 } else {
@@ -899,7 +707,7 @@ fn check_matcher_core(cx: &mut ExtCtxt,
899707 for & ( sp, ref next_token) in & suffix_first. tokens {
900708 match is_in_follow ( cx, next_token, & frag_spec. name . as_str ( ) ) {
901709 Err ( ( msg, help) ) => {
902- on_fail . react ( cx , sp, & msg, Some ( help) ) ;
710+ cx . struct_span_err ( sp, & msg) . help ( help) . emit ( ) ;
903711 // don't bother reporting every source of
904712 // conflict for a particular element of `last`.
905713 continue ' each_last;
@@ -914,15 +722,14 @@ fn check_matcher_core(cx: &mut ExtCtxt,
914722 "may be"
915723 } ;
916724
917- on_fail . react (
918- cx , sp,
725+ cx . span_err (
726+ sp,
919727 & format ! ( "`${name}:{frag}` {may_be} followed by `{next}`, which \
920728 is not allowed for `{frag}` fragments",
921729 name=name,
922730 frag=frag_spec,
923731 next=token_to_string( next_token) ,
924- may_be=may_be) ,
925- None
732+ may_be=may_be)
926733 ) ;
927734 }
928735 }
@@ -952,33 +759,11 @@ fn token_can_be_followed_by_any(tok: &Token) -> bool {
952759/// ANYTHING without fear of future compatibility hazards).
953760fn frag_can_be_followed_by_any ( frag : & str ) -> bool {
954761 match frag {
955- "item" | // always terminated by `}` or `;`
956- "block" | // exactly one token tree
957- "ident" | // exactly one token tree
958- "meta" | // exactly one token tree
959- "tt" => // exactly one token tree
960- true ,
961-
962- _ =>
963- false ,
964- }
965- }
966-
967- /// True if a fragment of type `frag` can be followed by any sort of
968- /// token. We use this (among other things) as a useful approximation
969- /// for when `frag` can be followed by a repetition like `$(...)*` or
970- /// `$(...)+`. In general, these can be a bit tricky to reason about,
971- /// so we adopt a conservative position that says that any fragment
972- /// specifier which consumes at most one token tree can be followed by
973- /// a fragment specifier (indeed, these fragments can be followed by
974- /// ANYTHING without fear of future compatibility hazards).
975- fn can_be_followed_by_any ( frag : & str ) -> bool {
976- match frag {
977- "item" | // always terminated by `}` or `;`
762+ "item" | // always terminated by `}` or `;`
978763 "block" | // exactly one token tree
979764 "ident" | // exactly one token tree
980- "meta" | // exactly one token tree
981- "tt" => // exactly one token tree
765+ "meta" | // exactly one token tree
766+ "tt" => // exactly one token tree
982767 true ,
983768
984769 _ =>
0 commit comments