[gcc r15-6083] c++: P2865R5, Remove Deprecated Array Comparisons from C++26 [PR117788]
Marek Polacek
mpolacek@gcc.gnu.org
Tue Dec 10 15:17:30 GMT 2024
https://gcc.gnu.org/g:c628def52c87b40b6270618252488bcd731e1843
commit r15-6083-gc628def52c87b40b6270618252488bcd731e1843
Author: Marek Polacek <polacek@redhat.com>
Date: Wed Nov 27 18:00:24 2024 -0500
c++: P2865R5, Remove Deprecated Array Comparisons from C++26 [PR117788]
This patch implements P2865R5 by promoting the warning to permerror in
C++26 only.
In C++20 we should warn even without -Wall. Jason fixed this in r15-5713
but let's add a test that doesn't use -Wall.
This caused a FAIL in conditionally_borrowed.cc because we end up
comparing two array types in equality_comparable_with ->
__weakly_eq_cmp_with. That could be fixed in libstc++, perhaps by
adding std::decay in the appropriate place.
PR c++/117788
gcc/c-family/ChangeLog:
* c-warn.cc (do_warn_array_compare): Emit a permerror in C++26.
gcc/cp/ChangeLog:
* typeck.cc (cp_build_binary_op) <case EQ_EXPR>: Don't check
warn_array_compare. Check tf_warning_or_error instead of just
tf_warning. Maybe return an error_mark_node in C++26.
<case LE_EXPR>: Likewise.
gcc/testsuite/ChangeLog:
* c-c++-common/Warray-compare-1.c: Expect an error in C++26.
* c-c++-common/Warray-compare-3.c: Likewise.
* c-c++-common/Warray-compare-4.c: New test.
* c-c++-common/Warray-compare-5.c: New test.
* g++.dg/warn/Warray-compare-1.C: New test.
libstdc++-v3/ChangeLog:
* testsuite/std/ranges/adaptors/conditionally_borrowed.cc: Add a
FIXME, adjust.
Reviewed-by: Jason Merrill <jason@redhat.com>
Diff:
---
gcc/c-family/c-warn.cc | 25 +++++++---
gcc/cp/typeck.cc | 56 ++++++++++++----------
gcc/testsuite/c-c++-common/Warray-compare-1.c | 21 +++++---
gcc/testsuite/c-c++-common/Warray-compare-3.c | 7 +--
gcc/testsuite/c-c++-common/Warray-compare-4.c | 50 +++++++++++++++++++
gcc/testsuite/c-c++-common/Warray-compare-5.c | 44 +++++++++++++++++
gcc/testsuite/g++.dg/warn/Warray-compare-1.C | 26 ++++++++++
.../std/ranges/adaptors/conditionally_borrowed.cc | 5 +-
8 files changed, 193 insertions(+), 41 deletions(-)
diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc
index 140d97a00d8a..0b71842e48dc 100644
--- a/gcc/c-family/c-warn.cc
+++ b/gcc/c-family/c-warn.cc
@@ -3820,8 +3820,9 @@ maybe_warn_sizeof_array_div (location_t loc, tree arr, tree arr_type,
/* Warn about C++20 [depr.array.comp] array comparisons: "Equality
and relational comparisons between two operands of array type are
- deprecated." We also warn in C and earlier C++ standards. CODE is
- the code for this comparison, OP0 and OP1 are the operands. */
+ deprecated." In C++26 this is a permerror. We also warn in C and earlier
+ C++ standards. CODE is the code for this comparison, OP0 and OP1 are
+ the operands. */
void
do_warn_array_compare (location_t location, tree_code code, tree op0, tree op1)
@@ -3834,10 +3835,22 @@ do_warn_array_compare (location_t location, tree_code code, tree op0, tree op1)
op1 = TREE_OPERAND (op1, 0);
auto_diagnostic_group d;
- if (warning_at (location, OPT_Warray_compare,
- (c_dialect_cxx () && cxx_dialect >= cxx20)
- ? G_("comparison between two arrays is deprecated in C++20")
- : G_("comparison between two arrays")))
+ diagnostic_t kind = DK_WARNING;
+ const char *msg;
+ if (c_dialect_cxx () && cxx_dialect >= cxx20)
+ {
+ /* P2865R5 made this comparison ill-formed in C++26. */
+ if (cxx_dialect >= cxx26)
+ {
+ msg = G_("comparison between two arrays is not allowed in C++26");
+ kind = DK_PERMERROR;
+ }
+ else
+ msg = G_("comparison between two arrays is deprecated in C++20");
+ }
+ else
+ msg = G_("comparison between two arrays");
+ if (emit_diagnostic (kind, location, OPT_Warray_compare, msg))
{
/* C doesn't allow +arr. */
if (c_dialect_cxx ())
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index adc711327217..964e549a6122 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -5830,23 +5830,28 @@ cp_build_binary_op (const op_location_t &location,
warning_at (location, OPT_Wfloat_equal,
"comparing floating-point with %<==%> "
"or %<!=%> is unsafe");
- if (complain & tf_warning)
- {
- tree stripped_orig_op0 = tree_strip_any_location_wrapper (orig_op0);
- tree stripped_orig_op1 = tree_strip_any_location_wrapper (orig_op1);
- if ((TREE_CODE (stripped_orig_op0) == STRING_CST
- && !integer_zerop (cp_fully_fold (op1)))
- || (TREE_CODE (stripped_orig_op1) == STRING_CST
- && !integer_zerop (cp_fully_fold (op0))))
- warning_at (location, OPT_Waddress,
- "comparison with string literal results in "
- "unspecified behavior");
- else if (warn_array_compare
- && TREE_CODE (TREE_TYPE (orig_op0)) == ARRAY_TYPE
- && TREE_CODE (TREE_TYPE (orig_op1)) == ARRAY_TYPE)
- do_warn_array_compare (location, code, stripped_orig_op0,
- stripped_orig_op1);
- }
+ {
+ tree stripped_orig_op0 = tree_strip_any_location_wrapper (orig_op0);
+ tree stripped_orig_op1 = tree_strip_any_location_wrapper (orig_op1);
+ if ((complain & tf_warning_or_error)
+ && ((TREE_CODE (stripped_orig_op0) == STRING_CST
+ && !integer_zerop (cp_fully_fold (op1)))
+ || (TREE_CODE (stripped_orig_op1) == STRING_CST
+ && !integer_zerop (cp_fully_fold (op0)))))
+ warning_at (location, OPT_Waddress,
+ "comparison with string literal results in "
+ "unspecified behavior");
+ else if (TREE_CODE (TREE_TYPE (orig_op0)) == ARRAY_TYPE
+ && TREE_CODE (TREE_TYPE (orig_op1)) == ARRAY_TYPE)
+ {
+ /* P2865R5 made array comparisons ill-formed in C++26. */
+ if (complain & tf_warning_or_error)
+ do_warn_array_compare (location, code, stripped_orig_op0,
+ stripped_orig_op1);
+ else if (cxx_dialect >= cxx26)
+ return error_mark_node;
+ }
+ }
build_type = boolean_type_node;
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
@@ -6125,14 +6130,17 @@ cp_build_binary_op (const op_location_t &location,
"comparison with string literal results "
"in unspecified behavior");
}
- else if (warn_array_compare
- && TREE_CODE (TREE_TYPE (orig_op0)) == ARRAY_TYPE
+ else if (TREE_CODE (TREE_TYPE (orig_op0)) == ARRAY_TYPE
&& TREE_CODE (TREE_TYPE (orig_op1)) == ARRAY_TYPE
- && code != SPACESHIP_EXPR
- && (complain & tf_warning))
- do_warn_array_compare (location, code,
- tree_strip_any_location_wrapper (orig_op0),
- tree_strip_any_location_wrapper (orig_op1));
+ && code != SPACESHIP_EXPR)
+ {
+ if (complain & tf_warning_or_error)
+ do_warn_array_compare (location, code,
+ tree_strip_any_location_wrapper (orig_op0),
+ tree_strip_any_location_wrapper (orig_op1));
+ else if (cxx_dialect >= cxx26)
+ return error_mark_node;
+ }
if (gnu_vector_type_p (type0) && gnu_vector_type_p (type1))
{
diff --git a/gcc/testsuite/c-c++-common/Warray-compare-1.c b/gcc/testsuite/c-c++-common/Warray-compare-1.c
index 922396c0a1a0..90191ecd0565 100644
--- a/gcc/testsuite/c-c++-common/Warray-compare-1.c
+++ b/gcc/testsuite/c-c++-common/Warray-compare-1.c
@@ -14,12 +14,18 @@ int arr4[2][2];
bool
g ()
{
- bool b = arr1 == arr2; /* { dg-warning "comparison between two arrays" } */
- b &= arr1 != arr2; /* { dg-warning "comparison between two arrays" } */
- b &= arr1 > arr2; /* { dg-warning "comparison between two arrays" } */
- b &= arr1 >= arr2; /* { dg-warning "comparison between two arrays" } */
- b &= arr1 < arr2; /* { dg-warning "comparison between two arrays" } */
- b &= arr1 <= arr2; /* { dg-warning "comparison between two arrays" } */
+ bool b = arr1 == arr2; /* { dg-warning "comparison between two arrays" "" { target { c || c++23_down } } } */
+/* { dg-error "comparison between two arrays" "" { target c++26 } .-1 } */
+ b &= arr1 != arr2; /* { dg-warning "comparison between two arrays" "" { target { c || c++23_down } } } */
+/* { dg-error "comparison between two arrays" "" { target c++26 } .-1 } */
+ b &= arr1 > arr2; /* { dg-warning "comparison between two arrays" "" { target { c || c++23_down } } } */
+/* { dg-error "comparison between two arrays" "" { target c++26 } .-1 } */
+ b &= arr1 >= arr2; /* { dg-warning "comparison between two arrays" "" { target { c || c++23_down } } } */
+/* { dg-error "comparison between two arrays" "" { target c++26 } .-1 } */
+ b &= arr1 < arr2; /* { dg-warning "comparison between two arrays" "" { target { c || c++23_down } } } */
+/* { dg-error "comparison between two arrays" "" { target c++26 } .-1 } */
+ b &= arr1 <= arr2; /* { dg-warning "comparison between two arrays" "" { target { c || c++23_down } } } */
+/* { dg-error "comparison between two arrays" "" { target c++26 } .-1 } */
#ifdef __cplusplus
b &= +arr1 == +arr2;
b &= +arr1 != +arr2;
@@ -35,7 +41,8 @@ g ()
b &= &arr1[0] < &arr2[0];
b &= &arr1[0] <= &arr2[0];
- b &= arr3 == arr4; /* { dg-warning "comparison between two arrays" } */
+ b &= arr3 == arr4; /* { dg-warning "comparison between two arrays" "" { target { c || c++23_down } } } */
+/* { dg-error "comparison between two arrays" "" { target c++26 } .-1 } */
#if defined(__cplusplus) && __cplusplus > 201703L
auto cmp = arr1 <=> arr2; /* { dg-error "invalid operands" "" { target c++20 } } */
diff --git a/gcc/testsuite/c-c++-common/Warray-compare-3.c b/gcc/testsuite/c-c++-common/Warray-compare-3.c
index 4725aa2b38bf..afcc934010e4 100644
--- a/gcc/testsuite/c-c++-common/Warray-compare-3.c
+++ b/gcc/testsuite/c-c++-common/Warray-compare-3.c
@@ -7,7 +7,8 @@ int a[32][32], b[32][32];
int
foo (int x, int y)
{
- return (x ? a : b) == (y ? a : b); /* { dg-warning "comparison between two arrays" } */
-/* { dg-message "use '&\\\(\[^\n\r]*\\\)\\\[0\\\] == &\\\(\[^\n\r]*\\\)\\\[0\\\]' to compare the addresses" "" { target c } .-1 } */
-/* { dg-message "use unary '\\\+' which decays operands to pointers or '&\\\(\[^\n\r]*\\\)\\\[0\\\] == &\\\(\[^\n\r]*\\\)\\\[0\\\]' to compare the addresses" "" { target c++ } .-2 } */
+ return (x ? a : b) == (y ? a : b); /* { dg-warning "comparison between two arrays" "" { target { c || c++23_down } } } */
+/* { dg-error "comparison between two arrays" "" { target c++26 } .-1 } */
+/* { dg-message "use '&\\\(\[^\n\r]*\\\)\\\[0\\\] == &\\\(\[^\n\r]*\\\)\\\[0\\\]' to compare the addresses" "" { target c } .-2 } */
+/* { dg-message "use unary '\\\+' which decays operands to pointers or '&\\\(\[^\n\r]*\\\)\\\[0\\\] == &\\\(\[^\n\r]*\\\)\\\[0\\\]' to compare the addresses" "" { target c++ } .-3 } */
}
diff --git a/gcc/testsuite/c-c++-common/Warray-compare-4.c b/gcc/testsuite/c-c++-common/Warray-compare-4.c
new file mode 100644
index 000000000000..8cfb4b2ffe6a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Warray-compare-4.c
@@ -0,0 +1,50 @@
+/* PR c++/97573 */
+/* { dg-do compile } */
+
+#ifndef __cplusplus
+# define bool _Bool
+#endif
+
+int arr1[5];
+int arr2[5];
+int arr3[2][2];
+int arr4[2][2];
+
+bool
+g ()
+{
+ bool b = arr1 == arr2; /* { dg-warning "comparison between two arrays" "" { target { c++20 && c++23_down } } } */
+/* { dg-error "comparison between two arrays" "" { target c++26 } .-1 } */
+ b &= arr1 != arr2; /* { dg-warning "comparison between two arrays" "" { target { c++20 && c++23_down } } } */
+/* { dg-error "comparison between two arrays" "" { target c++26 } .-1 } */
+ b &= arr1 > arr2; /* { dg-warning "comparison between two arrays" "" { target { c++20 && c++23_down } } } */
+/* { dg-error "comparison between two arrays" "" { target c++26 } .-1 } */
+ b &= arr1 >= arr2; /* { dg-warning "comparison between two arrays" "" { target { c++20 && c++23_down } } } */
+/* { dg-error "comparison between two arrays" "" { target c++26 } .-1 } */
+ b &= arr1 < arr2; /* { dg-warning "comparison between two arrays" "" { target { c++20 && c++23_down } } } */
+/* { dg-error "comparison between two arrays" "" { target c++26 } .-1 } */
+ b &= arr1 <= arr2; /* { dg-warning "comparison between two arrays" "" { target { c++20 && c++23_down } } } */
+/* { dg-error "comparison between two arrays" "" { target c++26 } .-1 } */
+#ifdef __cplusplus
+ b &= +arr1 == +arr2;
+ b &= +arr1 != +arr2;
+ b &= +arr1 > +arr2;
+ b &= +arr1 >= +arr2;
+ b &= +arr1 < +arr2;
+ b &= +arr1 <= +arr2;
+#endif
+ b &= &arr1[0] == &arr2[0];
+ b &= &arr1[0] != &arr2[0];
+ b &= &arr1[0] > &arr2[0];
+ b &= &arr1[0] >= &arr2[0];
+ b &= &arr1[0] < &arr2[0];
+ b &= &arr1[0] <= &arr2[0];
+
+ b &= arr3 == arr4; /* { dg-warning "comparison between two arrays" "" { target { c++20 && c++23_down } } } */
+/* { dg-error "comparison between two arrays" "" { target c++26 } .-1 } */
+
+#if defined(__cplusplus) && __cplusplus > 201703L
+ auto cmp = arr1 <=> arr2; /* { dg-error "invalid operands" "" { target c++20 } } */
+#endif
+ return b;
+}
diff --git a/gcc/testsuite/c-c++-common/Warray-compare-5.c b/gcc/testsuite/c-c++-common/Warray-compare-5.c
new file mode 100644
index 000000000000..eab00d63bd02
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Warray-compare-5.c
@@ -0,0 +1,44 @@
+/* PR c++/97573 */
+/* { dg-do compile } */
+/* { dg-options "-Wall -Wno-error=array-compare" } */
+
+#ifndef __cplusplus
+# define bool _Bool
+#endif
+
+int arr1[5];
+int arr2[5];
+int arr3[2][2];
+int arr4[2][2];
+
+bool
+g ()
+{
+ bool b = arr1 == arr2; /* { dg-warning "comparison between two arrays" } */
+ b &= arr1 != arr2; /* { dg-warning "comparison between two arrays" } */
+ b &= arr1 > arr2; /* { dg-warning "comparison between two arrays" } */
+ b &= arr1 >= arr2; /* { dg-warning "comparison between two arrays" } */
+ b &= arr1 < arr2; /* { dg-warning "comparison between two arrays" } */
+ b &= arr1 <= arr2; /* { dg-warning "comparison between two arrays" } */
+#ifdef __cplusplus
+ b &= +arr1 == +arr2;
+ b &= +arr1 != +arr2;
+ b &= +arr1 > +arr2;
+ b &= +arr1 >= +arr2;
+ b &= +arr1 < +arr2;
+ b &= +arr1 <= +arr2;
+#endif
+ b &= &arr1[0] == &arr2[0];
+ b &= &arr1[0] != &arr2[0];
+ b &= &arr1[0] > &arr2[0];
+ b &= &arr1[0] >= &arr2[0];
+ b &= &arr1[0] < &arr2[0];
+ b &= &arr1[0] <= &arr2[0];
+
+ b &= arr3 == arr4; /* { dg-warning "comparison between two arrays" } */
+
+#if defined(__cplusplus) && __cplusplus > 201703L
+ auto cmp = arr1 <=> arr2; /* { dg-error "invalid operands" "" { target c++20 } } */
+#endif
+ return b;
+}
diff --git a/gcc/testsuite/g++.dg/warn/Warray-compare-1.C b/gcc/testsuite/g++.dg/warn/Warray-compare-1.C
new file mode 100644
index 000000000000..32413292f449
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Warray-compare-1.C
@@ -0,0 +1,26 @@
+// PR c++/117788
+// { dg-do compile { target c++11 } }
+
+constexpr int arr1[5]{};
+constexpr int arr2[5]{};
+
+template<int I>
+void f1 (int(*)[arr1 == arr2 ? I : I]) = delete; // { dg-warning "comparison between two arrays" "" { target { c++20 && c++23_down } } }
+// { dg-error "comparison between two arrays" "" { target c++26 } .-1 }
+
+template<int>
+void f1 (...) { }
+
+template<int I>
+void f2 (int(*)[arr1 > arr2 ? I : 1]) = delete; // { dg-warning "comparison between two arrays" "" { target { c++20 && c++23_down } } }
+// { dg-error "comparison between two arrays" "" { target c++26 } .-1 }
+
+template<int>
+void f2 (...) { }
+
+void
+g ()
+{
+ f1<0>(nullptr);
+ f2<0>(nullptr);
+}
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/conditionally_borrowed.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/conditionally_borrowed.cc
index 4a0d1ff001a1..4bc0d2da9e07 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/conditionally_borrowed.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/conditionally_borrowed.cc
@@ -61,7 +61,10 @@ void
test02()
{
std::pair<int, std::string_view> a[2]{ {1,"two"}, {3,"four"}};
- auto pos = ranges::find(a | views::values, "four");
+ // FIXME: We should be able to get rid of the decay via the + here.
+ // But we'd end up comparing two array types in equality_comparable_with
+ // -> __weakly_eq_cmp_with which is ill-formed in C++26 due to P2865.
+ auto pos = ranges::find(a | views::values, +"four");
VERIFY( *pos == "four" );
static_assert( ranges::borrowed_range<decltype(a | views::keys)> );
More information about the Libstdc++-cvs
mailing list