I noticed that C++20 P1120R0 deprecated certain arithmetic conversions as outlined in [depr.arith.conv.enum], but we don't warn about them. In particular, "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." These will likely become ill-formed in C++23, so we should warn by default in C++20. To this effect, this patch adds two new warnings (like clang++): -Wdeprecated-enum-enum-conversion and -Wdeprecated-enum-float-conversion. They are enabled by default in C++20. In older dialects, to enable these warnings you can now use -Wenum-conversion which I made available in C++ too. Note that unlike C, in C++ it is not enabled by -Wextra, because that breaks bootstrap. We already warn about comparisons of two different enumeration types via -Wenum-compare, the rest is handled in this patch: we're performing the usual arithmetic conversions in these contexts: - an arithmetic operation, - a bitwise operation, - a comparison, - a conditional operator, - a compound assign operator. Using the spaceship operator as enum <=> real_type is ill-formed but we don't reject it yet. We should also address [depr.array.comp] too, but it's not handled in this patch. 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.
116 lines
5.0 KiB
C
116 lines
5.0 KiB
C
// 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;
|
|
}
|