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. 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. PR c++/117788 gcc/c-family/ChangeLog: * c-warn.cc (do_warn_array_compare): Emit an error 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. <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-2.c: Likewise. * c-c++-common/Warray-compare-3.c: Likewise. * c-c++-common/Warray-compare-4.c: New test. * g++.dg/tree-ssa/pr15791-1.C: Expect an error in C++26. --- gcc/c-family/c-warn.cc | 25 +++++++--- gcc/cp/typeck.cc | 10 ++-- gcc/testsuite/c-c++-common/Warray-compare-1.c | 21 +++++--- gcc/testsuite/c-c++-common/Warray-compare-2.c | 21 +++++--- gcc/testsuite/c-c++-common/Warray-compare-3.c | 7 +-- gcc/testsuite/c-c++-common/Warray-compare-4.c | 50 +++++++++++++++++++ gcc/testsuite/g++.dg/tree-ssa/pr15791-1.C | 2 +- 7 files changed, 106 insertions(+), 30 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/Warray-compare-4.c diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc index 05d6e37edae..acda9a3ee3d 100644 --- a/gcc/c-family/c-warn.cc +++ b/gcc/c-family/c-warn.cc @@ -3818,8 +3818,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 an error. 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) @@ -3832,10 +3833,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_ERROR; + } + 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 102a8ed131c..c3895eb5fb2 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -5816,7 +5816,7 @@ 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) + if (complain & tf_warning_or_error) { tree stripped_orig_op0 = tree_strip_any_location_wrapper (orig_op0); tree stripped_orig_op1 = tree_strip_any_location_wrapper (orig_op1); @@ -5827,8 +5827,7 @@ cp_build_binary_op (const op_location_t &location, 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 + else if (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); @@ -6111,11 +6110,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)); 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-2.c b/gcc/testsuite/c-c++-common/Warray-compare-2.c index b3688e69b37..c5af1409eb7 100644 --- a/gcc/testsuite/c-c++-common/Warray-compare-2.c +++ b/gcc/testsuite/c-c++-common/Warray-compare-2.c @@ -14,12 +14,18 @@ int arr4[2][2]; bool g () { - bool b = arr1 == arr2; /* { dg-bogus "comparison between two arrays" } */ - b &= arr1 != arr2; /* { dg-bogus "comparison between two arrays" } */ - b &= arr1 > arr2; /* { dg-bogus "comparison between two arrays" } */ - b &= arr1 >= arr2; /* { dg-bogus "comparison between two arrays" } */ - b &= arr1 < arr2; /* { dg-bogus "comparison between two arrays" } */ - b &= arr1 <= arr2; /* { dg-bogus "comparison between two arrays" } */ + bool b = arr1 == arr2; /* { dg-bogus "comparison between two arrays" "" { target { c || c++23_down } } } */ +/* { dg-error "comparison between two arrays" "" { target c++26 } .-1 } */ + b &= arr1 != arr2; /* { dg-bogus "comparison between two arrays" "" { target { c || c++23_down } } } */ +/* { dg-error "comparison between two arrays" "" { target c++26 } .-1 } */ + b &= arr1 > arr2; /* { dg-bogus "comparison between two arrays" "" { target { c || c++23_down } } } */ +/* { dg-error "comparison between two arrays" "" { target c++26 } .-1 } */ + b &= arr1 >= arr2; /* { dg-bogus "comparison between two arrays" "" { target { c || c++23_down } } } */ +/* { dg-error "comparison between two arrays" "" { target c++26 } .-1 } */ + b &= arr1 < arr2; /* { dg-bogus "comparison between two arrays" "" { target { c || c++23_down } } } */ +/* { dg-error "comparison between two arrays" "" { target c++26 } .-1 } */ + b &= arr1 <= arr2; /* { dg-bogus "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-bogus "comparison between two arrays" } */ + b &= arr3 == arr4; /* { dg-bogus "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/g++.dg/tree-ssa/pr15791-1.C b/gcc/testsuite/g++.dg/tree-ssa/pr15791-1.C index 9905851ee7c..8a18f013ff4 100644 --- a/gcc/testsuite/g++.dg/tree-ssa/pr15791-1.C +++ b/gcc/testsuite/g++.dg/tree-ssa/pr15791-1.C @@ -13,7 +13,7 @@ int main () link_error (); if (b == &b[2]) link_error (); - if (b != b) + if (b != b) // { dg-error "comparison between two arrays" "" { target c++26 } } link_error (); if (&x.b[1] == &x.b[0]) link_error (); base-commit: 1046c32de4956c3d706a2ff8683582fd21b8f360 -- 2.47.0