public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
@ 2022-08-17 14:40 Qing Zhao
  2022-08-17 14:40 ` [[GCC13][Patch][V3] 2/2] Use array_at_struct_end_p in __builtin_object_size [PR101836] Qing Zhao
                   ` (2 more replies)
  0 siblings, 3 replies; 27+ messages in thread
From: Qing Zhao @ 2022-08-17 14:40 UTC (permalink / raw)
  To: gcc-patches; +Cc: rguenther, jakub, msebor, keescook, joseph, Qing Zhao

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

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

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

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

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

     This option is only valid when flexible array member is supported in the
     language. FOR ISO C before C99 and ISO C++, no language support for the flexible
     array member at all, this option will be invalid and a warning will be issued.
     When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
     extension and one-size array are supported, as a result, LEVEL=3 will be
     invalid and a warning will be issued.

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

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

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

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

     This attribute is only valid when flexible array member is supported in the
     language. For ISO C before C99 and ISO C++, no language support for the flexible
     array member at all, this attribute will be invalid and a warning is issued.
     When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
     extension and one-size array are supported, as a result, LEVEL=3 will be
     invalid and a warning is issued.

gcc/c-family/ChangeLog:

	* c-attribs.cc (handle_strict_flex_arrays_attribute): New function.
	(c_common_attribute_table): New item for strict_flex_array.
	* c-opts.cc (c_common_post_options): Handle the combination of
	-fstrict-flex-arrays and -std specially.
	* c.opt: (fstrict-flex-array): New option.
	(fstrict-flex-array=): 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_array attribute.
	* doc/invoke.texi: Document -fstrict-flex-array[=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.
	* g++.dg/strict-flex-array-2.C: New test.
	* g++.dg/strict-flex-array-3.C: New test.
	* g++.dg/strict-flex-array-4.C: New test.
	* gcc.dg/strict-flex-array-1.c: New test.
	* gcc.dg/strict-flex-array-2.c: New test.
	* gcc.dg/strict-flex-array-3.c: New test.
	* gcc.dg/strict-flex-array-4.c: New test.
---
 gcc/c-family/c-attribs.cc                  |  94 +++++++++++++++
 gcc/c-family/c-opts.cc                     |  41 +++++++
 gcc/c-family/c.opt                         |   7 ++
 gcc/c/c-decl.cc                            | 130 +++++++++++++++++++--
 gcc/cp/module.cc                           |   2 +
 gcc/doc/extend.texi                        |  33 ++++++
 gcc/doc/invoke.texi                        |  34 +++++-
 gcc/print-tree.cc                          |   8 +-
 gcc/testsuite/g++.dg/strict-flex-array-1.C |  31 +++++
 gcc/testsuite/g++.dg/strict-flex-array-2.C |  16 +++
 gcc/testsuite/g++.dg/strict-flex-array-3.C |  21 ++++
 gcc/testsuite/g++.dg/strict-flex-array-4.C |   9 ++
 gcc/testsuite/gcc.dg/strict-flex-array-1.c |  31 +++++
 gcc/testsuite/gcc.dg/strict-flex-array-2.c |  15 +++
 gcc/testsuite/gcc.dg/strict-flex-array-3.c |  21 ++++
 gcc/testsuite/gcc.dg/strict-flex-array-4.c |  10 ++
 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 ++-
 21 files changed, 541 insertions(+), 28 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-1.C
 create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-2.C
 create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-3.C
 create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-4.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
 create mode 100644 gcc/testsuite/gcc.dg/strict-flex-array-4.c

diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index e4f1d3542f37..9c9927cefa0d 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,96 @@ 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;
+    }
+  else
+    {
+      unsigned int level = tree_to_uhwi (argval);
+      /* check whether the attribute is valid based on language standard.
+	 the attribute is only valid when flexible array member is
+	 supported in the language. Therefore, we should invalid this attribute or
+	 specific level of this attribute for the following situations:
+	A. When -std=c89 is specified, no language support at all, invalid this
+	   attribute and issue a warning;
+	B. When -std=gnu89 is specified, only zero-length array extension and
+	   one-size array are supported, level=3 will be invalid and a warning
+	   will be issued.
+	C. C++ without GNU extension, no language support at all, invalid this
+	   attribute and issue a warning;
+	D. C++ with GNU extension, only zero-length array extension and one-size
+	   array are supported, level=3 will be invalid and a warning will be
+	   issued.  */
+      if (level > 0)
+	{
+	  if (!c_dialect_cxx () && flag_iso && flag_isoc99 == 0)
+	  {
+	    warning (OPT_Wattributes, "%qE attribute ignored since it is "
+		     "not supported with a ISO C before C99", name);
+	    *no_add_attrs = true;
+	  }
+	  else if (!c_dialect_cxx () && !flag_iso
+		   && flag_isoc99 == 0 && level == 3)
+	  {
+	    warning (OPT_Wattributes, "%qE = 3 attribute ignored since it is "
+		     "not supported with a GNU extension GNU89", name);
+	    *no_add_attrs = true;
+	  }
+	  else if (c_dialect_cxx () && flag_iso)
+	  {
+	    warning (OPT_Wattributes, "%qE attribute ignored since it is "
+		     "not supported with a ISO C++", name);
+	    *no_add_attrs = true;
+	  }
+	  else if (c_dialect_cxx () && !flag_iso
+		   && level == 3)
+	  {
+	    warning (OPT_Wattributes, "%qE = 3 attribute ignored since it is "
+		     "not supported for C++ with GNU extension", name);
+	    *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-opts.cc b/gcc/c-family/c-opts.cc
index 4e1463689de3..639eb40f3c86 100644
--- a/gcc/c-family/c-opts.cc
+++ b/gcc/c-family/c-opts.cc
@@ -870,6 +870,47 @@ c_common_post_options (const char **pfilename)
     SET_OPTION_IF_UNSET (&global_options, &global_options_set,
 			 flag_tree_loop_distribute_patterns, 0);
 
+  /* -fstrict-flex-arrays is only valid when flexible array member is
+     supported in the language. Therefore, we should invalid this option or
+     specific level of this option for the following situations:
+     A. When -std=c89 is specified, no language support at all, invalid this
+	option and issue a warning;
+     B. When -std=gnu89 is specified, only zero-length array extension and
+	one-size array are supported, level=3 will be invalid and a warning
+	will be issued.
+     C. C++ without GNU extension, no language support at all, invalid this
+	option and issue a warning;
+     D. C++ with GNU extension, only zero-length array extension and one-size
+	array are supported, level=3 will be invalid and a warning will be
+	issued.  */
+  if (flag_strict_flex_arrays > 0)
+    {
+      if (!c_dialect_cxx () && flag_iso && flag_isoc99 == 0)
+	{
+	  flag_strict_flex_arrays = 0;
+	  warning (0, "%<-fstrict-flex-arrays%> is not supported with a ISO C "
+		   "before C99, ignored");
+	}
+      else if (!c_dialect_cxx () && !flag_iso && flag_isoc99 == 0 && flag_strict_flex_arrays == 3)
+	{
+	  flag_strict_flex_arrays = 0;
+	  warning (0, "%<-fstrict-flex-arrays=3%> is not supported with a "
+		   "GNU extension GNU89, ignored");
+	}
+      else if (c_dialect_cxx () && flag_iso)
+	{
+	  flag_strict_flex_arrays = 0;
+	  warning (0, "%<-fstrict-flex-arrays%> is not supported with a ISO "
+		   "C++, ignored");
+	}
+      else if (c_dialect_cxx () && !flag_iso && flag_strict_flex_arrays == 3)
+	{
+	  flag_strict_flex_arrays = 0;
+	  warning (0, "%<-fstrict-flex-arrays=3%> is not supported for C++ "
+		   "with GNU extension, ignored");
+	}
+    }
+
   /* -Woverlength-strings is off by default, but is enabled by -Wpedantic.
      It is never enabled in C++, as the minimum limit is not normative
      in that standard.  */
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 44e1a60ce246..1e944f8a3055 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -2060,6 +2060,13 @@ fsized-deallocation
 C++ ObjC++ Var(flag_sized_deallocation) Init(-1)
 Enable C++14 sized deallocation support.
 
+fstrict-flex-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 ae8990c138fd..a2e125d4ddd5 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -4999,6 +4999,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.  */
@@ -5013,10 +5048,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)
@@ -8720,6 +8752,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.
@@ -8781,6 +8888,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;
 
@@ -8819,10 +8931,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)
 	    {
@@ -8830,7 +8939,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
 			"flexible array member in union");
 	      TREE_TYPE (x) = error_mark_node;
 	    }
-	  else if (DECL_CHAIN (x) != NULL_TREE)
+	  else if (!is_last_field)
 	    {
 	      error_at (DECL_SOURCE_LOCATION (x),
 			"flexible array member not at end of struct");
@@ -8850,6 +8959,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 7fe7f8817cdd..99b43ed3852c 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -7473,6 +7473,39 @@ 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 ([]), it is treated as a flexible array member.
+
+There are two more levels in between 0 and 3, which are provided to support
+older codes that use GCC zero-length array extension ([0]) or one-size array
+as flexible array member ([1]):
+When @var{level} is 1, the trailing array is treated as a flexible array member
+when it is declared as either "[]", "[0]", or "[1]";
+When @var{level} is 2, the trailing array is treated as a flexible array member
+when it is declared as either "[]", or "[0]".
+
+This attribute can be used with or without 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.
+
+This attribute is only valid when flexible array member is supported in the
+language. For ISO C before C99 and ISO C++, no language support for the flexible
+array member at all, this attribute will be invalid and a warning is issued.
+When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
+extension and one-size array are supported, as a result, @var{level}=3 will be
+invalid and a warning is issued.
+
+
 @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 863580b3710a..2a0a3cf3de10 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,37 @@ 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_array} attribute (@pxref{Variable Attributes}).
+
+You can control this behavior for a specific trailing array field of a
+structure by using the variable attribute @code{strict_flex_array} attribute
+(@pxref{Variable Attributes}).
+
+This option is only valid when flexible array member is supported in the
+language. FOR ISO C before C99 and ISO C++, no language support for the flexible
+array member at all, this option will be invalid and a warning will be issued.
+When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
+extension and one-size array are supported, as a result, @var{level}=3 will be
+invalid and a warning will be issued.
+
 @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..47adaf7bac4a
--- /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/g++.dg/strict-flex-array-2.C b/gcc/testsuite/g++.dg/strict-flex-array-2.C
new file mode 100644
index 000000000000..245f8fe0bc73
--- /dev/null
+++ b/gcc/testsuite/g++.dg/strict-flex-array-2.C
@@ -0,0 +1,16 @@
+/* testing the correct usage of flag -fstrict_flex_array for C++.  */   
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays -std=c++98" } */
+
+struct trailing_array {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "attribute ignored since it is not supported with a ISO C\\+\\+" } */
+};
+
+int foo(int a)
+{
+  return 0;
+}
+
+/* { dg-warning "is not supported with a ISO C\\+\\+, ignored" ""  { target *-*-* } 0 } */
diff --git a/gcc/testsuite/g++.dg/strict-flex-array-3.C b/gcc/testsuite/g++.dg/strict-flex-array-3.C
new file mode 100644
index 000000000000..2a733a5bccf4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/strict-flex-array-3.C
@@ -0,0 +1,21 @@
+/* testing the correct usage of flag -fstrict_flex_array for C++.  */   
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays -std=gnu++98" } */
+/* { dg-warning "'-fstrict-flex-arrays=3' is not supported for C\\+\\+ with GNU extension, ignored" ""  { target *-*-* } 0 } */
+
+struct trailing_array {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "'strict_flex_arrays' = 3 attribute ignored since it is not supported for C\\+\\+ with GNU extension" } */
+};
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (2))); /* { dg-bogus "'strict_flex_arrays' = 3 attribute ignored since it is not supported for C\\+\\+ with GNU extension" } */
+};
+
+int foo(int a)
+{
+  return a + 2;
+}
diff --git a/gcc/testsuite/g++.dg/strict-flex-array-4.C b/gcc/testsuite/g++.dg/strict-flex-array-4.C
new file mode 100644
index 000000000000..804e4cf459ef
--- /dev/null
+++ b/gcc/testsuite/g++.dg/strict-flex-array-4.C
@@ -0,0 +1,9 @@
+/* testing the correct usage of flag -fstrict_flex_array.  */   
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays=2 -std=gnu++98" } */
+/* { dg-bogus "is not supported for C\\+\\+ with GNU extension, ignored" ""  { target *-*-* } 0 } */
+
+int foo(int a)
+{
+  return a + 2;
+}
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..47adaf7bac4a
--- /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/testsuite/gcc.dg/strict-flex-array-2.c b/gcc/testsuite/gcc.dg/strict-flex-array-2.c
new file mode 100644
index 000000000000..967a240040dc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strict-flex-array-2.c
@@ -0,0 +1,15 @@
+/* testing the correct usage of flag -fstrict_flex_array.  */   
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays -std=c89" } */
+/* { dg-warning "'-fstrict-flex-arrays' is not supported with a ISO C before C99, ignored" ""  { target *-*-* } 0 } */
+
+struct trailing_array {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "'strict_flex_arrays' attribute ignored since it is not supported with a ISO C before C99" } */
+};
+
+int foo(int a)
+{
+  return a + 2;
+}
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..879de7f203c8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strict-flex-array-3.c
@@ -0,0 +1,21 @@
+/* testing the correct usage of flag -fstrict_flex_array.  */   
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays -std=gnu89" } */
+/* { dg-warning "'-fstrict-flex-arrays=3' is not supported with a GNU extension GNU89, ignored" ""  { target *-*-* } 0 } */
+
+struct trailing_array {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "'strict_flex_arrays' = 3 attribute ignored since it is not supported with a GNU extension GNU89" } */
+};
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (2))); /* { dg-bogus "'strict_flex_arrays' = 3 attribute ignored since it is not supported with a GNU extension GNU89" } */
+};
+
+int foo(int a)
+{
+  return a + 2;
+}
diff --git a/gcc/testsuite/gcc.dg/strict-flex-array-4.c b/gcc/testsuite/gcc.dg/strict-flex-array-4.c
new file mode 100644
index 000000000000..ce64c24db301
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strict-flex-array-4.c
@@ -0,0 +1,10 @@
+/* testing the correct usage of flag -fstrict_flex_array.  */   
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays=2 -std=gnu89" } */
+/* { dg-bogus "is not supported with a GNU extension GNU89, ignored" ""  { target *-*-* } 0 } */
+
+
+int foo(int a)
+{
+  return a + 2;
+}
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 86a07c282af2..f822cb539dd0 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1813,7 +1813,10 @@ struct GTY(()) tree_decl_common {
      TYPE_WARN_IF_NOT_ALIGN.  */
   unsigned int warn_if_not_align : 6;
 
-  /* 14 bits unused.  */
+  /* In FIELD_DECL, this is DECL_NOT_FLEXARRAY.  */
+  unsigned int decl_not_flexarray : 1;
+
+  /* 13 bits unused.  */
 
   /* UID for points-to sets, stable over copying from inlining.  */
   unsigned int pt_uid;
diff --git a/gcc/tree-streamer-in.cc b/gcc/tree-streamer-in.cc
index 196f19c759f2..21e6e8eb1c0a 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 d39dc158a465..68e40dbdb8f2 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 fed1434d141d..d698e8c9c213 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -12678,14 +12678,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)
@@ -12695,7 +12711,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);
@@ -12707,6 +12726,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))
@@ -12760,13 +12780,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).  */
@@ -12788,9 +12811,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)))
@@ -12798,12 +12821,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 e6564aaccb7b..f911c0a46e69 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2993,6 +2993,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.  */
@@ -5531,10 +5537,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] 27+ messages in thread

* [[GCC13][Patch][V3] 2/2] Use array_at_struct_end_p in __builtin_object_size [PR101836]
  2022-08-17 14:40 [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array Qing Zhao
@ 2022-08-17 14:40 ` Qing Zhao
  2022-08-26  8:49   ` Richard Biener
  2022-08-26  8:48 ` [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array Richard Biener
  2022-08-30 20:30 ` Fwd: " Qing Zhao
  2 siblings, 1 reply; 27+ messages in thread
From: Qing Zhao @ 2022-08-17 14:40 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-5.c: New test.
	* gcc.dg/strict-flex-array-6.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-5.c | 60 ++++++++++++++++++++++
 gcc/testsuite/gcc.dg/strict-flex-array-6.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-5.c
 create mode 100644 gcc/testsuite/gcc.dg/strict-flex-array-6.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-5.c b/gcc/testsuite/gcc.dg/strict-flex-array-5.c
new file mode 100644
index 000000000000..e474b9ec43fa
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strict-flex-array-5.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-6.c b/gcc/testsuite/gcc.dg/strict-flex-array-6.c
new file mode 100644
index 000000000000..b45e7b32f6d1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strict-flex-array-6.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] 27+ messages in thread

