Patchwork PR c++/51475 - ICE with invalid initializer-list

login
register
mail settings
Submitter Dodji Seketeli
Date Dec. 14, 2011, 6:15 p.m.
Message ID <m34nx32f59.fsf@redhat.com>
Download mbox | patch
Permalink /patch/131452/
State New
Headers show

Comments

Dodji Seketeli - Dec. 14, 2011, 6:15 p.m.
Hello,

When we walk conversions, we need to be careful that the struct
conversion::u.next union field is the one that is active, depending on
the struct conversion::kind field.

In this bug for instance we are wrongly accessing conversion::u.next
when conversion::kind is a ck_list.  Oops.

So I am introducing a next_conversion function that returns NULL when
we are at the end of the of the conversion chain and fixes the issue.

Bootstrapped and tested on x86_64-unknown-linux-gnu against trunk.

If this patch is okay-ish to you at least, would you accept a separate
cleanup patch (for next stage 1) that uses next_conversion in the
other places that touch conversion::u.next?

gcc/cp/

	PR c++/51475
	* call.c (struct conversion)<u.next>: Update comment.
	(next_conversion): New static function.
	(convert_like_real): Use it.

gcc/testsuite/

	PR c++/51475
	* g++.dg/cpp0x/initlist63.C: New test.
---
 gcc/cp/call.c                           |   25 ++++++++++++++++++++++---
 gcc/testsuite/g++.dg/cpp0x/initlist63.C |   16 ++++++++++++++++
 2 files changed, 38 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist63.C
Jason Merrill - Dec. 14, 2011, 8:01 p.m.
OK.

Jason

Patch

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 6528368..dd716a4 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -111,12 +111,15 @@  struct conversion {
     /* The next conversion in the chain.  Since the conversions are
        arranged from outermost to innermost, the NEXT conversion will
        actually be performed before this conversion.  This variant is
-       used only when KIND is neither ck_identity nor ck_ambig.  */
+       used only when KIND is neither ck_identity, ck_ambig nor
+       ck_list.  Please use the next_conversion function instead
+       of using this field directly.  */
     conversion *next;
     /* The expression at the beginning of the conversion chain.  This
        variant is used only if KIND is ck_identity or ck_ambig.  */
     tree expr;
-    /* The array of conversions for an initializer_list.  */
+    /* The array of conversions for an initializer_list, so this
+       variant is used only when KIN D is ck_list.  */
     conversion **list;
   } u;
   /* The function candidate corresponding to this conversion
@@ -193,6 +196,7 @@  static conversion *standard_conversion (tree, tree, tree, bool, int);
 static conversion *reference_binding (tree, tree, tree, bool, int);
 static conversion *build_conv (conversion_kind, tree, conversion *);
 static conversion *build_list_conv (tree, tree, int);
+static conversion *next_conversion (conversion *);
 static bool is_subseq (conversion *, conversion *);
 static conversion *maybe_handle_ref_bind (conversion **);
 static void maybe_handle_implicit_object (conversion **);
@@ -833,6 +837,21 @@  build_list_conv (tree type, tree ctor, int flags)
   return t;
 }
 
+/* Return the next conversion of the conversion chain (if applicable),
+   or NULL otherwise.  Please use this function instead of directly
+   accessing fields of struct conversion.  */
+
+static conversion *
+next_conversion (conversion *conv)
+{
+  if (conv == NULL
+      || conv->kind == ck_identity
+      || conv->kind == ck_ambig
+      || conv->kind == ck_list)
+    return NULL;
+  return conv->u.next;
+}
+
 /* Subroutine of build_aggr_conv: check whether CTOR, a braced-init-list,
    is a valid aggregate initializer for array type ATYPE.  */
 
@@ -5603,7 +5622,7 @@  convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 	  && BRACE_ENCLOSED_INITIALIZER_P (CONSTRUCTOR_ELT (expr, 0)->value))
 	permerror (input_location, "too many braces around initializer for %qT", totype);
 
-      for (; t; t = t->u.next)
+      for (; t ; t = next_conversion (t))
 	{
 	  if (t->kind == ck_user && t->cand->reason)
 	    {
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist63.C b/gcc/testsuite/g++.dg/cpp0x/initlist63.C
new file mode 100644
index 0000000..a72c0ab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist63.C
@@ -0,0 +1,16 @@ 
+// Origin PR c++/51475
+// { dg-options -std=c++11 }
+
+#include <initializer_list>
+
+struct A
+{
+    A(int*);
+};
+
+struct B
+{
+    const std::initializer_list<A>& x;
+};
+
+B b = {{1}}; // { dg-error "invalid conversion|cannot convert" }