public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [GCC13][Patch][V4][PATCH 0/2] Add a new option -fstrict-flex-array[=n] and attribute strict_flex_array(n) and use it in PR101836
@ 2022-09-07  0:28 Qing Zhao
  2022-09-07  0:28 ` [GCC13][Patch][V4][PATCH 1/2] Add a new option -fstrict-flex-arrays[=n] and new attribute strict_flex_arrays Qing Zhao
  2022-09-07  0:28 ` [GCC13][Patch][V4][PATCH 2/2] Use array_at_struct_end_p in __builtin_object_size [PR101836] Qing Zhao
  0 siblings, 2 replies; 7+ messages in thread
From: Qing Zhao @ 2022-09-07  0:28 UTC (permalink / raw)
  To: gcc-patches; +Cc: rguenther, jakub, msebor, keescook, joseph, Qing Zhao

This is the 4th version of the patch set.
Compare to the 3rd version, the following are the major change:

1. delete all the warnings for the confliction between -std and
-fstrict-flex-arrays per our discussion.
2. delete all the related testing cases for these warnings.
3. update all the wording changes, and documentation format changes
recommanded by Joseph.
I have bootstrapped and regression tested on both aarch64 and x86, no issues.

Let me know if you have any comments on the patches.

thanks.

Qing Zhao (2):
  Add a new option -fstrict-flex-arrays[=n] and new attribute
    strict_flex_arrays
  Use array_at_struct_end_p in __builtin_object_size [PR101836]

 gcc/c-family/c-attribs.cc                  |  47 ++++++++
 gcc/c-family/c.opt                         |   7 ++
 gcc/c/c-decl.cc                            | 130 +++++++++++++++++++--
 gcc/cp/module.cc                           |   2 +
 gcc/doc/extend.texi                        |  25 ++++
 gcc/doc/invoke.texi                        |  27 ++++-
 gcc/print-tree.cc                          |   8 +-
 gcc/testsuite/g++.dg/strict-flex-array-1.C |  31 +++++
 gcc/testsuite/gcc.dg/pr101836.c            |  60 ++++++++++
 gcc/testsuite/gcc.dg/pr101836_1.c          |  60 ++++++++++
 gcc/testsuite/gcc.dg/pr101836_2.c          |  60 ++++++++++
 gcc/testsuite/gcc.dg/pr101836_3.c          |  60 ++++++++++
 gcc/testsuite/gcc.dg/pr101836_4.c          |  60 ++++++++++
 gcc/testsuite/gcc.dg/pr101836_5.c          |  60 ++++++++++
 gcc/testsuite/gcc.dg/strict-flex-array-1.c |  31 +++++
 gcc/testsuite/gcc.dg/strict-flex-array-2.c |  60 ++++++++++
 gcc/testsuite/gcc.dg/strict-flex-array-3.c |  60 ++++++++++
 gcc/tree-core.h                            |   5 +-
 gcc/tree-object-size.cc                    |  16 ++-
 gcc/tree-streamer-in.cc                    |   1 +
 gcc/tree-streamer-out.cc                   |   1 +
 gcc/tree.cc                                |  45 +++++--
 gcc/tree.h                                 |  14 ++-
 23 files changed, 833 insertions(+), 37 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-1.C
 create mode 100644 gcc/testsuite/gcc.dg/pr101836.c
 create mode 100644 gcc/testsuite/gcc.dg/pr101836_1.c
 create mode 100644 gcc/testsuite/gcc.dg/pr101836_2.c
 create mode 100644 gcc/testsuite/gcc.dg/pr101836_3.c
 create mode 100644 gcc/testsuite/gcc.dg/pr101836_4.c
 create mode 100644 gcc/testsuite/gcc.dg/pr101836_5.c
 create mode 100644 gcc/testsuite/gcc.dg/strict-flex-array-1.c
 create mode 100644 gcc/testsuite/gcc.dg/strict-flex-array-2.c
 create mode 100644 gcc/testsuite/gcc.dg/strict-flex-array-3.c

-- 
2.31.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [GCC13][Patch][V4][PATCH 1/2] Add a new option -fstrict-flex-arrays[=n] and new attribute strict_flex_arrays
  2022-09-07  0:28 [GCC13][Patch][V4][PATCH 0/2] Add a new option -fstrict-flex-array[=n] and attribute strict_flex_array(n) and use it in PR101836 Qing Zhao
@ 2022-09-07  0:28 ` Qing Zhao
  2022-09-12 16:42   ` Martin Sebor
  2022-09-07  0:28 ` [GCC13][Patch][V4][PATCH 2/2] Use array_at_struct_end_p in __builtin_object_size [PR101836] Qing Zhao
  1 sibling, 1 reply; 7+ messages in thread
From: Qing Zhao @ 2022-09-07  0:28 UTC (permalink / raw)
  To: gcc-patches; +Cc: rguenther, jakub, msebor, keescook, joseph, Qing Zhao

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

'-fstrict-flex-arrays'
     Treat the trailing array of a structure as a flexible array member
     in a stricter way.  The positive form is equivalent to
     '-fstrict-flex-arrays=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-arrays=0', which is the least
     strict.  All trailing arrays of structures are treated as flexible
     array members.

'-fstrict-flex-arrays=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_arrays' 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_arrays'
     attribute (*note Variable Attributes::).

'strict_flex_arrays (LEVEL)'
     The 'strict_flex_arrays' 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 the
     '-fstrict-flex-arrays'.  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_arrays_attribute): New function.
	(c_common_attribute_table): New item for strict_flex_arrays.
	* c.opt: (fstrict-flex-arrays): New option.
	(fstrict-flex-arrays=): New option.

gcc/c/ChangeLog:

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

gcc/cp/ChangeLog:

	* module.cc (trees_out::core_bools): Stream out new bit
	decl_not_flexarray.
	(trees_in::core_bools): Stream in new bit decl_not_flexarray.

gcc/ChangeLog:

	* doc/extend.texi: Document strict_flex_arrays attribute.
	* doc/invoke.texi: Document -fstrict-flex-arrays[=n] option.
	* print-tree.cc (print_node): Print new bit decl_not_flexarray.
	* tree-core.h (struct tree_decl_common): New bit field
	decl_not_flexarray.
	* tree-streamer-in.cc (unpack_ts_decl_common_value_fields): Stream
	in new bit decl_not_flexarray.
	* tree-streamer-out.cc (pack_ts_decl_common_value_fields): Stream
	out new bit decl_not_flexarray.
	* tree.cc (array_at_struct_end_p): Update it with the new bit field
	decl_not_flexarray.
	* tree.h (DECL_NOT_FLEXARRAY): New flag.

gcc/testsuite/ChangeLog:

	* g++.dg/strict-flex-array-1.C: New test.
	* 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                            | 130 +++++++++++++++++++--
 gcc/cp/module.cc                           |   2 +
 gcc/doc/extend.texi                        |  25 ++++
 gcc/doc/invoke.texi                        |  27 ++++-
 gcc/print-tree.cc                          |   8 +-
 gcc/testsuite/g++.dg/strict-flex-array-1.C |  31 +++++
 gcc/testsuite/gcc.dg/strict-flex-array-1.c |  31 +++++
 gcc/tree-core.h                            |   5 +-
 gcc/tree-streamer-in.cc                    |   1 +
 gcc/tree-streamer-out.cc                   |   1 +
 gcc/tree.cc                                |  45 +++++--
 gcc/tree.h                                 |  14 ++-
 14 files changed, 346 insertions(+), 28 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-1.C
 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 8bb80e251dc2..0becd4bbe8d2 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_arrays_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 *);
@@ -368,6 +370,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_arrays",      1, 1, false, false, false, false,
+			      handle_strict_flex_arrays_attribute, NULL },
   { "weak",                   0, 0, true,  false, false, false,
 			      handle_weak_attribute, NULL },
   { "noplt",                   0, 0, true,  false, false, false,
@@ -2505,6 +2509,49 @@ handle_warn_if_not_aligned_attribute (tree *node, tree name,
 					  no_add_attrs, true);
 }
 
+/* Handle a "strict_flex_arrays" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_strict_flex_arrays_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 4515664aa590..e053bd939559 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -2072,6 +2072,13 @@ fsized-deallocation
 C++ ObjC++ Var(flag_sized_deallocation) Init(-1)
 Enable C++14 sized deallocation support.
 
+fstrict-flex-arrays
+C C++ Common Alias(fstrict-flex-arrays=,3,0)
+
+fstrict-flex-arrays=
+C C++ Common Joined RejectNegative UInteger Var(flag_strict_flex_arrays) Init(0) IntegerRange(0,3)
+-fstrict-flex-arrays=<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 34f8feda897f..ee90808bcb0e 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5005,6 +5005,41 @@ set_array_declarator_inner (struct c_declarator *decl,
   return decl;
 }
 
+/* Determine whether TYPE is a ISO C99 flexible array memeber type "[]".  */
+static bool
+flexible_array_member_type_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 one-element array type "[1]".  */
+static bool
+one_element_array_type_p (const_tree type)
+{
+  if (TREE_CODE (type) != ARRAY_TYPE)
+    return false;
+  return integer_zerop (array_type_nelts (type));
+}
+
+/* Determine whether TYPE is a zero-length array type "[0]".  */
+static bool
+zero_length_array_type_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;
+}
+
 /* INIT is a constructor that forms DECL's initializer.  If the final
    element initializes a flexible array field, add the size of that
    initializer to DECL's size.  */
@@ -5019,10 +5054,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_type_p (type))
     {
       complete_array_type (&type, elt, false);
       DECL_SIZE (decl)
@@ -8710,6 +8742,81 @@ 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_arrays;
+  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_type_p (TREE_TYPE (x));
+  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_arrays",
+						  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;
+    }
+
+  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.
@@ -8771,6 +8878,11 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
   bool saw_named_field = false;
   for (x = fieldlist; x; x = DECL_CHAIN (x))
     {
+      /* whether this field is the last field of the structure or union.
+	 for UNION, any field is the last field of it.  */
+      bool is_last_field = (DECL_CHAIN (x) == NULL_TREE)
+			    || (TREE_CODE (t) == UNION_TYPE);
+
       if (TREE_TYPE (x) == error_mark_node)
 	continue;
 
@@ -8809,10 +8921,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_type_p (TREE_TYPE (x)))
 	{
 	  if (TREE_CODE (t) == UNION_TYPE)
 	    {
@@ -8820,7 +8929,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");
@@ -8840,6 +8949,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/cp/module.cc b/gcc/cp/module.cc
index f27f4d091e5e..75ee2514f66b 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -5414,6 +5414,7 @@ trees_out::core_bools (tree t)
       WB (t->decl_common.decl_by_reference_flag);
       WB (t->decl_common.decl_read_flag);
       WB (t->decl_common.decl_nonshareable_flag);
+      WB (t->decl_common.decl_not_flexarray);
     }
 
   if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
@@ -5558,6 +5559,7 @@ trees_in::core_bools (tree t)
       RB (t->decl_common.decl_by_reference_flag);
       RB (t->decl_common.decl_read_flag);
       RB (t->decl_common.decl_nonshareable_flag);
+      RB (t->decl_common.decl_not_flexarray);
     }
 
   if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 0fedab96610b..62328d77c78c 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -7459,6 +7459,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_arrays} variable attribute
+@item strict_flex_arrays (@var{level})
+The @code{strict_flex_arrays} 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 (@samp{[]}), 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 (@samp{[0]}) or one-size
+array as flexible array member (@samp{[1]}):
+When @var{level} is 1, the trailing array is treated as a flexible array member
+when it is declared as either @samp{[]}, @samp{[0]}, or @samp{[1]};
+When @var{level} is 2, the trailing array is treated as a flexible array member
+when it is declared as either @samp{[]}, or @samp{[0]}.
+
+This attribute can be used with or without the @option{-fstrict-flex-arrays}.
+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 9d662e353163..db1a68cd545c 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-arrays[=@var{n}] @gol
+-fsso-struct=@var{endianness}}
 
 @item C++ Language Options
 @xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
@@ -2826,6 +2827,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-arrays
+@opindex fstrict-flex-arrays
+@opindex fno-strict-flex-arrays
+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-arrays=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-arrays=0}, which is the
+least strict.  All trailing arrays of structures are treated as flexible array
+members.
+
+@item -fstrict-flex-arrays=@var{level}
+@opindex fstrict-flex-arrays=@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_arrays} 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_arrays} 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/print-tree.cc b/gcc/print-tree.cc
index 6d45a4a59669..58a98250cc4f 100644
--- a/gcc/print-tree.cc
+++ b/gcc/print-tree.cc
@@ -517,8 +517,12 @@ print_node (FILE *file, const char *prefix, tree node, int indent,
 	  fprintf (file, " align:%d warn_if_not_align:%d",
 		   DECL_ALIGN (node), DECL_WARN_IF_NOT_ALIGN (node));
 	  if (code == FIELD_DECL)
-	    fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED,
-		     DECL_OFFSET_ALIGN (node));
+	    {
+	      fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED,
+		       DECL_OFFSET_ALIGN (node));
+	      fprintf (file, " decl_not_flexarray: %d",
+		       DECL_NOT_FLEXARRAY (node));
+	    }
 
 	  if (code == FUNCTION_DECL && fndecl_built_in_p (node))
 	    {
diff --git a/gcc/testsuite/g++.dg/strict-flex-array-1.C b/gcc/testsuite/g++.dg/strict-flex-array-1.C
new file mode 100644
index 000000000000..cd6a65d2b7e6
--- /dev/null
+++ b/gcc/testsuite/g++.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_arrays (1))); /* { dg-error "'strict_flex_arrays' attribute may not be specified for 'x'" } */
+
+struct trailing {
+    int a;
+    int c __attribute ((strict_flex_arrays)); /* { dg-error "wrong number of arguments specified for 'strict_flex_arrays' attribute" } */
+};
+
+struct trailing_1 {
+    int a;
+    int b;
+    int c __attribute ((strict_flex_arrays (2))); /* { dg-error "'strict_flex_arrays' 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_arrays (d))); /* { dg-error "'strict_flex_arrays' attribute argument not an integer" } */
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (5))); /* { dg-error "'strict_flex_arrays' attribute argument '5' is not an integer constant between 0 and 3" } */
+};
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 000000000000..cd6a65d2b7e6
--- /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_arrays (1))); /* { dg-error "'strict_flex_arrays' attribute may not be specified for 'x'" } */
+
+struct trailing {
+    int a;
+    int c __attribute ((strict_flex_arrays)); /* { dg-error "wrong number of arguments specified for 'strict_flex_arrays' attribute" } */
+};
+
+struct trailing_1 {
+    int a;
+    int b;
+    int c __attribute ((strict_flex_arrays (2))); /* { dg-error "'strict_flex_arrays' 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_arrays (d))); /* { dg-error "'strict_flex_arrays' attribute argument not an integer" } */
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (5))); /* { dg-error "'strict_flex_arrays' 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 80c2bcb333dd..18bd6d82a32d 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1823,7 +1823,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-streamer-in.cc b/gcc/tree-streamer-in.cc
index 219cf5e7ef45..57923da3741e 100644
--- a/gcc/tree-streamer-in.cc
+++ b/gcc/tree-streamer-in.cc
@@ -261,6 +261,7 @@ unpack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
       else
 	SET_DECL_FIELD_ABI_IGNORED (expr, val);
       expr->decl_common.off_align = bp_unpack_value (bp, 8);
+      DECL_NOT_FLEXARRAY (expr) = (unsigned) bp_unpack_value (bp, 1);
     }
 
   else if (VAR_P (expr))
diff --git a/gcc/tree-streamer-out.cc b/gcc/tree-streamer-out.cc
index 9b114dc05bb1..68a2818a9f93 100644
--- a/gcc/tree-streamer-out.cc
+++ b/gcc/tree-streamer-out.cc
@@ -229,6 +229,7 @@ pack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
       else
 	bp_pack_value (bp, DECL_FIELD_ABI_IGNORED (expr), 1);
       bp_pack_value (bp, expr->decl_common.off_align, 8);
+      bp_pack_value (bp, DECL_NOT_FLEXARRAY (expr), 1);
     }
 
   else if (VAR_P (expr))
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 2f488e4467c4..e4664eab54ef 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -12688,14 +12688,30 @@ array_ref_up_bound (tree exp)
 }
 
 /* Returns true if REF is an array reference, component reference,
-   or memory reference to an array at the end of a structure.
-   If this is the case, the array may be allocated larger
-   than its upper bound implies.  */
+   or memory reference to an array whose actual size might be larger
+   than its upper bound implies, there are multiple cases:
+   A. a ref to a flexible array member at the end of a structure;
+   B. a ref to an array with a different type against the original decl;
+      for example:
 
+   short a[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+   (*((char(*)[16])&a[0]))[i+8]
+
+   C. a ref to an array that was passed as a parameter;
+      for example:
+
+   int test (uint8_t *p, uint32_t t[1][1], int n) {
+   for (int i = 0; i < 4; i++, p++)
+     t[i][0] = ...;
+
+   FIXME, the name of this routine need to be changed to be more accurate.  */
 bool
 array_at_struct_end_p (tree ref)
 {
-  tree atype;
+  /* the TYPE for this array referece.  */
+  tree atype = NULL_TREE;
+  /* the FIELD_DECL for the array field in the containing structure.  */
+  tree afield_decl = NULL_TREE;
 
   if (TREE_CODE (ref) == ARRAY_REF
       || TREE_CODE (ref) == ARRAY_RANGE_REF)
@@ -12705,7 +12721,10 @@ array_at_struct_end_p (tree ref)
     }
   else if (TREE_CODE (ref) == COMPONENT_REF
 	   && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 1))) == ARRAY_TYPE)
-    atype = TREE_TYPE (TREE_OPERAND (ref, 1));
+    {
+      atype = TREE_TYPE (TREE_OPERAND (ref, 1));
+      afield_decl = TREE_OPERAND (ref, 1);
+    }
   else if (TREE_CODE (ref) == MEM_REF)
     {
       tree arg = TREE_OPERAND (ref, 0);
@@ -12717,6 +12736,7 @@ array_at_struct_end_p (tree ref)
 	  if (tree fld = last_field (argtype))
 	    {
 	      atype = TREE_TYPE (fld);
+	      afield_decl = fld;
 	      if (TREE_CODE (atype) != ARRAY_TYPE)
 		return false;
 	      if (VAR_P (arg) && DECL_SIZE (fld))
@@ -12770,13 +12790,16 @@ array_at_struct_end_p (tree ref)
       ref = TREE_OPERAND (ref, 0);
     }
 
-  /* The array now is at struct end.  Treat flexible arrays as
+  gcc_assert (!afield_decl
+	      || (afield_decl && TREE_CODE (afield_decl) == FIELD_DECL));
+
+  /* The array now is at struct end.  Treat flexible array member as
      always subject to extend, even into just padding constrained by
      an underlying decl.  */
   if (! TYPE_SIZE (atype)
       || ! TYPE_DOMAIN (atype)
       || ! TYPE_MAX_VALUE (TYPE_DOMAIN (atype)))
-    return true;
+    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).  */
@@ -12798,9 +12821,9 @@ array_at_struct_end_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 true;
+	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
       if (! get_addr_base_and_unit_offset (ref_to_array, &offset))
-	return true;
+	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)))
@@ -12808,12 +12831,12 @@ array_at_struct_end_p (tree ref)
 		     + 2)
 		    * wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (atype))),
 		    wi::to_offset (DECL_SIZE_UNIT (ref)) - offset))
-	return true;
+	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
 
       return false;
     }
 
-  return true;
+  return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
 }
 
 /* Return a tree representing the offset, in bytes, of the field referenced
diff --git a/gcc/tree.h b/gcc/tree.h
index 266e24a05633..81076b045003 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3005,6 +3005,12 @@ 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. This is only valid for the last array type field of a
+   structure.  */
+#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.  */
@@ -5543,10 +5549,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
-- 
2.31.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [GCC13][Patch][V4][PATCH 2/2] Use array_at_struct_end_p in __builtin_object_size [PR101836]
  2022-09-07  0:28 [GCC13][Patch][V4][PATCH 0/2] Add a new option -fstrict-flex-array[=n] and attribute strict_flex_array(n) and use it in PR101836 Qing Zhao
  2022-09-07  0:28 ` [GCC13][Patch][V4][PATCH 1/2] Add a new option -fstrict-flex-arrays[=n] and new attribute strict_flex_arrays Qing Zhao
