>From 3854004802b8e2f132ebf218fc35a632f5e80c6a Mon Sep 17 00:00:00 2001
From: Qing Zhao <qing.z...@oracle.com>
Date: Mon, 18 Jul 2022 17:04:12 +0000
Subject: [PATCH 1/2] Add a new option -fstrict-flex-array[=n] and new
attribute strict_flex_array

Add the following new option -fstrict-flex-array[=n] and a corresponding
attribute strict_flex_array to GCC:

'-fstrict-flex-array'
    Treat the trailing array of a structure as a flexible array member
    in a stricter way.  The positive form is equivalent to
    '-fstrict-flex-array=3', which is the strictest.  A trailing array
    is treated as a flexible array member only when it is declared as a
    flexible array member per C99 standard onwards.  The negative form
    is equivalent to '-fstrict-flex-array=0', which is the least
    strict.  All trailing arrays of structures are treated as flexible
    array members.

'-fstrict-flex-array=LEVEL'
    Treat the trailing array of a structure as a flexible array member
    in a stricter way.  The value of LEVEL controls the level of
    strictness.

    The possible values of LEVEL are the same as for the
    'strict_flex_array' attribute (*note Variable Attributes::).

    You can control this behavior for a specific trailing array field
    of a structure by using the variable attribute 'strict_flex_array'
    attribute (*note Variable Attributes::).

'strict_flex_array (LEVEL)'
    The 'strict_flex_array' attribute should be attached to the
    trailing array field of a structure.  It specifies the level of
    strictness of treating the trailing array field of a structure as a
    flexible array member.  LEVEL must be an integer betwen 0 to 3.

    LEVEL=0 is the least strict level, all trailing arrays of
    structures are treated as flexible array members.  LEVEL=3 is the
    strictest level, only when the trailing array is declared as a
    flexible array member per C99 standard onwards ([]), it is treated
    as a flexible array member.

    There are two more levels in between 0 and 3, which are provided to
    support older codes that use GCC zero-length array extension ([0])
    or one-size array as flexible array member ([1]): When LEVEL is 1,
    the trailing array is treated as a flexible array member when it is
    declared as either [], [0], or [1]; When LEVEL is 2, the trailing
    array is treated as a flexible array member when it is declared as
    either [], or [0].

    This attribute can be used with or without '-fstrict-flex-array'.
    When both the attribute and the option present at the same time,
    the level of the strictness for the specific trailing array field
    is determined by the attribute.

gcc/c-family/ChangeLog:

        * c-attribs.cc (handle_strict_flex_array_attribute): New function.
        (c_common_attribute_table): New item for strict_flex_array.
        * c.opt (fstrict-flex-array): New option.
        (fstrict-flex-array=): New option.

gcc/c/ChangeLog:

        * c-decl.cc (add_flexible_array_elts_to_size): Call new utility
        routine flexible_array_member_p.
        (is_flexible_array_member_p): New function.
        (finish_struct): Set the new DECL_NOT_FLEXARRAY flag.

gcc/ChangeLog:

        * doc/extend.texi: Document strict_flex_array attribute.
        * doc/invoke.texi: Document -fstrict-flex-array[=n] option.
        * tree-core.h (struct tree_decl_common): New bit field
        decl_not_flexarray.
        * tree.cc (component_ref_size): Reorg by using new utility functions.
        (flexible_array_member_p): New function.
        (zero_length_array_p): Likewise.
        (one_element_array_p): Likewise.
        (flexible_array_type_p): Likewise.
        * tree.h (DECL_NOT_FLEXARRAY): New flag.
        (zero_length_array_p): New function prototype.
        (one_element_array_p): Likewise.
        (flexible_array_member_p): Likewise.

gcc/testsuite/ChangeLog:

        * gcc.dg/strict-flex-array-1.c: New test.
