From patchwork Fri Aug 16 22:42:55 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Sebor X-Patchwork-Id: 1148492 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-507159-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="vE3XUQQn"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="qU2qO3Ts"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 469JJ26JZfz9sBF for ; Sat, 17 Aug 2019 08:43:12 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :subject:to:message-id:date:mime-version:content-type; q=dns; s= default; b=LVwiULcuPV9bXy5XbrlLsnAZtH3NzrRAJm1UmS/3ga/w33WAjiKtP Ok3gvIHi2DrNg/zI2KPdE9AgcgXFnRKF3gyISr0znti4Yc2oTaeh8iuQ+bxaX+3Q p/drWDD6HasEDeNq6N11Fmoo2IDhTpKpxKYFB7RF0JRQySnA2obiqE= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :subject:to:message-id:date:mime-version:content-type; s= default; bh=xd6Zn15Fzr8ZKehwsoFkkdiNvHY=; b=vE3XUQQnDX1MSoJTosFL IUzPKXSWPBn3iI6y9HN4RBiJW3Ry01rwXSGTwVohBbD9SFHeGCKb6J13Qa2tPg3S wqJdgWSJTKxNrxQOPuqbJrBj1QvkootyKoHGYHYSm8nFLBhIO4ZrWFyCTP+w+eXv YH8ZQJX6gCz75uyrt56/Egk= Received: (qmail 2067 invoked by alias); 16 Aug 2019 22:43:03 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 2057 invoked by uid 89); 16 Aug 2019 22:43:03 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-12.2 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.1 spammy=influence, 274541, UD:tree-vrp.c, treevrpc X-HELO: mail-io1-f47.google.com Received: from mail-io1-f47.google.com (HELO mail-io1-f47.google.com) (209.85.166.47) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 16 Aug 2019 22:42:59 +0000 Received: by mail-io1-f47.google.com with SMTP id q22so9327212iog.4 for ; Fri, 16 Aug 2019 15:42:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:subject:to:message-id:date:user-agent:mime-version :content-language; bh=MMyEjKIG2qYf+Pp7+2nzxu7hFiM4doTJsdQ3nOmSE9I=; b=qU2qO3Tso9JaYCQbS42JSwFEN4NFzEXIIS6NTPoZaaHWNhvR5NUi50G6njV6jMt2jW po/n87kmQoJ/vcB09k5UTXZzW8tI69EGaH9ZF2K0ovRtMaiRj/zHBol8eBCtYvfgWAQ8 BuzVGBgsDH9buKS/XnLlGZYTbnmGQFcSEZA/tW7IxXHknrk7xfywJOV1pj/3ZfJI4b5J AAqaqX/PolNmqujDY1UMUxyNvQzGzC3h0H1VAfWQGtvBKRRODQ/emC+AHzcEtYeOzcTu tBjSCY6d53wb/+qn6/t3J3pXl8Ntcv9eQiMIvGenvIAjwrPpEen8mxHI/FY1PnJZ5dzh 1G9A== Received: from [192.168.0.41] (97-118-116-95.hlrn.qwest.net. [97.118.116.95]) by smtp.gmail.com with ESMTPSA id h19sm4662548iol.65.2019.08.16.15.42.55 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 16 Aug 2019 15:42:56 -0700 (PDT) From: Martin Sebor Subject: [PATCH] issue consistent warning for past-the-end array stores (PR 91457) To: gcc-patches Message-ID: Date: Fri, 16 Aug 2019 16:42:55 -0600 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.6.1 MIME-Version: 1.0 X-IsSubscribed: yes With the recent enhancement to the strlen handling of multibyte stores the g++.dg/warn/Warray-bounds-4.C for zero-length arrays started failing on hppa (and probably elsewhere as well). This is partly the result of the added detection of past-the-end writes into the strlen pass which detects more instances of the problem than -Warray-bounds. Since the IL each warning works with varies between targets, the same invalid code can be diagnosed by one warning one target and different warning on another. The attached patch does three things: 1) It enhances compute_objsize to also determine the size of a flexible array member (and its various variants), including from its initializer if necessary. (This resolves 91457 but introduces another warning where was previously just one.) 2) It guards the new instance of -Wstringop-overflow with the no-warning bit on the assignment to avoid warning on code that's already been diagnosed. 3) It arranges for -Warray-bounds to set the no-warning bit on the enclosing expression to keep -Wstringop-overflow from issuing another warning for the same problem. Testing the compute_objsize enhancement to bring it up to par with -Warray-bounds in turn exposed a weakness in the latter warning for flexible array members. Rather than snowballing additional improvements into this one I decided to put that off until later, so the new -Warray-bounds test has a bunch of XFAILs. I'll see if I can find the time to deal with those either still in stage 1 or in stage 3 (one of them is actually an ancient regression). Martin PS I imagine the new get_flexarray_size function will probably need to move somewhere more appropriate so that other warnings (like -Warray-bounds to remove the XFAILs) and optimizations can make use of it. PR tree-optimization/91458 - inconsistent warning for writing past the end of an array member gcc/testsuite/ChangeLog: PR tree-optimization/91458 * g++.dg/warn/Warray-bounds-8.C: New test. * g++.dg/warn/Wstringop-overflow-3.C: New test. gcc/ChangeLog: PR tree-optimization/91458 * builtins.c (get_initializer_for, get_flexarray_size): New functions. (compute_objsize): Add argument. Handle ARRAY_REF and COMPONENT_REF. * builtins.h ((compute_objsize): Add argument. * tree-ssa-strlen.c (handle_store): Handle no-warning bit. * tree-vrp.c (vrp_prop::check_array_ref): Return warning result. (vrp_prop::check_mem_ref): Same. (vrp_prop::search_for_addr_array): Set no-warning bit. (check_array_bounds): Same. Index: gcc/builtins.c =================================================================== --- gcc/builtins.c (revision 274541) +++ gcc/builtins.c (working copy) @@ -3560,6 +3560,51 @@ check_access (tree exp, tree, tree, tree dstwrite, return true; } +/* Given the initializer INIT, return the initializer for the field + DECL if it exists, otherwise null. Used to obtain the initializer + for a flexible array member and determine its size. */ + +static tree +get_initializer_for (tree init, tree decl) +{ + STRIP_NOPS (init); + + tree fld, fld_init; + unsigned HOST_WIDE_INT i; + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), i, fld, fld_init) + { + if (decl == fld) + return fld_init; + + if (TREE_CODE (fld) == CONSTRUCTOR) + { + fld_init = get_initializer_for (fld_init, decl); + if (fld_init) + return fld_init; + } + } + + return NULL_TREE; +} + +/* Determine the size of the flexible array FLD from the initializer + expression for the struct object DECL in which the meber is declared + (possibly recursively). Return the size or zero constant if it isn't + initialized. */ + +static tree +get_flexarray_size (tree decl, tree fld) +{ + if (tree init = DECL_INITIAL (decl)) + { + init = get_initializer_for (init, fld); + if (init) + return TYPE_SIZE_UNIT (TREE_TYPE (init)); + } + + return integer_zero_node; +} + /* Helper to compute the size of the object referenced by the DEST expression which must have pointer type, using Object Size type OSTYPE (only the least significant 2 bits are used). Return @@ -3567,12 +3612,18 @@ check_access (tree exp, tree, tree, tree dstwrite, the size cannot be determined. When the referenced object involves a non-constant offset in some range the returned value represents the largest size given the smallest non-negative offset in the - range. The function is intended for diagnostics and should not - be used to influence code generation or optimization. */ + range. If nonnull, set *PDECL to the decl of the referenced + subobject if it can be determined, or to null otherwise. + The function is intended for diagnostics and should not be used + to influence code generation or optimization. */ tree -compute_objsize (tree dest, int ostype) +compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */) { + tree dummy = NULL_TREE; + if (!pdecl) + pdecl = &dummy; + unsigned HOST_WIDE_INT size; /* Only the two least significant bits are meaningful. */ @@ -3599,7 +3650,7 @@ tree tree off = gimple_assign_rhs2 (stmt); if (TREE_CODE (off) == INTEGER_CST) { - if (tree size = compute_objsize (dest, ostype)) + if (tree size = compute_objsize (dest, ostype, pdecl)) { wide_int wioff = wi::to_wide (off); wide_int wisiz = wi::to_wide (size); @@ -3624,7 +3675,7 @@ tree if (rng == VR_RANGE) { - if (tree size = compute_objsize (dest, ostype)) + if (tree size = compute_objsize (dest, ostype, pdecl)) { wide_int wisiz = wi::to_wide (size); @@ -3652,12 +3703,32 @@ tree if (!ostype) return NULL_TREE; - if (TREE_CODE (dest) == MEM_REF) + if (TREE_CODE (dest) == ARRAY_REF + || TREE_CODE (dest) == MEM_REF) { tree ref = TREE_OPERAND (dest, 0); tree off = TREE_OPERAND (dest, 1); - if (tree size = compute_objsize (ref, ostype)) + if (tree size = compute_objsize (ref, ostype, pdecl)) { + /* If the declaration of the destination object is known to + have zero size, return zero. Otherwise, if the returned + size is zero and the idex/offset is unsigned, also return + zero. */ + if (integer_zerop (size)) + return integer_zero_node; + + if (TREE_CODE (off) != INTEGER_CST) + return NULL_TREE; + + if (TREE_CODE (dest) == ARRAY_REF) + { + tree eltype = TREE_TYPE (dest); + if (tree tpsize = TYPE_SIZE_UNIT (eltype)) + off = fold_build2 (MULT_EXPR, size_type_node, off, tpsize); + else + return NULL_TREE; + } + if (tree_int_cst_lt (off, size)) return fold_build2 (MINUS_EXPR, size_type_node, size, off); return integer_zero_node; @@ -3666,9 +3737,34 @@ tree return NULL_TREE; } + if (TREE_CODE (dest) == COMPONENT_REF) + { + *pdecl = TREE_OPERAND (dest, 1); + + /* If the member has a size return it. Otherwise it's a flexible + array member. */ + if (tree size = DECL_SIZE_UNIT (*pdecl)) + return size; + + /* If the destination is a declared object with zero size try to + determine its size from its initializer. */ + if (tree base = get_base_address (dest)) + if (VAR_P (base)) + return get_flexarray_size (base, *pdecl); + + return NULL_TREE; + } + if (TREE_CODE (dest) != ADDR_EXPR) return NULL_TREE; + tree ref = TREE_OPERAND (dest, 0); + if (DECL_P (ref)) + { + *pdecl = ref; + return DECL_SIZE_UNIT (ref); + } + tree type = TREE_TYPE (dest); if (TREE_CODE (type) == POINTER_TYPE) type = TREE_TYPE (type); @@ -3678,12 +3774,8 @@ tree if (TREE_CODE (type) == ARRAY_TYPE && !array_at_struct_end_p (TREE_OPERAND (dest, 0))) { - /* Return the constant size unless it's zero (that's a zero-length - array likely at the end of a struct). */ - tree size = TYPE_SIZE_UNIT (type); - if (size && TREE_CODE (size) == INTEGER_CST - && !integer_zerop (size)) - return size; + if (tree size = TYPE_SIZE_UNIT (type)) + return TREE_CODE (size) == INTEGER_CST ? size : NULL_TREE; } return NULL_TREE; Index: gcc/builtins.h =================================================================== --- gcc/builtins.h (revision 274541) +++ gcc/builtins.h (working copy) @@ -134,7 +134,7 @@ extern tree fold_call_stmt (gcall *, bool); extern void set_builtin_user_assembler_name (tree decl, const char *asmspec); extern bool is_simple_builtin (tree); extern bool is_inexpensive_builtin (tree); -extern tree compute_objsize (tree, int); +extern tree compute_objsize (tree, int, tree * = NULL); extern bool readonly_data_expr (tree exp); extern bool init_target_chars (void); Index: gcc/testsuite/g++.dg/warn/Warray-bounds-8.C =================================================================== --- gcc/testsuite/g++.dg/warn/Warray-bounds-8.C (nonexistent) +++ gcc/testsuite/g++.dg/warn/Warray-bounds-8.C (working copy) @@ -0,0 +1,61 @@ +/* PR middle-end/91458 - inconsistent warning for writing past the end + of an array member + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +struct A0 +{ + char n, a[0]; + + A0 () { a[0] = 0; } // { dg-warning "\\\[-Warray-bounds" } +}; + +void f (void*); + +void g0 (void) +{ + struct A0 a; + f (&a); +} + + +struct A1 +{ + char n, a[1]; + + A1 () { a[1] = 0; } // { dg-warning "\\\[-Warray-bounds" } +}; + +void g1 (void) +{ + struct A1 a; + f (&a); +} + + +struct A123 +{ + char n, a[123]; + + A123 () { a[123] = 0; } // { dg-warning "\\\[-Warray-bounds" } +}; + +void g123 (void) +{ + struct A123 a; + f (&a); +} + + +struct A234 +{ + char n, a[234]; + + A234 (int i) { a[i] = 0; } // { dg-warning "\\\[-Warray-bounds" } +}; + +void g234 (void) +{ + struct A234 a (234); + f (&a); +} Index: gcc/testsuite/g++.dg/warn/Wstringop-overflow-3.C =================================================================== --- gcc/testsuite/g++.dg/warn/Wstringop-overflow-3.C (nonexistent) +++ gcc/testsuite/g++.dg/warn/Wstringop-overflow-3.C (working copy) @@ -0,0 +1,112 @@ +/* PR middle-end/91458 - inconsistent warning for writing past the end + of an array member + { dg-do compile } + { dg-options "-O2 -Wall -Wno-array-bounds" } */ + +struct Axi +{ + char n; + char a[]; // { dg-message "destination object declared here" } +}; + +Axi ax2 = { 2, { 1, 0 } }; + +void gx2 () +{ + ax2.a[0] = 0; + ax2.a[1] = 0; + ax2.a[2] = 0; // { dg-warning "\\\[-Wstringop-overflow" } +} + +void gxx (Axi *p) +{ + p->a[0] = 0; + p->a[3] = 0; + p->a[9] = 0; +} + +struct Ax +{ + char n; + char a[]; // { dg-message "destination object declared here" } + + // Verify the warning for a constant. + Ax () { a[0] = 0; } // { dg-warning "\\\[-Wstringop-overflow" } + + // And also for a non-constant. Regardless of the subscript, the array + // of the object in function gxi() below has a zero size. + Ax (int i) { a[i] = 0; } // { dg-warning "\\\[-Wstringop-overflow" } +}; + +void f (void*); + +void gx (void) +{ + struct Ax a; + f (&a); +} + +void gxi (int i) +{ + struct Ax a (i); + f (&a); +} + +struct A0 +{ + char n; + char a[0]; // { dg-message "destination object declared here" } + + A0 () { a[0] = 0; } // { dg-warning "\\\[-Wstringop-overflow" } +}; + +void f (void*); + +void g0 (void) +{ + struct A0 a; + f (&a); +} + + +struct A1 +{ + char n; + char a[1]; // { dg-message "destination object declared here" } + + A1 () { a[1] = 0; } // { dg-warning "\\\[-Wstringop-overflow" } +}; + +void g1 (void) +{ + struct A1 a; + f (&a); +} + + +struct A123 +{ + char a[123]; // { dg-message "destination object declared here" } + + A123 () { a[123] = 0; } // { dg-warning "\\\[-Wstringop-overflow" } +}; + +void g123 (void) +{ + struct A123 a; + f (&a); +} + + +struct A234 +{ + char a[234]; // { dg-message "destination object declared here" } + + A234 (int i) { a[i] = 0; } // { dg-warning "\\\[-Wstringop-overflow" } +}; + +void g234 (void) +{ + struct A234 a (234); + f (&a); +} Index: gcc/tree-ssa-strlen.c =================================================================== --- gcc/tree-ssa-strlen.c (revision 274541) +++ gcc/tree-ssa-strlen.c (working copy) @@ -3679,16 +3679,30 @@ handle_store (gimple_stmt_iterator *gsi) rhs_minlen = lenrange[0]; storing_nonzero_p = lenrange[1] > 0; - if (tree dstsize = compute_objsize (lhs, 1)) - if (compare_tree_int (dstsize, lenrange[2]) < 0) - { - location_t loc = gimple_nonartificial_location (stmt); - warning_n (loc, OPT_Wstringop_overflow_, - lenrange[2], - "%Gwriting %u byte into a region of size %E", - "%Gwriting %u bytes into a region of size %E", - stmt, lenrange[2], dstsize); - } + /* Avoid issuing multiple warnings for the same LHS or statement. + For example, -Warray-bounds may have already been issued for + an out-of-bounds subscript. */ + if (!TREE_NO_WARNING (lhs) && !gimple_no_warning_p (stmt)) + { + /* Set to the declaration referenced by LHS (if known). */ + tree decl = NULL_TREE; + if (tree dstsize = compute_objsize (lhs, 1, &decl)) + if (compare_tree_int (dstsize, lenrange[2]) < 0) + { + location_t loc = gimple_nonartificial_location (stmt); + if (warning_n (loc, OPT_Wstringop_overflow_, + lenrange[2], + "%Gwriting %u byte into a region of size %E", + "%Gwriting %u bytes into a region of size %E", + stmt, lenrange[2], dstsize)) + { + if (decl) + inform (DECL_SOURCE_LOCATION (decl), + "destination object declared here"); + gimple_set_no_warning (stmt, true); + } + } + } } else { Index: gcc/tree-vrp.c =================================================================== --- gcc/tree-vrp.c (revision 274541) +++ gcc/tree-vrp.c (working copy) @@ -4354,8 +4354,8 @@ class vrp_prop : public ssa_propagation_engine void vrp_initialize (void); void vrp_finalize (bool); void check_all_array_refs (void); - void check_array_ref (location_t, tree, bool); - void check_mem_ref (location_t, tree, bool); + bool check_array_ref (location_t, tree, bool); + bool check_mem_ref (location_t, tree, bool); void search_for_addr_array (tree, location_t); class vr_values vr_values; @@ -4381,9 +4381,10 @@ class vrp_prop : public ssa_propagation_engine array subscript is a constant, check if it is outside valid range. If the array subscript is a RANGE, warn if it is non-overlapping with valid range. - IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside a ADDR_EXPR. */ + IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside a ADDR_EXPR. + Returns true if a warning has been issued. */ -void +bool vrp_prop::check_array_ref (location_t location, tree ref, bool ignore_off_by_one) { @@ -4392,7 +4393,7 @@ vrp_prop::check_array_ref (location_t location, tr tree low_bound, up_bound, up_bound_p1; if (TREE_NO_WARNING (ref)) - return; + return false; low_sub = up_sub = TREE_OPERAND (ref, 1); up_bound = array_ref_up_bound (ref); @@ -4513,6 +4514,8 @@ vrp_prop::check_array_ref (location_t location, tr TREE_NO_WARNING (ref) = 1; } + + return warned; } /* Checks one MEM_REF in REF, located at LOCATION, for out-of-bounds @@ -4522,14 +4525,15 @@ vrp_prop::check_array_ref (location_t location, tr with valid range. IGNORE_OFF_BY_ONE is true if the MEM_REF is inside an ADDR_EXPR (used to allow one-past-the-end indices for code that takes - the address of the just-past-the-end element of an array). */ + the address of the just-past-the-end element of an array). + Returns true if a warning has been issued. */ -void +bool vrp_prop::check_mem_ref (location_t location, tree ref, bool ignore_off_by_one) { if (TREE_NO_WARNING (ref)) - return; + return false; tree arg = TREE_OPERAND (ref, 0); /* The constant and variable offset of the reference. */ @@ -4581,7 +4585,7 @@ vrp_prop::check_mem_ref (location_t location, tree continue; } else - return; + return false; /* VAROFF should always be a SSA_NAME here (and not even INTEGER_CST) but there's no point in taking chances. */ @@ -4643,10 +4647,10 @@ vrp_prop::check_mem_ref (location_t location, tree arg = TREE_OPERAND (arg, 0); if (TREE_CODE (arg) != STRING_CST && TREE_CODE (arg) != VAR_DECL) - return; + return false; } else - return; + return false; /* The type of the object being referred to. It can be an array, string literal, or a non-array type when the MEM_REF represents @@ -4661,7 +4665,7 @@ vrp_prop::check_mem_ref (location_t location, tree || !COMPLETE_TYPE_P (reftype) || TREE_CODE (TYPE_SIZE_UNIT (reftype)) != INTEGER_CST || RECORD_OR_UNION_TYPE_P (reftype)) - return; + return false; offset_int eltsize; if (TREE_CODE (reftype) == ARRAY_TYPE) @@ -4763,11 +4767,11 @@ vrp_prop::check_mem_ref (location_t location, tree if (warned) TREE_NO_WARNING (ref) = 1; - return; + return warned; } if (warn_array_bounds < 2) - return; + return false; /* At level 2 check also intermediate offsets. */ int i = 0; @@ -4778,8 +4782,13 @@ vrp_prop::check_mem_ref (location_t location, tree if (warning_at (location, OPT_Warray_bounds, "intermediate array offset %wi is outside array bounds " "of %qT", tmpidx, reftype)) - TREE_NO_WARNING (ref) = 1; + { + TREE_NO_WARNING (ref) = 1; + return true; + } } + + return false; } /* Searches if the expr T, located at LOCATION computes @@ -4791,11 +4800,15 @@ vrp_prop::search_for_addr_array (tree t, location_ /* Check each ARRAY_REF and MEM_REF in the reference chain. */ do { + bool warned = false; if (TREE_CODE (t) == ARRAY_REF) - check_array_ref (location, t, true /*ignore_off_by_one*/); + warned = check_array_ref (location, t, true /*ignore_off_by_one*/); else if (TREE_CODE (t) == MEM_REF) - check_mem_ref (location, t, true /*ignore_off_by_one*/); + warned = check_mem_ref (location, t, true /*ignore_off_by_one*/); + if (warned) + TREE_NO_WARNING (t) = true; + t = TREE_OPERAND (t, 0); } while (handled_component_p (t) || TREE_CODE (t) == MEM_REF); @@ -4886,16 +4899,20 @@ check_array_bounds (tree *tp, int *walk_subtree, v *walk_subtree = TRUE; + bool warned = false; vrp_prop *vrp_prop = (class vrp_prop *)wi->info; if (TREE_CODE (t) == ARRAY_REF) - vrp_prop->check_array_ref (location, t, false /*ignore_off_by_one*/); + warned = vrp_prop->check_array_ref (location, t, false/*ignore_off_by_one*/); else if (TREE_CODE (t) == MEM_REF) - vrp_prop->check_mem_ref (location, t, false /*ignore_off_by_one*/); + warned = vrp_prop->check_mem_ref (location, t, false /*ignore_off_by_one*/); else if (TREE_CODE (t) == ADDR_EXPR) { vrp_prop->search_for_addr_array (t, location); *walk_subtree = FALSE; } + /* Propagate the no-warning bit to the outer expression. */ + if (warned) + TREE_NO_WARNING (t) = true; return NULL_TREE; }