diff --git a/gcc/c-family/c-attribs.cc<http://c-attribs.cc> b/gcc/c-family/c-attribs.cc<http://c-attribs.cc>
index e4f1d3542f37..9c9927cefa0d 100644
--- a/gcc/c-family/c-attribs.cc<http://c-attribs.cc>
+++ b/gcc/c-family/c-attribs.cc<http://c-attribs.cc>
@@ -101,6 +101,8 @@ static tree handle_special_var_sec_attribute (tree *, tree, tree, int, bool *);
static tree handle_aligned_attribute (tree *, tree, tree, int, bool *);
static tree handle_warn_if_not_aligned_attribute (tree *, tree, tree,
 int, bool *);
+static tree handle_strict_flex_arrays_attribute (tree *, tree, tree,
+ int, bool *);
static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ;
static tree handle_noplt_attribute (tree *, tree, tree, int, bool *) ;
static tree handle_alias_ifunc_attribute (bool, tree *, tree, tree, bool *);
@@ -368,6 +370,8 @@ const struct attribute_spec c_common_attribute_table[] =
                     attr_aligned_exclusions },
  { "warn_if_not_aligned",    0, 1, false, false, false, false,
     handle_warn_if_not_aligned_attribute, NULL },
+  { "strict_flex_arrays",      1, 1, false, false, false, false,
+      handle_strict_flex_arrays_attribute, NULL },
  { "weak",                   0, 0, true,  false, false, false,
     handle_weak_attribute, NULL },
  { "noplt",                   0, 0, true,  false, false, false,
@@ -2505,6 +2509,96 @@ handle_warn_if_not_aligned_attribute (tree *node, tree name,
 no_add_attrs, true);
}

+/* Handle a "strict_flex_arrays" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_strict_flex_arrays_attribute (tree *node, tree name,
+     tree args, int ARG_UNUSED (flags),
+     bool *no_add_attrs)
+{
+  tree decl = *node;
+  tree argval = TREE_VALUE (args);
+
+  /* This attribute only applies to field decls of a structure.  */
+  if (TREE_CODE (decl) != FIELD_DECL)
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+ "%qE attribute may not be specified for %q+D", name, decl);
+      *no_add_attrs = true;
+    }
+  /* This attribute only applies to field with array type.  */
+  else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE)
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+ "%qE attribute may not be specified for a non array field",
+ name);
+      *no_add_attrs = true;
+    }
+  else if (TREE_CODE (argval) != INTEGER_CST)
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+ "%qE attribute argument not an integer", name);
+      *no_add_attrs = true;
+    }
+  else if (!tree_fits_uhwi_p (argval) || tree_to_uhwi (argval) > 3)
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+ "%qE attribute argument %qE is not an integer constant"
+ " between 0 and 3", name, argval);
+      *no_add_attrs = true;
+    }
+  else
+    {
+      unsigned int level = tree_to_uhwi (argval);
+      /* check whether the attribute is valid based on language standard.
+ the attribute is only valid when flexible array member is
+ supported in the language. Therefore, we should invalid this attribute or
+ specific level of this attribute for the following situations:
+ A. When -std=c89 is specified, no language support at all, invalid this
+   attribute and issue a warning;
+ B. When -std=gnu89 is specified, only zero-length array extension and
+   one-size array are supported, level=3 will be invalid and a warning
+   will be issued.
+ C. C++ without GNU extension, no language support at all, invalid this
+   attribute and issue a warning;
+ D. C++ with GNU extension, only zero-length array extension and one-size
+   array are supported, level=3 will be invalid and a warning will be
+   issued.  */
+      if (level > 0)
+ {
+  if (!c_dialect_cxx () && flag_iso && flag_isoc99 == 0)
+  {
+    warning (OPT_Wattributes, "%qE attribute ignored since it is "
+     "not supported with a ISO C before C99", name);
+    *no_add_attrs = true;
+  }
+  else if (!c_dialect_cxx () && !flag_iso
+   && flag_isoc99 == 0 && level == 3)
+  {
+    warning (OPT_Wattributes, "%qE = 3 attribute ignored since it is "
+     "not supported with a GNU extension GNU89", name);
+    *no_add_attrs = true;
+  }
+  else if (c_dialect_cxx () && flag_iso)
+  {
+    warning (OPT_Wattributes, "%qE attribute ignored since it is "
+     "not supported with a ISO C++", name);
+    *no_add_attrs = true;
+  }
+  else if (c_dialect_cxx () && !flag_iso
+   && level == 3)
+  {
+    warning (OPT_Wattributes, "%qE = 3 attribute ignored since it is "
+     "not supported for C++ with GNU extension", name);
+    *no_add_attrs = true;
+  }
+ }
+      }
+
+  return NULL_TREE;
+}
+
/* Handle a "weak" attribute; arguments as in
   struct attribute_spec.handler.  */