---
gcc/c-family/c-attribs.cc                  |  47 ++++++++
gcc/c-family/c.opt                         |   7 ++
gcc/c/c-decl.cc                            |  91 +++++++++++++--
gcc/doc/extend.texi                        |  25 ++++
gcc/doc/invoke.texi                        |  27 ++++-
gcc/testsuite/gcc.dg/strict-flex-array-1.c |  31 +++++
gcc/tree-core.h                            |   5 +-
gcc/tree.cc                                | 130 ++++++++++++++-------
gcc/tree.h                                 |  16 ++-
9 files changed, 322 insertions(+), 57 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/strict-flex-array-1.c

diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index c8d96723f4c..10d16532f0d 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -101,6 +101,8 @@ static tree handle_special_var_sec_attribute (tree *, tree, 
tree, int, bool *);
static tree handle_aligned_attribute (tree *, tree, tree, int, bool *);
static tree handle_warn_if_not_aligned_attribute (tree *, tree, tree,
                                                  int, bool *);
+static tree handle_strict_flex_array_attribute (tree *, tree, tree,
+                                               int, bool *);
static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ;
static tree handle_noplt_attribute (tree *, tree, tree, int, bool *) ;
static tree handle_alias_ifunc_attribute (bool, tree *, tree, tree, bool *);
@@ -367,6 +369,8 @@ const struct attribute_spec c_common_attribute_table[] =
                              attr_aligned_exclusions },
  { "warn_if_not_aligned",    0, 1, false, false, false, false,
                              handle_warn_if_not_aligned_attribute, NULL },
+  { "strict_flex_array",      1, 1, false, false, false, false,
+                             handle_strict_flex_array_attribute, NULL },
  { "weak",                   0, 0, true,  false, false, false,
                              handle_weak_attribute, NULL },
  { "noplt",                   0, 0, true,  false, false, false,
@@ -2498,6 +2502,49 @@ handle_warn_if_not_aligned_attribute (tree *node, tree 
name,
                                          no_add_attrs, true);
}

+/* Handle a "strict_flex_array" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_strict_flex_array_attribute (tree *node, tree name,
+                                   tree args, int ARG_UNUSED (flags),
+                                   bool *no_add_attrs)
+{
+  tree decl = *node;
+  tree argval = TREE_VALUE (args);
+
+  /* This attribute only applies to field decls of a structure.  */
+  if (TREE_CODE (decl) != FIELD_DECL)
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+               "%qE attribute may not be specified for %q+D", name, decl);
+      *no_add_attrs = true;
+    }
+  /* This attribute only applies to field with array type.  */
+  else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE)
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+               "%qE attribute may not be specified for a non array field",
+               name);
+      *no_add_attrs = true;
+    }
+  else if (TREE_CODE (argval) != INTEGER_CST)
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+               "%qE attribute argument not an integer", name);
+      *no_add_attrs = true;
+    }
+  else if (!tree_fits_uhwi_p (argval) || tree_to_uhwi (argval) > 3)
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+               "%qE attribute argument %qE is not an integer constant"
+               " between 0 and 3", name, argval);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
/* Handle a "weak" attribute; arguments as in
   struct attribute_spec.handler.  */

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 44e1a60ce24..864cd8df1d3 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -2060,6 +2060,13 @@ fsized-deallocation
C++ ObjC++ Var(flag_sized_deallocation) Init(-1)
Enable C++14 sized deallocation support.

+fstrict-flex-array
+C C++ Common Alias(fstrict-flex-array=,3,0)
+
+fstrict-flex-array=
+C C++ Common Joined RejectNegative UInteger Var(flag_strict_flex_array) 
Init(0) IntegerRange(0,3)
+-fstrict-flex-array=<level>    Treat the trailing array of a structure as a 
flexible array in a stricter way.  The default is treating all trailing arrays 
of structures as flexible arrays.
+
fsquangle
C++ ObjC++ WarnRemoved

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index ae8990c138f..14defae9584 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5013,10 +5013,7 @@ add_flexible_array_elts_to_size (tree decl, tree init)

  elt = CONSTRUCTOR_ELTS (init)->last ().value;
  type = TREE_TYPE (elt);
