Skip to content

Commit 371bf0e

Browse files
committedJun 8, 2016
Auto merge of #33982 - LeoTestard:remove-check-matcher-old, r=pnkfelix
Remove the old FOLLOW checking (aka `check_matcher_old`). It was supposed to be removed at the next release cycle but is still in the tree since like 6 months. Potential breaking change, since some cases (such as #25658) will change from a warning to an error. But the warning stating that it will be a hard error in the next release has been there for 6 months now. I think it's safe to break this code. ^_^
2 parents ec872dc + 4dab8ae commit 371bf0e

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
@@ -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-
387352
fn 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 {
785594
fn 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).
948755
fn 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
_ =>

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

-33
This file was deleted.

0 commit comments

Comments
 (0)