@ 2022-09-07  0:28 ` Qing Zhao
  1 sibling, 0 replies; 7+ messages in thread
From: Qing Zhao @ 2022-09-07  0:28 UTC (permalink / raw)
  To: gcc-patches; +Cc: rguenther, jakub, msebor, keescook, joseph, Qing Zhao

Use array_at_struct_end_p to determine whether the trailing array
of a structure is flexible array member in __builtin_object_size.

gcc/ChangeLog:

	PR tree-optimization/101836
	* tree-object-size.cc (addr_object_size): Use array_at_struct_end_p
	to determine a flexible array member reference.

gcc/testsuite/ChangeLog:

	PR tree-optimization/101836
	* gcc.dg/pr101836.c: New test.
	* gcc.dg/pr101836_1.c: New test.
	* gcc.dg/pr101836_2.c: New test.
	* gcc.dg/pr101836_3.c: New test.
	* gcc.dg/pr101836_4.c: New test.
	* gcc.dg/pr101836_5.c: New test.
	* gcc.dg/strict-flex-array-2.c: New test.
	* gcc.dg/strict-flex-array-3.c: New test.
---
 gcc/testsuite/gcc.dg/pr101836.c            | 60 ++++++++++++++++++++++
 gcc/testsuite/gcc.dg/pr101836_1.c          | 60 ++++++++++++++++++++++
 gcc/testsuite/gcc.dg/pr101836_2.c          | 60 ++++++++++++++++++++++
 gcc/testsuite/gcc.dg/pr101836_3.c          | 60 ++++++++++++++++++++++
 gcc/testsuite/gcc.dg/pr101836_4.c          | 60 ++++++++++++++++++++++
 gcc/testsuite/gcc.dg/pr101836_5.c          | 60 ++++++++++++++++++++++
 gcc/testsuite/gcc.dg/strict-flex-array-2.c | 60 ++++++++++++++++++++++
 gcc/testsuite/gcc.dg/strict-flex-array-3.c | 60 ++++++++++++++++++++++
 gcc/tree-object-size.cc                    | 16 +++---
 9 files changed, 487 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr101836.c
 create mode 100644 gcc/testsuite/gcc.dg/pr101836_1.c
 create mode 100644 gcc/testsuite/gcc.dg/pr101836_2.c
 create mode 100644 gcc/testsuite/gcc.dg/pr101836_3.c
 create mode 100644 gcc/testsuite/gcc.dg/pr101836_4.c
 create mode 100644 gcc/testsuite/gcc.dg/pr101836_5.c
 create mode 100644 gcc/testsuite/gcc.dg/strict-flex-array-2.c
 create mode 100644 gcc/testsuite/gcc.dg/strict-flex-array-3.c

diff --git a/gcc/testsuite/gcc.dg/pr101836.c b/gcc/testsuite/gcc.dg/pr101836.c
new file mode 100644
index 000000000000..efad02cfe899
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr101836.c
@@ -0,0 +1,60 @@
+/* -fstrict-flex-arrays is aliased with -ftrict-flex-arrays=3, which is the
+   strictest, only [] is treated as flexible array.  */ 
+/* PR tree-optimization/101836 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fstrict-flex-arrays" } */
+
+#include <stdio.h>
+
+#define expect(p, _v) do { \
+    size_t v = _v; \
+    if (p == v) \
+        printf("ok:  %s == %zd\n", #p, p); \
+    else \
+	{  \
+          printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
+	  __builtin_abort (); \
+	} \
+} while (0);
+
+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)
+{
+    expect(__builtin_object_size(normal->c, 1), 16);
+    expect(__builtin_object_size(trailing_1->c, 1), 4);
+    expect(__builtin_object_size(trailing_0->c, 1), 0);
+    expect(__builtin_object_size(trailing_flex->c, 1), -1);
+}
+
+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/pr101836_1.c b/gcc/testsuite/gcc.dg/pr101836_1.c
new file mode 100644
index 000000000000..e2931ce1012e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr101836_1.c
@@ -0,0 +1,60 @@
+/* -fstrict-flex-arrays=3 is the strictest, only [] is treated as
+   flexible array.  */ 
+/* PR tree-optimization/101836 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fstrict-flex-arrays=3" } */
+
+#include <stdio.h>
+
+#define expect(p, _v) do { \
+    size_t v = _v; \
+    if (p == v) \
+        printf("ok:  %s == %zd\n", #p, p); \
+    else \
+	{  \
+          printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
+	  __builtin_abort (); \
+	} \
+} while (0);
+
+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)
+{
+    expect(__builtin_object_size(normal->c, 1), 16);
+    expect(__builtin_object_size(trailing_1->c, 1), 4);
+    expect(__builtin_object_size(trailing_0->c, 1), 0);
+    expect(__builtin_object_size(trailing_flex->c, 1), -1);
+}
+
+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/pr101836_2.c b/gcc/testsuite/gcc.dg/pr101836_2.c
new file mode 100644
index 000000000000..78974187721f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr101836_2.c
@@ -0,0 +1,60 @@
+/* When -fstrict-flex-arrays=2, only [] and [0] are treated as flexiable
+   arrays.  */
+/* PR tree-optimization/101836 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fstrict-flex-arrays=2" } */
+
+#include <stdio.h>
+
+#define expect(p, _v) do { \
+    size_t v = _v; \
+    if (p == v) \
+        printf("ok:  %s == %zd\n", #p, p); \
+    else \
+	{  \
+          printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
+	  __builtin_abort (); \
+	} \
+} while (0);
+
+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)
+{
+    expect(__builtin_object_size(normal->c, 1), 16);
+    expect(__builtin_object_size(trailing_1->c, 1), 4);
+    expect(__builtin_object_size(trailing_0->c, 1), -1);
+    expect(__builtin_object_size(trailing_flex->c, 1), -1);
+}
+
+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/pr101836_3.c b/gcc/testsuite/gcc.dg/pr101836_3.c
new file mode 100644
index 000000000000..0e69388e81fb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr101836_3.c
@@ -0,0 +1,60 @@
+/* When -fstrict-flex-arrays=1, [], [0], and [1] are treated as flexible
+   arrays.  */
+/* PR tree-optimization/101836 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fstrict-flex-arrays=1" } */
+
+#include <stdio.h>
+
+#define expect(p, _v) do { \
+    size_t v = _v; \
+    if (p == v) \
+        printf("ok:  %s == %zd\n", #p, p); \
+    else \
+	{  \
+          printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
+	  __builtin_abort (); \
+	} \
+} while (0);
+
+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)
+{
+    expect(__builtin_object_size(normal->c, 1), 16);
+    expect(__builtin_object_size(trailing_1->c, 1), -1);
+    expect(__builtin_object_size(trailing_0->c, 1), -1);
+    expect(__builtin_object_size(trailing_flex->c, 1), -1);
+}
+
+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/pr101836_4.c b/gcc/testsuite/gcc.dg/pr101836_4.c
new file mode 100644
index 000000000000..e0025aa9a7b5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr101836_4.c
@@ -0,0 +1,60 @@
+/* when -fstrict-flex-arrays=0, all trailing arrays are treated as
+   flexible arrays.  */
+/* PR tree-optimization/101836 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fstrict-flex-arrays=0" } */
+
+#include <stdio.h>
+
+#define expect(p, _v) do { \
+    size_t v = _v; \
+    if (p == v) \
+        printf("ok:  %s == %zd\n", #p, p); \
+    else \
+	{  \
+          printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
+	  __builtin_abort (); \
+	} \
+} while (0);
+
+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)
+{
+    expect(__builtin_object_size(normal->c, 1), -1);
+    expect(__builtin_object_size(trailing_1->c, 1), -1);
+    expect(__builtin_object_size(trailing_0->c, 1), -1);
+    expect(__builtin_object_size(trailing_flex->c, 1), -1);
+}
+
+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/pr101836_5.c b/gcc/testsuite/gcc.dg/pr101836_5.c
new file mode 100644
index 000000000000..0ad8bbf693ce
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr101836_5.c
@@ -0,0 +1,60 @@
+/* -fno-strict-flex-arrays is aliased to -fstrict-flex-arrays=0,
+   all trailing arrays are treated as flexible array.  */
+/* PR tree-optimization/101836 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fno-strict-flex-arrays" } */
+
+#include <stdio.h>
+
+#define expect(p, _v) do { \
+    size_t v = _v; \
+    if (p == v) \
+        printf("ok:  %s == %zd\n", #p, p); \
+    else \
+	{  \
+          printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
+	  __builtin_abort (); \
+	} \
+} while (0);
+
+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)
+{
+    expect(__builtin_object_size(normal->c, 1), -1);
+    expect(__builtin_object_size(trailing_1->c, 1), -1);
+    expect(__builtin_object_size(trailing_0->c, 1), -1);
+    expect(__builtin_object_size(trailing_flex->c, 1), -1);
+}
+
+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/strict-flex-array-2.c b/gcc/testsuite/gcc.dg/strict-flex-array-2.c
new file mode 100644
index 000000000000..e474b9ec43fa
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strict-flex-array-2.c
@@ -0,0 +1,60 @@
+/* test the combination of attribute strict_flex_arrays and option
+   -fstrict-flex-arrays: when both attribute and option specified,
+   attribute will have higher priority.  */
+/* { dg-do run } */
+/* { dg-options "-O2 -fstrict-flex-arrays=3" } */
+
+#include <stdio.h>
+
+#define expect(p, _v) do { \
+    size_t v = _v; \
+    if (p == v) \
+        printf("ok:  %s == %zd\n", #p, p); \
+    else \
+	{  \
+          printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
+	  __builtin_abort (); \
+	} \
+} while (0);
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[4] __attribute__ ((strict_flex_arrays (0)));
+};
+
+struct trailing_array_2 {
+    int a;
+    int b;
+    int c[1] __attribute__ ((strict_flex_arrays (1)));
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0] __attribute__ ((strict_flex_arrays (2)));
+};
+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)
+{
+    expect(__builtin_object_size(normal->c, 1), -1);
+    expect(__builtin_object_size(trailing_1->c, 1), -1);
+    expect(__builtin_object_size(trailing_0->c, 1), -1);
+    expect(__builtin_object_size(trailing_flex->c, 1), -1);
+}
+
+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/strict-flex-array-3.c b/gcc/testsuite/gcc.dg/strict-flex-array-3.c
new file mode 100644
index 000000000000..b45e7b32f6d1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strict-flex-array-3.c
@@ -0,0 +1,60 @@
+/* test the combination of attribute strict_flex_arrays and option
+   -fstrict-flex-arrays: when both attribute and option specified,
+   attribute will have higher priority.  */
+/* { dg-do run } */
+/* { dg-options "-O2 -fstrict-flex-arrays=0" } */
+
+#include <stdio.h>
+
+#define expect(p, _v) do { \
+    size_t v = _v; \
+    if (p == v) \
+        printf("ok:  %s == %zd\n", #p, p); \
+    else \
+	{  \
+          printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
+	  __builtin_abort (); \
+	} \
+} while (0);
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[4] __attribute__ ((strict_flex_arrays (1)));
+};
+
+struct trailing_array_2 {
+    int a;
+    int b;
+    int c[1] __attribute__ ((strict_flex_arrays (2)));
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0] __attribute__ ((strict_flex_arrays (3)));
+};
+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)
+{
+    expect(__builtin_object_size(normal->c, 1), 16);
+    expect(__builtin_object_size(trailing_1->c, 1), 4);
+    expect(__builtin_object_size(trailing_0->c, 1), 0);
+    expect(__builtin_object_size(trailing_flex->c, 1), -1);
+}
+
+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-object-size.cc b/gcc/tree-object-size.cc
index 4eb454a4a33b..1f04cb80fd0a 100644
--- a/gcc/tree-object-size.cc
+++ b/gcc/tree-object-size.cc
@@ -604,9 +604,9 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
 	  else if (var != pt_var && TREE_CODE (pt_var) == MEM_REF)
 	    {
 	      tree v = var;
-	      /* For &X->fld, compute object size only if fld isn't the last
-		 field, as struct { int i; char c[1]; } is often used instead
-		 of flexible array member.  */
+	      /* For &X->fld, compute object size if fld isn't a flexible array
+		 member.  */
+	      bool is_flexible_array_mem_ref = false;
 	      while (v && v != pt_var)
 		switch (TREE_CODE (v))
 		  {
@@ -633,6 +633,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
 			v = NULL_TREE;
 			break;
 		      }
+		    is_flexible_array_mem_ref = array_at_struct_end_p (v);
 		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
 		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
 			  != UNION_TYPE
@@ -645,12 +646,9 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
 			&& TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
 			   == RECORD_TYPE)
 		      {
-			tree fld_chain = DECL_CHAIN (TREE_OPERAND (v, 1));
-			for (; fld_chain; fld_chain = DECL_CHAIN (fld_chain))
-			  if (TREE_CODE (fld_chain) == FIELD_DECL)
-			    break;
-
-			if (fld_chain)
+			/* compute object size only if v is not a
+			   flexible array member.  */
+			if (!is_flexible_array_mem_ref)
 			  {
 			    v = NULL_TREE;
 			    break;
-- 
2.31.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [GCC13][Patch][V4][PATCH 1/2] Add a new option -fstrict-flex-arrays[=n] and new attribute strict_flex_arrays
  2022-09-07  0:28 ` [GCC13][Patch][V4][PATCH 1/2] Add a new option -fstrict-flex-arrays[=n] and new attribute strict_flex_arrays Qing Zhao