-  if (TREE_CODE (type) == ARRAY_TYPE
-      && TYPE_SIZE (type) == NULL_TREE
-      && TYPE_DOMAIN (type) != NULL_TREE
-      && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)
+  if (flexible_array_member_p (type))
    {
      complete_array_type (&type, elt, false);
      DECL_SIZE (decl)
@@ -8720,6 +8717,80 @@ 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;
+  B. whether the FIELD_DECL is an array that is declared as "[]", "[0]",
+     or "[1]";
+  C. flag_strict_flex_array;
+  D. the attribute strict_flex_array that is attached to the field
+     if presenting.
+  Return TRUE when it's a flexible array member, FALSE otherwise.  */
+
+static bool
+is_flexible_array_member_p (bool is_last_field,
+                           tree x)
+{
+  /* if not the last field, return false.  */
+  if (!is_last_field)
+    return false;
+
+  /* if not an array field, return false.  */
+  if (TREE_CODE (TREE_TYPE (x)) != ARRAY_TYPE)
+    return false;
+
+  bool is_zero_length_array = zero_length_array_p (TREE_TYPE (x));
+  bool is_one_element_array = one_element_array_p (TREE_TYPE (x));
+  bool is_flexible_array = flexible_array_member_p (TREE_TYPE (x));
+
+  unsigned int strict_flex_array_level = flag_strict_flex_array;
+
+  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_array.  */
+  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;
+    }
+
+  switch (strict_flex_array_level)
+    {
+      case 0:
+       /* default, all trailing arrays are flexiable array members.  */
+       return true;
+      case 1:
+       /* Level 1: all "[1]", "[0]", and "[]" are flexiable array members.  */
+       if (is_one_element_array)
+         return true;
+       /* FALLTHROUGH.  */
+      case 2:
+       /* Level 2: all "[0]", and "[]" are flexiable array members.  */
+       if (is_zero_length_array)
+         return true;
+       /* FALLTHROUGH.  */
+      case 3:
+       /* Level 3: Only "[]" are flexible array members.  */
+       if (is_flexible_array)
+         return true;
+       break;
+      default:
+       gcc_unreachable ();
+    }
+  return false;
+}
+
+
/* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T.
   LOC is the location of the RECORD_TYPE or UNION_TYPE's definition.
   FIELDLIST is a chain of FIELD_DECL nodes for the fields.
@@ -8781,6 +8852,8 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
  bool saw_named_field = false;
  for (x = fieldlist; x; x = DECL_CHAIN (x))
    {
+      bool is_last_field = (DECL_CHAIN (x) == NULL_TREE);
+
      if (TREE_TYPE (x) == error_mark_node)
        continue;

@@ -8819,10 +8892,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
        DECL_PACKED (x) = 1;

      /* Detect flexible array member in an invalid context.  */
-      if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
-         && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
-         && TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE
-         && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (x))) == NULL_TREE)
+      if (flexible_array_member_p (TREE_TYPE (x)))
        {
          if (TREE_CODE (t) == UNION_TYPE)
            {
@@ -8830,7 +8900,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
                        "flexible array member in union");
              TREE_TYPE (x) = error_mark_node;
            }