diff --git a/gcc/c-family/c-opts.cc<http://c-opts.cc> b/gcc/c-family/c-opts.cc<http://c-opts.cc>
index 4e1463689de3..639eb40f3c86 100644
--- a/gcc/c-family/c-opts.cc<http://c-opts.cc>
+++ b/gcc/c-family/c-opts.cc<http://c-opts.cc>
@@ -870,6 +870,47 @@ c_common_post_options (const char **pfilename)
    SET_OPTION_IF_UNSET (&global_options, &global_options_set,
flag_tree_loop_distribute_patterns, 0);

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

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

diff --git a/gcc/c/c-decl.cc<http://c-decl.cc> b/gcc/c/c-decl.cc<http://c-decl.cc>
index ae8990c138fd..a2e125d4ddd5 100644
--- a/gcc/c/c-decl.cc<http://c-decl.cc>
+++ b/gcc/c/c-decl.cc<http://c-decl.cc>
@@ -4999,6 +4999,41 @@ set_array_declarator_inner (struct c_declarator *decl,
  return decl;
}

+/* Determine whether TYPE is a ISO C99 flexible array memeber type "[]".  */
+static bool
+flexible_array_member_type_p (const_tree type)
+{
+  if (TREE_CODE (type) == ARRAY_TYPE
+      && TYPE_SIZE (type) == NULL_TREE
+      && TYPE_DOMAIN (type) != NULL_TREE
+      && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)
+    return true;
+
+  return false;
+}
+
+/* Determine whether TYPE is a one-element array type "[1]".  */
+static bool
+one_element_array_type_p (const_tree type)
+{
+  if (TREE_CODE (type) != ARRAY_TYPE)
+    return false;
+  return integer_zerop (array_type_nelts (type));
+}
+
+/* Determine whether TYPE is a zero-length array type "[0]".  */
+static bool
+zero_length_array_type_p (const_tree type)
+{
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    if (tree type_size = TYPE_SIZE_UNIT (type))
+      if ((integer_zerop (type_size))
+   && TYPE_DOMAIN (type) != NULL_TREE
+   && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)
+ return true;
+  return false;
+}
+
/* INIT is a constructor that forms DECL's initializer.  If the final
   element initializes a flexible array field, add the size of that
   initializer to DECL's size.  */
@@ -5013,10 +5048,7 @@ add_flexible_array_elts_to_size (tree decl, tree init)

  elt = CONSTRUCTOR_ELTS (init)->last ().value;
  type = TREE_TYPE (elt);
-  if (TREE_CODE (type) == ARRAY_TYPE
-      && TYPE_SIZE (type) == NULL_TREE
-      && TYPE_DOMAIN (type) != NULL_TREE
-      && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)
+  if (flexible_array_member_type_p (type))
    {
      complete_array_type (&type, elt, false);
      DECL_SIZE (decl)
@@ -8720,6 +8752,81 @@ finish_incomplete_vars (tree incomplete_vars, bool toplevel)
    }
}

