diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-03-24 09:34:19 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-24 09:34:19 +0000 |
commit | ff5f3005d0e0c9771e042fc45c8f12fc1ae5a373 (patch) | |
tree | 42538b9379105f303a23f649a1f95f03377b7cca /gcc/rust/parse/rust-parse.cc | |
parent | 90f938c2ecefbf16b4793a4135531ed5394a52ac (diff) | |
parent | 6821a642ab796aba5024032e3ace118a5e8277e1 (diff) | |
download | gcc-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.cc | 100 |
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; } |