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:
Marek Polacek 2020-10-28 19:02:29 -04:00
parent e1344fe7b6
commit 79991e2348
3 changed files with 34 additions and 5 deletions

View File

@ -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;

View File

@ -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;

View File

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