@@ -349,203 +349,12 @@ fn check_rhs(cx: &mut ExtCtxt, rhs: &TokenTree) -> bool {
349349 false
350350}
351351
352- // Issue 30450: when we are through a warning cycle, we can just error
353- // on all failure conditions and remove this struct and enum.
354-
355- #[ derive( Debug ) ]
356- struct OnFail {
357- saw_failure : bool ,
358- action : OnFailAction ,
359- }
360-
361- #[ derive( Copy , Clone , Debug , PartialEq ) ]
362- enum OnFailAction { Warn , Error , DoNothing }
363-
364- impl OnFail {
365- fn warn ( ) -> OnFail { OnFail { saw_failure : false , action : OnFailAction :: Warn } }
366- fn error ( ) -> OnFail { OnFail { saw_failure : false , action : OnFailAction :: Error } }
367- fn do_nothing ( ) -> OnFail { OnFail { saw_failure : false , action : OnFailAction :: DoNothing } }
368- fn react ( & mut self , cx : & mut ExtCtxt , sp : Span , msg : & str , help : Option < & str > ) {
369- match self . action {
370- OnFailAction :: DoNothing => { }
371- OnFailAction :: Error => {
372- let mut err = cx. struct_span_err ( sp, msg) ;
373- if let Some ( msg) = help { err. span_help ( sp, msg) ; }
374- err. emit ( ) ;
375- }
376- OnFailAction :: Warn => {
377- let mut warn = cx. struct_span_warn ( sp, msg) ;
378- if let Some ( msg) = help { warn. span_help ( sp, msg) ; }
379- warn. span_note ( sp, "The above warning will be a hard error in the next release." )
380- . emit ( ) ;
381- }
382- } ;
383- self . saw_failure = true ;
384- }
385- }
386-
387352fn check_matcher ( cx : & mut ExtCtxt , matcher : & [ TokenTree ] ) -> bool {
388- // Issue 30450: when we are through a warning cycle, we can just
389- // error on all failure conditions (and remove check_matcher_old).
390-
391- // First run the old-pass, but *only* to find out if it would have failed.
392- let mut on_fail = OnFail :: do_nothing ( ) ;
393- check_matcher_old ( cx, matcher. iter ( ) , & Eof , & mut on_fail) ;
394- // Then run the new pass, but merely warn if the old pass accepts and new pass rejects.
395- // (Note this silently accepts code if new pass accepts.)
396- let mut on_fail = if on_fail. saw_failure {
397- OnFail :: error ( )
398- } else {
399- OnFail :: warn ( )
400- } ;
401- check_matcher_new ( cx, matcher, & mut on_fail) ;
402- // matcher is valid if the new pass didn't see any error,
403- // or if errors were considered warnings
404- on_fail. action != OnFailAction :: Error || !on_fail. saw_failure
405- }
406-
407- // returns the last token that was checked, for TokenTree::Sequence.
408- // return value is used by recursive calls.
409- fn check_matcher_old < ' a , I > ( cx : & mut ExtCtxt , matcher : I , follow : & Token , on_fail : & mut OnFail )
410- -> Option < ( Span , Token ) > where I : Iterator < Item =& ' a TokenTree > {
411- use print:: pprust:: token_to_string;
412- use std:: iter:: once;
413-
414- let mut last = None ;
415-
416- // 2. For each token T in M:
417- let mut tokens = matcher. peekable ( ) ;
418- while let Some ( token) = tokens. next ( ) {
419- last = match * token {
420- TokenTree :: Token ( sp, MatchNt ( ref name, ref frag_spec) ) => {
421- // ii. If T is a simple NT, look ahead to the next token T' in
422- // M. If T' is in the set FOLLOW(NT), continue. Else; reject.
423- if can_be_followed_by_any ( & frag_spec. name . as_str ( ) ) {
424- continue
425- } else {
426- let next_token = match tokens. peek ( ) {
427- // If T' closes a complex NT, replace T' with F
428- Some ( & & TokenTree :: Token ( _, CloseDelim ( _) ) ) => follow. clone ( ) ,
429- Some ( & & TokenTree :: Token ( _, ref tok) ) => tok. clone ( ) ,
430- Some ( & & TokenTree :: Sequence ( sp, _) ) => {
431- // Be conservative around sequences: to be
432- // more specific, we would need to
433- // consider FIRST sets, but also the
434- // possibility that the sequence occurred
435- // zero times (in which case we need to
436- // look at the token that follows the
437- // sequence, which may itself be a sequence,
438- // and so on).
439- on_fail. react ( cx, sp,
440- & format ! ( "`${0}:{1}` is followed by a \
441- sequence repetition, which is not \
442- allowed for `{1}` fragments",
443- name, frag_spec) ,
444- None ) ;
445- Eof
446- } ,
447- // die next iteration
448- Some ( & & TokenTree :: Delimited ( _, ref delim) ) => delim. close_token ( ) ,
449- // else, we're at the end of the macro or sequence
450- None => follow. clone ( )
451- } ;
452-
453- let tok = if let TokenTree :: Token ( _, ref tok) = * token {
454- tok
455- } else {
456- unreachable ! ( )
457- } ;
458-
459- // If T' is in the set FOLLOW(NT), continue. Else, reject.
460- match ( & next_token, is_in_follow ( cx, & next_token, & frag_spec. name . as_str ( ) ) ) {
461- ( _, Err ( ( msg, _) ) ) => {
462- // no need for help message, those messages
463- // are never emitted anyway...
464- on_fail. react ( cx, sp, & msg, None ) ;
465- continue
466- }
467- ( & Eof , _) => return Some ( ( sp, tok. clone ( ) ) ) ,
468- ( _, Ok ( true ) ) => continue ,
469- ( next, Ok ( false ) ) => {
470- on_fail. react ( cx, sp, & format ! ( "`${0}:{1}` is followed by `{2}`, which \
471- is not allowed for `{1}` fragments",
472- name, frag_spec,
473- token_to_string( next) ) , None ) ;
474- continue
475- } ,
476- }
477- }
478- } ,
479- TokenTree :: Sequence ( sp, ref seq) => {
480- // iii. Else, T is a complex NT.
481- match seq. separator {
482- // If T has the form $(...)U+ or $(...)U* for some token U,
483- // run the algorithm on the contents with F set to U. If it
484- // accepts, continue, else, reject.
485- Some ( ref u) => {
486- let last = check_matcher_old ( cx, seq. tts . iter ( ) , u, on_fail) ;
487- match last {
488- // Since the delimiter isn't required after the last
489- // repetition, make sure that the *next* token is
490- // sane. This doesn't actually compute the FIRST of
491- // the rest of the matcher yet, it only considers
492- // single tokens and simple NTs. This is imprecise,
493- // but conservatively correct.
494- Some ( ( span, tok) ) => {
495- let fol = match tokens. peek ( ) {
496- Some ( & & TokenTree :: Token ( _, ref tok) ) => tok. clone ( ) ,
497- Some ( & & TokenTree :: Delimited ( _, ref delim) ) =>
498- delim. close_token ( ) ,
499- Some ( _) => {
500- on_fail. react ( cx, sp, "sequence repetition followed by \
501- another sequence repetition, which is not allowed",
502- None ) ;
503- Eof
504- } ,
505- None => Eof
506- } ;
507- check_matcher_old ( cx, once ( & TokenTree :: Token ( span, tok. clone ( ) ) ) ,
508- & fol, on_fail)
509- } ,
510- None => last,
511- }
512- } ,
513- // If T has the form $(...)+ or $(...)*, run the algorithm
514- // on the contents with F set to the token following the
515- // sequence. If it accepts, continue, else, reject.
516- None => {
517- let fol = match tokens. peek ( ) {
518- Some ( & & TokenTree :: Token ( _, ref tok) ) => tok. clone ( ) ,
519- Some ( & & TokenTree :: Delimited ( _, ref delim) ) => delim. close_token ( ) ,
520- Some ( _) => {
521- on_fail. react ( cx, sp, "sequence repetition followed by another \
522- sequence repetition, which is not allowed", None ) ;
523- Eof
524- } ,
525- None => Eof
526- } ;
527- check_matcher_old ( cx, seq. tts . iter ( ) , & fol, on_fail)
528- }
529- }
530- } ,
531- TokenTree :: Token ( ..) => {
532- // i. If T is not an NT, continue.
533- continue
534- } ,
535- TokenTree :: Delimited ( _, ref tts) => {
536- // if we don't pass in that close delimiter, we'll incorrectly consider the matcher
537- // `{ $foo:ty }` as having a follow that isn't `RBrace`
538- check_matcher_old ( cx, tts. tts . iter ( ) , & tts. close_token ( ) , on_fail)
539- }
540- }
541- }
542- last
543- }
544-
545- fn check_matcher_new ( cx : & mut ExtCtxt , matcher : & [ TokenTree ] , on_fail : & mut OnFail ) {
546353 let first_sets = FirstSets :: new ( matcher) ;
547354 let empty_suffix = TokenSet :: empty ( ) ;
548- check_matcher_core ( cx, & first_sets, matcher, & empty_suffix, on_fail) ;
355+ let err = cx. parse_sess . span_diagnostic . err_count ( ) ;
356+ check_matcher_core ( cx, & first_sets, matcher, & empty_suffix) ;
357+ err == cx. parse_sess . span_diagnostic . err_count ( )
549358}
550359
551360// The FirstSets for a matcher is a mapping from subsequences in the
@@ -785,8 +594,7 @@ impl TokenSet {
785594fn check_matcher_core ( cx : & mut ExtCtxt ,
786595 first_sets : & FirstSets ,
787596 matcher : & [ TokenTree ] ,
788- follow : & TokenSet ,
789- on_fail : & mut OnFail ) -> TokenSet {
597+ follow : & TokenSet ) -> TokenSet {
790598 use print:: pprust:: token_to_string;
791599
792600 let mut last = TokenSet :: empty ( ) ;
@@ -815,11 +623,11 @@ fn check_matcher_core(cx: &mut ExtCtxt,
815623 TokenTree :: Token ( sp, ref tok) => {
816624 let can_be_followed_by_any;
817625 if let Err ( bad_frag) = has_legal_fragment_specifier ( tok) {
818- on_fail . react ( cx , sp ,
819- & format ! ( "invalid fragment specifier `{}`" , bad_frag ) ,
820- Some ( "valid fragment specifiers are `ident `, `block`, \
821- `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \
822- and `item`" ) ) ;
626+ cx . struct_span_err ( sp , & format ! ( "invalid fragment specifier `{}`" , bad_frag ) )
627+ . help ( "valid fragment specifiers are `ident`, `block`, \
628+ `stmt`, `expr`, `pat`, `ty`, `path `, `meta`, `tt` \
629+ and `item`" )
630+ . emit ( ) ;
823631 // (This eliminates false positives and duplicates
824632 // from error messages.)
825633 can_be_followed_by_any = true ;
@@ -840,7 +648,7 @@ fn check_matcher_core(cx: &mut ExtCtxt,
840648 }
841649 TokenTree :: Delimited ( _, ref d) => {
842650 let my_suffix = TokenSet :: singleton ( ( d. close_span , Token :: CloseDelim ( d. delim ) ) ) ;
843- check_matcher_core ( cx, first_sets, & d. tts , & my_suffix, on_fail ) ;
651+ check_matcher_core ( cx, first_sets, & d. tts , & my_suffix) ;
844652 // don't track non NT tokens
845653 last. replace_with_irrelevant ( ) ;
846654
@@ -872,7 +680,7 @@ fn check_matcher_core(cx: &mut ExtCtxt,
872680 // At this point, `suffix_first` is built, and
873681 // `my_suffix` is some TokenSet that we can use
874682 // for checking the interior of `seq_rep`.
875- let next = check_matcher_core ( cx, first_sets, & seq_rep. tts , my_suffix, on_fail ) ;
683+ let next = check_matcher_core ( cx, first_sets, & seq_rep. tts , my_suffix) ;
876684 if next. maybe_empty {
877685 last. add_all ( & next) ;
878686 } else {
@@ -894,7 +702,7 @@ fn check_matcher_core(cx: &mut ExtCtxt,
894702 for & ( sp, ref next_token) in & suffix_first. tokens {
895703 match is_in_follow ( cx, next_token, & frag_spec. name . as_str ( ) ) {
896704 Err ( ( msg, help) ) => {
897- on_fail . react ( cx , sp, & msg, Some ( help) ) ;
705+ cx . struct_span_err ( sp, & msg) . help ( help) . emit ( ) ;
898706 // don't bother reporting every source of
899707 // conflict for a particular element of `last`.
900708 continue ' each_last;
@@ -909,15 +717,14 @@ fn check_matcher_core(cx: &mut ExtCtxt,
909717 "may be"
910718 } ;
911719
912- on_fail . react (
913- cx , sp,
720+ cx . span_err (
721+ sp,
914722 & format ! ( "`${name}:{frag}` {may_be} followed by `{next}`, which \
915723 is not allowed for `{frag}` fragments",
916724 name=name,
917725 frag=frag_spec,
918726 next=token_to_string( next_token) ,
919- may_be=may_be) ,
920- None
727+ may_be=may_be)
921728 ) ;
922729 }
923730 }
@@ -947,33 +754,11 @@ fn token_can_be_followed_by_any(tok: &Token) -> bool {
947754/// ANYTHING without fear of future compatibility hazards).
948755fn frag_can_be_followed_by_any ( frag : & str ) -> bool {
949756 match frag {
950- "item" | // always terminated by `}` or `;`
951- "block" | // exactly one token tree
952- "ident" | // exactly one token tree
953- "meta" | // exactly one token tree
954- "tt" => // exactly one token tree
955- true ,
956-
957- _ =>
958- false ,
959- }
960- }
961-
962- /// True if a fragment of type `frag` can be followed by any sort of
963- /// token. We use this (among other things) as a useful approximation
964- /// for when `frag` can be followed by a repetition like `$(...)*` or
965- /// `$(...)+`. In general, these can be a bit tricky to reason about,
966- /// so we adopt a conservative position that says that any fragment
967- /// specifier which consumes at most one token tree can be followed by
968- /// a fragment specifier (indeed, these fragments can be followed by
969- /// ANYTHING without fear of future compatibility hazards).
970- fn can_be_followed_by_any ( frag : & str ) -> bool {
971- match frag {
972- "item" | // always terminated by `}` or `;`
757+ "item" | // always terminated by `}` or `;`
973758 "block" | // exactly one token tree
974759 "ident" | // exactly one token tree
975- "meta" | // exactly one token tree
976- "tt" => // exactly one token tree
760+ "meta" | // exactly one token tree
761+ "tt" => // exactly one token tree
977762 true ,
978763
979764 _ =>
0 commit comments