public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 0/2] Add a new warning option -Wstrict-flex-array
@ 2022-11-08 14:51 Qing Zhao
  2022-11-08 14:51 ` [PATCH 1/2] Change the name of array_at_struct_end_p to array_ref_flexible_size_p Qing Zhao
  2022-11-08 14:51 ` [PATCH 2/2] Add a new warning option -Wstrict-flex-arrays Qing Zhao
  0 siblings, 2 replies; 15+ messages in thread
From: Qing Zhao @ 2022-11-08 14:51 UTC (permalink / raw)
  To: rguenther, joseph; +Cc: gcc-patches, keescook, siddhesh, Qing Zhao


This patch serie include two changes:
  1. Change the name of array_at_struct_end_p to array_ref_flexible_size_p.
  2. Add a new warning option -Wstrict-flex-arrays and at the same time
keep -Warray-bounds unchanged from -fstrict-flex-arrays.

The new warning -Wstrict-flex-arrays is implemented at the same place as 
-Warray-bounds. Since we need to keep the old behaviors of
-Warray-bounds=[1|2], we refactor the routine
"array_bounds_checker::check_array_ref" to make it work for both
-Warray-bounds and -Wstrict-flex-arrays.  

if -Warray-bounds, -Wstrict-flex-arrays, -fstrict-flex-arrays presents
at the same time:
  A. -Warray-bounds will be not controlled by -fstrict-flex-arrays;
  B. -Wstrict-flex-arrays will be controled by -fstrict-flex-arrays;
  C. both -Warray-bounds and -Wstrict-flex-arrays will report warnings
     according to it's own rules.

bootstrapped and regression tested on both x86 and aarch64. no issue.
Okay for commit?

thanks.

Qing



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

* [PATCH 1/2] Change the name of array_at_struct_end_p to array_ref_flexible_size_p
  2022-11-08 14:51 [PATCH 0/2] Add a new warning option -Wstrict-flex-array Qing Zhao
@ 2022-11-08 14:51 ` Qing Zhao
  2022-11-09  7:57   ` Richard Biener
  2022-11-08 14:51 ` [PATCH 2/2] Add a new warning option -Wstrict-flex-arrays Qing Zhao
  1 sibling, 1 reply; 15+ messages in thread
From: Qing Zhao @ 2022-11-08 14:51 UTC (permalink / raw)
  To: rguenther, joseph; +Cc: gcc-patches, keescook, siddhesh, Qing Zhao

The name of the utility routine "array_at_struct_end_p" is misleading
and should be changed to a new name that more accurately reflects its
real meaning.

The routine "array_at_struct_end_p" is used to check whether an array
reference is to an array whose actual size might be larger than its
upper bound implies, which includes 3 different 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;
   C. a ref to an array that was passed as a parameter;

The old name only reflects the above case A, therefore very confusing
when reading the corresponding gcc source code.

In this patch, A new name "array_ref_flexible_size_p" is used to replace
the old name.

All the references to the routine "array_at_struct_end_p" was replaced
with this new name, and the corresponding comments were updated to make
them clean and consistent.

gcc/ChangeLog:

	* gimple-array-bounds.cc (trailing_array): Replace
	array_at_struct_end_p with new name and update comments.
	* gimple-fold.cc (get_range_strlen_tree): Likewise.
	* gimple-ssa-warn-restrict.cc (builtin_memref::builtin_memref):
	Likewise.
	* graphite-sese-to-poly.cc (bounds_are_valid): Likewise.
	* tree-if-conv.cc (idx_within_array_bound): Likewise.
	* tree-object-size.cc (addr_object_size): Likewise.
	* tree-ssa-alias.cc (component_ref_to_zero_sized_trailing_array_p):
	Likewise.
	(stmt_kills_ref_p): Likewise.
	* tree-ssa-loop-niter.cc (idx_infer_loop_bounds): Likewise.
	* tree-ssa-strlen.cc (maybe_set_strlen_range): Likewise.
	* tree.cc (array_at_struct_end_p): Rename to ...
	(array_ref_flexible_size_p): ... this.
	(component_ref_size): Replace array_at_struct_end_p with new name.
	* tree.h (array_at_struct_end_p): Rename to ...
	(array_ref_flexible_size_p): ... this.
---
 gcc/gimple-array-bounds.cc      |  4 ++--
 gcc/gimple-fold.cc              |  6 ++----
 gcc/gimple-ssa-warn-restrict.cc |  5 +++--
 gcc/graphite-sese-to-poly.cc    |  4 ++--
 gcc/tree-if-conv.cc             |  7 +++----
 gcc/tree-object-size.cc         |  2 +-
 gcc/tree-ssa-alias.cc           |  8 ++++----
 gcc/tree-ssa-loop-niter.cc      | 15 +++++++--------
 gcc/tree-ssa-strlen.cc          |  2 +-
 gcc/tree.cc                     | 11 ++++++-----
 gcc/tree.h                      |  8 ++++----
 11 files changed, 35 insertions(+), 37 deletions(-)

diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc
index e190b93aa85..fbf448e045d 100644
--- a/gcc/gimple-array-bounds.cc
+++ b/gcc/gimple-array-bounds.cc
@@ -129,7 +129,7 @@ get_ref_size (tree arg, tree *pref)
 }
 
 /* Return true if REF is (likely) an ARRAY_REF to a trailing array member
-   of a struct.  It refines array_at_struct_end_p by detecting a pointer
+   of a struct.  It refines array_ref_flexible_size_p by detecting a pointer
    to an array and an array parameter declared using the [N] syntax (as
    opposed to a pointer) and returning false.  Set *PREF to the decl or
    expression REF refers to.  */
@@ -167,7 +167,7 @@ trailing_array (tree arg, tree *pref)
 	return false;
     }
 
-  return array_at_struct_end_p (arg);
+  return array_ref_flexible_size_p (arg);
 }
 
 /* Checks one ARRAY_REF in REF, located at LOCUS. Ignores flexible
diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index 9055cd8982d..cafd331ca98 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -1690,13 +1690,11 @@ get_range_strlen_tree (tree arg, bitmap visited, strlen_range_kind rkind,
 	  /* Handle a MEM_REF into a DECL accessing an array of integers,
 	     being conservative about references to extern structures with
 	     flexible array members that can be initialized to arbitrary
-	     numbers of elements as an extension (static structs are okay).
-	     FIXME: Make this less conservative -- see
-	     component_ref_size in tree.cc.  */
+	     numbers of elements as an extension (static structs are okay).  */
 	  tree ref = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
 	  if ((TREE_CODE (ref) == PARM_DECL || VAR_P (ref))
 	      && (decl_binds_to_current_def_p (ref)
-		  || !array_at_struct_end_p (arg)))
+		  || !array_ref_flexible_size_p (arg)))
 	    {
 	      /* Fail if the offset is out of bounds.  Such accesses
 		 should be diagnosed at some point.  */
diff --git a/gcc/gimple-ssa-warn-restrict.cc b/gcc/gimple-ssa-warn-restrict.cc
index b7ed15c8902..832456ba6fc 100644
--- a/gcc/gimple-ssa-warn-restrict.cc
+++ b/gcc/gimple-ssa-warn-restrict.cc
@@ -296,8 +296,9 @@ builtin_memref::builtin_memref (pointer_query &ptrqry, gimple *stmt, tree expr,
   tree basetype = TREE_TYPE (base);
   if (TREE_CODE (basetype) == ARRAY_TYPE)
     {
-      if (ref && array_at_struct_end_p (ref))
-	;   /* Use the maximum possible offset for last member arrays.  */
+      if (ref && array_ref_flexible_size_p (ref))
+	;   /* Use the maximum possible offset for an array that might
+	       have flexible size.  */
       else if (tree basesize = TYPE_SIZE_UNIT (basetype))
 	if (TREE_CODE (basesize) == INTEGER_CST)
 	  /* Size could be non-constant for a variable-length type such
diff --git a/gcc/graphite-sese-to-poly.cc b/gcc/graphite-sese-to-poly.cc
index 51ba3af204f..7eb24c1c991 100644
--- a/gcc/graphite-sese-to-poly.cc
+++ b/gcc/graphite-sese-to-poly.cc
@@ -536,9 +536,9 @@ bounds_are_valid (tree ref, tree low, tree high)
       || !tree_fits_shwi_p (high))
     return false;
 
-  /* 1-element arrays at end of structures may extend over
+  /* An array that has flexible size may extend over
      their declared size.  */
-  if (array_at_struct_end_p (ref)
+  if (array_ref_flexible_size_p (ref)
       && operand_equal_p (low, high, 0))
     return false;
 
diff --git a/gcc/tree-if-conv.cc b/gcc/tree-if-conv.cc
index a83b013d2ad..34bb507ff3b 100644
--- a/gcc/tree-if-conv.cc
+++ b/gcc/tree-if-conv.cc
@@ -763,10 +763,9 @@ idx_within_array_bound (tree ref, tree *idx, void *dta)
   if (TREE_CODE (ref) != ARRAY_REF)
     return false;
 
-  /* For arrays at the end of the structure, we are not guaranteed that they
-     do not really extend over their declared size.  However, for arrays of
-     size greater than one, this is unlikely to be intended.  */
-  if (array_at_struct_end_p (ref))
+  /* For arrays that might have flexible sizes, it is not guaranteed that they
+     do not extend over their declared size.  */
+  if (array_ref_flexible_size_p (ref))
     return false;
 
   ev = analyze_scalar_evolution (loop, *idx);
diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
index 1f04cb80fd0..2e5d267d8ce 100644
--- a/gcc/tree-object-size.cc
+++ b/gcc/tree-object-size.cc
@@ -633,7 +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);
+		    is_flexible_array_mem_ref = array_ref_flexible_size_p (v);
 		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
 		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
 			  != UNION_TYPE
diff --git a/gcc/tree-ssa-alias.cc b/gcc/tree-ssa-alias.cc
index b4c65da5718..d3a91b1f238 100644
--- a/gcc/tree-ssa-alias.cc
+++ b/gcc/tree-ssa-alias.cc
@@ -1073,7 +1073,7 @@ component_ref_to_zero_sized_trailing_array_p (tree ref)
 	  && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 1))) == ARRAY_TYPE
 	  && (!TYPE_SIZE (TREE_TYPE (TREE_OPERAND (ref, 1)))
 	      || integer_zerop (TYPE_SIZE (TREE_TYPE (TREE_OPERAND (ref, 1)))))
-	  && array_at_struct_end_p (ref));
+	  && array_ref_flexible_size_p (ref));
 }
 
 /* Worker for aliasing_component_refs_p. Most parameters match parameters of
@@ -3433,10 +3433,10 @@ stmt_kills_ref_p (gimple *stmt, ao_ref *ref)
 	    }
 	  /* Finally check if the lhs has the same address and size as the
 	     base candidate of the access.  Watch out if we have dropped
-	     an array-ref that was at struct end, this means ref->ref may
-	     be outside of the TYPE_SIZE of its base.  */
+	     an array-ref that might have flexible size, this means ref->ref
+	     may be outside of the TYPE_SIZE of its base.  */
 	  if ((! innermost_dropped_array_ref
-	       || ! array_at_struct_end_p (innermost_dropped_array_ref))
+	       || ! array_ref_flexible_size_p (innermost_dropped_array_ref))
 	      && (lhs == base
 		  || (((TYPE_SIZE (TREE_TYPE (lhs))
 			== TYPE_SIZE (TREE_TYPE (base)))
diff --git a/gcc/tree-ssa-loop-niter.cc b/gcc/tree-ssa-loop-niter.cc
index 4ffcef4f4ff..3fbbf4367ed 100644
--- a/gcc/tree-ssa-loop-niter.cc
+++ b/gcc/tree-ssa-loop-niter.cc
@@ -3716,18 +3716,17 @@ idx_infer_loop_bounds (tree base, tree *idx, void *dta)
   struct ilb_data *data = (struct ilb_data *) dta;
   tree ev, init, step;
   tree low, high, type, next;
-  bool sign, upper = true, at_end = false;
+  bool sign, upper = true, has_flexible_size = false;
   class loop *loop = data->loop;
 
   if (TREE_CODE (base) != ARRAY_REF)
     return true;
 
-  /* For arrays at the end of the structure, we are not guaranteed that they
-     do not really extend over their declared size.  However, for arrays of
-     size greater than one, this is unlikely to be intended.  */
-  if (array_at_struct_end_p (base))
+  /* For arrays that might have flexible sizes, it is not guaranteed that they
+     do not really extend over their declared size.  */ 
+  if (array_ref_flexible_size_p (base))
     {
-      at_end = true;
+      has_flexible_size = true;
       upper = false;
     }
 
@@ -3760,9 +3759,9 @@ idx_infer_loop_bounds (tree base, tree *idx, void *dta)
   sign = tree_int_cst_sign_bit (step);
   type = TREE_TYPE (step);
 
-  /* The array of length 1 at the end of a structure most likely extends
+  /* The array that might have flexible size most likely extends
      beyond its bounds.  */
-  if (at_end
+  if (has_flexible_size
       && operand_equal_p (low, high, 0))
     return true;
 
diff --git a/gcc/tree-ssa-strlen.cc b/gcc/tree-ssa-strlen.cc
index 5afbae1b72e..b87c7c7ce1f 100644
--- a/gcc/tree-ssa-strlen.cc
+++ b/gcc/tree-ssa-strlen.cc
@@ -1987,7 +1987,7 @@ maybe_set_strlen_range (tree lhs, tree src, tree bound)
 	 suggests if it's treated as a poor-man's flexible array member.  */
       src = TREE_OPERAND (src, 0);
       if (TREE_CODE (src) != MEM_REF
-	  && !array_at_struct_end_p (src))
+	  && !array_ref_flexible_size_p (src))
 	{
 	  tree type = TREE_TYPE (src);
 	  tree size = TYPE_SIZE_UNIT (type);
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 04603c8c902..d2b0b34a725 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -12710,8 +12710,8 @@ array_ref_up_bound (tree exp)
   return NULL_TREE;
 }
 
-/* Returns true if REF is an array reference, component reference,
-   or memory reference to an array whose actual size might be larger
+/* Returns true if REF is an array reference, a component reference,
+   or a memory reference to an array whose actual size might be larger
    than its upper bound implies, 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;
@@ -12726,10 +12726,10 @@ array_ref_up_bound (tree exp)
    int test (uint8_t *p, uint32_t t[1][1], int n) {
    for (int i = 0; i < 4; i++, p++)
      t[i][0] = ...;
+*/
 
-   FIXME, the name of this routine need to be changed to be more accurate.  */
 bool
-array_at_struct_end_p (tree ref)
+array_ref_flexible_size_p (tree ref)
 {
   /* the TYPE for this array referece.  */
   tree atype = NULL_TREE;
@@ -12862,6 +12862,7 @@ array_at_struct_end_p (tree ref)
   return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
 }
 
+
 /* Return a tree representing the offset, in bytes, of the field referenced
    by EXP.  This does not include any offset in DECL_FIELD_BIT_OFFSET.  */
 
@@ -12957,7 +12958,7 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */)
 	return (tree_int_cst_equal (memsize, TYPE_SIZE_UNIT (memtype))
 		? memsize : NULL_TREE);
 
-      bool trailing = array_at_struct_end_p (ref);
+      bool trailing = array_ref_flexible_size_p (ref);
       bool zero_length = integer_zerop (memsize);
       if (!trailing && !zero_length)
 	/* MEMBER is either an interior array or is an array with
diff --git a/gcc/tree.h b/gcc/tree.h
index a50f7b2be9d..0fcdd6b06d0 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5548,10 +5548,10 @@ extern tree array_ref_up_bound (tree);
    EXP, an ARRAY_REF or an ARRAY_RANGE_REF.  */
 extern tree array_ref_low_bound (tree);
 
-/* Returns true if REF is an array reference or a component 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.  */
-extern bool array_at_struct_end_p (tree);
+/* Returns true if REF is an array reference, a component reference,
+   or a memory reference to an array whose actual size might be larger
+   than its upper bound implies.  */
+extern bool array_ref_flexible_size_p (tree);
 
 /* Return a tree representing the offset, in bytes, of the field referenced
    by EXP.  This does not include any offset in DECL_FIELD_BIT_OFFSET.  */
-- 
2.31.1


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

* [PATCH 2/2] Add a new warning option -Wstrict-flex-arrays.
  2022-11-08 14:51 [PATCH 0/2] Add a new warning option -Wstrict-flex-array Qing Zhao
  2022-11-08 14:51 ` [PATCH 1/2] Change the name of array_at_struct_end_p to array_ref_flexible_size_p Qing Zhao
