From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) by sourceware.org (Postfix) with ESMTPS id DCF98384F4AD; Fri, 18 Nov 2022 13:14:12 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org DCF98384F4AD Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=suse.de Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=suse.de Received: from relay2.suse.de (relay2.suse.de [149.44.160.134]) by smtp-out1.suse.de (Postfix) with ESMTP id 8CF1A210E6; Fri, 18 Nov 2022 13:14:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1668777251; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=8iA9AwHChS+x8yWK2iAHE+ZgV0qo7e/0YBg6OjJyi+A=; b=ETLn7zHxrYnhe51CQ91BsssHuNlFjrtTVXdIgauNp2O3T+kqM+ndW458DGTmKbvuMZ5RqZ +QEnRvwRkoTgRrBUkA9OKPACOR4p7m80PEh+pFPFtSmgU5bh2/WMz4LpRoRjBerx9XgzYQ g1xiQx5wxSz0m6r1YCdziRSPIOMzK/o= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1668777251; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=8iA9AwHChS+x8yWK2iAHE+ZgV0qo7e/0YBg6OjJyi+A=; b=yRPj8cMddGM9IRSeQWyPKusQx1Fjm2QAQaIsH12Ay3ETauahgbrus1x5fXXtUTMSMtBTwR bdgTS9o9unjZ2iAA== Received: from wotan.suse.de (wotan.suse.de [10.160.0.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by relay2.suse.de (Postfix) with ESMTPS id 57AC62C141; Fri, 18 Nov 2022 13:14:11 +0000 (UTC) Date: Fri, 18 Nov 2022 13:14:11 +0000 (UTC) From: Richard Biener To: Qing Zhao cc: joseph@codesourcery.com, gcc-patches@gcc.gnu.org, keescook@chromium.org, siddhesh@gcc.gnu.org Subject: Re: [PATCH 2/2] Add a new warning option -Wstrict-flex-arrays. In-Reply-To: <20221108145113.955321-3-qing.zhao@oracle.com> Message-ID: References: <20221108145113.955321-1-qing.zhao@oracle.com> <20221108145113.955321-3-qing.zhao@oracle.com> User-Agent: Alpine 2.22 (LSU 394 2020-01-19) MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII X-Spam-Status: No, score=-11.1 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On Tue, 8 Nov 2022, Qing Zhao wrote: > '-Wstrict-flex-arrays' > Warn about inproper usages of flexible array members according to > the LEVEL of the 'strict_flex_array (LEVEL)' attribute attached to > the trailing array field of a structure if it's available, > otherwise according to the LEVEL of the option > '-fstrict-flex-arrays=LEVEL'. > > This option is effective only when LEVEL is bigger than 0. > Otherwise, it will be ignored with a warning. > > when LEVEL=1, warnings will be issued for a trailing array > reference of a structure that have 2 or more elements if the > trailing array is referenced as a flexible array member. > > when LEVEL=2, in addition to LEVEL=1, additional warnings will be > issued for a trailing one-element array reference of a structure if > the array is referenced as a flexible array member. > > when LEVEL=3, in addition to LEVEL=2, additional warnings will be > issued for a trailing zero-length array reference of a structure if > the array is referenced as a flexible array member. > > At the same time, keep -Warray-bounds=[1|2] warnings unchanged from > -fstrict-flex-arrays. Looking at this, is this a way to avoid interpreting -Warray-bounds=N together with -fstrict-flex-arrays=M? Won't this be just confusing to users? Especially since -Wall includes -Warray-bounds and thus we'll diagnose + if (opts->x_warn_array_bounds) + if (opts->x_flag_strict_flex_arrays) + { + warning_at (UNKNOWN_LOCATION, 0, + "%<-Warray-bounds%> is not impacted by " + "%<-fstrict-flex-arrays%>"); + } and do that even when -Wstrict-flex-arrays is given? Would it be better/possible to add a note: to existing -Warray-bounds diagnostics on how the behavior is altered by -fstrict-flex-arrays? I guess this will inevitably re-iterate the -fstrict-flex-arrays=N vs. -Warray-bounds=M discussion ... I think it would be better to stick with -Warray-bounds and flex its =2 mode to work according to -fstrict-flex-arrays=N instead of "out of bounds accesses to trailing struct members of one-element array types" (thus, not add [1] but instead the cases that are not flex arrays according to -fstrict-flex-arrays). Richard. > gcc/ChangeLog: > > * attribs.cc (strict_flex_array_level_of): New function. > * attribs.h (strict_flex_array_level_of): Prototype for new function. > * doc/invoke.texi: Document -Wstrict-flex-arrays option. Update > -fstrict-flex-arrays[=n] options. > * gimple-array-bounds.cc (array_bounds_checker::check_array_ref): > Issue warnings for -Wstrict-flex-arrays. > (get_up_bounds_for_array_ref): New function. > (check_out_of_bounds_and_warn): New function. > * opts.cc (finish_options): Issue warnings for unsupported combination > of -Warray-bounds and -fstrict-flex-arrays, -Wstrict_flex_arrays and > -fstrict-flex-array. > * tree-vrp.cc (execute_vrp): Enable the pass when > warn_strict_flex_array is true. > (execute_ranger_vrp): Likewise. > * tree.cc (array_ref_flexible_size_p): Add one new argument. > (component_ref_sam_type): New function. > (component_ref_size): Add one new argument, > * tree.h (array_ref_flexible_size_p): Update prototype. > (enum struct special_array_member): Add two new enum values. > (component_ref_sam_type): New prototype. > (component_ref_size): Update prototype. > > gcc/c-family/ChangeLog: > > * c.opt (Wstrict-flex-arrays): New option. > > gcc/c/ChangeLog: > > * c-decl.cc (is_flexible_array_member_p): Call new function > strict_flex_array_level_of. > > gcc/testsuite/ChangeLog: > > * c-c++-common/Wstrict-flex-arrays.c: New test. > * c-c++-common/Wstrict-flex-arrays_2.c: New test. > * gcc.dg/Wstrict-flex-arrays-2.c: New test. > * gcc.dg/Wstrict-flex-arrays-3.c: New test. > * gcc.dg/Wstrict-flex-arrays-4.c: New test. > * gcc.dg/Wstrict-flex-arrays-5.c: New test. > * gcc.dg/Wstrict-flex-arrays-6.c: New test. > * gcc.dg/Wstrict-flex-arrays-7.c: New test. > * gcc.dg/Wstrict-flex-arrays-8.c: New test. > * gcc.dg/Wstrict-flex-arrays-9.c: New test. > * gcc.dg/Wstrict-flex-arrays.c: New test. > --- > gcc/attribs.cc | 30 ++ > gcc/attribs.h | 2 + > gcc/c-family/c.opt | 5 + > gcc/c/c-decl.cc | 22 +- > gcc/doc/invoke.texi | 33 ++- > gcc/gimple-array-bounds.cc | 264 +++++++++++++----- > gcc/opts.cc | 15 + > .../c-c++-common/Wstrict-flex-arrays.c | 9 + > .../c-c++-common/Wstrict-flex-arrays_2.c | 9 + > gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c | 46 +++ > gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c | 46 +++ > gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c | 49 ++++ > gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c | 48 ++++ > gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c | 48 ++++ > gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c | 50 ++++ > gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c | 49 ++++ > gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c | 49 ++++ > gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c | 46 +++ > gcc/tree-vrp.cc | 6 +- > gcc/tree.cc | 165 ++++++++--- > gcc/tree.h | 15 +- > 21 files changed, 870 insertions(+), 136 deletions(-) > create mode 100644 gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c > create mode 100644 gcc/testsuite/c-c++-common/Wstrict-flex-arrays_2.c > create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c > create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c > create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c > create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c > create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c > create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c > create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c > create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c > create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c > > diff --git a/gcc/attribs.cc b/gcc/attribs.cc > index 27dea748561..095def4d6b0 100644 > --- a/gcc/attribs.cc > +++ b/gcc/attribs.cc > @@ -2456,6 +2456,36 @@ init_attr_rdwr_indices (rdwr_map *rwm, tree attrs) > } > } > > +/* Get the LEVEL of the strict_flex_array for the ARRAY_FIELD based on the > + values of attribute strict_flex_array and the flag_strict_flex_arrays. */ > +unsigned int > +strict_flex_array_level_of (tree array_field) > +{ > + gcc_assert (TREE_CODE (array_field) == FIELD_DECL); > + unsigned int strict_flex_array_level = flag_strict_flex_arrays; > + > + tree attr_strict_flex_array > + = lookup_attribute ("strict_flex_array", DECL_ATTRIBUTES (array_field)); > + /* If there is a strict_flex_array attribute attached to the field, > + override the flag_strict_flex_arrays. */ > + if (attr_strict_flex_array) > + { > + /* Get the value of the level first from the attribute. */ > + unsigned HOST_WIDE_INT attr_strict_flex_array_level = 0; > + gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE); > + attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array); > + gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE); > + attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array); > + gcc_assert (tree_fits_uhwi_p (attr_strict_flex_array)); > + attr_strict_flex_array_level = tree_to_uhwi (attr_strict_flex_array); > + > + /* The attribute has higher priority than flag_struct_flex_array. */ > + strict_flex_array_level = attr_strict_flex_array_level; > + } > + return strict_flex_array_level; > +} > + > + > /* Return the access specification for a function parameter PARM > or null if the current function has no such specification. */ > > diff --git a/gcc/attribs.h b/gcc/attribs.h > index 1dc16e4bc4e..742811e6fda 100644 > --- a/gcc/attribs.h > +++ b/gcc/attribs.h > @@ -398,4 +398,6 @@ extern void init_attr_rdwr_indices (rdwr_map *, tree); > extern attr_access *get_parm_access (rdwr_map &, tree, > tree = current_function_decl); > > +extern unsigned int strict_flex_array_level_of (tree); > + > #endif // GCC_ATTRIBS_H > diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt > index 01d480759ae..bc33710a649 100644 > --- a/gcc/c-family/c.opt > +++ b/gcc/c-family/c.opt > @@ -968,6 +968,11 @@ Wstringop-truncation > C ObjC C++ LTO ObjC++ Var(warn_stringop_truncation) Warning Init (1) LangEnabledBy(C ObjC C++ LTO ObjC++, Wall) > Warn about truncation in string manipulation functions like strncat and strncpy. > > +Wstrict-flex-arrays > +C C++ Var(warn_strict_flex_arrays) Warning > +Warn about inproper usages of flexible array members > +according to the level of -fstrict-flex-arrays. > + > Wsuggest-attribute=format > C ObjC C++ ObjC++ Var(warn_suggest_attribute_format) Warning > Warn about functions which might be candidates for format attributes. > diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc > index 4746e310d2d..c9cb46daacc 100644 > --- a/gcc/c/c-decl.cc > +++ b/gcc/c/c-decl.cc > @@ -8828,7 +8828,6 @@ finish_incomplete_vars (tree incomplete_vars, bool toplevel) > } > } > > - > /* Determine whether the FIELD_DECL X is a flexible array member according to > the following info: > A. whether the FIELD_DECL X is the last field of the DECL_CONTEXT; > @@ -8855,26 +8854,7 @@ is_flexible_array_member_p (bool is_last_field, > bool is_one_element_array = one_element_array_type_p (TREE_TYPE (x)); > bool is_flexible_array = flexible_array_member_type_p (TREE_TYPE (x)); > > - unsigned int strict_flex_array_level = flag_strict_flex_arrays; > - > - tree attr_strict_flex_array = lookup_attribute ("strict_flex_array", > - DECL_ATTRIBUTES (x)); > - /* If there is a strict_flex_array attribute attached to the field, > - override the flag_strict_flex_arrays. */ > - if (attr_strict_flex_array) > - { > - /* Get the value of the level first from the attribute. */ > - unsigned HOST_WIDE_INT attr_strict_flex_array_level = 0; > - gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE); > - attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array); > - gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE); > - attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array); > - gcc_assert (tree_fits_uhwi_p (attr_strict_flex_array)); > - attr_strict_flex_array_level = tree_to_uhwi (attr_strict_flex_array); > - > - /* The attribute has higher priority than flag_struct_flex_array. */ > - strict_flex_array_level = attr_strict_flex_array_level; > - } > + unsigned int strict_flex_array_level = strict_flex_array_level_of (x); > > switch (strict_flex_array_level) > { > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > index 64f77e8367a..a35e6bf27e0 100644 > --- a/gcc/doc/invoke.texi > +++ b/gcc/doc/invoke.texi > @@ -397,7 +397,7 @@ Objective-C and Objective-C++ Dialects}. > -Wstrict-aliasing=n -Wstrict-overflow -Wstrict-overflow=@var{n} @gol > -Wstring-compare @gol > -Wno-stringop-overflow -Wno-stringop-overread @gol > --Wno-stringop-truncation @gol > +-Wno-stringop-truncation -Wstrict-flex-arrays @gol > -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{|}malloc@r{]} @gol > -Wswitch -Wno-switch-bool -Wswitch-default -Wswitch-enum @gol > -Wno-switch-outside-range -Wno-switch-unreachable -Wsync-nand @gol > @@ -2848,12 +2848,18 @@ The negative form is equivalent to @option{-fstrict-flex-arrays=0}, which is the > least strict. All trailing arrays of structures are treated as flexible array > members. > > +This option is not compatible with @option{-Warray-bounds} due to historical > +reason. The behavior of @option{-Warray-bounds} is not changed by this option. > + > @item -fstrict-flex-arrays=@var{level} > @opindex fstrict-flex-arrays=@var{level} > Control when to treat the trailing array of a structure as a flexible array > member for the purpose of accessing the elements of such an array. The value > of @var{level} controls the level of strictness. > > +This option is not compatible with @option{-Warray-bounds} due to historical > +reason. The behavior of @option{-Warray-bounds} is not changed by this option. > + > The possible values of @var{level} are the same as for the > @code{strict_flex_array} attribute (@pxref{Variable Attributes}). > > @@ -7662,6 +7668,31 @@ however, are not suitable arguments to functions that expect > such arrays GCC issues warnings unless it can prove that the use is > safe. @xref{Common Variable Attributes}. > > +@item -Wstrict-flex-arrays > +@opindex Wstrict-flex-arrays > +@opindex Wno-strict-flex-arrays > +Warn about inproper usages of flexible array members > +according to the @var{level} of the @code{strict_flex_array (@var{level})} > +attribute attached to the trailing array field of a structure if it's > +available, otherwise according to the @var{level} of the option > +@option{-fstrict-flex-arrays=@var{level}}. > + > +This option is effective only when @var{level} is bigger than 0. Otherwise, > +it will be ignored with a warning. > + > +when @var{level}=1, warnings will be issued for a trailing array reference > +of a structure that have 2 or more elements if the trailing array is referenced > +as a flexible array member. > + > +when @var{level}=2, in addition to @var{level}=1, additional warnings will be > +issued for a trailing one-element array reference of a structure > +if the array is referenced as a flexible array member. > + > +when @var{level}=3, in addition to @var{level}=2, additional warnings will be > +issued for a trailing zero-length array reference of a structure > +if the array is referenced as a flexible array member. > + > + > @item -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{|}cold@r{|}malloc@r{]} > @opindex Wsuggest-attribute= > @opindex Wno-suggest-attribute= > diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc > index fbf448e045d..7f790c5a19a 100644 > --- a/gcc/gimple-array-bounds.cc > +++ b/gcc/gimple-array-bounds.cc > @@ -170,38 +170,20 @@ trailing_array (tree arg, tree *pref) > return array_ref_flexible_size_p (arg); > } > > -/* Checks one ARRAY_REF in REF, located at LOCUS. Ignores flexible > - arrays and "struct" hacks. If VRP can determine that the 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. Return true if a warning has been issued or if > - no-warning is set. */ > - > -bool > -array_bounds_checker::check_array_ref (location_t location, tree ref, > - gimple *stmt, bool ignore_off_by_one) > +/* Acquire the upper bound and upper bound plus one for the array > + reference REF and record them into UP_BOUND and UP_BOUND_P1. > + Set *DECL to the decl or expresssion REF refers to. > + FOR_ARRAY_BOUND is true when this is for array bound checking. */ > + > +static void > +get_up_bounds_for_array_ref (tree ref, tree *decl, > + tree *up_bound, tree *up_bound_p1, > + bool for_array_bound) > { > - if (warning_suppressed_p (ref, OPT_Warray_bounds)) > - /* Return true to have the caller prevent warnings for enclosing > - refs. */ > - return true; > - > - tree low_sub = TREE_OPERAND (ref, 1); > - tree up_sub = low_sub; > - tree up_bound = array_ref_up_bound (ref); > - > - /* Referenced decl if one can be determined. */ > - tree decl = NULL_TREE; > - > - /* Set for accesses to interior zero-length arrays. */ > - special_array_member sam{ }; > - > - tree up_bound_p1; > - > - if (!up_bound > - || TREE_CODE (up_bound) != INTEGER_CST > - || (warn_array_bounds < 2 && trailing_array (ref, &decl))) > + if (!(*up_bound) > + || TREE_CODE (*up_bound) != INTEGER_CST > + || ((for_array_bound ? (warn_array_bounds < 2) : warn_strict_flex_arrays) > + && trailing_array (ref, decl))) > { > /* Accesses to trailing arrays via pointers may access storage > beyond the types array bounds. For such arrays, or for flexible > @@ -213,8 +195,8 @@ array_bounds_checker::check_array_ref (location_t location, tree ref, > if (TREE_CODE (eltsize) != INTEGER_CST > || integer_zerop (eltsize)) > { > - up_bound = NULL_TREE; > - up_bound_p1 = NULL_TREE; > + *up_bound = NULL_TREE; > + *up_bound_p1 = NULL_TREE; > } > else > { > @@ -227,7 +209,8 @@ array_bounds_checker::check_array_ref (location_t location, tree ref, > { > /* Try to determine the size of the trailing array from > its initializer (if it has one). */ > - if (tree refsize = component_ref_size (arg, &sam)) > + if (tree refsize > + = component_ref_size (arg, NULL, for_array_bound)) > if (TREE_CODE (refsize) == INTEGER_CST) > maxbound = refsize; > } > @@ -246,7 +229,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref, > { > /* Try to determine the size from a pointer to > an array if BASE is one. */ > - if (tree size = get_ref_size (base, &decl)) > + if (tree size = get_ref_size (base, decl)) > maxbound = size; > } > else if (!compref && DECL_P (base)) > @@ -254,7 +237,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref, > if (TREE_CODE (basesize) == INTEGER_CST) > { > maxbound = basesize; > - decl = base; > + *decl = base; > } > > if (known_gt (off, 0)) > @@ -266,40 +249,47 @@ array_bounds_checker::check_array_ref (location_t location, tree ref, > else > maxbound = fold_convert (sizetype, maxbound); > > - up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize); > + *up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize); > > - if (up_bound_p1 != NULL_TREE) > - up_bound = int_const_binop (MINUS_EXPR, up_bound_p1, > + if (*up_bound_p1 != NULL_TREE) > + *up_bound = int_const_binop (MINUS_EXPR, *up_bound_p1, > build_int_cst (ptrdiff_type_node, 1)); > else > - up_bound = NULL_TREE; > + *up_bound = NULL_TREE; > } > } > else > - up_bound_p1 = int_const_binop (PLUS_EXPR, up_bound, > - build_int_cst (TREE_TYPE (up_bound), 1)); > + *up_bound_p1 = int_const_binop (PLUS_EXPR, *up_bound, > + build_int_cst (TREE_TYPE (*up_bound), 1)); > + return; > +} > > - tree low_bound = array_ref_low_bound (ref); > +/* Given the LOW_SUB_ORG, LOW_SUB and UP_SUB, and the computed UP_BOUND > + and UP_BOUND_P1, check whether the array reference REF is out of bound. > + When out of bounds, issue warnings if FOR_ARRAY_BOUND is true. > + otherwise, return true without issue warnings. */ > > +static bool > +check_out_of_bounds_and_warn (location_t location, tree ref, > + tree low_sub_org, tree low_sub, tree up_sub, > + tree up_bound, tree up_bound_p1, > + const value_range *vr, > + bool ignore_off_by_one, bool for_array_bound) > +{ > + tree low_bound = array_ref_low_bound (ref); > tree artype = TREE_TYPE (TREE_OPERAND (ref, 0)); > > bool warned = false; > > /* Empty array. */ > if (up_bound && tree_int_cst_equal (low_bound, up_bound_p1)) > - warned = warning_at (location, OPT_Warray_bounds, > - "array subscript %E is outside array bounds of %qT", > - low_sub, artype); > - > - const value_range *vr = NULL; > - if (TREE_CODE (low_sub) == SSA_NAME) > { > - vr = get_value_range (low_sub, stmt); > - if (!vr->undefined_p () && !vr->varying_p ()) > - { > - low_sub = vr->kind () == VR_RANGE ? vr->max () : vr->min (); > - up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max (); > - } > + if (for_array_bound) > + warned = warning_at (location, OPT_Warray_bounds, > + "array subscript %E is outside array" > + " bounds of %qT", low_sub_org, artype); > + else > + warned = true; > } > > if (warned) > @@ -313,24 +303,127 @@ array_bounds_checker::check_array_ref (location_t location, tree ref, > : tree_int_cst_le (up_bound, up_sub)) > && TREE_CODE (low_sub) == INTEGER_CST > && tree_int_cst_le (low_sub, low_bound)) > - warned = warning_at (location, OPT_Warray_bounds, > - "array subscript [%E, %E] is outside " > - "array bounds of %qT", > - low_sub, up_sub, artype); > + { > + if (for_array_bound) > + warned = warning_at (location, OPT_Warray_bounds, > + "array subscript [%E, %E] is outside " > + "array bounds of %qT", > + low_sub, up_sub, artype); > + else > + warned = true; > + } > } > else if (up_bound > && TREE_CODE (up_sub) == INTEGER_CST > && (ignore_off_by_one > ? !tree_int_cst_le (up_sub, up_bound_p1) > : !tree_int_cst_le (up_sub, up_bound))) > - warned = warning_at (location, OPT_Warray_bounds, > - "array subscript %E is above array bounds of %qT", > - up_sub, artype); > + { > + if (for_array_bound) > + warned = warning_at (location, OPT_Warray_bounds, > + "array subscript %E is above array bounds of %qT", > + up_sub, artype); > + else > + warned = true; > + } > else if (TREE_CODE (low_sub) == INTEGER_CST > && tree_int_cst_lt (low_sub, low_bound)) > - warned = warning_at (location, OPT_Warray_bounds, > - "array subscript %E is below array bounds of %qT", > - low_sub, artype); > + { > + if (for_array_bound) > + warned = warning_at (location, OPT_Warray_bounds, > + "array subscript %E is below array bounds of %qT", > + low_sub, artype); > + else > + warned = true; > + } > + return warned; > +} > + > +/* Checks one ARRAY_REF in REF, located at LOCUS. Ignores flexible > + arrays and "struct" hacks. If VRP can determine that the 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. Return true if a warning has been issued or if > + no-warning is set. */ > + > +bool > +array_bounds_checker::check_array_ref (location_t location, tree ref, > + gimple *stmt, bool ignore_off_by_one) > +{ > + if (warning_suppressed_p (ref, OPT_Warray_bounds)) > + /* Return true to have the caller prevent warnings for enclosing > + refs. */ > + return true; > + > + /* Upper bound and Upper bound plus one for -Warray-bounds. */ > + tree up_bound = array_ref_up_bound (ref); > + tree up_bound_p1 = NULL_TREE; > + > + /* Upper bound and upper bound plus one for -Wstrict-flex-array. */ > + tree up_bound_strict = up_bound; > + tree up_bound_p1_strict = NULL_TREE; > + > + /* Referenced decl if one can be determined. */ > + tree decl = NULL_TREE; > + > + /* Set to the type of the special array member for a COMPONENT_REF. */ > + special_array_member sam{ }; > + > + tree arg = TREE_OPERAND (ref, 0); > + const bool compref = TREE_CODE (arg) == COMPONENT_REF; > + > + unsigned int strict_flex_array_level = flag_strict_flex_arrays; > + > + if (compref) > + { > + /* Try to determine special array member type for this COMPONENT_REF. */ > + sam = component_ref_sam_type (arg); > + /* Get the level of strict_flex_array for this array field. */ > + tree afield_decl = TREE_OPERAND (arg, 1); > + strict_flex_array_level = strict_flex_array_level_of (afield_decl); > + } > + > + if (warn_array_bounds) > + get_up_bounds_for_array_ref (ref, &decl, &up_bound, &up_bound_p1, > + true); > + if (warn_strict_flex_arrays) > + get_up_bounds_for_array_ref (ref, &decl, &up_bound_strict, > + &up_bound_p1_strict, false); > + > + > + > + bool warned = false; > + bool out_of_bound = false; > + > + tree artype = TREE_TYPE (TREE_OPERAND (ref, 0)); > + tree low_sub_org = TREE_OPERAND (ref, 1); > + tree up_sub = low_sub_org; > + tree low_sub = low_sub_org; > + > + const value_range *vr = NULL; > + if (TREE_CODE (low_sub_org) == SSA_NAME) > + { > + vr = get_value_range (low_sub_org, stmt); > + if (!vr->undefined_p () && !vr->varying_p ()) > + { > + low_sub = vr->kind () == VR_RANGE ? vr->max () : vr->min (); > + up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max (); > + } > + } > + > + if (warn_array_bounds) > + warned = check_out_of_bounds_and_warn (location, ref, > + low_sub_org, low_sub, up_sub, > + up_bound, up_bound_p1, vr, > + ignore_off_by_one, true); > + > + if (warn_strict_flex_arrays) > + out_of_bound = check_out_of_bounds_and_warn (location, ref, > + low_sub_org, low_sub, up_sub, > + up_bound_strict, > + up_bound_p1_strict, vr, > + ignore_off_by_one, false); > > if (!warned && sam == special_array_member::int_0) > warned = warning_at (location, OPT_Wzero_length_bounds, > @@ -341,19 +434,56 @@ array_bounds_checker::check_array_ref (location_t location, tree ref, > "of an interior zero-length array %qT")), > low_sub, artype); > > - if (warned) > + if (warned || out_of_bound) > { > - if (dump_file && (dump_flags & TDF_DETAILS)) > + if (warned && dump_file && (dump_flags & TDF_DETAILS)) > { > fprintf (dump_file, "Array bound warning for "); > dump_generic_expr (MSG_NOTE, TDF_SLIM, ref); > fprintf (dump_file, "\n"); > } > > + /* issue warnings for -Wstrict-flex-arrays according to the level of > + flag_strict_flex_arrays. */ > + if (out_of_bound && warn_strict_flex_arrays) > + switch (strict_flex_array_level) > + { > + case 3: > + /* Issue additional warnings for trailing arrays [0]. */ > + if (sam == special_array_member::trail_0) > + warned = warning_at (location, OPT_Wstrict_flex_arrays, > + "trailing array %qT should not be used as " > + "a flexible array member for level 3", > + artype); > + /* FALLTHROUGH. */ > + case 2: > + /* Issue additional warnings for trailing arrays [1]. */ > + if (sam == special_array_member::trail_1) > + warned = warning_at (location, OPT_Wstrict_flex_arrays, > + "trailing array %qT should not be used as " > + "a flexible array member for level 2 and " > + "above", artype); > + /* FALLTHROUGH. */ > + case 1: > + /* Issue warnings for trailing arrays [n]. */ > + if (sam == special_array_member::trail_n) > + warned = warning_at (location, OPT_Wstrict_flex_arrays, > + "trailing array %qT should not be used as " > + "a flexible array member for level 1 and " > + "above", artype); > + break; > + case 0: > + /* Do nothing. */ > + break; > + default: > + gcc_unreachable (); > + } > + > /* Avoid more warnings when checking more significant subscripts > of the same expression. */ > ref = TREE_OPERAND (ref, 0); > suppress_warning (ref, OPT_Warray_bounds); > + suppress_warning (ref, OPT_Wstrict_flex_arrays); > > if (decl) > ref = decl; > diff --git a/gcc/opts.cc b/gcc/opts.cc > index ae079fcd20e..ca162aa781c 100644 > --- a/gcc/opts.cc > +++ b/gcc/opts.cc > @@ -1409,6 +1409,21 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, > opts->x_profile_flag = 0; > } > > + if (opts->x_warn_array_bounds) > + if (opts->x_flag_strict_flex_arrays) > + { > + warning_at (UNKNOWN_LOCATION, 0, > + "%<-Warray-bounds%> is not impacted by " > + "%<-fstrict-flex-arrays%>"); > + } > + if (opts->x_warn_strict_flex_arrays) > + if (opts->x_flag_strict_flex_arrays == 0) > + { > + opts->x_warn_strict_flex_arrays = 0; > + warning_at (UNKNOWN_LOCATION, 0, > + "%<-Wstrict-flex-arrays%> is ignored when" > + " %<-fstrict-flex-arrays%> does not present"); > + } > > diagnose_options (opts, opts_set, loc); > } > diff --git a/gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c > new file mode 100644 > index 00000000000..72b4b7c6406 > --- /dev/null > +++ b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c > @@ -0,0 +1,9 @@ > +/* Test the usage of option -Wstrict-flex-arrays. */ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -Wstrict-flex-arrays" } */ > + > +int main(int argc, char *argv[]) > +{ > + return 0; > +} > +/* { dg-warning "is ignored when \'-fstrict-flex-arrays\' does not present" "" { target *-*-* } 0 } */ > diff --git a/gcc/testsuite/c-c++-common/Wstrict-flex-arrays_2.c b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays_2.c > new file mode 100644 > index 00000000000..af9ec922dea > --- /dev/null > +++ b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays_2.c > @@ -0,0 +1,9 @@ > +/* Test the usage of option -Wstrict-flex-arrays. */ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -Warray-bounds -fstrict-flex-arrays" } */ > + > +int main(int argc, char *argv[]) > +{ > + return 0; > +} > +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */ > diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c > new file mode 100644 > index 00000000000..59d5a5fcb23 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c > @@ -0,0 +1,46 @@ > +/* Test -Wstrict-flex-arrays. */ > +/* { dg-do run } */ > +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=2" } */ > + > +struct trailing_array_1 { > + int a; > + int b; > + int c[4]; > +}; > + > +struct trailing_array_2 { > + int a; > + int b; > + int c[1]; > +}; > + > +struct trailing_array_3 { > + int a; > + int b; > + int c[0]; > +}; > +struct trailing_array_4 { > + int a; > + int b; > + int c[]; > +}; > + > +void __attribute__((__noinline__)) stuff( > + struct trailing_array_1 *normal, > + struct trailing_array_2 *trailing_1, > + struct trailing_array_3 *trailing_0, > + struct trailing_array_4 *trailing_flex) > +{ > + normal->c[5] = 5; /*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */ > + trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */ > + trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */ > + trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */ > + > +} > + > +int main(int argc, char *argv[]) > +{ > + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]); > + > + return 0; > +} > diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c > new file mode 100644 > index 00000000000..2f66151e927 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c > @@ -0,0 +1,46 @@ > +/* Test -Wstrict-flex-arrays. */ > +/* { dg-do run } */ > +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=3" } */ > + > +struct trailing_array_1 { > + int a; > + int b; > + int c[4]; > +}; > + > +struct trailing_array_2 { > + int a; > + int b; > + int c[1]; > +}; > + > +struct trailing_array_3 { > + int a; > + int b; > + int c[0]; > +}; > +struct trailing_array_4 { > + int a; > + int b; > + int c[]; > +}; > + > +void __attribute__((__noinline__)) stuff( > + struct trailing_array_1 *normal, > + struct trailing_array_2 *trailing_1, > + struct trailing_array_3 *trailing_0, > + struct trailing_array_4 *trailing_flex) > +{ > + normal->c[5] = 5; /*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */ > + trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */ > + trailing_0->c[1] = 1; /* { dg-warning "should not be used as a flexible array member for level 3" } */ > + trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 3" } */ > + > +} > + > +int main(int argc, char *argv[]) > +{ > + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]); > + > + return 0; > +} > diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c > new file mode 100644 > index 00000000000..6a4576568ac > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c > @@ -0,0 +1,49 @@ > +/* Test -Wstrict-flex-arrays + -Warray-bounds. */ > +/* { dg-do run } */ > +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=1 -Warray-bounds" } */ > + > +struct trailing_array_1 { > + int a; > + int b; > + int c[4]; > +}; > + > +struct trailing_array_2 { > + int a; > + int b; > + int c[1]; > +}; > + > +struct trailing_array_3 { > + int a; > + int b; > + int c[0]; > +}; > +struct trailing_array_4 { > + int a; > + int b; > + int c[]; > +}; > + > +void __attribute__((__noinline__)) stuff( > + struct trailing_array_1 *normal, > + struct trailing_array_2 *trailing_1, > + struct trailing_array_3 *trailing_0, > + struct trailing_array_4 *trailing_flex) > +{ > + normal->c[5] = 5; /*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */ > + /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */ > + trailing_1->c[2] = 2; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */ > + trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */ > + trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */ > + > +} > + > +int main(int argc, char *argv[]) > +{ > + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]); > + > + return 0; > +} > + > +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */ > diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c > new file mode 100644 > index 00000000000..e550fbd24e1 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c > @@ -0,0 +1,48 @@ > +/* Test -Wstrict-flex-arrays + -Warray-bounds. */ > +/* { dg-do run } */ > +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=2 -Warray-bounds" } */ > + > +struct trailing_array_1 { > + int a; > + int b; > + int c[4]; > +}; > + > +struct trailing_array_2 { > + int a; > + int b; > + int c[1]; > +}; > + > +struct trailing_array_3 { > + int a; > + int b; > + int c[0]; > +}; > +struct trailing_array_4 { > + int a; > + int b; > + int c[]; > +}; > + > +void __attribute__((__noinline__)) stuff( > + struct trailing_array_1 *normal, > + struct trailing_array_2 *trailing_1, > + struct trailing_array_3 *trailing_0, > + struct trailing_array_4 *trailing_flex) > +{ > + normal->c[5] = 5; /*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */ > + /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */ > + trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */ > + trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */ > + trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */ > + > +} > + > +int main(int argc, char *argv[]) > +{ > + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]); > + > + return 0; > +} > +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */ > diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c > new file mode 100644 > index 00000000000..d5b61136b3a > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c > @@ -0,0 +1,48 @@ > +/* Test -Wstrict-flex-arrays. */ > +/* { dg-do run } */ > +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=3 -Warray-bounds" } */ > + > +struct trailing_array_1 { > + int a; > + int b; > + int c[4]; > +}; > + > +struct trailing_array_2 { > + int a; > + int b; > + int c[1]; > +}; > + > +struct trailing_array_3 { > + int a; > + int b; > + int c[0]; > +}; > +struct trailing_array_4 { > + int a; > + int b; > + int c[]; > +}; > + > +void __attribute__((__noinline__)) stuff( > + struct trailing_array_1 *normal, > + struct trailing_array_2 *trailing_1, > + struct trailing_array_3 *trailing_0, > + struct trailing_array_4 *trailing_flex) > +{ > + normal->c[5] = 5; /*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */ > + /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */ > + trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */ > + trailing_0->c[1] = 1; /* { dg-warning "should not be used as a flexible array member for level 3" } */ > + trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 3" } */ > + > +} > + > +int main(int argc, char *argv[]) > +{ > + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]); > + > + return 0; > +} > +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */ > diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c > new file mode 100644 > index 00000000000..eb82a60c261 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c > @@ -0,0 +1,50 @@ > +/* Test -Wstrict-flex-arrays + -Warray-bounds=2. */ > +/* { dg-do run } */ > +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=1 -Warray-bounds=2" } */ > + > +struct trailing_array_1 { > + int a; > + int b; > + int c[4]; > +}; > + > +struct trailing_array_2 { > + int a; > + int b; > + int c[1]; > +}; > + > +struct trailing_array_3 { > + int a; > + int b; > + int c[0]; > +}; > +struct trailing_array_4 { > + int a; > + int b; > + int c[]; > +}; > + > +void __attribute__((__noinline__)) stuff( > + struct trailing_array_1 *normal, > + struct trailing_array_2 *trailing_1, > + struct trailing_array_3 *trailing_0, > + struct trailing_array_4 *trailing_flex) > +{ > + normal->c[5] = 5; /*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */ > + /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */ > + trailing_1->c[2] = 2; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */ > + /*{ dg-warning "array subscript 2 is above array bounds of" "" { target *-*-* } .-1 } */ > + trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */ > + trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */ > + > +} > + > +int main(int argc, char *argv[]) > +{ > + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]); > + > + return 0; > +} > + > +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */ > diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c > new file mode 100644 > index 00000000000..f48a50e04f5 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c > @@ -0,0 +1,49 @@ > +/* Test -Wstrict-flex-arrays + -Warray-bounds=2. */ > +/* { dg-do run } */ > +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=2 -Warray-bounds=2" } */ > + > +struct trailing_array_1 { > + int a; > + int b; > + int c[4]; > +}; > + > +struct trailing_array_2 { > + int a; > + int b; > + int c[1]; > +}; > + > +struct trailing_array_3 { > + int a; > + int b; > + int c[0]; > +}; > +struct trailing_array_4 { > + int a; > + int b; > + int c[]; > +}; > + > +void __attribute__((__noinline__)) stuff( > + struct trailing_array_1 *normal, > + struct trailing_array_2 *trailing_1, > + struct trailing_array_3 *trailing_0, > + struct trailing_array_4 *trailing_flex) > +{ > + normal->c[5] = 5; /*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */ > + /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */ > + trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */ > + /*{ dg-warning "array subscript 2 is above array bounds of" "" { target *-*-* } .-1 } */ > + trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */ > + trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */ > + > +} > + > +int main(int argc, char *argv[]) > +{ > + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]); > + > + return 0; > +} > +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */ > diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c > new file mode 100644 > index 00000000000..9f2877ef4e1 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c > @@ -0,0 +1,49 @@ > +/* Test -Wstrict-flex-arrays + -Warray-bounds=2. */ > +/* { dg-do run } */ > +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=3 -Warray-bounds=2" } */ > + > +struct trailing_array_1 { > + int a; > + int b; > + int c[4]; > +}; > + > +struct trailing_array_2 { > + int a; > + int b; > + int c[1]; > +}; > + > +struct trailing_array_3 { > + int a; > + int b; > + int c[0]; > +}; > +struct trailing_array_4 { > + int a; > + int b; > + int c[]; > +}; > + > +void __attribute__((__noinline__)) stuff( > + struct trailing_array_1 *normal, > + struct trailing_array_2 *trailing_1, > + struct trailing_array_3 *trailing_0, > + struct trailing_array_4 *trailing_flex) > +{ > + normal->c[5] = 5; /*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */ > + /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */ > + trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */ > + /*{ dg-warning "array subscript 2 is above array bounds of" "" { target *-*-* } .-1 } */ > + trailing_0->c[1] = 1; /* { dg-warning "should not be used as a flexible array member for level 3" } */ > + trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 3" } */ > + > +} > + > +int main(int argc, char *argv[]) > +{ > + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]); > + > + return 0; > +} > +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */ > diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c > new file mode 100644 > index 00000000000..43a9098f138 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c > @@ -0,0 +1,46 @@ > +/* Test -Wstrict-flex-arrays. */ > +/* { dg-do run } */ > +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=1" } */ > + > +struct trailing_array_1 { > + int a; > + int b; > + int c[4]; > +}; > + > +struct trailing_array_2 { > + int a; > + int b; > + int c[1]; > +}; > + > +struct trailing_array_3 { > + int a; > + int b; > + int c[0]; > +}; > +struct trailing_array_4 { > + int a; > + int b; > + int c[]; > +}; > + > +void __attribute__((__noinline__)) stuff( > + struct trailing_array_1 *normal, > + struct trailing_array_2 *trailing_1, > + struct trailing_array_3 *trailing_0, > + struct trailing_array_4 *trailing_flex) > +{ > + normal->c[5] = 5; /*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */ > + trailing_1->c[2] = 2; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */ > + trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */ > + trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */ > + > +} > + > +int main(int argc, char *argv[]) > +{ > + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]); > + > + return 0; > +} > diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc > index e5a292bb875..1f1b56c1a52 100644 > --- a/gcc/tree-vrp.cc > +++ b/gcc/tree-vrp.cc > @@ -4229,12 +4229,12 @@ execute_vrp (struct function *fun, bool warn_array_bounds_p) > the flag on every edge now, rather than in > check_array_bounds_dom_walker's ctor; vrp_folder may clear > it from some edges. */ > - if (warn_array_bounds && warn_array_bounds_p) > + if ((warn_array_bounds || warn_strict_flex_arrays) && warn_array_bounds_p) > set_all_edges_as_executable (fun); > > folder.substitute_and_fold (); > > - if (warn_array_bounds && warn_array_bounds_p) > + if ((warn_array_bounds || warn_strict_flex_arrays) && warn_array_bounds_p) > { > array_bounds_checker array_checker (fun, &vrp_vr_values); > array_checker.check (); > @@ -4353,7 +4353,7 @@ execute_ranger_vrp (struct function *fun, bool warn_array_bounds_p) > if (dump_file && (dump_flags & TDF_DETAILS)) > ranger->dump (dump_file); > > - if (warn_array_bounds && warn_array_bounds_p) > + if ((warn_array_bounds || warn_strict_flex_arrays) && warn_array_bounds_p) > { > // Set all edges as executable, except those ranger says aren't. > int non_exec_flag = ranger->non_executable_edge_flag; > diff --git a/gcc/tree.cc b/gcc/tree.cc > index d2b0b34a725..0f5f7151b6b 100644 > --- a/gcc/tree.cc > +++ b/gcc/tree.cc > @@ -12726,15 +12726,21 @@ array_ref_up_bound (tree exp) > int test (uint8_t *p, uint32_t t[1][1], int n) { > for (int i = 0; i < 4; i++, p++) > t[i][0] = ...; > + > + If non-null, set IS_TRAILING_ARRAY to true if the ref is the above case A. > */ > > bool > -array_ref_flexible_size_p (tree ref) > +array_ref_flexible_size_p (tree ref, bool *is_trailing_array /* = NULL */) > { > - /* the TYPE for this array referece. */ > + /* The TYPE for this array referece. */ > tree atype = NULL_TREE; > - /* the FIELD_DECL for the array field in the containing structure. */ > + /* The FIELD_DECL for the array field in the containing structure. */ > tree afield_decl = NULL_TREE; > + /* Whether this array is the trailing array of a structure. */ > + bool is_trailing_array_tmp = false; > + if (!is_trailing_array) > + is_trailing_array = &is_trailing_array_tmp; > > if (TREE_CODE (ref) == ARRAY_REF > || TREE_CODE (ref) == ARRAY_RANGE_REF) > @@ -12822,7 +12828,10 @@ array_ref_flexible_size_p (tree ref) > if (! TYPE_SIZE (atype) > || ! TYPE_DOMAIN (atype) > || ! TYPE_MAX_VALUE (TYPE_DOMAIN (atype))) > - return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; > + { > + *is_trailing_array = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL; > + return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; > + } > > /* If the reference is based on a declared entity, the size of the array > is constrained by its given domain. (Do not trust commons PR/69368). */ > @@ -12844,9 +12853,17 @@ array_ref_flexible_size_p (tree ref) > if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (atype))) != INTEGER_CST > || TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST > || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST) > - return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; > + { > + *is_trailing_array > + = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL; > + return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; > + } > if (! get_addr_base_and_unit_offset (ref_to_array, &offset)) > - return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; > + { > + *is_trailing_array > + = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL; > + return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; > + } > > /* If at least one extra element fits it is a flexarray. */ > if (known_le ((wi::to_offset (TYPE_MAX_VALUE (TYPE_DOMAIN (atype))) > @@ -12854,11 +12871,16 @@ array_ref_flexible_size_p (tree ref) > + 2) > * wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (atype))), > wi::to_offset (DECL_SIZE_UNIT (ref)) - offset)) > - return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; > + { > + *is_trailing_array > + = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL; > + return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; > + } > > return false; > } > > + *is_trailing_array = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL; > return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; > } > > @@ -12920,24 +12942,81 @@ get_initializer_for (tree init, tree decl) > return NULL_TREE; > } > > +/* Determines the special array member type for the array reference REF. */ > +special_array_member > +component_ref_sam_type (tree ref) > +{ > + special_array_member sam_type = special_array_member::none; > + > + tree member = TREE_OPERAND (ref, 1); > + tree memsize = DECL_SIZE_UNIT (member); > + if (memsize) > + { > + tree memtype = TREE_TYPE (member); > + if (TREE_CODE (memtype) != ARRAY_TYPE) > + return sam_type; > + > + bool trailing = false; > + (void)array_ref_flexible_size_p (ref, &trailing); > + bool zero_length = integer_zerop (memsize); > + if (!trailing && !zero_length) > + /* MEMBER is an interior array with > + more than one element. */ > + return special_array_member::int_n; > + > + if (zero_length) > + { > + if (trailing) > + return special_array_member::trail_0; > + else > + return special_array_member::int_0; > + } > + > + if (!zero_length) > + if (tree dom = TYPE_DOMAIN (memtype)) > + if (tree min = TYPE_MIN_VALUE (dom)) > + if (tree max = TYPE_MAX_VALUE (dom)) > + if (TREE_CODE (min) == INTEGER_CST > + && TREE_CODE (max) == INTEGER_CST) > + { > + offset_int minidx = wi::to_offset (min); > + offset_int maxidx = wi::to_offset (max); > + offset_int neltsm1 = maxidx - minidx; > + if (neltsm1 > 0) > + /* MEMBER is a trailing array with more than > + one elements. */ > + return special_array_member::trail_n; > + > + if (neltsm1 == 0) > + return special_array_member::trail_1; > + } > + } > + > + return sam_type; > +} > + > /* Determines the size of the member referenced by the COMPONENT_REF > REF, using its initializer expression if necessary in order to > determine the size of an initialized flexible array member. > - If non-null, set *ARK when REF refers to an interior zero-length > + If non-null, set *SAM when REF refers to an interior zero-length > array or a trailing one-element array. > Returns the size as sizetype (which might be zero for an object > with an uninitialized flexible array member) or null if the size > - cannot be determined. */ > + cannot be determined. > + when FOR_ARRAY_BOUND_CHECK is true, this routine is called for > + -Warray-bounds check only, due to historical reason, the LEVEL > + of -Warray-bounds=LEVEL is not controled by -fstrict-flex-arrays. */ > > tree > -component_ref_size (tree ref, special_array_member *sam /* = NULL */) > +component_ref_size (tree ref, special_array_member *sam /* = NULL */, > + bool for_array_bound_check /* = FALSE */) > { > gcc_assert (TREE_CODE (ref) == COMPONENT_REF); > > special_array_member sambuf; > if (!sam) > sam = &sambuf; > - *sam = special_array_member::none; > + *sam = component_ref_sam_type (ref); > > /* The object/argument referenced by the COMPONENT_REF and its type. */ > tree arg = TREE_OPERAND (ref, 0); > @@ -12958,41 +13037,49 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */) > return (tree_int_cst_equal (memsize, TYPE_SIZE_UNIT (memtype)) > ? memsize : NULL_TREE); > > - bool trailing = array_ref_flexible_size_p (ref); > - bool zero_length = integer_zerop (memsize); > - if (!trailing && !zero_length) > - /* MEMBER is either an interior array or is an array with > - more than one element. */ > + /* 2-or-more elements arrays are treated as normal arrays by default. */ > + if (*sam == special_array_member::int_n > + || *sam == special_array_member::trail_n) > return memsize; > > - if (zero_length) > + /* For -Warray-bounds=LEVEL check, historically we have to treat > + trail_0 and trail_1 as flexible arrays by default when LEVEL=1. > + for other cases, flag_strict_flex_arrays will control how to treat > + the trailing arrays as flexiable array members. */ > + > + tree afield_decl = TREE_OPERAND (ref, 1); > + unsigned int strict_flex_array_level > + = strict_flex_array_level_of (afield_decl); > + > + if (!for_array_bound_check) > { > - if (trailing) > - *sam = special_array_member::trail_0; > - else > + switch (strict_flex_array_level) > { > - *sam = special_array_member::int_0; > - memsize = NULL_TREE; > + case 3: > + /* Treaing 0-length trailing arrays as normal array. */ > + if (*sam == special_array_member::trail_0) > + return size_zero_node; > + /* FALLTHROUGH. */ > + case 2: > + /* Treating 1-element trailing arrays as normal array. */ > + if (*sam == special_array_member::trail_1) > + return memsize; > + /* FALLTHROUGH. */ > + case 1: > + /* Treating 2-or-more elements trailing arrays as normal > + array. */ > + if (*sam == special_array_member::trail_n) > + return memsize; > + /* FALLTHROUGH. */ > + case 0: > + break; > + default: > + gcc_unreachable (); > } > } > > - if (!zero_length) > - if (tree dom = TYPE_DOMAIN (memtype)) > - if (tree min = TYPE_MIN_VALUE (dom)) > - if (tree max = TYPE_MAX_VALUE (dom)) > - if (TREE_CODE (min) == INTEGER_CST > - && TREE_CODE (max) == INTEGER_CST) > - { > - offset_int minidx = wi::to_offset (min); > - offset_int maxidx = wi::to_offset (max); > - offset_int neltsm1 = maxidx - minidx; > - if (neltsm1 > 0) > - /* MEMBER is an array with more than one element. */ > - return memsize; > - > - if (neltsm1 == 0) > - *sam = special_array_member::trail_1; > - } > + if (*sam == special_array_member::int_0) > + memsize = NULL_TREE; > > /* For a reference to a zero- or one-element array member of a union > use the size of the union instead of the size of the member. */ > diff --git a/gcc/tree.h b/gcc/tree.h > index 0fcdd6b06d0..f81a1f6efa1 100644 > --- a/gcc/tree.h > +++ b/gcc/tree.h > @@ -5551,28 +5551,33 @@ extern tree array_ref_low_bound (tree); > /* Returns true if REF is an array reference, a component reference, > or a memory reference to an array whose actual size might be larger > than its upper bound implies. */ > -extern bool array_ref_flexible_size_p (tree); > +extern bool array_ref_flexible_size_p (tree, bool * = NULL); > > /* Return a tree representing the offset, in bytes, of the field referenced > by EXP. This does not include any offset in DECL_FIELD_BIT_OFFSET. */ > extern tree component_ref_field_offset (tree); > > -/* Describes a "special" array member due to which component_ref_size > - returns null. */ > +/* Describes a "special" array member for a COMPONENT_REF. */ > enum struct special_array_member > { > none, /* Not a special array member. */ > int_0, /* Interior array member with size zero. */ > trail_0, /* Trailing array member with size zero. */ > - trail_1 /* Trailing array member with one element. */ > + trail_1, /* Trailing array member with one element. */ > + trail_n, /* Trailing array member with two or more elements. */ > + int_n /* Interior array member with one or more elements. */ > }; > > +/* Determines the special array member type for a COMPONENT_REF. */ > +extern special_array_member component_ref_sam_type (tree); > + > /* Return the size of the member referenced by the COMPONENT_REF, using > its initializer expression if necessary in order to determine the size > of an initialized flexible array member. The size might be zero for > an object with an uninitialized flexible array member or null if it > cannot be determined. */ > -extern tree component_ref_size (tree, special_array_member * = NULL); > +extern tree component_ref_size (tree, special_array_member * = NULL, > + bool = false); > > extern int tree_map_base_eq (const void *, const void *); > extern unsigned int tree_map_base_hash (const void *); > -- Richard Biener SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman; HRB 36809 (AG Nuernberg)