* Re: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-17 14:40 [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array Qing Zhao
  2022-08-17 14:40 ` [[GCC13][Patch][V3] 2/2] Use array_at_struct_end_p in __builtin_object_size [PR101836] Qing Zhao
@ 2022-08-26  8:48 ` Richard Biener
  2022-08-26 13:47   ` Qing Zhao
  2022-08-30 20:30 ` Fwd: " Qing Zhao
  2 siblings, 1 reply; 27+ messages in thread
From: Richard Biener @ 2022-08-26  8:48 UTC (permalink / raw)
  To: Qing Zhao; +Cc: gcc-patches, jakub, msebor, keescook, joseph

On Wed, 17 Aug 2022, Qing Zhao wrote:

> Add the following new option -fstrict-flex-array[=n] and a corresponding
> attribute strict_flex_array to GCC:
> 
> '-fstrict-flex-array'
>      Treat the trailing array of a structure as a flexible array member
>      in a stricter way.  The positive form is equivalent to
>      '-fstrict-flex-array=3', which is the strictest.  A trailing array
>      is treated as a flexible array member only when it is declared as a
>      flexible array member per C99 standard onwards.  The negative form
>      is equivalent to '-fstrict-flex-array=0', which is the least
>      strict.  All trailing arrays of structures are treated as flexible
>      array members.
> 
> '-fstrict-flex-array=LEVEL'
>      Treat the trailing array of a structure as a flexible array member
>      in a stricter way.  The value of LEVEL controls the level of
>      strictness.
> 
>      The possible values of LEVEL are the same as for the
>      'strict_flex_array' attribute (*note Variable Attributes::).
> 
>      You can control this behavior for a specific trailing array field
>      of a structure by using the variable attribute 'strict_flex_array'
>      attribute (*note Variable Attributes::).
> 
>      This option is only valid when flexible array member is supported in the
>      language. FOR ISO C before C99 and ISO C++, no language support for the flexible
>      array member at all, this option will be invalid and a warning will be issued.
>      When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
>      extension and one-size array are supported, as a result, LEVEL=3 will be
>      invalid and a warning will be issued.
> 
> 'strict_flex_array (LEVEL)'
>      The 'strict_flex_array' attribute should be attached to the
>      trailing array field of a structure.  It specifies the level of
>      strictness of treating the trailing array field of a structure as a
>      flexible array member.  LEVEL must be an integer betwen 0 to 3.
> 
>      LEVEL=0 is the least strict level, all trailing arrays of
>      structures are treated as flexible array members.  LEVEL=3 is the
>      strictest level, only when the trailing array is declared as a
>      flexible array member per C99 standard onwards ([]), it is treated
>      as a flexible array member.
> 
>      There are two more levels in between 0 and 3, which are provided to
>      support older codes that use GCC zero-length array extension ([0])
>      or one-size array as flexible array member ([1]): When LEVEL is 1,
>      the trailing array is treated as a flexible array member when it is
>      declared as either [], [0], or [1]; When LEVEL is 2, the trailing
>      array is treated as a flexible array member when it is declared as
>      either [], or [0].
> 
>      This attribute can be used with or without '-fstrict-flex-array'.
>      When both the attribute and the option present at the same time,
>      the level of the strictness for the specific trailing array field
>      is determined by the attribute.
> 
>      This attribute is only valid when flexible array member is supported in the
>      language. For ISO C before C99 and ISO C++, no language support for the flexible
>      array member at all, this attribute will be invalid and a warning is issued.
>      When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
>      extension and one-size array are supported, as a result, LEVEL=3 will be
>      invalid and a warning is issued.
> 
> gcc/c-family/ChangeLog:
> 
> 	* c-attribs.cc (handle_strict_flex_arrays_attribute): New function.
> 	(c_common_attribute_table): New item for strict_flex_array.
> 	* c-opts.cc (c_common_post_options): Handle the combination of
> 	-fstrict-flex-arrays and -std specially.
> 	* c.opt: (fstrict-flex-array): New option.
> 	(fstrict-flex-array=): 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_array attribute.
> 	* doc/invoke.texi: Document -fstrict-flex-array[=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 fla

The middle-end changes are OK, the c/ and cp/ changes need review
from a frontend maintainer.

Are the testcases actually C/C++ code?  You can use
testsuite/c-c++-common/ to place tests that run with both frontends.

Richard.

> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/strict-flex-array-1.C: New test.
> 	* g++.dg/strict-flex-array-2.C: New test.
> 	* g++.dg/strict-flex-array-3.C: New test.
> 	* g++.dg/strict-flex-array-4.C: New test.
> 	* gcc.dg/strict-flex-array-1.c: New test.
> 	* gcc.dg/strict-flex-array-2.c: New test.
> 	* gcc.dg/strict-flex-array-3.c: New test.
> 	* gcc.dg/strict-flex-array-4.c: New test.
> ---
>  gcc/c-family/c-attribs.cc                  |  94 +++++++++++++++
>  gcc/c-family/c-opts.cc                     |  41 +++++++
>  gcc/c-family/c.opt                         |   7 ++
>  gcc/c/c-decl.cc                            | 130 +++++++++++++++++++--
>  gcc/cp/module.cc                           |   2 +
>  gcc/doc/extend.texi                        |  33 ++++++
>  gcc/doc/invoke.texi                        |  34 +++++-
>  gcc/print-tree.cc                          |   8 +-
>  gcc/testsuite/g++.dg/strict-flex-array-1.C |  31 +++++
>  gcc/testsuite/g++.dg/strict-flex-array-2.C |  16 +++
>  gcc/testsuite/g++.dg/strict-flex-array-3.C |  21 ++++
>  gcc/testsuite/g++.dg/strict-flex-array-4.C |   9 ++
>  gcc/testsuite/gcc.dg/strict-flex-array-1.c |  31 +++++
>  gcc/testsuite/gcc.dg/strict-flex-array-2.c |  15 +++
>  gcc/testsuite/gcc.dg/strict-flex-array-3.c |  21 ++++
>  gcc/testsuite/gcc.dg/strict-flex-array-4.c |  10 ++
>  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 ++-
>  21 files changed, 541 insertions(+), 28 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-1.C
>  create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-2.C
>  create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-3.C
>  create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-4.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
>  create mode 100644 gcc/testsuite/gcc.dg/strict-flex-array-4.c
> 
> diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
> index e4f1d3542f37..9c9927cefa0d 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,96 @@ 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;
> +    }
> +  else
> +    {
> +      unsigned int level = tree_to_uhwi (argval);
> +      /* check whether the attribute is valid based on language standard.
> +	 the attribute is only valid when flexible array member is
> +	 supported in the language. Therefore, we should invalid this attribute or
> +	 specific level of this attribute for the following situations:
> +	A. When -std=c89 is specified, no language support at all, invalid this
> +	   attribute and issue a warning;
> +	B. When -std=gnu89 is specified, only zero-length array extension and
> +	   one-size array are supported, level=3 will be invalid and a warning
> +	   will be issued.
> +	C. C++ without GNU extension, no language support at all, invalid this
> +	   attribute and issue a warning;
> +	D. C++ with GNU extension, only zero-length array extension and one-size
> +	   array are supported, level=3 will be invalid and a warning will be
> +	   issued.  */
> +      if (level > 0)
> +	{
> +	  if (!c_dialect_cxx () && flag_iso && flag_isoc99 == 0)
> +	  {
> +	    warning (OPT_Wattributes, "%qE attribute ignored since it is "
> +		     "not supported with a ISO C before C99", name);
> +	    *no_add_attrs = true;
> +	  }
> +	  else if (!c_dialect_cxx () && !flag_iso
> +		   && flag_isoc99 == 0 && level == 3)
> +	  {
> +	    warning (OPT_Wattributes, "%qE = 3 attribute ignored since it is "
> +		     "not supported with a GNU extension GNU89", name);
> +	    *no_add_attrs = true;
> +	  }
> +	  else if (c_dialect_cxx () && flag_iso)
> +	  {
> +	    warning (OPT_Wattributes, "%qE attribute ignored since it is "
> +		     "not supported with a ISO C++", name);
> +	    *no_add_attrs = true;
> +	  }
> +	  else if (c_dialect_cxx () && !flag_iso
> +		   && level == 3)
> +	  {
> +	    warning (OPT_Wattributes, "%qE = 3 attribute ignored since it is "
> +		     "not supported for C++ with GNU extension", name);
> +	    *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-opts.cc b/gcc/c-family/c-opts.cc
> index 4e1463689de3..639eb40f3c86 100644
> --- a/gcc/c-family/c-opts.cc
> +++ b/gcc/c-family/c-opts.cc
> @@ -870,6 +870,47 @@ c_common_post_options (const char **pfilename)
>      SET_OPTION_IF_UNSET (&global_options, &global_options_set,
>  			 flag_tree_loop_distribute_patterns, 0);
>  
> +  /* -fstrict-flex-arrays is only valid when flexible array member is
> +     supported in the language. Therefore, we should invalid this option or
> +     specific level of this option for the following situations:
> +     A. When -std=c89 is specified, no language support at all, invalid this
> +	option and issue a warning;
> +     B. When -std=gnu89 is specified, only zero-length array extension and
> +	one-size array are supported, level=3 will be invalid and a warning
> +	will be issued.
> +     C. C++ without GNU extension, no language support at all, invalid this
> +	option and issue a warning;
> +     D. C++ with GNU extension, only zero-length array extension and one-size
> +	array are supported, level=3 will be invalid and a warning will be
> +	issued.  */
> +  if (flag_strict_flex_arrays > 0)
> +    {
> +      if (!c_dialect_cxx () && flag_iso && flag_isoc99 == 0)
> +	{
> +	  flag_strict_flex_arrays = 0;
> +	  warning (0, "%<-fstrict-flex-arrays%> is not supported with a ISO C "
> +		   "before C99, ignored");
> +	}
> +      else if (!c_dialect_cxx () && !flag_iso && flag_isoc99 == 0 && flag_strict_flex_arrays == 3)
> +	{
> +	  flag_strict_flex_arrays = 0;
> +	  warning (0, "%<-fstrict-flex-arrays=3%> is not supported with a "
> +		   "GNU extension GNU89, ignored");
> +	}
> +      else if (c_dialect_cxx () && flag_iso)
> +	{
> +	  flag_strict_flex_arrays = 0;
> +	  warning (0, "%<-fstrict-flex-arrays%> is not supported with a ISO "
> +		   "C++, ignored");
> +	}
> +      else if (c_dialect_cxx () && !flag_iso && flag_strict_flex_arrays == 3)
> +	{
> +	  flag_strict_flex_arrays = 0;
> +	  warning (0, "%<-fstrict-flex-arrays=3%> is not supported for C++ "
> +		   "with GNU extension, ignored");
> +	}
> +    }
> +
>    /* -Woverlength-strings is off by default, but is enabled by -Wpedantic.
>       It is never enabled in C++, as the minimum limit is not normative
>       in that standard.  */
> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
> index 44e1a60ce246..1e944f8a3055 100644
> --- a/gcc/c-family/c.opt
> +++ b/gcc/c-family/c.opt
> @@ -2060,6 +2060,13 @@ fsized-deallocation
>  C++ ObjC++ Var(flag_sized_deallocation) Init(-1)
>  Enable C++14 sized deallocation support.
>  
> +fstrict-flex-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 ae8990c138fd..a2e125d4ddd5 100644
> --- a/gcc/c/c-decl.cc
> +++ b/gcc/c/c-decl.cc
> @@ -4999,6 +4999,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.  */
> @@ -5013,10 +5048,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)
> @@ -8720,6 +8752,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.
> @@ -8781,6 +8888,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;
>  
> @@ -8819,10 +8931,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)
>  	    {
> @@ -8830,7 +8939,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
>  			"flexible array member in union");
>  	      TREE_TYPE (x) = error_mark_node;
>  	    }
> -	  else if (DECL_CHAIN (x) != NULL_TREE)
> +	  else if (!is_last_field)
>  	    {
>  	      error_at (DECL_SOURCE_LOCATION (x),
>  			"flexible array member not at end of struct");
> @@ -8850,6 +8959,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 7fe7f8817cdd..99b43ed3852c 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -7473,6 +7473,39 @@ 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 ([]), it is treated as a flexible array member.
> +
> +There are two more levels in between 0 and 3, which are provided to support
> +older codes that use GCC zero-length array extension ([0]) or one-size array
> +as flexible array member ([1]):
> +When @var{level} is 1, the trailing array is treated as a flexible array member
> +when it is declared as either "[]", "[0]", or "[1]";
> +When @var{level} is 2, the trailing array is treated as a flexible array member
> +when it is declared as either "[]", or "[0]".
> +
> +This attribute can be used with or without 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.
> +
> +This attribute is only valid when flexible array member is supported in the
> +language. For ISO C before C99 and ISO C++, no language support for the flexible
> +array member at all, this attribute will be invalid and a warning is issued.
> +When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
> +extension and one-size array are supported, as a result, @var{level}=3 will be
> +invalid and a warning is issued.
> +
> +
>  @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 863580b3710a..2a0a3cf3de10 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,37 @@ 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_array} attribute (@pxref{Variable Attributes}).
> +
> +You can control this behavior for a specific trailing array field of a
> +structure by using the variable attribute @code{strict_flex_array} attribute
> +(@pxref{Variable Attributes}).
> +
> +This option is only valid when flexible array member is supported in the
> +language. FOR ISO C before C99 and ISO C++, no language support for the flexible
> +array member at all, this option will be invalid and a warning will be issued.
> +When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
> +extension and one-size array are supported, as a result, @var{level}=3 will be
> +invalid and a warning will be issued.
> +
>  @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..47adaf7bac4a
> --- /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/g++.dg/strict-flex-array-2.C b/gcc/testsuite/g++.dg/strict-flex-array-2.C
> new file mode 100644
> index 000000000000..245f8fe0bc73
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/strict-flex-array-2.C
> @@ -0,0 +1,16 @@
> +/* testing the correct usage of flag -fstrict_flex_array for C++.  */   
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fstrict-flex-arrays -std=c++98" } */
> +
> +struct trailing_array {
> +    int a;
> +    int b;
> +    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "attribute ignored since it is not supported with a ISO C\\+\\+" } */
> +};
> +
> +int foo(int a)
> +{
> +  return 0;
> +}
> +
> +/* { dg-warning "is not supported with a ISO C\\+\\+, ignored" ""  { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/g++.dg/strict-flex-array-3.C b/gcc/testsuite/g++.dg/strict-flex-array-3.C
> new file mode 100644
> index 000000000000..2a733a5bccf4
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/strict-flex-array-3.C
> @@ -0,0 +1,21 @@
> +/* testing the correct usage of flag -fstrict_flex_array for C++.  */   
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fstrict-flex-arrays -std=gnu++98" } */
> +/* { dg-warning "'-fstrict-flex-arrays=3' is not supported for C\\+\\+ with GNU extension, ignored" ""  { target *-*-* } 0 } */
> +
> +struct trailing_array {
> +    int a;
> +    int b;
> +    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "'strict_flex_arrays' = 3 attribute ignored since it is not supported for C\\+\\+ with GNU extension" } */
> +};
> +
> +struct trailing_array_1 {
> +    int a;
> +    int b;
> +    int c[0] __attribute ((strict_flex_arrays (2))); /* { dg-bogus "'strict_flex_arrays' = 3 attribute ignored since it is not supported for C\\+\\+ with GNU extension" } */
> +};
> +
> +int foo(int a)
> +{
> +  return a + 2;
> +}
> diff --git a/gcc/testsuite/g++.dg/strict-flex-array-4.C b/gcc/testsuite/g++.dg/strict-flex-array-4.C
> new file mode 100644
> index 000000000000..804e4cf459ef
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/strict-flex-array-4.C
> @@ -0,0 +1,9 @@
> +/* testing the correct usage of flag -fstrict_flex_array.  */   
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fstrict-flex-arrays=2 -std=gnu++98" } */
> +/* { dg-bogus "is not supported for C\\+\\+ with GNU extension, ignored" ""  { target *-*-* } 0 } */
> +
> +int foo(int a)
> +{
> +  return a + 2;
> +}
> 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..47adaf7bac4a
> --- /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/testsuite/gcc.dg/strict-flex-array-2.c b/gcc/testsuite/gcc.dg/strict-flex-array-2.c
> new file mode 100644
> index 000000000000..967a240040dc
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/strict-flex-array-2.c
> @@ -0,0 +1,15 @@
> +/* testing the correct usage of flag -fstrict_flex_array.  */   
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fstrict-flex-arrays -std=c89" } */
> +/* { dg-warning "'-fstrict-flex-arrays' is not supported with a ISO C before C99, ignored" ""  { target *-*-* } 0 } */
> +
> +struct trailing_array {
> +    int a;
> +    int b;
> +    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "'strict_flex_arrays' attribute ignored since it is not supported with a ISO C before C99" } */
> +};
> +
> +int foo(int a)
> +{
> +  return a + 2;
> +}
> 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..879de7f203c8
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/strict-flex-array-3.c
> @@ -0,0 +1,21 @@
> +/* testing the correct usage of flag -fstrict_flex_array.  */   
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fstrict-flex-arrays -std=gnu89" } */
> +/* { dg-warning "'-fstrict-flex-arrays=3' is not supported with a GNU extension GNU89, ignored" ""  { target *-*-* } 0 } */
> +
> +struct trailing_array {
> +    int a;
> +    int b;
> +    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "'strict_flex_arrays' = 3 attribute ignored since it is not supported with a GNU extension GNU89" } */
> +};
> +
> +struct trailing_array_1 {
> +    int a;
> +    int b;
> +    int c[0] __attribute ((strict_flex_arrays (2))); /* { dg-bogus "'strict_flex_arrays' = 3 attribute ignored since it is not supported with a GNU extension GNU89" } */
> +};
> +
> +int foo(int a)
> +{
> +  return a + 2;
> +}
> diff --git a/gcc/testsuite/gcc.dg/strict-flex-array-4.c b/gcc/testsuite/gcc.dg/strict-flex-array-4.c
> new file mode 100644
> index 000000000000..ce64c24db301
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/strict-flex-array-4.c
> @@ -0,0 +1,10 @@
> +/* testing the correct usage of flag -fstrict_flex_array.  */   
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fstrict-flex-arrays=2 -std=gnu89" } */
> +/* { dg-bogus "is not supported with a GNU extension GNU89, ignored" ""  { target *-*-* } 0 } */
> +
> +
> +int foo(int a)
> +{
> +  return a + 2;
> +}
> diff --git a/gcc/tree-core.h b/gcc/tree-core.h
> index 86a07c282af2..f822cb539dd0 100644
> --- a/gcc/tree-core.h
> +++ b/gcc/tree-core.h
> @@ -1813,7 +1813,10 @@ struct GTY(()) tree_decl_common {
>       TYPE_WARN_IF_NOT_ALIGN.  */
>    unsigned int warn_if_not_align : 6;
>  
> -  /* 14 bits unused.  */
> +  /* In FIELD_DECL, this is DECL_NOT_FLEXARRAY.  */
> +  unsigned int decl_not_flexarray : 1;
> +
> +  /* 13 bits unused.  */
>  
>    /* UID for points-to sets, stable over copying from inlining.  */
>    unsigned int pt_uid;
> diff --git a/gcc/tree-streamer-in.cc b/gcc/tree-streamer-in.cc
> index 196f19c759f2..21e6e8eb1c0a 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 d39dc158a465..68e40dbdb8f2 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 fed1434d141d..d698e8c9c213 100644
> --- a/gcc/tree.cc
> +++ b/gcc/tree.cc
> @@ -12678,14 +12678,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)
> @@ -12695,7 +12711,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);
> @@ -12707,6 +12726,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))
> @@ -12760,13 +12780,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).  */
> @@ -12788,9 +12811,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)))
> @@ -12798,12 +12821,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 e6564aaccb7b..f911c0a46e69 100644
> --- a/gcc/tree.h
> +++ b/gcc/tree.h
> @@ -2993,6 +2993,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.  */
> @@ -5531,10 +5537,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
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
HRB 36809 (AG Nuernberg)

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

* Re: [[GCC13][Patch][V3] 2/2] Use array_at_struct_end_p in __builtin_object_size [PR101836]
  2022-08-17 14:40 ` [[GCC13][Patch][V3] 2/2] Use array_at_struct_end_p in __builtin_object_size [PR101836] Qing Zhao
@ 2022-08-26  8:49   ` Richard Biener
  2022-08-26 13:37     ` Qing Zhao
  0 siblings, 1 reply; 27+ messages in thread
From: Richard Biener @ 2022-08-26  8:49 UTC (permalink / raw)
  To: Qing Zhao; +Cc: gcc-patches, jakub, msebor, keescook, joseph

On Wed, 17 Aug 2022, Qing Zhao wrote:

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

With the discussion about what array_at_struct_end_p actually computes,
is this now the correct utility for __builtin_object_size or should
it use a stricter variant?

> 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-5.c: New test.
> 	* gcc.dg/strict-flex-array-6.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-5.c | 60 ++++++++++++++++++++++
>  gcc/testsuite/gcc.dg/strict-flex-array-6.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-5.c
>  create mode 100644 gcc/testsuite/gcc.dg/strict-flex-array-6.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-5.c b/gcc/testsuite/gcc.dg/strict-flex-array-5.c
> new file mode 100644
> index 000000000000..e474b9ec43fa
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/strict-flex-array-5.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-6.c b/gcc/testsuite/gcc.dg/strict-flex-array-6.c
> new file mode 100644
> index 000000000000..b45e7b32f6d1
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/strict-flex-array-6.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;
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
HRB 36809 (AG Nuernberg)

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

* Re: [[GCC13][Patch][V3] 2/2] Use array_at_struct_end_p in __builtin_object_size [PR101836]
  2022-08-26  8:49   ` Richard Biener