@ 2022-11-08 14:51 ` Qing Zhao
  2022-11-15 15:41   ` Qing Zhao
  2022-11-18 13:14   ` Richard Biener
  1 sibling, 2 replies; 15+ messages in thread
From: Qing Zhao @ 2022-11-08 14:51 UTC (permalink / raw)
  To: rguenther, joseph; +Cc: gcc-patches, keescook, siddhesh, Qing Zhao

'-Wstrict-flex-arrays'
     Warn about inproper usages of flexible array members according to
     the LEVEL of the 'strict_flex_array (LEVEL)' attribute attached to
     the trailing array field of a structure if it's available,
     otherwise according to the LEVEL of the option
     '-fstrict-flex-arrays=LEVEL'.

     This option is effective only when LEVEL is bigger than 0.
     Otherwise, it will be ignored with a warning.

     when LEVEL=1, warnings will be issued for a trailing array
     reference of a structure that have 2 or more elements if the
     trailing array is referenced as a flexible array member.

     when LEVEL=2, in addition to LEVEL=1, additional warnings will be
     issued for a trailing one-element array reference of a structure if
     the array is referenced as a flexible array member.

     when LEVEL=3, in addition to LEVEL=2, additional warnings will be
     issued for a trailing zero-length array reference of a structure if
     the array is referenced as a flexible array member.

At the same time, keep -Warray-bounds=[1|2] warnings unchanged from
 -fstrict-flex-arrays.

gcc/ChangeLog:

	* attribs.cc (strict_flex_array_level_of): New function.
	* attribs.h (strict_flex_array_level_of): Prototype for new function.
	* doc/invoke.texi: Document -Wstrict-flex-arrays option. Update
	-fstrict-flex-arrays[=n] options.
	* gimple-array-bounds.cc (array_bounds_checker::check_array_ref):
	Issue warnings for -Wstrict-flex-arrays.
	(get_up_bounds_for_array_ref): New function.
	(check_out_of_bounds_and_warn): New function.
	* opts.cc (finish_options): Issue warnings for unsupported combination
	of -Warray-bounds and -fstrict-flex-arrays, -Wstrict_flex_arrays and
	-fstrict-flex-array.
	* tree-vrp.cc (execute_vrp): Enable the pass when
	warn_strict_flex_array is true.
	(execute_ranger_vrp): Likewise.
	* tree.cc (array_ref_flexible_size_p): Add one new argument.
	(component_ref_sam_type): New function.
	(component_ref_size): Add one new argument,
	* tree.h (array_ref_flexible_size_p): Update prototype.
	(enum struct special_array_member): Add two new enum values.
	(component_ref_sam_type): New prototype.
	(component_ref_size): Update prototype.

gcc/c-family/ChangeLog:

	* c.opt (Wstrict-flex-arrays): New option.

gcc/c/ChangeLog:

	* c-decl.cc (is_flexible_array_member_p): Call new function
	strict_flex_array_level_of.

gcc/testsuite/ChangeLog:

	* c-c++-common/Wstrict-flex-arrays.c: New test.
	* c-c++-common/Wstrict-flex-arrays_2.c: New test.
	* gcc.dg/Wstrict-flex-arrays-2.c: New test.
	* gcc.dg/Wstrict-flex-arrays-3.c: New test.
	* gcc.dg/Wstrict-flex-arrays-4.c: New test.
	* gcc.dg/Wstrict-flex-arrays-5.c: New test.
	* gcc.dg/Wstrict-flex-arrays-6.c: New test.
	* gcc.dg/Wstrict-flex-arrays-7.c: New test.
	* gcc.dg/Wstrict-flex-arrays-8.c: New test.
	* gcc.dg/Wstrict-flex-arrays-9.c: New test.
	* gcc.dg/Wstrict-flex-arrays.c: New test.
---
 gcc/attribs.cc                                |  30 ++
 gcc/attribs.h                                 |   2 +
 gcc/c-family/c.opt                            |   5 +
 gcc/c/c-decl.cc                               |  22 +-
 gcc/doc/invoke.texi                           |  33 ++-
 gcc/gimple-array-bounds.cc                    | 264 +++++++++++++-----
 gcc/opts.cc                                   |  15 +
 .../c-c++-common/Wstrict-flex-arrays.c        |   9 +
 .../c-c++-common/Wstrict-flex-arrays_2.c      |   9 +
 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c  |  46 +++
 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c  |  46 +++
 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c  |  49 ++++
 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c  |  48 ++++
 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c  |  48 ++++
 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c  |  50 ++++
 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c  |  49 ++++
 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c  |  49 ++++
 gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c    |  46 +++
 gcc/tree-vrp.cc                               |   6 +-
 gcc/tree.cc                                   | 165 ++++++++---
 gcc/tree.h                                    |  15 +-
 21 files changed, 870 insertions(+), 136 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c
 create mode 100644 gcc/testsuite/c-c++-common/Wstrict-flex-arrays_2.c
 create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c
 create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c
 create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c
 create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c
 create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c
 create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c
 create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c
 create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c
 create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c

diff --git a/gcc/attribs.cc b/gcc/attribs.cc
index 27dea748561..095def4d6b0 100644
--- a/gcc/attribs.cc
+++ b/gcc/attribs.cc
@@ -2456,6 +2456,36 @@ init_attr_rdwr_indices (rdwr_map *rwm, tree attrs)
     }
 }
 
+/* Get the LEVEL of the strict_flex_array for the ARRAY_FIELD based on the
+   values of attribute strict_flex_array and the flag_strict_flex_arrays.  */
+unsigned int
+strict_flex_array_level_of (tree array_field)
+{
+  gcc_assert (TREE_CODE (array_field) == FIELD_DECL);
+  unsigned int strict_flex_array_level = flag_strict_flex_arrays;
+
+  tree attr_strict_flex_array
+    = lookup_attribute ("strict_flex_array", DECL_ATTRIBUTES (array_field));
+  /* If there is a strict_flex_array attribute attached to the field,
+     override the flag_strict_flex_arrays.  */
+  if (attr_strict_flex_array)
+    {
+      /* Get the value of the level first from the attribute.  */
+      unsigned HOST_WIDE_INT attr_strict_flex_array_level = 0;
+      gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
+      attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
+      gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
+      attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
+      gcc_assert (tree_fits_uhwi_p (attr_strict_flex_array));
+      attr_strict_flex_array_level = tree_to_uhwi (attr_strict_flex_array);
+
+      /* The attribute has higher priority than flag_struct_flex_array.  */
+      strict_flex_array_level = attr_strict_flex_array_level;
+    }
+  return strict_flex_array_level;
+}
+
+
 /* Return the access specification for a function parameter PARM
    or null if the current function has no such specification.  */
 
diff --git a/gcc/attribs.h b/gcc/attribs.h
index 1dc16e4bc4e..742811e6fda 100644
--- a/gcc/attribs.h
+++ b/gcc/attribs.h
@@ -398,4 +398,6 @@ extern void init_attr_rdwr_indices (rdwr_map *, tree);
 extern attr_access *get_parm_access (rdwr_map &, tree,
 				     tree = current_function_decl);
 
+extern unsigned int strict_flex_array_level_of (tree);
+
 #endif // GCC_ATTRIBS_H
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 01d480759ae..bc33710a649 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -968,6 +968,11 @@ Wstringop-truncation
 C ObjC C++ LTO ObjC++ Var(warn_stringop_truncation) Warning Init (1) LangEnabledBy(C ObjC C++ LTO ObjC++, Wall)
 Warn about truncation in string manipulation functions like strncat and strncpy.
 
+Wstrict-flex-arrays
+C C++ Var(warn_strict_flex_arrays) Warning
+Warn about inproper usages of flexible array members
+according to the level of -fstrict-flex-arrays.
+
 Wsuggest-attribute=format
 C ObjC C++ ObjC++ Var(warn_suggest_attribute_format) Warning
 Warn about functions which might be candidates for format attributes.
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 4746e310d2d..c9cb46daacc 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8828,7 +8828,6 @@ finish_incomplete_vars (tree incomplete_vars, bool toplevel)
     }
 }
 
-
 /* Determine whether the FIELD_DECL X is a flexible array member according to
    the following info:
   A. whether the FIELD_DECL X is the last field of the DECL_CONTEXT;
@@ -8855,26 +8854,7 @@ is_flexible_array_member_p (bool is_last_field,
   bool is_one_element_array = one_element_array_type_p (TREE_TYPE (x));
   bool is_flexible_array = flexible_array_member_type_p (TREE_TYPE (x));
 
-  unsigned int strict_flex_array_level = flag_strict_flex_arrays;
-
-  tree attr_strict_flex_array = lookup_attribute ("strict_flex_array",
-						  DECL_ATTRIBUTES (x));
-  /* If there is a strict_flex_array attribute attached to the field,
-     override the flag_strict_flex_arrays.  */
-  if (attr_strict_flex_array)
-    {
-      /* Get the value of the level first from the attribute.  */
-      unsigned HOST_WIDE_INT attr_strict_flex_array_level = 0;
-      gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
-      attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
-      gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
-      attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
-      gcc_assert (tree_fits_uhwi_p (attr_strict_flex_array));
-      attr_strict_flex_array_level = tree_to_uhwi (attr_strict_flex_array);
-
-      /* The attribute has higher priority than flag_struct_flex_array.  */
-      strict_flex_array_level = attr_strict_flex_array_level;
-    }
+  unsigned int strict_flex_array_level = strict_flex_array_level_of (x);
 
   switch (strict_flex_array_level)
     {
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 64f77e8367a..a35e6bf27e0 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -397,7 +397,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wstrict-aliasing=n  -Wstrict-overflow  -Wstrict-overflow=@var{n} @gol
 -Wstring-compare @gol
 -Wno-stringop-overflow -Wno-stringop-overread @gol
--Wno-stringop-truncation @gol
+-Wno-stringop-truncation -Wstrict-flex-arrays @gol
 -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{|}malloc@r{]} @gol
 -Wswitch  -Wno-switch-bool  -Wswitch-default  -Wswitch-enum @gol
 -Wno-switch-outside-range  -Wno-switch-unreachable  -Wsync-nand @gol
@@ -2848,12 +2848,18 @@ The negative form is equivalent to @option{-fstrict-flex-arrays=0}, which is the
 least strict.  All trailing arrays of structures are treated as flexible array
 members.
 
+This option is not compatible with @option{-Warray-bounds} due to historical
+reason.  The behavior of @option{-Warray-bounds} is not changed by this option.
+
 @item -fstrict-flex-arrays=@var{level}
 @opindex fstrict-flex-arrays=@var{level}
 Control when to treat the trailing array of a structure as a flexible array
 member for the purpose of accessing the elements of such an array.  The value
 of @var{level} controls the level of strictness.
 
+This option is not compatible with @option{-Warray-bounds} due to historical
+reason.  The behavior of @option{-Warray-bounds} is not changed by this option.
+
 The possible values of @var{level} are the same as for the
 @code{strict_flex_array} attribute (@pxref{Variable Attributes}).
 
@@ -7662,6 +7668,31 @@ however, are not suitable arguments to functions that expect
 such arrays GCC issues warnings unless it can prove that the use is
 safe.  @xref{Common Variable Attributes}.
 
+@item -Wstrict-flex-arrays
+@opindex Wstrict-flex-arrays
+@opindex Wno-strict-flex-arrays
+Warn about inproper usages of flexible array members
+according to the @var{level} of the @code{strict_flex_array (@var{level})}
+attribute attached to the trailing array field of a structure if it's
+available, otherwise according to the @var{level} of the option
+@option{-fstrict-flex-arrays=@var{level}}.
+
+This option is effective only when @var{level} is bigger than 0.  Otherwise,
+it will be ignored with a warning.
+
+when @var{level}=1, warnings will be issued for a trailing array reference
+of a structure that have 2 or more elements if the trailing array is referenced
+as a flexible array member.
+
+when @var{level}=2, in addition to @var{level}=1, additional warnings will be
+issued for a trailing one-element array reference of a structure
+if the array is referenced as a flexible array member.
+
+when @var{level}=3, in addition to @var{level}=2, additional warnings will be
+issued for a trailing zero-length array reference of a structure
+if the array is referenced as a flexible array member.
+
+
 @item -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{|}cold@r{|}malloc@r{]}
 @opindex Wsuggest-attribute=
 @opindex Wno-suggest-attribute=
diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc
index fbf448e045d..7f790c5a19a 100644
--- a/gcc/gimple-array-bounds.cc
+++ b/gcc/gimple-array-bounds.cc
@@ -170,38 +170,20 @@ trailing_array (tree arg, tree *pref)
   return array_ref_flexible_size_p (arg);
 }
 
-/* Checks one ARRAY_REF in REF, located at LOCUS. Ignores flexible
-   arrays and "struct" hacks. If VRP can determine that the array
-   subscript is a constant, check if it is outside valid range.  If
-   the array subscript is a RANGE, warn if it is non-overlapping with
-   valid range.  IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside
-   a ADDR_EXPR.  Return  true if a warning has been issued or if
-   no-warning is set.  */
-
-bool
-array_bounds_checker::check_array_ref (location_t location, tree ref,
-				       gimple *stmt, bool ignore_off_by_one)
+/* Acquire the upper bound and upper bound plus one for the array
+   reference REF and record them into UP_BOUND and UP_BOUND_P1.
+   Set *DECL to the decl or expresssion REF refers to.
+   FOR_ARRAY_BOUND is true when this is for array bound checking.  */
+
+static void
+get_up_bounds_for_array_ref (tree ref, tree *decl,
+			     tree *up_bound, tree *up_bound_p1,
+			     bool for_array_bound)
 {
-  if (warning_suppressed_p (ref, OPT_Warray_bounds))
-    /* Return true to have the caller prevent warnings for enclosing
-       refs.  */
-    return true;
-
-  tree low_sub = TREE_OPERAND (ref, 1);
-  tree up_sub = low_sub;
-  tree up_bound = array_ref_up_bound (ref);
-
-  /* Referenced decl if one can be determined.  */
-  tree decl = NULL_TREE;
-
-  /* Set for accesses to interior zero-length arrays.  */
-  special_array_member sam{ };
-
-  tree up_bound_p1;
-
-  if (!up_bound
-      || TREE_CODE (up_bound) != INTEGER_CST
-      || (warn_array_bounds < 2 && trailing_array (ref, &decl)))
+  if (!(*up_bound)
+      || TREE_CODE (*up_bound) != INTEGER_CST
+      || ((for_array_bound ? (warn_array_bounds < 2) : warn_strict_flex_arrays)
+	   && trailing_array (ref, decl)))
     {
       /* Accesses to trailing arrays via pointers may access storage
 	 beyond the types array bounds.  For such arrays, or for flexible
@@ -213,8 +195,8 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
       if (TREE_CODE (eltsize) != INTEGER_CST
 	  || integer_zerop (eltsize))
 	{
-	  up_bound = NULL_TREE;
-	  up_bound_p1 = NULL_TREE;
+	  *up_bound = NULL_TREE;
+	  *up_bound_p1 = NULL_TREE;
 	}
       else
 	{
@@ -227,7 +209,8 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
 	    {
 	      /* Try to determine the size of the trailing array from
 		 its initializer (if it has one).  */
-	      if (tree refsize = component_ref_size (arg, &sam))
+	      if (tree refsize
+		    = component_ref_size (arg, NULL, for_array_bound))
 		if (TREE_CODE (refsize) == INTEGER_CST)
 		  maxbound = refsize;
 	    }
@@ -246,7 +229,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
 		    {
 		      /* Try to determine the size from a pointer to
 			 an array if BASE is one.  */
-		      if (tree size = get_ref_size (base, &decl))
+		      if (tree size = get_ref_size (base, decl))
 			maxbound = size;
 		    }
 		  else if (!compref && DECL_P (base))
@@ -254,7 +237,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
 		      if (TREE_CODE (basesize) == INTEGER_CST)
 			{
 			  maxbound = basesize;
-			  decl = base;
+			  *decl = base;
 			}
 
 		  if (known_gt (off, 0))
@@ -266,40 +249,47 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
 	  else
 	    maxbound = fold_convert (sizetype, maxbound);
 
-	  up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize);
+	  *up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize);
 
-	  if (up_bound_p1 != NULL_TREE)
-	    up_bound = int_const_binop (MINUS_EXPR, up_bound_p1,
+	  if (*up_bound_p1 != NULL_TREE)
+	    *up_bound = int_const_binop (MINUS_EXPR, *up_bound_p1,
 					build_int_cst (ptrdiff_type_node, 1));
 	  else
-	    up_bound = NULL_TREE;
+	    *up_bound = NULL_TREE;
 	}
     }
   else
-    up_bound_p1 = int_const_binop (PLUS_EXPR, up_bound,
-				   build_int_cst (TREE_TYPE (up_bound), 1));
+    *up_bound_p1 = int_const_binop (PLUS_EXPR, *up_bound,
+				   build_int_cst (TREE_TYPE (*up_bound), 1));
+  return;
+}
 
-  tree low_bound = array_ref_low_bound (ref);
+/* Given the LOW_SUB_ORG, LOW_SUB and UP_SUB, and the computed UP_BOUND
+   and UP_BOUND_P1, check whether the array reference REF is out of bound.
+   When out of bounds, issue warnings if FOR_ARRAY_BOUND is true.
+   otherwise, return true without issue warnings.  */
 
+static bool
+check_out_of_bounds_and_warn (location_t location, tree ref,
+			      tree low_sub_org, tree low_sub, tree up_sub,
+			      tree up_bound, tree up_bound_p1,
+			      const value_range *vr,
+			      bool ignore_off_by_one, bool for_array_bound)
+{
+  tree low_bound = array_ref_low_bound (ref);
   tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
 
   bool warned = false;
 
   /* Empty array.  */
   if (up_bound && tree_int_cst_equal (low_bound, up_bound_p1))
-    warned = warning_at (location, OPT_Warray_bounds,
-			 "array subscript %E is outside array bounds of %qT",
-			 low_sub, artype);
-
-  const value_range *vr = NULL;
-  if (TREE_CODE (low_sub) == SSA_NAME)
     {
-      vr = get_value_range (low_sub, stmt);
-      if (!vr->undefined_p () && !vr->varying_p ())
-	{
-	  low_sub = vr->kind () == VR_RANGE ? vr->max () : vr->min ();
-	  up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max ();
-	}
+      if (for_array_bound)
+	warned = warning_at (location, OPT_Warray_bounds,
+			     "array subscript %E is outside array"
+			     " bounds of %qT", low_sub_org, artype);
+      else
+	warned = true;
     }
 
   if (warned)
@@ -313,24 +303,127 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
 	      : tree_int_cst_le (up_bound, up_sub))
 	  && TREE_CODE (low_sub) == INTEGER_CST
 	  && tree_int_cst_le (low_sub, low_bound))
-	warned = warning_at (location, OPT_Warray_bounds,
-			     "array subscript [%E, %E] is outside "
-			     "array bounds of %qT",
-			     low_sub, up_sub, artype);
+	{
+	  if (for_array_bound)
+	    warned = warning_at (location, OPT_Warray_bounds,
+				 "array subscript [%E, %E] is outside "
+				 "array bounds of %qT",
+				 low_sub, up_sub, artype);
+	  else
+	    warned = true;
+	}
     }
   else if (up_bound
 	   && TREE_CODE (up_sub) == INTEGER_CST
 	   && (ignore_off_by_one
 	       ? !tree_int_cst_le (up_sub, up_bound_p1)
 	       : !tree_int_cst_le (up_sub, up_bound)))
-    warned = warning_at (location, OPT_Warray_bounds,
-			 "array subscript %E is above array bounds of %qT",
-			 up_sub, artype);
+    {
+      if (for_array_bound)
+	warned = warning_at (location, OPT_Warray_bounds,
+			     "array subscript %E is above array bounds of %qT",
+			     up_sub, artype);
+      else
+	warned = true;
+    }
   else if (TREE_CODE (low_sub) == INTEGER_CST
 	   && tree_int_cst_lt (low_sub, low_bound))
-    warned = warning_at (location, OPT_Warray_bounds,
-			 "array subscript %E is below array bounds of %qT",
-			 low_sub, artype);
+    {
+      if (for_array_bound)
+	warned = warning_at (location, OPT_Warray_bounds,
+			     "array subscript %E is below array bounds of %qT",
+			     low_sub, artype);
+      else
+	warned = true;
+    }
+  return warned;
+}
+
+/* Checks one ARRAY_REF in REF, located at LOCUS.  Ignores flexible
+   arrays and "struct" hacks.  If VRP can determine that the array
+   subscript is a constant, check if it is outside valid range.  If
+   the array subscript is a RANGE, warn if it is non-overlapping with
+   valid range.  IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside
+   a ADDR_EXPR.  Return  true if a warning has been issued or if
+   no-warning is set.  */
+
+bool
+array_bounds_checker::check_array_ref (location_t location, tree ref,
+				       gimple *stmt, bool ignore_off_by_one)
+{
+  if (warning_suppressed_p (ref, OPT_Warray_bounds))
+    /* Return true to have the caller prevent warnings for enclosing
+       refs.  */
+    return true;
+
+  /* Upper bound and Upper bound plus one for -Warray-bounds.  */
+  tree up_bound = array_ref_up_bound (ref);
+  tree up_bound_p1 = NULL_TREE;
+
+  /* Upper bound and upper bound plus one for -Wstrict-flex-array.  */
+  tree up_bound_strict = up_bound;
+  tree up_bound_p1_strict = NULL_TREE;
+
+  /* Referenced decl if one can be determined.  */
+  tree decl = NULL_TREE;
+
+  /* Set to the type of the special array member for a COMPONENT_REF.  */
+  special_array_member sam{ };
+
+  tree arg = TREE_OPERAND (ref, 0);
+  const bool compref = TREE_CODE (arg) == COMPONENT_REF;
+
+  unsigned int strict_flex_array_level = flag_strict_flex_arrays;
+
+  if (compref)
+    {
+      /* Try to determine special array member type for this COMPONENT_REF.  */
+      sam = component_ref_sam_type (arg);
+      /* Get the level of strict_flex_array for this array field.  */
+      tree afield_decl = TREE_OPERAND (arg, 1);
+      strict_flex_array_level = strict_flex_array_level_of (afield_decl);
+    }
+
+  if (warn_array_bounds)
+    get_up_bounds_for_array_ref (ref, &decl, &up_bound, &up_bound_p1,
+				 true);
+  if (warn_strict_flex_arrays)
+    get_up_bounds_for_array_ref (ref, &decl, &up_bound_strict,
+				 &up_bound_p1_strict, false);
+
+
+
+  bool warned = false;
+  bool out_of_bound = false;
+
+  tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
+  tree low_sub_org = TREE_OPERAND (ref, 1);
+  tree up_sub = low_sub_org;
+  tree low_sub = low_sub_org;
+
+  const value_range *vr = NULL;
+  if (TREE_CODE (low_sub_org) == SSA_NAME)
+    {
+      vr = get_value_range (low_sub_org, stmt);
+      if (!vr->undefined_p () && !vr->varying_p ())
+	{
+	  low_sub = vr->kind () == VR_RANGE ? vr->max () : vr->min ();
+	  up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max ();
+	}
+    }
+
+  if (warn_array_bounds)
+    warned = check_out_of_bounds_and_warn (location, ref,
+					   low_sub_org, low_sub, up_sub,
+					   up_bound, up_bound_p1, vr,
+					   ignore_off_by_one, true);
+
+  if (warn_strict_flex_arrays)
+    out_of_bound = check_out_of_bounds_and_warn (location, ref,
+						 low_sub_org, low_sub, up_sub,
+						 up_bound_strict,
+						 up_bound_p1_strict, vr,
+						 ignore_off_by_one, false);
 
   if (!warned && sam == special_array_member::int_0)
     warned = warning_at (location, OPT_Wzero_length_bounds,
@@ -341,19 +434,56 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
 			       "of an interior zero-length array %qT")),
 			 low_sub, artype);
 
-  if (warned)
+  if (warned || out_of_bound)
     {
-      if (dump_file && (dump_flags & TDF_DETAILS))
+      if (warned && dump_file && (dump_flags & TDF_DETAILS))
 	{
 	  fprintf (dump_file, "Array bound warning for ");
 	  dump_generic_expr (MSG_NOTE, TDF_SLIM, ref);
 	  fprintf (dump_file, "\n");
 	}
 
+      /* issue warnings for -Wstrict-flex-arrays according to the level of
+	 flag_strict_flex_arrays.  */
+      if (out_of_bound && warn_strict_flex_arrays)
+	switch (strict_flex_array_level)
+	  {
+	    case 3:
+	      /* Issue additional warnings for trailing arrays [0].  */
+	      if (sam == special_array_member::trail_0)
+		warned = warning_at (location, OPT_Wstrict_flex_arrays,
+				     "trailing array %qT should not be used as "
+				     "a flexible array member for level 3",
+				     artype);
+	      /* FALLTHROUGH.  */
+	    case 2:
+	      /* Issue additional warnings for trailing arrays [1].  */
+	      if (sam == special_array_member::trail_1)
+		warned = warning_at (location, OPT_Wstrict_flex_arrays,
+				     "trailing array %qT should not be used as "
+				     "a flexible array member for level 2 and "
+				     "above", artype);
+	      /* FALLTHROUGH.  */
+	    case 1:
+	      /* Issue warnings for trailing arrays [n].  */
+	      if (sam == special_array_member::trail_n)
+		warned = warning_at (location, OPT_Wstrict_flex_arrays,
+				     "trailing array %qT should not be used as "
+				     "a flexible array member for level 1 and "
+				     "above", artype);
+	      break;
+	    case 0:
+	      /* Do nothing.  */
+	      break;
+	    default:
+	      gcc_unreachable ();
+	  }
+
       /* Avoid more warnings when checking more significant subscripts
 	 of the same expression.  */
       ref = TREE_OPERAND (ref, 0);
       suppress_warning (ref, OPT_Warray_bounds);
+      suppress_warning (ref, OPT_Wstrict_flex_arrays);
 
       if (decl)
 	ref = decl;
diff --git a/gcc/opts.cc b/gcc/opts.cc
index ae079fcd20e..ca162aa781c 100644
--- a/gcc/opts.cc
+++ b/gcc/opts.cc
@@ -1409,6 +1409,21 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
       opts->x_profile_flag = 0;
     }
 
+  if (opts->x_warn_array_bounds)
+    if (opts->x_flag_strict_flex_arrays)
+      {
+	warning_at (UNKNOWN_LOCATION, 0,
+		    "%<-Warray-bounds%> is not impacted by "
+		    "%<-fstrict-flex-arrays%>");
+      }
+  if (opts->x_warn_strict_flex_arrays)
+    if (opts->x_flag_strict_flex_arrays == 0)
+      {
+	opts->x_warn_strict_flex_arrays = 0;
+	warning_at (UNKNOWN_LOCATION, 0,
+		    "%<-Wstrict-flex-arrays%> is ignored when"
+		    " %<-fstrict-flex-arrays%> does not present");
+      }
 
   diagnose_options (opts, opts_set, loc);
 }
diff --git a/gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c
new file mode 100644
index 00000000000..72b4b7c6406
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c
@@ -0,0 +1,9 @@
+/* Test the usage of option -Wstrict-flex-arrays.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wstrict-flex-arrays" } */
+
+int main(int argc, char *argv[])
+{
+    return 0;
+}
+/* { dg-warning "is ignored when \'-fstrict-flex-arrays\' does not present" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/c-c++-common/Wstrict-flex-arrays_2.c b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays_2.c
new file mode 100644
index 00000000000..af9ec922dea
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays_2.c
@@ -0,0 +1,9 @@
+/* Test the usage of option -Wstrict-flex-arrays.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -Warray-bounds -fstrict-flex-arrays" } */
+
+int main(int argc, char *argv[])
+{
+    return 0;
+}
+/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c
new file mode 100644
index 00000000000..59d5a5fcb23
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c
@@ -0,0 +1,46 @@
+/* Test -Wstrict-flex-arrays.  */
+/* { dg-do run } */
+/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=2" } */
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[4]; 
+};
+
+struct trailing_array_2 {
+    int a;
+    int b;
+    int c[1]; 
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0];
+};
+struct trailing_array_4 {
+    int a;
+    int b;
+    int c[];
+};
+
+void __attribute__((__noinline__)) stuff(
+    struct trailing_array_1 *normal,
+    struct trailing_array_2 *trailing_1,
+    struct trailing_array_3 *trailing_0,
+    struct trailing_array_4 *trailing_flex)
+{
+    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
+    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
+    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
+    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
+
+}
+
+int main(int argc, char *argv[])
+{
+    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
+
+    return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c
new file mode 100644
index 00000000000..2f66151e927
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c
@@ -0,0 +1,46 @@
+/* Test -Wstrict-flex-arrays.  */
+/* { dg-do run } */
+/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=3" } */
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[4]; 
+};
+
+struct trailing_array_2 {
+    int a;
+    int b;
+    int c[1]; 
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0];
+};
+struct trailing_array_4 {
+    int a;
+    int b;
+    int c[];
+};
+
+void __attribute__((__noinline__)) stuff(
+    struct trailing_array_1 *normal,
+    struct trailing_array_2 *trailing_1,
+    struct trailing_array_3 *trailing_0,
+    struct trailing_array_4 *trailing_flex)
+{
+    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
+    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
+    trailing_0->c[1] = 1; /* { dg-warning "should not be used as a flexible array member for level 3" } */
+    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 3" } */
+
+}
+
+int main(int argc, char *argv[])
+{
+    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
+
+    return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c
new file mode 100644
index 00000000000..6a4576568ac
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c
@@ -0,0 +1,49 @@
+/* Test -Wstrict-flex-arrays + -Warray-bounds.  */
+/* { dg-do run } */
+/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=1 -Warray-bounds" } */
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[4]; 
+};
+
+struct trailing_array_2 {
+    int a;
+    int b;
+    int c[1]; 
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0];
+};
+struct trailing_array_4 {
+    int a;
+    int b;
+    int c[];
+};
+
+void __attribute__((__noinline__)) stuff(
+    struct trailing_array_1 *normal,
+    struct trailing_array_2 *trailing_1,
+    struct trailing_array_3 *trailing_0,
+    struct trailing_array_4 *trailing_flex)
+{
+    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
+    			 /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
+    trailing_1->c[2] = 2; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
+    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
+    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
+
+}
+
+int main(int argc, char *argv[])
+{
+    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
+
+    return 0;
+}
+
+/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c
new file mode 100644
index 00000000000..e550fbd24e1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c
@@ -0,0 +1,48 @@
+/* Test -Wstrict-flex-arrays + -Warray-bounds.  */
+/* { dg-do run } */
+/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=2 -Warray-bounds" } */
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[4]; 
+};
+
+struct trailing_array_2 {
+    int a;
+    int b;
+    int c[1]; 
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0];
+};
+struct trailing_array_4 {
+    int a;
+    int b;
+    int c[];
+};
+
+void __attribute__((__noinline__)) stuff(
+    struct trailing_array_1 *normal,
+    struct trailing_array_2 *trailing_1,
+    struct trailing_array_3 *trailing_0,
+    struct trailing_array_4 *trailing_flex)
+{
+    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
+    			 /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
+    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
+    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
+    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
+
+}
+
+int main(int argc, char *argv[])
+{
+    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
+
+    return 0;
+}
+/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c
new file mode 100644
index 00000000000..d5b61136b3a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c
@@ -0,0 +1,48 @@
+/* Test -Wstrict-flex-arrays.  */
+/* { dg-do run } */
+/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=3 -Warray-bounds" } */
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[4]; 
+};
+
+struct trailing_array_2 {
+    int a;
+    int b;
+    int c[1]; 
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0];
+};
+struct trailing_array_4 {
+    int a;
+    int b;
+    int c[];
+};
+
+void __attribute__((__noinline__)) stuff(
+    struct trailing_array_1 *normal,
+    struct trailing_array_2 *trailing_1,
+    struct trailing_array_3 *trailing_0,
+    struct trailing_array_4 *trailing_flex)
+{
+    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
+   			/*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */ 
+    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
+    trailing_0->c[1] = 1; /* { dg-warning "should not be used as a flexible array member for level 3" } */
+    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 3" } */
+
+}
+
+int main(int argc, char *argv[])
+{
+    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
+
+    return 0;
+}
+/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c
new file mode 100644
index 00000000000..eb82a60c261
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c
@@ -0,0 +1,50 @@
+/* Test -Wstrict-flex-arrays + -Warray-bounds=2.  */
+/* { dg-do run } */
+/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=1 -Warray-bounds=2" } */
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[4]; 
+};
+
+struct trailing_array_2 {
+    int a;
+    int b;
+    int c[1]; 
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0];
+};
+struct trailing_array_4 {
+    int a;
+    int b;
+    int c[];
+};
+
+void __attribute__((__noinline__)) stuff(
+    struct trailing_array_1 *normal,
+    struct trailing_array_2 *trailing_1,
+    struct trailing_array_3 *trailing_0,
+    struct trailing_array_4 *trailing_flex)
+{
+    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
+    			 /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
+    trailing_1->c[2] = 2; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
+    			 /*{ dg-warning "array subscript 2 is above array bounds of" "" { target *-*-* } .-1 } */
+    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
+    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
+
+}
+
+int main(int argc, char *argv[])
+{
+    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
+
+    return 0;
+}
+
+/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c
new file mode 100644
index 00000000000..f48a50e04f5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c
@@ -0,0 +1,49 @@
+/* Test -Wstrict-flex-arrays + -Warray-bounds=2.  */
+/* { dg-do run } */
+/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=2 -Warray-bounds=2" } */
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[4]; 
+};
+
+struct trailing_array_2 {
+    int a;
+    int b;
+    int c[1]; 
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0];
+};
+struct trailing_array_4 {
+    int a;
+    int b;
+    int c[];
+};
+
+void __attribute__((__noinline__)) stuff(
+    struct trailing_array_1 *normal,
+    struct trailing_array_2 *trailing_1,
+    struct trailing_array_3 *trailing_0,
+    struct trailing_array_4 *trailing_flex)
+{
+    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
+    			 /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
+    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
+    			  /*{ dg-warning "array subscript 2 is above array bounds of" "" { target *-*-* } .-1 } */
+    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
+    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
+
+}
+
+int main(int argc, char *argv[])
+{
+    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
+
+    return 0;
+}
+/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c
new file mode 100644
index 00000000000..9f2877ef4e1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c
@@ -0,0 +1,49 @@
+/* Test -Wstrict-flex-arrays + -Warray-bounds=2.  */
+/* { dg-do run } */
+/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=3 -Warray-bounds=2" } */
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[4]; 
+};
+
+struct trailing_array_2 {
+    int a;
+    int b;
+    int c[1]; 
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0];
+};
+struct trailing_array_4 {
+    int a;
+    int b;
+    int c[];
+};
+
+void __attribute__((__noinline__)) stuff(
+    struct trailing_array_1 *normal,
+    struct trailing_array_2 *trailing_1,
+    struct trailing_array_3 *trailing_0,
+    struct trailing_array_4 *trailing_flex)
+{
+    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
+   			/*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */ 
+    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
+    			/*{ dg-warning "array subscript 2 is above array bounds of" "" { target *-*-* } .-1 } */
+    trailing_0->c[1] = 1; /* { dg-warning "should not be used as a flexible array member for level 3" } */
+    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 3" } */
+
+}
+
+int main(int argc, char *argv[])
+{
+    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
+
+    return 0;
+}
+/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c
new file mode 100644
index 00000000000..43a9098f138
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c
@@ -0,0 +1,46 @@
+/* Test -Wstrict-flex-arrays.  */
+/* { dg-do run } */
+/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=1" } */
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[4]; 
+};
+
+struct trailing_array_2 {
+    int a;
+    int b;
+    int c[1]; 
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0];
+};
+struct trailing_array_4 {
+    int a;
+    int b;
+    int c[];
+};
+
+void __attribute__((__noinline__)) stuff(
+    struct trailing_array_1 *normal,
+    struct trailing_array_2 *trailing_1,
+    struct trailing_array_3 *trailing_0,
+    struct trailing_array_4 *trailing_flex)
+{
+    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
+    trailing_1->c[2] = 2; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
+    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
+    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
+
+}
+
+int main(int argc, char *argv[])
+{
+    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
+
+    return 0;
+}
diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
index e5a292bb875..1f1b56c1a52 100644
--- a/gcc/tree-vrp.cc
+++ b/gcc/tree-vrp.cc
@@ -4229,12 +4229,12 @@ execute_vrp (struct function *fun, bool warn_array_bounds_p)
      the flag on every edge now, rather than in
      check_array_bounds_dom_walker's ctor; vrp_folder may clear
      it from some edges.  */
-  if (warn_array_bounds && warn_array_bounds_p)
+  if ((warn_array_bounds || warn_strict_flex_arrays) && warn_array_bounds_p)
     set_all_edges_as_executable (fun);
 
   folder.substitute_and_fold ();
 
-  if (warn_array_bounds && warn_array_bounds_p)
+  if ((warn_array_bounds || warn_strict_flex_arrays) && warn_array_bounds_p)
     {
       array_bounds_checker array_checker (fun, &vrp_vr_values);
       array_checker.check ();
@@ -4353,7 +4353,7 @@ execute_ranger_vrp (struct function *fun, bool warn_array_bounds_p)
   if (dump_file && (dump_flags & TDF_DETAILS))
     ranger->dump (dump_file);
 
-  if (warn_array_bounds && warn_array_bounds_p)
+  if ((warn_array_bounds || warn_strict_flex_arrays) && warn_array_bounds_p)
     {
       // Set all edges as executable, except those ranger says aren't.
       int non_exec_flag = ranger->non_executable_edge_flag;
diff --git a/gcc/tree.cc b/gcc/tree.cc
index d2b0b34a725..0f5f7151b6b 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -12726,15 +12726,21 @@ array_ref_up_bound (tree exp)
    int test (uint8_t *p, uint32_t t[1][1], int n) {
    for (int i = 0; i < 4; i++, p++)
      t[i][0] = ...;
+
+   If non-null, set IS_TRAILING_ARRAY to true if the ref is the above case A.
 */
 
 bool
-array_ref_flexible_size_p (tree ref)
+array_ref_flexible_size_p (tree ref, bool *is_trailing_array /* = NULL */)
 {
-  /* the TYPE for this array referece.  */
+  /* The TYPE for this array referece.  */
   tree atype = NULL_TREE;
-  /* the FIELD_DECL for the array field in the containing structure.  */
+  /* The FIELD_DECL for the array field in the containing structure.  */
   tree afield_decl = NULL_TREE;
+  /* Whether this array is the trailing array of a structure.  */
+  bool is_trailing_array_tmp = false;
+  if (!is_trailing_array)
+    is_trailing_array = &is_trailing_array_tmp;
 
   if (TREE_CODE (ref) == ARRAY_REF
       || TREE_CODE (ref) == ARRAY_RANGE_REF)
@@ -12822,7 +12828,10 @@ array_ref_flexible_size_p (tree ref)
   if (! TYPE_SIZE (atype)
       || ! TYPE_DOMAIN (atype)
       || ! TYPE_MAX_VALUE (TYPE_DOMAIN (atype)))
-    return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
+    {
+      *is_trailing_array = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
+      return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
+    }
 
   /* If the reference is based on a declared entity, the size of the array
      is constrained by its given domain.  (Do not trust commons PR/69368).  */
@@ -12844,9 +12853,17 @@ array_ref_flexible_size_p (tree ref)
       if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (atype))) != INTEGER_CST
 	  || TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST
           || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST)
-	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
+	{
+	  *is_trailing_array
+	    = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
+	  return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
+	}
       if (! get_addr_base_and_unit_offset (ref_to_array, &offset))
-	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
+	{
+	  *is_trailing_array
+	    = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
+	  return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
+	}
 
       /* If at least one extra element fits it is a flexarray.  */
       if (known_le ((wi::to_offset (TYPE_MAX_VALUE (TYPE_DOMAIN (atype)))
@@ -12854,11 +12871,16 @@ array_ref_flexible_size_p (tree ref)
 		     + 2)
 		    * wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (atype))),
 		    wi::to_offset (DECL_SIZE_UNIT (ref)) - offset))
-	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
+	{
+	  *is_trailing_array
+	    = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
+	  return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
+	}
 
       return false;
     }
 
+  *is_trailing_array = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
   return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
 }
 
@@ -12920,24 +12942,81 @@ get_initializer_for (tree init, tree decl)
   return NULL_TREE;
 }
 
+/* Determines the special array member type for the array reference REF.  */
+special_array_member
+component_ref_sam_type (tree ref)
+{
+  special_array_member sam_type = special_array_member::none;
+
+  tree member = TREE_OPERAND (ref, 1);
+  tree memsize = DECL_SIZE_UNIT (member);
+  if (memsize)
+    {
+      tree memtype = TREE_TYPE (member);
+      if (TREE_CODE (memtype) != ARRAY_TYPE)
+	return sam_type;
+
+      bool trailing = false;
+      (void)array_ref_flexible_size_p (ref, &trailing);
+      bool zero_length = integer_zerop (memsize);
+      if (!trailing && !zero_length)
+	/* MEMBER is an interior array with
+	  more than one element.  */
+	return special_array_member::int_n;
+
+      if (zero_length)
+	{
+	  if (trailing)
+	    return special_array_member::trail_0;
+	  else
+	    return special_array_member::int_0;
+	}
+
+      if (!zero_length)
+	if (tree dom = TYPE_DOMAIN (memtype))
+	  if (tree min = TYPE_MIN_VALUE (dom))
+	    if (tree max = TYPE_MAX_VALUE (dom))
+	      if (TREE_CODE (min) == INTEGER_CST
+		  && TREE_CODE (max) == INTEGER_CST)
+		{
+		  offset_int minidx = wi::to_offset (min);
+		  offset_int maxidx = wi::to_offset (max);
+		  offset_int neltsm1 = maxidx - minidx;
+		  if (neltsm1 > 0)
+		    /* MEMBER is a trailing array with more than
+		       one elements.  */
+		    return special_array_member::trail_n;
+
+		  if (neltsm1 == 0)
+		    return special_array_member::trail_1;
+		}
+    }
+
+  return sam_type;
+}
+
 /* Determines the size of the member referenced by the COMPONENT_REF
    REF, using its initializer expression if necessary in order to
    determine the size of an initialized flexible array member.
-   If non-null, set *ARK when REF refers to an interior zero-length
+   If non-null, set *SAM when REF refers to an interior zero-length
    array or a trailing one-element array.
    Returns the size as sizetype (which might be zero for an object
    with an uninitialized flexible array member) or null if the size
-   cannot be determined.  */
+   cannot be determined.
+   when FOR_ARRAY_BOUND_CHECK is true, this routine is called for
+   -Warray-bounds check only, due to historical reason, the LEVEL
+   of -Warray-bounds=LEVEL is not controled by -fstrict-flex-arrays.  */
 
 tree
-component_ref_size (tree ref, special_array_member *sam /* = NULL */)
+component_ref_size (tree ref, special_array_member *sam /* = NULL */,
+		    bool for_array_bound_check /* = FALSE */)
 {
   gcc_assert (TREE_CODE (ref) == COMPONENT_REF);
 
   special_array_member sambuf;
   if (!sam)
     sam = &sambuf;
-  *sam = special_array_member::none;
+  *sam = component_ref_sam_type (ref);
 
   /* The object/argument referenced by the COMPONENT_REF and its type.  */
   tree arg = TREE_OPERAND (ref, 0);
@@ -12958,41 +13037,49 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */)
 	return (tree_int_cst_equal (memsize, TYPE_SIZE_UNIT (memtype))
 		? memsize : NULL_TREE);
 
-      bool trailing = array_ref_flexible_size_p (ref);
-      bool zero_length = integer_zerop (memsize);
-      if (!trailing && !zero_length)
-	/* MEMBER is either an interior array or is an array with
-	   more than one element.  */
+      /* 2-or-more elements arrays are treated as normal arrays by default.  */
+      if (*sam == special_array_member::int_n
+	  || *sam == special_array_member::trail_n)
 	return memsize;
 
-      if (zero_length)
+      /* For -Warray-bounds=LEVEL check, historically we have to treat
+	 trail_0 and trail_1 as flexible arrays by default when LEVEL=1.
+	 for other cases, flag_strict_flex_arrays will control how to treat
+	 the trailing arrays as flexiable array members.  */
+
+      tree afield_decl = TREE_OPERAND (ref, 1);
+      unsigned int strict_flex_array_level
+	= strict_flex_array_level_of (afield_decl);
+
+      if (!for_array_bound_check)
 	{
-	  if (trailing)
-	    *sam = special_array_member::trail_0;
-	  else
+	  switch (strict_flex_array_level)
 	    {
-	      *sam = special_array_member::int_0;
-	      memsize = NULL_TREE;
+	      case 3:
+		/* Treaing 0-length trailing arrays as normal array.  */
+		if (*sam == special_array_member::trail_0)
+		  return size_zero_node;
+		/* FALLTHROUGH.  */
+	      case 2:
+		/* Treating 1-element trailing arrays as normal array.  */
+		if (*sam == special_array_member::trail_1)
+		  return memsize;
+		/* FALLTHROUGH.  */
+	      case 1:
+		/* Treating 2-or-more elements trailing arrays as normal
+		   array.  */
+		if (*sam == special_array_member::trail_n)
+		  return memsize;
+		/* FALLTHROUGH.  */
+	      case 0:
+		break;
+	      default:
+		gcc_unreachable ();
 	    }
 	}
 
-      if (!zero_length)
-	if (tree dom = TYPE_DOMAIN (memtype))
-	  if (tree min = TYPE_MIN_VALUE (dom))
-	    if (tree max = TYPE_MAX_VALUE (dom))
-	      if (TREE_CODE (min) == INTEGER_CST
-		  && TREE_CODE (max) == INTEGER_CST)
-		{
-		  offset_int minidx = wi::to_offset (min);
-		  offset_int maxidx = wi::to_offset (max);
-		  offset_int neltsm1 = maxidx - minidx;
-		  if (neltsm1 > 0)
-		    /* MEMBER is an array with more than one element.  */
-		    return memsize;
-
-		  if (neltsm1 == 0)
-		    *sam = special_array_member::trail_1;
-		}
+	if (*sam == special_array_member::int_0)
+	  memsize = NULL_TREE;
 
       /* For a reference to a zero- or one-element array member of a union
 	 use the size of the union instead of the size of the member.  */
diff --git a/gcc/tree.h b/gcc/tree.h
index 0fcdd6b06d0..f81a1f6efa1 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5551,28 +5551,33 @@ extern tree array_ref_low_bound (tree);
 /* Returns true if REF is an array reference, a component reference,
    or a memory reference to an array whose actual size might be larger
    than its upper bound implies.  */
-extern bool array_ref_flexible_size_p (tree);
+extern bool array_ref_flexible_size_p (tree, bool * = NULL);
 
 /* Return a tree representing the offset, in bytes, of the field referenced
    by EXP.  This does not include any offset in DECL_FIELD_BIT_OFFSET.  */
 extern tree component_ref_field_offset (tree);
 
-/* Describes a "special" array member due to which component_ref_size
-   returns null.  */
+/* Describes a "special" array member for a COMPONENT_REF.  */
 enum struct special_array_member
   {
     none,	/* Not a special array member.  */
     int_0,	/* Interior array member with size zero.  */
     trail_0,	/* Trailing array member with size zero.  */
-    trail_1	/* Trailing array member with one element.  */
+    trail_1,	/* Trailing array member with one element.  */
+    trail_n,	/* Trailing array member with two or more elements.  */
+    int_n	/* Interior array member with one or more elements.  */
   };
 
+/* Determines the special array member type for a COMPONENT_REF.  */
+extern special_array_member component_ref_sam_type (tree);
+
 /* Return the size of the member referenced by the COMPONENT_REF, using
    its initializer expression if necessary in order to determine the size
    of an initialized flexible array member.  The size might be zero for
    an object with an uninitialized flexible array member or null if it
    cannot be determined.  */
-extern tree component_ref_size (tree, special_array_member * = NULL);
+extern tree component_ref_size (tree, special_array_member * = NULL,
+				bool = false);
 
 extern int tree_map_base_eq (const void *, const void *);
 extern unsigned int tree_map_base_hash (const void *);
-- 
2.31.1


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

* Re: [PATCH 1/2] Change the name of array_at_struct_end_p to array_ref_flexible_size_p
  2022-11-08 14:51 ` [PATCH 1/2] Change the name of array_at_struct_end_p to array_ref_flexible_size_p Qing Zhao
@ 2022-11-09  7:57   ` Richard Biener
  2022-11-09 15:50     ` Qing Zhao
  0 siblings, 1 reply; 15+ messages in thread
From: Richard Biener @ 2022-11-09  7:57 UTC (permalink / raw)
  To: Qing Zhao; +Cc: joseph, gcc-patches, keescook, siddhesh

On Tue, 8 Nov 2022, Qing Zhao wrote:

> The name of the utility routine "array_at_struct_end_p" is misleading
> and should be changed to a new name that more accurately reflects its
> real meaning.
> 
> The routine "array_at_struct_end_p" is used to check whether an array
> reference is to an array whose actual size might be larger than its
> upper bound implies, which includes 3 different 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;
>    C. a ref to an array that was passed as a parameter;
> 
> The old name only reflects the above case A, therefore very confusing
> when reading the corresponding gcc source code.
> 
> In this patch, A new name "array_ref_flexible_size_p" is used to replace
> the old name.
> 
> All the references to the routine "array_at_struct_end_p" was replaced
> with this new name, and the corresponding comments were updated to make
> them clean and consistent.

Since you seem to feel strongly about this - OK.

Thanks,
Richard.

