On Wed, Oct 28, 2020 at 02:43:30PM -0400, Jason Merrill wrote: > On 10/28/20 2:01 PM, Marek Polacek wrote: > > 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. > > Hmm, oops. Will you fix that as well? It should be simple to fix in the > SPACESHIP_EXPR block that starts just at the end of this patch.
Sure. Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? >From 8ae2e45f2dd35510aed3be1ab249b8612e33f00d Mon Sep 17 00:00:00 2001 From: Marek Polacek <pola...@redhat.com> Date: Wed, 28 Oct 2020 19:02:29 -0400 Subject: [PATCH] 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. --- gcc/cp/typeck.c | 13 ++++++++++-- gcc/testsuite/g++.dg/cpp2a/enum-conv1.C | 3 --- gcc/testsuite/g++.dg/cpp2a/spaceship-err5.C | 23 +++++++++++++++++++++ 3 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/spaceship-err5.C 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 <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." } +} base-commit: 4166ebedf8b8a302b86132fdf846fac204c83368 -- 2.28.0