On 11/14/23 12:38, Jakub Jelinek wrote:
> On Mon, Nov 13, 2023 at 10:59:52PM -0500, Jason Merrill wrote:
>> On 11/13/23 06:50, Jakub Jelinek wrote:
>>> The following patch implements C++26 P2864R2 by emitting pedwarn enabled by
>>> the same options as the C++20 and later warnings (i.e. -Wenum-compare,
>>> -Wdeprecated-enum-enum-conversion and -Wdeprecated-enum-float-conversion
>>> which are all enabled by default). I think we still want to allow users
>>> some option workaround, so am not using directly error, but if that is
>>> what you want instead, I can change it.
>>
>> I agree, but we also need to return error_mark_node for these cases when
>> SFINAE, i.e. !(complain & tf_warning_or_error)
>
> So like this then?
>
> Bootstrapped/regtested on x86_64-linux and i686-linux.
>
> 2023-11-14 Jakub Jelinek <jakub@redhat.com>
>
> gcc/cp/
> * typeck.cc: Implement C++26 P2864R2 - Remove Deprecated Arithmetic
> Conversion on Enumerations From C++26.
> (do_warn_enum_conversions): Return bool rather than void, add COMPLAIN
> argument. Use pedwarn rather than warning_at for C++26 and remove
> " is deprecated" part of the diagnostics in that case. For SFINAE
> in C++26 return true on newly erroneous cases.
> (cp_build_binary_op): For C++26 call do_warn_enum_conversions
> unconditionally, pass complain argument to it and if it returns true,
> return error_mark_node.
> * call.cc (build_conditional_expr): Use pedwarn rather than warning_at
> for C++26 and remove " is deprecated" part of the diagnostics in that
> case and check for complain & tf_warning_or_error. Use emit_diagnostic
> with cxx_dialect >= cxx26 ? DK_PEDWARN : DK_WARNING. For SFINAE in
> C++26 return error_mark_node on newly erroneous cases.
> (build_new_op): Use emit_diagnostic with cxx_dialect >= cxx26
> ? DK_PEDWARN : DK_WARNING and complain & tf_warning_or_error check
> for C++26. For SFINAE in C++26 return error_mark_node on newly
> erroneous cases.
> gcc/testsuite/
> * g++.dg/cpp26/enum-conv1.C: New test.
> * g++.dg/cpp2a/enum-conv1.C: Adjust expected diagnostics in C++26.
> * g++.dg/diagnostic/enum3.C: Likewise.
> * g++.dg/parse/attr3.C: Likewise.
> * g++.dg/cpp0x/linkage2.C: Likewise.
>
> --- gcc/cp/typeck.cc.jj 2023-11-13 13:02:21.573785549 +0100
> +++ gcc/cp/typeck.cc 2023-11-14 09:49:31.026997048 +0100
> @@ -4940,16 +4940,25 @@ warn_for_null_address (location_t locati
> 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.
> + For C++26 this is ill-formed rather than deprecated.
> + Return true for SFINAE errors.
> TODO: Consider combining this with -Wenum-compare in build_new_op_1. */
>
> -static void
> +static bool
> do_warn_enum_conversions (location_t loc, enum tree_code code, tree type0,
> - tree type1)
> + tree type1, tsubst_flags_t complain)
> {
> if (TREE_CODE (type0) == ENUMERAL_TYPE
> && TREE_CODE (type1) == ENUMERAL_TYPE
> && TYPE_MAIN_VARIANT (type0) != TYPE_MAIN_VARIANT (type1))
> {
> + if (cxx_dialect >= cxx26)
> + {
> + if ((complain & tf_warning_or_error) == 0)
> + return true;
> + }
> + else if ((complain & tf_warning) == 0)
> + return false;
> /* In C++20, -Wdeprecated-enum-enum-conversion is on by default.
> Otherwise, warn if -Wenum-conversion is on. */
> enum opt_code opt;
> @@ -4958,7 +4967,7 @@ do_warn_enum_conversions (location_t loc
> else if (warn_enum_conversion)
> opt = OPT_Wenum_conversion;
> else
> - return;
> + return false;
>
> switch (code)
> {
> @@ -4969,21 +4978,29 @@ do_warn_enum_conversions (location_t loc
> case EQ_EXPR:
> case NE_EXPR:
> /* Comparisons are handled by -Wenum-compare. */
> - return;
> + return false;
> case SPACESHIP_EXPR:
> /* This is invalid, don't warn. */
> - return;
> + return false;
> 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;
> + if (cxx_dialect >= cxx26)
> + pedwarn (loc, opt, "bitwise operation between different "
> + "enumeration types %qT and %qT", type0, type1);
> + else
> + warning_at (loc, opt, "bitwise operation between different "
> + "enumeration types %qT and %qT is deprecated",
> + type0, type1);
> + return false;
> default:
> - warning_at (loc, opt, "arithmetic between different enumeration "
> - "types %qT and %qT is deprecated", type0, type1);
> - return;
> + if (cxx_dialect >= cxx26)
> + pedwarn (loc, opt, "arithmetic between different enumeration "
> + "types %qT and %qT", type0, type1);
> + else
> + warning_at (loc, opt, "arithmetic between different enumeration "
> + "types %qT and %qT is deprecated", type0, type1);
> + return false;
> }
> }
> else if ((TREE_CODE (type0) == ENUMERAL_TYPE
> @@ -4991,6 +5008,13 @@ do_warn_enum_conversions (location_t loc
> || (SCALAR_FLOAT_TYPE_P (type0)
> && TREE_CODE (type1) == ENUMERAL_TYPE))
> {
> + if (cxx_dialect >= cxx26)
> + {
> + if ((complain & tf_warning_or_error) == 0)
> + return true;
> + }
> + else if ((complain & tf_warning) == 0)
> + return false;
> 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. */
> @@ -5000,7 +5024,7 @@ do_warn_enum_conversions (location_t loc
> else if (warn_enum_conversion)
> opt = OPT_Wenum_conversion;
> else
> - return;
> + return false;
>
> switch (code)
> {
> @@ -5010,7 +5034,13 @@ do_warn_enum_conversions (location_t loc
> case LE_EXPR:
> case EQ_EXPR:
> case NE_EXPR:
> - if (enum_first_p)
> + if (enum_first_p && cxx_dialect >= cxx26)
> + pedwarn (loc, opt, "comparison of enumeration type %qT with "
> + "floating-point type %qT", type0, type1);
> + else if (cxx_dialect >= cxx26)
> + pedwarn (loc, opt, "comparison of floating-point type %qT "
> + "with enumeration type %qT", type0, type1);
> + else if (enum_first_p)
> warning_at (loc, opt, "comparison of enumeration type %qT with "
> "floating-point type %qT is deprecated",
> type0, type1);
> @@ -5018,12 +5048,18 @@ do_warn_enum_conversions (location_t loc
> warning_at (loc, opt, "comparison of floating-point type %qT "
> "with enumeration type %qT is deprecated",
> type0, type1);
> - return;
> + return false;
> case SPACESHIP_EXPR:
> /* This is invalid, don't warn. */
> - return;
> + return false;
> default:
> - if (enum_first_p)
> + if (enum_first_p && cxx_dialect >= cxx26)
> + pedwarn (loc, opt, "arithmetic between enumeration type %qT "
> + "and floating-point type %qT", type0, type1);
> + else if (cxx_dialect >= cxx26)
> + pedwarn (loc, opt, "arithmetic between floating-point type %qT "
> + "and enumeration type %qT", type0, type1);
> + else if (enum_first_p)
> warning_at (loc, opt, "arithmetic between enumeration type %qT "
> "and floating-point type %qT is deprecated",
> type0, type1);
> @@ -5031,9 +5067,10 @@ do_warn_enum_conversions (location_t loc
> warning_at (loc, opt, "arithmetic between floating-point type %qT "
> "and enumeration type %qT is deprecated",
> type0, type1);
> - return;
> + return true;
Shouldn't this be return false?
OK with that change.
Jason
@@ -4940,16 +4940,25 @@ warn_for_null_address (location_t locati
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.
+ For C++26 this is ill-formed rather than deprecated.
+ Return true for SFINAE errors.
TODO: Consider combining this with -Wenum-compare in build_new_op_1. */
-static void
+static bool
do_warn_enum_conversions (location_t loc, enum tree_code code, tree type0,
- tree type1)
+ tree type1, tsubst_flags_t complain)
{
if (TREE_CODE (type0) == ENUMERAL_TYPE
&& TREE_CODE (type1) == ENUMERAL_TYPE
&& TYPE_MAIN_VARIANT (type0) != TYPE_MAIN_VARIANT (type1))
{
+ if (cxx_dialect >= cxx26)
+ {
+ if ((complain & tf_warning_or_error) == 0)
+ return true;
+ }
+ else if ((complain & tf_warning) == 0)
+ return false;
/* In C++20, -Wdeprecated-enum-enum-conversion is on by default.
Otherwise, warn if -Wenum-conversion is on. */
enum opt_code opt;
@@ -4958,7 +4967,7 @@ do_warn_enum_conversions (location_t loc
else if (warn_enum_conversion)
opt = OPT_Wenum_conversion;
else
- return;
+ return false;
switch (code)
{
@@ -4969,21 +4978,29 @@ do_warn_enum_conversions (location_t loc
case EQ_EXPR:
case NE_EXPR:
/* Comparisons are handled by -Wenum-compare. */
- return;
+ return false;
case SPACESHIP_EXPR:
/* This is invalid, don't warn. */
- return;
+ return false;
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;
+ if (cxx_dialect >= cxx26)
+ pedwarn (loc, opt, "bitwise operation between different "
+ "enumeration types %qT and %qT", type0, type1);
+ else
+ warning_at (loc, opt, "bitwise operation between different "
+ "enumeration types %qT and %qT is deprecated",
+ type0, type1);
+ return false;
default:
- warning_at (loc, opt, "arithmetic between different enumeration "
- "types %qT and %qT is deprecated", type0, type1);
- return;
+ if (cxx_dialect >= cxx26)
+ pedwarn (loc, opt, "arithmetic between different enumeration "
+ "types %qT and %qT", type0, type1);
+ else
+ warning_at (loc, opt, "arithmetic between different enumeration "
+ "types %qT and %qT is deprecated", type0, type1);
+ return false;
}
}
else if ((TREE_CODE (type0) == ENUMERAL_TYPE
@@ -4991,6 +5008,13 @@ do_warn_enum_conversions (location_t loc
|| (SCALAR_FLOAT_TYPE_P (type0)
&& TREE_CODE (type1) == ENUMERAL_TYPE))
{
+ if (cxx_dialect >= cxx26)
+ {
+ if ((complain & tf_warning_or_error) == 0)
+ return true;
+ }
+ else if ((complain & tf_warning) == 0)
+ return false;
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. */
@@ -5000,7 +5024,7 @@ do_warn_enum_conversions (location_t loc
else if (warn_enum_conversion)
opt = OPT_Wenum_conversion;
else
- return;
+ return false;
switch (code)
{
@@ -5010,7 +5034,13 @@ do_warn_enum_conversions (location_t loc
case LE_EXPR:
case EQ_EXPR:
case NE_EXPR:
- if (enum_first_p)
+ if (enum_first_p && cxx_dialect >= cxx26)
+ pedwarn (loc, opt, "comparison of enumeration type %qT with "
+ "floating-point type %qT", type0, type1);
+ else if (cxx_dialect >= cxx26)
+ pedwarn (loc, opt, "comparison of floating-point type %qT "
+ "with enumeration type %qT", type0, type1);
+ else if (enum_first_p)
warning_at (loc, opt, "comparison of enumeration type %qT with "
"floating-point type %qT is deprecated",
type0, type1);
@@ -5018,12 +5048,18 @@ do_warn_enum_conversions (location_t loc
warning_at (loc, opt, "comparison of floating-point type %qT "
"with enumeration type %qT is deprecated",
type0, type1);
- return;
+ return false;
case SPACESHIP_EXPR:
/* This is invalid, don't warn. */
- return;
+ return false;
default:
- if (enum_first_p)
+ if (enum_first_p && cxx_dialect >= cxx26)
+ pedwarn (loc, opt, "arithmetic between enumeration type %qT "
+ "and floating-point type %qT", type0, type1);
+ else if (cxx_dialect >= cxx26)
+ pedwarn (loc, opt, "arithmetic between floating-point type %qT "
+ "and enumeration type %qT", type0, type1);
+ else if (enum_first_p)
warning_at (loc, opt, "arithmetic between enumeration type %qT "
"and floating-point type %qT is deprecated",
type0, type1);
@@ -5031,9 +5067,10 @@ do_warn_enum_conversions (location_t loc
warning_at (loc, opt, "arithmetic between floating-point type %qT "
"and enumeration type %qT is deprecated",
type0, type1);
- return;
+ return true;
}
}
+ return false;
}
/* Build a binary-operation expression without default conversions.
@@ -6163,15 +6200,13 @@ cp_build_binary_op (const op_location_t
return error_mark_node;
}
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_enum_conversions (location, code, TREE_TYPE (orig_op0),
- TREE_TYPE (orig_op1));
- }
+ do_warn_double_promotion (result_type, type0, type1,
+ "implicit conversion from %qH to %qI "
+ "to match other operand of binary "
+ "expression", location);
+ if (do_warn_enum_conversions (location, code, TREE_TYPE (orig_op0),
+ TREE_TYPE (orig_op1), complain))
+ return error_mark_node;
}
if (may_need_excess_precision
&& (orig_type0 != type0 || orig_type1 != type1)
@@ -6163,19 +6163,36 @@ build_conditional_expr (const op_locatio
== DECL_CONTEXT (stripped_orig_arg3)))
/* Two enumerators from the same enumeration can have different
types when the enumeration is still being defined. */;
- else if (complain & tf_warning)
- warning_at (loc, OPT_Wenum_compare, "enumerated mismatch "
- "in conditional expression: %qT vs %qT",
- arg2_type, arg3_type);
+ else if (complain & (cxx_dialect >= cxx26
+ ? tf_warning_or_error : tf_warning))
+ emit_diagnostic (cxx_dialect >= cxx26 ? DK_PEDWARN : DK_WARNING,
+ loc, OPT_Wenum_compare, "enumerated mismatch "
+ "in conditional expression: %qT vs %qT",
+ arg2_type, arg3_type);
+ else if (cxx_dialect >= cxx26)
+ return error_mark_node;
}
- else if ((complain & tf_warning)
- && warn_deprecated_enum_float_conv
+ else if ((((complain & (cxx_dialect >= cxx26
+ ? tf_warning_or_error : tf_warning))
+ && warn_deprecated_enum_float_conv)
+ || (cxx_dialect >= cxx26
+ && (complain & tf_warning_or_error) == 0))
&& ((TREE_CODE (arg2_type) == ENUMERAL_TYPE
&& SCALAR_FLOAT_TYPE_P (arg3_type))
|| (SCALAR_FLOAT_TYPE_P (arg2_type)
&& TREE_CODE (arg3_type) == ENUMERAL_TYPE)))
{
- if (TREE_CODE (arg2_type) == ENUMERAL_TYPE)
+ if (cxx_dialect >= cxx26 && (complain & tf_warning_or_error) == 0)
+ return error_mark_node;
+ if (cxx_dialect >= cxx26 && TREE_CODE (arg2_type) == ENUMERAL_TYPE)
+ pedwarn (loc, OPT_Wdeprecated_enum_float_conversion,
+ "conditional expression between enumeration type "
+ "%qT and floating-point type %qT", arg2_type, arg3_type);
+ else if (cxx_dialect >= cxx26)
+ pedwarn (loc, OPT_Wdeprecated_enum_float_conversion,
+ "conditional expression between floating-point type "
+ "%qT and enumeration type %qT", arg2_type, arg3_type);
+ else 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",
@@ -7258,11 +7275,18 @@ build_new_op (const op_location_t &loc,
if (TREE_CODE (arg1_type) == ENUMERAL_TYPE
&& TREE_CODE (arg2_type) == ENUMERAL_TYPE
&& (TYPE_MAIN_VARIANT (arg1_type)
- != TYPE_MAIN_VARIANT (arg2_type))
- && (complain & tf_warning))
- warning_at (loc, OPT_Wenum_compare,
- "comparison between %q#T and %q#T",
- arg1_type, arg2_type);
+ != TYPE_MAIN_VARIANT (arg2_type)))
+ {
+ if (cxx_dialect >= cxx26
+ && (complain & tf_warning_or_error) == 0)
+ result = error_mark_node;
+ else if (cxx_dialect >= cxx26 || (complain & tf_warning))
+ emit_diagnostic (cxx_dialect >= cxx26
+ ? DK_PEDWARN : DK_WARNING,
+ loc, OPT_Wenum_compare,
+ "comparison between %q#T and %q#T",
+ arg1_type, arg2_type);
+ }
break;
default:
break;
@@ -5,5 +5,6 @@ enum e1 { e1val };
enum e2 { e3val };
int main( int, char * [] ) {
- if ( e1val == e3val ) return 1; // { dg-warning -Wenum-compare }
+ if ( e1val == e3val ) return 1; // { dg-warning "comparison between 'enum e1' and 'enum e2'" "" { target c++23_down } }
+ // { dg-error "comparison between 'enum e1' and 'enum e2'" "" { target c++26 } .-1 }
}
@@ -0,0 +1,39 @@
+// P2864R2 - Remove Deprecated Arithmetic Conversion on Enumerations From C++26
+// { dg-do compile { target c++20 } }
+
+enum A { a };
+enum B { b };
+
+template <auto X, auto Y> decltype (true ? X : Y) f1 () { throw 1; }
+// { dg-error "enumerated mismatch in conditional expression: 'A' vs 'B'" "" { target c++26 } .-1 }
+// { dg-error "conditional expression between enumeration type 'A' and floating-point type 'double'" "" { target c++26 } .-2 }
+// { dg-error "conditional expression between floating-point type 'double' and enumeration type 'A'" "" { target c++26 } .-3 }
+template <auto X, auto Y> decltype (X + Y) f2 () { throw 1; }
+// { dg-error "arithmetic between different enumeration types 'A' and 'B'" "" { target c++26 } .-1 }
+// { dg-error "arithmetic between enumeration type 'A' and floating-point type 'double'" "" { target c++26 } .-2 }
+// { dg-error "arithmetic between floating-point type 'double' and enumeration type 'A'" "" { target c++26 } .-3 }
+template <auto X, auto Y> decltype (X | Y) f3 () { throw 1; }
+// { dg-error "bitwise operation between different enumeration types 'A' and 'B'" "" { target c++26 } .-1 }
+template <auto X, auto Y> decltype (X < Y) f4 () { throw 1; }
+// { dg-error "comparison between 'enum A' and 'enum B'" "" { target c++26 } .-1 }
+// { dg-error "comparison of enumeration type 'A' with floating-point type 'double'" "" { target c++26 } .-2 }
+// { dg-error "comparison of floating-point type 'double' with enumeration type 'A'" "" { target c++26 } .-3 }
+
+int
+main ()
+{
+ f1<a, a> ();
+ f2<a, a> ();
+ f3<b, b> ();
+ f4<b, b> ();
+ f1<a, b> (); // { dg-error "no matching function for call to" "" { target c++26 } }
+ f2<a, b> (); // { dg-error "no matching function for call to" "" { target c++26 } }
+ f3<a, b> (); // { dg-error "no matching function for call to" "" { target c++26 } }
+ f4<a, b> (); // { dg-error "no matching function for call to" "" { target c++26 } }
+ f1<a, 0.0> (); // { dg-error "no matching function for call to" "" { target c++26 } }
+ f2<a, 0.0> (); // { dg-error "no matching function for call to" "" { target c++26 } }
+ f4<a, 0.0> (); // { dg-error "no matching function for call to" "" { target c++26 } }
+ f1<0.0, a> (); // { dg-error "no matching function for call to" "" { target c++26 } }
+ f2<0.0, a> (); // { dg-error "no matching function for call to" "" { target c++26 } }
+ f4<0.0, a> (); // { dg-error "no matching function for call to" "" { target c++26 } }
+}
@@ -10,5 +10,6 @@ int main () {
S::F y; // { dg-warning "'F' is deprecated" }
y = S::f;
- return x + y; // { dg-warning "arithmetic between different enumeration types" "" { target c++20 } }
+ return x + y; // { dg-warning "arithmetic between different enumeration types" "" { target { c++20 && c++23_down } } }
+ // { dg-error "arithmetic between different enumeration types" "" { target c++26 } .-1 }
}
@@ -14,11 +14,16 @@ 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 } }
+ bool b2 = e == f; // { dg-warning "comparison between .enum E1. and .enum E2." "" { target c++23_down } }
+ // { dg-error "comparison between .enum E1. and .enum E2." "" { target c++26 } .-1 }
+ bool b3 = e == 0.0; // { dg-warning "comparison of enumeration type .E1. with floating-point type .double." "" { target { c++20 && c++23_down } } }
+ // { dg-error "comparison of enumeration type .E1. with floating-point type .double." "" { target c++26 } .-1 }
+ bool b4 = 0.0 == f; // { dg-warning "comparison of floating-point type .double. with enumeration type .E2." "" { target { c++20 && c++23_down } } }
+ // { dg-error "comparison of floating-point type .double. with enumeration type .E2." "" { target c++26 } .-1 }
+ int n1 = true ? e : f; // { dg-warning "enumerated mismatch" "" { target c++23_down } }
+ // { dg-error "enumerated mismatch" "" { target c++26 } .-1 }
+ int n2 = true ? e : 0.0; // { dg-warning "conditional expression between" "" { target { c++20 && c++23_down } } }
+ // { dg-error "conditional expression between" "" { target c++26 } .-1 }
}
int
@@ -29,42 +34,60 @@ enum_enum (bool b)
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 += e - f; // { dg-warning "arithmetic between different enumeration types .E1. and .E2." "" { target { c++20 && c++23_down } } }
+ // { dg-error "arithmetic between different enumeration types .E1. and .E2." "" { target c++26 } .-1 }
+ r += f - e; // { dg-warning "arithmetic between different enumeration types .E2. and .E1." "" { target { c++20 && c++23_down } } }
+ // { dg-error "arithmetic between different enumeration types .E2. and .E1." "" { target c++26 } .-1 }
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 += f + e; // { dg-warning "arithmetic between different enumeration types .E2. and .E1." "" { target { c++20 && c++23_down } } }
+ // { dg-error "arithmetic between different enumeration types .E2. and .E1." "" { target c++26 } .-1 }
+ r += e + f; // { dg-warning "arithmetic between different enumeration types .E1. and .E2." "" { target { c++20 && c++23_down } } }
+ // { dg-error "arithmetic between different enumeration types .E1. and .E2." "" { target c++26 } .-1 }
- r += e1 - e2; // { 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 && c++23_down } } }
+ // { dg-error "arithmetic between different enumeration types .E1. and .E2." "" { target c++26 } .-1 }
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 * f; // { dg-warning "arithmetic between different enumeration types .E1. and .E2." "" { target { c++20 && c++23_down } } }
+ // { dg-error "arithmetic between different enumeration types .E1. and .E2." "" { target c++26 } .-1 }
+ r += f * e; // { dg-warning "arithmetic between different enumeration types .E2. and .E1." "" { target { c++20 && c++23_down } } }
+ // { dg-error "arithmetic between different enumeration types .E2. and .E1." "" { target c++26 } .-1 }
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 < e2; // { dg-warning "comparison between .enum E1. and .enum E2." "" { target c++23_down } }
+ // { dg-error "comparison between .enum E1. and .enum E2." "" { target c++26 } .-1 }
+ r += e < f; // { dg-warning "comparison between .enum E1. and .enum E2." "" { target c++23_down } }
+ // { dg-error "comparison between .enum E1. and .enum E2." "" { target c++26 } .-1 }
+ r += f < e; // { dg-warning "comparison between .enum E2. and .enum E1." "" { target c++23_down } }
+ // { dg-error "comparison between .enum E2. and .enum E1." "" { target c++26 } .-1 }
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 += e == f; // { dg-warning "comparison between .enum E1. and .enum E2." "" { target c++23_down } }
+ // { dg-error "comparison between .enum E1. and .enum E2." "" { target c++26 } .-1 }
+ r += f == e; // { dg-warning "comparison between .enum E2. and .enum E1." "" { target c++23_down } }
+ // { dg-error "comparison between .enum E2. and .enum E1." "" { target c++26 } .-1 }
+ r += e1 == e2; // { dg-warning "comparison between .enum E1. and .enum E2." "" { target c++23_down } }
+ // { dg-error "comparison between .enum E1. and .enum E2." "" { target c++26 } .-1 }
+ r += e2 == e1; // { dg-warning "comparison between .enum E2. and .enum E1." "" { target c++23_down } }
+ // { dg-error "comparison between .enum E2. and .enum E1." "" { target c++26 } .-1 }
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 += b ? f : e; // { dg-warning "enumerated mismatch in conditional expression: .E2. vs .E1." "" { target c++23_down } }
+ // { dg-error "enumerated mismatch in conditional expression: .E2. vs .E1." "" { target c++26 } .-1 }
+ r += b ? e1 : e2; // { dg-warning "enumerated mismatch in conditional expression: .E1. vs .E2." "" { target c++23_down } }
+ // { dg-error "enumerated mismatch in conditional expression: .E1. vs .E2." "" { target c++26 } .-1 }
+
+ r += e | f; // { dg-warning "bitwise operation between different enumeration types .E1. and .E2." "" { target { c++20 && c++23_down } } }
+ // { dg-error "bitwise operation between different enumeration types .E1. and .E2." "" { target c++26 } .-1 }
+ r += e ^ f; // { dg-warning "bitwise operation between different enumeration types .E1. and .E2." "" { target { c++20 && c++23_down } } }
+ // { dg-error "bitwise operation between different enumeration types .E1. and .E2." "" { target c++26 } .-1 }
+ r += e & f; // { dg-warning "bitwise operation between different enumeration types .E1. and .E2." "" { target { c++20 && c++23_down } } }
+ // { dg-error "bitwise operation between different enumeration types .E1. and .E2." "" { target c++26 } .-1 }
r += !e;
r += e1 | e;
@@ -76,10 +99,14 @@ enum_enum (bool b)
// 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 } }
+ r += u1 + u2; // { dg-warning "arithmetic between different enumeration types" "" { target { c++20 && c++23_down } } }
+ // { dg-error "arithmetic between different enumeration types" "" { target c++26 } .-1 }
+ r += u1 * u2; // { dg-warning "arithmetic between different enumeration types" "" { target { c++20 && c++23_down } } }
+ // { dg-error "arithmetic between different enumeration types" "" { target c++26 } .-1 }
+ r += u1 == u2; // { dg-warning "comparison between" "" { target c++23_down } }
+ // { dg-error "comparison between" "" { target c++26 } .-1 }
+ r += u1 & u2; // { dg-warning "bitwise operation between different enumeration types" "" { target { c++20 && c++23_down } } }
+ // { dg-error "bitwise operation between different enumeration types" "" { target c++26 } .-1 }
return r;
}
@@ -89,28 +116,47 @@ 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 } }
+ r += e1 - d; // { dg-warning "arithmetic between enumeration type .E1. and floating-point type .double." "" { target { c++20 && c++23_down } } }
+ // { dg-error "arithmetic between enumeration type .E1. and floating-point type .double." "" { target c++26 } .-1 }
+ r += d - e1; // { dg-warning "arithmetic between floating-point type .double. and enumeration type .E1." "" { target { c++20 && c++23_down } } }
+ // { dg-error "arithmetic between floating-point type .double. and enumeration type .E1." "" { target c++26 } .-1 }
+ r += e1 + d; // { dg-warning "arithmetic between enumeration type .E1. and floating-point type .double." "" { target { c++20 && c++23_down } } }
+ // { dg-error "arithmetic between enumeration type .E1. and floating-point type .double." "" { target c++26 } .-1 }
+ r += d + e1; // { dg-warning "arithmetic between floating-point type .double. and enumeration type .E1." "" { target { c++20 && c++23_down } } }
+ // { dg-error "arithmetic between floating-point type .double. and enumeration type .E1." "" { target c++26 } .-1 }
+ r += e1 * d; // { dg-warning "arithmetic between enumeration type .E1. and floating-point type .double." "" { target { c++20 && c++23_down } } }
+ // { dg-error "arithmetic between enumeration type .E1. and floating-point type .double." "" { target c++26 } .-1 }
+ r += d * e1; // { dg-warning "arithmetic between floating-point type .double. and enumeration type .E1." "" { target { c++20 && c++23_down } } }
+ // { dg-error "arithmetic between floating-point type .double. and enumeration type .E1." "" { target c++26 } .-1 }
+ r += u1 * d; // { dg-warning "arithmetic between enumeration type" "" { target { c++20 && c++23_down } } }
+ // { dg-error "arithmetic between enumeration type" "" { target c++26 } .-1 }
+ r += d * u1; // { dg-warning "arithmetic between floating-point type" "" { target { c++20 && c++23_down } } }
+ // { dg-error "arithmetic between floating-point type" "" { target c++26 } .-1 }
+
+ r += e1 < d; // { dg-warning "comparison of enumeration type .E1. with floating-point type .double." "" { target { c++20 && c++23_down } } }
+ // { dg-error "comparison of enumeration type .E1. with floating-point type .double." "" { target c++26 } .-1 }
+ r += d < e1; // { dg-warning "comparison of floating-point type .double. with enumeration type .E1." "" { target { c++20 && c++23_down } } }
+ // { dg-error "comparison of floating-point type .double. with enumeration type .E1." "" { target c++26 } .-1 }
+ r += d == e1; // { dg-warning "comparison of floating-point type .double. with enumeration type .E1." "" { target { c++20 && c++23_down } } }
+ // { dg-error "comparison of floating-point type .double. with enumeration type .E1." "" { target c++26 } .-1 }
+ r += e1 == d; // { dg-warning "comparison of enumeration type .E1. with floating-point type .double." "" { target { c++20 && c++23_down } } }
+ // { dg-error "comparison of enumeration type .E1. with floating-point type .double." "" { target c++26 } .-1 }
+ r += u1 == d; // { dg-warning "comparison of enumeration type" "" { target { c++20 && c++23_down } } }
+ // { dg-error "comparison of enumeration type" "" { target c++26 } .-1 }
+ r += d == u1; // { dg-warning "comparison of floating-point type" "" { target { c++20 && c++23_down } } }
+ // { dg-error "comparison of floating-point type" "" { target c++26 } .-1 }
+
+ r += b ? e1 : d; // { dg-warning "conditional expression between enumeration type .E1. and floating-point type .double." "" { target { c++20 && c++23_down } } }
+ // { dg-error "conditional expression between enumeration type .E1. and floating-point type .double." "" { target c++26 } .-1 }
+ r += b ? d : e1; // { dg-warning "conditional expression between floating-point type .double. and enumeration type .E1." "" { target { c++20 && c++23_down } } }
+ // { dg-error "conditional expression between floating-point type .double. and enumeration type .E1." "" { target c++26 } .-1 }
+ r += b ? d : u1; // { dg-warning "conditional expression between" "" { target { c++20 && c++23_down } } }
+ // { dg-error "conditional expression between" "" { target c++26 } .-1 }
+ r += b ? u1 : d; // { dg-warning "conditional expression between" "" { target { c++20 && c++23_down } } }
+ // { dg-error "conditional expression between" "" { target c++26 } .-1 }
- d += e1; // { dg-warning "arithmetic between floating-point type .double. and enumeration type .E1." "" { target c++20 } }
+ d += e1; // { dg-warning "arithmetic between floating-point type .double. and enumeration type .E1." "" { target { c++20 && c++23_down } } }
+ // { dg-error "arithmetic between floating-point type .double. and enumeration type .E1." "" { target c++26 } .-1 }
d = e1;
return r;
@@ -29,5 +29,6 @@ void f() {
ba.g(a); // OK
ba.h(a); // error, B<T>::h never defined
i(ba, a); // OK
- e1+e2+e3; // { dg-warning "arithmetic between different enumeration types" "" { target c++20 } }
+ e1+e2+e3; // { dg-warning "arithmetic between different enumeration types" "" { target { c++20 && c++23_down } } }
+ // { dg-error "arithmetic between different enumeration types" "" { target c++26 } .-1 }
}