On 12/9/24 6:32 PM, Marek Polacek wrote:
On Fri, Dec 06, 2024 at 12:48:35PM -0500, Jason Merrill wrote:
On 12/6/24 12:29 PM, Marek Polacek wrote:
On Thu, Dec 05, 2024 at 01:15:49PM -0500, Jason Merrill wrote:
On 12/4/24 12:27 PM, Marek Polacek wrote:
On Tue, Dec 03, 2024 at 04:27:22PM -0500, Jason Merrill wrote:
On 12/3/24 2:46 PM, Marek Polacek wrote:
On Thu, Nov 28, 2024 at 12:04:56PM -0500, Jason Merrill wrote:
On 11/27/24 9:06 PM, Marek Polacek wrote:
Not a bugfix, but this should only affect C++26.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8--
This patch implements P2865R5 by promoting the warning to error in C++26
only.  -Wno-array-compare shouldn't disable the error, so adjust the call
sites as well.

I think it's fine for -Wno-array-compare to suppress the error (and
-Wno-error=array-compare to reduce it to a warning), so how about
DK_PERMERROR rather than DK_ERROR?

Sounds good.
We also need SFINAE for this when !tf_warning_or_error.

I've added Warray-compare-1.C, which has:

      template<int I>
      void f (int(*)[arr1 == arr2 ? I : I]);

but when we call cp_build_binary_op from the parser, complain is
tf_warning_or_error, so we warn (as does clang++).  I suspect
that goes against [temp.deduct.general]/8.

No, that's fine; in C++26 that template is IFNDR because no well-formed
instantiation exists, it's OK for us to give a diagnostic and then continue
just like in a non-template.

Ah yes.

I'm not sure there is a SFINAE situation where this would come up, but I'd
still like to adjust this:

@@ -6125,11 +6124,10 @@ 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))
+              && (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));

If we happen to get here when not complaining, we'll silently accept it.
Either we should handle that case by returning error_mark_node in C++26 and
above, or we should assert that it can't happen.

We actually can get there.  But returning error_mark_node in C++26
causes problems: we hit:

           /* If we ran into a problem, make sure we complained.  */
           gcc_assert (seen_error ());

because a permerror doesn't count as an error.  Either we'd have to go
back to DK_ERROR, or leave the patch as-is.

Hmm, I guess cp_seen_error should also consider werrorcount.

That still wouldn't work with -Wno-array-compare.  Nor would adding
permerrorcount.

I suppose I could still add permerrorcount and do permerrorcount++;,
and have cp_seen_error check permerrorcount.  Does that seem acceptable?

If we didn't actually give an error, we shouldn't return error_mark_node.
That's what the assert is checking, and it's important to preserve that
property (outside of SFINAE).  An error_mark_node without an error means
silently generating garbage.

Hopefully done correctly in the following patch.

conditionally_borrowed.cc regressed with this patch as described below,
so I adjusted the test.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

Thanks,

-- >8 --
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.
---
  gcc/c-family/c-warn.cc                        | 25 +++++++--
  gcc/cp/typeck.cc                              | 55 +++++++++++--------
  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 +++++++++
  .../ranges/adaptors/conditionally_borrowed.cc |  5 +-
  8 files changed, 192 insertions(+), 41 deletions(-)
  create mode 100644 gcc/testsuite/c-c++-common/Warray-compare-4.c
  create mode 100644 gcc/testsuite/c-c++-common/Warray-compare-5.c
  create mode 100644 gcc/testsuite/g++.dg/warn/Warray-compare-1.C

diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc
index 140d97a00d8..0b71842e48d 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 adc71132721..b35eb4d17cc 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -5830,23 +5830,27 @@ 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)
+         {
+           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;

Please add a comment referring to P2865R5 here.  OK with that change.

+         }
+      }
build_type = boolean_type_node;
        if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
@@ -6125,14 +6129,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 922396c0a1a..90191ecd056 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 4725aa2b38b..afcc934010e 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 00000000000..8cfb4b2ffe6
--- /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 00000000000..eab00d63bd0
--- /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 00000000000..32413292f44
--- /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 4a0d1ff001a..4bc0d2da9e0 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)> );

base-commit: d4525729b747827afa62320696709ca499904860

Reply via email to