@ 2022-08-26 13:37     ` Qing Zhao
  0 siblings, 0 replies; 27+ messages in thread
From: Qing Zhao @ 2022-08-26 13:37 UTC (permalink / raw)
  To: Richard Biener, Kees Cook
  Cc: GCC Patches, jakub Jelinek, martin Sebor, joseph



> On Aug 26, 2022, at 4:49 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Wed, 17 Aug 2022, Qing Zhao wrote:
> 
>> Use array_at_struct_end_p to determine whether the trailing array
>> of a structure is flexible array member in __builtin_object_size.
> 
> With the discussion about what array_at_struct_end_p actually computes,
> is this now the correct utility for __builtin_object_size or should
> it use a stricter variant?

My understanding is, -fstrict-flex-arrays should control all the GCC analysis consistently, including __bultin_object_size. 
For a standard conforming application, use -fstrict-flex-arrays=3 for the most efficient code. 

Kees, is it okay for Linux Kernel to add -fstrict-flex-arrays in order to enable FORTIFY_SOURCE work better for regular trailing arrays?

Thanks.

Qing
> 
>> 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-5.c: New test.
>> 	* gcc.dg/strict-flex-array-6.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-5.c | 60 ++++++++++++++++++++++
>> gcc/testsuite/gcc.dg/strict-flex-array-6.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-5.c
>> create mode 100644 gcc/testsuite/gcc.dg/strict-flex-array-6.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-5.c b/gcc/testsuite/gcc.dg/strict-flex-array-5.c
>> new file mode 100644
>> index 000000000000..e474b9ec43fa
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/strict-flex-array-5.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-6.c b/gcc/testsuite/gcc.dg/strict-flex-array-6.c
>> new file mode 100644
>> index 000000000000..b45e7b32f6d1
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/strict-flex-array-6.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;
>> 
> 
> -- 
> Richard Biener <rguenther@suse.de>
> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
> Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
> HRB 36809 (AG Nuernberg)


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

* Re: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-26  8:48 ` [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array Richard Biener
@ 2022-08-26 13:47   ` Qing Zhao
  2022-08-29  8:04     ` Richard Biener
  0 siblings, 1 reply; 27+ messages in thread
From: Qing Zhao @ 2022-08-26 13:47 UTC (permalink / raw)
  To: Richard Biener, joseph, Nathan Sidwell
  Cc: GCC Patches, jakub Jelinek, martin Sebor, Kees Cook



> On Aug 26, 2022, at 4:48 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Wed, 17 Aug 2022, Qing Zhao wrote:
> 
>> Add the following new option -fstrict-flex-array[=n] and a corresponding
>> attribute strict_flex_array to GCC:
>> 
>> '-fstrict-flex-array'
>>     Treat the trailing array of a structure as a flexible array member
>>     in a stricter way.  The positive form is equivalent to
>>     '-fstrict-flex-array=3', which is the strictest.  A trailing array
>>     is treated as a flexible array member only when it is declared as a
>>     flexible array member per C99 standard onwards.  The negative form
>>     is equivalent to '-fstrict-flex-array=0', which is the least
>>     strict.  All trailing arrays of structures are treated as flexible
>>     array members.
>> 
>> '-fstrict-flex-array=LEVEL'
>>     Treat the trailing array of a structure as a flexible array member
>>     in a stricter way.  The value of LEVEL controls the level of
>>     strictness.
>> 
>>     The possible values of LEVEL are the same as for the
>>     'strict_flex_array' attribute (*note Variable Attributes::).
>> 
>>     You can control this behavior for a specific trailing array field
>>     of a structure by using the variable attribute 'strict_flex_array'
>>     attribute (*note Variable Attributes::).
>> 
>>     This option is only valid when flexible array member is supported in the
>>     language. FOR ISO C before C99 and ISO C++, no language support for the flexible
>>     array member at all, this option will be invalid and a warning will be issued.
>>     When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
>>     extension and one-size array are supported, as a result, LEVEL=3 will be
>>     invalid and a warning will be issued.
>> 
>> 'strict_flex_array (LEVEL)'
>>     The 'strict_flex_array' attribute should be attached to the
>>     trailing array field of a structure.  It specifies the level of
>>     strictness of treating the trailing array field of a structure as a
>>     flexible array member.  LEVEL must be an integer betwen 0 to 3.
>> 
>>     LEVEL=0 is the least strict level, all trailing arrays of
>>     structures are treated as flexible array members.  LEVEL=3 is the
>>     strictest level, only when the trailing array is declared as a
>>     flexible array member per C99 standard onwards ([]), it is treated
>>     as a flexible array member.
>> 
>>     There are two more levels in between 0 and 3, which are provided to
>>     support older codes that use GCC zero-length array extension ([0])
>>     or one-size array as flexible array member ([1]): When LEVEL is 1,
>>     the trailing array is treated as a flexible array member when it is
>>     declared as either [], [0], or [1]; When LEVEL is 2, the trailing
>>     array is treated as a flexible array member when it is declared as
>>     either [], or [0].
>> 
>>     This attribute can be used with or without '-fstrict-flex-array'.
>>     When both the attribute and the option present at the same time,
>>     the level of the strictness for the specific trailing array field
>>     is determined by the attribute.
>> 
>>     This attribute is only valid when flexible array member is supported in the
>>     language. For ISO C before C99 and ISO C++, no language support for the flexible
>>     array member at all, this attribute will be invalid and a warning is issued.
>>     When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
>>     extension and one-size array are supported, as a result, LEVEL=3 will be
>>     invalid and a warning is issued.
>> 
>> gcc/c-family/ChangeLog:
>> 
>> 	* c-attribs.cc (handle_strict_flex_arrays_attribute): New function.
>> 	(c_common_attribute_table): New item for strict_flex_array.
>> 	* c-opts.cc (c_common_post_options): Handle the combination of
>> 	-fstrict-flex-arrays and -std specially.
>> 	* c.opt: (fstrict-flex-array): New option.
>> 	(fstrict-flex-array=): 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_array attribute.
>> 	* doc/invoke.texi: Document -fstrict-flex-array[=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 fla
> 
> The middle-end changes are OK, the c/ and cp/ changes need review
> from a frontend maintainer.

I CC’ed Joseph Myers for the FE part review. Joseph, could you please review the changes in c-family and c?
And Nathan Sidwell for the C++ part, Nathan, could you please review the changes in cp?


> 
> Are the testcases actually C/C++ code?  You can use
> testsuite/c-c++-common/ to place tests that run with both frontends.

The major issue when I tried to add these test cases into c-c++-common is, these testing cases mainly for the options usage, for example, -std=c89, -std=gnu89 for C, -std=c++98, -std=gnu++98 for C++.

For C and C++, the options that are tested are different. So, I am not sure how can I put the same testing case for C and C++ but with different options?

Qing

> 
> Richard.
> 
>> 
>> gcc/testsuite/ChangeLog:
>> 
>> 	* g++.dg/strict-flex-array-1.C: New test.
>> 	* g++.dg/strict-flex-array-2.C: New test.
>> 	* g++.dg/strict-flex-array-3.C: New test.
>> 	* g++.dg/strict-flex-array-4.C: New test.
>> 	* gcc.dg/strict-flex-array-1.c: New test.
>> 	* gcc.dg/strict-flex-array-2.c: New test.
>> 	* gcc.dg/strict-flex-array-3.c: New test.
>> 	* gcc.dg/strict-flex-array-4.c: New test.
>> ---
>> gcc/c-family/c-attribs.cc                  |  94 +++++++++++++++
>> gcc/c-family/c-opts.cc                     |  41 +++++++
>> gcc/c-family/c.opt                         |   7 ++
>> gcc/c/c-decl.cc                            | 130 +++++++++++++++++++--
>> gcc/cp/module.cc                           |   2 +
>> gcc/doc/extend.texi                        |  33 ++++++
>> gcc/doc/invoke.texi                        |  34 +++++-
>> gcc/print-tree.cc                          |   8 +-
>> gcc/testsuite/g++.dg/strict-flex-array-1.C |  31 +++++
>> gcc/testsuite/g++.dg/strict-flex-array-2.C |  16 +++
>> gcc/testsuite/g++.dg/strict-flex-array-3.C |  21 ++++
>> gcc/testsuite/g++.dg/strict-flex-array-4.C |   9 ++
>> gcc/testsuite/gcc.dg/strict-flex-array-1.c |  31 +++++
>> gcc/testsuite/gcc.dg/strict-flex-array-2.c |  15 +++
>> gcc/testsuite/gcc.dg/strict-flex-array-3.c |  21 ++++
>> gcc/testsuite/gcc.dg/strict-flex-array-4.c |  10 ++
>> 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 ++-
>> 21 files changed, 541 insertions(+), 28 deletions(-)
>> create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-1.C
>> create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-2.C
>> create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-3.C
>> create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-4.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
>> create mode 100644 gcc/testsuite/gcc.dg/strict-flex-array-4.c
>> 
>> diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
>> index e4f1d3542f37..9c9927cefa0d 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,96 @@ 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;
>> +    }
>> +  else
>> +    {
>> +      unsigned int level = tree_to_uhwi (argval);
>> +      /* check whether the attribute is valid based on language standard.
>> +	 the attribute is only valid when flexible array member is
>> +	 supported in the language. Therefore, we should invalid this attribute or
>> +	 specific level of this attribute for the following situations:
>> +	A. When -std=c89 is specified, no language support at all, invalid this
>> +	   attribute and issue a warning;
>> +	B. When -std=gnu89 is specified, only zero-length array extension and
>> +	   one-size array are supported, level=3 will be invalid and a warning
>> +	   will be issued.
>> +	C. C++ without GNU extension, no language support at all, invalid this
>> +	   attribute and issue a warning;
>> +	D. C++ with GNU extension, only zero-length array extension and one-size
>> +	   array are supported, level=3 will be invalid and a warning will be
>> +	   issued.  */
>> +      if (level > 0)
>> +	{
>> +	  if (!c_dialect_cxx () && flag_iso && flag_isoc99 == 0)
>> +	  {
>> +	    warning (OPT_Wattributes, "%qE attribute ignored since it is "
>> +		     "not supported with a ISO C before C99", name);
>> +	    *no_add_attrs = true;
>> +	  }
>> +	  else if (!c_dialect_cxx () && !flag_iso
>> +		   && flag_isoc99 == 0 && level == 3)
>> +	  {
>> +	    warning (OPT_Wattributes, "%qE = 3 attribute ignored since it is "
>> +		     "not supported with a GNU extension GNU89", name);
>> +	    *no_add_attrs = true;
>> +	  }
>> +	  else if (c_dialect_cxx () && flag_iso)
>> +	  {
>> +	    warning (OPT_Wattributes, "%qE attribute ignored since it is "
>> +		     "not supported with a ISO C++", name);
>> +	    *no_add_attrs = true;
>> +	  }
>> +	  else if (c_dialect_cxx () && !flag_iso
>> +		   && level == 3)
>> +	  {
>> +	    warning (OPT_Wattributes, "%qE = 3 attribute ignored since it is "
>> +		     "not supported for C++ with GNU extension", name);
>> +	    *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-opts.cc b/gcc/c-family/c-opts.cc
>> index 4e1463689de3..639eb40f3c86 100644
>> --- a/gcc/c-family/c-opts.cc
>> +++ b/gcc/c-family/c-opts.cc
>> @@ -870,6 +870,47 @@ c_common_post_options (const char **pfilename)
>>     SET_OPTION_IF_UNSET (&global_options, &global_options_set,
>> 			 flag_tree_loop_distribute_patterns, 0);
>> 
>> +  /* -fstrict-flex-arrays is only valid when flexible array member is
>> +     supported in the language. Therefore, we should invalid this option or
>> +     specific level of this option for the following situations:
>> +     A. When -std=c89 is specified, no language support at all, invalid this
>> +	option and issue a warning;
>> +     B. When -std=gnu89 is specified, only zero-length array extension and
>> +	one-size array are supported, level=3 will be invalid and a warning
>> +	will be issued.
>> +     C. C++ without GNU extension, no language support at all, invalid this
>> +	option and issue a warning;
>> +     D. C++ with GNU extension, only zero-length array extension and one-size
>> +	array are supported, level=3 will be invalid and a warning will be
>> +	issued.  */
>> +  if (flag_strict_flex_arrays > 0)
>> +    {
>> +      if (!c_dialect_cxx () && flag_iso && flag_isoc99 == 0)
>> +	{
>> +	  flag_strict_flex_arrays = 0;
>> +	  warning (0, "%<-fstrict-flex-arrays%> is not supported with a ISO C "
>> +		   "before C99, ignored");
>> +	}
>> +      else if (!c_dialect_cxx () && !flag_iso && flag_isoc99 == 0 && flag_strict_flex_arrays == 3)
>> +	{
>> +	  flag_strict_flex_arrays = 0;
>> +	  warning (0, "%<-fstrict-flex-arrays=3%> is not supported with a "
>> +		   "GNU extension GNU89, ignored");
>> +	}
>> +      else if (c_dialect_cxx () && flag_iso)
>> +	{
>> +	  flag_strict_flex_arrays = 0;
>> +	  warning (0, "%<-fstrict-flex-arrays%> is not supported with a ISO "
>> +		   "C++, ignored");
>> +	}
>> +      else if (c_dialect_cxx () && !flag_iso && flag_strict_flex_arrays == 3)
>> +	{
>> +	  flag_strict_flex_arrays = 0;
>> +	  warning (0, "%<-fstrict-flex-arrays=3%> is not supported for C++ "
>> +		   "with GNU extension, ignored");
>> +	}
>> +    }
>> +
>>   /* -Woverlength-strings is off by default, but is enabled by -Wpedantic.
>>      It is never enabled in C++, as the minimum limit is not normative
>>      in that standard.  */
>> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
>> index 44e1a60ce246..1e944f8a3055 100644
>> --- a/gcc/c-family/c.opt
>> +++ b/gcc/c-family/c.opt
>> @@ -2060,6 +2060,13 @@ fsized-deallocation
>> C++ ObjC++ Var(flag_sized_deallocation) Init(-1)
>> Enable C++14 sized deallocation support.
>> 
>> +fstrict-flex-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 ae8990c138fd..a2e125d4ddd5 100644
>> --- a/gcc/c/c-decl.cc
>> +++ b/gcc/c/c-decl.cc
>> @@ -4999,6 +4999,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.  */
>> @@ -5013,10 +5048,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)
>> @@ -8720,6 +8752,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.
>> @@ -8781,6 +8888,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;
>> 
>> @@ -8819,10 +8931,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)
>> 	    {
>> @@ -8830,7 +8939,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
>> 			"flexible array member in union");
>> 	      TREE_TYPE (x) = error_mark_node;
>> 	    }
>> -	  else if (DECL_CHAIN (x) != NULL_TREE)
>> +	  else if (!is_last_field)
>> 	    {
>> 	      error_at (DECL_SOURCE_LOCATION (x),
>> 			"flexible array member not at end of struct");
>> @@ -8850,6 +8959,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 7fe7f8817cdd..99b43ed3852c 100644
>> --- a/gcc/doc/extend.texi
>> +++ b/gcc/doc/extend.texi
>> @@ -7473,6 +7473,39 @@ 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 ([]), it is treated as a flexible array member.
>> +
>> +There are two more levels in between 0 and 3, which are provided to support
>> +older codes that use GCC zero-length array extension ([0]) or one-size array
>> +as flexible array member ([1]):
>> +When @var{level} is 1, the trailing array is treated as a flexible array member
>> +when it is declared as either "[]", "[0]", or "[1]";
>> +When @var{level} is 2, the trailing array is treated as a flexible array member
>> +when it is declared as either "[]", or "[0]".
>> +
>> +This attribute can be used with or without 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.
>> +
>> +This attribute is only valid when flexible array member is supported in the
>> +language. For ISO C before C99 and ISO C++, no language support for the flexible
>> +array member at all, this attribute will be invalid and a warning is issued.
>> +When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
>> +extension and one-size array are supported, as a result, @var{level}=3 will be
>> +invalid and a warning is issued.
>> +
>> +
>> @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 863580b3710a..2a0a3cf3de10 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,37 @@ 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_array} attribute (@pxref{Variable Attributes}).
>> +
>> +You can control this behavior for a specific trailing array field of a
>> +structure by using the variable attribute @code{strict_flex_array} attribute
>> +(@pxref{Variable Attributes}).
>> +
>> +This option is only valid when flexible array member is supported in the
>> +language. FOR ISO C before C99 and ISO C++, no language support for the flexible
>> +array member at all, this option will be invalid and a warning will be issued.
>> +When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
>> +extension and one-size array are supported, as a result, @var{level}=3 will be
>> +invalid and a warning will be issued.
>> +
>> @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..47adaf7bac4a
>> --- /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/g++.dg/strict-flex-array-2.C b/gcc/testsuite/g++.dg/strict-flex-array-2.C
>> new file mode 100644
>> index 000000000000..245f8fe0bc73
>> --- /dev/null
>> +++ b/gcc/testsuite/g++.dg/strict-flex-array-2.C
>> @@ -0,0 +1,16 @@
>> +/* testing the correct usage of flag -fstrict_flex_array for C++.  */   
>> +/* { dg-do compile } */
>> +/* { dg-options "-O2 -fstrict-flex-arrays -std=c++98" } */
>> +
>> +struct trailing_array {
>> +    int a;
>> +    int b;
>> +    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "attribute ignored since it is not supported with a ISO C\\+\\+" } */
>> +};
>> +
>> +int foo(int a)
>> +{
>> +  return 0;
>> +}
>> +
>> +/* { dg-warning "is not supported with a ISO C\\+\\+, ignored" ""  { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/g++.dg/strict-flex-array-3.C b/gcc/testsuite/g++.dg/strict-flex-array-3.C
>> new file mode 100644
>> index 000000000000..2a733a5bccf4
>> --- /dev/null
>> +++ b/gcc/testsuite/g++.dg/strict-flex-array-3.C
>> @@ -0,0 +1,21 @@
>> +/* testing the correct usage of flag -fstrict_flex_array for C++.  */   
>> +/* { dg-do compile } */
>> +/* { dg-options "-O2 -fstrict-flex-arrays -std=gnu++98" } */
>> +/* { dg-warning "'-fstrict-flex-arrays=3' is not supported for C\\+\\+ with GNU extension, ignored" ""  { target *-*-* } 0 } */
>> +
>> +struct trailing_array {
>> +    int a;
>> +    int b;
>> +    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "'strict_flex_arrays' = 3 attribute ignored since it is not supported for C\\+\\+ with GNU extension" } */
>> +};
>> +
>> +struct trailing_array_1 {
>> +    int a;
>> +    int b;
>> +    int c[0] __attribute ((strict_flex_arrays (2))); /* { dg-bogus "'strict_flex_arrays' = 3 attribute ignored since it is not supported for C\\+\\+ with GNU extension" } */
>> +};
>> +
>> +int foo(int a)
>> +{
>> +  return a + 2;
>> +}
>> diff --git a/gcc/testsuite/g++.dg/strict-flex-array-4.C b/gcc/testsuite/g++.dg/strict-flex-array-4.C
>> new file mode 100644
>> index 000000000000..804e4cf459ef
>> --- /dev/null
>> +++ b/gcc/testsuite/g++.dg/strict-flex-array-4.C
>> @@ -0,0 +1,9 @@
>> +/* testing the correct usage of flag -fstrict_flex_array.  */   
>> +/* { dg-do compile } */
>> +/* { dg-options "-O2 -fstrict-flex-arrays=2 -std=gnu++98" } */
>> +/* { dg-bogus "is not supported for C\\+\\+ with GNU extension, ignored" ""  { target *-*-* } 0 } */
>> +
>> +int foo(int a)
>> +{
>> +  return a + 2;
>> +}
>> 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..47adaf7bac4a
>> --- /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/testsuite/gcc.dg/strict-flex-array-2.c b/gcc/testsuite/gcc.dg/strict-flex-array-2.c
>> new file mode 100644
>> index 000000000000..967a240040dc
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/strict-flex-array-2.c
>> @@ -0,0 +1,15 @@
>> +/* testing the correct usage of flag -fstrict_flex_array.  */   
>> +/* { dg-do compile } */
>> +/* { dg-options "-O2 -fstrict-flex-arrays -std=c89" } */
>> +/* { dg-warning "'-fstrict-flex-arrays' is not supported with a ISO C before C99, ignored" ""  { target *-*-* } 0 } */
>> +
>> +struct trailing_array {
>> +    int a;
>> +    int b;
>> +    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "'strict_flex_arrays' attribute ignored since it is not supported with a ISO C before C99" } */
>> +};
>> +
>> +int foo(int a)
>> +{
>> +  return a + 2;
>> +}
>> 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..879de7f203c8
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/strict-flex-array-3.c
>> @@ -0,0 +1,21 @@
>> +/* testing the correct usage of flag -fstrict_flex_array.  */   
>> +/* { dg-do compile } */
>> +/* { dg-options "-O2 -fstrict-flex-arrays -std=gnu89" } */
>> +/* { dg-warning "'-fstrict-flex-arrays=3' is not supported with a GNU extension GNU89, ignored" ""  { target *-*-* } 0 } */
>> +
>> +struct trailing_array {
>> +    int a;
>> +    int b;
>> +    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "'strict_flex_arrays' = 3 attribute ignored since it is not supported with a GNU extension GNU89" } */
>> +};
>> +
>> +struct trailing_array_1 {
>> +    int a;
>> +    int b;
>> +    int c[0] __attribute ((strict_flex_arrays (2))); /* { dg-bogus "'strict_flex_arrays' = 3 attribute ignored since it is not supported with a GNU extension GNU89" } */
>> +};
>> +
>> +int foo(int a)
>> +{
>> +  return a + 2;
>> +}
>> diff --git a/gcc/testsuite/gcc.dg/strict-flex-array-4.c b/gcc/testsuite/gcc.dg/strict-flex-array-4.c
>> new file mode 100644
>> index 000000000000..ce64c24db301
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/strict-flex-array-4.c
>> @@ -0,0 +1,10 @@
>> +/* testing the correct usage of flag -fstrict_flex_array.  */   
>> +/* { dg-do compile } */
>> +/* { dg-options "-O2 -fstrict-flex-arrays=2 -std=gnu89" } */
>> +/* { dg-bogus "is not supported with a GNU extension GNU89, ignored" ""  { target *-*-* } 0 } */
>> +
>> +
>> +int foo(int a)
>> +{
>> +  return a + 2;
>> +}
>> diff --git a/gcc/tree-core.h b/gcc/tree-core.h
>> index 86a07c282af2..f822cb539dd0 100644
>> --- a/gcc/tree-core.h
>> +++ b/gcc/tree-core.h
>> @@ -1813,7 +1813,10 @@ struct GTY(()) tree_decl_common {
>>      TYPE_WARN_IF_NOT_ALIGN.  */
>>   unsigned int warn_if_not_align : 6;
>> 
>> -  /* 14 bits unused.  */
>> +  /* In FIELD_DECL, this is DECL_NOT_FLEXARRAY.  */
>> +  unsigned int decl_not_flexarray : 1;
>> +
>> +  /* 13 bits unused.  */
>> 
>>   /* UID for points-to sets, stable over copying from inlining.  */
>>   unsigned int pt_uid;
>> diff --git a/gcc/tree-streamer-in.cc b/gcc/tree-streamer-in.cc
>> index 196f19c759f2..21e6e8eb1c0a 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 d39dc158a465..68e40dbdb8f2 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 fed1434d141d..d698e8c9c213 100644
>> --- a/gcc/tree.cc
>> +++ b/gcc/tree.cc
>> @@ -12678,14 +12678,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)
>> @@ -12695,7 +12711,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);
>> @@ -12707,6 +12726,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))
>> @@ -12760,13 +12780,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).  */
>> @@ -12788,9 +12811,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)))
>> @@ -12798,12 +12821,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 e6564aaccb7b..f911c0a46e69 100644
>> --- a/gcc/tree.h
>> +++ b/gcc/tree.h
>> @@ -2993,6 +2993,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.  */
>> @@ -5531,10 +5537,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
>> 
> 
> -- 
> Richard Biener <rguenther@suse.de>
> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
> Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
> HRB 36809 (AG Nuernberg)


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

