aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2019-03-04 19:57:13 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2019-03-04 19:57:13 +0100
commitf0103f7bb010405798fe14afc5972f327835ae57 (patch)
treefb7a50e5c8217a9d5958492b77333d7ea47a78ab /gcc
parent209cd3bd47287d4dabb94a7c2ce965588fd0389d (diff)
downloadgcc-f0103f7bb010405798fe14afc5972f327835ae57.zip
gcc-f0103f7bb010405798fe14afc5972f327835ae57.tar.gz
gcc-f0103f7bb010405798fe14afc5972f327835ae57.tar.bz2
re PR c++/71446 (Incorrect overload resolution when using designated initializers)
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog6
-rw-r--r--gcc/cp/call.c83
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/desig12.C15
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/desig13.C16
5 files changed, 121 insertions, 5 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index e17537a..8c0bfd9 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 1a9cf7e..1a29eb7 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 3d883f6..3186805c 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..cfff9a7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/desig12.C
@@ -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
index 0000000..442e8b7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/desig13.C
@@ -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'" }
+}