This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]