* Re: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-26 13:47   ` Qing Zhao
@ 2022-08-29  8:04     ` Richard Biener
  0 siblings, 0 replies; 27+ messages in thread
From: Richard Biener @ 2022-08-29  8:04 UTC (permalink / raw)
  To: Qing Zhao
  Cc: joseph, Nathan Sidwell, GCC Patches, jakub Jelinek, martin Sebor,
	Kees Cook

On Fri, 26 Aug 2022, Qing Zhao wrote:

> 
> 
> > On Aug 26, 2022, at 4:48 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> > On Wed, 17 Aug 2022, Qing Zhao wrote:
> > 
> >> Add the following new option -fstrict-flex-array[=n] and a corresponding
> >> attribute strict_flex_array to GCC:
> >> 
> >> '-fstrict-flex-array'
> >>     Treat the trailing array of a structure as a flexible array member
> >>     in a stricter way.  The positive form is equivalent to
> >>     '-fstrict-flex-array=3', which is the strictest.  A trailing array
> >>     is treated as a flexible array member only when it is declared as a
> >>     flexible array member per C99 standard onwards.  The negative form
> >>     is equivalent to '-fstrict-flex-array=0', which is the least
> >>     strict.  All trailing arrays of structures are treated as flexible
> >>     array members.
> >> 
> >> '-fstrict-flex-array=LEVEL'
> >>     Treat the trailing array of a structure as a flexible array member
> >>     in a stricter way.  The value of LEVEL controls the level of
> >>     strictness.
> >> 
> >>     The possible values of LEVEL are the same as for the
> >>     'strict_flex_array' attribute (*note Variable Attributes::).
> >> 
> >>     You can control this behavior for a specific trailing array field
> >>     of a structure by using the variable attribute 'strict_flex_array'
> >>     attribute (*note Variable Attributes::).
> >> 
> >>     This option is only valid when flexible array member is supported in the
> >>     language. FOR ISO C before C99 and ISO C++, no language support for the flexible
> >>     array member at all, this option will be invalid and a warning will be issued.
> >>     When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
> >>     extension and one-size array are supported, as a result, LEVEL=3 will be
> >>     invalid and a warning will be issued.
> >> 
> >> 'strict_flex_array (LEVEL)'
> >>     The 'strict_flex_array' attribute should be attached to the
> >>     trailing array field of a structure.  It specifies the level of
> >>     strictness of treating the trailing array field of a structure as a
> >>     flexible array member.  LEVEL must be an integer betwen 0 to 3.
> >> 
> >>     LEVEL=0 is the least strict level, all trailing arrays of
> >>     structures are treated as flexible array members.  LEVEL=3 is the
> >>     strictest level, only when the trailing array is declared as a
> >>     flexible array member per C99 standard onwards ([]), it is treated
> >>     as a flexible array member.
> >> 
> >>     There are two more levels in between 0 and 3, which are provided to
> >>     support older codes that use GCC zero-length array extension ([0])
> >>     or one-size array as flexible array member ([1]): When LEVEL is 1,
> >>     the trailing array is treated as a flexible array member when it is
> >>     declared as either [], [0], or [1]; When LEVEL is 2, the trailing
> >>     array is treated as a flexible array member when it is declared as
> >>     either [], or [0].
> >> 
> >>     This attribute can be used with or without '-fstrict-flex-array'.
> >>     When both the attribute and the option present at the same time,
> >>     the level of the strictness for the specific trailing array field
> >>     is determined by the attribute.
> >> 
> >>     This attribute is only valid when flexible array member is supported in the
> >>     language. For ISO C before C99 and ISO C++, no language support for the flexible
> >>     array member at all, this attribute will be invalid and a warning is issued.
> >>     When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
> >>     extension and one-size array are supported, as a result, LEVEL=3 will be
> >>     invalid and a warning is issued.
> >> 
> >> gcc/c-family/ChangeLog:
> >> 
> >> 	* c-attribs.cc (handle_strict_flex_arrays_attribute): New function.
> >> 	(c_common_attribute_table): New item for strict_flex_array.
> >> 	* c-opts.cc (c_common_post_options): Handle the combination of
> >> 	-fstrict-flex-arrays and -std specially.
> >> 	* c.opt: (fstrict-flex-array): New option.
> >> 	(fstrict-flex-array=): 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_array attribute.
> >> 	* doc/invoke.texi: Document -fstrict-flex-array[=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 fla
> > 
> > The middle-end changes are OK, the c/ and cp/ changes need review
> > from a frontend maintainer.
> 
> I CC?ed Joseph Myers for the FE part review. Joseph, could you please review the changes in c-family and c?
> And Nathan Sidwell for the C++ part, Nathan, could you please review the changes in cp?
> 
> 
> > 
> > Are the testcases actually C/C++ code?  You can use
> > testsuite/c-c++-common/ to place tests that run with both frontends.
> 
> The major issue when I tried to add these test cases into c-c++-common is, these testing cases mainly for the options usage, for example, -std=c89, -std=gnu89 for C, -std=c++98, -std=gnu++98 for C++.
> 
> For C and C++, the options that are tested are different. So, I am not 
> sure how can I put the same testing case for C and C++ but with 
> different options?

Ah, right, I failed to spot that.

Richard.

> Qing
> 
> > 
> > Richard.
> > 
> >> 
> >> gcc/testsuite/ChangeLog:
> >> 
> >> 	* g++.dg/strict-flex-array-1.C: New test.
> >> 	* g++.dg/strict-flex-array-2.C: New test.
> >> 	* g++.dg/strict-flex-array-3.C: New test.
> >> 	* g++.dg/strict-flex-array-4.C: New test.
> >> 	* gcc.dg/strict-flex-array-1.c: New test.
> >> 	* gcc.dg/strict-flex-array-2.c: New test.
> >> 	* gcc.dg/strict-flex-array-3.c: New test.
> >> 	* gcc.dg/strict-flex-array-4.c: New test.
> >> ---
> >> gcc/c-family/c-attribs.cc                  |  94 +++++++++++++++
> >> gcc/c-family/c-opts.cc                     |  41 +++++++
> >> gcc/c-family/c.opt                         |   7 ++
> >> gcc/c/c-decl.cc                            | 130 +++++++++++++++++++--
> >> gcc/cp/module.cc                           |   2 +
> >> gcc/doc/extend.texi                        |  33 ++++++
> >> gcc/doc/invoke.texi                        |  34 +++++-
> >> gcc/print-tree.cc                          |   8 +-
> >> gcc/testsuite/g++.dg/strict-flex-array-1.C |  31 +++++
> >> gcc/testsuite/g++.dg/strict-flex-array-2.C |  16 +++
> >> gcc/testsuite/g++.dg/strict-flex-array-3.C |  21 ++++
> >> gcc/testsuite/g++.dg/strict-flex-array-4.C |   9 ++
> >> gcc/testsuite/gcc.dg/strict-flex-array-1.c |  31 +++++
> >> gcc/testsuite/gcc.dg/strict-flex-array-2.c |  15 +++
> >> gcc/testsuite/gcc.dg/strict-flex-array-3.c |  21 ++++
> >> gcc/testsuite/gcc.dg/strict-flex-array-4.c |  10 ++
> >> 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 ++-
> >> 21 files changed, 541 insertions(+), 28 deletions(-)
> >> create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-1.C
> >> create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-2.C
> >> create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-3.C
> >> create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-4.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
> >> create mode 100644 gcc/testsuite/gcc.dg/strict-flex-array-4.c
> >> 
> >> diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
> >> index e4f1d3542f37..9c9927cefa0d 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,96 @@ 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;
> >> +    }
> >> +  else
> >> +    {
> >> +      unsigned int level = tree_to_uhwi (argval);
> >> +      /* check whether the attribute is valid based on language standard.
> >> +	 the attribute is only valid when flexible array member is
> >> +	 supported in the language. Therefore, we should invalid this attribute or
> >> +	 specific level of this attribute for the following situations:
> >> +	A. When -std=c89 is specified, no language support at all, invalid this
> >> +	   attribute and issue a warning;
> >> +	B. When -std=gnu89 is specified, only zero-length array extension and
> >> +	   one-size array are supported, level=3 will be invalid and a warning
> >> +	   will be issued.
> >> +	C. C++ without GNU extension, no language support at all, invalid this
> >> +	   attribute and issue a warning;
> >> +	D. C++ with GNU extension, only zero-length array extension and one-size
> >> +	   array are supported, level=3 will be invalid and a warning will be
> >> +	   issued.  */
> >> +      if (level > 0)
> >> +	{
> >> +	  if (!c_dialect_cxx () && flag_iso && flag_isoc99 == 0)
> >> +	  {
> >> +	    warning (OPT_Wattributes, "%qE attribute ignored since it is "
> >> +		     "not supported with a ISO C before C99", name);
> >> +	    *no_add_attrs = true;
> >> +	  }
> >> +	  else if (!c_dialect_cxx () && !flag_iso
> >> +		   && flag_isoc99 == 0 && level == 3)
> >> +	  {
> >> +	    warning (OPT_Wattributes, "%qE = 3 attribute ignored since it is "
> >> +		     "not supported with a GNU extension GNU89", name);
> >> +	    *no_add_attrs = true;
> >> +	  }
> >> +	  else if (c_dialect_cxx () && flag_iso)
> >> +	  {
> >> +	    warning (OPT_Wattributes, "%qE attribute ignored since it is "
> >> +		     "not supported with a ISO C++", name);
> >> +	    *no_add_attrs = true;
> >> +	  }
> >> +	  else if (c_dialect_cxx () && !flag_iso
> >> +		   && level == 3)
> >> +	  {
> >> +	    warning (OPT_Wattributes, "%qE = 3 attribute ignored since it is "
> >> +		     "not supported for C++ with GNU extension", name);
> >> +	    *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-opts.cc b/gcc/c-family/c-opts.cc
> >> index 4e1463689de3..639eb40f3c86 100644
> >> --- a/gcc/c-family/c-opts.cc
> >> +++ b/gcc/c-family/c-opts.cc
> >> @@ -870,6 +870,47 @@ c_common_post_options (const char **pfilename)
> >>     SET_OPTION_IF_UNSET (&global_options, &global_options_set,
> >> 			 flag_tree_loop_distribute_patterns, 0);
> >> 
> >> +  /* -fstrict-flex-arrays is only valid when flexible array member is
> >> +     supported in the language. Therefore, we should invalid this option or
> >> +     specific level of this option for the following situations:
> >> +     A. When -std=c89 is specified, no language support at all, invalid this
> >> +	option and issue a warning;
> >> +     B. When -std=gnu89 is specified, only zero-length array extension and
> >> +	one-size array are supported, level=3 will be invalid and a warning
> >> +	will be issued.
> >> +     C. C++ without GNU extension, no language support at all, invalid this
> >> +	option and issue a warning;
> >> +     D. C++ with GNU extension, only zero-length array extension and one-size
> >> +	array are supported, level=3 will be invalid and a warning will be
> >> +	issued.  */
> >> +  if (flag_strict_flex_arrays > 0)
> >> +    {
> >> +      if (!c_dialect_cxx () && flag_iso && flag_isoc99 == 0)
> >> +	{
> >> +	  flag_strict_flex_arrays = 0;
> >> +	  warning (0, "%<-fstrict-flex-arrays%> is not supported with a ISO C "
> >> +		   "before C99, ignored");
> >> +	}
> >> +      else if (!c_dialect_cxx () && !flag_iso && flag_isoc99 == 0 && flag_strict_flex_arrays == 3)
> >> +	{
> >> +	  flag_strict_flex_arrays = 0;
> >> +	  warning (0, "%<-fstrict-flex-arrays=3%> is not supported with a "
> >> +		   "GNU extension GNU89, ignored");
> >> +	}
> >> +      else if (c_dialect_cxx () && flag_iso)
> >> +	{
> >> +	  flag_strict_flex_arrays = 0;
> >> +	  warning (0, "%<-fstrict-flex-arrays%> is not supported with a ISO "
> >> +		   "C++, ignored");
> >> +	}
> >> +      else if (c_dialect_cxx () && !flag_iso && flag_strict_flex_arrays == 3)
> >> +	{
> >> +	  flag_strict_flex_arrays = 0;
> >> +	  warning (0, "%<-fstrict-flex-arrays=3%> is not supported for C++ "
> >> +		   "with GNU extension, ignored");
> >> +	}
> >> +    }
> >> +
> >>   /* -Woverlength-strings is off by default, but is enabled by -Wpedantic.
> >>      It is never enabled in C++, as the minimum limit is not normative
> >>      in that standard.  */
> >> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
> >> index 44e1a60ce246..1e944f8a3055 100644
> >> --- a/gcc/c-family/c.opt
> >> +++ b/gcc/c-family/c.opt
> >> @@ -2060,6 +2060,13 @@ fsized-deallocation
> >> C++ ObjC++ Var(flag_sized_deallocation) Init(-1)
> >> Enable C++14 sized deallocation support.
> >> 
> >> +fstrict-flex-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 ae8990c138fd..a2e125d4ddd5 100644
> >> --- a/gcc/c/c-decl.cc
> >> +++ b/gcc/c/c-decl.cc
> >> @@ -4999,6 +4999,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.  */
> >> @@ -5013,10 +5048,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)
> >> @@ -8720,6 +8752,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.
> >> @@ -8781,6 +8888,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;
> >> 
> >> @@ -8819,10 +8931,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)
> >> 	    {
> >> @@ -8830,7 +8939,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
> >> 			"flexible array member in union");
> >> 	      TREE_TYPE (x) = error_mark_node;
> >> 	    }
> >> -	  else if (DECL_CHAIN (x) != NULL_TREE)
> >> +	  else if (!is_last_field)
> >> 	    {
> >> 	      error_at (DECL_SOURCE_LOCATION (x),
> >> 			"flexible array member not at end of struct");
> >> @@ -8850,6 +8959,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 7fe7f8817cdd..99b43ed3852c 100644
> >> --- a/gcc/doc/extend.texi
> >> +++ b/gcc/doc/extend.texi
> >> @@ -7473,6 +7473,39 @@ 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 ([]), it is treated as a flexible array member.
> >> +
> >> +There are two more levels in between 0 and 3, which are provided to support
> >> +older codes that use GCC zero-length array extension ([0]) or one-size array
> >> +as flexible array member ([1]):
> >> +When @var{level} is 1, the trailing array is treated as a flexible array member
> >> +when it is declared as either "[]", "[0]", or "[1]";
> >> +When @var{level} is 2, the trailing array is treated as a flexible array member
> >> +when it is declared as either "[]", or "[0]".
> >> +
> >> +This attribute can be used with or without 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.
> >> +
> >> +This attribute is only valid when flexible array member is supported in the
> >> +language. For ISO C before C99 and ISO C++, no language support for the flexible
> >> +array member at all, this attribute will be invalid and a warning is issued.
> >> +When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
> >> +extension and one-size array are supported, as a result, @var{level}=3 will be
> >> +invalid and a warning is issued.
> >> +
> >> +
> >> @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 863580b3710a..2a0a3cf3de10 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,37 @@ 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_array} attribute (@pxref{Variable Attributes}).
> >> +
> >> +You can control this behavior for a specific trailing array field of a
> >> +structure by using the variable attribute @code{strict_flex_array} attribute
> >> +(@pxref{Variable Attributes}).
> >> +
> >> +This option is only valid when flexible array member is supported in the
> >> +language. FOR ISO C before C99 and ISO C++, no language support for the flexible
> >> +array member at all, this option will be invalid and a warning will be issued.
> >> +When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
> >> +extension and one-size array are supported, as a result, @var{level}=3 will be
> >> +invalid and a warning will be issued.
> >> +
> >> @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..47adaf7bac4a
> >> --- /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/g++.dg/strict-flex-array-2.C b/gcc/testsuite/g++.dg/strict-flex-array-2.C
> >> new file mode 100644
> >> index 000000000000..245f8fe0bc73
> >> --- /dev/null
> >> +++ b/gcc/testsuite/g++.dg/strict-flex-array-2.C
> >> @@ -0,0 +1,16 @@
> >> +/* testing the correct usage of flag -fstrict_flex_array for C++.  */   
> >> +/* { dg-do compile } */
> >> +/* { dg-options "-O2 -fstrict-flex-arrays -std=c++98" } */
> >> +
> >> +struct trailing_array {
> >> +    int a;
> >> +    int b;
> >> +    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "attribute ignored since it is not supported with a ISO C\\+\\+" } */
> >> +};
> >> +
> >> +int foo(int a)
> >> +{
> >> +  return 0;
> >> +}
> >> +
> >> +/* { dg-warning "is not supported with a ISO C\\+\\+, ignored" ""  { target *-*-* } 0 } */
> >> diff --git a/gcc/testsuite/g++.dg/strict-flex-array-3.C b/gcc/testsuite/g++.dg/strict-flex-array-3.C
> >> new file mode 100644
> >> index 000000000000..2a733a5bccf4
> >> --- /dev/null
> >> +++ b/gcc/testsuite/g++.dg/strict-flex-array-3.C
> >> @@ -0,0 +1,21 @@
> >> +/* testing the correct usage of flag -fstrict_flex_array for C++.  */   
> >> +/* { dg-do compile } */
> >> +/* { dg-options "-O2 -fstrict-flex-arrays -std=gnu++98" } */
> >> +/* { dg-warning "'-fstrict-flex-arrays=3' is not supported for C\\+\\+ with GNU extension, ignored" ""  { target *-*-* } 0 } */
> >> +
> >> +struct trailing_array {
> >> +    int a;
> >> +    int b;
> >> +    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "'strict_flex_arrays' = 3 attribute ignored since it is not supported for C\\+\\+ with GNU extension" } */
> >> +};
> >> +
> >> +struct trailing_array_1 {
> >> +    int a;
> >> +    int b;
> >> +    int c[0] __attribute ((strict_flex_arrays (2))); /* { dg-bogus "'strict_flex_arrays' = 3 attribute ignored since it is not supported for C\\+\\+ with GNU extension" } */
> >> +};
> >> +
> >> +int foo(int a)
> >> +{
> >> +  return a + 2;
> >> +}
> >> diff --git a/gcc/testsuite/g++.dg/strict-flex-array-4.C b/gcc/testsuite/g++.dg/strict-flex-array-4.C
> >> new file mode 100644
> >> index 000000000000..804e4cf459ef
> >> --- /dev/null
> >> +++ b/gcc/testsuite/g++.dg/strict-flex-array-4.C
> >> @@ -0,0 +1,9 @@
> >> +/* testing the correct usage of flag -fstrict_flex_array.  */   
> >> +/* { dg-do compile } */
> >> +/* { dg-options "-O2 -fstrict-flex-arrays=2 -std=gnu++98" } */
> >> +/* { dg-bogus "is not supported for C\\+\\+ with GNU extension, ignored" ""  { target *-*-* } 0 } */
> >> +
> >> +int foo(int a)
> >> +{
> >> +  return a + 2;
> >> +}
> >> 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..47adaf7bac4a
> >> --- /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/testsuite/gcc.dg/strict-flex-array-2.c b/gcc/testsuite/gcc.dg/strict-flex-array-2.c
> >> new file mode 100644
> >> index 000000000000..967a240040dc
> >> --- /dev/null
> >> +++ b/gcc/testsuite/gcc.dg/strict-flex-array-2.c
> >> @@ -0,0 +1,15 @@
> >> +/* testing the correct usage of flag -fstrict_flex_array.  */   
> >> +/* { dg-do compile } */
> >> +/* { dg-options "-O2 -fstrict-flex-arrays -std=c89" } */
> >> +/* { dg-warning "'-fstrict-flex-arrays' is not supported with a ISO C before C99, ignored" ""  { target *-*-* } 0 } */
> >> +
> >> +struct trailing_array {
> >> +    int a;
> >> +    int b;
> >> +    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "'strict_flex_arrays' attribute ignored since it is not supported with a ISO C before C99" } */
> >> +};
> >> +
> >> +int foo(int a)
> >> +{
> >> +  return a + 2;
> >> +}
> >> 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..879de7f203c8
> >> --- /dev/null
> >> +++ b/gcc/testsuite/gcc.dg/strict-flex-array-3.c
> >> @@ -0,0 +1,21 @@
> >> +/* testing the correct usage of flag -fstrict_flex_array.  */   
> >> +/* { dg-do compile } */
> >> +/* { dg-options "-O2 -fstrict-flex-arrays -std=gnu89" } */
> >> +/* { dg-warning "'-fstrict-flex-arrays=3' is not supported with a GNU extension GNU89, ignored" ""  { target *-*-* } 0 } */
> >> +
> >> +struct trailing_array {
> >> +    int a;
> >> +    int b;
> >> +    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "'strict_flex_arrays' = 3 attribute ignored since it is not supported with a GNU extension GNU89" } */
> >> +};
> >> +
> >> +struct trailing_array_1 {
> >> +    int a;
> >> +    int b;
> >> +    int c[0] __attribute ((strict_flex_arrays (2))); /* { dg-bogus "'strict_flex_arrays' = 3 attribute ignored since it is not supported with a GNU extension GNU89" } */
> >> +};
> >> +
> >> +int foo(int a)
> >> +{
> >> +  return a + 2;
> >> +}
> >> diff --git a/gcc/testsuite/gcc.dg/strict-flex-array-4.c b/gcc/testsuite/gcc.dg/strict-flex-array-4.c
> >> new file mode 100644
> >> index 000000000000..ce64c24db301
> >> --- /dev/null
> >> +++ b/gcc/testsuite/gcc.dg/strict-flex-array-4.c
> >> @@ -0,0 +1,10 @@
> >> +/* testing the correct usage of flag -fstrict_flex_array.  */   
> >> +/* { dg-do compile } */
> >> +/* { dg-options "-O2 -fstrict-flex-arrays=2 -std=gnu89" } */
> >> +/* { dg-bogus "is not supported with a GNU extension GNU89, ignored" ""  { target *-*-* } 0 } */
> >> +
> >> +
> >> +int foo(int a)
> >> +{
> >> +  return a + 2;
> >> +}
> >> diff --git a/gcc/tree-core.h b/gcc/tree-core.h
> >> index 86a07c282af2..f822cb539dd0 100644
> >> --- a/gcc/tree-core.h
> >> +++ b/gcc/tree-core.h
> >> @@ -1813,7 +1813,10 @@ struct GTY(()) tree_decl_common {
> >>      TYPE_WARN_IF_NOT_ALIGN.  */
> >>   unsigned int warn_if_not_align : 6;
> >> 
> >> -  /* 14 bits unused.  */
> >> +  /* In FIELD_DECL, this is DECL_NOT_FLEXARRAY.  */
> >> +  unsigned int decl_not_flexarray : 1;
> >> +
> >> +  /* 13 bits unused.  */
> >> 
> >>   /* UID for points-to sets, stable over copying from inlining.  */
> >>   unsigned int pt_uid;
> >> diff --git a/gcc/tree-streamer-in.cc b/gcc/tree-streamer-in.cc
> >> index 196f19c759f2..21e6e8eb1c0a 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 d39dc158a465..68e40dbdb8f2 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 fed1434d141d..d698e8c9c213 100644
> >> --- a/gcc/tree.cc
> >> +++ b/gcc/tree.cc
> >> @@ -12678,14 +12678,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)
> >> @@ -12695,7 +12711,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);
> >> @@ -12707,6 +12726,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))
> >> @@ -12760,13 +12780,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).  */
> >> @@ -12788,9 +12811,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)))
> >> @@ -12798,12 +12821,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 e6564aaccb7b..f911c0a46e69 100644
> >> --- a/gcc/tree.h
> >> +++ b/gcc/tree.h
> >> @@ -2993,6 +2993,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.  */
> >> @@ -5531,10 +5537,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
> >> 
> > 
> > -- 
> > Richard Biener <rguenther@suse.de>
> > SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
> > Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
> > HRB 36809 (AG Nuernberg)
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
HRB 36809 (AG Nuernberg)

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

