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