diff mbox series

[1/4] c: runtime checking for assigment of VM types 1/4

Message ID c179e0ea10f1d14b56ada367b0cda0fafe5b5632.camel@tugraz.at
State New
Headers show
Series [1/4] c: runtime checking for assigment of VM types 1/4 | expand

Commit Message

Martin Uecker Nov. 18, 2023, 9:12 p.m. UTC
When checking compatibility of types during assignment, collect
all pairs of types where the outermost bound needs to match at
run-time.  This list is then processed to add runtime checks for
each bound.

gcc/c-family:
	* c-opt (fvla-bounds): New flag.

gcc/c:
	* c-typeck.cc (struct instrument_data): New structure.
	(comp_target_types_instr convert_for_assignment_instrument): New
	interfaces for existing functions.
	(struct comptypes_data): Add instrumentation.
 	(comptypes_check_enum_int_intr): New interface.
 	(comptypes_check_enum_int): Old interface (calls new).
	(comptypes_internal): Collect VLA types needed for UBSan.
	(comp_target_types_instr): New interface.
	(comp_target_types): Old interface (calls new).
	(function_types_compatible_p): No instrumentation for function
	arguments.
	(process_vm_constraints): New function.
	(convert_argument): Adapt.
	(convert_for_assignment_instrument): New interface.
 	(convert_for_assignment): Instrument assignments.
	(c_instrument_vm_assign): Helper function.
	(process_vm_constraints): Helper function.

gcc/doc/:
	* invoke.texi (fvla-bounds): Document new flag.

gcc/testsuite:
	* gcc.dg/vla-bounds-1.c: New test.
	* gcc.dg/vla-bounds-assign-1.c: New test.
	* gcc.dg/vla-bounds-assign-2.c: New test.
	* gcc.dg/vla-bounds-assign-3.c: New test.
	* gcc.dg/vla-bounds-assign-4.c: New test.
	* gcc.dg/vla-bounds-func-1.c: New test.
	* gcc.dg/vla-bounds-init-1.c: New test.
	* gcc.dg/vla-bounds-init-2.c: New test.
	* gcc.dg/vla-bounds-init-3.c: New test.
	* gcc.dg/vla-bounds-init-4.c: New test.
	* gcc.dg/vla-bounds-nest-1.c: New test.
	* gcc.dg/vla-bounds-nest-2.c: New test.
	* gcc.dg/vla-bounds-ret-1.c: New test.
	* gcc.dg/vla-bounds-ret-2.c: New test.
---
 gcc/c-family/c.opt                         |   4 +
 gcc/c/c-typeck.cc                          | 171 ++++++++++++++++++---
 gcc/doc/invoke.texi                        |  15 ++
 gcc/testsuite/gcc.dg/vla-bounds-1.c        |  85 ++++++++++
 gcc/testsuite/gcc.dg/vla-bounds-assign-1.c | 126 +++++++++++++++
 gcc/testsuite/gcc.dg/vla-bounds-assign-2.c | 126 +++++++++++++++
 gcc/testsuite/gcc.dg/vla-bounds-assign-3.c | 126 +++++++++++++++
 gcc/testsuite/gcc.dg/vla-bounds-assign-4.c | 133 ++++++++++++++++
 gcc/testsuite/gcc.dg/vla-bounds-func-1.c   |  56 +++++++
 gcc/testsuite/gcc.dg/vla-bounds-init-1.c   | 125 +++++++++++++++
 gcc/testsuite/gcc.dg/vla-bounds-init-2.c   | 125 +++++++++++++++
 gcc/testsuite/gcc.dg/vla-bounds-init-3.c   | 126 +++++++++++++++
 gcc/testsuite/gcc.dg/vla-bounds-init-4.c   | 125 +++++++++++++++
 gcc/testsuite/gcc.dg/vla-bounds-nest-1.c   |  39 +++++
 gcc/testsuite/gcc.dg/vla-bounds-nest-2.c   |  33 ++++
 gcc/testsuite/gcc.dg/vla-bounds-ret-1.c    | 132 ++++++++++++++++
 gcc/testsuite/gcc.dg/vla-bounds-ret-2.c    | 133 ++++++++++++++++
 17 files changed, 1661 insertions(+), 19 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-1.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-1.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-2.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-3.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-4.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-1.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-1.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-2.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-3.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-4.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-nest-1.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-nest-2.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-ret-1.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-ret-2.c
diff mbox series

Patch

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index b10c6057cd1..29bc0956181 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -2280,6 +2280,10 @@  fvisibility-ms-compat
 C++ ObjC++ Var(flag_visibility_ms_compat)
 Changes visibility to match Microsoft Visual Studio by default.
 
+fvla-bounds
+C Var(flag_vla_bounds)
+Emit run-time consistency checks for variably-modified types.
+
 fvtable-gc
 C++ ObjC++ WarnRemoved
 No longer supported.
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 1dbb4471a88..cb5887b6255 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -93,11 +93,13 @@  static tree qualify_type (tree, tree);
 struct comptypes_data;
 static bool tagged_types_tu_compatible_p (const_tree, const_tree,
 					  struct comptypes_data *);
-static bool comp_target_types (location_t, tree, tree);
 static bool function_types_compatible_p (const_tree, const_tree,
 					 struct comptypes_data *);
 static bool type_lists_compatible_p (const_tree, const_tree,
 				     struct comptypes_data *);
+
+static bool comp_target_types_instr (location_t, tree, tree,
+				     struct instrument_data **);
 static tree lookup_field (tree, tree);
 static int convert_arguments (location_t, vec<location_t>, tree,
 			      vec<tree, va_gc> *, vec<tree, va_gc> *, tree,
@@ -106,6 +108,9 @@  static tree pointer_diff (location_t, tree, tree, tree *);
 static tree convert_for_assignment (location_t, location_t, tree, tree, tree,
 				    enum impl_conv, bool, tree, tree, int,
 				    int = 0);
+static tree convert_for_assignment_instrument (location_t, location_t, tree, tree, tree,
+				    enum impl_conv, bool, tree, tree, int, int,
+				    struct instrument_data **);
 static tree valid_compound_expr_initializer (tree, tree);
 static void push_string (const char *);
 static void push_member_name (tree);
@@ -1058,6 +1063,38 @@  common_type (tree t1, tree t2)
   return c_common_type (t1, t2);
 }
 
+
+/* Instrument assignment of variably modified types.  */
+
+static tree
+c_instrument_vm_assign (location_t loc, tree a, tree b)
+{
+  gcc_assert (flag_vla_bounds);
+
+  gcc_assert (TREE_CODE (a) == ARRAY_TYPE);
+  gcc_assert (TREE_CODE (b) == ARRAY_TYPE);
+
+  tree as = TYPE_MAX_VALUE (TYPE_DOMAIN (a));
+  tree bs = TYPE_MAX_VALUE (TYPE_DOMAIN (b));
+
+  as = fold_build2 (PLUS_EXPR, sizetype, as, size_one_node);
+  bs = fold_build2 (PLUS_EXPR, sizetype, bs, size_one_node);
+
+  tree t = build2 (NE_EXPR, boolean_type_node, as, bs);
+  tree tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
+
+  return build3 (COND_EXPR, void_type_node, t, tt, void_node);
+}
+
+
+
+struct instrument_data {
+
+  tree t1;
+  tree t2;
+  struct instrument_data *next;
+};
+
 struct comptypes_data {
   bool enum_and_int_p;
   bool different_types_p;
@@ -1065,6 +1102,8 @@  struct comptypes_data {
   bool anon_field;
 
   const struct tagged_tu_seen_cache* cache;
+
+  struct instrument_data **instr_vec;
 };
 
 /* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
@@ -1083,16 +1122,25 @@  comptypes (tree type1, tree type2)
 /* Like comptypes, but if it returns non-zero because enum and int are
    compatible, it sets *ENUM_AND_INT_P to true.  */
 
-int
-comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p)
+static int
+comptypes_check_enum_int_instr (tree type1, tree type2, bool *enum_and_int_p,
+				struct instrument_data **instr_vec)
 {
   struct comptypes_data data = { };
+  data.instr_vec = instr_vec;
   bool ret = comptypes_internal (type1, type2, &data);
+
   *enum_and_int_p = data.enum_and_int_p;
 
   return ret ? (data.warning_needed ? 2 : 1) : 0;
 }
 
