[PATCH] c++: Implement C++20 -Wdeprecated-array-compare [PR97573]

Marek Polacek polacek@redhat.com
Fri Oct 1 15:43:28 GMT 2021


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



More information about the Gcc-patches mailing list