re PR c++/71446 (Incorrect overload resolution when using designated initializers)
authorJakub Jelinek <jakub@redhat.com>
Mon, 4 Mar 2019 18:57:13 +0000 (19:57 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Mon, 4 Mar 2019 18:57:13 +0000 (19:57 +0100)
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.

From-SVN: r269371

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp2a/desig12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/desig13.C [new file with mode: 0644]

index e17537a..8c0bfd9 100644 (file)
@@ -1,3 +1,9 @@
+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.
+
 2019-03-02  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/71446
index 1a9cf7e..1a29eb7 100644 (file)
@@ -902,6 +902,28 @@ can_convert_array (tree atype, tree ctor, int flags, tsubst_flags_t complain)
   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, int flags, tsubst_flags_t complain)
   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, int flags, tsubst_flags_t complain)
      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, int flags, tsubst_flags_t complain)
                              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;
index 3d883f6..3186805 100644 (file)
@@ -1,3 +1,9 @@
+2019-03-04  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/71446
+       * g++.dg/cpp2a/desig12.C: New test.
+       * g++.dg/cpp2a/desig13.C: New test.
+
 2019-03-04  Tamar Christina  <tamar.christina@arm.com>
 
        PR target/88530
diff --git a/gcc/testsuite/g++.dg/cpp2a/desig12.C b/gcc/testsuite/g++.dg/cpp2a/desig12.C
new file mode 100644 (file)
index 0000000..cfff9a7
--- /dev/null
@@ -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});
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/desig13.C b/gcc/testsuite/g++.dg/cpp2a/desig13.C
new file mode 100644 (file)
index 0000000..442e8b7
--- /dev/null
@@ -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'" }
+}