From patchwork Fri Oct 1 20:11:08 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Polacek X-Patchwork-Id: 45733 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 1DA333857414 for ; Fri, 1 Oct 2021 20:31:32 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1DA333857414 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1633120292; bh=BKD8MowPyEqWlLb9Y5jsLvwel5eh5hBW+EmjnEVvxdE=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=IF/PMeDqrT+eOLLSjBuzWrXMqEC92/2Us97Nn5auR7HPLGyRuyET0Yz6QVa89FkMO yj0uMezT6UyzYmmgUngSLyrqoB0udvM0+EVpT7iAcA2DTzxBhY0zn4/swqfZmWSCrw jz4hE04WGvCxGeFsICwBakeQcApHNmZ+E8wWQAGo= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by sourceware.org (Postfix) with ESMTP id 7079D3857C62 for ; Fri, 1 Oct 2021 20:11:23 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 7079D3857C62 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-197-Tay88sJ2PoSIASuG3mO3DQ-1; Fri, 01 Oct 2021 16:11:19 -0400 X-MC-Unique: Tay88sJ2PoSIASuG3mO3DQ-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id BED8C8015C7; Fri, 1 Oct 2021 20:11:18 +0000 (UTC) Received: from pdp-11.redhat.com (unknown [10.22.8.239]) by smtp.corp.redhat.com (Postfix) with ESMTP id 357F260936; Fri, 1 Oct 2021 20:11:18 +0000 (UTC) To: GCC Patches , Jason Merrill , Joseph Myers Subject: [PATCH] c-family: Implement -Warray-compare [PR97573] Date: Fri, 1 Oct 2021 16:11:08 -0400 Message-Id: <20211001201108.78108-1-polacek@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-14.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Marek Polacek via Gcc-patches From: Marek Polacek Reply-To: Marek Polacek Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" 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 -Warray-compare. Since the code in question is dubious (the comparison doesn't actually compare the array elements), I've added this warning for C too, and enabled it in all C++ modes. Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? PR c++/97573 gcc/c-family/ChangeLog: * c-common.h (do_warn_array_compare): Declare. * c-warn.c (do_warn_array_compare): New. * c.opt (Warray-compare): New option. gcc/c/ChangeLog: * c-typeck.c (parser_build_binary_op): Call do_warn_array_compare. gcc/cp/ChangeLog: * typeck.c (cp_build_binary_op): Call do_warn_array_compare. gcc/ChangeLog: * doc/invoke.texi: Document -Warray-compare. gcc/testsuite/ChangeLog: * c-c++-common/Warray-compare-1.c: New test. * c-c++-common/Warray-compare-2.c: New test. --- gcc/c-family/c-common.h | 1 + gcc/c-family/c-warn.c | 32 ++++++++++++++ gcc/c-family/c.opt | 4 ++ gcc/c/c-typeck.c | 9 +++- gcc/cp/typeck.c | 13 ++++++ gcc/doc/invoke.texi | 20 ++++++++- gcc/testsuite/c-c++-common/Warray-compare-1.c | 44 +++++++++++++++++++ gcc/testsuite/c-c++-common/Warray-compare-2.c | 44 +++++++++++++++++++ 8 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/Warray-compare-1.c create mode 100644 gcc/testsuite/c-c++-common/Warray-compare-2.c base-commit: acf3a21cbc26b39b73c0006300f35ff017ddd6cb diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 849cefab882..078730f1e64 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1421,6 +1421,7 @@ extern bool warn_for_restrict (unsigned, tree *, unsigned); extern void warn_for_address_or_pointer_of_packed_member (tree, tree); extern void warn_parm_array_mismatch (location_t, tree, tree); extern void maybe_warn_sizeof_array_div (location_t, tree, tree, tree, tree); +extern void do_warn_array_compare (location_t, tree_code, tree, tree); /* Places where an lvalue, or modifiable lvalue, may be required. Used to select diagnostic messages in lvalue_error and diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c index 84ad6633c96..96aff1c0e5a 100644 --- a/gcc/c-family/c-warn.c +++ b/gcc/c-family/c-warn.c @@ -3726,3 +3726,35 @@ 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. */ + +void +do_warn_array_compare (location_t location, tree_code code, tree op0, tree op1) +{ + STRIP_NOPS (op0); + STRIP_NOPS (op1); + if (TREE_CODE (op0) == ADDR_EXPR) + op0 = TREE_OPERAND (op0, 0); + if (TREE_CODE (op1) == ADDR_EXPR) + op1 = TREE_OPERAND (op1, 0); + + auto_diagnostic_group d; + if (warning_at (location, OPT_Warray_compare, + "comparison between two arrays%s", + (c_dialect_cxx () && cxx_dialect >= cxx20) + ? " is deprecated in C++20" : "")) + { + /* C doesn't allow +arr. */ + if (c_dialect_cxx ()) + 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); + else + inform (location, "use %<&%D[0] %s &%D[0]%> to compare the addresses", + op0, op_symbol_code (code), op1); + } +} diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 9c151d19870..06457ac739e 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -350,6 +350,10 @@ Warray-bounds= LangEnabledBy(C ObjC C++ LTO ObjC++,Wall,1,0) ; in common.opt +Warray-compare +C ObjC C++ ObjC++ Var(warn_array_compare) Warning LangEnabledBy(C ObjC C++ ObjC++, Wall) +Warn about comparisons between two operands of array type. + Warray-parameter C ObjC C++ ObjC++ Warning Alias(Warray-parameter=, 2, 0) Warn about mismatched declarations of array parameters and unsafe accesses to them. diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 33963d7555a..f9eb0e5176f 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -3940,7 +3940,14 @@ parser_build_binary_op (location_t location, enum tree_code code, else if (TREE_CODE_CLASS (code) == tcc_comparison && (code1 == STRING_CST || code2 == STRING_CST)) warning_at (location, OPT_Waddress, - "comparison with string literal results in unspecified behavior"); + "comparison with string literal results in unspecified " + "behavior"); + + if (warn_array_compare + && TREE_CODE_CLASS (code) == tcc_comparison + && TREE_CODE (type1) == ARRAY_TYPE + && TREE_CODE (type2) == ARRAY_TYPE) + do_warn_array_compare (location, code, arg1.value, arg2.value); if (TREE_OVERFLOW_P (result.value) && !TREE_OVERFLOW_P (arg1.value) diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index e880d34dcfe..ab0f9da2552 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -5357,6 +5357,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 (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); } build_type = boolean_type_node; @@ -5629,6 +5634,14 @@ 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 + && 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)); if (gnu_vector_type_p (type0) && gnu_vector_type_p (type1)) { diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index d35114c0727..a397afe1caf 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 @@ -323,7 +324,7 @@ Objective-C and Objective-C++ Dialects}. -Walloca -Walloca-larger-than=@var{byte-size} @gol -Wno-aggressive-loop-optimizations @gol -Warith-conversion @gol --Warray-bounds -Warray-bounds=@var{n} @gol +-Warray-bounds -Warray-bounds=@var{n} -Warray-compare @gol -Wno-attributes -Wattribute-alias=@var{n} -Wno-attribute-alias @gol -Wno-attribute-warning -Wbool-compare -Wbool-operation @gol -Wno-builtin-declaration-mismatch @gol @@ -5562,6 +5563,7 @@ Options} and @ref{Objective-C and Objective-C++ Dialect Options}. @gccoptlist{-Waddress @gol -Warray-bounds=1 @r{(only with} @option{-O2}@r{)} @gol +-Warray-compare @gol -Warray-parameter=2 @r{(C and Objective-C only)} @gol -Wbool-compare @gol -Wbool-operation @gol @@ -7533,6 +7535,20 @@ pointers. This warning level may give a larger number of false positives and is deactivated by default. @end table +@item -Warray-compare +@opindex Warray-compare +@opindex Wno-array-compare +Warn 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{-Warray-compare} is enabled by @option{-Wall}. + @item -Warray-parameter @itemx -Warray-parameter=@var{n} @opindex Wno-array-parameter diff --git a/gcc/testsuite/c-c++-common/Warray-compare-1.c b/gcc/testsuite/c-c++-common/Warray-compare-1.c new file mode 100644 index 00000000000..922396c0a1a --- /dev/null +++ b/gcc/testsuite/c-c++-common/Warray-compare-1.c @@ -0,0 +1,44 @@ +/* PR c++/97573 */ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +#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/c-c++-common/Warray-compare-2.c b/gcc/testsuite/c-c++-common/Warray-compare-2.c new file mode 100644 index 00000000000..b3688e69b37 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Warray-compare-2.c @@ -0,0 +1,44 @@ +/* PR c++/97573 */ +/* { dg-do compile } */ +/* { dg-options "-Wall -Wno-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-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" } */ +#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-bogus "comparison between two arrays" } */ + +#if defined(__cplusplus) && __cplusplus > 201703L + auto cmp = arr1 <=> arr2; /* { dg-error "invalid operands" "" { target c++20 } } */ +#endif + return b; +}