@ 2022-09-12 16:42   ` Martin Sebor
  2022-09-28 19:17     ` Qing Zhao
  0 siblings, 1 reply; 7+ messages in thread
From: Martin Sebor @ 2022-09-12 16:42 UTC (permalink / raw)
  To: Qing Zhao, gcc-patches; +Cc: rguenther, jakub, keescook, joseph

On 9/6/22 18:28, Qing Zhao wrote:
> Add the following new option -fstrict-flex-arrays[=n] and a corresponding
> attribute strict_flex_arrays to GCC:
> 
> '-fstrict-flex-arrays'
>       Treat the trailing array of a structure as a flexible array member
>       in a stricter way.

A minor problem with this phrasing was pointed out in the review
of the Clang option: https://reviews.llvm.org/D126864#inline-1282716
It would be good to avoid it here.  (I think qualifying the sentence
by adding "for the purposes of accessing the elements of such arrays"
might be one way to do it).

>  The positive form is equivalent to
>       '-fstrict-flex-arrays=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-arrays=0', which is the least
>       strict.  All trailing arrays of structures are treated as flexible
>       array members.
> 
> '-fstrict-flex-arrays=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_arrays' 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_arrays'
>       attribute (*note Variable Attributes::).
> 
> 'strict_flex_arrays (LEVEL)'
>       The 'strict_flex_arrays' 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.


Since the attribute applies to just a single array declaration it
seems that its name should be strict_flex_array (i.e., singular,
without the trailing 's').

Martin

