aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/parse/rust-parse.cc
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-03-24 09:34:19 +0000
committerGitHub <noreply@github.com>2022-03-24 09:34:19 +0000
commitff5f3005d0e0c9771e042fc45c8f12fc1ae5a373 (patch)
tree42538b9379105f303a23f649a1f95f03377b7cca /gcc/rust/parse/rust-parse.cc
parent90f938c2ecefbf16b4793a4135531ed5394a52ac (diff)
parent6821a642ab796aba5024032e3ace118a5e8277e1 (diff)
downloadgcc-ff5f3005d0e0c9771e042fc45c8f12fc1ae5a373.zip
gcc-ff5f3005d0e0c9771e042fc45c8f12fc1ae5a373.tar.gz
gcc-ff5f3005d0e0c9771e042fc45c8f12fc1ae5a373.tar.bz2
Merge #1051
1051: macros: Add remaining restrictions for follow-set restrictions r=CohenArthur a=CohenArthur Adds the remaining restrictions for follow-set ambiguities in macros. This means adding the remaining allowed tokens for all fragment specifiers with follow-up restrictions, as well as handling allowed fragment specifiers in certain cases. For example, :vis specifiers can sometimes be followed by fragments, if they have the :ident, :ty or :path specifier. Likewise for :path and :ty which can be followed by a :block. Finally, we also allow *any* fragment after a matcher: Since the matcher is delimiter by parentheses, brackets or curlies, anything is allowed afterwards. Some edge cases or allowed tokens that we cannot handle yet remain, for which FIXMEs exist. I'll open up corresponding issues. Addresses #947 Co-authored-by: Arthur Cohen <arthur.cohen@embecosm.com>
Diffstat (limited to 'gcc/rust/parse/rust-parse.cc')
-rw-r--r--gcc/rust/parse/rust-parse.cc100
1 files changed, 82 insertions, 18 deletions
diff --git a/gcc/rust/parse/rust-parse.cc b/gcc/rust/parse/rust-parse.cc
index 16ed4a0..57c5324 100644
--- a/gcc/rust/parse/rust-parse.cc
+++ b/gcc/rust/parse/rust-parse.cc
@@ -93,15 +93,83 @@ extract_module_path (const AST::AttrVec &inner_attrs,
return path;
}
+template <typename T>
+static bool
+contains (std::vector<T> &vec, T elm)
+{
+ return std::find (vec.begin (), vec.end (), elm) != vec.end ();
+}
+
+static bool
+peculiar_fragment_match_compatible_fragment (
+ const AST::MacroFragSpec &last_spec, const AST::MacroFragSpec &spec,
+ Location match_locus)
+{
+ static std::unordered_map<AST::MacroFragSpec::Kind,
+ std::vector<AST::MacroFragSpec::Kind>>
+ fragment_follow_set
+ = {{AST::MacroFragSpec::PATH, {AST::MacroFragSpec::BLOCK}},
+ {AST::MacroFragSpec::TY, {AST::MacroFragSpec::BLOCK}},
+ {AST::MacroFragSpec::VIS,
+ {AST::MacroFragSpec::IDENT, AST::MacroFragSpec::TY,
+ AST::MacroFragSpec::PATH}}};
+
+ auto is_valid
+ = contains (fragment_follow_set[last_spec.get_kind ()], spec.get_kind ());
+
+ if (!is_valid)
+ rust_error_at (
+ match_locus,
+ "fragment specifier %<%s%> is not allowed after %<%s%> fragments",
+ spec.as_string ().c_str (), last_spec.as_string ().c_str ());
+
+ return is_valid;
+}
+
static bool
peculiar_fragment_match_compatible (AST::MacroMatchFragment &last_match,
AST::MacroMatch &match)
{
static std::unordered_map<AST::MacroFragSpec::Kind, std::vector<TokenId>>
- follow_set = {
- {AST::MacroFragSpec::EXPR, {MATCH_ARROW, COMMA, SEMICOLON}},
- {AST::MacroFragSpec::STMT, {MATCH_ARROW, COMMA, SEMICOLON}},
- };
+ follow_set
+ = {{AST::MacroFragSpec::EXPR, {MATCH_ARROW, COMMA, SEMICOLON}},
+ {AST::MacroFragSpec::STMT, {MATCH_ARROW, COMMA, SEMICOLON}},
+ {AST::MacroFragSpec::PAT, {MATCH_ARROW, COMMA, EQUAL, PIPE, IF, IN}},
+ {AST::MacroFragSpec::PATH,
+ {MATCH_ARROW, COMMA, EQUAL, PIPE, SEMICOLON, COLON, RIGHT_ANGLE,
+ RIGHT_SHIFT, LEFT_SQUARE, LEFT_CURLY, AS, WHERE}},
+ {AST::MacroFragSpec::TY,
+ {MATCH_ARROW, COMMA, EQUAL, PIPE, SEMICOLON, COLON, RIGHT_ANGLE,
+ RIGHT_SHIFT, LEFT_SQUARE, LEFT_CURLY, AS, WHERE}},
+ {AST::MacroFragSpec::VIS,
+ {
+ COMMA,
+ IDENTIFIER /* FIXME: Other than `priv` */,
+ LEFT_PAREN,
+ LEFT_SQUARE,
+ EXCLAM,
+ ASTERISK,
+ AMP,
+ LOGICAL_AND,
+ QUESTION_MARK,
+ LIFETIME,
+ LEFT_ANGLE,
+ LEFT_SHIFT,
+ SUPER,
+ SELF,
+ SELF_ALIAS,
+ EXTERN_TOK,
+ CRATE,
+ UNDERSCORE,
+ FOR,
+ IMPL,
+ FN_TOK,
+ UNSAFE,
+ TYPEOF,
+ DYN
+ // FIXME: Add Non kw identifiers
+ // FIXME: Add $crate as valid
+ }}};
Location error_locus = match.get_match_locus ();
@@ -117,9 +185,7 @@ peculiar_fragment_match_compatible (AST::MacroMatchFragment &last_match,
auto tok = static_cast<AST::Token *> (&match);
auto &allowed_toks
= follow_set[last_match.get_frag_spec ().get_kind ()];
- auto is_valid = std::find (allowed_toks.begin (), allowed_toks.end (),
- tok->get_id ())
- != allowed_toks.end ();
+ auto is_valid = contains (allowed_toks, tok->get_id ());
if (!is_valid)
// FIXME: Add hint about allowed fragments
rust_error_at (tok->get_match_locus (),
@@ -143,10 +209,17 @@ peculiar_fragment_match_compatible (AST::MacroMatchFragment &last_match,
error_locus = matches.front ()->get_match_locus ();
break;
}
- default:
+ case AST::MacroMatch::Fragment: {
+ auto last_spec = last_match.get_frag_spec ();
+ auto fragment = static_cast<AST::MacroMatchFragment *> (&match);
+ if (last_spec.has_follow_set_fragment_restrictions ())
+ return peculiar_fragment_match_compatible_fragment (
+ last_spec, fragment->get_frag_spec (), match.get_match_locus ());
+ }
break;
}
+ // FIXME: Improve error message
rust_error_at (error_locus, "fragment not allowed after %<%s%> fragment",
last_match.get_frag_spec ().as_string ().c_str ());
@@ -213,16 +286,7 @@ is_match_compatible (AST::MacroMatch &last_match, AST::MacroMatch &match)
return true;
break;
}
- case AST::MacroMatch::Matcher: {
- // Likewise for another matcher
- auto matcher = static_cast<AST::MacroMatcher *> (&last_match);
- new_last = get_back_ptr (matcher->get_matches ());
- // If there are no matches in the matcher, then it can be followed by
- // anything
- if (!new_last)
- return true;
- break;
- }
+ case AST::MacroMatch::Matcher:
case AST::MacroMatch::Tok:
return true;
}