On 2/10/26 5:40 PM, Ben Wu wrote:
Tested on x86_64-pc-linux-gnu. Any thoughts welcome on these
diagnostics changes, or cases where valid code is now rejected.

I'm not sure how to provide a fixit as suggested in the PR, but
hopefully this is a start to better diagnostics for these testcases.

-- 8< --

Instead of returning NULL_TREE on an error when parsing an underlying
type for an enum, we can improve diagnostics by giving a clearer error
and returning error_mark_node.

        PR c++/118374

gcc/cp/ChangeLog:

        * parser.cc (cp_parser_enum_specifier): Emit new error and
        return error_mark_node on failure to parse an underlying
        type.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp0x/enum1.C: Adjust test to expect new error.

This is breaking the 41127 testcase, but it seems that 41127 was wrong: [dcl.enum]/1 "A : following “enum nested-name-specifier[opt] identifier” within the decl-specifier-seq of a member-declaration is parsed as part of an enum-base. [Note 1: This resolves a potential ambiguity between the declaration of an enumeration with an enum-base and the declaration of an unnamed bit-field of enumeration type.
[Example 1: 
struct S {
  enum E : int {};
  enum E : int {};              // error: redeclaration of enumeration
};
— end example]"

So I think the right solution here is to revert my parser changes for 41127 (in ea434efe287a965838c546a340f69cdd71983b92).

        * g++.dg/cpp0x/enum_base4.C: Likewise.
        * g++.dg/cpp0x/enum_base5.C: Likewise.
        * g++.dg/parse/enum5.C: Likewise.
        * g++.dg/cpp0x/enum45.C: New test.

---
  gcc/cp/parser.cc                        | 12 +++++++++++-
  gcc/testsuite/g++.dg/cpp0x/enum1.C      |  4 ++--
  gcc/testsuite/g++.dg/cpp0x/enum45.C     |  4 ++++
  gcc/testsuite/g++.dg/cpp0x/enum_base4.C |  2 +-
  gcc/testsuite/g++.dg/cpp0x/enum_base5.C |  2 +-
  gcc/testsuite/g++.dg/parse/enum5.C      |  2 +-
  6 files changed, 20 insertions(+), 6 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/cpp0x/enum45.C

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 5f1d028de0c..d8e148b62b3 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -23825,7 +23825,17 @@ cp_parser_enum_specifier (cp_parser* parser)
/* At this point this is surely not elaborated type specifier. */
        if (!cp_parser_parse_definitely (parser))
-       return NULL_TREE;
+       {
+         error_at (type_start_token->location, "invalid underlying type");
+         cp_parser_commit_to_tentative_parse (parser);
+         cp_parser_skip_to_end_of_block_or_statement (parser);
+         cp_token *prev_tok = cp_lexer_previous_token (parser->lexer);
+         if (prev_tok->type == CPP_SEMICOLON)
+           cp_lexer_set_token_position (parser->lexer,
+             cp_lexer_previous_token_position (parser->lexer));
+
+         return error_mark_node;
+       }
if (cxx_dialect < cxx11)
          maybe_warn_cpp0x (CPP0X_SCOPED_ENUMS);
diff --git a/gcc/testsuite/g++.dg/cpp0x/enum1.C 
b/gcc/testsuite/g++.dg/cpp0x/enum1.C
index bf174295248..c3b3dba3c44 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 : 3 { };  // { dg-error "expected" }
+enum : { };    // { dg-error "invalid underlying type" }
+enum : 3 { };  // { dg-error "invalid underlying type" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/enum45.C 
b/gcc/testsuite/g++.dg/cpp0x/enum45.C
new file mode 100644
index 00000000000..b2eb7b3fbe4
--- /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 : bogus; // { dg-error "invalid underlying type" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/enum_base4.C 
b/gcc/testsuite/g++.dg/cpp0x/enum_base4.C
index b3015256386..6330070b47c 100644
--- a/gcc/testsuite/g++.dg/cpp0x/enum_base4.C
+++ b/gcc/testsuite/g++.dg/cpp0x/enum_base4.C
@@ -4,5 +4,5 @@
  extern const int a, b;
  enum struct c;
  template <class>
-enum struct c : union enum struct c { e = b, f = a };  // { dg-error "types may not 
be defined|expected|elaborated-type-specifier" }
+enum struct c : union enum struct c { e = b, f = a };  // { dg-error "types may not 
be defined|invalid underlying type" }
  enum class c {};
diff --git a/gcc/testsuite/g++.dg/cpp0x/enum_base5.C 
b/gcc/testsuite/g++.dg/cpp0x/enum_base5.C
index c01e857e612..44e132c83bc 100644
--- a/gcc/testsuite/g++.dg/cpp0x/enum_base5.C
+++ b/gcc/testsuite/g++.dg/cpp0x/enum_base5.C
@@ -4,4 +4,4 @@
  extern const int a, b;
  enum struct c;
  template <class>
-enum struct c : union enum struct c { e = b, f = a }; // { dg-error "types may not 
be defined|expected|elaborated-type-specifier" }
+enum struct c : union enum struct c { e = b, f = a }; // { dg-error "types may not 
be defined|invalid underlying type" }
diff --git a/gcc/testsuite/g++.dg/parse/enum5.C 
b/gcc/testsuite/g++.dg/parse/enum5.C
index 18480520a6f..001fa04edab 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 "invalid underlying 
type" }
          enum EE xxxx : sizeof(EE) * CHAR_BIT; // OK
          T x : sizeof(unsigned int) * CHAR_BIT; // OK
          enum FF {ff} : sizeof(FF) * CHAR_BIT; // OK

Reply via email to