+int
+comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p)
+{
+  return comptypes_check_enum_int_instr (type1, type2, enum_and_int_p, NULL);
+}
+
 /* Like comptypes, but if it returns nonzero for different types, it
    sets *DIFFERENT_TYPES_P to true.  */
 
@@ -1252,7 +1300,18 @@  comptypes_internal (const_tree type1, const_tree type2,
 	if (d1_variable != d2_variable)
 	  data->different_types_p = true;
 	if (d1_variable || d2_variable)
-	  return true;
+	  {
+	    if (NULL != data->instr_vec)
+	      {
+		struct instrument_data *id
+			= (struct instrument_data *)xmalloc (sizeof *id);;
+		id->t1 = TYPE_MAIN_VARIANT (t2);
+		id->t2 = TYPE_MAIN_VARIANT (t1);
+		id->next = *data->instr_vec;
+		*data->instr_vec = id;
+	      }
+	    return true;
+	  }
 	if (d1_zero && d2_zero)
 	  return true;
 	if (d1_zero || d2_zero
@@ -1288,7 +1347,8 @@  comptypes_internal (const_tree type1, const_tree type2,
    subset of the other.  */
 
 static bool
-comp_target_types (location_t location, tree ttl, tree ttr)
+comp_target_types_instr (location_t location, tree ttl, tree ttr,
+			 struct instrument_data **instr_vec)
 {
   int val;
   int val_ped;
@@ -1322,8 +1382,7 @@  comp_target_types (location_t location, tree ttl, tree ttr)
 	 ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), TYPE_QUAL_ATOMIC)
 	 : TYPE_MAIN_VARIANT (mvr));
 
-  enum_and_int_p = false;
-  val = comptypes_check_enum_int (mvl, mvr, &enum_and_int_p);
+  val = comptypes_check_enum_int_instr (mvl, mvr, &enum_and_int_p, instr_vec);
 
   if (val == 1 && val_ped != 1)
     pedwarn_c11 (location, OPT_Wpedantic, "invalid use of pointers to arrays with different qualifiers "
@@ -1338,6 +1397,13 @@  comp_target_types (location_t location, tree ttl, tree ttr)
 
   return val;
 }
+
+static int
+comp_target_types (location_t location, tree ttl, tree ttr)
+{
+  return comp_target_types_instr (location, ttl, ttr, NULL);
+}
+
 
 /* Subroutines of `comptypes'.  */
 
@@ -1551,8 +1617,13 @@  function_types_compatible_p (const_tree f1, const_tree f2,
       return val;
     }
 
-  /* Both types have argument lists: compare them and propagate results.  */
+  /* Both types have argument lists: compare them and propagate results.
+     Turn off instrumentation for bounds as these are all arrays of
+     unspecified size.  */
+  auto instr_vec_tmp = data->instr_vec;
+  data->instr_vec = NULL;
   val1 = type_lists_compatible_p (args1, args2, data);
+  data->instr_vec = instr_vec_tmp;
   return val1;
 }
 
@@ -3371,10 +3442,11 @@  convert_argument (location_t ploc, tree function, tree fundecl,
   if (excess_precision)
     val = build1 (EXCESS_PRECISION_EXPR, valtype, val);
 
-  tree parmval = convert_for_assignment (ploc, ploc, type,
-					 val, origtype, ic_argpass,
-					 npc, fundecl, function,
-					 parmnum + 1, warnopt);
+  tree parmval = convert_for_assignment_instrument (ploc, ploc, type,
+						    val, origtype, ic_argpass,
+						    npc, fundecl, function,
+						    parmnum + 1, warnopt,
+						    NULL);
 
   if (targetm.calls.promote_prototypes (fundecl ? TREE_TYPE (fundecl) : 0)
       && INTEGRAL_TYPE_P (type)
@@ -3384,6 +3456,24 @@  convert_argument (location_t ploc, tree function, tree fundecl,
   return parmval;
 }
 
+
+/* Process all constraints for variably-modified types.  */
+
+static tree
+process_vm_constraints (location_t location,
+			struct instrument_data **instr_vec)
+{
+  tree instr_expr = void_node;
+
+  for (struct instrument_data* d = *instr_vec; d; d = d->next)
+    {
+      tree in = c_instrument_vm_assign (location, d->t1, d->t2);
+      instr_expr = fold_build2 (COMPOUND_EXPR, void_type_node, in, instr_expr);
+    }
+  return instr_expr;
+}
+
+
 /* Convert the argument expressions in the vector VALUES
    to the types in the list TYPELIST.
 
@@ -6741,7 +6831,50 @@  static tree
 convert_for_assignment (location_t location, location_t expr_loc, tree type,
 			tree rhs, tree origtype, enum impl_conv errtype,
 			bool null_pointer_constant, tree fundecl,
-			tree function, int parmnum, int warnopt /* = 0 */)
+			tree function, int parmnum, int warnopt)
+{
+  struct instrument_data *instr_first = NULL;
+  struct instrument_data **instr_vec = NULL;
+
+  if (flag_vla_bounds && (ic_init_const != errtype))
+    instr_vec = &instr_first;
+
+  tree ret = convert_for_assignment_instrument (location, expr_loc, type,
+						rhs, origtype, errtype,
+						null_pointer_constant, fundecl,
+						function, parmnum, warnopt,
+						instr_vec);
+  if (instr_vec)
+    {
+      if (ret && error_mark_node != ret && instr_first != NULL)
+	{
+	  /* We have to make sure that the rhs is evaluated first,
+	     because we may use size expressions in it to check bounds.  */
+	  tree instr_expr = process_vm_constraints (location, instr_vec);
+	  if (void_node != instr_expr)
+	    {
+	      ret = save_expr (ret);
+	      instr_expr = fold_build2 (COMPOUND_EXPR, void_type_node, ret, instr_expr);
+	      ret = fold_build2 (COMPOUND_EXPR, TREE_TYPE (ret), instr_expr, ret);
+	    }
+	}
+      while (instr_first)
+	{
+	  struct instrument_data *next = instr_first->next;
+	  free (instr_first);
+	  instr_first = next;
+	}
+      instr_vec = NULL;
+    }
+  return ret;
+}
+
+static tree
+convert_for_assignment_instrument (location_t location, location_t expr_loc, tree type,
+			tree rhs, tree origtype, enum impl_conv errtype,
+			bool null_pointer_constant, tree fundecl,
+			tree function, int parmnum, int warnopt,
+			struct instrument_data **instr_vec)
 {
   enum tree_code codel = TREE_CODE (type);
   tree orig_rhs = rhs;
@@ -6985,11 +7118,11 @@  convert_for_assignment (location_t location, location_t expr_loc, tree type,
       rhs = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (rhs)), rhs);
       SET_EXPR_LOCATION (rhs, location);
 
-      rhs = convert_for_assignment (location, expr_loc,
-				    build_pointer_type (TREE_TYPE (type)),
-				    rhs, origtype, errtype,
-				    null_pointer_constant, fundecl, function,
-				    parmnum, warnopt);
+      rhs = convert_for_assignment_instrument (location, expr_loc,
+					       build_pointer_type (TREE_TYPE (type)),
+					       rhs, origtype, errtype,
+					       null_pointer_constant, fundecl, function,
+					       parmnum, warnopt, instr_vec);
       if (rhs == error_mark_node)
 	return error_mark_node;
 