> gcc/ChangeLog:
> 
> 	* gimple-array-bounds.cc (trailing_array): Replace
> 	array_at_struct_end_p with new name and update comments.
> 	* gimple-fold.cc (get_range_strlen_tree): Likewise.
> 	* gimple-ssa-warn-restrict.cc (builtin_memref::builtin_memref):
> 	Likewise.
> 	* graphite-sese-to-poly.cc (bounds_are_valid): Likewise.
> 	* tree-if-conv.cc (idx_within_array_bound): Likewise.
> 	* tree-object-size.cc (addr_object_size): Likewise.
> 	* tree-ssa-alias.cc (component_ref_to_zero_sized_trailing_array_p):
> 	Likewise.
> 	(stmt_kills_ref_p): Likewise.
> 	* tree-ssa-loop-niter.cc (idx_infer_loop_bounds): Likewise.
> 	* tree-ssa-strlen.cc (maybe_set_strlen_range): Likewise.
> 	* tree.cc (array_at_struct_end_p): Rename to ...
> 	(array_ref_flexible_size_p): ... this.
> 	(component_ref_size): Replace array_at_struct_end_p with new name.
> 	* tree.h (array_at_struct_end_p): Rename to ...
> 	(array_ref_flexible_size_p): ... this.
> ---
>  gcc/gimple-array-bounds.cc      |  4 ++--
>  gcc/gimple-fold.cc              |  6 ++----
>  gcc/gimple-ssa-warn-restrict.cc |  5 +++--
>  gcc/graphite-sese-to-poly.cc    |  4 ++--
>  gcc/tree-if-conv.cc             |  7 +++----
>  gcc/tree-object-size.cc         |  2 +-
>  gcc/tree-ssa-alias.cc           |  8 ++++----
>  gcc/tree-ssa-loop-niter.cc      | 15 +++++++--------
>  gcc/tree-ssa-strlen.cc          |  2 +-
>  gcc/tree.cc                     | 11 ++++++-----
>  gcc/tree.h                      |  8 ++++----
>  11 files changed, 35 insertions(+), 37 deletions(-)
> 
> diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc
> index e190b93aa85..fbf448e045d 100644
> --- a/gcc/gimple-array-bounds.cc
> +++ b/gcc/gimple-array-bounds.cc
> @@ -129,7 +129,7 @@ get_ref_size (tree arg, tree *pref)
>  }
>  
>  /* Return true if REF is (likely) an ARRAY_REF to a trailing array member
> -   of a struct.  It refines array_at_struct_end_p by detecting a pointer
> +   of a struct.  It refines array_ref_flexible_size_p by detecting a pointer
>     to an array and an array parameter declared using the [N] syntax (as
>     opposed to a pointer) and returning false.  Set *PREF to the decl or
>     expression REF refers to.  */
> @@ -167,7 +167,7 @@ trailing_array (tree arg, tree *pref)
>  	return false;
>      }
>  
> -  return array_at_struct_end_p (arg);
> +  return array_ref_flexible_size_p (arg);
>  }
>  
>  /* Checks one ARRAY_REF in REF, located at LOCUS. Ignores flexible
> diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
> index 9055cd8982d..cafd331ca98 100644
> --- a/gcc/gimple-fold.cc
> +++ b/gcc/gimple-fold.cc
> @@ -1690,13 +1690,11 @@ get_range_strlen_tree (tree arg, bitmap visited, strlen_range_kind rkind,
>  	  /* Handle a MEM_REF into a DECL accessing an array of integers,
>  	     being conservative about references to extern structures with
>  	     flexible array members that can be initialized to arbitrary
> -	     numbers of elements as an extension (static structs are okay).
> -	     FIXME: Make this less conservative -- see
> -	     component_ref_size in tree.cc.  */
> +	     numbers of elements as an extension (static structs are okay).  */
>  	  tree ref = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
>  	  if ((TREE_CODE (ref) == PARM_DECL || VAR_P (ref))
>  	      && (decl_binds_to_current_def_p (ref)
> -		  || !array_at_struct_end_p (arg)))
> +		  || !array_ref_flexible_size_p (arg)))
>  	    {
>  	      /* Fail if the offset is out of bounds.  Such accesses
>  		 should be diagnosed at some point.  */
> diff --git a/gcc/gimple-ssa-warn-restrict.cc b/gcc/gimple-ssa-warn-restrict.cc
> index b7ed15c8902..832456ba6fc 100644
> --- a/gcc/gimple-ssa-warn-restrict.cc
> +++ b/gcc/gimple-ssa-warn-restrict.cc
> @@ -296,8 +296,9 @@ builtin_memref::builtin_memref (pointer_query &ptrqry, gimple *stmt, tree expr,
>    tree basetype = TREE_TYPE (base);
>    if (TREE_CODE (basetype) == ARRAY_TYPE)
>      {
> -      if (ref && array_at_struct_end_p (ref))
> -	;   /* Use the maximum possible offset for last member arrays.  */
> +      if (ref && array_ref_flexible_size_p (ref))
> +	;   /* Use the maximum possible offset for an array that might
> +	       have flexible size.  */
>        else if (tree basesize = TYPE_SIZE_UNIT (basetype))
>  	if (TREE_CODE (basesize) == INTEGER_CST)
>  	  /* Size could be non-constant for a variable-length type such
> diff --git a/gcc/graphite-sese-to-poly.cc b/gcc/graphite-sese-to-poly.cc
> index 51ba3af204f..7eb24c1c991 100644
> --- a/gcc/graphite-sese-to-poly.cc
> +++ b/gcc/graphite-sese-to-poly.cc
> @@ -536,9 +536,9 @@ bounds_are_valid (tree ref, tree low, tree high)
>        || !tree_fits_shwi_p (high))
>      return false;
>  
> -  /* 1-element arrays at end of structures may extend over
> +  /* An array that has flexible size may extend over
>       their declared size.  */
> -  if (array_at_struct_end_p (ref)
> +  if (array_ref_flexible_size_p (ref)
>        && operand_equal_p (low, high, 0))
>      return false;
>  
> diff --git a/gcc/tree-if-conv.cc b/gcc/tree-if-conv.cc
> index a83b013d2ad..34bb507ff3b 100644
> --- a/gcc/tree-if-conv.cc
> +++ b/gcc/tree-if-conv.cc
> @@ -763,10 +763,9 @@ idx_within_array_bound (tree ref, tree *idx, void *dta)
>    if (TREE_CODE (ref) != ARRAY_REF)
>      return false;
>  
> -  /* For arrays at the end of the structure, we are not guaranteed that they
> -     do not really extend over their declared size.  However, for arrays of
> -     size greater than one, this is unlikely to be intended.  */
> -  if (array_at_struct_end_p (ref))
> +  /* For arrays that might have flexible sizes, it is not guaranteed that they
> +     do not extend over their declared size.  */
> +  if (array_ref_flexible_size_p (ref))
>      return false;
>  
>    ev = analyze_scalar_evolution (loop, *idx);
> diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
> index 1f04cb80fd0..2e5d267d8ce 100644
> --- a/gcc/tree-object-size.cc
> +++ b/gcc/tree-object-size.cc
> @@ -633,7 +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);
> +		    is_flexible_array_mem_ref = array_ref_flexible_size_p (v);
>  		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>  		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>  			  != UNION_TYPE
> diff --git a/gcc/tree-ssa-alias.cc b/gcc/tree-ssa-alias.cc
> index b4c65da5718..d3a91b1f238 100644
> --- a/gcc/tree-ssa-alias.cc
> +++ b/gcc/tree-ssa-alias.cc
> @@ -1073,7 +1073,7 @@ component_ref_to_zero_sized_trailing_array_p (tree ref)
>  	  && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 1))) == ARRAY_TYPE
>  	  && (!TYPE_SIZE (TREE_TYPE (TREE_OPERAND (ref, 1)))
>  	      || integer_zerop (TYPE_SIZE (TREE_TYPE (TREE_OPERAND (ref, 1)))))
> -	  && array_at_struct_end_p (ref));
> +	  && array_ref_flexible_size_p (ref));
>  }
>  
>  /* Worker for aliasing_component_refs_p. Most parameters match parameters of
> @@ -3433,10 +3433,10 @@ stmt_kills_ref_p (gimple *stmt, ao_ref *ref)
>  	    }
>  	  /* Finally check if the lhs has the same address and size as the
>  	     base candidate of the access.  Watch out if we have dropped
> -	     an array-ref that was at struct end, this means ref->ref may
> -	     be outside of the TYPE_SIZE of its base.  */
> +	     an array-ref that might have flexible size, this means ref->ref
> +	     may be outside of the TYPE_SIZE of its base.  */
>  	  if ((! innermost_dropped_array_ref
> -	       || ! array_at_struct_end_p (innermost_dropped_array_ref))
> +	       || ! array_ref_flexible_size_p (innermost_dropped_array_ref))
>  	      && (lhs == base
>  		  || (((TYPE_SIZE (TREE_TYPE (lhs))
>  			== TYPE_SIZE (TREE_TYPE (base)))
> diff --git a/gcc/tree-ssa-loop-niter.cc b/gcc/tree-ssa-loop-niter.cc
> index 4ffcef4f4ff..3fbbf4367ed 100644
> --- a/gcc/tree-ssa-loop-niter.cc
> +++ b/gcc/tree-ssa-loop-niter.cc
> @@ -3716,18 +3716,17 @@ idx_infer_loop_bounds (tree base, tree *idx, void *dta)
>    struct ilb_data *data = (struct ilb_data *) dta;
>    tree ev, init, step;
>    tree low, high, type, next;
> -  bool sign, upper = true, at_end = false;
> +  bool sign, upper = true, has_flexible_size = false;
>    class loop *loop = data->loop;
>  
>    if (TREE_CODE (base) != ARRAY_REF)
>      return true;
>  
> -  /* For arrays at the end of the structure, we are not guaranteed that they
> -     do not really extend over their declared size.  However, for arrays of
> -     size greater than one, this is unlikely to be intended.  */
> -  if (array_at_struct_end_p (base))
> +  /* For arrays that might have flexible sizes, it is not guaranteed that they
> +     do not really extend over their declared size.  */ 
> +  if (array_ref_flexible_size_p (base))
>      {
> -      at_end = true;
> +      has_flexible_size = true;
>        upper = false;
>      }
>  
> @@ -3760,9 +3759,9 @@ idx_infer_loop_bounds (tree base, tree *idx, void *dta)
>    sign = tree_int_cst_sign_bit (step);
>    type = TREE_TYPE (step);
>  
> -  /* The array of length 1 at the end of a structure most likely extends
> +  /* The array that might have flexible size most likely extends
>       beyond its bounds.  */
> -  if (at_end
> +  if (has_flexible_size
>        && operand_equal_p (low, high, 0))
>      return true;
>  
> diff --git a/gcc/tree-ssa-strlen.cc b/gcc/tree-ssa-strlen.cc
> index 5afbae1b72e..b87c7c7ce1f 100644
> --- a/gcc/tree-ssa-strlen.cc
> +++ b/gcc/tree-ssa-strlen.cc
> @@ -1987,7 +1987,7 @@ maybe_set_strlen_range (tree lhs, tree src, tree bound)
>  	 suggests if it's treated as a poor-man's flexible array member.  */
>        src = TREE_OPERAND (src, 0);
>        if (TREE_CODE (src) != MEM_REF
> -	  && !array_at_struct_end_p (src))
> +	  && !array_ref_flexible_size_p (src))
>  	{
>  	  tree type = TREE_TYPE (src);
>  	  tree size = TYPE_SIZE_UNIT (type);
> diff --git a/gcc/tree.cc b/gcc/tree.cc
> index 04603c8c902..d2b0b34a725 100644
> --- a/gcc/tree.cc
> +++ b/gcc/tree.cc
> @@ -12710,8 +12710,8 @@ array_ref_up_bound (tree exp)
>    return NULL_TREE;
>  }
>  
> -/* Returns true if REF is an array reference, component reference,
> -   or memory reference to an array whose actual size might be larger
> +/* Returns true if REF is an array reference, a component reference,
> +   or a memory reference to an array whose actual size might be larger
>     than its upper bound implies, 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;
> @@ -12726,10 +12726,10 @@ array_ref_up_bound (tree exp)
>     int test (uint8_t *p, uint32_t t[1][1], int n) {
>     for (int i = 0; i < 4; i++, p++)
>       t[i][0] = ...;
> +*/
>  
> -   FIXME, the name of this routine need to be changed to be more accurate.  */
>  bool
> -array_at_struct_end_p (tree ref)
> +array_ref_flexible_size_p (tree ref)
>  {
>    /* the TYPE for this array referece.  */
>    tree atype = NULL_TREE;
> @@ -12862,6 +12862,7 @@ array_at_struct_end_p (tree ref)
>    return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>  }
>  
> +
>  /* Return a tree representing the offset, in bytes, of the field referenced
>     by EXP.  This does not include any offset in DECL_FIELD_BIT_OFFSET.  */
>  
> @@ -12957,7 +12958,7 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */)
>  	return (tree_int_cst_equal (memsize, TYPE_SIZE_UNIT (memtype))
>  		? memsize : NULL_TREE);
>  
> -      bool trailing = array_at_struct_end_p (ref);
> +      bool trailing = array_ref_flexible_size_p (ref);
>        bool zero_length = integer_zerop (memsize);
>        if (!trailing && !zero_length)
>  	/* MEMBER is either an interior array or is an array with
> diff --git a/gcc/tree.h b/gcc/tree.h
> index a50f7b2be9d..0fcdd6b06d0 100644
> --- a/gcc/tree.h
> +++ b/gcc/tree.h
> @@ -5548,10 +5548,10 @@ extern tree array_ref_up_bound (tree);
>     EXP, an ARRAY_REF or an ARRAY_RANGE_REF.  */
>  extern tree array_ref_low_bound (tree);
>  
> -/* Returns true if REF is an array reference or a component 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.  */
> -extern bool array_at_struct_end_p (tree);
> +/* Returns true if REF is an array reference, a component reference,
> +   or a memory reference to an array whose actual size might be larger
> +   than its upper bound implies.  */
> +extern bool array_ref_flexible_size_p (tree);
>  
>  /* Return a tree representing the offset, in bytes, of the field referenced
>     by EXP.  This does not include any offset in DECL_FIELD_BIT_OFFSET.  */
> 

-- 
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] 15+ messages in thread

* Re: [PATCH 1/2] Change the name of array_at_struct_end_p to array_ref_flexible_size_p
  2022-11-09  7:57   ` Richard Biener
@ 2022-11-09 15:50     ` Qing Zhao
  0 siblings, 0 replies; 15+ messages in thread
From: Qing Zhao @ 2022-11-09 15:50 UTC (permalink / raw)
  To: Richard Biener; +Cc: joseph, gcc Patches, Kees Cook, siddhesh

Thanks.

Committed as:  https://gcc.gnu.org/pipermail/gcc-cvs/2022-November/373830.html

Qing
> On Nov 9, 2022, at 2:57 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Tue, 8 Nov 2022, Qing Zhao wrote:
> 
>> The name of the utility routine "array_at_struct_end_p" is misleading
>> and should be changed to a new name that more accurately reflects its
>> real meaning.
>> 
>> The routine "array_at_struct_end_p" is used to check whether an array
>> reference is to an array whose actual size might be larger than its
>> upper bound implies, which includes 3 different 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;
>>   C. a ref to an array that was passed as a parameter;
>> 
>> The old name only reflects the above case A, therefore very confusing
>> when reading the corresponding gcc source code.
>> 
>> In this patch, A new name "array_ref_flexible_size_p" is used to replace
>> the old name.
>> 
>> All the references to the routine "array_at_struct_end_p" was replaced
>> with this new name, and the corresponding comments were updated to make
>> them clean and consistent.
> 
> Since you seem to feel strongly about this - OK.
> 
> Thanks,
> Richard.
> 
>> gcc/ChangeLog:
>> 
>> 	* gimple-array-bounds.cc (trailing_array): Replace
>> 	array_at_struct_end_p with new name and update comments.
>> 	* gimple-fold.cc (get_range_strlen_tree): Likewise.
>> 	* gimple-ssa-warn-restrict.cc (builtin_memref::builtin_memref):
>> 	Likewise.
>> 	* graphite-sese-to-poly.cc (bounds_are_valid): Likewise.
>> 	* tree-if-conv.cc (idx_within_array_bound): Likewise.
>> 	* tree-object-size.cc (addr_object_size): Likewise.
>> 	* tree-ssa-alias.cc (component_ref_to_zero_sized_trailing_array_p):
>> 	Likewise.
>> 	(stmt_kills_ref_p): Likewise.
>> 	* tree-ssa-loop-niter.cc (idx_infer_loop_bounds): Likewise.
>> 	* tree-ssa-strlen.cc (maybe_set_strlen_range): Likewise.
>> 	* tree.cc (array_at_struct_end_p): Rename to ...
>> 	(array_ref_flexible_size_p): ... this.
>> 	(component_ref_size): Replace array_at_struct_end_p with new name.
>> 	* tree.h (array_at_struct_end_p): Rename to ...
>> 	(array_ref_flexible_size_p): ... this.
>> ---
>> gcc/gimple-array-bounds.cc      |  4 ++--
>> gcc/gimple-fold.cc              |  6 ++----
>> gcc/gimple-ssa-warn-restrict.cc |  5 +++--
>> gcc/graphite-sese-to-poly.cc    |  4 ++--
>> gcc/tree-if-conv.cc             |  7 +++----
>> gcc/tree-object-size.cc         |  2 +-
>> gcc/tree-ssa-alias.cc           |  8 ++++----
>> gcc/tree-ssa-loop-niter.cc      | 15 +++++++--------
>> gcc/tree-ssa-strlen.cc          |  2 +-
>> gcc/tree.cc                     | 11 ++++++-----
>> gcc/tree.h                      |  8 ++++----
>> 11 files changed, 35 insertions(+), 37 deletions(-)
>> 
>> diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc
>> index e190b93aa85..fbf448e045d 100644
>> --- a/gcc/gimple-array-bounds.cc
>> +++ b/gcc/gimple-array-bounds.cc
>> @@ -129,7 +129,7 @@ get_ref_size (tree arg, tree *pref)
>> }
>> 
>> /* Return true if REF is (likely) an ARRAY_REF to a trailing array member
>> -   of a struct.  It refines array_at_struct_end_p by detecting a pointer
>> +   of a struct.  It refines array_ref_flexible_size_p by detecting a pointer
>>    to an array and an array parameter declared using the [N] syntax (as
>>    opposed to a pointer) and returning false.  Set *PREF to the decl or
>>    expression REF refers to.  */
>> @@ -167,7 +167,7 @@ trailing_array (tree arg, tree *pref)
>> 	return false;
>>     }
>> 
>> -  return array_at_struct_end_p (arg);
>> +  return array_ref_flexible_size_p (arg);
>> }
>> 
>> /* Checks one ARRAY_REF in REF, located at LOCUS. Ignores flexible
>> diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
>> index 9055cd8982d..cafd331ca98 100644
>> --- a/gcc/gimple-fold.cc
>> +++ b/gcc/gimple-fold.cc
>> @@ -1690,13 +1690,11 @@ get_range_strlen_tree (tree arg, bitmap visited, strlen_range_kind rkind,
>> 	  /* Handle a MEM_REF into a DECL accessing an array of integers,
>> 	     being conservative about references to extern structures with
>> 	     flexible array members that can be initialized to arbitrary
>> -	     numbers of elements as an extension (static structs are okay).
>> -	     FIXME: Make this less conservative -- see
>> -	     component_ref_size in tree.cc.  */
>> +	     numbers of elements as an extension (static structs are okay).  */
>> 	  tree ref = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
>> 	  if ((TREE_CODE (ref) == PARM_DECL || VAR_P (ref))
>> 	      && (decl_binds_to_current_def_p (ref)
>> -		  || !array_at_struct_end_p (arg)))
>> +		  || !array_ref_flexible_size_p (arg)))
>> 	    {
>> 	      /* Fail if the offset is out of bounds.  Such accesses
>> 		 should be diagnosed at some point.  */
>> diff --git a/gcc/gimple-ssa-warn-restrict.cc b/gcc/gimple-ssa-warn-restrict.cc
>> index b7ed15c8902..832456ba6fc 100644
>> --- a/gcc/gimple-ssa-warn-restrict.cc
>> +++ b/gcc/gimple-ssa-warn-restrict.cc
>> @@ -296,8 +296,9 @@ builtin_memref::builtin_memref (pointer_query &ptrqry, gimple *stmt, tree expr,
>>   tree basetype = TREE_TYPE (base);
>>   if (TREE_CODE (basetype) == ARRAY_TYPE)
>>     {
>> -      if (ref && array_at_struct_end_p (ref))
>> -	;   /* Use the maximum possible offset for last member arrays.  */
>> +      if (ref && array_ref_flexible_size_p (ref))
>> +	;   /* Use the maximum possible offset for an array that might
>> +	       have flexible size.  */
>>       else if (tree basesize = TYPE_SIZE_UNIT (basetype))
>> 	if (TREE_CODE (basesize) == INTEGER_CST)
>> 	  /* Size could be non-constant for a variable-length type such
>> diff --git a/gcc/graphite-sese-to-poly.cc b/gcc/graphite-sese-to-poly.cc
>> index 51ba3af204f..7eb24c1c991 100644
>> --- a/gcc/graphite-sese-to-poly.cc
>> +++ b/gcc/graphite-sese-to-poly.cc
>> @@ -536,9 +536,9 @@ bounds_are_valid (tree ref, tree low, tree high)
>>       || !tree_fits_shwi_p (high))
>>     return false;
>> 
>> -  /* 1-element arrays at end of structures may extend over
>> +  /* An array that has flexible size may extend over
>>      their declared size.  */
>> -  if (array_at_struct_end_p (ref)
>> +  if (array_ref_flexible_size_p (ref)
>>       && operand_equal_p (low, high, 0))
>>     return false;
>> 
>> diff --git a/gcc/tree-if-conv.cc b/gcc/tree-if-conv.cc
>> index a83b013d2ad..34bb507ff3b 100644
>> --- a/gcc/tree-if-conv.cc
>> +++ b/gcc/tree-if-conv.cc
>> @@ -763,10 +763,9 @@ idx_within_array_bound (tree ref, tree *idx, void *dta)
>>   if (TREE_CODE (ref) != ARRAY_REF)
>>     return false;
>> 
>> -  /* For arrays at the end of the structure, we are not guaranteed that they
>> -     do not really extend over their declared size.  However, for arrays of
>> -     size greater than one, this is unlikely to be intended.  */
>> -  if (array_at_struct_end_p (ref))
>> +  /* For arrays that might have flexible sizes, it is not guaranteed that they
>> +     do not extend over their declared size.  */
>> +  if (array_ref_flexible_size_p (ref))
>>     return false;
>> 
>>   ev = analyze_scalar_evolution (loop, *idx);
>> diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
>> index 1f04cb80fd0..2e5d267d8ce 100644
>> --- a/gcc/tree-object-size.cc
>> +++ b/gcc/tree-object-size.cc
>> @@ -633,7 +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);
>> +		    is_flexible_array_mem_ref = array_ref_flexible_size_p (v);
>> 		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>> 		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>> 			  != UNION_TYPE
>> diff --git a/gcc/tree-ssa-alias.cc b/gcc/tree-ssa-alias.cc
>> index b4c65da5718..d3a91b1f238 100644
>> --- a/gcc/tree-ssa-alias.cc
>> +++ b/gcc/tree-ssa-alias.cc
>> @@ -1073,7 +1073,7 @@ component_ref_to_zero_sized_trailing_array_p (tree ref)
>> 	  && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 1))) == ARRAY_TYPE
>> 	  && (!TYPE_SIZE (TREE_TYPE (TREE_OPERAND (ref, 1)))
>> 	      || integer_zerop (TYPE_SIZE (TREE_TYPE (TREE_OPERAND (ref, 1)))))
>> -	  && array_at_struct_end_p (ref));
>> +	  && array_ref_flexible_size_p (ref));
>> }
>> 
>> /* Worker for aliasing_component_refs_p. Most parameters match parameters of
>> @@ -3433,10 +3433,10 @@ stmt_kills_ref_p (gimple *stmt, ao_ref *ref)
>> 	    }
>> 	  /* Finally check if the lhs has the same address and size as the
>> 	     base candidate of the access.  Watch out if we have dropped
>> -	     an array-ref that was at struct end, this means ref->ref may
>> -	     be outside of the TYPE_SIZE of its base.  */
>> +	     an array-ref that might have flexible size, this means ref->ref
>> +	     may be outside of the TYPE_SIZE of its base.  */
>> 	  if ((! innermost_dropped_array_ref
>> -	       || ! array_at_struct_end_p (innermost_dropped_array_ref))
>> +	       || ! array_ref_flexible_size_p (innermost_dropped_array_ref))
>> 	      && (lhs == base
>> 		  || (((TYPE_SIZE (TREE_TYPE (lhs))
>> 			== TYPE_SIZE (TREE_TYPE (base)))
>> diff --git a/gcc/tree-ssa-loop-niter.cc b/gcc/tree-ssa-loop-niter.cc
>> index 4ffcef4f4ff..3fbbf4367ed 100644
>> --- a/gcc/tree-ssa-loop-niter.cc
>> +++ b/gcc/tree-ssa-loop-niter.cc
>> @@ -3716,18 +3716,17 @@ idx_infer_loop_bounds (tree base, tree *idx, void *dta)
>>   struct ilb_data *data = (struct ilb_data *) dta;
>>   tree ev, init, step;
>>   tree low, high, type, next;
>> -  bool sign, upper = true, at_end = false;
>> +  bool sign, upper = true, has_flexible_size = false;
>>   class loop *loop = data->loop;
>> 
>>   if (TREE_CODE (base) != ARRAY_REF)
>>     return true;
>> 
>> -  /* For arrays at the end of the structure, we are not guaranteed that they
>> -     do not really extend over their declared size.  However, for arrays of
>> -     size greater than one, this is unlikely to be intended.  */
>> -  if (array_at_struct_end_p (base))
>> +  /* For arrays that might have flexible sizes, it is not guaranteed that they
>> +     do not really extend over their declared size.  */ 
>> +  if (array_ref_flexible_size_p (base))
>>     {
>> -      at_end = true;
>> +      has_flexible_size = true;
>>       upper = false;
>>     }
>> 
>> @@ -3760,9 +3759,9 @@ idx_infer_loop_bounds (tree base, tree *idx, void *dta)
>>   sign = tree_int_cst_sign_bit (step);
>>   type = TREE_TYPE (step);
>> 
>> -  /* The array of length 1 at the end of a structure most likely extends
>> +  /* The array that might have flexible size most likely extends
>>      beyond its bounds.  */
>> -  if (at_end
>> +  if (has_flexible_size
>>       && operand_equal_p (low, high, 0))
>>     return true;
>> 
>> diff --git a/gcc/tree-ssa-strlen.cc b/gcc/tree-ssa-strlen.cc
>> index 5afbae1b72e..b87c7c7ce1f 100644
>> --- a/gcc/tree-ssa-strlen.cc
>> +++ b/gcc/tree-ssa-strlen.cc
>> @@ -1987,7 +1987,7 @@ maybe_set_strlen_range (tree lhs, tree src, tree bound)
>> 	 suggests if it's treated as a poor-man's flexible array member.  */
>>       src = TREE_OPERAND (src, 0);
>>       if (TREE_CODE (src) != MEM_REF
>> -	  && !array_at_struct_end_p (src))
>> +	  && !array_ref_flexible_size_p (src))
>> 	{
>> 	  tree type = TREE_TYPE (src);
>> 	  tree size = TYPE_SIZE_UNIT (type);
>> diff --git a/gcc/tree.cc b/gcc/tree.cc
>> index 04603c8c902..d2b0b34a725 100644
>> --- a/gcc/tree.cc
>> +++ b/gcc/tree.cc
>> @@ -12710,8 +12710,8 @@ array_ref_up_bound (tree exp)
>>   return NULL_TREE;
>> }
>> 
>> -/* Returns true if REF is an array reference, component reference,
>> -   or memory reference to an array whose actual size might be larger
>> +/* Returns true if REF is an array reference, a component reference,
>> +   or a memory reference to an array whose actual size might be larger
>>    than its upper bound implies, 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;
>> @@ -12726,10 +12726,10 @@ array_ref_up_bound (tree exp)
>>    int test (uint8_t *p, uint32_t t[1][1], int n) {
>>    for (int i = 0; i < 4; i++, p++)
>>      t[i][0] = ...;
>> +*/
>> 
>> -   FIXME, the name of this routine need to be changed to be more accurate.  */
>> bool
>> -array_at_struct_end_p (tree ref)
>> +array_ref_flexible_size_p (tree ref)
>> {
>>   /* the TYPE for this array referece.  */
>>   tree atype = NULL_TREE;
>> @@ -12862,6 +12862,7 @@ array_at_struct_end_p (tree ref)
>>   return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>> }
>> 
>> +
>> /* Return a tree representing the offset, in bytes, of the field referenced
>>    by EXP.  This does not include any offset in DECL_FIELD_BIT_OFFSET.  */
>> 
>> @@ -12957,7 +12958,7 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */)
>> 	return (tree_int_cst_equal (memsize, TYPE_SIZE_UNIT (memtype))
>> 		? memsize : NULL_TREE);
>> 
>> -      bool trailing = array_at_struct_end_p (ref);
>> +      bool trailing = array_ref_flexible_size_p (ref);
>>       bool zero_length = integer_zerop (memsize);
>>       if (!trailing && !zero_length)
>> 	/* MEMBER is either an interior array or is an array with
>> diff --git a/gcc/tree.h b/gcc/tree.h
>> index a50f7b2be9d..0fcdd6b06d0 100644
>> --- a/gcc/tree.h
>> +++ b/gcc/tree.h
>> @@ -5548,10 +5548,10 @@ extern tree array_ref_up_bound (tree);
>>    EXP, an ARRAY_REF or an ARRAY_RANGE_REF.  */
>> extern tree array_ref_low_bound (tree);
>> 
>> -/* Returns true if REF is an array reference or a component 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.  */
>> -extern bool array_at_struct_end_p (tree);
>> +/* Returns true if REF is an array reference, a component reference,
>> +   or a memory reference to an array whose actual size might be larger
>> +   than its upper bound implies.  */
>> +extern bool array_ref_flexible_size_p (tree);
>> 
>> /* Return a tree representing the offset, in bytes, of the field referenced
>>    by EXP.  This does not include any offset in DECL_FIELD_BIT_OFFSET.  */
>> 
> 
> -- 
> 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] 15+ messages in thread

* Re: [PATCH 2/2] Add a new warning option -Wstrict-flex-arrays.
  2022-11-08 14:51 ` [PATCH 2/2] Add a new warning option -Wstrict-flex-arrays Qing Zhao
@ 2022-11-15 15:41   ` Qing Zhao
  2022-11-18 13:14   ` Richard Biener
  1 sibling, 0 replies; 15+ messages in thread
From: Qing Zhao @ 2022-11-15 15:41 UTC (permalink / raw)
  To: Richard Biener, joseph; +Cc: gcc Patches, Kees Cook, siddhesh

Ping on this patch.

thanks.

Qing

> On Nov 8, 2022, at 9:51 AM, Qing Zhao <qing.zhao@oracle.com> wrote:
> 
> '-Wstrict-flex-arrays'
>     Warn about inproper usages of flexible array members according to
>     the LEVEL of the 'strict_flex_array (LEVEL)' attribute attached to
>     the trailing array field of a structure if it's available,
>     otherwise according to the LEVEL of the option
>     '-fstrict-flex-arrays=LEVEL'.
> 
>     This option is effective only when LEVEL is bigger than 0.
>     Otherwise, it will be ignored with a warning.
> 
>     when LEVEL=1, warnings will be issued for a trailing array
>     reference of a structure that have 2 or more elements if the
>     trailing array is referenced as a flexible array member.
> 
>     when LEVEL=2, in addition to LEVEL=1, additional warnings will be
>     issued for a trailing one-element array reference of a structure if
>     the array is referenced as a flexible array member.
> 
>     when LEVEL=3, in addition to LEVEL=2, additional warnings will be
>     issued for a trailing zero-length array reference of a structure if
>     the array is referenced as a flexible array member.
> 
> At the same time, keep -Warray-bounds=[1|2] warnings unchanged from
> -fstrict-flex-arrays.
> 
> gcc/ChangeLog:
> 
> 	* attribs.cc (strict_flex_array_level_of): New function.
> 	* attribs.h (strict_flex_array_level_of): Prototype for new function.
> 	* doc/invoke.texi: Document -Wstrict-flex-arrays option. Update
> 	-fstrict-flex-arrays[=n] options.
> 	* gimple-array-bounds.cc (array_bounds_checker::check_array_ref):
> 	Issue warnings for -Wstrict-flex-arrays.
> 	(get_up_bounds_for_array_ref): New function.
> 	(check_out_of_bounds_and_warn): New function.
> 	* opts.cc (finish_options): Issue warnings for unsupported combination
> 	of -Warray-bounds and -fstrict-flex-arrays, -Wstrict_flex_arrays and
> 	-fstrict-flex-array.
> 	* tree-vrp.cc (execute_vrp): Enable the pass when
> 	warn_strict_flex_array is true.
> 	(execute_ranger_vrp): Likewise.
> 	* tree.cc (array_ref_flexible_size_p): Add one new argument.
> 	(component_ref_sam_type): New function.
> 	(component_ref_size): Add one new argument,
> 	* tree.h (array_ref_flexible_size_p): Update prototype.
> 	(enum struct special_array_member): Add two new enum values.
> 	(component_ref_sam_type): New prototype.
> 	(component_ref_size): Update prototype.
> 
> gcc/c-family/ChangeLog:
> 
> 	* c.opt (Wstrict-flex-arrays): New option.
> 
> gcc/c/ChangeLog:
> 
> 	* c-decl.cc (is_flexible_array_member_p): Call new function
> 	strict_flex_array_level_of.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* c-c++-common/Wstrict-flex-arrays.c: New test.
> 	* c-c++-common/Wstrict-flex-arrays_2.c: New test.
> 	* gcc.dg/Wstrict-flex-arrays-2.c: New test.
> 	* gcc.dg/Wstrict-flex-arrays-3.c: New test.
> 	* gcc.dg/Wstrict-flex-arrays-4.c: New test.
> 	* gcc.dg/Wstrict-flex-arrays-5.c: New test.
> 	* gcc.dg/Wstrict-flex-arrays-6.c: New test.
> 	* gcc.dg/Wstrict-flex-arrays-7.c: New test.
> 	* gcc.dg/Wstrict-flex-arrays-8.c: New test.
> 	* gcc.dg/Wstrict-flex-arrays-9.c: New test.
> 	* gcc.dg/Wstrict-flex-arrays.c: New test.
> ---
> gcc/attribs.cc                                |  30 ++
> gcc/attribs.h                                 |   2 +
> gcc/c-family/c.opt                            |   5 +
> gcc/c/c-decl.cc                               |  22 +-
> gcc/doc/invoke.texi                           |  33 ++-
> gcc/gimple-array-bounds.cc                    | 264 +++++++++++++-----
> gcc/opts.cc                                   |  15 +
> .../c-c++-common/Wstrict-flex-arrays.c        |   9 +
> .../c-c++-common/Wstrict-flex-arrays_2.c      |   9 +
> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c  |  46 +++
> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c  |  46 +++
> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c  |  49 ++++
> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c  |  48 ++++
> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c  |  48 ++++
> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c  |  50 ++++
> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c  |  49 ++++
> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c  |  49 ++++
> gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c    |  46 +++
> gcc/tree-vrp.cc                               |   6 +-
> gcc/tree.cc                                   | 165 ++++++++---
> gcc/tree.h                                    |  15 +-
> 21 files changed, 870 insertions(+), 136 deletions(-)
> create mode 100644 gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c
> create mode 100644 gcc/testsuite/c-c++-common/Wstrict-flex-arrays_2.c
> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c
> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c
> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c
> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c
> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c
> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c
> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c
> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c
> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c
> 
> diff --git a/gcc/attribs.cc b/gcc/attribs.cc
> index 27dea748561..095def4d6b0 100644
> --- a/gcc/attribs.cc
> +++ b/gcc/attribs.cc
> @@ -2456,6 +2456,36 @@ init_attr_rdwr_indices (rdwr_map *rwm, tree attrs)
>     }
> }
> 
> +/* Get the LEVEL of the strict_flex_array for the ARRAY_FIELD based on the
> +   values of attribute strict_flex_array and the flag_strict_flex_arrays.  */
> +unsigned int
> +strict_flex_array_level_of (tree array_field)
> +{
> +  gcc_assert (TREE_CODE (array_field) == FIELD_DECL);
> +  unsigned int strict_flex_array_level = flag_strict_flex_arrays;
> +
> +  tree attr_strict_flex_array
> +    = lookup_attribute ("strict_flex_array", DECL_ATTRIBUTES (array_field));
> +  /* If there is a strict_flex_array attribute attached to the field,
> +     override the flag_strict_flex_arrays.  */
> +  if (attr_strict_flex_array)
> +    {
> +      /* Get the value of the level first from the attribute.  */
> +      unsigned HOST_WIDE_INT attr_strict_flex_array_level = 0;
> +      gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
> +      attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
> +      gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
> +      attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
> +      gcc_assert (tree_fits_uhwi_p (attr_strict_flex_array));
> +      attr_strict_flex_array_level = tree_to_uhwi (attr_strict_flex_array);
> +
> +      /* The attribute has higher priority than flag_struct_flex_array.  */
> +      strict_flex_array_level = attr_strict_flex_array_level;
> +    }
> +  return strict_flex_array_level;
> +}
> +
> +
> /* Return the access specification for a function parameter PARM
>    or null if the current function has no such specification.  */
> 
> diff --git a/gcc/attribs.h b/gcc/attribs.h
> index 1dc16e4bc4e..742811e6fda 100644
> --- a/gcc/attribs.h
> +++ b/gcc/attribs.h
> @@ -398,4 +398,6 @@ extern void init_attr_rdwr_indices (rdwr_map *, tree);
> extern attr_access *get_parm_access (rdwr_map &, tree,
> 				     tree = current_function_decl);
> 
> +extern unsigned int strict_flex_array_level_of (tree);
> +
> #endif // GCC_ATTRIBS_H
> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
> index 01d480759ae..bc33710a649 100644
> --- a/gcc/c-family/c.opt
> +++ b/gcc/c-family/c.opt
> @@ -968,6 +968,11 @@ Wstringop-truncation
> C ObjC C++ LTO ObjC++ Var(warn_stringop_truncation) Warning Init (1) LangEnabledBy(C ObjC C++ LTO ObjC++, Wall)
> Warn about truncation in string manipulation functions like strncat and strncpy.
> 
> +Wstrict-flex-arrays
> +C C++ Var(warn_strict_flex_arrays) Warning
> +Warn about inproper usages of flexible array members
> +according to the level of -fstrict-flex-arrays.
> +
> Wsuggest-attribute=format
> C ObjC C++ ObjC++ Var(warn_suggest_attribute_format) Warning
> Warn about functions which might be candidates for format attributes.
> diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
> index 4746e310d2d..c9cb46daacc 100644
> --- a/gcc/c/c-decl.cc
> +++ b/gcc/c/c-decl.cc
> @@ -8828,7 +8828,6 @@ finish_incomplete_vars (tree incomplete_vars, bool toplevel)
>     }
> }
> 
> -
> /* Determine whether the FIELD_DECL X is a flexible array member according to
>    the following info:
>   A. whether the FIELD_DECL X is the last field of the DECL_CONTEXT;
> @@ -8855,26 +8854,7 @@ is_flexible_array_member_p (bool is_last_field,
>   bool is_one_element_array = one_element_array_type_p (TREE_TYPE (x));
>   bool is_flexible_array = flexible_array_member_type_p (TREE_TYPE (x));
> 
> -  unsigned int strict_flex_array_level = flag_strict_flex_arrays;
> -
> -  tree attr_strict_flex_array = lookup_attribute ("strict_flex_array",
> -						  DECL_ATTRIBUTES (x));
> -  /* If there is a strict_flex_array attribute attached to the field,
> -     override the flag_strict_flex_arrays.  */
> -  if (attr_strict_flex_array)
> -    {
> -      /* Get the value of the level first from the attribute.  */
> -      unsigned HOST_WIDE_INT attr_strict_flex_array_level = 0;
> -      gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
> -      attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
> -      gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
> -      attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
> -      gcc_assert (tree_fits_uhwi_p (attr_strict_flex_array));
> -      attr_strict_flex_array_level = tree_to_uhwi (attr_strict_flex_array);
> -
> -      /* The attribute has higher priority than flag_struct_flex_array.  */
> -      strict_flex_array_level = attr_strict_flex_array_level;
> -    }
> +  unsigned int strict_flex_array_level = strict_flex_array_level_of (x);
> 
>   switch (strict_flex_array_level)
>     {
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 64f77e8367a..a35e6bf27e0 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -397,7 +397,7 @@ Objective-C and Objective-C++ Dialects}.
> -Wstrict-aliasing=n  -Wstrict-overflow  -Wstrict-overflow=@var{n} @gol
> -Wstring-compare @gol
> -Wno-stringop-overflow -Wno-stringop-overread @gol
> --Wno-stringop-truncation @gol
> +-Wno-stringop-truncation -Wstrict-flex-arrays @gol
> -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{|}malloc@r{]} @gol
> -Wswitch  -Wno-switch-bool  -Wswitch-default  -Wswitch-enum @gol
> -Wno-switch-outside-range  -Wno-switch-unreachable  -Wsync-nand @gol
> @@ -2848,12 +2848,18 @@ The negative form is equivalent to @option{-fstrict-flex-arrays=0}, which is the
> least strict.  All trailing arrays of structures are treated as flexible array
> members.
> 
> +This option is not compatible with @option{-Warray-bounds} due to historical
> +reason.  The behavior of @option{-Warray-bounds} is not changed by this option.
> +
> @item -fstrict-flex-arrays=@var{level}
> @opindex fstrict-flex-arrays=@var{level}
> Control when to treat the trailing array of a structure as a flexible array
> member for the purpose of accessing the elements of such an array.  The value
> of @var{level} controls the level of strictness.
> 
> +This option is not compatible with @option{-Warray-bounds} due to historical
> +reason.  The behavior of @option{-Warray-bounds} is not changed by this option.
> +
> The possible values of @var{level} are the same as for the
> @code{strict_flex_array} attribute (@pxref{Variable Attributes}).
> 
> @@ -7662,6 +7668,31 @@ however, are not suitable arguments to functions that expect
> such arrays GCC issues warnings unless it can prove that the use is
> safe.  @xref{Common Variable Attributes}.
> 
> +@item -Wstrict-flex-arrays
> +@opindex Wstrict-flex-arrays
> +@opindex Wno-strict-flex-arrays
> +Warn about inproper usages of flexible array members
> +according to the @var{level} of the @code{strict_flex_array (@var{level})}
> +attribute attached to the trailing array field of a structure if it's
> +available, otherwise according to the @var{level} of the option
> +@option{-fstrict-flex-arrays=@var{level}}.
> +
> +This option is effective only when @var{level} is bigger than 0.  Otherwise,
> +it will be ignored with a warning.
> +
> +when @var{level}=1, warnings will be issued for a trailing array reference
> +of a structure that have 2 or more elements if the trailing array is referenced
> +as a flexible array member.
> +
> +when @var{level}=2, in addition to @var{level}=1, additional warnings will be
> +issued for a trailing one-element array reference of a structure
> +if the array is referenced as a flexible array member.
> +
> +when @var{level}=3, in addition to @var{level}=2, additional warnings will be
> +issued for a trailing zero-length array reference of a structure
> +if the array is referenced as a flexible array member.
> +
> +
> @item -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{|}cold@r{|}malloc@r{]}
> @opindex Wsuggest-attribute=
> @opindex Wno-suggest-attribute=
> diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc
> index fbf448e045d..7f790c5a19a 100644
> --- a/gcc/gimple-array-bounds.cc
> +++ b/gcc/gimple-array-bounds.cc
> @@ -170,38 +170,20 @@ trailing_array (tree arg, tree *pref)
>   return array_ref_flexible_size_p (arg);
> }
> 
> -/* Checks one ARRAY_REF in REF, located at LOCUS. Ignores flexible
> -   arrays and "struct" hacks. If VRP can determine that the array
> -   subscript is a constant, check if it is outside valid range.  If
> -   the array subscript is a RANGE, warn if it is non-overlapping with
> -   valid range.  IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside
> -   a ADDR_EXPR.  Return  true if a warning has been issued or if
> -   no-warning is set.  */
> -
> -bool
> -array_bounds_checker::check_array_ref (location_t location, tree ref,
> -				       gimple *stmt, bool ignore_off_by_one)
> +/* Acquire the upper bound and upper bound plus one for the array
> +   reference REF and record them into UP_BOUND and UP_BOUND_P1.
> +   Set *DECL to the decl or expresssion REF refers to.
> +   FOR_ARRAY_BOUND is true when this is for array bound checking.  */
> +
> +static void
> +get_up_bounds_for_array_ref (tree ref, tree *decl,
> +			     tree *up_bound, tree *up_bound_p1,
> +			     bool for_array_bound)
> {
> -  if (warning_suppressed_p (ref, OPT_Warray_bounds))
> -    /* Return true to have the caller prevent warnings for enclosing
> -       refs.  */
> -    return true;
> -
> -  tree low_sub = TREE_OPERAND (ref, 1);
> -  tree up_sub = low_sub;
> -  tree up_bound = array_ref_up_bound (ref);
> -
> -  /* Referenced decl if one can be determined.  */
> -  tree decl = NULL_TREE;
> -
> -  /* Set for accesses to interior zero-length arrays.  */
> -  special_array_member sam{ };
> -
> -  tree up_bound_p1;
> -
> -  if (!up_bound
> -      || TREE_CODE (up_bound) != INTEGER_CST
> -      || (warn_array_bounds < 2 && trailing_array (ref, &decl)))
> +  if (!(*up_bound)
> +      || TREE_CODE (*up_bound) != INTEGER_CST
> +      || ((for_array_bound ? (warn_array_bounds < 2) : warn_strict_flex_arrays)
> +	   && trailing_array (ref, decl)))
>     {
>       /* Accesses to trailing arrays via pointers may access storage
> 	 beyond the types array bounds.  For such arrays, or for flexible
> @@ -213,8 +195,8 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
>       if (TREE_CODE (eltsize) != INTEGER_CST
> 	  || integer_zerop (eltsize))
> 	{
> -	  up_bound = NULL_TREE;
> -	  up_bound_p1 = NULL_TREE;
> +	  *up_bound = NULL_TREE;
> +	  *up_bound_p1 = NULL_TREE;
> 	}
>       else
> 	{
> @@ -227,7 +209,8 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
> 	    {
> 	      /* Try to determine the size of the trailing array from
> 		 its initializer (if it has one).  */
> -	      if (tree refsize = component_ref_size (arg, &sam))
> +	      if (tree refsize
> +		    = component_ref_size (arg, NULL, for_array_bound))
> 		if (TREE_CODE (refsize) == INTEGER_CST)
> 		  maxbound = refsize;
> 	    }
> @@ -246,7 +229,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
> 		    {
> 		      /* Try to determine the size from a pointer to
> 			 an array if BASE is one.  */
> -		      if (tree size = get_ref_size (base, &decl))
> +		      if (tree size = get_ref_size (base, decl))
> 			maxbound = size;
> 		    }
> 		  else if (!compref && DECL_P (base))
> @@ -254,7 +237,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
> 		      if (TREE_CODE (basesize) == INTEGER_CST)
> 			{
> 			  maxbound = basesize;
> -			  decl = base;
> +			  *decl = base;
> 			}
> 
> 		  if (known_gt (off, 0))
> @@ -266,40 +249,47 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
> 	  else
> 	    maxbound = fold_convert (sizetype, maxbound);
> 
> -	  up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize);
> +	  *up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize);
> 
> -	  if (up_bound_p1 != NULL_TREE)
> -	    up_bound = int_const_binop (MINUS_EXPR, up_bound_p1,
> +	  if (*up_bound_p1 != NULL_TREE)
> +	    *up_bound = int_const_binop (MINUS_EXPR, *up_bound_p1,
> 					build_int_cst (ptrdiff_type_node, 1));
> 	  else
> -	    up_bound = NULL_TREE;
> +	    *up_bound = NULL_TREE;
> 	}
>     }
>   else
> -    up_bound_p1 = int_const_binop (PLUS_EXPR, up_bound,
> -				   build_int_cst (TREE_TYPE (up_bound), 1));
> +    *up_bound_p1 = int_const_binop (PLUS_EXPR, *up_bound,
> +				   build_int_cst (TREE_TYPE (*up_bound), 1));
> +  return;
> +}
> 
> -  tree low_bound = array_ref_low_bound (ref);
> +/* Given the LOW_SUB_ORG, LOW_SUB and UP_SUB, and the computed UP_BOUND
> +   and UP_BOUND_P1, check whether the array reference REF is out of bound.
> +   When out of bounds, issue warnings if FOR_ARRAY_BOUND is true.
> +   otherwise, return true without issue warnings.  */
> 
> +static bool
> +check_out_of_bounds_and_warn (location_t location, tree ref,
> +			      tree low_sub_org, tree low_sub, tree up_sub,
> +			      tree up_bound, tree up_bound_p1,
> +			      const value_range *vr,
> +			      bool ignore_off_by_one, bool for_array_bound)
> +{
> +  tree low_bound = array_ref_low_bound (ref);
>   tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
> 
>   bool warned = false;
> 
>   /* Empty array.  */
>   if (up_bound && tree_int_cst_equal (low_bound, up_bound_p1))
> -    warned = warning_at (location, OPT_Warray_bounds,
> -			 "array subscript %E is outside array bounds of %qT",
> -			 low_sub, artype);
> -
> -  const value_range *vr = NULL;
> -  if (TREE_CODE (low_sub) == SSA_NAME)
>     {
> -      vr = get_value_range (low_sub, stmt);
> -      if (!vr->undefined_p () && !vr->varying_p ())
> -	{
> -	  low_sub = vr->kind () == VR_RANGE ? vr->max () : vr->min ();
> -	  up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max ();
> -	}
> +      if (for_array_bound)
> +	warned = warning_at (location, OPT_Warray_bounds,
> +			     "array subscript %E is outside array"
> +			     " bounds of %qT", low_sub_org, artype);
> +      else
> +	warned = true;
>     }
> 
>   if (warned)
> @@ -313,24 +303,127 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
> 	      : tree_int_cst_le (up_bound, up_sub))
> 	  && TREE_CODE (low_sub) == INTEGER_CST
> 	  && tree_int_cst_le (low_sub, low_bound))
> -	warned = warning_at (location, OPT_Warray_bounds,
> -			     "array subscript [%E, %E] is outside "
> -			     "array bounds of %qT",
> -			     low_sub, up_sub, artype);
> +	{
> +	  if (for_array_bound)
> +	    warned = warning_at (location, OPT_Warray_bounds,
> +				 "array subscript [%E, %E] is outside "
> +				 "array bounds of %qT",
> +				 low_sub, up_sub, artype);
> +	  else
> +	    warned = true;
> +	}
>     }
>   else if (up_bound
> 	   && TREE_CODE (up_sub) == INTEGER_CST
> 	   && (ignore_off_by_one
> 	       ? !tree_int_cst_le (up_sub, up_bound_p1)
> 	       : !tree_int_cst_le (up_sub, up_bound)))
> -    warned = warning_at (location, OPT_Warray_bounds,
> -			 "array subscript %E is above array bounds of %qT",
> -			 up_sub, artype);
> +    {
> +      if (for_array_bound)
> +	warned = warning_at (location, OPT_Warray_bounds,
> +			     "array subscript %E is above array bounds of %qT",
> +			     up_sub, artype);
> +      else
> +	warned = true;
> +    }
>   else if (TREE_CODE (low_sub) == INTEGER_CST
> 	   && tree_int_cst_lt (low_sub, low_bound))
> -    warned = warning_at (location, OPT_Warray_bounds,
> -			 "array subscript %E is below array bounds of %qT",
> -			 low_sub, artype);
> +    {
> +      if (for_array_bound)
> +	warned = warning_at (location, OPT_Warray_bounds,
> +			     "array subscript %E is below array bounds of %qT",
> +			     low_sub, artype);
> +      else
> +	warned = true;
> +    }
> +  return warned;
> +}
> +
> +/* Checks one ARRAY_REF in REF, located at LOCUS.  Ignores flexible
> +   arrays and "struct" hacks.  If VRP can determine that the array
> +   subscript is a constant, check if it is outside valid range.  If
> +   the array subscript is a RANGE, warn if it is non-overlapping with
> +   valid range.  IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside
> +   a ADDR_EXPR.  Return  true if a warning has been issued or if
> +   no-warning is set.  */
> +
> +bool
> +array_bounds_checker::check_array_ref (location_t location, tree ref,
> +				       gimple *stmt, bool ignore_off_by_one)
> +{
> +  if (warning_suppressed_p (ref, OPT_Warray_bounds))
> +    /* Return true to have the caller prevent warnings for enclosing
> +       refs.  */
> +    return true;
> +
> +  /* Upper bound and Upper bound plus one for -Warray-bounds.  */
> +  tree up_bound = array_ref_up_bound (ref);
> +  tree up_bound_p1 = NULL_TREE;
> +
> +  /* Upper bound and upper bound plus one for -Wstrict-flex-array.  */
> +  tree up_bound_strict = up_bound;
> +  tree up_bound_p1_strict = NULL_TREE;
> +
> +  /* Referenced decl if one can be determined.  */
> +  tree decl = NULL_TREE;
> +
> +  /* Set to the type of the special array member for a COMPONENT_REF.  */
> +  special_array_member sam{ };
> +
> +  tree arg = TREE_OPERAND (ref, 0);
> +  const bool compref = TREE_CODE (arg) == COMPONENT_REF;
> +
> +  unsigned int strict_flex_array_level = flag_strict_flex_arrays;
> +
> +  if (compref)
> +    {
> +      /* Try to determine special array member type for this COMPONENT_REF.  */
> +      sam = component_ref_sam_type (arg);
> +      /* Get the level of strict_flex_array for this array field.  */
> +      tree afield_decl = TREE_OPERAND (arg, 1);
> +      strict_flex_array_level = strict_flex_array_level_of (afield_decl);
> +    }
> +
> +  if (warn_array_bounds)
> +    get_up_bounds_for_array_ref (ref, &decl, &up_bound, &up_bound_p1,
> +				 true);
> +  if (warn_strict_flex_arrays)
> +    get_up_bounds_for_array_ref (ref, &decl, &up_bound_strict,
> +				 &up_bound_p1_strict, false);
> +
> +
> +
> +  bool warned = false;
> +  bool out_of_bound = false;
> +
> +  tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
> +  tree low_sub_org = TREE_OPERAND (ref, 1);
> +  tree up_sub = low_sub_org;
> +  tree low_sub = low_sub_org;
> +
> +  const value_range *vr = NULL;
> +  if (TREE_CODE (low_sub_org) == SSA_NAME)
> +    {
> +      vr = get_value_range (low_sub_org, stmt);
> +      if (!vr->undefined_p () && !vr->varying_p ())
> +	{
> +	  low_sub = vr->kind () == VR_RANGE ? vr->max () : vr->min ();
> +	  up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max ();
> +	}
> +    }
> +
> +  if (warn_array_bounds)
> +    warned = check_out_of_bounds_and_warn (location, ref,
> +					   low_sub_org, low_sub, up_sub,
> +					   up_bound, up_bound_p1, vr,
> +					   ignore_off_by_one, true);
> +
> +  if (warn_strict_flex_arrays)
> +    out_of_bound = check_out_of_bounds_and_warn (location, ref,
> +						 low_sub_org, low_sub, up_sub,
> +						 up_bound_strict,
> +						 up_bound_p1_strict, vr,
> +						 ignore_off_by_one, false);
> 
>   if (!warned && sam == special_array_member::int_0)
>     warned = warning_at (location, OPT_Wzero_length_bounds,
> @@ -341,19 +434,56 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
> 			       "of an interior zero-length array %qT")),
> 			 low_sub, artype);
> 
> -  if (warned)
> +  if (warned || out_of_bound)
>     {
> -      if (dump_file && (dump_flags & TDF_DETAILS))
> +      if (warned && dump_file && (dump_flags & TDF_DETAILS))
> 	{
> 	  fprintf (dump_file, "Array bound warning for ");
> 	  dump_generic_expr (MSG_NOTE, TDF_SLIM, ref);
> 	  fprintf (dump_file, "\n");
> 	}
> 
> +      /* issue warnings for -Wstrict-flex-arrays according to the level of
> +	 flag_strict_flex_arrays.  */
> +      if (out_of_bound && warn_strict_flex_arrays)
> +	switch (strict_flex_array_level)
> +	  {
> +	    case 3:
> +	      /* Issue additional warnings for trailing arrays [0].  */
> +	      if (sam == special_array_member::trail_0)
> +		warned = warning_at (location, OPT_Wstrict_flex_arrays,
> +				     "trailing array %qT should not be used as "
> +				     "a flexible array member for level 3",
> +				     artype);
> +	      /* FALLTHROUGH.  */
> +	    case 2:
> +	      /* Issue additional warnings for trailing arrays [1].  */
> +	      if (sam == special_array_member::trail_1)
> +		warned = warning_at (location, OPT_Wstrict_flex_arrays,
> +				     "trailing array %qT should not be used as "
> +				     "a flexible array member for level 2 and "
> +				     "above", artype);
> +	      /* FALLTHROUGH.  */
> +	    case 1:
> +	      /* Issue warnings for trailing arrays [n].  */
> +	      if (sam == special_array_member::trail_n)
> +		warned = warning_at (location, OPT_Wstrict_flex_arrays,
> +				     "trailing array %qT should not be used as "
> +				     "a flexible array member for level 1 and "
> +				     "above", artype);
> +	      break;
> +	    case 0:
> +	      /* Do nothing.  */
> +	      break;
> +	    default:
> +	      gcc_unreachable ();
> +	  }
> +
>       /* Avoid more warnings when checking more significant subscripts
> 	 of the same expression.  */
>       ref = TREE_OPERAND (ref, 0);
>       suppress_warning (ref, OPT_Warray_bounds);
> +      suppress_warning (ref, OPT_Wstrict_flex_arrays);
> 
>       if (decl)
> 	ref = decl;
> diff --git a/gcc/opts.cc b/gcc/opts.cc
> index ae079fcd20e..ca162aa781c 100644
> --- a/gcc/opts.cc
> +++ b/gcc/opts.cc
> @@ -1409,6 +1409,21 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>       opts->x_profile_flag = 0;
>     }
> 
> +  if (opts->x_warn_array_bounds)
> +    if (opts->x_flag_strict_flex_arrays)
> +      {
> +	warning_at (UNKNOWN_LOCATION, 0,
> +		    "%<-Warray-bounds%> is not impacted by "
> +		    "%<-fstrict-flex-arrays%>");
> +      }
> +  if (opts->x_warn_strict_flex_arrays)
> +    if (opts->x_flag_strict_flex_arrays == 0)
> +      {
> +	opts->x_warn_strict_flex_arrays = 0;
> +	warning_at (UNKNOWN_LOCATION, 0,
> +		    "%<-Wstrict-flex-arrays%> is ignored when"
> +		    " %<-fstrict-flex-arrays%> does not present");
> +      }
> 
>   diagnose_options (opts, opts_set, loc);
> }
> diff --git a/gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c
> new file mode 100644
> index 00000000000..72b4b7c6406
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c
> @@ -0,0 +1,9 @@
> +/* Test the usage of option -Wstrict-flex-arrays.  */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays" } */
> +
> +int main(int argc, char *argv[])
> +{
> +    return 0;
> +}
> +/* { dg-warning "is ignored when \'-fstrict-flex-arrays\' does not present" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/Wstrict-flex-arrays_2.c b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays_2.c
> new file mode 100644
> index 00000000000..af9ec922dea
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays_2.c
> @@ -0,0 +1,9 @@
> +/* Test the usage of option -Wstrict-flex-arrays.  */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -Warray-bounds -fstrict-flex-arrays" } */
> +
> +int main(int argc, char *argv[])
> +{
> +    return 0;
> +}
> +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c
> new file mode 100644
> index 00000000000..59d5a5fcb23
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c
> @@ -0,0 +1,46 @@
> +/* Test -Wstrict-flex-arrays.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=2" } */
> +
> +struct trailing_array_1 {
> +    int a;
> +    int b;
> +    int c[4]; 
> +};
> +
> +struct trailing_array_2 {
> +    int a;
> +    int b;
> +    int c[1]; 
> +};
> +
> +struct trailing_array_3 {
> +    int a;
> +    int b;
> +    int c[0];
> +};
> +struct trailing_array_4 {
> +    int a;
> +    int b;
> +    int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> +    struct trailing_array_1 *normal,
> +    struct trailing_array_2 *trailing_1,
> +    struct trailing_array_3 *trailing_0,
> +    struct trailing_array_4 *trailing_flex)
> +{
> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> +    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
> +    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> +    return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c
> new file mode 100644
> index 00000000000..2f66151e927
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c
> @@ -0,0 +1,46 @@
> +/* Test -Wstrict-flex-arrays.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=3" } */
> +
> +struct trailing_array_1 {
> +    int a;
> +    int b;
> +    int c[4]; 
> +};
> +
> +struct trailing_array_2 {
> +    int a;
> +    int b;
> +    int c[1]; 
> +};
> +
> +struct trailing_array_3 {
> +    int a;
> +    int b;
> +    int c[0];
> +};
> +struct trailing_array_4 {
> +    int a;
> +    int b;
> +    int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> +    struct trailing_array_1 *normal,
> +    struct trailing_array_2 *trailing_1,
> +    struct trailing_array_3 *trailing_0,
> +    struct trailing_array_4 *trailing_flex)
> +{
> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> +    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
> +    trailing_0->c[1] = 1; /* { dg-warning "should not be used as a flexible array member for level 3" } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 3" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> +    return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c
> new file mode 100644
> index 00000000000..6a4576568ac
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c
> @@ -0,0 +1,49 @@
> +/* Test -Wstrict-flex-arrays + -Warray-bounds.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=1 -Warray-bounds" } */
> +
> +struct trailing_array_1 {
> +    int a;
> +    int b;
> +    int c[4]; 
> +};
> +
> +struct trailing_array_2 {
> +    int a;
> +    int b;
> +    int c[1]; 
> +};
> +
> +struct trailing_array_3 {
> +    int a;
> +    int b;
> +    int c[0];
> +};
> +struct trailing_array_4 {
> +    int a;
> +    int b;
> +    int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> +    struct trailing_array_1 *normal,
> +    struct trailing_array_2 *trailing_1,
> +    struct trailing_array_3 *trailing_0,
> +    struct trailing_array_4 *trailing_flex)
> +{
> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> +    			 /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
> +    trailing_1->c[2] = 2; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> +    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> +    return 0;
> +}
> +
> +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c
> new file mode 100644
> index 00000000000..e550fbd24e1
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c
> @@ -0,0 +1,48 @@
> +/* Test -Wstrict-flex-arrays + -Warray-bounds.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=2 -Warray-bounds" } */
> +
> +struct trailing_array_1 {
> +    int a;
> +    int b;
> +    int c[4]; 
> +};
> +
> +struct trailing_array_2 {
> +    int a;
> +    int b;
> +    int c[1]; 
> +};
> +
> +struct trailing_array_3 {
> +    int a;
> +    int b;
> +    int c[0];
> +};
> +struct trailing_array_4 {
> +    int a;
> +    int b;
> +    int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> +    struct trailing_array_1 *normal,
> +    struct trailing_array_2 *trailing_1,
> +    struct trailing_array_3 *trailing_0,
> +    struct trailing_array_4 *trailing_flex)
> +{
> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> +    			 /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
> +    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
> +    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> +    return 0;
> +}
> +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c
> new file mode 100644
> index 00000000000..d5b61136b3a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c
> @@ -0,0 +1,48 @@
> +/* Test -Wstrict-flex-arrays.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=3 -Warray-bounds" } */
> +
> +struct trailing_array_1 {
> +    int a;
> +    int b;
> +    int c[4]; 
> +};
> +
> +struct trailing_array_2 {
> +    int a;
> +    int b;
> +    int c[1]; 
> +};
> +
> +struct trailing_array_3 {
> +    int a;
> +    int b;
> +    int c[0];
> +};
> +struct trailing_array_4 {
> +    int a;
> +    int b;
> +    int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> +    struct trailing_array_1 *normal,
> +    struct trailing_array_2 *trailing_1,
> +    struct trailing_array_3 *trailing_0,
> +    struct trailing_array_4 *trailing_flex)
> +{
> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> +   			/*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */ 
> +    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
> +    trailing_0->c[1] = 1; /* { dg-warning "should not be used as a flexible array member for level 3" } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 3" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> +    return 0;
> +}
> +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c
> new file mode 100644
> index 00000000000..eb82a60c261
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c
> @@ -0,0 +1,50 @@
> +/* Test -Wstrict-flex-arrays + -Warray-bounds=2.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=1 -Warray-bounds=2" } */
> +
> +struct trailing_array_1 {
> +    int a;
> +    int b;
> +    int c[4]; 
> +};
> +
> +struct trailing_array_2 {
> +    int a;
> +    int b;
> +    int c[1]; 
> +};
> +
> +struct trailing_array_3 {
> +    int a;
> +    int b;
> +    int c[0];
> +};
> +struct trailing_array_4 {
> +    int a;
> +    int b;
> +    int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> +    struct trailing_array_1 *normal,
> +    struct trailing_array_2 *trailing_1,
> +    struct trailing_array_3 *trailing_0,
> +    struct trailing_array_4 *trailing_flex)
> +{
> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> +    			 /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
> +    trailing_1->c[2] = 2; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> +    			 /*{ dg-warning "array subscript 2 is above array bounds of" "" { target *-*-* } .-1 } */
> +    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> +    return 0;
> +}
> +
> +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c
> new file mode 100644
> index 00000000000..f48a50e04f5
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c
> @@ -0,0 +1,49 @@
> +/* Test -Wstrict-flex-arrays + -Warray-bounds=2.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=2 -Warray-bounds=2" } */
> +
> +struct trailing_array_1 {
> +    int a;
> +    int b;
> +    int c[4]; 
> +};
> +
> +struct trailing_array_2 {
> +    int a;
> +    int b;
> +    int c[1]; 
> +};
> +
> +struct trailing_array_3 {
> +    int a;
> +    int b;
> +    int c[0];
> +};
> +struct trailing_array_4 {
> +    int a;
> +    int b;
> +    int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> +    struct trailing_array_1 *normal,
> +    struct trailing_array_2 *trailing_1,
> +    struct trailing_array_3 *trailing_0,
> +    struct trailing_array_4 *trailing_flex)
> +{
> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> +    			 /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
> +    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
> +    			  /*{ dg-warning "array subscript 2 is above array bounds of" "" { target *-*-* } .-1 } */
> +    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> +    return 0;
> +}
> +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c
> new file mode 100644
> index 00000000000..9f2877ef4e1
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c
> @@ -0,0 +1,49 @@
> +/* Test -Wstrict-flex-arrays + -Warray-bounds=2.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=3 -Warray-bounds=2" } */
> +
> +struct trailing_array_1 {
> +    int a;
> +    int b;
> +    int c[4]; 
> +};
> +
> +struct trailing_array_2 {
> +    int a;
> +    int b;
> +    int c[1]; 
> +};
> +
> +struct trailing_array_3 {
> +    int a;
> +    int b;
> +    int c[0];
> +};
> +struct trailing_array_4 {
> +    int a;
> +    int b;
> +    int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> +    struct trailing_array_1 *normal,
> +    struct trailing_array_2 *trailing_1,
> +    struct trailing_array_3 *trailing_0,
> +    struct trailing_array_4 *trailing_flex)
> +{
> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> +   			/*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */ 
> +    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
> +    			/*{ dg-warning "array subscript 2 is above array bounds of" "" { target *-*-* } .-1 } */
> +    trailing_0->c[1] = 1; /* { dg-warning "should not be used as a flexible array member for level 3" } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 3" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> +    return 0;
> +}
> +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c
> new file mode 100644
> index 00000000000..43a9098f138
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c
> @@ -0,0 +1,46 @@
> +/* Test -Wstrict-flex-arrays.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=1" } */
> +
> +struct trailing_array_1 {
> +    int a;
> +    int b;
> +    int c[4]; 
> +};
> +
> +struct trailing_array_2 {
> +    int a;
> +    int b;
> +    int c[1]; 
> +};
> +
> +struct trailing_array_3 {
> +    int a;
> +    int b;
> +    int c[0];
> +};
> +struct trailing_array_4 {
> +    int a;
> +    int b;
> +    int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> +    struct trailing_array_1 *normal,
> +    struct trailing_array_2 *trailing_1,
> +    struct trailing_array_3 *trailing_0,
> +    struct trailing_array_4 *trailing_flex)
> +{
> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> +    trailing_1->c[2] = 2; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> +    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> +    return 0;
> +}
> diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
> index e5a292bb875..1f1b56c1a52 100644
> --- a/gcc/tree-vrp.cc
> +++ b/gcc/tree-vrp.cc
> @@ -4229,12 +4229,12 @@ execute_vrp (struct function *fun, bool warn_array_bounds_p)
>      the flag on every edge now, rather than in
>      check_array_bounds_dom_walker's ctor; vrp_folder may clear
>      it from some edges.  */
> -  if (warn_array_bounds && warn_array_bounds_p)
> +  if ((warn_array_bounds || warn_strict_flex_arrays) && warn_array_bounds_p)
>     set_all_edges_as_executable (fun);
> 
>   folder.substitute_and_fold ();
> 
> -  if (warn_array_bounds && warn_array_bounds_p)
> +  if ((warn_array_bounds || warn_strict_flex_arrays) && warn_array_bounds_p)
>     {
>       array_bounds_checker array_checker (fun, &vrp_vr_values);
>       array_checker.check ();
> @@ -4353,7 +4353,7 @@ execute_ranger_vrp (struct function *fun, bool warn_array_bounds_p)
>   if (dump_file && (dump_flags & TDF_DETAILS))
>     ranger->dump (dump_file);
> 
> -  if (warn_array_bounds && warn_array_bounds_p)
> +  if ((warn_array_bounds || warn_strict_flex_arrays) && warn_array_bounds_p)
>     {
>       // Set all edges as executable, except those ranger says aren't.
>       int non_exec_flag = ranger->non_executable_edge_flag;
> diff --git a/gcc/tree.cc b/gcc/tree.cc
> index d2b0b34a725..0f5f7151b6b 100644
> --- a/gcc/tree.cc
> +++ b/gcc/tree.cc
> @@ -12726,15 +12726,21 @@ array_ref_up_bound (tree exp)
>    int test (uint8_t *p, uint32_t t[1][1], int n) {
>    for (int i = 0; i < 4; i++, p++)
>      t[i][0] = ...;
> +
> +   If non-null, set IS_TRAILING_ARRAY to true if the ref is the above case A.
> */
> 
> bool
> -array_ref_flexible_size_p (tree ref)
> +array_ref_flexible_size_p (tree ref, bool *is_trailing_array /* = NULL */)
> {
> -  /* the TYPE for this array referece.  */
> +  /* The TYPE for this array referece.  */
>   tree atype = NULL_TREE;
> -  /* the FIELD_DECL for the array field in the containing structure.  */
> +  /* The FIELD_DECL for the array field in the containing structure.  */
>   tree afield_decl = NULL_TREE;
> +  /* Whether this array is the trailing array of a structure.  */
> +  bool is_trailing_array_tmp = false;
> +  if (!is_trailing_array)
> +    is_trailing_array = &is_trailing_array_tmp;
> 
>   if (TREE_CODE (ref) == ARRAY_REF
>       || TREE_CODE (ref) == ARRAY_RANGE_REF)
> @@ -12822,7 +12828,10 @@ array_ref_flexible_size_p (tree ref)
>   if (! TYPE_SIZE (atype)
>       || ! TYPE_DOMAIN (atype)
>       || ! TYPE_MAX_VALUE (TYPE_DOMAIN (atype)))
> -    return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> +    {
> +      *is_trailing_array = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
> +      return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> +    }
> 
>   /* If the reference is based on a declared entity, the size of the array
>      is constrained by its given domain.  (Do not trust commons PR/69368).  */
> @@ -12844,9 +12853,17 @@ array_ref_flexible_size_p (tree ref)
>       if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (atype))) != INTEGER_CST
> 	  || TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST
>           || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST)
> -	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> +	{
> +	  *is_trailing_array
> +	    = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
> +	  return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> +	}
>       if (! get_addr_base_and_unit_offset (ref_to_array, &offset))
> -	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> +	{
> +	  *is_trailing_array
> +	    = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
> +	  return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> +	}
> 
>       /* If at least one extra element fits it is a flexarray.  */
>       if (known_le ((wi::to_offset (TYPE_MAX_VALUE (TYPE_DOMAIN (atype)))
> @@ -12854,11 +12871,16 @@ array_ref_flexible_size_p (tree ref)
> 		     + 2)
> 		    * wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (atype))),
> 		    wi::to_offset (DECL_SIZE_UNIT (ref)) - offset))
> -	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> +	{
> +	  *is_trailing_array
> +	    = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
> +	  return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> +	}
> 
>       return false;
>     }
> 
> +  *is_trailing_array = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
>   return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> }
> 
> @@ -12920,24 +12942,81 @@ get_initializer_for (tree init, tree decl)
>   return NULL_TREE;
> }
> 
> +/* Determines the special array member type for the array reference REF.  */
> +special_array_member
> +component_ref_sam_type (tree ref)
> +{
> +  special_array_member sam_type = special_array_member::none;
> +
> +  tree member = TREE_OPERAND (ref, 1);
> +  tree memsize = DECL_SIZE_UNIT (member);
> +  if (memsize)
> +    {
> +      tree memtype = TREE_TYPE (member);
> +      if (TREE_CODE (memtype) != ARRAY_TYPE)
> +	return sam_type;
> +
> +      bool trailing = false;
> +      (void)array_ref_flexible_size_p (ref, &trailing);
> +      bool zero_length = integer_zerop (memsize);
> +      if (!trailing && !zero_length)
> +	/* MEMBER is an interior array with
> +	  more than one element.  */
> +	return special_array_member::int_n;
> +
> +      if (zero_length)
> +	{
> +	  if (trailing)
> +	    return special_array_member::trail_0;
> +	  else
> +	    return special_array_member::int_0;
> +	}
> +
> +      if (!zero_length)
> +	if (tree dom = TYPE_DOMAIN (memtype))
> +	  if (tree min = TYPE_MIN_VALUE (dom))
> +	    if (tree max = TYPE_MAX_VALUE (dom))
> +	      if (TREE_CODE (min) == INTEGER_CST
> +		  && TREE_CODE (max) == INTEGER_CST)
> +		{
> +		  offset_int minidx = wi::to_offset (min);
> +		  offset_int maxidx = wi::to_offset (max);
> +		  offset_int neltsm1 = maxidx - minidx;
> +		  if (neltsm1 > 0)
> +		    /* MEMBER is a trailing array with more than
> +		       one elements.  */
> +		    return special_array_member::trail_n;
> +
> +		  if (neltsm1 == 0)
> +		    return special_array_member::trail_1;
> +		}
> +    }
> +
> +  return sam_type;
> +}
> +
> /* Determines the size of the member referenced by the COMPONENT_REF
>    REF, using its initializer expression if necessary in order to
>    determine the size of an initialized flexible array member.
> -   If non-null, set *ARK when REF refers to an interior zero-length
> +   If non-null, set *SAM when REF refers to an interior zero-length
>    array or a trailing one-element array.
>    Returns the size as sizetype (which might be zero for an object
>    with an uninitialized flexible array member) or null if the size
> -   cannot be determined.  */
> +   cannot be determined.
> +   when FOR_ARRAY_BOUND_CHECK is true, this routine is called for
> +   -Warray-bounds check only, due to historical reason, the LEVEL
> +   of -Warray-bounds=LEVEL is not controled by -fstrict-flex-arrays.  */
> 
> tree
> -component_ref_size (tree ref, special_array_member *sam /* = NULL */)
> +component_ref_size (tree ref, special_array_member *sam /* = NULL */,
> +		    bool for_array_bound_check /* = FALSE */)
> {
>   gcc_assert (TREE_CODE (ref) == COMPONENT_REF);
> 
>   special_array_member sambuf;
>   if (!sam)
>     sam = &sambuf;
> -  *sam = special_array_member::none;
> +  *sam = component_ref_sam_type (ref);
> 
>   /* The object/argument referenced by the COMPONENT_REF and its type.  */
>   tree arg = TREE_OPERAND (ref, 0);
> @@ -12958,41 +13037,49 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */)
> 	return (tree_int_cst_equal (memsize, TYPE_SIZE_UNIT (memtype))
> 		? memsize : NULL_TREE);
> 
> -      bool trailing = array_ref_flexible_size_p (ref);
> -      bool zero_length = integer_zerop (memsize);
> -      if (!trailing && !zero_length)
> -	/* MEMBER is either an interior array or is an array with
> -	   more than one element.  */
> +      /* 2-or-more elements arrays are treated as normal arrays by default.  */
> +      if (*sam == special_array_member::int_n
> +	  || *sam == special_array_member::trail_n)
> 	return memsize;
> 
> -      if (zero_length)
> +      /* For -Warray-bounds=LEVEL check, historically we have to treat
> +	 trail_0 and trail_1 as flexible arrays by default when LEVEL=1.
> +	 for other cases, flag_strict_flex_arrays will control how to treat
> +	 the trailing arrays as flexiable array members.  */
> +
> +      tree afield_decl = TREE_OPERAND (ref, 1);
> +      unsigned int strict_flex_array_level
> +	= strict_flex_array_level_of (afield_decl);
> +
> +      if (!for_array_bound_check)
> 	{
> -	  if (trailing)
> -	    *sam = special_array_member::trail_0;
> -	  else
> +	  switch (strict_flex_array_level)
> 	    {
> -	      *sam = special_array_member::int_0;
> -	      memsize = NULL_TREE;
> +	      case 3:
> +		/* Treaing 0-length trailing arrays as normal array.  */
> +		if (*sam == special_array_member::trail_0)
> +		  return size_zero_node;
> +		/* FALLTHROUGH.  */
> +	      case 2:
> +		/* Treating 1-element trailing arrays as normal array.  */
> +		if (*sam == special_array_member::trail_1)
> +		  return memsize;
> +		/* FALLTHROUGH.  */
> +	      case 1:
> +		/* Treating 2-or-more elements trailing arrays as normal
> +		   array.  */
> +		if (*sam == special_array_member::trail_n)
> +		  return memsize;
> +		/* FALLTHROUGH.  */
> +	      case 0:
> +		break;
> +	      default:
> +		gcc_unreachable ();
> 	    }
> 	}
> 
> -      if (!zero_length)
> -	if (tree dom = TYPE_DOMAIN (memtype))
> -	  if (tree min = TYPE_MIN_VALUE (dom))
> -	    if (tree max = TYPE_MAX_VALUE (dom))
> -	      if (TREE_CODE (min) == INTEGER_CST
> -		  && TREE_CODE (max) == INTEGER_CST)
> -		{
> -		  offset_int minidx = wi::to_offset (min);
> -		  offset_int maxidx = wi::to_offset (max);
> -		  offset_int neltsm1 = maxidx - minidx;
> -		  if (neltsm1 > 0)
> -		    /* MEMBER is an array with more than one element.  */
> -		    return memsize;
> -
> -		  if (neltsm1 == 0)
> -		    *sam = special_array_member::trail_1;
> -		}
> +	if (*sam == special_array_member::int_0)
> +	  memsize = NULL_TREE;
> 
>       /* For a reference to a zero- or one-element array member of a union
> 	 use the size of the union instead of the size of the member.  */
> diff --git a/gcc/tree.h b/gcc/tree.h
> index 0fcdd6b06d0..f81a1f6efa1 100644
> --- a/gcc/tree.h
> +++ b/gcc/tree.h
> @@ -5551,28 +5551,33 @@ extern tree array_ref_low_bound (tree);
> /* Returns true if REF is an array reference, a component reference,
>    or a memory reference to an array whose actual size might be larger
>    than its upper bound implies.  */
> -extern bool array_ref_flexible_size_p (tree);
> +extern bool array_ref_flexible_size_p (tree, bool * = NULL);
> 
> /* Return a tree representing the offset, in bytes, of the field referenced
>    by EXP.  This does not include any offset in DECL_FIELD_BIT_OFFSET.  */
> extern tree component_ref_field_offset (tree);
> 
> -/* Describes a "special" array member due to which component_ref_size
> -   returns null.  */
> +/* Describes a "special" array member for a COMPONENT_REF.  */
> enum struct special_array_member
>   {
>     none,	/* Not a special array member.  */
>     int_0,	/* Interior array member with size zero.  */
>     trail_0,	/* Trailing array member with size zero.  */
> -    trail_1	/* Trailing array member with one element.  */
> +    trail_1,	/* Trailing array member with one element.  */
> +    trail_n,	/* Trailing array member with two or more elements.  */
> +    int_n	/* Interior array member with one or more elements.  */
>   };
> 
> +/* Determines the special array member type for a COMPONENT_REF.  */
> +extern special_array_member component_ref_sam_type (tree);
> +
> /* Return the size of the member referenced by the COMPONENT_REF, using
>    its initializer expression if necessary in order to determine the size
>    of an initialized flexible array member.  The size might be zero for
>    an object with an uninitialized flexible array member or null if it
>    cannot be determined.  */
> -extern tree component_ref_size (tree, special_array_member * = NULL);
> +extern tree component_ref_size (tree, special_array_member * = NULL,
> +				bool = false);
> 
> extern int tree_map_base_eq (const void *, const void *);
> extern unsigned int tree_map_base_hash (const void *);
> -- 
> 2.31.1
> 


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

* Re: [PATCH 2/2] Add a new warning option -Wstrict-flex-arrays.
  2022-11-08 14:51 ` [PATCH 2/2] Add a new warning option -Wstrict-flex-arrays Qing Zhao
  2022-11-15 15:41   ` Qing Zhao
@ 2022-11-18 13:14   ` Richard Biener
  2022-11-18 15:19     ` Qing Zhao
  1 sibling, 1 reply; 15+ messages in thread
From: Richard Biener @ 2022-11-18 13:14 UTC (permalink / raw)
  To: Qing Zhao; +Cc: joseph, gcc-patches, keescook, siddhesh

On Tue, 8 Nov 2022, Qing Zhao wrote:

> '-Wstrict-flex-arrays'
>      Warn about inproper usages of flexible array members according to
>      the LEVEL of the 'strict_flex_array (LEVEL)' attribute attached to
>      the trailing array field of a structure if it's available,
>      otherwise according to the LEVEL of the option
>      '-fstrict-flex-arrays=LEVEL'.
> 
>      This option is effective only when LEVEL is bigger than 0.
>      Otherwise, it will be ignored with a warning.
> 
>      when LEVEL=1, warnings will be issued for a trailing array
>      reference of a structure that have 2 or more elements if the
>      trailing array is referenced as a flexible array member.
> 
>      when LEVEL=2, in addition to LEVEL=1, additional warnings will be
>      issued for a trailing one-element array reference of a structure if
>      the array is referenced as a flexible array member.
> 
>      when LEVEL=3, in addition to LEVEL=2, additional warnings will be
>      issued for a trailing zero-length array reference of a structure if
>      the array is referenced as a flexible array member.
> 
> At the same time, keep -Warray-bounds=[1|2] warnings unchanged from
>  -fstrict-flex-arrays.

Looking at this, is this a way to avoid interpreting -Warray-bounds=N
together with -fstrict-flex-arrays=M?  Won't this be just confusing to
users?  Especially since -Wall includes -Warray-bounds and thus we'll
diagnose

+  if (opts->x_warn_array_bounds)
+    if (opts->x_flag_strict_flex_arrays)
+      {
+       warning_at (UNKNOWN_LOCATION, 0,
+                   "%<-Warray-bounds%> is not impacted by "
+                   "%<-fstrict-flex-arrays%>");
+      }

and do that even when -Wstrict-flex-arrays is given?

Would it be better/possible to add a note: to existing -Warray-bounds
diagnostics on how the behavior is altered by -fstrict-flex-arrays?

I guess this will inevitably re-iterate the -fstrict-flex-arrays=N
vs. -Warray-bounds=M discussion ...

I think it would be better to stick with -Warray-bounds and flex
its =2 mode to work according to -fstrict-flex-arrays=N instead of
"out of bounds accesses to trailing struct members of one-element array 
types" (thus, not add [1] but instead the cases that are not flex 
arrays according to -fstrict-flex-arrays).

Richard.

> gcc/ChangeLog:
> 
> 	* attribs.cc (strict_flex_array_level_of): New function.
> 	* attribs.h (strict_flex_array_level_of): Prototype for new function.
> 	* doc/invoke.texi: Document -Wstrict-flex-arrays option. Update
> 	-fstrict-flex-arrays[=n] options.
> 	* gimple-array-bounds.cc (array_bounds_checker::check_array_ref):
> 	Issue warnings for -Wstrict-flex-arrays.
> 	(get_up_bounds_for_array_ref): New function.
> 	(check_out_of_bounds_and_warn): New function.
> 	* opts.cc (finish_options): Issue warnings for unsupported combination
> 	of -Warray-bounds and -fstrict-flex-arrays, -Wstrict_flex_arrays and
> 	-fstrict-flex-array.
> 	* tree-vrp.cc (execute_vrp): Enable the pass when
> 	warn_strict_flex_array is true.
> 	(execute_ranger_vrp): Likewise.
> 	* tree.cc (array_ref_flexible_size_p): Add one new argument.
> 	(component_ref_sam_type): New function.
> 	(component_ref_size): Add one new argument,
> 	* tree.h (array_ref_flexible_size_p): Update prototype.
> 	(enum struct special_array_member): Add two new enum values.
> 	(component_ref_sam_type): New prototype.
> 	(component_ref_size): Update prototype.
> 
> gcc/c-family/ChangeLog:
> 
> 	* c.opt (Wstrict-flex-arrays): New option.
> 
> gcc/c/ChangeLog:
> 
> 	* c-decl.cc (is_flexible_array_member_p): Call new function
> 	strict_flex_array_level_of.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* c-c++-common/Wstrict-flex-arrays.c: New test.
> 	* c-c++-common/Wstrict-flex-arrays_2.c: New test.
> 	* gcc.dg/Wstrict-flex-arrays-2.c: New test.
> 	* gcc.dg/Wstrict-flex-arrays-3.c: New test.
> 	* gcc.dg/Wstrict-flex-arrays-4.c: New test.
> 	* gcc.dg/Wstrict-flex-arrays-5.c: New test.
> 	* gcc.dg/Wstrict-flex-arrays-6.c: New test.
> 	* gcc.dg/Wstrict-flex-arrays-7.c: New test.
> 	* gcc.dg/Wstrict-flex-arrays-8.c: New test.
> 	* gcc.dg/Wstrict-flex-arrays-9.c: New test.
> 	* gcc.dg/Wstrict-flex-arrays.c: New test.
> ---
>  gcc/attribs.cc                                |  30 ++
>  gcc/attribs.h                                 |   2 +
>  gcc/c-family/c.opt                            |   5 +
>  gcc/c/c-decl.cc                               |  22 +-
>  gcc/doc/invoke.texi                           |  33 ++-
>  gcc/gimple-array-bounds.cc                    | 264 +++++++++++++-----
>  gcc/opts.cc                                   |  15 +
>  .../c-c++-common/Wstrict-flex-arrays.c        |   9 +
>  .../c-c++-common/Wstrict-flex-arrays_2.c      |   9 +
>  gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c  |  46 +++
>  gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c  |  46 +++
>  gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c  |  49 ++++
>  gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c  |  48 ++++
>  gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c  |  48 ++++
>  gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c  |  50 ++++
>  gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c  |  49 ++++
>  gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c  |  49 ++++
>  gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c    |  46 +++
>  gcc/tree-vrp.cc                               |   6 +-
>  gcc/tree.cc                                   | 165 ++++++++---
>  gcc/tree.h                                    |  15 +-
>  21 files changed, 870 insertions(+), 136 deletions(-)
>  create mode 100644 gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c
>  create mode 100644 gcc/testsuite/c-c++-common/Wstrict-flex-arrays_2.c
>  create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c
>  create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c
>  create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c
>  create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c
>  create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c
>  create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c
>  create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c
>  create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c
>  create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c
> 
> diff --git a/gcc/attribs.cc b/gcc/attribs.cc
> index 27dea748561..095def4d6b0 100644
> --- a/gcc/attribs.cc
> +++ b/gcc/attribs.cc
> @@ -2456,6 +2456,36 @@ init_attr_rdwr_indices (rdwr_map *rwm, tree attrs)
>      }
>  }
>  
> +/* Get the LEVEL of the strict_flex_array for the ARRAY_FIELD based on the
> +   values of attribute strict_flex_array and the flag_strict_flex_arrays.  */
> +unsigned int
> +strict_flex_array_level_of (tree array_field)
> +{
> +  gcc_assert (TREE_CODE (array_field) == FIELD_DECL);
> +  unsigned int strict_flex_array_level = flag_strict_flex_arrays;
> +
> +  tree attr_strict_flex_array
> +    = lookup_attribute ("strict_flex_array", DECL_ATTRIBUTES (array_field));
> +  /* If there is a strict_flex_array attribute attached to the field,
> +     override the flag_strict_flex_arrays.  */
> +  if (attr_strict_flex_array)
> +    {
> +      /* Get the value of the level first from the attribute.  */
> +      unsigned HOST_WIDE_INT attr_strict_flex_array_level = 0;
> +      gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
> +      attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
> +      gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
> +      attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
> +      gcc_assert (tree_fits_uhwi_p (attr_strict_flex_array));
> +      attr_strict_flex_array_level = tree_to_uhwi (attr_strict_flex_array);
> +
> +      /* The attribute has higher priority than flag_struct_flex_array.  */
> +      strict_flex_array_level = attr_strict_flex_array_level;
> +    }
> +  return strict_flex_array_level;
> +}
> +
> +
>  /* Return the access specification for a function parameter PARM
>     or null if the current function has no such specification.  */
>  
> diff --git a/gcc/attribs.h b/gcc/attribs.h
> index 1dc16e4bc4e..742811e6fda 100644
> --- a/gcc/attribs.h
> +++ b/gcc/attribs.h
> @@ -398,4 +398,6 @@ extern void init_attr_rdwr_indices (rdwr_map *, tree);
>  extern attr_access *get_parm_access (rdwr_map &, tree,
>  				     tree = current_function_decl);
>  
> +extern unsigned int strict_flex_array_level_of (tree);
> +
>  #endif // GCC_ATTRIBS_H
> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
> index 01d480759ae..bc33710a649 100644
> --- a/gcc/c-family/c.opt
> +++ b/gcc/c-family/c.opt
> @@ -968,6 +968,11 @@ Wstringop-truncation
>  C ObjC C++ LTO ObjC++ Var(warn_stringop_truncation) Warning Init (1) LangEnabledBy(C ObjC C++ LTO ObjC++, Wall)
>  Warn about truncation in string manipulation functions like strncat and strncpy.
>  
> +Wstrict-flex-arrays
> +C C++ Var(warn_strict_flex_arrays) Warning
> +Warn about inproper usages of flexible array members
> +according to the level of -fstrict-flex-arrays.
> +
>  Wsuggest-attribute=format
>  C ObjC C++ ObjC++ Var(warn_suggest_attribute_format) Warning
>  Warn about functions which might be candidates for format attributes.
> diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
> index 4746e310d2d..c9cb46daacc 100644
> --- a/gcc/c/c-decl.cc
> +++ b/gcc/c/c-decl.cc
> @@ -8828,7 +8828,6 @@ finish_incomplete_vars (tree incomplete_vars, bool toplevel)
>      }
>  }
>  
> -
>  /* Determine whether the FIELD_DECL X is a flexible array member according to
>     the following info:
>    A. whether the FIELD_DECL X is the last field of the DECL_CONTEXT;
> @@ -8855,26 +8854,7 @@ is_flexible_array_member_p (bool is_last_field,
>    bool is_one_element_array = one_element_array_type_p (TREE_TYPE (x));
>    bool is_flexible_array = flexible_array_member_type_p (TREE_TYPE (x));
>  
> -  unsigned int strict_flex_array_level = flag_strict_flex_arrays;
> -
> -  tree attr_strict_flex_array = lookup_attribute ("strict_flex_array",
> -						  DECL_ATTRIBUTES (x));
> -  /* If there is a strict_flex_array attribute attached to the field,
> -     override the flag_strict_flex_arrays.  */
> -  if (attr_strict_flex_array)
> -    {
> -      /* Get the value of the level first from the attribute.  */
> -      unsigned HOST_WIDE_INT attr_strict_flex_array_level = 0;
> -      gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
> -      attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
> -      gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
> -      attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
> -      gcc_assert (tree_fits_uhwi_p (attr_strict_flex_array));
> -      attr_strict_flex_array_level = tree_to_uhwi (attr_strict_flex_array);
> -
> -      /* The attribute has higher priority than flag_struct_flex_array.  */
> -      strict_flex_array_level = attr_strict_flex_array_level;
> -    }
> +  unsigned int strict_flex_array_level = strict_flex_array_level_of (x);
>  
>    switch (strict_flex_array_level)
>      {
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 64f77e8367a..a35e6bf27e0 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -397,7 +397,7 @@ Objective-C and Objective-C++ Dialects}.
>  -Wstrict-aliasing=n  -Wstrict-overflow  -Wstrict-overflow=@var{n} @gol
>  -Wstring-compare @gol
>  -Wno-stringop-overflow -Wno-stringop-overread @gol
> --Wno-stringop-truncation @gol
> +-Wno-stringop-truncation -Wstrict-flex-arrays @gol
>  -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{|}malloc@r{]} @gol
>  -Wswitch  -Wno-switch-bool  -Wswitch-default  -Wswitch-enum @gol
>  -Wno-switch-outside-range  -Wno-switch-unreachable  -Wsync-nand @gol
> @@ -2848,12 +2848,18 @@ The negative form is equivalent to @option{-fstrict-flex-arrays=0}, which is the
>  least strict.  All trailing arrays of structures are treated as flexible array
>  members.
>  
> +This option is not compatible with @option{-Warray-bounds} due to historical
> +reason.  The behavior of @option{-Warray-bounds} is not changed by this option.
> +
>  @item -fstrict-flex-arrays=@var{level}
>  @opindex fstrict-flex-arrays=@var{level}
>  Control when to treat the trailing array of a structure as a flexible array
>  member for the purpose of accessing the elements of such an array.  The value
>  of @var{level} controls the level of strictness.
>  
> +This option is not compatible with @option{-Warray-bounds} due to historical
> +reason.  The behavior of @option{-Warray-bounds} is not changed by this option.
> +
>  The possible values of @var{level} are the same as for the
>  @code{strict_flex_array} attribute (@pxref{Variable Attributes}).
>  
> @@ -7662,6 +7668,31 @@ however, are not suitable arguments to functions that expect
>  such arrays GCC issues warnings unless it can prove that the use is
>  safe.  @xref{Common Variable Attributes}.
>  
> +@item -Wstrict-flex-arrays
> +@opindex Wstrict-flex-arrays
> +@opindex Wno-strict-flex-arrays
> +Warn about inproper usages of flexible array members
> +according to the @var{level} of the @code{strict_flex_array (@var{level})}
> +attribute attached to the trailing array field of a structure if it's
> +available, otherwise according to the @var{level} of the option
> +@option{-fstrict-flex-arrays=@var{level}}.
> +
> +This option is effective only when @var{level} is bigger than 0.  Otherwise,
> +it will be ignored with a warning.
> +
> +when @var{level}=1, warnings will be issued for a trailing array reference
> +of a structure that have 2 or more elements if the trailing array is referenced
> +as a flexible array member.
> +
> +when @var{level}=2, in addition to @var{level}=1, additional warnings will be
> +issued for a trailing one-element array reference of a structure
> +if the array is referenced as a flexible array member.
> +
> +when @var{level}=3, in addition to @var{level}=2, additional warnings will be
> +issued for a trailing zero-length array reference of a structure
> +if the array is referenced as a flexible array member.
> +
> +
>  @item -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{|}cold@r{|}malloc@r{]}
>  @opindex Wsuggest-attribute=
>  @opindex Wno-suggest-attribute=
> diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc
> index fbf448e045d..7f790c5a19a 100644
> --- a/gcc/gimple-array-bounds.cc
> +++ b/gcc/gimple-array-bounds.cc
> @@ -170,38 +170,20 @@ trailing_array (tree arg, tree *pref)
>    return array_ref_flexible_size_p (arg);
>  }
>  
> -/* Checks one ARRAY_REF in REF, located at LOCUS. Ignores flexible
> -   arrays and "struct" hacks. If VRP can determine that the array
> -   subscript is a constant, check if it is outside valid range.  If
> -   the array subscript is a RANGE, warn if it is non-overlapping with
> -   valid range.  IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside
> -   a ADDR_EXPR.  Return  true if a warning has been issued or if
> -   no-warning is set.  */
> -
> -bool
> -array_bounds_checker::check_array_ref (location_t location, tree ref,
> -				       gimple *stmt, bool ignore_off_by_one)
> +/* Acquire the upper bound and upper bound plus one for the array
> +   reference REF and record them into UP_BOUND and UP_BOUND_P1.
> +   Set *DECL to the decl or expresssion REF refers to.
> +   FOR_ARRAY_BOUND is true when this is for array bound checking.  */
> +
> +static void
> +get_up_bounds_for_array_ref (tree ref, tree *decl,
> +			     tree *up_bound, tree *up_bound_p1,
> +			     bool for_array_bound)
>  {
> -  if (warning_suppressed_p (ref, OPT_Warray_bounds))
> -    /* Return true to have the caller prevent warnings for enclosing
> -       refs.  */
> -    return true;
> -
> -  tree low_sub = TREE_OPERAND (ref, 1);
> -  tree up_sub = low_sub;
> -  tree up_bound = array_ref_up_bound (ref);
> -
> -  /* Referenced decl if one can be determined.  */
> -  tree decl = NULL_TREE;
> -
> -  /* Set for accesses to interior zero-length arrays.  */
> -  special_array_member sam{ };
> -
> -  tree up_bound_p1;
> -
> -  if (!up_bound
> -      || TREE_CODE (up_bound) != INTEGER_CST
> -      || (warn_array_bounds < 2 && trailing_array (ref, &decl)))
> +  if (!(*up_bound)
> +      || TREE_CODE (*up_bound) != INTEGER_CST
> +      || ((for_array_bound ? (warn_array_bounds < 2) : warn_strict_flex_arrays)
> +	   && trailing_array (ref, decl)))
>      {
>        /* Accesses to trailing arrays via pointers may access storage
>  	 beyond the types array bounds.  For such arrays, or for flexible
> @@ -213,8 +195,8 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
>        if (TREE_CODE (eltsize) != INTEGER_CST
>  	  || integer_zerop (eltsize))
>  	{
> -	  up_bound = NULL_TREE;
> -	  up_bound_p1 = NULL_TREE;
> +	  *up_bound = NULL_TREE;
> +	  *up_bound_p1 = NULL_TREE;
>  	}
>        else
>  	{
> @@ -227,7 +209,8 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
>  	    {
>  	      /* Try to determine the size of the trailing array from
>  		 its initializer (if it has one).  */
> -	      if (tree refsize = component_ref_size (arg, &sam))
> +	      if (tree refsize
> +		    = component_ref_size (arg, NULL, for_array_bound))
>  		if (TREE_CODE (refsize) == INTEGER_CST)
>  		  maxbound = refsize;
>  	    }
> @@ -246,7 +229,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
>  		    {
>  		      /* Try to determine the size from a pointer to
>  			 an array if BASE is one.  */
> -		      if (tree size = get_ref_size (base, &decl))
> +		      if (tree size = get_ref_size (base, decl))
>  			maxbound = size;
>  		    }
>  		  else if (!compref && DECL_P (base))
> @@ -254,7 +237,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
>  		      if (TREE_CODE (basesize) == INTEGER_CST)
>  			{
>  			  maxbound = basesize;
> -			  decl = base;
> +			  *decl = base;
>  			}
>  
>  		  if (known_gt (off, 0))
> @@ -266,40 +249,47 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
>  	  else
>  	    maxbound = fold_convert (sizetype, maxbound);
>  
> -	  up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize);
> +	  *up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize);
>  
> -	  if (up_bound_p1 != NULL_TREE)
> -	    up_bound = int_const_binop (MINUS_EXPR, up_bound_p1,
> +	  if (*up_bound_p1 != NULL_TREE)
> +	    *up_bound = int_const_binop (MINUS_EXPR, *up_bound_p1,
>  					build_int_cst (ptrdiff_type_node, 1));
>  	  else
> -	    up_bound = NULL_TREE;
> +	    *up_bound = NULL_TREE;
>  	}
>      }
>    else
> -    up_bound_p1 = int_const_binop (PLUS_EXPR, up_bound,
> -				   build_int_cst (TREE_TYPE (up_bound), 1));
> +    *up_bound_p1 = int_const_binop (PLUS_EXPR, *up_bound,
> +				   build_int_cst (TREE_TYPE (*up_bound), 1));
> +  return;
> +}
>  
> -  tree low_bound = array_ref_low_bound (ref);
> +/* Given the LOW_SUB_ORG, LOW_SUB and UP_SUB, and the computed UP_BOUND
> +   and UP_BOUND_P1, check whether the array reference REF is out of bound.
> +   When out of bounds, issue warnings if FOR_ARRAY_BOUND is true.
> +   otherwise, return true without issue warnings.  */
>  
> +static bool
> +check_out_of_bounds_and_warn (location_t location, tree ref,
> +			      tree low_sub_org, tree low_sub, tree up_sub,
> +			      tree up_bound, tree up_bound_p1,
> +			      const value_range *vr,
> +			      bool ignore_off_by_one, bool for_array_bound)
> +{
> +  tree low_bound = array_ref_low_bound (ref);
>    tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
>  
>    bool warned = false;
>  
>    /* Empty array.  */
>    if (up_bound && tree_int_cst_equal (low_bound, up_bound_p1))
> -    warned = warning_at (location, OPT_Warray_bounds,
> -			 "array subscript %E is outside array bounds of %qT",
> -			 low_sub, artype);
> -
> -  const value_range *vr = NULL;
> -  if (TREE_CODE (low_sub) == SSA_NAME)
>      {
> -      vr = get_value_range (low_sub, stmt);
> -      if (!vr->undefined_p () && !vr->varying_p ())
> -	{
> -	  low_sub = vr->kind () == VR_RANGE ? vr->max () : vr->min ();
> -	  up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max ();
> -	}
> +      if (for_array_bound)
> +	warned = warning_at (location, OPT_Warray_bounds,
> +			     "array subscript %E is outside array"
> +			     " bounds of %qT", low_sub_org, artype);
> +      else
> +	warned = true;
>      }
>  
>    if (warned)
> @@ -313,24 +303,127 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
>  	      : tree_int_cst_le (up_bound, up_sub))
>  	  && TREE_CODE (low_sub) == INTEGER_CST
>  	  && tree_int_cst_le (low_sub, low_bound))
> -	warned = warning_at (location, OPT_Warray_bounds,
> -			     "array subscript [%E, %E] is outside "
> -			     "array bounds of %qT",
> -			     low_sub, up_sub, artype);
> +	{
> +	  if (for_array_bound)
> +	    warned = warning_at (location, OPT_Warray_bounds,
> +				 "array subscript [%E, %E] is outside "
> +				 "array bounds of %qT",
> +				 low_sub, up_sub, artype);
> +	  else
> +	    warned = true;
> +	}
>      }
>    else if (up_bound
>  	   && TREE_CODE (up_sub) == INTEGER_CST
>  	   && (ignore_off_by_one
>  	       ? !tree_int_cst_le (up_sub, up_bound_p1)
>  	       : !tree_int_cst_le (up_sub, up_bound)))
> -    warned = warning_at (location, OPT_Warray_bounds,
> -			 "array subscript %E is above array bounds of %qT",
> -			 up_sub, artype);
> +    {
> +      if (for_array_bound)
> +	warned = warning_at (location, OPT_Warray_bounds,
> +			     "array subscript %E is above array bounds of %qT",
> +			     up_sub, artype);
> +      else
> +	warned = true;
> +    }
>    else if (TREE_CODE (low_sub) == INTEGER_CST
>  	   && tree_int_cst_lt (low_sub, low_bound))
> -    warned = warning_at (location, OPT_Warray_bounds,
> -			 "array subscript %E is below array bounds of %qT",
> -			 low_sub, artype);
> +    {
> +      if (for_array_bound)
> +	warned = warning_at (location, OPT_Warray_bounds,
> +			     "array subscript %E is below array bounds of %qT",
> +			     low_sub, artype);
> +      else
> +	warned = true;
> +    }
> +  return warned;
> +}
> +
> +/* Checks one ARRAY_REF in REF, located at LOCUS.  Ignores flexible
> +   arrays and "struct" hacks.  If VRP can determine that the array
> +   subscript is a constant, check if it is outside valid range.  If
> +   the array subscript is a RANGE, warn if it is non-overlapping with
> +   valid range.  IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside
> +   a ADDR_EXPR.  Return  true if a warning has been issued or if
> +   no-warning is set.  */
> +
> +bool
> +array_bounds_checker::check_array_ref (location_t location, tree ref,
> +				       gimple *stmt, bool ignore_off_by_one)
> +{
> +  if (warning_suppressed_p (ref, OPT_Warray_bounds))
> +    /* Return true to have the caller prevent warnings for enclosing
> +       refs.  */
> +    return true;
> +
> +  /* Upper bound and Upper bound plus one for -Warray-bounds.  */
> +  tree up_bound = array_ref_up_bound (ref);
> +  tree up_bound_p1 = NULL_TREE;
> +
> +  /* Upper bound and upper bound plus one for -Wstrict-flex-array.  */
> +  tree up_bound_strict = up_bound;
> +  tree up_bound_p1_strict = NULL_TREE;
> +
> +  /* Referenced decl if one can be determined.  */
> +  tree decl = NULL_TREE;
> +
> +  /* Set to the type of the special array member for a COMPONENT_REF.  */
> +  special_array_member sam{ };
> +
> +  tree arg = TREE_OPERAND (ref, 0);
> +  const bool compref = TREE_CODE (arg) == COMPONENT_REF;
> +
> +  unsigned int strict_flex_array_level = flag_strict_flex_arrays;
> +
> +  if (compref)
> +    {
> +      /* Try to determine special array member type for this COMPONENT_REF.  */
> +      sam = component_ref_sam_type (arg);
> +      /* Get the level of strict_flex_array for this array field.  */
> +      tree afield_decl = TREE_OPERAND (arg, 1);
> +      strict_flex_array_level = strict_flex_array_level_of (afield_decl);
> +    }
> +
> +  if (warn_array_bounds)
> +    get_up_bounds_for_array_ref (ref, &decl, &up_bound, &up_bound_p1,
> +				 true);
> +  if (warn_strict_flex_arrays)
> +    get_up_bounds_for_array_ref (ref, &decl, &up_bound_strict,
> +				 &up_bound_p1_strict, false);
> +
> +
> +
> +  bool warned = false;
> +  bool out_of_bound = false;
> +
> +  tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
> +  tree low_sub_org = TREE_OPERAND (ref, 1);
> +  tree up_sub = low_sub_org;
> +  tree low_sub = low_sub_org;
> +
> +  const value_range *vr = NULL;
> +  if (TREE_CODE (low_sub_org) == SSA_NAME)
> +    {
> +      vr = get_value_range (low_sub_org, stmt);
> +      if (!vr->undefined_p () && !vr->varying_p ())
> +	{
> +	  low_sub = vr->kind () == VR_RANGE ? vr->max () : vr->min ();
> +	  up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max ();
> +	}
> +    }
> +
> +  if (warn_array_bounds)
> +    warned = check_out_of_bounds_and_warn (location, ref,
> +					   low_sub_org, low_sub, up_sub,
> +					   up_bound, up_bound_p1, vr,
> +					   ignore_off_by_one, true);
> +
> +  if (warn_strict_flex_arrays)
> +    out_of_bound = check_out_of_bounds_and_warn (location, ref,
> +						 low_sub_org, low_sub, up_sub,
> +						 up_bound_strict,
> +						 up_bound_p1_strict, vr,
> +						 ignore_off_by_one, false);
>  
>    if (!warned && sam == special_array_member::int_0)
>      warned = warning_at (location, OPT_Wzero_length_bounds,
> @@ -341,19 +434,56 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
>  			       "of an interior zero-length array %qT")),
>  			 low_sub, artype);
>  
> -  if (warned)
> +  if (warned || out_of_bound)
>      {
> -      if (dump_file && (dump_flags & TDF_DETAILS))
> +      if (warned && dump_file && (dump_flags & TDF_DETAILS))
>  	{
>  	  fprintf (dump_file, "Array bound warning for ");
>  	  dump_generic_expr (MSG_NOTE, TDF_SLIM, ref);
>  	  fprintf (dump_file, "\n");
>  	}
>  
> +      /* issue warnings for -Wstrict-flex-arrays according to the level of
> +	 flag_strict_flex_arrays.  */
> +      if (out_of_bound && warn_strict_flex_arrays)
> +	switch (strict_flex_array_level)
> +	  {
> +	    case 3:
> +	      /* Issue additional warnings for trailing arrays [0].  */
> +	      if (sam == special_array_member::trail_0)
> +		warned = warning_at (location, OPT_Wstrict_flex_arrays,
> +				     "trailing array %qT should not be used as "
> +				     "a flexible array member for level 3",
> +				     artype);
> +	      /* FALLTHROUGH.  */
> +	    case 2:
> +	      /* Issue additional warnings for trailing arrays [1].  */
> +	      if (sam == special_array_member::trail_1)
> +		warned = warning_at (location, OPT_Wstrict_flex_arrays,
> +				     "trailing array %qT should not be used as "
> +				     "a flexible array member for level 2 and "
> +				     "above", artype);
> +	      /* FALLTHROUGH.  */
> +	    case 1:
> +	      /* Issue warnings for trailing arrays [n].  */
> +	      if (sam == special_array_member::trail_n)
> +		warned = warning_at (location, OPT_Wstrict_flex_arrays,
> +				     "trailing array %qT should not be used as "
> +				     "a flexible array member for level 1 and "
> +				     "above", artype);
> +	      break;
> +	    case 0:
> +	      /* Do nothing.  */
> +	      break;
> +	    default:
> +	      gcc_unreachable ();
> +	  }
> +
>        /* Avoid more warnings when checking more significant subscripts
>  	 of the same expression.  */
>        ref = TREE_OPERAND (ref, 0);
>        suppress_warning (ref, OPT_Warray_bounds);
> +      suppress_warning (ref, OPT_Wstrict_flex_arrays);
>  
>        if (decl)
>  	ref = decl;
> diff --git a/gcc/opts.cc b/gcc/opts.cc
> index ae079fcd20e..ca162aa781c 100644
> --- a/gcc/opts.cc
> +++ b/gcc/opts.cc
> @@ -1409,6 +1409,21 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>        opts->x_profile_flag = 0;
>      }
>  
> +  if (opts->x_warn_array_bounds)
> +    if (opts->x_flag_strict_flex_arrays)
> +      {
> +	warning_at (UNKNOWN_LOCATION, 0,
> +		    "%<-Warray-bounds%> is not impacted by "
> +		    "%<-fstrict-flex-arrays%>");
> +      }
> +  if (opts->x_warn_strict_flex_arrays)
> +    if (opts->x_flag_strict_flex_arrays == 0)
> +      {
> +	opts->x_warn_strict_flex_arrays = 0;
> +	warning_at (UNKNOWN_LOCATION, 0,
> +		    "%<-Wstrict-flex-arrays%> is ignored when"
> +		    " %<-fstrict-flex-arrays%> does not present");
> +      }
>  
>    diagnose_options (opts, opts_set, loc);
>  }
> diff --git a/gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c
> new file mode 100644
> index 00000000000..72b4b7c6406
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c
> @@ -0,0 +1,9 @@
> +/* Test the usage of option -Wstrict-flex-arrays.  */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays" } */
> +
> +int main(int argc, char *argv[])
> +{
> +    return 0;
> +}
> +/* { dg-warning "is ignored when \'-fstrict-flex-arrays\' does not present" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/Wstrict-flex-arrays_2.c b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays_2.c
> new file mode 100644
> index 00000000000..af9ec922dea
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays_2.c
> @@ -0,0 +1,9 @@
> +/* Test the usage of option -Wstrict-flex-arrays.  */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -Warray-bounds -fstrict-flex-arrays" } */
> +
> +int main(int argc, char *argv[])
> +{
> +    return 0;
> +}
> +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c
> new file mode 100644
> index 00000000000..59d5a5fcb23
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c
> @@ -0,0 +1,46 @@
> +/* Test -Wstrict-flex-arrays.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=2" } */
> +
> +struct trailing_array_1 {
> +    int a;
> +    int b;
> +    int c[4]; 
> +};
> +
> +struct trailing_array_2 {
> +    int a;
> +    int b;
> +    int c[1]; 
> +};
> +
> +struct trailing_array_3 {
> +    int a;
> +    int b;
> +    int c[0];
> +};
> +struct trailing_array_4 {
> +    int a;
> +    int b;
> +    int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> +    struct trailing_array_1 *normal,
> +    struct trailing_array_2 *trailing_1,
> +    struct trailing_array_3 *trailing_0,
> +    struct trailing_array_4 *trailing_flex)
> +{
> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> +    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
> +    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> +    return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c
> new file mode 100644
> index 00000000000..2f66151e927
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c
> @@ -0,0 +1,46 @@
> +/* Test -Wstrict-flex-arrays.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=3" } */
> +
> +struct trailing_array_1 {
> +    int a;
> +    int b;
> +    int c[4]; 
> +};
> +
> +struct trailing_array_2 {
> +    int a;
> +    int b;
> +    int c[1]; 
> +};
> +
> +struct trailing_array_3 {
> +    int a;
> +    int b;
> +    int c[0];
> +};
> +struct trailing_array_4 {
> +    int a;
> +    int b;
> +    int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> +    struct trailing_array_1 *normal,
> +    struct trailing_array_2 *trailing_1,
> +    struct trailing_array_3 *trailing_0,
> +    struct trailing_array_4 *trailing_flex)
> +{
> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> +    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
> +    trailing_0->c[1] = 1; /* { dg-warning "should not be used as a flexible array member for level 3" } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 3" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> +    return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c
> new file mode 100644
> index 00000000000..6a4576568ac
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c
> @@ -0,0 +1,49 @@
> +/* Test -Wstrict-flex-arrays + -Warray-bounds.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=1 -Warray-bounds" } */
> +
> +struct trailing_array_1 {
> +    int a;
> +    int b;
> +    int c[4]; 
> +};
> +
> +struct trailing_array_2 {
> +    int a;
> +    int b;
> +    int c[1]; 
> +};
> +
> +struct trailing_array_3 {
> +    int a;
> +    int b;
> +    int c[0];
> +};
> +struct trailing_array_4 {
> +    int a;
> +    int b;
> +    int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> +    struct trailing_array_1 *normal,
> +    struct trailing_array_2 *trailing_1,
> +    struct trailing_array_3 *trailing_0,
> +    struct trailing_array_4 *trailing_flex)
> +{
> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> +    			 /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
> +    trailing_1->c[2] = 2; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> +    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> +    return 0;
> +}
> +
> +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c
> new file mode 100644
> index 00000000000..e550fbd24e1
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c
> @@ -0,0 +1,48 @@
> +/* Test -Wstrict-flex-arrays + -Warray-bounds.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=2 -Warray-bounds" } */
> +
> +struct trailing_array_1 {
> +    int a;
> +    int b;
> +    int c[4]; 
> +};
> +
> +struct trailing_array_2 {
> +    int a;
> +    int b;
> +    int c[1]; 
> +};
> +
> +struct trailing_array_3 {
> +    int a;
> +    int b;
> +    int c[0];
> +};
> +struct trailing_array_4 {
> +    int a;
> +    int b;
> +    int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> +    struct trailing_array_1 *normal,
> +    struct trailing_array_2 *trailing_1,
> +    struct trailing_array_3 *trailing_0,
> +    struct trailing_array_4 *trailing_flex)
> +{
> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> +    			 /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
> +    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
> +    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> +    return 0;
> +}
> +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c
> new file mode 100644
> index 00000000000..d5b61136b3a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c
> @@ -0,0 +1,48 @@
> +/* Test -Wstrict-flex-arrays.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=3 -Warray-bounds" } */
> +
> +struct trailing_array_1 {
> +    int a;
> +    int b;
> +    int c[4]; 
> +};
> +
> +struct trailing_array_2 {
> +    int a;
> +    int b;
> +    int c[1]; 
> +};
> +
> +struct trailing_array_3 {
> +    int a;
> +    int b;
> +    int c[0];
> +};
> +struct trailing_array_4 {
> +    int a;
> +    int b;
> +    int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> +    struct trailing_array_1 *normal,
> +    struct trailing_array_2 *trailing_1,
> +    struct trailing_array_3 *trailing_0,
> +    struct trailing_array_4 *trailing_flex)
> +{
> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> +   			/*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */ 
> +    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
> +    trailing_0->c[1] = 1; /* { dg-warning "should not be used as a flexible array member for level 3" } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 3" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> +    return 0;
> +}
> +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c
> new file mode 100644
> index 00000000000..eb82a60c261
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c
> @@ -0,0 +1,50 @@
> +/* Test -Wstrict-flex-arrays + -Warray-bounds=2.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=1 -Warray-bounds=2" } */
> +
> +struct trailing_array_1 {
> +    int a;
> +    int b;
> +    int c[4]; 
> +};
> +
> +struct trailing_array_2 {
> +    int a;
> +    int b;
> +    int c[1]; 
> +};
> +
> +struct trailing_array_3 {
> +    int a;
> +    int b;
> +    int c[0];
> +};
> +struct trailing_array_4 {
> +    int a;
> +    int b;
> +    int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> +    struct trailing_array_1 *normal,
> +    struct trailing_array_2 *trailing_1,
> +    struct trailing_array_3 *trailing_0,
> +    struct trailing_array_4 *trailing_flex)
> +{
> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> +    			 /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
> +    trailing_1->c[2] = 2; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> +    			 /*{ dg-warning "array subscript 2 is above array bounds of" "" { target *-*-* } .-1 } */
> +    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> +    return 0;
> +}
> +
> +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c
> new file mode 100644
> index 00000000000..f48a50e04f5
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c
> @@ -0,0 +1,49 @@
> +/* Test -Wstrict-flex-arrays + -Warray-bounds=2.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=2 -Warray-bounds=2" } */
> +
> +struct trailing_array_1 {
> +    int a;
> +    int b;
> +    int c[4]; 
> +};
> +
> +struct trailing_array_2 {
> +    int a;
> +    int b;
> +    int c[1]; 
> +};
> +
> +struct trailing_array_3 {
> +    int a;
> +    int b;
> +    int c[0];
> +};
> +struct trailing_array_4 {
> +    int a;
> +    int b;
> +    int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> +    struct trailing_array_1 *normal,
> +    struct trailing_array_2 *trailing_1,
> +    struct trailing_array_3 *trailing_0,
> +    struct trailing_array_4 *trailing_flex)
> +{
> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> +    			 /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
> +    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
> +    			  /*{ dg-warning "array subscript 2 is above array bounds of" "" { target *-*-* } .-1 } */
> +    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> +    return 0;
> +}
> +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c
> new file mode 100644
> index 00000000000..9f2877ef4e1
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c
> @@ -0,0 +1,49 @@
> +/* Test -Wstrict-flex-arrays + -Warray-bounds=2.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=3 -Warray-bounds=2" } */
> +
> +struct trailing_array_1 {
> +    int a;
> +    int b;
> +    int c[4]; 
> +};
> +
> +struct trailing_array_2 {
> +    int a;
> +    int b;
> +    int c[1]; 
> +};
> +
> +struct trailing_array_3 {
> +    int a;
> +    int b;
> +    int c[0];
> +};
> +struct trailing_array_4 {
> +    int a;
> +    int b;
> +    int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> +    struct trailing_array_1 *normal,
> +    struct trailing_array_2 *trailing_1,
> +    struct trailing_array_3 *trailing_0,
> +    struct trailing_array_4 *trailing_flex)
> +{
> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> +   			/*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */ 
> +    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
> +    			/*{ dg-warning "array subscript 2 is above array bounds of" "" { target *-*-* } .-1 } */
> +    trailing_0->c[1] = 1; /* { dg-warning "should not be used as a flexible array member for level 3" } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 3" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> +    return 0;
> +}
> +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c
> new file mode 100644
> index 00000000000..43a9098f138
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c
> @@ -0,0 +1,46 @@
> +/* Test -Wstrict-flex-arrays.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=1" } */
> +
> +struct trailing_array_1 {
> +    int a;
> +    int b;
> +    int c[4]; 
> +};
> +
> +struct trailing_array_2 {
> +    int a;
> +    int b;
> +    int c[1]; 
> +};
> +
> +struct trailing_array_3 {
> +    int a;
> +    int b;
> +    int c[0];
> +};
> +struct trailing_array_4 {
> +    int a;
> +    int b;
> +    int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> +    struct trailing_array_1 *normal,
> +    struct trailing_array_2 *trailing_1,
> +    struct trailing_array_3 *trailing_0,
> +    struct trailing_array_4 *trailing_flex)
> +{
> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> +    trailing_1->c[2] = 2; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> +    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> +    return 0;
> +}
> diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
> index e5a292bb875..1f1b56c1a52 100644
> --- a/gcc/tree-vrp.cc
> +++ b/gcc/tree-vrp.cc
> @@ -4229,12 +4229,12 @@ execute_vrp (struct function *fun, bool warn_array_bounds_p)
>       the flag on every edge now, rather than in
>       check_array_bounds_dom_walker's ctor; vrp_folder may clear
>       it from some edges.  */
> -  if (warn_array_bounds && warn_array_bounds_p)
> +  if ((warn_array_bounds || warn_strict_flex_arrays) && warn_array_bounds_p)
>      set_all_edges_as_executable (fun);
>  
>    folder.substitute_and_fold ();
>  
> -  if (warn_array_bounds && warn_array_bounds_p)
> +  if ((warn_array_bounds || warn_strict_flex_arrays) && warn_array_bounds_p)
>      {
>        array_bounds_checker array_checker (fun, &vrp_vr_values);
>        array_checker.check ();
> @@ -4353,7 +4353,7 @@ execute_ranger_vrp (struct function *fun, bool warn_array_bounds_p)
>    if (dump_file && (dump_flags & TDF_DETAILS))
>      ranger->dump (dump_file);
>  
> -  if (warn_array_bounds && warn_array_bounds_p)
> +  if ((warn_array_bounds || warn_strict_flex_arrays) && warn_array_bounds_p)
>      {
>        // Set all edges as executable, except those ranger says aren't.
>        int non_exec_flag = ranger->non_executable_edge_flag;
> diff --git a/gcc/tree.cc b/gcc/tree.cc
> index d2b0b34a725..0f5f7151b6b 100644
> --- a/gcc/tree.cc
> +++ b/gcc/tree.cc
> @@ -12726,15 +12726,21 @@ array_ref_up_bound (tree exp)
>     int test (uint8_t *p, uint32_t t[1][1], int n) {
>     for (int i = 0; i < 4; i++, p++)
>       t[i][0] = ...;
> +
> +   If non-null, set IS_TRAILING_ARRAY to true if the ref is the above case A.
>  */
>  
>  bool
> -array_ref_flexible_size_p (tree ref)
> +array_ref_flexible_size_p (tree ref, bool *is_trailing_array /* = NULL */)
>  {
> -  /* the TYPE for this array referece.  */
> +  /* The TYPE for this array referece.  */
>    tree atype = NULL_TREE;
> -  /* the FIELD_DECL for the array field in the containing structure.  */
> +  /* The FIELD_DECL for the array field in the containing structure.  */
>    tree afield_decl = NULL_TREE;
> +  /* Whether this array is the trailing array of a structure.  */
> +  bool is_trailing_array_tmp = false;
> +  if (!is_trailing_array)
> +    is_trailing_array = &is_trailing_array_tmp;
>  
>    if (TREE_CODE (ref) == ARRAY_REF
>        || TREE_CODE (ref) == ARRAY_RANGE_REF)
> @@ -12822,7 +12828,10 @@ array_ref_flexible_size_p (tree ref)
>    if (! TYPE_SIZE (atype)
>        || ! TYPE_DOMAIN (atype)
>        || ! TYPE_MAX_VALUE (TYPE_DOMAIN (atype)))
> -    return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> +    {
> +      *is_trailing_array = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
> +      return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> +    }
>  
>    /* If the reference is based on a declared entity, the size of the array
>       is constrained by its given domain.  (Do not trust commons PR/69368).  */
> @@ -12844,9 +12853,17 @@ array_ref_flexible_size_p (tree ref)
>        if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (atype))) != INTEGER_CST
>  	  || TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST
>            || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST)
> -	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> +	{
> +	  *is_trailing_array
> +	    = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
> +	  return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> +	}
>        if (! get_addr_base_and_unit_offset (ref_to_array, &offset))
> -	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> +	{
> +	  *is_trailing_array
> +	    = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
> +	  return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> +	}
>  
>        /* If at least one extra element fits it is a flexarray.  */
>        if (known_le ((wi::to_offset (TYPE_MAX_VALUE (TYPE_DOMAIN (atype)))
> @@ -12854,11 +12871,16 @@ array_ref_flexible_size_p (tree ref)
>  		     + 2)
>  		    * wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (atype))),
>  		    wi::to_offset (DECL_SIZE_UNIT (ref)) - offset))
> -	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> +	{
> +	  *is_trailing_array
> +	    = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
> +	  return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> +	}
>  
>        return false;
>      }
>  
> +  *is_trailing_array = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
>    return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>  }
>  
> @@ -12920,24 +12942,81 @@ get_initializer_for (tree init, tree decl)
>    return NULL_TREE;
>  }
>  
> +/* Determines the special array member type for the array reference REF.  */
> +special_array_member
> +component_ref_sam_type (tree ref)
> +{
> +  special_array_member sam_type = special_array_member::none;
> +
> +  tree member = TREE_OPERAND (ref, 1);
> +  tree memsize = DECL_SIZE_UNIT (member);
> +  if (memsize)
> +    {
> +      tree memtype = TREE_TYPE (member);
> +      if (TREE_CODE (memtype) != ARRAY_TYPE)
> +	return sam_type;
> +
> +      bool trailing = false;
> +      (void)array_ref_flexible_size_p (ref, &trailing);
> +      bool zero_length = integer_zerop (memsize);
> +      if (!trailing && !zero_length)
> +	/* MEMBER is an interior array with
> +	  more than one element.  */
> +	return special_array_member::int_n;
> +
> +      if (zero_length)
> +	{
> +	  if (trailing)
> +	    return special_array_member::trail_0;
> +	  else
> +	    return special_array_member::int_0;
> +	}
> +
> +      if (!zero_length)
> +	if (tree dom = TYPE_DOMAIN (memtype))
> +	  if (tree min = TYPE_MIN_VALUE (dom))
> +	    if (tree max = TYPE_MAX_VALUE (dom))
> +	      if (TREE_CODE (min) == INTEGER_CST
> +		  && TREE_CODE (max) == INTEGER_CST)
> +		{
> +		  offset_int minidx = wi::to_offset (min);
> +		  offset_int maxidx = wi::to_offset (max);
> +		  offset_int neltsm1 = maxidx - minidx;
> +		  if (neltsm1 > 0)
> +		    /* MEMBER is a trailing array with more than
> +		       one elements.  */
> +		    return special_array_member::trail_n;
> +
> +		  if (neltsm1 == 0)
> +		    return special_array_member::trail_1;
> +		}
> +    }
> +
> +  return sam_type;
> +}
> +
>  /* Determines the size of the member referenced by the COMPONENT_REF
>     REF, using its initializer expression if necessary in order to
>     determine the size of an initialized flexible array member.
> -   If non-null, set *ARK when REF refers to an interior zero-length
> +   If non-null, set *SAM when REF refers to an interior zero-length
>     array or a trailing one-element array.
>     Returns the size as sizetype (which might be zero for an object
>     with an uninitialized flexible array member) or null if the size
> -   cannot be determined.  */
> +   cannot be determined.
> +   when FOR_ARRAY_BOUND_CHECK is true, this routine is called for
> +   -Warray-bounds check only, due to historical reason, the LEVEL
> +   of -Warray-bounds=LEVEL is not controled by -fstrict-flex-arrays.  */
>  
>  tree
> -component_ref_size (tree ref, special_array_member *sam /* = NULL */)
> +component_ref_size (tree ref, special_array_member *sam /* = NULL */,
> +		    bool for_array_bound_check /* = FALSE */)
>  {
>    gcc_assert (TREE_CODE (ref) == COMPONENT_REF);
>  
>    special_array_member sambuf;
>    if (!sam)
>      sam = &sambuf;
> -  *sam = special_array_member::none;
> +  *sam = component_ref_sam_type (ref);
>  
>    /* The object/argument referenced by the COMPONENT_REF and its type.  */
>    tree arg = TREE_OPERAND (ref, 0);
> @@ -12958,41 +13037,49 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */)
>  	return (tree_int_cst_equal (memsize, TYPE_SIZE_UNIT (memtype))
>  		? memsize : NULL_TREE);
>  
> -      bool trailing = array_ref_flexible_size_p (ref);
> -      bool zero_length = integer_zerop (memsize);
> -      if (!trailing && !zero_length)
> -	/* MEMBER is either an interior array or is an array with
> -	   more than one element.  */
> +      /* 2-or-more elements arrays are treated as normal arrays by default.  */
> +      if (*sam == special_array_member::int_n
> +	  || *sam == special_array_member::trail_n)
>  	return memsize;
>  
> -      if (zero_length)
> +      /* For -Warray-bounds=LEVEL check, historically we have to treat
> +	 trail_0 and trail_1 as flexible arrays by default when LEVEL=1.
> +	 for other cases, flag_strict_flex_arrays will control how to treat
> +	 the trailing arrays as flexiable array members.  */
> +
> +      tree afield_decl = TREE_OPERAND (ref, 1);
> +      unsigned int strict_flex_array_level
> +	= strict_flex_array_level_of (afield_decl);
> +
> +      if (!for_array_bound_check)
>  	{
> -	  if (trailing)
> -	    *sam = special_array_member::trail_0;
> -	  else
> +	  switch (strict_flex_array_level)
>  	    {
> -	      *sam = special_array_member::int_0;
> -	      memsize = NULL_TREE;
> +	      case 3:
> +		/* Treaing 0-length trailing arrays as normal array.  */
> +		if (*sam == special_array_member::trail_0)
> +		  return size_zero_node;
> +		/* FALLTHROUGH.  */
> +	      case 2:
> +		/* Treating 1-element trailing arrays as normal array.  */
> +		if (*sam == special_array_member::trail_1)
> +		  return memsize;
> +		/* FALLTHROUGH.  */
> +	      case 1:
> +		/* Treating 2-or-more elements trailing arrays as normal
> +		   array.  */
> +		if (*sam == special_array_member::trail_n)
> +		  return memsize;
> +		/* FALLTHROUGH.  */
> +	      case 0:
> +		break;
> +	      default:
> +		gcc_unreachable ();
>  	    }
>  	}
>  
> -      if (!zero_length)
> -	if (tree dom = TYPE_DOMAIN (memtype))
> -	  if (tree min = TYPE_MIN_VALUE (dom))
> -	    if (tree max = TYPE_MAX_VALUE (dom))
> -	      if (TREE_CODE (min) == INTEGER_CST
> -		  && TREE_CODE (max) == INTEGER_CST)
> -		{
> -		  offset_int minidx = wi::to_offset (min);
> -		  offset_int maxidx = wi::to_offset (max);
> -		  offset_int neltsm1 = maxidx - minidx;
> -		  if (neltsm1 > 0)
> -		    /* MEMBER is an array with more than one element.  */
> -		    return memsize;
> -
> -		  if (neltsm1 == 0)
> -		    *sam = special_array_member::trail_1;
> -		}
> +	if (*sam == special_array_member::int_0)
> +	  memsize = NULL_TREE;
>  
>        /* For a reference to a zero- or one-element array member of a union
>  	 use the size of the union instead of the size of the member.  */
> diff --git a/gcc/tree.h b/gcc/tree.h
> index 0fcdd6b06d0..f81a1f6efa1 100644
> --- a/gcc/tree.h
> +++ b/gcc/tree.h
> @@ -5551,28 +5551,33 @@ extern tree array_ref_low_bound (tree);
>  /* Returns true if REF is an array reference, a component reference,
>     or a memory reference to an array whose actual size might be larger
>     than its upper bound implies.  */
> -extern bool array_ref_flexible_size_p (tree);
> +extern bool array_ref_flexible_size_p (tree, bool * = NULL);
>  
>  /* Return a tree representing the offset, in bytes, of the field referenced
>     by EXP.  This does not include any offset in DECL_FIELD_BIT_OFFSET.  */
>  extern tree component_ref_field_offset (tree);
>  
> -/* Describes a "special" array member due to which component_ref_size
> -   returns null.  */
> +/* Describes a "special" array member for a COMPONENT_REF.  */
>  enum struct special_array_member
>    {
>      none,	/* Not a special array member.  */
>      int_0,	/* Interior array member with size zero.  */
>      trail_0,	/* Trailing array member with size zero.  */
> -    trail_1	/* Trailing array member with one element.  */
> +    trail_1,	/* Trailing array member with one element.  */
> +    trail_n,	/* Trailing array member with two or more elements.  */
> +    int_n	/* Interior array member with one or more elements.  */
>    };
>  
> +/* Determines the special array member type for a COMPONENT_REF.  */
> +extern special_array_member component_ref_sam_type (tree);
> +
>  /* Return the size of the member referenced by the COMPONENT_REF, using
>     its initializer expression if necessary in order to determine the size
>     of an initialized flexible array member.  The size might be zero for
>     an object with an uninitialized flexible array member or null if it
>     cannot be determined.  */
> -extern tree component_ref_size (tree, special_array_member * = NULL);
> +extern tree component_ref_size (tree, special_array_member * = NULL,
> +				bool = false);
>  
>  extern int tree_map_base_eq (const void *, const void *);
>  extern unsigned int tree_map_base_hash (const void *);
> 

-- 
Richard Biener <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] 15+ messages in thread

* Re: [PATCH 2/2] Add a new warning option -Wstrict-flex-arrays.
  2022-11-18 13:14   ` Richard Biener
@ 2022-11-18 15:19     ` Qing Zhao
  2022-11-18 16:31       ` Kees Cook
  0 siblings, 1 reply; 15+ messages in thread
From: Qing Zhao @ 2022-11-18 15:19 UTC (permalink / raw)
  To: Richard Biener; +Cc: joseph, gcc Patches, keescook, siddhesh

Hi, Richard,

Honestly, it’s very hard for me to decide what’s the best way to handle the interaction 
between -fstrict-flex-array=M and -Warray-bounds=N. 

Ideally,  -fstrict-flex-array=M should completely control the behavior of -Warray-bounds.
If possible, I prefer this solution.

However, -Warray-bounds is included in -Wall, and has been used extensively for a long time.
It’s not safe to change its default behavior. 

So, I guess that the bottom-line for this work is:

Keeping the default behavior of -Warray-bounds.

Is this correct understanding?


> On Nov 18, 2022, at 8:14 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Tue, 8 Nov 2022, Qing Zhao wrote:
> 
>> '-Wstrict-flex-arrays'
>>     Warn about inproper usages of flexible array members according to
>>     the LEVEL of the 'strict_flex_array (LEVEL)' attribute attached to
>>     the trailing array field of a structure if it's available,
>>     otherwise according to the LEVEL of the option
>>     '-fstrict-flex-arrays=LEVEL'.
>> 
>>     This option is effective only when LEVEL is bigger than 0.
>>     Otherwise, it will be ignored with a warning.
>> 
>>     when LEVEL=1, warnings will be issued for a trailing array
>>     reference of a structure that have 2 or more elements if the
>>     trailing array is referenced as a flexible array member.
>> 
>>     when LEVEL=2, in addition to LEVEL=1, additional warnings will be
>>     issued for a trailing one-element array reference of a structure if
>>     the array is referenced as a flexible array member.
>> 
>>     when LEVEL=3, in addition to LEVEL=2, additional warnings will be
>>     issued for a trailing zero-length array reference of a structure if
>>     the array is referenced as a flexible array member.
>> 
>> At the same time, keep -Warray-bounds=[1|2] warnings unchanged from
>> -fstrict-flex-arrays.
> 
> Looking at this, is this a way to avoid interpreting -Warray-bounds=N
> together with -fstrict-flex-arrays=M?  Won't this be just confusing to
> users?  Especially since -Wall includes -Warray-bounds and thus we'll
> diagnose
> 
> +  if (opts->x_warn_array_bounds)
> +    if (opts->x_flag_strict_flex_arrays)
> +      {
> +       warning_at (UNKNOWN_LOCATION, 0,
> +                   "%<-Warray-bounds%> is not impacted by "
> +                   "%<-fstrict-flex-arrays%>");
> +      }
> 
> and do that even when -Wstrict-flex-arrays is given?

The basic idea here is:   -Warray-bounds=N will NOT be controlled by -fstrict-flex-array=M at all.
And the new -Wstrict-flex-array will be used to report warnings for different level of “M”. 

> 
> Would it be better/possible to add a note: to existing -Warray-bounds
> diagnostics on how the behavior is altered by -fstrict-flex-arrays?

If -Warray-bounds does not have the additional level “N” argument. It’s reasonable and natural for it to be controlled 
by the level of -fstrict-flex-arrays. 
> 
> I guess this will inevitably re-iterate the -fstrict-flex-arrays=N
> vs. -Warray-bounds=M discussion ...

Yes, that’s the most confusion and challenge part for this work… and took me a lot of thinking but still cannot
 find the best way to handle it…..
> 
> I think it would be better to stick with -Warray-bounds and flex
> its =2 mode to work according to -fstrict-flex-arrays=N instead of
> "out of bounds accesses to trailing struct members of one-element array 
> types" (thus, not add [1] but instead the cases that are not flex 
> arrays according to -fstrict-flex-arrays).