> 
>       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 the
>       '-fstrict-flex-arrays'.  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_arrays_attribute): New function.
> 	(c_common_attribute_table): New item for strict_flex_arrays.
> 	* c.opt: (fstrict-flex-arrays): New option.
> 	(fstrict-flex-arrays=): New option.
> 
> gcc/c/ChangeLog:
> 
> 	* c-decl.cc (flexible_array_member_type_p): New function.
> 	(one_element_array_type_p): Likewise.
> 	(zero_length_array_type_p): Likewise.
> 	(add_flexible_array_elts_to_size): Call new utility
> 	routine flexible_array_member_type_p.
> 	(is_flexible_array_member_p): New function.
> 	(finish_struct): Set the new DECL_NOT_FLEXARRAY flag.
> 
> gcc/cp/ChangeLog:
> 
> 	* module.cc (trees_out::core_bools): Stream out new bit
> 	decl_not_flexarray.
> 	(trees_in::core_bools): Stream in new bit decl_not_flexarray.
> 
> gcc/ChangeLog:
> 
> 	* doc/extend.texi: Document strict_flex_arrays attribute.
> 	* doc/invoke.texi: Document -fstrict-flex-arrays[=n] option.
> 	* print-tree.cc (print_node): Print new bit decl_not_flexarray.
> 	* tree-core.h (struct tree_decl_common): New bit field
> 	decl_not_flexarray.
> 	* tree-streamer-in.cc (unpack_ts_decl_common_value_fields): Stream
> 	in new bit decl_not_flexarray.
> 	* tree-streamer-out.cc (pack_ts_decl_common_value_fields): Stream
> 	out new bit decl_not_flexarray.
> 	* tree.cc (array_at_struct_end_p): Update it with the new bit field
> 	decl_not_flexarray.
> 	* tree.h (DECL_NOT_FLEXARRAY): New flag.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/strict-flex-array-1.C: New test.
> 	* 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                            | 130 +++++++++++++++++++--
>   gcc/cp/module.cc                           |   2 +
>   gcc/doc/extend.texi                        |  25 ++++
>   gcc/doc/invoke.texi                        |  27 ++++-
>   gcc/print-tree.cc                          |   8 +-
>   gcc/testsuite/g++.dg/strict-flex-array-1.C |  31 +++++
>   gcc/testsuite/gcc.dg/strict-flex-array-1.c |  31 +++++
>   gcc/tree-core.h                            |   5 +-
>   gcc/tree-streamer-in.cc                    |   1 +
>   gcc/tree-streamer-out.cc                   |   1 +
>   gcc/tree.cc                                |  45 +++++--
>   gcc/tree.h                                 |  14 ++-
>   14 files changed, 346 insertions(+), 28 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-1.C
>   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 8bb80e251dc2..0becd4bbe8d2 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_arrays_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 *);
> @@ -368,6 +370,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_arrays",      1, 1, false, false, false, false,
> +			      handle_strict_flex_arrays_attribute, NULL },
>     { "weak",                   0, 0, true,  false, false, false,
>   			      handle_weak_attribute, NULL },
>     { "noplt",                   0, 0, true,  false, false, false,
> @@ -2505,6 +2509,49 @@ handle_warn_if_not_aligned_attribute (tree *node, tree name,
>   					  no_add_attrs, true);
>   }
>   
> +/* Handle a "strict_flex_arrays" attribute; arguments as in
> +   struct attribute_spec.handler.  */
> +
> +static tree
> +handle_strict_flex_arrays_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 4515664aa590..e053bd939559 100644
> --- a/gcc/c-family/c.opt
> +++ b/gcc/c-family/c.opt
> @@ -2072,6 +2072,13 @@ fsized-deallocation
>   C++ ObjC++ Var(flag_sized_deallocation) Init(-1)
>   Enable C++14 sized deallocation support.
>   
> +fstrict-flex-arrays
> +C C++ Common Alias(fstrict-flex-arrays=,3,0)
> +
> +fstrict-flex-arrays=
> +C C++ Common Joined RejectNegative UInteger Var(flag_strict_flex_arrays) Init(0) IntegerRange(0,3)
> +-fstrict-flex-arrays=<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 34f8feda897f..ee90808bcb0e 100644
> --- a/gcc/c/c-decl.cc
> +++ b/gcc/c/c-decl.cc
> @@ -5005,6 +5005,41 @@ set_array_declarator_inner (struct c_declarator *decl,
>     return decl;
>   }
>   
> +/* Determine whether TYPE is a ISO C99 flexible array memeber type "[]".  */
> +static bool
> +flexible_array_member_type_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 one-element array type "[1]".  */
> +static bool
> +one_element_array_type_p (const_tree type)
> +{
> +  if (TREE_CODE (type) != ARRAY_TYPE)
> +    return false;
> +  return integer_zerop (array_type_nelts (type));
> +}
> +
> +/* Determine whether TYPE is a zero-length array type "[0]".  */
> +static bool
> +zero_length_array_type_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;
> +}
> +
>   /* INIT is a constructor that forms DECL's initializer.  If the final
>      element initializes a flexible array field, add the size of that
>      initializer to DECL's size.  */
> @@ -5019,10 +5054,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_type_p (type))
>       {
>         complete_array_type (&type, elt, false);
>         DECL_SIZE (decl)
> @@ -8710,6 +8742,81 @@ 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_arrays;
> +  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_type_p (TREE_TYPE (x));
> +  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_arrays",
> +						  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;
> +    }
> +
> +  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.
> @@ -8771,6 +8878,11 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
>     bool saw_named_field = false;
>     for (x = fieldlist; x; x = DECL_CHAIN (x))
>       {
> +      /* whether this field is the last field of the structure or union.
> +	 for UNION, any field is the last field of it.  */
> +      bool is_last_field = (DECL_CHAIN (x) == NULL_TREE)
> +			    || (TREE_CODE (t) == UNION_TYPE);
> +
>         if (TREE_TYPE (x) == error_mark_node)
>   	continue;
>   
> @@ -8809,10 +8921,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_type_p (TREE_TYPE (x)))
>   	{
>   	  if (TREE_CODE (t) == UNION_TYPE)
>   	    {
> @@ -8820,7 +8929,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");
> @@ -8840,6 +8949,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/cp/module.cc b/gcc/cp/module.cc
> index f27f4d091e5e..75ee2514f66b 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -5414,6 +5414,7 @@ trees_out::core_bools (tree t)
>         WB (t->decl_common.decl_by_reference_flag);
>         WB (t->decl_common.decl_read_flag);
>         WB (t->decl_common.decl_nonshareable_flag);
> +      WB (t->decl_common.decl_not_flexarray);
>       }
>   
>     if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
> @@ -5558,6 +5559,7 @@ trees_in::core_bools (tree t)
>         RB (t->decl_common.decl_by_reference_flag);
>         RB (t->decl_common.decl_read_flag);
>         RB (t->decl_common.decl_nonshareable_flag);
> +      RB (t->decl_common.decl_not_flexarray);
>       }
>   
>     if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> index 0fedab96610b..62328d77c78c 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -7459,6 +7459,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_arrays} variable attribute
> +@item strict_flex_arrays (@var{level})
> +The @code{strict_flex_arrays} 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 (@samp{[]}), 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 (@samp{[0]}) or one-size
> +array as flexible array member (@samp{[1]}):
> +When @var{level} is 1, the trailing array is treated as a flexible array member
> +when it is declared as either @samp{[]}, @samp{[0]}, or @samp{[1]};
> +When @var{level} is 2, the trailing array is treated as a flexible array member
> +when it is declared as either @samp{[]}, or @samp{[0]}.
> +
> +This attribute can be used with or without the @option{-fstrict-flex-arrays}.
> +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 9d662e353163..db1a68cd545c 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-arrays[=@var{n}] @gol
> +-fsso-struct=@var{endianness}}
>   
>   @item C++ Language Options
>   @xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
> @@ -2826,6 +2827,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-arrays
> +@opindex fstrict-flex-arrays
> +@opindex fno-strict-flex-arrays
> +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-arrays=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-arrays=0}, which is the
> +least strict.  All trailing arrays of structures are treated as flexible array
> +members.
> +
> +@item -fstrict-flex-arrays=@var{level}
> +@opindex fstrict-flex-arrays=@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_arrays} 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_arrays} 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/print-tree.cc b/gcc/print-tree.cc
> index 6d45a4a59669..58a98250cc4f 100644
> --- a/gcc/print-tree.cc
> +++ b/gcc/print-tree.cc
> @@ -517,8 +517,12 @@ print_node (FILE *file, const char *prefix, tree node, int indent,
>   	  fprintf (file, " align:%d warn_if_not_align:%d",
>   		   DECL_ALIGN (node), DECL_WARN_IF_NOT_ALIGN (node));
>   	  if (code == FIELD_DECL)
> -	    fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED,
> -		     DECL_OFFSET_ALIGN (node));
> +	    {
> +	      fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED,
> +		       DECL_OFFSET_ALIGN (node));
> +	      fprintf (file, " decl_not_flexarray: %d",
> +		       DECL_NOT_FLEXARRAY (node));
> +	    }
>   
>   	  if (code == FUNCTION_DECL && fndecl_built_in_p (node))
>   	    {
> diff --git a/gcc/testsuite/g++.dg/strict-flex-array-1.C b/gcc/testsuite/g++.dg/strict-flex-array-1.C
> new file mode 100644
> index 000000000000..cd6a65d2b7e6
> --- /dev/null
> +++ b/gcc/testsuite/g++.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_arrays (1))); /* { dg-error "'strict_flex_arrays' attribute may not be specified for 'x'" } */
> +
> +struct trailing {
> +    int a;
> +    int c __attribute ((strict_flex_arrays)); /* { dg-error "wrong number of arguments specified for 'strict_flex_arrays' attribute" } */
> +};
> +
> +struct trailing_1 {
> +    int a;
> +    int b;
> +    int c __attribute ((strict_flex_arrays (2))); /* { dg-error "'strict_flex_arrays' 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_arrays (d))); /* { dg-error "'strict_flex_arrays' attribute argument not an integer" } */
> +};
> +
> +struct trailing_array_3 {
> +    int a;
> +    int b;
> +    int c[0] __attribute ((strict_flex_arrays (5))); /* { dg-error "'strict_flex_arrays' attribute argument '5' is not an integer constant between 0 and 3" } */
> +};
> 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 000000000000..cd6a65d2b7e6
> --- /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_arrays (1))); /* { dg-error "'strict_flex_arrays' attribute may not be specified for 'x'" } */
> +
> +struct trailing {
> +    int a;
> +    int c __attribute ((strict_flex_arrays)); /* { dg-error "wrong number of arguments specified for 'strict_flex_arrays' attribute" } */
> +};
> +
> +struct trailing_1 {
> +    int a;
> +    int b;
> +    int c __attribute ((strict_flex_arrays (2))); /* { dg-error "'strict_flex_arrays' 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_arrays (d))); /* { dg-error "'strict_flex_arrays' attribute argument not an integer" } */
> +};
> +
> +struct trailing_array_3 {
> +    int a;
> +    int b;
> +    int c[0] __attribute ((strict_flex_arrays (5))); /* { dg-error "'strict_flex_arrays' 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 80c2bcb333dd..18bd6d82a32d 100644
> --- a/gcc/tree-core.h
> +++ b/gcc/tree-core.h
> @@ -1823,7 +1823,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-streamer-in.cc b/gcc/tree-streamer-in.cc
> index 219cf5e7ef45..57923da3741e 100644
> --- a/gcc/tree-streamer-in.cc
> +++ b/gcc/tree-streamer-in.cc
> @@ -261,6 +261,7 @@ unpack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
>         else
>   	SET_DECL_FIELD_ABI_IGNORED (expr, val);
>         expr->decl_common.off_align = bp_unpack_value (bp, 8);
> +      DECL_NOT_FLEXARRAY (expr) = (unsigned) bp_unpack_value (bp, 1);
>       }
>   
>     else if (VAR_P (expr))
> diff --git a/gcc/tree-streamer-out.cc b/gcc/tree-streamer-out.cc
> index 9b114dc05bb1..68a2818a9f93 100644
> --- a/gcc/tree-streamer-out.cc
> +++ b/gcc/tree-streamer-out.cc
> @@ -229,6 +229,7 @@ pack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
>         else
>   	bp_pack_value (bp, DECL_FIELD_ABI_IGNORED (expr), 1);
>         bp_pack_value (bp, expr->decl_common.off_align, 8);
> +      bp_pack_value (bp, DECL_NOT_FLEXARRAY (expr), 1);
>       }
>   
>     else if (VAR_P (expr))
> diff --git a/gcc/tree.cc b/gcc/tree.cc
> index 2f488e4467c4..e4664eab54ef 100644
> --- a/gcc/tree.cc
> +++ b/gcc/tree.cc
> @@ -12688,14 +12688,30 @@ array_ref_up_bound (tree exp)
>   }
>   
>   /* Returns true if REF is an array reference, component reference,
> -   or memory reference to an array at the end of a structure.
> -   If this is the case, the array may be allocated larger
> -   than its upper bound implies.  */
> +   or memory reference to an array whose actual size might be larger
> +   than its upper bound implies, there are multiple cases:
> +   A. a ref to a flexible array member at the end of a structure;
> +   B. a ref to an array with a different type against the original decl;
> +      for example:
>   
> +   short a[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
> +   (*((char(*)[16])&a[0]))[i+8]
> +
> +   C. a ref to an array that was passed as a parameter;
> +      for example:
> +
> +   int test (uint8_t *p, uint32_t t[1][1], int n) {
> +   for (int i = 0; i < 4; i++, p++)
> +     t[i][0] = ...;
> +
> +   FIXME, the name of this routine need to be changed to be more accurate.  */
>   bool
>   array_at_struct_end_p (tree ref)
>   {
> -  tree atype;
> +  /* the TYPE for this array referece.  */
> +  tree atype = NULL_TREE;
> +  /* the FIELD_DECL for the array field in the containing structure.  */
> +  tree afield_decl = NULL_TREE;
>   
>     if (TREE_CODE (ref) == ARRAY_REF
>         || TREE_CODE (ref) == ARRAY_RANGE_REF)
> @@ -12705,7 +12721,10 @@ array_at_struct_end_p (tree ref)
>       }
>     else if (TREE_CODE (ref) == COMPONENT_REF
>   	   && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 1))) == ARRAY_TYPE)
> -    atype = TREE_TYPE (TREE_OPERAND (ref, 1));
> +    {
> +      atype = TREE_TYPE (TREE_OPERAND (ref, 1));
> +      afield_decl = TREE_OPERAND (ref, 1);
> +    }
>     else if (TREE_CODE (ref) == MEM_REF)
>       {
>         tree arg = TREE_OPERAND (ref, 0);
> @@ -12717,6 +12736,7 @@ array_at_struct_end_p (tree ref)
>   	  if (tree fld = last_field (argtype))
>   	    {
>   	      atype = TREE_TYPE (fld);
> +	      afield_decl = fld;
>   	      if (TREE_CODE (atype) != ARRAY_TYPE)
>   		return false;
>   	      if (VAR_P (arg) && DECL_SIZE (fld))
> @@ -12770,13 +12790,16 @@ array_at_struct_end_p (tree ref)
>         ref = TREE_OPERAND (ref, 0);
>       }
>   
> -  /* The array now is at struct end.  Treat flexible arrays as
> +  gcc_assert (!afield_decl
> +	      || (afield_decl && TREE_CODE (afield_decl) == FIELD_DECL));
> +
> +  /* The array now is at struct end.  Treat flexible array member as
>        always subject to extend, even into just padding constrained by
>        an underlying decl.  */
>     if (! TYPE_SIZE (atype)
>         || ! TYPE_DOMAIN (atype)
>         || ! TYPE_MAX_VALUE (TYPE_DOMAIN (atype)))
> -    return true;
> +    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).  */
> @@ -12798,9 +12821,9 @@ array_at_struct_end_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 true;
> +	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>         if (! get_addr_base_and_unit_offset (ref_to_array, &offset))
> -	return true;
> +	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)))
> @@ -12808,12 +12831,12 @@ array_at_struct_end_p (tree ref)
>   		     + 2)
>   		    * wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (atype))),
>   		    wi::to_offset (DECL_SIZE_UNIT (ref)) - offset))
> -	return true;
> +	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>   
>         return false;
>       }
>   
> -  return true;
> +  return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>   }
>   
>   /* Return a tree representing the offset, in bytes, of the field referenced
> diff --git a/gcc/tree.h b/gcc/tree.h
> index 266e24a05633..81076b045003 100644
> --- a/gcc/tree.h
> +++ b/gcc/tree.h
> @@ -3005,6 +3005,12 @@ 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. This is only valid for the last array type field of a
> +   structure.  */
> +#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.  */
> @@ -5543,10 +5549,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


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [GCC13][Patch][V4][PATCH 1/2] Add a new option -fstrict-flex-arrays[=n] and new attribute strict_flex_arrays
  2022-09-12 16:42   ` Martin Sebor
@ 2022-09-28 19:17     ` Qing Zhao
  2022-09-30 17:39       ` Martin Sebor
  0 siblings, 1 reply; 7+ messages in thread
From: Qing Zhao @ 2022-09-28 19:17 UTC (permalink / raw)
  To: Martin Sebor; +Cc: gcc-patches, Richard Biener, jakub, keescook, joseph

Hi, Martin,

Thanks for the comments. And sorry for my late reply till now (I just came back home from LPC, GNU Cauldron and then a one-week vacation after that…)

> On Sep 12, 2022, at 12:42 PM, Martin Sebor <msebor@gmail.com> wrote:
> 
> On 9/6/22 18:28, Qing Zhao wrote:
>> Add the following new option -fstrict-flex-arrays[=n] and a corresponding
>> attribute strict_flex_arrays to GCC:
>> '-fstrict-flex-arrays'
>>      Treat the trailing array of a structure as a flexible array member
>>      in a stricter way.
> 
> A minor problem with this phrasing was pointed out in the review
> of the Clang option: https://reviews.llvm.org/D126864#inline-1282716
> It would be good to avoid it here.
Yes, I agree.

>  (I think qualifying the sentence
> by adding "for the purposes of accessing the elements of such arrays"
> might be one way to do it).

How about:

'-fstrict-flex-arrays’
     Treat the trailing array of a structure as a variable-length array
      in a stricter way.
?

> 
>> The positive form is equivalent to
>>      '-fstrict-flex-arrays=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-arrays=0', which is the least
>>      strict.  All trailing arrays of structures are treated as flexible
>>      array members.
>> '-fstrict-flex-arrays=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_arrays' 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_arrays'
>>      attribute (*note Variable Attributes::).
>> 'strict_flex_arrays (LEVEL)'
>>      The 'strict_flex_arrays' 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.
> 
> 
> Since the attribute applies to just a single array declaration it
> seems that its name should be strict_flex_array (i.e., singular,
> without the trailing 's').

Will make the change as you suggested.

Thanks.

Qing
> 
> Martin
> 
>>      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 the
>>      '-fstrict-flex-arrays'.  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_arrays_attribute): New function.
>> 	(c_common_attribute_table): New item for strict_flex_arrays.
>> 	* c.opt: (fstrict-flex-arrays): New option.
>> 	(fstrict-flex-arrays=): New option.
>> gcc/c/ChangeLog:
>> 	* c-decl.cc (flexible_array_member_type_p): New function.
>> 	(one_element_array_type_p): Likewise.
>> 	(zero_length_array_type_p): Likewise.
>> 	(add_flexible_array_elts_to_size): Call new utility
>> 	routine flexible_array_member_type_p.
>> 	(is_flexible_array_member_p): New function.
>> 	(finish_struct): Set the new DECL_NOT_FLEXARRAY flag.
>> gcc/cp/ChangeLog:
>> 	* module.cc (trees_out::core_bools): Stream out new bit
>> 	decl_not_flexarray.
>> 	(trees_in::core_bools): Stream in new bit decl_not_flexarray.
>> gcc/ChangeLog:
>> 	* doc/extend.texi: Document strict_flex_arrays attribute.
>> 	* doc/invoke.texi: Document -fstrict-flex-arrays[=n] option.
>> 	* print-tree.cc (print_node): Print new bit decl_not_flexarray.
>> 	* tree-core.h (struct tree_decl_common): New bit field
>> 	decl_not_flexarray.
>> 	* tree-streamer-in.cc (unpack_ts_decl_common_value_fields): Stream
>> 	in new bit decl_not_flexarray.
>> 	* tree-streamer-out.cc (pack_ts_decl_common_value_fields): Stream
>> 	out new bit decl_not_flexarray.
>> 	* tree.cc (array_at_struct_end_p): Update it with the new bit field
>> 	decl_not_flexarray.
>> 	* tree.h (DECL_NOT_FLEXARRAY): New flag.
>> gcc/testsuite/ChangeLog:
>> 	* g++.dg/strict-flex-array-1.C: New test.
>> 	* 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                            | 130 +++++++++++++++++++--
>>  gcc/cp/module.cc                           |   2 +
>>  gcc/doc/extend.texi                        |  25 ++++
>>  gcc/doc/invoke.texi                        |  27 ++++-
>>  gcc/print-tree.cc                          |   8 +-
>>  gcc/testsuite/g++.dg/strict-flex-array-1.C |  31 +++++
>>  gcc/testsuite/gcc.dg/strict-flex-array-1.c |  31 +++++
>>  gcc/tree-core.h                            |   5 +-
>>  gcc/tree-streamer-in.cc                    |   1 +
>>  gcc/tree-streamer-out.cc                   |   1 +
>>  gcc/tree.cc                                |  45 +++++--
>>  gcc/tree.h                                 |  14 ++-
>>  14 files changed, 346 insertions(+), 28 deletions(-)
>>  create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-1.C
>>  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 8bb80e251dc2..0becd4bbe8d2 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_arrays_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 *);
>> @@ -368,6 +370,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_arrays",      1, 1, false, false, false, false,
>> +			      handle_strict_flex_arrays_attribute, NULL },
>>    { "weak",                   0, 0, true,  false, false, false,
>>  			      handle_weak_attribute, NULL },
>>    { "noplt",                   0, 0, true,  false, false, false,
>> @@ -2505,6 +2509,49 @@ handle_warn_if_not_aligned_attribute (tree *node, tree name,
>>  					  no_add_attrs, true);
>>  }
>>  +/* Handle a "strict_flex_arrays" attribute; arguments as in
>> +   struct attribute_spec.handler.  */
>> +
>> +static tree
>> +handle_strict_flex_arrays_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 4515664aa590..e053bd939559 100644
>> --- a/gcc/c-family/c.opt
>> +++ b/gcc/c-family/c.opt
>> @@ -2072,6 +2072,13 @@ fsized-deallocation
>>  C++ ObjC++ Var(flag_sized_deallocation) Init(-1)
>>  Enable C++14 sized deallocation support.
>>  +fstrict-flex-arrays
>> +C C++ Common Alias(fstrict-flex-arrays=,3,0)
>> +
>> +fstrict-flex-arrays=
>> +C C++ Common Joined RejectNegative UInteger Var(flag_strict_flex_arrays) Init(0) IntegerRange(0,3)
>> +-fstrict-flex-arrays=<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 34f8feda897f..ee90808bcb0e 100644
>> --- a/gcc/c/c-decl.cc
>> +++ b/gcc/c/c-decl.cc
>> @@ -5005,6 +5005,41 @@ set_array_declarator_inner (struct c_declarator *decl,
>>    return decl;
>>  }
>>  +/* Determine whether TYPE is a ISO C99 flexible array memeber type "[]".  */
>> +static bool
>> +flexible_array_member_type_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 one-element array type "[1]".  */
>> +static bool
>> +one_element_array_type_p (const_tree type)
>> +{
>> +  if (TREE_CODE (type) != ARRAY_TYPE)
>> +    return false;
>> +  return integer_zerop (array_type_nelts (type));
>> +}
>> +
>> +/* Determine whether TYPE is a zero-length array type "[0]".  */
>> +static bool
>> +zero_length_array_type_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;
>> +}
>> +
>>  /* INIT is a constructor that forms DECL's initializer.  If the final
>>     element initializes a flexible array field, add the size of that
>>     initializer to DECL's size.  */
>> @@ -5019,10 +5054,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_type_p (type))
>>      {
>>        complete_array_type (&type, elt, false);
>>        DECL_SIZE (decl)
>> @@ -8710,6 +8742,81 @@ 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_arrays;
>> +  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_type_p (TREE_TYPE (x));
>> +  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_arrays",
>> +						  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;
>> +    }
>> +
>> +  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.
>> @@ -8771,6 +8878,11 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
>>    bool saw_named_field = false;
>>    for (x = fieldlist; x; x = DECL_CHAIN (x))
>>      {
>> +      /* whether this field is the last field of the structure or union.
>> +	 for UNION, any field is the last field of it.  */
>> +      bool is_last_field = (DECL_CHAIN (x) == NULL_TREE)
>> +			    || (TREE_CODE (t) == UNION_TYPE);
>> +
>>        if (TREE_TYPE (x) == error_mark_node)
>>  	continue;
>>  @@ -8809,10 +8921,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_type_p (TREE_TYPE (x)))
>>  	{
>>  	  if (TREE_CODE (t) == UNION_TYPE)
>>  	    {
>> @@ -8820,7 +8929,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");
>> @@ -8840,6 +8949,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/cp/module.cc b/gcc/cp/module.cc
>> index f27f4d091e5e..75ee2514f66b 100644
>> --- a/gcc/cp/module.cc
>> +++ b/gcc/cp/module.cc
>> @@ -5414,6 +5414,7 @@ trees_out::core_bools (tree t)
>>        WB (t->decl_common.decl_by_reference_flag);
>>        WB (t->decl_common.decl_read_flag);
>>        WB (t->decl_common.decl_nonshareable_flag);
>> +      WB (t->decl_common.decl_not_flexarray);
>>      }
>>      if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
>> @@ -5558,6 +5559,7 @@ trees_in::core_bools (tree t)
>>        RB (t->decl_common.decl_by_reference_flag);
>>        RB (t->decl_common.decl_read_flag);
>>        RB (t->decl_common.decl_nonshareable_flag);
>> +      RB (t->decl_common.decl_not_flexarray);
>>      }
>>      if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
>> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
>> index 0fedab96610b..62328d77c78c 100644
>> --- a/gcc/doc/extend.texi
>> +++ b/gcc/doc/extend.texi
>> @@ -7459,6 +7459,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_arrays} variable attribute
>> +@item strict_flex_arrays (@var{level})
>> +The @code{strict_flex_arrays} 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 (@samp{[]}), 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 (@samp{[0]}) or one-size
>> +array as flexible array member (@samp{[1]}):
>> +When @var{level} is 1, the trailing array is treated as a flexible array member
>> +when it is declared as either @samp{[]}, @samp{[0]}, or @samp{[1]};
>> +When @var{level} is 2, the trailing array is treated as a flexible array member
>> +when it is declared as either @samp{[]}, or @samp{[0]}.
>> +
>> +This attribute can be used with or without the @option{-fstrict-flex-arrays}.
>> +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 9d662e353163..db1a68cd545c 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-arrays[=@var{n}] @gol
>> +-fsso-struct=@var{endianness}}
>>    @item C++ Language Options
>>  @xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
>> @@ -2826,6 +2827,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-arrays
>> +@opindex fstrict-flex-arrays
>> +@opindex fno-strict-flex-arrays
>> +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-arrays=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-arrays=0}, which is the
>> +least strict.  All trailing arrays of structures are treated as flexible array
>> +members.
>> +
>> +@item -fstrict-flex-arrays=@var{level}
>> +@opindex fstrict-flex-arrays=@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_arrays} 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_arrays} 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/print-tree.cc b/gcc/print-tree.cc
>> index 6d45a4a59669..58a98250cc4f 100644
>> --- a/gcc/print-tree.cc
>> +++ b/gcc/print-tree.cc
>> @@ -517,8 +517,12 @@ print_node (FILE *file, const char *prefix, tree node, int indent,
>>  	  fprintf (file, " align:%d warn_if_not_align:%d",
>>  		   DECL_ALIGN (node), DECL_WARN_IF_NOT_ALIGN (node));
>>  	  if (code == FIELD_DECL)
>> -	    fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED,
>> -		     DECL_OFFSET_ALIGN (node));
>> +	    {
>> +	      fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED,
>> +		       DECL_OFFSET_ALIGN (node));
>> +	      fprintf (file, " decl_not_flexarray: %d",
>> +		       DECL_NOT_FLEXARRAY (node));
>> +	    }
>>    	  if (code == FUNCTION_DECL && fndecl_built_in_p (node))
>>  	    {
>> diff --git a/gcc/testsuite/g++.dg/strict-flex-array-1.C b/gcc/testsuite/g++.dg/strict-flex-array-1.C
>> new file mode 100644
>> index 000000000000..cd6a65d2b7e6
>> --- /dev/null
>> +++ b/gcc/testsuite/g++.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_arrays (1))); /* { dg-error "'strict_flex_arrays' attribute may not be specified for 'x'" } */
>> +
>> +struct trailing {
>> +    int a;
>> +    int c __attribute ((strict_flex_arrays)); /* { dg-error "wrong number of arguments specified for 'strict_flex_arrays' attribute" } */
>> +};
>> +
>> +struct trailing_1 {
>> +    int a;
>> +    int b;
>> +    int c __attribute ((strict_flex_arrays (2))); /* { dg-error "'strict_flex_arrays' 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_arrays (d))); /* { dg-error "'strict_flex_arrays' attribute argument not an integer" } */
>> +};
>> +
>> +struct trailing_array_3 {
>> +    int a;
>> +    int b;
>> +    int c[0] __attribute ((strict_flex_arrays (5))); /* { dg-error "'strict_flex_arrays' attribute argument '5' is not an integer constant between 0 and 3" } */
>> +};
>> 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 000000000000..cd6a65d2b7e6
>> --- /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_arrays (1))); /* { dg-error "'strict_flex_arrays' attribute may not be specified for 'x'" } */
>> +
>> +struct trailing {
>> +    int a;
>> +    int c __attribute ((strict_flex_arrays)); /* { dg-error "wrong number of arguments specified for 'strict_flex_arrays' attribute" } */
>> +};
>> +
>> +struct trailing_1 {
>> +    int a;
>> +    int b;
>> +    int c __attribute ((strict_flex_arrays (2))); /* { dg-error "'strict_flex_arrays' 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_arrays (d))); /* { dg-error "'strict_flex_arrays' attribute argument not an integer" } */
>> +};
>> +
>> +struct trailing_array_3 {
>> +    int a;
>> +    int b;
>> +    int c[0] __attribute ((strict_flex_arrays (5))); /* { dg-error "'strict_flex_arrays' 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 80c2bcb333dd..18bd6d82a32d 100644
>> --- a/gcc/tree-core.h
>> +++ b/gcc/tree-core.h
>> @@ -1823,7 +1823,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-streamer-in.cc b/gcc/tree-streamer-in.cc
>> index 219cf5e7ef45..57923da3741e 100644
>> --- a/gcc/tree-streamer-in.cc
>> +++ b/gcc/tree-streamer-in.cc
>> @@ -261,6 +261,7 @@ unpack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
>>        else
>>  	SET_DECL_FIELD_ABI_IGNORED (expr, val);
>>        expr->decl_common.off_align = bp_unpack_value (bp, 8);
>> +      DECL_NOT_FLEXARRAY (expr) = (unsigned) bp_unpack_value (bp, 1);
>>      }
>>      else if (VAR_P (expr))
>> diff --git a/gcc/tree-streamer-out.cc b/gcc/tree-streamer-out.cc
>> index 9b114dc05bb1..68a2818a9f93 100644
>> --- a/gcc/tree-streamer-out.cc
>> +++ b/gcc/tree-streamer-out.cc
>> @@ -229,6 +229,7 @@ pack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
>>        else
>>  	bp_pack_value (bp, DECL_FIELD_ABI_IGNORED (expr), 1);
>>        bp_pack_value (bp, expr->decl_common.off_align, 8);
>> +      bp_pack_value (bp, DECL_NOT_FLEXARRAY (expr), 1);
>>      }
>>      else if (VAR_P (expr))
>> diff --git a/gcc/tree.cc b/gcc/tree.cc
>> index 2f488e4467c4..e4664eab54ef 100644
>> --- a/gcc/tree.cc
>> +++ b/gcc/tree.cc
>> @@ -12688,14 +12688,30 @@ array_ref_up_bound (tree exp)
>>  }
>>    /* Returns true if REF is an array reference, component reference,
>> -   or memory reference to an array at the end of a structure.
>> -   If this is the case, the array may be allocated larger
>> -   than its upper bound implies.  */
>> +   or memory reference to an array whose actual size might be larger
>> +   than its upper bound implies, there are multiple cases:
>> +   A. a ref to a flexible array member at the end of a structure;
>> +   B. a ref to an array with a different type against the original decl;
>> +      for example:
>>  +   short a[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
>> +   (*((char(*)[16])&a[0]))[i+8]
>> +
>> +   C. a ref to an array that was passed as a parameter;
>> +      for example:
>> +
>> +   int test (uint8_t *p, uint32_t t[1][1], int n) {
>> +   for (int i = 0; i < 4; i++, p++)
>> +     t[i][0] = ...;
>> +
>> +   FIXME, the name of this routine need to be changed to be more accurate.  */
>>  bool
>>  array_at_struct_end_p (tree ref)
>>  {
>> -  tree atype;
>> +  /* the TYPE for this array referece.  */
>> +  tree atype = NULL_TREE;
>> +  /* the FIELD_DECL for the array field in the containing structure.  */
>> +  tree afield_decl = NULL_TREE;
>>      if (TREE_CODE (ref) == ARRAY_REF
>>        || TREE_CODE (ref) == ARRAY_RANGE_REF)
>> @@ -12705,7 +12721,10 @@ array_at_struct_end_p (tree ref)
>>      }
>>    else if (TREE_CODE (ref) == COMPONENT_REF
>>  	   && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 1))) == ARRAY_TYPE)
>> -    atype = TREE_TYPE (TREE_OPERAND (ref, 1));
>> +    {
>> +      atype = TREE_TYPE (TREE_OPERAND (ref, 1));
>> +      afield_decl = TREE_OPERAND (ref, 1);
>> +    }
>>    else if (TREE_CODE (ref) == MEM_REF)
>>      {
>>        tree arg = TREE_OPERAND (ref, 0);
>> @@ -12717,6 +12736,7 @@ array_at_struct_end_p (tree ref)
>>  	  if (tree fld = last_field (argtype))
>>  	    {
>>  	      atype = TREE_TYPE (fld);
>> +	      afield_decl = fld;
>>  	      if (TREE_CODE (atype) != ARRAY_TYPE)
>>  		return false;
>>  	      if (VAR_P (arg) && DECL_SIZE (fld))
>> @@ -12770,13 +12790,16 @@ array_at_struct_end_p (tree ref)
>>        ref = TREE_OPERAND (ref, 0);
>>      }
>>  -  /* The array now is at struct end.  Treat flexible arrays as
>> +  gcc_assert (!afield_decl
>> +	      || (afield_decl && TREE_CODE (afield_decl) == FIELD_DECL));
>> +
>> +  /* The array now is at struct end.  Treat flexible array member as
>>       always subject to extend, even into just padding constrained by
>>       an underlying decl.  */
>>    if (! TYPE_SIZE (atype)
>>        || ! TYPE_DOMAIN (atype)
>>        || ! TYPE_MAX_VALUE (TYPE_DOMAIN (atype)))
>> -    return true;
>> +    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).  */
>> @@ -12798,9 +12821,9 @@ array_at_struct_end_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 true;
>> +	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>>        if (! get_addr_base_and_unit_offset (ref_to_array, &offset))
>> -	return true;
>> +	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)))
>> @@ -12808,12 +12831,12 @@ array_at_struct_end_p (tree ref)
>>  		     + 2)
>>  		    * wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (atype))),
>>  		    wi::to_offset (DECL_SIZE_UNIT (ref)) - offset))
>> -	return true;
>> +	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>>          return false;
>>      }
>>  -  return true;
>> +  return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>>  }
>>    /* Return a tree representing the offset, in bytes, of the field referenced
>> diff --git a/gcc/tree.h b/gcc/tree.h
>> index 266e24a05633..81076b045003 100644
>> --- a/gcc/tree.h
>> +++ b/gcc/tree.h
>> @@ -3005,6 +3005,12 @@ 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. This is only valid for the last array type field of a
>> +   structure.  */
>> +#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.  */
>> @@ -5543,10 +5549,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


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [GCC13][Patch][V4][PATCH 1/2] Add a new option -fstrict-flex-arrays[=n] and new attribute strict_flex_arrays
  2022-09-28 19:17     ` Qing Zhao