+
+/* Determine whether the FIELD_DECL X is a flexible array member according to
+   the following info:
+  A. whether the FIELD_DECL X is the last field of the DECL_CONTEXT;
+  B. whether the FIELD_DECL is an array that is declared as "[]", "[0]",
+     or "[1]";
+  C. flag_strict_flex_arrays;
+  D. the attribute strict_flex_array that is attached to the field
+     if presenting.
+  Return TRUE when it's a flexible array member, FALSE otherwise.  */
+
+static bool
+is_flexible_array_member_p (bool is_last_field,
+    tree x)
+{
+  /* if not the last field, return false.  */
+  if (!is_last_field)
+    return false;
+
+  /* if not an array field, return false.  */
+  if (TREE_CODE (TREE_TYPE (x)) != ARRAY_TYPE)
+    return false;
+
+  bool is_zero_length_array = zero_length_array_type_p (TREE_TYPE (x));
+  bool is_one_element_array = one_element_array_type_p (TREE_TYPE (x));
+  bool is_flexible_array = flexible_array_member_type_p (TREE_TYPE (x));
+
+  unsigned int strict_flex_array_level = flag_strict_flex_arrays;
+
+  tree attr_strict_flex_array = lookup_attribute ("strict_flex_arrays",
+  DECL_ATTRIBUTES (x));
+  /* if there is a strict_flex_array attribute attached to the field,
+     override the flag_strict_flex_arrays.  */
+  if (attr_strict_flex_array)
+    {
+      /* get the value of the level first from the attribute.  */
+      unsigned HOST_WIDE_INT attr_strict_flex_array_level = 0;
+      gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
+      attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
+      gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
+      attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
+      gcc_assert (tree_fits_uhwi_p (attr_strict_flex_array));
+      attr_strict_flex_array_level = tree_to_uhwi (attr_strict_flex_array);
+
+      /* the attribute has higher priority than flag_struct_flex_array.  */
+      strict_flex_array_level = attr_strict_flex_array_level;
+    }
+
+  switch (strict_flex_array_level)
+    {
+      case 0:
+ /* default, all trailing arrays are flexiable array members.  */
+ return true;
+      case 1:
+ /* Level 1: all "[1]", "[0]", and "[]" are flexiable array members.  */
+ if (is_one_element_array)
+  return true;
+ /* FALLTHROUGH.  */
+      case 2:
+ /* Level 2: all "[0]", and "[]" are flexiable array members.  */
+ if (is_zero_length_array)
+  return true;
+ /* FALLTHROUGH.  */
+      case 3:
+ /* Level 3: Only "[]" are flexible array members.  */
+ if (is_flexible_array)
+  return true;
+ break;
+      default:
+ gcc_unreachable ();
+    }
+  return false;
+}
+
+
/* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T.
   LOC is the location of the RECORD_TYPE or UNION_TYPE's definition.
   FIELDLIST is a chain of FIELD_DECL nodes for the fields.
@@ -8781,6 +8888,11 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
  bool saw_named_field = false;
  for (x = fieldlist; x; x = DECL_CHAIN (x))
    {
+      /* whether this field is the last field of the structure or union.
+ for UNION, any field is the last field of it.  */
+      bool is_last_field = (DECL_CHAIN (x) == NULL_TREE)
+    || (TREE_CODE (t) == UNION_TYPE);
+
      if (TREE_TYPE (x) == error_mark_node)
continue;

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

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

+      /* Set DECL_NOT_FLEXARRAY flag for FIELD_DECL x.  */
+      DECL_NOT_FLEXARRAY (x) = !is_flexible_array_member_p (is_last_field, x);
+
      if (DECL_NAME (x)
 || RECORD_OR_UNION_TYPE_P (TREE_TYPE (x)))
saw_named_field = true;
diff --git a/gcc/cp/module.cc<http://module.cc> b/gcc/cp/module.cc<http://module.cc>
index f27f4d091e5e..75ee2514f66b 100644
--- a/gcc/cp/module.cc<http://module.cc>
+++ b/gcc/cp/module.cc<http://module.cc>
@@ -5414,6 +5414,7 @@ trees_out::core_bools (tree t)
      WB (t->decl_common.decl_by_reference_flag);
      WB (t->decl_common.decl_read_flag);
      WB (t->decl_common.decl_nonshareable_flag);
+      WB (t->decl_common.decl_not_flexarray);
    }

  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
@@ -5558,6 +5559,7 @@ trees_in::core_bools (tree t)
      RB (t->decl_common.decl_by_reference_flag);
      RB (t->decl_common.decl_read_flag);
      RB (t->decl_common.decl_nonshareable_flag);
+      RB (t->decl_common.decl_not_flexarray);
    }

  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 7fe7f8817cdd..99b43ed3852c 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -7473,6 +7473,39 @@ This warning can be disabled by @option{-Wno-if-not-aligned}.
The @code{warn_if_not_aligned} attribute can also be used for types
(@pxref{Common Type Attributes}.)

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

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

