Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 7fdffe1

Browse files
committedAug 2, 2020
Use NonterminalKind for MetaVarDecl
This is more type safe and allows us to remove a few dead branches
1 parent 2595d75 commit 7fdffe1

File tree

5 files changed

+95
-134
lines changed

5 files changed

+95
-134
lines changed
 

‎src/librustc_ast/token.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -760,7 +760,7 @@ pub enum Nonterminal {
760760
#[cfg(target_arch = "x86_64")]
761761
rustc_data_structures::static_assert_size!(Nonterminal, 40);
762762

763-
#[derive(Copy, Clone)]
763+
#[derive(Debug, Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
764764
pub enum NonterminalKind {
765765
Item,
766766
Block,
@@ -796,6 +796,29 @@ impl NonterminalKind {
796796
_ => return None,
797797
})
798798
}
799+
fn symbol(self) -> Symbol {
800+
match self {
801+
NonterminalKind::Item => sym::item,
802+
NonterminalKind::Block => sym::block,
803+
NonterminalKind::Stmt => sym::stmt,
804+
NonterminalKind::Pat => sym::pat,
805+
NonterminalKind::Expr => sym::expr,
806+
NonterminalKind::Ty => sym::ty,
807+
NonterminalKind::Ident => sym::ident,
808+
NonterminalKind::Lifetime => sym::lifetime,
809+
NonterminalKind::Literal => sym::literal,
810+
NonterminalKind::Meta => sym::meta,
811+
NonterminalKind::Path => sym::path,
812+
NonterminalKind::Vis => sym::vis,
813+
NonterminalKind::TT => sym::tt,
814+
}
815+
}
816+
}
817+
818+
impl fmt::Display for NonterminalKind {
819+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
820+
write!(f, "{}", self.symbol())
821+
}
799822
}
800823