-         else if (DECL_CHAIN (x) != NULL_TREE)
+         else if (!is_last_field)
            {
              error_at (DECL_SOURCE_LOCATION (x),
                        "flexible array member not at end of struct");
@@ -8850,6 +8920,9 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
        pedwarn (DECL_SOURCE_LOCATION (x), OPT_Wpedantic,
                 "invalid use of structure with flexible array member");

+      /* Set DECL_NOT_FLEXARRAY flag for FIELD_DECL x.  */
+      DECL_NOT_FLEXARRAY (x) = !is_flexible_array_member_p (is_last_field, x);
+
      if (DECL_NAME (x)
          || RECORD_OR_UNION_TYPE_P (TREE_TYPE (x)))
        saw_named_field = true;
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index dfbe33ac652..7451410a011 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -7436,6 +7436,31 @@ This warning can be disabled by 
@option{-Wno-if-not-aligned}.
The @code{warn_if_not_aligned} attribute can also be used for types
(@pxref{Common Type Attributes}.)

+@cindex @code{strict_flex_array} variable attribute
+@item strict_flex_array (@var{level})
+The @code{strict_flex_array} attribute should be attached to the trailing
+array field of a structure.  It specifies the level of strictness of
+treating the trailing array field of a structure as a flexible array
+member. @var{level} must be an integer betwen 0 to 3.
+
+@var{level}=0 is the least strict level, all trailing arrays of structures
+are treated as flexible array members. @var{level}=3 is the strictest level,
+only when the trailing array is declared as a flexible array member per C99
+standard onwards ([]), it is treated as a flexible array member.
+
+There are two more levels in between 0 and 3, which are provided to support
+older codes that use GCC zero-length array extension ([0]) or one-size array
+as flexible array member ([1]):
+When @var{level} is 1, the trailing array is treated as a flexible array member
+when it is declared as either "[]", "[0]", or "[1]";
+When @var{level} is 2, the trailing array is treated as a flexible array member
+when it is declared as either "[]", or "[0]".
+
+This attribute can be used with or without @option{-fstrict-flex-array}. When
+both the attribute and the option present at the same time, the level of the
+strictness for the specific trailing array field is determined by the 
attribute.
+
+
@item alloc_size (@var{position})
@itemx alloc_size (@var{position-1}, @var{position-2})
@cindex @code{alloc_size} variable attribute
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 94fe57aa4e2..9befe601817 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -207,7 +207,8 @@ in the following sections.
-fopenmp  -fopenmp-simd @gol
-fpermitted-flt-eval-methods=@var{standard} @gol
-fplan9-extensions  -fsigned-bitfields  -funsigned-bitfields @gol
--fsigned-char  -funsigned-char  -fsso-struct=@var{endianness}}
+-fsigned-char  -funsigned-char -fstrict-flex-array[=@var{n}] @gol
+-fsso-struct=@var{endianness}}

@item C++ Language Options
@xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
@@ -2825,6 +2826,30 @@ The type @code{char} is always a distinct type from each 
of
@code{signed char} or @code{unsigned char}, even though its behavior
is always just like one of those two.

+@item -fstrict-flex-array
+@opindex fstrict-flex-array
+@opindex fno-strict-flex-array
+Treat the trailing array of a structure as a flexible array member in a
+stricter way.
+The positive form is equivalent to @option{-fstrict-flex-array=3}, which is the
+strictest.  A trailing array is treated as a flexible array member only when it
+is declared as a flexible array member per C99 standard onwards.
+The negative form is equivalent to @option{-fstrict-flex-array=0}, which is the
+least strict.  All trailing arrays of structures are treated as flexible array
+members.
+
+@item -fstrict-flex-array=@var{level}
+@opindex fstrict-flex-array=@var{level}
+Treat the trailing array of a structure as a flexible array member in a
+stricter way.  The value of @var{level} controls the level of strictness.
+
+The possible values of @var{level} are the same as for the
+@code{strict_flex_array} attribute (@pxref{Variable Attributes}).
+
+You can control this behavior for a specific trailing array field of a
+structure by using the variable attribute @code{strict_flex_array} attribute
+(@pxref{Variable Attributes}).
+
@item -fsso-struct=@var{endianness}
@opindex fsso-struct
Set the default scalar storage order of structures and unions to the
diff --git a/gcc/testsuite/gcc.dg/strict-flex-array-1.c 
b/gcc/testsuite/gcc.dg/strict-flex-array-1.c
new file mode 100644
index 00000000000..ec886c99b25
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strict-flex-array-1.c
@@ -0,0 +1,31 @@
+/* testing the correct usage of attribute strict_flex_array.  */   
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+
+int x __attribute__ ((strict_flex_array (1))); /* { dg-error 
"'strict_flex_array' attribute may not be specified for 'x'" } */
+
+struct trailing {
+    int a;
+    int c __attribute ((strict_flex_array)); /* { dg-error "wrong number of 
arguments specified for 'strict_flex_array' attribute" } */
+};
+
+struct trailing_1 {
+    int a;
+    int b;
+    int c __attribute ((strict_flex_array (2))); /* { dg-error 
"'strict_flex_array' attribute may not be specified for a non array field" } */
+};
+
+extern int d;
+
+struct trailing_array_2 {
+    int a;
+    int b;
+    int c[1] __attribute ((strict_flex_array (d))); /* { dg-error 
"'strict_flex_array' attribute argument not an integer" } */
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_array (5))); /* { dg-error 
"'strict_flex_array' attribute argument '5' is not an integer constant between 
0 and 3" } */
+};
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index ea9f281f1cc..458c6e6ceea 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1813,7 +1813,10 @@ struct GTY(()) tree_decl_common {
     TYPE_WARN_IF_NOT_ALIGN.  */
  unsigned int warn_if_not_align : 6;

-  /* 14 bits unused.  */
+  /* In FIELD_DECL, this is DECL_NOT_FLEXARRAY.  */
+  unsigned int decl_not_flexarray : 1;
+
+  /* 13 bits unused.  */

  /* UID for points-to sets, stable over copying from inlining.  */
  unsigned int pt_uid;
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 84000dd8b69..02e274699fb 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -12862,7 +12862,7 @@ get_initializer_for (tree init, tree decl)
/* 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
@@ -12878,16 +12878,32 @@ component_ref_size (tree ref, special_array_member 
*sam /* = NULL */)
    sam = &sambuf;
  *sam = special_array_member::none;