+@item -fstrict-flex-arrays
+@opindex fstrict-flex-arrays
+@opindex fno-strict-flex-arrays
+Treat the trailing array of a structure as a flexible array member in a
+stricter way.
+The positive form is equivalent to @option{-fstrict-flex-arrays=3}, which is the
+strictest.  A trailing array is treated as a flexible array member only when it
+is declared as a flexible array member per C99 standard onwards.
+The negative form is equivalent to @option{-fstrict-flex-arrays=0}, which is the
+least strict.  All trailing arrays of structures are treated as flexible array
+members.
+
+@item -fstrict-flex-arrays=@var{level}
+@opindex fstrict-flex-arrays=@var{level}
+Treat the trailing array of a structure as a flexible array member in a
+stricter way.  The value of @var{level} controls the level of strictness.
+
+The possible values of @var{level} are the same as for the
+@code{strict_flex_array} attribute (@pxref{Variable Attributes}).
+
+You can control this behavior for a specific trailing array field of a
+structure by using the variable attribute @code{strict_flex_array} attribute
+(@pxref{Variable Attributes}).
+
+This option is only valid when flexible array member is supported in the
+language. FOR ISO C before C99 and ISO C++, no language support for the flexible
+array member at all, this option will be invalid and a warning will be issued.
+When -std=gnu89 is specified or C++ with GNU extension, only zero-length array
+extension and one-size array are supported, as a result, @var{level}=3 will be
+invalid and a warning will be issued.
+
@item -fsso-struct=@var{endianness}
@opindex fsso-struct
Set the default scalar storage order of structures and unions to the
diff --git a/gcc/print-tree.cc<http://print-tree.cc> b/gcc/print-tree.cc<http://print-tree.cc>
index 6d45a4a59669..58a98250cc4f 100644
--- a/gcc/print-tree.cc<http://print-tree.cc>
+++ b/gcc/print-tree.cc<http://print-tree.cc>
@@ -517,8 +517,12 @@ print_node (FILE *file, const char *prefix, tree node, int indent,
 fprintf (file, " align:%d warn_if_not_align:%d",
  DECL_ALIGN (node), DECL_WARN_IF_NOT_ALIGN (node));
 if (code == FIELD_DECL)
-    fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED,
-     DECL_OFFSET_ALIGN (node));
+    {
+      fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED,
+       DECL_OFFSET_ALIGN (node));
+      fprintf (file, " decl_not_flexarray: %d",
+       DECL_NOT_FLEXARRAY (node));
+    }

 if (code == FUNCTION_DECL && fndecl_built_in_p (node))
   {
diff --git a/gcc/testsuite/g++.dg/strict-flex-array-1.C b/gcc/testsuite/g++.dg/strict-flex-array-1.C
new file mode 100644
index 000000000000..47adaf7bac4a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/strict-flex-array-1.C
@@ -0,0 +1,31 @@
+/* testing the correct usage of attribute strict_flex_array.  */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+
+int x __attribute__ ((strict_flex_arrays (1))); /* { dg-error "'strict_flex_arrays' attribute may not be specified for 'x'" } */
+
+struct trailing {
+    int a;
+    int c __attribute ((strict_flex_arrays)); /* { dg-error "wrong number of arguments specified for 'strict_flex_arrays' attribute" } */
+};
+
+struct trailing_1 {
+    int a;
+    int b;
+    int c __attribute ((strict_flex_arrays (2))); /* { dg-error "'strict_flex_arrays' attribute may not be specified for a non array field" } */
+};
+
+extern int d;
+
+struct trailing_array_2 {
+    int a;
+    int b;
+    int c[1] __attribute ((strict_flex_arrays (d))); /* { dg-error "'strict_flex_arrays' attribute argument not an integer" } */
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (5))); /* { dg-error "'strict_flex_arrays' attribute argument '5' is not an integer constant between 0 and 3" } */
+};
diff --git a/gcc/testsuite/g++.dg/strict-flex-array-2.C b/gcc/testsuite/g++.dg/strict-flex-array-2.C
new file mode 100644
index 000000000000..245f8fe0bc73
--- /dev/null
+++ b/gcc/testsuite/g++.dg/strict-flex-array-2.C
@@ -0,0 +1,16 @@
+/* testing the correct usage of flag -fstrict_flex_array for C++.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays -std=c++98" } */
+
+struct trailing_array {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "attribute ignored since it is not supported with a ISO C\\+\\+" } */
+};
+
+int foo(int a)
+{
+  return 0;
+}
+
+/* { dg-warning "is not supported with a ISO C\\+\\+, ignored" ""  { target *-*-* } 0 } */
diff --git a/gcc/testsuite/g++.dg/strict-flex-array-3.C b/gcc/testsuite/g++.dg/strict-flex-array-3.C
new file mode 100644
index 000000000000..2a733a5bccf4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/strict-flex-array-3.C
@@ -0,0 +1,21 @@
+/* testing the correct usage of flag -fstrict_flex_array for C++.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays -std=gnu++98" } */
+/* { dg-warning "'-fstrict-flex-arrays=3' is not supported for C\\+\\+ with GNU extension, ignored" ""  { target *-*-* } 0 } */
+
+struct trailing_array {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "'strict_flex_arrays' = 3 attribute ignored since it is not supported for C\\+\\+ with GNU extension" } */
+};
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (2))); /* { dg-bogus "'strict_flex_arrays' = 3 attribute ignored since it is not supported for C\\+\\+ with GNU extension" } */
+};
+
+int foo(int a)
+{
+  return a + 2;
+}
diff --git a/gcc/testsuite/g++.dg/strict-flex-array-4.C b/gcc/testsuite/g++.dg/strict-flex-array-4.C
new file mode 100644
index 000000000000..804e4cf459ef
--- /dev/null
+++ b/gcc/testsuite/g++.dg/strict-flex-array-4.C
@@ -0,0 +1,9 @@
+/* testing the correct usage of flag -fstrict_flex_array.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays=2 -std=gnu++98" } */
+/* { dg-bogus "is not supported for C\\+\\+ with GNU extension, ignored" ""  { target *-*-* } 0 } */
+
+int foo(int a)
+{
+  return a + 2;
+}
diff --git a/gcc/testsuite/gcc.dg/strict-flex-array-1.c b/gcc/testsuite/gcc.dg/strict-flex-array-1.c
new file mode 100644
index 000000000000..47adaf7bac4a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strict-flex-array-1.c
@@ -0,0 +1,31 @@
+/* testing the correct usage of attribute strict_flex_array.  */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+
+int x __attribute__ ((strict_flex_arrays (1))); /* { dg-error "'strict_flex_arrays' attribute may not be specified for 'x'" } */
+
+struct trailing {
+    int a;
+    int c __attribute ((strict_flex_arrays)); /* { dg-error "wrong number of arguments specified for 'strict_flex_arrays' attribute" } */
+};
+
+struct trailing_1 {
+    int a;
+    int b;
+    int c __attribute ((strict_flex_arrays (2))); /* { dg-error "'strict_flex_arrays' attribute may not be specified for a non array field" } */
+};
+
+extern int d;
+
+struct trailing_array_2 {
+    int a;
+    int b;
+    int c[1] __attribute ((strict_flex_arrays (d))); /* { dg-error "'strict_flex_arrays' attribute argument not an integer" } */
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (5))); /* { dg-error "'strict_flex_arrays' attribute argument '5' is not an integer constant between 0 and 3" } */
+};
diff --git a/gcc/testsuite/gcc.dg/strict-flex-array-2.c b/gcc/testsuite/gcc.dg/strict-flex-array-2.c
new file mode 100644
index 000000000000..967a240040dc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strict-flex-array-2.c
@@ -0,0 +1,15 @@
+/* testing the correct usage of flag -fstrict_flex_array.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays -std=c89" } */
+/* { dg-warning "'-fstrict-flex-arrays' is not supported with a ISO C before C99, ignored" ""  { target *-*-* } 0 } */
+
+struct trailing_array {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "'strict_flex_arrays' attribute ignored since it is not supported with a ISO C before C99" } */
+};
+
+int foo(int a)
+{
+  return a + 2;
+}
diff --git a/gcc/testsuite/gcc.dg/strict-flex-array-3.c b/gcc/testsuite/gcc.dg/strict-flex-array-3.c
new file mode 100644
index 000000000000..879de7f203c8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strict-flex-array-3.c
@@ -0,0 +1,21 @@
+/* testing the correct usage of flag -fstrict_flex_array.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays -std=gnu89" } */
+/* { dg-warning "'-fstrict-flex-arrays=3' is not supported with a GNU extension GNU89, ignored" ""  { target *-*-* } 0 } */
+
+struct trailing_array {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (3))); /* { dg-warning "'strict_flex_arrays' = 3 attribute ignored since it is not supported with a GNU extension GNU89" } */
+};
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[0] __attribute ((strict_flex_arrays (2))); /* { dg-bogus "'strict_flex_arrays' = 3 attribute ignored since it is not supported with a GNU extension GNU89" } */
+};
+
+int foo(int a)
+{
+  return a + 2;
+}
diff --git a/gcc/testsuite/gcc.dg/strict-flex-array-4.c b/gcc/testsuite/gcc.dg/strict-flex-array-4.c
new file mode 100644
index 000000000000..ce64c24db301
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strict-flex-array-4.c
@@ -0,0 +1,10 @@
+/* testing the correct usage of flag -fstrict_flex_array.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays=2 -std=gnu89" } */
+/* { dg-bogus "is not supported with a GNU extension GNU89, ignored" ""  { target *-*-* } 0 } */
+
+
+int foo(int a)
+{
+  return a + 2;
+}
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 86a07c282af2..f822cb539dd0 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1813,7 +1813,10 @@ struct GTY(()) tree_decl_common {
     TYPE_WARN_IF_NOT_ALIGN.  */
  unsigned int warn_if_not_align : 6;

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

  /* UID for points-to sets, stable over copying from inlining.  */
  unsigned int pt_uid;
diff --git a/gcc/tree-streamer-in.cc<http://tree-streamer-in.cc> b/gcc/tree-streamer-in.cc<http://tree-streamer-in.cc>
index 196f19c759f2..21e6e8eb1c0a 100644
--- a/gcc/tree-streamer-in.cc<http://tree-streamer-in.cc>
+++ b/gcc/tree-streamer-in.cc<http://tree-streamer-in.cc>
@@ -261,6 +261,7 @@ unpack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
      else
SET_DECL_FIELD_ABI_IGNORED (expr, val);
      expr->decl_common.off_align = bp_unpack_value (bp, 8);
+      DECL_NOT_FLEXARRAY (expr) = (unsigned) bp_unpack_value (bp, 1);
    }

  else if (VAR_P (expr))
