PR c++/70652 - [6 Regression] r234966 causes bootstrap to fail

PR c++/70652 - [6 Regression] r234966 causes bootstrap to fail
  Revert patch for c++/69517, c++/70019, and c++/70588.

From-SVN: r234981
This commit is contained in:
Martin Sebor 2016-04-14 17:35:23 +00:00 committed by Martin Sebor
parent 8512855950
commit d8747845fd
15 changed files with 47 additions and 872 deletions

View File

@ -1,3 +1,10 @@
2016-04-14 Martin Sebor <msebor@redhat.com>
PR c++/69517
PR c++/70019
PR c++/70588
* doc/extend.texi (Variable Length): Revert.
2016-04-14 Marek Polacek <polacek@redhat.com>
Jan Hubicka <hubicka@ucw.cz>

View File

@ -1,3 +1,10 @@
2016-04-14 Martin Sebor <msebor@redhat.com>
PR c++/69517
PR c++/70019
PR c++/70588
* cp-tree.h, decl.c, init.c, typeck2.c: Revert.
2016-04-14 Jason Merrill <jason@redhat.com>
* call.c, decl.c, error.c, cp-tree.h, decl.c: Revert empty

View File

@ -5944,7 +5944,6 @@ 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,
@ -5966,7 +5965,6 @@ 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);

View File

@ -5892,16 +5892,6 @@ 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);
}
@ -6054,10 +6044,6 @@ 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));
@ -6209,9 +6195,7 @@ 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));
saved_init_for_vla_check = init;
init = NULL_TREE;
init = NULL;
}
}
else
@ -6225,33 +6209,6 @@ 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);

View File

@ -2262,20 +2262,6 @@ 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. */
@ -4723,304 +4709,3 @@ 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;
}

View File

@ -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))
|| variably_modified_type_p (type, NULL_TREE))
|| array_of_runtime_bound_p (type))
{
/* 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)
|| variably_modified_type_p (type, NULL_TREE)
|| array_of_runtime_bound_p (type)
|| ! 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

View File

@ -1638,48 +1638,14 @@ 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 available in GCC for all targets and
provide type safety.
variable-length arrays are more elegant.
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.
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:
You can also use variable-length arrays as arguments to functions:
@smallexample
struct entry

View File

@ -1,3 +1,17 @@
2016-04-14 Martin Sebor <msebor@redhat.com>
PR c++/69517
PR c++/70019
PR c++/70588
* c-c++-common/ubsan/vla-1.c: Revert.
* g++.dg/cpp1y/vla11.C: Same.
* g++.dg/cpp1y/vla12.C: Same.
* g++.dg/cpp1y/vla13.C: Same.
* g++.dg/cpp1y/vla14.C: Same.
* g++.dg/cpp1y/vla3.C: Same.
* gcc/testsuite/g++.dg/init/array24.C: Same.
* g++.dg/ubsan/vla-1.C: Same.
2016-04-14 Marek Polacek <polacek@redhat.com>
Jan Hubicka <hubicka@ucw.cz>

View File

@ -87,24 +87,18 @@ fn12 (void)
int
main (void)
{
#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 ());
fn1 ();
fn2 ();
fn3 ();
fn4 ();
fn5 ();
fn6 ();
fn7 ();
fn8 ();
fn9 ();
fn10 ();
fn11 ();
fn12 ();
return 0;
}

View File

@ -1,99 +0,0 @@
// Test to verify that variable length arrays the product of whose constant
// bounds overflows or exceeds the implementation-defined limit are diagnosed.
// { dg-do compile { 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;
#define MAX (SIZE_MAX / 2)
void test (int x)
{
const size_t amax = MAX;
// The following are valid and shouldn't elicit a bounds overflow warning.
{
char a [x][amax]; // { dg-warning "forbids" }
(void)a;
}
{
char a [amax][x]; // { dg-warning "forbids" }
(void)a;
}
// The following is invalid and should be diagnosed. Unfortunately,
// when the VLA maximum size is (SIZE_MAX / 2), G++ also issues
// a (bogus) -Woverflow because it computes the array bound in
// a signed type (ssize_t) instead of size_t, in addition to
// rejecting the declaration with error: size of array a is too
// large, before the VLA constant bound check has had a chance to
// see it. So the test is disabled.
// {
// char a [x][amax + 1];
// (void)a;
// }
{
char a [x][x][amax]; // { dg-warning "forbids" }
(void)a;
}
{
char a [x][amax][x]; // { dg-warning "forbids" }
(void)a;
}
{
char a [amax][x][x]; // { dg-warning "forbids" }
(void)a;
}
{
char a [2][x][amax]; // { dg-warning "forbids|exceeds maximum" }
(void)a;
}
{
// Unfortunately, the following 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
// Ditto for other multidimensional VLAs where the overflow occurs
// in the computation of the product of adjacent constant bounds.
// char a [x][amax][amax];
// char b [x][2][amax];
// 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][x][amax]; // { dg-warning "forbids|exceeds maximum" }
(void)a;
}
{
char a [amax][amax][x]; // { dg-warning "forbids|exceeds maximum" }
(void)a;
}
{
struct A256 { __attribute__ ((aligned (256))) char a; };
enum {
M = 1024,
N = MAX / (sizeof (A256) * M)
};
A256 a [x][M][x][N]; // { dg-warning "forbids" }
(void)a;
A256 b [2][x][M][x][N]; // { dg-warning "forbids|exceeds maximum" }
(void)b;
}
}

View File

@ -1,260 +0,0 @@
// 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 ();
}

View File

@ -1,48 +0,0 @@
// 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;
}

View File

@ -1,43 +0,0 @@
// 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 ();
}

View File

@ -3,5 +3,5 @@
void foo(int i)
{
int x[][i] = { { 0 } };
int x[][i] = { 0 };
}

View File

@ -1,8 +1,5 @@
// { dg-do run }
// 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-options "-Wno-vla -fsanitize=undefined" }
// { dg-output "index 1 out of bounds" }
void f(int i) {