+  /* Whether this ref is an array at the end of a structure.  */
+  bool trailing = array_at_struct_end_p (ref);
+
  /* The object/argument referenced by the COMPONENT_REF and its type.  */
  tree arg = TREE_OPERAND (ref, 0);
  tree argtype = TREE_TYPE (arg);
-  /* The referenced member.  */
-  tree member = TREE_OPERAND (ref, 1);

+  /* The referenced field member.  */
+  tree member = TREE_OPERAND (ref, 1);
+  tree memtype = TREE_TYPE (member);
  tree memsize = DECL_SIZE_UNIT (member);
+
+  bool is_zero_length_array_ref = zero_length_array_p (memtype);
+  bool is_constant_length_array_ref = false;
+  bool is_one_element_array_ref
+       = one_element_array_p (memtype, &is_constant_length_array_ref);
+
+  /* Determine the type of the special array member.  */
+  if (is_zero_length_array_ref)
+    *sam = trailing ? special_array_member::trail_0
+          : special_array_member::int_0;
+  else if (is_one_element_array_ref && trailing)
+    *sam = special_array_member::trail_1;
+
  if (memsize)
    {
-      tree memtype = TREE_TYPE (member);
      if (TREE_CODE (memtype) != ARRAY_TYPE)
        /* DECL_SIZE may be less than TYPE_SIZE in C++ when referring
           to the type of a class with a virtual base which doesn't
@@ -12897,50 +12913,30 @@ 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_at_struct_end_p (ref);
-      bool zero_length = integer_zerop (memsize);
-      if (!trailing && !zero_length)
+      if (!trailing && !is_zero_length_array_ref)
        /* MEMBER is either an interior array or is an array with
           more than one element.  */
        return memsize;

-      if (zero_length)
-       {
-         if (trailing)
-           *sam = special_array_member::trail_0;
-         else
-           {
-             *sam = special_array_member::int_0;
-             memsize = NULL_TREE;
-           }
-       }
+      if (*sam != special_array_member::trail_1
+         && is_constant_length_array_ref)
+       /* MEMBER is a constant length array which is not a one-element
+          trailing array.  */
+       return memsize;

-      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.  */
+      /* For a reference to a flexible array member, an interior zero length
+        array, or an array with variable length 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);
    }

-  /* MEMBER is either a bona fide flexible array member, or a zero-length
-     array member, or an array of length one treated as such.  */
+  /* MEMBER now is a flexible array member, an interior zero length array, or
+     an array with variable length.  We need to decide its size from its
+     initializer.  */

  /* If the reference is to a declared object and the member a true
     flexible array, try to determine its size from its initializer.  */
@@ -14351,6 +14347,59 @@ default_is_empty_record (const_tree type)
  return is_empty_type (TYPE_MAIN_VARIANT (type));
}

