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