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

Jakub Jelinek jakub@redhat.com
Mon Mar 4 09:21:00 GMT 2019


On Sat, Mar 02, 2019 at 10:30:36AM +0100, Jakub Jelinek wrote:
> 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.

Actually, seems if the designators can match corresponding type,
reshape_init* already fills in the ce->index even on elements without
original designators.  So, the following works fine for all the testcases I
came up with.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2019-03-04  Jakub Jelinek  <jakub@redhat.com>

	PR c++/71446
	* call.c (field_in_pset): New function.
	(build_aggr_conv): Handle CONSTRUCTOR_IS_DESIGNATED_INIT correctly.

	* g++.dg/cpp2a/desig12.C: New test.
	* g++.dg/cpp2a/desig13.C: New test.

--- gcc/cp/call.c.jj	2019-03-02 09:05:44.442524338 +0100
+++ gcc/cp/call.c	2019-03-02 18:57:12.221904541 +0100
@@ -902,6 +902,28 @@ can_convert_array (tree atype, tree ctor
   return true;
 }
 
+/* Helper for build_aggr_conv.  Return true if FIELD is in PSET, or if
+   FIELD has ANON_AGGR_TYPE_P and any initializable field in there recursively
+   is in PSET.  */
+
+static bool
+field_in_pset (hash_set<tree> *pset, tree field)
+{
+  if (pset->contains (field))
+    return true;
+  if (ANON_AGGR_TYPE_P (TREE_TYPE (field)))
+    for (field = TYPE_FIELDS (TREE_TYPE (field));
+	 field; field = DECL_CHAIN (field))
+      {
+	field = next_initializable_field (field);
+	if (field == NULL_TREE)
+	  break;
+	if (field_in_pset (pset, field))
+	  return true;
+      }
+  return false;
+}
+
 /* Represent a conversion from CTOR, a braced-init-list, to TYPE, an
    aggregate class, if such a conversion is possible.  */
 
@@ -912,6 +934,7 @@ build_aggr_conv (tree type, tree ctor, i
   conversion *c;
   tree field = next_initializable_field (TYPE_FIELDS (type));
   tree empty_ctor = NULL_TREE;
+  hash_set<tree> *pset = NULL;
 
   /* We already called reshape_init in implicit_conversion.  */
 
@@ -919,26 +942,69 @@ build_aggr_conv (tree type, tree ctor, i
      context; they're always simple copy-initialization.  */
   flags = LOOKUP_IMPLICIT|LOOKUP_NO_NARROWING;
 
+  /* For designated initializers, verify that each initializer is convertible
+     to corresponding TREE_TYPE (ce->index) and mark those FIELD_DECLs as
+     visited.  In the following loop then ignore already visited
+     FIELD_DECLs.  */
+  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);
+	      bool ok;
+
+	      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)
+		goto fail;
+	      /* For unions, there should be just one initializer.  */
+	      if (TREE_CODE (type) == UNION_TYPE)
+		{
+		  field = NULL_TREE;
+		  i = 1;
+		  break;
+		}
+	      if (pset == NULL)
+		pset = new hash_set<tree>;
+	      pset->add (idx);
+	    }
+	  else
+	    goto fail;
+	}
+    }
+
   for (; field; field = next_initializable_field (DECL_CHAIN (field)))
     {
       tree ftype = TREE_TYPE (field);
       tree val;
       bool ok;
 
+      if (pset && field_in_pset (pset, field))
+	continue;
       if (i < CONSTRUCTOR_NELTS (ctor))
-	val = CONSTRUCTOR_ELT (ctor, i)->value;
+	{
+	  val = CONSTRUCTOR_ELT (ctor, i)->value;
+	  ++i;
+	}
       else if (DECL_INITIAL (field))
 	val = get_nsdmi (field, /*ctor*/false, complain);
       else if (TYPE_REF_P (ftype))
 	/* Value-initialization of reference is ill-formed.  */
-	return NULL;
+	goto fail;
       else
 	{
 	  if (empty_ctor == NULL_TREE)
 	    empty_ctor = build_constructor (init_list_type_node, NULL);
 	  val = empty_ctor;
 	}
-      ++i;
 
       if (TREE_CODE (ftype) == ARRAY_TYPE
 	  && TREE_CODE (val) == CONSTRUCTOR)
@@ -948,15 +1014,22 @@ build_aggr_conv (tree type, tree ctor, i
 			      complain);
 
       if (!ok)
-	return NULL;
+	goto fail;
 
       if (TREE_CODE (type) == UNION_TYPE)
 	break;
     }
 
   if (i < CONSTRUCTOR_NELTS (ctor))
-    return NULL;
+    {
+    fail:
+      if (pset)
+	delete pset;
+      return NULL;
+    }
 
+  if (pset)
+    delete pset;
   c = alloc_conversion (ck_aggr);
   c->type = type;
   c->rank = cr_exact;
--- gcc/testsuite/g++.dg/cpp2a/desig12.C.jj	2019-03-02 18:58:26.300704919 +0100
+++ gcc/testsuite/g++.dg/cpp2a/desig12.C	2019-03-02 18:59:29.033689025 +0100
@@ -0,0 +1,15 @@
+// PR c++/71446
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct T { void *a; int b; };
+struct U { int a; union { int b; union { long c; short d; }; }; int e; };
+void bar (T);
+void baz (U);
+
+void
+foo ()
+{
+  bar ({.b = 1});
+  baz ({.c = 5L, .e = 6});
+}
--- gcc/testsuite/g++.dg/cpp2a/desig13.C.jj	2019-03-02 19:00:33.812639999 +0100
+++ gcc/testsuite/g++.dg/cpp2a/desig13.C	2019-03-02 19:03:48.043494642 +0100
@@ -0,0 +1,16 @@
+// PR c++/71446
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct S { int a, b, c, d, e; };
+struct T { int a, b; };
+void foo (S);
+void bar (T);
+
+void
+baz ()
+{
+  foo ({.d = 5, 6, .b = 2, 3});	// { dg-error "designator order for field 'S::b' does not match declaration order in 'S'" }
+				// { dg-error "either all initializer clauses should be designated or none of them should be" "" { target c++2a } .-1 }
+  bar ({.b = 1, .a = 2});	// { dg-error "designator order for field 'T::a' does not match declaration order in 'T'" }
+}

	Jakub



More information about the Gcc-patches mailing list