On Fri, Oct 01, 2021 at 09:16:53AM -0600, Martin Sebor wrote: > On 9/30/21 8:50 AM, Marek Polacek via Gcc-patches wrote: > > This patch addresses one of my leftovers from GCC 11. C++20 introduced > > [depr.array.comp]: > > "Equality and relational comparisons between two operands of array type are > > deprecated." > > so this patch adds -Wdeprecated-array-compare (enabled by default in C++20). > > A warning like this would be useful in C as well even though there > array equality is not deprecated (though relational expressions > involving distinct objects are undefined). Recently, while working > on my -Waddress enhancement to "warn for more impossible null > pointer tests​, I noticed Clang warns for some of these equality > tests in both languages (it issues -Wtautological-compare).
I'll look into adding this warning to the C FE; it should be trivial. > Rather that referring to deprecation, if one is necessary, I would > suggest to choose a name for the option that reflects the problem > the warning (and presumably the deprecation in C++) tries to prevent. > That said, since GCC already has both -Waddress and -Wtautological- > compare for these problems, the warning could be issued under either > of these. In my previous email I suggested -Warray-compare -- I wanted to avoid the "deprecated" part outside C++20. I also noticed the -Wtautological warning clang emits but I don't have time to look into it. It probably won't warn for arrays declared with __attribute__((weak)) so -Warray-compare still makes sense. > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? > > > > PR c++/97573 > > > > gcc/c-family/ChangeLog: > > > > * c-opts.c (c_common_post_options): In C++20, turn on > > -Wdeprecated-array-compare. > > * c.opt (Wdeprecated-array-compare): New option. > > > > gcc/cp/ChangeLog: > > > > * typeck.c (do_warn_deprecated_array_compare): New. > > (cp_build_binary_op): Call it for equality and relational comparisons. > > > > gcc/ChangeLog: > > > > * doc/invoke.texi: Document -Wdeprecated-array-compare. > > > > gcc/testsuite/ChangeLog: > > > > * g++.dg/tree-ssa/pr15791-1.C: Add dg-warning. > > * g++.dg/cpp2a/array-comp1.C: New test. > > * g++.dg/cpp2a/array-comp2.C: New test. > > * g++.dg/cpp2a/array-comp3.C: New test. > > --- > > gcc/c-family/c-opts.c | 5 ++++ > > gcc/c-family/c.opt | 4 +++ > > gcc/cp/typeck.c | 28 +++++++++++++++++++ > > gcc/doc/invoke.texi | 19 ++++++++++++- > > gcc/testsuite/g++.dg/cpp2a/array-comp1.C | 34 +++++++++++++++++++++++ > > gcc/testsuite/g++.dg/cpp2a/array-comp2.C | 31 +++++++++++++++++++++ > > gcc/testsuite/g++.dg/cpp2a/array-comp3.C | 29 +++++++++++++++++++ > > gcc/testsuite/g++.dg/tree-ssa/pr15791-1.C | 2 +- > > 8 files changed, 150 insertions(+), 2 deletions(-) > > create mode 100644 gcc/testsuite/g++.dg/cpp2a/array-comp1.C > > create mode 100644 gcc/testsuite/g++.dg/cpp2a/array-comp2.C > > create mode 100644 gcc/testsuite/g++.dg/cpp2a/array-comp3.C > > > > diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c > > index 3eaab5e1530..00b52cc5e12 100644 > > --- a/gcc/c-family/c-opts.c > > +++ b/gcc/c-family/c-opts.c > > @@ -962,6 +962,11 @@ c_common_post_options (const char **pfilename) > > warn_deprecated_enum_float_conv, > > cxx_dialect >= cxx20 && warn_deprecated); > > + /* -Wdeprecated-array-compare is enabled by default in C++20. */ > > + SET_OPTION_IF_UNSET (&global_options, &global_options_set, > > + warn_deprecated_array_compare, > > + cxx_dialect >= cxx20 && warn_deprecated); > > + > > /* Declone C++ 'structors if -Os. */ > > if (flag_declone_ctor_dtor == -1) > > flag_declone_ctor_dtor = optimize_size; > > diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt > > index 9c151d19870..a4f0ea68594 100644 > > --- a/gcc/c-family/c.opt > > +++ b/gcc/c-family/c.opt > > @@ -540,6 +540,10 @@ Wdeprecated > > C C++ ObjC ObjC++ CPP(cpp_warn_deprecated) CppReason(CPP_W_DEPRECATED) > > ; Documented in common.opt > > +Wdeprecated-array-compare > > +C++ ObjC++ Var(warn_deprecated_array_compare) Warning > > +Warn about deprecated comparisons between two operands of array type. > > + > > Wdeprecated-copy > > C++ ObjC++ Var(warn_deprecated_copy) Warning LangEnabledBy(C++ ObjC++, > > Wextra) > > Mark implicitly-declared copy operations as deprecated if the class has a > > diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c > > index a2398dbe660..1e3a41104d6 100644 > > --- a/gcc/cp/typeck.c > > +++ b/gcc/cp/typeck.c > > @@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see > > #include "attribs.h" > > #include "asan.h" > > #include "gimplify.h" > > +#include "tree-pretty-print.h" > > static tree cp_build_addr_expr_strict (tree, tsubst_flags_t); > > static tree cp_build_function_call (tree, tree, tsubst_flags_t); > > @@ -4725,6 +4726,21 @@ do_warn_enum_conversions (location_t loc, enum > > tree_code code, tree type0, > > } > > } > > +/* Warn about C++20 [depr.array.comp] array comparisons: "Equality > > + and relational comparisons between two operands of array type are > > + deprecated." */ > > + > > +static inline void > > +do_warn_deprecated_array_compare (location_t location, tree_code code, > > + tree op0, tree op1) > > +{ > > + if (warning_at (location, OPT_Wdeprecated_array_compare, > > + "comparison between two arrays is deprecated")) > > + inform (location, "use unary %<+%> which decays operands to pointers " > > + "or %<&%D[0] %s &%D[0]%> to compare the addresses", > > + op0, op_symbol_code (code), op1); > > +} > > + > > /* Build a binary-operation expression without default conversions. > > CODE is the kind of expression to build. > > LOCATION is the location_t of the operator in the source code. > > @@ -5289,6 +5305,11 @@ cp_build_binary_op (const op_location_t &location, > > 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) > > + do_warn_deprecated_array_compare (location, code, > > + stripped_orig_op0, > > + stripped_orig_op1); > > } > > build_type = boolean_type_node; > > @@ -5559,6 +5580,13 @@ cp_build_binary_op (const op_location_t &location, > > "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 > > + && code != SPACESHIP_EXPR > > + && (complain & tf_warning)) > > + do_warn_deprecated_array_compare > > + (location, code, tree_strip_any_location_wrapper (orig_op0), > > + tree_strip_any_location_wrapper (orig_op1)); > > if (gnu_vector_type_p (type0) && gnu_vector_type_p (type1)) > > { > > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > > index 5b016166972..a6c6a737639 100644 > > --- a/gcc/doc/invoke.texi > > +++ b/gcc/doc/invoke.texi > > @@ -249,7 +249,8 @@ in the following sections. > > -Wcomma-subscript -Wconditionally-supported @gol > > -Wno-conversion-null -Wctad-maybe-unsupported @gol > > -Wctor-dtor-privacy -Wno-delete-incomplete @gol > > --Wdelete-non-virtual-dtor -Wdeprecated-copy -Wdeprecated-copy-dtor @gol > > +-Wdelete-non-virtual-dtor -Wno-deprecated-array-compare @gol > > +-Wdeprecated-copy -Wdeprecated-copy-dtor @gol > > -Wno-deprecated-enum-enum-conversion > > -Wno-deprecated-enum-float-conversion @gol > > -Weffc++ -Wno-exceptions -Wextra-semi -Wno-inaccessible-base @gol > > -Wno-inherited-variadic-ctor -Wno-init-list-lifetime @gol > > @@ -3521,6 +3522,22 @@ warning is enabled by @option{-Wextra}. With > > @option{-Wdeprecated-copy-dtor}, also deprecate if the class has a > > user-provided destructor. > > +@item -Wno-deprecated-array-compare @r{(C++ and Objective-C++ only)} > > +@opindex Wdeprecated-array-compare > > +@opindex Wno-deprecated-array-compare > > +Disable the warning about equality and relational comparisons between two > > +operands of array type. This comparison was deprecated in C++20. For > > +example: > > + > > +@smallexample > > +int arr1[5]; > > +int arr2[5]; > > +bool same = arr1 == arr2; > > +@end smallexample > > + > > +@option{-Wdeprecated-array-compare} is enabled by default with > > +@option{-std=c++20}. > > + > > @item -Wno-deprecated-enum-enum-conversion @r{(C++ and Objective-C++ > > only)} > > @opindex Wdeprecated-enum-enum-conversion > > @opindex Wno-deprecated-enum-enum-conversion > > diff --git a/gcc/testsuite/g++.dg/cpp2a/array-comp1.C > > b/gcc/testsuite/g++.dg/cpp2a/array-comp1.C > > new file mode 100644 > > index 00000000000..140d4d3c1dd > > --- /dev/null > > +++ b/gcc/testsuite/g++.dg/cpp2a/array-comp1.C > > @@ -0,0 +1,34 @@ > > +// PR c++/97573 - C++20 [depr.array.comp] > > +// { dg-do compile } > > +// No special options. In C++20 (only), we should get the deprecated > > warnings > > +// by default. > > + > > +int arr1[5]; > > +int arr2[5]; > > +int arr3[2][2]; > > +int arr4[2][2]; > > + > > +bool s1 = arr1 == arr2; // { dg-warning "comparison between two arrays is > > deprecated" "" { target c++20 } } > > +bool s2 = arr1 != arr2; // { dg-warning "comparison between two arrays is > > deprecated" "" { target c++20 } } > > +bool s3 = arr1 > arr2; // { dg-warning "comparison between two arrays is > > deprecated" "" { target c++20 } } > > +bool s4 = arr1 >= arr2; // { dg-warning "comparison between two arrays is > > deprecated" "" { target c++20 } } > > +bool s5 = arr1 < arr2; // { dg-warning "comparison between two arrays is > > deprecated" "" { target c++20 } } > > +bool s6 = arr1 <= arr2; // { dg-warning "comparison between two arrays is > > deprecated" "" { target c++20 } } > > +bool ok1 = +arr1 == +arr2; > > +bool ok2 = +arr1 != +arr2; > > +bool ok3 = +arr1 > +arr2; > > +bool ok4 = +arr1 >= +arr2; > > +bool ok5 = +arr1 < +arr2; > > +bool ok6 = +arr1 <= +arr2; > > +bool ok7 = &arr1[0] == &arr2[0]; > > +bool ok8 = &arr1[0] != &arr2[0]; > > +bool ok9 = &arr1[0] > &arr2[0]; > > +bool ok10 = &arr1[0] >= &arr2[0]; > > +bool ok11 = &arr1[0] < &arr2[0]; > > +bool ok12 = &arr1[0] <= &arr2[0]; > > + > > +bool s7 = arr3 == arr4; // { dg-warning "comparison between two arrays is > > deprecated" "" { target c++20 } } > > + > > +#if __cplusplus > 201703L > > +auto cmp = arr1 <=> arr2; // { dg-error "invalid operands" "" { > > target c++20 } } > > +#endif > > diff --git a/gcc/testsuite/g++.dg/cpp2a/array-comp2.C > > b/gcc/testsuite/g++.dg/cpp2a/array-comp2.C > > new file mode 100644 > > index 00000000000..b8409abb50a > > --- /dev/null > > +++ b/gcc/testsuite/g++.dg/cpp2a/array-comp2.C > > @@ -0,0 +1,31 @@ > > +// PR c++/97573 - C++20 [depr.array.comp] > > +// { dg-do compile { target c++20 } } > > +// { dg-options "-Wno-deprecated" } > > + > > +int arr1[5]; > > +int arr2[5]; > > +int arr3[2][2]; > > +int arr4[2][2]; > > + > > +bool s1 = arr1 == arr2; // { dg-bogus "comparison between two arrays is > > deprecated" } > > +bool s2 = arr1 != arr2; // { dg-bogus "comparison between two arrays is > > deprecated" } > > +bool s3 = arr1 > arr2; // { dg-bogus "comparison between two arrays is > > deprecated" } > > +bool s4 = arr1 >= arr2; // { dg-bogus "comparison between two arrays is > > deprecated" } > > +bool s5 = arr1 < arr2; // { dg-bogus "comparison between two arrays is > > deprecated" } > > +bool s6 = arr1 <= arr2; // { dg-bogus "comparison between two arrays is > > deprecated" } > > +bool ok1 = +arr1 == +arr2; > > +bool ok2 = +arr1 != +arr2; > > +bool ok3 = +arr1 > +arr2; > > +bool ok4 = +arr1 >= +arr2; > > +bool ok5 = +arr1 < +arr2; > > +bool ok6 = +arr1 <= +arr2; > > +bool ok7 = &arr1[0] == &arr2[0]; > > +bool ok8 = &arr1[0] != &arr2[0]; > > +bool ok9 = &arr1[0] > &arr2[0]; > > +bool ok10 = &arr1[0] >= &arr2[0]; > > +bool ok11 = &arr1[0] < &arr2[0]; > > +bool ok12 = &arr1[0] <= &arr2[0]; > > + > > +bool s7 = arr3 == arr4; // { dg-bogus "comparison between two arrays is > > deprecated" } > > + > > +auto cmp = arr1 <=> arr2; // { dg-error "invalid operands" } > > diff --git a/gcc/testsuite/g++.dg/cpp2a/array-comp3.C > > b/gcc/testsuite/g++.dg/cpp2a/array-comp3.C > > new file mode 100644 > > index 00000000000..70a6b4cbfea > > --- /dev/null > > +++ b/gcc/testsuite/g++.dg/cpp2a/array-comp3.C > > @@ -0,0 +1,29 @@ > > +// PR c++/97573 - C++20 [depr.array.comp] > > +// { dg-do compile { target { c++17_down } } } > > +// { dg-options "-Wdeprecated-array-compare" } > > + > > +int arr1[5]; > > +int arr2[5]; > > +int arr3[2][2]; > > +int arr4[2][2]; > > + > > +bool s1 = arr1 == arr2; // { dg-warning "comparison between two arrays is > > deprecated" } > > +bool s2 = arr1 != arr2; // { dg-warning "comparison between two arrays is > > deprecated" } > > +bool s3 = arr1 > arr2; // { dg-warning "comparison between two arrays is > > deprecated" } > > +bool s4 = arr1 >= arr2; // { dg-warning "comparison between two arrays is > > deprecated" } > > +bool s5 = arr1 < arr2; // { dg-warning "comparison between two arrays is > > deprecated" } > > +bool s6 = arr1 <= arr2; // { dg-warning "comparison between two arrays is > > deprecated" } > > +bool ok1 = +arr1 == +arr2; > > +bool ok2 = +arr1 != +arr2; > > +bool ok3 = +arr1 > +arr2; > > +bool ok4 = +arr1 >= +arr2; > > +bool ok5 = +arr1 < +arr2; > > +bool ok6 = +arr1 <= +arr2; > > +bool ok7 = &arr1[0] == &arr2[0]; > > +bool ok8 = &arr1[0] != &arr2[0]; > > +bool ok9 = &arr1[0] > &arr2[0]; > > +bool ok10 = &arr1[0] >= &arr2[0]; > > +bool ok11 = &arr1[0] < &arr2[0]; > > +bool ok12 = &arr1[0] <= &arr2[0]; > > + > > +bool s7 = arr3 == arr4; // { dg-warning "comparison between two arrays is > > deprecated" } > > diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr15791-1.C > > b/gcc/testsuite/g++.dg/tree-ssa/pr15791-1.C > > index 68f14adad00..5fc6a8ae5b3 100644 > > --- a/gcc/testsuite/g++.dg/tree-ssa/pr15791-1.C > > +++ b/gcc/testsuite/g++.dg/tree-ssa/pr15791-1.C > > @@ -12,7 +12,7 @@ int main () > > link_error (); > > if (b == &b[2]) > > link_error (); > > - if (b != b) > > + if (b != b) // { dg-warning "comparison between two arrays is > > deprecated" "" { target c++20 } } > > link_error (); > > if (&x.b[1] == &x.b[0]) > > link_error (); > > > > base-commit: ef37ddf477ac4b21ec4d1be9260cfd3b431fd4a9 > > > Marek