diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 7305310ecbe..d3b701610cf 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -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; diff --git a/gcc/testsuite/g++.dg/cpp2a/enum-conv1.C b/gcc/testsuite/g++.dg/cpp2a/enum-conv1.C index d4960f334dd..4571b5e8968 100644 --- a/gcc/testsuite/g++.dg/cpp2a/enum-conv1.C +++ b/gcc/testsuite/g++.dg/cpp2a/enum-conv1.C @@ -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; diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-err5.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-err5.C new file mode 100644 index 00000000000..3dc2a0f2365 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-err5.C @@ -0,0 +1,23 @@ +// { dg-do compile { target c++20 } } +// Test [depr.arith.conv.enum] for <=>. + +#include + +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." } +}