+/* Determine whether TYPE is a ISO flexible array memeber type "[]".  */
+bool
+flexible_array_member_p (const_tree type)
+{
+  if (TREE_CODE (type) == ARRAY_TYPE
+      && TYPE_SIZE (type) == NULL_TREE
+      && TYPE_DOMAIN (type) != NULL_TREE
+      && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)
+    return true;
+
+  return false;
+}
+
+/* Determine whether TYPE is a zero-length array type "[0]".  */
+bool
+zero_length_array_p (const_tree type)
+{
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    if (tree type_size = TYPE_SIZE_UNIT (type))
+      if ((integer_zerop (type_size))
+          && TYPE_DOMAIN (type) != NULL_TREE
+          && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)
+       return true;
+  return false;
+}
+
+/* Determine whether TYPE is a one-element array type "[1]".
+   Set IS_CONSTANT_LENGTH to true if the length is constant,
+   otherwise, IS_CONSTANT_LENGTH is set to false.  */
+bool
+one_element_array_p (const_tree type, bool *is_constant_length /* = NULL */)
+{
+  if (is_constant_length)
+    *is_constant_length = false;
+
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    if (tree dom = TYPE_DOMAIN (type))
+      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 (is_constant_length)
+               *is_constant_length = true;
+             if (neltsm1 == 0)
+               return true;
+           }
+  return false;
+}
+
/* Determine whether TYPE is a structure with a flexible array member,
   or a union containing such a structure (possibly recursively).  */

@@ -14367,10 +14416,7 @@ flexible_array_type_p (const_tree type)
          last = x;
      if (last == NULL_TREE)
        return false;
-      if (TREE_CODE (TREE_TYPE (last)) == ARRAY_TYPE
-         && TYPE_SIZE (TREE_TYPE (last)) == NULL_TREE
-         && TYPE_DOMAIN (TREE_TYPE (last)) != NULL_TREE
-         && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (last))) == NULL_TREE)
+      if (flexible_array_member_p (TREE_TYPE (last)))
        return true;
      return false;
    case UNION_TYPE:
diff --git a/gcc/tree.h b/gcc/tree.h
index e6564aaccb7..3107de5b499 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2993,6 +2993,11 @@ extern void decl_value_expr_insert (tree, tree);
#define DECL_PADDING_P(NODE) \
  (FIELD_DECL_CHECK (NODE)->decl_common.decl_flag_3)

+/* Used in a FIELD_DECL to indicate whether this field is not a flexible
+   array member.  */
+#define DECL_NOT_FLEXARRAY(NODE) \
+  (FIELD_DECL_CHECK (NODE)->decl_common.decl_not_flexarray)
+
/* A numeric unique identifier for a LABEL_DECL.  The UID allocation is
   dense, unique within any one function, and may be used to index arrays.
   If the value is -1, then no UID has been assigned.  */
@@ -5531,10 +5536,10 @@ extern tree component_ref_field_offset (tree);
   returns null.  */
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.  */
+    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.  */
  };

/* Return the size of the member referenced by the COMPONENT_REF, using
@@ -6489,6 +6494,9 @@ extern void gt_pch_nx (tree &, gt_pointer_operator, void 
*);
extern bool nonnull_arg_p (const_tree);
extern bool is_empty_type (const_tree);
extern bool default_is_empty_record (const_tree);
+extern bool zero_length_array_p (const_tree);
+extern bool one_element_array_p (const_tree, bool * = NULL);
+extern bool flexible_array_member_p (const_tree);
extern bool flexible_array_type_p (const_tree);
extern HOST_WIDE_INT arg_int_size_in_bytes (const_tree);
extern tree arg_size_in_bytes (const_tree);
-- 
2.27.0

Reply via email to