From my understanding, you suggested the following:

1. Keep -Warray-bounds default behavior.
    i.e. when -Warray-bounds=1, it’s behavior will not be impacted by -fstrict-flex-array=M

2. When -Warray-bounds=2,  it’s behavior will be controlled by -fstrict-flex-array=M


Is the above understanding correct?

If yes, then the major question is:

When -Warray-bounds=2, -fstrict-flex-array = 0 or 1,2,  i.e, when the level of -fstrict-flex-array is lower or equal to 2. 
 [0] and [1] will be treated as flexible array member by -fstrict-flex-array, it’s conflict with how -Warray-bounds=2’s 
behavior on treating flexible array members.  Under such situation, which one has higher priority?


I have another idea now:

1. Keep -Warray-bounds=1 default behavior. 
2. Change the behavior of -Warray-bounds=2 from:

Current:
-Warray-bounds=2
This warning level also warns about out of bounds accesses to trailing struct members of one-element array types (see Zero Length) and about the intermediate results of pointer arithmetic that may yield out of bounds values. This warning level may give a larger number of false positives and is deactivated by default.

New:
-Warray-bounds=2
This warning level also warns  about the intermediate results of pointer arithmetic that may yield out of bounds values. This warning level may give a larger number of false positives and is deactivated by default.

