On Tue, 6 Dec 2022, Qing Zhao wrote:

>      A. add the following to clarify the relationship between -Warray-bounds
>         and the LEVEL of -fstrict-flex-array:
> 
>      By default, the trailing array of a structure will be treated as a
>      flexible array member by '-Warray-bounds' or '-Warray-bounds=N' if
>      it is declared as either a flexible array member per C99 standard
>      onwards ('[]'), a GCC zero-length array extension ('[0]'), or an
>      one-element array ('[1]').  As a result, out of bounds subscripts
>      or offsets into zero-length arrays or one-element arrays are not
>      warned by default.
> 
>      You can add the option '-fstrict-flex-arrays' or
>      '-fstrict-flex-arrays=LEVEL' to control how this option treat
>      trailing array of a structure as a flexible array member.
> 
>      when LEVEL<=1, no change to the default behavior.
> 
>      when LEVEL=2, additional warnings will be issued for out of bounds
>      subscripts or offsets into one-element arrays;
> 
>      when LEVEL=3, in addition to LEVEL=2, additional warnings will be
>      issued for out of bounds subscripts or offsets into zero-length
>      arrays.
> 
>      B. change -Warray-bounds=2 to exclude its control on how to treat
>         trailing arrays as flexible array members:
> 
>      '-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.

OK.