* Fwd: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-17 14:40 [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array Qing Zhao
  2022-08-17 14:40 ` [[GCC13][Patch][V3] 2/2] Use array_at_struct_end_p in __builtin_object_size [PR101836] Qing Zhao
  2022-08-26  8:48 ` [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array Richard Biener
@ 2022-08-30 20:30 ` Qing Zhao
  2022-08-30 20:30   ` Qing Zhao
  2022-08-30 22:53   ` Joseph Myers
  2 siblings, 2 replies; 27+ messages in thread
From: Qing Zhao @ 2022-08-30 20:30 UTC (permalink / raw)
  To: joseph, Nathan Sidwell
  Cc: gcc Patches, richard Biener, jakub Jelinek, martin Sebor, Kees Cook

Hi, Joseph and Nathan,

Could you please review the C and C++ FE parts of the patch?

https://gcc.gnu.org/pipermail/gcc-patches/2022-August/599901.html

The middle-end changes have been approved by Richard already.

https://gcc.gnu.org/pipermail/gcc-patches/2022-August/600379.html

Thanks.



Begin forwarded message:

From: Qing Zhao <qing.zhao@oracle.com<mailto:qing.zhao@oracle.com>>
Subject: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
Date: August 17, 2022 at 10:40:41 AM EDT
To: gcc-patches@gcc.gnu.org<mailto:gcc-patches@gcc.gnu.org>
Cc: rguenther@suse.de<mailto:rguenther@suse.de>, jakub@redhat.com<mailto:jakub@redhat.com>, msebor@gmail.com<mailto:msebor@gmail.com>, keescook@chromium.org<mailto:keescook@chromium.org>, joseph@codesourcery.com<mailto:joseph@codesourcery.com>, Qing Zhao <qing.zhao@oracle.com<mailto:qing.zhao@oracle.com>>

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

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

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

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

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

    This option is only valid when flexible array member is supported in the
    language. FOR ISO C before C99 and ISO C++, no language support for the flexible
    array member at all, this option will be invalid and a warning will be issued.
    When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
    extension and one-size array are supported, as a result, LEVEL=3 will be
    invalid and a warning will be issued.

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

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

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

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

    This attribute is only valid when flexible array member is supported in the
    language. For ISO C before C99 and ISO C++, no language support for the flexible
    array member at all, this attribute will be invalid and a warning is issued.
    When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
    extension and one-size array are supported, as a result, LEVEL=3 will be
    invalid and a warning is issued.

gcc/c-family/ChangeLog:

* c-attribs.cc<http://c-attribs.cc> (handle_strict_flex_arrays_attribute): New function.
(c_common_attribute_table): New item for strict_flex_array.
* c-opts.cc<http://c-opts.cc> (c_common_post_options): Handle the combination of
-fstrict-flex-arrays and -std specially.
* c.opt: (fstrict-flex-array): New option.
(fstrict-flex-array=): New option.

gcc/c/ChangeLog:

* c-decl.cc<http://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<http://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_array attribute.
* doc/invoke.texi: Document -fstrict-flex-array[=n] option.
* print-tree.cc<http://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<http://tree-streamer-in.cc> (unpack_ts_decl_common_value_fields): Stream
in new bit decl_not_flexarray.
* tree-streamer-out.cc<http://tree-streamer-out.cc> (pack_ts_decl_common_value_fields): Stream
out new bit decl_not_flexarray.
* tree.cc<http://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.
* g++.dg/strict-flex-array-2.C: New test.
* g++.dg/strict-flex-array-3.C: New test.
* g++.dg/strict-flex-array-4.C: New test.
* gcc.dg/strict-flex-array-1.c: New test.
* gcc.dg/strict-flex-array-2.c: New test.
* gcc.dg/strict-flex-array-3.c: New test.
* gcc.dg/strict-flex-array-4.c: New test.
---
gcc/c-family/c-attribs.cc<http://c-attribs.cc>                  |  94 +++++++++++++++
gcc/c-family/c-opts.cc<http://c-opts.cc>                     |  41 +++++++
gcc/c-family/c.opt                         |   7 ++
gcc/c/c-decl.cc<http://c-decl.cc>                            | 130 +++++++++++++++++++--
gcc/cp/module.cc<http://module.cc>                           |   2 +
gcc/doc/extend.texi                        |  33 ++++++
gcc/doc/invoke.texi                        |  34 +++++-
gcc/print-tree.cc<http://print-tree.cc>                          |   8 +-
gcc/testsuite/g++.dg/strict-flex-array-1.C |  31 +++++
gcc/testsuite/g++.dg/strict-flex-array-2.C |  16 +++
gcc/testsuite/g++.dg/strict-flex-array-3.C |  21 ++++
gcc/testsuite/g++.dg/strict-flex-array-4.C |   9 ++
gcc/testsuite/gcc.dg/strict-flex-array-1.c |  31 +++++
gcc/testsuite/gcc.dg/strict-flex-array-2.c |  15 +++
gcc/testsuite/gcc.dg/strict-flex-array-3.c |  21 ++++
gcc/testsuite/gcc.dg/strict-flex-array-4.c |  10 ++
gcc/tree-core.h                            |   5 +-
gcc/tree-streamer-in.cc<http://tree-streamer-in.cc>                    |   1 +
gcc/tree-streamer-out.cc<http://tree-streamer-out.cc>                   |   1 +
gcc/tree.cc<http://tree.cc>                                |  45 +++++--
gcc/tree.h                                 |  14 ++-
21 files changed, 541 insertions(+), 28 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-1.C
create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-2.C
create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-3.C
create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-4.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
create mode 100644 gcc/testsuite/gcc.dg/strict-flex-array-4.c

diff --git a/gcc/c-family/c-attribs.cc<http://c-attribs.cc> b/gcc/c-family/c-attribs.cc<http://c-attribs.cc>
index e4f1d3542f37..9c9927cefa0d 100644
--- a/gcc/c-family/c-attribs.cc<http://c-attribs.cc>
+++ b/gcc/c-family/c-attribs.cc<http://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,96 @@ 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;
+    }
+  else
+    {
+      unsigned int level = tree_to_uhwi (argval);
+      /* check whether the attribute is valid based on language standard.
+ the attribute is only valid when flexible array member is
+ supported in the language. Therefore, we should invalid this attribute or
+ specific level of this attribute for the following situations:
+ A. When -std=c89 is specified, no language support at all, invalid this
+   attribute and issue a warning;
+ B. When -std=gnu89 is specified, only zero-length array extension and
+   one-size array are supported, level=3 will be invalid and a warning
+   will be issued.
+ C. C++ without GNU extension, no language support at all, invalid this
+   attribute and issue a warning;
+ D. C++ with GNU extension, only zero-length array extension and one-size
+   array are supported, level=3 will be invalid and a warning will be
+   issued.  */
+      if (level > 0)
+ {
+  if (!c_dialect_cxx () && flag_iso && flag_isoc99 == 0)
+  {
+    warning (OPT_Wattributes, "%qE attribute ignored since it is "
+     "not supported with a ISO C before C99", name);
+    *no_add_attrs = true;
+  }
+  else if (!c_dialect_cxx () && !flag_iso
+   && flag_isoc99 == 0 && level == 3)
+  {
+    warning (OPT_Wattributes, "%qE = 3 attribute ignored since it is "
+     "not supported with a GNU extension GNU89", name);
+    *no_add_attrs = true;
+  }
+  else if (c_dialect_cxx () && flag_iso)
+  {
+    warning (OPT_Wattributes, "%qE attribute ignored since it is "
+     "not supported with a ISO C++", name);
+    *no_add_attrs = true;
+  }
+  else if (c_dialect_cxx () && !flag_iso
+   && level == 3)
+  {
+    warning (OPT_Wattributes, "%qE = 3 attribute ignored since it is "
+     "not supported for C++ with GNU extension", name);
+    *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-opts.cc<http://c-opts.cc> b/gcc/c-family/c-opts.cc<http://c-opts.cc>
index 4e1463689de3..639eb40f3c86 100644
--- a/gcc/c-family/c-opts.cc<http://c-opts.cc>
+++ b/gcc/c-family/c-opts.cc<http://c-opts.cc>
@@ -870,6 +870,47 @@ c_common_post_options (const char **pfilename)
    SET_OPTION_IF_UNSET (&global_options, &global_options_set,
flag_tree_loop_distribute_patterns, 0);

+  /* -fstrict-flex-arrays is only valid when flexible array member is
+     supported in the language. Therefore, we should invalid this option or
+     specific level of this option for the following situations:
+     A. When -std=c89 is specified, no language support at all, invalid this
+ option and issue a warning;
+     B. When -std=gnu89 is specified, only zero-length array extension and
+ one-size array are supported, level=3 will be invalid and a warning
+ will be issued.
+     C. C++ without GNU extension, no language support at all, invalid this
+ option and issue a warning;
+     D. C++ with GNU extension, only zero-length array extension and one-size
+ array are supported, level=3 will be invalid and a warning will be
+ issued.  */
+  if (flag_strict_flex_arrays > 0)
+    {
+      if (!c_dialect_cxx () && flag_iso && flag_isoc99 == 0)
+ {
+  flag_strict_flex_arrays = 0;
+  warning (0, "%<-fstrict-flex-arrays%> is not supported with a ISO C "
+   "before C99, ignored");
+ }
+      else if (!c_dialect_cxx () && !flag_iso && flag_isoc99 == 0 && flag_strict_flex_arrays == 3)
+ {
+  flag_strict_flex_arrays = 0;
+  warning (0, "%<-fstrict-flex-arrays=3%> is not supported with a "
+   "GNU extension GNU89, ignored");
+ }
+      else if (c_dialect_cxx () && flag_iso)
+ {
+  flag_strict_flex_arrays = 0;
+  warning (0, "%<-fstrict-flex-arrays%> is not supported with a ISO "
+   "C++, ignored");
+ }
+      else if (c_dialect_cxx () && !flag_iso && flag_strict_flex_arrays == 3)
+ {
+  flag_strict_flex_arrays = 0;
+  warning (0, "%<-fstrict-flex-arrays=3%> is not supported for C++ "
+   "with GNU extension, ignored");
+ }
+    }
+
  /* -Woverlength-strings is off by default, but is enabled by -Wpedantic.
     It is never enabled in C++, as the minimum limit is not normative
     in that standard.  */
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 44e1a60ce246..1e944f8a3055 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -2060,6 +2060,13 @@ fsized-deallocation
C++ ObjC++ Var(flag_sized_deallocation) Init(-1)
Enable C++14 sized deallocation support.

+fstrict-flex-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<http://c-decl.cc> b/gcc/c/c-decl.cc<http://c-decl.cc>
index ae8990c138fd..a2e125d4ddd5 100644
--- a/gcc/c/c-decl.cc<http://c-decl.cc>
+++ b/gcc/c/c-decl.cc<http://c-decl.cc>
@@ -4999,6 +4999,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.  */
@@ -5013,10 +5048,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)
@@ -8720,6 +8752,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.
@@ -8781,6 +8888,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;

@@ -8819,10 +8931,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)
   {
@@ -8830,7 +8939,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
"flexible array member in union");
     TREE_TYPE (x) = error_mark_node;
   }
-  else if (DECL_CHAIN (x) != NULL_TREE)
+  else if (!is_last_field)
   {
     error_at (DECL_SOURCE_LOCATION (x),
"flexible array member not at end of struct");
@@ -8850,6 +8959,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<http://module.cc> b/gcc/cp/module.cc<http://module.cc>
index f27f4d091e5e..75ee2514f66b 100644
--- a/gcc/cp/module.cc<http://module.cc>
+++ b/gcc/cp/module.cc<http://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 7fe7f8817cdd..99b43ed3852c 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -7473,6 +7473,39 @@ 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 ([]), it is treated as a flexible array member.
+
+There are two more levels in between 0 and 3, which are provided to support
+older codes that use GCC zero-length array extension ([0]) or one-size array
+as flexible array member ([1]):
+When @var{level} is 1, the trailing array is treated as a flexible array member
+when it is declared as either "[]", "[0]", or "[1]";
+When @var{level} is 2, the trailing array is treated as a flexible array member
+when it is declared as either "[]", or "[0]".
+
+This attribute can be used with or without 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.
+
+This attribute is only valid when flexible array member is supported in the
+language. For ISO C before C99 and ISO C++, no language support for the flexible
+array member at all, this attribute will be invalid and a warning is issued.
+When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
+extension and one-size array are supported, as a result, @var{level}=3 will be
+invalid and a warning is issued.
+
+
@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 863580b3710a..2a0a3cf3de10 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,37 @@ 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_array} attribute (@pxref{Variable Attributes}).
+
+You can control this behavior for a specific trailing array field of a
+structure by using the variable attribute @code{strict_flex_array} attribute
+(@pxref{Variable Attributes}).
+
+This option is only valid when flexible array member is supported in the
+language. FOR ISO C before C99 and ISO C++, no language support for the flexible
+array member at all, this option will be invalid and a warning will be issued.
+When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
+extension and one-size array are supported, as a result, @var{level}=3 will be
+invalid and a warning will be issued.
+
@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<http://print-tree.cc> b/gcc/print-tree.cc<http://print-tree.cc>
index 6d45a4a59669..58a98250cc4f 100644
--- a/gcc/print-tree.cc<http://print-tree.cc>
+++ b/gcc/print-tree.cc<http://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..47adaf7bac4a
--- /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/g++.dg/strict-flex-array-2.C b/gcc/testsuite/g++.dg/strict-flex-array-2.C
new file mode 100644
index 000000000000..245f8fe0bc73
--- /dev/null
+++ b/gcc/testsuite/g++.dg/strict-flex-array-2.C
@@ -0,0 +1,16 @@
+/* testing the correct usage of flag -fstrict_flex_array for C++.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays -std=c++98" } */
+
+struct trailing_array {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "attribute ignored since it is not supported with a ISO C\\+\\+" } */
+};
+
+int foo(int a)
+{
+  return 0;
+}
+
+/* { dg-warning "is not supported with a ISO C\\+\\+, ignored" ""  { target *-*-* } 0 } */
diff --git a/gcc/testsuite/g++.dg/strict-flex-array-3.C b/gcc/testsuite/g++.dg/strict-flex-array-3.C
new file mode 100644
index 000000000000..2a733a5bccf4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/strict-flex-array-3.C
@@ -0,0 +1,21 @@
+/* testing the correct usage of flag -fstrict_flex_array for C++.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays -std=gnu++98" } */
+/* { dg-warning "'-fstrict-flex-arrays=3' is not supported for C\\+\\+ with GNU extension, ignored" ""  { target *-*-* } 0 } */
+
+struct trailing_array {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "'strict_flex_arrays' = 3 attribute ignored since it is not supported for C\\+\\+ with GNU extension" } */
+};
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (2))); /* { dg-bogus "'strict_flex_arrays' = 3 attribute ignored since it is not supported for C\\+\\+ with GNU extension" } */
+};
+
+int foo(int a)
+{
+  return a + 2;
+}
diff --git a/gcc/testsuite/g++.dg/strict-flex-array-4.C b/gcc/testsuite/g++.dg/strict-flex-array-4.C
new file mode 100644
index 000000000000..804e4cf459ef
--- /dev/null
+++ b/gcc/testsuite/g++.dg/strict-flex-array-4.C
@@ -0,0 +1,9 @@
+/* testing the correct usage of flag -fstrict_flex_array.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays=2 -std=gnu++98" } */
+/* { dg-bogus "is not supported for C\\+\\+ with GNU extension, ignored" ""  { target *-*-* } 0 } */
+
+int foo(int a)
+{
+  return a + 2;
+}
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..47adaf7bac4a
--- /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/testsuite/gcc.dg/strict-flex-array-2.c b/gcc/testsuite/gcc.dg/strict-flex-array-2.c
new file mode 100644
index 000000000000..967a240040dc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strict-flex-array-2.c
@@ -0,0 +1,15 @@
+/* testing the correct usage of flag -fstrict_flex_array.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays -std=c89" } */
+/* { dg-warning "'-fstrict-flex-arrays' is not supported with a ISO C before C99, ignored" ""  { target *-*-* } 0 } */
+
+struct trailing_array {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "'strict_flex_arrays' attribute ignored since it is not supported with a ISO C before C99" } */
+};
+
+int foo(int a)
+{
+  return a + 2;
+}
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..879de7f203c8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strict-flex-array-3.c
@@ -0,0 +1,21 @@
+/* testing the correct usage of flag -fstrict_flex_array.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays -std=gnu89" } */
+/* { dg-warning "'-fstrict-flex-arrays=3' is not supported with a GNU extension GNU89, ignored" ""  { target *-*-* } 0 } */
+
+struct trailing_array {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "'strict_flex_arrays' = 3 attribute ignored since it is not supported with a GNU extension GNU89" } */
+};
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (2))); /* { dg-bogus "'strict_flex_arrays' = 3 attribute ignored since it is not supported with a GNU extension GNU89" } */
+};
+
+int foo(int a)
+{
+  return a + 2;
+}
diff --git a/gcc/testsuite/gcc.dg/strict-flex-array-4.c b/gcc/testsuite/gcc.dg/strict-flex-array-4.c
new file mode 100644
index 000000000000..ce64c24db301
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strict-flex-array-4.c
@@ -0,0 +1,10 @@
+/* testing the correct usage of flag -fstrict_flex_array.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays=2 -std=gnu89" } */
+/* { dg-bogus "is not supported with a GNU extension GNU89, ignored" ""  { target *-*-* } 0 } */
+
+
+int foo(int a)
+{
+  return a + 2;
+}
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 86a07c282af2..f822cb539dd0 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1813,7 +1813,10 @@ struct GTY(()) tree_decl_common {
     TYPE_WARN_IF_NOT_ALIGN.  */
  unsigned int warn_if_not_align : 6;

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

  /* UID for points-to sets, stable over copying from inlining.  */
  unsigned int pt_uid;
diff --git a/gcc/tree-streamer-in.cc<http://tree-streamer-in.cc> b/gcc/tree-streamer-in.cc<http://tree-streamer-in.cc>
index 196f19c759f2..21e6e8eb1c0a 100644
--- a/gcc/tree-streamer-in.cc<http://tree-streamer-in.cc>
+++ b/gcc/tree-streamer-in.cc<http://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<http://tree-streamer-out.cc> b/gcc/tree-streamer-out.cc<http://tree-streamer-out.cc>
index d39dc158a465..68e40dbdb8f2 100644
--- a/gcc/tree-streamer-out.cc<http://tree-streamer-out.cc>
+++ b/gcc/tree-streamer-out.cc<http://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<http://tree.cc> b/gcc/tree.cc<http://tree.cc>
index fed1434d141d..d698e8c9c213 100644
--- a/gcc/tree.cc<http://tree.cc>
+++ b/gcc/tree.cc<http://tree.cc>
@@ -12678,14 +12678,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)
@@ -12695,7 +12711,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);
@@ -12707,6 +12726,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))
@@ -12760,13 +12780,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).  */
@@ -12788,9 +12811,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)))
@@ -12798,12 +12821,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 e6564aaccb7b..f911c0a46e69 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2993,6 +2993,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.  */
@@ -5531,10 +5537,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] 27+ messages in thread

* Fwd: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-30 20:30 ` Fwd: " Qing Zhao
@ 2022-08-30 20:30   ` Qing Zhao
  2022-08-30 22:53   ` Joseph Myers
  1 sibling, 0 replies; 27+ messages in thread
From: Qing Zhao @ 2022-08-30 20:30 UTC (permalink / raw)
  To: joseph, Nathan Sidwell
  Cc: gcc Patches, richard Biener, jakub Jelinek, martin Sebor, Kees Cook

[-- Attachment #1: Type: text/plain, Size: 43800 bytes --]

Hi, Joseph and Nathan,

Could you please review the C and C++ FE parts of the patch?

https://gcc.gnu.org/pipermail/gcc-patches/2022-August/599901.html

The middle-end changes have been approved by Richard already.

https://gcc.gnu.org/pipermail/gcc-patches/2022-August/600379.html

Thanks.



Begin forwarded message:

From: Qing Zhao <qing.zhao@oracle.com<mailto:qing.zhao@oracle.com>>
Subject: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
Date: August 17, 2022 at 10:40:41 AM EDT
To: gcc-patches@gcc.gnu.org<mailto:gcc-patches@gcc.gnu.org>
Cc: rguenther@suse.de<mailto:rguenther@suse.de>, jakub@redhat.com<mailto:jakub@redhat.com>, msebor@gmail.com<mailto:msebor@gmail.com>, keescook@chromium.org<mailto:keescook@chromium.org>, joseph@codesourcery.com<mailto:joseph@codesourcery.com>, Qing Zhao <qing.zhao@oracle.com<mailto:qing.zhao@oracle.com>>

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

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

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

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

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

    This option is only valid when flexible array member is supported in the
    language. FOR ISO C before C99 and ISO C++, no language support for the flexible
    array member at all, this option will be invalid and a warning will be issued.
    When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
    extension and one-size array are supported, as a result, LEVEL=3 will be
    invalid and a warning will be issued.

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

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

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

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

    This attribute is only valid when flexible array member is supported in the
    language. For ISO C before C99 and ISO C++, no language support for the flexible
    array member at all, this attribute will be invalid and a warning is issued.
    When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
    extension and one-size array are supported, as a result, LEVEL=3 will be
    invalid and a warning is issued.

gcc/c-family/ChangeLog:

* c-attribs.cc<http://c-attribs.cc> (handle_strict_flex_arrays_attribute): New function.
(c_common_attribute_table): New item for strict_flex_array.
* c-opts.cc<http://c-opts.cc> (c_common_post_options): Handle the combination of
-fstrict-flex-arrays and -std specially.
* c.opt: (fstrict-flex-array): New option.
(fstrict-flex-array=): New option.

gcc/c/ChangeLog:

* c-decl.cc<http://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<http://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_array attribute.
* doc/invoke.texi: Document -fstrict-flex-array[=n] option.
* print-tree.cc<http://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<http://tree-streamer-in.cc> (unpack_ts_decl_common_value_fields): Stream
in new bit decl_not_flexarray.
* tree-streamer-out.cc<http://tree-streamer-out.cc> (pack_ts_decl_common_value_fields): Stream
out new bit decl_not_flexarray.
* tree.cc<http://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.
* g++.dg/strict-flex-array-2.C: New test.
* g++.dg/strict-flex-array-3.C: New test.
* g++.dg/strict-flex-array-4.C: New test.
* gcc.dg/strict-flex-array-1.c: New test.
* gcc.dg/strict-flex-array-2.c: New test.
* gcc.dg/strict-flex-array-3.c: New test.
* gcc.dg/strict-flex-array-4.c: New test.
---
gcc/c-family/c-attribs.cc<http://c-attribs.cc>                  |  94 +++++++++++++++
gcc/c-family/c-opts.cc<http://c-opts.cc>                     |  41 +++++++
gcc/c-family/c.opt                         |   7 ++
gcc/c/c-decl.cc<http://c-decl.cc>                            | 130 +++++++++++++++++++--
gcc/cp/module.cc<http://module.cc>                           |   2 +
gcc/doc/extend.texi                        |  33 ++++++
gcc/doc/invoke.texi                        |  34 +++++-
gcc/print-tree.cc<http://print-tree.cc>                          |   8 +-
gcc/testsuite/g++.dg/strict-flex-array-1.C |  31 +++++
gcc/testsuite/g++.dg/strict-flex-array-2.C |  16 +++
gcc/testsuite/g++.dg/strict-flex-array-3.C |  21 ++++
gcc/testsuite/g++.dg/strict-flex-array-4.C |   9 ++
gcc/testsuite/gcc.dg/strict-flex-array-1.c |  31 +++++
gcc/testsuite/gcc.dg/strict-flex-array-2.c |  15 +++
gcc/testsuite/gcc.dg/strict-flex-array-3.c |  21 ++++
gcc/testsuite/gcc.dg/strict-flex-array-4.c |  10 ++
gcc/tree-core.h                            |   5 +-
gcc/tree-streamer-in.cc<http://tree-streamer-in.cc>                    |   1 +
gcc/tree-streamer-out.cc<http://tree-streamer-out.cc>                   |   1 +
gcc/tree.cc<http://tree.cc>                                |  45 +++++--
gcc/tree.h                                 |  14 ++-
21 files changed, 541 insertions(+), 28 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-1.C
create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-2.C
create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-3.C
create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-4.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
create mode 100644 gcc/testsuite/gcc.dg/strict-flex-array-4.c

diff --git a/gcc/c-family/c-attribs.cc<http://c-attribs.cc> b/gcc/c-family/c-attribs.cc<http://c-attribs.cc>
index e4f1d3542f37..9c9927cefa0d 100644
--- a/gcc/c-family/c-attribs.cc<http://c-attribs.cc>
+++ b/gcc/c-family/c-attribs.cc<http://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,96 @@ 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;
+    }
+  else
+    {
+      unsigned int level = tree_to_uhwi (argval);
+      /* check whether the attribute is valid based on language standard.
+ the attribute is only valid when flexible array member is
+ supported in the language. Therefore, we should invalid this attribute or
+ specific level of this attribute for the following situations:
+ A. When -std=c89 is specified, no language support at all, invalid this
+   attribute and issue a warning;
+ B. When -std=gnu89 is specified, only zero-length array extension and
+   one-size array are supported, level=3 will be invalid and a warning
+   will be issued.
+ C. C++ without GNU extension, no language support at all, invalid this
+   attribute and issue a warning;
+ D. C++ with GNU extension, only zero-length array extension and one-size
+   array are supported, level=3 will be invalid and a warning will be
+   issued.  */
+      if (level > 0)
+ {
+  if (!c_dialect_cxx () && flag_iso && flag_isoc99 == 0)
+  {
+    warning (OPT_Wattributes, "%qE attribute ignored since it is "
+     "not supported with a ISO C before C99", name);
+    *no_add_attrs = true;
+  }
+  else if (!c_dialect_cxx () && !flag_iso
+   && flag_isoc99 == 0 && level == 3)
+  {
+    warning (OPT_Wattributes, "%qE = 3 attribute ignored since it is "
+     "not supported with a GNU extension GNU89", name);
+    *no_add_attrs = true;
+  }
+  else if (c_dialect_cxx () && flag_iso)
+  {
+    warning (OPT_Wattributes, "%qE attribute ignored since it is "
+     "not supported with a ISO C++", name);
+    *no_add_attrs = true;
+  }
+  else if (c_dialect_cxx () && !flag_iso
+   && level == 3)
+  {
+    warning (OPT_Wattributes, "%qE = 3 attribute ignored since it is "
+     "not supported for C++ with GNU extension", name);
+    *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-opts.cc<http://c-opts.cc> b/gcc/c-family/c-opts.cc<http://c-opts.cc>
index 4e1463689de3..639eb40f3c86 100644
--- a/gcc/c-family/c-opts.cc<http://c-opts.cc>
+++ b/gcc/c-family/c-opts.cc<http://c-opts.cc>
@@ -870,6 +870,47 @@ c_common_post_options (const char **pfilename)
    SET_OPTION_IF_UNSET (&global_options, &global_options_set,
flag_tree_loop_distribute_patterns, 0);

+  /* -fstrict-flex-arrays is only valid when flexible array member is
+     supported in the language. Therefore, we should invalid this option or
+     specific level of this option for the following situations:
+     A. When -std=c89 is specified, no language support at all, invalid this
+ option and issue a warning;
+     B. When -std=gnu89 is specified, only zero-length array extension and
+ one-size array are supported, level=3 will be invalid and a warning
+ will be issued.
+     C. C++ without GNU extension, no language support at all, invalid this
+ option and issue a warning;
+     D. C++ with GNU extension, only zero-length array extension and one-size
+ array are supported, level=3 will be invalid and a warning will be
+ issued.  */
+  if (flag_strict_flex_arrays > 0)
+    {
+      if (!c_dialect_cxx () && flag_iso && flag_isoc99 == 0)
+ {
+  flag_strict_flex_arrays = 0;
+  warning (0, "%<-fstrict-flex-arrays%> is not supported with a ISO C "
+   "before C99, ignored");
+ }
+      else if (!c_dialect_cxx () && !flag_iso && flag_isoc99 == 0 && flag_strict_flex_arrays == 3)
+ {
+  flag_strict_flex_arrays = 0;
+  warning (0, "%<-fstrict-flex-arrays=3%> is not supported with a "
+   "GNU extension GNU89, ignored");
+ }
+      else if (c_dialect_cxx () && flag_iso)
+ {
+  flag_strict_flex_arrays = 0;
+  warning (0, "%<-fstrict-flex-arrays%> is not supported with a ISO "
+   "C++, ignored");
+ }
+      else if (c_dialect_cxx () && !flag_iso && flag_strict_flex_arrays == 3)
+ {
+  flag_strict_flex_arrays = 0;
+  warning (0, "%<-fstrict-flex-arrays=3%> is not supported for C++ "
+   "with GNU extension, ignored");
+ }
+    }
+
  /* -Woverlength-strings is off by default, but is enabled by -Wpedantic.
     It is never enabled in C++, as the minimum limit is not normative
     in that standard.  */
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 44e1a60ce246..1e944f8a3055 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -2060,6 +2060,13 @@ fsized-deallocation
C++ ObjC++ Var(flag_sized_deallocation) Init(-1)
Enable C++14 sized deallocation support.

+fstrict-flex-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<http://c-decl.cc> b/gcc/c/c-decl.cc<http://c-decl.cc>
index ae8990c138fd..a2e125d4ddd5 100644
--- a/gcc/c/c-decl.cc<http://c-decl.cc>
+++ b/gcc/c/c-decl.cc<http://c-decl.cc>
@@ -4999,6 +4999,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.  */
@@ -5013,10 +5048,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)
@@ -8720,6 +8752,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.
@@ -8781,6 +8888,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;

@@ -8819,10 +8931,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)
   {
@@ -8830,7 +8939,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
"flexible array member in union");
     TREE_TYPE (x) = error_mark_node;
   }
-  else if (DECL_CHAIN (x) != NULL_TREE)
+  else if (!is_last_field)
   {
     error_at (DECL_SOURCE_LOCATION (x),
"flexible array member not at end of struct");
@@ -8850,6 +8959,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<http://module.cc> b/gcc/cp/module.cc<http://module.cc>
index f27f4d091e5e..75ee2514f66b 100644
--- a/gcc/cp/module.cc<http://module.cc>
+++ b/gcc/cp/module.cc<http://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 7fe7f8817cdd..99b43ed3852c 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -7473,6 +7473,39 @@ 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 ([]), it is treated as a flexible array member.
+
+There are two more levels in between 0 and 3, which are provided to support
+older codes that use GCC zero-length array extension ([0]) or one-size array
+as flexible array member ([1]):
+When @var{level} is 1, the trailing array is treated as a flexible array member
+when it is declared as either "[]", "[0]", or "[1]";
+When @var{level} is 2, the trailing array is treated as a flexible array member
+when it is declared as either "[]", or "[0]".
+
+This attribute can be used with or without 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.
+
+This attribute is only valid when flexible array member is supported in the
+language. For ISO C before C99 and ISO C++, no language support for the flexible
+array member at all, this attribute will be invalid and a warning is issued.
+When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
+extension and one-size array are supported, as a result, @var{level}=3 will be
+invalid and a warning is issued.
+
+
@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 863580b3710a..2a0a3cf3de10 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,37 @@ 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_array} attribute (@pxref{Variable Attributes}).
+
+You can control this behavior for a specific trailing array field of a
+structure by using the variable attribute @code{strict_flex_array} attribute
+(@pxref{Variable Attributes}).
+
+This option is only valid when flexible array member is supported in the
+language. FOR ISO C before C99 and ISO C++, no language support for the flexible
+array member at all, this option will be invalid and a warning will be issued.
+When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
+extension and one-size array are supported, as a result, @var{level}=3 will be
+invalid and a warning will be issued.
+
@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<http://print-tree.cc> b/gcc/print-tree.cc<http://print-tree.cc>
index 6d45a4a59669..58a98250cc4f 100644
--- a/gcc/print-tree.cc<http://print-tree.cc>
+++ b/gcc/print-tree.cc<http://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..47adaf7bac4a
--- /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/g++.dg/strict-flex-array-2.C b/gcc/testsuite/g++.dg/strict-flex-array-2.C
new file mode 100644
index 000000000000..245f8fe0bc73
--- /dev/null
+++ b/gcc/testsuite/g++.dg/strict-flex-array-2.C
@@ -0,0 +1,16 @@
+/* testing the correct usage of flag -fstrict_flex_array for C++.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays -std=c++98" } */
+
+struct trailing_array {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "attribute ignored since it is not supported with a ISO C\\+\\+" } */
+};
+
+int foo(int a)
+{
+  return 0;
+}
+
+/* { dg-warning "is not supported with a ISO C\\+\\+, ignored" ""  { target *-*-* } 0 } */
diff --git a/gcc/testsuite/g++.dg/strict-flex-array-3.C b/gcc/testsuite/g++.dg/strict-flex-array-3.C
new file mode 100644
index 000000000000..2a733a5bccf4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/strict-flex-array-3.C
@@ -0,0 +1,21 @@
+/* testing the correct usage of flag -fstrict_flex_array for C++.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays -std=gnu++98" } */
+/* { dg-warning "'-fstrict-flex-arrays=3' is not supported for C\\+\\+ with GNU extension, ignored" ""  { target *-*-* } 0 } */
+
+struct trailing_array {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "'strict_flex_arrays' = 3 attribute ignored since it is not supported for C\\+\\+ with GNU extension" } */
+};
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (2))); /* { dg-bogus "'strict_flex_arrays' = 3 attribute ignored since it is not supported for C\\+\\+ with GNU extension" } */
+};
+
+int foo(int a)
+{
+  return a + 2;
+}
diff --git a/gcc/testsuite/g++.dg/strict-flex-array-4.C b/gcc/testsuite/g++.dg/strict-flex-array-4.C
new file mode 100644
index 000000000000..804e4cf459ef
--- /dev/null
+++ b/gcc/testsuite/g++.dg/strict-flex-array-4.C
@@ -0,0 +1,9 @@
+/* testing the correct usage of flag -fstrict_flex_array.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays=2 -std=gnu++98" } */
+/* { dg-bogus "is not supported for C\\+\\+ with GNU extension, ignored" ""  { target *-*-* } 0 } */
+
+int foo(int a)
+{
+  return a + 2;
+}
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..47adaf7bac4a
--- /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/testsuite/gcc.dg/strict-flex-array-2.c b/gcc/testsuite/gcc.dg/strict-flex-array-2.c
new file mode 100644
index 000000000000..967a240040dc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strict-flex-array-2.c
@@ -0,0 +1,15 @@
+/* testing the correct usage of flag -fstrict_flex_array.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays -std=c89" } */
+/* { dg-warning "'-fstrict-flex-arrays' is not supported with a ISO C before C99, ignored" ""  { target *-*-* } 0 } */
+
+struct trailing_array {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "'strict_flex_arrays' attribute ignored since it is not supported with a ISO C before C99" } */
+};
+
+int foo(int a)
+{
+  return a + 2;
+}
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..879de7f203c8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strict-flex-array-3.c
@@ -0,0 +1,21 @@
+/* testing the correct usage of flag -fstrict_flex_array.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays -std=gnu89" } */
+/* { dg-warning "'-fstrict-flex-arrays=3' is not supported with a GNU extension GNU89, ignored" ""  { target *-*-* } 0 } */
+
+struct trailing_array {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "'strict_flex_arrays' = 3 attribute ignored since it is not supported with a GNU extension GNU89" } */
+};
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (2))); /* { dg-bogus "'strict_flex_arrays' = 3 attribute ignored since it is not supported with a GNU extension GNU89" } */
+};
+
+int foo(int a)
+{
+  return a + 2;
+}
diff --git a/gcc/testsuite/gcc.dg/strict-flex-array-4.c b/gcc/testsuite/gcc.dg/strict-flex-array-4.c
new file mode 100644
index 000000000000..ce64c24db301
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strict-flex-array-4.c
@@ -0,0 +1,10 @@
+/* testing the correct usage of flag -fstrict_flex_array.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays=2 -std=gnu89" } */
+/* { dg-bogus "is not supported with a GNU extension GNU89, ignored" ""  { target *-*-* } 0 } */
+
+
+int foo(int a)
+{
+  return a + 2;
+}
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 86a07c282af2..f822cb539dd0 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1813,7 +1813,10 @@ struct GTY(()) tree_decl_common {
     TYPE_WARN_IF_NOT_ALIGN.  */
  unsigned int warn_if_not_align : 6;

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

  /* UID for points-to sets, stable over copying from inlining.  */
  unsigned int pt_uid;
diff --git a/gcc/tree-streamer-in.cc<http://tree-streamer-in.cc> b/gcc/tree-streamer-in.cc<http://tree-streamer-in.cc>
index 196f19c759f2..21e6e8eb1c0a 100644
--- a/gcc/tree-streamer-in.cc<http://tree-streamer-in.cc>
+++ b/gcc/tree-streamer-in.cc<http://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<http://tree-streamer-out.cc> b/gcc/tree-streamer-out.cc<http://tree-streamer-out.cc>
index d39dc158a465..68e40dbdb8f2 100644
--- a/gcc/tree-streamer-out.cc<http://tree-streamer-out.cc>
+++ b/gcc/tree-streamer-out.cc<http://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<http://tree.cc> b/gcc/tree.cc<http://tree.cc>
index fed1434d141d..d698e8c9c213 100644
--- a/gcc/tree.cc<http://tree.cc>
+++ b/gcc/tree.cc<http://tree.cc>
@@ -12678,14 +12678,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)
@@ -12695,7 +12711,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);
@@ -12707,6 +12726,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))
@@ -12760,13 +12780,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).  */
@@ -12788,9 +12811,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)))
@@ -12798,12 +12821,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 e6564aaccb7b..f911c0a46e69 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2993,6 +2993,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.  */
@@ -5531,10 +5537,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] 27+ messages in thread