i.e, delete the control on flexible array member from the level of -Warray-bounds. 

3. Use -fstrict-flex-array to control how the -Warray-bounds treat the tailing array as flexible array member? 

Is this better?

thanks.

Qing

> 
> Richard.
> 
>> gcc/ChangeLog:
>> 
>> 	* attribs.cc (strict_flex_array_level_of): New function.
>> 	* attribs.h (strict_flex_array_level_of): Prototype for new function.
>> 	* doc/invoke.texi: Document -Wstrict-flex-arrays option. Update
>> 	-fstrict-flex-arrays[=n] options.
>> 	* gimple-array-bounds.cc (array_bounds_checker::check_array_ref):
>> 	Issue warnings for -Wstrict-flex-arrays.
>> 	(get_up_bounds_for_array_ref): New function.
>> 	(check_out_of_bounds_and_warn): New function.
>> 	* opts.cc (finish_options): Issue warnings for unsupported combination
>> 	of -Warray-bounds and -fstrict-flex-arrays, -Wstrict_flex_arrays and
>> 	-fstrict-flex-array.
>> 	* tree-vrp.cc (execute_vrp): Enable the pass when
>> 	warn_strict_flex_array is true.
>> 	(execute_ranger_vrp): Likewise.
>> 	* tree.cc (array_ref_flexible_size_p): Add one new argument.
>> 	(component_ref_sam_type): New function.
>> 	(component_ref_size): Add one new argument,
>> 	* tree.h (array_ref_flexible_size_p): Update prototype.
>> 	(enum struct special_array_member): Add two new enum values.
>> 	(component_ref_sam_type): New prototype.
>> 	(component_ref_size): Update prototype.
>> 
>> gcc/c-family/ChangeLog:
>> 
>> 	* c.opt (Wstrict-flex-arrays): New option.
>> 
>> gcc/c/ChangeLog:
>> 
>> 	* c-decl.cc (is_flexible_array_member_p): Call new function
>> 	strict_flex_array_level_of.
>> 
>> gcc/testsuite/ChangeLog:
>> 
>> 	* c-c++-common/Wstrict-flex-arrays.c: New test.
>> 	* c-c++-common/Wstrict-flex-arrays_2.c: New test.
>> 	* gcc.dg/Wstrict-flex-arrays-2.c: New test.
>> 	* gcc.dg/Wstrict-flex-arrays-3.c: New test.
>> 	* gcc.dg/Wstrict-flex-arrays-4.c: New test.
>> 	* gcc.dg/Wstrict-flex-arrays-5.c: New test.
>> 	* gcc.dg/Wstrict-flex-arrays-6.c: New test.
>> 	* gcc.dg/Wstrict-flex-arrays-7.c: New test.
>> 	* gcc.dg/Wstrict-flex-arrays-8.c: New test.
>> 	* gcc.dg/Wstrict-flex-arrays-9.c: New test.
>> 	* gcc.dg/Wstrict-flex-arrays.c: New test.
>> ---
>> gcc/attribs.cc                                |  30 ++
>> gcc/attribs.h                                 |   2 +
>> gcc/c-family/c.opt                            |   5 +
>> gcc/c/c-decl.cc                               |  22 +-
>> gcc/doc/invoke.texi                           |  33 ++-
>> gcc/gimple-array-bounds.cc                    | 264 +++++++++++++-----
>> gcc/opts.cc                                   |  15 +
>> .../c-c++-common/Wstrict-flex-arrays.c        |   9 +
>> .../c-c++-common/Wstrict-flex-arrays_2.c      |   9 +
>> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c  |  46 +++
>> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c  |  46 +++
>> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c  |  49 ++++
>> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c  |  48 ++++
>> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c  |  48 ++++
>> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c  |  50 ++++
>> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c  |  49 ++++
>> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c  |  49 ++++
>> gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c    |  46 +++
>> gcc/tree-vrp.cc                               |   6 +-
>> gcc/tree.cc                                   | 165 ++++++++---
>> gcc/tree.h                                    |  15 +-
>> 21 files changed, 870 insertions(+), 136 deletions(-)
>> create mode 100644 gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c
>> create mode 100644 gcc/testsuite/c-c++-common/Wstrict-flex-arrays_2.c
>> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c
>> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c
>> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c
>> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c
>> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c
>> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c
>> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c
>> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c
>> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c
>> 
>> diff --git a/gcc/attribs.cc b/gcc/attribs.cc
>> index 27dea748561..095def4d6b0 100644
>> --- a/gcc/attribs.cc
>> +++ b/gcc/attribs.cc
>> @@ -2456,6 +2456,36 @@ init_attr_rdwr_indices (rdwr_map *rwm, tree attrs)
>>     }
>> }
>> 
>> +/* Get the LEVEL of the strict_flex_array for the ARRAY_FIELD based on the
>> +   values of attribute strict_flex_array and the flag_strict_flex_arrays.  */
>> +unsigned int
>> +strict_flex_array_level_of (tree array_field)
>> +{
>> +  gcc_assert (TREE_CODE (array_field) == FIELD_DECL);
>> +  unsigned int strict_flex_array_level = flag_strict_flex_arrays;
>> +
>> +  tree attr_strict_flex_array
>> +    = lookup_attribute ("strict_flex_array", DECL_ATTRIBUTES (array_field));
>> +  /* If there is a strict_flex_array attribute attached to the field,
>> +     override the flag_strict_flex_arrays.  */
>> +  if (attr_strict_flex_array)
>> +    {
>> +      /* Get the value of the level first from the attribute.  */
>> +      unsigned HOST_WIDE_INT attr_strict_flex_array_level = 0;
>> +      gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
>> +      attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
>> +      gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
>> +      attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
>> +      gcc_assert (tree_fits_uhwi_p (attr_strict_flex_array));
>> +      attr_strict_flex_array_level = tree_to_uhwi (attr_strict_flex_array);
>> +
>> +      /* The attribute has higher priority than flag_struct_flex_array.  */
>> +      strict_flex_array_level = attr_strict_flex_array_level;
>> +    }
>> +  return strict_flex_array_level;
>> +}
>> +
>> +
>> /* Return the access specification for a function parameter PARM
>>    or null if the current function has no such specification.  */
>> 
>> diff --git a/gcc/attribs.h b/gcc/attribs.h
>> index 1dc16e4bc4e..742811e6fda 100644
>> --- a/gcc/attribs.h
>> +++ b/gcc/attribs.h
>> @@ -398,4 +398,6 @@ extern void init_attr_rdwr_indices (rdwr_map *, tree);
>> extern attr_access *get_parm_access (rdwr_map &, tree,
>> 				     tree = current_function_decl);
>> 
>> +extern unsigned int strict_flex_array_level_of (tree);
>> +
>> #endif // GCC_ATTRIBS_H
>> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
>> index 01d480759ae..bc33710a649 100644
>> --- a/gcc/c-family/c.opt
>> +++ b/gcc/c-family/c.opt
>> @@ -968,6 +968,11 @@ Wstringop-truncation
>> C ObjC C++ LTO ObjC++ Var(warn_stringop_truncation) Warning Init (1) LangEnabledBy(C ObjC C++ LTO ObjC++, Wall)
>> Warn about truncation in string manipulation functions like strncat and strncpy.
>> 
>> +Wstrict-flex-arrays
>> +C C++ Var(warn_strict_flex_arrays) Warning
>> +Warn about inproper usages of flexible array members
>> +according to the level of -fstrict-flex-arrays.
>> +
>> Wsuggest-attribute=format
>> C ObjC C++ ObjC++ Var(warn_suggest_attribute_format) Warning
>> Warn about functions which might be candidates for format attributes.
>> diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
>> index 4746e310d2d..c9cb46daacc 100644
>> --- a/gcc/c/c-decl.cc
>> +++ b/gcc/c/c-decl.cc
>> @@ -8828,7 +8828,6 @@ finish_incomplete_vars (tree incomplete_vars, bool toplevel)
>>     }
>> }
>> 
>> -
>> /* Determine whether the FIELD_DECL X is a flexible array member according to
>>    the following info:
>>   A. whether the FIELD_DECL X is the last field of the DECL_CONTEXT;
>> @@ -8855,26 +8854,7 @@ is_flexible_array_member_p (bool is_last_field,
>>   bool is_one_element_array = one_element_array_type_p (TREE_TYPE (x));
>>   bool is_flexible_array = flexible_array_member_type_p (TREE_TYPE (x));
>> 
>> -  unsigned int strict_flex_array_level = flag_strict_flex_arrays;
>> -
>> -  tree attr_strict_flex_array = lookup_attribute ("strict_flex_array",
>> -						  DECL_ATTRIBUTES (x));
>> -  /* If there is a strict_flex_array attribute attached to the field,
>> -     override the flag_strict_flex_arrays.  */
>> -  if (attr_strict_flex_array)
>> -    {
>> -      /* Get the value of the level first from the attribute.  */
>> -      unsigned HOST_WIDE_INT attr_strict_flex_array_level = 0;
>> -      gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
>> -      attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
>> -      gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
>> -      attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
>> -      gcc_assert (tree_fits_uhwi_p (attr_strict_flex_array));
>> -      attr_strict_flex_array_level = tree_to_uhwi (attr_strict_flex_array);
>> -
>> -      /* The attribute has higher priority than flag_struct_flex_array.  */
>> -      strict_flex_array_level = attr_strict_flex_array_level;
>> -    }
>> +  unsigned int strict_flex_array_level = strict_flex_array_level_of (x);
>> 
>>   switch (strict_flex_array_level)
>>     {
>> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
>> index 64f77e8367a..a35e6bf27e0 100644
>> --- a/gcc/doc/invoke.texi
>> +++ b/gcc/doc/invoke.texi
>> @@ -397,7 +397,7 @@ Objective-C and Objective-C++ Dialects}.
>> -Wstrict-aliasing=n  -Wstrict-overflow  -Wstrict-overflow=@var{n} @gol
>> -Wstring-compare @gol
>> -Wno-stringop-overflow -Wno-stringop-overread @gol
>> --Wno-stringop-truncation @gol
>> +-Wno-stringop-truncation -Wstrict-flex-arrays @gol
>> -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{|}malloc@r{]} @gol
>> -Wswitch  -Wno-switch-bool  -Wswitch-default  -Wswitch-enum @gol
>> -Wno-switch-outside-range  -Wno-switch-unreachable  -Wsync-nand @gol
>> @@ -2848,12 +2848,18 @@ The negative form is equivalent to @option{-fstrict-flex-arrays=0}, which is the
>> least strict.  All trailing arrays of structures are treated as flexible array
>> members.
>> 
>> +This option is not compatible with @option{-Warray-bounds} due to historical
>> +reason.  The behavior of @option{-Warray-bounds} is not changed by this option.
>> +
>> @item -fstrict-flex-arrays=@var{level}
>> @opindex fstrict-flex-arrays=@var{level}
>> Control when to treat the trailing array of a structure as a flexible array
>> member for the purpose of accessing the elements of such an array.  The value
>> of @var{level} controls the level of strictness.
>> 
>> +This option is not compatible with @option{-Warray-bounds} due to historical
>> +reason.  The behavior of @option{-Warray-bounds} is not changed by this option.
>> +
>> The possible values of @var{level} are the same as for the
>> @code{strict_flex_array} attribute (@pxref{Variable Attributes}).
>> 
>> @@ -7662,6 +7668,31 @@ however, are not suitable arguments to functions that expect
>> such arrays GCC issues warnings unless it can prove that the use is
>> safe.  @xref{Common Variable Attributes}.
>> 
>> +@item -Wstrict-flex-arrays
>> +@opindex Wstrict-flex-arrays
>> +@opindex Wno-strict-flex-arrays
>> +Warn about inproper usages of flexible array members
>> +according to the @var{level} of the @code{strict_flex_array (@var{level})}
>> +attribute attached to the trailing array field of a structure if it's
>> +available, otherwise according to the @var{level} of the option
>> +@option{-fstrict-flex-arrays=@var{level}}.
>> +
>> +This option is effective only when @var{level} is bigger than 0.  Otherwise,
>> +it will be ignored with a warning.
>> +
>> +when @var{level}=1, warnings will be issued for a trailing array reference
>> +of a structure that have 2 or more elements if the trailing array is referenced
>> +as a flexible array member.
>> +
>> +when @var{level}=2, in addition to @var{level}=1, additional warnings will be
>> +issued for a trailing one-element array reference of a structure
>> +if the array is referenced as a flexible array member.
>> +
>> +when @var{level}=3, in addition to @var{level}=2, additional warnings will be
>> +issued for a trailing zero-length array reference of a structure
>> +if the array is referenced as a flexible array member.
>> +
>> +
>> @item -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{|}cold@r{|}malloc@r{]}
>> @opindex Wsuggest-attribute=
>> @opindex Wno-suggest-attribute=
>> diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc
>> index fbf448e045d..7f790c5a19a 100644
>> --- a/gcc/gimple-array-bounds.cc
>> +++ b/gcc/gimple-array-bounds.cc
>> @@ -170,38 +170,20 @@ trailing_array (tree arg, tree *pref)
>>   return array_ref_flexible_size_p (arg);
>> }
>> 
>> -/* Checks one ARRAY_REF in REF, located at LOCUS. Ignores flexible
>> -   arrays and "struct" hacks. If VRP can determine that the array
>> -   subscript is a constant, check if it is outside valid range.  If
>> -   the array subscript is a RANGE, warn if it is non-overlapping with
>> -   valid range.  IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside
>> -   a ADDR_EXPR.  Return  true if a warning has been issued or if
>> -   no-warning is set.  */
>> -
>> -bool
>> -array_bounds_checker::check_array_ref (location_t location, tree ref,
>> -				       gimple *stmt, bool ignore_off_by_one)
>> +/* Acquire the upper bound and upper bound plus one for the array
>> +   reference REF and record them into UP_BOUND and UP_BOUND_P1.
>> +   Set *DECL to the decl or expresssion REF refers to.
>> +   FOR_ARRAY_BOUND is true when this is for array bound checking.  */
>> +
>> +static void
>> +get_up_bounds_for_array_ref (tree ref, tree *decl,
>> +			     tree *up_bound, tree *up_bound_p1,
>> +			     bool for_array_bound)
>> {
>> -  if (warning_suppressed_p (ref, OPT_Warray_bounds))
>> -    /* Return true to have the caller prevent warnings for enclosing
>> -       refs.  */
>> -    return true;
>> -
>> -  tree low_sub = TREE_OPERAND (ref, 1);
>> -  tree up_sub = low_sub;
>> -  tree up_bound = array_ref_up_bound (ref);
>> -
>> -  /* Referenced decl if one can be determined.  */
>> -  tree decl = NULL_TREE;
>> -
>> -  /* Set for accesses to interior zero-length arrays.  */
>> -  special_array_member sam{ };
>> -
>> -  tree up_bound_p1;
>> -
>> -  if (!up_bound
>> -      || TREE_CODE (up_bound) != INTEGER_CST
>> -      || (warn_array_bounds < 2 && trailing_array (ref, &decl)))
>> +  if (!(*up_bound)
>> +      || TREE_CODE (*up_bound) != INTEGER_CST
>> +      || ((for_array_bound ? (warn_array_bounds < 2) : warn_strict_flex_arrays)
>> +	   && trailing_array (ref, decl)))
>>     {
>>       /* Accesses to trailing arrays via pointers may access storage
>> 	 beyond the types array bounds.  For such arrays, or for flexible
>> @@ -213,8 +195,8 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
>>       if (TREE_CODE (eltsize) != INTEGER_CST
>> 	  || integer_zerop (eltsize))
>> 	{
>> -	  up_bound = NULL_TREE;
>> -	  up_bound_p1 = NULL_TREE;
>> +	  *up_bound = NULL_TREE;
>> +	  *up_bound_p1 = NULL_TREE;
>> 	}
>>       else
>> 	{
>> @@ -227,7 +209,8 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
>> 	    {
>> 	      /* Try to determine the size of the trailing array from
>> 		 its initializer (if it has one).  */
>> -	      if (tree refsize = component_ref_size (arg, &sam))
>> +	      if (tree refsize
>> +		    = component_ref_size (arg, NULL, for_array_bound))
>> 		if (TREE_CODE (refsize) == INTEGER_CST)
>> 		  maxbound = refsize;
>> 	    }
>> @@ -246,7 +229,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
>> 		    {
>> 		      /* Try to determine the size from a pointer to
>> 			 an array if BASE is one.  */
>> -		      if (tree size = get_ref_size (base, &decl))
>> +		      if (tree size = get_ref_size (base, decl))
>> 			maxbound = size;
>> 		    }
>> 		  else if (!compref && DECL_P (base))
>> @@ -254,7 +237,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
>> 		      if (TREE_CODE (basesize) == INTEGER_CST)
>> 			{
>> 			  maxbound = basesize;
>> -			  decl = base;
>> +			  *decl = base;
>> 			}
>> 
>> 		  if (known_gt (off, 0))
>> @@ -266,40 +249,47 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
>> 	  else
>> 	    maxbound = fold_convert (sizetype, maxbound);
>> 
>> -	  up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize);
>> +	  *up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize);
>> 
>> -	  if (up_bound_p1 != NULL_TREE)
>> -	    up_bound = int_const_binop (MINUS_EXPR, up_bound_p1,
>> +	  if (*up_bound_p1 != NULL_TREE)
>> +	    *up_bound = int_const_binop (MINUS_EXPR, *up_bound_p1,
>> 					build_int_cst (ptrdiff_type_node, 1));
>> 	  else
>> -	    up_bound = NULL_TREE;
>> +	    *up_bound = NULL_TREE;
>> 	}
>>     }
>>   else
>> -    up_bound_p1 = int_const_binop (PLUS_EXPR, up_bound,
>> -				   build_int_cst (TREE_TYPE (up_bound), 1));
>> +    *up_bound_p1 = int_const_binop (PLUS_EXPR, *up_bound,
>> +				   build_int_cst (TREE_TYPE (*up_bound), 1));
>> +  return;
>> +}
>> 
>> -  tree low_bound = array_ref_low_bound (ref);
>> +/* Given the LOW_SUB_ORG, LOW_SUB and UP_SUB, and the computed UP_BOUND
>> +   and UP_BOUND_P1, check whether the array reference REF is out of bound.
>> +   When out of bounds, issue warnings if FOR_ARRAY_BOUND is true.
>> +   otherwise, return true without issue warnings.  */
>> 
>> +static bool
>> +check_out_of_bounds_and_warn (location_t location, tree ref,
>> +			      tree low_sub_org, tree low_sub, tree up_sub,
>> +			      tree up_bound, tree up_bound_p1,
>> +			      const value_range *vr,
>> +			      bool ignore_off_by_one, bool for_array_bound)
>> +{
>> +  tree low_bound = array_ref_low_bound (ref);
>>   tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
>> 
>>   bool warned = false;
>> 
>>   /* Empty array.  */
>>   if (up_bound && tree_int_cst_equal (low_bound, up_bound_p1))
>> -    warned = warning_at (location, OPT_Warray_bounds,
>> -			 "array subscript %E is outside array bounds of %qT",
>> -			 low_sub, artype);
>> -
>> -  const value_range *vr = NULL;
>> -  if (TREE_CODE (low_sub) == SSA_NAME)
>>     {
>> -      vr = get_value_range (low_sub, stmt);
>> -      if (!vr->undefined_p () && !vr->varying_p ())
>> -	{
>> -	  low_sub = vr->kind () == VR_RANGE ? vr->max () : vr->min ();
>> -	  up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max ();
>> -	}
>> +      if (for_array_bound)
>> +	warned = warning_at (location, OPT_Warray_bounds,
>> +			     "array subscript %E is outside array"
>> +			     " bounds of %qT", low_sub_org, artype);
>> +      else
>> +	warned = true;
>>     }
>> 
>>   if (warned)
>> @@ -313,24 +303,127 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
>> 	      : tree_int_cst_le (up_bound, up_sub))
>> 	  && TREE_CODE (low_sub) == INTEGER_CST
>> 	  && tree_int_cst_le (low_sub, low_bound))
>> -	warned = warning_at (location, OPT_Warray_bounds,
>> -			     "array subscript [%E, %E] is outside "
>> -			     "array bounds of %qT",
>> -			     low_sub, up_sub, artype);
>> +	{
>> +	  if (for_array_bound)
>> +	    warned = warning_at (location, OPT_Warray_bounds,
>> +				 "array subscript [%E, %E] is outside "
>> +				 "array bounds of %qT",
>> +				 low_sub, up_sub, artype);
>> +	  else
>> +	    warned = true;
>> +	}
>>     }
>>   else if (up_bound
>> 	   && TREE_CODE (up_sub) == INTEGER_CST
>> 	   && (ignore_off_by_one
>> 	       ? !tree_int_cst_le (up_sub, up_bound_p1)
>> 	       : !tree_int_cst_le (up_sub, up_bound)))
>> -    warned = warning_at (location, OPT_Warray_bounds,
>> -			 "array subscript %E is above array bounds of %qT",
>> -			 up_sub, artype);
>> +    {
>> +      if (for_array_bound)
>> +	warned = warning_at (location, OPT_Warray_bounds,
>> +			     "array subscript %E is above array bounds of %qT",
>> +			     up_sub, artype);
>> +      else
>> +	warned = true;
>> +    }
>>   else if (TREE_CODE (low_sub) == INTEGER_CST
>> 	   && tree_int_cst_lt (low_sub, low_bound))
>> -    warned = warning_at (location, OPT_Warray_bounds,
>> -			 "array subscript %E is below array bounds of %qT",
>> -			 low_sub, artype);
>> +    {
>> +      if (for_array_bound)
>> +	warned = warning_at (location, OPT_Warray_bounds,
>> +			     "array subscript %E is below array bounds of %qT",
>> +			     low_sub, artype);
>> +      else
>> +	warned = true;
>> +    }
>> +  return warned;
>> +}
>> +
>> +/* Checks one ARRAY_REF in REF, located at LOCUS.  Ignores flexible
>> +   arrays and "struct" hacks.  If VRP can determine that the array
>> +   subscript is a constant, check if it is outside valid range.  If
>> +   the array subscript is a RANGE, warn if it is non-overlapping with
>> +   valid range.  IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside
>> +   a ADDR_EXPR.  Return  true if a warning has been issued or if
>> +   no-warning is set.  */
>> +
>> +bool
>> +array_bounds_checker::check_array_ref (location_t location, tree ref,
>> +				       gimple *stmt, bool ignore_off_by_one)
>> +{
>> +  if (warning_suppressed_p (ref, OPT_Warray_bounds))
>> +    /* Return true to have the caller prevent warnings for enclosing
>> +       refs.  */
>> +    return true;
>> +
>> +  /* Upper bound and Upper bound plus one for -Warray-bounds.  */
>> +  tree up_bound = array_ref_up_bound (ref);
>> +  tree up_bound_p1 = NULL_TREE;
>> +
>> +  /* Upper bound and upper bound plus one for -Wstrict-flex-array.  */
>> +  tree up_bound_strict = up_bound;
>> +  tree up_bound_p1_strict = NULL_TREE;
>> +
>> +  /* Referenced decl if one can be determined.  */
>> +  tree decl = NULL_TREE;
>> +
>> +  /* Set to the type of the special array member for a COMPONENT_REF.  */
>> +  special_array_member sam{ };
>> +
>> +  tree arg = TREE_OPERAND (ref, 0);
>> +  const bool compref = TREE_CODE (arg) == COMPONENT_REF;
>> +
>> +  unsigned int strict_flex_array_level = flag_strict_flex_arrays;
>> +
>> +  if (compref)
>> +    {
>> +      /* Try to determine special array member type for this COMPONENT_REF.  */
>> +      sam = component_ref_sam_type (arg);
>> +      /* Get the level of strict_flex_array for this array field.  */
>> +      tree afield_decl = TREE_OPERAND (arg, 1);
>> +      strict_flex_array_level = strict_flex_array_level_of (afield_decl);
>> +    }
>> +
>> +  if (warn_array_bounds)
>> +    get_up_bounds_for_array_ref (ref, &decl, &up_bound, &up_bound_p1,
>> +				 true);
>> +  if (warn_strict_flex_arrays)
>> +    get_up_bounds_for_array_ref (ref, &decl, &up_bound_strict,
>> +				 &up_bound_p1_strict, false);
>> +
>> +
>> +
>> +  bool warned = false;
>> +  bool out_of_bound = false;
>> +
>> +  tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
>> +  tree low_sub_org = TREE_OPERAND (ref, 1);
>> +  tree up_sub = low_sub_org;
>> +  tree low_sub = low_sub_org;
>> +
>> +  const value_range *vr = NULL;
>> +  if (TREE_CODE (low_sub_org) == SSA_NAME)
>> +    {
>> +      vr = get_value_range (low_sub_org, stmt);
>> +      if (!vr->undefined_p () && !vr->varying_p ())
>> +	{
>> +	  low_sub = vr->kind () == VR_RANGE ? vr->max () : vr->min ();
>> +	  up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max ();
>> +	}
>> +    }
>> +
>> +  if (warn_array_bounds)
>> +    warned = check_out_of_bounds_and_warn (location, ref,
>> +					   low_sub_org, low_sub, up_sub,
>> +					   up_bound, up_bound_p1, vr,
>> +					   ignore_off_by_one, true);
>> +
>> +  if (warn_strict_flex_arrays)
>> +    out_of_bound = check_out_of_bounds_and_warn (location, ref,
>> +						 low_sub_org, low_sub, up_sub,
>> +						 up_bound_strict,
>> +						 up_bound_p1_strict, vr,
>> +						 ignore_off_by_one, false);
>> 
>>   if (!warned && sam == special_array_member::int_0)
>>     warned = warning_at (location, OPT_Wzero_length_bounds,
>> @@ -341,19 +434,56 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
>> 			       "of an interior zero-length array %qT")),
>> 			 low_sub, artype);
>> 
>> -  if (warned)
>> +  if (warned || out_of_bound)
>>     {
>> -      if (dump_file && (dump_flags & TDF_DETAILS))
>> +      if (warned && dump_file && (dump_flags & TDF_DETAILS))
>> 	{
>> 	  fprintf (dump_file, "Array bound warning for ");
>> 	  dump_generic_expr (MSG_NOTE, TDF_SLIM, ref);
>> 	  fprintf (dump_file, "\n");
>> 	}
>> 
>> +      /* issue warnings for -Wstrict-flex-arrays according to the level of
>> +	 flag_strict_flex_arrays.  */
>> +      if (out_of_bound && warn_strict_flex_arrays)
>> +	switch (strict_flex_array_level)
>> +	  {
>> +	    case 3:
>> +	      /* Issue additional warnings for trailing arrays [0].  */
>> +	      if (sam == special_array_member::trail_0)
>> +		warned = warning_at (location, OPT_Wstrict_flex_arrays,
>> +				     "trailing array %qT should not be used as "
>> +				     "a flexible array member for level 3",
>> +				     artype);
>> +	      /* FALLTHROUGH.  */
>> +	    case 2:
>> +	      /* Issue additional warnings for trailing arrays [1].  */
>> +	      if (sam == special_array_member::trail_1)
>> +		warned = warning_at (location, OPT_Wstrict_flex_arrays,
>> +				     "trailing array %qT should not be used as "
>> +				     "a flexible array member for level 2 and "
>> +				     "above", artype);
>> +	      /* FALLTHROUGH.  */
>> +	    case 1:
>> +	      /* Issue warnings for trailing arrays [n].  */
>> +	      if (sam == special_array_member::trail_n)
>> +		warned = warning_at (location, OPT_Wstrict_flex_arrays,
>> +				     "trailing array %qT should not be used as "
>> +				     "a flexible array member for level 1 and "
>> +				     "above", artype);
>> +	      break;
>> +	    case 0:
>> +	      /* Do nothing.  */
>> +	      break;
>> +	    default:
>> +	      gcc_unreachable ();
>> +	  }
>> +
>>       /* Avoid more warnings when checking more significant subscripts
>> 	 of the same expression.  */
>>       ref = TREE_OPERAND (ref, 0);
>>       suppress_warning (ref, OPT_Warray_bounds);
>> +      suppress_warning (ref, OPT_Wstrict_flex_arrays);
>> 
>>       if (decl)
>> 	ref = decl;
>> diff --git a/gcc/opts.cc b/gcc/opts.cc
>> index ae079fcd20e..ca162aa781c 100644
>> --- a/gcc/opts.cc
>> +++ b/gcc/opts.cc
>> @@ -1409,6 +1409,21 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>>       opts->x_profile_flag = 0;
>>     }
>> 
>> +  if (opts->x_warn_array_bounds)
>> +    if (opts->x_flag_strict_flex_arrays)
>> +      {
>> +	warning_at (UNKNOWN_LOCATION, 0,
>> +		    "%<-Warray-bounds%> is not impacted by "
>> +		    "%<-fstrict-flex-arrays%>");
>> +      }
>> +  if (opts->x_warn_strict_flex_arrays)
>> +    if (opts->x_flag_strict_flex_arrays == 0)
>> +      {
>> +	opts->x_warn_strict_flex_arrays = 0;
>> +	warning_at (UNKNOWN_LOCATION, 0,
>> +		    "%<-Wstrict-flex-arrays%> is ignored when"
>> +		    " %<-fstrict-flex-arrays%> does not present");
>> +      }
>> 
>>   diagnose_options (opts, opts_set, loc);
>> }
>> diff --git a/gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c
>> new file mode 100644
>> index 00000000000..72b4b7c6406
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c
>> @@ -0,0 +1,9 @@
>> +/* Test the usage of option -Wstrict-flex-arrays.  */
>> +/* { dg-do compile } */
>> +/* { dg-options "-O2 -Wstrict-flex-arrays" } */
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    return 0;
>> +}
>> +/* { dg-warning "is ignored when \'-fstrict-flex-arrays\' does not present" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/c-c++-common/Wstrict-flex-arrays_2.c b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays_2.c
>> new file mode 100644
>> index 00000000000..af9ec922dea
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays_2.c
>> @@ -0,0 +1,9 @@
>> +/* Test the usage of option -Wstrict-flex-arrays.  */
>> +/* { dg-do compile } */
>> +/* { dg-options "-O2 -Warray-bounds -fstrict-flex-arrays" } */
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    return 0;
>> +}
>> +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c
>> new file mode 100644
>> index 00000000000..59d5a5fcb23
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c
>> @@ -0,0 +1,46 @@
>> +/* Test -Wstrict-flex-arrays.  */
>> +/* { dg-do run } */
>> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=2" } */
>> +
>> +struct trailing_array_1 {
>> +    int a;
>> +    int b;
>> +    int c[4]; 
>> +};
>> +
>> +struct trailing_array_2 {
>> +    int a;
>> +    int b;
>> +    int c[1]; 
>> +};
>> +
>> +struct trailing_array_3 {
>> +    int a;
>> +    int b;
>> +    int c[0];
>> +};
>> +struct trailing_array_4 {
>> +    int a;
>> +    int b;
>> +    int c[];
>> +};
>> +
>> +void __attribute__((__noinline__)) stuff(
>> +    struct trailing_array_1 *normal,
>> +    struct trailing_array_2 *trailing_1,
>> +    struct trailing_array_3 *trailing_0,
>> +    struct trailing_array_4 *trailing_flex)
>> +{
>> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
>> +    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
>> +    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
>> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
>> +
>> +}
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
>> +
>> +    return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c
>> new file mode 100644
>> index 00000000000..2f66151e927
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c
>> @@ -0,0 +1,46 @@
>> +/* Test -Wstrict-flex-arrays.  */
>> +/* { dg-do run } */
>> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=3" } */
>> +
>> +struct trailing_array_1 {
>> +    int a;
>> +    int b;
>> +    int c[4]; 
>> +};
>> +
>> +struct trailing_array_2 {
>> +    int a;
>> +    int b;
>> +    int c[1]; 
>> +};
>> +
>> +struct trailing_array_3 {
>> +    int a;
>> +    int b;
>> +    int c[0];
>> +};
>> +struct trailing_array_4 {
>> +    int a;
>> +    int b;
>> +    int c[];
>> +};
>> +
>> +void __attribute__((__noinline__)) stuff(
>> +    struct trailing_array_1 *normal,
>> +    struct trailing_array_2 *trailing_1,
>> +    struct trailing_array_3 *trailing_0,
>> +    struct trailing_array_4 *trailing_flex)
>> +{
>> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
>> +    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
>> +    trailing_0->c[1] = 1; /* { dg-warning "should not be used as a flexible array member for level 3" } */
>> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 3" } */
>> +
>> +}
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
>> +
>> +    return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c
>> new file mode 100644
>> index 00000000000..6a4576568ac
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c
>> @@ -0,0 +1,49 @@
>> +/* Test -Wstrict-flex-arrays + -Warray-bounds.  */
>> +/* { dg-do run } */
>> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=1 -Warray-bounds" } */
>> +
>> +struct trailing_array_1 {
>> +    int a;
>> +    int b;
>> +    int c[4]; 
>> +};
>> +
>> +struct trailing_array_2 {
>> +    int a;
>> +    int b;
>> +    int c[1]; 
>> +};
>> +
>> +struct trailing_array_3 {
>> +    int a;
>> +    int b;
>> +    int c[0];
>> +};
>> +struct trailing_array_4 {
>> +    int a;
>> +    int b;
>> +    int c[];
>> +};
>> +
>> +void __attribute__((__noinline__)) stuff(
>> +    struct trailing_array_1 *normal,
>> +    struct trailing_array_2 *trailing_1,
>> +    struct trailing_array_3 *trailing_0,
>> +    struct trailing_array_4 *trailing_flex)
>> +{
>> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
>> +    			 /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
>> +    trailing_1->c[2] = 2; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
>> +    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
>> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
>> +
>> +}
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
>> +
>> +    return 0;
>> +}
>> +
>> +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c
>> new file mode 100644
>> index 00000000000..e550fbd24e1
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c
>> @@ -0,0 +1,48 @@
>> +/* Test -Wstrict-flex-arrays + -Warray-bounds.  */
>> +/* { dg-do run } */
>> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=2 -Warray-bounds" } */
>> +
>> +struct trailing_array_1 {
>> +    int a;
>> +    int b;
>> +    int c[4]; 
>> +};
>> +
>> +struct trailing_array_2 {
>> +    int a;
>> +    int b;
>> +    int c[1]; 
>> +};
>> +
>> +struct trailing_array_3 {
>> +    int a;
>> +    int b;
>> +    int c[0];
>> +};
>> +struct trailing_array_4 {
>> +    int a;
>> +    int b;
>> +    int c[];
>> +};
>> +
>> +void __attribute__((__noinline__)) stuff(
>> +    struct trailing_array_1 *normal,
>> +    struct trailing_array_2 *trailing_1,
>> +    struct trailing_array_3 *trailing_0,
>> +    struct trailing_array_4 *trailing_flex)
>> +{
>> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
>> +    			 /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
>> +    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
>> +    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
>> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
>> +
>> +}
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
>> +
>> +    return 0;
>> +}
>> +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c
>> new file mode 100644
>> index 00000000000..d5b61136b3a
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c
>> @@ -0,0 +1,48 @@
>> +/* Test -Wstrict-flex-arrays.  */
>> +/* { dg-do run } */
>> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=3 -Warray-bounds" } */
>> +
>> +struct trailing_array_1 {
>> +    int a;
>> +    int b;
>> +    int c[4]; 
>> +};
>> +
>> +struct trailing_array_2 {
>> +    int a;
>> +    int b;
>> +    int c[1]; 
>> +};
>> +
>> +struct trailing_array_3 {
>> +    int a;
>> +    int b;
>> +    int c[0];
>> +};
>> +struct trailing_array_4 {
>> +    int a;
>> +    int b;
>> +    int c[];
>> +};
>> +
>> +void __attribute__((__noinline__)) stuff(
>> +    struct trailing_array_1 *normal,
>> +    struct trailing_array_2 *trailing_1,
>> +    struct trailing_array_3 *trailing_0,
>> +    struct trailing_array_4 *trailing_flex)
>> +{
>> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
>> +   			/*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */ 
>> +    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
>> +    trailing_0->c[1] = 1; /* { dg-warning "should not be used as a flexible array member for level 3" } */
>> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 3" } */
>> +
>> +}
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
>> +
>> +    return 0;
>> +}
>> +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c
>> new file mode 100644
>> index 00000000000..eb82a60c261
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c
>> @@ -0,0 +1,50 @@
>> +/* Test -Wstrict-flex-arrays + -Warray-bounds=2.  */
>> +/* { dg-do run } */
>> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=1 -Warray-bounds=2" } */
>> +
>> +struct trailing_array_1 {
>> +    int a;
>> +    int b;
>> +    int c[4]; 
>> +};
>> +
>> +struct trailing_array_2 {
>> +    int a;
>> +    int b;
>> +    int c[1]; 
>> +};
>> +
>> +struct trailing_array_3 {
>> +    int a;
>> +    int b;
>> +    int c[0];
>> +};
>> +struct trailing_array_4 {
>> +    int a;
>> +    int b;
>> +    int c[];
>> +};
>> +
>> +void __attribute__((__noinline__)) stuff(
>> +    struct trailing_array_1 *normal,
>> +    struct trailing_array_2 *trailing_1,
>> +    struct trailing_array_3 *trailing_0,
>> +    struct trailing_array_4 *trailing_flex)
>> +{
>> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
>> +    			 /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
>> +    trailing_1->c[2] = 2; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
>> +    			 /*{ dg-warning "array subscript 2 is above array bounds of" "" { target *-*-* } .-1 } */
>> +    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
>> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
>> +
>> +}
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
>> +
>> +    return 0;
>> +}
>> +
>> +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c
>> new file mode 100644
>> index 00000000000..f48a50e04f5
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c
>> @@ -0,0 +1,49 @@
>> +/* Test -Wstrict-flex-arrays + -Warray-bounds=2.  */
>> +/* { dg-do run } */
>> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=2 -Warray-bounds=2" } */
>> +
>> +struct trailing_array_1 {
>> +    int a;
>> +    int b;
>> +    int c[4]; 
>> +};
>> +
>> +struct trailing_array_2 {
>> +    int a;
>> +    int b;
>> +    int c[1]; 
>> +};
>> +
>> +struct trailing_array_3 {
>> +    int a;
>> +    int b;
>> +    int c[0];
>> +};
>> +struct trailing_array_4 {
>> +    int a;
>> +    int b;
>> +    int c[];
>> +};
>> +
>> +void __attribute__((__noinline__)) stuff(
>> +    struct trailing_array_1 *normal,
>> +    struct trailing_array_2 *trailing_1,
>> +    struct trailing_array_3 *trailing_0,
>> +    struct trailing_array_4 *trailing_flex)
>> +{
>> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
>> +    			 /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
>> +    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
>> +    			  /*{ dg-warning "array subscript 2 is above array bounds of" "" { target *-*-* } .-1 } */
>> +    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
>> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
>> +
>> +}
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
>> +
>> +    return 0;
>> +}
>> +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c
>> new file mode 100644
>> index 00000000000..9f2877ef4e1
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c
>> @@ -0,0 +1,49 @@
>> +/* Test -Wstrict-flex-arrays + -Warray-bounds=2.  */
>> +/* { dg-do run } */
>> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=3 -Warray-bounds=2" } */
>> +
>> +struct trailing_array_1 {
>> +    int a;
>> +    int b;
>> +    int c[4]; 
>> +};
>> +
>> +struct trailing_array_2 {
>> +    int a;
>> +    int b;
>> +    int c[1]; 
>> +};
>> +
>> +struct trailing_array_3 {
>> +    int a;
>> +    int b;
>> +    int c[0];
>> +};
>> +struct trailing_array_4 {
>> +    int a;
>> +    int b;
>> +    int c[];
>> +};
>> +
>> +void __attribute__((__noinline__)) stuff(
>> +    struct trailing_array_1 *normal,
>> +    struct trailing_array_2 *trailing_1,
>> +    struct trailing_array_3 *trailing_0,
>> +    struct trailing_array_4 *trailing_flex)
>> +{
>> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
>> +   			/*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */ 
>> +    trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
>> +    			/*{ dg-warning "array subscript 2 is above array bounds of" "" { target *-*-* } .-1 } */
>> +    trailing_0->c[1] = 1; /* { dg-warning "should not be used as a flexible array member for level 3" } */
>> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 3" } */
>> +
>> +}
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
>> +
>> +    return 0;
>> +}
>> +/* { dg-warning "\'-Warray-bounds\' is not impacted by \'-fstrict-flex-arrays\'" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c
>> new file mode 100644
>> index 00000000000..43a9098f138
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c
>> @@ -0,0 +1,46 @@
>> +/* Test -Wstrict-flex-arrays.  */
>> +/* { dg-do run } */
>> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=1" } */
>> +
>> +struct trailing_array_1 {
>> +    int a;
>> +    int b;
>> +    int c[4]; 
>> +};
>> +
>> +struct trailing_array_2 {
>> +    int a;
>> +    int b;
>> +    int c[1]; 
>> +};
>> +
>> +struct trailing_array_3 {
>> +    int a;
>> +    int b;
>> +    int c[0];
>> +};
>> +struct trailing_array_4 {
>> +    int a;
>> +    int b;
>> +    int c[];
>> +};
>> +
>> +void __attribute__((__noinline__)) stuff(
>> +    struct trailing_array_1 *normal,
>> +    struct trailing_array_2 *trailing_1,
>> +    struct trailing_array_3 *trailing_0,
>> +    struct trailing_array_4 *trailing_flex)
>> +{
>> +    normal->c[5] = 5; 	/*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
>> +    trailing_1->c[2] = 2; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
>> +    trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
>> +    trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
>> +
>> +}
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
>> +
>> +    return 0;
>> +}
>> diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
>> index e5a292bb875..1f1b56c1a52 100644
>> --- a/gcc/tree-vrp.cc
>> +++ b/gcc/tree-vrp.cc
>> @@ -4229,12 +4229,12 @@ execute_vrp (struct function *fun, bool warn_array_bounds_p)
>>      the flag on every edge now, rather than in
>>      check_array_bounds_dom_walker's ctor; vrp_folder may clear
>>      it from some edges.  */
>> -  if (warn_array_bounds && warn_array_bounds_p)
>> +  if ((warn_array_bounds || warn_strict_flex_arrays) && warn_array_bounds_p)
>>     set_all_edges_as_executable (fun);
>> 
>>   folder.substitute_and_fold ();
>> 
>> -  if (warn_array_bounds && warn_array_bounds_p)
>> +  if ((warn_array_bounds || warn_strict_flex_arrays) && warn_array_bounds_p)
>>     {
>>       array_bounds_checker array_checker (fun, &vrp_vr_values);
>>       array_checker.check ();
>> @@ -4353,7 +4353,7 @@ execute_ranger_vrp (struct function *fun, bool warn_array_bounds_p)
>>   if (dump_file && (dump_flags & TDF_DETAILS))
>>     ranger->dump (dump_file);
>> 
>> -  if (warn_array_bounds && warn_array_bounds_p)
>> +  if ((warn_array_bounds || warn_strict_flex_arrays) && warn_array_bounds_p)
>>     {
>>       // Set all edges as executable, except those ranger says aren't.
>>       int non_exec_flag = ranger->non_executable_edge_flag;
>> diff --git a/gcc/tree.cc b/gcc/tree.cc
>> index d2b0b34a725..0f5f7151b6b 100644
>> --- a/gcc/tree.cc
>> +++ b/gcc/tree.cc
>> @@ -12726,15 +12726,21 @@ array_ref_up_bound (tree exp)
>>    int test (uint8_t *p, uint32_t t[1][1], int n) {
>>    for (int i = 0; i < 4; i++, p++)
>>      t[i][0] = ...;
>> +
>> +   If non-null, set IS_TRAILING_ARRAY to true if the ref is the above case A.
>> */
>> 
>> bool
>> -array_ref_flexible_size_p (tree ref)
>> +array_ref_flexible_size_p (tree ref, bool *is_trailing_array /* = NULL */)
>> {
>> -  /* the TYPE for this array referece.  */
>> +  /* The TYPE for this array referece.  */
>>   tree atype = NULL_TREE;
>> -  /* the FIELD_DECL for the array field in the containing structure.  */
>> +  /* The FIELD_DECL for the array field in the containing structure.  */
>>   tree afield_decl = NULL_TREE;
>> +  /* Whether this array is the trailing array of a structure.  */
>> +  bool is_trailing_array_tmp = false;
>> +  if (!is_trailing_array)
>> +    is_trailing_array = &is_trailing_array_tmp;
>> 
>>   if (TREE_CODE (ref) == ARRAY_REF
>>       || TREE_CODE (ref) == ARRAY_RANGE_REF)
>> @@ -12822,7 +12828,10 @@ array_ref_flexible_size_p (tree ref)
>>   if (! TYPE_SIZE (atype)
>>       || ! TYPE_DOMAIN (atype)
>>       || ! TYPE_MAX_VALUE (TYPE_DOMAIN (atype)))
>> -    return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>> +    {
>> +      *is_trailing_array = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
>> +      return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>> +    }
>> 
>>   /* If the reference is based on a declared entity, the size of the array
>>      is constrained by its given domain.  (Do not trust commons PR/69368).  */
>> @@ -12844,9 +12853,17 @@ array_ref_flexible_size_p (tree ref)
>>       if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (atype))) != INTEGER_CST
>> 	  || TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST
>>           || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST)
>> -	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>> +	{
>> +	  *is_trailing_array
>> +	    = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
>> +	  return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>> +	}
>>       if (! get_addr_base_and_unit_offset (ref_to_array, &offset))
>> -	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>> +	{
>> +	  *is_trailing_array
>> +	    = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
>> +	  return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>> +	}
>> 
>>       /* If at least one extra element fits it is a flexarray.  */
>>       if (known_le ((wi::to_offset (TYPE_MAX_VALUE (TYPE_DOMAIN (atype)))
>> @@ -12854,11 +12871,16 @@ array_ref_flexible_size_p (tree ref)
>> 		     + 2)
>> 		    * wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (atype))),
>> 		    wi::to_offset (DECL_SIZE_UNIT (ref)) - offset))
>> -	return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>> +	{
>> +	  *is_trailing_array
>> +	    = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
>> +	  return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>> +	}
>> 
>>       return false;
>>     }
>> 
>> +  *is_trailing_array = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
>>   return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
>> }
>> 
>> @@ -12920,24 +12942,81 @@ get_initializer_for (tree init, tree decl)
>>   return NULL_TREE;
>> }
>> 
>> +/* Determines the special array member type for the array reference REF.  */
>> +special_array_member
>> +component_ref_sam_type (tree ref)
>> +{
>> +  special_array_member sam_type = special_array_member::none;
>> +
>> +  tree member = TREE_OPERAND (ref, 1);
>> +  tree memsize = DECL_SIZE_UNIT (member);
>> +  if (memsize)
>> +    {
>> +      tree memtype = TREE_TYPE (member);
>> +      if (TREE_CODE (memtype) != ARRAY_TYPE)
>> +	return sam_type;
>> +
>> +      bool trailing = false;
>> +      (void)array_ref_flexible_size_p (ref, &trailing);
>> +      bool zero_length = integer_zerop (memsize);
>> +      if (!trailing && !zero_length)
>> +	/* MEMBER is an interior array with
>> +	  more than one element.  */
>> +	return special_array_member::int_n;
>> +
>> +      if (zero_length)
>> +	{
>> +	  if (trailing)
>> +	    return special_array_member::trail_0;
>> +	  else
>> +	    return special_array_member::int_0;
>> +	}
>> +
>> +      if (!zero_length)
>> +	if (tree dom = TYPE_DOMAIN (memtype))
>> +	  if (tree min = TYPE_MIN_VALUE (dom))
>> +	    if (tree max = TYPE_MAX_VALUE (dom))
>> +	      if (TREE_CODE (min) == INTEGER_CST
>> +		  && TREE_CODE (max) == INTEGER_CST)
>> +		{
>> +		  offset_int minidx = wi::to_offset (min);
>> +		  offset_int maxidx = wi::to_offset (max);
>> +		  offset_int neltsm1 = maxidx - minidx;
>> +		  if (neltsm1 > 0)
>> +		    /* MEMBER is a trailing array with more than
>> +		       one elements.  */
>> +		    return special_array_member::trail_n;
>> +
>> +		  if (neltsm1 == 0)
>> +		    return special_array_member::trail_1;
>> +		}
>> +    }
>> +
>> +  return sam_type;
>> +}
>> +
>> /* Determines the size of the member referenced by the COMPONENT_REF
>>    REF, using its initializer expression if necessary in order to
>>    determine the size of an initialized flexible array member.
>> -   If non-null, set *ARK when REF refers to an interior zero-length
>> +   If non-null, set *SAM when REF refers to an interior zero-length
>>    array or a trailing one-element array.
>>    Returns the size as sizetype (which might be zero for an object
>>    with an uninitialized flexible array member) or null if the size
>> -   cannot be determined.  */
>> +   cannot be determined.
>> +   when FOR_ARRAY_BOUND_CHECK is true, this routine is called for
>> +   -Warray-bounds check only, due to historical reason, the LEVEL
>> +   of -Warray-bounds=LEVEL is not controled by -fstrict-flex-arrays.  */
>> 
>> tree
>> -component_ref_size (tree ref, special_array_member *sam /* = NULL */)
>> +component_ref_size (tree ref, special_array_member *sam /* = NULL */,
>> +		    bool for_array_bound_check /* = FALSE */)
>> {
>>   gcc_assert (TREE_CODE (ref) == COMPONENT_REF);
>> 
>>   special_array_member sambuf;
>>   if (!sam)
>>     sam = &sambuf;
>> -  *sam = special_array_member::none;
>> +  *sam = component_ref_sam_type (ref);
>> 
>>   /* The object/argument referenced by the COMPONENT_REF and its type.  */
>>   tree arg = TREE_OPERAND (ref, 0);
>> @@ -12958,41 +13037,49 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */)
>> 	return (tree_int_cst_equal (memsize, TYPE_SIZE_UNIT (memtype))
>> 		? memsize : NULL_TREE);
>> 
>> -      bool trailing = array_ref_flexible_size_p (ref);
>> -      bool zero_length = integer_zerop (memsize);
>> -      if (!trailing && !zero_length)
>> -	/* MEMBER is either an interior array or is an array with
>> -	   more than one element.  */
>> +      /* 2-or-more elements arrays are treated as normal arrays by default.  */
>> +      if (*sam == special_array_member::int_n
>> +	  || *sam == special_array_member::trail_n)
>> 	return memsize;
>> 
>> -      if (zero_length)
>> +      /* For -Warray-bounds=LEVEL check, historically we have to treat
>> +	 trail_0 and trail_1 as flexible arrays by default when LEVEL=1.
>> +	 for other cases, flag_strict_flex_arrays will control how to treat
>> +	 the trailing arrays as flexiable array members.  */
>> +
>> +      tree afield_decl = TREE_OPERAND (ref, 1);
>> +      unsigned int strict_flex_array_level
>> +	= strict_flex_array_level_of (afield_decl);
>> +
>> +      if (!for_array_bound_check)
>> 	{
>> -	  if (trailing)
>> -	    *sam = special_array_member::trail_0;
>> -	  else
>> +	  switch (strict_flex_array_level)
>> 	    {
>> -	      *sam = special_array_member::int_0;
>> -	      memsize = NULL_TREE;
>> +	      case 3:
>> +		/* Treaing 0-length trailing arrays as normal array.  */
>> +		if (*sam == special_array_member::trail_0)
>> +		  return size_zero_node;
>> +		/* FALLTHROUGH.  */
>> +	      case 2:
>> +		/* Treating 1-element trailing arrays as normal array.  */
>> +		if (*sam == special_array_member::trail_1)
>> +		  return memsize;
>> +		/* FALLTHROUGH.  */
>> +	      case 1:
>> +		/* Treating 2-or-more elements trailing arrays as normal
>> +		   array.  */
>> +		if (*sam == special_array_member::trail_n)
>> +		  return memsize;
>> +		/* FALLTHROUGH.  */
>> +	      case 0:
>> +		break;
>> +	      default:
>> +		gcc_unreachable ();
>> 	    }
>> 	}
>> 
>> -      if (!zero_length)
>> -	if (tree dom = TYPE_DOMAIN (memtype))
>> -	  if (tree min = TYPE_MIN_VALUE (dom))
>> -	    if (tree max = TYPE_MAX_VALUE (dom))
>> -	      if (TREE_CODE (min) == INTEGER_CST
>> -		  && TREE_CODE (max) == INTEGER_CST)
>> -		{
>> -		  offset_int minidx = wi::to_offset (min);
>> -		  offset_int maxidx = wi::to_offset (max);
>> -		  offset_int neltsm1 = maxidx - minidx;
>> -		  if (neltsm1 > 0)
>> -		    /* MEMBER is an array with more than one element.  */
>> -		    return memsize;
>> -
>> -		  if (neltsm1 == 0)
>> -		    *sam = special_array_member::trail_1;
>> -		}
>> +	if (*sam == special_array_member::int_0)
>> +	  memsize = NULL_TREE;
>> 
>>       /* For a reference to a zero- or one-element array member of a union
>> 	 use the size of the union instead of the size of the member.  */
>> diff --git a/gcc/tree.h b/gcc/tree.h
>> index 0fcdd6b06d0..f81a1f6efa1 100644
>> --- a/gcc/tree.h
>> +++ b/gcc/tree.h
>> @@ -5551,28 +5551,33 @@ extern tree array_ref_low_bound (tree);
>> /* Returns true if REF is an array reference, a component reference,
>>    or a memory reference to an array whose actual size might be larger
>>    than its upper bound implies.  */
>> -extern bool array_ref_flexible_size_p (tree);
>> +extern bool array_ref_flexible_size_p (tree, bool * = NULL);
>> 
>> /* Return a tree representing the offset, in bytes, of the field referenced
>>    by EXP.  This does not include any offset in DECL_FIELD_BIT_OFFSET.  */
>> extern tree component_ref_field_offset (tree);
>> 
>> -/* Describes a "special" array member due to which component_ref_size
>> -   returns null.  */
>> +/* Describes a "special" array member for a COMPONENT_REF.  */
>> enum struct special_array_member
>>   {
>>     none,	/* Not a special array member.  */
>>     int_0,	/* Interior array member with size zero.  */
>>     trail_0,	/* Trailing array member with size zero.  */
>> -    trail_1	/* Trailing array member with one element.  */
>> +    trail_1,	/* Trailing array member with one element.  */
>> +    trail_n,	/* Trailing array member with two or more elements.  */
>> +    int_n	/* Interior array member with one or more elements.  */
>>   };
>> 
>> +/* Determines the special array member type for a COMPONENT_REF.  */
>> +extern special_array_member component_ref_sam_type (tree);
>> +
>> /* Return the size of the member referenced by the COMPONENT_REF, using
>>    its initializer expression if necessary in order to determine the size
>>    of an initialized flexible array member.  The size might be zero for
>>    an object with an uninitialized flexible array member or null if it
>>    cannot be determined.  */
>> -extern tree component_ref_size (tree, special_array_member * = NULL);
>> +extern tree component_ref_size (tree, special_array_member * = NULL,
>> +				bool = false);
>> 
>> extern int tree_map_base_eq (const void *, const void *);
>> extern unsigned int tree_map_base_hash (const void *);
>> 
> 
> -- 
> Richard Biener <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] 15+ messages in thread

