diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 3333cddeece..660ac07f3d4 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -737,6 +737,11 @@ Wformat-truncation=
 C ObjC C++ LTO ObjC++ Joined RejectNegative UInteger Var(warn_format_trunc) Warning LangEnabledBy(C ObjC C++ LTO ObjC++,Wformat=, warn_format >= 1, 0) IntegerRange(0, 2)
 Warn about calls to snprintf and similar functions that truncate output.
 
+Wgnu-variable-sized-type-not-at-end
+C C++ Var(warn_variable_sized_type_not_at_end) Warning
+Warn about structures or unions with C99 flexible array members are not
+at the end of a structure.
+
 Wif-not-aligned
 C ObjC C++ ObjC++ Var(warn_if_not_aligned) Init(1) Warning
 Warn when the field in a struct is not aligned.
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 14c54809b9d..1632043a8ff 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -9269,6 +9269,14 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
 	TYPE_INCLUDE_FLEXARRAY (t)
 	  = is_last_field && TYPE_INCLUDE_FLEXARRAY (TREE_TYPE (x));
 
+      if (warn_variable_sized_type_not_at_end
+	  && !is_last_field
+	  && RECORD_OR_UNION_TYPE_P (TREE_TYPE (x))
+	  && TYPE_INCLUDE_FLEXARRAY (TREE_TYPE (x)))
+	warning_at (DECL_SOURCE_LOCATION (x),
+		    OPT_Wgnu_variable_sized_type_not_at_end,
+		    "variable sized type not at the end of a struct");
+
       if (DECL_NAME (x)
 	  || RECORD_OR_UNION_TYPE_P (TREE_TYPE (x)))
 	saw_named_field = true;
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index fd3745c5608..0928b962a60 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -1748,7 +1748,50 @@ Flexible array members may only appear as the last member of a
 A structure containing a flexible array member, or a union containing
 such a structure (possibly recursively), may not be a member of a
 structure or an element of an array.  (However, these uses are
-permitted by GCC as extensions.)
+permitted by GCC as extensions, see details below.)
+@end itemize
+
+GCC extension accepts a structure containing an ISO C99 @dfn{flexible array
+member}, or a union containing such a structure (possibly recursively)
+to be a member of a structure.
+
+There are two situations:
+
+@itemize @bullet
+@item
+A structure or a union with a C99 flexible array member is the last field
+of another structure, for example:
+
+@smallexample
+struct flex  @{ int length; char data[]; @};
+union union_flex @{ int others; struct flex f; @};
+
+struct out_flex_struct @{ int m; struct flex flex_data; @};
+struct out_flex_union @{ int n; union union_flex flex_data; @};
+@end smallexample
+
+In the above, both @code{out_flex_struct.flex_data.data[]} and
+@code{out_flex_union.flex_data.f.data[]} are considered as flexible arrays too.
+
+
+@item
+A structure or a union with a C99 flexible array member is the middle field
+of another structure, for example:
+
+@smallexample
+struct flex  @{ int length; char data[]; @};
+
+struct mid_flex @{ int m; struct flex flex_data; int n; @};
+@end smallexample
+
+In the above, @code{mid_flex.flex_data.data[]} has undefined behavior.
+Compilers do not handle such case consistently, Any code relying on
+such case should be modified to ensure that flexible array members
+only end up at the ends of structures.
+
+Please use warning option  @option{-Wgnu-variable-sized-type-not-at-end} to
+identify all such cases in the source code and modify them.  This extension
+will be deprecated from gcc in the next release.
 @end itemize
 
 Non-empty initialization of zero-length
diff --git a/gcc/testsuite/gcc.dg/variable-sized-type-flex-array.c b/gcc/testsuite/gcc.dg/variable-sized-type-flex-array.c
new file mode 100644
index 00000000000..e3f65c5ed07
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/variable-sized-type-flex-array.c
@@ -0,0 +1,31 @@
+/* Test for -Wgnu-variable-sized-type-not-at-end on structure/union with 
+   C99 flexible array members being embedded into another structure.  */
+/* { dg-do compile } */
+/* { dg-options "-Wgnu-variable-sized-type-not-at-end" } */
+
+struct flex { int n; int data[]; };
+struct out_flex_end { int m; struct flex flex_data; }; /* { dg-bogus "variable sized type not at the end of a struct" } */
+struct out_flex_mid { struct flex flex_data; int m; };  /* { dg-warning "variable sized type not at the end of a struct" } */
+/* since the warning has been issued for out_flex_mid, no need to
+   issue warning again when it is included in another structure/union.  */
+struct outer_flex_mid { struct out_flex_mid out_flex_data; int p; }; /* { dg-bogus "variable sized type not at the end of a struct" } */
+union flex_union_mid { int a; struct outer_flex_mid b; }; /* { dg-bogus "variable sized type not at the end of a struct" } */
+
+
+struct flex0 { int n; int data[0]; };
+struct out_flex_end0 { int m; struct flex0 flex_data; }; /* { dg-bogus "variable sized type not at the end of a struct" } */
+struct out_flex_mid0 { struct flex0 flex_data; int m; };  /* { dg-bogus "variable sized type not at the end of a struct" } */
+struct outer_flex_mid0 { struct out_flex_mid0 out_flex_data; int p; }; /* { dg-bogus "variable sized type not at the end of a struct" } */
+union flex_union_mid0 { int a; struct outer_flex_mid0 b; }; /* { dg-bogus "variable sized type not at the end of a struct" } */
+
+struct flex1 { int n; int data[1]; };
+struct out_flex_end1 { int m; struct flex1 flex_data; }; /* { dg-bogus "variable sized type not at the end of a struct" } */
+struct out_flex_mid1 { struct flex1 flex_data; int m; }; /* { dg-bogus "variable sized type not at the end of a struct" } */ 
+struct outer_flex_mid1 { struct out_flex_mid1 out_flex_data; int p; }; /* { dg-bogus "variable sized type not at the end of a struct" } */
+union flex_union_mid1 { int a; struct outer_flex_mid1 b; }; /* { dg-bogus "variable sized type not at the end of a struct" } */
+
+struct flexn { int n; int data[8]; }; 
+struct out_flex_endn { int m; struct flexn flex_data; }; /* { dg-bogus "variable sized type not at the end of a struct" } */
+struct out_flex_midn { struct flexn flex_data; int m; }; /* { dg-bogus"variable sized type not at the end of a struct" } */ 
+struct outer_flex_midn { struct out_flex_midn out_flex_data; int p; }; /* { dg-bogus"variable sized type not at the end of a struct" } */
+union flex_union_midn { int a; struct outer_flex_midn b; }; /* { dg-bogus "variable sized type not at the end of a struct" } */