Thanks,
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: Update -Warray-bounds by specifying the impact from
>       -fstrict-flex-arrays. Also update -Warray-bounds=2 by eliminating its
>       impact on treating trailing arrays as flexible array members.
>       * gimple-array-bounds.cc (get_up_bounds_for_array_ref): New function.
>       (check_out_of_bounds_and_warn): New function.
>       (array_bounds_checker::check_array_ref): Update with calls to the above
>       new functions.
>       * tree.cc (array_ref_flexible_size_p): Add one new argument.
>       (component_ref_sam_type): New function.
>       (component_ref_size): Control with level of strict-flex-array.
>       * 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.
> 
> gcc/c/ChangeLog:
> 
>       * c-decl.cc (is_flexible_array_member_p): Call new function
>       strict_flex_array_level_of.
> 
> gcc/testsuite/ChangeLog:
> 
>       * gcc.dg/Warray-bounds-11.c: Update warnings for -Warray-bounds=2.
>       * gcc.dg/Warray-bounds-flex-arrays-1.c: New test.
>       * gcc.dg/Warray-bounds-flex-arrays-2.c: New test.
>       * gcc.dg/Warray-bounds-flex-arrays-3.c: New test.
>       * gcc.dg/Warray-bounds-flex-arrays-4.c: New test.
>       * gcc.dg/Warray-bounds-flex-arrays-5.c: New test.
>       * gcc.dg/Warray-bounds-flex-arrays-6.c: New test.
> ---
>  gcc/attribs.cc                                |  30 ++++
>  gcc/attribs.h                                 |   2 +
>  gcc/c/c-decl.cc                               |  21 +--
>  gcc/doc/invoke.texi                           |  27 ++-
>  gcc/gimple-array-bounds.cc                    | 150 +++++++++++------
>  gcc/testsuite/gcc.dg/Warray-bounds-11.c       |   2 +-
>  .../gcc.dg/Warray-bounds-flex-arrays-1.c      |  39 +++++
>  .../gcc.dg/Warray-bounds-flex-arrays-2.c      |  39 +++++
>  .../gcc.dg/Warray-bounds-flex-arrays-3.c      |  39 +++++
>  .../gcc.dg/Warray-bounds-flex-arrays-4.c      |  39 +++++
>  .../gcc.dg/Warray-bounds-flex-arrays-5.c      |  39 +++++
>  .../gcc.dg/Warray-bounds-flex-arrays-6.c      |  39 +++++
>  gcc/tree.cc                                   | 159 +++++++++++++-----
>  gcc/tree.h                                    |  12 +-
>  14 files changed, 512 insertions(+), 125 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-1.c
>  create mode 100644 gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-2.c
>  create mode 100644 gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-3.c
>  create mode 100644 gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-4.c
>  create mode 100644 gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-5.c
>  create mode 100644 gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-6.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/c-decl.cc b/gcc/c/c-decl.cc
> index 4adb89e4aaf..111f05e2a40 100644
> --- a/gcc/c/c-decl.cc
> +++ b/gcc/c/c-decl.cc
> @@ -9067,26 +9067,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 277ac35ad16..726392409b6 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -8040,17 +8040,34 @@ is enabled by @option{-Wall}.  It is more effective 
> when @option{-ftree-vrp}
>  is active (the default for @option{-O2} and above) but a subset of instances
>  are issued even without optimization.
>  
> +By default, the trailing array of a structure will be treated as a flexible
> +array member by @option{-Warray-bounds} or @option{-Warray-bounds=@var{n}}
> +if it is declared as either a flexible array member per C99 standard onwards
> +(@samp{[]}), a GCC zero-length array extension (@samp{[0]}), or an 
> one-element
> +array (@samp{[1]}). As a result, out of bounds subscripts or offsets into
> +zero-length arrays or one-element arrays are not warned by default.
> +
> +You can add the option @option{-fstrict-flex-arrays} or
> +@option{-fstrict-flex-arrays=@var{level}} to control how this
> +option treat trailing array of a structure as a flexible array member:
> +
> +when @var{level}<=1, no change to the default behavior.
> +
> +when @var{level}=2, additional warnings will be issued for out of bounds
> +subscripts or offsets into one-element arrays;
> +
> +when @var{level}=3, in addition to @var{level}=2, additional warnings will be
> +issued for out of bounds subscripts or offsets into zero-length arrays.
> +
>  @table @gcctabopt
>  @item -Warray-bounds=1
>  This is the default warning level of @option{-Warray-bounds} and is enabled
>  by @option{-Wall}; higher levels are not, and must be explicitly requested.
>  
>  @item -Warray-bounds=2
> -This warning level also warns about out of bounds accesses to trailing
> -struct members of one-element array types (@pxref{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.
> +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.
>  @end table
>  
>  @item -Warray-compare
> diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc
> index 972e25fdb31..db3459af325 100644
> --- a/gcc/gimple-array-bounds.cc
> +++ b/gcc/gimple-array-bounds.cc
> @@ -160,38 +160,17 @@ 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.  */
> +/* 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.  */
>  
> -bool
> -array_bounds_checker::check_array_ref (location_t location, tree ref,
> -                                    gimple *stmt, bool ignore_off_by_one)
> +static void
> +get_up_bounds_for_array_ref (tree ref, tree *decl,
> +                          tree *up_bound, tree *up_bound_p1)
>  {
> -  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
> +      || trailing_array (ref, decl))
>      {
>        /* Accesses to trailing arrays via pointers may access storage
>        beyond the types array bounds.  For such arrays, or for flexible
> @@ -203,8 +182,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
>       {
> @@ -217,7 +196,7 @@ 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))
>               if (TREE_CODE (refsize) == INTEGER_CST)
>                 maxbound = refsize;
>           }
> @@ -236,7 +215,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))
> @@ -244,7 +223,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))
> @@ -256,21 +235,33 @@ 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.
> +   Issue warnings if out of bound, return TRUE if warnings are issued.  */ 
>  
> +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)
> +{
> +  tree low_bound = array_ref_low_bound (ref);
>    tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
>  
>    bool warned = false;
> @@ -279,18 +270,7 @@ array_bounds_checker::check_array_ref (location_t 
> location, tree ref,
>    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 ();
> -     }
> -    }
> +                      low_sub_org, artype);
>  
>    if (warned)
>      ; /* Do nothing.  */
> @@ -321,6 +301,68 @@ array_bounds_checker::check_array_ref (location_t 
> location, tree ref,
>      warned = warning_at (location, OPT_Warray_bounds_,
>                        "array subscript %E is below array bounds of %qT",
>                        low_sub, artype);
> +  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;
> +
> +  /* 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;
> +
> +  if (compref)
> +    /* Try to determine special array member type for this COMPONENT_REF.  */
> +    sam = component_ref_sam_type (arg);
> +
> +  get_up_bounds_for_array_ref (ref, &decl, &up_bound, &up_bound_p1);
> +
> +  bool warned = 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 ();
> +     }
> +    }
> +
> +  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);
> +
>  
>    if (!warned && sam == special_array_member::int_0)
>      warned = warning_at (location, OPT_Wzero_length_bounds,
> diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-11.c 
> b/gcc/testsuite/gcc.dg/Warray-bounds-11.c
> index c9fc461942f..3ba2bb67fa0 100644
> --- a/gcc/testsuite/gcc.dg/Warray-bounds-11.c
> +++ b/gcc/testsuite/gcc.dg/Warray-bounds-11.c
> @@ -78,7 +78,7 @@ void foo(int (*a)[3])
>  
>       h->j[4] = 1;    // flexible array member
>       h0->j[4] = 1;   // zero-sized array extension
> -     h1->j[4] = 1;   /* { dg-warning "subscript 4 is above array bound" } */
> +     h1->j[4] = 1;   /* { dg-bogus "subscript 4 is above array bound" } */
>       h3->j[4] = 1;   /* { dg-warning "subscript 4 is above array bound" } */
>  
>       struct h0b* h0b = malloc(sizeof(struct h) + 3 * sizeof(int));
> diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-1.c 
> b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-1.c
> new file mode 100644
> index 00000000000..d36ba4d86cb
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-1.c
> @@ -0,0 +1,39 @@
> +/* Test -fstrict-flex-arrays + -Warray-bounds.  */
> +/* { dg-do compile} */
> +/* { dg-options "-O2 -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 "array subscript 5 is above 
> array bounds of" } */
> +    trailing_1->c[2] = 2; /* { dg-bogus "array subscript " } */
> +    trailing_0->c[1] = 1; /* { dg-bogus "array subscript " } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "array subscript " } */
> +
> +}
> diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-2.c 
> b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-2.c
> new file mode 100644
> index 00000000000..f63206e1948
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-2.c
> @@ -0,0 +1,39 @@
> +/* Test -fstrict-flex-arrays + -Warray-bounds.  */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -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 "array subscript 5 is above 
> array bounds of" } */
> +    trailing_1->c[2] = 2; /* { dg-warning "array subscript 2 is above array 
> bounds of"  } */
> +    trailing_0->c[1] = 1; /* { dg-bogus "array subscript " } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "array subscript " } */
> +
> +}
> diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-3.c 
> b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-3.c
> new file mode 100644
> index 00000000000..e3273714e8b
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-3.c
> @@ -0,0 +1,39 @@
> +/* Test -fstrict-flex-arrays + -Warray-bounds.  */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -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 "array subscript 5 is above 
> array bounds of" } */ 
> +    trailing_1->c[2] = 2; /*{ dg-warning "array subscript 2 is above array 
> bounds of" } */ 
> +    trailing_0->c[1] = 1; /*{ dg-warning "array subscript 1 is outside array 
> bounds of" } */ 
> +    trailing_flex->c[10] = 10; /* { dg-bogus "array subscript" } */
> +
> +}
> diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-4.c 
> b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-4.c
> new file mode 100644
> index 00000000000..cabaea77dc2
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-4.c
> @@ -0,0 +1,39 @@
> +/* Test -fstrict-flex-arrays + -Warray-bounds=2.  */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -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 "array subscript 5 is above 
> array bounds of" } */
> +    trailing_1->c[2] = 2; /* { dg-bogus "array subscript " } */
> +    trailing_0->c[1] = 1; /* { dg-bogus "array subscript " } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "array subscript " } */
> +
> +}
> diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-5.c 
> b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-5.c
> new file mode 100644
> index 00000000000..8b7db6e4f39
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-5.c
> @@ -0,0 +1,39 @@
> +/* Test -fstrict-flex-arrays + -Warray-bounds=2.  */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -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 "array subscript 5 is above array 
> bounds of" } */
> +    trailing_1->c[2] = 2; /*{ dg-warning "array subscript 2 is above array 
> bounds of" } */
> +    trailing_0->c[1] = 1; /* { dg-bogus "array subscript " } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "array subscript " } */
> +
> +}
> diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-6.c 
> b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-6.c
> new file mode 100644
> index 00000000000..035bf481396
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-6.c
> @@ -0,0 +1,39 @@
> +/* Test -fstrict-flex-arrays + -Warray-bounds=2.  */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -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 "array subscript 5 is above 
> array bounds of" } */ 
> +    trailing_1->c[2] = 2; /*{ dg-warning "array subscript 2 is above array 
> bounds of" } */
> +    trailing_0->c[1] = 1; /*{ dg-warning "array subscript 1 is outside array 
> bounds of" } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "array subscript " } */
> +
> +}
> diff --git a/gcc/tree.cc b/gcc/tree.cc
> index 254b2373dcf..b40c95ae8c4 100644
> --- a/gcc/tree.cc
> +++ b/gcc/tree.cc
> @@ -12719,15 +12719,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)
> @@ -12815,7 +12821,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).  
> */
> @@ -12837,9 +12846,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)))
> @@ -12847,11 +12864,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;
>  }
>  
> @@ -12913,11 +12935,63 @@ 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
> -   array or a trailing one-element array.
> +   If non-null, set *SAM to the type of special array member.
>     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.  */
> @@ -12930,7 +13004,7 @@ component_ref_size (tree ref, special_array_member 
> *sam /* = NULL */)
>    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);
> @@ -12951,43 +13025,46 @@ 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)
> +      /* 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);
> +
> +      switch (strict_flex_array_level)
>       {
> -       if (trailing)
> -         *sam = special_array_member::trail_0;
> -       else
> -         {
> -           *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
> +      /* For a reference to a flexible array member of a union
>        use the size of the union instead of the size of the member.  */
>        if (TREE_CODE (argtype) == UNION_TYPE)
>       memsize = TYPE_SIZE_UNIT (argtype);
> diff --git a/gcc/tree.h b/gcc/tree.h
> index 4a19de1c94d..23223ca0c87 100644
> --- a/gcc/tree.h
> +++ b/gcc/tree.h
> @@ -5553,22 +5553,26 @@ 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
> 

-- 
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)

Reply via email to