* Re: [PATCH 2/2] Add a new warning option -Wstrict-flex-arrays.
  2022-11-18 15:19     ` Qing Zhao
@ 2022-11-18 16:31       ` Kees Cook
  2022-11-21 15:02         ` Qing Zhao
  0 siblings, 1 reply; 15+ messages in thread
From: Kees Cook @ 2022-11-18 16:31 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Richard Biener, joseph, gcc Patches, siddhesh

On Fri, Nov 18, 2022 at 03:19:07PM +0000, Qing Zhao wrote:
> Hi, Richard,
> 
> Honestly, it’s very hard for me to decide what’s the best way to handle the interaction 
> between -fstrict-flex-array=M and -Warray-bounds=N. 
> 
> Ideally,  -fstrict-flex-array=M should completely control the behavior of -Warray-bounds.
> If possible, I prefer this solution.
> 
> However, -Warray-bounds is included in -Wall, and has been used extensively for a long time.
> It’s not safe to change its default behavior. 

I prefer that -fstrict-flex-arrays controls -Warray-bounds. That
it is in -Wall is _good_ for this reason. :) No one is going to add
-fstrict-flex-arrays (at any level) without understanding what it does
and wanting those effects on -Warray-bounds.

-- 
Kees Cook

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

* Re: [PATCH 2/2] Add a new warning option -Wstrict-flex-arrays.
  2022-11-18 16:31       ` Kees Cook