@ 2022-09-30 17:39       ` Martin Sebor
  2022-10-03 15:20         ` Qing Zhao
  0 siblings, 1 reply; 7+ messages in thread
From: Martin Sebor @ 2022-09-30 17:39 UTC (permalink / raw)
  To: Qing Zhao; +Cc: gcc-patches, Richard Biener, jakub, keescook, joseph

On 9/28/22 13:17, Qing Zhao wrote:
> Hi, Martin,
> 
> Thanks for the comments. And sorry for my late reply till now (I just came back home from LPC, GNU Cauldron and then a one-week vacation after that…)
> 
>> On Sep 12, 2022, at 12:42 PM, Martin Sebor <msebor@gmail.com> wrote:
>>
>> On 9/6/22 18:28, Qing Zhao wrote:
>>> Add the following new option -fstrict-flex-arrays[=n] and a corresponding
>>> attribute strict_flex_arrays to GCC:
>>> '-fstrict-flex-arrays'
>>>       Treat the trailing array of a structure as a flexible array member
>>>       in a stricter way.
>>
>> A minor problem with this phrasing was pointed out in the review
>> of the Clang option: https://reviews.llvm.org/D126864#inline-1282716
>> It would be good to avoid it here.
> Yes, I agree.
> 
>>   (I think qualifying the sentence
>> by adding "for the purposes of accessing the elements of such arrays"
>> might be one way to do it).
> 
> How about:
> 
> '-fstrict-flex-arrays’
>       Treat the trailing array of a structure as a variable-length array
>        in a stricter way.
> ?