* Re: Fwd: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-30 20:30 ` Fwd: " Qing Zhao
  2022-08-30 20:30   ` Qing Zhao
@ 2022-08-30 22:53   ` Joseph Myers
  2022-08-31 14:00     ` Qing Zhao
  1 sibling, 1 reply; 27+ messages in thread
From: Joseph Myers @ 2022-08-30 22:53 UTC (permalink / raw)
  To: Qing Zhao
  Cc: Nathan Sidwell, jakub Jelinek, richard Biener, gcc Patches,
	martin Sebor, Kees Cook

On Tue, 30 Aug 2022, Qing Zhao via Gcc-patches wrote:

> Hi, Joseph and Nathan,
> 
> Could you please review the C and C++ FE parts of the patch?
> 
> https://gcc.gnu.org/pipermail/gcc-patches/2022-August/599901.html

I think some work is still needed on the diagnostic wording.

> +  "%qE attribute may not be specified for a non array field",

"non-array" not "non array".

> +       "not supported with a ISO C before C99", name);

"a ISO C" is not proper usage.  I think something like "by ISO C before 
C99" would be better.  Likewise "a ISO C++".

"!flag_isoc99" is more usual than "flag_isoc99 == 0".

> +       "not supported with a GNU extension GNU89", name);

"a GNU extension" suggests a particular language feature, but I think 
you're actually referring here to a whole language version rather than an 
individual feature.

