Message ID | ZIG2PaKQvzGAfbd2@arm.com |
---|---|
State | New |
Headers | show |
Series | [RFC] c++: Accept elaborated-enum-base in system headers | expand |
On 6/8/23 07:06, Alex Coplan wrote: > Hi, > > macOS SDK headers using the CF_ENUM macro can expand to invalid C++ code > of the form: > > typedef enum T : BaseType T; > > i.e. an elaborated-type-specifier with an additional enum-base. > Upstream LLVM can be made to accept the above construct with > -Wno-error=elaborated-enum-base. I guess we might as well follow that example, and so instead of this check: > + || (underlying_type && !in_system_header_at (colon_loc))) Make the below an on-by-default pedwarn using OPT_Welaborated_enum_base, and don't return error_mark_node. > + cp_parser_commit_to_tentative_parse (parser); > + error_at (colon_loc, > + "declaration of enumeration with " > + "fixed underlying type and no enumerator list is " > + "only permitted as a standalone declaration");
> Begin forwarded message: > > From: Jason Merrill <jason@redhat.com> > Subject: Re: [PATCH][RFC] c++: Accept elaborated-enum-base in system headers > Date: 8 June 2023 at 19:06:36 BST > To: Alex Coplan <alex.coplan@arm.com>, gcc-patches@gcc.gnu.org > Cc: Nathan Sidwell <nathan@acm.org>, Iain Sandoe <iain@sandoe.co.uk> > > On 6/8/23 07:06, Alex Coplan wrote: >> Hi, >> macOS SDK headers using the CF_ENUM macro can expand to invalid C++ code >> of the form: >> typedef enum T : BaseType T; >> i.e. an elaborated-type-specifier with an additional enum-base. >> Upstream LLVM can be made to accept the above construct with >> -Wno-error=elaborated-enum-base. > > I guess we might as well follow that example, and so instead of this check: > >> + || (underlying_type && !in_system_header_at (colon_loc))) > > Make the below an on-by-default pedwarn using OPT_Welaborated_enum_base, and don't return error_mark_node. I was also wondering about (for this and other reasons) a -fclang-compat to put some of these things behind (since std=clang++NN is not really going to work to describe other non-standard extensions etc. since most are not synchronised to std revisions.) Iain > >> + cp_parser_commit_to_tentative_parse (parser); >> + error_at (colon_loc, >> + "declaration of enumeration with " >> + "fixed underlying type and no enumerator list is " >> + "only permitted as a standalone declaration"); > >
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index d77fbd20e56..e13133a6cfb 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -21024,11 +21024,13 @@ cp_parser_enum_specifier (cp_parser* parser) /* Check for the `:' that denotes a specified underlying type in C++0x. Note that a ':' could also indicate a bitfield width, however. */ + 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 @@ -21073,12 +21075,20 @@ cp_parser_enum_specifier (cp_parser* parser) return error_mark_node; } /* An opaque-enum-specifier must have a ';' here. */ - if ((scoped_enum_p || underlying_type) + if ((scoped_enum_p + || (underlying_type && !in_system_header_at (colon_loc))) && cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) { if (has_underlying_type) - cp_parser_commit_to_tentative_parse (parser); - cp_parser_error (parser, "expected %<;%> or %<{%>"); + { + cp_parser_commit_to_tentative_parse (parser); + error_at (colon_loc, + "declaration of enumeration with " + "fixed underlying type and no enumerator list is " + "only permitted as a standalone declaration"); + } + else + cp_parser_error (parser, "expected %<;%> or %<{%>"); if (has_underlying_type) return error_mark_node; } diff --git a/gcc/testsuite/g++.dg/cpp0x/enum40.C b/gcc/testsuite/g++.dg/cpp0x/enum40.C index cfdf2a4a18a..d3ffeb62d70 100644 --- a/gcc/testsuite/g++.dg/cpp0x/enum40.C +++ b/gcc/testsuite/g++.dg/cpp0x/enum40.C @@ -4,23 +4,25 @@ void foo () { - enum : int a alignas; // { dg-error "expected" } + enum : int a alignas; // { dg-error "declaration of enum" } + // { dg-error {expected '\(' before ';'} "" { target *-*-* } .-1 } } void bar () { - enum : int a; // { dg-error "expected" } + enum : int a; // { dg-error "declaration of enum" } } void baz () { - enum class a : int b alignas; // { dg-error "expected" } + enum class a : int b alignas; // { dg-error "declaration of enum" } + // { dg-error {expected '\(' before ';'} "" { target *-*-* } .-1 } } void qux () { - enum class a : int b; // { dg-error "expected" } + enum class a : int b; // { dg-error "declaration of enum" } } diff --git a/gcc/testsuite/g++.dg/cpp0x/forw_enum6.C b/gcc/testsuite/g++.dg/cpp0x/forw_enum6.C index 01bf563bcdd..8ad3f733292 100644 --- a/gcc/testsuite/g++.dg/cpp0x/forw_enum6.C +++ b/gcc/testsuite/g++.dg/cpp0x/forw_enum6.C @@ -23,7 +23,7 @@ enum class E7 : int; //ok enum class E3 e3; // { dg-error "scoped enum must not use" } enum struct E3 e4; // { dg-error "scoped enum must not use" } -enum E5 : int e5; // { dg-error "expected|invalid type" } +enum E5 : int e5; // { dg-error "declaration of enumeration with fixed underlying type|invalid type" } enum E6 : int { a, b, c }; // { dg-message "previous definition" } enum E6 : int { a, b, c }; // { dg-error "multiple definition" } diff --git a/gcc/testsuite/g++.dg/ext/elab-enum-header.C b/gcc/testsuite/g++.dg/ext/elab-enum-header.C new file mode 100644 index 00000000000..d8c03faf443 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/elab-enum-header.C @@ -0,0 +1,5 @@ +// { dg-do compile { target c++11 } } +// { dg-additional-options "-fpreprocessed" } +# 1 "" 3 +typedef long CFIndex; +typedef enum CFComparisonResult : CFIndex CFComparisonResult; diff --git a/gcc/testsuite/g++.dg/ext/elab-enum-invalid.C b/gcc/testsuite/g++.dg/ext/elab-enum-invalid.C new file mode 100644 index 00000000000..db3957d7367 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/elab-enum-invalid.C @@ -0,0 +1,4 @@ +// { dg-do compile { target c++11 } } +typedef long CFIndex; +typedef enum CFComparisonResult : CFIndex CFComparisonResult; +// { dg-error "declaration of enumeration with fixed underlying type" "" {target *-*-*} .-1 }