I don't think talking about variable length arrays in this context
would be appropriate (they're a different thing).  The concern in
the review above was that the a in something like

   struct { int n, a[1]; } s;

is treated as a flexible array member only for the purposes of
accessing a's elements, but not also in a sizeof expression, for
instance.  sizeof s.a is 1 regardless of the -fstrict-flex-arrays
argument, but if s.a were considered a flexible array member then
sizeof s.a would a constraint violation.  Similarly, if s.a were
treated as a FAM the definition of s would pedantically speaking
be invalid, and s's size would be equal to sizeof (int) because
GCC accepts the defintion but adds no padding.

One way to avoid implying that might be qualifying the description
with what I suggested above:

   Control when to treat the trailing array of a structure as
   a flexible array member for the purposes of accessing
   the elements of such an array.

But I'm sure there are better ways to put it.

In addition, it should probably also be made clear whether this
stays the same when an object of such a structure is itself
a subobject of another aggregate (array or struct).  E.g.,

   struct A { int n, a[1]; };
   struct A a[2];                       // is a.a treated as a FAM?
   struct B { struct A a; } b;          // is b.a.a treated as a FAM?
   struct C { struct A a; int i; } c;   // how about c.a.a?

Finally, and with the caveat that I haven't been very close
attention to the GCC patches so this may not be an issue, but I have
the impression that the decision in Clang is to let -Warray-bounds
trigger (at least somewhat) independently of -fstrict-flex-arrays.
The goal is to make it possible to diagnose misuses without causing
runtime errors.  This has also been the historical GCC behavior that
I think it should be maintained going forward.

Martin

> 
>>
>>> The positive form is equivalent to
>>>       '-fstrict-flex-arrays=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-arrays=0', which is the least
>>>       strict.  All trailing arrays of structures are treated as flexible
>>>       array members.
>>> '-fstrict-flex-arrays=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_arrays' 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_arrays'
>>>       attribute (*note Variable Attributes::).
>>> 'strict_flex_arrays (LEVEL)'
>>>       The 'strict_flex_arrays' 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.
>>
>>
>> Since the attribute applies to just a single array declaration it
>> seems that its name should be strict_flex_array (i.e., singular,
>> without the trailing 's').
> 
> Will make the change as you suggested.
> 
> Thanks.
> 
> Qing
>>
>> Martin
>>
>>>       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 the
>>>       '-fstrict-flex-arrays'.  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_arrays_attribute): New function.
>>> 	(c_common_attribute_table): New item for strict_flex_arrays.
>>> 	* c.opt: (fstrict-flex-arrays): New option.
>>> 	(fstrict-flex-arrays=): New option.
>>> gcc/c/ChangeLog:
>>> 	* c-decl.cc (flexible_array_member_type_p): New function.
>>> 	(one_element_array_type_p): Likewise.
>>> 	(zero_length_array_type_p): Likewise.
>>> 	(add_flexible_array_elts_to_size): Call new utility
>>> 	routine flexible_array_member_type_p.
>>> 	(is_flexible_array_member_p): New function.
>>> 	(finish_struct): Set the new DECL_NOT_FLEXARRAY flag.
>>> gcc/cp/ChangeLog:
>>> 	* module.cc (trees_out::core_bools): Stream out new bit
>>> 	decl_not_flexarray.
>>> 	(trees_in::core_bools): Stream in new bit decl_not_flexarray.
>>> gcc/ChangeLog:
>>> 	* doc/extend.texi: Document strict_flex_arrays attribute.
>>> 	* doc/invoke.texi: Document -fstrict-flex-arrays[=n] option.
>>> 	* print-tree.cc (print_node): Print new bit decl_not_flexarray.
>>> 	* tree-core.h (struct tree_decl_common): New bit field
>>> 	decl_not_flexarray.
>>> 	* tree-streamer-in.cc (unpack_ts_decl_common_value_fields): Stream
>>> 	in new bit decl_not_flexarray.
>>> 	* tree-streamer-out.cc (pack_ts_decl_common_value_fields): Stream
>>> 	out new bit decl_not_flexarray.
>>> 	* tree.cc (array_at_struct_end_p): Update it with the new bit field
>>> 	decl_not_flexarray.
>>> 	* tree.h (DECL_NOT_FLEXARRAY): New flag.
>>> gcc/testsuite/ChangeLog:
>>> 	* g++.dg/strict-flex-array-1.C: New test.
>>> 	* 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                            | 130 +++++++++++++++++++--
>>>   gcc/cp/module.cc                           |   2 +
>>>   gcc/doc/extend.texi                        |  25 ++++
>>>   gcc/doc/invoke.texi                        |  27 ++++-
>>>   gcc/print-tree.cc                          |   8 +-
>>>   gcc/testsuite/g++.dg/strict-flex-array-1.C |  31 +++++
>>>   gcc/testsuite/gcc.dg/strict-flex-array-1.c |  31 +++++
>>>   gcc/tree-core.h                            |   5 +-
>>>   gcc/tree-streamer-in.cc                    |   1 +
>>>   gcc/tree-streamer-out.cc                   |   1 +
>>>   gcc/tree.cc                                |  45 +++++--
>>>   gcc/tree.h                                 |  14 ++-
>>>   14 files changed, 346 insertions(+), 28 deletions(-)
>>>   create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-1.C
>>>   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 8bb80e251dc2..0becd4bbe8d2 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_arrays_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 *);
>>> @@ -368,6 +370,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_arrays",      1, 1, false, false, false, false,
>>> +			      handle_strict_flex_arrays_attribute, NULL },
>>>     { "weak",                   0, 0, true,  false, false, false,
>>>   			      handle_weak_attribute, NULL },
>>>     { "noplt",                   0, 0, true,  false, false, false,
>>> @@ -2505,6 +2509,49 @@ handle_warn_if_not_aligned_attribute (tree *node, tree name,
>>>   					  no_add_attrs, true);
>>>   }
>>>   +/* Handle a "strict_flex_arrays" attribute; arguments as in
>>> +   struct attribute_spec.handler.  */
>>> +
>>> +static tree
>>> +handle_strict_flex_arrays_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 4515664aa590..e053bd939559 100644
>>> --- a/gcc/c-family/c.opt
>>> +++ b/gcc/c-family/c.opt
>>> @@ -2072,6 +2072,13 @@ fsized-deallocation
>>>   C++ ObjC++ Var(flag_sized_deallocation) Init(-1)
>>>   Enable C++14 sized deallocation support.
>>>   +fstrict-flex-arrays
>>> +C C++ Common Alias(fstrict-flex-arrays=,3,0)
>>> +
>>> +fstrict-flex-arrays=
>>> +C C++ Common Joined RejectNegative UInteger Var(flag_strict_flex_arrays) Init(0) IntegerRange(0,3)
>>> +-fstrict-flex-arrays=<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 34f8feda897f..ee90808bcb0e 100644
>>> --- a/gcc/c/c-decl.cc
>>> +++ b/gcc/c/c-decl.cc
>>> @@ -5005,6 +5005,41 @@ set_array_declarator_inner (struct c_declarator *decl,
>>>     return decl;
>>>   }
>>>   +/* Determine whether TYPE is a ISO C99 flexible array memeber type "[]".  */
>>> +static bool
>>> +flexible_array_member_type_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 one-element array type "[1]".  */
>>> +static bool
>>> +one_element_array_type_p (const_tree type)
>>> +{
>>> +  if (TREE_CODE (type) != ARRAY_TYPE)
>>> +    return false;
>>> +  return integer_zerop (array_type_nelts (type));
>>> +}
>>> +
>>> +/* Determine whether TYPE is a zero-length array type "[0]".  */
>>> +static bool
>>> +zero_length_array_type_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;
>>> +}
>>> +
>>>   /* INIT is a constructor that forms DECL's initializer.  If the final
>>>      element initializes a flexible array field, add the size of that
>>>      initializer to DECL's size.  */
>>> @@ -5019,10 +5054,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_type_p (type))
>>>       {
>>>         complete_array_type (&type, elt, false);
>>>         DECL_SIZE (decl)
>>> @@ -8710,6 +8742,81 @@ 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_arrays;
>>> +  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_type_p (TREE_TYPE (x));
>>> +  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_arrays",
>>> +						  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;
>>> +    }
>>> +
>>> +  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.
>>> @@ -8771,6 +8878,11 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
>>>     bool saw_named_field = false;
>>>     for (x = fieldlist; x; x = DECL_CHAIN (x))
>>>       {
>>> +      /* whether this field is the last field of the structure or union.
>>> +	 for UNION, any field is the last field of it.  */
>>> +      bool is_last_field = (DECL_CHAIN (x) == NULL_TREE)
>>> +			    || (TREE_CODE (t) == UNION_TYPE);
>>> +
>>>         if (TREE_TYPE (x) == error_mark_node)
>>>   	continue;
>>>   @@ -8809,10 +8921,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_type_p (TREE_TYPE (x)))
>>>   	{
>>>   	  if (TREE_CODE (t) == UNION_TYPE)
>>>   	    {
>>> @@ -8820,7 +8929,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");
>>> @@ -8840,6 +8949,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/cp/module.cc b/gcc/cp/module.cc
>>> index f27f4d091e5e..75ee2514f66b 100644
>>> --- a/gcc/cp/module.cc
>>> +++ b/gcc/cp/module.cc
>>> @@ -5414,6 +5414,7 @@ trees_out::core_bools (tree t)
>>>         WB (t->decl_common.decl_by_reference_flag);
>>>         WB (t->decl_common.decl_read_flag);
>>>         WB (t->decl_common.decl_nonshareable_flag);
>>> +      WB (t->decl_common.decl_not_flexarray);
>>>       }
>>>       if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
>>> @@ -5558,6 +5559,7 @@ trees_in::core_bools (tree t)
>>>         RB (t->decl_common.decl_by_reference_flag);
>>>         RB (t->decl_common.decl_read_flag);
>>>         RB (t->decl_common.decl_nonshareable_flag);
>>> +      RB (t->decl_common.decl_not_flexarray);
>>>       }
>>>       if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
>>> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
>>> index 0fedab96610b..62328d77c78c 100644
>>> --- a/gcc/doc/extend.texi
>>> +++ b/gcc/doc/extend.texi
>>> @@ -7459,6 +7459,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_arrays} variable attribute
>>> +@item strict_flex_arrays (@var{level})
>>> +The @code{strict_flex_arrays} 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 (@samp{[]}), 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 (@samp{[0]}) or one-size
>>> +array as flexible array member (@samp{[1]}):
>>> +When @var{level} is 1, the trailing array is treated as a flexible array member
>>> +when it is declared as either @samp{[]}, @samp{[0]}, or @samp{[1]};
>>> +When @var{level} is 2, the trailing array is treated as a flexible array member
>>> +when it is declared as either @samp{[]}, or @samp{[0]}.
>>> +
>>> +This attribute can be used with or without the @option{-fstrict-flex-arrays}.
>>> +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 9d662e353163..db1a68cd545c 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-arrays[=@var{n}] @gol
>>> +-fsso-struct=@var{endianness}}
>>>     @item C++ Language Options
>>>   @xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
>>> @@ -2826,6 +2827,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-arrays
>>> +@opindex fstrict-flex-arrays
>>> +@opindex fno-strict-flex-arrays
>>> +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-arrays=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-arrays=0}, which is the
>>> +least strict.  All trailing arrays of structures are treated as flexible array
>>> +members.
>>> +
>>> +@item -fstrict-flex-arrays=@var{level}
>>> +@opindex fstrict-flex-arrays=@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_arrays} 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_arrays} 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/print-tree.cc b/gcc/print-tree.cc
>>> index 6d45a4a59669..58a98250cc4f 100644
>>> --- a/gcc/print-tree.cc
>>> +++ b/gcc/print-tree.cc
>>> @@ -517,8 +517,12 @@ print_node (FILE *file, const char *prefix, tree node, int indent,
>>>   	  fprintf (file, " align:%d warn_if_not_align:%d",
>>>   		   DECL_ALIGN (node), DECL_WARN_IF_NOT_ALIGN (node));
>>>   	  if (code == FIELD_DECL)
>>> -	    fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED,
>>> -		     DECL_OFFSET_ALIGN (node));
>>> +	    {
>>> +	      fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED,
>>> +		       DECL_OFFSET_ALIGN (node));
>>> +	      fprintf (file, " decl_not_flexarray: %d",
>>> +		       DECL_NOT_FLEXARRAY (node));
>>> +	    }
>>>     	  if (code == FUNCTION_DECL && fndecl_built_in_p (node))
>>>   	    {
>>> diff --git a/gcc/testsuite/g++.dg/strict-flex-array-1.C b/gcc/testsuite/g++.dg/strict-flex-array-1.C
>>> new file mode 100644
>>> index 000000000000..cd6a65d2b7e6
>>> --- /dev/null
>>> +++ b/gcc/testsuite/g++.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_arrays (1))); /* { dg-error "'strict_flex_arrays' attribute may not be specified for 'x'" } */
>>> +
>>> +struct trailing {
>>> +    int a;
>>> +    int c __attribute ((strict_flex_arrays)); /* { dg-error "wrong number of arguments specified for 'strict_flex_arrays' attribute" } */
>>> +};
>>> +
>>> +struct trailing_1 {
>>> +    int a;
>>> +    int b;
>>> +    int c __attribute ((strict_flex_arrays (2))); /* { dg-error "'strict_flex_arrays' 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_arrays (d))); /* { dg-error "'strict_flex_arrays' attribute argument not an integer" } */
>>> +};
>>> +
>>> +struct trailing_array_3 {
>>> +    int a;
>>> +    int b;
>>> +    int c[0] __attribute ((strict_flex_arrays (5))); /* { dg-error "'strict_flex_arrays' attribute argument '5' is not an integer constant between 0 and 3" } */
>>> +};
>>> 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 000000000000..cd6a65d2b7e6
>>> --- /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_arrays (1))); /* { dg-error "'strict_flex_arrays' attribute may not be specified for 'x'" } */
>>> +
>>> +struct trailing {
>>> +    int a;
>>> +    int c __attribute ((strict_flex_arrays)); /* { dg-error "wrong number of arguments specified for 'strict_flex_arrays' attribute" } */
>>> +};
>>> +
>>> +struct trailing_1 {
>>> +    int a;
>>> +    int b;
>>> +    int c __attribute ((strict_flex_arrays (2))); /* { dg-error "'strict_flex_arrays' 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_arrays (d))); /* { dg-error "'strict_flex_arrays' attribute argument not an integer" } */
>>> +};
>>> +
>>> +struct trailing_array_3 {
>>> +    int a;
>>> +    int b;
>>> +    int c[0] __attribute ((strict_flex_arrays (5))); /* { dg-error "'strict_flex_arrays' 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 80c2bcb333dd..18bd6d82a32d 100644
>>> --- a/gcc/tree-core.h
>>> +++ b/gcc/tree-core.h
>>> @@ -1823,7 +1823,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-streamer-in.cc b/gcc/tree-streamer-in.cc
>>> index 219cf5e7ef45..57923da3741e 100644
>>> --- a/gcc/tree-streamer-in.cc
>>> +++ b/gcc/tree-streamer-in.cc
>>> @@ -261,6 +261,7 @@ unpack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
>>>         else
>>>   	SET_DECL_FIELD_ABI_IGNORED (expr, val);
>>>         expr->decl_common.off_align = bp_unpack_value (bp, 8);
>>> +      DECL_NOT_FLEXARRAY (expr) = (unsigned) bp_unpack_value (bp, 1);
>>>       }
>>>       else if (VAR_P (expr))
>>> diff --git a/gcc/tree-streamer-out.cc b/gcc/tree-streamer-out.cc
>>> index 9b114dc05bb1..68a2818a9f93 100644
>>> --- a/gcc/tree-streamer-out.cc
>>> +++ b/gcc/tree-streamer-out.cc
>>> @@ -229,6 +229,7 @@ pack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
>>>         else
>>>   	bp_pack_value (bp, DECL_FIELD_ABI_IGNORED (expr), 1);
>>>         bp_pack_value (bp, expr->decl_common.off_align, 8);
>>> +      bp_pack_value (bp, DECL_NOT_FLEXARRAY (expr), 1);
>>>       }
>>>       else if (VAR_P (expr))
>>> diff --git a/gcc/tree.cc b/gcc/tree.cc
>>> index 2f488e4467c4..e4664eab54ef 100644
>>> --- a/gcc/tree.cc
>>> +++ b/gcc/tree.cc
>>> @@ -12688,14 +12688,30 @@ array_ref_up_bound (tree exp)
>>>   }
>>>     /* Returns true if REF is an array reference, component reference,
>>> -   or memory reference to an array at the end of a structure.
>>> -   If this is the case, the array may be allocated larger
>>> -   than its upper bound implies.  */
>>> +   or memory reference to an array whose actual size might be larger
>>> +   than its upper bound implies, there are multiple cases:
>>> +   A. a ref to a flexible array member at the end of a structure;
>>> +   B. a ref to an array with a different type against the original decl;
>>> +      for example:
>>>   +   short a[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
>>> +   (*((char(*)[16])&a[0]))[i+8]
>>> +
>>> +   C. a ref to an array that was passed as a parameter;
>>> +      for example:
>>> +
>>> +   int test (uint8_t *p, uint32_t t[1][1], int n) {
>>> +   for (int i = 0; i < 4; i++, p++)
>>> +     t[i][0] = ...;
>>> +
>>> +   FIXME, the name of this routine need to be changed to be more accurate.  */
>>>   bool
>>>   array_at_struct_end_p (tree ref)
>>>   {
>>> -  tree atype;
>>> +  /* the TYPE for this array referece.  */
>>> +  tree atype = NULL_TREE;
>>> +  /* the FIELD_DECL for the array field in the containing structure.  */
>>> +  tree afield_decl = NULL_TREE;
>>>       if (TREE_CODE (ref) == ARRAY_REF
>>>         || TREE_CODE (ref) == ARRAY_RANGE_REF)
>>> @@ -12705,7 +12721,10 @@ array_at_struct_end_p (tree ref)
>>>       }
>>>     else if (TREE_CODE (ref) == COMPONENT_REF
>>>   	   && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 1))) == ARRAY_TYPE)
>>> -    atype = TREE_TYPE (TREE_OPERAND (ref, 1));
>>> +    {
>>> +      atype = TREE_TYPE (TREE_OPERAND (ref, 1));
>>> +      afield_decl = TREE_OPERAND (ref, 1);
>>> +    }
>>>     else if (TREE_CODE (ref) == MEM_REF)
>>>       {
>>>         tree arg = TREE_OPERAND (ref, 0);
>>> @@ -12717,6 +12736,7 @@ array_at_struct_end_p (tree ref)
>>>   	  if (tree fld = last_field (argtype))
>>>   	    {
>>>   	      atype = TREE_TYPE (fld);
>>> +	      afield_decl = fld;
>>>   	      if (TREE_CODE (atype) != ARRAY_TYPE)
>>>   		return false;
>>>   	      if (VAR_P (arg) && DECL_SIZE (fld))
>>> @@ -12770,13 +12790,16 @@ array_at_struct_end_p (tree ref)
>>>         ref = TREE_OPERAND (ref, 0);
>>>       }
>>>   -  /* The array now is at struct end.  Treat flexible arrays as
>>> +  gcc_assert (!afield_decl
>>> +	      || (afield_decl && TREE_CODE (afield_decl) == FIELD_DECL));
>>> +
>>> +  /* The array now is at struct end.  Treat flexible array member as
>>>        always subject to extend, even into just padding constrained by
>>>        an underlying decl.  */
>>>     if (! TYPE_SIZE (atype)
>>>         || ! TYPE_DOMAIN (atype)
>>>         || ! TYPE_MAX_VALUE (TYPE_DOMAIN (atype)))
>>> -    return true;
>>> +    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).  */
>>> @@ -12798,9 +12821,9 @@ array_at_struct_end_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 true;
>>> +	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>>>         if (! get_addr_base_and_unit_offset (ref_to_array, &offset))
>>> -	return true;
>>> +	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)))
>>> @@ -12808,12 +12831,12 @@ array_at_struct_end_p (tree ref)
>>>   		     + 2)
>>>   		    * wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (atype))),
>>>   		    wi::to_offset (DECL_SIZE_UNIT (ref)) - offset))
>>> -	return true;
>>> +	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>>>           return false;
>>>       }
>>>   -  return true;
>>> +  return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>>>   }
>>>     /* Return a tree representing the offset, in bytes, of the field referenced
>>> diff --git a/gcc/tree.h b/gcc/tree.h
>>> index 266e24a05633..81076b045003 100644
>>> --- a/gcc/tree.h
>>> +++ b/gcc/tree.h
>>> @@ -3005,6 +3005,12 @@ 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. This is only valid for the last array type field of a
>>> +   structure.  */
>>> +#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.  */
>>> @@ -5543,10 +5549,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
> 


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [GCC13][Patch][V4][PATCH 1/2] Add a new option -fstrict-flex-arrays[=n] and new attribute strict_flex_arrays
  2022-09-30 17:39       ` Martin Sebor
@ 2022-10-03 15:20         ` Qing Zhao
  0 siblings, 0 replies; 7+ messages in thread