diff --git a/gcc/tree-streamer-out.cc<http://tree-streamer-out.cc> b/gcc/tree-streamer-out.cc<http://tree-streamer-out.cc>
index d39dc158a465..68e40dbdb8f2 100644
--- a/gcc/tree-streamer-out.cc<http://tree-streamer-out.cc>
+++ b/gcc/tree-streamer-out.cc<http://tree-streamer-out.cc>
@@ -229,6 +229,7 @@ pack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
      else
bp_pack_value (bp, DECL_FIELD_ABI_IGNORED (expr), 1);
      bp_pack_value (bp, expr->decl_common.off_align, 8);
+      bp_pack_value (bp, DECL_NOT_FLEXARRAY (expr), 1);
    }

  else if (VAR_P (expr))
diff --git a/gcc/tree.cc<http://tree.cc> b/gcc/tree.cc<http://tree.cc>
index fed1434d141d..d698e8c9c213 100644
--- a/gcc/tree.cc<http://tree.cc>
+++ b/gcc/tree.cc<http://tree.cc>
@@ -12678,14 +12678,30 @@ array_ref_up_bound (tree exp)
}

/* Returns true if REF is an array reference, component reference,
-   or memory reference to an array at the end of a structure.
-   If this is the case, the array may be allocated larger
-   than its upper bound implies.  */
+   or memory reference to an array whose actual size might be larger
+   than its upper bound implies, there are multiple cases:
+   A. a ref to a flexible array member at the end of a structure;
+   B. a ref to an array with a different type against the original decl;
+      for example:

+   short a[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+   (*((char(*)[16])&a[0]))[i+8]
+
+   C. a ref to an array that was passed as a parameter;
+      for example:
+
+   int test (uint8_t *p, uint32_t t[1][1], int n) {
+   for (int i = 0; i < 4; i++, p++)
+     t[i][0] = ...;
+
+   FIXME, the name of this routine need to be changed to be more accurate.  */
bool
array_at_struct_end_p (tree ref)
{
-  tree atype;
+  /* the TYPE for this array referece.  */
+  tree atype = NULL_TREE;
+  /* the FIELD_DECL for the array field in the containing structure.  */
+  tree afield_decl = NULL_TREE;

  if (TREE_CODE (ref) == ARRAY_REF
      || TREE_CODE (ref) == ARRAY_RANGE_REF)
@@ -12695,7 +12711,10 @@ array_at_struct_end_p (tree ref)
    }
  else if (TREE_CODE (ref) == COMPONENT_REF
  && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 1))) == ARRAY_TYPE)
-    atype = TREE_TYPE (TREE_OPERAND (ref, 1));
+    {
+      atype = TREE_TYPE (TREE_OPERAND (ref, 1));
+      afield_decl = TREE_OPERAND (ref, 1);
+    }
  else if (TREE_CODE (ref) == MEM_REF)
    {
      tree arg = TREE_OPERAND (ref, 0);
@@ -12707,6 +12726,7 @@ array_at_struct_end_p (tree ref)
 if (tree fld = last_field (argtype))
   {
     atype = TREE_TYPE (fld);
+      afield_decl = fld;
     if (TREE_CODE (atype) != ARRAY_TYPE)
return false;
     if (VAR_P (arg) && DECL_SIZE (fld))
@@ -12760,13 +12780,16 @@ array_at_struct_end_p (tree ref)
      ref = TREE_OPERAND (ref, 0);
    }

-  /* The array now is at struct end.  Treat flexible arrays as
+  gcc_assert (!afield_decl
+      || (afield_decl && TREE_CODE (afield_decl) == FIELD_DECL));
+
+  /* The array now is at struct end.  Treat flexible array member as
     always subject to extend, even into just padding constrained by
     an underlying decl.  */
  if (! TYPE_SIZE (atype)
      || ! TYPE_DOMAIN (atype)
      || ! TYPE_MAX_VALUE (TYPE_DOMAIN (atype)))
-    return true;
+    return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;

  /* If the reference is based on a declared entity, the size of the array
     is constrained by its given domain.  (Do not trust commons PR/69368).  */
@@ -12788,9 +12811,9 @@ array_at_struct_end_p (tree ref)
      if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (atype))) != INTEGER_CST
 || TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST
          || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST)