@ 2022-11-21 15:02         ` Qing Zhao
  2022-11-22  8:16           ` Richard Biener
  0 siblings, 1 reply; 15+ messages in thread
From: Qing Zhao @ 2022-11-21 15:02 UTC (permalink / raw)
  To: Kees Cook; +Cc: Richard Biener, joseph, gcc Patches, siddhesh



> On Nov 18, 2022, at 11:31 AM, Kees Cook <keescook@chromium.org> wrote:
> 
> On Fri, Nov 18, 2022 at 03:19:07PM +0000, Qing Zhao wrote:
>> Hi, Richard,
>> 
>> Honestly, it’s very hard for me to decide what’s the best way to handle the interaction 
>> between -fstrict-flex-array=M and -Warray-bounds=N. 
>> 
>> Ideally,  -fstrict-flex-array=M should completely control the behavior of -Warray-bounds.
>> If possible, I prefer this solution.
>> 
>> However, -Warray-bounds is included in -Wall, and has been used extensively for a long time.
>> It’s not safe to change its default behavior. 
> 
> I prefer that -fstrict-flex-arrays controls -Warray-bounds. That
> it is in -Wall is _good_ for this reason. :) No one is going to add
> -fstrict-flex-arrays (at any level) without understanding what it does
> and wanting those effects on -Warray-bounds.


