Skip to content

Commit 4dab8ae

Browse files
committed
Remove the old FOLLOW checking (aka check_matcher_old).
1 parent 298730e commit 4dab8ae

File tree

3 files changed

+29
-277
lines changed

3 files changed

+29
-277
lines changed

src/libsyntax/ext/tt/macro_rules.rs

+18-233
Original file line numberDiff line numberDiff line change
@@ -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-
392357
fn 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 {
790599
fn 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).
953760
fn 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
_ =>

src/test/compile-fail/issue-30715.rs

-33
This file was deleted.

0 commit comments

Comments
 (0)