c++: Reject float <=> enum.
As [depr.arith.conv.enum] says, these are ill-formed. gcc/cp/ChangeLog: * typeck.c (do_warn_enum_conversions): Don't warn for SPACESHIP_EXPR. (cp_build_binary_op): Reject float <=> enum or enum <=> float. Use CP_INTEGRAL_TYPE_P instead of INTEGRAL_OR_ENUMERATION_TYPE_P. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/enum-conv1.C: Remove unused code. * g++.dg/cpp2a/spaceship-err5.C: New test.
This commit is contained in:
parent
e1344fe7b6
commit
79991e2348
|
@ -4512,6 +4512,9 @@ do_warn_enum_conversions (location_t loc, enum tree_code code, tree type0,
|
|||
"with enumeration type %qT is deprecated",
|
||||
type0, type1);
|
||||
return;
|
||||
case SPACESHIP_EXPR:
|
||||
/* This is invalid, don't warn. */
|
||||
return;
|
||||
default:
|
||||
if (enum_first_p)
|
||||
warning_at (loc, opt, "arithmetic between enumeration type %qT "
|
||||
|
@ -5584,6 +5587,12 @@ cp_build_binary_op (const op_location_t &location,
|
|||
arithmetic conversions are applied to the operands." So we don't do
|
||||
arithmetic conversions if the operands both have enumeral type. */
|
||||
result_type = NULL_TREE;
|
||||
else if ((orig_code0 == ENUMERAL_TYPE && orig_code1 == REAL_TYPE)
|
||||
|| (orig_code0 == REAL_TYPE && orig_code1 == ENUMERAL_TYPE))
|
||||
/* [depr.arith.conv.enum]: Three-way comparisons between such operands
|
||||
[where one is of enumeration type and the other is of a different
|
||||
enumeration type or a floating-point type] are ill-formed. */
|
||||
result_type = NULL_TREE;
|
||||
|
||||
if (result_type)
|
||||
{
|
||||
|
@ -5598,12 +5607,12 @@ cp_build_binary_op (const op_location_t &location,
|
|||
type to a floating point type, the program is ill-formed. */
|
||||
bool ok = true;
|
||||
if (TREE_CODE (result_type) == REAL_TYPE
|
||||
&& INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (orig_op0)))
|
||||
&& CP_INTEGRAL_TYPE_P (orig_type0))
|
||||
/* OK */;
|
||||
else if (!check_narrowing (result_type, orig_op0, complain))
|
||||
ok = false;
|
||||
if (TREE_CODE (result_type) == REAL_TYPE
|
||||
&& INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (orig_op1)))
|
||||
&& CP_INTEGRAL_TYPE_P (orig_type1))
|
||||
/* OK */;
|
||||
else if (!check_narrowing (result_type, orig_op1, complain))
|
||||
ok = false;
|
||||
|
|
|
@ -110,9 +110,6 @@ enum_float (bool b)
|
|||
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;
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
// { dg-do compile { target c++20 } }
|
||||
// Test [depr.arith.conv.enum] for <=>.
|
||||
|
||||
#include <compare>
|
||||
|
||||
enum E1 { e } e1;
|
||||
enum E2 { f } e2;
|
||||
static double d;
|
||||
|
||||
void
|
||||
g ()
|
||||
{
|
||||
void(e1 <=> e);
|
||||
e1 <=> d; // { dg-error "invalid operands of types .E1. and .double." }
|
||||
d <=> e1; // { dg-error "invalid operands of types .double. and .E1." }
|
||||
e <=> d; // { dg-error "invalid operands of types .E1. and .double." }
|
||||
d <=> e; // { dg-error "invalid operands of types .double. and .E1." }
|
||||
|
||||
e <=> f; // { dg-error "invalid operands of types .E1. and .E2." }
|
||||
f <=> e; // { dg-error "invalid operands of types .E2. and .E1." }
|
||||
e1 <=> e2; // { dg-error "invalid operands of types .E1. and .E2." }
|
||||
e2 <=> e1; // { dg-error "invalid operands of types .E2. and .E1." }
|
||||
}
|
Loading…
Reference in New Issue