Hi, Richard, Honestly, it’s very hard for me to decide what’s the best way to handle the interaction between -fstrict-flex-array=M and -Warray-bounds=N.
Ideally, -fstrict-flex-array=M should completely control the behavior of -Warray-bounds. If possible, I prefer this solution. However, -Warray-bounds is included in -Wall, and has been used extensively for a long time. It’s not safe to change its default behavior. So, I guess that the bottom-line for this work is: Keeping the default behavior of -Warray-bounds. Is this correct understanding? > On Nov 18, 2022, at 8:14 AM, Richard Biener <rguent...@suse.de> wrote: > > 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? The basic idea here is: -Warray-bounds=N will NOT be controlled by -fstrict-flex-array=M at all. And the new -Wstrict-flex-array will be used to report warnings for different level of “M”. > > Would it be better/possible to add a note: to existing -Warray-bounds > diagnostics on how the behavior is altered by -fstrict-flex-arrays? If -Warray-bounds does not have the additional level “N” argument. It’s reasonable and natural for it to be controlled by the level of -fstrict-flex-arrays. > > I guess this will inevitably re-iterate the -fstrict-flex-arrays=N > vs. -Warray-bounds=M discussion ... Yes, that’s the most confusion and challenge part for this work… and took me a lot of thinking but still cannot find the best way to handle it….. > > 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). From my understanding, you suggested the following: 1. Keep -Warray-bounds default behavior. i.e. when -Warray-bounds=1, it’s behavior will not be impacted by -fstrict-flex-array=M 2. When -Warray-bounds=2, it’s behavior will be controlled by -fstrict-flex-array=M Is the above understanding correct? If yes, then the major question is: When -Warray-bounds=2, -fstrict-flex-array = 0 or 1,2, i.e, when the level of -fstrict-flex-array is lower or equal to 2. [0] and [1] will be treated as flexible array member by -fstrict-flex-array, it’s conflict with how -Warray-bounds=2’s behavior on treating flexible array members. Under such situation, which one has higher priority? I have another idea now: 1. Keep -Warray-bounds=1 default behavior. 2. Change the behavior of -Warray-bounds=2 from: Current: -Warray-bounds=2 This warning level also warns about out of bounds accesses to trailing struct members of one-element array types (see Zero Length) and about the intermediate results of pointer arithmetic that may yield out of bounds values. This warning level may give a larger number of false positives and is deactivated by default. New: -Warray-bounds=2 This warning level also warns about the intermediate results of pointer arithmetic that may yield out of bounds values. This warning level may give a larger number of false positives and is deactivated by default. i.e, delete the control on flexible array member from the level of -Warray-bounds. 3. Use -fstrict-flex-array to control how the -Warray-bounds treat the tailing array as flexible array member? Is this better? thanks. Qing > > 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 <rguent...@suse.de> > SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, > Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman; > HRB 36809 (AG Nuernberg)