public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
@ 2016-03-07  1:38 Martin Sebor
  2016-03-14 21:26 ` Martin Sebor
  2016-03-23 18:34 ` Jason Merrill
  0 siblings, 2 replies; 22+ messages in thread
From: Martin Sebor @ 2016-03-07  1:38 UTC (permalink / raw)
  To: Gcc Patch List, Jason Merrill

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

GCC 4.9 had added support for C++ VLAs as specified in WG21
document N3639 expected to be included in C++ 14.  However,
WG21 ultimately decided not to include N3639 in C++ 14 and
the G++ support was partially removed in 5.1.  Unfortunately,
the removal rendered some safe albeit erroneous G++ 4.9 code
undefined.  This patch restores the well-defined behavior of
such code by having it throw an exception in response to
the erroneous conditions.

While testing the patch I found a number of other problems in
the G++ support for VLAs, including PR c++/70019 - VLA size
overflow not detected, which was never implemented (not even
in 4.9).  Since this is closely related to the regression
discussed in 69517 the patch also provides that support.

There are a few additional points to note about the patch:

1) It restores the std::bad_array_length exception from N3639,
    even though the class isn't specified by the C++ standard.
    At first I thought that introducing a different (private)
    type would be more appropriate, but in the end couldn't come
    up with a good argument for not keeping the same type.  Using
    the same type also allows programs that rely on the exception
    and that were built with GCC 4.9 to be ported to GCC 6 without
    change.

2) It hardwires a rather arbitrarily restrictive limit of 64 KB
    on the size of the biggest C++ VLA.  (This could stand to be
    improved and made more intelligent, and perhaps integrated
    with stack  checking via -fstack-limit, after the GCC 6
    release.)

3) By throwing an exception for erroneous VLAs the patch largely
    defeats the VLA Sanitizer.  The sanitizer is still useful in
    C++ 98 mode where the N3639 VLA runtime checking is disabled,
    and when exceptions are disabled via -fno-exceptions.
    Disabling  the VLA checking in C++ 98 mode doesn't seem like
    a useful feature, but I didn't feel like reverting what was
    a deliberate decision.

Martin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: gcc-69517.patch --]
[-- Type: text/x-patch; name="gcc-69517.patch", Size: 43533 bytes --]

PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
PR c++/70019 - VLA size overflow not detected

gcc/testsuite/ChangeLog:
2016-03-06  Martin Sebor  <msebor@redhat.com>

	PR c++/69517
	PR c++/70019
	* c-c++-common/ubsan/vla-1.c (main): Catch exceptions.
	* g++.dg/cpp1y/vla11.C: New test.
	* g++.dg/cpp1y/vla12.C: New test.
	* g++.dg/cpp1y/vla13.C: New test.
	* g++.dg/cpp1y/vla14.C: New test.
	* g++.dg/cpp1y/vla3.C: Restore deleted test.
	* g++.dg/ubsan/vla-1.C: Disable exceptions.

gcc/cp/ChangeLog:
2016-03-06  Martin Sebor  <msebor@redhat.com>

	PR c++/69517
	PR c++/70019
	* decl.c (vla_p, throw_bad_array_length, build_vla_check): New
	functions.
	(check_initializer, cp_finish_decl): Call them.

gcc/doc/ChangeLog:

2016-03-06  Martin Sebor  <msebor@redhat.com>

	PR c++/69517
	PR c++/70019
	* extend.texi (Variable Length): Document C++ specifics.

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 5ec6589..682828c 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -106,6 +106,22 @@ static tree build_cp_library_fn (tree, enum tree_code, tree, int);
 static void store_parm_decls (tree);
 static void initialize_local_var (tree, tree);
 static void expand_static_init (tree, tree);
+static bool vla_p (tree);
+static tree build_vla_check (tree, tree = NULL_TREE, tree = NULL_TREE,
+			     tree = NULL_TREE, offset_int * = 0);
+
+/* Call __cxa_throw_bad_array_length to indicate that the size calculation
+   overflowed.  */
+tree
+throw_bad_array_length (void)
+{
+  tree fn = get_identifier ("__cxa_throw_bad_array_length");
+  if (!get_global_value_if_present (fn, &fn))
+    fn = push_throw_library_fn (fn, build_function_type_list (void_type_node,
+                                                             NULL_TREE));
+
+  return build_cxx_call (fn, 0, NULL, tf_warning_or_error);
+}
 
 /* The following symbols are subsumed in the cp_global_trees array, and
    listed here individually for documentation purposes.
@@ -6160,6 +6176,33 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
 	      && PAREN_STRING_LITERAL_P (DECL_INITIAL (decl)))
 	    warning (0, "array %qD initialized by parenthesized string literal %qE",
 		     decl, DECL_INITIAL (decl));
+
+	  if (TREE_CODE (type) == ARRAY_TYPE
+	      && vla_p (type)
+	      && !processing_template_decl)
+	    {
+	      /* Statically check for overflow in VLA bounds and build
+		 an expression that checks whether the VLA is erroneous
+		 at runtime, either due to invalid (runtime) bounds or
+		 due to excess initializers for the runtime bounds.  */
+	      tree check = build_vla_check (TREE_TYPE (decl), init);
+
+	      if (cxx_dialect >= cxx11 && flag_exceptions
+		  && current_function_decl
+		  /* Avoid instrumenting constexpr functions.  Those must
+		     be checked statically, and the (non-constexpr) dynamic
+		     instrumentation would cause them to be rejected.  */
+		  && !DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+		{
+		  /* Use the runtime check only in C++ 11 mode and later
+		     and when exceptions are enabled.  Otherwise let bad
+		     things happen...  */
+		  check = build3 (COND_EXPR, void_type_node, check,
+				  throw_bad_array_length (), void_node);
+
+		  finish_expr_stmt (check);
+		}
+	    }
 	  init = NULL;
 	}
     }
@@ -6499,6 +6542,226 @@ is_concept_var (tree decl)
           && DECL_DECLARED_CONCEPT_P (decl));
 }
 
+/* Build an expression to determine whether the VLA TYPE is erroneous.
+   INIT is the VLA initializer expression or NULL_TREE when the VLA
+   is not initialized.
+   VLASIZE is initially expected to be NULL_TREE and is used internally
+   pass the incrementally computed size of the VLA object down to its
+   recursive invocations.
+   MAX_VLASIZE is the maximum valid size of the VLA in bytes.  A default
+   value is hardcoded by the function when MAX_VLASIZE is initially NULL.
+   CST_SIZE, initially ignored, is the product of the constant dimensions
+   of the array.  */
+
+static tree
+build_vla_check (tree type,
+		 tree init /* = NULL_TREE */,
+		 tree vlasize /* NULL_TREE */,
+		 tree max_vlasize /* = NULL_TREE */,
+		 offset_int *cst_size /* = 0 */)
+{
+  /* The product of all constant dimensions of the VLA shared by recursive
+     invocations of the function.  Set to 1 by the first call and reset
+     after the first error to avoid redundant diagnostics.  */
+  offset_int cst_size_data = 1;
+
+  tree vmul = builtin_decl_explicit (BUILT_IN_MUL_OVERFLOW);
+
+  if (vlasize == NULL_TREE)
+    {
+      vlasize = build_decl (input_location,
+			    VAR_DECL, NULL_TREE, sizetype);
+      DECL_ARTIFICIAL (vlasize) = 1;
+      DECL_IGNORED_P (vlasize) = 1;
+      DECL_CONTEXT (vlasize) = current_function_decl;
+      DECL_INITIAL (vlasize) = size_one_node;
+      layout_decl (vlasize, 0);
+      vlasize = pushdecl (vlasize);
+      cp_finish_decl (vlasize, size_one_node, true, NULL_TREE, 0);
+
+      cst_size = &cst_size_data;
+    }
+
+  /* Impose a size limit on the size of the biggest VLA in bytes.  */
+  if (max_vlasize == NULL_TREE)
+    max_vlasize = fold_convert (size_type_node,
+				build_all_ones_cst (uint16_type_node));
+
+  tree vlasizeaddr = build_unary_op (input_location, ADDR_EXPR, vlasize, 0);
+
+  tree check = boolean_false_node;
+
+  bool overflow = false;
+
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      /* Compute the upper bound of this array type.  */
+      tree inner_nelts = array_type_nelts_top (type);
+      tree inner_nelts_cst = maybe_constant_value (inner_nelts);
+
+      if (TREE_CODE (inner_nelts_cst) == INTEGER_CST)
+	{
+	  /* The upper bound is a constant expression.  Compute the product
+	     of the constant upper bounds seen so far so that overflow can
+	     be diagnosed.  */
+	  offset_int result = wi::mul (wi::to_offset (inner_nelts_cst),
+				       *cst_size, SIGNED, &overflow);
+	  *cst_size = overflow ? 0 : result;
+	}
+
+      size_t len;
+
+      if (init == NULL_TREE
+	  || (TREE_CODE (init) == CONSTRUCTOR && !CONSTRUCTOR_ELTS (init)))
+	{
+	  /* This array either has no initializer or the initializer is
+	     empty.  Check only for overflow in its (runtime) upper bounds.  */
+	  tree vflowcheck = build_call_expr (vmul, 3, inner_nelts,
+					     vlasize, vlasizeaddr);
+
+	  /* Recursively check for overflow in the remaining major bounds.  */
+	  tree subcheck = build_vla_check (TREE_TYPE (type), init,
+					   vlasize, max_vlasize,
+					   cst_size);
+	  check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			       check, vflowcheck);
+	  check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			       check, subcheck);
+	}
+      else if (TREE_CODE (init) == CONSTRUCTOR)
+	{
+	  /* The initializer of this array is itself an array.  Build
+	     an expression to check if the number of elements in the
+	     initializer array exceeds the upper bound of the type
+	     of the object being initialized.  */
+	  vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (init);
+
+	  len = v->length ();
+	  tree initelts = build_int_cstu (size_type_node, len);
+	  check = fold_build2 (LT_EXPR, boolean_type_node, inner_nelts,
+			       initelts);
+
+	  constructor_elt *ce;
+	  HOST_WIDE_INT i;
+
+	  /* Iterate over all non-empty initializers in this array, recursively
+	     building expressions to see if the elements of each are in excess
+	     of the (runtime) bounds of of the array type.  */
+	  FOR_EACH_VEC_SAFE_ELT (v, i, ce)
+	    {
+	      if (1) // !vec_safe_is_empty (CONSTRUCTOR_ELTS (ce->value)))
+		{
+		  tree subcheck = build_vla_check (TREE_TYPE (type),
+						   ce->value,
+						   vlasize, max_vlasize,
+						   cst_size);
+		  check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+				       check, subcheck);
+		}
+	    }
+
+	  /* Check for overflow in runtime bounds.  */
+	  tree vflowcheck = build_call_expr (vmul, 3, inner_nelts,
+					     vlasize, vlasizeaddr);
+	  vflowcheck = fold_build2 (LT_EXPR, boolean_type_node,
+				    max_vlasize, vlasize);
+	  check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, check,
+			       vflowcheck);
+	}
+      else if (TREE_CODE (init) == STRING_CST
+	       && (len = TREE_STRING_LENGTH (init)))
+	{
+	  /* The initializer of this array is a string.  */
+	  tree ctype = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init)));
+	  len /= TYPE_PRECISION (ctype) / BITS_PER_UNIT;
+
+	  /* A C++ string literal initializer must have at most as many
+	     characters as there are elements in the array, including
+	     the terminating NUL.  */
+	  tree initelts = build_int_cstu (size_type_node, len);
+	  tree initcheck = fold_build2 (LT_EXPR, boolean_type_node,
+					inner_nelts, initelts);
+	  check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, check,
+			       initcheck);
+	}
+      else if (TREE_CODE (init) == ERROR_MARK)
+	{
+	  // No checking is possible.
+	  check = boolean_false_node;
+	}
+      else
+	{
+	  /* What's this array initializer?  */
+	  gcc_unreachable ();
+	}
+    }
+  else
+    {
+      /* Get the size of the VLA element type in bytes.  */
+      tree typesize = TYPE_SIZE_UNIT (type);
+
+      /* See if the size, when multipled by the product of the VLA's
+	 constant dimensions, is within range of size_t.  If not,
+	 the VLA is definitely erroneous amd must be diagnosed at
+	 compile time.  */
+      offset_int result = wi::mul (wi::to_offset (typesize), *cst_size,
+				   SIGNED, &overflow);
+      *cst_size = overflow ? 0 : result;
+
+      /* Multiply the (non-constant) VLA size so far by the element size.  */
+      tree vflowcheck = build_call_expr (vmul, 3, typesize,
+					 vlasize, vlasizeaddr);
+
+      /* Check to see if the size exceeds the maximum.  */
+      vflowcheck = fold_build2 (LT_EXPR, boolean_type_node,
+				max_vlasize, vlasize);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, vflowcheck);
+
+      /* Also check to see if it's zero or negative.  */
+      tree zerocheck = fold_build2 (LE_EXPR, boolean_type_node,
+				    vlasize, size_zero_node);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, zerocheck);
+    }
+
+  /* Diagnose overflow determined at compile time.  */
+  if (overflow)
+    {
+      error ("integer overflow in array size");
+      /* Reset to suppress any further diagnostics.  The error takes
+	 precendence over the warning below.  */
+      *cst_size = 0;
+    }
+  else if (cst_size == &cst_size_data
+	   && wi::ltu_p (wi::to_offset (max_vlasize), *cst_size))
+    {
+      /* Issue the warning only in the "topmost" (non-recursive) call
+	 to avoid duplicating diagnostics.  This is only a warning to
+	 allow programs to be portable to more permissive environments.  */
+      warning (OPT_Wvla, "size of variable length array exceeds maximum "
+	       "of %qE bytes",  max_vlasize);
+    }
+
+  return check;
+}
+
+/* Return true when either T is a variably modified array type,
+   or (recursively) when T is an array of variable modified types.  */
+static bool
+vla_p (tree t)
+{
+  if (array_of_runtime_bound_p (t))
+    return true;
+
+  if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
+    return vla_p (TREE_TYPE (t));
+
+  return false;
+}
+
 /* Finish processing of a declaration;
    install its line number and initial value.
    If the length of an array type is not known before,
@@ -6619,21 +6882,50 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 	}
     }
 
-  if (init && VAR_P (decl))
+  if (VAR_P (decl))
     {
-      DECL_NONTRIVIALLY_INITIALIZED_P (decl) = 1;
-      /* If DECL is a reference, then we want to know whether init is a
-	 reference constant; init_const_expr_p as passed tells us whether
-	 it's an rvalue constant.  */
-      if (TREE_CODE (type) == REFERENCE_TYPE)
-	init_const_expr_p = potential_constant_expression (init);
-      if (init_const_expr_p)
-	{
-	  /* Set these flags now for templates.  We'll update the flags in
-	     store_init_value for instantiations.  */
-	  DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
-	  if (decl_maybe_constant_var_p (decl))
-	    TREE_CONSTANT (decl) = 1;
+      if (init)
+	{
+	  DECL_NONTRIVIALLY_INITIALIZED_P (decl) = 1;
+	  /* If DECL is a reference, then we want to know whether init is a
+	     reference constant; init_const_expr_p as passed tells us whether
+	     it's an rvalue constant.  */
+	  if (TREE_CODE (type) == REFERENCE_TYPE)
+	    init_const_expr_p = potential_constant_expression (init);
+	  if (init_const_expr_p)
+	    {
+	      /* Set these flags now for templates.  We'll update the flags in
+		 store_init_value for instantiations.  */
+	      DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
+	      if (decl_maybe_constant_var_p (decl))
+		TREE_CONSTANT (decl) = 1;
+	    }
+	}
+      else if (TREE_CODE (type) == ARRAY_TYPE
+	       && vla_p (type)
+	       && !processing_template_decl)
+	{
+	  /* Statically check for overflow in VLA bounds and build
+	     an expression that checks whether the VLA is erroneous
+	     at runtime.  */
+	  tree check = build_vla_check (type);
+
+	  if (cxx_dialect >= cxx11
+	      && flag_exceptions
+	      && current_function_decl
+	      /* Avoid instrumenting constexpr functions.  Those must
+		 be checked statically, and the (non-constexpr) dynamic
+		 instrumentation would cause them to be rejected.  */
+	      && !DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+	    {
+	      /* Use the runtime check only in C++ 11 mode and later
+		 and when exceptions are enabled.  Otherwise let bad
+		 things happen...  */
+	      check = build3 (COND_EXPR, void_type_node, check,
+			      throw_bad_array_length (), void_node);
+
+	      finish_expr_stmt (check);
+	    }
 	}
     }
 
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 10a42b6..a287dee 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -1634,14 +1634,24 @@ foo (int n)
 You can use the function @code{alloca} to get an effect much like
 variable-length arrays.  The function @code{alloca} is available in
 many other C implementations (but not in all).  On the other hand,
-variable-length arrays are more elegant.
+variable-length arrays are available in GCC for all targets and
+provide type safety.
 
 There are other differences between these two methods.  Space allocated
 with @code{alloca} exists until the containing @emph{function} returns.
 The space for a variable-length array is deallocated as soon as the array
 name's scope ends, unless you also use @code{alloca} in this scope.
 
-You can also use variable-length arrays as arguments to functions:
+Unlike GCC, in C++ 11 mode and later, G++ instruments variable-length
+arrays with checks for erroneous uses: when a variable-length array
+object is created its bounds are checked to detect non-positive bounds,
+integer overflows, sizes in excess of 64 KB, and excess initializers.
+When an erroneous variable-length array is detected the runtime arranges
+for an exception to be thrown that matches a handler of type
+@code{std::bad_array_length}.
+
+In C programs (but not in C++) variable-length arrays can also be declared
+as function arguments:
 
 @smallexample
 struct entry
diff --git a/gcc/testsuite/c-c++-common/ubsan/vla-1.c b/gcc/testsuite/c-c++-common/ubsan/vla-1.c
index 52ade3a..27ef110 100644
--- a/gcc/testsuite/c-c++-common/ubsan/vla-1.c
+++ b/gcc/testsuite/c-c++-common/ubsan/vla-1.c
@@ -87,18 +87,24 @@ fn12 (void)
 int
 main (void)
 {
-  fn1 ();
-  fn2 ();
-  fn3 ();
-  fn4 ();
-  fn5 ();
-  fn6 ();
-  fn7 ();
-  fn8 ();
-  fn9 ();
-  fn10 ();
-  fn11 ();
-  fn12 ();
+#if __cplusplus
+#  define TRY(stmt)   do { try { stmt; } catch (...) { } } while (0)
+#else
+#  define TRY(stmt)   stmt
+#endif
+
+  TRY (fn1 ());
+  TRY (fn2 ());
+  TRY (fn3 ());
+  TRY (fn4 ());
+  TRY (fn5 ());
+  TRY (fn6 ());
+  TRY (fn7 ());
+  TRY (fn8 ());
+  TRY (fn9 ());
+  TRY (fn10 ());
+  TRY (fn11 ());
+  TRY (fn12 ());
   return 0;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla11.C b/gcc/testsuite/g++.dg/cpp1y/vla11.C
new file mode 100644
index 0000000..4cdfbc9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla11.C
@@ -0,0 +1,469 @@
+// PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer
+//   elements
+// Test to verify that attempting to create an erroneous VLA or to
+// initialize a valid VLA with excess elements causes an exception
+// to be thrown.
+
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-Wno-vla" }
+
+#define INT_MAX    __INT_MAX__
+#define LONG_MAX   __LONG_MAX__
+#define SIZE_MAX   __SIZE_MAX__
+
+#define INT_MIN    (-__INT_MAX__ - 1)
+#define LONG_MIN   (-__LONG_MAX__ - 1)
+
+// The size of the largest allowed VLA in bytes.  Bigger objects
+// cause an exception to be thrown.
+#define VLA_SIZE_MAX   0xffffU
+
+typedef __SIZE_TYPE__ size_t;
+
+void __attribute__ ((noclone, noinline))
+sink (void*)
+{
+}
+
+template <class T>
+void __attribute__ ((noclone, noinline))
+test_vla (size_t rank, const long *dims, int init)
+{
+  switch (rank)
+    {
+    case 1:
+      switch (init)
+        {
+        case -1: {
+          T a [dims [0]];
+          sink (a);
+          break;
+        }
+        case 0: {
+          T a [dims [0]] = { };
+          sink (a);
+          break;
+        }
+        case 1: {
+          T a [dims [0]] = { 0 };
+          sink (a);
+          break;
+        }
+        case 2: {
+          T a [dims [0]] = { 0, 1 };
+          sink (a);
+          break;
+        }
+        case 3: {
+          T a [dims [0]] = { 0, 1, 2 };
+          sink (a);
+          break;
+        }
+        case 4: {
+          T a [dims [0]] = { 0, 1, 2, 3 };
+          sink (a);
+          break;
+        }
+        default:
+          __builtin_printf ("too many initializers in test\n");
+          __builtin_abort ();
+        }
+      break;
+
+    case 2:
+      switch (init)
+        {
+        case -1: {
+          T a [dims [0]][dims [1]];
+          sink (a);
+          break;
+        }
+        case 0: {
+          T a [dims [0]][dims [1]] = { };
+          sink (a);
+          break;
+        }
+        case 1: {
+          T a [dims [0]][dims [1]] = { 0 };
+          sink (a);
+          break;
+        }
+        case 2: {
+          T a [dims [0]][dims [1]] = { 0, 1 };
+          sink (a);
+          break;
+        }
+        case 3: {
+          T a [dims [0]][dims [1]] = { 0, 1, 2 };
+          sink (a);
+          break;
+        }
+        case 4: {
+          T a [dims [0]][dims [1]] = { 0, 1, 2, 3 };
+          sink (a);
+          break;
+        }
+        default:
+          __builtin_printf ("too many initializers in test\n");
+          __builtin_abort ();
+        }
+      break;
+
+    case 3:
+      switch (init)
+        {
+        case -1: {
+          T a [dims [0]][dims [1]][dims [2]];
+          sink (a);
+          break;
+        }
+        case 0: {
+          T a [dims [0]][dims [1]][dims [2]] = { };
+          sink (a);
+          break;
+        }
+        case 1: {
+          T a [dims [0]][dims [1]][dims [2]] = { 0 };
+          sink (a);
+          break;
+        }
+        case 2: {
+          T a [dims [0]][dims [1]][dims [2]] = { 0, 1 };
+          sink (a);
+          break;
+        }
+        case 3: {
+          T a [dims [0]][dims [1]][dims [2]] = { 0, 1, 2 };
+          sink (a);
+          break;
+        }
+        case 4: {
+          T a [dims [0]][dims [1]][dims [2]] = { 0, 1, 2, 3 };
+          sink (a);
+          break;
+        }
+        default:
+          __builtin_printf ("too many initializers in test\n");
+          __builtin_abort ();
+        }
+      break;
+
+    case 4:
+      switch (init)
+        {
+        case -1: {
+          T a [dims [0]][dims [1]][dims [2]][dims [3]];
+          sink (a);
+          break;
+        }
+        case 0: {
+          T a [dims [0]][dims [1]][dims [2]][dims [3]] = { };
+          sink (a);
+          break;
+        }
+        case 1: {
+          T a [dims [0]][dims [1]][dims [2]][dims [3]] = { 0 };
+          sink (a);
+          break;
+        }
+        case 2: {
+          T a [dims [0]][dims [1]][dims [2]][dims [3]] = { 0, 1 };
+          sink (a);
+          break;
+        }
+        case 3: {
+          T a [dims [0]][dims [1]][dims [2]][dims [3]] = { 0, 1, 2 };
+          sink (a);
+          break;
+        }
+        case 4: {
+          T a [dims [0]][dims [1]][dims [2]][dims [3]] = { 0, 1, 2, 3 };
+          sink (a);
+          break;
+        }
+        default:
+          __builtin_printf ("too many initializers in test\n");
+          __builtin_abort ();
+        }
+      break;
+
+    default:
+      __builtin_printf ("unexpected array rank in test\n");
+      __builtin_abort ();
+    }
+}
+
+// Compute whether a declaration of a VLA of the specified RANK
+// and the specified dimensions DIMS would overflow either due
+// to the dimensions exceeding the range of size_t or due to
+// the size of the object exceeding the maximum allowed VLA
+// size, or the size being zero.
+bool vflow (size_t tsize, int rank, const long *dims)
+{
+  size_t nbytes = tsize;
+
+  for (int i = 0; i < rank; ++i)
+    if (__builtin_mul_overflow (nbytes, dims [i], &nbytes))
+      return true;
+
+  return 0 == nbytes || VLA_SIZE_MAX < nbytes;
+}
+
+#define Aligned(N) __attribute__ ((aligned (N)))
+#define Packed     __attribute__ ((packed))
+
+struct Packed S1 { char i; };
+struct Packed S4 { Aligned (4) char i; };
+struct Packed S128 { Aligned (128) char i; };
+struct Packed S1024 { Aligned (1024) char i; };
+
+int main (void)
+{
+  static const struct {
+    int line;
+    void (*fun)(size_t, const long*, int);
+    size_t size;
+    int rank;
+    const long dims[8];
+    int init;
+    int except;
+  } test [] = {
+
+#define T(type) __LINE__, &test_vla<type>, sizeof (type)
+
+    // Rank-1 VLAs with no initializers.
+    // Valid:
+    { T (  S1), 1, {    1 }, -1, false },
+    { T (  S1), 1, {    2 }, -1, false },
+    { T (  S1), 1, {  256 }, -1, false },
+
+    { T (  S4), 1, {    1 }, -1, false },
+    { T (  S4), 1, {    2 }, -1, false },
+    { T (  S4), 1, {    3 }, -1, false },
+    { T (  S4), 1, {    4 }, -1, false },
+    { T (  S4), 1, {    5 }, -1, false },
+    { T (  S4), 1, {    6 }, -1, false },
+    { T (  S4), 1, {    7 }, -1, false },
+    { T (  S4), 1, {    8 }, -1, false },
+    { T (  S4), 1, { 1024 }, -1, false },
+    { T (  S4), 1, { 4096 }, -1, false },
+
+    // Valid with initializers.
+    { T (  S1), 1, {    1 },  1, false },
+    { T (  S1), 1, {    2 },  2, false },
+    { T (  S1), 1, {    3 },  3, false },
+    { T (  S1), 1, {    4 },  4, false },
+    { T (  S1), 1, {    5 },  4, false },
+    { T (  S1), 1, {  123 },  4, false },
+
+    // Possibly erroneous.
+    { T (S128), 1, { 4096 }, -1, -1 },
+
+    { T (  S1), 1, { VLA_SIZE_MAX >> 16 }, -1, -1 },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 15 }, -1, -1 },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 14 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 13 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 12 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 11 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 10 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 9 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 8 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 7 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 6 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 5 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 4 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 3 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 2 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 1 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 0 }, -1, false },
+
+    // Erroneous: size in excess of implementation-defined limit.
+    { T (S4), 1, { LONG_MIN }, -1, true },
+    { T (S4), 1, {  INT_MIN }, -1, true },
+    { T (S4), 1, {    -4096 }, -1, true },
+    { T (S4), 1, {    -1024 }, -1, true },
+    { T (S4), 1, {       -1 }, -1, true },
+    { T (S4), 1, {        0 }, -1, true },
+    { T (S4), 1, {  INT_MAX }, -1, true },
+    { T (S4), 1, { LONG_MAX }, -1, true },
+
+    // Erroneous: excess initializers.
+    { T (S1), 1, {        1 },  2, true },
+    { T (S1), 1, {        2 },  3, true },
+    { T (S1), 1, {        3 },  4, true },
+
+    // Rank-2 VLAs with no initializers.
+    // Valid:
+    { T (S4), 2, { 1,    1 }, -1, false },
+    { T (S4), 2, { 1,    2 }, -1, false },
+    { T (S4), 2, { 1,    3 }, -1, false },
+    { T (S4), 2, { 1,    4 }, -1, false },
+    { T (S4), 2, { 1,    5 }, -1, false },
+    { T (S4), 2, { 1,    6 }, -1, false },
+    { T (S4), 2, { 1,    7 }, -1, false },
+    { T (S4), 2, { 1,    8 }, -1, false },
+    { T (S4), 2, { 1, 1024 }, -1, false },
+    { T (S4), 2, { 1, 4096 }, -1, false },
+
+    { T (S4), 2, {  2,    1 }, -1, false },
+    { T (S4), 2, {  3,    2 }, -1, false },
+    { T (S4), 2, {  4,    3 }, -1, false },
+    { T (S4), 2, {  5,    4 }, -1, false },
+    { T (S4), 2, {  6,    5 }, -1, false },
+    { T (S4), 2, {  7,    6 }, -1, false },
+    { T (S4), 2, {  8,    7 }, -1, false },
+    { T (S4), 2, {  9,    8 }, -1, false },
+
+    // Possibly erroneous.
+    { T (S4), 2, { 10, 1024 }, -1, -1 },
+    { T (S4), 2, { 11, 4096 }, -1, -1 },
+
+    // Erroneous.
+    { T (S4), 2, { 1, LONG_MIN }, -1, true },
+    { T (S4), 2, { 1,  INT_MIN }, -1, true },
+    { T (S4), 2, { 1,    -4096 }, -1, true },
+    { T (S4), 2, { 1,    -1024 }, -1, true },
+    { T (S4), 2, { 1,       -1 }, -1, true },
+    { T (S4), 2, { 1,        0 }, -1, true },
+    { T (S4), 2, { 1,  INT_MAX }, -1, true },
+    { T (S4), 2, { 1, LONG_MAX }, -1, true },
+
+    { T (S4), 2, { 0, LONG_MIN }, -1, true },
+    { T (S4), 2, { 0,  INT_MIN }, -1, true },
+    { T (S4), 2, { 0,    -4096 }, -1, true },
+    { T (S4), 2, { 0,    -1024 }, -1, true },
+    { T (S4), 2, { 0,       -1 }, -1, true },
+    { T (S4), 2, { 0,        0 }, -1, true },
+    { T (S4), 2, { 0,  INT_MAX }, -1, true },
+    { T (S4), 2, { 0, LONG_MAX }, -1, true },
+
+    { T (S4), 2, { -1, LONG_MIN }, -1, true },
+    { T (S4), 2, { -1,  INT_MIN }, -1, true },
+    { T (S4), 2, { -1,    -4096 }, -1, true },
+    { T (S4), 2, { -1,    -1024 }, -1, true },
+    { T (S4), 2, { -1,       -1 }, -1, true },
+    { T (S4), 2, { -1,        0 }, -1, true },
+    { T (S4), 2, { -1,  INT_MAX }, -1, true },
+    { T (S4), 2, { -1, LONG_MAX }, -1, true },
+
+    { T (S4), 2, { LONG_MIN, -1 }, -1, true },
+    { T (S4), 2, {  INT_MIN, -1 }, -1, true },
+    { T (S4), 2, {    -4096, -1 }, -1, true },
+    { T (S4), 2, {    -1024, -1 }, -1, true },
+    { T (S4), 2, {       -1, -1 }, -1, true },
+    { T (S4), 2, {        0, -1 }, -1, true },
+    { T (S4), 2, {  INT_MAX, -1 }, -1, true },
+    { T (S4), 2, { LONG_MAX, -1 }, -1, true },
+
+    { T (S4), 2, { LONG_MIN, 0 }, -1, true },
+    { T (S4), 2, {  INT_MIN, 0 }, -1, true },
+    { T (S4), 2, {    -4096, 0 }, -1, true },
+    { T (S4), 2, {    -1024, 0 }, -1, true },
+    { T (S4), 2, {       -1, 0 }, -1, true },
+    { T (S4), 2, {        0, 0 }, -1, true },
+    { T (S4), 2, {  INT_MAX, 0 }, -1, true },
+    { T (S4), 2, { LONG_MAX, 0 }, -1, true },
+
+    { T (S4), 2, { LONG_MIN, LONG_MIN }, -1, true },
+    { T (S4), 2, {  INT_MIN,  INT_MIN }, -1, true },
+    { T (S4), 2, {    -4096     -4096 }, -1, true },
+    { T (S4), 2, {    -1024,    -1024 }, -1, true },
+    { T (S4), 2, {       -1,       -1 }, -1, true },
+    { T (S4), 2, {        0,        0 }, -1, true },
+    { T (S4), 2, {  INT_MAX,  INT_MAX }, -1, true },
+    { T (S4), 2, { LONG_MAX, LONG_MAX }, -1, true },
+
+    // Erroneous: excess initializers (and/or bad size).
+    { T (S4), 2, {        0,        0 },  0, true },
+    { T (S4), 2, {        0,        1 },  1, true },
+    { T (S4), 2, {        1,        0 },  2, true },
+    { T (S4), 2, {        1,        1 },  2, true },
+    { T (S4), 2, {        1,        1 },  2, true },
+    { T (S4), 2, {        1,        2 },  3, true },
+    { T (S4), 2, {        2,        1 },  3, true },
+
+    // Rank-3 VLAs with no initializers.
+    // Valid:
+    { T (S4), 3, {    1,    1,    1 }, -1, false },
+    { T (S4), 3, {    2,    2,    2 }, -1, false },
+    { T (S4), 3, {    3,    3,    3 }, -1, false },
+    { T (S4), 3, {    4,    4,    4 }, -1, false },
+    { T (S4), 3, {    5,    5,    5 }, -1, false },
+    { T (S4), 3, {    6,    6,    6 }, -1, false },
+    { T (S4), 3, {    7,    7,    7 }, -1, false },
+    { T (S4), 3, {    8,    8,    8 }, -1, false },
+
+    // Possibly erroneous:
+    { T (S4), 3, {    9,   16,   64 }, -1, -1 },
+
+    // Erroneous: bad size.
+    { T (S4), 3, {       -1,       -1,       -1 }, -1, true },
+    { T (S4), 3, {        0,       -1,       -1 }, -1, true },
+    { T (S4), 3, {       -1,        0,       -1 }, -1, true },
+    { T (S4), 3, {       -1,       -1,        0 }, -1, true },
+    { T (S4), 3, {        0,        0,        0 }, -1, true },
+    { T (S4), 3, {        1,        1,        0 }, -1, true },
+    { T (S4), 3, {        2,        0,        2 }, -1, true },
+    { T (S4), 3, {        0,        3,        3 }, -1, true },
+    { T (S4), 3, {        4,        4,       -1 }, -1, true },
+    { T (S4), 3, {        5,       -1,        5 }, -1, true },
+    { T (S4), 3, {       -1,        6,        6 }, -1, true },
+    { T (S4), 3, {        7,        7,  INT_MAX }, -1, true },
+    { T (S4), 3, {        8,  INT_MAX,        8 }, -1, true },
+    { T (S4), 3, {  INT_MAX,        9,        9 }, -1, true },
+    { T (S4), 3, {        0,        0,  INT_MIN }, -1, true },
+    { T (S4), 3, {        0,  INT_MIN,        0 }, -1, true },
+    { T (S4), 3, {  INT_MIN,        0,        0 }, -1, true },
+    { T (S4), 3, {  INT_MIN,  INT_MIN,  INT_MIN }, -1, true },
+    { T (S4), 3, {        0,        0,  INT_MAX }, -1, true },
+    { T (S4), 3, {        0,  INT_MAX,        0 }, -1, true },
+    { T (S4), 3, {  INT_MAX,        0,        0 }, -1, true },
+    { T (S4), 3, {        0,        0, LONG_MIN }, -1, true },
+    { T (S4), 3, {        0, LONG_MIN,        0 }, -1, true },
+    { T (S4), 3, { LONG_MIN,        0,        0 }, -1, true },
+    { T (S4), 3, { LONG_MIN, LONG_MIN, LONG_MIN }, -1, true },
+    { T (S4), 3, {        0,        0, LONG_MAX }, -1, true },
+    { T (S4), 3, {        0, LONG_MAX,        0 }, -1, true },
+    { T (S4), 3, { LONG_MAX,        0,        0 }, -1, true },
+
+    // Erroneous: integer overflow.
+    { T (S4), 3, {  INT_MAX,  INT_MAX,  INT_MAX }, -1, true },
+    { T (S4), 3, { LONG_MAX, LONG_MAX, LONG_MAX }, -1, true },
+    { T (S4), 3, {       10,       10, LONG_MAX }, -1, true },
+    { T (S4), 3, {       11, LONG_MAX,       11 }, -1, true },
+    { T (S4), 3, { LONG_MAX,       12,       12 }, -1, true },
+  };
+
+  static const size_t ntests = sizeof test / sizeof *test;
+
+  for (size_t i = 0; i != ntests; ++i)
+    {
+      // If test [i].except is negative, compute whether an exception
+      // should be expected based on the VLA rank and dimensions.
+      // Otherwise, use the hardcoded value.
+      bool vflow = ::vflow (test [i].size, test [i].rank, test [i].dims);
+      bool except = test [i].except < 0 ? vflow : test [i].except;
+
+      if (vflow && !except)
+        {
+          // When the VLA size computatiom overflows an exception
+          // must either be hardcoded as expected (true) or be left
+          // up to the computation.  Otherwise it's a consistency
+          // bug in the test case.
+          __builtin_printf ("line %i: test inconsistency\n", test [i].line);
+          __builtin_abort ();
+        }
+
+      try {
+        test [i].fun (test [i].rank, test [i].dims, test [i].init);
+        if (except)
+          __builtin_printf ("line %i: failed to throw\n",
+                            test [i].line);
+      }
+      catch (...) {
+        if (!except)
+          __builtin_printf ("line %i: unexpectedly threw\n",
+                            test [i].line);
+      }
+    }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla12.C b/gcc/testsuite/g++.dg/cpp1y/vla12.C
new file mode 100644
index 0000000..a8db578
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla12.C
@@ -0,0 +1,69 @@
+// Test to verify that variable length arrays whose size overflows
+// or exceeds the implementation-defined limit is diagnosed.
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-Wno-error=vla" }
+
+#define INT_MAX    __INT_MAX__
+#define LONG_MAX   __LONG_MAX__
+#define SIZE_MAX   __SIZE_MAX__
+
+typedef __SIZE_TYPE__ size_t;
+
+void test (int x, int y, int z)
+{
+  const size_t amax = SIZE_MAX / 2;
+
+  {
+    char a [x][amax];         // { dg-warning "forbids|size of variable length array exceeds maximum" }
+    (void)a;
+  }
+
+  {
+    char a [amax][y];         // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    char a [x][y][amax];      // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    char a [x][amax][z];      // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    char a [amax][y][z];      // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    // Unfortunately, this is rejected with a different error earlier
+    // during parsing and before the VLA checking gets to see it:
+    //   error: size of array ‘a’ is too large
+    char a [x][amax][amax];   // { dg-error "size of array" }
+
+    // That error above also leads to the following error when using
+    // the variable below.
+    //   error:’ was not declared in this scope
+    // (void)a;
+  }
+
+  {
+    char a [amax][y][amax];   // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    char a [amax][amax][z];   // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    struct A256 { __attribute__ ((aligned (256))) char a; };
+
+    A256 a [x][1024][y][1024][z][1024][x][1024][z];   // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla13.C b/gcc/testsuite/g++.dg/cpp1y/vla13.C
new file mode 100644
index 0000000..7a7b423
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla13.C
@@ -0,0 +1,159 @@
+// PR c++/70019 - VLA size overflow not detected
+// Runtime test to verify that attempting to initialize a VLA with a string
+// longer than the number of elements causes an exception to be thrown.
+
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-Wno-vla" }
+
+#define INT_MAX    __INT_MAX__
+#define LONG_MAX   __LONG_MAX__
+#define SIZE_MAX   __SIZE_MAX__
+
+#define INT_MIN    (-__INT_MAX__ - 1)
+#define LONG_MIN   (-__LONG_MAX__ - 1)
+
+// The size of the largest allowed VLA in bytes.  Bigger objects
+// cause an exception to be thrown.
+#define VLA_SIZE_MAX   0xffffU
+
+typedef __SIZE_TYPE__ size_t;
+
+// Incremented for each test failure.
+int fail;
+
+// Used to convert a constant array dimension to a non-constant one.
+int d (int n)
+{
+  return n;
+}
+
+// Verify either that an expected exception has been thrown or that
+// one hasn't been thrown if one isn't expected.
+int __attribute__ ((noclone, noinline))
+sink (void *p, int line, bool expect, const char *expr)
+{
+  if (!p != expect)
+    {
+      __builtin_printf ("line %i: Assertion failed: '%s': "
+                        "exception unexpectedly %sthrown\n",
+                        line, expr, !p ? "" : "not ");
+      ++fail;
+    }
+  return 0;
+}
+
+template <class T, int>
+int test ();
+
+#define _CAT(name, line) name ## line
+#define CAT(name, line) _CAT (name, line)
+
+#define STR(...) #__VA_ARGS__
+
+// Macro to define a unique specialization of a function template to
+// exercise a VLA of type T, rank N, with dimensions given by Dims
+// and initializer Init.  Expect is true when the VLA initialization
+// is expected to trigger an exception.
+// The macro creates a unique global dummy int object and initializes
+// it with the result of the function.  The dummy object servers no
+// other purpose but to call the function.  The function verifies
+// the expected postconditions.
+#define TEST(T, Dims, Init, Expect)                                     \
+  template <>                                                           \
+  int test<T, __LINE__>()                                               \
+  {                                                                     \
+    const char str[] = "char a" #Dims " = { " STR (Init) " }";          \
+    try {                                                               \
+      T a Dims = { Init };                                              \
+      return sink (a, __LINE__, Expect, str);                           \
+    }                                                                   \
+    catch (...) {                                                       \
+      return sink (0, __LINE__, Expect, str);                           \
+    }                                                                   \
+  }                                                                     \
+  const int CAT (dummy, __LINE__) = test<T, __LINE__>()
+
+
+// Create and run a test function exercising a VLA definition
+//    +-- Element Type
+//    |     +-- VLA Dimensions
+//    |     |       +-- VLA Initializer
+//    |     |       |
+//    |     |       |             +-- Expect Exception
+//    |     |       |             |
+//    V     V       V             V
+TEST (char, [d(1)], "",           false);
+TEST (char, [d(1)], "1",          true);
+TEST (char, [d(1)], "12",         true);
+TEST (char, [d(1)], "1234567890", true);
+
+TEST (char, [d(2)], "",           false);
+TEST (char, [d(2)], "1",          false);
+TEST (char, [d(2)], "12",         true);
+TEST (char, [d(2)], "123",        true);
+TEST (char, [d(2)], "1234567890", true);
+
+TEST (char, [d(3)], "",           false);
+TEST (char, [d(3)], "1",          false);
+TEST (char, [d(3)], "12",         false);
+TEST (char, [d(3)], "123",        true);
+TEST (char, [d(3)], "1234",       true);
+TEST (char, [d(3)], "1234567890", true);
+
+TEST (wchar_t, [d(1)], L"",           false);
+TEST (wchar_t, [d(1)], L"1",          true);
+TEST (wchar_t, [d(1)], L"12",         true);
+TEST (wchar_t, [d(1)], L"1234567890", true);
+
+TEST (wchar_t, [d(2)], L"",           false);
+TEST (wchar_t, [d(2)], L"1",          false);
+TEST (wchar_t, [d(2)], L"12",         true);
+TEST (wchar_t, [d(2)], L"123",        true);
+TEST (wchar_t, [d(2)], L"1234567890", true);
+
+// Helper macro to make it possible to pass as one multpile arguments
+// to another macro.
+#define Init(...) __VA_ARGS__
+
+TEST (char, [d(1)][d(1)], Init (""),        false);
+TEST (char, [1][d(1)],    Init (""),        false);
+TEST (char, [d(1)][1],    Init (""),        false);
+
+TEST (char, [d(1)][d(1)], Init ("1"),       true);
+
+// The following is accepted at compile time but throws an exception
+// at runtime since in C++ a one-element array cannot be initialized
+// with a string literal of length one because there isn't room for
+// the terminating NUL
+TEST (char, [1][d(1)],    Init ("1"),       true);
+
+// The following is rejected at comile-time since a one-element array
+// cannot be initialized with a string literal of length one because
+// there isn't room for the terminating NUL (see vla14.C).
+// TEST (char, [d(1)][1],    Init ("1"),       false);
+
+TEST (char, [d(1)][d(1)], Init ("12"),      true);
+TEST (char, [d(1)][d(1)], Init ("1", "2"),  true);
+TEST (char, [d(1)][d(1)], Init ("1", "23"), true);
+
+TEST (char, [d(2)][d(2)], Init ("", ""),    false);
+TEST (char, [d(2)][d(2)], Init ("", "1"),   false);
+TEST (char, [d(2)][d(2)], Init ("1", ""),   false);
+TEST (char, [d(2)][d(2)], Init ("1", "1"),  false);
+TEST (char, [2][d(2)],    Init ("",  "1"),  false);
+TEST (char, [2][d(2)],    Init ("1", ""),   false);
+TEST (char, [2][d(2)],    Init ("1", "1"),  false);
+TEST (char, [d(2)][2],    Init ("",  "1"),  false);
+TEST (char, [d(2)][2],    Init ("1", ""),   false);
+TEST (char, [d(2)][2],    Init ("1", "1"),  false);
+
+TEST (char, [2][d(2)],    Init ("1", "23"), true);
+TEST (char, [d(2)][d(2)], Init ("1", "23"), true);
+TEST (char, [d(2)][d(2)], Init ("1", "23"), true);
+TEST (char, [d(2)][d(2)], Init ("12","3"),  true);
+
+int main ()
+{
+  if (fail)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla14.C b/gcc/testsuite/g++.dg/cpp1y/vla14.C
new file mode 100644
index 0000000..a2db08a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla14.C
@@ -0,0 +1,47 @@
+// PR c++/70019 - VLA size overflow not detected
+// Compile-time test to verify that attempting to initialize a VLA with
+// a string that's longer than the number of elements.
+
+// { dg-do run }
+// { dg-additional-options "-Wno-vla" }
+
+
+void test (int n)
+{
+  char a1[n][1] = { { "a" } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a1;
+
+  char a2[1][n] = { { "a" } };
+  (void)a2;
+
+  char a3[n][1][1] = { { { "a" } } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a3;
+
+  char a4[1][1][n] = { { { "a" } } };
+  (void)a4;
+
+  char a5[1][n][1] = { { { "a" } } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a5;
+
+  char a6[n][1][n] = { { { "a" } } };
+  (void)a6;
+
+
+  wchar_t a7[n][1] = { { L"a" } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a7;
+
+  wchar_t a8[1][n] = { { L"a" } };
+  (void)a8;
+
+  wchar_t a9[n][1][1] = { { { L"a" } } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a9;
+
+  wchar_t a10[1][1][n] = { { { L"a" } } };
+  (void)a10;
+
+  wchar_t a11[][n][1] = { { { L"a" } } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a11;
+
+  wchar_t a12[n][1][n] = { { { L"a" } } };
+  (void)a12;
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla3.C b/gcc/testsuite/g++.dg/cpp1y/vla3.C
new file mode 100644
index 0000000..9b2d6b3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla3.C
@@ -0,0 +1,43 @@
+// Test for throwing bad_array_length on invalid array length.
+// { dg-do run { target c++14 } }
+// { dg-additional-options "-Wno-vla" }
+
+namespace std
+{
+struct exception
+{
+  virtual ~exception ();
+  virtual const char* what () const throw ();
+};
+}
+
+int f(int i)
+{
+  int ar[i]{1,2,3,4};
+  return ar[i-1];
+}
+
+void g(int i)
+{
+  int ar[i];
+  ar[0] = 42;
+}
+
+int main()
+{
+  int ok = 0;
+  f(4);				// OK
+  try {
+    f(3);			// too small
+  }
+  catch (std::exception &e) {
+    ++ok;
+  }
+  try { g(-24); }		// negative
+  catch (std::exception &e) {
+    ++ok;
+  }
+
+  if (ok != 2)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/ubsan/vla-1.C b/gcc/testsuite/g++.dg/ubsan/vla-1.C
index 311cdb1..374c80a 100644
--- a/gcc/testsuite/g++.dg/ubsan/vla-1.C
+++ b/gcc/testsuite/g++.dg/ubsan/vla-1.C
@@ -1,5 +1,8 @@
 // { dg-do run }
-// { dg-options "-Wno-vla -fsanitize=undefined" }
+// Disable exceptions to prevent the erroneous initializer from
+// throwing before the sanitizer instrumentation has detected
+// the problem.
+// { dg-options "-Wno-vla -fno-exceptions -fsanitize=undefined" }
 // { dg-output "index 1 out of bounds" }
 
 void f(int i) {

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

* Re: [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
  2016-03-07  1:38 [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements Martin Sebor
@ 2016-03-14 21:26 ` Martin Sebor
  2016-03-21 22:10   ` PING #2 " Martin Sebor
  2016-03-23 18:34 ` Jason Merrill
  1 sibling, 1 reply; 22+ messages in thread
From: Martin Sebor @ 2016-03-14 21:26 UTC (permalink / raw)
  To: Gcc Patch List, Jason Merrill

Ping:
   https://gcc.gnu.org/ml/gcc-patches/2016-03/msg00441.html

On 03/06/2016 06:38 PM, Martin Sebor wrote:
> GCC 4.9 had added support for C++ VLAs as specified in WG21
> document N3639 expected to be included in C++ 14.  However,
> WG21 ultimately decided not to include N3639 in C++ 14 and
> the G++ support was partially removed in 5.1.  Unfortunately,
> the removal rendered some safe albeit erroneous G++ 4.9 code
> undefined.  This patch restores the well-defined behavior of
> such code by having it throw an exception in response to
> the erroneous conditions.
>
> While testing the patch I found a number of other problems in
> the G++ support for VLAs, including PR c++/70019 - VLA size
> overflow not detected, which was never implemented (not even
> in 4.9).  Since this is closely related to the regression
> discussed in 69517 the patch also provides that support.
>
> There are a few additional points to note about the patch:
>
> 1) It restores the std::bad_array_length exception from N3639,
>     even though the class isn't specified by the C++ standard.
>     At first I thought that introducing a different (private)
>     type would be more appropriate, but in the end couldn't come
>     up with a good argument for not keeping the same type.  Using
>     the same type also allows programs that rely on the exception
>     and that were built with GCC 4.9 to be ported to GCC 6 without
>     change.
>
> 2) It hardwires a rather arbitrarily restrictive limit of 64 KB
>     on the size of the biggest C++ VLA.  (This could stand to be
>     improved and made more intelligent, and perhaps integrated
>     with stack  checking via -fstack-limit, after the GCC 6
>     release.)
>
> 3) By throwing an exception for erroneous VLAs the patch largely
>     defeats the VLA Sanitizer.  The sanitizer is still useful in
>     C++ 98 mode where the N3639 VLA runtime checking is disabled,
>     and when exceptions are disabled via -fno-exceptions.
>     Disabling  the VLA checking in C++ 98 mode doesn't seem like
>     a useful feature, but I didn't feel like reverting what was
>     a deliberate decision.
>
> Martin

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

* PING #2 [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
  2016-03-14 21:26 ` Martin Sebor
@ 2016-03-21 22:10   ` Martin Sebor
  0 siblings, 0 replies; 22+ messages in thread
From: Martin Sebor @ 2016-03-21 22:10 UTC (permalink / raw)
  To: Gcc Patch List, Jason Merrill

I'm looking for a review of the patch below.  I noticed a piece
of commented out code in there.  Please assume that I will remove
it before the final commit.

As a heads up, I'm traveling this Thursday through Sunday and
won't have access to email to answer questions or address
comments until next Monday.

Martin

On 03/14/2016 03:26 PM, Martin Sebor wrote:
> Ping:
>    https://gcc.gnu.org/ml/gcc-patches/2016-03/msg00441.html
>
> On 03/06/2016 06:38 PM, Martin Sebor wrote:
>> GCC 4.9 had added support for C++ VLAs as specified in WG21
>> document N3639 expected to be included in C++ 14.  However,
>> WG21 ultimately decided not to include N3639 in C++ 14 and
>> the G++ support was partially removed in 5.1.  Unfortunately,
>> the removal rendered some safe albeit erroneous G++ 4.9 code
>> undefined.  This patch restores the well-defined behavior of
>> such code by having it throw an exception in response to
>> the erroneous conditions.
>>
>> While testing the patch I found a number of other problems in
>> the G++ support for VLAs, including PR c++/70019 - VLA size
>> overflow not detected, which was never implemented (not even
>> in 4.9).  Since this is closely related to the regression
>> discussed in 69517 the patch also provides that support.
>>
>> There are a few additional points to note about the patch:
>>
>> 1) It restores the std::bad_array_length exception from N3639,
>>     even though the class isn't specified by the C++ standard.
>>     At first I thought that introducing a different (private)
>>     type would be more appropriate, but in the end couldn't come
>>     up with a good argument for not keeping the same type.  Using
>>     the same type also allows programs that rely on the exception
>>     and that were built with GCC 4.9 to be ported to GCC 6 without
>>     change.
>>
>> 2) It hardwires a rather arbitrarily restrictive limit of 64 KB
>>     on the size of the biggest C++ VLA.  (This could stand to be
>>     improved and made more intelligent, and perhaps integrated
>>     with stack  checking via -fstack-limit, after the GCC 6
>>     release.)
>>
>> 3) By throwing an exception for erroneous VLAs the patch largely
>>     defeats the VLA Sanitizer.  The sanitizer is still useful in
>>     C++ 98 mode where the N3639 VLA runtime checking is disabled,
>>     and when exceptions are disabled via -fno-exceptions.
>>     Disabling  the VLA checking in C++ 98 mode doesn't seem like
>>     a useful feature, but I didn't feel like reverting what was
>>     a deliberate decision.
>>
>> Martin
>

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

* Re: [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
  2016-03-07  1:38 [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements Martin Sebor
  2016-03-14 21:26 ` Martin Sebor
@ 2016-03-23 18:34 ` Jason Merrill
  2016-03-23 22:50   ` Martin Sebor
  1 sibling, 1 reply; 22+ messages in thread
From: Jason Merrill @ 2016-03-23 18:34 UTC (permalink / raw)
  To: Martin Sebor, Gcc Patch List

On 03/06/2016 08:38 PM, Martin Sebor wrote:
> There are a few additional points to note about the patch:
>
> 1) It restores the std::bad_array_length exception from N3639,
>     even though the class isn't specified by the C++ standard.
>     At first I thought that introducing a different (private)
>     type would be more appropriate, but in the end couldn't come
>     up with a good argument for not keeping the same type.  Using
>     the same type also allows programs that rely on the exception
>     and that were built with GCC 4.9 to be ported to GCC 6 without
>     change.

Makes sense.

> 2) It hardwires a rather arbitrarily restrictive limit of 64 KB
>     on the size of the biggest C++ VLA.  (This could stand to be
>     improved and made more intelligent, and perhaps integrated
>     with stack checking via -fstack-limit, after the GCC 6
>     release.)

The bounds checking should share code with build_new_1.

> 3) By throwing an exception for erroneous VLAs the patch largely
>     defeats the VLA Sanitizer.  The sanitizer is still useful in
>     C++ 98 mode where the N3639 VLA runtime checking is disabled,
>     and when exceptions are disabled via -fno-exceptions.
>     Disabling  the VLA checking in C++ 98 mode doesn't seem like
>     a useful feature, but I didn't feel like reverting what was
>     a deliberate decision.

What deliberate decision?  The old code checked for C++14 mode because 
the feature was part of the C++14 working paper.  What's the rationale 
for C++11 as the cutoff?

Jason

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

* Re: [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
  2016-03-23 18:34 ` Jason Merrill
@ 2016-03-23 22:50   ` Martin Sebor
  2016-03-24 16:24     ` Jason Merrill
  0 siblings, 1 reply; 22+ messages in thread
From: Martin Sebor @ 2016-03-23 22:50 UTC (permalink / raw)
  To: Jason Merrill, Gcc Patch List

Thanks for the comments.

>> 2) It hardwires a rather arbitrarily restrictive limit of 64 KB
>>     on the size of the biggest C++ VLA.  (This could stand to be
>>     improved and made more intelligent, and perhaps integrated
>>     with stack checking via -fstack-limit, after the GCC 6
>>     release.)
>
> The bounds checking should share code with build_new_1.

I agree that sharing the same code is right long term approach.

I had initially started out down that path, by factoring out code
from build_new_1 into a general function that I had thought could
be shared between it and cp_finish_decl.  But I ended up abandoning
that approach two reasons:

a) The checking expression built for array new is quite a bit less
    involved because only the major dimension of the array in requires
    runtime checking (the others must be constant and are checked at
    compile time).  In contrast, all VLA dimensions are potentially
    dynamic and so must be checked at runtime.

b) While (a) can be solved by making the checking function smart
    and general enough, it felt too intrusive and potentially risky
    to change array new at this stage.

That said, I'm happy to do this refactoring in stage 1.

>
>> 3) By throwing an exception for erroneous VLAs the patch largely
>>     defeats the VLA Sanitizer.  The sanitizer is still useful in
>>     C++ 98 mode where the N3639 VLA runtime checking is disabled,
>>     and when exceptions are disabled via -fno-exceptions.
>>     Disabling  the VLA checking in C++ 98 mode doesn't seem like
>>     a useful feature, but I didn't feel like reverting what was
>>     a deliberate decision.
>
> What deliberate decision?  The old code checked for C++14 mode because
> the feature was part of the C++14 working paper.  What's the rationale
> for C++11 as the cutoff?

Sorry, I had misremembered the original C++ 14 check as one for
C++ 11.  Are you suggesting to restore the checking only for C++
14 mode, or for all modes?  Either is easy enough to do though,
IMO, it should be safe in all modes and I would expect it to be
preferable to undefined behavior.

Martin

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

* Re: [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
  2016-03-23 22:50   ` Martin Sebor
@ 2016-03-24 16:24     ` Jason Merrill
  2016-04-01 23:02       ` Martin Sebor
  0 siblings, 1 reply; 22+ messages in thread
From: Jason Merrill @ 2016-03-24 16:24 UTC (permalink / raw)
  To: Martin Sebor, Gcc Patch List

On 03/23/2016 03:47 PM, Martin Sebor wrote:
> Thanks for the comments.
>
>>> 2) It hardwires a rather arbitrarily restrictive limit of 64 KB
>>>     on the size of the biggest C++ VLA.  (This could stand to be
>>>     improved and made more intelligent, and perhaps integrated
>>>     with stack checking via -fstack-limit, after the GCC 6
>>>     release.)
>>
>> The bounds checking should share code with build_new_1.
>
> I agree that sharing the same code is right long term approach.
>
> I had initially started out down that path, by factoring out code
> from build_new_1 into a general function that I had thought could
> be shared between it and cp_finish_decl.  But I ended up abandoning
> that approach two reasons:
>
> a) The checking expression built for array new is quite a bit less
>     involved because only the major dimension of the array in requires
>     runtime checking (the others must be constant and are checked at
>     compile time).  In contrast, all VLA dimensions are potentially
>     dynamic and so must be checked at runtime.
>
> b) While (a) can be solved by making the checking function smart
>     and general enough, it felt too intrusive and potentially risky
>     to change array new at this stage.
>
> That said, I'm happy to do this refactoring in stage 1.

Fair enough.  I don't think we can impose an arbitrary 64K limit, 
however, as that is a lot smaller than the 8MB default stack size, and 
programs can use setrlimit to increase the stack farther.  For GCC 6 let 
not impose any limit beyond non-negative/overflowing, and as you say we 
can do something better in GCC 7.

>>> 3) By throwing an exception for erroneous VLAs the patch largely
>>>     defeats the VLA Sanitizer.  The sanitizer is still useful in
>>>     C++ 98 mode where the N3639 VLA runtime checking is disabled,
>>>     and when exceptions are disabled via -fno-exceptions.
>>>     Disabling  the VLA checking in C++ 98 mode doesn't seem like
>>>     a useful feature, but I didn't feel like reverting what was
>>>     a deliberate decision.
>>
>> What deliberate decision?  The old code checked for C++14 mode because
>> the feature was part of the C++14 working paper.  What's the rationale
>> for C++11 as the cutoff?
>
> Sorry, I had misremembered the original C++ 14 check as one for
> C++ 11.  Are you suggesting to restore the checking only for C++
> 14 mode, or for all modes?  Either is easy enough to do though,
> IMO, it should be safe in all modes and I would expect it to be
> preferable to undefined behavior.

I think all modes.

> +	  /* Iterate over all non-empty initializers in this array, recursively
> +	     building expressions to see if the elements of each are in excess
> +	     of the (runtime) bounds of of the array type.  */
> +	  FOR_EACH_VEC_SAFE_ELT (v, i, ce)
> +	    {
> +	      if (1) // !vec_safe_is_empty (CONSTRUCTOR_ELTS (ce->value)))
> +		{
> +		  tree subcheck = build_vla_check (TREE_TYPE (type),
> +						   ce->value,
> +						   vlasize, max_vlasize,
> +						   cst_size);
> +		  check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
> +				       check, subcheck);
> +		}
> +	    }

The if (1) seems left over from development.

It looks like this will multiply *cst_size by the sub-array length once 
for each element of the outer array, leading to a too-large result.  And 
also generate redundant code to check the bounds of the sub-array 
multiple times.

It seems to me that we want use the existing check for excess 
initializers in build_vec_init, in the if (length_check) section, though 
as you mention in 70019 that needs to be improved to handle STRING_CST.

Also, I think we should check for invalid bounds in 
compute_array_index_type, next to the UBsan code.  Checking bounds only 
from cp_finish_decl means that we don't check uses of VLA types other 
than variable declarations.

> +	      /* Avoid instrumenting constexpr functions.  Those must
> +		 be checked statically, and the (non-constexpr) dynamic
> +		 instrumentation would cause them to be rejected.  */

Hmm, this sounds wrong; constexpr functions can also be called with 
non-constant arguments, and the instrumentation should be folded away 
when evaluating a call with constant arguments.

Jason

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

* Re: [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
  2016-03-24 16:24     ` Jason Merrill
@ 2016-04-01 23:02       ` Martin Sebor
  2016-04-04 23:35         ` Jason Merrill
  0 siblings, 1 reply; 22+ messages in thread
From: Martin Sebor @ 2016-04-01 23:02 UTC (permalink / raw)
  To: Jason Merrill, Gcc Patch List

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

> Fair enough.  I don't think we can impose an arbitrary 64K limit,
> however, as that is a lot smaller than the 8MB default stack size, and
> programs can use setrlimit to increase the stack farther.  For GCC 6 let
> not impose any limit beyond non-negative/overflowing, and as you say we
> can do something better in GCC 7.

Would you be open to imposing a somewhat more permissive limit,
say on the order of one or a few megabytes (but less than the
default 8 MB on Linux)?

I ask because I expect the majority of programmer errors with
VLAs to be due to out-of-range bounds that couldn't be
accommodated even if stack space was extended well beyond
the Linux default (say hundreds of MB), or that would result
in complete stack space exhaustion.  I.e., not caused by
deliberately trying to create very large VLAs but rather by
accidentally creating VLAs with unconstrained bounds (due to
a failure to validate input, uninitialized unsigned variables,
etc.)

I expect fewer cases to be due to negative or zero bounds or
excessive initializers.

I also expect programmers to want to find out about such bugs
sooner (i.e., in unit testing with plentiful stack space) rather
than after software has been deployed (and under low stack space
conditions not exercised during unit testing).

To that end, I think a lower limit is going to be more helpful
than a permissive one (or none at all).

But if even a few MB seems too strict, I would find having even
an exceedingly liberal limit (say 1GB) much preferable to none
at all as it makes it possible to exercise boundary conditions
such as the size overflow problem you noted below.

>
> I think all modes.

Sounds good.  I've enabled it in all modes.

> The if (1) seems left over from development.

Right.

>
> It looks like this will multiply *cst_size by the sub-array length once
> for each element of the outer array, leading to a too-large result.  And
> also generate redundant code to check the bounds of the sub-array
> multiple times.

Great catch, thank you!  I think it was a mistake on my part to
try to build both kinds of checks in the same function.  In the
update patch I split it up into two: one to build the bounds
check and another to build the initializer check.

During additional testing it dawned on me that there is no good
way to validate (or even to initialize) the initializer list of
a multi-dimensional VLA that isn't unambiguously braced.

For example, the following VLA with N = 2 and N = 3:

     int A [M][N] = { 1, 2, 3, 4 };

Unpatched, GCC initializes it to { { 1, 2, 3 }, { 0, 0, 0 } }.
With my first patch, GCC throws.  Neither is correct, but doing
the right thing would involve emitting parameterizing the
initialization code for the value of each bound.  While that
might be doable it feels like a bigger change than I would be
comfortable attempting at this stage.  To avoid the problem I've
made it an error to specify a partially braced VLA initializer.
If you think it's worthwhile, I can see about implementing the
runtime reshaping in stage 1.

>
> It seems to me that we want use the existing check for excess
> initializers in build_vec_init, in the if (length_check) section, though
> as you mention in 70019 that needs to be improved to handle STRING_CST.

I don't think modifying build_vec_init() alone would be sufficient.
For example, the function isn't called for a VLA with a constant
bound like this one:

  int A [2][N] = { 1, 2, 3, 4 };

> Also, I think we should check for invalid bounds in
> compute_array_index_type, next to the UBsan code.  Checking bounds only
> from cp_finish_decl means that we don't check uses of VLA types other
> than variable declarations.

You mean VLA typedefs?  That's true, though I have consciously
avoided dealing with those.  They're outlawed in N3639 and so
I've been focusing just on variables.  But since GCC accepts
VLA typedefs too I was thinking I would bring them up at some
point in the future to decide what to do about them.

As for where to add the bounds checking code, I also at first
thought of checking the bounds parallel to the UBSan code in
compute_array_index_type() and even tried that approach. The
problem with it is that it only considers one array dimension
at a time, without the knowledge of the others.  As a result,
as noted in sanitizer/70051, it doesn't correctly detect
overflows in the bounds of multidimensional VLAs.

>
>> +          /* Avoid instrumenting constexpr functions.  Those must
>> +         be checked statically, and the (non-constexpr) dynamic
>> +         instrumentation would cause them to be rejected.  */
>
> Hmm, this sounds wrong; constexpr functions can also be called with
> non-constant arguments, and the instrumentation should be folded away
> when evaluating a call with constant arguments.

You're right that constexpr functions should be checked as
well.  Unfortunately, at present, due to c++/70507 the check
(or rather the call to __builtin_mul_overflow) isn't folded
away and we end up with error: call to internal function.
As much as I'd like to fix this I'm concerned that it might
take me too long and don't want to hold up the schedule or
risk that the patch, incomplete though it may be, won't make
it into GCC 6.

Attached is the latest update.  I've taken the liberty of
setting the limit to 1 MB in hopes you'll find it acceptable.
I can easily bump it up to an even more permissive value,
though as I mention above, I'd prefer not to lift altogether.

I'm happy to continue improving the patch but since time is
running out I want to post an updated version for consideration
as is and get feedback on it.

Thanks
Martin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: gcc-69517.patch --]
[-- Type: text/x-patch; name="gcc-69517.patch", Size: 64183 bytes --]

PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
PR c++/70019 - VLA size overflow not detected

gcc/testsuite/ChangeLog:
2016-04-01  Martin Sebor  <msebor@redhat.com>

	PR c++/69517
	PR c++/70019
	* c-c++-common/ubsan/vla-1.c (main): Catch exceptions.
	* g++.dg/cpp1y/vla11.C: New test.
	* g++.dg/cpp1y/vla12.C: New test.
	* g++.dg/cpp1y/vla13.C: New test.
	* g++.dg/cpp1y/vla14.C: New test.
	* g++.dg/cpp1y/vla3.C: Restore deleted test.
	* gcc/testsuite/g++.dg/init/array24.C: Fully brace VLA initializer.
	* g++.dg/ubsan/vla-1.C: Disable exceptions.

gcc/cp/ChangeLog:
2016-04-01  Martin Sebor  <msebor@redhat.com>

	PR c++/69517
	PR c++/70019
	* decl.c (vla_p, throw_bad_array_length, build_vla_check_size,
	build_vla_check_init, build_vla_check): New functions.
	(check_initializer, cp_finish_decl): Call them.
	(reshape_init_r): Reject incompletely braced intializer-lists
	for VLAs.

gcc/doc/ChangeLog:

2016-04-01  Martin Sebor  <msebor@redhat.com>

	PR c++/69517
	PR c++/70019
	* extend.texi (Variable Length): Document C++ specifics.

libstdc++-v3/ChangeLog:

2016-04-01  Martin Sebor  <msebor@redhat.com>

	PR c++/69517
	* testsuite/25_algorithms/rotate/moveable2.cc: Make sure VLA
	upper bound is positive.

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index cfae210..dbfbdb1 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -106,6 +106,21 @@ static tree build_cp_library_fn (tree, enum tree_code, tree, int);
 static void store_parm_decls (tree);
 static void initialize_local_var (tree, tree);
 static void expand_static_init (tree, tree);
+static bool vla_p (tree);
+static tree build_vla_check (tree, tree = NULL_TREE);
+
+/* Call __cxa_throw_bad_array_length to indicate that the size calculation
+   overflowed.  */
+tree
+throw_bad_array_length (void)
+{
+  tree fn = get_identifier ("__cxa_throw_bad_array_length");
+  if (!get_global_value_if_present (fn, &fn))
+    fn = push_throw_library_fn (fn, build_function_type_list (void_type_node,
+                                                             NULL_TREE));
+
+  return build_cxx_call (fn, 0, NULL, tf_warning_or_error);
+}
 
 /* The following symbols are subsumed in the cp_global_trees array, and
    listed here individually for documentation purposes.
@@ -5852,6 +5867,16 @@ reshape_init_r (tree type, reshape_iter *d, bool first_initializer_p,
 	    }
 	}
 
+      if (vla_p (type))
+	{
+	  /* Require VLAs to have their initializers fully braced
+	     to avoid initializing the wrong elements.  */
+	  if (complain & tf_error)
+	    error ("missing braces around initializer for a variable length "
+		   "array %qT", type);
+	  return error_mark_node;
+	}
+
       warning (OPT_Wmissing_braces, "missing braces around initializer for %qT",
 	       type);
     }
@@ -6155,6 +6180,32 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
 	      && PAREN_STRING_LITERAL_P (DECL_INITIAL (decl)))
 	    warning (0, "array %qD initialized by parenthesized string literal %qE",
 		     decl, DECL_INITIAL (decl));
+
+	  if (TREE_CODE (type) == ARRAY_TYPE
+	      && vla_p (type)
+	      && !processing_template_decl)
+	    {
+	      /* Statically check for overflow in VLA bounds and build
+		 an expression that checks whether the VLA is erroneous
+		 at runtime, either due to invalid (runtime) bounds or
+		 due to excess initializers for the runtime bounds.  */
+	      tree check = build_vla_check (TREE_TYPE (decl), init);
+
+	      if (flag_exceptions && current_function_decl
+		  /* Avoid instrumenting constexpr functions for now.
+		     Those must be checked statically, and the (non-
+		     constexpr) dynamic instrumentation would cause
+		     them to be rejected.  See c++/70507.  */
+		  && !DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+		{
+		  /* Use the runtime check only when exceptions are enabled.
+		     Otherwise let bad things happen...  */
+		  check = build3 (COND_EXPR, void_type_node, check,
+				  throw_bad_array_length (), void_node);
+
+		  finish_expr_stmt (check);
+		}
+	    }
 	  init = NULL;
 	}
     }
@@ -6510,6 +6561,253 @@ notice_forced_label_r (tree *tp, int *walk_subtrees, void *)
   return NULL_TREE;
 }
 
+/* The implementation of build_vla_check() that recursively builds
+   an expression to determine whether the VLA TYPE is erroneous.
+   VLASIZE is used internally to pass the incrementally computed size
+   of the VLA object down to its recursive invocations.
+   MAX_VLASIZE is the maximum valid size of the VLA in bytes.
+   CST_SIZE is the product of the constant dimensions of the array.  */
+
+static tree
+build_vla_size_check (tree type,
+		      tree vlasize,
+		      tree max_vlasize,
+		      offset_int *cst_size)
+{
+  tree vmul = builtin_decl_explicit (BUILT_IN_MUL_OVERFLOW);
+
+  tree vlasizeaddr = build_unary_op (input_location, ADDR_EXPR, vlasize, 0);
+
+  tree check = boolean_false_node;
+
+  bool overflow = false;
+
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      /* Compute the upper bound of this array type.  */
+      tree inner_nelts = array_type_nelts_top (type);
+      tree inner_nelts_cst = maybe_constant_value (inner_nelts);
+
+      if (TREE_CODE (inner_nelts_cst) == INTEGER_CST)
+	{
+	  /* The upper bound is a constant expression.  Compute the product
+	     of the constant upper bounds seen so far so that overflow can
+	     be diagnosed.  */
+	  offset_int result = wi::mul (wi::to_offset (inner_nelts_cst),
+				       *cst_size, SIGNED, &overflow);
+	  *cst_size = overflow ? 0 : result;
+	}
+
+      /* Check for overflow in the VLAs (runtime) upper bounds.  */
+      tree vflowcheck = build_call_expr (vmul, 3, inner_nelts,
+					 vlasize, vlasizeaddr);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, vflowcheck);
+
+      /* Recursively check for overflow in the remaining major bounds.  */
+      tree subcheck = build_vla_size_check (TREE_TYPE (type),
+					    vlasize, max_vlasize,
+					    cst_size);
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, subcheck);
+    }
+  else
+    {
+      /* Get the size of the VLA element type in bytes.  */
+      tree typesize = TYPE_SIZE_UNIT (type);
+
+      /* See if the size, when multipled by the product of the VLA's
+	 constant dimensions, is within range of size_t.  If not,
+	 the VLA is definitely erroneous amd must be diagnosed at
+	 compile time.  */
+      offset_int result = wi::mul (wi::to_offset (typesize), *cst_size,
+				   SIGNED, &overflow);
+      *cst_size = overflow ? 0 : result;
+
+      /* Multiply the (non-constant) VLA size so far by the element size,
+	 checking for overflow, and replacing the value of vlasize with
+	 the product in the absence of overflow.  */
+      tree vflowcheck = build_call_expr (vmul, 3, typesize,
+					 vlasize, vlasizeaddr);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, vflowcheck);
+
+      /* Check to see if the final VLA size exceeds the maximum.  */
+      tree sizecheck = fold_build2 (LT_EXPR, boolean_type_node,
+				    max_vlasize, vlasize);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, sizecheck);
+
+      /* Also check to see if it's zero or negative.  */
+      tree zerocheck = fold_build2 (LE_EXPR, boolean_type_node,
+				    vlasize, size_zero_node);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, zerocheck);
+    }
+
+  /* Diagnose overflow determined at compile time.  */
+  if (overflow)
+    {
+      error ("integer overflow in array size");
+      /* Reset to suppress any further diagnostics.  */
+      *cst_size = 0;
+    }
+
+  return check;
+}
+
+/* The implementation of build_vla_check() that recursively builds
+   an expression to determine whether the VLA initializer-list for
+   TYPE is erroneous.
+   INIT is the VLA initializer expression to check against TYPE.  */
+
+static tree
+build_vla_init_check (tree type, tree init)
+{
+  tree check = boolean_false_node;
+
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      /* Compute the upper bound of this array type.  */
+      tree inner_nelts = array_type_nelts_top (type);
+
+      size_t len;
+
+      if (TREE_CODE (init) == CONSTRUCTOR)
+	{
+	  /* The initializer of this array is itself an array.  Build
+	     an expression to check if the number of elements in the
+	     initializer array exceeds the upper bound of the type
+	     of the object being initialized.  */
+	  if (vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (init))
+	    {
+	      len = v->length ();
+	      tree initelts = build_int_cstu (size_type_node, len);
+	      check = fold_build2 (LT_EXPR, boolean_type_node, inner_nelts,
+				   initelts);
+
+	      constructor_elt *ce;
+	      HOST_WIDE_INT i;
+
+	      /* Iterate over all non-empty initializers in this array,
+		 recursively building expressions to see if the elements
+		 of each are in excess of the corresponding (runtime)
+		 bound of the array type.  */
+	      FOR_EACH_VEC_SAFE_ELT (v, i, ce)
+		{
+		  tree subcheck = build_vla_init_check (TREE_TYPE (type),
+							ce->value);
+
+		  check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+				       check, subcheck);
+		}
+	    }
+	}
+      else if (TREE_CODE (init) == STRING_CST
+	       && (len = TREE_STRING_LENGTH (init)))
+	{
+	  /* The initializer of this array is a string.  */
+	  tree ctype = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init)));
+	  len /= TYPE_PRECISION (ctype) / BITS_PER_UNIT;
+
+	  /* A C++ string literal initializer must have at most as many
+	     characters as there are elements in the array, including
+	     the terminating NUL.  */
+	  tree initelts = build_int_cstu (size_type_node, len);
+	  tree initcheck = fold_build2 (LT_EXPR, boolean_type_node,
+					inner_nelts, initelts);
+	  check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, check,
+			       initcheck);
+	}
+      else if (TREE_CODE (init) == ERROR_MARK)
+	{
+	  // No checking is possible.
+	  check = boolean_false_node;
+	}
+      else
+	{
+	  /* What's this array initializer?  */
+	  gcc_unreachable ();
+	}
+    }
+
+  return check;
+}
+
+/* Build an expression to determine whether the VLA TYPE is erroneous.
+   INIT is the VLA initializer expression or NULL_TREE when the VLA is
+   not initialized.  */
+
+static tree
+build_vla_check (tree type, tree init /* = NULL_TREE */)
+{
+  /* This is the initial (non-recursive) call to the function.
+     Build a variable storing the total runtime size of the VLA.  */
+  tree vlasize = build_decl (input_location,
+			     VAR_DECL, NULL_TREE, sizetype);
+  DECL_ARTIFICIAL (vlasize) = 1;
+  DECL_IGNORED_P (vlasize) = 1;
+  DECL_CONTEXT (vlasize) = current_function_decl;
+  DECL_INITIAL (vlasize) = size_one_node;
+  layout_decl (vlasize, 0);
+  vlasize = pushdecl (vlasize);
+  cp_finish_decl (vlasize, size_one_node, true, NULL_TREE, 0);
+
+  /* Impose a limit on the size of the biggest VLA in bytes.  */
+  tree max_vlasize
+    = fold_build2 (LSHIFT_EXPR, size_type_node, size_one_node,
+		   wide_int_to_tree (size_type_node, 20) /* 1 MB */);
+
+  /* The product of all constant dimensions of the VLA shared by recursive
+     invocations of the function.  */
+  offset_int cst_size = 1;
+
+  /* Build an expression that checks the runtime bounds of the VLA for
+     invalid values and the size of the VLA for overflow.  */
+  tree check
+    = build_vla_size_check (type, vlasize, max_vlasize, &cst_size);
+
+  if (wi::ltu_p (wi::to_offset (max_vlasize), cst_size))
+    {
+      /* Issue the warning only in the "topmost" (non-recursive) call
+	 to avoid duplicating diagnostics.  This is only a warning to
+	 allow programs to be portable to more permissive environments.  */
+      warning (OPT_Wvla, "size of variable length array exceeds maximum "
+	       "of %qE bytes",  max_vlasize);
+    }
+
+  if (init)
+    {
+      /* Build an expression that checks the VLA initializer expression
+	 against the type of the VLA for excess elements.  */
+      tree init_check
+	= build_vla_init_check (type, init);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, check,
+			   init_check);
+    }
+
+  return check;
+}
+
+/* Return true when either T is a variably modified array type,
+   or (recursively) when T is an array of variable modified types.  */
+static bool
+vla_p (tree t)
+{
+  if (array_of_runtime_bound_p (t))
+    return true;
+
+  if (TREE_TYPE (t) && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
+    return vla_p (TREE_TYPE (t));
+
+  return false;
+}
+
 /* Finish processing of a declaration;
    install its line number and initial value.
    If the length of an array type is not known before,
@@ -6630,21 +6928,24 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 	}
     }
 
-  if (init && VAR_P (decl))
+  if (VAR_P (decl))
     {
-      DECL_NONTRIVIALLY_INITIALIZED_P (decl) = 1;
-      /* If DECL is a reference, then we want to know whether init is a
-	 reference constant; init_const_expr_p as passed tells us whether
-	 it's an rvalue constant.  */
-      if (TREE_CODE (type) == REFERENCE_TYPE)
-	init_const_expr_p = potential_constant_expression (init);
-      if (init_const_expr_p)
+      if (init)
 	{
-	  /* Set these flags now for templates.  We'll update the flags in
-	     store_init_value for instantiations.  */
-	  DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
-	  if (decl_maybe_constant_var_p (decl))
-	    TREE_CONSTANT (decl) = 1;
+	  DECL_NONTRIVIALLY_INITIALIZED_P (decl) = 1;
+	  /* If DECL is a reference, then we want to know whether init is a
+	     reference constant; init_const_expr_p as passed tells us whether
+	     it's an rvalue constant.  */
+	  if (TREE_CODE (type) == REFERENCE_TYPE)
+	    init_const_expr_p = potential_constant_expression (init);
+	  if (init_const_expr_p)
+	    {
+	      /* Set these flags now for templates.  We'll update the flags in
+		 store_init_value for instantiations.  */
+	      DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
+	      if (decl_maybe_constant_var_p (decl))
+		TREE_CONSTANT (decl) = 1;
+	    }
 	}
     }
 
@@ -6797,6 +7098,33 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 	  cleanups = make_tree_vector ();
 	  init = check_initializer (decl, init, flags, &cleanups);
 
+	  if (TREE_CODE (type) == ARRAY_TYPE
+	      && vla_p (type)
+	      && !processing_template_decl)
+	    {
+	      /* Statically check for overflow in VLA bounds and build
+		 an expression that checks whether the VLA is erroneous
+		 at runtime.  */
+	      tree check = build_vla_check (type);
+
+	      if (cxx_dialect >= cxx11
+		  && flag_exceptions
+		  && current_function_decl
+		  /* Avoid instrumenting constexpr functions.  Those must
+		     be checked statically, and the (non-constexpr) dynamic
+		     instrumentation would cause them to be rejected.  */
+		  && !DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+		{
+		  /* Use the runtime check only in C++ 11 mode and later
+		     and when exceptions are enabled.  Otherwise let bad
+		     things happen...  */
+		  check = build3 (COND_EXPR, void_type_node, check,
+				  throw_bad_array_length (), void_node);
+
+		  finish_expr_stmt (check);
+		}
+	    }
+
 	  /* Handle:
 
 	     [dcl.init]
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 6e27029..616479d 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -1634,14 +1634,48 @@ foo (int n)
 You can use the function @code{alloca} to get an effect much like
 variable-length arrays.  The function @code{alloca} is available in
 many other C implementations (but not in all).  On the other hand,
-variable-length arrays are more elegant.
+variable-length arrays are available in GCC for all targets and
+provide type safety.
 
 There are other differences between these two methods.  Space allocated
 with @code{alloca} exists until the containing @emph{function} returns.
 The space for a variable-length array is deallocated as soon as the array
 name's scope ends, unless you also use @code{alloca} in this scope.
 
-You can also use variable-length arrays as arguments to functions:
+Unlike GCC, G++ instruments variable-length arrays (@xref{Variable Length})
+with checks for erroneous uses: when a variable-length array object is
+created its runtime bounds are checked to detect non-positive values,
+integer overflows, sizes in excess of 1 MB, and excess initializers.
+When an erroneous variable-length array is detected the runtime arranges
+for an exception to be thrown that matches a handler of type
+@code{std::bad_array_length}.
+
+Also unlike GCC, G++ allows variable-length arrays to be initialized.
+However, unlike initializer lists for ordinary multidimensional arrays,
+those for multidimensional variable-length arrays must be enclosed in
+pairs of curly braces delimiting each sequence of values to use to
+initialize each subarray.  Initializer lists that aren't unambiguously
+enclosed in braces are rejected with an error.  For example, in the
+following function, the initializer list for the ordinary @code{array}
+is accepted even though it isn't fully enclosed in braces.  The same
+initializer list, however, wouldn't be accepted for a multidimensional
+variable-length array.  To initialize the variable-length array @code{vla},
+the elements of the subarray @code{vla[m]} must be enclosed in braces
+as shown.  As with ordinary arrays, elements that aren't initialized
+explicitly are default-initialized.
+
+@smallexample
+void
+foo (int m, int n)
+@{
+  int array[2][3] = @{ 1, 2, 4, 5, 6 @};
+  int vla[m][n] = @{ @{ 1, 2 @}, @{ 4, 5, 6 @} @};
+@}
+@end smallexample
+
+
+In C programs (but not in C++) variable-length arrays can also be declared
+as function arguments:
 
 @smallexample
 struct entry
diff --git a/gcc/testsuite/c-c++-common/ubsan/vla-1.c b/gcc/testsuite/c-c++-common/ubsan/vla-1.c
index 52ade3a..27ef110 100644
--- a/gcc/testsuite/c-c++-common/ubsan/vla-1.c
+++ b/gcc/testsuite/c-c++-common/ubsan/vla-1.c
@@ -87,18 +87,24 @@ fn12 (void)
 int
 main (void)
 {
-  fn1 ();
-  fn2 ();
-  fn3 ();
-  fn4 ();
-  fn5 ();
-  fn6 ();
-  fn7 ();
-  fn8 ();
-  fn9 ();
-  fn10 ();
-  fn11 ();
-  fn12 ();
+#if __cplusplus
+#  define TRY(stmt)   do { try { stmt; } catch (...) { } } while (0)
+#else
+#  define TRY(stmt)   stmt
+#endif
+
+  TRY (fn1 ());
+  TRY (fn2 ());
+  TRY (fn3 ());
+  TRY (fn4 ());
+  TRY (fn5 ());
+  TRY (fn6 ());
+  TRY (fn7 ());
+  TRY (fn8 ());
+  TRY (fn9 ());
+  TRY (fn10 ());
+  TRY (fn11 ());
+  TRY (fn12 ());
   return 0;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla11.C b/gcc/testsuite/g++.dg/cpp1y/vla11.C
new file mode 100644
index 0000000..c1d5fb9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla11.C
@@ -0,0 +1,621 @@
+// PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer
+//   elements
+// PR c++/70019 - VLA size overflow not detected
+//
+// Runtime test to verify that attempting to either construct a VLA with
+// erroneous bounds, or initialize one with an initializer-list that
+// contains more elements than the VLA's non-constant (runtime) bounds
+// causes an exception to be thrown.  Test also verifies that valid
+// VLAs and their initializers don't cause such an exception.
+
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-Wno-vla" }
+
+#pragma GCC diagnostic ignored "-Wvla"
+
+#define INT_MAX    __INT_MAX__
+#define LONG_MAX   __LONG_MAX__
+#define SIZE_MAX   __SIZE_MAX__
+#define UINT_MAX   (~0U)
+#define ULONG_MAX  (~0LU)
+
+#define INT_MIN    (-__INT_MAX__ - 1)
+#define LONG_MIN   (-__LONG_MAX__ - 1)
+
+// Undefine to enable tests that cause an ICE due to c++/58646.
+#define BUG_58646 1
+
+// Helper macro to make it possible to pass as one multpile arguments
+// to another macro.
+#define Init(...) __VA_ARGS__
+
+// The size of the largest allowed VLA in bytes.  Bigger objects
+// cause an exception to be thrown.
+#define MAX   (1 << 20)
+
+typedef __SIZE_TYPE__ size_t;
+
+// Incremented for each test failure.
+int fail;
+
+// Used to convert a constant array dimension to a non-constant one.
+template <class T>
+T d (T n)
+{
+  return n;
+}
+
+// Verify either that an expected exception has been thrown or that
+// one hasn't been thrown if one isn't expected.
+int __attribute__ ((noclone, noinline))
+sink (void *p, int line, bool expect, const char *expr)
+{
+  if (!p != expect)
+    {
+      __builtin_printf ("line %i: Assertion failed: '%s': "
+                        "exception unexpectedly %sthrown\n",
+                        line, expr, !p ? "" : "not ");
+      ++fail;
+    }
+  else
+    {
+#if defined DEBUG && DEBUG
+    __builtin_printf ("line %i: Assertion passed: '%s': "
+		      "exception %sthrown as expected\n",
+		      line, expr, !p ? "" : "not ");
+#endif
+    }
+    
+  return 0;
+}
+
+#define _CAT(name, line) name ## line
+#define CAT(name, line) _CAT (name, line)
+
+#define STR(...) #__VA_ARGS__
+
+// Type to exercise VLA with.  TYPESIZE is the size of the type in bytes.
+// Using a template serves two purposes.  First, it makes it possible to
+// parameterize the test on VLAs of different size.  Second, it verifies
+// that the checking code can deal with templates (i.e., completes
+// the element type of the VLA when necessary).
+template <unsigned TypeSize>
+struct alignas (TypeSize) TestType
+{
+  char data;
+};
+
+// Test function invoked with a pointer to each test case.  Must
+// return a value though what value doesn't matter.
+int __attribute__ ((noclone, noinline))
+tester (int (*testcase)(const char*),
+	const char *str, int line, bool expect)
+{
+  try
+    {
+      return testcase (str);
+    }
+  catch (...)
+    {
+      return sink (0, __LINE__, expect, str);
+    }
+}
+
+// Macro to define a unique specialization of a function template to
+// exercise a VLA of type T, rank N, with dimensions given by Dims
+// and initializer Init.  Expect is true when the VLA initialization
+// is expected to trigger an exception.
+// The macro creates a unique global dummy int object and initializes
+// it with the result of the function.  The dummy object servers no
+// other purpose but to call the function.  The function verifies
+// the expected postconditions.
+#define TEST(TypeSize, Dims, Init, Expect)				\
+  static int CAT (testcase, __LINE__)(const char *str)			\
+  {									\
+    TestType<TypeSize> vla Dims Init;					\
+    static_assert (sizeof (TestType<TypeSize>) == TypeSize,		\
+		   "wrong test type size");				\
+    return sink (vla, __LINE__, Expect, str);				\
+  }									\
+  const int CAT (dummy, __LINE__)					\
+    = tester (CAT (testcase, __LINE__),					\
+	      "T<" #TypeSize "> a" #Dims " = { " STR (Init) " }",	\
+	      __LINE__, Expect)
+
+
+// Create and run a test function exercising a VLA definition
+// of one of the following forms:
+//    TestType<Size> VLA Dims;        // uninitialized (with Init ())
+// or:
+//    TestType<Size> VLA Dims Init;   // initialized (with = Init ({...})
+//
+//    +-- Element Size (in Bytes)
+//    |  +-- VLA Dimensions (constant as in [3], otherwise d(3))
+//    |  |         +-- VLA Initializer Expression (if any)
+//    |  |         |                  +-- Expect Exception
+//    |  |         |                  |
+//    V  V         V                  V
+TEST (1, [d(0)],   Init (/* none*/),  true);   // uninitialized
+
+#if !BUG_58646
+// The following causes an ICE due to c++/58646.
+TEST (1, [d(0)],   Init ({}),         true);
+#endif
+TEST (1, [d(0)],   Init ({1}),        true);   // initialized with " {1}"
+TEST (1, [d(0)],   = Init ({1}),      true);   // initialized with "= {1}"
+
+TEST (1, [d(1)],   Init (),           false);
+TEST (1, [d(1)],   Init ({}),         false);
+TEST (1, [d(1)],   = Init ({}),       false);
+TEST (1, [d(1)],   Init ({1}),        false);
+TEST (1, [d(1)],   = Init ({1}),      false);
+TEST (1, [d(1)],   Init ({1, 2}),     true);
+TEST (1, [d(1)],   = Init ({1, 2}),   true);
+
+TEST (1, [d(2)],   Init (),           false);
+TEST (1, [d(2)],   Init ({}),         false);
+TEST (1, [d(2)],   Init ({1}),        false);
+TEST (1, [d(2)],   Init ({1, 2}),     false);
+TEST (1, [d(2)],   Init ({1, 2, 3}),  true);
+
+TEST (1, [d(MAX)], Init (),           false);
+TEST (1, [d(MAX)], Init ({}),         false);
+TEST (1, [d(MAX)], Init ({1}),        false);
+TEST (1, [d(MAX)], Init ({1, 2}),     false);
+TEST (1, [d(MAX)], Init ({1, 2, 3}),  false);
+
+// Very large but not erroneous one dimensional VLAs.
+TEST ( 2, [d(MAX / 2)],   Init (),    false);
+TEST ( 4, [d(MAX / 4)],   Init (),    false);
+TEST ( 8, [d(MAX / 8)],   Init (),    false);
+TEST (16, [d(MAX / 16)],  Init (),    false);
+TEST (32, [d(MAX / 32)],  Init (),    false);
+TEST (64, [d(MAX / 64)],  Init (),    false);
+
+// Excessively large one dimensional VLAs.
+TEST (1, [d(LONG_MIN)],  Init (),       true);
+TEST (1, [d(INT_MIN)],   Init (),       true);
+TEST (1, [d(-1)],        Init (),       true);
+TEST (1, [d(INT_MAX)],   Init (),       true);
+TEST (1, [d(LONG_MAX)],  Init (),       true);
+TEST (1, [d(UINT_MAX)],  Init (),       true);
+TEST (1, [d(ULONG_MAX)], Init (),       true);
+TEST (1, [d(SIZE_MAX)],  Init (),       true);
+
+TEST ( 1, [d(MAX + 1)],   Init (),      true);
+TEST ( 2, [d(MAX)],       Init (),      true);
+TEST ( 4, [d(MAX / 2)],   Init (),      true);
+TEST ( 4, [d(MAX / 3)],   Init (),      true);
+TEST ( 8, [d(MAX / 2)],   Init (),      true);
+TEST ( 8, [d(MAX / 3)],   Init (),      true);
+TEST ( 8, [d(MAX / 4)],   Init (),      true);
+TEST ( 8, [d(MAX / 5)],   Init (),      true);
+TEST ( 8, [d(MAX / 6)],   Init (),      true);
+TEST ( 8, [d(MAX / 7)],   Init (),      true);
+TEST (16, [d(MAX / 15)],  Init (),      true);
+TEST (32, [d(MAX / 31)],  Init (),      true);
+TEST (64, [d(MAX / 63)],  Init (),      true);
+
+TEST (1, [d(LONG_MIN)],  Init ({}),     true);
+TEST (1, [d(INT_MIN)],   Init ({}),     true);
+TEST (1, [d(-1)],        Init ({}),     true);
+TEST (1, [d(INT_MAX)],   Init ({}),     true);
+TEST (1, [d(LONG_MAX)],  Init ({}),     true);
+TEST (1, [d(UINT_MAX)],  Init ({}),     true);
+TEST (1, [d(ULONG_MAX)], Init ({}),     true);
+TEST (1, [d(SIZE_MAX)],  Init ({}),     true);
+
+TEST (1, [d(LONG_MIN)],  Init ({0}),    true);
+TEST (1, [d(INT_MIN)],   Init ({0}),    true);
+TEST (1, [d(-1)],        Init ({0}),    true);
+TEST (1, [d(INT_MAX)],   Init ({0}),    true);
+TEST (1, [d(LONG_MAX)],  Init ({0}),    true);
+TEST (1, [d(UINT_MAX)],  Init ({0}),    true);
+TEST (1, [d(ULONG_MAX)], Init ({0}),    true);
+TEST (1, [d(SIZE_MAX)],  Init ({0}),    true);
+
+// Two dimensional VLAs with one constant bound.
+
+TEST (1, [1][d(0)],   Init (),          true);
+
+#if !BUG_58646
+// The following causes an ICE due to c++/58646.
+TEST (1, [1][d(0)],   Init ({}),        true);
+#endif
+TEST (1, [1][d(0)],   Init ({{1}}),     true);
+
+TEST (1, [1][d(1)],   Init (),             false);
+TEST (1, [1][d(1)],   Init ({{1}}),        false);
+TEST (1, [1][d(1)],   Init ({{1, 2}}),     true);
+
+TEST (1, [1][d(2)],   Init (),             false);
+TEST (1, [1][d(2)],   Init ({{1}}),        false);
+TEST (1, [1][d(2)],   Init ({{1, 2}}),     false);
+TEST (1, [1][d(2)],   Init ({{1, 2, 3}}),  true);
+
+TEST (1, [2][d(1)],   Init (),                 false);
+TEST (1, [2][d(1)],   Init ({{1}}),            false);
+TEST (1, [2][d(1)],   Init ({{1}, {2}}),       false);
+TEST (1, [2][d(1)],   Init ({{1, 2}}),         true);
+TEST (1, [2][d(1)],   Init ({{1}, {2, 3}}),    true);
+TEST (1, [2][d(1)],   Init ({{1, 2, 3}}),      true);
+TEST (1, [2][d(1)],   Init ({{1, 2, 3}, {4}}), true);
+TEST (1, [2][d(1)],   Init ({{1, 2}, {3, 4}}), true);
+
+TEST (1, [2][d(2)],   Init (),                       false);
+TEST (1, [2][d(2)],   Init ({{1}}),                  false);
+TEST (1, [2][d(2)],   Init ({{1, 2}}),               false);
+TEST (1, [2][d(2)],   Init ({{1, 2}, {3}}),          false);
+TEST (1, [2][d(2)],   Init ({{1, 2}, {3, 4}}),       false);
+TEST (1, [2][d(2)],   Init ({{1}, {2, 3, 4}}),       true);
+TEST (1, [2][d(2)],   Init ({{1}, {2, 3, 4, 5}}),    true);
+TEST (1, [2][d(2)],   Init ({{1, 2}, {3, 4, 5}}),    true);
+TEST (1, [2][d(2)],   Init ({{1, 2, 3}, {4, 5}}),    true);
+TEST (1, [2][d(2)],   Init ({{1, 2, 3}, {4, 5, 6}}), true);
+
+TEST (1, [2][d(3)],   Init (),                          false);
+TEST (1, [2][d(3)],   Init ({{1}}),                     false);
+TEST (1, [2][d(3)],   Init ({{1, 2}}),                  false);
+TEST (1, [2][d(3)],   Init ({{1, 2}, {3}}),             false);
+TEST (1, [2][d(3)],   Init ({{1, 2}, {3, 4}}),          false);
+TEST (1, [2][d(3)],   Init ({{1}, {2, 3, 4}}),          false);
+TEST (1, [2][d(3)],   Init ({{1}, {2, 3, 4, 5}}),       true);
+TEST (1, [2][d(3)],   Init ({{1, 2}, {3, 4, 5}}),       false);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3}, {4, 5}}),       false);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3}, {4, 5, 6}}),    false);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3}, {4, 5, 6, 7}}), true);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3, 4}, {5, 6, 7}}), true);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3, 4, 5}, {6, 7}}), true);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3, 4, 5, 6}, {7}}), true);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3, 4, 5, 6, 7}}),   true);
+
+TEST (1, [1][d(MAX)], Init (),                 false);
+#if !BUG_58646
+// The following causes an ICE due to c++/58646.
+TEST (1, [1][d(MAX)], Init ({}),               false);
+#endif
+TEST (1, [1][d(MAX)], Init ({{1}}),            false);
+TEST (1, [1][d(MAX)], Init ({{1, 2}}),         false);
+TEST (1, [1][d(MAX)], Init ({{1, 2, 3}}),      false);
+TEST (1, [1][d(MAX)], Init ({{1, 2, 3, 4}}),   false);
+
+TEST (1, [2][d(MAX / 2)], Init (),                       false);
+TEST (1, [2][d(MAX / 2)], Init ({{1}}),                  false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2}}),               false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}}),            false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3, 4}}),         false);
+TEST (1, [2][d(MAX / 2)], Init ({{1}, {2}}),             false);
+TEST (1, [2][d(MAX / 2)], Init ({{1}, {2, 3}}),          false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2}, {3}}),          false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2}, {3, 4}}),       false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}, {4}}),       false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5}}),    false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5, 6}}), false);
+
+// Excessively large two dimensional VLAs.
+TEST (1, [1][d(LONG_MIN)],  Init (),       true);
+TEST (1, [1][d(INT_MIN)],   Init (),       true);
+TEST (1, [1][d(-1)],        Init (),       true);
+TEST (1, [1][d(INT_MAX)],   Init (),       true);
+TEST (1, [1][d(LONG_MAX)],  Init (),       true);
+TEST (1, [1][d(UINT_MAX)],  Init (),       true);
+TEST (1, [1][d(ULONG_MAX)], Init (),       true);
+TEST (1, [1][d(SIZE_MAX)],  Init (),       true);
+
+#if !BUG_58646
+// The following cause an ICE due to c++/58646.
+TEST (1, [1][d(LONG_MIN)],  Init ({}),     true);
+TEST (1, [1][d(INT_MIN)],   Init ({}),     true);
+TEST (1, [1][d(-1)],        Init ({}),     true);
+TEST (1, [1][d(INT_MAX)],   Init ({}),     true);
+TEST (1, [1][d(LONG_MAX)],  Init ({}),     true);
+TEST (1, [1][d(UINT_MAX)],  Init ({}),     true);
+TEST (1, [1][d(ULONG_MAX)], Init ({}),     true);
+TEST (1, [1][d(SIZE_MAX)],  Init ({}),     true);
+#endif
+
+TEST (1, [1][d(LONG_MIN)],  Init ({{0}}),  true);
+TEST (1, [1][d(INT_MIN)],   Init ({{0}}),  true);
+TEST (1, [1][d(-1)],        Init ({{0}}),  true);
+TEST (1, [1][d(INT_MAX)],   Init ({{0}}),  true);
+TEST (1, [1][d(LONG_MAX)],  Init ({{0}}),  true);
+TEST (1, [1][d(UINT_MAX)],  Init ({{0}}),  true);
+TEST (1, [1][d(ULONG_MAX)], Init ({{0}}),  true);
+TEST (1, [1][d(SIZE_MAX)],  Init ({{0}}),  true);
+
+TEST (1, [d(LONG_MIN)][1],  Init (),       true);
+TEST (1, [d(INT_MIN)][1],   Init (),       true);
+TEST (1, [d(-1)][1],        Init (),       true);
+TEST (1, [d(INT_MAX)][1],   Init (),       true);
+TEST (1, [d(LONG_MAX)][1],  Init (),       true);
+TEST (1, [d(UINT_MAX)][1],  Init (),       true);
+TEST (1, [d(ULONG_MAX)][1], Init (),       true);
+TEST (1, [d(SIZE_MAX)][1],  Init (),       true);
+
+TEST (1, [d(LONG_MIN)][1],  Init ({}),     true);
+TEST (1, [d(INT_MIN)][1],   Init ({}),     true);
+TEST (1, [d(-1)][1],        Init ({}),     true);
+TEST (1, [d(INT_MAX)][1],   Init ({}),     true);
+TEST (1, [d(LONG_MAX)][1],  Init ({}),     true);
+TEST (1, [d(UINT_MAX)][1],  Init ({}),     true);
+TEST (1, [d(ULONG_MAX)][1], Init ({}),     true);
+TEST (1, [d(SIZE_MAX)][1],  Init ({}),     true);
+
+TEST (1, [d(LONG_MIN)][1],  Init ({{0}}),  true);
+TEST (1, [d(INT_MIN)][1],   Init ({{0}}),  true);
+TEST (1, [d(-1)][1],        Init ({{0}}),  true);
+TEST (1, [d(INT_MAX)][1],   Init ({{0}}),  true);
+TEST (1, [d(LONG_MAX)][1],  Init ({{0}}),  true);
+TEST (1, [d(UINT_MAX)][1],  Init ({{0}}),  true);
+TEST (1, [d(ULONG_MAX)][1], Init ({{0}}),  true);
+TEST (1, [d(SIZE_MAX)][1],  Init ({{0}}),  true);
+
+// Two dimensional VLAs with no constant bound.
+TEST (1, [d(0)][d(0)],   Init (),          true);
+TEST (1, [d(0)][d(0)],   Init ({}),        true);
+#if !BUG_58646
+// The following cause an ICE due to c++/58646.
+TEST (1, [d(0)][d(0)],   Init ({{}}),      true);
+TEST (1, [d(0)][d(0)],   Init ({{}, {}}),  true);
+#endif
+
+TEST (1, [d(0)][d(0)],   Init ({{1}}),     true);
+TEST (1, [d(0)][d(0)],   Init ({{1, 2}}),  true);
+#if !BUG_58646
+TEST (1, [d(0)][d(0)],   Init ({{1}, {}}), true);
+TEST (1, [d(0)][d(0)],   Init ({{}, {1}}), true);
+#endif
+
+TEST (1, [d(1)][d(0)],   Init (),          true);
+TEST (1, [d(1)][d(0)],   Init ({}),        true);
+TEST (1, [d(1)][d(0)],   Init ({{1}}),     true);
+
+TEST (1, [d(1)][d(1)],   Init (),             false);
+TEST (1, [d(1)][d(1)],   Init ({{1}}),        false);
+TEST (1, [d(1)][d(1)],   Init ({{1, 2}}),     true);
+
+TEST (1, [d(1)][d(2)],   Init (),             false);
+TEST (1, [d(1)][d(2)],   Init ({{1}}),        false);
+TEST (1, [d(1)][d(2)],   Init ({{1, 2}}),     false);
+TEST (1, [d(1)][d(2)],   Init ({{1, 2, 3}}),  true);
+
+TEST (1, [d(2)][d(1)],   Init (),                 false);
+TEST (1, [d(2)][d(1)],   Init ({{1}}),            false);
+TEST (1, [d(2)][d(1)],   Init ({{1}, {2}}),       false);
+TEST (1, [d(2)][d(1)],   Init ({{1, 2}}),         true);
+TEST (1, [d(2)][d(1)],   Init ({{1}, {2, 3}}),    true);
+TEST (1, [d(2)][d(1)],   Init ({{1, 2, 3}}),      true);
+TEST (1, [d(2)][d(1)],   Init ({{1, 2, 3}, {4}}), true);
+TEST (1, [d(2)][d(1)],   Init ({{1, 2}, {3, 4}}), true);
+
+TEST (1, [d(2)][d(2)],   Init (),                       false);
+TEST (1, [d(2)][d(2)],   Init ({{1}}),                  false);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2}}),               false);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2}, {3}}),          false);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2}, {3, 4}}),       false);
+TEST (1, [d(2)][d(2)],   Init ({{1}, {2, 3, 4}}),       true);
+TEST (1, [d(2)][d(2)],   Init ({{1}, {2, 3, 4, 5}}),    true);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2}, {3, 4, 5}}),    true);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2, 3}, {4, 5}}),    true);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2, 3}, {4, 5, 6}}), true);
+
+TEST (1, [d(2)][d(3)],   Init (),                          false);
+TEST (1, [d(2)][d(3)],   Init ({{1}}),                     false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2}}),                  false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2}, {3}}),             false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2}, {3, 4}}),          false);
+TEST (1, [d(2)][d(3)],   Init ({{1}, {2, 3, 4}}),          false);
+TEST (1, [d(2)][d(3)],   Init ({{1}, {2, 3, 4, 5}}),       true);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2}, {3, 4, 5}}),       false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3}, {4, 5}}),       false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3}, {4, 5, 6}}),    false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3}, {4, 5, 6, 7}}), true);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3, 4}, {5, 6, 7}}), true);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3, 4, 5}, {6, 7}}), true);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3, 4, 5, 6}, {7}}), true);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3, 4, 5, 6, 7}}),   true);
+
+TEST (1, [d(1)][d(MAX)], Init (),                              false);
+TEST (1, [d(1)][d(MAX)], Init ({}),                            false);
+TEST (1, [d(1)][d(MAX)], Init ({{1}}),                         false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2}}),                      false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3}}),                   false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4}}),                false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5}}),             false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6}}),          false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6, 7}}),       false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6, 7, 8}}),    false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6, 7, 8, 9}}), false);
+
+TEST (1, [d(2)][d(MAX / 2)], Init (),                              false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1}}),                         false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2}}),                      false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}}),                   false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4}}),                false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5}}),             false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6}}),          false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6, 7}}),       false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6, 7, 8}}),    false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6, 7, 8, 9}}), false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1}, {2}}),                    false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1}, {2, 3}}),                 false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2}, {3}}),                 false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2}, {3, 4}}),              false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}, {4}}),              false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5}}),           false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5, 6}}),        false);
+
+TEST (1, [d(2)][d(MAX)],   Init (),                         true);
+TEST (1, [d(2)][d(MAX)],   Init ({{1}}),                    true);
+TEST (1, [d(MAX)][d(MAX)], Init ({{1}}),                    true);
+TEST (1, [d(0)][d(MAX)],   Init ({{1}}),                    true);
+TEST (1, [d(INT_MAX)][d(MAX)], Init ({{1}}),                true);
+TEST (1, [d(SIZE_MAX)][d(MAX)], Init ({{1}}),               true);
+TEST (1, [d(INT_MAX)][d(INT_MAX)], Init ({{1}}),            true);
+TEST (1, [d(LONG_MAX)][d(LONG_MAX)], Init ({{1}}),          true);
+TEST (1, [d(SIZE_MAX)][d(SIZE_MAX)], Init ({{1}}),          true);
+
+// Three dimensional VLAs with two constant bounds.
+
+TEST (1, [1][1][d(-1)], Init (),                    true);
+TEST (1, [1][1][d(0)], Init (),                     true);
+
+#if !BUG_58646
+// The following causes an ICE due to c++/58646.
+TEST (1, [1][1][d(0)], Init ({}),                    true);
+#endif
+
+TEST (1, [1][1][d(-1)], Init ({{}}),                 true);
+TEST (1, [1][d(-1)][1], Init ({{}}),                 true);
+TEST (1, [d(-1)][1][1], Init ({{}}),                 true);
+
+TEST (1, [1][1][d(0)], Init ({{}}),                  true);
+TEST (1, [1][d(0)][1], Init ({{}}),                  true);
+TEST (1, [d(0)][1][1], Init ({{}}),                  true);
+
+TEST (1, [1][1][d(1)], Init (),                      false);
+TEST (1, [1][1][d(1)], Init ({{}}),                  false);
+TEST (1, [1][1][d(1)], Init ({{{}}}),                false);
+TEST (1, [1][1][d(1)], Init ({{{1}}}),               false);
+TEST (1, [1][1][d(1)], Init ({{{1, 2}}}),            true);
+TEST (1, [1][1][d(1)], Init ({{{1, 2, 3}}}),         true);
+
+TEST (1, [1][d(1)][1], Init (),                      false);
+TEST (1, [1][d(1)][1], Init ({{}}),                  false);
+TEST (1, [1][d(1)][1], Init ({{{}}}),                false);
+TEST (1, [1][d(1)][1], Init ({{{1}}}),               false);
+TEST (1, [1][d(1)][1], Init ({{{1}, {2}}}),          true);
+TEST (1, [1][d(1)][1], Init ({{{1}, {2}, {3}}}),     true);
+
+TEST (1, [d(1)][1][1], Init (),                      false);
+TEST (1, [d(1)][1][1], Init ({{}}),                  false);
+TEST (1, [d(1)][1][1], Init ({{{}}}),                false);
+TEST (1, [d(1)][1][1], Init ({{{1}}}),               false);
+TEST (1, [d(1)][1][1], Init ({{{1}}, {{2}}}),        true);
+TEST (1, [d(1)][1][1], Init ({{{1}}, {{2}}, {{3}}}), true);
+
+TEST (1, [1][1][d(2)], Init (),                      false);
+TEST (1, [1][1][d(2)], Init ({{}}),                  false);
+TEST (1, [1][1][d(2)], Init ({{{}}}),                false);
+TEST (1, [1][1][d(2)], Init ({{{1}}}),               false);
+TEST (1, [1][1][d(2)], Init ({{{1, 2}}}),            false);
+TEST (1, [1][1][d(2)], Init ({{{1, 2, 3}}}),         true);
+
+TEST (1, [1][d(2)][1], Init (),                      false);
+TEST (1, [1][d(2)][1], Init ({{}}),                  false);
+TEST (1, [1][d(2)][1], Init ({{{}}}),                false);
+TEST (1, [1][d(2)][1], Init ({{{1}}}),               false);
+TEST (1, [1][d(2)][1], Init ({{{1}, {2}}}),          false);
+TEST (1, [1][d(2)][1], Init ({{{1}, {2}, {3}}}),     true);
+
+TEST (1, [d(2)][1][1], Init (),                      false);
+TEST (1, [d(2)][1][1], Init ({{}}),                  false);
+TEST (1, [d(2)][1][1], Init ({{{}}}),                false);
+TEST (1, [d(2)][1][1], Init ({{{1}}}),               false);
+TEST (1, [d(2)][1][1], Init ({{{1}}, {{2}}}),        false);
+TEST (1, [d(2)][1][1], Init ({{{1}}, {{2}}, {{3}}}), true);
+
+TEST (1, [1][2][d(2)], Init (),                      false);
+TEST (1, [1][2][d(2)], Init ({{}}),                  false);
+TEST (1, [1][2][d(2)], Init ({{{}}}),                false);
+TEST (1, [1][2][d(2)], Init ({{{1}}}),               false);
+TEST (1, [1][2][d(2)], Init ({{{1, 2}}}),            false);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3}}}),         true);
+
+TEST (1, [1][2][d(2)], Init ({{{1}, {2}}}),          false);
+TEST (1, [1][2][d(2)], Init ({{{1}, {2, 3}}}),       false);
+TEST (1, [1][2][d(2)], Init ({{{1, 2}, {3}}}),       false);
+TEST (1, [1][2][d(2)], Init ({{{1, 2}, {3, 4}}}),    false);
+TEST (1, [1][2][d(2)], Init ({{{1}, {2, 3, 4}}}),    true);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3}, {}}}),     true);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3}, {4}}}),    true);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3, 4}}}),      true);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3, 4}, {}}}),  true);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3, 4}, {5}}}), true);
+
+TEST (1, [2][2][d(2)], Init ({{{1}, {2}}}),                         false);
+TEST (1, [2][2][d(2)], Init ({{{1}, {2, 3}}}),                      false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}}}),                           false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3}}}),                      false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}}),                   false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5}}}),            false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}}}),         false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7}}}),    false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}), false);
+
+TEST (1, [2][2][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3}, {}}}),                       true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3}, {4}}}),                      true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3, 4}}}),                        true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3, 4}, {}}}),                    true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3, 4}, {5}}}),                   true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8, 9}}}), true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6, 7}, {8, 9}}}), true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4, 5}}, {{6, 7}, {8, 9}}}), true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3}, {4, 5}}, {{6, 7}, {8, 9}}}), true);
+TEST (1, [2][2][d(2)], Init ({{{1}, {2}}, {{3}, {4, 5, 6}}}),          true);
+TEST (1, [2][2][d(2)], Init ({{{1}}, {{2}, {3, 4, 5, 6}}}),            true);
+
+// Three dimensional VLAs with one constant bound.
+TEST (1, [2][d(-1)][d(-1)], Init (),                                      true);
+TEST (1, [2][d(-1)][d(0)],  Init (),                                      true);
+TEST (1, [2][d(0)][d(-1)],  Init (),                                      true);
+TEST (1, [2][d(1)][d(-1)],  Init (),                                      true);
+TEST (1, [2][d(1)][d(0)],   Init (),                                      true);
+TEST (1, [2][d(-1)][d(1)],  Init (),                                      true);
+TEST (1, [2][d(0)][d(1)],   Init (),                                      true);
+
+TEST (1, [2][d(2)][d(2)], Init (),                                        false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}}}),                                 false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2}}}),                            false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3}}}),                         false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3}}}),                         false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}}),                      false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}),    false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {}}}),                       true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {4}}}),                      true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}}}),                        true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {}}}),                    true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {5}}}),                   true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3}, {4}}}),                    true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {}}}),                       true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {4}}}),                      true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}}}),                        true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {}}}),                    true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {5}}}),                   true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8, 9}}}), true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6, 7}, {8, 9}}}), true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4, 5}}, {{6, 7}, {8, 9}}}), true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {4, 5}}, {{6, 7}, {8, 9}}}), true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2}}, {{3}, {4, 5, 6}}}),          true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}}, {{2}, {3, 4, 5, 6}}}),            true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2}, {3}}}),                       true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3}, {4}}}),                    true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3, 4}, {5}}}),                 true);
+
+// Very large but not erroneous three-dimensional VLAs.
+TEST ( 1, [2][d(1)][d(MAX/2)], Init (),  false);
+TEST ( 2, [2][d(1)][d(MAX/4)], Init (),  false);
+TEST ( 4, [2][d(1)][d(MAX/8)], Init (),  false);
+TEST ( 8, [2][d(1)][d(MAX/16)], Init (), false);
+TEST (16, [2][d(1)][d(MAX/32)], Init (), false);
+
+TEST ( 1, [2][d(MAX/2)][d(1)], Init (),  false);
+TEST ( 2, [2][d(MAX/4)][d(1)], Init (),  false);
+TEST ( 4, [2][d(MAX/8)][d(1)], Init (),  false);
+TEST ( 8, [2][d(MAX/16)][d(1)], Init (), false);
+TEST (16, [2][d(MAX/32)][d(1)], Init (), false);
+
+TEST ( 1, [d(MAX/2)][2][d(1)], Init (),  false);
+TEST ( 2, [d(MAX/4)][2][d(1)], Init (),  false);
+TEST ( 4, [d(MAX/8)][2][d(1)], Init (),  false);
+TEST ( 8, [d(MAX/16)][2][d(1)], Init (), false);
+TEST (16, [d(MAX/32)][2][d(1)], Init (), false);
+
+int main ()
+{
+  if (fail)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla12.C b/gcc/testsuite/g++.dg/cpp1y/vla12.C
new file mode 100644
index 0000000..a8db578
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla12.C
@@ -0,0 +1,69 @@
+// Test to verify that variable length arrays whose size overflows
+// or exceeds the implementation-defined limit is diagnosed.
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-Wno-error=vla" }
+
+#define INT_MAX    __INT_MAX__
+#define LONG_MAX   __LONG_MAX__
+#define SIZE_MAX   __SIZE_MAX__
+
+typedef __SIZE_TYPE__ size_t;
+
+void test (int x, int y, int z)
+{
+  const size_t amax = SIZE_MAX / 2;
+
+  {
+    char a [x][amax];         // { dg-warning "forbids|size of variable length array exceeds maximum" }
+    (void)a;
+  }
+
+  {
+    char a [amax][y];         // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    char a [x][y][amax];      // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    char a [x][amax][z];      // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    char a [amax][y][z];      // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    // Unfortunately, this is rejected with a different error earlier
+    // during parsing and before the VLA checking gets to see it:
+    //   error: size of array ‘a’ is too large
+    char a [x][amax][amax];   // { dg-error "size of array" }
+
+    // That error above also leads to the following error when using
+    // the variable below.
+    //   error:’ was not declared in this scope
+    // (void)a;
+  }
+
+  {
+    char a [amax][y][amax];   // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    char a [amax][amax][z];   // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    struct A256 { __attribute__ ((aligned (256))) char a; };
+
+    A256 a [x][1024][y][1024][z][1024][x][1024][z];   // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla13.C b/gcc/testsuite/g++.dg/cpp1y/vla13.C
new file mode 100644
index 0000000..43db6cb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla13.C
@@ -0,0 +1,223 @@
+// PR c++/70019 - VLA size overflow not detected
+// Runtime test to verify that attempting to initialize a VLA with a string
+// or character array that's longer than the non-constant (runtime) bound
+// of the VLA causes an exception to be thrown.  For a compile-time version
+// of the test see vla14.C.
+
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-Wno-vla" }
+
+#define INT_MAX    __INT_MAX__
+#define LONG_MAX   __LONG_MAX__
+#define SIZE_MAX   __SIZE_MAX__
+
+#define INT_MIN    (-__INT_MAX__ - 1)
+#define LONG_MIN   (-__LONG_MAX__ - 1)
+
+// Helper macro to make it possible to pass as one multpile arguments
+// to another macro.
+#define Init(...) __VA_ARGS__
+
+// The size of the largest allowed VLA in bytes.  Bigger objects
+// cause an exception to be thrown.
+#define MAX   (1 << 20)
+
+typedef __SIZE_TYPE__ size_t;
+
+// Incremented for each test failure.
+int fail;
+
+// Used to convert a constant array dimension to a non-constant one.
+int d (int n)
+{
+  return n;
+}
+
+// Verify either that an expected exception has been thrown or that
+// one hasn't been thrown if one isn't expected.
+int __attribute__ ((noclone, noinline))
+sink (void *p, int line, bool expect, const char *expr)
+{
+  if (!p != expect)
+    {
+      __builtin_printf ("line %i: Assertion failed: '%s': "
+                        "exception unexpectedly %sthrown\n",
+                        line, expr, !p ? "" : "not ");
+      ++fail;
+    }
+  else
+    {
+#ifdef DEBUG
+    __builtin_printf ("line %i: Assertion passed: '%s': "
+		      "exception %sthrown as expected\n",
+		      line, expr, !p ? "" : "not ");
+#endif
+    }
+    
+  return 0;
+}
+
+template <class T, int>
+int test ();
+
+#define _CAT(name, line) name ## line
+#define CAT(name, line) _CAT (name, line)
+
+#define STR(...) #__VA_ARGS__
+
+// Macro to define a unique specialization of a function template to
+// exercise a VLA of type T, rank N, with dimensions given by Dims
+// and initializer Init.  Expect is true when the VLA initialization
+// is expected to trigger an exception.
+// The macro creates a unique global dummy int object and initializes
+// it with the result of the function.  The dummy object servers no
+// other purpose but to call the function.  The function verifies
+// the expected postconditions.
+#define TEST(T, Dims, Init, Expect)                                     \
+  template <>                                                           \
+  int test<T, __LINE__>()                                               \
+  {                                                                     \
+    const char str[] = "char a" #Dims " = { " STR (Init) " }";          \
+    try {                                                               \
+      T a Dims = { Init };                                              \
+      return sink (a, __LINE__, Expect, str);                           \
+    }                                                                   \
+    catch (...) {                                                       \
+      return sink (0, __LINE__, Expect, str);                           \
+    }                                                                   \
+  }                                                                     \
+  const int CAT (dummy, __LINE__) = test<T, __LINE__>()
+
+
+// Create and run a test function exercising a VLA definition
+//    +-- Element Type
+//    |     +-- VLA Dimensions
+//    |     |       +-- VLA Initializer
+//    |     |       |
+//    |     |       |             +-- Expect Exception
+//    |     |       |             |
+//    V     V       V             V
+TEST (char, [d(1)], "",           false);
+TEST (char, [d(1)], "1",          true);
+TEST (char, [d(1)], "12",         true);
+TEST (char, [d(1)], "1234567890", true);
+
+TEST (char, [d(2)], "",           false);
+TEST (char, [d(2)], "1",          false);
+TEST (char, [d(2)], "12",         true);
+TEST (char, [d(2)], "123",        true);
+TEST (char, [d(2)], "1234567890", true);
+
+TEST (char, [d(3)], "",           false);
+TEST (char, [d(3)], "1",          false);
+TEST (char, [d(3)], "12",         false);
+TEST (char, [d(3)], "123",        true);
+TEST (char, [d(3)], "1234",       true);
+TEST (char, [d(3)], "1234567890", true);
+
+// The following crash due to c++/70440.
+// TEST (char, [d(MAX)], "",           false);
+// TEST (char, [d(MAX)], "1",          false);
+// TEST (char, [d(MAX)], "12",         false);
+// TEST (char, [d(MAX)], "1234567890", false);
+
+TEST (char, [d(MAX)], Init (),                             false);
+TEST (char, [d(MAX)], Init (1),                            false);
+TEST (char, [d(MAX)], Init (1, 2),                         false);
+TEST (char, [d(MAX)], Init (1, 2, 3, 4, 5, 6, 7, 8, 9, 0), false);
+
+TEST (wchar_t, [d(1)], L"",           false);
+TEST (wchar_t, [d(1)], L"1",          true);
+TEST (wchar_t, [d(1)], L"12",         true);
+TEST (wchar_t, [d(1)], L"1234567890", true);
+
+TEST (wchar_t, [d(2)], L"",           false);
+TEST (wchar_t, [d(2)], L"1",          false);
+TEST (wchar_t, [d(2)], L"12",         true);
+TEST (wchar_t, [d(2)], L"123",        true);
+TEST (wchar_t, [d(2)], L"1234567890", true);
+
+TEST (char, [d(1)][d(1)], Init (""),        false);
+TEST (char, [1]   [d(1)], Init (""),        false);
+TEST (char, [d(1)][1],    Init (""),        false);
+
+TEST (char, [d(1)][d(1)], Init ("1"),       true);
+
+// The following is accepted at compile time but throws an exception
+// at runtime since in C++ a one-element array cannot be initialized
+// with a string literal of length one because there isn't room for
+// the terminating NUL
+TEST (char, [1][d(1)],    Init ("1"),       true);
+
+// The following is rejected at compile-time since a one-element array
+// cannot be initialized with a string literal of length one because
+// there isn't room for the terminating NUL (see vla14.C).
+// TEST (char, [d(1)][1],    Init ("1"),       false);
+
+TEST (char, [d(1)][d(1)], Init ("12"),      true);
+TEST (char, [d(1)][d(1)], Init ("1", "2"),  true);
+TEST (char, [d(1)][d(1)], Init ("1", "23"), true);
+
+TEST (char, [d(2)][d(2)], Init ("", ""),    false);
+TEST (char, [d(2)][d(2)], Init ("", "1"),   false);
+TEST (char, [d(2)][d(2)], Init ("1", ""),   false);
+TEST (char, [d(2)][d(2)], Init ("1", "1"),  false);
+TEST (char, [2][d(2)],    Init ("",  "1"),  false);
+TEST (char, [2][d(2)],    Init ("1", ""),   false);
+TEST (char, [2][d(2)],    Init ("1", "1"),  false);
+TEST (char, [d(2)][2],    Init ("",  "1"),  false);
+TEST (char, [d(2)][2],    Init ("1", ""),   false);
+TEST (char, [d(2)][2],    Init ("1", "1"),  false);
+
+TEST (char, [2][d(2)],    Init ("1", "23"), true);
+TEST (char, [d(2)][d(2)], Init ("1", "23"), true);
+TEST (char, [d(2)][d(2)], Init ("1", "23"), true);
+TEST (char, [d(2)][d(2)], Init ("12","3"),  true);
+
+// The following crash due to c++/70440.
+// TEST (char, [1][d(MAX)], Init (""),           false);
+// TEST (char, [1][d(MAX)], Init ("1"),          false);
+// TEST (char, [1][d(MAX)], Init ("12"),         false);
+// TEST (char, [1][d(MAX)], Init ("1234567890"), false);
+
+// The following causes an ICE due to c++/58646.
+// TEST (char, [1][d(MAX)], Init (),                             false);
+
+TEST (char, [1][d(MAX)], Init ({1}),                            false);
+TEST (char, [1][d(MAX)], Init ({1, 2}),                         false);
+TEST (char, [1][d(MAX)], Init ({1, 2, 3}),                      false);
+TEST (char, [1][d(MAX)], Init ({1, 2, 3, 4, 5, 6, 7, 8, 9, 0}), false);
+
+TEST (char, [d(MAX)][1], Init ({1}),                            false);
+TEST (char, [d(MAX)][1], Init ({1}, {2}),                       false);
+TEST (char, [d(MAX)][1], Init ({1}, {2}, {3}),                  false);
+TEST (char, [d(MAX)][1], Init ({1}, {2}, {3}, {4}, {5},
+			       {6}, {7}, {8}, {9}, {0}),        false);
+
+// The following are expected to throw due to excessive size.
+TEST (char, [2][d(MAX)], Init ({1}),                                 true);
+TEST (char, [2][d(MAX)], Init ({1, 2}),                              true);
+TEST (char, [2][d(MAX)], Init ({1}, {2}),                            true);
+TEST (char, [2][d(MAX)], Init ({1, 2}, {3, 4}),                      true);
+TEST (char, [2][d(MAX)], Init ({1, 2, 3}, {4, 5, 6}),                true);
+TEST (char, [2][d(MAX)], Init ({1, 2, 3, 4}, {5, 6, 7, 8}),          true);
+
+TEST (char, [d(MAX)][2], Init ({1}),                                 true);
+TEST (char, [d(MAX)][2], Init ({1, 2}),                              true);
+TEST (char, [d(MAX)][2], Init ({1}, {2}),                            true);
+TEST (char, [d(MAX)][2], Init ({1, 2}, {3, 4}),                      true);
+TEST (char, [d(MAX)][2], Init ({1, 2}, {3, 4}, {5, 6}),              true);
+TEST (char, [d(MAX)][2], Init ({1, 2}, {3, 4}, {5, 6}, {7, 8}),      true);
+
+TEST (char, [d(MAX)][d(MAX)], Init ({1}),                            true);
+TEST (char, [d(MAX)][d(MAX)], Init ({1, 2}),                         true);
+TEST (char, [d(MAX)][d(MAX)], Init ({1}, {2}),                       true);
+TEST (char, [d(MAX)][d(MAX)], Init ({1, 2}, {3, 4}),                 true);
+TEST (char, [d(MAX)][d(MAX)], Init ({1, 2}, {3, 4}, {5, 6}),         true);
+TEST (char, [d(MAX)][d(MAX)], Init ({1, 2}, {3, 4}, {5, 6}, {7, 8}), true);
+
+int main ()
+{
+  if (fail)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla14.C b/gcc/testsuite/g++.dg/cpp1y/vla14.C
new file mode 100644
index 0000000..4a0e827
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla14.C
@@ -0,0 +1,48 @@
+// PR c++/70019 - VLA size overflow not detected
+// Compile-time test to verify that attempting to initialize a VLA with
+// a string that's longer than the VLA's constant bound is diagnosed at
+// compile time.  For a runtime version of the test see vla13.C.
+
+// { dg-do run }
+// { dg-additional-options "-Wno-vla" }
+
+
+void test (int n)
+{
+  char a1[n][1] = { { "a" } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a1;
+
+  char a2[1][n] = { { "a" } };
+  (void)a2;
+
+  char a3[n][1][1] = { { { "a" } } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a3;
+
+  char a4[1][1][n] = { { { "a" } } };
+  (void)a4;
+
+  char a5[1][n][1] = { { { "a" } } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a5;
+
+  char a6[n][1][n] = { { { "a" } } };
+  (void)a6;
+
+
+  wchar_t a7[n][1] = { { L"a" } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a7;
+
+  wchar_t a8[1][n] = { { L"a" } };
+  (void)a8;
+
+  wchar_t a9[n][1][1] = { { { L"a" } } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a9;
+
+  wchar_t a10[1][1][n] = { { { L"a" } } };
+  (void)a10;
+
+  wchar_t a11[][n][1] = { { { L"a" } } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a11;
+
+  wchar_t a12[n][1][n] = { { { L"a" } } };
+  (void)a12;
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla3.C b/gcc/testsuite/g++.dg/cpp1y/vla3.C
new file mode 100644
index 0000000..9b2d6b3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla3.C
@@ -0,0 +1,43 @@
+// Test for throwing bad_array_length on invalid array length.
+// { dg-do run { target c++14 } }
+// { dg-additional-options "-Wno-vla" }
+
+namespace std
+{
+struct exception
+{
+  virtual ~exception ();
+  virtual const char* what () const throw ();
+};
+}
+
+int f(int i)
+{
+  int ar[i]{1,2,3,4};
+  return ar[i-1];
+}
+
+void g(int i)
+{
+  int ar[i];
+  ar[0] = 42;
+}
+
+int main()
+{
+  int ok = 0;
+  f(4);				// OK
+  try {
+    f(3);			// too small
+  }
+  catch (std::exception &e) {
+    ++ok;
+  }
+  try { g(-24); }		// negative
+  catch (std::exception &e) {
+    ++ok;
+  }
+
+  if (ok != 2)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/init/array24.C b/gcc/testsuite/g++.dg/init/array24.C
index 2d72df4..fc10c0a 100644
--- a/gcc/testsuite/g++.dg/init/array24.C
+++ b/gcc/testsuite/g++.dg/init/array24.C
@@ -3,5 +3,5 @@
 
 void foo(int i)
 {
-  int x[][i] = { 0 };
+  int x[][i] = { { 0 } };
 }
diff --git a/gcc/testsuite/g++.dg/ubsan/vla-1.C b/gcc/testsuite/g++.dg/ubsan/vla-1.C
index 311cdb1..374c80a 100644
--- a/gcc/testsuite/g++.dg/ubsan/vla-1.C
+++ b/gcc/testsuite/g++.dg/ubsan/vla-1.C
@@ -1,5 +1,8 @@
 // { dg-do run }
-// { dg-options "-Wno-vla -fsanitize=undefined" }
+// Disable exceptions to prevent the erroneous initializer from
+// throwing before the sanitizer instrumentation has detected
+// the problem.
+// { dg-options "-Wno-vla -fno-exceptions -fsanitize=undefined" }
 // { dg-output "index 1 out of bounds" }
 
 void f(int i) {
* Unmerged path gcc/testsuite/g++.dg/warn/overflow-warn-7.C
diff --git a/libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc b/libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc
index d9d1f2a..f944236 100644
--- a/libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc
@@ -44,7 +44,8 @@ template<typename Con>
   {
     bool test __attribute__((unused)) = true;
 
-    rvalstruct array[length];
+    /* Make sure the VLA upper bound is positive. */
+    rvalstruct array[length + 1];
     for(int i = 0; i < length; ++i)
       array[i] = i;
     Con con(array, array + length);

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

* Re: [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
  2016-04-01 23:02       ` Martin Sebor
@ 2016-04-04 23:35         ` Jason Merrill
  2016-04-08  0:05           ` Martin Sebor
  0 siblings, 1 reply; 22+ messages in thread
From: Jason Merrill @ 2016-04-04 23:35 UTC (permalink / raw)
  To: Martin Sebor, Gcc Patch List

On 04/01/2016 07:02 PM, Martin Sebor wrote:
>> Fair enough.  I don't think we can impose an arbitrary 64K limit,
>> however, as that is a lot smaller than the 8MB default stack size, and
>> programs can use setrlimit to increase the stack farther.  For GCC 6 let
>> not impose any limit beyond non-negative/overflowing, and as you say we
>> can do something better in GCC 7.
>
> Would you be open to imposing a somewhat more permissive limit,
> say on the order of one or a few megabytes (but less than the
> default 8 MB on Linux)?
>
> I ask because I expect the majority of programmer errors with
> VLAs to be due to out-of-range bounds that couldn't be
> accommodated even if stack space was extended well beyond
> the Linux default (say hundreds of MB), or that would result
> in complete stack space exhaustion.  I.e., not caused by
> deliberately trying to create very large VLAs but rather by
> accidentally creating VLAs with unconstrained bounds (due to
> a failure to validate input, uninitialized unsigned variables,
> etc.)
>
> I expect fewer cases to be due to negative or zero bounds or
> excessive initializers.
>
> I also expect programmers to want to find out about such bugs
> sooner (i.e., in unit testing with plentiful stack space) rather
> than after software has been deployed (and under low stack space
> conditions not exercised during unit testing).
>
> To that end, I think a lower limit is going to be more helpful
> than a permissive one (or none at all).

> But if even a few MB seems too strict, I would find having even
> an exceedingly liberal limit (say 1GB) much preferable to none
> at all as it makes it possible to exercise boundary conditions
> such as the size overflow problem you noted below.

That sounds reasonable, as long as users with unusual needs can adjust 
it with a flag, but even so I'm nervous about doing this in stage 4.  It 
certainly isn't a regression.

> During additional testing it dawned on me that there is no good
> way to validate (or even to initialize) the initializer list of
> a multi-dimensional VLA that isn't unambiguously braced.
>
> For example, the following VLA with N = 2 and N = 3:
>
>      int A [M][N] = { 1, 2, 3, 4 };
>
> Unpatched, GCC initializes it to { { 1, 2, 3 }, { 0, 0, 0 } }.
> With my first patch, GCC throws.  Neither is correct, but doing
> the right thing would involve emitting parameterizing the
> initialization code for the value of each bound.  While that
> might be doable it feels like a bigger change than I would be
> comfortable attempting at this stage.  To avoid the problem I've
> made it an error to specify a partially braced VLA initializer.

Sounds good.

> If you think it's worthwhile, I can see about implementing the
> runtime reshaping in stage 1.

No, thanks.  I think requiring explicit bracing is fine.

>> It seems to me that we want use the existing check for excess
>> initializers in build_vec_init, in the if (length_check) section, though
>> as you mention in 70019 that needs to be improved to handle STRING_CST.
>
> I don't think modifying build_vec_init() alone would be sufficient.
> For example, the function isn't called for a VLA with a constant
> bound like this one:
>
>   int A [2][N] = { 1, 2, 3, 4 };

That seems like a bug, due to array_of_runtime_bound_p returning false 
for that array.

>> Also, I think we should check for invalid bounds in
>> compute_array_index_type, next to the UBsan code.  Checking bounds only
>> from cp_finish_decl means that we don't check uses of VLA types other
>> than variable declarations.
>
> You mean VLA typedefs?  That's true, though I have consciously
> avoided dealing with those.  They're outlawed in N3639 and so
> I've been focusing just on variables.  But since GCC accepts
> VLA typedefs too I was thinking I would bring them up at some
> point in the future to decide what to do about them.

And cast to pointer to VLAs.  But for non-variable cases we don't care 
about available stack, so we wouldn't want your allocation limit to apply.

> As for where to add the bounds checking code, I also at first
> thought of checking the bounds parallel to the UBSan code in
> compute_array_index_type() and even tried that approach. The
> problem with it is that it only considers one array dimension
> at a time, without the knowledge of the others.  As a result,
> as noted in sanitizer/70051, it doesn't correctly detect
> overflows in the bounds of multidimensional VLAs.

It doesn't, but I don't see why it couldn't.  It should be fine to check 
each dimension for overflow separately; if an inner dimension doesn't 
overflow, we can go on and consider the outer dimension.

Incidentally, I was wondering if it would make sense to use the 
overflowing calculation for both TYPE_SIZE and the sanity check when 
we're doing both.

>>> +          /* Avoid instrumenting constexpr functions.  Those must
>>> +         be checked statically, and the (non-constexpr) dynamic
>>> +         instrumentation would cause them to be rejected.  */

>> Hmm, this sounds wrong; constexpr functions can also be called with
>> non-constant arguments, and the instrumentation should be folded away
>> when evaluating a call with constant arguments.

> You're right that constexpr functions should be checked as
> well.  Unfortunately, at present, due to c++/70507 the check
> (or rather the call to __builtin_mul_overflow) isn't folded
> away and we end up with error: call to internal function.

Ah, sure.  It should be pretty simple to teach the constexpr code how to 
handle that built-in.

Jason

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

* Re: [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
  2016-04-04 23:35         ` Jason Merrill
@ 2016-04-08  0:05           ` Martin Sebor
  2016-04-10 23:14             ` Martin Sebor
  0 siblings, 1 reply; 22+ messages in thread
From: Martin Sebor @ 2016-04-08  0:05 UTC (permalink / raw)
  To: Jason Merrill, Gcc Patch List

I've spent a ton of time trying to implement the suggested
changes (far too much in large part because of my own mistakes)
but I don't think they will work.  I'll try to clean up what
I have and post it for review.  I wanted to respond to this
how in case you have some suggestions or concerns with the
direction I'm taking in the meantime.

>> But if even a few MB seems too strict, I would find having even
>> an exceedingly liberal limit (say 1GB) much preferable to none
>> at all as it makes it possible to exercise boundary conditions
>> such as the size overflow problem you noted below.
>
> That sounds reasonable, as long as users with unusual needs can adjust
> it with a flag, but even so I'm nervous about doing this in stage 4.  It
> certainly isn't a regression.

I'm not comfortable adding a new option at this stage.  I'm also
not sure that an option to impose a static limit is the best
solution.  It seems that if we go to the trouble of making the limit
customizable it should be possible to change it without recompiling
everything (e.g., on ELF, we could check for a weak function and
call it to get the most up-to-date limit).

Let me restore the 4.9.3 behavior by setting the VLA size limit to
SIZE_MAX / 2 (that fixes the other regression that I just raised
in c++/70588 for the record).

>> I don't think modifying build_vec_init() alone would be sufficient.
>> For example, the function isn't called for a VLA with a constant
>> bound like this one:
>>
>>   int A [2][N] = { 1, 2, 3, 4 };
>
> That seems like a bug, due to array_of_runtime_bound_p returning false
> for that array.

It seems that a complete fix would involve (among other things)
replacing calls to array_of_runtime_bound_p with
variably_modified_type_p or similar since the N3639 arrays are
just a subset of those accepted by G++.  Unfortunately, that has
other repercussions (e.g., c++70555).

I replaced the call to array_of_runtime_bound_p in build_vec_init
with one to variably_modified_type_p to get around the above.
That  works, but it's only good for checking for excess
initializers in build_vec_init.  It's too late to check for
overflow in the VLA bounds because by that time the code to
allocate the stack has already been emitted.

>>> Also, I think we should check for invalid bounds in
>>> compute_array_index_type, next to the UBsan code.  Checking bounds only
>>> from cp_finish_decl means that we don't check uses of VLA types other
>>> than variable declarations.

I don't see how to make this work.  compute_array_index_type
doesn't have access to the CONSTRUCTOR for the initializer of
the VLA the initializer hasn't been parsed yet).  Without it
it's not possible to detect VLA size overflow in cases such
as in:

     T a [][N] = { { ... }, { ... } };

where the number of top-level elements determines whether or
not the size of the whole VLA would overflow or exceed the
maximum.

Given this, I believe the check does need to be implemented
somewhere in cp_finish_decl or one of the functions it calls
(such as check_initializer) and emitted before build_vec_init
is called or the initializer code it creates is emitted.

>>
>> You mean VLA typedefs?  That's true, though I have consciously
>> avoided dealing with those.  They're outlawed in N3639 and so
>> I've been focusing just on variables.  But since GCC accepts
>> VLA typedefs too I was thinking I would bring them up at some
>> point in the future to decide what to do about them.
>
> And cast to pointer to VLAs.  But for non-variable cases we don't care
> about available stack, so we wouldn't want your allocation limit to apply.

I don't want to implement it now, but I think the same limit
should apply in all cases, otherwise code remains susceptible
to unsigned integer wrapping.  For example:

   extern size_t N;
   typedef int A [N];
   int *a = (int*)malloc (sizeof (A));   // possible wraparound
   a [N - 1] = 0;                        // out-of-bounds write

It seems that the typedef will need to be accepted (in case it's
unused) but the runtime sizeof would need to do the checking and
potentially throw.  I haven't thought through the ramifications
yet.

>
>> As for where to add the bounds checking code, I also at first
>> thought of checking the bounds parallel to the UBSan code in
>> compute_array_index_type() and even tried that approach. The
>> problem with it is that it only considers one array dimension
>> at a time, without the knowledge of the others.  As a result,
>> as noted in sanitizer/70051, it doesn't correctly detect
>> overflows in the bounds of multidimensional VLAs.
>
> It doesn't, but I don't see why it couldn't.  It should be fine to check
> each dimension for overflow separately; if an inner dimension doesn't
> overflow, we can go on and consider the outer dimension.

As I explained above, I don't see how to make this work.

>
> Incidentally, I was wondering if it would make sense to use the
> overflowing calculation for both TYPE_SIZE and the sanity check when
> we're doing both.

I'm not sure what you mean here.  Can you elaborate?

>
>>>> +          /* Avoid instrumenting constexpr functions.  Those must
>>>> +         be checked statically, and the (non-constexpr) dynamic
>>>> +         instrumentation would cause them to be rejected.  */
>
>>> Hmm, this sounds wrong; constexpr functions can also be called with
>>> non-constant arguments, and the instrumentation should be folded away
>>> when evaluating a call with constant arguments.
>
>> You're right that constexpr functions should be checked as
>> well.  Unfortunately, at present, due to c++/70507 the check
>> (or rather the call to __builtin_mul_overflow) isn't folded
>> away and we end up with error: call to internal function.
>
> Ah, sure.  It should be pretty simple to teach the constexpr code how to
> handle that built-in.

I'd be glad to do this work but I don't believe I can get it done
in time for 6.0.

Martin

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

* Re: [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
  2016-04-08  0:05           ` Martin Sebor
@ 2016-04-10 23:14             ` Martin Sebor
  2016-04-12 15:43               ` Jason Merrill
  2016-04-12 18:17               ` Jason Merrill
  0 siblings, 2 replies; 22+ messages in thread
From: Martin Sebor @ 2016-04-10 23:14 UTC (permalink / raw)
  To: Jason Merrill, Gcc Patch List

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

Attached is an updated patch with some the changes you suggested.
I also moved the new functions from decl.c to init.c because they
logically seem to belong there.

The suggested changes resulted in introducing the checking code
into split_nonconstant_init() in cp/typeck2.c in addition to
build_vec_init().  I would expect it to be preferable to check
in as few places as possible so I attach an alternate version
of the patch without this proliferation of call (the tests and
the documentation changes are the same so I excluded those).

Let me know which of the two approaches you prefer and/or if
you have any other requests or suggestions.

Martin

On 04/07/2016 06:05 PM, Martin Sebor wrote:
> I've spent a ton of time trying to implement the suggested
> changes (far too much in large part because of my own mistakes)
> but I don't think they will work.  I'll try to clean up what
> I have and post it for review.  I wanted to respond to this
> how in case you have some suggestions or concerns with the
> direction I'm taking in the meantime.
>
>>> But if even a few MB seems too strict, I would find having even
>>> an exceedingly liberal limit (say 1GB) much preferable to none
>>> at all as it makes it possible to exercise boundary conditions
>>> such as the size overflow problem you noted below.
>>
>> That sounds reasonable, as long as users with unusual needs can adjust
>> it with a flag, but even so I'm nervous about doing this in stage 4.  It
>> certainly isn't a regression.
>
> I'm not comfortable adding a new option at this stage.  I'm also
> not sure that an option to impose a static limit is the best
> solution.  It seems that if we go to the trouble of making the limit
> customizable it should be possible to change it without recompiling
> everything (e.g., on ELF, we could check for a weak function and
> call it to get the most up-to-date limit).
>
> Let me restore the 4.9.3 behavior by setting the VLA size limit to
> SIZE_MAX / 2 (that fixes the other regression that I just raised
> in c++/70588 for the record).
>
>>> I don't think modifying build_vec_init() alone would be sufficient.
>>> For example, the function isn't called for a VLA with a constant
>>> bound like this one:
>>>
>>>   int A [2][N] = { 1, 2, 3, 4 };
>>
>> That seems like a bug, due to array_of_runtime_bound_p returning false
>> for that array.
>
> It seems that a complete fix would involve (among other things)
> replacing calls to array_of_runtime_bound_p with
> variably_modified_type_p or similar since the N3639 arrays are
> just a subset of those accepted by G++.  Unfortunately, that has
> other repercussions (e.g., c++70555).
>
> I replaced the call to array_of_runtime_bound_p in build_vec_init
> with one to variably_modified_type_p to get around the above.
> That  works, but it's only good for checking for excess
> initializers in build_vec_init.  It's too late to check for
> overflow in the VLA bounds because by that time the code to
> allocate the stack has already been emitted.
>
>>>> Also, I think we should check for invalid bounds in
>>>> compute_array_index_type, next to the UBsan code.  Checking bounds only
>>>> from cp_finish_decl means that we don't check uses of VLA types other
>>>> than variable declarations.
>
> I don't see how to make this work.  compute_array_index_type
> doesn't have access to the CONSTRUCTOR for the initializer of
> the VLA the initializer hasn't been parsed yet).  Without it
> it's not possible to detect VLA size overflow in cases such
> as in:
>
>      T a [][N] = { { ... }, { ... } };
>
> where the number of top-level elements determines whether or
> not the size of the whole VLA would overflow or exceed the
> maximum.
>
> Given this, I believe the check does need to be implemented
> somewhere in cp_finish_decl or one of the functions it calls
> (such as check_initializer) and emitted before build_vec_init
> is called or the initializer code it creates is emitted.
>
>>>
>>> You mean VLA typedefs?  That's true, though I have consciously
>>> avoided dealing with those.  They're outlawed in N3639 and so
>>> I've been focusing just on variables.  But since GCC accepts
>>> VLA typedefs too I was thinking I would bring them up at some
>>> point in the future to decide what to do about them.
>>
>> And cast to pointer to VLAs.  But for non-variable cases we don't care
>> about available stack, so we wouldn't want your allocation limit to
>> apply.
>
> I don't want to implement it now, but I think the same limit
> should apply in all cases, otherwise code remains susceptible
> to unsigned integer wrapping.  For example:
>
>    extern size_t N;
>    typedef int A [N];
>    int *a = (int*)malloc (sizeof (A));   // possible wraparound
>    a [N - 1] = 0;                        // out-of-bounds write
>
> It seems that the typedef will need to be accepted (in case it's
> unused) but the runtime sizeof would need to do the checking and
> potentially throw.  I haven't thought through the ramifications
> yet.
>
>>
>>> As for where to add the bounds checking code, I also at first
>>> thought of checking the bounds parallel to the UBSan code in
>>> compute_array_index_type() and even tried that approach. The
>>> problem with it is that it only considers one array dimension
>>> at a time, without the knowledge of the others.  As a result,
>>> as noted in sanitizer/70051, it doesn't correctly detect
>>> overflows in the bounds of multidimensional VLAs.
>>
>> It doesn't, but I don't see why it couldn't.  It should be fine to check
>> each dimension for overflow separately; if an inner dimension doesn't
>> overflow, we can go on and consider the outer dimension.
>
> As I explained above, I don't see how to make this work.
>
>>
>> Incidentally, I was wondering if it would make sense to use the
>> overflowing calculation for both TYPE_SIZE and the sanity check when
>> we're doing both.
>
> I'm not sure what you mean here.  Can you elaborate?
>
>>
>>>>> +          /* Avoid instrumenting constexpr functions.  Those must
>>>>> +         be checked statically, and the (non-constexpr) dynamic
>>>>> +         instrumentation would cause them to be rejected.  */
>>
>>>> Hmm, this sounds wrong; constexpr functions can also be called with
>>>> non-constant arguments, and the instrumentation should be folded away
>>>> when evaluating a call with constant arguments.
>>
>>> You're right that constexpr functions should be checked as
>>> well.  Unfortunately, at present, due to c++/70507 the check
>>> (or rather the call to __builtin_mul_overflow) isn't folded
>>> away and we end up with error: call to internal function.
>>
>> Ah, sure.  It should be pretty simple to teach the constexpr code how to
>> handle that built-in.
>
> I'd be glad to do this work but I don't believe I can get it done
> in time for 6.0.
>
> Martin


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: gcc-69517.patch --]
[-- Type: text/x-patch; name="gcc-69517.patch", Size: 75483 bytes --]

PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
PR c++/70019 - VLA size overflow not detected

gcc/testsuite/ChangeLog:
2016-04-10  Martin Sebor  <msebor@redhat.com>

	PR c++/69517
	PR c++/70019
	* c-c++-common/ubsan/vla-1.c (main): Catch exceptions.
	* g++.dg/cpp1y/vla11.C: New test.
	* g++.dg/cpp1y/vla12.C: New test.
	* g++.dg/cpp1y/vla13.C: New test.
	* g++.dg/cpp1y/vla14.C: New test.
	* g++.dg/cpp1y/vla3.C: Restore deleted test.
	* gcc/testsuite/g++.dg/init/array24.C: Fully brace VLA initializer.
	* g++.dg/ubsan/vla-1.C: Disable exceptions.

gcc/cp/ChangeLog:
2016-04-10  Martin Sebor  <msebor@redhat.com>

	PR c++/69517
	PR c++/70019
	* cp-tree.h (throw_bad_array_length, build_vla_check): Declare new
	functions.
	* decl.c (check_initializer, cp_finish_decl): Call them.
	(reshape_init_r): Reject incompletely braced intializer-lists
	for VLAs.
	* init.c (throw_bad_array_length, build_vla_check)
	(build_vla_size_check, build_vla_init_check): Define new functions.
	(build_vec_init): Use variably_modified_type_p() to detect a VLA.
	Call throw_bad_array_length() and build_vla_check().
	* typeck2.c (split_nonconstant_init_1): Use variably_modified_type_p()
	to detect a VLA.
	(store_init_value): Same.
	(split_nonconstant_init): Handle excess elements in string literal
	initializers for VLAs.

gcc/doc/ChangeLog:

2016-04-10  Martin Sebor  <msebor@redhat.com>

	PR c++/69517
	PR c++/70019
	* extend.texi (Variable Length): Document C++ specifics.

libstdc++-v3/ChangeLog:

2016-04-10  Martin Sebor  <msebor@redhat.com>

	PR c++/69517
	* testsuite/25_algorithms/rotate/moveable2.cc: Make sure VLA
	upper bound is positive.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b7b770f..1d726fd 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5978,6 +5978,7 @@ extern tree build_value_init_noctor		(tree, tsubst_flags_t);
 extern tree get_nsdmi				(tree, bool);
 extern tree build_offset_ref			(tree, tree, bool,
 						 tsubst_flags_t);
+extern tree throw_bad_array_length              (void);
 extern tree throw_bad_array_new_length		(void);
 extern tree build_new				(vec<tree, va_gc> **, tree, tree,
 						 vec<tree, va_gc> **, int,
@@ -5999,6 +6000,7 @@ extern tree scalar_constant_value		(tree);
 extern tree decl_really_constant_value		(tree);
 extern int diagnose_uninitialized_cst_or_ref_member (tree, bool, bool);
 extern tree build_vtbl_address                  (tree);
+extern tree build_vla_check                     (tree, tree = NULL_TREE);
 
 /* in lex.c */
 extern void cxx_dup_lang_specific_decl		(tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 9260f4c..c8caeea 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5864,6 +5864,16 @@ reshape_init_r (tree type, reshape_iter *d, bool first_initializer_p,
 	    }
 	}
 
+      if (variably_modified_type_p (type, NULL_TREE))
+	{
+	  /* Require VLAs to have their initializers fully braced
+	     to avoid initializing the wrong elements.  */
+	  if (complain & tf_error)
+	    error ("missing braces around initializer for a variable length "
+		   "array %qT", type);
+	  return error_mark_node;
+	}
+
       warning (OPT_Wmissing_braces, "missing braces around initializer for %qT",
 	       type);
     }
@@ -6167,6 +6177,33 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
 	      && PAREN_STRING_LITERAL_P (DECL_INITIAL (decl)))
 	    warning (0, "array %qD initialized by parenthesized string literal %qE",
 		     decl, DECL_INITIAL (decl));
+
+	  if (TREE_CODE (type) == ARRAY_TYPE
+	      && variably_modified_type_p (type, NULL_TREE)
+	      && !processing_template_decl)
+	    {
+	      /* Statically check for overflow in VLA bounds and build
+		 an expression that checks at runtime whether the VLA
+		 is erroneous due to invalid (runtime) bounds.
+		 Another expression to check for excess initializers
+		 is built in build_vec_init.  */
+	      tree check = build_vla_check (TREE_TYPE (decl), NULL_TREE);
+
+	      if (flag_exceptions && current_function_decl
+		  /* Avoid instrumenting constexpr functions for now.
+		     Those must be checked statically, and the (non-
+		     constexpr) dynamic instrumentation would cause
+		     them to be rejected.  See c++/70507.  */
+		  && !DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+		{
+		  /* Use the runtime check only when exceptions are enabled.
+		     Otherwise let bad things happen...  */
+		  check = build3 (COND_EXPR, void_type_node, check,
+				  throw_bad_array_length (), void_node);
+
+		  finish_expr_stmt (check);
+		}
+	    }
 	  init = NULL;
 	}
     }
@@ -6809,6 +6846,38 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 	  cleanups = make_tree_vector ();
 	  init = check_initializer (decl, init, flags, &cleanups);
 
+	  if (TREE_CODE (type) == ARRAY_TYPE
+	      && variably_modified_type_p (type, NULL_TREE)
+	      && !processing_template_decl
+	      && !init)
+	    {
+	      /* Statically check for overflow in VLA bounds and build
+		 an expression that checks whether the VLA is erroneous
+		 at runtime.  A runtime check for the bounds of
+		 initialized VLAs along with excess initializer
+		 elements is built in build_vec_init() for initializer
+		 lists and in split_nonconstant_init() for string
+		 literals.  */
+	      tree check = build_vla_check (type);
+
+	      if (flag_exceptions
+		  && current_function_decl
+		  /* Avoid instrumenting constexpr functions.  Those must
+		     be checked statically for now since the (non-constexpr)
+		     dynamic instrumentation would cause them to be rejected
+		     due to c++/70507.  */
+		  && !DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+		{
+		  /* Use the runtime check only when exceptions are enabled.
+		     Otherwise let bad things happen (though perhaps emitting
+		     a trap would be appropriate).  */
+		  check = build3 (COND_EXPR, void_type_node, check,
+				  throw_bad_array_length (), void_node);
+
+		  finish_expr_stmt (check);
+		}
+	    }
+
 	  /* Handle:
 
 	     [dcl.init]
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 5997d53..8e33df0 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2262,6 +2262,20 @@ diagnose_uninitialized_cst_or_ref_member (tree type, bool using_new, bool compla
   return diagnose_uninitialized_cst_or_ref_member_1 (type, type, using_new, complain);
 }
 
+/* Call __cxa_throw_bad_array_length to indicate that the size calculation
+   in the bounds of a variable length array overflowed.  */
+
+tree
+throw_bad_array_length (void)
+{
+  tree fn = get_identifier ("__cxa_throw_bad_array_length");
+  if (!get_global_value_if_present (fn, &fn))
+    fn = push_throw_library_fn (fn, build_function_type_list (void_type_node,
+                                                             NULL_TREE));
+
+  return build_cxx_call (fn, 0, NULL, tf_warning_or_error);
+}
+
 /* Call __cxa_bad_array_new_length to indicate that the size calculation
    overflowed.  Pretend it returns sizetype so that it plays nicely in the
    COND_EXPR.  */
@@ -3819,15 +3833,20 @@ build_vec_init (tree base, tree maxindex, tree init,
       && from_array != 2)
     init = TARGET_EXPR_INITIAL (init);
 
+  /* Is ATYPE a variable modified type such as a VLA with either
+     a const or non-const major bound.  */
+  bool vartype_p = (!TREE_CONSTANT (maxindex)
+		    || variably_modified_type_p (atype, NULL_TREE));
+
   /* If we have a braced-init-list, make sure that the array
      is big enough for all the initializers.  */
   bool length_check = (init && TREE_CODE (init) == CONSTRUCTOR
 		       && CONSTRUCTOR_NELTS (init) > 0
-		       && !TREE_CONSTANT (maxindex));
+		       && vartype_p);
 
   if (init
       && TREE_CODE (atype) == ARRAY_TYPE
-      && TREE_CONSTANT (maxindex)
+      && !vartype_p
       && (from_array == 2
 	  ? vec_copy_assign_is_trivial (inner_elt_type, init)
 	  : !TYPE_NEEDS_CONSTRUCTING (type))
@@ -3925,7 +3944,7 @@ build_vec_init (tree base, tree maxindex, tree init,
 
   /* Should we try to create a constant initializer?  */
   bool try_const = (TREE_CODE (atype) == ARRAY_TYPE
-		    && TREE_CONSTANT (maxindex)
+		    && !vartype_p
 		    && (init ? TREE_CODE (init) == CONSTRUCTOR
 			: (type_has_constexpr_default_constructor
 			   (inner_elt_type)))
@@ -3973,6 +3992,24 @@ build_vec_init (tree base, tree maxindex, tree init,
 		}
 	      /* Don't check an array new when -fno-exceptions.  */
 	    }
+	  else if (flag_exceptions
+		   && current_function_decl
+		  /* Avoid instrumenting constexpr functions.  Those must
+		     be checked statically for now since the (non-constexpr)
+		     dynamic instrumentation would cause them to be rejected
+		     due to c++/70507.  */
+		   && !DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+	    {
+	      /* Use the runtime check only when exceptions are enabled.
+		 Otherwise let bad things happen (though perhaps emitting
+		 a trap would be appropriate).  */
+	      tree check = build_vla_check (atype, init);
+
+	      check = build3 (COND_EXPR, void_type_node, check,
+			      throw_bad_array_length (), void_node);
+
+	      finish_expr_stmt (check);
+	    }
 	  else if (flag_sanitize & SANITIZE_BOUNDS
 		   && do_ubsan_in_current_function ())
 	    {
@@ -4709,3 +4746,293 @@ build_vec_delete (tree base, tree maxindex,
 
   return rval;
 }
+
+
+/* The implementation of build_vla_check() that recursively builds
+   an expression to determine whether the VLA TYPE is erroneous due
+   either to its bounds being invalid or to integer overflow in
+   the computation of its total size.
+   CHECK is the boolean expression being built, initialized to
+   boolean_false_node.
+   VLASIZE is used internally to pass the incrementally computed
+   size of the VLA object down to its recursive invocations.
+   MAX_VLASIZE is the maximum valid size of the VLA in bytes.
+   CST_SIZE is the product of the VLA's constant dimensions.  */
+
+static tree
+build_vla_size_check (tree check,
+		      tree type,
+		      tree vlasize,
+		      tree max_vlasize,
+		      offset_int *cst_size)
+{
+  tree vmul = builtin_decl_explicit (BUILT_IN_MUL_OVERFLOW);
+
+  tree vlasizeaddr = build_unary_op (input_location, ADDR_EXPR, vlasize, 0);
+
+  bool overflow = false;
+
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      /* Compute the upper bound of this array type.  */
+      tree inner_nelts = array_type_nelts_top (type);
+      tree inner_nelts_cst = maybe_constant_value (inner_nelts);
+
+      if (TREE_CODE (inner_nelts_cst) == INTEGER_CST)
+	{
+	  /* The upper bound is a constant expression.  Compute the product
+	     of the constant upper bounds seen so far so that overflow can
+	     be diagnosed.  */
+	  offset_int result = wi::mul (wi::to_offset (inner_nelts_cst),
+				       *cst_size, SIGNED, &overflow);
+	  *cst_size = overflow ? 0 : result;
+	}
+
+      /* Check for overflow in the VLAs (runtime) upper bounds.  */
+      tree vflowcheck = build_call_expr (vmul, 3, inner_nelts,
+					 vlasize, vlasizeaddr);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, vflowcheck);
+
+      /* Recursively check for overflow in the remaining major bounds.  */
+      check = build_vla_size_check (check, TREE_TYPE (type),
+				    vlasize, max_vlasize,
+				    cst_size);
+    }
+  else
+    {
+      /* Get the size of the VLA element type in bytes.  */
+      tree typesize = TYPE_SIZE_UNIT (type);
+
+      /* See if the size, when multipled by the product of the VLA's
+	 constant dimensions, is within range of size_t.  If not,
+	 the VLA is definitely erroneous amd must be diagnosed at
+	 compile time.  */
+      offset_int result = wi::mul (wi::to_offset (typesize), *cst_size,
+				   SIGNED, &overflow);
+      *cst_size = overflow ? 0 : result;
+
+      /* Multiply the (non-constant) VLA size so far by the element size,
+	 checking for overflow, and replacing the value of vlasize with
+	 the product in the absence of overflow.  This size is the total
+	 runtime size of the VLA in bytes.  */
+      tree vflowcheck = build_call_expr (vmul, 3, typesize,
+					 vlasize, vlasizeaddr);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, vflowcheck);
+
+      /* Check to see if the final VLA size exceeds the maximum.  */
+      tree sizecheck = fold_build2 (LT_EXPR, boolean_type_node,
+				    max_vlasize, vlasize);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, sizecheck);
+
+      /* Also check to see if the final array size is zero (the size
+	 is unsigned so the earlier overflow check detects negative
+	 values as well.  */
+      tree zerocheck = fold_build2 (EQ_EXPR, boolean_type_node,
+				    vlasize, size_zero_node);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, zerocheck);
+    }
+
+  /* Diagnose overflow determined at compile time.  */
+  if (overflow)
+    {
+      error ("integer overflow in variable array size");
+      /* Reset to suppress any further diagnostics.  */
+      *cst_size = 0;
+    }
+
+  return check;
+}
+
+/* The implementation of build_vla_check() that recursively builds
+   an expression to determine whether the VLA initializer-list for
+   TYPE is erroneous due to excess initializers.
+   CHECK is the boolean expression being built, initialized to
+   the result of build_vla_size_check().
+   INIT is the VLA initializer expression to check against TYPE.
+   On the first (non-recursive) call, INIT_ELTS is set either to 1,
+   or to the number of elements in the initializer-list for VLAs
+   of unspecified (major) bound.  On subsequent (recursive) calls.
+   it is set to NULL and computed from the number of elements in
+   the (nested) initializer-list.
+*/
+
+static tree
+build_vla_init_check (tree check, tree type, tree init, tree init_elts)
+{
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      /* Compute the upper bound of this array type unless it has
+	 already been computed by the caller for an array of unspecified
+	 bound, as in 'T a[];'  */
+      tree inner_nelts = init_elts ? init_elts : array_type_nelts_top (type);
+
+      size_t len;
+
+      if (TREE_CODE (init) == CONSTRUCTOR)
+	{
+	  /* The initializer of this array is itself an array.  Build
+	     an expression to check if the number of elements in the
+	     initializer array exceeds the upper bound of the type
+	     of the object being initialized.  */
+	  if (vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (init))
+	    {
+	      len = v->length ();
+	      tree initelts = build_int_cstu (size_type_node, len);
+	      tree initcheck = fold_build2 (LT_EXPR, boolean_type_node,
+					    inner_nelts, initelts);
+
+	      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+				   check, initcheck);
+
+	      constructor_elt *ce;
+	      HOST_WIDE_INT i;
+
+	      /* Iterate over all non-empty initializers in this array,
+		 recursively building expressions to see if the elements
+		 of each are in excess of the corresponding (runtime)
+		 bound of the array type.  */
+	      FOR_EACH_VEC_SAFE_ELT (v, i, ce)
+		check = build_vla_init_check (check, TREE_TYPE (type),
+					      ce->value, NULL_TREE);
+	    }
+	}
+      else if (TREE_CODE (init) == STRING_CST
+	       && (len = TREE_STRING_LENGTH (init)))
+	{
+	  /* The initializer of this array is a string.  */
+	  tree ctype = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init)));
+	  len /= TYPE_PRECISION (ctype) / BITS_PER_UNIT;
+
+	  /* A C++ string literal initializer must have at most as many
+	     characters as there are elements in the array, including
+	     the terminating NUL.  */
+	  tree initelts = build_int_cstu (size_type_node, len);
+	  tree initcheck = fold_build2 (LT_EXPR, boolean_type_node,
+					inner_nelts, initelts);
+	  check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			       check, initcheck);
+	}
+      else if (TREE_CODE (init) == ERROR_MARK)
+	{
+	  // No checking is possible.
+	  check = boolean_false_node;
+	}
+      else
+	{
+	  /* What's this array initializer?  */
+	  gcc_unreachable ();
+	}
+    }
+
+  return check;
+}
+
+/* Build an expression to determine whether the VLA TYPE is erroneous.
+   INIT is the VLA initializer expression or NULL_TREE when the VLA is
+   not initialized.  */
+
+/* Build an expression to determine whether the VLA TYPE is erroneous.
+   INIT is the VLA initializer expression or NULL_TREE when the VLA is
+   not initialized.  */
+
+tree
+build_vla_check (tree type, tree init /* = NULL_TREE */)
+{
+  tree check = boolean_false_node;
+
+  /* The product of all constant dimensions of the VLA, initialized
+     to either 1 in the common case or to the number of elements in
+     the VLA's initializer-list for VLAs of unspecified (major)
+     bound.  */
+  offset_int cst_size = 1;
+
+  /* The initial size of the VLA to start the computation of the total
+     size with.  Like CST_SIZE above, initialized to 1 or the number
+     of elements in the VLA's initializer-list for VLAs of unspecified
+     bound.  */
+  tree initial_size = size_one_node;
+
+  /* For a VLA of unspecified (major) bound, the number of elements
+     it is initialized with determined from the initializer-list.  */
+  tree initial_elts = NULL_TREE;
+
+  if (init)
+    {
+      /* Determine the upper bound of the VLA of unspecified bound,
+	 as in 'T a[];' if this is such a VLA.  Such a VLA can be
+	 initialized with any number of elements but the number of
+	 elements so determined must be used to check the total size
+	 of the VLA.  */
+      gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
+
+      if (tree dom = TYPE_DOMAIN (type))
+	if (tree max = TYPE_MAX_VALUE (dom))
+	  if (integer_zerop (max))
+	    {
+	      if (TREE_CODE (init) == CONSTRUCTOR)
+		{
+		  vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (init);
+
+		  /* Since the upper bound of every array must be positive
+		     a VLA with an unspecified major bound must be initized
+		     by a non-empty initializer list.  */
+		  gcc_assert (v != NULL);
+
+		  cst_size = v->length ();
+		}
+	      else if (TREE_CODE (init) == STRING_CST)
+		{
+		  /* The initializer is a (possibly empty) string consisting
+		     at a minumum of one character, the terminating NUL.
+		     This condition implies a definition like
+		       char s [][N] = "";
+		     which is an error but even though it has been diagnosed
+		     by this point the initializer still winds up here.  */
+		  size_t nchars = TREE_STRING_LENGTH (init);
+		  tree ctype = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init)));
+		  nchars /= TYPE_PRECISION (ctype) / BITS_PER_UNIT;
+
+		  cst_size = nchars + 1;
+		}
+
+	      initial_elts = wide_int_to_tree (size_type_node, cst_size);
+	      initial_size = initial_elts;
+	    }
+    }
+
+  /* Build a variable storing the total runtime size of the VLA and
+     initialize it either to 1 (in the common case) or to the number
+     of topmost elements in the initializer-list when the VLA is
+     an array of unspecified (major) bound.  */
+  tree vlasize = build_decl (input_location,
+			     VAR_DECL, NULL_TREE, sizetype);
+  DECL_ARTIFICIAL (vlasize) = 1;
+  DECL_IGNORED_P (vlasize) = 1;
+  DECL_CONTEXT (vlasize) = current_function_decl;
+  DECL_INITIAL (vlasize) = initial_size;
+  vlasize = pushdecl (vlasize);
+  add_decl_expr (vlasize);
+
+  /* Impose a lenient limit on the size of the biggest VLA in bytes.
+     FIXME: Tighten up the limit to make it more useful and make it
+     configurable for users with unusual requirements.  */
+  tree max_vlasize
+    = fold_build2 (RSHIFT_EXPR, size_type_node,
+		   build_all_ones_cst (size_type_node),
+		   integer_one_node);
+
+  /* Build an expression that checks the runtime bounds of the VLA
+     for invalid values and the total size of the VLA for overflow.  */
+  check = build_vla_size_check (check, type, vlasize, max_vlasize, &cst_size);
+
+  if (wi::ltu_p (wi::to_offset (max_vlasize), cst_size))
+    {
+      /* Issue the warning only in the "topmost" (non-recursive) call
+	 to avoid duplicating diagnostics.  This is only a warning to
+	 allow programs to be portable to more permissive environments.  */
+      warning (OPT_Wvla, "size of variable length array exceeds maximum "
+	       "of %qE bytes",  max_vlasize);
+    }
+
+  if (init)
+    {
+      /* Build an expression that checks the VLA initializer expression
+	 against the type of the VLA for excess elements.  */
+      check = build_vla_init_check (check, type, init, initial_elts);
+    }
+
+  return check;
+}
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index b921689..092d512 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -603,7 +603,7 @@ split_nonconstant_init_1 (tree dest, tree init)
       array_type_p = true;
       if ((TREE_SIDE_EFFECTS (init)
 	   && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
-	  || array_of_runtime_bound_p (type))
+	  || variably_modified_type_p (type, NULL_TREE))
 	{
 	  /* For an array, we only need/want a single cleanup region rather
 	     than one per element.  */
@@ -749,7 +749,26 @@ split_nonconstant_init (tree dest, tree init)
       TREE_READONLY (dest) = 0;
     }
   else
-    code = build2 (INIT_EXPR, TREE_TYPE (dest), dest, init);
+    {
+      tree type = TREE_TYPE (dest);
+
+      if (TREE_CODE (init) == STRING_CST
+	  && TREE_CODE (type) == ARRAY_TYPE
+	  && variably_modified_type_p (type, NULL_TREE))
+	{
+	  /* Statically check for overflow in VLA bounds and build
+	     an expression that checks whether the VLA is erroneous
+	     at runtime due to excess elements in the string literal.  */
+	  tree check = build_vla_check (type, init);
+
+	  check = build3 (COND_EXPR, void_type_node, check,
+			  throw_bad_array_length (), void_node);
+
+	  finish_expr_stmt (check);
+	}
+
+      code = build2 (INIT_EXPR, TREE_TYPE (dest), dest, init);
+    }
 
   return code;
 }
@@ -845,7 +864,8 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
      will perform the dynamic initialization.  */
   if (value != error_mark_node
       && (TREE_SIDE_EFFECTS (value)
-	  || array_of_runtime_bound_p (type)
+	  || variably_modified_type_p (type, NULL_TREE)
 	  || ! reduced_constant_expression_p (value)))
     return split_nonconstant_init (decl, value);
   /* If the value is a constant, just put it in DECL_INITIAL.  If DECL
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 6e27029..616479d 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -1634,14 +1634,48 @@ foo (int n)
 You can use the function @code{alloca} to get an effect much like
 variable-length arrays.  The function @code{alloca} is available in
 many other C implementations (but not in all).  On the other hand,
-variable-length arrays are more elegant.
+variable-length arrays are available in GCC for all targets and
+provide type safety.
 
 There are other differences between these two methods.  Space allocated
 with @code{alloca} exists until the containing @emph{function} returns.
 The space for a variable-length array is deallocated as soon as the array
 name's scope ends, unless you also use @code{alloca} in this scope.
 
-You can also use variable-length arrays as arguments to functions:
+Unlike GCC, G++ instruments variable-length arrays (@xref{Variable Length})
+with checks for erroneous uses: when a variable-length array object is
+created its runtime bounds are checked to detect non-positive values,
+integer overflows, sizes in excess of 1 MB, and excess initializers.
+When an erroneous variable-length array is detected the runtime arranges
+for an exception to be thrown that matches a handler of type
+@code{std::bad_array_length}.
+
+Also unlike GCC, G++ allows variable-length arrays to be initialized.
+However, unlike initializer lists for ordinary multidimensional arrays,
+those for multidimensional variable-length arrays must be enclosed in
+pairs of curly braces delimiting each sequence of values to use to
+initialize each subarray.  Initializer lists that aren't unambiguously
+enclosed in braces are rejected with an error.  For example, in the
+following function, the initializer list for the ordinary @code{array}
+is accepted even though it isn't fully enclosed in braces.  The same
+initializer list, however, wouldn't be accepted for a multidimensional
+variable-length array.  To initialize the variable-length array @code{vla},
+the elements of the subarray @code{vla[m]} must be enclosed in braces
+as shown.  As with ordinary arrays, elements that aren't initialized
+explicitly are default-initialized.
+
+@smallexample
+void
+foo (int m, int n)
+@{
+  int array[2][3] = @{ 1, 2, 4, 5, 6 @};
+  int vla[m][n] = @{ @{ 1, 2 @}, @{ 4, 5, 6 @} @};
+@}
+@end smallexample
+
+
+In C programs (but not in C++) variable-length arrays can also be declared
+as function arguments:
 
 @smallexample
 struct entry
diff --git a/gcc/testsuite/c-c++-common/ubsan/vla-1.c b/gcc/testsuite/c-c++-common/ubsan/vla-1.c
index 52ade3a..27ef110 100644
--- a/gcc/testsuite/c-c++-common/ubsan/vla-1.c
+++ b/gcc/testsuite/c-c++-common/ubsan/vla-1.c
@@ -87,18 +87,24 @@ fn12 (void)
 int
 main (void)
 {
-  fn1 ();
-  fn2 ();
-  fn3 ();
-  fn4 ();
-  fn5 ();
-  fn6 ();
-  fn7 ();
-  fn8 ();
-  fn9 ();
-  fn10 ();
-  fn11 ();
-  fn12 ();
+#if __cplusplus
+#  define TRY(stmt)   do { try { stmt; } catch (...) { } } while (0)
+#else
+#  define TRY(stmt)   stmt
+#endif
+
+  TRY (fn1 ());
+  TRY (fn2 ());
+  TRY (fn3 ());
+  TRY (fn4 ());
+  TRY (fn5 ());
+  TRY (fn6 ());
+  TRY (fn7 ());
+  TRY (fn8 ());
+  TRY (fn9 ());
+  TRY (fn10 ());
+  TRY (fn11 ());
+  TRY (fn12 ());
   return 0;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla11.C b/gcc/testsuite/g++.dg/cpp1y/vla11.C
new file mode 100644
index 0000000..af9624a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla11.C
@@ -0,0 +1,711 @@
+// PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer
+//   elements
+// PR c++/70019 - VLA size overflow not detected
+//
+// Runtime test to verify that attempting to either construct a VLA with
+// erroneous bounds, or initialize one with an initializer-list that
+// contains more elements than the VLA's non-constant (runtime) bounds
+// causes an exception to be thrown.  Test also verifies that valid
+// VLAs and their initializers don't cause such an exception.
+
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-Wno-vla" }
+
+#pragma GCC diagnostic ignored "-Wvla"
+
+#define INT_MAX    __INT_MAX__
+#define LONG_MAX   __LONG_MAX__
+#define SIZE_MAX   __SIZE_MAX__
+#define UINT_MAX   (~0U)
+#define ULONG_MAX  (~0LU)
+
+#define INT_MIN    (-__INT_MAX__ - 1)
+#define LONG_MIN   (-__LONG_MAX__ - 1)
+
+// The size of the largest allowed VLA in bytes.  Bigger objects
+// cause an exception to be thrown.  Unless the maximum size is
+// obscenely large, smaller objects should be successfully created
+// provided there's enough stack space.  See TEST_NEAR_VLA_MAX_SIZE
+// below.
+#define MAX   (__SIZE_MAX__ / 2)
+
+// Define to non-zero to exercise very large VLAs with size just
+// below the implementation-defined maximum.
+#define TEST_NEAR_VLA_MAX_SIZE    0
+
+// Define to zero to enable tests that cause an ICE due to c++/58646.
+#define BUG_58646 1
+
+// Helper macro to make it possible to pass as one multpile arguments
+// to another macro.
+#define Init(...) __VA_ARGS__
+
+typedef __SIZE_TYPE__ size_t;
+
+// Incremented for each test failure.
+int fail;
+
+// Used to convert a constant array dimension to a non-constant one.
+template <class T>
+T d (T n)
+{
+  return n;
+}
+
+// Verify either that an expected exception has been thrown or that
+// one hasn't been thrown if one isn't expected.
+int __attribute__ ((noclone, noinline))
+sink (void *p, int line, bool expect, const char *expr)
+{
+  if (!p != expect)
+    {
+      __builtin_printf ("line %i: Assertion failed: '%s': "
+                        "exception unexpectedly %sthrown\n",
+                        line, expr, !p ? "" : "not ");
+      ++fail;
+    }
+  else
+    {
+#if defined DEBUG && DEBUG
+    __builtin_printf ("line %i: Assertion passed: '%s': "
+		      "exception %sthrown as expected\n",
+		      line, expr, !p ? "" : "not ");
+#endif
+    }
+  return 0;
+}
+
+#define _CAT(name, line) name ## line
+#define CAT(name, line) _CAT (name, line)
+
+#define STR(...) #__VA_ARGS__
+
+// Type to exercise VLA with.  TYPESIZE is the size of the type in bytes.
+// Using a template serves two purposes.  First, it makes it possible to
+// parameterize the test on VLAs of different size.  Second, it verifies
+// that the checking code can deal with templates (i.e., completes
+// the element type of the VLA when necessary).
+template <unsigned TypeSize>
+struct alignas (TypeSize) TestType
+{
+  char data;
+};
+
+// Test function invoked with a pointer to each test case.  Must
+// return a value though what value doesn't matter.
+int __attribute__ ((noclone, noinline))
+tester (int (*testcase)(const char*),
+	const char *str, int line, bool expect)
+{
+  try
+    {
+      return testcase (str);
+    }
+  catch (...)
+    {
+      return sink (0, line, expect, str);
+    }
+}
+
+// Macro to define a unique specialization of a function template to
+// exercise a VLA of type T, rank N, with dimensions given by Dims
+// and initializer Init.  Expect is true when the VLA initialization
+// is expected to trigger an exception.
+// The macro creates a unique global dummy int object and initializes
+// it with the result of the function.  The dummy object servers no
+// other purpose but to call the function.  The function verifies
+// the expected postconditions.
+#define TEST(TypeSize, Dims, Init, Expect)				\
+  static int CAT (testcase, __LINE__)(const char *str)			\
+  {									\
+    TestType<TypeSize> vla Dims Init;					\
+    static_assert (sizeof (TestType<TypeSize>) == TypeSize,		\
+		   "wrong test type size");				\
+    return sink (vla, __LINE__, Expect, str);				\
+  }									\
+  const int CAT (dummy, __LINE__)					\
+    = tester (CAT (testcase, __LINE__),					\
+	      "T<" #TypeSize "> a" #Dims " " STR (Init) ";",		\
+	      __LINE__, Expect)
+
+
+// Create and run a test function exercising a VLA definition
+// of one of the following forms:
+//    TestType<Size> VLA Dims;        // uninitialized (with Init ())
+// or:
+//    TestType<Size> VLA Dims Init;   // initialized (with = Init ({...})
+//
+//    +-- Element Size (in Bytes)
+//    |  +-- VLA Dimensions (constant as in [3], otherwise d(3))
+//    |  |         +-- VLA Initializer Expression (if any)
+//    |  |         |                  +-- Expect Exception
+//    |  |         |                  |
+//    V  V         V                  V
+TEST (1, [d(0)],   Init (/* none*/),  true);   // uninitialized
+
+#if !BUG_58646
+// The following causes an ICE due to c++/58646.
+TEST (1, [d(0)],   Init ({}),         true);
+#endif
+TEST (1, [d(0)],   Init ({1}),        true);   // initialized with " {1}"
+TEST (1, [d(0)],   = Init ({1}),      true);   // initialized with "= {1}"
+
+TEST (1, [d(1)],   Init (),           false);
+TEST (1, [d(1)],   Init ({}),         false);
+TEST (1, [d(1)],   = Init ({}),       false);
+TEST (1, [d(1)],   Init ({1}),        false);
+TEST (1, [d(1)],   = Init ({1}),      false);
+TEST (1, [d(1)],   Init ({1, 2}),     true);
+TEST (1, [d(1)],   = Init ({1, 2}),   true);
+
+TEST (1, [d(2)],   Init (),           false);
+TEST (1, [d(2)],   Init ({}),         false);
+TEST (1, [d(2)],   Init ({1}),        false);
+TEST (1, [d(2)],   Init ({1, 2}),     false);
+TEST (1, [d(2)],   Init ({1, 2, 3}),  true);
+
+#if TEST_NEAR_VLA_MAX_SIZE
+// Very large but not erroneous one dimensional VLAs.
+TEST (1, [d(MAX)], Init (),           false);
+TEST (1, [d(MAX)], Init ({}),         false);
+TEST (1, [d(MAX)], Init ({1}),        false);
+TEST (1, [d(MAX)], Init ({1, 2}),     false);
+TEST (1, [d(MAX)], Init ({1, 2, 3}),  false);
+
+TEST ( 2, [d(MAX / 2)],   Init (),    false);
+TEST ( 4, [d(MAX / 4)],   Init (),    false);
+TEST ( 8, [d(MAX / 8)],   Init (),    false);
+TEST (16, [d(MAX / 16)],  Init (),    false);
+TEST (32, [d(MAX / 32)],  Init (),    false);
+TEST (64, [d(MAX / 64)],  Init (),    false);
+#endif   // TEST_NEAR_VLA_MAX_SIZE
+
+// One dimensional VLAs with a negative upper bound.
+TEST (1, [d(LONG_MIN)],  Init (),       true);
+TEST (1, [d(INT_MIN)],   Init (),       true);
+TEST (1, [d(-1234)],     Init (),       true);
+TEST (1, [d(-1)],        Init (),       true);
+
+// Excessively large one dimensional VLAs.
+TEST ( 1, [d(MAX + 1)],   Init (),      true);
+TEST ( 2, [d(MAX)],       Init (),      true);
+TEST ( 4, [d(MAX / 2)],   Init (),      true);
+TEST ( 4, [d(MAX / 3)],   Init (),      true);
+TEST ( 8, [d(MAX / 2)],   Init (),      true);
+TEST ( 8, [d(MAX / 3)],   Init (),      true);
+TEST ( 8, [d(MAX / 4)],   Init (),      true);
+TEST ( 8, [d(MAX / 5)],   Init (),      true);
+TEST ( 8, [d(MAX / 6)],   Init (),      true);
+TEST ( 8, [d(MAX / 7)],   Init (),      true);
+TEST (16, [d(MAX / 15)],  Init (),      true);
+TEST (32, [d(MAX / 31)],  Init (),      true);
+TEST (64, [d(MAX / 63)],  Init (),      true);
+TEST ( 1, [d(SIZE_MAX)],  Init (),      true);
+
+TEST (1, [d(LONG_MIN)],  Init ({}),     true);
+TEST (1, [d(INT_MIN)],   Init ({}),     true);
+TEST (1, [d(-1)],        Init ({}),     true);
+
+TEST (1, [d(SIZE_MAX)],  Init ({}),     true);
+
+TEST (1, [d(LONG_MIN)],  Init ({0}),    true);
+TEST (1, [d(INT_MIN)],   Init ({0}),    true);
+TEST (1, [d(-1)],        Init ({0}),    true);
+
+TEST (1, [d(SIZE_MAX)],  Init ({0}),    true);
+
+TEST ( 1, [d(SIZE_MAX/2)  + 1], Init (), true);
+TEST ( 2, [d(SIZE_MAX/4)  + 1], Init (), true);
+TEST ( 4, [d(SIZE_MAX/8)  + 1], Init (), true);
+TEST ( 8, [d(SIZE_MAX/16) + 1], Init (), true);
+TEST (16, [d(SIZE_MAX/32) + 1], Init (), true);
+
+TEST ( 1, [d(SIZE_MAX/2)  + 1], Init ({1}),             true);
+TEST ( 2, [d(SIZE_MAX/4)  + 1], Init ({1, 2}),          true);
+TEST ( 4, [d(SIZE_MAX/8)  + 1], Init ({1, 2, 3}),       true);
+TEST ( 8, [d(SIZE_MAX/16) + 1], Init ({1, 2, 3, 4}),    true);
+TEST (16, [d(SIZE_MAX/32) + 1], Init ({1, 2, 3, 4, 5}), true);
+
+// Two dimensional VLAs with one constant bound.
+
+TEST (1, [1][d(0)],   Init (),          true);
+
+#if !BUG_58646
+// The following causes an ICE due to c++/58646.
+TEST (1, [1][d(0)],   Init ({}),        true);
+#endif
+TEST (1, [ ][d(0)],   Init ({{1}}),     true);   // unspecified bound
+TEST (1, [1][d(0)],   Init ({{1}}),     true);
+
+TEST (1, [1][d(1)],   Init (),             false);
+TEST (1, [1][d(1)],   Init ({{1}}),        false);
+TEST (1, [1][d(1)],   Init ({{1, 2}}),     true);
+TEST (1, [ ][d(1)],   Init ({{1, 2}}),     true);
+
+TEST (1, [1][d(2)],   Init (),             false);
+TEST (1, [1][d(2)],   Init ({{1}}),        false);
+TEST (1, [1][d(2)],   Init ({{1, 2}}),     false);
+TEST (1, [ ][d(2)],   Init ({{1, 2}}),     false);
+TEST (1, [1][d(2)],   Init ({{1, 2, 3}}),  true);
+TEST (1, [ ][d(2)],   Init ({{1, 2, 3}}),  true);
+
+TEST (1, [2][d(1)],   Init (),                 false);
+TEST (1, [2][d(1)],   Init ({{1}}),            false);
+TEST (1, [ ][d(1)],   Init ({{1}}),            false);
+TEST (1, [2][d(1)],   Init ({{1}, {2}}),       false);
+TEST (1, [ ][d(1)],   Init ({{1}, {2}}),       false);
+TEST (1, [2][d(1)],   Init ({{1, 2}}),         true);
+TEST (1, [ ][d(1)],   Init ({{1, 2}}),         true);
+TEST (1, [2][d(1)],   Init ({{1}, {2, 3}}),    true);
+TEST (1, [ ][d(1)],   Init ({{1}, {2, 3}}),    true);
+TEST (1, [2][d(1)],   Init ({{1, 2, 3}}),      true);
+TEST (1, [ ][d(1)],   Init ({{1, 2, 3}}),      true);
+TEST (1, [2][d(1)],   Init ({{1, 2, 3}, {4}}), true);
+TEST (1, [ ][d(1)],   Init ({{1, 2, 3}, {4}}), true);
+TEST (1, [2][d(1)],   Init ({{1, 2}, {3, 4}}), true);
+TEST (1, [ ][d(1)],   Init ({{1, 2}, {3, 4}}), true);
+
+TEST (1, [2][d(2)],   Init (),                       false);
+TEST (1, [2][d(2)],   Init ({{1}}),                  false);
+TEST (1, [2][d(2)],   Init ({{1, 2}}),               false);
+TEST (1, [2][d(2)],   Init ({{1, 2}, {3}}),          false);
+TEST (1, [2][d(2)],   Init ({{1, 2}, {3, 4}}),       false);
+TEST (1, [2][d(2)],   Init ({{1}, {2, 3, 4}}),       true);
+TEST (1, [2][d(2)],   Init ({{1}, {2, 3, 4, 5}}),    true);
+TEST (1, [2][d(2)],   Init ({{1, 2}, {3, 4, 5}}),    true);
+TEST (1, [2][d(2)],   Init ({{1, 2, 3}, {4, 5}}),    true);
+TEST (1, [2][d(2)],   Init ({{1, 2, 3}, {4, 5, 6}}), true);
+
+TEST (1, [2][d(3)],   Init (),                          false);
+TEST (1, [2][d(3)],   Init ({{1}}),                     false);
+TEST (1, [2][d(3)],   Init ({{1, 2}}),                  false);
+TEST (1, [2][d(3)],   Init ({{1, 2}, {3}}),             false);
+TEST (1, [2][d(3)],   Init ({{1, 2}, {3, 4}}),          false);
+TEST (1, [2][d(3)],   Init ({{1}, {2, 3, 4}}),          false);
+TEST (1, [2][d(3)],   Init ({{1}, {2, 3, 4, 5}}),       true);
+TEST (1, [2][d(3)],   Init ({{1, 2}, {3, 4, 5}}),       false);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3}, {4, 5}}),       false);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3}, {4, 5, 6}}),    false);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3}, {4, 5, 6, 7}}), true);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3, 4}, {5, 6, 7}}), true);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3, 4, 5}, {6, 7}}), true);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3, 4, 5, 6}, {7}}), true);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3, 4, 5, 6, 7}}),   true);
+
+#if TEST_NEAR_VLA_MAX_SIZE
+TEST (1, [1][d(MAX)], Init (),                 false);
+#  if !BUG_58646
+// The following causes an ICE due to c++/58646.
+TEST (1, [1][d(MAX)], Init ({}),               false);
+#  endif
+TEST (1, [1][d(MAX)], Init ({{1}}),            false);
+TEST (1, [1][d(MAX)], Init ({{1, 2}}),         false);
+TEST (1, [1][d(MAX)], Init ({{1, 2, 3}}),      false);
+TEST (1, [1][d(MAX)], Init ({{1, 2, 3, 4}}),   false);
+
+TEST (1, [2][d(MAX / 2)], Init (),                       false);
+TEST (1, [2][d(MAX / 2)], Init ({{1}}),                  false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2}}),               false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}}),            false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3, 4}}),         false);
+TEST (1, [2][d(MAX / 2)], Init ({{1}, {2}}),             false);
+TEST (1, [2][d(MAX / 2)], Init ({{1}, {2, 3}}),          false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2}, {3}}),          false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2}, {3, 4}}),       false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}, {4}}),       false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5}}),    false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5, 6}}), false);
+#endif   // TEST_NEAR_VLA_MAX_SIZE
+
+// Excessively large two dimensional VLAs.
+TEST (1, [1][d(LONG_MIN)],  Init (),       true);
+TEST (1, [1][d(INT_MIN)],   Init (),       true);
+TEST (1, [1][d(-1)],        Init (),       true);
+
+TEST (1, [1][d(SIZE_MAX)],  Init (),       true);
+
+#if !BUG_58646
+// The following cause an ICE due to c++/58646.
+TEST (1, [1][d(LONG_MIN)],  Init ({}),     true);
+TEST (1, [1][d(INT_MIN)],   Init ({}),     true);
+TEST (1, [1][d(-1)],        Init ({}),     true);
+TEST (1, [1][d(SIZE_MAX)],  Init ({}),     true);
+#endif
+
+TEST (1, [1][d(LONG_MIN)],  Init ({{0}}),  true);
+TEST (1, [1][d(INT_MIN)],   Init ({{0}}),  true);
+TEST (1, [1][d(-1)],        Init ({{0}}),  true);
+TEST (1, [1][d(SIZE_MAX)],  Init ({{0}}),  true);
+
+TEST (1, [d(LONG_MIN)][1],  Init (),       true);
+TEST (1, [d(INT_MIN)][1],   Init (),       true);
+TEST (1, [d(-1)][1],        Init (),       true);
+TEST (1, [d(SIZE_MAX)][1],  Init (),       true);
+
+TEST (1, [d(LONG_MIN)][1],  Init ({}),     true);
+TEST (1, [d(INT_MIN)][1],   Init ({}),     true);
+TEST (1, [d(-1)][1],        Init ({}),     true);
+TEST (1, [d(SIZE_MAX)][1],  Init ({}),     true);
+
+TEST (1, [d(LONG_MIN)][1],  Init ({{0}}),  true);
+TEST (1, [d(INT_MIN)][1],   Init ({{0}}),  true);
+TEST (1, [d(-1)][1],        Init ({{0}}),  true);
+TEST (1, [d(SIZE_MAX)][1],  Init ({{0}}),  true);
+
+// Two dimensional VLAs with no constant bound.
+TEST (1, [d(0)][d(0)],   Init (),          true);
+TEST (1, [d(0)][d(0)],   Init ({}),        true);
+#if !BUG_58646
+// The following cause an ICE due to c++/58646.
+TEST (1, [d(0)][d(0)],   Init ({{}}),      true);
+TEST (1, [d(0)][d(0)],   Init ({{}, {}}),  true);
+#endif
+
+TEST (1, [d(0)][d(0)],   Init ({{1}}),     true);
+TEST (1, [d(0)][d(0)],   Init ({{1, 2}}),  true);
+#if !BUG_58646
+TEST (1, [d(0)][d(0)],   Init ({{1}, {}}), true);
+TEST (1, [d(0)][d(0)],   Init ({{}, {1}}), true);
+#endif
+
+TEST (1, [d(1)][d(0)],   Init (),          true);
+TEST (1, [d(1)][d(0)],   Init ({}),        true);
+TEST (1, [d(1)][d(0)],   Init ({{1}}),     true);
+
+TEST (1, [d(1)][d(1)],   Init (),             false);
+TEST (1, [d(1)][d(1)],   Init ({{1}}),        false);
+TEST (1, [d(1)][d(1)],   Init ({{1, 2}}),     true);
+
+TEST (1, [d(1)][d(2)],   Init (),             false);
+TEST (1, [d(1)][d(2)],   Init ({{1}}),        false);
+TEST (1, [d(1)][d(2)],   Init ({{1, 2}}),     false);
+TEST (1, [d(1)][d(2)],   Init ({{1, 2, 3}}),  true);
+
+TEST (1, [d(2)][d(1)],   Init (),                 false);
+TEST (1, [d(2)][d(1)],   Init ({{1}}),            false);
+TEST (1, [d(2)][d(1)],   Init ({{1}, {2}}),       false);
+TEST (1, [d(2)][d(1)],   Init ({{1, 2}}),         true);
+TEST (1, [d(2)][d(1)],   Init ({{1}, {2, 3}}),    true);
+TEST (1, [d(2)][d(1)],   Init ({{1, 2, 3}}),      true);
+TEST (1, [d(2)][d(1)],   Init ({{1, 2, 3}, {4}}), true);
+TEST (1, [d(2)][d(1)],   Init ({{1, 2}, {3, 4}}), true);
+
+TEST (1, [d(2)][d(2)],   Init (),                       false);
+TEST (1, [d(2)][d(2)],   Init ({{1}}),                  false);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2}}),               false);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2}, {3}}),          false);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2}, {3, 4}}),       false);
+TEST (1, [d(2)][d(2)],   Init ({{1}, {2, 3, 4}}),       true);
+TEST (1, [d(2)][d(2)],   Init ({{1}, {2, 3, 4, 5}}),    true);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2}, {3, 4, 5}}),    true);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2, 3}, {4, 5}}),    true);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2, 3}, {4, 5, 6}}), true);
+
+TEST (1, [d(2)][d(3)],   Init (),                          false);
+TEST (1, [d(2)][d(3)],   Init ({{1}}),                     false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2}}),                  false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2}, {3}}),             false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2}, {3, 4}}),          false);
+TEST (1, [d(2)][d(3)],   Init ({{1}, {2, 3, 4}}),          false);
+TEST (1, [d(2)][d(3)],   Init ({{1}, {2, 3, 4, 5}}),       true);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2}, {3, 4, 5}}),       false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3}, {4, 5}}),       false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3}, {4, 5, 6}}),    false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3}, {4, 5, 6, 7}}), true);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3, 4}, {5, 6, 7}}), true);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3, 4, 5}, {6, 7}}), true);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3, 4, 5, 6}, {7}}), true);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3, 4, 5, 6, 7}}),   true);
+
+#if TEST_NEAR_VLA_MAX_SIZE
+TEST (1, [d(1)][d(MAX)], Init (),                              false);
+TEST (1, [d(1)][d(MAX)], Init ({}),                            false);
+TEST (1, [d(1)][d(MAX)], Init ({{1}}),                         false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2}}),                      false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3}}),                   false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4}}),                false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5}}),             false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6}}),          false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6, 7}}),       false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6, 7, 8}}),    false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6, 7, 8, 9}}), false);
+
+TEST (1, [d(2)][d(MAX / 2)], Init (),                              false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1}}),                         false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2}}),                      false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}}),                   false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4}}),                false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5}}),             false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6}}),          false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6, 7}}),       false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6, 7, 8}}),    false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6, 7, 8, 9}}), false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1}, {2}}),                    false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1}, {2, 3}}),                 false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2}, {3}}),                 false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2}, {3, 4}}),              false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}, {4}}),              false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5}}),           false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5, 6}}),        false);
+#endif
+
+TEST (1, [d(2)][d(MAX)],        Init (),                         true);
+TEST (1, [d(2)][d(MAX)],        Init ({{1}}),                    true);
+TEST (1, [d(MAX)][d(MAX)],      Init ({{1, 2}}),                 true);
+TEST (1, [d(0)][d(MAX)],        Init ({{1}, {2}}),               true);
+TEST (1, [d(INT_MAX)][d(MAX)],  Init ({{1}, {2, 3}}),            true);
+TEST (1, [d(SIZE_MAX)][d(MAX)], Init ({{1, 2}, {3, 4}, {5}}),    true);
+
+// Erroneous two-dimensional VLAs with size exceeding SIZE_MAX / 2
+// (those must be rejected because no object can be bigger than that,
+// otherwise pointer arithmetic breaks).
+TEST ( 1, [2][d(SIZE_MAX/2)],  Init (), true);
+TEST ( 2, [2][d(SIZE_MAX/4)],  Init (), true);
+TEST ( 4, [2][d(SIZE_MAX/8)],  Init (), true);
+TEST ( 8, [2][d(SIZE_MAX/16)], Init (), true);
+TEST (16, [2][d(SIZE_MAX/32)], Init (), true);
+
+TEST ( 1, [d(SIZE_MAX/2)][2],  Init (), true);
+TEST ( 2, [d(SIZE_MAX/4)][2],  Init (), true);
+TEST ( 4, [d(SIZE_MAX/8)][2],  Init (), true);
+TEST ( 8, [d(SIZE_MAX/16)][2], Init (), true);
+TEST (16, [d(SIZE_MAX/32)][2], Init (), true);
+
+// Verify that the unspecified bound is factored into the computation
+// of the total size.
+TEST ( 1, [][d(SIZE_MAX/2)],  Init ({{1}, {2}}),      true);
+TEST ( 2, [][d(SIZE_MAX/4)],  Init ({{1}, {2}}),      true);
+TEST ( 4, [][d(SIZE_MAX/8)],  Init ({{1}, {2}}),      true);
+TEST ( 8, [][d(SIZE_MAX/16)], Init ({{1}, {2}}),      true);
+TEST (16, [][d(SIZE_MAX/32)], Init ({{1}, {2}}),      true);
+TEST (16, [][d(SIZE_MAX/64)], Init ({{1}, {2}, {3}}), true);
+
+// Three dimensional VLAs with two constant bounds.
+
+TEST (1, [1][1][d(-1)], Init (),                    true);
+TEST (1, [1][1][d(0)], Init (),                     true);
+
+#if !BUG_58646
+// The following causes an ICE due to c++/58646.
+TEST (1, [1][1][d(0)],  Init ({}),                   true);
+TEST (1, [1][1][d(-1)], Init ({{}}),                 true);
+TEST (1, [1][d(-1)][1], Init ({{}}),                 true);
+TEST (1, [d(-1)][1][1], Init ({{}}),                 true);
+
+TEST (1, [1][1][d(0)], Init ({{}}),                  true);
+TEST (1, [1][d(0)][1], Init ({{}}),                  true);
+TEST (1, [d(0)][1][1], Init ({{}}),                  true);
+#endif
+
+TEST (1, [1][1][d(1)], Init (),                      false);
+
+#if !BUG_58646
+TEST (1, [1][1][d(1)], Init ({{}}),                  false);
+TEST (1, [1][1][d(1)], Init ({{{}}}),                false);
+TEST (1, [1][1][d(1)], Init ({{{1}}}),               false);
+#endif
+
+TEST (1, [1][1][d(1)], Init ({{{1, 2}}}),            true);
+TEST (1, [1][1][d(1)], Init ({{{1, 2, 3}}}),         true);
+
+TEST (1, [1][d(1)][1], Init (),                      false);
+
+#if !BUG_58646
+TEST (1, [1][d(1)][1], Init ({{}}),                  false);
+TEST (1, [1][d(1)][1], Init ({{{}}}),                false);
+#endif
+
+TEST (1, [1][d(1)][1], Init ({{{1}}}),               false);
+TEST (1, [1][d(1)][1], Init ({{{1}, {2}}}),          true);
+TEST (1, [1][d(1)][1], Init ({{{1}, {2}, {3}}}),     true);
+
+TEST (1, [d(1)][1][1], Init (),                      false);
+
+#if !BUG_58646
+TEST (1, [d(1)][1][1], Init ({{}}),                  false);
+TEST (1, [d(1)][1][1], Init ({{{}}}),                false);
+#endif
+
+TEST (1, [d(1)][1][1], Init ({{{1}}}),               false);
+TEST (1, [d(1)][1][1], Init ({{{1}}, {{2}}}),        true);
+TEST (1, [d(1)][1][1], Init ({{{1}}, {{2}}, {{3}}}), true);
+
+TEST (1, [1][1][d(2)], Init (),                      false);
+
+#if !BUG_58646
+TEST (1, [1][1][d(2)], Init ({{}}),                  false);
+TEST (1, [1][1][d(2)], Init ({{{}}}),                false);
+#endif
+
+TEST (1, [1][1][d(2)], Init ({{{1}}}),               false);
+TEST (1, [1][1][d(2)], Init ({{{1, 2}}}),            false);
+TEST (1, [1][1][d(2)], Init ({{{1, 2, 3}}}),         true);
+
+TEST (1, [1][d(2)][1], Init (),                      false);
+
+#if !BUG_58646
+TEST (1, [1][d(2)][1], Init ({{}}),                  false);
+TEST (1, [1][d(2)][1], Init ({{{}}}),                false);
+#endif
+TEST (1, [1][d(2)][1], Init ({{{1}}}),               false);
+TEST (1, [1][d(2)][1], Init ({{{1}, {2}}}),          false);
+TEST (1, [1][d(2)][1], Init ({{{1}, {2}, {3}}}),     true);
+
+TEST (1, [d(2)][1][1], Init (),                      false);
+
+#if !BUG_58646
+TEST (1, [d(2)][1][1], Init ({{}}),                  false);
+TEST (1, [d(2)][1][1], Init ({{{}}}),                false);
+#endif
+TEST (1, [d(2)][1][1], Init ({{{1}}}),               false);
+TEST (1, [d(2)][1][1], Init ({{{1}}, {{2}}}),        false);
+TEST (1, [d(2)][1][1], Init ({{{1}}, {{2}}, {{3}}}), true);
+
+TEST (1, [1][2][d(2)], Init (),                      false);
+
+#if !BUG_58646
+TEST (1, [1][2][d(2)], Init ({{}}),                  false);
+TEST (1, [1][2][d(2)], Init ({{{}}}),                false);
+#endif
+
+TEST (1, [1][2][d(2)], Init ({{{1}}}),               false);
+TEST (1, [1][2][d(2)], Init ({{{1, 2}}}),            false);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3}}}),         true);
+
+TEST (1, [1][2][d(2)], Init ({{{1}, {2}}}),          false);
+TEST (1, [1][2][d(2)], Init ({{{1}, {2, 3}}}),       false);
+TEST (1, [1][2][d(2)], Init ({{{1, 2}, {3}}}),       false);
+TEST (1, [1][2][d(2)], Init ({{{1, 2}, {3, 4}}}),    false);
+TEST (1, [1][2][d(2)], Init ({{{1}, {2, 3, 4}}}),    true);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3}, {}}}),     true);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3}, {4}}}),    true);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3, 4}}}),      true);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3, 4}, {}}}),  true);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3, 4}, {5}}}), true);
+
+TEST (1, [2][2][d(2)], Init ({{{1}, {2}}}),                         false);
+TEST (1, [2][2][d(2)], Init ({{{1}, {2, 3}}}),                      false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}}}),                           false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3}}}),                      false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}}),                   false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5}}}),            false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}}}),         false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7}}}),    false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}), false);
+
+TEST (1, [2][2][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3}, {}}}),                       true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3}, {4}}}),                      true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3, 4}}}),                        true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3, 4}, {}}}),                    true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3, 4}, {5}}}),                   true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8, 9}}}), true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6, 7}, {8, 9}}}), true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4, 5}}, {{6, 7}, {8, 9}}}), true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3}, {4, 5}}, {{6, 7}, {8, 9}}}), true);
+TEST (1, [2][2][d(2)], Init ({{{1}, {2}}, {{3}, {4, 5, 6}}}),          true);
+TEST (1, [2][2][d(2)], Init ({{{1}}, {{2}, {3, 4, 5, 6}}}),            true);
+
+// Three dimensional VLAs with one constant bound.
+TEST (1, [2][d(-1)][d(-1)], Init (),                                      true);
+TEST (1, [2][d(-1)][d(0)],  Init (),                                      true);
+TEST (1, [2][d(0)][d(-1)],  Init (),                                      true);
+TEST (1, [2][d(1)][d(-1)],  Init (),                                      true);
+TEST (1, [2][d(1)][d(0)],   Init (),                                      true);
+TEST (1, [2][d(-1)][d(1)],  Init (),                                      true);
+TEST (1, [2][d(0)][d(1)],   Init (),                                      true);
+
+TEST (1, [2][d(2)][d(2)], Init (),                                        false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}}}),                                 false);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1}}}),                                 false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2}}}),                            false);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1}, {2}}}),                            false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3}}}),                         false);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1}, {2, 3}}}),                         false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3}}}),                         false);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2}, {3}}}),                         false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}}),                      false);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}}),                      false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}),    false);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}),    false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {}}}),                       true);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3}, {}}}),                       true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {4}}}),                      true);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3}, {4}}}),                      true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}}}),                        true);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3, 4}}}),                        true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {}}}),                    true);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {}}}),                    true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {5}}}),                   true);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {5}}}),                   true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3}, {4}}}),                    true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {}}}),                       true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {4}}}),                      true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}}}),                        true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {}}}),                    true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {5}}}),                   true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8, 9}}}), true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6, 7}, {8, 9}}}), true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4, 5}}, {{6, 7}, {8, 9}}}), true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {4, 5}}, {{6, 7}, {8, 9}}}), true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2}}, {{3}, {4, 5, 6}}}),          true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}}, {{2}, {3, 4, 5, 6}}}),            true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2}, {3}}}),                       true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3}, {4}}}),                    true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3, 4}, {5}}}),                 true);
+
+#if TEST_NEAR_VLA_MAX_SIZE
+// Very large but not erroneous three-dimensional VLAs.
+TEST ( 1, [2][d(1)][d(MAX/2)], Init (),  false);
+TEST ( 2, [2][d(1)][d(MAX/4)], Init (),  false);
+TEST ( 4, [2][d(1)][d(MAX/8)], Init (),  false);
+TEST ( 8, [2][d(1)][d(MAX/16)], Init (), false);
+TEST (16, [2][d(1)][d(MAX/32)], Init (), false);
+
+TEST ( 1, [2][d(MAX/2)][d(1)], Init (),  false);
+TEST ( 2, [2][d(MAX/4)][d(1)], Init (),  false);
+TEST ( 4, [2][d(MAX/8)][d(1)], Init (),  false);
+TEST ( 8, [2][d(MAX/16)][d(1)], Init (), false);
+TEST (16, [2][d(MAX/32)][d(1)], Init (), false);
+
+TEST ( 1, [d(MAX/2)][2][d(1)], Init (),  false);
+TEST ( 2, [d(MAX/4)][2][d(1)], Init (),  false);
+TEST ( 4, [d(MAX/8)][2][d(1)], Init (),  false);
+TEST ( 8, [d(MAX/16)][2][d(1)], Init (), false);
+TEST (16, [d(MAX/32)][2][d(1)], Init (), false);
+#endif   // TEST_NEAR_VLA_MAX_SIZE
+
+// Erroneous three-dimensional VLAs with size exceeding SIZE_MAX / 2
+// (those must be rejected because no object can be bigger than that,
+// otherwise pointer arithmetic breaks).
+TEST ( 1, [2][d(1)][d(SIZE_MAX/2)],  Init (), true);
+TEST ( 2, [2][d(1)][d(SIZE_MAX/4)],  Init (), true);
+TEST ( 4, [2][d(1)][d(SIZE_MAX/8)],  Init (), true);
+TEST ( 8, [2][d(1)][d(SIZE_MAX/16)], Init (), true);
+TEST (16, [2][d(1)][d(SIZE_MAX/32)], Init (), true);
+
+TEST ( 1, [2][d(SIZE_MAX/2)][d(1)],  Init (), true);
+TEST ( 2, [2][d(SIZE_MAX/4)][d(1)],  Init (), true);
+TEST ( 4, [2][d(SIZE_MAX/8)][d(1)],  Init (), true);
+TEST ( 8, [2][d(SIZE_MAX/16)][d(1)], Init (), true);
+TEST (16, [2][d(SIZE_MAX/32)][d(1)], Init (), true);
+
+TEST ( 1, [d(SIZE_MAX/2)][2][d(1)],  Init (), true);
+TEST ( 2, [d(SIZE_MAX/4)][2][d(1)],  Init (), true);
+TEST ( 4, [d(SIZE_MAX/8)][2][d(1)],  Init (), true);
+TEST ( 8, [d(SIZE_MAX/16)][2][d(1)], Init (), true);
+TEST (16, [d(SIZE_MAX/32)][2][d(1)], Init (), true);
+
+TEST (16, [3][d(SIZE_MAX)][d(SIZE_MAX)], Init (), true);
+TEST (32, [d(SIZE_MAX)][5][d(SIZE_MAX)], Init (), true);
+TEST (64, [d(SIZE_MAX)][d(SIZE_MAX)][7], Init (), true);
+
+int main ()
+{
+  if (fail)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla12.C b/gcc/testsuite/g++.dg/cpp1y/vla12.C
new file mode 100644
index 0000000..a8db578
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla12.C
@@ -0,0 +1,69 @@
+// Test to verify that variable length arrays whose size overflows
+// or exceeds the implementation-defined limit is diagnosed.
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-Wno-error=vla" }
+
+#define INT_MAX    __INT_MAX__
+#define LONG_MAX   __LONG_MAX__
+#define SIZE_MAX   __SIZE_MAX__
+
+typedef __SIZE_TYPE__ size_t;
+
+void test (int x, int y, int z)
+{
+  const size_t amax = SIZE_MAX / 2;
+
+  {
+    char a [x][amax];         // { dg-warning "forbids|size of variable length array exceeds maximum" }
+    (void)a;
+  }
+
+  {
+    char a [amax][y];         // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    char a [x][y][amax];      // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    char a [x][amax][z];      // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    char a [amax][y][z];      // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    // Unfortunately, this is rejected with a different error earlier
+    // during parsing and before the VLA checking gets to see it:
+    //   error: size of array ‘a’ is too large
+    char a [x][amax][amax];   // { dg-error "size of array" }
+
+    // That error above also leads to the following error when using
+    // the variable below.
+    //   error:’ was not declared in this scope
+    // (void)a;
+  }
+
+  {
+    char a [amax][y][amax];   // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    char a [amax][amax][z];   // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    struct A256 { __attribute__ ((aligned (256))) char a; };
+
+    A256 a [x][1024][y][1024][z][1024][x][1024][z];   // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla13.C b/gcc/testsuite/g++.dg/cpp1y/vla13.C
new file mode 100644
index 0000000..7ddf893
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla13.C
@@ -0,0 +1,250 @@
+// PR c++/70019 - VLA size overflow not detected
+// Runtime test to verify that attempting to initialize a VLA with a string
+// or character array that's longer than the non-constant (runtime) bound
+// of the VLA causes an exception to be thrown.  For a compile-time version
+// of the test see vla14.C.
+
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-Wno-vla" }
+
+#pragma GCC diagnostic ignored "-Wvla"
+
+#define SIZE_MAX   __SIZE_MAX__
+
+// The size of the largest allowed VLA in bytes.  Bigger objects
+// cause an exception to be thrown.  Unless the maximum size is
+// obscenely large, smaller objects should be successfully created
+// provided there's enough stack space.  See TEST_NEAR_VLA_MAX_SIZE
+// below.
+#define MAX   (__SIZE_MAX__ / 2)
+
+// Define to non-zero to exercise very large VLAs with size just
+// below the implementation-defined maximum.
+#define TEST_NEAR_VLA_MAX_SIZE    0
+
+// Define to zero to enable tests that cause an ICE due to c++/58646.
+#define BUG_58646 1
+
+// Define to zero to enable tests that cause an ICE due to c++/69487.
+#define BUG_69487 1
+
+// Helper macro to make it possible to pass as one multpile arguments
+// to another macro.
+#define Init(...) __VA_ARGS__
+
+typedef __SIZE_TYPE__ size_t;
+
+// Incremented for each test failure.
+int fail;
+
+// Used to convert a constant array dimension to a non-constant one.
+template <class T>
+T d (T n)
+{
+  return n;
+}
+
+// Verify either that an expected exception has been thrown or that
+// one hasn't been thrown if one isn't expected.
+int __attribute__ ((noclone, noinline))
+sink (void *p, int line, bool expect, const char *expr)
+{
+  if (!p != expect)
+    {
+      __builtin_printf ("line %i: Assertion failed: '%s': "
+                        "exception unexpectedly %sthrown\n",
+                        line, expr, !p ? "" : "not ");
+      ++fail;
+    }
+  else
+    {
+#if defined DEBUG && DEBUG
+    __builtin_printf ("line %i: Assertion passed: '%s': "
+		      "exception %sthrown as expected\n",
+		      line, expr, !p ? "" : "not ");
+#endif
+    }
+  return 0;
+}
+
+template <class T, int>
+int test ();
+
+#define _CAT(name, line) name ## line
+#define CAT(name, line) _CAT (name, line)
+
+#define STR(...) #__VA_ARGS__
+
+// Macro to define a unique specialization of a function template to
+// exercise a VLA of type T, rank N, with dimensions given by Dims
+// and initializer Init.  Expect is true when the VLA initialization
+// is expected to trigger an exception.
+// The macro creates a unique global dummy int object and initializes
+// it with the result of the function.  The dummy object servers no
+// other purpose but to call the function.  The function verifies
+// the expected postconditions.
+#define TEST(T, Dims, Init, Expect)                                     \
+  template <>                                                           \
+  int test<T, __LINE__>()                                               \
+  {                                                                     \
+    const char str[] = "char a" #Dims " = { " STR (Init) " }";          \
+    try {                                                               \
+      T a Dims = { Init };                                              \
+      return sink (a, __LINE__, Expect, str);                           \
+    }                                                                   \
+    catch (...) {                                                       \
+      return sink (0, __LINE__, Expect, str);                           \
+    }                                                                   \
+  }                                                                     \
+  const int CAT (dummy, __LINE__) = test<T, __LINE__>()
+
+
+// Create and run a test function exercising a VLA definition
+//    +-- Element Type
+//    |     +-- VLA Dimensions
+//    |     |        +-- VLA Initializer
+//    |     |        |
+//    |     |        |             +-- Expect Exception
+//    |     |        |             |
+//    V     V        V             V
+TEST (char, [d(-1)], "",           true);
+TEST (char, [d(0)],  "",           true);
+TEST (char, [d(1)],  "",           false);
+TEST (char, [d(1)],  "1",          true);
+TEST (char, [d(1)],  "12",         true);
+TEST (char, [d(1)],  "1234567890", true);
+
+TEST (char, [d(2)], "",           false);
+TEST (char, [d(2)], "1",          false);
+TEST (char, [d(2)], "12",         true);
+TEST (char, [d(2)], "123",        true);
+TEST (char, [d(2)], "1234567890", true);
+
+TEST (char, [d(3)], "",           false);
+TEST (char, [d(3)], "1",          false);
+TEST (char, [d(3)], "12",         false);
+TEST (char, [d(3)], "123",        true);
+TEST (char, [d(3)], "1234",       true);
+TEST (char, [d(3)], "1234567890", true);
+
+#if TEST_NEAR_VLA_MAX_SIZE
+
+#  if !BUG_69487
+// The following crash due to c++/69487.
+TEST (char, [d(MAX)], "",           false);
+TEST (char, [d(MAX)], "1",          false);
+TEST (char, [d(MAX)], "12",         false);
+TEST (char, [d(MAX)], "1234567890", false);
+#  endif
+
+TEST (char, [d(MAX)], Init (),                             false);
+TEST (char, [d(MAX)], Init (1),                            false);
+TEST (char, [d(MAX)], Init (1, 2),                         false);
+TEST (char, [d(MAX)], Init (1, 2, 3, 4, 5, 6, 7, 8, 9, 0), false);
+#endif
+
+TEST (char, [d(SIZE_MAX / 2 + 1)], "", true);
+TEST (char, [d(SIZE_MAX - 2)],     "", true);
+TEST (char, [d(SIZE_MAX - 1)],     "", true);
+
+TEST (wchar_t, [d(1)], L"",           false);
+TEST (wchar_t, [d(1)], L"1",          true);
+TEST (wchar_t, [d(1)], L"12",         true);
+TEST (wchar_t, [d(1)], L"1234567890", true);
+
+TEST (wchar_t, [d(2)], L"",           false);
+TEST (wchar_t, [d(2)], L"1",          false);
+TEST (wchar_t, [d(2)], L"12",         true);
+TEST (wchar_t, [d(2)], L"123",        true);
+TEST (wchar_t, [d(2)], L"1234567890", true);
+
+TEST (char, [d(1)][d(1)], Init (""),        false);
+TEST (char, [1]   [d(1)], Init (""),        false);
+TEST (char, [d(1)][1],    Init (""),        false);
+
+TEST (char, [d(1)][d(1)], Init ("1"),       true);
+
+// The following is accepted at compile time but throws an exception
+// at runtime since in C++ a one-element array cannot be initialized
+// with a string literal of length one because there isn't room for
+// the terminating NUL
+TEST (char, [1][d(1)],    Init ("1"),       true);
+
+// The following is rejected at compile-time since a one-element array
+// cannot be initialized with a string literal of length one because
+// there isn't room for the terminating NUL (see vla14.C).
+// TEST (char, [d(1)][1],    Init ("1"),       false);
+
+TEST (char, [d(1)][d(1)], Init ("12"),      true);
+TEST (char, [d(1)][d(1)], Init ("1", "2"),  true);
+TEST (char, [d(1)][d(1)], Init ("1", "23"), true);
+
+TEST (char, [d(2)][d(2)], Init ("", ""),    false);
+TEST (char, [d(2)][d(2)], Init ("", "1"),   false);
+TEST (char, [d(2)][d(2)], Init ("1", ""),   false);
+TEST (char, [d(2)][d(2)], Init ("1", "1"),  false);
+TEST (char, [2][d(2)],    Init ("",  "1"),  false);
+TEST (char, [2][d(2)],    Init ("1", ""),   false);
+TEST (char, [2][d(2)],    Init ("1", "1"),  false);
+TEST (char, [d(2)][2],    Init ("",  "1"),  false);
+TEST (char, [d(2)][2],    Init ("1", ""),   false);
+TEST (char, [d(2)][2],    Init ("1", "1"),  false);
+
+TEST (char, [2][d(2)],    Init ("1", "23"), true);
+TEST (char, [d(2)][d(2)], Init ("1", "23"), true);
+TEST (char, [d(2)][d(2)], Init ("1", "23"), true);
+TEST (char, [d(2)][d(2)], Init ("12","3"),  true);
+
+#if TEST_NEAR_VLA_MAX_SIZE
+#  if !BUG_69487
+   // The following crash due to c++/69487.
+TEST (char, [1][d(MAX)], Init (""),           false);
+TEST (char, [1][d(MAX)], Init ("1"),          false);
+TEST (char, [1][d(MAX)], Init ("12"),         false);
+TEST (char, [1][d(MAX)], Init ("1234567890"), false);
+#  endif
+
+#  if !BUG_58646
+// The following causes an ICE due to c++/58646.
+TEST (char, [1][d(MAX)], Init (),                               false);
+#  endif
+
+TEST (char, [1][d(MAX)], Init ({1}),                            false);
+TEST (char, [1][d(MAX)], Init ({1, 2}),                         false);
+TEST (char, [1][d(MAX)], Init ({1, 2, 3}),                      false);
+TEST (char, [1][d(MAX)], Init ({1, 2, 3, 4, 5, 6, 7, 8, 9, 0}), false);
+
+TEST (char, [d(MAX)][1], Init ({1}),                            false);
+TEST (char, [d(MAX)][1], Init ({1}, {2}),                       false);
+TEST (char, [d(MAX)][1], Init ({1}, {2}, {3}),                  false);
+TEST (char, [d(MAX)][1], Init ({1}, {2}, {3}, {4}, {5},
+			       {6}, {7}, {8}, {9}, {0}),        false);
+#endif   // TEST_NEAR_VLA_MAX_SIZE
+
+// The following are expected to throw due to excessive size.
+TEST (char, [2][d(MAX)], Init ({1}),                                 true);
+TEST (char, [2][d(MAX)], Init ({1, 2}),                              true);
+TEST (char, [2][d(MAX)], Init ({1}, {2}),                            true);
+TEST (char, [2][d(MAX)], Init ({1, 2}, {3, 4}),                      true);
+TEST (char, [2][d(MAX)], Init ({1, 2, 3}, {4, 5, 6}),                true);
+TEST (char, [2][d(MAX)], Init ({1, 2, 3, 4}, {5, 6, 7, 8}),          true);
+
+TEST (char, [d(MAX)][2], Init ({1}),                                 true);
+TEST (char, [d(MAX)][2], Init ({1, 2}),                              true);
+TEST (char, [d(MAX)][2], Init ({1}, {2}),                            true);
+TEST (char, [d(MAX)][2], Init ({1, 2}, {3, 4}),                      true);
+TEST (char, [d(MAX)][2], Init ({1, 2}, {3, 4}, {5, 6}),              true);
+TEST (char, [d(MAX)][2], Init ({1, 2}, {3, 4}, {5, 6}, {7, 8}),      true);
+
+TEST (char, [d(MAX)][d(MAX)], Init ({1}),                            true);
+TEST (char, [d(MAX)][d(MAX)], Init ({1, 2}),                         true);
+TEST (char, [d(MAX)][d(MAX)], Init ({1}, {2}),                       true);
+TEST (char, [d(MAX)][d(MAX)], Init ({1, 2}, {3, 4}),                 true);
+TEST (char, [d(MAX)][d(MAX)], Init ({1, 2}, {3, 4}, {5, 6}),         true);
+TEST (char, [d(MAX)][d(MAX)], Init ({1, 2}, {3, 4}, {5, 6}, {7, 8}), true);
+
+int main ()
+{
+  if (fail)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla14.C b/gcc/testsuite/g++.dg/cpp1y/vla14.C
new file mode 100644
index 0000000..4a0e827
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla14.C
@@ -0,0 +1,48 @@
+// PR c++/70019 - VLA size overflow not detected
+// Compile-time test to verify that attempting to initialize a VLA with
+// a string that's longer than the VLA's constant bound is diagnosed at
+// compile time.  For a runtime version of the test see vla13.C.
+
+// { dg-do run }
+// { dg-additional-options "-Wno-vla" }
+
+
+void test (int n)
+{
+  char a1[n][1] = { { "a" } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a1;
+
+  char a2[1][n] = { { "a" } };
+  (void)a2;
+
+  char a3[n][1][1] = { { { "a" } } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a3;
+
+  char a4[1][1][n] = { { { "a" } } };
+  (void)a4;
+
+  char a5[1][n][1] = { { { "a" } } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a5;
+
+  char a6[n][1][n] = { { { "a" } } };
+  (void)a6;
+
+
+  wchar_t a7[n][1] = { { L"a" } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a7;
+
+  wchar_t a8[1][n] = { { L"a" } };
+  (void)a8;
+
+  wchar_t a9[n][1][1] = { { { L"a" } } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a9;
+
+  wchar_t a10[1][1][n] = { { { L"a" } } };
+  (void)a10;
+
+  wchar_t a11[][n][1] = { { { L"a" } } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a11;
+
+  wchar_t a12[n][1][n] = { { { L"a" } } };
+  (void)a12;
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla3.C b/gcc/testsuite/g++.dg/cpp1y/vla3.C
new file mode 100644
index 0000000..9b2d6b3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla3.C
@@ -0,0 +1,43 @@
+// Test for throwing bad_array_length on invalid array length.
+// { dg-do run { target c++14 } }
+// { dg-additional-options "-Wno-vla" }
+
+namespace std
+{
+struct exception
+{
+  virtual ~exception ();
+  virtual const char* what () const throw ();
+};
+}
+
+int f(int i)
+{
+  int ar[i]{1,2,3,4};
+  return ar[i-1];
+}
+
+void g(int i)
+{
+  int ar[i];
+  ar[0] = 42;
+}
+
+int main()
+{
+  int ok = 0;
+  f(4);				// OK
+  try {
+    f(3);			// too small
+  }
+  catch (std::exception &e) {
+    ++ok;
+  }
+  try { g(-24); }		// negative
+  catch (std::exception &e) {
+    ++ok;
+  }
+
+  if (ok != 2)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/init/array24.C b/gcc/testsuite/g++.dg/init/array24.C
index 2d72df4..fc10c0a 100644
--- a/gcc/testsuite/g++.dg/init/array24.C
+++ b/gcc/testsuite/g++.dg/init/array24.C
@@ -3,5 +3,5 @@
 
 void foo(int i)
 {
-  int x[][i] = { 0 };
+  int x[][i] = { { 0 } };
 }
diff --git a/gcc/testsuite/g++.dg/ubsan/vla-1.C b/gcc/testsuite/g++.dg/ubsan/vla-1.C
index 311cdb1..374c80a 100644
--- a/gcc/testsuite/g++.dg/ubsan/vla-1.C
+++ b/gcc/testsuite/g++.dg/ubsan/vla-1.C
@@ -1,5 +1,8 @@
 // { dg-do run }
-// { dg-options "-Wno-vla -fsanitize=undefined" }
+// Disable exceptions to prevent the erroneous initializer from
+// throwing before the sanitizer instrumentation has detected
+// the problem.
+// { dg-options "-Wno-vla -fno-exceptions -fsanitize=undefined" }
 // { dg-output "index 1 out of bounds" }
 
 void f(int i) {
diff --git a/libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc b/libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc
index d9d1f2a..f944236 100644
--- a/libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc
@@ -44,7 +44,8 @@ template<typename Con>
   {
     bool test __attribute__((unused)) = true;
 
-    rvalstruct array[length];
+    /* Make sure the VLA upper bound is positive. */
+    rvalstruct array[length + 1];
     for(int i = 0; i < length; ++i)
       array[i] = i;
     Con con(array, array + length);

[-- Attachment #3: gcc-69517-alt.patch --]
[-- Type: text/x-patch, Size: 18078 bytes --]

PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
PR c++/70019 - VLA size overflow not detected

gcc/cp/ChangeLog:
2016-04-10  Martin Sebor  <msebor@redhat.com>

	PR c++/69517
	PR c++/70019
	* cp-tree.h (throw_bad_array_length, build_vla_check): Declare new
	functions.
	* decl.c (check_initializer, cp_finish_decl): Call them.
	(reshape_init_r): Reject incompletely braced intializer-lists
	for VLAs.
	* init.c (throw_bad_array_length, build_vla_check)
	(build_vla_size_check, build_vla_init_check): Define new functions.
	* typeck2.c (split_nonconstant_init_1): Use variably_modified_type_p()
	to detect a VLA.
	(store_init_value): Same.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b7b770f..1d726fd 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5978,6 +5978,7 @@ extern tree build_value_init_noctor		(tree, tsubst_flags_t);
 extern tree get_nsdmi				(tree, bool);
 extern tree build_offset_ref			(tree, tree, bool,
 						 tsubst_flags_t);
+extern tree throw_bad_array_length              (void);
 extern tree throw_bad_array_new_length		(void);
 extern tree build_new				(vec<tree, va_gc> **, tree, tree,
 						 vec<tree, va_gc> **, int,
@@ -5999,6 +6000,7 @@ extern tree scalar_constant_value		(tree);
 extern tree decl_really_constant_value		(tree);
 extern int diagnose_uninitialized_cst_or_ref_member (tree, bool, bool);
 extern tree build_vtbl_address                  (tree);
+extern tree build_vla_check                     (tree, tree = NULL_TREE);
 
 /* in lex.c */
 extern void cxx_dup_lang_specific_decl		(tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 9260f4c..c5ec0da 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5864,6 +5864,16 @@ reshape_init_r (tree type, reshape_iter *d, bool first_initializer_p,
 	    }
 	}
 
+      if (variably_modified_type_p (type, NULL_TREE))
+	{
+	  /* Require VLAs to have their initializers fully braced
+	     to avoid initializing the wrong elements.  */
+	  if (complain & tf_error)
+	    error ("missing braces around initializer for a variable length "
+		   "array %qT", type);
+	  return error_mark_node;
+	}
+
       warning (OPT_Wmissing_braces, "missing braces around initializer for %qT",
 	       type);
     }
@@ -6167,6 +6177,34 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
 	      && PAREN_STRING_LITERAL_P (DECL_INITIAL (decl)))
 	    warning (0, "array %qD initialized by parenthesized string literal %qE",
 		     decl, DECL_INITIAL (decl));
+
+	  if (TREE_CODE (type) == ARRAY_TYPE
+	      && variably_modified_type_p (type, NULL_TREE)
+	      && !processing_template_decl)
+	    {
+	      /* Statically check for overflow in VLA bounds and build
+		 an expression that checks at runtime whether the VLA
+		 is erroneous due to invalid (runtime) bounds.
+		 Another expression to check for excess initializers
+		 is built in build_vec_init.  */
+	      tree check = build_vla_check (TREE_TYPE (decl), init);
+
+	      if (flag_exceptions && current_function_decl
+		  /* Avoid instrumenting constexpr functions for now.
+		     Those must be checked statically, and the (non-
+		     constexpr) dynamic instrumentation would cause
+		     them to be rejected.  See c++/70507.  */
+		  && !DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+		{
+		  /* Use the runtime check only when exceptions are enabled.
+		     Otherwise let bad things happen...  */
+		  check = build3 (COND_EXPR, void_type_node, check,
+				  throw_bad_array_length (), void_node);
+
+		  finish_expr_stmt (check);
+		}
+	    }
+
 	  init = NULL;
 	}
     }
@@ -6809,6 +6847,36 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 	  cleanups = make_tree_vector ();
 	  init = check_initializer (decl, init, flags, &cleanups);
 
+	  if (TREE_CODE (type) == ARRAY_TYPE
+	      && variably_modified_type_p (type, NULL_TREE)
+	      && !processing_template_decl
+	      && !init)
+	    {
+	      /* Statically check for overflow in VLA bounds and build
+		 an expression that checks whether the VLA is erroneous
+		 at runtime.  A runtime check for the bounds of
+		 initialized VLAs along with excess initializer
+		 elements is built in build_vec_init().  */
+	      tree check = build_vla_check (type);
+
+	      if (flag_exceptions
+		  && current_function_decl
+		  /* Avoid instrumenting constexpr functions.  Those must
+		     be checked statically for now since the (non-constexpr)
+		     dynamic instrumentation would cause them to be rejected
+		     due to c++/70507.  */
+		  && !DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+		{
+		  /* Use the runtime check only when exceptions are enabled.
+		     Otherwise let bad things happen (though perhaps emitting
+		     a trap would be appropriate).  */
+		  check = build3 (COND_EXPR, void_type_node, check,
+				  throw_bad_array_length (), void_node);
+
+		  finish_expr_stmt (check);
+		}
+	    }
+
 	  /* Handle:
 
 	     [dcl.init]
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 5997d53..ec19d72 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2262,6 +2262,20 @@ diagnose_uninitialized_cst_or_ref_member (tree type, bool using_new, bool compla
   return diagnose_uninitialized_cst_or_ref_member_1 (type, type, using_new, complain);
 }
 
+/* Call __cxa_throw_bad_array_length to indicate that the size calculation
+   in the bounds of a variable length array overflowed.  */
+
+tree
+throw_bad_array_length (void)
+{
+  tree fn = get_identifier ("__cxa_throw_bad_array_length");
+  if (!get_global_value_if_present (fn, &fn))
+    fn = push_throw_library_fn (fn, build_function_type_list (void_type_node,
+                                                             NULL_TREE));
+
+  return build_cxx_call (fn, 0, NULL, tf_warning_or_error);
+}
+
 /* Call __cxa_bad_array_new_length to indicate that the size calculation
    overflowed.  Pretend it returns sizetype so that it plays nicely in the
    COND_EXPR.  */
@@ -4709,3 +4723,304 @@ build_vec_delete (tree base, tree maxindex,
 
   return rval;
 }
+
+
+/* The implementation of build_vla_check() that recursively builds
+   an expression to determine whether the VLA TYPE is erroneous due
+   either to its bounds being invalid or to integer overflow in
+   the computation of its total size.
+   CHECK is the boolean expression being built, initialized to
+   boolean_false_node.
+   VLASIZE is used internally to pass the incrementally computed
+   size of the VLA object down to its recursive invocations.
+   MAX_VLASIZE is the maximum valid size of the VLA in bytes.
+   CST_SIZE is the product of the VLA's constant dimensions.  */
+
+static tree
+build_vla_size_check (tree check,
+		      tree type,
+		      tree vlasize,
+		      tree max_vlasize,
+		      offset_int *cst_size)
+{
+  tree vmul = builtin_decl_explicit (BUILT_IN_MUL_OVERFLOW);
+
+  tree vlasizeaddr = build_unary_op (input_location, ADDR_EXPR, vlasize, 0);
+
+  bool overflow = false;
+
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      /* Compute the upper bound of this array type.  */
+      tree inner_nelts = array_type_nelts_top (type);
+      tree inner_nelts_cst = maybe_constant_value (inner_nelts);
+
+      if (TREE_CODE (inner_nelts_cst) == INTEGER_CST)
+	{
+	  /* The upper bound is a constant expression.  Compute the product
+	     of the constant upper bounds seen so far so that overflow can
+	     be diagnosed.  */
+	  offset_int result = wi::mul (wi::to_offset (inner_nelts_cst),
+				       *cst_size, SIGNED, &overflow);
+	  *cst_size = overflow ? 0 : result;
+	}
+
+      /* Check for overflow in the VLAs (runtime) upper bounds.  */
+      tree vflowcheck = build_call_expr (vmul, 3, inner_nelts,
+					 vlasize, vlasizeaddr);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, vflowcheck);
+
+      /* Recursively check for overflow in the remaining major bounds.  */
+      check = build_vla_size_check (check, TREE_TYPE (type),
+				    vlasize, max_vlasize,
+				    cst_size);
+    }
+  else
+    {
+      /* Get the size of the VLA element type in bytes.  */
+      tree typesize = TYPE_SIZE_UNIT (type);
+
+      /* See if the size, when multipled by the product of the VLA's
+	 constant dimensions, is within range of size_t.  If not,
+	 the VLA is definitely erroneous amd must be diagnosed at
+	 compile time.  */
+      offset_int result = wi::mul (wi::to_offset (typesize), *cst_size,
+				   SIGNED, &overflow);
+      *cst_size = overflow ? 0 : result;
+
+      /* Multiply the (non-constant) VLA size so far by the element size,
+	 checking for overflow, and replacing the value of vlasize with
+	 the product in the absence of overflow.  This size is the total
+	 runtime size of the VLA in bytes.  */
+      tree vflowcheck = build_call_expr (vmul, 3, typesize,
+					 vlasize, vlasizeaddr);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, vflowcheck);
+
+      /* Check to see if the final VLA size exceeds the maximum.  */
+      tree sizecheck = fold_build2 (LT_EXPR, boolean_type_node,
+				    max_vlasize, vlasize);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, sizecheck);
+
+      /* Also check to see if the final array size is zero (the size
+	 is unsigned so the earlier overflow check detects negative
+	 values as well.  */
+      tree zerocheck = fold_build2 (EQ_EXPR, boolean_type_node,
+				    vlasize, size_zero_node);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, zerocheck);
+    }
+
+  /* Diagnose overflow determined at compile time.  */
+  if (overflow)
+    {
+      error ("integer overflow in variable array size");
+      /* Reset to suppress any further diagnostics.  */
+      *cst_size = 0;
+    }
+
+  return check;
+}
+
+/* The implementation of build_vla_check() that recursively builds
+   an expression to determine whether the VLA initializer-list for
+   TYPE is erroneous due to excess initializers.
+   CHECK is the boolean expression being built, initialized to
+   the result of build_vla_size_check().
+   INIT is the VLA initializer expression to check against TYPE.
+   On the first (non-recursive) call, INIT_ELTS is set either to 1,
+   or to the number of elements in the initializer-list for VLAs
+   of unspecified (major) bound.  On subsequent (recursive) calls.
+   it is set to NULL and computed from the number of elements in
+   the (nested) initializer-list.
+*/
+
+static tree
+build_vla_init_check (tree check, tree type, tree init, tree init_elts)
+{
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      /* Compute the upper bound of this array type unless it has
+	 already been computed by the caller for an array of unspecified
+	 bound, as in 'T a[];'  */
+      tree inner_nelts = init_elts ? init_elts : array_type_nelts_top (type);
+
+      size_t len;
+
+      if (TREE_CODE (init) == CONSTRUCTOR)
+	{
+	  /* The initializer of this array is itself an array.  Build
+	     an expression to check if the number of elements in the
+	     initializer array exceeds the upper bound of the type
+	     of the object being initialized.  */
+	  if (vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (init))
+	    {
+	      len = v->length ();
+	      tree initelts = build_int_cstu (size_type_node, len);
+	      tree initcheck = fold_build2 (LT_EXPR, boolean_type_node,
+					    inner_nelts, initelts);
+
+	      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+				   check, initcheck);
+
+	      constructor_elt *ce;
+	      HOST_WIDE_INT i;
+
+	      /* Iterate over all non-empty initializers in this array,
+		 recursively building expressions to see if the elements
+		 of each are in excess of the corresponding (runtime)
+		 bound of the array type.  */
+	      FOR_EACH_VEC_SAFE_ELT (v, i, ce)
+		check = build_vla_init_check (check, TREE_TYPE (type),
+					      ce->value, NULL_TREE);
+	    }
+	}
+      else if (TREE_CODE (init) == STRING_CST
+	       && (len = TREE_STRING_LENGTH (init)))
+	{
+	  /* The initializer of this array is a string.  */
+	  tree ctype = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init)));
+	  len /= TYPE_PRECISION (ctype) / BITS_PER_UNIT;
+
+	  /* A C++ string literal initializer must have at most as many
+	     characters as there are elements in the array, including
+	     the terminating NUL.  */
+	  tree initelts = build_int_cstu (size_type_node, len);
+	  tree initcheck = fold_build2 (LT_EXPR, boolean_type_node,
+					inner_nelts, initelts);
+	  check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			       check, initcheck);
+	}
+      else if (TREE_CODE (init) == ERROR_MARK)
+	{
+	  // No checking is possible.
+	  check = boolean_false_node;
+	}
+      else
+	{
+	  /* What's this array initializer?  */
+	  gcc_unreachable ();
+	}
+    }
+
+  return check;
+}
+
+/* Build an expression to determine whether the VLA TYPE is erroneous.
+   INIT is the VLA initializer expression or NULL_TREE when the VLA is
+   not initialized.  */
+
+tree
+build_vla_check (tree type, tree init /* = NULL_TREE */)
+{
+  tree check = boolean_false_node;
+
+  /* The product of all constant dimensions of the VLA, initialized
+     to either 1 in the common case or to the number of elements in
+     the VLA's initializer-list for VLAs of unspecified (major)
+     bound.  */
+  offset_int cst_size = 1;
+
+  /* The initial size of the VLA to start the computation of the total
+     size with.  Like CST_SIZE above, initialized to 1 or the number
+     of elements in the VLA's initializer-list for VLAs of unspecified
+     bound.  */
+  tree initial_size = size_one_node;
+
+  /* For a VLA of unspecified (major) bound, the number of elements
+     it is initialized with determined from the initializer-list.  */
+  tree initial_elts = NULL_TREE;
+
+  if (init)
+    {
+      /* Determine the upper bound of the VLA of unspecified bound,
+	 as in 'T a[];' if this is such a VLA.  Such a VLA can be
+	 initialized with any number of elements but the number of
+	 elements so determined must be used to check the total size
+	 of the VLA.  */
+      gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
+
+      if (tree dom = TYPE_DOMAIN (type))
+	if (tree max = TYPE_MAX_VALUE (dom))
+	  if (integer_zerop (max))
+	    {
+	      if (TREE_CODE (init) == CONSTRUCTOR)
+		{
+		  vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (init);
+
+		  /* Since the upper bound of every array must be positive
+		     a VLA with an unspecified major bound must be initized
+		     by a non-empty initializer list.  */
+		  gcc_assert (v != NULL);
+
+		  cst_size = v->length ();
+		}
+	      else if (TREE_CODE (init) == STRING_CST)
+		{
+		  /* The initializer is a (possibly empty) string consisting
+		     at a minumum of one character, the terminating NUL.
+		     This condition implies a definition like
+		       char s [][N] = "";
+		     which is an error but even though it has been diagnosed
+		     by this point the initializer still winds up here.  */
+		  size_t nchars = TREE_STRING_LENGTH (init);
+		  tree ctype = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init)));
+		  nchars /= TYPE_PRECISION (ctype) / BITS_PER_UNIT;
+
+		  cst_size = nchars + 1;
+		}
+
+	      initial_elts = wide_int_to_tree (size_type_node, cst_size);
+	      initial_size = initial_elts;
+	    }
+    }
+
+  /* Build a variable storing the total runtime size of the VLA and
+     initialize it either to 1 (in the common case) or to the number
+     of topmost elements in the initializer-list when the VLA is
+     an array of unspecified (major) bound.  */
+  tree vlasize = build_decl (input_location,
+			     VAR_DECL, NULL_TREE, sizetype);
+  DECL_ARTIFICIAL (vlasize) = 1;
+  DECL_IGNORED_P (vlasize) = 1;
+  DECL_CONTEXT (vlasize) = current_function_decl;
+  DECL_INITIAL (vlasize) = initial_size;
+  vlasize = pushdecl (vlasize);
+  add_decl_expr (vlasize);
+
+  /* Impose a lenient limit on the size of the biggest VLA in bytes.
+     FIXME: Tighten up the limit to make it more useful and make it
+     configurable for users with unusual requirements.  */
+  tree max_vlasize
+    = fold_build2 (RSHIFT_EXPR, size_type_node,
+		   build_all_ones_cst (size_type_node),
+		   integer_one_node);
+
+  /* Build an expression that checks the runtime bounds of the VLA
+     for invalid values and the total size of the VLA for overflow.  */
+  check = build_vla_size_check (check, type, vlasize, max_vlasize, &cst_size);
+
+  if (wi::ltu_p (wi::to_offset (max_vlasize), cst_size))
+    {
+      /* Issue the warning only in the "topmost" (non-recursive) call
+	 to avoid duplicating diagnostics.  This is only a warning to
+	 allow programs to be portable to more permissive environments.  */
+      warning (OPT_Wvla, "size of variable length array exceeds maximum "
+	       "of %qE bytes",  max_vlasize);
+    }
+
+  if (init)
+    {
+      /* Build an expression that checks the VLA initializer expression
+	 against the type of the VLA for excess elements.  */
+      check = build_vla_init_check (check, type, init, initial_elts);
+    }
+
+  return check;
+}
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index b921689..eba19ca 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -603,7 +603,7 @@ split_nonconstant_init_1 (tree dest, tree init)
       array_type_p = true;
       if ((TREE_SIDE_EFFECTS (init)
 	   && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
-	  || array_of_runtime_bound_p (type))
+	  || variably_modified_type_p (type, NULL_TREE))
 	{
 	  /* For an array, we only need/want a single cleanup region rather
 	     than one per element.  */
@@ -845,7 +845,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
      will perform the dynamic initialization.  */
   if (value != error_mark_node
       && (TREE_SIDE_EFFECTS (value)
-	  || array_of_runtime_bound_p (type)
+	  || variably_modified_type_p (type, NULL_TREE)
 	  || ! reduced_constant_expression_p (value)))
     return split_nonconstant_init (decl, value);
   /* If the value is a constant, just put it in DECL_INITIAL.  If DECL

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

* Re: [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
  2016-04-10 23:14             ` Martin Sebor
@ 2016-04-12 15:43               ` Jason Merrill
  2016-04-12 17:37                 ` Martin Sebor
  2016-04-12 18:17               ` Jason Merrill
  1 sibling, 1 reply; 22+ messages in thread
From: Jason Merrill @ 2016-04-12 15:43 UTC (permalink / raw)
  To: Martin Sebor, Gcc Patch List

On 04/10/2016 07:14 PM, Martin Sebor wrote:
> +	  if (TREE_CODE (type) == ARRAY_TYPE
> +	      && variably_modified_type_p (type, NULL_TREE)
> +	      && !processing_template_decl)
> +	    {
> +	      /* Statically check for overflow in VLA bounds and build
> +		 an expression that checks at runtime whether the VLA
> +		 is erroneous due to invalid (runtime) bounds.
> +		 Another expression to check for excess initializers
> +		 is built in build_vec_init.  */

Why do this both in check_initializer and then again in cp_finish_decl 
right after the call to check_initializer?

> +      /* Also check to see if the final array size is zero (the size
> +	 is unsigned so the earlier overflow check detects negative
> +	 values as well.  */
> +      tree zerocheck = fold_build2 (EQ_EXPR, boolean_type_node,
> +				    vlasize, size_zero_node);

I'm not sure whether we want this, given that GCC allows zero-length 
arrays in general.  As I recall, with the C++14 stuff whether we checked 
for zero was dependent on flag_iso, though I wasn't particularly happy 
with that.  If you want to check this unconditionally that's fine.

Jason

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

* Re: [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
  2016-04-12 15:43               ` Jason Merrill
@ 2016-04-12 17:37                 ` Martin Sebor
  0 siblings, 0 replies; 22+ messages in thread
From: Martin Sebor @ 2016-04-12 17:37 UTC (permalink / raw)
  To: Jason Merrill, Gcc Patch List

On 04/12/2016 09:43 AM, Jason Merrill wrote:
> On 04/10/2016 07:14 PM, Martin Sebor wrote:
>> +      if (TREE_CODE (type) == ARRAY_TYPE
>> +          && variably_modified_type_p (type, NULL_TREE)
>> +          && !processing_template_decl)
>> +        {
>> +          /* Statically check for overflow in VLA bounds and build
>> +         an expression that checks at runtime whether the VLA
>> +         is erroneous due to invalid (runtime) bounds.
>> +         Another expression to check for excess initializers
>> +         is built in build_vec_init.  */
>
> Why do this both in check_initializer and then again in cp_finish_decl
> right after the call to check_initializer?

I would have liked to make just one call but I couldn't find
a good way to do it.

The call to build_vla_check() in check_initializer() is to check
only explicitly initialized VLAs.  The latter function may need
to complete the VLA element type and reshape the initializer so
the call cannot be made earlier.  The function returns the runtime
initializer code so the call cannot be made after it returns.

The call to build_vla_check() in cp_finish_decl() is guarded with
!init and made to check VLAs that are not explicitly initialized.
This call could perhaps be moved into check_initializer() though
it doesn't seem like it logically belongs there (since there is
no initializer).  If it were moved there, it seems to me that it
would require more extensive changes to the function than making
it in cp_finish_decl().

>> +      /* Also check to see if the final array size is zero (the size
>> +     is unsigned so the earlier overflow check detects negative
>> +     values as well.  */
>> +      tree zerocheck = fold_build2 (EQ_EXPR, boolean_type_node,
>> +                    vlasize, size_zero_node);
>
> I'm not sure whether we want this, given that GCC allows zero-length
> arrays in general.  As I recall, with the C++14 stuff whether we checked
> for zero was dependent on flag_iso, though I wasn't particularly happy
> with that.  If you want to check this unconditionally that's fine.

The (sizeof A / sizeof *A) expression is commonly used to compute
the number of elements in an array.  When A is a two-dimensional
VLA with a runtime minor bound of zero, the division is undefined
and usually traps at runtime.  (This is also true for ordinary
arrays but there GCC warns about it with -Wdiv-by-zero.)  Since
we're already doing the runtime checking for VLAs it costs almost
nothing to detect and prevent it and results in arguably safer
code.  So if it's okay with you, my preference is to keep it
without providing a way to disable it.

Martin

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

* Re: [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
  2016-04-10 23:14             ` Martin Sebor
  2016-04-12 15:43               ` Jason Merrill
@ 2016-04-12 18:17               ` Jason Merrill
  2016-04-13 18:37                 ` Martin Sebor
  1 sibling, 1 reply; 22+ messages in thread
From: Jason Merrill @ 2016-04-12 18:17 UTC (permalink / raw)
  To: Martin Sebor, Gcc Patch List

On 04/10/2016 07:14 PM, Martin Sebor wrote:
> The call to build_vla_check() in check_initializer() is to check
> only explicitly initialized VLAs.  The latter function may need
> to complete the VLA element type and reshape the initializer so
> the call cannot be made earlier.  The function returns the runtime
> initializer code so the call cannot be made after it returns.

But this call isn't checking the initializer; we're looking at the 
initializer in build_vec_init now.

> The call to build_vla_check() in cp_finish_decl() is guarded with
> !init and made to check VLAs that are not explicitly initialized.
> This call could perhaps be moved into check_initializer() though
> it doesn't seem like it logically belongs there (since there is
> no initializer).

check_initializer handles implicit (default-) as well as explicit 
initialization.

> If it were moved there, it seems to me that it
> would require more extensive changes to the function than making
> it in cp_finish_decl().

I don't see that; you ought to be able to move the check_initializer 
copy down out of the if/else structure and use that for both cases.

> +/* Build an expression to determine whether the VLA TYPE is erroneous.
> +   INIT is the VLA initializer expression or NULL_TREE when the VLA is
> +   not initialized.  */
> +
> +/* Build an expression to determine whether the VLA TYPE is erroneous.
> +   INIT is the VLA initializer expression or NULL_TREE when the VLA is
> +   not initialized.  */

Duplicate comment.

Jason

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

* Re: [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
  2016-04-12 18:17               ` Jason Merrill
@ 2016-04-13 18:37                 ` Martin Sebor
  2016-04-13 19:26                   ` Jason Merrill
                                     ` (2 more replies)
  0 siblings, 3 replies; 22+ messages in thread
From: Martin Sebor @ 2016-04-13 18:37 UTC (permalink / raw)
  To: Jason Merrill, Gcc Patch List

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

On 04/12/2016 12:17 PM, Jason Merrill wrote:
> On 04/10/2016 07:14 PM, Martin Sebor wrote:
>> The call to build_vla_check() in check_initializer() is to check
>> only explicitly initialized VLAs.  The latter function may need
>> to complete the VLA element type and reshape the initializer so
>> the call cannot be made earlier.  The function returns the runtime
>> initializer code so the call cannot be made after it returns.
>
> But this call isn't checking the initializer; we're looking at the
> initializer in build_vec_init now.

Let me try to explain.  Strings aside, there are three cases each
of which the patch handles in a different function:

1) The No Initializer case is handled by calling build_vla_check
     directly from cp_finish_decl.

2) The Empty initializer case is handled from check_initializer
     in the hunk you had pasted upthread.  (It isn't handled in
     build_vec_init because length_check is false for empty
     initializers, and because it's too late to check VLA bounds
     there anyway -- see below.)

3) In the Non-empty Initializer case, excess initializer elements
     are checked for in build_vec_init.  VLA bounds are checked from
     check_initializer same as in (2).

As I mentioned last Friday, emitting the check for the VLA bounds
in build_vec_init appears to be too late because by then the code
to allocate the stack has already been emitted.  Maybe there's
a way to do it, I don't know.  Controlling what piece of code is
emitted when is something I don't know much about yet.

>> The call to build_vla_check() in cp_finish_decl() is guarded with
>> !init and made to check VLAs that are not explicitly initialized.
>> This call could perhaps be moved into check_initializer() though
>> it doesn't seem like it logically belongs there (since there is
>> no initializer).
>
> check_initializer handles implicit (default-) as well as explicit
> initialization.
>
>> If it were moved there, it seems to me that it
>> would require more extensive changes to the function than making
>> it in cp_finish_decl().
>
> I don't see that; you ought to be able to move the check_initializer
> copy down out of the if/else structure and use that for both cases.

You're right, it was simpler than I thought.  I was being overly
conservative in an effort to avoid changing more code than is
absolutely necessary.

Attached is an updated patch with this simplification. It avoids
case (1) above.  It also adds an argument to build_vla_check to
avoid building the size check when it's called from build_vec_init.

I also modified the alternate patch accordingly.  It's attached
for comparison. I still find it preferable to the first patch.
It's simpler because it doesn't require the special handling for
strings and avoids parameterizing build_vla_check so as not to
build the duplicate check in build_vec_init.

I don't see the benefit in doing the checking in build_vec_init
and split_constant_init_1 when it can all be done just in
check_initializer.  I'm sure you have your reasons for going that
route so I'd appreciate if you could let me know why you think
that's better.

Thanks
Martin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: gcc-69517.patch --]
[-- Type: text/x-patch; name="gcc-69517.patch", Size: 74559 bytes --]

PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
PR c++/70019 - VLA size overflow not detected

gcc/testsuite/ChangeLog:
2016-04-10  Martin Sebor  <msebor@redhat.com>

	PR c++/69517
	PR c++/70019
	* c-c++-common/ubsan/vla-1.c (main): Catch exceptions.
	* g++.dg/cpp1y/vla11.C: New test.
	* g++.dg/cpp1y/vla12.C: New test.
	* g++.dg/cpp1y/vla13.C: New test.
	* g++.dg/cpp1y/vla14.C: New test.
	* g++.dg/cpp1y/vla3.C: Restore deleted test.
	* gcc/testsuite/g++.dg/init/array24.C: Fully brace VLA initializer.
	* g++.dg/ubsan/vla-1.C: Disable exceptions.

gcc/cp/ChangeLog:
2016-04-10  Martin Sebor  <msebor@redhat.com>

	PR c++/69517
	PR c++/70019
	* cp-tree.h (throw_bad_array_length, build_vla_check): Declare new
	functions.
	* decl.c (check_initializer): Call them.
	(reshape_init_r): Reject incompletely braced intializer-lists
	for VLAs.
	* init.c (throw_bad_array_length, build_vla_check)
	(build_vla_size_check, build_vla_init_check): Define new functions.
	(build_vec_init): Use variably_modified_type_p() to detect a VLA.
	Call throw_bad_array_length() and build_vla_check().
	* typeck2.c (split_nonconstant_init_1): Use variably_modified_type_p()
	to detect a VLA.
	(store_init_value): Same.
	(split_nonconstant_init): Handle excess elements in string literal
	initializers for VLAs.

gcc/doc/ChangeLog:

2016-04-10  Martin Sebor  <msebor@redhat.com>

	PR c++/69517
	PR c++/70019
	* extend.texi (Variable Length): Document C++ specifics.

libstdc++-v3/ChangeLog:

2016-04-10  Martin Sebor  <msebor@redhat.com>

	PR c++/69517
	* testsuite/25_algorithms/rotate/moveable2.cc: Make sure VLA
	upper bound is positive.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b7b770f..2936ac9 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5978,6 +5978,7 @@ extern tree build_value_init_noctor		(tree, tsubst_flags_t);
 extern tree get_nsdmi				(tree, bool);
 extern tree build_offset_ref			(tree, tree, bool,
 						 tsubst_flags_t);
+extern tree throw_bad_array_length              (void);
 extern tree throw_bad_array_new_length		(void);
 extern tree build_new				(vec<tree, va_gc> **, tree, tree,
 						 vec<tree, va_gc> **, int,
@@ -5999,6 +6000,8 @@ extern tree scalar_constant_value		(tree);
 extern tree decl_really_constant_value		(tree);
 extern int diagnose_uninitialized_cst_or_ref_member (tree, bool, bool);
 extern tree build_vtbl_address                  (tree);
+extern tree build_vla_check                     (tree, tree = NULL_TREE,
+						 bool = true);
 
 /* in lex.c */
 extern void cxx_dup_lang_specific_decl		(tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 9260f4c..699e209 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5864,6 +5864,16 @@ reshape_init_r (tree type, reshape_iter *d, bool first_initializer_p,
 	    }
 	}
 
+      if (variably_modified_type_p (type, NULL_TREE))
+	{
+	  /* Require VLAs to have their initializers fully braced
+	     to avoid initializing the wrong elements.  */
+	  if (complain & tf_error)
+	    error ("missing braces around initializer for a variable length "
+		   "array %qT", type);
+	  return error_mark_node;
+	}
+
       warning (OPT_Wmissing_braces, "missing braces around initializer for %qT",
 	       type);
     }
@@ -6181,6 +6191,33 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
       check_for_uninitialized_const_var (decl);
     }
 
+  if (TREE_CODE (type) == ARRAY_TYPE
+      && variably_modified_type_p (type, NULL_TREE)
+      && !processing_template_decl)
+    {
+      /* Statically check for overflow in VLA bounds and build
+	 an expression that checks at runtime whether the VLA
+	 is erroneous due to invalid (runtime) bounds.
+	 Another expression to check for excess initializers
+	 is built in build_vec_init.  */
+      tree check = build_vla_check (TREE_TYPE (decl));
+
+      if (flag_exceptions && current_function_decl
+	  /* Avoid instrumenting constexpr functions for now.
+	     Those must be checked statically, and the (non-
+	     constexpr) dynamic instrumentation would cause
+	     them to be rejected.  See c++/70507.  */
+	  && !DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+	{
+	  /* Use the runtime check only when exceptions are enabled.
+	     Otherwise let bad things happen...  */
+	  check = build3 (COND_EXPR, void_type_node, check,
+			  throw_bad_array_length (), void_node);
+
+	  finish_expr_stmt (check);
+	}
+    }
+
   if (init && init != error_mark_node)
     init_code = build2 (INIT_EXPR, type, decl, init);
 
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 5997d53..a212508 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2262,6 +2262,20 @@ diagnose_uninitialized_cst_or_ref_member (tree type, bool using_new, bool compla
   return diagnose_uninitialized_cst_or_ref_member_1 (type, type, using_new, complain);
 }
 
+/* Call __cxa_throw_bad_array_length to indicate that the size calculation
+   in the bounds of a variable length array overflowed.  */
+
+tree
+throw_bad_array_length (void)
+{
+  tree fn = get_identifier ("__cxa_throw_bad_array_length");
+  if (!get_global_value_if_present (fn, &fn))
+    fn = push_throw_library_fn (fn, build_function_type_list (void_type_node,
+                                                             NULL_TREE));
+
+  return build_cxx_call (fn, 0, NULL, tf_warning_or_error);
+}
+
 /* Call __cxa_bad_array_new_length to indicate that the size calculation
    overflowed.  Pretend it returns sizetype so that it plays nicely in the
    COND_EXPR.  */
@@ -3819,15 +3833,20 @@ build_vec_init (tree base, tree maxindex, tree init,
       && from_array != 2)
     init = TARGET_EXPR_INITIAL (init);
 
+  /* Is ATYPE a variable modified type such as a VLA with either
+     a const or non-const major bound.  */
+  bool vartype_p = (!TREE_CONSTANT (maxindex)
+		    || variably_modified_type_p (atype, NULL_TREE));
+
   /* If we have a braced-init-list, make sure that the array
      is big enough for all the initializers.  */
   bool length_check = (init && TREE_CODE (init) == CONSTRUCTOR
 		       && CONSTRUCTOR_NELTS (init) > 0
-		       && !TREE_CONSTANT (maxindex));
+		       && vartype_p);
 
   if (init
       && TREE_CODE (atype) == ARRAY_TYPE
-      && TREE_CONSTANT (maxindex)
+      && !vartype_p
       && (from_array == 2
 	  ? vec_copy_assign_is_trivial (inner_elt_type, init)
 	  : !TYPE_NEEDS_CONSTRUCTING (type))
@@ -3925,7 +3944,7 @@ build_vec_init (tree base, tree maxindex, tree init,
 
   /* Should we try to create a constant initializer?  */
   bool try_const = (TREE_CODE (atype) == ARRAY_TYPE
-		    && TREE_CONSTANT (maxindex)
+		    && !vartype_p
 		    && (init ? TREE_CODE (init) == CONSTRUCTOR
 			: (type_has_constexpr_default_constructor
 			   (inner_elt_type)))
@@ -3973,6 +3992,24 @@ build_vec_init (tree base, tree maxindex, tree init,
 		}
 	      /* Don't check an array new when -fno-exceptions.  */
 	    }
+	  else if (flag_exceptions
+		   && current_function_decl
+		  /* Avoid instrumenting constexpr functions.  Those must
+		     be checked statically for now since the (non-constexpr)
+		     dynamic instrumentation would cause them to be rejected
+		     due to c++/70507.  */
+		   && !DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+	    {
+	      /* Use the runtime check only when exceptions are enabled.
+		 Otherwise let bad things happen (though perhaps emitting
+		 a trap would be appropriate).  */
+	      tree check = build_vla_check (atype, init, false);
+
+	      check = build3 (COND_EXPR, void_type_node, check,
+			      throw_bad_array_length (), void_node);
+
+	      finish_expr_stmt (check);
+	    }
 	  else if (flag_sanitize & SANITIZE_BOUNDS
 		   && do_ubsan_in_current_function ())
 	    {
@@ -4709,3 +4746,316 @@ build_vec_delete (tree base, tree maxindex,
 
   return rval;
 }
+
+
+/* The implementation of build_vla_check() that recursively builds
+   an expression to determine whether the VLA TYPE is erroneous due
+   either to its bounds being invalid or to integer overflow in
+   the computation of its total size.
+   CHECK is the boolean expression being built, initialized to
+   boolean_false_node.
+   VLASIZE is used internally to pass the incrementally computed
+   size of the VLA object down to its recursive invocations.
+   MAX_VLASIZE is the maximum valid size of the VLA in bytes.
+   CST_SIZE is the product of the VLA's constant dimensions.  */
+
+static tree
+build_vla_size_check (tree check,
+		      tree type,
+		      tree vlasize,
+		      tree max_vlasize,
+		      offset_int *cst_size)
+{
+  tree vmul = builtin_decl_explicit (BUILT_IN_MUL_OVERFLOW);
+
+  tree vlasizeaddr = build_unary_op (input_location, ADDR_EXPR, vlasize, 0);
+
+  bool overflow = false;
+
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      /* Compute the upper bound of this array type.  */
+      tree inner_nelts = array_type_nelts_top (type);
+      tree inner_nelts_cst = maybe_constant_value (inner_nelts);
+
+      if (TREE_CODE (inner_nelts_cst) == INTEGER_CST)
+	{
+	  /* The upper bound is a constant expression.  Compute the product
+	     of the constant upper bounds seen so far so that overflow can
+	     be diagnosed.  */
+	  offset_int result = wi::mul (wi::to_offset (inner_nelts_cst),
+				       *cst_size, SIGNED, &overflow);
+	  *cst_size = overflow ? 0 : result;
+	}
+
+      /* Check for overflow in the VLAs (runtime) upper bounds.  */
+      tree vflowcheck = build_call_expr (vmul, 3, inner_nelts,
+					 vlasize, vlasizeaddr);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, vflowcheck);
+
+      /* Recursively check for overflow in the remaining major bounds.  */
+      check = build_vla_size_check (check, TREE_TYPE (type),
+				    vlasize, max_vlasize,
+				    cst_size);
+    }
+  else
+    {
+      /* Get the size of the VLA element type in bytes.  */
+      tree typesize = TYPE_SIZE_UNIT (type);
+
+      /* See if the size, when multipled by the product of the VLA's
+	 constant dimensions, is within range of size_t.  If not,
+	 the VLA is definitely erroneous amd must be diagnosed at
+	 compile time.  */
+      offset_int result = wi::mul (wi::to_offset (typesize), *cst_size,
+				   SIGNED, &overflow);
+      *cst_size = overflow ? 0 : result;
+
+      /* Multiply the (non-constant) VLA size so far by the element size,
+	 checking for overflow, and replacing the value of vlasize with
+	 the product in the absence of overflow.  This size is the total
+	 runtime size of the VLA in bytes.  */
+      tree vflowcheck = build_call_expr (vmul, 3, typesize,
+					 vlasize, vlasizeaddr);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, vflowcheck);
+
+      /* Check to see if the final VLA size exceeds the maximum.  */
+      tree sizecheck = fold_build2 (LT_EXPR, boolean_type_node,
+				    max_vlasize, vlasize);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, sizecheck);
+
+      /* Also check to see if the final array size is zero (the size
+	 is unsigned so the earlier overflow check detects negative
+	 values as well.  */
+      tree zerocheck = fold_build2 (EQ_EXPR, boolean_type_node,
+				    vlasize, size_zero_node);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, zerocheck);
+    }
+
+  /* Diagnose overflow determined at compile time.  */
+  if (overflow)
+    {
+      error ("integer overflow in variable array size");
+      /* Reset to suppress any further diagnostics.  */
+      *cst_size = 0;
+    }
+
+  return check;
+}
+
+/* The implementation of build_vla_check() that recursively builds
+   an expression to determine whether the VLA initializer-list for
+   TYPE is erroneous due to excess initializers.
+   CHECK is the boolean expression being built, initialized to
+   the result of build_vla_size_check().
+   INIT is the VLA initializer expression to check against TYPE.
+   On the first (non-recursive) call, INIT_ELTS is set either to 1,
+   or to the number of elements in the initializer-list for VLAs
+   of unspecified (major) bound.  On subsequent (recursive) calls.
+   it is set to NULL and computed from the number of elements in
+   the (nested) initializer-list.
+*/
+
+static tree
+build_vla_init_check (tree check, tree type, tree init, tree init_elts)
+{
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      /* Compute the upper bound of this array type unless it has
+	 already been computed by the caller for an array of unspecified
+	 bound, as in 'T a[];'  */
+      tree inner_nelts = init_elts ? init_elts : array_type_nelts_top (type);
+
+      size_t len;
+
+      if (TREE_CODE (init) == CONSTRUCTOR)
+	{
+	  /* The initializer of this array is itself an array.  Build
+	     an expression to check if the number of elements in the
+	     initializer array exceeds the upper bound of the type
+	     of the object being initialized.  */
+	  if (vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (init))
+	    {
+	      len = v->length ();
+	      tree initelts = build_int_cstu (size_type_node, len);
+	      tree initcheck = fold_build2 (LT_EXPR, boolean_type_node,
+					    inner_nelts, initelts);
+
+	      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+				   check, initcheck);
+
+	      constructor_elt *ce;
+	      HOST_WIDE_INT i;
+
+	      /* Iterate over all non-empty initializers in this array,
+		 recursively building expressions to see if the elements
+		 of each are in excess of the corresponding (runtime)
+		 bound of the array type.  */
+	      FOR_EACH_VEC_SAFE_ELT (v, i, ce)
+		check = build_vla_init_check (check, TREE_TYPE (type),
+					      ce->value, NULL_TREE);
+	    }
+	}
+      else if (TREE_CODE (init) == STRING_CST
+	       && (len = TREE_STRING_LENGTH (init)))
+	{
+	  /* The initializer of this array is a string.  */
+	  tree ctype = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init)));
+	  len /= TYPE_PRECISION (ctype) / BITS_PER_UNIT;
+
+	  /* A C++ string literal initializer must have at most as many
+	     characters as there are elements in the array, including
+	     the terminating NUL.  */
+	  tree initelts = build_int_cstu (size_type_node, len);
+	  tree initcheck = fold_build2 (LT_EXPR, boolean_type_node,
+					inner_nelts, initelts);
+	  check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			       check, initcheck);
+	}
+      else if (TREE_CODE (init) == ERROR_MARK)
+	{
+	  // No checking is possible.
+	  check = boolean_false_node;
+	}
+      else
+	{
+	  /* What's this array initializer?  */
+	  gcc_unreachable ();
+	}
+    }
+
+  return check;
+}
+
+/* Build an expression to determine whether the VLA TYPE is erroneous.
+   INIT is the VLA initializer expression or NULL_TREE when the VLA is
+   not initialized.
+   CHECK_SIZE is true the size of the array should be considered,
+   otherwise only the initializer INIT should be, provided it is not
+   null.  When both INIT and CHECK_SIZE are clear the function does
+   nothing and returns boolean_false_node.  */
+
+tree
+build_vla_check (tree type, tree init /* = NULL_TREE */,
+		 bool check_size /* = true */)
+{
+  tree check = boolean_false_node;
+
+  /* The product of all constant dimensions of the VLA, initialized
+     to either 1 in the common case or to the number of elements in
+     the VLA's initializer-list for VLAs of unspecified (major)
+     bound.  */
+  offset_int cst_size = 1;
+
+  /* The initial size of the VLA to start the computation of the total
+     size with.  Like CST_SIZE above, initialized to 1 or the number
+     of elements in the VLA's initializer-list for VLAs of unspecified
+     bound.  */
+  tree initial_size = size_one_node;
+
+  /* For a VLA of unspecified (major) bound, the number of elements
+     it is initialized with determined from the initializer-list.  */
+  tree initial_elts = NULL_TREE;
+
+  if (init)
+    {
+      /* Determine the upper bound of the VLA of unspecified bound,
+	 as in 'T a[];' if this is such a VLA.  Such a VLA can be
+	 initialized with any number of elements but the number of
+	 elements so determined must be used to check the total size
+	 of the VLA.  */
+      gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
+
+      if (tree dom = TYPE_DOMAIN (type))
+	if (tree max = TYPE_MAX_VALUE (dom))
+	  if (integer_zerop (max))
+	    {
+	      if (TREE_CODE (init) == CONSTRUCTOR)
+		{
+		  vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (init);
+
+		  /* Since the upper bound of every array must be positive
+		     a VLA with an unspecified major bound must be initized
+		     by a non-empty initializer list.  */
+		  gcc_assert (v != NULL);
+
+		  cst_size = v->length ();
+		}
+	      else if (TREE_CODE (init) == STRING_CST)
+		{
+		  /* The initializer is a (possibly empty) string consisting
+		     at a minumum of one character, the terminating NUL.
+		     This condition implies a definition like
+		       char s [][N] = "";
+		     which is an error but even though it has been diagnosed
+		     by this point the initializer still winds up here.  */
+		  size_t nchars = TREE_STRING_LENGTH (init);
+		  tree ctype = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init)));
+		  nchars /= TYPE_PRECISION (ctype) / BITS_PER_UNIT;
+
+		  cst_size = nchars + 1;
+		}
+
+	      initial_elts = wide_int_to_tree (size_type_node, cst_size);
+	      initial_size = initial_elts;
+	    }
+    }
+
+  if (check_size)
+    {
+      /* Build a variable storing the total runtime size of the VLA and
+	 initialize it either to 1 (in the common case) or to the number
+	 of topmost elements in the initializer-list when the VLA is
+	 an array of unspecified (major) bound.  */
+      tree vlasize = build_decl (input_location, VAR_DECL, NULL_TREE, sizetype);
+      DECL_ARTIFICIAL (vlasize) = 1;
+      DECL_IGNORED_P (vlasize) = 1;
+      DECL_CONTEXT (vlasize) = current_function_decl;
+      DECL_INITIAL (vlasize) = initial_size;
+      vlasize = pushdecl (vlasize);
+      add_decl_expr (vlasize);
+
+      /* Impose a lenient limit on the size of the biggest VLA in bytes.
+	 FIXME: Tighten up the limit to make it more useful and make it
+	 configurable for users with unusual requirements.  */
+
+      tree max_vlasize = fold_build2 (RSHIFT_EXPR, size_type_node,
+				      build_all_ones_cst (size_type_node),
+				      integer_one_node);
+
+      /* Build an expression that checks the runtime bounds of the VLA
+	 for invalid values and the total size of the VLA for overflow.  */
+      check = build_vla_size_check (check, type,
+				    vlasize, max_vlasize, &cst_size);
+
+      if (wi::ltu_p (wi::to_offset (max_vlasize), cst_size))
+	{
+	  /* Issue the warning only in the "topmost" (non-recursive) call
+	     to avoid duplicating diagnostics.  This is only a warning to
+	     allow programs to be portable to more permissive environments.  */
+	  warning (OPT_Wvla, "size of variable length array exceeds maximum "
+		   "of %qE bytes",  max_vlasize);
+
+	  /* The VLA is known to throw so discard the size check and skip
+	     the initializer check and simply return true.  */
+	  return boolean_true_node;
+	}
+    }
+
+  if (init)
+    {
+      /* Build an expression that checks the VLA initializer expression
+	 against the type of the VLA for excess elements.  */
+      check = build_vla_init_check (check, type, init, initial_elts);
+    }
+
+  return check;
+}
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index b921689..797ec9a 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -603,7 +603,7 @@ split_nonconstant_init_1 (tree dest, tree init)
       array_type_p = true;
       if ((TREE_SIDE_EFFECTS (init)
 	   && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
-	  || array_of_runtime_bound_p (type))
+	  || variably_modified_type_p (type, NULL_TREE))
 	{
 	  /* For an array, we only need/want a single cleanup region rather
 	     than one per element.  */
@@ -749,7 +749,26 @@ split_nonconstant_init (tree dest, tree init)
       TREE_READONLY (dest) = 0;
     }
   else
-    code = build2 (INIT_EXPR, TREE_TYPE (dest), dest, init);
+    {
+      tree type = TREE_TYPE (dest);
+
+      if (TREE_CODE (init) == STRING_CST
+	  && TREE_CODE (type) == ARRAY_TYPE
+	  && variably_modified_type_p (type, NULL_TREE))
+	{
+	  /* Statically check for overflow in VLA bounds and build
+	     an expression that checks whether the VLA is erroneous
+	     at runtime due to excess elements in the string literal.  */
+	  tree check = build_vla_check (type, init);
+
+	  check = build3 (COND_EXPR, void_type_node, check,
+			  throw_bad_array_length (), void_node);
+
+	  finish_expr_stmt (check);
+	}
+
+      code = build2 (INIT_EXPR, TREE_TYPE (dest), dest, init);
+    }
 
   return code;
 }
@@ -845,7 +864,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
      will perform the dynamic initialization.  */
   if (value != error_mark_node
       && (TREE_SIDE_EFFECTS (value)
-	  || array_of_runtime_bound_p (type)
+	  || variably_modified_type_p (type, NULL_TREE)
 	  || ! reduced_constant_expression_p (value)))
     return split_nonconstant_init (decl, value);
   /* If the value is a constant, just put it in DECL_INITIAL.  If DECL
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 6e27029..9d9c0c0 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -1634,14 +1634,48 @@ foo (int n)
 You can use the function @code{alloca} to get an effect much like
 variable-length arrays.  The function @code{alloca} is available in
 many other C implementations (but not in all).  On the other hand,
-variable-length arrays are more elegant.
+variable-length arrays are available in GCC for all targets and
+provide type safety.
 
 There are other differences between these two methods.  Space allocated
 with @code{alloca} exists until the containing @emph{function} returns.
 The space for a variable-length array is deallocated as soon as the array
 name's scope ends, unless you also use @code{alloca} in this scope.
 
-You can also use variable-length arrays as arguments to functions:
+Unlike GCC, G++ instruments variable-length arrays (@xref{Variable Length})
+with checks for erroneous uses: when a variable-length array object is
+created its runtime bounds are checked to detect non-positive values,
+integer overflows, sizes in excess of SIZE_MAX / 2 bytes, and excess
+initializers.  When an erroneous variable-length array is detected
+the runtime arranges for an exception to be thrown that matches a handler
+of type @code{std::bad_array_length}.
+
+Also unlike GCC, G++ allows variable-length arrays to be initialized.
+However, unlike initializer lists for ordinary multidimensional arrays,
+those for multidimensional variable-length arrays must be enclosed in
+pairs of curly braces delimiting each sequence of values to use to
+initialize each subarray.  Initializer lists that aren't unambiguously
+enclosed in braces are rejected with an error.  For example, in the
+following function, the initializer list for the ordinary @code{array}
+is accepted even though it isn't fully enclosed in braces.  The same
+initializer list, however, wouldn't be accepted for a multidimensional
+variable-length array.  To initialize the variable-length array @code{vla},
+the elements of the subarray @code{vla[m]} must be enclosed in braces
+as shown.  As with ordinary arrays, elements that aren't initialized
+explicitly are default-initialized.
+
+@smallexample
+void
+foo (int m, int n)
+@{
+  int array[2][3] = @{ 1, 2, 4, 5, 6 @};
+  int vla[m][n] = @{ @{ 1, 2 @}, @{ 4, 5, 6 @} @};
+@}
+@end smallexample
+
+
+In C programs (but not in C++) variable-length arrays can also be declared
+as function arguments:
 
 @smallexample
 struct entry
diff --git a/gcc/testsuite/c-c++-common/ubsan/vla-1.c b/gcc/testsuite/c-c++-common/ubsan/vla-1.c
index 52ade3a..27ef110 100644
--- a/gcc/testsuite/c-c++-common/ubsan/vla-1.c
+++ b/gcc/testsuite/c-c++-common/ubsan/vla-1.c
@@ -87,18 +87,24 @@ fn12 (void)
 int
 main (void)
 {
-  fn1 ();
-  fn2 ();
-  fn3 ();
-  fn4 ();
-  fn5 ();
-  fn6 ();
-  fn7 ();
-  fn8 ();
-  fn9 ();
-  fn10 ();
-  fn11 ();
-  fn12 ();
+#if __cplusplus
+#  define TRY(stmt)   do { try { stmt; } catch (...) { } } while (0)
+#else
+#  define TRY(stmt)   stmt
+#endif
+
+  TRY (fn1 ());
+  TRY (fn2 ());
+  TRY (fn3 ());
+  TRY (fn4 ());
+  TRY (fn5 ());
+  TRY (fn6 ());
+  TRY (fn7 ());
+  TRY (fn8 ());
+  TRY (fn9 ());
+  TRY (fn10 ());
+  TRY (fn11 ());
+  TRY (fn12 ());
   return 0;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla11.C b/gcc/testsuite/g++.dg/cpp1y/vla11.C
new file mode 100644
index 0000000..af9624a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla11.C
@@ -0,0 +1,711 @@
+// PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer
+//   elements
+// PR c++/70019 - VLA size overflow not detected
+//
+// Runtime test to verify that attempting to either construct a VLA with
+// erroneous bounds, or initialize one with an initializer-list that
+// contains more elements than the VLA's non-constant (runtime) bounds
+// causes an exception to be thrown.  Test also verifies that valid
+// VLAs and their initializers don't cause such an exception.
+
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-Wno-vla" }
+
+#pragma GCC diagnostic ignored "-Wvla"
+
+#define INT_MAX    __INT_MAX__
+#define LONG_MAX   __LONG_MAX__
+#define SIZE_MAX   __SIZE_MAX__
+#define UINT_MAX   (~0U)
+#define ULONG_MAX  (~0LU)
+
+#define INT_MIN    (-__INT_MAX__ - 1)
+#define LONG_MIN   (-__LONG_MAX__ - 1)
+
+// The size of the largest allowed VLA in bytes.  Bigger objects
+// cause an exception to be thrown.  Unless the maximum size is
+// obscenely large, smaller objects should be successfully created
+// provided there's enough stack space.  See TEST_NEAR_VLA_MAX_SIZE
+// below.
+#define MAX   (__SIZE_MAX__ / 2)
+
+// Define to non-zero to exercise very large VLAs with size just
+// below the implementation-defined maximum.
+#define TEST_NEAR_VLA_MAX_SIZE    0
+
+// Define to zero to enable tests that cause an ICE due to c++/58646.
+#define BUG_58646 1
+
+// Helper macro to make it possible to pass as one multpile arguments
+// to another macro.
+#define Init(...) __VA_ARGS__
+
+typedef __SIZE_TYPE__ size_t;
+
+// Incremented for each test failure.
+int fail;
+
+// Used to convert a constant array dimension to a non-constant one.
+template <class T>
+T d (T n)
+{
+  return n;
+}
+
+// Verify either that an expected exception has been thrown or that
+// one hasn't been thrown if one isn't expected.
+int __attribute__ ((noclone, noinline))
+sink (void *p, int line, bool expect, const char *expr)
+{
+  if (!p != expect)
+    {
+      __builtin_printf ("line %i: Assertion failed: '%s': "
+                        "exception unexpectedly %sthrown\n",
+                        line, expr, !p ? "" : "not ");
+      ++fail;
+    }
+  else
+    {
+#if defined DEBUG && DEBUG
+    __builtin_printf ("line %i: Assertion passed: '%s': "
+		      "exception %sthrown as expected\n",
+		      line, expr, !p ? "" : "not ");
+#endif
+    }
+  return 0;
+}
+
+#define _CAT(name, line) name ## line
+#define CAT(name, line) _CAT (name, line)
+
+#define STR(...) #__VA_ARGS__
+
+// Type to exercise VLA with.  TYPESIZE is the size of the type in bytes.
+// Using a template serves two purposes.  First, it makes it possible to
+// parameterize the test on VLAs of different size.  Second, it verifies
+// that the checking code can deal with templates (i.e., completes
+// the element type of the VLA when necessary).
+template <unsigned TypeSize>
+struct alignas (TypeSize) TestType
+{
+  char data;
+};
+
+// Test function invoked with a pointer to each test case.  Must
+// return a value though what value doesn't matter.
+int __attribute__ ((noclone, noinline))
+tester (int (*testcase)(const char*),
+	const char *str, int line, bool expect)
+{
+  try
+    {
+      return testcase (str);
+    }
+  catch (...)
+    {
+      return sink (0, line, expect, str);
+    }
+}
+
+// Macro to define a unique specialization of a function template to
+// exercise a VLA of type T, rank N, with dimensions given by Dims
+// and initializer Init.  Expect is true when the VLA initialization
+// is expected to trigger an exception.
+// The macro creates a unique global dummy int object and initializes
+// it with the result of the function.  The dummy object servers no
+// other purpose but to call the function.  The function verifies
+// the expected postconditions.
+#define TEST(TypeSize, Dims, Init, Expect)				\
+  static int CAT (testcase, __LINE__)(const char *str)			\
+  {									\
+    TestType<TypeSize> vla Dims Init;					\
+    static_assert (sizeof (TestType<TypeSize>) == TypeSize,		\
+		   "wrong test type size");				\
+    return sink (vla, __LINE__, Expect, str);				\
+  }									\
+  const int CAT (dummy, __LINE__)					\
+    = tester (CAT (testcase, __LINE__),					\
+	      "T<" #TypeSize "> a" #Dims " " STR (Init) ";",		\
+	      __LINE__, Expect)
+
+
+// Create and run a test function exercising a VLA definition
+// of one of the following forms:
+//    TestType<Size> VLA Dims;        // uninitialized (with Init ())
+// or:
+//    TestType<Size> VLA Dims Init;   // initialized (with = Init ({...})
+//
+//    +-- Element Size (in Bytes)
+//    |  +-- VLA Dimensions (constant as in [3], otherwise d(3))
+//    |  |         +-- VLA Initializer Expression (if any)
+//    |  |         |                  +-- Expect Exception
+//    |  |         |                  |
+//    V  V         V                  V
+TEST (1, [d(0)],   Init (/* none*/),  true);   // uninitialized
+
+#if !BUG_58646
+// The following causes an ICE due to c++/58646.
+TEST (1, [d(0)],   Init ({}),         true);
+#endif
+TEST (1, [d(0)],   Init ({1}),        true);   // initialized with " {1}"
+TEST (1, [d(0)],   = Init ({1}),      true);   // initialized with "= {1}"
+
+TEST (1, [d(1)],   Init (),           false);
+TEST (1, [d(1)],   Init ({}),         false);
+TEST (1, [d(1)],   = Init ({}),       false);
+TEST (1, [d(1)],   Init ({1}),        false);
+TEST (1, [d(1)],   = Init ({1}),      false);
+TEST (1, [d(1)],   Init ({1, 2}),     true);
+TEST (1, [d(1)],   = Init ({1, 2}),   true);
+
+TEST (1, [d(2)],   Init (),           false);
+TEST (1, [d(2)],   Init ({}),         false);
+TEST (1, [d(2)],   Init ({1}),        false);
+TEST (1, [d(2)],   Init ({1, 2}),     false);
+TEST (1, [d(2)],   Init ({1, 2, 3}),  true);
+
+#if TEST_NEAR_VLA_MAX_SIZE
+// Very large but not erroneous one dimensional VLAs.
+TEST (1, [d(MAX)], Init (),           false);
+TEST (1, [d(MAX)], Init ({}),         false);
+TEST (1, [d(MAX)], Init ({1}),        false);
+TEST (1, [d(MAX)], Init ({1, 2}),     false);
+TEST (1, [d(MAX)], Init ({1, 2, 3}),  false);
+
+TEST ( 2, [d(MAX / 2)],   Init (),    false);
+TEST ( 4, [d(MAX / 4)],   Init (),    false);
+TEST ( 8, [d(MAX / 8)],   Init (),    false);
+TEST (16, [d(MAX / 16)],  Init (),    false);
+TEST (32, [d(MAX / 32)],  Init (),    false);
+TEST (64, [d(MAX / 64)],  Init (),    false);
+#endif   // TEST_NEAR_VLA_MAX_SIZE
+
+// One dimensional VLAs with a negative upper bound.
+TEST (1, [d(LONG_MIN)],  Init (),       true);
+TEST (1, [d(INT_MIN)],   Init (),       true);
+TEST (1, [d(-1234)],     Init (),       true);
+TEST (1, [d(-1)],        Init (),       true);
+
+// Excessively large one dimensional VLAs.
+TEST ( 1, [d(MAX + 1)],   Init (),      true);
+TEST ( 2, [d(MAX)],       Init (),      true);
+TEST ( 4, [d(MAX / 2)],   Init (),      true);
+TEST ( 4, [d(MAX / 3)],   Init (),      true);
+TEST ( 8, [d(MAX / 2)],   Init (),      true);
+TEST ( 8, [d(MAX / 3)],   Init (),      true);
+TEST ( 8, [d(MAX / 4)],   Init (),      true);
+TEST ( 8, [d(MAX / 5)],   Init (),      true);
+TEST ( 8, [d(MAX / 6)],   Init (),      true);
+TEST ( 8, [d(MAX / 7)],   Init (),      true);
+TEST (16, [d(MAX / 15)],  Init (),      true);
+TEST (32, [d(MAX / 31)],  Init (),      true);
+TEST (64, [d(MAX / 63)],  Init (),      true);
+TEST ( 1, [d(SIZE_MAX)],  Init (),      true);
+
+TEST (1, [d(LONG_MIN)],  Init ({}),     true);
+TEST (1, [d(INT_MIN)],   Init ({}),     true);
+TEST (1, [d(-1)],        Init ({}),     true);
+
+TEST (1, [d(SIZE_MAX)],  Init ({}),     true);
+
+TEST (1, [d(LONG_MIN)],  Init ({0}),    true);
+TEST (1, [d(INT_MIN)],   Init ({0}),    true);
+TEST (1, [d(-1)],        Init ({0}),    true);
+
+TEST (1, [d(SIZE_MAX)],  Init ({0}),    true);
+
+TEST ( 1, [d(SIZE_MAX/2)  + 1], Init (), true);
+TEST ( 2, [d(SIZE_MAX/4)  + 1], Init (), true);
+TEST ( 4, [d(SIZE_MAX/8)  + 1], Init (), true);
+TEST ( 8, [d(SIZE_MAX/16) + 1], Init (), true);
+TEST (16, [d(SIZE_MAX/32) + 1], Init (), true);
+
+TEST ( 1, [d(SIZE_MAX/2)  + 1], Init ({1}),             true);
+TEST ( 2, [d(SIZE_MAX/4)  + 1], Init ({1, 2}),          true);
+TEST ( 4, [d(SIZE_MAX/8)  + 1], Init ({1, 2, 3}),       true);
+TEST ( 8, [d(SIZE_MAX/16) + 1], Init ({1, 2, 3, 4}),    true);
+TEST (16, [d(SIZE_MAX/32) + 1], Init ({1, 2, 3, 4, 5}), true);
+
+// Two dimensional VLAs with one constant bound.
+
+TEST (1, [1][d(0)],   Init (),          true);
+
+#if !BUG_58646
+// The following causes an ICE due to c++/58646.
+TEST (1, [1][d(0)],   Init ({}),        true);
+#endif
+TEST (1, [ ][d(0)],   Init ({{1}}),     true);   // unspecified bound
+TEST (1, [1][d(0)],   Init ({{1}}),     true);
+
+TEST (1, [1][d(1)],   Init (),             false);
+TEST (1, [1][d(1)],   Init ({{1}}),        false);
+TEST (1, [1][d(1)],   Init ({{1, 2}}),     true);
+TEST (1, [ ][d(1)],   Init ({{1, 2}}),     true);
+
+TEST (1, [1][d(2)],   Init (),             false);
+TEST (1, [1][d(2)],   Init ({{1}}),        false);
+TEST (1, [1][d(2)],   Init ({{1, 2}}),     false);
+TEST (1, [ ][d(2)],   Init ({{1, 2}}),     false);
+TEST (1, [1][d(2)],   Init ({{1, 2, 3}}),  true);
+TEST (1, [ ][d(2)],   Init ({{1, 2, 3}}),  true);
+
+TEST (1, [2][d(1)],   Init (),                 false);
+TEST (1, [2][d(1)],   Init ({{1}}),            false);
+TEST (1, [ ][d(1)],   Init ({{1}}),            false);
+TEST (1, [2][d(1)],   Init ({{1}, {2}}),       false);
+TEST (1, [ ][d(1)],   Init ({{1}, {2}}),       false);
+TEST (1, [2][d(1)],   Init ({{1, 2}}),         true);
+TEST (1, [ ][d(1)],   Init ({{1, 2}}),         true);
+TEST (1, [2][d(1)],   Init ({{1}, {2, 3}}),    true);
+TEST (1, [ ][d(1)],   Init ({{1}, {2, 3}}),    true);
+TEST (1, [2][d(1)],   Init ({{1, 2, 3}}),      true);
+TEST (1, [ ][d(1)],   Init ({{1, 2, 3}}),      true);
+TEST (1, [2][d(1)],   Init ({{1, 2, 3}, {4}}), true);
+TEST (1, [ ][d(1)],   Init ({{1, 2, 3}, {4}}), true);
+TEST (1, [2][d(1)],   Init ({{1, 2}, {3, 4}}), true);
+TEST (1, [ ][d(1)],   Init ({{1, 2}, {3, 4}}), true);
+
+TEST (1, [2][d(2)],   Init (),                       false);
+TEST (1, [2][d(2)],   Init ({{1}}),                  false);
+TEST (1, [2][d(2)],   Init ({{1, 2}}),               false);
+TEST (1, [2][d(2)],   Init ({{1, 2}, {3}}),          false);
+TEST (1, [2][d(2)],   Init ({{1, 2}, {3, 4}}),       false);
+TEST (1, [2][d(2)],   Init ({{1}, {2, 3, 4}}),       true);
+TEST (1, [2][d(2)],   Init ({{1}, {2, 3, 4, 5}}),    true);
+TEST (1, [2][d(2)],   Init ({{1, 2}, {3, 4, 5}}),    true);
+TEST (1, [2][d(2)],   Init ({{1, 2, 3}, {4, 5}}),    true);
+TEST (1, [2][d(2)],   Init ({{1, 2, 3}, {4, 5, 6}}), true);
+
+TEST (1, [2][d(3)],   Init (),                          false);
+TEST (1, [2][d(3)],   Init ({{1}}),                     false);
+TEST (1, [2][d(3)],   Init ({{1, 2}}),                  false);
+TEST (1, [2][d(3)],   Init ({{1, 2}, {3}}),             false);
+TEST (1, [2][d(3)],   Init ({{1, 2}, {3, 4}}),          false);
+TEST (1, [2][d(3)],   Init ({{1}, {2, 3, 4}}),          false);
+TEST (1, [2][d(3)],   Init ({{1}, {2, 3, 4, 5}}),       true);
+TEST (1, [2][d(3)],   Init ({{1, 2}, {3, 4, 5}}),       false);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3}, {4, 5}}),       false);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3}, {4, 5, 6}}),    false);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3}, {4, 5, 6, 7}}), true);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3, 4}, {5, 6, 7}}), true);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3, 4, 5}, {6, 7}}), true);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3, 4, 5, 6}, {7}}), true);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3, 4, 5, 6, 7}}),   true);
+
+#if TEST_NEAR_VLA_MAX_SIZE
+TEST (1, [1][d(MAX)], Init (),                 false);
+#  if !BUG_58646
+// The following causes an ICE due to c++/58646.
+TEST (1, [1][d(MAX)], Init ({}),               false);
+#  endif
+TEST (1, [1][d(MAX)], Init ({{1}}),            false);
+TEST (1, [1][d(MAX)], Init ({{1, 2}}),         false);
+TEST (1, [1][d(MAX)], Init ({{1, 2, 3}}),      false);
+TEST (1, [1][d(MAX)], Init ({{1, 2, 3, 4}}),   false);
+
+TEST (1, [2][d(MAX / 2)], Init (),                       false);
+TEST (1, [2][d(MAX / 2)], Init ({{1}}),                  false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2}}),               false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}}),            false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3, 4}}),         false);
+TEST (1, [2][d(MAX / 2)], Init ({{1}, {2}}),             false);
+TEST (1, [2][d(MAX / 2)], Init ({{1}, {2, 3}}),          false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2}, {3}}),          false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2}, {3, 4}}),       false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}, {4}}),       false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5}}),    false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5, 6}}), false);
+#endif   // TEST_NEAR_VLA_MAX_SIZE
+
+// Excessively large two dimensional VLAs.
+TEST (1, [1][d(LONG_MIN)],  Init (),       true);
+TEST (1, [1][d(INT_MIN)],   Init (),       true);
+TEST (1, [1][d(-1)],        Init (),       true);
+
+TEST (1, [1][d(SIZE_MAX)],  Init (),       true);
+
+#if !BUG_58646
+// The following cause an ICE due to c++/58646.
+TEST (1, [1][d(LONG_MIN)],  Init ({}),     true);
+TEST (1, [1][d(INT_MIN)],   Init ({}),     true);
+TEST (1, [1][d(-1)],        Init ({}),     true);
+TEST (1, [1][d(SIZE_MAX)],  Init ({}),     true);
+#endif
+
+TEST (1, [1][d(LONG_MIN)],  Init ({{0}}),  true);
+TEST (1, [1][d(INT_MIN)],   Init ({{0}}),  true);
+TEST (1, [1][d(-1)],        Init ({{0}}),  true);
+TEST (1, [1][d(SIZE_MAX)],  Init ({{0}}),  true);
+
+TEST (1, [d(LONG_MIN)][1],  Init (),       true);
+TEST (1, [d(INT_MIN)][1],   Init (),       true);
+TEST (1, [d(-1)][1],        Init (),       true);
+TEST (1, [d(SIZE_MAX)][1],  Init (),       true);
+
+TEST (1, [d(LONG_MIN)][1],  Init ({}),     true);
+TEST (1, [d(INT_MIN)][1],   Init ({}),     true);
+TEST (1, [d(-1)][1],        Init ({}),     true);
+TEST (1, [d(SIZE_MAX)][1],  Init ({}),     true);
+
+TEST (1, [d(LONG_MIN)][1],  Init ({{0}}),  true);
+TEST (1, [d(INT_MIN)][1],   Init ({{0}}),  true);
+TEST (1, [d(-1)][1],        Init ({{0}}),  true);
+TEST (1, [d(SIZE_MAX)][1],  Init ({{0}}),  true);
+
+// Two dimensional VLAs with no constant bound.
+TEST (1, [d(0)][d(0)],   Init (),          true);
+TEST (1, [d(0)][d(0)],   Init ({}),        true);
+#if !BUG_58646
+// The following cause an ICE due to c++/58646.
+TEST (1, [d(0)][d(0)],   Init ({{}}),      true);
+TEST (1, [d(0)][d(0)],   Init ({{}, {}}),  true);
+#endif
+
+TEST (1, [d(0)][d(0)],   Init ({{1}}),     true);
+TEST (1, [d(0)][d(0)],   Init ({{1, 2}}),  true);
+#if !BUG_58646
+TEST (1, [d(0)][d(0)],   Init ({{1}, {}}), true);
+TEST (1, [d(0)][d(0)],   Init ({{}, {1}}), true);
+#endif
+
+TEST (1, [d(1)][d(0)],   Init (),          true);
+TEST (1, [d(1)][d(0)],   Init ({}),        true);
+TEST (1, [d(1)][d(0)],   Init ({{1}}),     true);
+
+TEST (1, [d(1)][d(1)],   Init (),             false);
+TEST (1, [d(1)][d(1)],   Init ({{1}}),        false);
+TEST (1, [d(1)][d(1)],   Init ({{1, 2}}),     true);
+
+TEST (1, [d(1)][d(2)],   Init (),             false);
+TEST (1, [d(1)][d(2)],   Init ({{1}}),        false);
+TEST (1, [d(1)][d(2)],   Init ({{1, 2}}),     false);
+TEST (1, [d(1)][d(2)],   Init ({{1, 2, 3}}),  true);
+
+TEST (1, [d(2)][d(1)],   Init (),                 false);
+TEST (1, [d(2)][d(1)],   Init ({{1}}),            false);
+TEST (1, [d(2)][d(1)],   Init ({{1}, {2}}),       false);
+TEST (1, [d(2)][d(1)],   Init ({{1, 2}}),         true);
+TEST (1, [d(2)][d(1)],   Init ({{1}, {2, 3}}),    true);
+TEST (1, [d(2)][d(1)],   Init ({{1, 2, 3}}),      true);
+TEST (1, [d(2)][d(1)],   Init ({{1, 2, 3}, {4}}), true);
+TEST (1, [d(2)][d(1)],   Init ({{1, 2}, {3, 4}}), true);
+
+TEST (1, [d(2)][d(2)],   Init (),                       false);
+TEST (1, [d(2)][d(2)],   Init ({{1}}),                  false);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2}}),               false);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2}, {3}}),          false);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2}, {3, 4}}),       false);
+TEST (1, [d(2)][d(2)],   Init ({{1}, {2, 3, 4}}),       true);
+TEST (1, [d(2)][d(2)],   Init ({{1}, {2, 3, 4, 5}}),    true);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2}, {3, 4, 5}}),    true);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2, 3}, {4, 5}}),    true);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2, 3}, {4, 5, 6}}), true);
+
+TEST (1, [d(2)][d(3)],   Init (),                          false);
+TEST (1, [d(2)][d(3)],   Init ({{1}}),                     false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2}}),                  false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2}, {3}}),             false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2}, {3, 4}}),          false);
+TEST (1, [d(2)][d(3)],   Init ({{1}, {2, 3, 4}}),          false);
+TEST (1, [d(2)][d(3)],   Init ({{1}, {2, 3, 4, 5}}),       true);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2}, {3, 4, 5}}),       false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3}, {4, 5}}),       false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3}, {4, 5, 6}}),    false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3}, {4, 5, 6, 7}}), true);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3, 4}, {5, 6, 7}}), true);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3, 4, 5}, {6, 7}}), true);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3, 4, 5, 6}, {7}}), true);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3, 4, 5, 6, 7}}),   true);
+
+#if TEST_NEAR_VLA_MAX_SIZE
+TEST (1, [d(1)][d(MAX)], Init (),                              false);
+TEST (1, [d(1)][d(MAX)], Init ({}),                            false);
+TEST (1, [d(1)][d(MAX)], Init ({{1}}),                         false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2}}),                      false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3}}),                   false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4}}),                false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5}}),             false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6}}),          false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6, 7}}),       false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6, 7, 8}}),    false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6, 7, 8, 9}}), false);
+
+TEST (1, [d(2)][d(MAX / 2)], Init (),                              false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1}}),                         false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2}}),                      false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}}),                   false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4}}),                false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5}}),             false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6}}),          false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6, 7}}),       false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6, 7, 8}}),    false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6, 7, 8, 9}}), false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1}, {2}}),                    false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1}, {2, 3}}),                 false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2}, {3}}),                 false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2}, {3, 4}}),              false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}, {4}}),              false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5}}),           false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5, 6}}),        false);
+#endif
+
+TEST (1, [d(2)][d(MAX)],        Init (),                         true);
+TEST (1, [d(2)][d(MAX)],        Init ({{1}}),                    true);
+TEST (1, [d(MAX)][d(MAX)],      Init ({{1, 2}}),                 true);
+TEST (1, [d(0)][d(MAX)],        Init ({{1}, {2}}),               true);
+TEST (1, [d(INT_MAX)][d(MAX)],  Init ({{1}, {2, 3}}),            true);
+TEST (1, [d(SIZE_MAX)][d(MAX)], Init ({{1, 2}, {3, 4}, {5}}),    true);
+
+// Erroneous two-dimensional VLAs with size exceeding SIZE_MAX / 2
+// (those must be rejected because no object can be bigger than that,
+// otherwise pointer arithmetic breaks).
+TEST ( 1, [2][d(SIZE_MAX/2)],  Init (), true);
+TEST ( 2, [2][d(SIZE_MAX/4)],  Init (), true);
+TEST ( 4, [2][d(SIZE_MAX/8)],  Init (), true);
+TEST ( 8, [2][d(SIZE_MAX/16)], Init (), true);
+TEST (16, [2][d(SIZE_MAX/32)], Init (), true);
+
+TEST ( 1, [d(SIZE_MAX/2)][2],  Init (), true);
+TEST ( 2, [d(SIZE_MAX/4)][2],  Init (), true);
+TEST ( 4, [d(SIZE_MAX/8)][2],  Init (), true);
+TEST ( 8, [d(SIZE_MAX/16)][2], Init (), true);
+TEST (16, [d(SIZE_MAX/32)][2], Init (), true);
+
+// Verify that the unspecified bound is factored into the computation
+// of the total size.
+TEST ( 1, [][d(SIZE_MAX/2)],  Init ({{1}, {2}}),      true);
+TEST ( 2, [][d(SIZE_MAX/4)],  Init ({{1}, {2}}),      true);
+TEST ( 4, [][d(SIZE_MAX/8)],  Init ({{1}, {2}}),      true);
+TEST ( 8, [][d(SIZE_MAX/16)], Init ({{1}, {2}}),      true);
+TEST (16, [][d(SIZE_MAX/32)], Init ({{1}, {2}}),      true);
+TEST (16, [][d(SIZE_MAX/64)], Init ({{1}, {2}, {3}}), true);
+
+// Three dimensional VLAs with two constant bounds.
+
+TEST (1, [1][1][d(-1)], Init (),                    true);
+TEST (1, [1][1][d(0)], Init (),                     true);
+
+#if !BUG_58646
+// The following causes an ICE due to c++/58646.
+TEST (1, [1][1][d(0)],  Init ({}),                   true);
+TEST (1, [1][1][d(-1)], Init ({{}}),                 true);
+TEST (1, [1][d(-1)][1], Init ({{}}),                 true);
+TEST (1, [d(-1)][1][1], Init ({{}}),                 true);
+
+TEST (1, [1][1][d(0)], Init ({{}}),                  true);
+TEST (1, [1][d(0)][1], Init ({{}}),                  true);
+TEST (1, [d(0)][1][1], Init ({{}}),                  true);
+#endif
+
+TEST (1, [1][1][d(1)], Init (),                      false);
+
+#if !BUG_58646
+TEST (1, [1][1][d(1)], Init ({{}}),                  false);
+TEST (1, [1][1][d(1)], Init ({{{}}}),                false);
+TEST (1, [1][1][d(1)], Init ({{{1}}}),               false);
+#endif
+
+TEST (1, [1][1][d(1)], Init ({{{1, 2}}}),            true);
+TEST (1, [1][1][d(1)], Init ({{{1, 2, 3}}}),         true);
+
+TEST (1, [1][d(1)][1], Init (),                      false);
+
+#if !BUG_58646
+TEST (1, [1][d(1)][1], Init ({{}}),                  false);
+TEST (1, [1][d(1)][1], Init ({{{}}}),                false);
+#endif
+
+TEST (1, [1][d(1)][1], Init ({{{1}}}),               false);
+TEST (1, [1][d(1)][1], Init ({{{1}, {2}}}),          true);
+TEST (1, [1][d(1)][1], Init ({{{1}, {2}, {3}}}),     true);
+
+TEST (1, [d(1)][1][1], Init (),                      false);
+
+#if !BUG_58646
+TEST (1, [d(1)][1][1], Init ({{}}),                  false);
+TEST (1, [d(1)][1][1], Init ({{{}}}),                false);
+#endif
+
+TEST (1, [d(1)][1][1], Init ({{{1}}}),               false);
+TEST (1, [d(1)][1][1], Init ({{{1}}, {{2}}}),        true);
+TEST (1, [d(1)][1][1], Init ({{{1}}, {{2}}, {{3}}}), true);
+
+TEST (1, [1][1][d(2)], Init (),                      false);
+
+#if !BUG_58646
+TEST (1, [1][1][d(2)], Init ({{}}),                  false);
+TEST (1, [1][1][d(2)], Init ({{{}}}),                false);
+#endif
+
+TEST (1, [1][1][d(2)], Init ({{{1}}}),               false);
+TEST (1, [1][1][d(2)], Init ({{{1, 2}}}),            false);
+TEST (1, [1][1][d(2)], Init ({{{1, 2, 3}}}),         true);
+
+TEST (1, [1][d(2)][1], Init (),                      false);
+
+#if !BUG_58646
+TEST (1, [1][d(2)][1], Init ({{}}),                  false);
+TEST (1, [1][d(2)][1], Init ({{{}}}),                false);
+#endif
+TEST (1, [1][d(2)][1], Init ({{{1}}}),               false);
+TEST (1, [1][d(2)][1], Init ({{{1}, {2}}}),          false);
+TEST (1, [1][d(2)][1], Init ({{{1}, {2}, {3}}}),     true);
+
+TEST (1, [d(2)][1][1], Init (),                      false);
+
+#if !BUG_58646
+TEST (1, [d(2)][1][1], Init ({{}}),                  false);
+TEST (1, [d(2)][1][1], Init ({{{}}}),                false);
+#endif
+TEST (1, [d(2)][1][1], Init ({{{1}}}),               false);
+TEST (1, [d(2)][1][1], Init ({{{1}}, {{2}}}),        false);
+TEST (1, [d(2)][1][1], Init ({{{1}}, {{2}}, {{3}}}), true);
+
+TEST (1, [1][2][d(2)], Init (),                      false);
+
+#if !BUG_58646
+TEST (1, [1][2][d(2)], Init ({{}}),                  false);
+TEST (1, [1][2][d(2)], Init ({{{}}}),                false);
+#endif
+
+TEST (1, [1][2][d(2)], Init ({{{1}}}),               false);
+TEST (1, [1][2][d(2)], Init ({{{1, 2}}}),            false);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3}}}),         true);
+
+TEST (1, [1][2][d(2)], Init ({{{1}, {2}}}),          false);
+TEST (1, [1][2][d(2)], Init ({{{1}, {2, 3}}}),       false);
+TEST (1, [1][2][d(2)], Init ({{{1, 2}, {3}}}),       false);
+TEST (1, [1][2][d(2)], Init ({{{1, 2}, {3, 4}}}),    false);
+TEST (1, [1][2][d(2)], Init ({{{1}, {2, 3, 4}}}),    true);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3}, {}}}),     true);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3}, {4}}}),    true);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3, 4}}}),      true);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3, 4}, {}}}),  true);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3, 4}, {5}}}), true);
+
+TEST (1, [2][2][d(2)], Init ({{{1}, {2}}}),                         false);
+TEST (1, [2][2][d(2)], Init ({{{1}, {2, 3}}}),                      false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}}}),                           false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3}}}),                      false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}}),                   false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5}}}),            false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}}}),         false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7}}}),    false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}), false);
+
+TEST (1, [2][2][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3}, {}}}),                       true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3}, {4}}}),                      true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3, 4}}}),                        true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3, 4}, {}}}),                    true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3, 4}, {5}}}),                   true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8, 9}}}), true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6, 7}, {8, 9}}}), true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4, 5}}, {{6, 7}, {8, 9}}}), true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3}, {4, 5}}, {{6, 7}, {8, 9}}}), true);
+TEST (1, [2][2][d(2)], Init ({{{1}, {2}}, {{3}, {4, 5, 6}}}),          true);
+TEST (1, [2][2][d(2)], Init ({{{1}}, {{2}, {3, 4, 5, 6}}}),            true);
+
+// Three dimensional VLAs with one constant bound.
+TEST (1, [2][d(-1)][d(-1)], Init (),                                      true);
+TEST (1, [2][d(-1)][d(0)],  Init (),                                      true);
+TEST (1, [2][d(0)][d(-1)],  Init (),                                      true);
+TEST (1, [2][d(1)][d(-1)],  Init (),                                      true);
+TEST (1, [2][d(1)][d(0)],   Init (),                                      true);
+TEST (1, [2][d(-1)][d(1)],  Init (),                                      true);
+TEST (1, [2][d(0)][d(1)],   Init (),                                      true);
+
+TEST (1, [2][d(2)][d(2)], Init (),                                        false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}}}),                                 false);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1}}}),                                 false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2}}}),                            false);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1}, {2}}}),                            false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3}}}),                         false);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1}, {2, 3}}}),                         false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3}}}),                         false);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2}, {3}}}),                         false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}}),                      false);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}}),                      false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}),    false);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}),    false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {}}}),                       true);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3}, {}}}),                       true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {4}}}),                      true);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3}, {4}}}),                      true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}}}),                        true);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3, 4}}}),                        true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {}}}),                    true);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {}}}),                    true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {5}}}),                   true);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {5}}}),                   true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3}, {4}}}),                    true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {}}}),                       true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {4}}}),                      true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}}}),                        true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {}}}),                    true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {5}}}),                   true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8, 9}}}), true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6, 7}, {8, 9}}}), true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4, 5}}, {{6, 7}, {8, 9}}}), true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {4, 5}}, {{6, 7}, {8, 9}}}), true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2}}, {{3}, {4, 5, 6}}}),          true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}}, {{2}, {3, 4, 5, 6}}}),            true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2}, {3}}}),                       true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3}, {4}}}),                    true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3, 4}, {5}}}),                 true);
+
+#if TEST_NEAR_VLA_MAX_SIZE
+// Very large but not erroneous three-dimensional VLAs.
+TEST ( 1, [2][d(1)][d(MAX/2)], Init (),  false);
+TEST ( 2, [2][d(1)][d(MAX/4)], Init (),  false);
+TEST ( 4, [2][d(1)][d(MAX/8)], Init (),  false);
+TEST ( 8, [2][d(1)][d(MAX/16)], Init (), false);
+TEST (16, [2][d(1)][d(MAX/32)], Init (), false);
+
+TEST ( 1, [2][d(MAX/2)][d(1)], Init (),  false);
+TEST ( 2, [2][d(MAX/4)][d(1)], Init (),  false);
+TEST ( 4, [2][d(MAX/8)][d(1)], Init (),  false);
+TEST ( 8, [2][d(MAX/16)][d(1)], Init (), false);
+TEST (16, [2][d(MAX/32)][d(1)], Init (), false);
+
+TEST ( 1, [d(MAX/2)][2][d(1)], Init (),  false);
+TEST ( 2, [d(MAX/4)][2][d(1)], Init (),  false);
+TEST ( 4, [d(MAX/8)][2][d(1)], Init (),  false);
+TEST ( 8, [d(MAX/16)][2][d(1)], Init (), false);
+TEST (16, [d(MAX/32)][2][d(1)], Init (), false);
+#endif   // TEST_NEAR_VLA_MAX_SIZE
+
+// Erroneous three-dimensional VLAs with size exceeding SIZE_MAX / 2
+// (those must be rejected because no object can be bigger than that,
+// otherwise pointer arithmetic breaks).
+TEST ( 1, [2][d(1)][d(SIZE_MAX/2)],  Init (), true);
+TEST ( 2, [2][d(1)][d(SIZE_MAX/4)],  Init (), true);
+TEST ( 4, [2][d(1)][d(SIZE_MAX/8)],  Init (), true);
+TEST ( 8, [2][d(1)][d(SIZE_MAX/16)], Init (), true);
+TEST (16, [2][d(1)][d(SIZE_MAX/32)], Init (), true);
+
+TEST ( 1, [2][d(SIZE_MAX/2)][d(1)],  Init (), true);
+TEST ( 2, [2][d(SIZE_MAX/4)][d(1)],  Init (), true);
+TEST ( 4, [2][d(SIZE_MAX/8)][d(1)],  Init (), true);
+TEST ( 8, [2][d(SIZE_MAX/16)][d(1)], Init (), true);
+TEST (16, [2][d(SIZE_MAX/32)][d(1)], Init (), true);
+
+TEST ( 1, [d(SIZE_MAX/2)][2][d(1)],  Init (), true);
+TEST ( 2, [d(SIZE_MAX/4)][2][d(1)],  Init (), true);
+TEST ( 4, [d(SIZE_MAX/8)][2][d(1)],  Init (), true);
+TEST ( 8, [d(SIZE_MAX/16)][2][d(1)], Init (), true);
+TEST (16, [d(SIZE_MAX/32)][2][d(1)], Init (), true);
+
+TEST (16, [3][d(SIZE_MAX)][d(SIZE_MAX)], Init (), true);
+TEST (32, [d(SIZE_MAX)][5][d(SIZE_MAX)], Init (), true);
+TEST (64, [d(SIZE_MAX)][d(SIZE_MAX)][7], Init (), true);
+
+int main ()
+{
+  if (fail)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla12.C b/gcc/testsuite/g++.dg/cpp1y/vla12.C
new file mode 100644
index 0000000..a8db578
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla12.C
@@ -0,0 +1,69 @@
+// Test to verify that variable length arrays whose size overflows
+// or exceeds the implementation-defined limit is diagnosed.
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-Wno-error=vla" }
+
+#define INT_MAX    __INT_MAX__
+#define LONG_MAX   __LONG_MAX__
+#define SIZE_MAX   __SIZE_MAX__
+
+typedef __SIZE_TYPE__ size_t;
+
+void test (int x, int y, int z)
+{
+  const size_t amax = SIZE_MAX / 2;
+
+  {
+    char a [x][amax];         // { dg-warning "forbids|size of variable length array exceeds maximum" }
+    (void)a;
+  }
+
+  {
+    char a [amax][y];         // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    char a [x][y][amax];      // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    char a [x][amax][z];      // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    char a [amax][y][z];      // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    // Unfortunately, this is rejected with a different error earlier
+    // during parsing and before the VLA checking gets to see it:
+    //   error: size of array ‘a’ is too large
+    char a [x][amax][amax];   // { dg-error "size of array" }
+
+    // That error above also leads to the following error when using
+    // the variable below.
+    //   error:’ was not declared in this scope
+    // (void)a;
+  }
+
+  {
+    char a [amax][y][amax];   // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    char a [amax][amax][z];   // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+
+  {
+    struct A256 { __attribute__ ((aligned (256))) char a; };
+
+    A256 a [x][1024][y][1024][z][1024][x][1024][z];   // { dg-warning "forbids|size of variable length array" }
+    (void)a;
+  }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla13.C b/gcc/testsuite/g++.dg/cpp1y/vla13.C
new file mode 100644
index 0000000..d473a63
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla13.C
@@ -0,0 +1,260 @@
+// PR c++/70019 - VLA size overflow not detected
+// Runtime test to verify that attempting to initialize a VLA with a string
+// or character array that's longer than the non-constant (runtime) bound
+// of the VLA causes an exception to be thrown.  For a compile-time version
+// of the test see vla14.C.
+
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-Wno-vla" }
+
+#pragma GCC diagnostic ignored "-Wvla"
+
+#define SIZE_MAX   __SIZE_MAX__
+
+// The size of the largest allowed VLA in bytes.  Bigger objects
+// cause an exception to be thrown.  Unless the maximum size is
+// obscenely large, smaller objects should be successfully created
+// provided there's enough stack space.  See TEST_NEAR_VLA_MAX_SIZE
+// below.
+#define MAX   (__SIZE_MAX__ / 2)
+
+// Define to non-zero to exercise very large VLAs with size just
+// below the implementation-defined maximum.
+#define TEST_NEAR_VLA_MAX_SIZE    0
+
+// Define to zero to enable tests that cause an ICE due to c++/58646.
+#define BUG_58646 1
+
+// Define to zero to enable tests that cause an ICE due to c++/69487.
+#define BUG_69487 1
+
+// Helper macro to make it possible to pass as one multpile arguments
+// to another macro.
+#define Init(...) __VA_ARGS__
+
+typedef __SIZE_TYPE__ size_t;
+
+// Incremented for each test failure.
+int fail;
+
+// Used to convert a constant array dimension to a non-constant one.
+template <class T>
+T d (T n)
+{
+  return n;
+}
+
+// Verify either that an expected exception has been thrown or that
+// one hasn't been thrown if one isn't expected.
+int __attribute__ ((noclone, noinline))
+sink (void *p, int line, bool expect, const char *expr)
+{
+  if (!p != expect)
+    {
+      __builtin_printf ("line %i: Assertion failed: '%s': "
+                        "exception unexpectedly %sthrown\n",
+                        line, expr, !p ? "" : "not ");
+      ++fail;
+    }
+  else
+    {
+#if defined DEBUG && DEBUG
+    __builtin_printf ("line %i: Assertion passed: '%s': "
+		      "exception %sthrown as expected\n",
+		      line, expr, !p ? "" : "not ");
+#endif
+    }
+  return 0;
+}
+
+template <class T, int>
+int test ();
+
+#define _CAT(name, line) name ## line
+#define CAT(name, line) _CAT (name, line)
+
+#define STR(...) #__VA_ARGS__
+
+// Macro to define a unique specialization of a function template to
+// exercise a VLA of type T, rank N, with dimensions given by Dims
+// and initializer Init.  Expect is true when the VLA initialization
+// is expected to trigger an exception.
+// The macro creates a unique global dummy int object and initializes
+// it with the result of the function.  The dummy object servers no
+// other purpose but to call the function.  The function verifies
+// the expected postconditions.
+#define TEST(T, Dims, Init, Expect)                                     \
+  template <>                                                           \
+  int test<T, __LINE__>()                                               \
+  {                                                                     \
+    const char str[] = "char a" #Dims " = { " STR (Init) " }";          \
+    try {                                                               \
+      T a Dims = { Init };                                              \
+      return sink (a, __LINE__, Expect, str);                           \
+    }                                                                   \
+    catch (...) {                                                       \
+      return sink (0, __LINE__, Expect, str);                           \
+    }                                                                   \
+  }                                                                     \
+  const int CAT (dummy, __LINE__) = test<T, __LINE__>()
+
+
+// Create and run a test function exercising a VLA definition
+//    +-- Element Type
+//    |     +-- VLA Dimensions
+//    |     |        +-- VLA Initializer
+//    |     |        |
+//    |     |        |             +-- Expect Exception
+//    |     |        |             |
+//    V     V        V             V
+TEST (char, [d(-1)], "",           true);
+
+TEST (char, [d(0)],  "",           true);
+TEST (char, [d(0)],  (""),         true);
+
+TEST (char, [d(1)],  "",           false);
+TEST (char, [d(1)],  (""),         false);
+
+TEST (char, [d(1)],  "1",          true);
+TEST (char, [d(1)],  ("1"),        true);
+
+TEST (char, [d(1)],  "12",         true);
+TEST (char, [d(1)],  "1234567890", true);
+
+TEST (char, [d(2)], "",           false);
+TEST (char, [d(2)], (""),         false);
+
+TEST (char, [d(2)], "1",          false);
+TEST (char, [d(2)], "12",         true);
+TEST (char, [d(2)], "123",        true);
+TEST (char, [d(2)], "1234567890", true);
+
+TEST (char, [d(3)], "",           false);
+TEST (char, [d(3)], "1",          false);
+TEST (char, [d(3)], "12",         false);
+TEST (char, [d(3)], "123",        true);
+TEST (char, [d(3)], "1234",       true);
+TEST (char, [d(3)], "1234567890", true);
+
+#if TEST_NEAR_VLA_MAX_SIZE
+
+#  if !BUG_69487
+// The following crash due to c++/69487.
+TEST (char, [d(MAX)], "",           false);
+TEST (char, [d(MAX)], "1",          false);
+TEST (char, [d(MAX)], "12",         false);
+TEST (char, [d(MAX)], "1234567890", false);
+#  endif
+
+TEST (char, [d(MAX)], Init (),                             false);
+TEST (char, [d(MAX)], Init (1),                            false);
+TEST (char, [d(MAX)], Init (1, 2),                         false);
+TEST (char, [d(MAX)], Init (1, 2, 3, 4, 5, 6, 7, 8, 9, 0), false);
+#endif
+
+TEST (char, [d(SIZE_MAX / 2 + 1)], "", true);
+TEST (char, [d(SIZE_MAX - 2)],     "", true);
+TEST (char, [d(SIZE_MAX - 1)],     "", true);
+
+TEST (wchar_t, [d(1)], L"",           false);
+TEST (wchar_t, [d(1)], (L""),         false);
+TEST (wchar_t, [d(1)], L"1",          true);
+TEST (wchar_t, [d(1)], L"12",         true);
+TEST (wchar_t, [d(1)], L"1234567890", true);
+
+TEST (wchar_t, [d(2)], L"",           false);
+TEST (wchar_t, [d(2)], L"1",          false);
+TEST (wchar_t, [d(2)], L"12",         true);
+TEST (wchar_t, [d(2)], L"123",        true);
+TEST (wchar_t, [d(2)], L"1234567890", true);
+
+TEST (char, [d(1)][d(1)], Init (""),        false);
+TEST (char, [1]   [d(1)], Init (""),        false);
+TEST (char, [d(1)][1],    Init (""),        false);
+
+TEST (char, [d(1)][d(1)], Init ("1"),       true);
+
+// The following is accepted at compile time but throws an exception
+// at runtime since in C++ a one-element array cannot be initialized
+// with a string literal of length one because there isn't room for
+// the terminating NUL
+TEST (char, [1][d(1)],    Init ("1"),       true);
+
+// The following is rejected at compile-time since a one-element array
+// cannot be initialized with a string literal of length one because
+// there isn't room for the terminating NUL (see vla14.C).
+// TEST (char, [d(1)][1],    Init ("1"),       false);
+
+TEST (char, [d(1)][d(1)], Init ("12"),      true);
+TEST (char, [d(1)][d(1)], Init ("1", "2"),  true);
+TEST (char, [d(1)][d(1)], Init ("1", "23"), true);
+
+TEST (char, [d(2)][d(2)], Init ("", ""),    false);
+TEST (char, [d(2)][d(2)], Init ("", "1"),   false);
+TEST (char, [d(2)][d(2)], Init ("1", ""),   false);
+TEST (char, [d(2)][d(2)], Init ("1", "1"),  false);
+TEST (char, [2][d(2)],    Init ("",  "1"),  false);
+TEST (char, [2][d(2)],    Init ("1", ""),   false);
+TEST (char, [2][d(2)],    Init ("1", "1"),  false);
+TEST (char, [d(2)][2],    Init ("",  "1"),  false);
+TEST (char, [d(2)][2],    Init ("1", ""),   false);
+TEST (char, [d(2)][2],    Init ("1", "1"),  false);
+
+TEST (char, [2][d(2)],    Init ("1", "23"), true);
+TEST (char, [d(2)][d(2)], Init ("1", "23"), true);
+TEST (char, [d(2)][d(2)], Init ("1", "23"), true);
+TEST (char, [d(2)][d(2)], Init ("12","3"),  true);
+
+#if TEST_NEAR_VLA_MAX_SIZE
+#  if !BUG_69487
+   // The following crash due to c++/69487.
+TEST (char, [1][d(MAX)], Init (""),           false);
+TEST (char, [1][d(MAX)], Init ("1"),          false);
+TEST (char, [1][d(MAX)], Init ("12"),         false);
+TEST (char, [1][d(MAX)], Init ("1234567890"), false);
+#  endif
+
+#  if !BUG_58646
+// The following causes an ICE due to c++/58646.
+TEST (char, [1][d(MAX)], Init (),                               false);
+#  endif
+
+TEST (char, [1][d(MAX)], Init ({1}),                            false);
+TEST (char, [1][d(MAX)], Init ({1, 2}),                         false);
+TEST (char, [1][d(MAX)], Init ({1, 2, 3}),                      false);
+TEST (char, [1][d(MAX)], Init ({1, 2, 3, 4, 5, 6, 7, 8, 9, 0}), false);
+
+TEST (char, [d(MAX)][1], Init ({1}),                            false);
+TEST (char, [d(MAX)][1], Init ({1}, {2}),                       false);
+TEST (char, [d(MAX)][1], Init ({1}, {2}, {3}),                  false);
+TEST (char, [d(MAX)][1], Init ({1}, {2}, {3}, {4}, {5},
+			       {6}, {7}, {8}, {9}, {0}),        false);
+#endif   // TEST_NEAR_VLA_MAX_SIZE
+
+// The following are expected to throw due to excessive size.
+TEST (char, [2][d(MAX)], Init ({1}),                                 true);
+TEST (char, [2][d(MAX)], Init ({1, 2}),                              true);
+TEST (char, [2][d(MAX)], Init ({1}, {2}),                            true);
+TEST (char, [2][d(MAX)], Init ({1, 2}, {3, 4}),                      true);
+TEST (char, [2][d(MAX)], Init ({1, 2, 3}, {4, 5, 6}),                true);
+TEST (char, [2][d(MAX)], Init ({1, 2, 3, 4}, {5, 6, 7, 8}),          true);
+
+TEST (char, [d(MAX)][2], Init ({1}),                                 true);
+TEST (char, [d(MAX)][2], Init ({1, 2}),                              true);
+TEST (char, [d(MAX)][2], Init ({1}, {2}),                            true);
+TEST (char, [d(MAX)][2], Init ({1, 2}, {3, 4}),                      true);
+TEST (char, [d(MAX)][2], Init ({1, 2}, {3, 4}, {5, 6}),              true);
+TEST (char, [d(MAX)][2], Init ({1, 2}, {3, 4}, {5, 6}, {7, 8}),      true);
+
+TEST (char, [d(MAX)][d(MAX)], Init ({1}),                            true);
+TEST (char, [d(MAX)][d(MAX)], Init ({1, 2}),                         true);
+TEST (char, [d(MAX)][d(MAX)], Init ({1}, {2}),                       true);
+TEST (char, [d(MAX)][d(MAX)], Init ({1, 2}, {3, 4}),                 true);
+TEST (char, [d(MAX)][d(MAX)], Init ({1, 2}, {3, 4}, {5, 6}),         true);
+TEST (char, [d(MAX)][d(MAX)], Init ({1, 2}, {3, 4}, {5, 6}, {7, 8}), true);
+
+int main ()
+{
+  if (fail)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla14.C b/gcc/testsuite/g++.dg/cpp1y/vla14.C
new file mode 100644
index 0000000..4a0e827
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla14.C
@@ -0,0 +1,48 @@
+// PR c++/70019 - VLA size overflow not detected
+// Compile-time test to verify that attempting to initialize a VLA with
+// a string that's longer than the VLA's constant bound is diagnosed at
+// compile time.  For a runtime version of the test see vla13.C.
+
+// { dg-do run }
+// { dg-additional-options "-Wno-vla" }
+
+
+void test (int n)
+{
+  char a1[n][1] = { { "a" } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a1;
+
+  char a2[1][n] = { { "a" } };
+  (void)a2;
+
+  char a3[n][1][1] = { { { "a" } } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a3;
+
+  char a4[1][1][n] = { { { "a" } } };
+  (void)a4;
+
+  char a5[1][n][1] = { { { "a" } } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a5;
+
+  char a6[n][1][n] = { { { "a" } } };
+  (void)a6;
+
+
+  wchar_t a7[n][1] = { { L"a" } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a7;
+
+  wchar_t a8[1][n] = { { L"a" } };
+  (void)a8;
+
+  wchar_t a9[n][1][1] = { { { L"a" } } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a9;
+
+  wchar_t a10[1][1][n] = { { { L"a" } } };
+  (void)a10;
+
+  wchar_t a11[][n][1] = { { { L"a" } } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a11;
+
+  wchar_t a12[n][1][n] = { { { L"a" } } };
+  (void)a12;
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla3.C b/gcc/testsuite/g++.dg/cpp1y/vla3.C
new file mode 100644
index 0000000..9b2d6b3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla3.C
@@ -0,0 +1,43 @@
+// Test for throwing bad_array_length on invalid array length.
+// { dg-do run { target c++14 } }
+// { dg-additional-options "-Wno-vla" }
+
+namespace std
+{
+struct exception
+{
+  virtual ~exception ();
+  virtual const char* what () const throw ();
+};
+}
+
+int f(int i)
+{
+  int ar[i]{1,2,3,4};
+  return ar[i-1];
+}
+
+void g(int i)
+{
+  int ar[i];
+  ar[0] = 42;
+}
+
+int main()
+{
+  int ok = 0;
+  f(4);				// OK
+  try {
+    f(3);			// too small
+  }
+  catch (std::exception &e) {
+    ++ok;
+  }
+  try { g(-24); }		// negative
+  catch (std::exception &e) {
+    ++ok;
+  }
+
+  if (ok != 2)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/init/array24.C b/gcc/testsuite/g++.dg/init/array24.C
index 2d72df4..fc10c0a 100644
--- a/gcc/testsuite/g++.dg/init/array24.C
+++ b/gcc/testsuite/g++.dg/init/array24.C
@@ -3,5 +3,5 @@
 
 void foo(int i)
 {
-  int x[][i] = { 0 };
+  int x[][i] = { { 0 } };
 }
diff --git a/gcc/testsuite/g++.dg/ubsan/vla-1.C b/gcc/testsuite/g++.dg/ubsan/vla-1.C
index 311cdb1..374c80a 100644
--- a/gcc/testsuite/g++.dg/ubsan/vla-1.C
+++ b/gcc/testsuite/g++.dg/ubsan/vla-1.C
@@ -1,5 +1,8 @@
 // { dg-do run }
-// { dg-options "-Wno-vla -fsanitize=undefined" }
+// Disable exceptions to prevent the erroneous initializer from
+// throwing before the sanitizer instrumentation has detected
+// the problem.
+// { dg-options "-Wno-vla -fno-exceptions -fsanitize=undefined" }
 // { dg-output "index 1 out of bounds" }
 
 void f(int i) {
diff --git a/libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc b/libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc
index d9d1f2a..f944236 100644
--- a/libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc
@@ -44,7 +44,8 @@ template<typename Con>
   {
     bool test __attribute__((unused)) = true;
 
-    rvalstruct array[length];
+    /* Make sure the VLA upper bound is positive. */
+    rvalstruct array[length + 1];
     for(int i = 0; i < length; ++i)
       array[i] = i;
     Con con(array, array + length);


[-- Attachment #3: gcc-69517-alt.patch --]
[-- Type: text/x-patch, Size: 17622 bytes --]

PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
PR c++/70019 - VLA size overflow not detected
PR c++/70588 - SIGBUS on a VLA larger than SIZE_MAX / 2

gcc/cp/ChangeLog:
2016-04-13  Martin Sebor  <msebor@redhat.com>

	PR c++/69517
	PR c++/70019
	PR c++/70588
	* cp-tree.h (throw_bad_array_length, build_vla_check): Declare new
	functions.
	* decl.c (check_initializer, cp_finish_decl): Call them.
	(reshape_init_r): Reject incompletely braced intializer-lists
	for VLAs.
	* init.c (throw_bad_array_length, build_vla_check)
	(build_vla_size_check, build_vla_init_check): Define new functions.
	* typeck2.c (split_nonconstant_init_1): Use variably_modified_type_p()
	to detect a VLA.
	(store_init_value): Same.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b7b770f..1d726fd 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5978,6 +5978,7 @@ extern tree build_value_init_noctor		(tree, tsubst_flags_t);
 extern tree get_nsdmi				(tree, bool);
 extern tree build_offset_ref			(tree, tree, bool,
 						 tsubst_flags_t);
+extern tree throw_bad_array_length              (void);
 extern tree throw_bad_array_new_length		(void);
 extern tree build_new				(vec<tree, va_gc> **, tree, tree,
 						 vec<tree, va_gc> **, int,
@@ -5999,6 +6000,7 @@ extern tree scalar_constant_value		(tree);
 extern tree decl_really_constant_value		(tree);
 extern int diagnose_uninitialized_cst_or_ref_member (tree, bool, bool);
 extern tree build_vtbl_address                  (tree);
+extern tree build_vla_check                     (tree, tree = NULL_TREE);
 
 /* in lex.c */
 extern void cxx_dup_lang_specific_decl		(tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 9260f4c..e626875 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5864,6 +5864,16 @@ reshape_init_r (tree type, reshape_iter *d, bool first_initializer_p,
 	    }
 	}
 
+      if (variably_modified_type_p (type, NULL_TREE))
+	{
+	  /* Require VLAs to have their initializers fully braced
+	     to avoid initializing the wrong elements.  */
+	  if (complain & tf_error)
+	    error ("missing braces around initializer for a variable length "
+		   "array %qT", type);
+	  return error_mark_node;
+	}
+
       warning (OPT_Wmissing_braces, "missing braces around initializer for %qT",
 	       type);
     }
@@ -6016,6 +6026,10 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
     /* There is no way to make a variable-sized class type in GNU C++.  */
     gcc_assert (TREE_CONSTANT (TYPE_SIZE (type)));
 
+  /* Initializer exression used to check invalid VLA bounds and excess
+     initializer elements.  */
+  tree saved_init_for_vla_check = NULL_TREE;
+
   if (init && BRACE_ENCLOSED_INITIALIZER_P (init))
     {
       int init_len = vec_safe_length (CONSTRUCTOR_ELTS (init));
@@ -6167,7 +6181,9 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
 	      && PAREN_STRING_LITERAL_P (DECL_INITIAL (decl)))
 	    warning (0, "array %qD initialized by parenthesized string literal %qE",
 		     decl, DECL_INITIAL (decl));
-	  init = NULL;
+
+	  saved_init_for_vla_check = init;
+	  init = NULL_TREE;
 	}
     }
   else
@@ -6181,6 +6197,33 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
       check_for_uninitialized_const_var (decl);
     }
 
+  if (TREE_CODE (type) == ARRAY_TYPE
+      && variably_modified_type_p (type, NULL_TREE)
+      && !processing_template_decl)
+    {
+      /* Statically check for overflow in VLA bounds and build
+	 an expression that checks at runtime whether the VLA
+	 is erroneous due to invalid (runtime) bounds.
+	 Another expression to check for excess initializers
+	 is built in build_vec_init.  */
+      tree check = build_vla_check (TREE_TYPE (decl), saved_init_for_vla_check);
+
+      if (flag_exceptions && current_function_decl
+	  /* Avoid instrumenting constexpr functions for now.
+	     Those must be checked statically, and the (non-
+	     constexpr) dynamic instrumentation would cause
+	     them to be rejected.  See c++/70507.  */
+	  && !DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+	{
+	  /* Use the runtime check only when exceptions are enabled.
+	     Otherwise let bad things happen...  */
+	  check = build3 (COND_EXPR, void_type_node, check,
+			  throw_bad_array_length (), void_node);
+
+	  finish_expr_stmt (check);
+	}
+    }
+
   if (init && init != error_mark_node)
     init_code = build2 (INIT_EXPR, type, decl, init);
 
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 5997d53..ec19d72 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2262,6 +2262,20 @@ diagnose_uninitialized_cst_or_ref_member (tree type, bool using_new, bool compla
   return diagnose_uninitialized_cst_or_ref_member_1 (type, type, using_new, complain);
 }
 
+/* Call __cxa_throw_bad_array_length to indicate that the size calculation
+   in the bounds of a variable length array overflowed.  */
+
+tree
+throw_bad_array_length (void)
+{
+  tree fn = get_identifier ("__cxa_throw_bad_array_length");
+  if (!get_global_value_if_present (fn, &fn))
+    fn = push_throw_library_fn (fn, build_function_type_list (void_type_node,
+                                                             NULL_TREE));
+
+  return build_cxx_call (fn, 0, NULL, tf_warning_or_error);
+}
+
 /* Call __cxa_bad_array_new_length to indicate that the size calculation
    overflowed.  Pretend it returns sizetype so that it plays nicely in the
    COND_EXPR.  */
@@ -4709,3 +4723,304 @@ build_vec_delete (tree base, tree maxindex,
 
   return rval;
 }
+
+
+/* The implementation of build_vla_check() that recursively builds
+   an expression to determine whether the VLA TYPE is erroneous due
+   either to its bounds being invalid or to integer overflow in
+   the computation of its total size.
+   CHECK is the boolean expression being built, initialized to
+   boolean_false_node.
+   VLASIZE is used internally to pass the incrementally computed
+   size of the VLA object down to its recursive invocations.
+   MAX_VLASIZE is the maximum valid size of the VLA in bytes.
+   CST_SIZE is the product of the VLA's constant dimensions.  */
+
+static tree
+build_vla_size_check (tree check,
+		      tree type,
+		      tree vlasize,
+		      tree max_vlasize,
+		      offset_int *cst_size)
+{
+  tree vmul = builtin_decl_explicit (BUILT_IN_MUL_OVERFLOW);
+
+  tree vlasizeaddr = build_unary_op (input_location, ADDR_EXPR, vlasize, 0);
+
+  bool overflow = false;
+
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      /* Compute the upper bound of this array type.  */
+      tree inner_nelts = array_type_nelts_top (type);
+      tree inner_nelts_cst = maybe_constant_value (inner_nelts);
+
+      if (TREE_CODE (inner_nelts_cst) == INTEGER_CST)
+	{
+	  /* The upper bound is a constant expression.  Compute the product
+	     of the constant upper bounds seen so far so that overflow can
+	     be diagnosed.  */
+	  offset_int result = wi::mul (wi::to_offset (inner_nelts_cst),
+				       *cst_size, SIGNED, &overflow);
+	  *cst_size = overflow ? 0 : result;
+	}
+
+      /* Check for overflow in the VLAs (runtime) upper bounds.  */
+      tree vflowcheck = build_call_expr (vmul, 3, inner_nelts,
+					 vlasize, vlasizeaddr);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, vflowcheck);
+
+      /* Recursively check for overflow in the remaining major bounds.  */
+      check = build_vla_size_check (check, TREE_TYPE (type),
+				    vlasize, max_vlasize,
+				    cst_size);
+    }
+  else
+    {
+      /* Get the size of the VLA element type in bytes.  */
+      tree typesize = TYPE_SIZE_UNIT (type);
+
+      /* See if the size, when multipled by the product of the VLA's
+	 constant dimensions, is within range of size_t.  If not,
+	 the VLA is definitely erroneous amd must be diagnosed at
+	 compile time.  */
+      offset_int result = wi::mul (wi::to_offset (typesize), *cst_size,
+				   SIGNED, &overflow);
+      *cst_size = overflow ? 0 : result;
+
+      /* Multiply the (non-constant) VLA size so far by the element size,
+	 checking for overflow, and replacing the value of vlasize with
+	 the product in the absence of overflow.  This size is the total
+	 runtime size of the VLA in bytes.  */
+      tree vflowcheck = build_call_expr (vmul, 3, typesize,
+					 vlasize, vlasizeaddr);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, vflowcheck);
+
+      /* Check to see if the final VLA size exceeds the maximum.  */
+      tree sizecheck = fold_build2 (LT_EXPR, boolean_type_node,
+				    max_vlasize, vlasize);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, sizecheck);
+
+      /* Also check to see if the final array size is zero (the size
+	 is unsigned so the earlier overflow check detects negative
+	 values as well.  */
+      tree zerocheck = fold_build2 (EQ_EXPR, boolean_type_node,
+				    vlasize, size_zero_node);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, zerocheck);
+    }
+
+  /* Diagnose overflow determined at compile time.  */
+  if (overflow)
+    {
+      error ("integer overflow in variable array size");
+      /* Reset to suppress any further diagnostics.  */
+      *cst_size = 0;
+    }
+
+  return check;
+}
+
+/* The implementation of build_vla_check() that recursively builds
+   an expression to determine whether the VLA initializer-list for
+   TYPE is erroneous due to excess initializers.
+   CHECK is the boolean expression being built, initialized to
+   the result of build_vla_size_check().
+   INIT is the VLA initializer expression to check against TYPE.
+   On the first (non-recursive) call, INIT_ELTS is set either to 1,
+   or to the number of elements in the initializer-list for VLAs
+   of unspecified (major) bound.  On subsequent (recursive) calls.
+   it is set to NULL and computed from the number of elements in
+   the (nested) initializer-list.
+*/
+
+static tree
+build_vla_init_check (tree check, tree type, tree init, tree init_elts)
+{
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      /* Compute the upper bound of this array type unless it has
+	 already been computed by the caller for an array of unspecified
+	 bound, as in 'T a[];'  */
+      tree inner_nelts = init_elts ? init_elts : array_type_nelts_top (type);
+
+      size_t len;
+
+      if (TREE_CODE (init) == CONSTRUCTOR)
+	{
+	  /* The initializer of this array is itself an array.  Build
+	     an expression to check if the number of elements in the
+	     initializer array exceeds the upper bound of the type
+	     of the object being initialized.  */
+	  if (vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (init))
+	    {
+	      len = v->length ();
+	      tree initelts = build_int_cstu (size_type_node, len);
+	      tree initcheck = fold_build2 (LT_EXPR, boolean_type_node,
+					    inner_nelts, initelts);
+
+	      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+				   check, initcheck);
+
+	      constructor_elt *ce;
+	      HOST_WIDE_INT i;
+
+	      /* Iterate over all non-empty initializers in this array,
+		 recursively building expressions to see if the elements
+		 of each are in excess of the corresponding (runtime)
+		 bound of the array type.  */
+	      FOR_EACH_VEC_SAFE_ELT (v, i, ce)
+		check = build_vla_init_check (check, TREE_TYPE (type),
+					      ce->value, NULL_TREE);
+	    }
+	}
+      else if (TREE_CODE (init) == STRING_CST
+	       && (len = TREE_STRING_LENGTH (init)))
+	{
+	  /* The initializer of this array is a string.  */
+	  tree ctype = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init)));
+	  len /= TYPE_PRECISION (ctype) / BITS_PER_UNIT;
+
+	  /* A C++ string literal initializer must have at most as many
+	     characters as there are elements in the array, including
+	     the terminating NUL.  */
+	  tree initelts = build_int_cstu (size_type_node, len);
+	  tree initcheck = fold_build2 (LT_EXPR, boolean_type_node,
+					inner_nelts, initelts);
+	  check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			       check, initcheck);
+	}
+      else if (TREE_CODE (init) == ERROR_MARK)
+	{
+	  // No checking is possible.
+	  check = boolean_false_node;
+	}
+      else
+	{
+	  /* What's this array initializer?  */
+	  gcc_unreachable ();
+	}
+    }
+
+  return check;
+}
+
+/* Build an expression to determine whether the VLA TYPE is erroneous.
+   INIT is the VLA initializer expression or NULL_TREE when the VLA is
+   not initialized.  */
+
+tree
+build_vla_check (tree type, tree init /* = NULL_TREE */)
+{
+  tree check = boolean_false_node;
+
+  /* The product of all constant dimensions of the VLA, initialized
+     to either 1 in the common case or to the number of elements in
+     the VLA's initializer-list for VLAs of unspecified (major)
+     bound.  */
+  offset_int cst_size = 1;
+
+  /* The initial size of the VLA to start the computation of the total
+     size with.  Like CST_SIZE above, initialized to 1 or the number
+     of elements in the VLA's initializer-list for VLAs of unspecified
+     bound.  */
+  tree initial_size = size_one_node;
+
+  /* For a VLA of unspecified (major) bound, the number of elements
+     it is initialized with determined from the initializer-list.  */
+  tree initial_elts = NULL_TREE;
+
+  if (init)
+    {
+      /* Determine the upper bound of the VLA of unspecified bound,
+	 as in 'T a[];' if this is such a VLA.  Such a VLA can be
+	 initialized with any number of elements but the number of
+	 elements so determined must be used to check the total size
+	 of the VLA.  */
+      gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
+
+      if (tree dom = TYPE_DOMAIN (type))
+	if (tree max = TYPE_MAX_VALUE (dom))
+	  if (integer_zerop (max))
+	    {
+	      if (TREE_CODE (init) == CONSTRUCTOR)
+		{
+		  vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (init);
+
+		  /* Since the upper bound of every array must be positive
+		     a VLA with an unspecified major bound must be initized
+		     by a non-empty initializer list.  */
+		  gcc_assert (v != NULL);
+
+		  cst_size = v->length ();
+		}
+	      else if (TREE_CODE (init) == STRING_CST)
+		{
+		  /* The initializer is a (possibly empty) string consisting
+		     at a minumum of one character, the terminating NUL.
+		     This condition implies a definition like
+		       char s [][N] = "";
+		     which is an error but even though it has been diagnosed
+		     by this point the initializer still winds up here.  */
+		  size_t nchars = TREE_STRING_LENGTH (init);
+		  tree ctype = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init)));
+		  nchars /= TYPE_PRECISION (ctype) / BITS_PER_UNIT;
+
+		  cst_size = nchars + 1;
+		}
+
+	      initial_elts = wide_int_to_tree (size_type_node, cst_size);
+	      initial_size = initial_elts;
+	    }
+    }
+
+  /* Build a variable storing the total runtime size of the VLA and
+     initialize it either to 1 (in the common case) or to the number
+     of topmost elements in the initializer-list when the VLA is
+     an array of unspecified (major) bound.  */
+  tree vlasize = build_decl (input_location,
+			     VAR_DECL, NULL_TREE, sizetype);
+  DECL_ARTIFICIAL (vlasize) = 1;
+  DECL_IGNORED_P (vlasize) = 1;
+  DECL_CONTEXT (vlasize) = current_function_decl;
+  DECL_INITIAL (vlasize) = initial_size;
+  vlasize = pushdecl (vlasize);
+  add_decl_expr (vlasize);
+
+  /* Impose a lenient limit on the size of the biggest VLA in bytes.
+     FIXME: Tighten up the limit to make it more useful and make it
+     configurable for users with unusual requirements.  */
+  tree max_vlasize
+    = fold_build2 (RSHIFT_EXPR, size_type_node,
+		   build_all_ones_cst (size_type_node),
+		   integer_one_node);
+
+  /* Build an expression that checks the runtime bounds of the VLA
+     for invalid values and the total size of the VLA for overflow.  */
+  check = build_vla_size_check (check, type, vlasize, max_vlasize, &cst_size);
+
+  if (wi::ltu_p (wi::to_offset (max_vlasize), cst_size))
+    {
+      /* Issue the warning only in the "topmost" (non-recursive) call
+	 to avoid duplicating diagnostics.  This is only a warning to
+	 allow programs to be portable to more permissive environments.  */
+      warning (OPT_Wvla, "size of variable length array exceeds maximum "
+	       "of %qE bytes",  max_vlasize);
+    }
+
+  if (init)
+    {
+      /* Build an expression that checks the VLA initializer expression
+	 against the type of the VLA for excess elements.  */
+      check = build_vla_init_check (check, type, init, initial_elts);
+    }
+
+  return check;
+}
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index b921689..eba19ca 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -603,7 +603,7 @@ split_nonconstant_init_1 (tree dest, tree init)
       array_type_p = true;
       if ((TREE_SIDE_EFFECTS (init)
 	   && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
-	  || array_of_runtime_bound_p (type))
+	  || variably_modified_type_p (type, NULL_TREE))
 	{
 	  /* For an array, we only need/want a single cleanup region rather
 	     than one per element.  */
@@ -845,7 +845,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
      will perform the dynamic initialization.  */
   if (value != error_mark_node
       && (TREE_SIDE_EFFECTS (value)
-	  || array_of_runtime_bound_p (type)
+	  || variably_modified_type_p (type, NULL_TREE)
 	  || ! reduced_constant_expression_p (value)))
     return split_nonconstant_init (decl, value);
   /* If the value is a constant, just put it in DECL_INITIAL.  If DECL

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

* Re: [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
  2016-04-13 18:37                 ` Martin Sebor
@ 2016-04-13 19:26                   ` Jason Merrill
  2016-04-14  2:35                   ` H.J. Lu
  2016-04-14 10:40                   ` Andreas Schwab
  2 siblings, 0 replies; 22+ messages in thread
From: Jason Merrill @ 2016-04-13 19:26 UTC (permalink / raw)
  To: Martin Sebor, Gcc Patch List

On 04/13/2016 02:36 PM, Martin Sebor wrote:
> I don't see the benefit in doing the checking in build_vec_init
> and split_constant_init_1 when it can all be done just in
> check_initializer.  I'm sure you have your reasons for going that
> route so I'd appreciate if you could let me know why you think
> that's better.

In order to share the code for checking VLAs and array new, but I take 
your point that they aren't similar enough for that.  Your alternate 
patch is OK.

Jason

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

* Re: [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
  2016-04-13 18:37                 ` Martin Sebor
  2016-04-13 19:26                   ` Jason Merrill
@ 2016-04-14  2:35                   ` H.J. Lu
  2016-04-14 15:32                     ` Martin Sebor
  2016-04-14 10:40                   ` Andreas Schwab
  2 siblings, 1 reply; 22+ messages in thread
From: H.J. Lu @ 2016-04-14  2:35 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Jason Merrill, Gcc Patch List

On Wed, Apr 13, 2016 at 11:36 AM, Martin Sebor <msebor@gmail.com> wrote:
> On 04/12/2016 12:17 PM, Jason Merrill wrote:
>>
>> On 04/10/2016 07:14 PM, Martin Sebor wrote:
>>>
>>> The call to build_vla_check() in check_initializer() is to check
>>> only explicitly initialized VLAs.  The latter function may need
>>> to complete the VLA element type and reshape the initializer so
>>> the call cannot be made earlier.  The function returns the runtime
>>> initializer code so the call cannot be made after it returns.
>>
>>
>> But this call isn't checking the initializer; we're looking at the
>> initializer in build_vec_init now.
>
>
> Let me try to explain.  Strings aside, there are three cases each
> of which the patch handles in a different function:
>
> 1) The No Initializer case is handled by calling build_vla_check
>     directly from cp_finish_decl.
>
> 2) The Empty initializer case is handled from check_initializer
>     in the hunk you had pasted upthread.  (It isn't handled in
>     build_vec_init because length_check is false for empty
>     initializers, and because it's too late to check VLA bounds
>     there anyway -- see below.)
>
> 3) In the Non-empty Initializer case, excess initializer elements
>     are checked for in build_vec_init.  VLA bounds are checked from
>     check_initializer same as in (2).
>
> As I mentioned last Friday, emitting the check for the VLA bounds
> in build_vec_init appears to be too late because by then the code
> to allocate the stack has already been emitted.  Maybe there's
> a way to do it, I don't know.  Controlling what piece of code is
> emitted when is something I don't know much about yet.
>
>>> The call to build_vla_check() in cp_finish_decl() is guarded with
>>> !init and made to check VLAs that are not explicitly initialized.
>>> This call could perhaps be moved into check_initializer() though
>>> it doesn't seem like it logically belongs there (since there is
>>> no initializer).
>>
>>
>> check_initializer handles implicit (default-) as well as explicit
>> initialization.
>>
>>> If it were moved there, it seems to me that it
>>> would require more extensive changes to the function than making
>>> it in cp_finish_decl().
>>
>>
>> I don't see that; you ought to be able to move the check_initializer
>> copy down out of the if/else structure and use that for both cases.
>
>
> You're right, it was simpler than I thought.  I was being overly
> conservative in an effort to avoid changing more code than is
> absolutely necessary.
>
> Attached is an updated patch with this simplification. It avoids
> case (1) above.  It also adds an argument to build_vla_check to
> avoid building the size check when it's called from build_vec_init.
>
> I also modified the alternate patch accordingly.  It's attached
> for comparison. I still find it preferable to the first patch.
> It's simpler because it doesn't require the special handling for
> strings and avoids parameterizing build_vla_check so as not to
> build the duplicate check in build_vec_init.
>
> I don't see the benefit in doing the checking in build_vec_init
> and split_constant_init_1 when it can all be done just in
> check_initializer.  I'm sure you have your reasons for going that
> route so I'd appreciate if you could let me know why you think
> that's better.

It caused:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70652


-- 
H.J.

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

* Re: [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
  2016-04-13 18:37                 ` Martin Sebor
  2016-04-13 19:26                   ` Jason Merrill
  2016-04-14  2:35                   ` H.J. Lu
@ 2016-04-14 10:40                   ` Andreas Schwab
  2016-04-14 15:26                     ` Martin Sebor
  2 siblings, 1 reply; 22+ messages in thread
From: Andreas Schwab @ 2016-04-14 10:40 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Jason Merrill, Gcc Patch List

Martin Sebor <msebor@gmail.com> writes:

> diff --git a/gcc/testsuite/g++.dg/cpp1y/vla11.C b/gcc/testsuite/g++.dg/cpp1y/vla11.C
> new file mode 100644
> index 0000000..af9624a
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1y/vla11.C
> @@ -0,0 +1,711 @@
> +// PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer
> +//   elements
> +// PR c++/70019 - VLA size overflow not detected
> +//
> +// Runtime test to verify that attempting to either construct a VLA with
> +// erroneous bounds, or initialize one with an initializer-list that
> +// contains more elements than the VLA's non-constant (runtime) bounds
> +// causes an exception to be thrown.  Test also verifies that valid
> +// VLAs and their initializers don't cause such an exception.
> +
> +// { dg-do run { target c++11 } }
> +// { dg-additional-options "-Wno-vla" }

On m68k:

/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C: In instantiation of 'struct TestType<32u>':
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:201:1:   required from here
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:89:27: error: requested alignment 32 is larger than 16 [-Wattributes]
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C: In function 'int testcase201(const char*)':
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:122:5: error: static assertion failed: wrong test type size
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:201:1: note: in expansion of macro 'TEST'
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C: In instantiation of 'struct TestType<64u>':
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:202:1:   required from here
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:89:27: error: requested alignment 64 is larger than 16 [-Wattributes]
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C: In function 'int testcase202(const char*)':
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:122:5: error: static assertion failed: wrong test type size
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:202:1: note: in expansion of macro 'TEST'
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C: In function 'int testcase704(const char*)':
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:122:5: error: static assertion failed: wrong test type size
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:704:1: note: in expansion of macro 'TEST'
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C: In function 'int testcase705(const char*)':
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:122:5: error: static assertion failed: wrong test type size
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:705:1: note: in expansion of macro 'TEST'

FAIL: g++.dg/cpp1y/vla11.C  -std=c++11 (test for excess errors)
Excess errors:
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:89:27: error: requested alignment 32 is larger than 16 [-Wattributes]
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:122:5: error: static assertion failed: wrong test type size
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:89:27: error: requested alignment 64 is larger than 16 [-Wattributes]
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:122:5: error: static assertion failed: wrong test type size
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:122:5: error: static assertion failed: wrong test type size
/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:122:5: error: static assertion failed: wrong test type size

Andreas.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

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

* Re: [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
  2016-04-14 10:40                   ` Andreas Schwab
@ 2016-04-14 15:26                     ` Martin Sebor
  2016-04-15  7:11                       ` Christophe Lyon
  2016-04-15 12:31                       ` Jakub Jelinek
  0 siblings, 2 replies; 22+ messages in thread
From: Martin Sebor @ 2016-04-14 15:26 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Jason Merrill, Gcc Patch List

On 04/14/2016 04:39 AM, Andreas Schwab wrote:
> Martin Sebor <msebor@gmail.com> writes:
>
>> diff --git a/gcc/testsuite/g++.dg/cpp1y/vla11.C b/gcc/testsuite/g++.dg/cpp1y/vla11.C
>> new file mode 100644
>> index 0000000..af9624a
>> --- /dev/null
>> +++ b/gcc/testsuite/g++.dg/cpp1y/vla11.C
>> @@ -0,0 +1,711 @@
>> +// PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer
>> +//   elements
>> +// PR c++/70019 - VLA size overflow not detected
>> +//
>> +// Runtime test to verify that attempting to either construct a VLA with
>> +// erroneous bounds, or initialize one with an initializer-list that
>> +// contains more elements than the VLA's non-constant (runtime) bounds
>> +// causes an exception to be thrown.  Test also verifies that valid
>> +// VLAs and their initializers don't cause such an exception.
>> +
>> +// { dg-do run { target c++11 } }
>> +// { dg-additional-options "-Wno-vla" }
>
> On m68k:
>
> /daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C: In instantiation of 'struct TestType<32u>':
> /daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:201:1:   required from here
> /daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:89:27: error: requested alignment 32 is larger than 16 [-Wattributes]

Thank you for the heads up (and sorry about the breakage).  I've
committed r234976 to fix that.

Martin

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

* Re: [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
  2016-04-14  2:35                   ` H.J. Lu
@ 2016-04-14 15:32                     ` Martin Sebor
  0 siblings, 0 replies; 22+ messages in thread
From: Martin Sebor @ 2016-04-14 15:32 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Jason Merrill, Gcc Patch List

> It caused:
>
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70652

Sorry about that (I missed java among the languages when configuring
my build for regression testing).  I'm testing a libjava patch that
I expect will eliminate the linker error.

Martin

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

* Re: [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
  2016-04-14 15:26                     ` Martin Sebor
@ 2016-04-15  7:11                       ` Christophe Lyon
  2016-04-15 12:31                       ` Jakub Jelinek
  1 sibling, 0 replies; 22+ messages in thread
From: Christophe Lyon @ 2016-04-15  7:11 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Andreas Schwab, Jason Merrill, Gcc Patch List

On 14 April 2016 at 17:26, Martin Sebor <msebor@gmail.com> wrote:
> On 04/14/2016 04:39 AM, Andreas Schwab wrote:
>>
>> Martin Sebor <msebor@gmail.com> writes:
>>
>>> diff --git a/gcc/testsuite/g++.dg/cpp1y/vla11.C
>>> b/gcc/testsuite/g++.dg/cpp1y/vla11.C
>>> new file mode 100644
>>> index 0000000..af9624a
>>> --- /dev/null
>>> +++ b/gcc/testsuite/g++.dg/cpp1y/vla11.C
>>> @@ -0,0 +1,711 @@
>>> +// PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer
>>> +//   elements
>>> +// PR c++/70019 - VLA size overflow not detected
>>> +//
>>> +// Runtime test to verify that attempting to either construct a VLA with
>>> +// erroneous bounds, or initialize one with an initializer-list that
>>> +// contains more elements than the VLA's non-constant (runtime) bounds
>>> +// causes an exception to be thrown.  Test also verifies that valid
>>> +// VLAs and their initializers don't cause such an exception.
>>> +
>>> +// { dg-do run { target c++11 } }
>>> +// { dg-additional-options "-Wno-vla" }
>>
>>
>> On m68k:
>>
>> /daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C: In
>> instantiation of 'struct TestType<32u>':
>> /daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:201:1:
>> required from here
>> /daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:89:27:
>> error: requested alignment 32 is larger than 16 [-Wattributes]
>
>
> Thank you for the heads up (and sorry about the breakage).  I've
> committed r234976 to fix that.
>
Hi,

In your follow-up commit r234981, your gcc/testsuite/ChangeLog entry
says that you reverted vla11.C, but the commit does not actually
modify this testcase. As a matter of fact, I see it failing on arm and aarch64.

Did you forget to remove it, or did you expect r234976 to fix it?

Christophe.

> Martin

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

* Re: [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
  2016-04-14 15:26                     ` Martin Sebor
  2016-04-15  7:11                       ` Christophe Lyon
@ 2016-04-15 12:31                       ` Jakub Jelinek
  2016-04-15 14:33                         ` Martin Sebor
  1 sibling, 1 reply; 22+ messages in thread
From: Jakub Jelinek @ 2016-04-15 12:31 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Andreas Schwab, Jason Merrill, Gcc Patch List

On Thu, Apr 14, 2016 at 09:26:11AM -0600, Martin Sebor wrote:
> >/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C: In instantiation of 'struct TestType<32u>':
> >/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:201:1:   required from here
> >/daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:89:27: error: requested alignment 32 is larger than 16 [-Wattributes]
> 
> Thank you for the heads up (and sorry about the breakage).  I've
> committed r234976 to fix that.

Probably because of this change you haven't reverted (removed) the vla11.C
testcase even when the ChangeLog said you've done that.
And, the testcase obviously fails on the trunk, so I've committed following
as obvious:

2016-04-15  Jakub Jelinek  <jakub@redhat.com>
 
	PR c++/69517
	PR c++/70019
	PR c++/70588
	* g++.dg/cpp1y/vla11.C: Revert for real.

--- g++.dg/cpp1y/vla11.C	(revision 235020)
+++ g++.dg/cpp1y/vla11.C	(revision 235021)
@@ -1,712 +0,0 @@
-// PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer
-//   elements
-// PR c++/70019 - VLA size overflow not detected
-//
-// Runtime test to verify that attempting to either construct a VLA with
-// erroneous bounds, or initialize one with an initializer-list that
-// contains more elements than the VLA's non-constant (runtime) bounds
-// causes an exception to be thrown.  Test also verifies that valid
-// VLAs and their initializers don't cause such an exception.
-
-// { dg-do run { target c++11 } }
-// { dg-additional-options "-Wno-vla" }
-
-#pragma GCC diagnostic ignored "-Wvla"
-
-#define INT_MAX    __INT_MAX__
-#define LONG_MAX   __LONG_MAX__
-#define SIZE_MAX   __SIZE_MAX__
-#define UINT_MAX   (~0U)
-#define ULONG_MAX  (~0LU)
-
-#define INT_MIN    (-__INT_MAX__ - 1)
-#define LONG_MIN   (-__LONG_MAX__ - 1)
-
-// The size of the largest allowed VLA in bytes.  Bigger objects
-// cause an exception to be thrown.  Unless the maximum size is
-// obscenely large, smaller objects should be successfully created
-// provided there's enough stack space.  See TEST_NEAR_VLA_MAX_SIZE
-// below.
-#define MAX   (__SIZE_MAX__ / 2)
-
-// Define to non-zero to exercise very large VLAs with size just
-// below the implementation-defined maximum.
-#define TEST_NEAR_VLA_MAX_SIZE    0
-
-// Define to zero to enable tests that cause an ICE due to c++/58646.
-#define BUG_58646 1
-
-// Helper macro to make it possible to pass as one multpile arguments
-// to another macro.
-#define Init(...) __VA_ARGS__
-
-typedef __SIZE_TYPE__ size_t;
-
-// Incremented for each test failure.
-int fail;
-
-// Used to convert a constant array dimension to a non-constant one.
-template <class T>
-T d (T n)
-{
-  return n;
-}
-
-// Verify either that an expected exception has been thrown or that
-// one hasn't been thrown if one isn't expected.
-int __attribute__ ((noclone, noinline))
-sink (void *p, int line, bool expect, const char *expr)
-{
-  if (!p != expect)
-    {
-      __builtin_printf ("line %i: Assertion failed: '%s': "
-                        "exception unexpectedly %sthrown\n",
-                        line, expr, !p ? "" : "not ");
-      ++fail;
-    }
-  else
-    {
-#if defined DEBUG && DEBUG
-    __builtin_printf ("line %i: Assertion passed: '%s': "
-		      "exception %sthrown as expected\n",
-		      line, expr, !p ? "" : "not ");
-#endif
-    }
-  return 0;
-}
-
-#define _CAT(name, line) name ## line
-#define CAT(name, line) _CAT (name, line)
-
-#define STR(...) #__VA_ARGS__
-
-// Type to exercise VLA with.  TYPESIZE is the size of the type in bytes.
-// Using a template serves two purposes.  First, it makes it possible to
-// parameterize the test on VLAs of different size.  Second, it verifies
-// that the checking code can deal with templates (i.e., completes
-// the element type of the VLA when necessary).
-template <unsigned TypeSize>
-union TestType
-{
-  char data;
-  char padding [TypeSize];
-};
-
-// Test function invoked with a pointer to each test case.  Must
-// return a value though what value doesn't matter.
-int __attribute__ ((noclone, noinline))
-tester (int (*testcase)(const char*),
-	const char *str, int line, bool expect)
-{
-  try
-    {
-      return testcase (str);
-    }
-  catch (...)
-    {
-      return sink (0, line, expect, str);
-    }
-}
-
-// Macro to define a unique specialization of a function template to
-// exercise a VLA of type T, rank N, with dimensions given by Dims
-// and initializer Init.  Expect is true when the VLA initialization
-// is expected to trigger an exception.
-// The macro creates a unique global dummy int object and initializes
-// it with the result of the function.  The dummy object servers no
-// other purpose but to call the function.  The function verifies
-// the expected postconditions.
-#define TEST(TypeSize, Dims, Init, Expect)				\
-  static int CAT (testcase, __LINE__)(const char *str)			\
-  {									\
-    TestType<TypeSize> vla Dims Init;					\
-    static_assert (sizeof (TestType<TypeSize>) == TypeSize,		\
-		   "wrong test type size");				\
-    return sink (vla, __LINE__, Expect, str);				\
-  }									\
-  const int CAT (dummy, __LINE__)					\
-    = tester (CAT (testcase, __LINE__),					\
-	      "T<" #TypeSize "> a" #Dims " " STR (Init) ";",		\
-	      __LINE__, Expect)
-
-
-// Create and run a test function exercising a VLA definition
-// of one of the following forms:
-//    TestType<Size> VLA Dims;        // uninitialized (with Init ())
-// or:
-//    TestType<Size> VLA Dims Init;   // initialized (with = Init ({...})
-//
-//    +-- Element Size (in Bytes)
-//    |  +-- VLA Dimensions (constant as in [3], otherwise d(3))
-//    |  |         +-- VLA Initializer Expression (if any)
-//    |  |         |                  +-- Expect Exception
-//    |  |         |                  |
-//    V  V         V                  V
-TEST (1, [d(0)],   Init (/* none*/),  true);   // uninitialized
-
-#if !BUG_58646
-// The following causes an ICE due to c++/58646.
-TEST (1, [d(0)],   Init ({}),         true);
-#endif
-TEST (1, [d(0)],   Init ({1}),        true);   // initialized with " {1}"
-TEST (1, [d(0)],   = Init ({1}),      true);   // initialized with "= {1}"
-
-TEST (1, [d(1)],   Init (),           false);
-TEST (1, [d(1)],   Init ({}),         false);
-TEST (1, [d(1)],   = Init ({}),       false);
-TEST (1, [d(1)],   Init ({1}),        false);
-TEST (1, [d(1)],   = Init ({1}),      false);
-TEST (1, [d(1)],   Init ({1, 2}),     true);
-TEST (1, [d(1)],   = Init ({1, 2}),   true);
-
-TEST (1, [d(2)],   Init (),           false);
-TEST (1, [d(2)],   Init ({}),         false);
-TEST (1, [d(2)],   Init ({1}),        false);
-TEST (1, [d(2)],   Init ({1, 2}),     false);
-TEST (1, [d(2)],   Init ({1, 2, 3}),  true);
-
-#if TEST_NEAR_VLA_MAX_SIZE
-// Very large but not erroneous one dimensional VLAs.
-TEST (1, [d(MAX)], Init (),           false);
-TEST (1, [d(MAX)], Init ({}),         false);
-TEST (1, [d(MAX)], Init ({1}),        false);
-TEST (1, [d(MAX)], Init ({1, 2}),     false);
-TEST (1, [d(MAX)], Init ({1, 2, 3}),  false);
-
-TEST ( 2, [d(MAX / 2)],   Init (),    false);
-TEST ( 4, [d(MAX / 4)],   Init (),    false);
-TEST ( 8, [d(MAX / 8)],   Init (),    false);
-TEST (16, [d(MAX / 16)],  Init (),    false);
-TEST (32, [d(MAX / 32)],  Init (),    false);
-TEST (64, [d(MAX / 64)],  Init (),    false);
-#endif   // TEST_NEAR_VLA_MAX_SIZE
-
-// One dimensional VLAs with a negative upper bound.
-TEST (1, [d(LONG_MIN)],  Init (),       true);
-TEST (1, [d(INT_MIN)],   Init (),       true);
-TEST (1, [d(-1234)],     Init (),       true);
-TEST (1, [d(-1)],        Init (),       true);
-
-// Excessively large one dimensional VLAs.
-TEST ( 1, [d(MAX + 1)],   Init (),      true);
-TEST ( 2, [d(MAX)],       Init (),      true);
-TEST ( 4, [d(MAX / 2)],   Init (),      true);
-TEST ( 4, [d(MAX / 3)],   Init (),      true);
-TEST ( 8, [d(MAX / 2)],   Init (),      true);
-TEST ( 8, [d(MAX / 3)],   Init (),      true);
-TEST ( 8, [d(MAX / 4)],   Init (),      true);
-TEST ( 8, [d(MAX / 5)],   Init (),      true);
-TEST ( 8, [d(MAX / 6)],   Init (),      true);
-TEST ( 8, [d(MAX / 7)],   Init (),      true);
-TEST (16, [d(MAX / 15)],  Init (),      true);
-TEST (32, [d(MAX / 31)],  Init (),      true);
-TEST (64, [d(MAX / 63)],  Init (),      true);
-TEST ( 1, [d(SIZE_MAX)],  Init (),      true);
-
-TEST (1, [d(LONG_MIN)],  Init ({}),     true);
-TEST (1, [d(INT_MIN)],   Init ({}),     true);
-TEST (1, [d(-1)],        Init ({}),     true);
-
-TEST (1, [d(SIZE_MAX)],  Init ({}),     true);
-
-TEST (1, [d(LONG_MIN)],  Init ({0}),    true);
-TEST (1, [d(INT_MIN)],   Init ({0}),    true);
-TEST (1, [d(-1)],        Init ({0}),    true);
-
-TEST (1, [d(SIZE_MAX)],  Init ({0}),    true);
-
-TEST ( 1, [d(SIZE_MAX/2)  + 1], Init (), true);
-TEST ( 2, [d(SIZE_MAX/4)  + 1], Init (), true);
-TEST ( 4, [d(SIZE_MAX/8)  + 1], Init (), true);
-TEST ( 8, [d(SIZE_MAX/16) + 1], Init (), true);
-TEST (16, [d(SIZE_MAX/32) + 1], Init (), true);
-
-TEST ( 1, [d(SIZE_MAX/2)  + 1], Init ({1}),             true);
-TEST ( 2, [d(SIZE_MAX/4)  + 1], Init ({1, 2}),          true);
-TEST ( 4, [d(SIZE_MAX/8)  + 1], Init ({1, 2, 3}),       true);
-TEST ( 8, [d(SIZE_MAX/16) + 1], Init ({1, 2, 3, 4}),    true);
-TEST (16, [d(SIZE_MAX/32) + 1], Init ({1, 2, 3, 4, 5}), true);
-
-// Two dimensional VLAs with one constant bound.
-
-TEST (1, [1][d(0)],   Init (),          true);
-
-#if !BUG_58646
-// The following causes an ICE due to c++/58646.
-TEST (1, [1][d(0)],   Init ({}),        true);
-#endif
-TEST (1, [ ][d(0)],   Init ({{1}}),     true);   // unspecified bound
-TEST (1, [1][d(0)],   Init ({{1}}),     true);
-
-TEST (1, [1][d(1)],   Init (),             false);
-TEST (1, [1][d(1)],   Init ({{1}}),        false);
-TEST (1, [1][d(1)],   Init ({{1, 2}}),     true);
-TEST (1, [ ][d(1)],   Init ({{1, 2}}),     true);
-
-TEST (1, [1][d(2)],   Init (),             false);
-TEST (1, [1][d(2)],   Init ({{1}}),        false);
-TEST (1, [1][d(2)],   Init ({{1, 2}}),     false);
-TEST (1, [ ][d(2)],   Init ({{1, 2}}),     false);
-TEST (1, [1][d(2)],   Init ({{1, 2, 3}}),  true);
-TEST (1, [ ][d(2)],   Init ({{1, 2, 3}}),  true);
-
-TEST (1, [2][d(1)],   Init (),                 false);
-TEST (1, [2][d(1)],   Init ({{1}}),            false);
-TEST (1, [ ][d(1)],   Init ({{1}}),            false);
-TEST (1, [2][d(1)],   Init ({{1}, {2}}),       false);
-TEST (1, [ ][d(1)],   Init ({{1}, {2}}),       false);
-TEST (1, [2][d(1)],   Init ({{1, 2}}),         true);
-TEST (1, [ ][d(1)],   Init ({{1, 2}}),         true);
-TEST (1, [2][d(1)],   Init ({{1}, {2, 3}}),    true);
-TEST (1, [ ][d(1)],   Init ({{1}, {2, 3}}),    true);
-TEST (1, [2][d(1)],   Init ({{1, 2, 3}}),      true);
-TEST (1, [ ][d(1)],   Init ({{1, 2, 3}}),      true);
-TEST (1, [2][d(1)],   Init ({{1, 2, 3}, {4}}), true);
-TEST (1, [ ][d(1)],   Init ({{1, 2, 3}, {4}}), true);
-TEST (1, [2][d(1)],   Init ({{1, 2}, {3, 4}}), true);
-TEST (1, [ ][d(1)],   Init ({{1, 2}, {3, 4}}), true);
-
-TEST (1, [2][d(2)],   Init (),                       false);
-TEST (1, [2][d(2)],   Init ({{1}}),                  false);
-TEST (1, [2][d(2)],   Init ({{1, 2}}),               false);
-TEST (1, [2][d(2)],   Init ({{1, 2}, {3}}),          false);
-TEST (1, [2][d(2)],   Init ({{1, 2}, {3, 4}}),       false);
-TEST (1, [2][d(2)],   Init ({{1}, {2, 3, 4}}),       true);
-TEST (1, [2][d(2)],   Init ({{1}, {2, 3, 4, 5}}),    true);
-TEST (1, [2][d(2)],   Init ({{1, 2}, {3, 4, 5}}),    true);
-TEST (1, [2][d(2)],   Init ({{1, 2, 3}, {4, 5}}),    true);
-TEST (1, [2][d(2)],   Init ({{1, 2, 3}, {4, 5, 6}}), true);
-
-TEST (1, [2][d(3)],   Init (),                          false);
-TEST (1, [2][d(3)],   Init ({{1}}),                     false);
-TEST (1, [2][d(3)],   Init ({{1, 2}}),                  false);
-TEST (1, [2][d(3)],   Init ({{1, 2}, {3}}),             false);
-TEST (1, [2][d(3)],   Init ({{1, 2}, {3, 4}}),          false);
-TEST (1, [2][d(3)],   Init ({{1}, {2, 3, 4}}),          false);
-TEST (1, [2][d(3)],   Init ({{1}, {2, 3, 4, 5}}),       true);
-TEST (1, [2][d(3)],   Init ({{1, 2}, {3, 4, 5}}),       false);
-TEST (1, [2][d(3)],   Init ({{1, 2, 3}, {4, 5}}),       false);
-TEST (1, [2][d(3)],   Init ({{1, 2, 3}, {4, 5, 6}}),    false);
-TEST (1, [2][d(3)],   Init ({{1, 2, 3}, {4, 5, 6, 7}}), true);
-TEST (1, [2][d(3)],   Init ({{1, 2, 3, 4}, {5, 6, 7}}), true);
-TEST (1, [2][d(3)],   Init ({{1, 2, 3, 4, 5}, {6, 7}}), true);
-TEST (1, [2][d(3)],   Init ({{1, 2, 3, 4, 5, 6}, {7}}), true);
-TEST (1, [2][d(3)],   Init ({{1, 2, 3, 4, 5, 6, 7}}),   true);
-
-#if TEST_NEAR_VLA_MAX_SIZE
-TEST (1, [1][d(MAX)], Init (),                 false);
-#  if !BUG_58646
-// The following causes an ICE due to c++/58646.
-TEST (1, [1][d(MAX)], Init ({}),               false);
-#  endif
-TEST (1, [1][d(MAX)], Init ({{1}}),            false);
-TEST (1, [1][d(MAX)], Init ({{1, 2}}),         false);
-TEST (1, [1][d(MAX)], Init ({{1, 2, 3}}),      false);
-TEST (1, [1][d(MAX)], Init ({{1, 2, 3, 4}}),   false);
-
-TEST (1, [2][d(MAX / 2)], Init (),                       false);
-TEST (1, [2][d(MAX / 2)], Init ({{1}}),                  false);
-TEST (1, [2][d(MAX / 2)], Init ({{1, 2}}),               false);
-TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}}),            false);
-TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3, 4}}),         false);
-TEST (1, [2][d(MAX / 2)], Init ({{1}, {2}}),             false);
-TEST (1, [2][d(MAX / 2)], Init ({{1}, {2, 3}}),          false);
-TEST (1, [2][d(MAX / 2)], Init ({{1, 2}, {3}}),          false);
-TEST (1, [2][d(MAX / 2)], Init ({{1, 2}, {3, 4}}),       false);
-TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}, {4}}),       false);
-TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5}}),    false);
-TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5, 6}}), false);
-#endif   // TEST_NEAR_VLA_MAX_SIZE
-
-// Excessively large two dimensional VLAs.
-TEST (1, [1][d(LONG_MIN)],  Init (),       true);
-TEST (1, [1][d(INT_MIN)],   Init (),       true);
-TEST (1, [1][d(-1)],        Init (),       true);
-
-TEST (1, [1][d(SIZE_MAX)],  Init (),       true);
-
-#if !BUG_58646
-// The following cause an ICE due to c++/58646.
-TEST (1, [1][d(LONG_MIN)],  Init ({}),     true);
-TEST (1, [1][d(INT_MIN)],   Init ({}),     true);
-TEST (1, [1][d(-1)],        Init ({}),     true);
-TEST (1, [1][d(SIZE_MAX)],  Init ({}),     true);
-#endif
-
-TEST (1, [1][d(LONG_MIN)],  Init ({{0}}),  true);
-TEST (1, [1][d(INT_MIN)],   Init ({{0}}),  true);
-TEST (1, [1][d(-1)],        Init ({{0}}),  true);
-TEST (1, [1][d(SIZE_MAX)],  Init ({{0}}),  true);
-
-TEST (1, [d(LONG_MIN)][1],  Init (),       true);
-TEST (1, [d(INT_MIN)][1],   Init (),       true);
-TEST (1, [d(-1)][1],        Init (),       true);
-TEST (1, [d(SIZE_MAX)][1],  Init (),       true);
-
-TEST (1, [d(LONG_MIN)][1],  Init ({}),     true);
-TEST (1, [d(INT_MIN)][1],   Init ({}),     true);
-TEST (1, [d(-1)][1],        Init ({}),     true);
-TEST (1, [d(SIZE_MAX)][1],  Init ({}),     true);
-
-TEST (1, [d(LONG_MIN)][1],  Init ({{0}}),  true);
-TEST (1, [d(INT_MIN)][1],   Init ({{0}}),  true);
-TEST (1, [d(-1)][1],        Init ({{0}}),  true);
-TEST (1, [d(SIZE_MAX)][1],  Init ({{0}}),  true);
-
-// Two dimensional VLAs with no constant bound.
-TEST (1, [d(0)][d(0)],   Init (),          true);
-TEST (1, [d(0)][d(0)],   Init ({}),        true);
-#if !BUG_58646
-// The following cause an ICE due to c++/58646.
-TEST (1, [d(0)][d(0)],   Init ({{}}),      true);
-TEST (1, [d(0)][d(0)],   Init ({{}, {}}),  true);
-#endif
-
-TEST (1, [d(0)][d(0)],   Init ({{1}}),     true);
-TEST (1, [d(0)][d(0)],   Init ({{1, 2}}),  true);
-#if !BUG_58646
-TEST (1, [d(0)][d(0)],   Init ({{1}, {}}), true);
-TEST (1, [d(0)][d(0)],   Init ({{}, {1}}), true);
-#endif
-
-TEST (1, [d(1)][d(0)],   Init (),          true);
-TEST (1, [d(1)][d(0)],   Init ({}),        true);
-TEST (1, [d(1)][d(0)],   Init ({{1}}),     true);
-
-TEST (1, [d(1)][d(1)],   Init (),             false);
-TEST (1, [d(1)][d(1)],   Init ({{1}}),        false);
-TEST (1, [d(1)][d(1)],   Init ({{1, 2}}),     true);
-
-TEST (1, [d(1)][d(2)],   Init (),             false);
-TEST (1, [d(1)][d(2)],   Init ({{1}}),        false);
-TEST (1, [d(1)][d(2)],   Init ({{1, 2}}),     false);
-TEST (1, [d(1)][d(2)],   Init ({{1, 2, 3}}),  true);
-
-TEST (1, [d(2)][d(1)],   Init (),                 false);
-TEST (1, [d(2)][d(1)],   Init ({{1}}),            false);
-TEST (1, [d(2)][d(1)],   Init ({{1}, {2}}),       false);
-TEST (1, [d(2)][d(1)],   Init ({{1, 2}}),         true);
-TEST (1, [d(2)][d(1)],   Init ({{1}, {2, 3}}),    true);
-TEST (1, [d(2)][d(1)],   Init ({{1, 2, 3}}),      true);
-TEST (1, [d(2)][d(1)],   Init ({{1, 2, 3}, {4}}), true);
-TEST (1, [d(2)][d(1)],   Init ({{1, 2}, {3, 4}}), true);
-
-TEST (1, [d(2)][d(2)],   Init (),                       false);
-TEST (1, [d(2)][d(2)],   Init ({{1}}),                  false);
-TEST (1, [d(2)][d(2)],   Init ({{1, 2}}),               false);
-TEST (1, [d(2)][d(2)],   Init ({{1, 2}, {3}}),          false);
-TEST (1, [d(2)][d(2)],   Init ({{1, 2}, {3, 4}}),       false);
-TEST (1, [d(2)][d(2)],   Init ({{1}, {2, 3, 4}}),       true);
-TEST (1, [d(2)][d(2)],   Init ({{1}, {2, 3, 4, 5}}),    true);
-TEST (1, [d(2)][d(2)],   Init ({{1, 2}, {3, 4, 5}}),    true);
-TEST (1, [d(2)][d(2)],   Init ({{1, 2, 3}, {4, 5}}),    true);
-TEST (1, [d(2)][d(2)],   Init ({{1, 2, 3}, {4, 5, 6}}), true);
-
-TEST (1, [d(2)][d(3)],   Init (),                          false);
-TEST (1, [d(2)][d(3)],   Init ({{1}}),                     false);
-TEST (1, [d(2)][d(3)],   Init ({{1, 2}}),                  false);
-TEST (1, [d(2)][d(3)],   Init ({{1, 2}, {3}}),             false);
-TEST (1, [d(2)][d(3)],   Init ({{1, 2}, {3, 4}}),          false);
-TEST (1, [d(2)][d(3)],   Init ({{1}, {2, 3, 4}}),          false);
-TEST (1, [d(2)][d(3)],   Init ({{1}, {2, 3, 4, 5}}),       true);
-TEST (1, [d(2)][d(3)],   Init ({{1, 2}, {3, 4, 5}}),       false);
-TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3}, {4, 5}}),       false);
-TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3}, {4, 5, 6}}),    false);
-TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3}, {4, 5, 6, 7}}), true);
-TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3, 4}, {5, 6, 7}}), true);
-TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3, 4, 5}, {6, 7}}), true);
-TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3, 4, 5, 6}, {7}}), true);
-TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3, 4, 5, 6, 7}}),   true);
-
-#if TEST_NEAR_VLA_MAX_SIZE
-TEST (1, [d(1)][d(MAX)], Init (),                              false);
-TEST (1, [d(1)][d(MAX)], Init ({}),                            false);
-TEST (1, [d(1)][d(MAX)], Init ({{1}}),                         false);
-TEST (1, [d(1)][d(MAX)], Init ({{1, 2}}),                      false);
-TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3}}),                   false);
-TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4}}),                false);
-TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5}}),             false);
-TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6}}),          false);
-TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6, 7}}),       false);
-TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6, 7, 8}}),    false);
-TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6, 7, 8, 9}}), false);
-
-TEST (1, [d(2)][d(MAX / 2)], Init (),                              false);
-TEST (1, [d(2)][d(MAX / 2)], Init ({{1}}),                         false);
-TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2}}),                      false);
-TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}}),                   false);
-TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4}}),                false);
-TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5}}),             false);
-TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6}}),          false);
-TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6, 7}}),       false);
-TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6, 7, 8}}),    false);
-TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6, 7, 8, 9}}), false);
-TEST (1, [d(2)][d(MAX / 2)], Init ({{1}, {2}}),                    false);
-TEST (1, [d(2)][d(MAX / 2)], Init ({{1}, {2, 3}}),                 false);
-TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2}, {3}}),                 false);
-TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2}, {3, 4}}),              false);
-TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}, {4}}),              false);
-TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5}}),           false);
-TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5, 6}}),        false);
-#endif
-
-TEST (1, [d(2)][d(MAX)],        Init (),                         true);
-TEST (1, [d(2)][d(MAX)],        Init ({{1}}),                    true);
-TEST (1, [d(MAX)][d(MAX)],      Init ({{1, 2}}),                 true);
-TEST (1, [d(0)][d(MAX)],        Init ({{1}, {2}}),               true);
-TEST (1, [d(INT_MAX)][d(MAX)],  Init ({{1}, {2, 3}}),            true);
-TEST (1, [d(SIZE_MAX)][d(MAX)], Init ({{1, 2}, {3, 4}, {5}}),    true);
-
-// Erroneous two-dimensional VLAs with size exceeding SIZE_MAX / 2
-// (those must be rejected because no object can be bigger than that,
-// otherwise pointer arithmetic breaks).
-TEST ( 1, [2][d(SIZE_MAX/2)],  Init (), true);
-TEST ( 2, [2][d(SIZE_MAX/4)],  Init (), true);
-TEST ( 4, [2][d(SIZE_MAX/8)],  Init (), true);
-TEST ( 8, [2][d(SIZE_MAX/16)], Init (), true);
-TEST (16, [2][d(SIZE_MAX/32)], Init (), true);
-
-TEST ( 1, [d(SIZE_MAX/2)][2],  Init (), true);
-TEST ( 2, [d(SIZE_MAX/4)][2],  Init (), true);
-TEST ( 4, [d(SIZE_MAX/8)][2],  Init (), true);
-TEST ( 8, [d(SIZE_MAX/16)][2], Init (), true);
-TEST (16, [d(SIZE_MAX/32)][2], Init (), true);
-
-// Verify that the unspecified bound is factored into the computation
-// of the total size.
-TEST ( 1, [][d(SIZE_MAX/2)],  Init ({{1}, {2}}),      true);
-TEST ( 2, [][d(SIZE_MAX/4)],  Init ({{1}, {2}}),      true);
-TEST ( 4, [][d(SIZE_MAX/8)],  Init ({{1}, {2}}),      true);
-TEST ( 8, [][d(SIZE_MAX/16)], Init ({{1}, {2}}),      true);
-TEST (16, [][d(SIZE_MAX/32)], Init ({{1}, {2}}),      true);
-TEST (16, [][d(SIZE_MAX/64)], Init ({{1}, {2}, {3}}), true);
-
-// Three dimensional VLAs with two constant bounds.
-
-TEST (1, [1][1][d(-1)], Init (),                    true);
-TEST (1, [1][1][d(0)], Init (),                     true);
-
-#if !BUG_58646
-// The following causes an ICE due to c++/58646.
-TEST (1, [1][1][d(0)],  Init ({}),                   true);
-TEST (1, [1][1][d(-1)], Init ({{}}),                 true);
-TEST (1, [1][d(-1)][1], Init ({{}}),                 true);
-TEST (1, [d(-1)][1][1], Init ({{}}),                 true);
-
-TEST (1, [1][1][d(0)], Init ({{}}),                  true);
-TEST (1, [1][d(0)][1], Init ({{}}),                  true);
-TEST (1, [d(0)][1][1], Init ({{}}),                  true);
-#endif
-
-TEST (1, [1][1][d(1)], Init (),                      false);
-
-#if !BUG_58646
-TEST (1, [1][1][d(1)], Init ({{}}),                  false);
-TEST (1, [1][1][d(1)], Init ({{{}}}),                false);
-TEST (1, [1][1][d(1)], Init ({{{1}}}),               false);
-#endif
-
-TEST (1, [1][1][d(1)], Init ({{{1, 2}}}),            true);
-TEST (1, [1][1][d(1)], Init ({{{1, 2, 3}}}),         true);
-
-TEST (1, [1][d(1)][1], Init (),                      false);
-
-#if !BUG_58646
-TEST (1, [1][d(1)][1], Init ({{}}),                  false);
-TEST (1, [1][d(1)][1], Init ({{{}}}),                false);
-#endif
-
-TEST (1, [1][d(1)][1], Init ({{{1}}}),               false);
-TEST (1, [1][d(1)][1], Init ({{{1}, {2}}}),          true);
-TEST (1, [1][d(1)][1], Init ({{{1}, {2}, {3}}}),     true);
-
-TEST (1, [d(1)][1][1], Init (),                      false);
-
-#if !BUG_58646
-TEST (1, [d(1)][1][1], Init ({{}}),                  false);
-TEST (1, [d(1)][1][1], Init ({{{}}}),                false);
-#endif
-
-TEST (1, [d(1)][1][1], Init ({{{1}}}),               false);
-TEST (1, [d(1)][1][1], Init ({{{1}}, {{2}}}),        true);
-TEST (1, [d(1)][1][1], Init ({{{1}}, {{2}}, {{3}}}), true);
-
-TEST (1, [1][1][d(2)], Init (),                      false);
-
-#if !BUG_58646
-TEST (1, [1][1][d(2)], Init ({{}}),                  false);
-TEST (1, [1][1][d(2)], Init ({{{}}}),                false);
-#endif
-
-TEST (1, [1][1][d(2)], Init ({{{1}}}),               false);
-TEST (1, [1][1][d(2)], Init ({{{1, 2}}}),            false);
-TEST (1, [1][1][d(2)], Init ({{{1, 2, 3}}}),         true);
-
-TEST (1, [1][d(2)][1], Init (),                      false);
-
-#if !BUG_58646
-TEST (1, [1][d(2)][1], Init ({{}}),                  false);
-TEST (1, [1][d(2)][1], Init ({{{}}}),                false);
-#endif
-TEST (1, [1][d(2)][1], Init ({{{1}}}),               false);
-TEST (1, [1][d(2)][1], Init ({{{1}, {2}}}),          false);
-TEST (1, [1][d(2)][1], Init ({{{1}, {2}, {3}}}),     true);
-
-TEST (1, [d(2)][1][1], Init (),                      false);
-
-#if !BUG_58646
-TEST (1, [d(2)][1][1], Init ({{}}),                  false);
-TEST (1, [d(2)][1][1], Init ({{{}}}),                false);
-#endif
-TEST (1, [d(2)][1][1], Init ({{{1}}}),               false);
-TEST (1, [d(2)][1][1], Init ({{{1}}, {{2}}}),        false);
-TEST (1, [d(2)][1][1], Init ({{{1}}, {{2}}, {{3}}}), true);
-
-TEST (1, [1][2][d(2)], Init (),                      false);
-
-#if !BUG_58646
-TEST (1, [1][2][d(2)], Init ({{}}),                  false);
-TEST (1, [1][2][d(2)], Init ({{{}}}),                false);
-#endif
-
-TEST (1, [1][2][d(2)], Init ({{{1}}}),               false);
-TEST (1, [1][2][d(2)], Init ({{{1, 2}}}),            false);
-TEST (1, [1][2][d(2)], Init ({{{1, 2, 3}}}),         true);
-
-TEST (1, [1][2][d(2)], Init ({{{1}, {2}}}),          false);
-TEST (1, [1][2][d(2)], Init ({{{1}, {2, 3}}}),       false);
-TEST (1, [1][2][d(2)], Init ({{{1, 2}, {3}}}),       false);
-TEST (1, [1][2][d(2)], Init ({{{1, 2}, {3, 4}}}),    false);
-TEST (1, [1][2][d(2)], Init ({{{1}, {2, 3, 4}}}),    true);
-TEST (1, [1][2][d(2)], Init ({{{1, 2, 3}, {}}}),     true);
-TEST (1, [1][2][d(2)], Init ({{{1, 2, 3}, {4}}}),    true);
-TEST (1, [1][2][d(2)], Init ({{{1, 2, 3, 4}}}),      true);
-TEST (1, [1][2][d(2)], Init ({{{1, 2, 3, 4}, {}}}),  true);
-TEST (1, [1][2][d(2)], Init ({{{1, 2, 3, 4}, {5}}}), true);
-
-TEST (1, [2][2][d(2)], Init ({{{1}, {2}}}),                         false);
-TEST (1, [2][2][d(2)], Init ({{{1}, {2, 3}}}),                      false);
-TEST (1, [2][2][d(2)], Init ({{{1, 2}}}),                           false);
-TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3}}}),                      false);
-TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}}),                   false);
-TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5}}}),            false);
-TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}}}),         false);
-TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7}}}),    false);
-TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}), false);
-
-TEST (1, [2][2][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
-TEST (1, [2][2][d(2)], Init ({{{1, 2, 3}, {}}}),                       true);
-TEST (1, [2][2][d(2)], Init ({{{1, 2, 3}, {4}}}),                      true);
-TEST (1, [2][2][d(2)], Init ({{{1, 2, 3, 4}}}),                        true);
-TEST (1, [2][2][d(2)], Init ({{{1, 2, 3, 4}, {}}}),                    true);
-TEST (1, [2][2][d(2)], Init ({{{1, 2, 3, 4}, {5}}}),                   true);
-TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8, 9}}}), true);
-TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6, 7}, {8, 9}}}), true);
-TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4, 5}}, {{6, 7}, {8, 9}}}), true);
-TEST (1, [2][2][d(2)], Init ({{{1, 2, 3}, {4, 5}}, {{6, 7}, {8, 9}}}), true);
-TEST (1, [2][2][d(2)], Init ({{{1}, {2}}, {{3}, {4, 5, 6}}}),          true);
-TEST (1, [2][2][d(2)], Init ({{{1}}, {{2}, {3, 4, 5, 6}}}),            true);
-
-// Three dimensional VLAs with one constant bound.
-TEST (1, [2][d(-1)][d(-1)], Init (),                                      true);
-TEST (1, [2][d(-1)][d(0)],  Init (),                                      true);
-TEST (1, [2][d(0)][d(-1)],  Init (),                                      true);
-TEST (1, [2][d(1)][d(-1)],  Init (),                                      true);
-TEST (1, [2][d(1)][d(0)],   Init (),                                      true);
-TEST (1, [2][d(-1)][d(1)],  Init (),                                      true);
-TEST (1, [2][d(0)][d(1)],   Init (),                                      true);
-
-TEST (1, [2][d(2)][d(2)], Init (),                                        false);
-TEST (1, [2][d(2)][d(2)], Init ({{{1}}}),                                 false);
-TEST (1, [ ][d(2)][d(2)], Init ({{{1}}}),                                 false);
-TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2}}}),                            false);
-TEST (1, [ ][d(2)][d(2)], Init ({{{1}, {2}}}),                            false);
-TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3}}}),                         false);
-TEST (1, [ ][d(2)][d(2)], Init ({{{1}, {2, 3}}}),                         false);
-TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3}}}),                         false);
-TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2}, {3}}}),                         false);
-TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}}),                      false);
-TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}}),                      false);
-TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}),    false);
-TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}),    false);
-TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
-TEST (1, [ ][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
-TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {}}}),                       true);
-TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3}, {}}}),                       true);
-TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {4}}}),                      true);
-TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3}, {4}}}),                      true);
-TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}}}),                        true);
-TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3, 4}}}),                        true);
-TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {}}}),                    true);
-TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {}}}),                    true);
-TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {5}}}),                   true);
-TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {5}}}),                   true);
-TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
-TEST (1, [ ][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
-TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3}, {4}}}),                    true);
-TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {}}}),                       true);
-TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {4}}}),                      true);
-TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}}}),                        true);
-TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {}}}),                    true);
-TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {5}}}),                   true);
-TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8, 9}}}), true);
-TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6, 7}, {8, 9}}}), true);
-TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4, 5}}, {{6, 7}, {8, 9}}}), true);
-TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {4, 5}}, {{6, 7}, {8, 9}}}), true);
-TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2}}, {{3}, {4, 5, 6}}}),          true);
-TEST (1, [2][d(2)][d(2)], Init ({{{1}}, {{2}, {3, 4, 5, 6}}}),            true);
-TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2}, {3}}}),                       true);
-TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3}, {4}}}),                    true);
-TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3, 4}, {5}}}),                 true);
-
-#if TEST_NEAR_VLA_MAX_SIZE
-// Very large but not erroneous three-dimensional VLAs.
-TEST ( 1, [2][d(1)][d(MAX/2)], Init (),  false);
-TEST ( 2, [2][d(1)][d(MAX/4)], Init (),  false);
-TEST ( 4, [2][d(1)][d(MAX/8)], Init (),  false);
-TEST ( 8, [2][d(1)][d(MAX/16)], Init (), false);
-TEST (16, [2][d(1)][d(MAX/32)], Init (), false);
-
-TEST ( 1, [2][d(MAX/2)][d(1)], Init (),  false);
-TEST ( 2, [2][d(MAX/4)][d(1)], Init (),  false);
-TEST ( 4, [2][d(MAX/8)][d(1)], Init (),  false);
-TEST ( 8, [2][d(MAX/16)][d(1)], Init (), false);
-TEST (16, [2][d(MAX/32)][d(1)], Init (), false);
-
-TEST ( 1, [d(MAX/2)][2][d(1)], Init (),  false);
-TEST ( 2, [d(MAX/4)][2][d(1)], Init (),  false);
-TEST ( 4, [d(MAX/8)][2][d(1)], Init (),  false);
-TEST ( 8, [d(MAX/16)][2][d(1)], Init (), false);
-TEST (16, [d(MAX/32)][2][d(1)], Init (), false);
-#endif   // TEST_NEAR_VLA_MAX_SIZE
-
-// Erroneous three-dimensional VLAs with size exceeding SIZE_MAX / 2
-// (those must be rejected because no object can be bigger than that,
-// otherwise pointer arithmetic breaks).
-TEST ( 1, [2][d(1)][d(SIZE_MAX/2)],  Init (), true);
-TEST ( 2, [2][d(1)][d(SIZE_MAX/4)],  Init (), true);
-TEST ( 4, [2][d(1)][d(SIZE_MAX/8)],  Init (), true);
-TEST ( 8, [2][d(1)][d(SIZE_MAX/16)], Init (), true);
-TEST (16, [2][d(1)][d(SIZE_MAX/32)], Init (), true);
-
-TEST ( 1, [2][d(SIZE_MAX/2)][d(1)],  Init (), true);
-TEST ( 2, [2][d(SIZE_MAX/4)][d(1)],  Init (), true);
-TEST ( 4, [2][d(SIZE_MAX/8)][d(1)],  Init (), true);
-TEST ( 8, [2][d(SIZE_MAX/16)][d(1)], Init (), true);
-TEST (16, [2][d(SIZE_MAX/32)][d(1)], Init (), true);
-
-TEST ( 1, [d(SIZE_MAX/2)][2][d(1)],  Init (), true);
-TEST ( 2, [d(SIZE_MAX/4)][2][d(1)],  Init (), true);
-TEST ( 4, [d(SIZE_MAX/8)][2][d(1)],  Init (), true);
-TEST ( 8, [d(SIZE_MAX/16)][2][d(1)], Init (), true);
-TEST (16, [d(SIZE_MAX/32)][2][d(1)], Init (), true);
-
-TEST (16, [3][d(SIZE_MAX)][d(SIZE_MAX)], Init (), true);
-TEST (32, [d(SIZE_MAX)][5][d(SIZE_MAX)], Init (), true);
-TEST (64, [d(SIZE_MAX)][d(SIZE_MAX)][7], Init (), true);
-
-int main ()
-{
-  if (fail)
-    __builtin_abort ();
-}

	Jakub

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

* Re: [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
  2016-04-15 12:31                       ` Jakub Jelinek
@ 2016-04-15 14:33                         ` Martin Sebor
  0 siblings, 0 replies; 22+ messages in thread
From: Martin Sebor @ 2016-04-15 14:33 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Andreas Schwab, Jason Merrill, Gcc Patch List

On 04/15/2016 06:31 AM, Jakub Jelinek wrote:
> On Thu, Apr 14, 2016 at 09:26:11AM -0600, Martin Sebor wrote:
>>> /daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C: In instantiation of 'struct TestType<32u>':
>>> /daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:201:1:   required from here
>>> /daten/aranym/gcc/gcc-20160414/gcc/testsuite/g++.dg/cpp1y/vla11.C:89:27: error: requested alignment 32 is larger than 16 [-Wattributes]
>>
>> Thank you for the heads up (and sorry about the breakage).  I've
>> committed r234976 to fix that.
>
> Probably because of this change you haven't reverted (removed) the vla11.C
> testcase even when the ChangeLog said you've done that.
> And, the testcase obviously fails on the trunk, so I've committed following
> as obvious:

Probably.  I was rushing to unblock others whose bootstrap was
failing and didn't check carefully enough.  Thanks for fixing that.

Martin

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

end of thread, other threads:[~2016-04-15 14:33 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-07  1:38 [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements Martin Sebor
2016-03-14 21:26 ` Martin Sebor
2016-03-21 22:10   ` PING #2 " Martin Sebor
2016-03-23 18:34 ` Jason Merrill
2016-03-23 22:50   ` Martin Sebor
2016-03-24 16:24     ` Jason Merrill
2016-04-01 23:02       ` Martin Sebor
2016-04-04 23:35         ` Jason Merrill
2016-04-08  0:05           ` Martin Sebor
2016-04-10 23:14             ` Martin Sebor
2016-04-12 15:43               ` Jason Merrill
2016-04-12 17:37                 ` Martin Sebor
2016-04-12 18:17               ` Jason Merrill
2016-04-13 18:37                 ` Martin Sebor
2016-04-13 19:26                   ` Jason Merrill
2016-04-14  2:35                   ` H.J. Lu
2016-04-14 15:32                     ` Martin Sebor
2016-04-14 10:40                   ` Andreas Schwab
2016-04-14 15:26                     ` Martin Sebor
2016-04-15  7:11                       ` Christophe Lyon
2016-04-15 12:31                       ` Jakub Jelinek
2016-04-15 14:33                         ` Martin Sebor

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