From 1e26d88a08a00f3ab609a0d07aad48c3f1bcdfd9 Mon Sep 17 00:00:00 2001
From: mmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Tue, 5 Dec 2006 21:33:20 +0000
Subject: [PATCH] 	PR c++/29728 	* decl.c
 (check_array_designated_initializer): New function. 
 (maybe_deduce_size_from_array_init): Use it. 	(reshape_init_array):
 Likewise. 	PR c++/29728 	* g++.dg/template/crash62.C: New test.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@119558 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/cp/ChangeLog                        |  7 ++
 gcc/cp/decl.c                           | 95 +++++++++++++++++--------
 gcc/testsuite/ChangeLog                 |  5 ++
 gcc/testsuite/g++.dg/template/crash62.C |  6 ++
 4 files changed, 82 insertions(+), 31 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/crash62.C

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 8c57d4fffa31..d9de3612f743 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,10 @@
+2006-12-05  Mark Mitchell  <mark@codesourcery.com>
+
+	PR c++/29728
+	* decl.c (check_array_designated_initializer): New function.
+	(maybe_deduce_size_from_array_init): Use it.
+	(reshape_init_array): Likewise.
+
 2006-12-05  Aldy Hernandez  <aldyh@redhat.com>
 
 	Merge from gimple-tuples-branch.
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 8a55e417d40e..1edd7ea9d700 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4092,6 +4092,30 @@ grok_reference_init (tree decl, tree type, tree init, tree *cleanup)
   return NULL_TREE;
 }
 
+/* Designated initializers in arrays are not supported in GNU C++.
+   The parser cannot detect this error since it does not know whether
+   a given brace-enclosed initializer is for a class type or for an
+   array.  This function checks that CE does not use a designated
+   initializer.  If it does, an error is issued.  Returns true if CE
+   is valid, i.e., does not have a designated initializer.  */
+
+static bool
+check_array_designated_initializer (const constructor_elt *ce)
+{
+  /* Designated initializers for array elements arenot supported.  */
+  if (ce->index)
+    {
+      /* The parser only allows identifiers as designated
+	 intializers.  */
+      gcc_assert (TREE_CODE (ce->index) == IDENTIFIER_NODE);
+      error ("name %qD used in a GNU-style designated "
+	     "initializer for an array", ce->index);
+      return false;
+    }
+
+  return true;
+}
+
 /* When parsing `int a[] = {1, 2};' we don't know the size of the
    array until we finish parsing the initializer.  If that's the
    situation we're in, update DECL accordingly.  */
@@ -4109,32 +4133,52 @@ maybe_deduce_size_from_array_init (tree decl, tree init)
 	 But let's leave it here to ease the eventual merge.  */
       int do_default = !DECL_EXTERNAL (decl);
       tree initializer = init ? init : DECL_INITIAL (decl);
-      int failure = cp_complete_array_type (&TREE_TYPE (decl), initializer,
-					    do_default);
+      int failure = 0;
 
-      if (failure == 1)
+      /* Check that there are no designated initializers in INIT, as
+	 those are not supported in GNU C++, and as the middle-end
+	 will crash if presented with a non-numeric designated
+	 initializer.  */
+      if (initializer && TREE_CODE (initializer) == CONSTRUCTOR)
 	{
-	  error ("initializer fails to determine size of %qD", decl);
-	  TREE_TYPE (decl) = error_mark_node;
+	  VEC(constructor_elt,gc) *v = CONSTRUCTOR_ELTS (initializer);
+	  constructor_elt *ce;
+	  HOST_WIDE_INT i;
+	  for (i = 0; 
+	       VEC_iterate (constructor_elt, v, i, ce);
+	       ++i)
+	    if (!check_array_designated_initializer (ce))
+	      failure = 1;
 	}
-      else if (failure == 2)
+
+      if (!failure)
 	{
-	  if (do_default)
+	  failure = cp_complete_array_type (&TREE_TYPE (decl), initializer,
+					    do_default);
+	  if (failure == 1)
 	    {
-	      error ("array size missing in %qD", decl);
+	      error ("initializer fails to determine size of %qD", decl);
+	      TREE_TYPE (decl) = error_mark_node;
+	    }
+	  else if (failure == 2)
+	    {
+	      if (do_default)
+		{
+		  error ("array size missing in %qD", decl);
+		  TREE_TYPE (decl) = error_mark_node;
+		}
+	      /* If a `static' var's size isn't known, make it extern as
+		 well as static, so it does not get allocated.  If it's not
+		 `static', then don't mark it extern; finish_incomplete_decl
+		 will give it a default size and it will get allocated.  */
+	      else if (!pedantic && TREE_STATIC (decl) && !TREE_PUBLIC (decl))
+		DECL_EXTERNAL (decl) = 1;
+	    }
+	  else if (failure == 3)
+	    {
+	      error ("zero-size array %qD", decl);
 	      TREE_TYPE (decl) = error_mark_node;
 	    }
-	  /* If a `static' var's size isn't known, make it extern as
-	     well as static, so it does not get allocated.  If it's not
-	     `static', then don't mark it extern; finish_incomplete_decl
-	     will give it a default size and it will get allocated.  */
-	  else if (!pedantic && TREE_STATIC (decl) && !TREE_PUBLIC (decl))
-	    DECL_EXTERNAL (decl) = 1;
-	}
-      else if (failure == 3)
-	{
-	  error ("zero-size array %qD", decl);
-	  TREE_TYPE (decl) = error_mark_node;
 	}
 
       cp_apply_type_quals_to_decl (cp_type_quals (TREE_TYPE (decl)), decl);
@@ -4346,18 +4390,7 @@ reshape_init_array_1 (tree elt_type, tree max_index, reshape_iter *d)
     {
       tree elt_init;
 
-      if (d->cur->index)
-	{
-	  /* Handle array designated initializers (GNU extension).  */
-	  if (TREE_CODE (d->cur->index) == IDENTIFIER_NODE)
-	    {
-	      error ("name %qD used in a GNU-style designated "
-		     "initializer for an array", d->cur->index);
-	    }
-	  else
-	    gcc_unreachable ();
-	}
-
+      check_array_designated_initializer (d->cur);
       elt_init = reshape_init_r (elt_type, d, /*first_initializer_p=*/false);
       if (elt_init == error_mark_node)
 	return error_mark_node;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index dc199b6aac07..d7bae48f0a10 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2006-12-05  Mark Mitchell  <mark@codesourcery.com>
+
+	PR c++/29728
+	* g++.dg/template/crash62.C: New test.
+
 2006-12-05  Paul Thomas  <pault@gcc.gnu.org>
 
 	PR fortran/30003
diff --git a/gcc/testsuite/g++.dg/template/crash62.C b/gcc/testsuite/g++.dg/template/crash62.C
new file mode 100644
index 000000000000..bd8a0f40e058
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/crash62.C
@@ -0,0 +1,6 @@
+// PR c++/29728
+
+template<int> void foo()
+{
+  int a[] = { X: 0 }; // { dg-error "designated initializer" }
+}
-- 
GitLab