Patchwork C++ PATCH for c++/46289 (ICE on invalid mem-init-list in constexpr ctor)

login
register
mail settings
Submitter Jason Merrill
Date Nov. 4, 2010, 2:02 a.m.
Message ID <4CD2142E.7000102@redhat.com>
Download mbox | patch
Permalink /patch/70092/
State New
Headers show

Comments

Jason Merrill - Nov. 4, 2010, 2:02 a.m.
On 11/03/2010 03:01 PM, Jason Merrill wrote:
> The testcase in the PR ought to be valid, but even on an invalid
> initializer we shouldn't ICE. This patch just fixes the ICE.

And this patch fixes the error.

Tested x86_64-pc-linux-gnu, applied to trunk.
commit 806ad75a68d2a2ecede77d1857cc1404d395e6a6
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Nov 3 18:28:18 2010 -0400

    	PR c++/46289
    	* call.c (can_convert_array): New fn.
    	(build_aggr_conv): Use it.

Patch

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index a1c8682..4507f3d 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -639,6 +639,29 @@  build_list_conv (tree type, tree ctor, int flags)
   return t;
 }
 
+/* Subroutine of build_aggr_conv: check whether CTOR, a braced-init-list,
+   is a valid aggregate initializer for array type ATYPE.  */
+
+static bool
+can_convert_array (tree atype, tree ctor, int flags)
+{
+  unsigned i;
+  tree elttype = TREE_TYPE (atype);
+  for (i = 0; i < CONSTRUCTOR_NELTS (ctor); ++i)
+    {
+      tree val = CONSTRUCTOR_ELT (ctor, i)->value;
+      bool ok;
+      if (TREE_CODE (elttype) == ARRAY_TYPE
+	  && TREE_CODE (val) == CONSTRUCTOR)
+	ok = can_convert_array (elttype, val, flags);
+      else
+	ok = can_convert_arg (elttype, TREE_TYPE (val), val, flags);
+      if (!ok)
+	return false;
+    }
+  return true;
+}
+
 /* Represent a conversion from CTOR, a braced-init-list, to TYPE, an
    aggregate class, if such a conversion is possible.  */
 
@@ -652,24 +675,31 @@  build_aggr_conv (tree type, tree ctor, int flags)
 
   for (; field; field = next_initializable_field (DECL_CHAIN (field)))
     {
+      tree ftype = TREE_TYPE (field);
+      tree val;
+      bool ok;
+
       if (i < CONSTRUCTOR_NELTS (ctor))
-	{
-	  constructor_elt *ce = CONSTRUCTOR_ELT (ctor, i);
-	  if (!can_convert_arg (TREE_TYPE (field), TREE_TYPE (ce->value),
-				ce->value, flags))
-	    return NULL;
-	  ++i;
-	  if (TREE_CODE (type) == UNION_TYPE)
-	    break;
-	}
+	val = CONSTRUCTOR_ELT (ctor, i)->value;
       else
 	{
 	  if (empty_ctor == NULL_TREE)
 	    empty_ctor = build_constructor (init_list_type_node, NULL);
-	  if (!can_convert_arg (TREE_TYPE (field), TREE_TYPE (empty_ctor),
-				empty_ctor, flags))
-	    return NULL;
+	  val = empty_ctor;
 	}
+      ++i;
+
+      if (TREE_CODE (ftype) == ARRAY_TYPE
+	  && TREE_CODE (val) == CONSTRUCTOR)
+	ok = can_convert_array (ftype, val, flags);
+      else
+	ok = can_convert_arg (ftype, TREE_TYPE (val), val, flags);
+
+      if (!ok)
+	return NULL;
+
+      if (TREE_CODE (type) == UNION_TYPE)
+	break;
     }
 
   if (i < CONSTRUCTOR_NELTS (ctor))
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist45.C b/gcc/testsuite/g++.dg/cpp0x/initlist45.C
new file mode 100644
index 0000000..0e34bc1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist45.C
@@ -0,0 +1,13 @@ 
+// PR c++/46289
+// { dg-options -std=c++0x }
+
+struct A
+{
+  int i[2];
+};
+
+struct B
+{
+  A a;
+  B(): a({{1,2}}) { }
+};