c++: Fix wrong conversion error with non-viable overload [PR94124]
authorMarek Polacek <polacek@redhat.com>
Tue, 10 Mar 2020 22:55:42 +0000 (18:55 -0400)
committerMarek Polacek <polacek@redhat.com>
Wed, 11 Mar 2020 03:12:41 +0000 (23:12 -0400)
This is a bad interaction between sharing a constructor for an array
and stripping its trailing zero-initializers.  Here we reuse a ctor
and then strip its 0s.  This breaks overload resolution in this test:
D can be initialized from {} but not from {0}, so if we truncate the
constructor not to include the zero, the F(D) overload becomes valid
and then we get the ambiguous conversion error.

PR c++/94124 - wrong conversion error with non-viable overload.
* decl.c (reshape_init_array_1): Unshare a constructor if we
stripped trailing zero-initializers.

* g++.dg/cpp0x/initlist-overload1.C: New test.

gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/initlist-overload1.C [new file with mode: 0644]

index 9e0b488..ebccb51 100644 (file)
@@ -1,3 +1,9 @@
+2020-03-10  Marek Polacek  <polacek@redhat.com>
+
+       PR c++/94124 - wrong conversion error with non-viable overload.
+       * decl.c (reshape_init_array_1): Unshare a constructor if we
+       stripped trailing zero-initializers.
+
 2020-03-10  Jason Merrill  <jason@redhat.com>
 
        PR c++/93901
index bb24274..aa58e5f 100644 (file)
@@ -6062,6 +6062,13 @@ reshape_init_array_1 (tree elt_type, tree max_index, reshape_iter *d,
       else if (last_nonzero < nelts - 1)
        nelts = last_nonzero + 1;
 
+      /* Sharing a stripped constructor can get in the way of
+        overload resolution.  E.g., initializing a class from
+        {{0}} might be invalid while initializing the same class
+        from {{}} might be valid.  */
+      if (reuse)
+       new_init = unshare_constructor (new_init);
+
       vec_safe_truncate (CONSTRUCTOR_ELTS (new_init), nelts);
     }
 
index c76d891..d243255 100644 (file)
@@ -1,3 +1,8 @@
+2020-03-10  Marek Polacek  <polacek@redhat.com>
+
+       PR c++/94124 - wrong conversion error with non-viable overload.
+       * g++.dg/cpp0x/initlist-overload1.C: New test.
+
 2020-03-10  Jiufu Guo  <guojiufu@linux.ibm.com>
 
        PR target/93709
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-overload1.C b/gcc/testsuite/g++.dg/cpp0x/initlist-overload1.C
new file mode 100644 (file)
index 0000000..12bb606
--- /dev/null
@@ -0,0 +1,15 @@
+// PR c++/94124 - wrong conversion error with non-viable overload.
+// { dg-do compile { target c++11 } }
+
+template <int N> struct A { typedef int _Type[N]; };
+template <int N> struct B { typename A<N>::_Type _M_elems; };
+class C { };
+struct D {
+  D(C);
+};
+
+struct F {
+  F(B<2>);
+  F(D); // This overload should not be viable.
+};
+F fn1() { return {{{0}}}; }