From: Qing Zhao @ 2022-10-03 15:20 UTC (permalink / raw)
  To: Martin Sebor; +Cc: gcc-patches, Richard Biener, jakub, keescook, joseph



> On Sep 30, 2022, at 1:39 PM, Martin Sebor <msebor@gmail.com> wrote:
> 
> On 9/28/22 13:17, Qing Zhao wrote:
>> Hi, Martin,
>> Thanks for the comments. And sorry for my late reply till now (I just came back home from LPC, GNU Cauldron and then a one-week vacation after that…)
>>> On Sep 12, 2022, at 12:42 PM, Martin Sebor <msebor@gmail.com> wrote:
>>> 
>>> On 9/6/22 18:28, Qing Zhao wrote:
>>>> Add the following new option -fstrict-flex-arrays[=n] and a corresponding
>>>> attribute strict_flex_arrays to GCC:
>>>> '-fstrict-flex-arrays'
>>>>      Treat the trailing array of a structure as a flexible array member
>>>>      in a stricter way.
>>> 
>>> A minor problem with this phrasing was pointed out in the review
>>> of the Clang option: https://reviews.llvm.org/D126864#inline-1282716
>>> It would be good to avoid it here.
>> Yes, I agree.
>>>  (I think qualifying the sentence
>>> by adding "for the purposes of accessing the elements of such arrays"
>>> might be one way to do it).
>> How about:
>> '-fstrict-flex-arrays’
>>      Treat the trailing array of a structure as a variable-length array
>>       in a stricter way.
>> ?
> 
> I don't think talking about variable length arrays in this context
> would be appropriate (they're a different thing).  The concern in
> the review above was that the a in something like
> 
>  struct { int n, a[1]; } s;
> 
> is treated as a flexible array member only for the purposes of
> accessing a's elements, but not also in a sizeof expression, for
> instance.  sizeof s.a is 1 regardless of the -fstrict-flex-arrays
> argument, but if s.a were considered a flexible array member then
> sizeof s.a would a constraint violation.  Similarly, if s.a were
> treated as a FAM the definition of s would pedantically speaking
> be invalid, and s's size would be equal to sizeof (int) because
> GCC accepts the defintion but adds no padding.

Okay, understood now.  -:)
> 
> One way to avoid implying that might be qualifying the description
> with what I suggested above:
> 
>  Control when to treat the trailing array of a structure as
>  a flexible array member for the purposes of accessing
>  the elements of such an array.

Okay, I will use this, I think it’s good enough.

Thank you!


> 
> But I'm sure there are better ways to put it.
> 
> In addition, it should probably also be made clear whether this
> stays the same when an object of such a structure is itself
> a subobject of another aggregate (array or struct).  E.g.,
> 
>  struct A { int n, a[1]; };
>  struct A a[2];                       // is a.a treated as a FAM?
>  struct B { struct A a; } b;          // is b.a.a treated as a FAM?
>  struct C { struct A a; int i; } c;   // how about c.a.a?

Yes, right now, it stay the same behavior as before. 
But I am not sure whether the current behavior is correct or not. 

Any suggestion here?

> 
> Finally, and with the caveat that I haven't been very close
> attention to the GCC patches so this may not be an issue, but I have
> the impression that the decision in Clang is to let -Warray-bounds
> trigger (at least somewhat) independently of -fstrict-flex-arrays.
> The goal is to make it possible to diagnose misuses without causing
> runtime errors.

You mean that in Clang,  -Warray-bounds will NOT be adjusted with different level of -fstrict-flex-array?
If so, I don’t think that’s a good idea.

>  This has also been the historical GCC behavior that
> I think it should be maintained going forward.

I think that -Warray-bounds need to be adjusted to reflect the different level of -fstrict-flex-array. 
Only when all the phases (both analysis phase and warning phases) in GCC can behavior consistently, we can consistently encourage the standard conforming coding style.
Otherwise, the user and developers will be even more confusing with another inconsistency added into GCC.