801824
impl Nonterminal {

‎src/librustc_expand/mbe.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ crate mod macro_rules;
99
crate mod quoted;
1010
crate mod transcribe;
1111

12-
use rustc_ast::token::{self, Token, TokenKind};
12+
use rustc_ast::token::{self, NonterminalKind, Token, TokenKind};
1313
use rustc_ast::tokenstream::DelimSpan;
1414

1515
use rustc_span::symbol::Ident;
@@ -84,7 +84,7 @@ enum TokenTree {
8484
/// e.g., `$var`
8585
MetaVar(Span, Ident),
8686
/// e.g., `$var:expr`. This is only used in the left hand side of MBE macros.
87-
MetaVarDecl(Span, Ident /* name to bind */, Ident /* kind of nonterminal */),
87+
MetaVarDecl(Span, Ident /* name to bind */, Option<NonterminalKind>),
8888
}
8989

9090
impl TokenTree {

‎src/librustc_expand/mbe/macro_parser.rs

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,10 @@ use TokenTreeOrTokenTreeSlice::*;
7676

7777
use crate::mbe::{self, TokenTree};
7878

79-
use rustc_ast::token::{self, DocComment, Nonterminal, NonterminalKind, Token};
79+
use rustc_ast::token::{self, DocComment, Nonterminal, Token};
8080
use rustc_parse::parser::Parser;
8181
use rustc_session::parse::ParseSess;
82-
use rustc_span::symbol::{kw, MacroRulesNormalizedIdent};
82+
use rustc_span::symbol::MacroRulesNormalizedIdent;
8383

8484
use smallvec::{smallvec, SmallVec};
8585

@@ -378,7 +378,7 @@ fn nameize<I: Iterator<Item = NamedMatch>>(
378378
n_rec(sess, next_m, res.by_ref(), ret_val)?;
379379
}
380380
}
381-
TokenTree::MetaVarDecl(span, _, id) if id.name == kw::Invalid => {
381+
TokenTree::MetaVarDecl(span, _, None) => {
382382
if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() {
383383
return Err((span, "missing fragment specifier".to_string()));
384384
}
@@ -561,18 +561,17 @@ fn inner_parse_loop<'root, 'tt>(
561561
}
562562

563563
// We need to match a metavar (but the identifier is invalid)... this is an error
564-
TokenTree::MetaVarDecl(span, _, id) if id.name == kw::Invalid => {
564+
TokenTree::MetaVarDecl(span, _, None) => {
565565
if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() {
566566
return Error(span, "missing fragment specifier".to_string());
567567
}
568568
}
569569

570570
// We need to match a metavar with a valid ident... call out to the black-box
571571
// parser by adding an item to `bb_items`.
572-
TokenTree::MetaVarDecl(_, _, id) => {
572+
TokenTree::MetaVarDecl(_, _, Some(kind)) => {
573573
// Built-in nonterminals never start with these tokens,
574574
// so we can eliminate them from consideration.
575-
let kind = NonterminalKind::from_symbol(id.name).unwrap();
576575
if Parser::nonterminal_may_begin_with(kind, token) {
577576
bb_items.push(item);
578577
}
@@ -703,7 +702,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na
703702
let nts = bb_items
704703
.iter()
705704
.map(|item| match item.top_elts.get_tt(item.idx) {
706-
TokenTree::MetaVarDecl(_, bind, name) => format!("{} ('{}')", name, bind),
705+
TokenTree::MetaVarDecl(_, bind, Some(kind)) => format!("{} ('{}')", kind, bind),
707706
_ => panic!(),
708707
})
709708
.collect::<Vec<String>>()
@@ -733,17 +732,13 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na
733732
assert_eq!(bb_items.len(), 1);
734733

735734
let mut item = bb_items.pop().unwrap();
736-
if let TokenTree::MetaVarDecl(span, _, ident) = item.top_elts.get_tt(item.idx) {
735+
if let TokenTree::MetaVarDecl(span, _, Some(kind)) = item.top_elts.get_tt(item.idx) {
737736
let match_cur = item.match_cur;
738-
let kind = NonterminalKind::from_symbol(ident.name).unwrap();
739737
let nt = match parser.to_mut().parse_nonterminal(kind) {
740738
Err(mut err) => {
741739
err.span_label(
742740
span,
743-
format!(
744-
"while parsing argument for this `{}` macro fragment",
745-
ident.name
746-
),
741+
format!("while parsing argument for this `{}` macro fragment", kind),
747742
)
748743
.emit();
749744
return ErrorReported;

‎src/librustc_expand/mbe/macro_rules.rs

Lines changed: 42 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,14 @@ use rustc_parse::parser::Parser;
2121
use rustc_session::parse::ParseSess;
2222
use rustc_span::edition::Edition;
2323
use rustc_span::hygiene::Transparency;
24-
use rustc_span::symbol::{kw, sym, Ident, MacroRulesNormalizedIdent, Symbol};
24+
use rustc_span::symbol::{kw, sym, Ident, MacroRulesNormalizedIdent};
2525
use rustc_span::Span;
2626

2727
use log::debug;
2828
use std::borrow::Cow;
2929
use std::collections::hash_map::Entry;
3030
use std::{mem, slice};
3131

32-
const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
33-
`ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \
34-
`literal`, `path`, `meta`, `tt`, `item` and `vis`";
35-
3632
crate struct ParserAnyMacro<'a> {
3733
parser: Parser<'a>,
3834

@@ -403,7 +399,7 @@ pub fn compile_declarative_macro(
403399
let diag = &sess.span_diagnostic;
404400
let lhs_nm = Ident::new(sym::lhs, def.span);
405401
let rhs_nm = Ident::new(sym::rhs, def.span);
406-
let tt_spec = Ident::new(sym::tt, def.span);
402+
let tt_spec = Some(NonterminalKind::TT);
407403

408404
// Parse the macro_rules! invocation
409405
let (macro_rules, body) = match &def.kind {
@@ -571,7 +567,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
571567
TokenTree::Sequence(span, ref seq) => {
572568
if seq.separator.is_none()
573569
&& seq.tts.iter().all(|seq_tt| match *seq_tt {
574-
TokenTree::MetaVarDecl(_, _, id) => id.name == sym::vis,
570+
TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => true,
575571
TokenTree::Sequence(_, ref sub_seq) => {
576572
sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore
577573
|| sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne
@@ -890,21 +886,7 @@ fn check_matcher_core(
890886
// of NT tokens that might end the sequence `... token`.
891887
match *token {
892888
TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => {
893-
let can_be_followed_by_any;
894-
if let Err(bad_frag) = has_legal_fragment_specifier(sess, features, attrs, token) {
895-
let msg = format!("invalid fragment specifier `{}`", bad_frag);
896-
sess.span_diagnostic
897-
.struct_span_err(token.span(), &msg)
898-
.help(VALID_FRAGMENT_NAMES_MSG)
899-
.emit();
900-
// (This eliminates false positives and duplicates
901-
// from error messages.)
902-
can_be_followed_by_any = true;
903-
} else {
904-
can_be_followed_by_any = token_can_be_followed_by_any(token);
905-
}
906-
907-
if can_be_followed_by_any {
889+
if token_can_be_followed_by_any(token) {
908890
// don't need to track tokens that work with any,
909891
last.replace_with_irrelevant();
910892
// ... and don't need to check tokens that can be
@@ -967,19 +949,10 @@ fn check_matcher_core(
967949

968950
// Now `last` holds the complete set of NT tokens that could
969951
// end the sequence before SUFFIX. Check that every one works with `suffix`.
970-
'each_last: for token in &last.tokens {
971-
if let TokenTree::MetaVarDecl(_, name, frag_spec) = *token {
952+
for token in &last.tokens {
953+
if let TokenTree::MetaVarDecl(_, name, Some(kind)) = *token {
972954
for next_token in &suffix_first.tokens {
973-
match is_in_follow(next_token, frag_spec.name) {
974-
IsInFollow::Invalid(msg, help) => {
975-
sess.span_diagnostic
976-
.struct_span_err(next_token.span(), &msg)
977-
.help(help)
978-
.emit();
979-
// don't bother reporting every source of
980-
// conflict for a particular element of `last`.
981-
continue 'each_last;
982-
}
955+
match is_in_follow(next_token, kind) {
983956
IsInFollow::Yes => {}
984957
IsInFollow::No(possible) => {
985958
let may_be = if last.tokens.len() == 1 && suffix_first.tokens.len() == 1
@@ -996,22 +969,19 @@ fn check_matcher_core(
996969
"`${name}:{frag}` {may_be} followed by `{next}`, which \
997970
is not allowed for `{frag}` fragments",
998971
name = name,
999-
frag = frag_spec,
972+
frag = kind,
1000973
next = quoted_tt_to_string(next_token),
1001974
may_be = may_be
1002975
),
1003976
);
1004-
err.span_label(
1005-
sp,
1006-
format!("not allowed after `{}` fragments", frag_spec),
1007-
);
977+
err.span_label(sp, format!("not allowed after `{}` fragments", kind));
1008978
let msg = "allowed there are: ";
1009979
match possible {
1010980
&[] => {}
1011981
&[t] => {
1012982
err.note(&format!(
1013983
"only {} is allowed after `{}` fragments",
1014-
t, frag_spec,
984+
t, kind,
1015985
));
1016986
}
1017987
ts => {
@@ -1038,8 +1008,8 @@ fn check_matcher_core(
10381008
}
10391009

10401010
fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool {
1041-
if let mbe::TokenTree::MetaVarDecl(_, _, frag_spec) = *tok {
1042-
frag_can_be_followed_by_any(frag_spec.name)
1011+
if let mbe::TokenTree::MetaVarDecl(_, _, Some(kind)) = *tok {
1012+
frag_can_be_followed_by_any(kind)
10431013
} else {
10441014
// (Non NT's can always be followed by anything in matchers.)
10451015
true
@@ -1054,26 +1024,23 @@ fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool {
10541024
/// specifier which consumes at most one token tree can be followed by
10551025
/// a fragment specifier (indeed, these fragments can be followed by
10561026
/// ANYTHING without fear of future compatibility hazards).
1057-
fn frag_can_be_followed_by_any(frag: Symbol) -> bool {
1058-
match frag {
1059-
sym::item | // always terminated by `}` or `;`
1060-
sym::block | // exactly one token tree
1061-
sym::ident | // exactly one token tree
1062-
sym::literal | // exactly one token tree
1063-
sym::meta | // exactly one token tree
1064-
sym::lifetime | // exactly one token tree
1065-
sym::tt => // exactly one token tree
1066-
true,
1067-
1068-
_ =>
1069-
false,
1027+
fn frag_can_be_followed_by_any(kind: NonterminalKind) -> bool {
1028+
match kind {
1029+
NonterminalKind::Item // always terminated by `}` or `;`
1030+
| NonterminalKind::Block // exactly one token tree
1031+
| NonterminalKind::Ident // exactly one token tree
1032+
| NonterminalKind::Literal // exactly one token tree
1033+
| NonterminalKind::Meta // exactly one token tree
1034+
| NonterminalKind::Lifetime // exactly one token tree
1035+
| NonterminalKind::TT => true, // exactly one token tree
1036+
1037+
_ => false,
10701038
}
10711039
}
10721040

10731041
enum IsInFollow {
10741042
Yes,
10751043
No(&'static [&'static str]),
1076-
Invalid(String, &'static str),
10771044
}
10781045

10791046
/// Returns `true` if `frag` can legally be followed by the token `tok`. For
@@ -1084,26 +1051,26 @@ enum IsInFollow {
10841051
/// break macros that were relying on that binary operator as a
10851052
/// separator.
10861053
// when changing this do not forget to update doc/book/macros.md!
1087-
fn is_in_follow(tok: &mbe::TokenTree, frag: Symbol) -> IsInFollow {
1054+
fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
10881055
use mbe::TokenTree;
10891056

10901057
if let TokenTree::Token(Token { kind: token::CloseDelim(_), .. }) = *tok {
10911058
// closing a token tree can never be matched by any fragment;
10921059
// iow, we always require that `(` and `)` match, etc.
10931060
IsInFollow::Yes
10941061
} else {
1095-
match frag {
1096-
sym::item => {
1062+
match kind {
1063+
NonterminalKind::Item => {
10971064
// since items *must* be followed by either a `;` or a `}`, we can
10981065
// accept anything after them
10991066
IsInFollow::Yes
11001067
}
1101-
sym::block => {
1068+
NonterminalKind::Block => {
11021069
// anything can follow block, the braces provide an easy boundary to
11031070
// maintain
11041071
IsInFollow::Yes
11051072
}
1106-
sym::stmt | sym::expr => {
1073+
NonterminalKind::Stmt | NonterminalKind::Expr => {
11071074
const TOKENS: &[&str] = &["`=>`", "`,`", "`;`"];
11081075
match tok {
11091076
TokenTree::Token(token) => match token.kind {
@@ -1113,7 +1080,7 @@ fn is_in_follow(tok: &mbe::TokenTree, frag: Symbol) -> IsInFollow {
11131080
_ => IsInFollow::No(TOKENS),
11141081
}
11151082
}
1116-
sym::pat => {
1083+
NonterminalKind::Pat => {
11171084
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"];
11181085
match tok {
11191086
TokenTree::Token(token) => match token.kind {
@@ -1124,7 +1091,7 @@ fn is_in_follow(tok: &mbe::TokenTree, frag: Symbol) -> IsInFollow {
11241091
_ => IsInFollow::No(TOKENS),
11251092
}
11261093
}
1127-
sym::path | sym::ty => {
1094+
NonterminalKind::Path | NonterminalKind::Ty => {
11281095
const TOKENS: &[&str] = &[
11291096
"`{`", "`[`", "`=>`", "`,`", "`>`", "`=`", "`:`", "`;`", "`|`", "`as`",
11301097
"`where`",
@@ -1146,26 +1113,24 @@ fn is_in_follow(tok: &mbe::TokenTree, frag: Symbol) -> IsInFollow {
11461113
}
11471114
_ => IsInFollow::No(TOKENS),
11481115
},
1149-
TokenTree::MetaVarDecl(_, _, frag) if frag.name == sym::block => {
1150-
IsInFollow::Yes
1151-
}
1116+
TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Block)) => IsInFollow::Yes,
11521117
_ => IsInFollow::No(TOKENS),
11531118
}
11541119
}
1155-
sym::ident | sym::lifetime => {
1120+
NonterminalKind::Ident | NonterminalKind::Lifetime => {
11561121
// being a single token, idents and lifetimes are harmless
11571122
IsInFollow::Yes
11581123
}
1159-
sym::literal => {
1124+
NonterminalKind::Literal => {
11601125
// literals may be of a single token, or two tokens (negative numbers)
11611126
IsInFollow::Yes
11621127
}
1163-
sym::meta | sym::tt => {
1128+
NonterminalKind::Meta | NonterminalKind::TT => {
11641129
// being either a single token or a delimited sequence, tt is
11651130
// harmless
11661131
IsInFollow::Yes
11671132
}
1168-
sym::vis => {
1133+
NonterminalKind::Vis => {
11691134
// Explicitly disallow `priv`, on the off chance it comes back.
11701135
const TOKENS: &[&str] = &["`,`", "an ident", "a type"];
11711136
match tok {
@@ -1180,62 +1145,24 @@ fn is_in_follow(tok: &mbe::TokenTree, frag: Symbol) -> IsInFollow {
11801145
}
11811146
}
11821147
},
1183-
TokenTree::MetaVarDecl(_, _, frag)
1184-
if frag.name == sym::ident
1185-
|| frag.name == sym::ty
1186-
|| frag.name == sym::path =>
1187-
{
1188-
IsInFollow::Yes
1189-
}
1148+
TokenTree::MetaVarDecl(
1149+
_,
1150+
_,
1151+
Some(NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path),
1152+
) => IsInFollow::Yes,
11901153
_ => IsInFollow::No(TOKENS),
11911154
}
11921155
}
1193-
kw::Invalid => IsInFollow::Yes,
1194-
_ => IsInFollow::Invalid(
1195-
format!("invalid fragment specifier `{}`", frag),
1196-
VALID_FRAGMENT_NAMES_MSG,
1197-
),
11981156
}
11991157
}
12001158
}
12011159

1202-
fn has_legal_fragment_specifier(
1203-
sess: &ParseSess,
1204-
features: &Features,
1205-
attrs: &[ast::Attribute],
1206-
tok: &mbe::TokenTree,
1207-
) -> Result<(), String> {
1208-
debug!("has_legal_fragment_specifier({:?})", tok);
1209-
if let mbe::TokenTree::MetaVarDecl(_, _, ref frag_spec) = *tok {
1210-
let frag_span = tok.span();
1211-
if !is_legal_fragment_specifier(sess, features, attrs, frag_spec.name, frag_span) {
1212-
return Err(frag_spec.to_string());
1213-
}
1214-
}
1215-
Ok(())
1216-
}
1217-
1218-
fn is_legal_fragment_specifier(
1219-
_sess: &ParseSess,
1220-
_features: &Features,
1221-
_attrs: &[ast::Attribute],
1222-
frag_name: Symbol,
1223-
_frag_span: Span,
1224-
) -> bool {
1225-
/*
1226-
* If new fragment specifiers are invented in nightly, `_sess`,
1227-
* `_features`, `_attrs`, and `_frag_span` will be useful here
1228-
* for checking against feature gates. See past versions of
1229-
* this function.
1230-
*/
1231-
NonterminalKind::from_symbol(frag_name).is_some() || frag_name == kw::Invalid
1232-
}
1233-
12341160
fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
12351161
match *tt {
12361162
mbe::TokenTree::Token(ref token) => pprust::token_to_string(&token),
12371163
mbe::TokenTree::MetaVar(_, name) => format!("${}", name),
1238-
mbe::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind),
1164+
mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${}:{}", name, kind),
1165+
mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${}:", name),
12391166
_ => panic!(
12401167
"unexpected mbe::TokenTree::{{Sequence or Delimited}} \
12411168
in follow set checker"

‎src/librustc_expand/mbe/quoted.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ use rustc_span::Span;
1212

1313
use rustc_data_structures::sync::Lrc;
1414

15+
const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
16+
`ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \
17+
`literal`, `path`, `meta`, `tt`, `item` and `vis`";
18+
1519
/// Takes a `tokenstream::TokenStream` and returns a `Vec<self::TokenTree>`. Specifically, this
1620
/// takes a generic `TokenStream`, such as is used in the rest of the compiler, and returns a
1721
/// collection of `TokenTree` for use in parsing a macro.
@@ -55,9 +59,21 @@ pub(super) fn parse(
5559
Some(tokenstream::TokenTree::Token(Token { kind: token::Colon, span })) => {
5660
match trees.next() {
5761
Some(tokenstream::TokenTree::Token(token)) => match token.ident() {
58-
Some((kind, _)) => {
62+
Some((frag, _)) => {
5963
let span = token.span.with_lo(start_sp.lo());
60-
result.push(TokenTree::MetaVarDecl(span, ident, kind));
64+
let kind = token::NonterminalKind::from_symbol(frag.name)
65+
.unwrap_or_else(|| {
66+
let msg = format!(
67+
"invalid fragment specifier `{}`",
68+
frag.name
69+
);
70+
sess.span_diagnostic
71+
.struct_span_err(span, &msg)
72+
.help(VALID_FRAGMENT_NAMES_MSG)
73+
.emit();
74+
token::NonterminalKind::Ident
75+
});
76+
result.push(TokenTree::MetaVarDecl(span, ident, Some(kind)));
6177
continue;
6278
}
6379
_ => token.span,
@@ -71,7 +87,7 @@ pub(super) fn parse(
7187
// Macros loaded from other crates have dummy node ids.
7288
sess.missing_fragment_specifiers.borrow_mut().insert(span, node_id);
7389
}
74-
result.push(TokenTree::MetaVarDecl(span, ident, Ident::invalid()));
90+
result.push(TokenTree::MetaVarDecl(span, ident, None));
7591
}
7692

7793
// Not a metavar or no matchers allowed, so just return the tree

0 commit comments

Comments
 (0)
Please sign in to comment.