Bootstrapped and tested on x86_64-pc-linux-gnu. I don't understand why we give the scoped enum pedantic error in parse/enum5.C, so maybe we can remove that pedwarn? I don't see why it would be helpful when parsing an enum-base...
See https://gcc.gnu.org/pipermail/gcc-patches/2026-February/708061.html for v1. -- 8< -- Previously, we did not parse definitely in cp_parser_enum_specifier after seeing CPP_COLON, since we allowed for bitfield widths to follow "enum identifier :" in member-declarations. However, ISO says that in such a situation, the colon should be parsed as an enum-base ([dcl.enum]/a), which means bitfield widths are not allowed. This patch reverts the changes which allowed for bitfield widths, since parsing definitely improves diagnostics for errant underlying types. PR c++/118374 gcc/cp/ChangeLog: * parser.cc (cp_parser_enum_specifier): Parse definitely before cp_parser_type_specifier_seq. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/enum1.C: Update test. * g++.dg/parse/enum5.C: Expect error with bitfield width and enum-key in member. * g++.dg/cpp0x/enum45.C: New test. --- gcc/cp/parser.cc | 24 +++++++++++++----------- gcc/testsuite/g++.dg/cpp0x/enum1.C | 2 +- gcc/testsuite/g++.dg/cpp0x/enum45.C | 4 ++++ gcc/testsuite/g++.dg/parse/enum5.C | 2 +- 4 files changed, 19 insertions(+), 13 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/enum45.C diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 0f53ff90215..f550ead1fb4 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -23838,26 +23838,18 @@ cp_parser_enum_specifier (cp_parser* parser) pop_deferring_access_checks (); /* Check for the `:' that denotes a specified underlying type in C++0x. - Note that a ':' could also indicate a bitfield width, however. */ + [dcl.enum]/1 says that a `:' following an enum-key is parsed as part + of an enum-base, so we can expect a type-specifier-seq rather than a + bitfield width. */ location_t colon_loc = UNKNOWN_LOCATION; if (cp_lexer_next_token_is (parser->lexer, CPP_COLON)) { cp_decl_specifier_seq type_specifiers; - /* Consume the `:'. */ - colon_loc = cp_lexer_peek_token (parser->lexer)->location; - cp_lexer_consume_token (parser->lexer); - auto tdf = make_temp_override (parser->type_definition_forbidden_message, G_("types may not be defined in enum-base")); - /* Parse the type-specifier-seq. */ - cp_parser_type_specifier_seq (parser, CP_PARSER_FLAGS_NONE, - /*is_declaration=*/false, - /*is_trailing_return=*/false, - &type_specifiers); - /* At this point this is surely not elaborated type specifier. */ if (!cp_parser_parse_definitely (parser)) return NULL_TREE; @@ -23865,8 +23857,18 @@ cp_parser_enum_specifier (cp_parser* parser) if (cxx_dialect < cxx11) maybe_warn_cpp0x (CPP0X_SCOPED_ENUMS); + /* Consume the `:'. */ + colon_loc = cp_lexer_peek_token (parser->lexer)->location; + cp_lexer_consume_token (parser->lexer); + has_underlying_type = true; + /* Parse the type-specifier-seq. */ + cp_parser_type_specifier_seq (parser, CP_PARSER_FLAGS_NONE, + /*is_declaration=*/false, + /*is_trailing_return=*/false, + &type_specifiers); + /* If that didn't work, stop. */ if (type_specifiers.type != error_mark_node) { diff --git a/gcc/testsuite/g++.dg/cpp0x/enum1.C b/gcc/testsuite/g++.dg/cpp0x/enum1.C index bf174295248..49d0fe1519d 100644 --- a/gcc/testsuite/g++.dg/cpp0x/enum1.C +++ b/gcc/testsuite/g++.dg/cpp0x/enum1.C @@ -1,5 +1,5 @@ // PR c++/38021 // { dg-do compile { target c++11 } } -enum : { }; // { dg-error "expected" } +enum : { }; // { dg-error "expected|ISO" } enum : 3 { }; // { dg-error "expected" } diff --git a/gcc/testsuite/g++.dg/cpp0x/enum45.C b/gcc/testsuite/g++.dg/cpp0x/enum45.C new file mode 100644 index 00000000000..c9f66d7be56 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/enum45.C @@ -0,0 +1,4 @@ +// PR c++/118374 +// { dg-do compile { target c++11 } } + +enum class X : int8_t; // { dg-error "does not name a type" } diff --git a/gcc/testsuite/g++.dg/parse/enum5.C b/gcc/testsuite/g++.dg/parse/enum5.C index 18480520a6f..3d2b0820934 100644 --- a/gcc/testsuite/g++.dg/parse/enum5.C +++ b/gcc/testsuite/g++.dg/parse/enum5.C @@ -7,7 +7,7 @@ typedef unsigned int T; struct D { T : sizeof(unsigned int) * CHAR_BIT; // OK EE : sizeof(EE) * CHAR_BIT; // OK - enum EE : sizeof(EE) * CHAR_BIT; // not OK + enum EE : sizeof(EE) * CHAR_BIT; // { dg-error "expected|scoped" } enum EE xxxx : sizeof(EE) * CHAR_BIT; // OK T x : sizeof(unsigned int) * CHAR_BIT; // OK enum FF {ff} : sizeof(FF) * CHAR_BIT; // OK -- 2.52.0
