On 10/28/20 10:46 PM, Marek Polacek wrote:
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?
OK, thanks.
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