diff options
Diffstat (limited to 'gcc/cp/parser.c')
-rw-r--r-- | gcc/cp/parser.c | 145 |
1 files changed, 117 insertions, 28 deletions
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 68f1cfa..42f7052 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -808,6 +808,14 @@ make_location (location_t caret, location_t start, cp_lexer *lexer) return make_location (caret, start, t->location); } +/* Overload for make_location taking tokens instead of locations. */ + +static inline location_t +make_location (cp_token *caret, cp_token *start, cp_token *end) +{ + return make_location (caret->location, start->location, end->location); +} + /* nonzero if we are presently saving tokens. */ static inline int @@ -2233,6 +2241,8 @@ static bool cp_parser_using_declaration (cp_parser *, bool); static void cp_parser_using_directive (cp_parser *); +static void cp_parser_using_enum + (cp_parser *); static tree cp_parser_alias_declaration (cp_parser *); static void cp_parser_asm_definition @@ -13726,6 +13736,8 @@ cp_parser_block_declaration (cp_parser *parser, token2 = cp_lexer_peek_nth_token (parser->lexer, 2); if (token2->keyword == RID_NAMESPACE) cp_parser_using_directive (parser); + else if (token2->keyword == RID_ENUM) + cp_parser_using_enum (parser); /* If the second token after 'using' is '=', then we have an alias-declaration. */ else if (cxx_dialect >= cxx11 @@ -20010,6 +20022,31 @@ cp_parser_qualified_namespace_specifier (cp_parser* parser) return cp_parser_namespace_name (parser); } +/* Subroutine of cp_parser_using_declaration. */ + +static tree +finish_using_decl (tree qscope, tree identifier, bool typename_p = false) +{ + tree decl = NULL_TREE; + if (at_class_scope_p ()) + { + /* Create the USING_DECL. */ + decl = do_class_using_decl (qscope, identifier); + + if (check_for_bare_parameter_packs (decl)) + return error_mark_node; + + if (decl && typename_p) + USING_DECL_TYPENAME_P (decl) = 1; + + /* Add it to the list of members in this class. */ + finish_member_declaration (decl); + } + else + finish_nonmember_using_decl (qscope, identifier); + return decl; +} + /* Parse a using-declaration, or, if ACCESS_DECLARATION_P is true, an access declaration. @@ -20029,7 +20066,6 @@ cp_parser_using_declaration (cp_parser* parser, cp_token *token; bool typename_p = false; bool global_scope_p; - tree decl; tree identifier; tree qscope; int oldcount = errorcount; @@ -20088,9 +20124,6 @@ cp_parser_using_declaration (cp_parser* parser, /*is_declaration=*/true); if (!qscope) qscope = global_namespace; - else if (UNSCOPED_ENUM_P (qscope) - && !TYPE_FUNCTION_SCOPE_P (qscope)) - qscope = CP_TYPE_CONTEXT (qscope); cp_warn_deprecated_use_scopes (qscope); @@ -20138,25 +20171,13 @@ cp_parser_using_declaration (cp_parser* parser, "a template-id may not appear in a using-declaration"); else { - if (at_class_scope_p ()) - { - /* Create the USING_DECL. */ - decl = do_class_using_decl (qscope, identifier); - - if (decl && typename_p) - USING_DECL_TYPENAME_P (decl) = 1; + tree decl = finish_using_decl (qscope, identifier, typename_p); - if (check_for_bare_parameter_packs (decl)) - { - cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); - return false; - } - else - /* Add it to the list of members in this class. */ - finish_member_declaration (decl); + if (decl == error_mark_node) + { + cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); + return false; } - else - finish_nonmember_using_decl (qscope, identifier); } if (!access_declaration_p @@ -20182,6 +20203,76 @@ cp_parser_using_declaration (cp_parser* parser, return true; } +/* C++20 using enum declaration. + + using-enum-declaration : + using elaborated-enum-specifier ; */ + +static void +cp_parser_using_enum (cp_parser *parser) +{ + cp_parser_require_keyword (parser, RID_USING, RT_USING); + + /* Using cp_parser_elaborated_type_specifier rejects typedef-names, which + breaks one of the motivating examples in using-enum-5.C. + cp_parser_simple_type_specifier seems to be closer to what we actually + want, though that hasn't been properly specified yet. */ + + /* Consume 'enum'. */ + gcc_checking_assert (cp_lexer_next_token_is_keyword (parser->lexer, RID_ENUM)); + cp_lexer_consume_token (parser->lexer); + + cp_token *start = cp_lexer_peek_token (parser->lexer); + + tree type = (cp_parser_simple_type_specifier + (parser, NULL, CP_PARSER_FLAGS_TYPENAME_OPTIONAL)); + + cp_token *end = cp_lexer_previous_token (parser->lexer); + + if (type == error_mark_node + || !cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) + { + cp_parser_skip_to_end_of_block_or_statement (parser); + return; + } + if (TREE_CODE (type) == TYPE_DECL) + type = TREE_TYPE (type); + + /* The elaborated-enum-specifier shall not name a dependent type and the type + shall have a reachable enum-specifier. */ + const char *msg = nullptr; + if (cxx_dialect < cxx20) + msg = _("%<using enum%> " + "only available with %<-std=c++20%> or %<-std=gnu++20%>"); + else if (dependent_type_p (type)) + msg = _("%<using enum%> of dependent type %qT"); + else if (TREE_CODE (type) != ENUMERAL_TYPE) + msg = _("%<using enum%> of non-enumeration type %q#T"); + else if (!COMPLETE_TYPE_P (type)) + msg = _("%<using enum%> of incomplete type %qT"); + else if (OPAQUE_ENUM_P (type)) + msg = _("%<using enum%> of %qT before its enum-specifier"); + if (msg) + { + location_t loc = make_location (start, start, end); + auto_diagnostic_group g; + error_at (loc, msg, type); + loc = location_of (type); + if (cxx_dialect < cxx20 || loc == input_location) + ; + else if (OPAQUE_ENUM_P (type)) + inform (loc, "opaque-enum-declaration here"); + else + inform (loc, "declared here"); + } + + /* A using-enum-declaration introduces the enumerator names of the named + enumeration as if by a using-declaration for each enumerator. */ + if (TREE_CODE (type) == ENUMERAL_TYPE) + for (tree v = TYPE_VALUES (type); v; v = TREE_CHAIN (v)) + finish_using_decl (type, DECL_NAME (TREE_VALUE (v))); +} + /* Parse an alias-declaration. alias-declaration: @@ -25279,12 +25370,10 @@ cp_parser_member_declaration (cp_parser* parser) if (cp_lexer_next_token_is_keyword (parser->lexer, RID_USING)) { if (cxx_dialect < cxx11) - { - /* Parse the using-declaration. */ - cp_parser_using_declaration (parser, - /*access_declaration_p=*/false); - return; - } + /* Parse the using-declaration. */ + cp_parser_using_declaration (parser, /*access_declaration_p=*/false); + else if (cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_ENUM)) + cp_parser_using_enum (parser); else { tree decl; @@ -25305,8 +25394,8 @@ cp_parser_member_declaration (cp_parser* parser) else cp_parser_using_declaration (parser, /*access_declaration_p=*/false); - return; } + return; } /* Check for @defs. */ |