In any case, -std=gnu89 supports flexible array members.  So I'd expect 
them to have exactly the same semantics as in C99, so disallowing a 
particular feature for gnu89 here seems suspect.

In the manual, any literal code should be enclosed in @code{} or @samp{}.  
That replaces the use of ASCII quotes "" that you currently have in the 
documentation (that should never be used outside of @code, @samp and 
similar).

> +When -std=gnu89 is specified or C++ with GNU extension, only zero-length array

And @option{} should be used around "-std=gnu89" here (except as noted 
above, I think it's suspect to disallow parts of this feature for gnu89).

> +language. FOR ISO C before C99 and ISO C++, no language support for the flexible

"FOR" should be "For".

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-30 22:53   ` Joseph Myers
@ 2022-08-31 14:00     ` Qing Zhao
  2022-08-31 17:21       ` Joseph Myers
  0 siblings, 1 reply; 27+ messages in thread
From: Qing Zhao @ 2022-08-31 14:00 UTC (permalink / raw)
  To: Joseph Myers
  Cc: Nathan Sidwell, jakub Jelinek, richard Biener, gcc Patches,
	martin Sebor, Kees Cook

Hi, Joseph,

Thanks a lot for your comment.

> On Aug 30, 2022, at 6:53 PM, Joseph Myers <joseph@codesourcery.com> wrote:
> 
> On Tue, 30 Aug 2022, Qing Zhao via Gcc-patches wrote:
> 
>> Hi, Joseph and Nathan,
>> 
>> Could you please review the C and C++ FE parts of the patch?
>> 
>> https://gcc.gnu.org/pipermail/gcc-patches/2022-August/599901.html
> 
> I think some work is still needed on the diagnostic wording.
> 
>> +  "%qE attribute may not be specified for a non array field",
> 
> "non-array" not "non array".

Okay.

> 
>> +       "not supported with a ISO C before C99", name);
> 
> "a ISO C" is not proper usage.  I think something like "by ISO C before 
> C99" would be better.  Likewise "a ISO C++".
> 
> "!flag_isoc99" is more usual than "flag_isoc99 == 0".

Okay.

> 
>> +       "not supported with a GNU extension GNU89", name);
> 
> "a GNU extension" suggests a particular language feature, but I think 
> you're actually referring here to a whole language version rather than an 
> individual feature.

Is “not supported by GNU extension GNU89” better?

> 
> In any case, -std=gnu89 supports flexible array members.

Yes, but only [0],[1] are supported as flexible array members.  The C99 flexible array member [] is not supported by GNU89, right?

Then, -fstrict-flex-arrays=3 is not supported by -std=gnu89.


>  So I'd expect 
> them to have exactly the same semantics as in C99, so disallowing a 
> particular feature for gnu89 here seems suspect.
> 
> In the manual, any literal code should be enclosed in @code{} or @samp{}.  
> That replaces the use of ASCII quotes "" that you currently have in the 
> documentation (that should never be used outside of @code, @samp and 
> similar).

Okay. Will update those places.
> 
>> +When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
> 
> And @option{} should be used around "-std=gnu89" here (except as noted 
> above, I think it's suspect to disallow parts of this feature for gnu89).

Okay. Will update.
> 
>> +language. FOR ISO C before C99 and ISO C++, no language support for the flexible
> 
> "FOR" should be "For".

Okay.

thanks.

Qing
> 
> -- 
> Joseph S. Myers
> joseph@codesourcery.com


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

* Re: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-31 14:00     ` Qing Zhao
@ 2022-08-31 17:21       ` Joseph Myers
  2022-08-31 17:21         ` Joseph Myers
  2022-08-31 18:55         ` Qing Zhao
  0 siblings, 2 replies; 27+ messages in thread
From: Joseph Myers @ 2022-08-31 17:21 UTC (permalink / raw)
  To: Qing Zhao
  Cc: jakub Jelinek, richard Biener, Kees Cook, gcc Patches,
	Nathan Sidwell, martin Sebor

[-- Attachment #1: Type: text/plain, Size: 1007 bytes --]

On Wed, 31 Aug 2022, Qing Zhao via Gcc-patches wrote:

> > "a GNU extension" suggests a particular language feature, but I think 
> > you're actually referring here to a whole language version rather than an 
> > individual feature.
> 
> Is “not supported by GNU extension GNU89” better?

There are no existing diagnostics referring to GNU89 at all.  I don't 
think "GNU extension" needs to be mentioned in that diagnostic, but I also 
think that having that diagnostic at all is ill-conceived.

> > In any case, -std=gnu89 supports flexible array members.
> 
> Yes, but only [0],[1] are supported as flexible array members.  The C99 
> flexible array member [] is not supported by GNU89, right?

C99 flexible array members are fully supported in GNU89 mode.  In general, 
any feature from a new language version that doesn't affect code that was 
valid in previous versions is likely to be accepted as an extension with 
options for older language versions.

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-31 17:21       ` Joseph Myers
@ 2022-08-31 17:21         ` Joseph Myers
  2022-08-31 18:55         ` Qing Zhao
  1 sibling, 0 replies; 27+ messages in thread
From: Joseph Myers @ 2022-08-31 17:21 UTC (permalink / raw)
  To: Qing Zhao
  Cc: jakub Jelinek, richard Biener, Kees Cook, gcc Patches,
	Nathan Sidwell, martin Sebor

On Wed, 31 Aug 2022, Qing Zhao via Gcc-patches wrote:

> > "a GNU extension" suggests a particular language feature, but I think 
> > you're actually referring here to a whole language version rather than an 
> > individual feature.
> 
> Is “not supported by GNU extension GNU89” better?

There are no existing diagnostics referring to GNU89 at all.  I don't 
think "GNU extension" needs to be mentioned in that diagnostic, but I also 
think that having that diagnostic at all is ill-conceived.

> > In any case, -std=gnu89 supports flexible array members.
> 
> Yes, but only [0],[1] are supported as flexible array members.  The C99 
> flexible array member [] is not supported by GNU89, right?

C99 flexible array members are fully supported in GNU89 mode.  In general, 
any feature from a new language version that doesn't affect code that was 
valid in previous versions is likely to be accepted as an extension with 
options for older language versions.

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-31 17:21       ` Joseph Myers
  2022-08-31 17:21         ` Joseph Myers
@ 2022-08-31 18:55         ` Qing Zhao
  2022-08-31 19:24           ` Qing Zhao
  2022-08-31 19:29           ` Joseph Myers
  1 sibling, 2 replies; 27+ messages in thread
From: Qing Zhao @ 2022-08-31 18:55 UTC (permalink / raw)
  To: Joseph Myers
  Cc: jakub Jelinek, richard Biener, Kees Cook, gcc Patches,
	Nathan Sidwell, martin Sebor



> On Aug 31, 2022, at 1:21 PM, Joseph Myers <joseph@codesourcery.com> wrote:
> 
> On Wed, 31 Aug 2022, Qing Zhao via Gcc-patches wrote:
> 
>>> "a GNU extension" suggests a particular language feature, but I think 
>>> you're actually referring here to a whole language version rather than an 
>>> individual feature.
>> 
>> Is “not supported by GNU extension GNU89” better?
> 
> There are no existing diagnostics referring to GNU89 at all.  I don't 
> think "GNU extension" needs to be mentioned in that diagnostic, but I also 
> think that having that diagnostic at all is ill-conceived.
> 
>>> In any case, -std=gnu89 supports flexible array members.
>> 
>> Yes, but only [0],[1] are supported as flexible array members.  The C99 
>> flexible array member [] is not supported by GNU89, right?
> 
> C99 flexible array members are fully supported in GNU89 mode.  In general, 
> any feature from a new language version that doesn't affect code that was 
> valid in previous versions is likely to be accepted as an extension with 
> options for older language versions.


We have a previous discussion on this: (https://gcc.gnu.org/pipermail/gcc-patches/2022-July/599067.html)

And looks like that the previous conclusion was wrong… please see the following:

======

> How is level 3 (thus -fstrict-flex-array) interpreted when you specify 
> -std=c89?  How for -std=gnu89?

1. what’s the major difference between -std=c89 and -std=gnu89 on flexible array? (Checked online, cannot find a concrete answer on this).
	** my understanding is:   -std=c89 will not support any flexible array (neither [], [0], [1]), but -std=gnu89 will support [0] and [1], but not [].
        Is this correct?

If my answer to the first question is correct, then:

2. When -fstrict-flex-array=n and -std=c89 present at the same time, which one has the higher priority? 
    	** I think that -std=c89 should be honored over -fstrict-flex-array, therefore we should disable -fstrict-flex-array=n when n > 0  and issue warnings to the user.


3. how about -fstrict-flex-array=n and -std=gnu89 present at the same time? 
    	** When -std=gnu89 present, [] is not supported. So, we need to issue an warning to disable -fstrict-flex-array=3; but level 1 and level 2 is Okay.

We also need to document the above.
====

So, from my understanding from what you said so far, 

-std=c89 will not support any flexible array (neither [], [0], [1]),  but -std=gnu89 will support ALL flexible array including [0], [1], and [].

Is this understanding correct?

thanks.

Qing


> 
> -- 
> Joseph S. Myers
> joseph@codesourcery.com


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

* Re: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-31 18:55         ` Qing Zhao
@ 2022-08-31 19:24           ` Qing Zhao
  2022-08-31 19:29           ` Joseph Myers
  1 sibling, 0 replies; 27+ messages in thread
From: Qing Zhao @ 2022-08-31 19:24 UTC (permalink / raw)
  To: Joseph
  Cc: jakub Jelinek, richard Biener, Kees Cook, gcc Patches,
	Nathan Sidwell, martin Sebor



> On Aug 31, 2022, at 2:55 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> 
> 
> 
>> On Aug 31, 2022, at 1:21 PM, Joseph Myers <joseph@codesourcery.com> wrote:
>> 
>> On Wed, 31 Aug 2022, Qing Zhao via Gcc-patches wrote:
>> 
>>>> "a GNU extension" suggests a particular language feature, but I think 
>>>> you're actually referring here to a whole language version rather than an 
>>>> individual feature.
>>> 
>>> Is “not supported by GNU extension GNU89” better?
>> 
>> There are no existing diagnostics referring to GNU89 at all.  I don't 
>> think "GNU extension" needs to be mentioned in that diagnostic, but I also 
>> think that having that diagnostic at all is ill-conceived.
>> 
>>>> In any case, -std=gnu89 supports flexible array members.
>>> 
>>> Yes, but only [0],[1] are supported as flexible array members.  The C99 
>>> flexible array member [] is not supported by GNU89, right?
>> 
>> C99 flexible array members are fully supported in GNU89 mode.  In general, 
>> any feature from a new language version that doesn't affect code that was 
>> valid in previous versions is likely to be accepted as an extension with 
>> options for older language versions.
> 
> 
> We have a previous discussion on this: (https://gcc.gnu.org/pipermail/gcc-patches/2022-July/599067.html)
> 
> And looks like that the previous conclusion was wrong… please see the following:
> 
> ======
> 
>> How is level 3 (thus -fstrict-flex-array) interpreted when you specify 
>> -std=c89?  How for -std=gnu89?
> 
> 1. what’s the major difference between -std=c89 and -std=gnu89 on flexible array? (Checked online, cannot find a concrete answer on this).
> 	** my understanding is:   -std=c89 will not support any flexible array (neither [], [0], [1]), but -std=gnu89 will support [0] and [1], but not [].
>        Is this correct?
> 
> If my answer to the first question is correct, then:
> 
> 2. When -fstrict-flex-array=n and -std=c89 present at the same time, which one has the higher priority? 
>    	** I think that -std=c89 should be honored over -fstrict-flex-array, therefore we should disable -fstrict-flex-array=n when n > 0  and issue warnings to the user.
> 
> 
> 3. how about -fstrict-flex-array=n and -std=gnu89 present at the same time? 
>    	** When -std=gnu89 present, [] is not supported. So, we need to issue an warning to disable -fstrict-flex-array=3; but level 1 and level 2 is Okay.
> 
> We also need to document the above.
> ====
> 
> So, from my understanding from what you said so far, 
> 
> -std=c89 will not support any flexible array (neither [], [0], [1]),  but -std=gnu89 will support ALL flexible array including [0], [1], and [].
> 
> Is this understanding correct?

And also for C++:

-std=c++98 will not support any flexible array, but -std=gnu++98 will support ALL flexible array ([0],[1].[])?

Qing
> 
> thanks.
> 
> Qing
> 
> 
>> 
>> -- 
>> Joseph S. Myers
>> joseph@codesourcery.com


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

* Re: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-31 18:55         ` Qing Zhao
  2022-08-31 19:24           ` Qing Zhao
@ 2022-08-31 19:29           ` Joseph Myers
  2022-08-31 19:29             ` Joseph Myers
  2022-08-31 19:47             ` Qing Zhao
  1 sibling, 2 replies; 27+ messages in thread
From: Joseph Myers @ 2022-08-31 19:29 UTC (permalink / raw)
  To: Qing Zhao
  Cc: jakub Jelinek, richard Biener, Kees Cook, gcc Patches,
	Nathan Sidwell, martin Sebor

[-- Attachment #1: Type: text/plain, Size: 888 bytes --]

On Wed, 31 Aug 2022, Qing Zhao via Gcc-patches wrote:

> > How is level 3 (thus -fstrict-flex-array) interpreted when you specify 
> > -std=c89?  How for -std=gnu89?
> 
> 1. what’s the major difference between -std=c89 and -std=gnu89 on flexible array? (Checked online, cannot find a concrete answer on this).
> 	** my understanding is:   -std=c89 will not support any flexible array (neither [], [0], [1]), but -std=gnu89 will support [0] and [1], but not [].
>         Is this correct?

Flexible array members are supported in all C standard modes, since they 
don't affect the semantics of any valid pre-C99 program (only make valid 
programs that were previously erroneous).

With -std=c89 or -std=gnu89, -pedantic will give a warning "ISO C90 does 
not support flexible array members" and -pedantic-errors will change that 
to an error.

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-31 19:29           ` Joseph Myers
@ 2022-08-31 19:29             ` Joseph Myers
  2022-08-31 19:47             ` Qing Zhao
  1 sibling, 0 replies; 27+ messages in thread
From: Joseph Myers @ 2022-08-31 19:29 UTC (permalink / raw)
  To: Qing Zhao
  Cc: jakub Jelinek, richard Biener, Kees Cook, gcc Patches,
	Nathan Sidwell, martin Sebor

On Wed, 31 Aug 2022, Qing Zhao via Gcc-patches wrote:

> > How is level 3 (thus -fstrict-flex-array) interpreted when you specify 
> > -std=c89?  How for -std=gnu89?
> 
> 1. what’s the major difference between -std=c89 and -std=gnu89 on flexible array? (Checked online, cannot find a concrete answer on this).
> 	** my understanding is:   -std=c89 will not support any flexible array (neither [], [0], [1]), but -std=gnu89 will support [0] and [1], but not [].
>         Is this correct?

Flexible array members are supported in all C standard modes, since they 
don't affect the semantics of any valid pre-C99 program (only make valid 
programs that were previously erroneous).

With -std=c89 or -std=gnu89, -pedantic will give a warning "ISO C90 does 
not support flexible array members" and -pedantic-errors will change that 
to an error.

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-31 19:29           ` Joseph Myers
  2022-08-31 19:29             ` Joseph Myers
@ 2022-08-31 19:47             ` Qing Zhao
  2022-08-31 19:52               ` Joseph Myers
  1 sibling, 1 reply; 27+ messages in thread
From: Qing Zhao @ 2022-08-31 19:47 UTC (permalink / raw)
  To: Joseph Myers
  Cc: jakub Jelinek, richard Biener, Kees Cook, gcc Patches,
	Nathan Sidwell, martin Sebor



> On Aug 31, 2022, at 3:29 PM, Joseph Myers <joseph@codesourcery.com> wrote:
> 
> On Wed, 31 Aug 2022, Qing Zhao via Gcc-patches wrote:
> 
>>> How is level 3 (thus -fstrict-flex-array) interpreted when you specify 
>>> -std=c89?  How for -std=gnu89?
>> 
>> 1. what’s the major difference between -std=c89 and -std=gnu89 on flexible array? (Checked online, cannot find a concrete answer on this).
>> 	** my understanding is:   -std=c89 will not support any flexible array (neither [], [0], [1]), but -std=gnu89 will support [0] and [1], but not [].
>>        Is this correct?
> 
> Flexible array members are supported in all C standard modes, since they 
> don't affect the semantics of any valid pre-C99 program (only make valid 
> programs that were previously erroneous).
> 
> With -std=c89 or -std=gnu89, -pedantic will give a warning "ISO C90 does 
> not support flexible array members" and -pedantic-errors will change that 
> to an error.