- return true;
+ return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
      if (! get_addr_base_and_unit_offset (ref_to_array, &offset))
- return true;
+ return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;

      /* If at least one extra element fits it is a flexarray.  */
      if (known_le ((wi::to_offset (TYPE_MAX_VALUE (TYPE_DOMAIN (atype)))
@@ -12798,12 +12821,12 @@ array_at_struct_end_p (tree ref)
    + 2)
   * wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (atype))),
   wi::to_offset (DECL_SIZE_UNIT (ref)) - offset))
- return true;
+ return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;

      return false;
    }

-  return true;
+  return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
}

/* Return a tree representing the offset, in bytes, of the field referenced
diff --git a/gcc/tree.h b/gcc/tree.h
index e6564aaccb7b..f911c0a46e69 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2993,6 +2993,12 @@ extern void decl_value_expr_insert (tree, tree);
#define DECL_PADDING_P(NODE) \
  (FIELD_DECL_CHECK (NODE)->decl_common.decl_flag_3)

+/* Used in a FIELD_DECL to indicate whether this field is not a flexible
+   array member. This is only valid for the last array type field of a
+   structure.  */
+#define DECL_NOT_FLEXARRAY(NODE) \
+  (FIELD_DECL_CHECK (NODE)->decl_common.decl_not_flexarray)
+
/* A numeric unique identifier for a LABEL_DECL.  The UID allocation is
   dense, unique within any one function, and may be used to index arrays.
   If the value is -1, then no UID has been assigned.  */
@@ -5531,10 +5537,10 @@ extern tree component_ref_field_offset (tree);
   returns null.  */
enum struct special_array_member
  {
-   none,      /* Not a special array member.  */
-   int_0,     /* Interior array member with size zero.  */
-   trail_0,   /* Trailing array member with size zero.  */
-   trail_1    /* Trailing array member with one element.  */
+    none, /* Not a special array member.  */
+    int_0, /* Interior array member with size zero.  */
+    trail_0, /* Trailing array member with size zero.  */
+    trail_1 /* Trailing array member with one element.  */
  };

/* Return the size of the member referenced by the COMPONENT_REF, using
