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
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" }
--
1.7.6.4
--
Dodji