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 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 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 PR c++/69517 PR c++/70019 * extend.texi (Variable Length): Document C++ specifics. libstdc++-v3/ChangeLog: 2016-04-01 Martin Sebor 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 **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 *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 +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 +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 vla Dims Init; \ + static_assert (sizeof (TestType) == 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 VLA Dims; // uninitialized (with Init ()) +// or: +// TestType 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 +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() \ + { \ + 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() + + +// 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 { 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);