This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH to implement C++14 VLA semantics
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches List <gcc-patches at gcc dot gnu dot org>
- Date: Thu, 09 May 2013 12:41:02 -0400
- Subject: PATCH to implement C++14 VLA semantics
At the last C++ standards meeting, we agreed to add VLAs to the
language. But they're significantly different from GNU/C99 VLAs: you
can't form a pointer to a VLA, or take its sizeof, or really anything
other than directly use it. We also need to throw an exception if we
try to create one with a negative or too large bound. And we need to
support lambda capture and range-based for loops.
The one thing I'm nervous about is our handling of an array which turns
out at runtime to be of length 0. GCC has always allowed zero-length
arrays, and they work fine, so I don't want to break existing code, but
I also want to offer a fully-conforming mode. What I ended up deciding
to do is throw on zero with -std=c++1y and not with -std=gnu++1y. But
I'm not terribly comfortable with this answer; anyone have any better ideas?
The first patch accepts VLAs in C++1y mode and adds new functionality;
the second patch adds diagnostics for invalid uses of C++1y VLAs.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit bc916afa64715b9629bb3a985f4207cf8635798d
Author: Jason Merrill <jason@redhat.com>
Date: Fri Apr 26 06:15:25 2013 -0400
N3639 C++1y VLA support
gcc/
* gimplify.c (gimplify_vla_decl): Don't touch an existing
DECL_VALUE_EXPR.
gcc/cp/
* decl.c (compute_array_index_type): Allow VLAs in C++1y mode.
(check_array_initializer): Allow VLA init.
(reshape_init_array_1): Adjust.
(cp_finish_decl): Check for invalid VLA length.
* typeck2.c (process_init_constructor_array): Adjust.
(store_init_value): Use build_vec_init for VLAs.
* semantics.c (add_capture): Capture VLA as ptr+len.
(vla_capture_type): New.
(build_capture_proxy): Rebuild the VLA.
* typeck.c (build_simple_component_ref): Split out from...
(build_ptrmemfunc_access_expr): ...here.
* tree.c (array_of_runtime_bound_p): New.
* init.c (throw_bad_array_length): New.
(build_vec_init): Use it.
* parser.c (cp_convert_range_for): When iterating over a VLA,
use it directly rather than bind a reference.
* cp-tree.h: Declare new functions.
libstdc++-v3/
* libsupc++/new: Add std::bad_array_length.
* libsupc++/bad_array_length.cc: New.
* libsupc++/eh_aux_runtime.cc: Add __cxa_bad_array_length.
* libsupc++/Makefile.in: Build them.
* config/abi/pre/gnu.ver: Add new symbols.
* config/abi/pre/gnu-versioned-namespace.ver: Add new symbols.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index dec7390..a2f59df 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5358,6 +5358,7 @@ extern tree build_value_init_noctor (tree, tsubst_flags_t);
extern tree build_offset_ref (tree, tree, bool,
tsubst_flags_t);
extern tree throw_bad_array_new_length (void);
+extern tree throw_bad_array_length (void);
extern tree build_new (vec<tree, va_gc> **, tree, tree,
vec<tree, va_gc> **, int,
tsubst_flags_t);
@@ -5849,6 +5850,7 @@ extern tree get_target_expr (tree);
extern tree get_target_expr_sfinae (tree, tsubst_flags_t);
extern tree build_cplus_array_type (tree, tree);
extern tree build_array_of_n_type (tree, int);
+extern bool array_of_runtime_bound_p (tree);
extern tree build_array_copy (tree);
extern tree build_vec_init_expr (tree, tree, tsubst_flags_t);
extern void diagnose_non_constexpr_vec_init (tree);
@@ -6032,6 +6034,7 @@ extern tree cp_build_binary_op (location_t,
enum tree_code, tree, tree,
tsubst_flags_t);
#define cxx_sizeof(T) cxx_sizeof_or_alignof_type (T, SIZEOF_EXPR, true)
+extern tree build_simple_component_ref (tree, tree);
extern tree build_ptrmemfunc_access_expr (tree, tree);
extern tree build_address (tree);
extern tree build_typed_address (tree, tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index d6e2861..cebd361 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5064,7 +5064,7 @@ reshape_init_array_1 (tree elt_type, tree max_index, reshape_iter *d,
tsubst_flags_t complain)
{
tree new_init;
- bool sized_array_p = (max_index != NULL_TREE);
+ bool sized_array_p = (max_index && TREE_CONSTANT (max_index));
unsigned HOST_WIDE_INT max_index_cst = 0;
unsigned HOST_WIDE_INT index;
@@ -5514,15 +5514,12 @@ check_array_initializer (tree decl, tree type, tree init)
error ("elements of array %q#T have incomplete type", type);
return true;
}
- /* It is not valid to initialize a VLA. */
- if (init
+ /* A compound literal can't have variable size. */
+ if (init && !decl
&& ((COMPLETE_TYPE_P (type) && !TREE_CONSTANT (TYPE_SIZE (type)))
|| !TREE_CONSTANT (TYPE_SIZE (element_type))))
{
- if (decl)
- error ("variable-sized object %qD may not be initialized", decl);
- else
- error ("variable-sized compound literal");
+ error ("variable-sized compound literal");
return true;
}
return false;
@@ -6405,6 +6402,21 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
&& TYPE_FOR_JAVA (type) && MAYBE_CLASS_TYPE_P (type))
error ("non-static data member %qD has Java class type", decl);
+ if (array_of_runtime_bound_p (type))
+ {
+ /* If the VLA bound is larger than half the address space, or less
+ than zero, throw std::bad_array_length. */
+ tree max = convert (ssizetype, TYPE_MAX_VALUE (TYPE_DOMAIN (type)));
+ /* C++1y says we should throw for length <= 0, but we have
+ historically supported zero-length arrays. Let's treat that as an
+ extension to be disabled by -std=c++NN. */
+ int lower = flag_iso ? 0 : -1;
+ tree comp = build2 (LT_EXPR, boolean_type_node, max, ssize_int (lower));
+ comp = build3 (COND_EXPR, void_type_node, comp,
+ throw_bad_array_length (), void_zero_node);
+ finish_expr_stmt (comp);
+ }
+
/* Add this declaration to the statement-tree. This needs to happen
after the call to check_initializer so that the DECL_EXPR for a
reference temp is added before the DECL_EXPR for the reference itself. */
@@ -8289,7 +8301,7 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
error ("size of array is not an integral constant-expression");
size = integer_one_node;
}
- else if (pedantic && warn_vla != 0)
+ else if (cxx_dialect < cxx1y && pedantic && warn_vla != 0)
{
if (name)
pedwarn (input_location, OPT_Wvla, "ISO C++ forbids variable length array %qD", name);
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 765c471..d687a84 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2185,6 +2185,20 @@ throw_bad_array_new_length (void)
return build_cxx_call (fn, 0, NULL, tf_warning_or_error);
}
+/* Call __cxa_bad_array_length to indicate that there were too many
+ initializers. */
+
+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);
+}
+
/* Generate code for a new-expression, including calling the "operator
new" function, initializing the object, and, if an exception occurs
during construction, cleaning up. The arguments are as for
@@ -3350,6 +3364,10 @@ build_vec_init (tree base, tree maxindex, tree init,
store_constructor will handle the semantics for us. */
stmt_expr = build2 (INIT_EXPR, atype, base, init);
+ if (length_check)
+ stmt_expr = build3 (COND_EXPR, atype, length_check,
+ throw_bad_array_length (),
+ stmt_expr);
return stmt_expr;
}
@@ -3467,6 +3485,9 @@ build_vec_init (tree base, tree maxindex, tree init,
if (length_check)
{
tree throw_call;
+ if (array_of_runtime_bound_p (atype))
+ throw_call = throw_bad_array_length ();
+ else
throw_call = throw_bad_array_new_length ();
length_check = build3 (COND_EXPR, void_type_node, length_check,
throw_call, void_zero_node);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 8d3f6c7..f65ec97 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -9842,13 +9842,21 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr)
begin_expr = end_expr = iter_type = error_mark_node;
else
{
- tree range_temp = build_range_temp (range_expr);
- pushdecl (range_temp);
- cp_finish_decl (range_temp, range_expr,
- /*is_constant_init*/false, NULL_TREE,
- LOOKUP_ONLYCONVERTING);
+ tree range_temp;
- range_temp = convert_from_reference (range_temp);
+ if (TREE_CODE (range_expr) == VAR_DECL
+ && array_of_runtime_bound_p (TREE_TYPE (range_expr)))
+ /* Can't bind a reference to an array of runtime bound. */
+ range_temp = range_expr;
+ else
+ {
+ range_temp = build_range_temp (range_expr);
+ pushdecl (range_temp);
+ cp_finish_decl (range_temp, range_expr,
+ /*is_constant_init*/false, NULL_TREE,
+ LOOKUP_ONLYCONVERTING);
+ range_temp = convert_from_reference (range_temp);
+ }
iter_type = cp_parser_perform_range_for_lookup (range_temp,
&begin_expr, &end_expr);
}
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 2165649..5917503 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -9379,6 +9379,21 @@ build_capture_proxy (tree member)
name = DECL_NAME (member);
type = lambda_proxy_type (object);
+
+ if (TREE_CODE (type) == RECORD_TYPE
+ && TYPE_NAME (type) == NULL_TREE)
+ {
+ /* Rebuild the VLA type from the pointer and maxindex. */
+ tree field = next_initializable_field (TYPE_FIELDS (type));
+ tree ptr = build_simple_component_ref (object, field);
+ field = next_initializable_field (DECL_CHAIN (field));
+ tree max = build_simple_component_ref (object, field);
+ type = build_array_type (TREE_TYPE (TREE_TYPE (ptr)),
+ build_index_type (max));
+ object = convert (build_reference_type (type), ptr);
+ object = convert_from_reference (object);
+ }
+
var = build_decl (input_location, VAR_DECL, name, type);
SET_DECL_VALUE_EXPR (var, object);
DECL_HAS_VALUE_EXPR_P (var) = 1;
@@ -9400,6 +9415,28 @@ build_capture_proxy (tree member)
return var;
}
+/* Return a struct containing a pointer and a length for lambda capture of
+ an array of runtime length. */
+
+static tree
+vla_capture_type (tree array_type)
+{
+ static tree ptr_id, max_id;
+ if (!ptr_id)
+ {
+ ptr_id = get_identifier ("ptr");
+ max_id = get_identifier ("max");
+ }
+ tree ptrtype = build_pointer_type (TREE_TYPE (array_type));
+ tree field1 = build_decl (input_location, FIELD_DECL, ptr_id, ptrtype);
+ tree field2 = build_decl (input_location, FIELD_DECL, max_id, sizetype);
+ DECL_CHAIN (field2) = field1;
+ tree type = make_node (RECORD_TYPE);
+ finish_builtin_struct (type, "__cap", field2, NULL_TREE);
+ TYPE_NAME (type) = NULL_TREE;
+ return type;
+}
+
/* From an ID and INITIALIZER, create a capture (by reference if
BY_REFERENCE_P is true), add it to the capture-list for LAMBDA,
and return it. */
@@ -9415,7 +9452,22 @@ add_capture (tree lambda, tree id, tree initializer, bool by_reference_p,
initializer = build_x_compound_expr_from_list (initializer, ELK_INIT,
tf_warning_or_error);
type = lambda_capture_field_type (initializer, explicit_init_p);
- if (by_reference_p)
+ if (array_of_runtime_bound_p (type))
+ {
+ /* For a VLA, we capture the address of the first element and the
+ maximum index, and then reconstruct the VLA for the proxy. */
+ gcc_assert (by_reference_p);
+ tree elt = cp_build_array_ref (input_location, initializer,
+ integer_zero_node, tf_warning_or_error);
+ tree ctype = vla_capture_type (type);
+ tree ptr_field = next_initializable_field (TYPE_FIELDS (ctype));
+ tree nelts_field = next_initializable_field (DECL_CHAIN (ptr_field));
+ initializer = build_constructor_va (ctype, 2,
+ ptr_field, build_address (elt),
+ nelts_field, array_type_nelts (type));
+ type = ctype;
+ }
+ else if (by_reference_p)
{
type = build_reference_type (type);
if (!real_lvalue_p (initializer))
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 5117319..2df2087 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -871,6 +871,21 @@ build_array_of_n_type (tree elt, int n)
return build_cplus_array_type (elt, build_index_type (size_int (n - 1)));
}
+/* True iff T is a C++1y array of runtime bound (VLA). */
+
+bool
+array_of_runtime_bound_p (tree t)
+{
+ if (!t || TREE_CODE (t) != ARRAY_TYPE)
+ return false;
+ tree dom = TYPE_DOMAIN (t);
+ if (!dom)
+ return false;
+ tree max = TYPE_MAX_VALUE (dom);
+ return (!value_dependent_expression_p (max)
+ && !TREE_CONSTANT (max));
+}
+
/* Return a reference type node referring to TO_TYPE. If RVAL is
true, return an rvalue reference type, otherwise return an lvalue
reference type. If a type node exists, reuse it, otherwise create
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 2d9711b..47670f2 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -2788,6 +2788,19 @@ finish_class_member_access_expr (tree object, tree name, bool template_p,
return expr;
}
+/* Build a COMPONENT_REF of OBJECT and MEMBER with the appropriate
+ type. */
+
+tree
+build_simple_component_ref (tree object, tree member)
+{
+ tree type = cp_build_qualified_type (TREE_TYPE (member),
+ cp_type_quals (TREE_TYPE (object)));
+ return fold_build3_loc (input_location,
+ COMPONENT_REF, type,
+ object, member, NULL_TREE);
+}
+
/* Return an expression for the MEMBER_NAME field in the internal
representation of PTRMEM, a pointer-to-member function. (Each
pointer-to-member function type gets its own RECORD_TYPE so it is
@@ -2800,7 +2813,6 @@ build_ptrmemfunc_access_expr (tree ptrmem, tree member_name)
{
tree ptrmem_type;
tree member;
- tree member_type;
/* This code is a stripped down version of
build_class_member_access_expr. It does not work to use that
@@ -2810,11 +2822,7 @@ build_ptrmemfunc_access_expr (tree ptrmem, tree member_name)
gcc_assert (TYPE_PTRMEMFUNC_P (ptrmem_type));
member = lookup_member (ptrmem_type, member_name, /*protect=*/0,
/*want_type=*/false, tf_warning_or_error);
- member_type = cp_build_qualified_type (TREE_TYPE (member),
- cp_type_quals (ptrmem_type));
- return fold_build3_loc (input_location,
- COMPONENT_REF, member_type,
- ptrmem, member, NULL_TREE);
+ return build_simple_component_ref (ptrmem, member);
}
/* Given an expression PTR for a pointer, return an expression
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index a0bc50b..e0ebae9 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -795,10 +795,12 @@ 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)
|| ! reduced_constant_expression_p (value)))
{
if (TREE_CODE (type) == ARRAY_TYPE
- && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (type)))
+ && (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (type))
+ || array_of_runtime_bound_p (type)))
/* For an array, we only need/want a single cleanup region rather
than one per element. */
return build_vec_init (decl, NULL_TREE, value, false, 1,
@@ -1114,7 +1116,7 @@ process_init_constructor_array (tree type, tree init,
if (TREE_CODE (type) == ARRAY_TYPE)
{
tree domain = TYPE_DOMAIN (type);
- if (domain)
+ if (domain && TREE_CONSTANT (TYPE_MAX_VALUE (domain)))
len = (tree_to_double_int (TYPE_MAX_VALUE (domain))
- tree_to_double_int (TYPE_MIN_VALUE (domain))
+ double_int_one)
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index fc7bfcf..e2ae893 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1382,6 +1382,10 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p)
gimplify_one_sizepos (&DECL_SIZE (decl), seq_p);
gimplify_one_sizepos (&DECL_SIZE_UNIT (decl), seq_p);
+ /* Don't mess with a DECL_VALUE_EXPR set by the front-end. */
+ if (DECL_HAS_VALUE_EXPR_P (decl))
+ return;
+
/* All occurrences of this decl in final gimplified code will be
replaced by indirection. Setting DECL_VALUE_EXPR does two
things: First, it lets the rest of the gimplifier know what
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla2.C b/gcc/testsuite/g++.dg/cpp1y/vla2.C
new file mode 100644
index 0000000..4cd95d4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla2.C
@@ -0,0 +1,15 @@
+// N3639 allows initialization and capture of VLAs
+// { dg-options -std=c++1y }
+// { dg-do run }
+
+void f(int n)
+{
+ int ar[n] = { 42 };
+ auto l = [&] { return ar[0]; };
+ if (l() != 42) __builtin_abort ();
+}
+
+int main()
+{
+ f(1);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla3.C b/gcc/testsuite/g++.dg/cpp1y/vla3.C
new file mode 100644
index 0000000..a016904
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla3.C
@@ -0,0 +1,30 @@
+// Test for throwing bad_array_length on invalid array length
+// { dg-options -std=c++1y }
+// { dg-do run }
+
+#include <new>
+
+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::bad_array_length) { ++ok; }
+ try { g(-24); } // negative
+ catch (std::bad_array_length) { ++ok; }
+
+ if (ok != 2)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla4.C b/gcc/testsuite/g++.dg/cpp1y/vla4.C
new file mode 100644
index 0000000..78b7eff
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla4.C
@@ -0,0 +1,24 @@
+// Test for range-based for with VLAs.
+// { dg-options -std=c++1y }
+// { dg-do run }
+
+#include <new>
+
+void f(int i)
+{
+ int ar[i];
+ int j = 0;
+ for (int& x : ar)
+ x = ++j;
+ [&ar]{
+ int k = 0;
+ for (int x : ar)
+ if (x != ++k)
+ __builtin_abort();
+ }();
+}
+
+int main()
+{
+ f(42); // OK
+}
diff --git a/gcc/testsuite/g++.dg/init/array24.C b/gcc/testsuite/g++.dg/init/array24.C
index ed4c1d8..2d72df4 100644
--- a/gcc/testsuite/g++.dg/init/array24.C
+++ b/gcc/testsuite/g++.dg/init/array24.C
@@ -1,7 +1,7 @@
// PR c++/29175
-// { dg-options "" }
+// { dg-options "-Wno-vla" }
void foo(int i)
{
- int x[][i] = { 0 }; // { dg-error "variable-sized|storage size" }
+ int x[][i] = { 0 };
}
diff --git a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
index 07feda0..33a0068 100644
--- a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
+++ b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
@@ -235,6 +235,9 @@ CXXABI_2.0 {
__cxa_throw_bad_array_new_length;
_Z*St20bad_array_new_length*;
+ __cxa_throw_bad_array_length;
+ _Z*St16bad_array_length*;
+
# Default function.
_ZSt11_Hash_bytesPKv*;
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index 7256c6f..446a685 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -1559,6 +1559,9 @@ CXXABI_1.3.7 {
CXXABI_1.3.8 {
__cxa_throw_bad_array_new_length;
_Z*St20bad_array_new_length*;
+
+ __cxa_throw_bad_array_length;
+ _Z*St16bad_array_length*;
} CXXABI_1.3.7;
# Symbols in the support library (libsupc++) supporting transactional memory.
diff --git a/libstdc++-v3/libsupc++/Makefile.in b/libstdc++-v3/libsupc++/Makefile.in
index 9f24fef..6ff4d0c 100644
--- a/libstdc++-v3/libsupc++/Makefile.in
+++ b/libstdc++-v3/libsupc++/Makefile.in
@@ -92,8 +92,8 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(bitsdir)" \
LTLIBRARIES = $(noinst_LTLIBRARIES) $(toolexeclib_LTLIBRARIES)
libsupc___la_LIBADD =
am__objects_1 = array_type_info.lo atexit_arm.lo atexit_thread.lo \
- bad_alloc.lo bad_array_new.lo bad_cast.lo bad_typeid.lo \
- class_type_info.lo \
+ bad_alloc.lo bad_array_length.lo bad_array_new.lo bad_cast.lo \
+ bad_typeid.lo class_type_info.lo \
del_op.lo del_opnt.lo del_opv.lo del_opvnt.lo dyncast.lo \
eh_alloc.lo eh_arm.lo eh_aux_runtime.lo eh_call.lo eh_catch.lo \
eh_exception.lo eh_globals.lo eh_personality.lo eh_ptr.lo \
@@ -367,6 +367,7 @@ sources = \
atexit_arm.cc \
atexit_thread.cc \
bad_alloc.cc \
+ bad_array_length.cc \
bad_array_new.cc \
bad_cast.cc \
bad_typeid.cc \
@@ -789,16 +790,22 @@ cp-demangle.lo: cp-demangle.c
cp-demangle.o: cp-demangle.c
$(C_COMPILE) -DIN_GLIBCPP_V3 -Wno-error -c $<
-# Use special rules for the C++11 sources so that the proper flags are passed.
+# Use special rules for the C++11 and C++1y sources so that the proper
+# flags are passed.
+bad_array_length.lo: bad_array_length.cc
+ $(LTCXXCOMPILE) -std=gnu++1y -c $<
+bad_array_length.o: bad_array_length.cc
+ $(CXXCOMPILE) -std=gnu++1y -c $<
+
bad_array_new.lo: bad_array_new.cc
$(LTCXXCOMPILE) -std=gnu++11 -c $<
bad_array_new.o: bad_array_new.cc
$(CXXCOMPILE) -std=gnu++11 -c $<
eh_aux_runtime.lo: eh_aux_runtime.cc
- $(LTCXXCOMPILE) -std=gnu++11 -c $<
+ $(LTCXXCOMPILE) -std=gnu++1y -c $<
eh_aux_runtime.o: eh_aux_runtime.cc
- $(CXXCOMPILE) -std=gnu++11 -c $<
+ $(CXXCOMPILE) -std=gnu++1y -c $<
eh_ptr.lo: eh_ptr.cc
$(LTCXXCOMPILE) -std=gnu++11 -c $<
diff --git a/libstdc++-v3/libsupc++/bad_array_length.cc b/libstdc++-v3/libsupc++/bad_array_length.cc
new file mode 100644
index 0000000..a63d660
--- /dev/null
+++ b/libstdc++-v3/libsupc++/bad_array_length.cc
@@ -0,0 +1,36 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of GCC.
+//
+// GCC is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// GCC is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+#include <new>
+
+namespace std {
+
+bad_array_length::~bad_array_length() _GLIBCXX_USE_NOEXCEPT { }
+
+const char*
+bad_array_length::what() const _GLIBCXX_USE_NOEXCEPT
+{
+ return "std::bad_array_length";
+}
+
+} // namespace std
diff --git a/libstdc++-v3/libsupc++/cxxabi.h b/libstdc++-v3/libsupc++/cxxabi.h
index 83749ce..cf2c060 100644
--- a/libstdc++-v3/libsupc++/cxxabi.h
+++ b/libstdc++-v3/libsupc++/cxxabi.h
@@ -154,6 +154,8 @@ namespace __cxxabiv1
void
__cxa_throw_bad_array_new_length() __attribute__((__noreturn__));
+ void
+ __cxa_throw_bad_array_length() __attribute__((__noreturn__));
/**
* @brief Demangling routine.
diff --git a/libstdc++-v3/libsupc++/eh_aux_runtime.cc b/libstdc++-v3/libsupc++/eh_aux_runtime.cc
index 1cc831b..806b479 100644
--- a/libstdc++-v3/libsupc++/eh_aux_runtime.cc
+++ b/libstdc++-v3/libsupc++/eh_aux_runtime.cc
@@ -40,3 +40,7 @@ __cxxabiv1::__cxa_bad_typeid ()
extern "C" void
__cxxabiv1::__cxa_throw_bad_array_new_length ()
{ _GLIBCXX_THROW_OR_ABORT(std::bad_array_new_length()); }
+
+extern "C" void
+__cxxabiv1::__cxa_throw_bad_array_length ()
+{ _GLIBCXX_THROW_OR_ABORT(std::bad_array_length()); }
diff --git a/libstdc++-v3/libsupc++/new b/libstdc++-v3/libsupc++/new
index 3087502..cdf4cab 100644
--- a/libstdc++-v3/libsupc++/new
+++ b/libstdc++-v3/libsupc++/new
@@ -79,6 +79,23 @@ namespace std
};
#endif
+ // We throw this exception for GNU VLAs of negative length in all C++
+ // dialects, so declare it if we aren't in strict conformance mode.
+#if __cplusplus > 201103L || !defined(__STRICT_ANSI__)
+ class bad_array_length : public bad_alloc
+ {
+ public:
+ bad_array_length() throw() { };
+
+ // This declaration is not useless:
+ // http://gcc.gnu.org/onlinedocs/gcc-3.0.2/gcc_6.html#SEC118
+ virtual ~bad_array_length() throw();
+
+ // See comment in eh_exception.cc.
+ virtual const char* what() const throw();
+ };
+#endif
+
struct nothrow_t { };
extern const nothrow_t nothrow;
commit 145fead03a44496158ccf901b9ead175db550282
Author: Jason Merrill <jason@redhat.com>
Date: Thu Apr 25 17:53:42 2013 -0400
N3639 C++1y VLA diagnostics
* decl.c (grokdeclarator): Complain about reference, pointer, or
typedef to VLA.
(create_array_type_for_decl): Complain about array of VLA.
* pt.c (tsubst): Likewise.
* rtti.c (get_tinfo_decl): Talk about "array of runtime bound".
* semantics.c (finish_decltype_type): Complain about decltype of VLA.
* typeck.c (cp_build_addr_expr_1): Complain about VLA.
(cxx_sizeof_or_alignof_type): Likewise.
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index b762d28..a3250a2 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8478,6 +8478,9 @@ create_array_type_for_decl (tree name, tree type, tree size)
return error_mark_node;
}
+ if (cxx_dialect >= cxx1y && array_of_runtime_bound_p (type))
+ pedwarn (input_location, OPT_Wvla, "array of array of runtime bound");
+
/* Figure out the index type for the array. */
if (size)
itype = compute_array_index_type (name, size, tf_warning_or_error);
@@ -9718,6 +9721,12 @@ grokdeclarator (const cp_declarator *declarator,
: G_("cannot declare pointer to qualified function type %qT"),
type);
+ if (cxx_dialect >= cxx1y && array_of_runtime_bound_p (type))
+ pedwarn (input_location, OPT_Wvla,
+ declarator->kind == cdk_reference
+ ? G_("reference to array of runtime bound")
+ : G_("pointer to array of runtime bound"));
+
/* When the pointed-to type involves components of variable size,
care must be taken to ensure that the size evaluation code is
emitted early enough to dominate all the possible later uses
@@ -10072,6 +10081,10 @@ grokdeclarator (const cp_declarator *declarator,
type = error_mark_node;
}
+ if (cxx_dialect >= cxx1y && array_of_runtime_bound_p (type))
+ pedwarn (input_location, OPT_Wvla,
+ "typedef naming array of runtime bound");
+
if (decl_context == FIELD)
decl = build_lang_decl (TYPE_DECL, unqualified_id, type);
else
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index dca3407..2cb2abd 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -11560,6 +11560,18 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
r = cp_build_reference_type (type, TYPE_REF_IS_RVALUE (t));
r = cp_build_qualified_type_real (r, cp_type_quals (t), complain);
+ if (cxx_dialect >= cxx1y && array_of_runtime_bound_p (type))
+ {
+ if (complain & tf_warning_or_error)
+ pedwarn
+ (input_location, OPT_Wvla,
+ code == REFERENCE_TYPE
+ ? G_("cannot declare reference to array of runtime bound")
+ : G_("cannot declare pointer to array of runtime bound"));
+ else
+ r = error_mark_node;
+ }
+
if (r != error_mark_node)
/* Will this ever be needed for TYPE_..._TO values? */
layout_type (r);
diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c
index 4e73165..9010440 100644
--- a/gcc/cp/rtti.c
+++ b/gcc/cp/rtti.c
@@ -393,9 +393,12 @@ get_tinfo_decl (tree type)
if (variably_modified_type_p (type, /*fn=*/NULL_TREE))
{
- error ("cannot create type information for type %qT because "
- "it involves types of variable size",
- type);
+ if (array_of_runtime_bound_p (type))
+ error ("typeid of array of runtime bound");
+ else
+ error ("cannot create type information for type %qT because "
+ "it involves types of variable size",
+ type);
return error_mark_node;
}
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 27e7822..ff8ac2a 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5456,6 +5456,15 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
}
}
+ if (cxx_dialect >= cxx1y && array_of_runtime_bound_p (type))
+ {
+ if (complain & tf_warning_or_error)
+ pedwarn (input_location, OPT_Wvla,
+ "taking decltype of array of runtime bound");
+ else
+ return error_mark_node;
+ }
+
return type;
}
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 47670f2..df5fc4a 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1547,6 +1547,15 @@ cxx_sizeof_or_alignof_type (tree type, enum tree_code op, bool complain)
return value;
}
+ if (cxx_dialect >= cxx1y && array_of_runtime_bound_p (type))
+ {
+ if (complain & tf_warning_or_error)
+ pedwarn (input_location, OPT_Wvla,
+ "taking sizeof array of runtime bound");
+ else
+ return error_mark_node;
+ }
+
return c_sizeof_or_alignof_type (input_location, complete_type (type),
op == SIZEOF_EXPR,
complain);
@@ -5316,7 +5325,17 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain)
}
if (argtype != error_mark_node)
- argtype = build_pointer_type (argtype);
+ {
+ if (cxx_dialect >= cxx1y && array_of_runtime_bound_p (argtype))
+ {
+ if (complain & tf_warning_or_error)
+ pedwarn (input_location, OPT_Wvla,
+ "taking address of array of runtime bound");
+ else
+ return error_mark_node;
+ }
+ argtype = build_pointer_type (argtype);
+ }
/* In a template, we are processing a non-dependent expression
so we can just form an ADDR_EXPR with the correct type. */
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla1.C b/gcc/testsuite/g++.dg/cpp1y/vla1.C
new file mode 100644
index 0000000..29a59ed
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla1.C
@@ -0,0 +1,40 @@
+// { dg-options "-std=c++1y -pedantic-errors" }
+
+#include <typeinfo>
+
+void f(int n)
+{
+ int a[n];
+ int aa[n][n]; // { dg-error "" }
+ &a; // { dg-error "" }
+ sizeof a; // { dg-error "" }
+ typeid(a); // { dg-error "" }
+ decltype(a) a2; // { dg-error "" }
+ typedef int at[n]; // { dg-error "" }
+ int (*p)[n]; // { dg-error "" }
+ int (&r)[n] = a; // { dg-error "" }
+ struct A
+ {
+ int a[n]; // { dg-error "" }
+ };
+}
+
+template <class T>
+void g(int n)
+{
+ int a[n];
+ int aa[n][n]; // { dg-error "" }
+ &a; // { dg-error "" }
+ sizeof a; // { dg-error "" }
+ typeid(a); // { dg-error "" }
+ decltype(a) a2; // { dg-error "" }
+ typedef int at[n]; // { dg-error "" }
+ int (*p)[n]; // { dg-error "" }
+ int (&r)[n] = a; // { dg-error "" }
+ struct A
+ {
+ int a[n]; // { dg-error "" }
+ };
+}
+
+template void g<int>(int);