diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/ast/rust-macro.h | 28 | ||||
-rw-r--r-- | gcc/rust/lex/rust-token.h | 1 | ||||
-rw-r--r-- | gcc/rust/parse/rust-parse.cc | 100 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/macro33.rs | 5 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/macro34.rs | 3 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/macro35.rs | 7 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/macro36.rs | 3 |
7 files changed, 120 insertions, 27 deletions
diff --git a/gcc/rust/ast/rust-macro.h b/gcc/rust/ast/rust-macro.h index 478d3ab..ab28d24 100644 --- a/gcc/rust/ast/rust-macro.h +++ b/gcc/rust/ast/rust-macro.h @@ -128,19 +128,29 @@ public: } } - bool has_follow_set_restrictions () + bool has_follow_set_restrictions () const { switch (kind) { case EXPR: case STMT: - // FIXME: Add the following cases once we can handle them properly - // in `is_match_compatible()` - // case PAT: - // // case PAT_PARAM: FIXME: Doesn't <metavar>:pat_param exist? - // case PATH: - // case TY: - // case VIS: + case PAT: + case PATH: + case TY: + case VIS: + return true; + default: + return false; + } + } + + bool has_follow_set_fragment_restrictions () const + { + switch (kind) + { + case PAT: + case TY: + case VIS: return true; default: return false; @@ -188,7 +198,7 @@ public: } Identifier get_ident () const { return ident; } - MacroFragSpec get_frag_spec () const { return frag_spec; } + const MacroFragSpec &get_frag_spec () const { return frag_spec; } protected: /* Use covariance to implement clone function as returning this object rather diff --git a/gcc/rust/lex/rust-token.h b/gcc/rust/lex/rust-token.h index 1306c51..bbc6d5d 100644 --- a/gcc/rust/lex/rust-token.h +++ b/gcc/rust/lex/rust-token.h @@ -165,6 +165,7 @@ enum PrimitiveCoreType RS_TOKEN_KEYWORD (CONST, "const") \ RS_TOKEN_KEYWORD (CONTINUE, "continue") \ RS_TOKEN_KEYWORD (CRATE, "crate") \ + /* FIXME: Do we need to add $crate (DOLLAR_CRATE) as a reserved kw? */ \ RS_TOKEN_KEYWORD (DO, "do") /* unused */ \ RS_TOKEN_KEYWORD (DYN, "dyn") \ RS_TOKEN_KEYWORD (ELSE, "else") \ 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; } diff --git a/gcc/testsuite/rust/compile/macro33.rs b/gcc/testsuite/rust/compile/macro33.rs new file mode 100644 index 0000000..2ccd33e --- /dev/null +++ b/gcc/testsuite/rust/compile/macro33.rs @@ -0,0 +1,5 @@ +macro_rules! forbidden_frag { + ($t:ty $not_block:ident) => {{}}; // { dg-error "fragment specifier .ident. is not allowed after .ty. fragments" } + // { dg-error "required first macro rule in macro rules definition could not be parsed" "" { target *-*-* } .-1 } + // { dg-error "failed to parse item in crate" "" { target *-*-* } .-2 } +} diff --git a/gcc/testsuite/rust/compile/macro34.rs b/gcc/testsuite/rust/compile/macro34.rs new file mode 100644 index 0000000..105d042 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro34.rs @@ -0,0 +1,3 @@ +macro_rules! allowed_after_expr_matcher { + (($t:expr) bok) => {{}}; // follow-set restrictions do not apply after a matcher, but they do apply inside the matcher +} diff --git a/gcc/testsuite/rust/compile/macro35.rs b/gcc/testsuite/rust/compile/macro35.rs new file mode 100644 index 0000000..a08bfd4 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro35.rs @@ -0,0 +1,7 @@ +macro_rules! inside_matcher { + (($e:expr tok) tok) => {{}}; // { dg-error "token .tok. is not allowed after .expr. fragment" } + // { dg-error "failed to parse macro matcher" "" { target *-*-* } .-1 } + // { dg-error "failed to parse macro match" "" { target *-*-* } .-2 } + // { dg-error "required first macro rule" "" { target *-*-* } .-3 } + // { dg-error "failed to parse item in crate" "" { target *-*-* } .-4 } +} diff --git a/gcc/testsuite/rust/compile/macro36.rs b/gcc/testsuite/rust/compile/macro36.rs new file mode 100644 index 0000000..e5d66b2 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro36.rs @@ -0,0 +1,3 @@ +macro_rules! ty_allowed { + ($t:ty $b:block) => {{}}; +} |