c++: Accept elaborated-enum-base with pedwarn

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.

This patch adds the -Welaborated-enum-base warning to GCC and adjusts
the C++ parser to emit this warning instead of rejecting this code
outright.

The macro expansion in the macOS headers occurs in the case that the
compiler declares support for enums with underlying type using
__has_feature, see
https://gcc.gnu.org/pipermail/gcc-patches/2023-May/618450.html

GCC rejecting this construct outright means that GCC fails to bootstrap
on Darwin in the case that it (correctly) implements __has_feature and
declares support for C++ enums with underlying type.

With this patch, GCC can bootstrap on Darwin in combination with the
(WIP) __has_feature patch posted at:
https://gcc.gnu.org/pipermail/gcc-patches/2023-May/617878.html

gcc/c-family/ChangeLog:

	* c.opt (Welaborated-enum-base): New.

gcc/ChangeLog:

	* doc/invoke.texi: Document -Welaborated-enum-base.

gcc/cp/ChangeLog:

	* parser.cc (cp_parser_enum_specifier): Don't reject
	elaborated-type-specifier with enum-base, instead emit new
	Welaborated-enum-base warning.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp0x/enum40.C: Adjust expected diagnostics.
	* g++.dg/cpp0x/forw_enum6.C: Likewise.
	* g++.dg/cpp0x/elab-enum-base.C: New test.
This commit is contained in:
Alex Coplan 2023-06-16 15:18:40 +01:00
parent b5ecca346f
commit b106f11dc6
6 changed files with 39 additions and 10 deletions

View file

@ -1488,6 +1488,10 @@ Wsubobject-linkage
C++ ObjC++ Var(warn_subobject_linkage) Warning Init(1)
Warn if a class type has a base or a field whose type uses the anonymous namespace or depends on a type with no linkage.
Welaborated-enum-base
C++ ObjC++ Var(warn_elaborated_enum_base) Warning Init(1)
Warn if an additional enum-base is used in an elaborated-type-specifier.
Wduplicate-decl-specifier
C ObjC Var(warn_duplicate_decl_specifier) Warning LangEnabledBy(C ObjC,Wall)
Warn when a declaration has duplicate const, volatile, restrict or _Atomic specifier.

View file

@ -21028,11 +21028,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
@ -21081,10 +21083,13 @@ cp_parser_enum_specifier (cp_parser* parser)
&& 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 %<{%>");
if (has_underlying_type)
return error_mark_node;
pedwarn (colon_loc,
OPT_Welaborated_enum_base,
"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 %<{%>");
}
}

View file

@ -254,7 +254,8 @@ in the following sections.
-Wdelete-non-virtual-dtor -Wno-deprecated-array-compare
-Wdeprecated-copy -Wdeprecated-copy-dtor
-Wno-deprecated-enum-enum-conversion -Wno-deprecated-enum-float-conversion
-Weffc++ -Wno-exceptions -Wextra-semi -Wno-inaccessible-base
-Weffc++ -Wno-elaborated-enum-base
-Wno-exceptions -Wextra-semi -Wno-inaccessible-base
-Wno-inherited-variadic-ctor -Wno-init-list-lifetime
-Winvalid-constexpr -Winvalid-imported-macros
-Wno-invalid-offsetof -Wno-literal-suffix
@ -3845,6 +3846,15 @@ bool b = e <= 3.7;
@option{-std=c++20}. In pre-C++20 dialects, this warning can be enabled
by @option{-Wenum-conversion}.
@opindex Welaborated-enum-base
@opindex Wno-elaborated-enum-base
@item -Wno-elaborated-enum-base
For C++11 and above, warn if an (invalid) additional enum-base is used
in an elaborated-type-specifier. That is, if an enum with given
underlying type and no enumerator list is used in a declaration other
than just a standalone declaration of the enum. Enabled by default. This
warning is upgraded to an error with -pedantic-errors.
@opindex Winit-list-lifetime
@opindex Wno-init-list-lifetime
@item -Wno-init-list-lifetime @r{(C++ and Objective-C++ only)}
@ -6054,6 +6064,7 @@ errors by @option{-pedantic-errors}. For instance:
-Wchanges-meaning @r{(C++)}
-Wcomma-subscript @r{(C++23 or later)}
-Wdeclaration-after-statement @r{(C90 or earlier)}
-Welaborated-enum-base @r{(C++11 or later)}
-Wimplicit-int @r{(C99 or later)}
-Wimplicit-function-declaration @r{(C99 or later)}
-Wincompatible-pointer-types

View file

@ -0,0 +1,7 @@
// { dg-do compile { target c++11 } }
// { dg-options "" }
// Empty dg-options to override -pedantic-errors.
typedef long CFIndex;
typedef enum CFComparisonResult : CFIndex CFComparisonResult;
// { dg-warning "declaration of enumeration with fixed underlying type" "" { target *-*-* } .-1 }

View file

@ -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" }
}

View file

@ -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" }