[C++ PATCH] Partially fix designated-initializer-list handling in overload resolution (PR c++/71446)

Jakub Jelinek jakub@redhat.com
Sat Mar 2 09:31:00 GMT 2019


On Fri, Mar 01, 2019 at 04:14:33PM -0500, Jason Merrill wrote:
> > Note, this is just a partial fix for the PR, for the second part (making
> > struct S { void *a; int b; };
> > void foo (S);
> > ... foo ({.b = 1}) work), I'm afraid I don't really understand what the C++
> > standard wants to say in http://eel.is/c++draft/over.ics.list#2 and what
> > build_aggr_conv should do, such that the cpp2a/desig{4,6}.C testcases taken
> > from the standard as well as the desig11.C in the earlier version of the
> > patch (would need to be renamed to desig12.C) can pass.
> 
> It seems to me that for designated initializers, we should make sure that
> all the designators match fields, and otherwise check convertibility like
> build_aggr_conv already does.

For the simple standard conforming case when if any initializer clause has
designator, then all of them have to I can imagine e.g. one loop
where we e.g.
  if (CONSTRUCTOR_IS_DESIGNATED_INIT (ctor))
    {
      tree idx, val;
      FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), i, idx, val)
	{
	  if (idx && TREE_CODE (idx) == FIELD_DECL)
	    {
	      tree ftype = TREE_TYPE (idx);
	      if (TREE_CODE (ftype) == ARRAY_TYPE
		  && TREE_CODE (val) == CONSTRUCTOR)
		ok = can_convert_array (ftype, val, flags, complain);
	      else
		ok = can_convert_arg (ftype, TREE_TYPE (val), val, flags,
				      complain);

	      if (!ok)
		return NULL;
	      // Put idx into some hash_set
	    }
	}
    }
and then in the current
  for (; field; field = next_initializable_field (DECL_CHAIN (field)))
loop for the if (CONSTRUCTOR_IS_DESIGNATED_INIT (ctor)) case assume all has
been done if field is in the hash_set (with the slightly more complicated
case of ANON_AGGR_TYPE_P (ftype) where we likely need to search recursively
for any initialized field) and just go the missing initializer way
otherwise.  But it isn't clear to me what to do in the case where
the initializer has some designators and doesn't have others, because
then the order is significant, the initializers without designator are
supposed to follow those that do have them.

struct S { int a, b, c, d, e; };

void foo (S);

void bar ()
{
  foo ({.d = 5, 6, .b = 2, 3});
}

or

struct T { int a, b; };

void baz (T);

void qux ()
{
  baz ({.b = 1, .a = 2});
}

clang++ currently accepts both, but I believe it doesn't claim to supported
the C++2a designated initializer, just an extension which likely allowed
reordering like C99 and maybe that is why the C++2a standard says the
ordering doesn't matter?

I'm not really sure what to do for foo.  Perhaps if we find that case just
require that the order is ok already during build_aggr_conv and fail the
conversion otherwise?  We are outside of the standard in that case anyway.

For baz we currently error with:
error: designator order for field ‘T::a’ does not match declaration order in ‘T’
and I guess we should continue to do so, but only after build_aggr_conv
succeeds, right?

	Jakub



More information about the Gcc-patches mailing list