A little confused here…

With both -std=c89 and -std=gnu89, -pedantic will warning on “[]” (C99 flexible array member):

[opc@qinzhao-ol8u3-x86 ~]$ gcc -std=c89 t.c  -pedantic
t.c:5:7: warning: ISO C90 does not support flexible array members [-Wpedantic]
    5 |   int b[];
      |       ^
[opc@qinzhao-ol8u3-x86 ~]$ gcc -std=gnu89 t.c  -pedantic
t.c:5:7: warning: ISO C90 does not support flexible array members [-Wpedantic]
    5 |   int b[];
      |       ^

Does the above mean that -std=gnu89 does not support C99 flexible array member,  then

When -std=gnu89 + -fstrict-flex-array=3  (ONLY C99 flexible array member [] is treated as a valid flexible array) present together, 

It should be reasonable to issue warning on this?      (-fstrict-flex-arrays=3 is not supported by GNU extension GNU89, ignored)

Right?

Qing




> 
> -- 
> Joseph S. Myers
> joseph@codesourcery.com


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

* Re: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-31 19:47             ` Qing Zhao
@ 2022-08-31 19:52               ` Joseph Myers
  2022-08-31 20:06                 ` Qing Zhao
  0 siblings, 1 reply; 27+ messages in thread
From: Joseph Myers @ 2022-08-31 19:52 UTC (permalink / raw)
  To: Qing Zhao
  Cc: jakub Jelinek, richard Biener, Kees Cook, gcc Patches,
	Nathan Sidwell, martin Sebor

On Wed, 31 Aug 2022, Qing Zhao wrote:

> Does the above mean that -std=gnu89 does not support C99 flexible array 
> member, then

No.

Flexible array members are supported by GCC in all C standards modes.  The 
C90 standard doesn't support them, but that's irrelevant to what GCC 
supports; it just means a diagnostic is required for strict conformance in 
pre-C99 modes.

> When -std=gnu89 + -fstrict-flex-array=3 (ONLY C99 flexible array member 
> [] is treated as a valid flexible array) present together,

That seems reasonable enough without a warning.  If people want a warning 
for flexible array members in older language modes, they can use 
-pedantic; I don't think we need to warn for any particular 
-fstrict-flex-array modes there.

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-31 19:52               ` Joseph Myers
@ 2022-08-31 20:06                 ` Qing Zhao
  2022-08-31 20:09                   ` Joseph Myers
  0 siblings, 1 reply; 27+ messages in thread
From: Qing Zhao @ 2022-08-31 20:06 UTC (permalink / raw)
  To: Joseph Myers
  Cc: jakub Jelinek, richard Biener, Kees Cook, gcc Patches,
	Nathan Sidwell, martin Sebor



> On Aug 31, 2022, at 3:52 PM, Joseph Myers <joseph@codesourcery.com> wrote:
> 
> On Wed, 31 Aug 2022, Qing Zhao wrote:
> 
>> Does the above mean that -std=gnu89 does not support C99 flexible array 
>> member, then
> 
> No.
> 
> Flexible array members are supported by GCC in all C standards modes.  The 
> C90 standard doesn't support them, but that's irrelevant to what GCC 
> supports; it just means a diagnostic is required for strict conformance in 
> pre-C99 modes.

Okay.

> 
>> When -std=gnu89 + -fstrict-flex-array=3 (ONLY C99 flexible array member 
>> [] is treated as a valid flexible array) present together,
> 
> That seems reasonable enough without a warning.  If people want a warning 
> for flexible array members in older language modes, they can use 
> -pedantic; I don't think we need to warn for any particular 
> -fstrict-flex-array modes there.

So, you mean,

1. GCC with -std=gnu89 support all [0], [1], and [] as Flexible array member;
2. Therefore. -std=gnu89 + -fstrict-flex-array=3 does not need a warning;

?

Then, how about:

-std=c89:

1. GCC with -std=c89 also support all [0], [1], and [] as Flexible array member;
2, therefore, -std=c89 + -fstrict-flex-array does not need a warning too.

?


Qing
> 
> -- 
> Joseph S. Myers
> joseph@codesourcery.com


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

* Re: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-31 20:06                 ` Qing Zhao
@ 2022-08-31 20:09                   ` Joseph Myers
  2022-08-31 20:16                     ` Qing Zhao
  0 siblings, 1 reply; 27+ messages in thread
From: Joseph Myers @ 2022-08-31 20:09 UTC (permalink / raw)
  To: Qing Zhao
  Cc: jakub Jelinek, richard Biener, Kees Cook, gcc Patches,
	Nathan Sidwell, martin Sebor

On Wed, 31 Aug 2022, Qing Zhao wrote:

> >> When -std=gnu89 + -fstrict-flex-array=3 (ONLY C99 flexible array member 
> >> [] is treated as a valid flexible array) present together,
> > 
> > That seems reasonable enough without a warning.  If people want a warning 
> > for flexible array members in older language modes, they can use 
> > -pedantic; I don't think we need to warn for any particular 
> > -fstrict-flex-array modes there.
> 
> So, you mean,
> 
> 1. GCC with -std=gnu89 support all [0], [1], and [] as Flexible array member;
> 2. Therefore. -std=gnu89 + -fstrict-flex-array=3 does not need a warning;
> 
> ?

Yes.

> Then, how about:
> 
> -std=c89:
> 
> 1. GCC with -std=c89 also support all [0], [1], and [] as Flexible array member;
> 2, therefore, -std=c89 + -fstrict-flex-array does not need a warning too.
> 
> ?

Yes.

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-31 20:09                   ` Joseph Myers
@ 2022-08-31 20:16                     ` Qing Zhao
  2022-08-31 20:35                       ` Qing Zhao
  2022-08-31 22:17                       ` Kees Cook
  0 siblings, 2 replies; 27+ messages in thread
From: Qing Zhao @ 2022-08-31 20:16 UTC (permalink / raw)
  To: Joseph Myers, Richard Biener, Kees Cook
  Cc: jakub Jelinek, gcc Patches, Nathan Sidwell, martin Sebor

Okay, I am fine with this.

Richard and Kees,  what’s your opinion on this?

thanks.

Qing

> On Aug 31, 2022, at 4:09 PM, Joseph Myers <joseph@codesourcery.com> wrote:
> 
> On Wed, 31 Aug 2022, Qing Zhao wrote:
> 
>>>> When -std=gnu89 + -fstrict-flex-array=3 (ONLY C99 flexible array member 
>>>> [] is treated as a valid flexible array) present together,
>>> 
>>> That seems reasonable enough without a warning.  If people want a warning 
>>> for flexible array members in older language modes, they can use 
>>> -pedantic; I don't think we need to warn for any particular 
>>> -fstrict-flex-array modes there.
>> 
>> So, you mean,
>> 
>> 1. GCC with -std=gnu89 support all [0], [1], and [] as Flexible array member;
>> 2. Therefore. -std=gnu89 + -fstrict-flex-array=3 does not need a warning;
>> 
>> ?
> 
> Yes.
> 
>> Then, how about:
>> 
>> -std=c89:
>> 
>> 1. GCC with -std=c89 also support all [0], [1], and [] as Flexible array member;
>> 2, therefore, -std=c89 + -fstrict-flex-array does not need a warning too.
>> 
>> ?
> 
> Yes.
> 
> -- 
> Joseph S. Myers
> joseph@codesourcery.com


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

* Re: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-31 20:16                     ` Qing Zhao
@ 2022-08-31 20:35                       ` Qing Zhao
  2022-08-31 22:23                         ` Kees Cook
  2022-08-31 22:17                       ` Kees Cook
  1 sibling, 1 reply; 27+ messages in thread
From: Qing Zhao @ 2022-08-31 20:35 UTC (permalink / raw)
  To: Joseph
  Cc: Richard Biener, Kees Cook, jakub Jelinek, gcc Patches,
	Nathan Sidwell, martin Sebor



> On Aug 31, 2022, at 4:16 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> 
> Okay, I am fine with this.

Another thought on this is:

One of the major purposes of the new option -fstrict-flex-array is to encourage standard conforming programming style. 

So, it might be reasonable to treat -fstrict-flex-array similar as -pedantic (but only for flexible array members)? 
If so, then issuing warnings when the standard doesn’t support is reasonable and desirable. 

(I guess that this is the original motivation to add such warnings).

Qing
> 
> Richard and Kees,  what’s your opinion on this?
> 
> thanks.
> 
> Qing
> 
>> On Aug 31, 2022, at 4:09 PM, Joseph Myers <joseph@codesourcery.com> wrote:
>> 
>> On Wed, 31 Aug 2022, Qing Zhao wrote:
>> 
>>>>> When -std=gnu89 + -fstrict-flex-array=3 (ONLY C99 flexible array member 
>>>>> [] is treated as a valid flexible array) present together,
>>>> 
>>>> That seems reasonable enough without a warning.  If people want a warning 
>>>> for flexible array members in older language modes, they can use 
>>>> -pedantic; I don't think we need to warn for any particular 
>>>> -fstrict-flex-array modes there.
>>> 
>>> So, you mean,
>>> 
>>> 1. GCC with -std=gnu89 support all [0], [1], and [] as Flexible array member;
>>> 2. Therefore. -std=gnu89 + -fstrict-flex-array=3 does not need a warning;
>>> 
>>> ?
>> 
>> Yes.
>> 
>>> Then, how about:
>>> 
>>> -std=c89:
>>> 
>>> 1. GCC with -std=c89 also support all [0], [1], and [] as Flexible array member;
>>> 2, therefore, -std=c89 + -fstrict-flex-array does not need a warning too.
>>> 
>>> ?
>> 
>> Yes.
>> 
>> -- 
>> Joseph S. Myers
>> joseph@codesourcery.com
> 


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

* Re: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-31 20:16                     ` Qing Zhao
  2022-08-31 20:35                       ` Qing Zhao
@ 2022-08-31 22:17                       ` Kees Cook
  1 sibling, 0 replies; 27+ messages in thread
From: Kees Cook @ 2022-08-31 22:17 UTC (permalink / raw)
  To: Qing Zhao
  Cc: Joseph Myers, Richard Biener, jakub Jelinek, gcc Patches,
	Nathan Sidwell, martin Sebor

On Wed, Aug 31, 2022 at 08:16:49PM +0000, Qing Zhao wrote:
> 
> > On Aug 31, 2022, at 4:09 PM, Joseph Myers <joseph@codesourcery.com> wrote:
> > 
> > On Wed, 31 Aug 2022, Qing Zhao wrote:
> > 
> >>>> When -std=gnu89 + -fstrict-flex-array=3 (ONLY C99 flexible array member 
> >>>> [] is treated as a valid flexible array) present together,
> >>> 
> >>> That seems reasonable enough without a warning.  If people want a warning 
> >>> for flexible array members in older language modes, they can use 
> >>> -pedantic; I don't think we need to warn for any particular 
> >>> -fstrict-flex-array modes there.
> >> 
> >> So, you mean,
> >> 
> >> 1. GCC with -std=gnu89 support all [0], [1], and [] as Flexible array member;
> >> 2. Therefore. -std=gnu89 + -fstrict-flex-array=3 does not need a warning;
> >> 
> >> ?
> > 
> > Yes.
> > 
> >> Then, how about:
> >> 
> >> -std=c89:
> >> 
> >> 1. GCC with -std=c89 also support all [0], [1], and [] as Flexible array member;
> >> 2, therefore, -std=c89 + -fstrict-flex-array does not need a warning too.
> >> 
> >> ?
> > 
> > Yes.
> > 
> 
> Okay, I am fine with this.
> 
> Richard and Kees,  what’s your opinion on this?

Agreed: I think it's fine not to warn about these "conflicting" flags in
those cases. It looks like the C standard warnings about flexible arrays
are already hidden behind -Wpedantic, so nothing else is needed, IMO.
Using -fstrict-flex-arrays just enforces that warning. ;)

-- 
Kees Cook

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

* Re: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-31 20:35                       ` Qing Zhao
@ 2022-08-31 22:23                         ` Kees Cook
  2022-09-01  6:11                           ` Richard Biener
  0 siblings, 1 reply; 27+ messages in thread
From: Kees Cook @ 2022-08-31 22:23 UTC (permalink / raw)
  To: Qing Zhao
  Cc: Joseph, Richard Biener, jakub Jelinek, gcc Patches,
	Nathan Sidwell, martin Sebor

On Wed, Aug 31, 2022 at 08:35:12PM +0000, Qing Zhao wrote:
> One of the major purposes of the new option -fstrict-flex-array is to encourage standard conforming programming style. 
> 
> So, it might be reasonable to treat -fstrict-flex-array similar as -pedantic (but only for flexible array members)? 
> If so, then issuing warnings when the standard doesn’t support is reasonable and desirable. 

I guess the point is that "-std=c89 -fstrict-flex-arrays=3" leaves "[]"
available for use still? I think this doesn't matter. If someone wants
it to be really strict, they'd just add -Wpedantic.

-- 
Kees Cook

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

* Re: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-08-31 22:23                         ` Kees Cook
@ 2022-09-01  6:11                           ` Richard Biener
  2022-09-04 14:17                             ` Qing Zhao
  0 siblings, 1 reply; 27+ messages in thread
From: Richard Biener @ 2022-09-01  6:11 UTC (permalink / raw)
  To: Kees Cook
  Cc: Qing Zhao, Joseph, jakub Jelinek, gcc Patches, Nathan Sidwell,
	martin Sebor

On Wed, 31 Aug 2022, Kees Cook wrote:

> On Wed, Aug 31, 2022 at 08:35:12PM +0000, Qing Zhao wrote:
> > One of the major purposes of the new option -fstrict-flex-array is to encourage standard conforming programming style. 
> > 
> > So, it might be reasonable to treat -fstrict-flex-array similar as -pedantic (but only for flexible array members)? 
> > If so, then issuing warnings when the standard doesn?t support is reasonable and desirable. 
> 
> I guess the point is that "-std=c89 -fstrict-flex-arrays=3" leaves "[]"
> available for use still? I think this doesn't matter. If someone wants
> it to be really strict, they'd just add -Wpedantic.

Yes, I think that makes sense.

Richard.

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

* Re: [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array
  2022-09-01  6:11                           ` Richard Biener
@ 2022-09-04 14:17                             ` Qing Zhao
  0 siblings, 0 replies; 27+ messages in thread
From: Qing Zhao @ 2022-09-04 14:17 UTC (permalink / raw)
  To: Richard Biener, Kees Cook, joseph
  Cc: jakub Jelinek, gcc Patches, Nathan Sidwell, martin Sebor

Okay, then I will delete those new warnings I added in the version 3 of the patch.

Thanks.

Qing

> On Sep 1, 2022, at 2:11 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Wed, 31 Aug 2022, Kees Cook wrote:
> 
>> On Wed, Aug 31, 2022 at 08:35:12PM +0000, Qing Zhao wrote:
>>> One of the major purposes of the new option -fstrict-flex-array is to encourage standard conforming programming style. 
>>> 
>>> So, it might be reasonable to treat -fstrict-flex-array similar as -pedantic (but only for flexible array members)? 
>>> If so, then issuing warnings when the standard doesn?t support is reasonable and desirable. 
>> 
>> I guess the point is that "-std=c89 -fstrict-flex-arrays=3" leaves "[]"
>> available for use still? I think this doesn't matter. If someone wants
>> it to be really strict, they'd just add -Wpedantic.
> 
> Yes, I think that makes sense.
> 
> Richard.


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

end of thread, other threads:[~2022-09-04 14:17 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-17 14:40 [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array Qing Zhao
2022-08-17 14:40 ` [[GCC13][Patch][V3] 2/2] Use array_at_struct_end_p in __builtin_object_size [PR101836] Qing Zhao
2022-08-26  8:49   ` Richard Biener
2022-08-26 13:37     ` Qing Zhao
2022-08-26  8:48 ` [[GCC13][Patch][V3] 1/2] Add a new option -fstrict-flex-array[=n] and new attribute strict_flex_array Richard Biener
2022-08-26 13:47   ` Qing Zhao
2022-08-29  8:04     ` Richard Biener
2022-08-30 20:30 ` Fwd: " Qing Zhao
2022-08-30 20:30   ` Qing Zhao
2022-08-30 22:53   ` Joseph Myers
2022-08-31 14:00     ` Qing Zhao
2022-08-31 17:21       ` Joseph Myers
2022-08-31 17:21         ` Joseph Myers
2022-08-31 18:55         ` Qing Zhao
2022-08-31 19:24           ` Qing Zhao
2022-08-31 19:29           ` Joseph Myers
2022-08-31 19:29             ` Joseph Myers
2022-08-31 19:47             ` Qing Zhao
2022-08-31 19:52               ` Joseph Myers
2022-08-31 20:06                 ` Qing Zhao
2022-08-31 20:09                   ` Joseph Myers
2022-08-31 20:16                     ` Qing Zhao
2022-08-31 20:35                       ` Qing Zhao
2022-08-31 22:23                         ` Kees Cook
2022-09-01  6:11                           ` Richard Biener
2022-09-04 14:17                             ` Qing Zhao
2022-08-31 22:17                       ` Kees Cook

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