Qing 
> 
> Martin
> 
>>> 
>>>> The positive form is equivalent to
>>>>      '-fstrict-flex-arrays=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-arrays=0', which is the least
>>>>      strict.  All trailing arrays of structures are treated as flexible
>>>>      array members.
>>>> '-fstrict-flex-arrays=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_arrays' 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_arrays'
>>>>      attribute (*note Variable Attributes::).
>>>> 'strict_flex_arrays (LEVEL)'
>>>>      The 'strict_flex_arrays' 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.
>>> 
>>> 
>>> Since the attribute applies to just a single array declaration it
>>> seems that its name should be strict_flex_array (i.e., singular,
>>> without the trailing 's').
>> Will make the change as you suggested.
>> Thanks.
>> Qing
>>> 
>>> Martin
>>> 
>>>>      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 the
>>>>      '-fstrict-flex-arrays'.  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_arrays_attribute): New function.
>>>> 	(c_common_attribute_table): New item for strict_flex_arrays.
>>>> 	* c.opt: (fstrict-flex-arrays): New option.
>>>> 	(fstrict-flex-arrays=): New option.
>>>> gcc/c/ChangeLog:
>>>> 	* c-decl.cc (flexible_array_member_type_p): New function.
>>>> 	(one_element_array_type_p): Likewise.
>>>> 	(zero_length_array_type_p): Likewise.
>>>> 	(add_flexible_array_elts_to_size): Call new utility
>>>> 	routine flexible_array_member_type_p.
>>>> 	(is_flexible_array_member_p): New function.
>>>> 	(finish_struct): Set the new DECL_NOT_FLEXARRAY flag.
>>>> gcc/cp/ChangeLog:
>>>> 	* module.cc (trees_out::core_bools): Stream out new bit
>>>> 	decl_not_flexarray.
>>>> 	(trees_in::core_bools): Stream in new bit decl_not_flexarray.
>>>> gcc/ChangeLog:
>>>> 	* doc/extend.texi: Document strict_flex_arrays attribute.
>>>> 	* doc/invoke.texi: Document -fstrict-flex-arrays[=n] option.
>>>> 	* print-tree.cc (print_node): Print new bit decl_not_flexarray.
>>>> 	* tree-core.h (struct tree_decl_common): New bit field
>>>> 	decl_not_flexarray.
>>>> 	* tree-streamer-in.cc (unpack_ts_decl_common_value_fields): Stream
>>>> 	in new bit decl_not_flexarray.
>>>> 	* tree-streamer-out.cc (pack_ts_decl_common_value_fields): Stream
>>>> 	out new bit decl_not_flexarray.
>>>> 	* tree.cc (array_at_struct_end_p): Update it with the new bit field
>>>> 	decl_not_flexarray.
>>>> 	* tree.h (DECL_NOT_FLEXARRAY): New flag.
>>>> gcc/testsuite/ChangeLog:
>>>> 	* g++.dg/strict-flex-array-1.C: New test.
>>>> 	* 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                            | 130 +++++++++++++++++++--
>>>>  gcc/cp/module.cc                           |   2 +
>>>>  gcc/doc/extend.texi                        |  25 ++++
>>>>  gcc/doc/invoke.texi                        |  27 ++++-
>>>>  gcc/print-tree.cc                          |   8 +-
>>>>  gcc/testsuite/g++.dg/strict-flex-array-1.C |  31 +++++
>>>>  gcc/testsuite/gcc.dg/strict-flex-array-1.c |  31 +++++
>>>>  gcc/tree-core.h                            |   5 +-
>>>>  gcc/tree-streamer-in.cc                    |   1 +
>>>>  gcc/tree-streamer-out.cc                   |   1 +
>>>>  gcc/tree.cc                                |  45 +++++--
>>>>  gcc/tree.h                                 |  14 ++-
>>>>  14 files changed, 346 insertions(+), 28 deletions(-)
>>>>  create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-1.C
>>>>  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 8bb80e251dc2..0becd4bbe8d2 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_arrays_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 *);
>>>> @@ -368,6 +370,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_arrays",      1, 1, false, false, false, false,
>>>> +			      handle_strict_flex_arrays_attribute, NULL },
>>>>    { "weak",                   0, 0, true,  false, false, false,
>>>>  			      handle_weak_attribute, NULL },
>>>>    { "noplt",                   0, 0, true,  false, false, false,
>>>> @@ -2505,6 +2509,49 @@ handle_warn_if_not_aligned_attribute (tree *node, tree name,
>>>>  					  no_add_attrs, true);
>>>>  }
>>>>  +/* Handle a "strict_flex_arrays" attribute; arguments as in
>>>> +   struct attribute_spec.handler.  */
>>>> +
>>>> +static tree
>>>> +handle_strict_flex_arrays_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 4515664aa590..e053bd939559 100644
>>>> --- a/gcc/c-family/c.opt
>>>> +++ b/gcc/c-family/c.opt
>>>> @@ -2072,6 +2072,13 @@ fsized-deallocation
>>>>  C++ ObjC++ Var(flag_sized_deallocation) Init(-1)
>>>>  Enable C++14 sized deallocation support.
>>>>  +fstrict-flex-arrays
>>>> +C C++ Common Alias(fstrict-flex-arrays=,3,0)
>>>> +
>>>> +fstrict-flex-arrays=
>>>> +C C++ Common Joined RejectNegative UInteger Var(flag_strict_flex_arrays) Init(0) IntegerRange(0,3)
>>>> +-fstrict-flex-arrays=<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 34f8feda897f..ee90808bcb0e 100644
>>>> --- a/gcc/c/c-decl.cc
>>>> +++ b/gcc/c/c-decl.cc
>>>> @@ -5005,6 +5005,41 @@ set_array_declarator_inner (struct c_declarator *decl,
>>>>    return decl;
>>>>  }
>>>>  +/* Determine whether TYPE is a ISO C99 flexible array memeber type "[]".  */
>>>> +static bool
>>>> +flexible_array_member_type_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 one-element array type "[1]".  */
>>>> +static bool
>>>> +one_element_array_type_p (const_tree type)
>>>> +{
>>>> +  if (TREE_CODE (type) != ARRAY_TYPE)
>>>> +    return false;
>>>> +  return integer_zerop (array_type_nelts (type));
>>>> +}
>>>> +
>>>> +/* Determine whether TYPE is a zero-length array type "[0]".  */
>>>> +static bool
>>>> +zero_length_array_type_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;
>>>> +}
>>>> +
>>>>  /* INIT is a constructor that forms DECL's initializer.  If the final
>>>>     element initializes a flexible array field, add the size of that
>>>>     initializer to DECL's size.  */
>>>> @@ -5019,10 +5054,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_type_p (type))
>>>>      {
>>>>        complete_array_type (&type, elt, false);
>>>>        DECL_SIZE (decl)
>>>> @@ -8710,6 +8742,81 @@ 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_arrays;
>>>> +  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_type_p (TREE_TYPE (x));
>>>> +  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_arrays",
>>>> +						  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;
>>>> +    }
>>>> +
>>>> +  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.
>>>> @@ -8771,6 +8878,11 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
>>>>    bool saw_named_field = false;
>>>>    for (x = fieldlist; x; x = DECL_CHAIN (x))
>>>>      {
>>>> +      /* whether this field is the last field of the structure or union.
>>>> +	 for UNION, any field is the last field of it.  */
>>>> +      bool is_last_field = (DECL_CHAIN (x) == NULL_TREE)
>>>> +			    || (TREE_CODE (t) == UNION_TYPE);
>>>> +
>>>>        if (TREE_TYPE (x) == error_mark_node)
>>>>  	continue;
>>>>  @@ -8809,10 +8921,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_type_p (TREE_TYPE (x)))
>>>>  	{
>>>>  	  if (TREE_CODE (t) == UNION_TYPE)
>>>>  	    {
>>>> @@ -8820,7 +8929,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");
>>>> @@ -8840,6 +8949,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/cp/module.cc b/gcc/cp/module.cc
>>>> index f27f4d091e5e..75ee2514f66b 100644
>>>> --- a/gcc/cp/module.cc
>>>> +++ b/gcc/cp/module.cc
>>>> @@ -5414,6 +5414,7 @@ trees_out::core_bools (tree t)
>>>>        WB (t->decl_common.decl_by_reference_flag);
>>>>        WB (t->decl_common.decl_read_flag);
>>>>        WB (t->decl_common.decl_nonshareable_flag);
>>>> +      WB (t->decl_common.decl_not_flexarray);
>>>>      }
>>>>      if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
>>>> @@ -5558,6 +5559,7 @@ trees_in::core_bools (tree t)
>>>>        RB (t->decl_common.decl_by_reference_flag);
>>>>        RB (t->decl_common.decl_read_flag);
>>>>        RB (t->decl_common.decl_nonshareable_flag);
>>>> +      RB (t->decl_common.decl_not_flexarray);
>>>>      }
>>>>      if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
>>>> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
>>>> index 0fedab96610b..62328d77c78c 100644
>>>> --- a/gcc/doc/extend.texi
>>>> +++ b/gcc/doc/extend.texi
>>>> @@ -7459,6 +7459,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_arrays} variable attribute
>>>> +@item strict_flex_arrays (@var{level})
>>>> +The @code{strict_flex_arrays} 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 (@samp{[]}), 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 (@samp{[0]}) or one-size
>>>> +array as flexible array member (@samp{[1]}):
>>>> +When @var{level} is 1, the trailing array is treated as a flexible array member
>>>> +when it is declared as either @samp{[]}, @samp{[0]}, or @samp{[1]};
>>>> +When @var{level} is 2, the trailing array is treated as a flexible array member
>>>> +when it is declared as either @samp{[]}, or @samp{[0]}.
>>>> +
>>>> +This attribute can be used with or without the @option{-fstrict-flex-arrays}.
>>>> +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 9d662e353163..db1a68cd545c 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-arrays[=@var{n}] @gol
>>>> +-fsso-struct=@var{endianness}}
>>>>    @item C++ Language Options
>>>>  @xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
>>>> @@ -2826,6 +2827,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-arrays
>>>> +@opindex fstrict-flex-arrays
>>>> +@opindex fno-strict-flex-arrays
>>>> +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-arrays=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-arrays=0}, which is the
>>>> +least strict.  All trailing arrays of structures are treated as flexible array
>>>> +members.
>>>> +
>>>> +@item -fstrict-flex-arrays=@var{level}
>>>> +@opindex fstrict-flex-arrays=@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_arrays} 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_arrays} 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/print-tree.cc b/gcc/print-tree.cc
>>>> index 6d45a4a59669..58a98250cc4f 100644
>>>> --- a/gcc/print-tree.cc
>>>> +++ b/gcc/print-tree.cc
>>>> @@ -517,8 +517,12 @@ print_node (FILE *file, const char *prefix, tree node, int indent,
>>>>  	  fprintf (file, " align:%d warn_if_not_align:%d",
>>>>  		   DECL_ALIGN (node), DECL_WARN_IF_NOT_ALIGN (node));
>>>>  	  if (code == FIELD_DECL)
>>>> -	    fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED,
>>>> -		     DECL_OFFSET_ALIGN (node));
>>>> +	    {
>>>> +	      fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED,
>>>> +		       DECL_OFFSET_ALIGN (node));
>>>> +	      fprintf (file, " decl_not_flexarray: %d",
>>>> +		       DECL_NOT_FLEXARRAY (node));
>>>> +	    }
>>>>    	  if (code == FUNCTION_DECL && fndecl_built_in_p (node))
>>>>  	    {
>>>> diff --git a/gcc/testsuite/g++.dg/strict-flex-array-1.C b/gcc/testsuite/g++.dg/strict-flex-array-1.C
>>>> new file mode 100644
>>>> index 000000000000..cd6a65d2b7e6
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/g++.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_arrays (1))); /* { dg-error "'strict_flex_arrays' attribute may not be specified for 'x'" } */
>>>> +
>>>> +struct trailing {
>>>> +    int a;
>>>> +    int c __attribute ((strict_flex_arrays)); /* { dg-error "wrong number of arguments specified for 'strict_flex_arrays' attribute" } */
>>>> +};
>>>> +
>>>> +struct trailing_1 {
>>>> +    int a;
>>>> +    int b;
>>>> +    int c __attribute ((strict_flex_arrays (2))); /* { dg-error "'strict_flex_arrays' 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_arrays (d))); /* { dg-error "'strict_flex_arrays' attribute argument not an integer" } */
>>>> +};
>>>> +
>>>> +struct trailing_array_3 {
>>>> +    int a;
>>>> +    int b;
>>>> +    int c[0] __attribute ((strict_flex_arrays (5))); /* { dg-error "'strict_flex_arrays' attribute argument '5' is not an integer constant between 0 and 3" } */
>>>> +};
>>>> 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 000000000000..cd6a65d2b7e6
>>>> --- /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_arrays (1))); /* { dg-error "'strict_flex_arrays' attribute may not be specified for 'x'" } */
>>>> +
>>>> +struct trailing {
>>>> +    int a;
>>>> +    int c __attribute ((strict_flex_arrays)); /* { dg-error "wrong number of arguments specified for 'strict_flex_arrays' attribute" } */
>>>> +};
>>>> +
>>>> +struct trailing_1 {
>>>> +    int a;
>>>> +    int b;
>>>> +    int c __attribute ((strict_flex_arrays (2))); /* { dg-error "'strict_flex_arrays' 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_arrays (d))); /* { dg-error "'strict_flex_arrays' attribute argument not an integer" } */
>>>> +};
>>>> +
>>>> +struct trailing_array_3 {
>>>> +    int a;
>>>> +    int b;
>>>> +    int c[0] __attribute ((strict_flex_arrays (5))); /* { dg-error "'strict_flex_arrays' 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 80c2bcb333dd..18bd6d82a32d 100644
>>>> --- a/gcc/tree-core.h
>>>> +++ b/gcc/tree-core.h
>>>> @@ -1823,7 +1823,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-streamer-in.cc b/gcc/tree-streamer-in.cc
>>>> index 219cf5e7ef45..57923da3741e 100644
>>>> --- a/gcc/tree-streamer-in.cc
>>>> +++ b/gcc/tree-streamer-in.cc
>>>> @@ -261,6 +261,7 @@ unpack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
>>>>        else
>>>>  	SET_DECL_FIELD_ABI_IGNORED (expr, val);
>>>>        expr->decl_common.off_align = bp_unpack_value (bp, 8);
>>>> +      DECL_NOT_FLEXARRAY (expr) = (unsigned) bp_unpack_value (bp, 1);
>>>>      }
>>>>      else if (VAR_P (expr))
>>>> diff --git a/gcc/tree-streamer-out.cc b/gcc/tree-streamer-out.cc
>>>> index 9b114dc05bb1..68a2818a9f93 100644
>>>> --- a/gcc/tree-streamer-out.cc
>>>> +++ b/gcc/tree-streamer-out.cc
>>>> @@ -229,6 +229,7 @@ pack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
>>>>        else
>>>>  	bp_pack_value (bp, DECL_FIELD_ABI_IGNORED (expr), 1);
>>>>        bp_pack_value (bp, expr->decl_common.off_align, 8);
>>>> +      bp_pack_value (bp, DECL_NOT_FLEXARRAY (expr), 1);
>>>>      }
>>>>      else if (VAR_P (expr))
>>>> diff --git a/gcc/tree.cc b/gcc/tree.cc
>>>> index 2f488e4467c4..e4664eab54ef 100644
>>>> --- a/gcc/tree.cc
>>>> +++ b/gcc/tree.cc
>>>> @@ -12688,14 +12688,30 @@ array_ref_up_bound (tree exp)
>>>>  }
>>>>    /* Returns true if REF is an array reference, component reference,
>>>> -   or memory reference to an array at the end of a structure.
>>>> -   If this is the case, the array may be allocated larger
>>>> -   than its upper bound implies.  */
>>>> +   or memory reference to an array whose actual size might be larger
>>>> +   than its upper bound implies, there are multiple cases:
>>>> +   A. a ref to a flexible array member at the end of a structure;
>>>> +   B. a ref to an array with a different type against the original decl;
>>>> +      for example:
>>>>  +   short a[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
>>>> +   (*((char(*)[16])&a[0]))[i+8]
>>>> +
>>>> +   C. a ref to an array that was passed as a parameter;
>>>> +      for example:
>>>> +
>>>> +   int test (uint8_t *p, uint32_t t[1][1], int n) {
>>>> +   for (int i = 0; i < 4; i++, p++)
>>>> +     t[i][0] = ...;
>>>> +
>>>> +   FIXME, the name of this routine need to be changed to be more accurate.  */
>>>>  bool
>>>>  array_at_struct_end_p (tree ref)
>>>>  {
>>>> -  tree atype;
>>>> +  /* the TYPE for this array referece.  */
>>>> +  tree atype = NULL_TREE;
>>>> +  /* the FIELD_DECL for the array field in the containing structure.  */
>>>> +  tree afield_decl = NULL_TREE;
>>>>      if (TREE_CODE (ref) == ARRAY_REF
>>>>        || TREE_CODE (ref) == ARRAY_RANGE_REF)
>>>> @@ -12705,7 +12721,10 @@ array_at_struct_end_p (tree ref)
>>>>      }
>>>>    else if (TREE_CODE (ref) == COMPONENT_REF
>>>>  	   && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 1))) == ARRAY_TYPE)
>>>> -    atype = TREE_TYPE (TREE_OPERAND (ref, 1));
>>>> +    {
>>>> +      atype = TREE_TYPE (TREE_OPERAND (ref, 1));
>>>> +      afield_decl = TREE_OPERAND (ref, 1);
>>>> +    }
>>>>    else if (TREE_CODE (ref) == MEM_REF)
>>>>      {
>>>>        tree arg = TREE_OPERAND (ref, 0);
>>>> @@ -12717,6 +12736,7 @@ array_at_struct_end_p (tree ref)
>>>>  	  if (tree fld = last_field (argtype))
>>>>  	    {
>>>>  	      atype = TREE_TYPE (fld);
>>>> +	      afield_decl = fld;
>>>>  	      if (TREE_CODE (atype) != ARRAY_TYPE)
>>>>  		return false;
>>>>  	      if (VAR_P (arg) && DECL_SIZE (fld))
>>>> @@ -12770,13 +12790,16 @@ array_at_struct_end_p (tree ref)
>>>>        ref = TREE_OPERAND (ref, 0);
>>>>      }
>>>>  -  /* The array now is at struct end.  Treat flexible arrays as
>>>> +  gcc_assert (!afield_decl
>>>> +	      || (afield_decl && TREE_CODE (afield_decl) == FIELD_DECL));
>>>> +
>>>> +  /* The array now is at struct end.  Treat flexible array member as
>>>>       always subject to extend, even into just padding constrained by
>>>>       an underlying decl.  */
>>>>    if (! TYPE_SIZE (atype)
>>>>        || ! TYPE_DOMAIN (atype)
>>>>        || ! TYPE_MAX_VALUE (TYPE_DOMAIN (atype)))
>>>> -    return true;
>>>> +    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).  */
>>>> @@ -12798,9 +12821,9 @@ array_at_struct_end_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 true;
>>>> +	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>>>>        if (! get_addr_base_and_unit_offset (ref_to_array, &offset))
>>>> -	return true;
>>>> +	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)))
>>>> @@ -12808,12 +12831,12 @@ array_at_struct_end_p (tree ref)
>>>>  		     + 2)
>>>>  		    * wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (atype))),
>>>>  		    wi::to_offset (DECL_SIZE_UNIT (ref)) - offset))
>>>> -	return true;
>>>> +	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>>>>          return false;
>>>>      }
>>>>  -  return true;
>>>> +  return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>>>>  }
>>>>    /* Return a tree representing the offset, in bytes, of the field referenced
>>>> diff --git a/gcc/tree.h b/gcc/tree.h
>>>> index 266e24a05633..81076b045003 100644
>>>> --- a/gcc/tree.h
>>>> +++ b/gcc/tree.h
>>>> @@ -3005,6 +3005,12 @@ 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. This is only valid for the last array type field of a
>>>> +   structure.  */
>>>> +#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.  */
>>>> @@ -5543,10 +5549,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


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2022-10-03 15:21 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-07  0:28 [GCC13][Patch][V4][PATCH 0/2] Add a new option -fstrict-flex-array[=n] and attribute strict_flex_array(n) and use it in PR101836 Qing Zhao
2022-09-07  0:28 ` [GCC13][Patch][V4][PATCH 1/2] Add a new option -fstrict-flex-arrays[=n] and new attribute strict_flex_arrays Qing Zhao
2022-09-12 16:42   ` Martin Sebor
2022-09-28 19:17     ` Qing Zhao
2022-09-30 17:39       ` Martin Sebor
2022-10-03 15:20         ` Qing Zhao
2022-09-07  0:28 ` [GCC13][Patch][V4][PATCH 2/2] Use array_at_struct_end_p in __builtin_object_size [PR101836] Qing Zhao

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).