gcc/c-family/ChangeLog:
PR c++/97573
* c-opts.c (c_common_post_options): In C++20, turn on
-Wdeprecated-enum-enum-conversion and
-Wdeprecated-enum-float-conversion.
* c.opt (Wdeprecated-enum-enum-conversion,
Wdeprecated-enum-float-conversion): New options.
(Wenum-conversion): Allow for C++ too.
gcc/cp/ChangeLog:
PR c++/97573
* call.c (build_conditional_expr_1): Warn about the deprecated
enum/real type conversion in C++20. Also warn about a non-enumerated
and enumerated type in ?: when -Wenum-conversion is on.
* typeck.c (do_warn_enum_conversions): New function.
(cp_build_binary_op): Call it.
gcc/ChangeLog:
PR c++/97573
* doc/invoke.texi: Document -Wdeprecated-enum-enum-conversion
and -Wdeprecated-enum-float-conversion. -Wenum-conversion is
no longer C/ObjC only.
gcc/testsuite/ChangeLog:
PR c++/97573
* g++.dg/cpp0x/linkage2.C: Add dg-warning.
* g++.dg/parse/attr3.C: Likewise.
* g++.dg/cpp2a/enum-conv1.C: New test.
* g++.dg/cpp2a/enum-conv2.C: New test.
* g++.dg/cpp2a/enum-conv3.C: New test.
---
gcc/c-family/c-opts.c | 10 ++
gcc/c-family/c.opt | 11 ++-
gcc/cp/call.c | 35 +++++--
gcc/cp/typeck.c | 112 +++++++++++++++++++++-
gcc/doc/invoke.texi | 44 ++++++++-
gcc/testsuite/g++.dg/cpp0x/linkage2.C | 2 +-
gcc/testsuite/g++.dg/cpp2a/enum-conv1.C | 120 ++++++++++++++++++++++++
gcc/testsuite/g++.dg/cpp2a/enum-conv2.C | 115 +++++++++++++++++++++++
gcc/testsuite/g++.dg/cpp2a/enum-conv3.C | 115 +++++++++++++++++++++++
gcc/testsuite/g++.dg/parse/attr3.C | 2 +-
10 files changed, 549 insertions(+), 17 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp2a/enum-conv1.C
create mode 100644 gcc/testsuite/g++.dg/cpp2a/enum-conv2.C
create mode 100644 gcc/testsuite/g++.dg/cpp2a/enum-conv3.C
diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index 38d33849423..120f4489f6c 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -925,6 +925,16 @@ c_common_post_options (const char **pfilename)
SET_OPTION_IF_UNSET (&global_options, &global_options_set, warn_volatile,
cxx_dialect >= cxx20 && warn_deprecated);
+ /* -Wdeprecated-enum-enum-conversion is enabled by default in C++20. */
+ SET_OPTION_IF_UNSET (&global_options, &global_options_set,
+ warn_deprecated_enum_enum_conv,
+ cxx_dialect >= cxx20 && warn_deprecated);
+
+ /* -Wdeprecated-enum-float-conversion is enabled by default in C++20. */
+ SET_OPTION_IF_UNSET (&global_options, &global_options_set,
+ warn_deprecated_enum_float_conv,
+ cxx_dialect >= cxx20 && warn_deprecated);
+
/* Declone C++ 'structors if -Os. */
if (flag_declone_ctor_dtor == -1)
flag_declone_ctor_dtor = optimize_size;
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 1009defbf16..10e53ea67c9 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -518,6 +518,15 @@ C++ ObjC++ Var(warn_deprecated_copy, 2) Warning
Mark implicitly-declared copy operations as deprecated if the class has a
user-provided copy operation or destructor.
+Wdeprecated-enum-enum-conversion
+C++ ObjC++ Var(warn_deprecated_enum_enum_conv) Warning
+Warn about deprecated arithmetic conversions on operands of enumeration types.
+
+Wdeprecated-enum-float-conversion
+C++ ObjC++ Var(warn_deprecated_enum_float_conv) Warning
+Warn about deprecated arithmetic conversions on operands where one is of
enumeration
+type and the other is of a floating-point type.
+
Wdesignated-init
C ObjC Var(warn_designated_init) Init(1) Warning
Warn about positional initialization of structs requiring designated
initializers.
@@ -559,7 +568,7 @@ C ObjC C++ ObjC++ Var(warn_enum_compare) Init(-1) Warning
LangEnabledBy(C ObjC,W
Warn about comparison of different enum types.
Wenum-conversion
-C ObjC Var(warn_enum_conversion) Init(0) Warning LangEnabledBy(C ObjC,Wextra)
+C ObjC C++ ObjC++ Var(warn_enum_conversion) Init(0) Warning LangEnabledBy(C
ObjC,Wextra)
Warn about implicit conversion of enum types.
Werror
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index bd662518958..9861be1f856 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5643,17 +5643,40 @@ build_conditional_expr_1 (const op_location_t &loc,
"in conditional expression: %qT vs %qT",
arg2_type, arg3_type);
}
- else if (extra_warnings
+ else if ((complain & tf_warning)
+ && warn_deprecated_enum_float_conv
+ && ((TREE_CODE (arg2_type) == ENUMERAL_TYPE
+ && TREE_CODE (arg3_type) == REAL_TYPE)
+ || (TREE_CODE (arg2_type) == REAL_TYPE
+ && TREE_CODE (arg3_type) == ENUMERAL_TYPE)))
+ {
+ if (TREE_CODE (arg2_type) == ENUMERAL_TYPE)
+ warning_at (loc, OPT_Wdeprecated_enum_float_conversion,
+ "conditional expression between enumeration type "
+ "%qT and floating-point type %qT is deprecated",
+ arg2_type, arg3_type);
+ else
+ warning_at (loc, OPT_Wdeprecated_enum_float_conversion,
+ "conditional expression between floating-point "
+ "type %qT and enumeration type %qT is deprecated",
+ arg2_type, arg3_type);
+ }
+ else if ((extra_warnings || warn_enum_conversion)
&& ((TREE_CODE (arg2_type) == ENUMERAL_TYPE
&& !same_type_p (arg3_type, type_promotes_to (arg2_type)))
|| (TREE_CODE (arg3_type) == ENUMERAL_TYPE
&& !same_type_p (arg2_type,
type_promotes_to (arg3_type)))))
- {
- if (complain & tf_warning)
- warning_at (loc, OPT_Wextra, "enumerated and non-enumerated "
- "type in conditional expression");
- }
+ {
+ if (complain & tf_warning)
+ {
+ enum opt_code opt = (warn_enum_conversion
+ ? OPT_Wenum_conversion
+ : OPT_Wextra);
+ warning_at (loc, opt, "enumerated and "
+ "non-enumerated type in conditional expression");
+ }
+ }
arg2 = perform_implicit_conversion (result_type, arg2, complain);
arg3 = perform_implicit_conversion (result_type, arg3, complain);
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 48d34f1132a..7305310ecbe 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -4428,6 +4428,104 @@ warn_for_null_address (location_t location, tree op,
tsubst_flags_t complain)
}
}
+/* Warn about [expr.arith.conv]/2: If one operand is of enumeration type and
+ the other operand is of a different enumeration type or a floating-point
+ type, this behavior is deprecated ([depr.arith.conv.enum]). CODE is the
+ code of the binary operation, TYPE0 and TYPE1 are the types of the operands,
+ and LOC is the location for the whole binary expression.
+ TODO: Consider combining this with -Wenum-compare in build_new_op_1. */
+
+static void
+do_warn_enum_conversions (location_t loc, enum tree_code code, tree type0,
+ tree type1)
+{
+ if (TREE_CODE (type0) == ENUMERAL_TYPE
+ && TREE_CODE (type1) == ENUMERAL_TYPE
+ && TYPE_MAIN_VARIANT (type0) != TYPE_MAIN_VARIANT (type1))
+ {
+ /* In C++20, -Wdeprecated-enum-enum-conversion is on by default.
+ Otherwise, warn if -Wenum-conversion is on. */
+ enum opt_code opt;
+ if (warn_deprecated_enum_enum_conv)
+ opt = OPT_Wdeprecated_enum_enum_conversion;
+ else if (warn_enum_conversion)
+ opt = OPT_Wenum_conversion;
+ else
+ return;
+
+ switch (code)
+ {
+ case GT_EXPR:
+ case LT_EXPR:
+ case GE_EXPR:
+ case LE_EXPR:
+ case EQ_EXPR:
+ case NE_EXPR:
+ /* Comparisons are handled by -Wenum-compare. */
+ return;
+ case SPACESHIP_EXPR:
+ /* This is invalid, don't warn. */
+ return;
+ case BIT_AND_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ warning_at (loc, opt, "bitwise operation between different "
+ "enumeration types %qT and %qT is deprecated",
+ type0, type1);
+ return;
+ default:
+ warning_at (loc, opt, "arithmetic between different enumeration "
+ "types %qT and %qT is deprecated", type0, type1);
+ return;
+ }
+ }
+ else if ((TREE_CODE (type0) == ENUMERAL_TYPE
+ && TREE_CODE (type1) == REAL_TYPE)
+ || (TREE_CODE (type0) == REAL_TYPE
+ && TREE_CODE (type1) == ENUMERAL_TYPE))
+ {
+ const bool enum_first_p = TREE_CODE (type0) == ENUMERAL_TYPE;
+ /* In C++20, -Wdeprecated-enum-float-conversion is on by default.
+ Otherwise, warn if -Wenum-conversion is on. */
+ enum opt_code opt;
+ if (warn_deprecated_enum_float_conv)
+ opt = OPT_Wdeprecated_enum_float_conversion;
+ else if (warn_enum_conversion)
+ opt = OPT_Wenum_conversion;
+ else
+ return;
+
+ switch (code)
+ {
+ case GT_EXPR:
+ case LT_EXPR:
+ case GE_EXPR:
+ case LE_EXPR:
+ case EQ_EXPR:
+ case NE_EXPR:
+ if (enum_first_p)
+ warning_at (loc, opt, "comparison of enumeration type %qT with "
+ "floating-point type %qT is deprecated",
+ type0, type1);
+ else
+ warning_at (loc, opt, "comparison of floating-point type %qT "
+ "with enumeration type %qT is deprecated",
+ type0, type1);
+ return;
+ default:
+ if (enum_first_p)
+ warning_at (loc, opt, "arithmetic between enumeration type %qT "
+ "and floating-point type %qT is deprecated",
+ type0, type1);
+ else
+ warning_at (loc, opt, "arithmetic between floating-point type %qT "
+ "and enumeration type %qT is deprecated",
+ type0, type1);
+ return;
+ }
+ }
+}
+
/* Build a binary-operation expression without default conversions.
CODE is the kind of expression to build.
LOCATION is the location_t of the operator in the source code.
@@ -5445,11 +5543,15 @@ cp_build_binary_op (const op_location_t &location,
{
result_type = cp_common_type (type0, type1);
if (complain & tf_warning)
- do_warn_double_promotion (result_type, type0, type1,
- "implicit conversion from %qH to %qI "
- "to match other operand of binary "
- "expression",
- location);
+ {
+ do_warn_double_promotion (result_type, type0, type1,
+ "implicit conversion from %qH to %qI "
+ "to match other operand of binary "
+ "expression",
+ location);
+ do_warn_enum_conversions (location, code, TREE_TYPE (orig_op0),
+ TREE_TYPE (orig_op1));
+ }
}
if (code == SPACESHIP_EXPR)
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index f82eeea097a..72ae4a23203 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -239,6 +239,7 @@ in the following sections.
-Wno-conversion-null -Wctad-maybe-unsupported @gol
-Wctor-dtor-privacy -Wno-delete-incomplete @gol
-Wdelete-non-virtual-dtor -Wdeprecated-copy -Wdeprecated-copy-dtor @gol
+-Wno-deprecated-enum-enum-conversion -Wno-deprecated-enum-float-conversion @gol
-Weffc++ -Wextra-semi -Wno-inaccessible-base @gol
-Wno-inherited-variadic-ctor -Wno-init-list-lifetime @gol
-Wno-invalid-offsetof -Wno-literal-suffix -Wmismatched-tags @gol
@@ -3358,6 +3359,42 @@ warning is enabled by @option{-Wextra}. With
@option{-Wdeprecated-copy-dtor}, also deprecate if the class has a
user-provided destructor.
+@item -Wno-deprecated-enum-enum-conversion @r{(C++ and Objective-C++ only)}
+@opindex Wdeprecated-enum-enum-conversion
+@opindex Wno-deprecated-enum-enum-conversion
+Disable the warning about the case when the usual arithmetic conversions
+are applied on operands where one is of enumeration type and the other is
+of a different enumeration type. This conversion was deprecated in C++20.
+For example:
+
+@smallexample
+enum E1 @{ e @};
+enum E2 @{ f @};
+int k = f - e;
+@end smallexample
+
+@option{-Wdeprecated-enum-enum-conversion} is enabled by default with
+@option{-std=c++20}. In pre-C++20 dialects, this warning can be enabled
+by @option{-Wenum-conversion}.
+
+@item -Wno-deprecated-enum-float-conversion @r{(C++ and Objective-C++ only)}
+@opindex Wdeprecated-enum-float-conversion
+@opindex Wno-deprecated-enum-float-conversion
+Disable the warning about the case when the usual arithmetic conversions
+are applied on operands where one is of enumeration type and the other is
+of a floating-point type. This conversion was deprecated in C++20. For
+example:
+
+@smallexample
+enum E1 @{ e @};
+enum E2 @{ f @};
+bool b = e <= 3.7;
+@end smallexample
+
+@option{-Wdeprecated-enum-float-conversion} is enabled by default with
+@option{-std=c++20}. In pre-C++20 dialects, this warning can be enabled
+by @option{-Wenum-conversion}.
+
@item -Wno-init-list-lifetime @r{(C++ and Objective-C++ only)}
@opindex Winit-list-lifetime
@opindex Wno-init-list-lifetime
@@ -5271,7 +5308,6 @@ Options} and @ref{Objective-C and Objective-C++ Dialect
Options}.
-Wcomment @gol
-Wduplicate-decl-specifier @r{(C and Objective-C only)} @gol
-Wenum-compare @r{(in C/ObjC; this is on by default in C++)} @gol
--Wenum-conversion @r{in C/ObjC;} @gol
-Wformat @gol
-Wformat-overflow @gol
-Wformat-truncation @gol
@@ -5340,6 +5376,7 @@ name is still supported, but the newer name is more
descriptive.)
-Wcast-function-type @gol
-Wdeprecated-copy @r{(C++ only)} @gol
-Wempty-body @gol
+-Wenum-conversion @r{(C only)} @gol
-Wignored-qualifiers @gol
-Wimplicit-fallthrough=3 @gol
-Wmissing-field-initializers @gol
@@ -8006,11 +8043,12 @@ In C++ enumerated type mismatches in conditional
expressions are also
diagnosed and the warning is enabled by default. In C this warning is
enabled by @option{-Wall}.
-@item -Wenum-conversion @r{(C, Objective-C only)}
+@item -Wenum-conversion
@opindex Wenum-conversion
@opindex Wno-enum-conversion
Warn when a value of enumerated type is implicitly converted to a
-different enumerated type. This warning is enabled by @option{-Wextra}.
+different enumerated type. This warning is enabled by @option{-Wextra}
+in C@.
@item -Wjump-misses-init @r{(C, Objective-C only)}
@opindex Wjump-misses-init
diff --git a/gcc/testsuite/g++.dg/cpp0x/linkage2.C
b/gcc/testsuite/g++.dg/cpp0x/linkage2.C
index 52858687ed3..549bd825aab 100644
--- a/gcc/testsuite/g++.dg/cpp0x/linkage2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/linkage2.C
@@ -29,5 +29,5 @@ void f() {
ba.g(a); // OK
ba.h(a); // error, B<T>::h never defined
i(ba, a); // OK
- e1+e2+e3;
+ e1+e2+e3; // { dg-warning "arithmetic between different enumeration types"
"" { target c++20 } }
}
diff --git a/gcc/testsuite/g++.dg/cpp2a/enum-conv1.C
b/gcc/testsuite/g++.dg/cpp2a/enum-conv1.C
new file mode 100644
index 00000000000..d4960f334dd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/enum-conv1.C
@@ -0,0 +1,120 @@
+// PR c++/97573
+// { dg-do compile }
+// No special options. In C++20 (only), we should get the deprecated warnings
+// by default. -Wenum-compare is enabled by default so some of them will be
+// printed even pre-C++20.
+
+enum E1 { e } e1;
+enum E2 { f } e2;
+__extension__ static enum { } u1;
+__extension__ static enum { } u2;
+static double d;
+
+void
+conv ()
+{
+ bool b1 = e == e1;
+ bool b2 = e == f; // { dg-warning "comparison between .enum E1. and .enum
E2." }
+ bool b3 = e == 0.0; // { dg-warning "comparison of enumeration type .E1. with
floating-point type .double." "" { target c++20 } }
+ bool b4 = 0.0 == f; // { dg-warning "comparison of floating-point type .double. with
enumeration type .E2." "" { target c++20 } }
+ int n1 = true ? e : f; // { dg-warning "enumerated mismatch" }
+ int n2 = true ? e : 0.0; // { dg-warning "conditional expression between" ""
{ target c++20 } }
+}
+
+int
+enum_enum (bool b)
+{
+ int r = 0;
+ const E1 e1c = e;
+
+ r += e - e;
+ r += e - e1;
+ r += e - f; // { dg-warning "arithmetic between different enumeration types .E1. and
.E2." "" { target c++20 } }
+ r += f - e; // { dg-warning "arithmetic between different enumeration types .E2. and
.E1." "" { target c++20 } }
+
+ r += f + f;
+ r += f + e; // { dg-warning "arithmetic between different enumeration types .E2. and
.E1." "" { target c++20 } }
+ r += e + f; // { dg-warning "arithmetic between different enumeration types .E1. and
.E2." "" { target c++20 } }
+
+ r += e1 - e2; // { dg-warning "arithmetic between different enumeration types .E1. and
.E2." "" { target c++20 } }
+ r += e1 - e1c;
+ r += e1c - e1;
+
+ r += e * f; // { dg-warning "arithmetic between different enumeration types .E1. and
.E2." "" { target c++20 } }
+ r += f * e; // { dg-warning "arithmetic between different enumeration types .E2. and
.E1." "" { target c++20 } }
+ r += e * e;
+
+ r += e1 < e1c;
+ r += e < e1;
+ r += e1 < e2; // { dg-warning "comparison between .enum E1. and .enum E2." }
+ r += e < f; // { dg-warning "comparison between .enum E1. and .enum E2." }
+ r += f < e; // { dg-warning "comparison between .enum E2. and .enum E1." }
+
+ r += e1 == e1c;
+ r += e == e1;
+ r += e == f; // { dg-warning "comparison between .enum E1. and .enum E2." }
+ r += f == e; // { dg-warning "comparison between .enum E2. and .enum E1." }
+ r += e1 == e2; // { dg-warning "comparison between .enum E1. and .enum E2." }
+ r += e2 == e1; // { dg-warning "comparison between .enum E2. and .enum E1." }
+
+ r += b ? e1 : e1c;
+ r += b ? e1 : e;
+ r += b ? f : e; // { dg-warning "enumerated mismatch in conditional expression:
.E2. vs .E1." }
+ r += b ? e1 : e2; // { dg-warning "enumerated mismatch in conditional expression:
.E1. vs .E2." }
+
+ r += e | f; // { dg-warning "bitwise operation between different enumeration types .E1. and
.E2." "" { target c++20 } }
+ r += e ^ f; // { dg-warning "bitwise operation between different enumeration types .E1. and
.E2." "" { target c++20 } }
+ r += e & f; // { dg-warning "bitwise operation between different enumeration types .E1. and
.E2." "" { target c++20 } }
+ r += !e;
+ r += e1 | e;
+
+ r += e << f;
+ r += e >> f;
+ r += e || f;
+ r += e && f;
+ e1 = e1c;
+
+ // Anonymous enum.
+ r += u1 - u1;
+ r += u1 + u2; // { dg-warning "arithmetic between different enumeration types"
"" { target c++20 } }
+ r += u1 * u2; // { dg-warning "arithmetic between different enumeration types"
"" { target c++20 } }
+ r += u1 == u2; // { dg-warning "comparison between" }
+ r += u1 & u2; // { dg-warning "bitwise operation between different enumeration types"
"" { target c++20 } }
+
+ return r;
+}
+
+double
+enum_float (bool b)
+{
+ double r = 0.0;
+
+ r += e1 - d; // { dg-warning "arithmetic between enumeration type .E1. and floating-point
type .double." "" { target c++20 } }
+ r += d - e1; // { dg-warning "arithmetic between floating-point type .double. and
enumeration type .E1." "" { target c++20 } }
+ r += e1 + d; // { dg-warning "arithmetic between enumeration type .E1. and floating-point
type .double." "" { target c++20 } }
+ r += d + e1; // { dg-warning "arithmetic between floating-point type .double. and
enumeration type .E1." "" { target c++20 } }
+ r += e1 * d; // { dg-warning "arithmetic between enumeration type .E1. and floating-point
type .double." "" { target c++20 } }
+ r += d * e1; // { dg-warning "arithmetic between floating-point type .double. and
enumeration type .E1." "" { target c++20 } }
+ r += u1 * d; // { dg-warning "arithmetic between enumeration type" "" {
target c++20 } }
+ r += d * u1; // { dg-warning "arithmetic between floating-point type" "" {
target c++20 } }
+
+ r += e1 < d; // { dg-warning "comparison of enumeration type .E1. with floating-point type
.double." "" { target c++20 } }
+ r += d < e1; // { dg-warning "comparison of floating-point type .double. with enumeration
type .E1." "" { target c++20 } }
+ r += d == e1; // { dg-warning "comparison of floating-point type .double. with enumeration
type .E1." "" { target c++20 } }
+ r += e1 == d; // { dg-warning "comparison of enumeration type .E1. with floating-point type
.double." "" { target c++20 } }
+ r += u1 == d; // { dg-warning "comparison of enumeration type" "" { target
c++20 } }
+ r += d == u1; // { dg-warning "comparison of floating-point type" "" {
target c++20 } }
+
+ r += b ? e1 : d; // { dg-warning "conditional expression between enumeration type .E1. and
floating-point type .double." "" { target c++20 } }
+ r += b ? d : e1; // { dg-warning "conditional expression between floating-point type
.double. and enumeration type .E1." "" { target c++20 } }
+ r += b ? d : u1; // { dg-warning "conditional expression between" "" {
target c++20 } }
+ r += b ? u1 : d; // { dg-warning "conditional expression between" "" {
target c++20 } }
+
+ // FIXME should be error
+ // e1 <=> d;
+
+ d += e1; // { dg-warning "arithmetic between floating-point type .double. and enumeration
type .E1." "" { target c++20 } }
+ d = e1;
+
+ return r;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/enum-conv2.C
b/gcc/testsuite/g++.dg/cpp2a/enum-conv2.C
new file mode 100644
index 00000000000..f15827bda14
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/enum-conv2.C
@@ -0,0 +1,115 @@
+// PR c++/97573
+// { dg-do compile { target c++20 } }
+// { dg-options "-Wno-deprecated -Wno-enum-compare" }
+
+enum E1 { e } e1;
+enum E2 { f } e2;
+__extension__ static enum { } u1;
+__extension__ static enum { } u2;
+static double d;
+
+void
+conv ()
+{
+ bool b1 = e == e1;
+ bool b2 = e == f;
+ bool b3 = e == 0.0;
+ bool b4 = 0.0 == f;
+ int n1 = true ? e : f;
+ int n2 = true ? e : 0.0;
+}
+
+int
+enum_enum (bool b)
+{
+ int r = 0;
+ const E1 e1c = e;
+
+ r += e - e;
+ r += e - e1;
+ r += e - f;
+ r += f - e;
+
+ r += f + f;
+ r += f + e;
+ r += e + f;
+
+ r += e1 - e2;
+ r += e1 - e1c;
+ r += e1c - e1;
+
+ r += e * f;
+ r += f * e;
+ r += e * e;
+
+ r += e1 < e1c;
+ r += e < e1;
+ r += e1 < e2;
+ r += e < f;
+ r += f < e;
+
+ r += e1 == e1c;
+ r += e == e1;
+ r += e == f;
+ r += f == e;
+ r += e1 == e2;
+ r += e2 == e1;
+
+ r += b ? e1 : e1c;
+ r += b ? e1 : e;
+ r += b ? f : e;
+ r += b ? e1 : e2;
+
+ r += e | f;
+ r += e ^ f;
+ r += e & f;
+ r += !e;
+ r += e1 | e;
+
+ r += e << f;
+ r += e >> f;
+ r += e || f;
+ r += e && f;
+ e1 = e1c;
+
+ // Anonymous enum.
+ r += u1 - u1;
+ r += u1 + u2;
+ r += u1 * u2;
+ r += u1 == u2;
+ r += u1 & u2;
+
+ return r;
+}
+
+double
+enum_float (bool b)
+{
+ double r = 0.0;
+
+ r += e1 - d;
+ r += d - e1;
+ r += e1 + d;
+ r += d + e1;
+ r += e1 * d;
+ r += d * e1;
+ r += u1 * d;
+ r += d * u1;
+
+ r += e1 < d;
+ r += d < e1;
+ r += d == e1;
+ r += e1 == d;
+ r += u1 == d;
+ r += d == u1;
+
+ r += b ? e1 : d;
+ r += b ? d : e1;
+ r += b ? d : u1;
+ r += b ? u1 : d;
+
+ d += e1;
+ d = e1;
+
+ return r;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/enum-conv3.C
b/gcc/testsuite/g++.dg/cpp2a/enum-conv3.C
new file mode 100644
index 00000000000..67bdf1600d7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/enum-conv3.C
@@ -0,0 +1,115 @@
+// PR c++/97573
+// { dg-do compile { target { c++17_down } } }
+// { dg-options "-Wenum-conversion" }
+
+enum E1 { e } e1;
+enum E2 { f } e2;
+__extension__ static enum { } u1;
+__extension__ static enum { } u2;
+static double d;
+
+void
+conv ()
+{
+ bool b1 = e == e1;
+ bool b2 = e == f; // { dg-warning "comparison between .enum E1. and .enum
E2." }
+ bool b3 = e == 0.0; // { dg-warning "comparison of enumeration type .E1. with
floating-point type .double." }
+ bool b4 = 0.0 == f; // { dg-warning "comparison of floating-point type .double.
with enumeration type .E2." }
+ int n1 = true ? e : f; // { dg-warning "enumerated mismatch" }
+ int n2 = true ? e : 0.0; // { dg-warning "enumerated and non-enumerated type in
conditional expression" }
+}
+
+int
+enum_enum (bool b)
+{
+ int r = 0;
+ const E1 e1c = e;
+
+ r += e - e;
+ r += e - e1;
+ r += e - f; // { dg-warning "arithmetic between different enumeration types .E1.
and .E2." }
+ r += f - e; // { dg-warning "arithmetic between different enumeration types .E2.
and .E1." }
+
+ r += f + f;
+ r += f + e; // { dg-warning "arithmetic between different enumeration types .E2.
and .E1." }
+ r += e + f; // { dg-warning "arithmetic between different enumeration types .E1.
and .E2." }
+
+ r += e1 - e2; // { dg-warning "arithmetic between different enumeration types
.E1. and .E2." }
+ r += e1 - e1c;
+ r += e1c - e1;
+
+ r += e * f; // { dg-warning "arithmetic between different enumeration types .E1.
and .E2." }
+ r += f * e; // { dg-warning "arithmetic between different enumeration types .E2.
and .E1." }
+ r += e * e;
+
+ r += e1 < e1c;
+ r += e < e1;
+ r += e1 < e2; // { dg-warning "comparison between .enum E1. and .enum E2." }
+ r += e < f; // { dg-warning "comparison between .enum E1. and .enum E2." }
+ r += f < e; // { dg-warning "comparison between .enum E2. and .enum E1." }
+
+ r += e1 == e1c;
+ r += e == e1;
+ r += e == f; // { dg-warning "comparison between .enum E1. and .enum E2." }
+ r += f == e; // { dg-warning "comparison between .enum E2. and .enum E1." }
+ r += e1 == e2; // { dg-warning "comparison between .enum E1. and .enum E2." }
+ r += e2 == e1; // { dg-warning "comparison between .enum E2. and .enum E1." }
+
+ r += b ? e1 : e1c;
+ r += b ? e1 : e;
+ r += b ? f : e; // { dg-warning "enumerated mismatch in conditional expression:
.E2. vs .E1." }
+ r += b ? e1 : e2; // { dg-warning "enumerated mismatch in conditional expression:
.E1. vs .E2." }
+
+ r += e | f; // { dg-warning "bitwise operation between different enumeration
types .E1. and .E2." }
+ r += e ^ f; // { dg-warning "bitwise operation between different enumeration
types .E1. and .E2." }
+ r += e & f; // { dg-warning "bitwise operation between different enumeration
types .E1. and .E2." }
+ r += !e;
+ r += e1 | e;
+
+ r += e << f;
+ r += e >> f;
+ r += e || f;
+ r += e && f;
+ e1 = e1c;
+
+ // Anonymous enum.
+ r += u1 - u1;
+ r += u1 + u2; // { dg-warning "arithmetic between different enumeration
types" }
+ r += u1 * u2; // { dg-warning "arithmetic between different enumeration
types" }
+ r += u1 == u2; // { dg-warning "comparison between" }
+ r += u1 & u2; // { dg-warning "bitwise operation between different enumeration
types" }
+
+ return r;
+}
+
+double
+enum_float (bool b)
+{
+ double r = 0.0;
+
+ r += e1 - d; // { dg-warning "arithmetic between enumeration type .E1. and
floating-point type .double." }
+ r += d - e1; // { dg-warning "arithmetic between floating-point type .double. and
enumeration type .E1." }
+ r += e1 + d; // { dg-warning "arithmetic between enumeration type .E1. and
floating-point type .double." }
+ r += d + e1; // { dg-warning "arithmetic between floating-point type .double. and
enumeration type .E1." }
+ r += e1 * d; // { dg-warning "arithmetic between enumeration type .E1. and
floating-point type .double." }
+ r += d * e1; // { dg-warning "arithmetic between floating-point type .double. and
enumeration type .E1." }
+ r += u1 * d; // { dg-warning "arithmetic between enumeration type" }
+ r += d * u1; // { dg-warning "arithmetic between floating-point type" }
+
+ r += e1 < d; // { dg-warning "comparison of enumeration type .E1. with
floating-point type .double." }
+ r += d < e1; // { dg-warning "comparison of floating-point type .double. with
enumeration type .E1." }
+ r += d == e1; // { dg-warning "comparison of floating-point type .double. with
enumeration type .E1." }
+ r += e1 == d; // { dg-warning "comparison of enumeration type .E1. with
floating-point type .double." }
+ r += u1 == d; // { dg-warning "comparison of enumeration type" }
+ r += d == u1; // { dg-warning "comparison of floating-point type" }
+
+ r += b ? e1 : d; // { dg-warning "enumerated and non-enumerated type in
conditional expression" }
+ r += b ? d : e1; // { dg-warning "enumerated and non-enumerated type in
conditional expression" }
+ r += b ? d : u1; // { dg-warning "enumerated and non-enumerated type in
conditional expression" }
+ r += b ? u1 : d; // { dg-warning "enumerated and non-enumerated type in
conditional expression" }
+
+ d += e1; // { dg-warning "arithmetic between floating-point type .double. and
enumeration type .E1." }
+ d = e1;
+
+ return r;
+}
diff --git a/gcc/testsuite/g++.dg/parse/attr3.C
b/gcc/testsuite/g++.dg/parse/attr3.C
index 57fa60e130e..de095988015 100644
--- a/gcc/testsuite/g++.dg/parse/attr3.C
+++ b/gcc/testsuite/g++.dg/parse/attr3.C
@@ -10,5 +10,5 @@ int main () {
S::F y; // { dg-warning "'F' is deprecated" }
y = S::f;
- return x + y;
+ return x + y; // { dg-warning "arithmetic between different enumeration types"
"" { target c++20 } }
}
base-commit: 75ce04fba49eb30b6a8fe23bc3605cf0ef9a8e28