@@ -7400,7 +7533,7 @@  convert_for_assignment (location_t location, location_t expr_loc, tree type,
 	 Meanwhile, the lhs target must have all the qualifiers of the rhs.  */
       if ((VOID_TYPE_P (ttl) && !TYPE_ATOMIC (ttl))
 	  || (VOID_TYPE_P (ttr) && !TYPE_ATOMIC (ttr))
-	  || (target_cmp = comp_target_types (location, type, rhstype))
+	  || (target_cmp = comp_target_types_instr (location, type, rhstype, instr_vec))
 	  || is_opaque_pointer
 	  || ((c_common_unsigned_type (mvl)
 	       == c_common_unsigned_type (mvr))
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 1748afdbfe0..c94ca59086b 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -10269,6 +10269,13 @@  void g (int n)
 @option{-Warray-parameter} option triggers warnings for similar problems
 involving ordinary array arguments.
 
+@opindex Wvla-parameter-missing-check
+@item -Wvla-parameter-missing-check
+Warn when function calls can not be instrumented with the use of
+@option{-fvla-bounds} to detect inconsistencies between the bounds of
+VLA parameters at runtime.
+
+
 @opindex Wvolatile-register-var
 @opindex Wno-volatile-register-var
 @item -Wvolatile-register-var
@@ -20052,6 +20059,14 @@  computing CRC32).
 
 The @var{string} should be different for every file you compile.
 
+@opindex fvla-bounds
+@item -fvla-bounds
+This option is only available when compiling C code.  If activated,
+additional code is emitted that verifies at run time for assignments
+involving variably-modified types that corresponding size expressions
+evaluate to the same value.
+
+
 @opindex save-temps
 @item -save-temps
 Store the usual ``temporary'' intermediate files permanently; name them
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-1.c b/gcc/testsuite/gcc.dg/vla-bounds-1.c
new file mode 100644
index 00000000000..7f71c1abbe5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-1.c
@@ -0,0 +1,85 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+/* test return types */
+
+int main()
+{
+	int m = 4, n = 3;
+
+	int u = 4;
+	int v = 3;
+
+	/* initialization */
+
+	char a[4];
+	char (*pa)[u] = &a;
+	char (*qa)[v];
+
+	char b[u];
+	const char (*pb)[u] = &b;
+	char (*qb)[v];
+
+	char c[4][3];
+	char (*pc0)[u][v] = &c;
+	char (*qc0)[v][u];
+
+	char (*pc1)[u][3] = &c;
+	char (*qc1)[v][3];
+
+	char (*pc2)[4][v] = &c;
+	char (*qc2)[4][u];
+
+	char (*pc3)[][v] = &c;	
+
+	char d[u][v];
+	char (*pd0)[4][3] = &d;
+	char (*qd0)[3][4];
+
+	char (*pd1)[u][3] = &d;	
+	char (*qd1)[v][4];
+
+	char (*pd2)[4][v] = &d;
+	char (*qd2)[3][u];
+
+	char (*pd3)[u][v] = &d;
+	char (*qd3)[v][u];
+
+	char e[4][v];
+	char (*pe0)[4][3] = &e;
+	char (*qe0)[4][4];
+
+	char f[u][3];
+	char (*pf)[4][3] = &f;
+	char (*qf)[3][3];
+
+	char (*g[u])[v];
+	char (*(*pg)[u])[v] = &g;
+
+	/* assignment */
+
+	pa = &a;
+
+	pb = &b;
+	
+	pc0 = &c;
+	
+	pc1 = &c;
+
+	pc2 = &c;
+
+	pd0 = &d;
+
+	pd1 = &d;
+	
+	pd2 = &d;
+	
+	pd3 = &d;
+	
+	pe0 = &e;
+
+	pf = &f;
+
+	return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-assign-1.c b/gcc/testsuite/gcc.dg/vla-bounds-assign-1.c
new file mode 100644
index 00000000000..40232925341
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-assign-1.c
@@ -0,0 +1,126 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+#define TRY(...) __VA_ARGS__ __builtin_abort();
+#define ERROR(...)
+
+int main()
+{
+	signal(SIGILL, handler);
+
+	int m = 4, n = 3;
+
+	int u = 4;
+	int v = 3;
+
+	/* initialization */
+
+	char a[4];
+	char (*pa)[u] = &a;
+ERROR(	char (*qa)[v] = &a; ) // 3 != 4
+	char (*qa)[v];
+
+	char b[u];
+	const char (*pb)[u] = &b;
+ERROR(	char (*qb)[v] = &b; )	// 3 != 4
+	char (*qb)[v];
+
+	char c[4][3];
+	char (*pc0)[u][v] = &c;
+ERROR(	char (*qc0)[v][u] = &c;	) // 3 != 4, 4 != 3
+	char (*qc0)[v][u];
+
+	char (*pc1)[u][3] = &c;
+ERROR(	char (*qc1)[v][3] = &c; ) // 3 != 4
+	char (*qc1)[v][3];
+
+	char (*pc2)[4][v] = &c;
+ERROR(	char (*qc2)[4][u] = &c; ) // 4 != 3
+	char (*qc2)[4][u];
+
+	char (*pc3)[][v] = &c;	
+ERROR(	char (*qc3)[][u] = &c; ) // 4 != 3
+
+	char d[u][v];
+	char (*pd0)[4][3] = &d;
+ERROR(	char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3
+	char (*qd0)[3][4];
+
+	char (*pd1)[u][3] = &d;	
+ERROR(	char (*qd1)[v][4] = &d;	) // 3 != 4, 4 != 3
+	char (*qd1)[v][4];
+
+	char (*pd2)[4][v] = &d;
+ERROR(	char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3
+	char (*qd2)[3][u];
+
+	char (*pd3)[u][v] = &d;
+ERROR(	char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3
+	char (*qd3)[v][u];
+
+	char e[4][v];
+	char (*pe0)[4][3] = &e;
+ERROR(	char (*qe0)[4][4] = &e; ) // 4 != 3
+	char (*qe0)[4][4];
+
+	char f[u][3];
+	char (*pf)[4][3] = &f;
+ERROR(	char (*qf)[3][3] = &f; ) // 3 != 4
+	char (*qf)[3][3];
+
+	char (*g[u])[v];
+	char (*(*pg)[u])[v] = &g;
+ERROR(	char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3
+
+	/* assignment */
+
+	pa = &a;
+TRY(	qa = &a; ) // 3 != 4
+
+	pb = &b;
+ERROR(	qb = &b; ) // 3 != 4
+	
+	pc0 = &c;
+ERROR(	qc0 = &c; ) // 3 != 4, 4 != 3
+	
+	pc1 = &c;
+ERROR(	qc1 = &c; ) // 3 != 4
+
+	pc2 = &c;
+ERROR(	qc2 = &c; ) // 4 != 3
+
+	pd0 = &d;
+ERROR(	qd0 = &d; ) // 3 != 4, 4 != 3
+
+	pd1 = &d;
+ERROR(	qd1 = &d; ) // 3 != 4, 4 != 3
+	
+	pd2 = &d;
+ERROR(	qd2 = &d; ) // 3 != 4, 4 != 3
+	
+	pd3 = &d;
+ERROR(	qd3 = &d; ) // 3 != 4, 4 != 3
+	
+	pe0 = &e;
+ERROR(	qe0 = &e; ) // 4 != 3
+
+	pf = &f;
+ERROR(	qf = &f; ) // 3 != 4
+
+	/* return */
+ERROR(	z0(); )	// 5 != 3, 5, != 3
+
+ERROR(	z1(); )	// 4 != 3
+
+ERROR(	z2(); )  //  5 != 4	
+
+ERROR(	char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5
+
+	return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-assign-2.c b/gcc/testsuite/gcc.dg/vla-bounds-assign-2.c
new file mode 100644
index 00000000000..f1f98704a1e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-assign-2.c
@@ -0,0 +1,126 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+#define TRY(...) __VA_ARGS__ __builtin_abort();
+#define ERROR(...)
+
+int main()
+{
+	signal(SIGILL, handler);
+
+	int m = 4, n = 3;
+
+	int u = 4;
+	int v = 3;
+
+	/* initialization */
+
+	char a[4];
+	char (*pa)[u] = &a;
+ERROR(	char (*qa)[v] = &a; ) // 3 != 4
+	char (*qa)[v];
+
+	char b[u];
+	const char (*pb)[u] = &b;
+ERROR(	char (*qb)[v] = &b; )	// 3 != 4
+	char (*qb)[v];
+
+	char c[4][3];
+	char (*pc0)[u][v] = &c;
+ERROR(	char (*qc0)[v][u] = &c;	) // 3 != 4, 4 != 3
+	char (*qc0)[v][u];
+
+	char (*pc1)[u][3] = &c;
+ERROR(	char (*qc1)[v][3] = &c; ) // 3 != 4
+	char (*qc1)[v][3];
+
+	char (*pc2)[4][v] = &c;
+ERROR(	char (*qc2)[4][u] = &c; ) // 4 != 3
+	char (*qc2)[4][u];
+
+	char (*pc3)[][v] = &c;	
+ERROR(	char (*qc3)[][u] = &c; ) // 4 != 3
+
+	char d[u][v];
+	char (*pd0)[4][3] = &d;
+ERROR(	char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3
+	char (*qd0)[3][4];
+
+	char (*pd1)[u][3] = &d;	
+ERROR(	char (*qd1)[v][4] = &d;	) // 3 != 4, 4 != 3
+	char (*qd1)[v][4];
+
+	char (*pd2)[4][v] = &d;
+ERROR(	char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3
+	char (*qd2)[3][u];
+
+	char (*pd3)[u][v] = &d;
+ERROR(	char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3
+	char (*qd3)[v][u];
+
+	char e[4][v];
+	char (*pe0)[4][3] = &e;
+ERROR(	char (*qe0)[4][4] = &e; ) // 4 != 3
+	char (*qe0)[4][4];
+
+	char f[u][3];
+	char (*pf)[4][3] = &f;
+ERROR(	char (*qf)[3][3] = &f; ) // 3 != 4
+	char (*qf)[3][3];
+
+	char (*g[u])[v];
+	char (*(*pg)[u])[v] = &g;
+ERROR(	char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3
+
+	/* assignment */
+
+	pa = &a;
+ERROR(	qa = &a; ) // 3 != 4
+
+	pb = &b;
+ERROR(	qb = &b; ) // 3 != 4
+	
+	pc0 = &c;
+TRY(	qc0 = &c; ) // 3 != 4, 4 != 3
+	
+	pc1 = &c;
+ERROR(	qc1 = &c; ) // 3 != 4
+
+	pc2 = &c;
+ERROR(	qc2 = &c; ) // 4 != 3
+
+	pd0 = &d;
+ERROR(	qd0 = &d; ) // 3 != 4, 4 != 3
+
+	pd1 = &d;
+ERROR(	qd1 = &d; ) // 3 != 4, 4 != 3
+	
+	pd2 = &d;
+ERROR(	qd2 = &d; ) // 3 != 4, 4 != 3
+	
+	pd3 = &d;
+ERROR(	qd3 = &d; ) // 3 != 4, 4 != 3
+	
+	pe0 = &e;
+ERROR(	qe0 = &e; ) // 4 != 3
+
+	pf = &f;
+ERROR(	qf = &f; ) // 3 != 4
+
+	/* return */
+ERROR(	z0(); )	// 5 != 3, 5, != 3
+
+ERROR(	z1(); )	// 4 != 3
+
+ERROR(	z2(); )  //  5 != 4	
+
+ERROR(	char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5
+
+	return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-assign-3.c b/gcc/testsuite/gcc.dg/vla-bounds-assign-3.c
new file mode 100644
index 00000000000..0a811de5ffc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-assign-3.c
@@ -0,0 +1,126 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+#define TRY(...) __VA_ARGS__ __builtin_abort();
+#define ERROR(...)
+
+int main()
+{
+	signal(SIGILL, handler);
+
+	int m = 4, n = 3;
+
+	int u = 4;
+	int v = 3;
+
+	/* initialization */
+
+	char a[4];
+	char (*pa)[u] = &a;
+ERROR(	char (*qa)[v] = &a; ) // 3 != 4
+	char (*qa)[v];
+
+	char b[u];
+	const char (*pb)[u] = &b;
+ERROR(	char (*qb)[v] = &b; )	// 3 != 4
+	char (*qb)[v];
+
+	char c[4][3];
+	char (*pc0)[u][v] = &c;
+ERROR(	char (*qc0)[v][u] = &c;	) // 3 != 4, 4 != 3
+	char (*qc0)[v][u];
+
+	char (*pc1)[u][3] = &c;
+ERROR(	char (*qc1)[v][3] = &c; ) // 3 != 4
+	char (*qc1)[v][3];
+
+	char (*pc2)[4][v] = &c;
+ERROR(	char (*qc2)[4][u] = &c; ) // 4 != 3
+	char (*qc2)[4][u];
+
+	char (*pc3)[][v] = &c;	
+ERROR(	char (*qc3)[][u] = &c; ) // 4 != 3
+
+	char d[u][v];
+	char (*pd0)[4][3] = &d;
+ERROR(	char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3
+	char (*qd0)[3][4];
+
+	char (*pd1)[u][3] = &d;	
+ERROR(	char (*qd1)[v][4] = &d;	) // 3 != 4, 4 != 3
+	char (*qd1)[v][4];
+
+	char (*pd2)[4][v] = &d;
+ERROR(	char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3
+	char (*qd2)[3][u];
+
+	char (*pd3)[u][v] = &d;
+ERROR(	char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3
+	char (*qd3)[v][u];
+
+	char e[4][v];
+	char (*pe0)[4][3] = &e;
+ERROR(	char (*qe0)[4][4] = &e; ) // 4 != 3
+	char (*qe0)[4][4];
+
+	char f[u][3];
+	char (*pf)[4][3] = &f;
+ERROR(	char (*qf)[3][3] = &f; ) // 3 != 4
+	char (*qf)[3][3];
+
+	char (*g[u])[v];
+	char (*(*pg)[u])[v] = &g;
+ERROR(	char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3
+
+	/* assignment */
+
+	pa = &a;
+ERROR(	qa = &a; ) // 3 != 4
+
+	pb = &b;
+ERROR(	qb = &b; ) // 3 != 4
+	
+	pc0 = &c;
+ERROR(	qc0 = &c; ) // 3 != 4, 4 != 3
+	
+	pc1 = &c;
+ERROR(	qc1 = &c; ) // 3 != 4
+
+	pc2 = &c;
+ERROR(	qc2 = &c; ) // 4 != 3
+
+	pd0 = &d;
+ERROR(	qd0 = &d; ) // 3 != 4, 4 != 3
+
+	pd1 = &d;
+ERROR(	qd1 = &d; ) // 3 != 4, 4 != 3
+	
+	pd2 = &d;
+ERROR(	qd2 = &d; ) // 3 != 4, 4 != 3
+	
+	pd3 = &d;
+ERROR(	qd3 = &d; ) // 3 != 4, 4 != 3
+	
+	pe0 = &e;
+ERROR(	qe0 = &e; ) // 4 != 3
+
+	pf = &f;
+TRY(	qf = &f; ) // 3 != 4
+
+	/* return */
+ERROR(	z0(); )	// 5 != 3, 5, != 3
+
+ERROR(	z1(); )	// 4 != 3
+
+ERROR(	z2(); )  //  5 != 4	
+
+ERROR(	char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5
+
+	return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-assign-4.c b/gcc/testsuite/gcc.dg/vla-bounds-assign-4.c
new file mode 100644
index 00000000000..3d8553c6426
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-assign-4.c
@@ -0,0 +1,133 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+#define TRY(...) __VA_ARGS__ __builtin_abort();
+#define ERROR(...)
+
+int m, n;
+
+static char (*z0(void))[5][5] { char (*p)[m][n] = 0; return p; }
+static char (*z1(void))[5][5] { char (*p)[5][n] = 0; return p; }
+static char (*z2(void))[5][5] { char (*p)[m][5] = 0; return p; }
+
+
+int main()
+{
+	signal(SIGILL, handler);
+
+	m = 4, n = 3;
+
+	int u = 4;
+	int v = 3;
+
+	/* initialization */
+
+	char a[4];
+	char (*pa)[u] = &a;
+ERROR(	char (*qa)[v] = &a; ) // 3 != 4
+	char (*qa)[v];
+
+	char b[u];
+	const char (*pb)[u] = &b;
+ERROR(	char (*qb)[v] = &b; )	// 3 != 4
+	char (*qb)[v];
+
+	char c[4][3];
+	char (*pc0)[u][v] = &c;
+ERROR(	char (*qc0)[v][u] = &c;	) // 3 != 4, 4 != 3
+	char (*qc0)[v][u];
+
+	char (*pc1)[u][3] = &c;
+ERROR(	char (*qc1)[v][3] = &c; ) // 3 != 4
+	char (*qc1)[v][3];
+
+	char (*pc2)[4][v] = &c;
+ERROR(	char (*qc2)[4][u] = &c; ) // 4 != 3
+	char (*qc2)[4][u];
+
+	char (*pc3)[][v] = &c;	
+ERROR(	char (*qc3)[][u] = &c; ) // 4 != 3
+
+	char d[u][v];
+	char (*pd0)[4][3] = &d;
+ERROR(	char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3
+	char (*qd0)[3][4];
+
+	char (*pd1)[u][3] = &d;	
+ERROR(	char (*qd1)[v][4] = &d;	) // 3 != 4, 4 != 3
+	char (*qd1)[v][4];
+
+	char (*pd2)[4][v] = &d;
+ERROR(	char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3
+	char (*qd2)[3][u];
+
+	char (*pd3)[u][v] = &d;
+ERROR(	char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3
+	char (*qd3)[v][u];
+
+	char e[4][v];
+	char (*pe0)[4][3] = &e;
+ERROR(	char (*qe0)[4][4] = &e; ) // 4 != 3
+	char (*qe0)[4][4];
+
+	char f[u][3];
+	char (*pf)[4][3] = &f;
+ERROR(	char (*qf)[3][3] = &f; ) // 3 != 4
+	char (*qf)[3][3];
+
+	char (*g[u])[v];
+	char (*(*pg)[u])[v] = &g;
+ERROR(	char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3
+
+	/* assignment */
+
+	pa = &a;
+ERROR(	qa = &a; ) // 3 != 4
+
+	pb = &b;
+ERROR(	qb = &b; ) // 3 != 4
+	
+	pc0 = &c;
+ERROR(	qc0 = &c; ) // 3 != 4, 4 != 3
+	
+	pc1 = &c;
+ERROR(	qc1 = &c; ) // 3 != 4
+
+	pc2 = &c;
+ERROR(	qc2 = &c; ) // 4 != 3
+
+	pd0 = &d;
+ERROR(	qd0 = &d; ) // 3 != 4, 4 != 3
+
+	pd1 = &d;
+ERROR(	qd1 = &d; ) // 3 != 4, 4 != 3
+	
+	pd2 = &d;
+ERROR(	qd2 = &d; ) // 3 != 4, 4 != 3
+	
+	pd3 = &d;
+ERROR(	qd3 = &d; ) // 3 != 4, 4 != 3
+	
+	pe0 = &e;
+ERROR(	qe0 = &e; ) // 4 != 3
+
+	pf = &f;
+ERROR(	qf = &f; ) // 3 != 4
+
+	/* return */
+ERROR(	z0(); )	// 5 != 3, 5, != 3
+
+ERROR(	z1(); )	// 4 != 3
+
+ERROR(	z2(); )  //  5 != 4	
+
+TRY(	char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5
+
+	return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-1.c b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c
new file mode 100644
index 00000000000..e4856017419
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c
@@ -0,0 +1,56 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fcheck-vla-bounds" } */
+
+// make sure we do not ICE on any of these
+
+const char* name = "hallo";
+
+
+typedef void (*ht)(int n, int m, char x[n][m]);
+void e(ht) { }
+
+int n, m;
+static void f0(char a[n][m]) { }
+static void f1(int u, int v, char a[u][v]) { }
+static void f2(int u, int v, char a[u][v]) { }
+
+void f(void)
+{
+	int x = 1;
+	int (*m)[x] = 0;
+	m = ({ long* d2; (int (*)[d2[0]])(0); });
+
+	/* function pointer assignments */
+
+	void (*gp)(char x[4][3]) = f0;
+	void (*hp)(int n, int m, char x[n][m]) = f1;
+	ht hp2 = f1;
+	e(f1);
+
+	/* composite type */
+
+	int u = 3; int v = 4;
+	char a[u][v];
+	(1 ? f1 : f2)(u, v, a);
+}
+
+/* size expression in parameter */
+
+extern void a(long N, char (*a)[N]);
+
+static void b(void)
+{
+	a(1, ({ int d = 0; (char (*)[d])0; }) );
+}
+
+/* composite type */
+
+int c(int u, char (*a)[u]);
+int c(int u, char (*a)[u]) { }
+
+int d(void)
+{
+	char a[3];
+	c(3, &a);
+}
+
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-init-1.c b/gcc/testsuite/gcc.dg/vla-bounds-init-1.c
new file mode 100644
index 00000000000..9c9d959ee9e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-init-1.c
@@ -0,0 +1,125 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+#define TRY(...) __VA_ARGS__ __builtin_abort();
+#define ERROR(...)
+
+int main()
+{
+	signal(SIGILL, handler);
+
+	int m = 4, n = 3;
+
+	int u = 4;
+	int v = 3;
+
+	/* initialization */
+
+	char a[4];
+	char (*pa)[u] = &a;
+TRY(	char (*qa)[v] = &a; ) // 3 != 4
+
+	char b[u];
+	const char (*pb)[u] = &b;
+ERROR(	char (*qb)[v] = &b; )	// 3 != 4
+	char (*qb)[v];
+
+	char c[4][3];
+	char (*pc0)[u][v] = &c;
+ERROR(	char (*qc0)[v][u] = &c;	) // 3 != 4, 4 != 3
+	char (*qc0)[v][u];
+
+	char (*pc1)[u][3] = &c;
+ERROR(	char (*qc1)[v][3] = &c; ) // 3 != 4
+	char (*qc1)[v][3];
+
+	char (*pc2)[4][v] = &c;
+ERROR(	char (*qc2)[4][u] = &c; ) // 4 != 3
+	char (*qc2)[4][u];
+
+	char (*pc3)[][v] = &c;	
+ERROR(	char (*qc3)[][u] = &c; ) // 4 != 3
+
+	char d[u][v];
+	char (*pd0)[4][3] = &d;
+ERROR(	char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3
+	char (*qd0)[3][4];
+
+	char (*pd1)[u][3] = &d;	
+ERROR(	char (*qd1)[v][4] = &d;	) // 3 != 4, 4 != 3
+	char (*qd1)[v][4];
+
+	char (*pd2)[4][v] = &d;
+ERROR(	char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3
+	char (*qd2)[3][u];
+
+	char (*pd3)[u][v] = &d;
+ERROR(	char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3
+	char (*qd3)[v][u];
+
+	char e[4][v];
+	char (*pe0)[4][3] = &e;
+ERROR(	char (*qe0)[4][4] = &e; ) // 4 != 3
+	char (*qe0)[4][4];
+
+	char f[u][3];
+	char (*pf)[4][3] = &f;
+ERROR(	char (*qf)[3][3] = &f; ) // 3 != 4
+	char (*qf)[3][3];
+
+	char (*g[u])[v];
+	char (*(*pg)[u])[v] = &g;
+ERROR(	char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3
+
+	/* assignment */
+
+	pa = &a;
+ERROR(	qa = &a; ) // 3 != 4
+
+	pb = &b;
+ERROR(	qb = &b; ) // 3 != 4
+	
+	pc0 = &c;
+ERROR(	qc0 = &c; ) // 3 != 4, 4 != 3
+	
+	pc1 = &c;
+ERROR(	qc1 = &c; ) // 3 != 4
+
+	pc2 = &c;
+ERROR(	qc2 = &c; ) // 4 != 3
+
+	pd0 = &d;
+ERROR(	qd0 = &d; ) // 3 != 4, 4 != 3
+
+	pd1 = &d;
+ERROR(	qd1 = &d; ) // 3 != 4, 4 != 3
+	
+	pd2 = &d;
+ERROR(	qd2 = &d; ) // 3 != 4, 4 != 3
+	
+	pd3 = &d;
+ERROR(	qd3 = &d; ) // 3 != 4, 4 != 3
+	
+	pe0 = &e;
+ERROR(	qe0 = &e; ) // 4 != 3
+
+	pf = &f;
+ERROR(	qf = &f; ) // 3 != 4
+
+	/* return */
+ERROR(	z0(); )	// 5 != 3, 5, != 3
+
+ERROR(	z1(); )	// 4 != 3
+
+ERROR(	z2(); )  //  5 != 4	
+
+ERROR(	char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5
+
+	return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-init-2.c b/gcc/testsuite/gcc.dg/vla-bounds-init-2.c
new file mode 100644
index 00000000000..8fb4ad8a3ea
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-init-2.c
@@ -0,0 +1,125 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+#define ERROR(...)
+#define TRY(...) __VA_ARGS__ __builtin_abort();
+
+int main()
+{
+	signal(SIGILL, handler);
+
+	int m = 4, n = 3;
+
+	int u = 4;
+	int v = 3;
+
+	/* initialization */
+
+	char a[4];
+	char (*pa)[u] = &a;
+ERROR(	char (*qa)[v] = &a; ) // 3 != 4
+	char (*qa)[v];
+
+	char b[u];
+	const char (*pb)[u] = &b;
+ERROR(	char (*qb)[v] = &b; )	// 3 != 4
+	char (*qb)[v];
+
+	char c[4][3];
+	char (*pc0)[u][v] = &c;
+TRY(	char (*qc0)[v][u] = &c;	) // 3 != 4, 4 != 3
+
+	char (*pc1)[u][3] = &c;
+ERROR(	char (*qc1)[v][3] = &c; ) // 3 != 4
+	char (*qc1)[v][3];
+
+	char (*pc2)[4][v] = &c;
+ERROR(	char (*qc2)[4][u] = &c; ) // 4 != 3
+	char (*qc2)[4][u];
+
+	char (*pc3)[][v] = &c;	
+ERROR(	char (*qc3)[][u] = &c; ) // 4 != 3
+
+	char d[u][v];
+	char (*pd0)[4][3] = &d;
+ERROR(	char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3
+	char (*qd0)[3][4];
+
+	char (*pd1)[u][3] = &d;	
+ERROR(	char (*qd1)[v][4] = &d;	) // 3 != 4, 4 != 3
+	char (*qd1)[v][4];
+
+	char (*pd2)[4][v] = &d;
+ERROR(	char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3
+	char (*qd2)[3][u];
+
+	char (*pd3)[u][v] = &d;
+ERROR(	char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3
+	char (*qd3)[v][u];
+
+	char e[4][v];
+	char (*pe0)[4][3] = &e;
+ERROR(	char (*qe0)[4][4] = &e; ) // 4 != 3
+	char (*qe0)[4][4];
+
+	char f[u][3];
+	char (*pf)[4][3] = &f;
+ERROR(	char (*qf)[3][3] = &f; ) // 3 != 4
+	char (*qf)[3][3];
+
+	char (*g[u])[v];
+	char (*(*pg)[u])[v] = &g;
+ERROR(	char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3
+
+	/* assignment */
+
+	pa = &a;
+ERROR(	qa = &a; ) // 3 != 4
+
+	pb = &b;
+ERROR(	qb = &b; ) // 3 != 4
+	
+	pc0 = &c;
+ERROR(	qc0 = &c; ) // 3 != 4, 4 != 3
+	
+	pc1 = &c;
+ERROR(	qc1 = &c; ) // 3 != 4
+
+	pc2 = &c;
+ERROR(	qc2 = &c; ) // 4 != 3
+
+	pd0 = &d;
+ERROR(	qd0 = &d; ) // 3 != 4, 4 != 3
+
+	pd1 = &d;
+ERROR(	qd1 = &d; ) // 3 != 4, 4 != 3
+	
+	pd2 = &d;
+ERROR(	qd2 = &d; ) // 3 != 4, 4 != 3
+	
+	pd3 = &d;
+ERROR(	qd3 = &d; ) // 3 != 4, 4 != 3
+	
+	pe0 = &e;
+ERROR(	qe0 = &e; ) // 4 != 3
+
+	pf = &f;
+ERROR(	qf = &f; ) // 3 != 4
+
+	/* return */
+ERROR(	z0(); )	// 5 != 3, 5, != 3
+
+ERROR(	z1(); )	// 4 != 3
+
+ERROR(	z2(); )  //  5 != 4	
+
+ERROR(	char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5
+
+	return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-init-3.c b/gcc/testsuite/gcc.dg/vla-bounds-init-3.c
new file mode 100644
index 00000000000..83df5796942
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-init-3.c
@@ -0,0 +1,126 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+#define ERROR(...)
+#define TRY(...) __VA_ARGS__ __builtin_abort();
+
+int main()
+{
+	signal(SIGILL, handler);
+
+	int m = 4, n = 3;
+
+	int u = 4;
+	int v = 3;
+
+	/* initialization */
+
+	char a[4];
+	char (*pa)[u] = &a;
+ERROR(	char (*qa)[v] = &a; ) // 3 != 4
+	char (*qa)[v];
+
+	char b[u];
+	const char (*pb)[u] = &b;
+ERROR(	char (*qb)[v] = &b; )	// 3 != 4
+	char (*qb)[v];
+
+	char c[4][3];
+	char (*pc0)[u][v] = &c;
+ERROR(	char (*qc0)[v][u] = &c;	) // 3 != 4, 4 != 3
+	char (*qc0)[v][u];
+
+	char (*pc1)[u][3] = &c;
+ERROR(	char (*qc1)[v][3] = &c; ) // 3 != 4
+	char (*qc1)[v][3];
+
+	char (*pc2)[4][v] = &c;
+ERROR(	char (*qc2)[4][u] = &c; ) // 4 != 3
+	char (*qc2)[4][u];
+
+	char (*pc3)[][v] = &c;	
+TRY(	char (*qc3)[][u] = &c; ) // 4 != 3
+
+	char d[u][v];
+	char (*pd0)[4][3] = &d;
+ERROR(	char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3
+	char (*qd0)[3][4];
+
+	char (*pd1)[u][3] = &d;	
+ERROR(	char (*qd1)[v][4] = &d;	) // 3 != 4, 4 != 3
+	char (*qd1)[v][4];
+
+	char (*pd2)[4][v] = &d;
+ERROR(	char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3
+	char (*qd2)[3][u];
+
+	char (*pd3)[u][v] = &d;
+ERROR(	char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3
+	char (*qd3)[v][u];
+
+	char e[4][v];
+	char (*pe0)[4][3] = &e;
+ERROR(	char (*qe0)[4][4] = &e; ) // 4 != 3
+	char (*qe0)[4][4];
+
+	char f[u][3];
+	char (*pf)[4][3] = &f;
+ERROR(	char (*qf)[3][3] = &f; ) // 3 != 4
+	char (*qf)[3][3];
+
+	char (*g[u])[v];
+	char (*(*pg)[u])[v] = &g;
+ERROR(	char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3
+
+	/* assignment */
+
+	pa = &a;
+ERROR(	qa = &a; ) // 3 != 4
+
+	pb = &b;
+ERROR(	qb = &b; ) // 3 != 4
+	
+	pc0 = &c;
+ERROR(	qc0 = &c; ) // 3 != 4, 4 != 3
+	
+	pc1 = &c;
+ERROR(	qc1 = &c; ) // 3 != 4
+
+	pc2 = &c;
+ERROR(	qc2 = &c; ) // 4 != 3
+
+	pd0 = &d;
+ERROR(	qd0 = &d; ) // 3 != 4, 4 != 3
+
+	pd1 = &d;
+ERROR(	qd1 = &d; ) // 3 != 4, 4 != 3
+	
+	pd2 = &d;
+ERROR(	qd2 = &d; ) // 3 != 4, 4 != 3
+	
+	pd3 = &d;
+ERROR(	qd3 = &d; ) // 3 != 4, 4 != 3
+	
+	pe0 = &e;
+ERROR(	qe0 = &e; ) // 4 != 3
+
+	pf = &f;
+ERROR(	qf = &f; ) // 3 != 4
+
+	/* return */
+ERROR(	z0(); )	// 5 != 3, 5, != 3
+
+ERROR(	z1(); )	// 4 != 3
+
+ERROR(	z2(); )  //  5 != 4	
+
+ERROR(	char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5
+
+	return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-init-4.c b/gcc/testsuite/gcc.dg/vla-bounds-init-4.c
new file mode 100644
index 00000000000..81d252e3957
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-init-4.c
@@ -0,0 +1,125 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+#define ERROR(...)
+#define TRY(...) __VA_ARGS__ __builtin_abort();
+
+int main()
+{
+	signal(SIGILL, handler);
+
+	int m = 4, n = 3;
+
+	int u = 4;
+	int v = 3;
+
+	/* initialization */
+
+	char a[4];
+	char (*pa)[u] = &a;
+ERROR(	char (*qa)[v] = &a; ) // 3 != 4
+	char (*qa)[v];
+
+	char b[u];
+	const char (*pb)[u] = &b;
+ERROR(	char (*qb)[v] = &b; )	// 3 != 4
+	char (*qb)[v];
+
+	char c[4][3];
+	char (*pc0)[u][v] = &c;
+ERROR(	char (*qc0)[v][u] = &c;	) // 3 != 4, 4 != 3
+	char (*qc0)[v][u];
+
+	char (*pc1)[u][3] = &c;
+ERROR(	char (*qc1)[v][3] = &c; ) // 3 != 4
+	char (*qc1)[v][3];
+
+	char (*pc2)[4][v] = &c;
+ERROR(	char (*qc2)[4][u] = &c; ) // 4 != 3
+	char (*qc2)[4][u];
+
+	char (*pc3)[][v] = &c;	
+ERROR(	char (*qc3)[][u] = &c; ) // 4 != 3
+
+	char d[u][v];
+	char (*pd0)[4][3] = &d;
+TRY(	char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3
+
+	char (*pd1)[u][3] = &d;	
+ERROR(	char (*qd1)[v][4] = &d;	) // 3 != 4, 4 != 3
+	char (*qd1)[v][4];
+
+	char (*pd2)[4][v] = &d;
+ERROR(	char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3
+	char (*qd2)[3][u];
+
+	char (*pd3)[u][v] = &d;
+ERROR(	char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3
+	char (*qd3)[v][u];
+
+	char e[4][v];
+	char (*pe0)[4][3] = &e;
+ERROR(	char (*qe0)[4][4] = &e; ) // 4 != 3
+	char (*qe0)[4][4];
+
+	char f[u][3];
+	char (*pf)[4][3] = &f;
+ERROR(	char (*qf)[3][3] = &f; ) // 3 != 4
+	char (*qf)[3][3];
+
+	char (*g[u])[v];
+	char (*(*pg)[u])[v] = &g;
+ERROR(	char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3
+
+	/* assignment */
+
+	pa = &a;
+ERROR(	qa = &a; ) // 3 != 4
+
+	pb = &b;
+ERROR(	qb = &b; ) // 3 != 4
+	
+	pc0 = &c;
+ERROR(	qc0 = &c; ) // 3 != 4, 4 != 3
+	
+	pc1 = &c;
+ERROR(	qc1 = &c; ) // 3 != 4
+
+	pc2 = &c;
+ERROR(	qc2 = &c; ) // 4 != 3
+
+	pd0 = &d;
+ERROR(	qd0 = &d; ) // 3 != 4, 4 != 3
+
+	pd1 = &d;
+ERROR(	qd1 = &d; ) // 3 != 4, 4 != 3
+	
+	pd2 = &d;
+ERROR(	qd2 = &d; ) // 3 != 4, 4 != 3
+	
+	pd3 = &d;
+ERROR(	qd3 = &d; ) // 3 != 4, 4 != 3
+	
+	pe0 = &e;
+ERROR(	qe0 = &e; ) // 4 != 3
+
+	pf = &f;
+ERROR(	qf = &f; ) // 3 != 4
+
+	/* return */
+ERROR(	z0(); )	// 5 != 3, 5, != 3
+
+ERROR(	z1(); )	// 4 != 3
+
+ERROR(	z2(); )  //  5 != 4	
+
+ERROR(	char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5
+
+	return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-nest-1.c b/gcc/testsuite/gcc.dg/vla-bounds-nest-1.c
new file mode 100644
index 00000000000..30b0496107c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-nest-1.c
@@ -0,0 +1,39 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+/* { dg-require-effective-target trampolines } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+void handler(int) { exit(0); }
+
+#define ERROR(...)
+#define TRY(...) __VA_ARGS__ __builtin_abort()
+
+static char bb[4][4];
+static char (*g())[4][4] { return &bb; }
+
+int main()
+{
+	signal(SIGILL, handler);
+
+	int n = 3;
+	char b[4];
+	char (*f())[++n] { return &b; }
+
+	if (4 != sizeof(*f()))
+		__builtin_abort();
+
+	TRY( char (*(*p)())[++n] = &f; );
+
+	if (5 != sizeof(*(*p)()))
+		__builtin_abort();
+
+	char (*(*q)())[++n][4];
+
+	if (6 * 4 != sizeof(*(*q)()))
+		__builtin_abort();
+
+	return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-nest-2.c b/gcc/testsuite/gcc.dg/vla-bounds-nest-2.c
new file mode 100644
index 00000000000..d871051225a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-nest-2.c
@@ -0,0 +1,33 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+/* { dg-require-effective-target trampolines } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+void handler(int) { exit(0); }
+
+#define ERROR(...)
+#define TRY(...) __VA_ARGS__ __builtin_abort();
+
+static char bb[4][4];
+static char (*g())[4][4] { return &bb; }
+
+int main()
+{
+	signal(SIGILL, handler);
+
+	int n = 3;
+	char b[4];
+	char (*f())[++n] { return &b; }
+
+	if (4 != sizeof(*f()))
+		__builtin_abort();
+
+	char (*(*p)())[++n] ERROR( = &f );
+
+TRY(	char (*(*q)())[++n][4] = &g; );
+
+	return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-ret-1.c b/gcc/testsuite/gcc.dg/vla-bounds-ret-1.c
new file mode 100644
index 00000000000..beb7dd414ed
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-ret-1.c
@@ -0,0 +1,132 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+#define TRY(...) __VA_ARGS__ __builtin_abort();
+#define ERROR(...)
+
+int m, n;
+
+static char (*z0(void))[5][5] { char (*p)[m][n] = 0; return p; }
+static char (*z1(void))[5][5] { char (*p)[5][n] = 0; return p; }
+static char (*z2(void))[5][5] { char (*p)[m][5] = 0; return p; }
+
+int main()
+{
+	signal(SIGILL, handler);
+
+	m = 4, n = 3;
+
+	int u = 4;
+	int v = 3;
+
+	/* initialization */
+
+	char a[4];
+	char (*pa)[u] = &a;
+ERROR(	char (*qa)[v] = &a; ) // 3 != 4
+	char (*qa)[v];
+
+	char b[u];
+	const char (*pb)[u] = &b;
+ERROR(	char (*qb)[v] = &b; )	// 3 != 4
+	char (*qb)[v];
+
+	char c[4][3];
+	char (*pc0)[u][v] = &c;
+ERROR(	char (*qc0)[v][u] = &c;	) // 3 != 4, 4 != 3
+	char (*qc0)[v][u];
+
+	char (*pc1)[u][3] = &c;
+ERROR(	char (*qc1)[v][3] = &c; ) // 3 != 4
+	char (*qc1)[v][3];
+
+	char (*pc2)[4][v] = &c;
+ERROR(	char (*qc2)[4][u] = &c; ) // 4 != 3
+	char (*qc2)[4][u];
+
+	char (*pc3)[][v] = &c;	
+ERROR(	char (*qc3)[][u] = &c; ) // 4 != 3
+
+	char d[u][v];
+	char (*pd0)[4][3] = &d;
+ERROR(	char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3
+	char (*qd0)[3][4];
+
+	char (*pd1)[u][3] = &d;	
+ERROR(	char (*qd1)[v][4] = &d;	) // 3 != 4, 4 != 3
+	char (*qd1)[v][4];
+
+	char (*pd2)[4][v] = &d;
+ERROR(	char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3
+	char (*qd2)[3][u];
+
+	char (*pd3)[u][v] = &d;
+ERROR(	char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3
+	char (*qd3)[v][u];
+
+	char e[4][v];
+	char (*pe0)[4][3] = &e;
+ERROR(	char (*qe0)[4][4] = &e; ) // 4 != 3
+	char (*qe0)[4][4];
+
+	char f[u][3];
+	char (*pf)[4][3] = &f;
+ERROR(	char (*qf)[3][3] = &f; ) // 3 != 4
+	char (*qf)[3][3];
+
+	char (*g[u])[v];
+	char (*(*pg)[u])[v] = &g;
+ERROR(	char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3
+
+	/* assignment */
+
+	pa = &a;
+ERROR(	qa = &a; ) // 3 != 4
+
+	pb = &b;
+ERROR(	qb = &b; ) // 3 != 4
+	
+	pc0 = &c;
+ERROR(	qc0 = &c; ) // 3 != 4, 4 != 3
+	
+	pc1 = &c;
+ERROR(	qc1 = &c; ) // 3 != 4
+
+	pc2 = &c;
+ERROR(	qc2 = &c; ) // 4 != 3
+
+	pd0 = &d;
+ERROR(	qd0 = &d; ) // 3 != 4, 4 != 3
+
+	pd1 = &d;
+ERROR(	qd1 = &d; ) // 3 != 4, 4 != 3
+	
+	pd2 = &d;
+ERROR(	qd2 = &d; ) // 3 != 4, 4 != 3
+	
+	pd3 = &d;
+ERROR(	qd3 = &d; ) // 3 != 4, 4 != 3
+	
+	pe0 = &e;
+ERROR(	qe0 = &e; ) // 4 != 3
+
+	pf = &f;
+ERROR(	qf = &f; ) // 3 != 4
+
+	/* return */
+TRY(	z0(); )	// 5 != 3, 5, != 3
+
+ERROR(	z1(); )	// 4 != 3
+
+ERROR(	z2(); )  //  5 != 4	
+
+ERROR(	char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5
+
+	return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-ret-2.c b/gcc/testsuite/gcc.dg/vla-bounds-ret-2.c
new file mode 100644
index 00000000000..2df515e557f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-ret-2.c
@@ -0,0 +1,133 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+#define ERROR(...) 
+#define TRY(...) __VA_ARGS__ __builtin_abort();
+
+int n, m;
+
+static char (*z0(void))[5][5] { char (*p)[m][n] = 0; return p; }
+static char (*z1(void))[5][5] { char (*p)[5][n] = 0; return p; }
+static char (*z2(void))[5][5] { char (*p)[m][5] = 0; return p; }
+
+
+int main()
+{
+	signal(SIGILL, handler);
+
+	m = 4, n = 3;
+
+	int u = 4;
+	int v = 3;
+
+	/* initialization */
+
+	char a[4];
+	char (*pa)[u] = &a;
+ERROR(	char (*qa)[v] = &a; ) // 3 != 4
+	char (*qa)[v];
+
+	char b[u];
+	const char (*pb)[u] = &b;
+ERROR(	char (*qb)[v] = &b; )	// 3 != 4
+	char (*qb)[v];
+
+	char c[4][3];
+	char (*pc0)[u][v] = &c;
+ERROR(	char (*qc0)[v][u] = &c;	) // 3 != 4, 4 != 3
+	char (*qc0)[v][u];
+
+	char (*pc1)[u][3] = &c;
+ERROR(	char (*qc1)[v][3] = &c; ) // 3 != 4
+	char (*qc1)[v][3];
+
+	char (*pc2)[4][v] = &c;
+ERROR(	char (*qc2)[4][u] = &c; ) // 4 != 3
+	char (*qc2)[4][u];
+
+	char (*pc3)[][v] = &c;	
+ERROR(	char (*qc3)[][u] = &c; ) // 4 != 3
+
+	char d[u][v];
+	char (*pd0)[4][3] = &d;
+ERROR(	char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3
+	char (*qd0)[3][4];
+
+	char (*pd1)[u][3] = &d;	
+ERROR(	char (*qd1)[v][4] = &d;	) // 3 != 4, 4 != 3
+	char (*qd1)[v][4];
+
+	char (*pd2)[4][v] = &d;
+ERROR(	char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3
+	char (*qd2)[3][u];
+
+	char (*pd3)[u][v] = &d;
+ERROR(	char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3
+	char (*qd3)[v][u];
+
+	char e[4][v];
+	char (*pe0)[4][3] = &e;
+ERROR(	char (*qe0)[4][4] = &e; ) // 4 != 3
+	char (*qe0)[4][4];
+
+	char f[u][3];
+	char (*pf)[4][3] = &f;
+ERROR(	char (*qf)[3][3] = &f; ) // 3 != 4
+	char (*qf)[3][3];
+
+	char (*g[u])[v];
+	char (*(*pg)[u])[v] = &g;
+ERROR(	char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3
+
+	/* assignment */
+
+	pa = &a;
+ERROR(	qa = &a; ) // 3 != 4
+
+	pb = &b;
+ERROR(	qb = &b; ) // 3 != 4
+	
+	pc0 = &c;
+ERROR(	qc0 = &c; ) // 3 != 4, 4 != 3
+	
+	pc1 = &c;
+ERROR(	qc1 = &c; ) // 3 != 4
+
+	pc2 = &c;
+ERROR(	qc2 = &c; ) // 4 != 3
+
+	pd0 = &d;
+ERROR(	qd0 = &d; ) // 3 != 4, 4 != 3
+
+	pd1 = &d;
+ERROR(	qd1 = &d; ) // 3 != 4, 4 != 3
+	
+	pd2 = &d;
+ERROR(	qd2 = &d; ) // 3 != 4, 4 != 3
+	
+	pd3 = &d;
+ERROR(	qd3 = &d; ) // 3 != 4, 4 != 3
+	
+	pe0 = &e;
+ERROR(	qe0 = &e; ) // 4 != 3
+
+	pf = &f;
+ERROR(	qf = &f; ) // 3 != 4
+
+	/* return */
+ERROR(	z0(); )	// 5 != 3, 5, != 3
+
+TRY(	z1(); )	// 4 != 3
+
+ERROR(	z2(); )  //  5 != 4	
+
+ERROR(	char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5
+
+	return 0;
+}
+