The major difficulties to let -fstrict-flex-arrays controlling -Warray-bounds was discussed in the following threads:

https://gcc.gnu.org/pipermail/gcc-patches/2022-October/604133.html

Please take a look at the discussion and let me know your opinion.

Thanks,

Qing

> 
> -- 
> Kees Cook


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

* Re: [PATCH 2/2] Add a new warning option -Wstrict-flex-arrays.
  2022-11-21 15:02         ` Qing Zhao
@ 2022-11-22  8:16           ` Richard Biener
  2022-11-22 14:10             ` Qing Zhao
  0 siblings, 1 reply; 15+ messages in thread
From: Richard Biener @ 2022-11-22  8:16 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Kees Cook, joseph, gcc Patches, siddhesh

On Mon, 21 Nov 2022, Qing Zhao wrote:

> 
> 
> > On Nov 18, 2022, at 11:31 AM, Kees Cook <keescook@chromium.org> wrote:
> > 
> > On Fri, Nov 18, 2022 at 03:19:07PM +0000, Qing Zhao wrote:
> >> Hi, Richard,
> >> 
> >> Honestly, it?s very hard for me to decide what?s the best way to handle the interaction 
> >> between -fstrict-flex-array=M and -Warray-bounds=N. 
> >> 
> >> Ideally,  -fstrict-flex-array=M should completely control the behavior of -Warray-bounds.
> >> If possible, I prefer this solution.
> >> 
> >> However, -Warray-bounds is included in -Wall, and has been used extensively for a long time.
> >> It?s not safe to change its default behavior. 
> > 
> > I prefer that -fstrict-flex-arrays controls -Warray-bounds. That
> > it is in -Wall is _good_ for this reason. :) No one is going to add
> > -fstrict-flex-arrays (at any level) without understanding what it does
> > and wanting those effects on -Warray-bounds.
> 
> 
> The major difficulties to let -fstrict-flex-arrays controlling -Warray-bounds was discussed in the following threads:
> 
> https://gcc.gnu.org/pipermail/gcc-patches/2022-October/604133.html
> 
> Please take a look at the discussion and let me know your opinion.

My opinion is now, after re-considering and with seeing your new 
patch, that -Warray-bounds=2 should be changed to only add
"the intermediate results of pointer arithmetic that may yield out of 
bounds values" and that what it considers a flex array should now
be controlled by -fstrict-flex-arrays only.

That is, I think, the only thing that's not confusing to users even
if that implies a change from previous behavior that we should
document by clarifying the -Warray-bounds documentation as well as
by adding an entry to the Caveats section of gcc-13/changes.html

That also means that =2 will get _less_ warnings with GCC 13 when
the user doesn't use -fstrict-flex-arrays as well.

Richard.

-- 
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] 15+ messages in thread

* Re: [PATCH 2/2] Add a new warning option -Wstrict-flex-arrays.
  2022-11-22  8:16           ` Richard Biener
@ 2022-11-22 14:10             ` Qing Zhao
  2022-11-22 15:02               ` Qing Zhao
  0 siblings, 1 reply; 15+ messages in thread
From: Qing Zhao @ 2022-11-22 14:10 UTC (permalink / raw)
  To: Richard Biener; +Cc: Kees Cook, joseph, gcc Patches, siddhesh



> On Nov 22, 2022, at 3:16 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Mon, 21 Nov 2022, Qing Zhao wrote:
> 
>> 
>> 
>>> On Nov 18, 2022, at 11:31 AM, Kees Cook <keescook@chromium.org> wrote:
>>> 
>>> On Fri, Nov 18, 2022 at 03:19:07PM +0000, Qing Zhao wrote:
>>>> Hi, Richard,
>>>> 
>>>> Honestly, it?s very hard for me to decide what?s the best way to handle the interaction 
>>>> between -fstrict-flex-array=M and -Warray-bounds=N. 
>>>> 
>>>> Ideally,  -fstrict-flex-array=M should completely control the behavior of -Warray-bounds.
>>>> If possible, I prefer this solution.
>>>> 
>>>> However, -Warray-bounds is included in -Wall, and has been used extensively for a long time.
>>>> It?s not safe to change its default behavior. 
>>> 
>>> I prefer that -fstrict-flex-arrays controls -Warray-bounds. That
>>> it is in -Wall is _good_ for this reason. :) No one is going to add
>>> -fstrict-flex-arrays (at any level) without understanding what it does
>>> and wanting those effects on -Warray-bounds.
>> 
>> 
>> The major difficulties to let -fstrict-flex-arrays controlling -Warray-bounds was discussed in the following threads:
>> 
>> https://gcc.gnu.org/pipermail/gcc-patches/2022-October/604133.html
>> 
>> Please take a look at the discussion and let me know your opinion.
> 
> My opinion is now, after re-considering and with seeing your new 
> patch, that -Warray-bounds=2 should be changed to only add
> "the intermediate results of pointer arithmetic that may yield out of 
> bounds values" and that what it considers a flex array should now
> be controlled by -fstrict-flex-arrays only.
> 
> That is, I think, the only thing that's not confusing to users even
> if that implies a change from previous behavior that we should
> document by clarifying the -Warray-bounds documentation as well as
> by adding an entry to the Caveats section of gcc-13/changes.html
> 
> That also means that =2 will get _less_ warnings with GCC 13 when
> the user doesn't use -fstrict-flex-arrays as well.

Okay.  So, this is for -Warray-bounds=2.

For -Warray-bounds=1 -fstrict-flex-array=N, if N > 1, should -fstrict-flex-array=N control -Warray-bounds=1?

Qing

> 
> Richard.
> 
> -- 
> 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] 15+ messages in thread

* Re: [PATCH 2/2] Add a new warning option -Wstrict-flex-arrays.
  2022-11-22 14:10             ` Qing Zhao
@ 2022-11-22 15:02               ` Qing Zhao
  2022-11-22 17:17                 ` Kees Cook
  0 siblings, 1 reply; 15+ messages in thread
From: Qing Zhao @ 2022-11-22 15:02 UTC (permalink / raw)
  To: richard Biener; +Cc: Kees Cook, joseph, gcc Patches, siddhesh



> On Nov 22, 2022, at 9:10 AM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> 
> 
> 
>> On Nov 22, 2022, at 3:16 AM, Richard Biener <rguenther@suse.de> wrote:
>> 
>> On Mon, 21 Nov 2022, Qing Zhao wrote:
>> 
>>> 
>>> 
>>>> On Nov 18, 2022, at 11:31 AM, Kees Cook <keescook@chromium.org> wrote:
>>>> 
>>>> On Fri, Nov 18, 2022 at 03:19:07PM +0000, Qing Zhao wrote:
>>>>> Hi, Richard,
>>>>> 
>>>>> Honestly, it?s very hard for me to decide what?s the best way to handle the interaction 
>>>>> between -fstrict-flex-array=M and -Warray-bounds=N. 
>>>>> 
>>>>> Ideally,  -fstrict-flex-array=M should completely control the behavior of -Warray-bounds.
>>>>> If possible, I prefer this solution.
>>>>> 
>>>>> However, -Warray-bounds is included in -Wall, and has been used extensively for a long time.
>>>>> It?s not safe to change its default behavior. 
>>>> 
>>>> I prefer that -fstrict-flex-arrays controls -Warray-bounds. That
>>>> it is in -Wall is _good_ for this reason. :) No one is going to add
>>>> -fstrict-flex-arrays (at any level) without understanding what it does
>>>> and wanting those effects on -Warray-bounds.
>>> 
>>> 
>>> The major difficulties to let -fstrict-flex-arrays controlling -Warray-bounds was discussed in the following threads:
>>> 
>>> https://gcc.gnu.org/pipermail/gcc-patches/2022-October/604133.html
>>> 
>>> Please take a look at the discussion and let me know your opinion.
>> 
>> My opinion is now, after re-considering and with seeing your new 
>> patch, that -Warray-bounds=2 should be changed to only add
>> "the intermediate results of pointer arithmetic that may yield out of 
>> bounds values" and that what it considers a flex array should now
>> be controlled by -fstrict-flex-arrays only.
>> 
>> That is, I think, the only thing that's not confusing to users even
>> if that implies a change from previous behavior that we should
>> document by clarifying the -Warray-bounds documentation as well as
>> by adding an entry to the Caveats section of gcc-13/changes.html
>> 
>> That also means that =2 will get _less_ warnings with GCC 13 when
>> the user doesn't use -fstrict-flex-arrays as well.
> 
> Okay.  So, this is for -Warray-bounds=2.
> 
> For -Warray-bounds=1 -fstrict-flex-array=N, if N > 1, should -fstrict-flex-array=N control -Warray-bounds=1?

More thinking on this. (I might misunderstand a little bit in the previous email)

If I understand correctly now, what you proposed was:

1. The level of -Warray-bounds will NOT control how a trailing array is considered as a flex array member anymore. 
2. Only the level of -fstrict-flex-arrays will control this;
3. Keep the current default  behavior of -Warray-bounds on treating trailing arrays as flex array member (treating all [0],[1], and [] as flexible array members). 
4. Updating the documentation for -Warray-bounds by clarifying this change, and also as an entry to the Caveats section on such change on -Warray-bounds.

If the above is correct, Yes, I like this change. Both the user interface and the internal implementation will be simplified and cleaner. 

Let me know if you see any issue with my above understanding.

Thanks a lot.

Qing

> 
> Qing
> 
>> 
>> Richard.
>> 
>> -- 
>> 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] 15+ messages in thread

* Re: [PATCH 2/2] Add a new warning option -Wstrict-flex-arrays.
  2022-11-22 15:02               ` Qing Zhao
@ 2022-11-22 17:17                 ` Kees Cook
  2022-11-24  6:45                   ` Richard Biener
  0 siblings, 1 reply; 15+ messages in thread
From: Kees Cook @ 2022-11-22 17:17 UTC (permalink / raw)
  To: Qing Zhao; +Cc: richard Biener, joseph, gcc Patches, siddhesh

On Tue, Nov 22, 2022 at 03:02:04PM +0000, Qing Zhao wrote:
> 
> 
> > On Nov 22, 2022, at 9:10 AM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> > 
> > 
> > 
> >> On Nov 22, 2022, at 3:16 AM, Richard Biener <rguenther@suse.de> wrote:
> >> 
> >> On Mon, 21 Nov 2022, Qing Zhao wrote:
> >> 
> >>> 
> >>> 
> >>>> On Nov 18, 2022, at 11:31 AM, Kees Cook <keescook@chromium.org> wrote:
> >>>> 
> >>>> On Fri, Nov 18, 2022 at 03:19:07PM +0000, Qing Zhao wrote:
> >>>>> Hi, Richard,
> >>>>> 
> >>>>> Honestly, it?s very hard for me to decide what?s the best way to handle the interaction 
> >>>>> between -fstrict-flex-array=M and -Warray-bounds=N. 
> >>>>> 
> >>>>> Ideally,  -fstrict-flex-array=M should completely control the behavior of -Warray-bounds.
> >>>>> If possible, I prefer this solution.
> >>>>> 
> >>>>> However, -Warray-bounds is included in -Wall, and has been used extensively for a long time.
> >>>>> It?s not safe to change its default behavior. 
> >>>> 
> >>>> I prefer that -fstrict-flex-arrays controls -Warray-bounds. That
> >>>> it is in -Wall is _good_ for this reason. :) No one is going to add
> >>>> -fstrict-flex-arrays (at any level) without understanding what it does
> >>>> and wanting those effects on -Warray-bounds.
> >>> 
> >>> 
> >>> The major difficulties to let -fstrict-flex-arrays controlling -Warray-bounds was discussed in the following threads:
> >>> 
> >>> https://gcc.gnu.org/pipermail/gcc-patches/2022-October/604133.html
> >>> 
> >>> Please take a look at the discussion and let me know your opinion.
> >> 
> >> My opinion is now, after re-considering and with seeing your new 
> >> patch, that -Warray-bounds=2 should be changed to only add
> >> "the intermediate results of pointer arithmetic that may yield out of 
> >> bounds values" and that what it considers a flex array should now
> >> be controlled by -fstrict-flex-arrays only.
> >> 
> >> That is, I think, the only thing that's not confusing to users even
> >> if that implies a change from previous behavior that we should
> >> document by clarifying the -Warray-bounds documentation as well as
> >> by adding an entry to the Caveats section of gcc-13/changes.html
> >> 
> >> That also means that =2 will get _less_ warnings with GCC 13 when
> >> the user doesn't use -fstrict-flex-arrays as well.
> > 
> > Okay.  So, this is for -Warray-bounds=2.
> > 
> > For -Warray-bounds=1 -fstrict-flex-array=N, if N > 1, should -fstrict-flex-array=N control -Warray-bounds=1?
> 
> More thinking on this. (I might misunderstand a little bit in the previous email)
> 
> If I understand correctly now, what you proposed was:
> 
> 1. The level of -Warray-bounds will NOT control how a trailing array is considered as a flex array member anymore. 
> 2. Only the level of -fstrict-flex-arrays will control this;
> 3. Keep the current default  behavior of -Warray-bounds on treating trailing arrays as flex array member (treating all [0],[1], and [] as flexible array members). 
> 4. Updating the documentation for -Warray-bounds by clarifying this change, and also as an entry to the Caveats section on such change on -Warray-bounds.
> 
> If the above is correct, Yes, I like this change. Both the user interface and the internal implementation will be simplified and cleaner. 
> 
> Let me know if you see any issue with my above understanding.
> 
> Thanks a lot.

FWIW, this matches what I think makes the most sense too.

-- 
Kees Cook

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

* Re: [PATCH 2/2] Add a new warning option -Wstrict-flex-arrays.
  2022-11-22 17:17                 ` Kees Cook
@ 2022-11-24  6:45                   ` Richard Biener
  0 siblings, 0 replies; 15+ messages in thread
From: Richard Biener @ 2022-11-24  6:45 UTC (permalink / raw)
  To: Kees Cook; +Cc: Qing Zhao, joseph, gcc Patches, siddhesh

On Tue, 22 Nov 2022, Kees Cook wrote:

> On Tue, Nov 22, 2022 at 03:02:04PM +0000, Qing Zhao wrote:
> > 
> > 
> > > On Nov 22, 2022, at 9:10 AM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> > > 
> > > 
> > > 
> > >> On Nov 22, 2022, at 3:16 AM, Richard Biener <rguenther@suse.de> wrote:
> > >> 
> > >> On Mon, 21 Nov 2022, Qing Zhao wrote:
> > >> 
> > >>> 
> > >>> 
> > >>>> On Nov 18, 2022, at 11:31 AM, Kees Cook <keescook@chromium.org> wrote:
> > >>>> 
> > >>>> On Fri, Nov 18, 2022 at 03:19:07PM +0000, Qing Zhao wrote:
> > >>>>> Hi, Richard,
> > >>>>> 
> > >>>>> Honestly, it?s very hard for me to decide what?s the best way to handle the interaction 
> > >>>>> between -fstrict-flex-array=M and -Warray-bounds=N. 
> > >>>>> 
> > >>>>> Ideally,  -fstrict-flex-array=M should completely control the behavior of -Warray-bounds.
> > >>>>> If possible, I prefer this solution.
> > >>>>> 
> > >>>>> However, -Warray-bounds is included in -Wall, and has been used extensively for a long time.
> > >>>>> It?s not safe to change its default behavior. 
> > >>>> 
> > >>>> I prefer that -fstrict-flex-arrays controls -Warray-bounds. That
> > >>>> it is in -Wall is _good_ for this reason. :) No one is going to add
> > >>>> -fstrict-flex-arrays (at any level) without understanding what it does
> > >>>> and wanting those effects on -Warray-bounds.
> > >>> 
> > >>> 
> > >>> The major difficulties to let -fstrict-flex-arrays controlling -Warray-bounds was discussed in the following threads:
> > >>> 
> > >>> https://gcc.gnu.org/pipermail/gcc-patches/2022-October/604133.html
> > >>> 
> > >>> Please take a look at the discussion and let me know your opinion.
> > >> 
> > >> My opinion is now, after re-considering and with seeing your new 
> > >> patch, that -Warray-bounds=2 should be changed to only add
> > >> "the intermediate results of pointer arithmetic that may yield out of 
> > >> bounds values" and that what it considers a flex array should now
> > >> be controlled by -fstrict-flex-arrays only.
> > >> 
> > >> That is, I think, the only thing that's not confusing to users even
> > >> if that implies a change from previous behavior that we should
> > >> document by clarifying the -Warray-bounds documentation as well as
> > >> by adding an entry to the Caveats section of gcc-13/changes.html
> > >> 
> > >> That also means that =2 will get _less_ warnings with GCC 13 when
> > >> the user doesn't use -fstrict-flex-arrays as well.
> > > 
> > > Okay.  So, this is for -Warray-bounds=2.
> > > 
> > > For -Warray-bounds=1 -fstrict-flex-array=N, if N > 1, should -fstrict-flex-array=N control -Warray-bounds=1?
> > 
> > More thinking on this. (I might misunderstand a little bit in the previous email)
> > 
> > If I understand correctly now, what you proposed was:
> > 
> > 1. The level of -Warray-bounds will NOT control how a trailing array is considered as a flex array member anymore. 
> > 2. Only the level of -fstrict-flex-arrays will control this;
> > 3. Keep the current default  behavior of -Warray-bounds on treating trailing arrays as flex array member (treating all [0],[1], and [] as flexible array members). 
> > 4. Updating the documentation for -Warray-bounds by clarifying this change, and also as an entry to the Caveats section on such change on -Warray-bounds.
> > 
> > If the above is correct, Yes, I like this change. Both the user interface and the internal implementation will be simplified and cleaner. 
> > 
> > Let me know if you see any issue with my above understanding.
> > 
> > Thanks a lot.
> 
> FWIW, this matches what I think makes the most sense too.

Yes, I think that makes most sense.  As said for -Warray-bounds=2 this
will change behavior but since that's not the default that should be
fine if documented.

Thanks,
Richard.

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

end of thread, other threads:[~2022-11-24  6:45 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-08 14:51 [PATCH 0/2] Add a new warning option -Wstrict-flex-array Qing Zhao
2022-11-08 14:51 ` [PATCH 1/2] Change the name of array_at_struct_end_p to array_ref_flexible_size_p Qing Zhao
2022-11-09  7:57   ` Richard Biener
2022-11-09 15:50     ` Qing Zhao
2022-11-08 14:51 ` [PATCH 2/2] Add a new warning option -Wstrict-flex-arrays Qing Zhao
2022-11-15 15:41   ` Qing Zhao
2022-11-18 13:14   ` Richard Biener
2022-11-18 15:19     ` Qing Zhao
2022-11-18 16:31       ` Kees Cook
2022-11-21 15:02         ` Qing Zhao
2022-11-22  8:16           ` Richard Biener
2022-11-22 14:10             ` Qing Zhao
2022-11-22 15:02               ` Qing Zhao
2022-11-22 17:17                 ` Kees Cook
2022-11-24  6:45                   ` Richard Biener

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