diff mbox series

[pushed] c++: fix initializer_list transformation [PR108071]

Message ID 20221215052557.608641-1-jason@redhat.com
State New
Headers show
Series [pushed] c++: fix initializer_list transformation [PR108071] | expand

Commit Message

Jason Merrill Dec. 15, 2022, 5:25 a.m. UTC
Tested x86_64-pc-linux-gnu, applying to trunk.

-- 8< --

In these testcases, we weren't adequately verifying that constructing the
element type from an array element would have the same effect as
constructing it from one of the initializers.

	PR c++/108071
	PR c++/105838

gcc/cp/ChangeLog:

	* call.cc (struct conversion_obstack_sentinel): New.
	(maybe_init_list_as_array): Compare conversion of dummy argument.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp0x/initlist131.C: New test.
	* g++.dg/cpp0x/initlist132.C: New test.
	* g++.dg/cpp0x/initlist133.C: New test.
---
 gcc/cp/call.cc                           | 35 ++++++++++++++++++++----
 gcc/testsuite/g++.dg/cpp0x/initlist131.C | 14 ++++++++++
 gcc/testsuite/g++.dg/cpp0x/initlist132.C | 30 ++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp0x/initlist133.C | 25 +++++++++++++++++
 4 files changed, 98 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist131.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist132.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist133.C


base-commit: 8c2451ba4601739654e2ea4907d6fa2a00d660aa
diff mbox series

Patch

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 33b5e7f87f5..c25df174280 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -622,6 +622,15 @@  conversion_obstack_alloc (size_t n)
   return p;
 }
 
+/* RAII class to discard anything added to conversion_obstack.  */
+
+struct conversion_obstack_sentinel
+{
+  void *p;
+  conversion_obstack_sentinel (): p (conversion_obstack_alloc (0)) {}
+  ~conversion_obstack_sentinel () { obstack_free (&conversion_obstack, p); }
+};
+
 /* Allocate rejection reasons.  */
 
 static struct rejection_reason *
@@ -4219,18 +4228,32 @@  static tree
 maybe_init_list_as_array (tree elttype, tree init)
 {
   /* Only do this if the array can go in rodata but not once converted.  */
-  if (!CLASS_TYPE_P (elttype))
+  if (!TYPE_NON_AGGREGATE_CLASS (elttype))
     return NULL_TREE;
   tree init_elttype = braced_init_element_type (init);
   if (!init_elttype || !SCALAR_TYPE_P (init_elttype) || !TREE_CONSTANT (init))
     return NULL_TREE;
 
+  /* Check with a stub expression to weed out special cases, and check whether
+     we call the same function for direct-init as copy-list-init.  */
+  conversion_obstack_sentinel cos;
+  tree arg = build_stub_object (init_elttype);
+  conversion *c = implicit_conversion (elttype, init_elttype, arg, false,
+				       LOOKUP_NORMAL, tf_none);
+  if (c && c->kind == ck_rvalue)
+    c = next_conversion (c);
+  if (!c || c->kind != ck_user)
+    return NULL_TREE;
+
   tree first = CONSTRUCTOR_ELT (init, 0)->value;
-  if (TREE_CODE (init_elttype) == INTEGER_TYPE && null_ptr_cst_p (first))
-    /* Avoid confusion from treating 0 as a null pointer constant.  */
-    first = build1 (UNARY_PLUS_EXPR, init_elttype, first);
-  first = (perform_implicit_conversion_flags
-	   (elttype, first, tf_none, LOOKUP_IMPLICIT|LOOKUP_NO_NARROWING));
+  conversion *fc = implicit_conversion (elttype, init_elttype, first, false,
+					LOOKUP_IMPLICIT|LOOKUP_NO_NARROWING,
+					tf_none);
+  if (fc && fc->kind == ck_rvalue)
+    fc = next_conversion (fc);
+  if (!fc || fc->kind != ck_user || fc->cand->fn != c->cand->fn)
+    return NULL_TREE;
+  first = convert_like (fc, first, tf_none);
   if (first == error_mark_node)
     /* Let the normal code give the error.  */
     return NULL_TREE;
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist131.C b/gcc/testsuite/g++.dg/cpp0x/initlist131.C
new file mode 100644
index 00000000000..a714215219a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist131.C
@@ -0,0 +1,14 @@ 
+// PR c++/108071
+// { dg-do compile { target c++11 } }
+
+#include <initializer_list>
+
+struct OptSpecifier {
+  explicit OptSpecifier(bool);
+  OptSpecifier(unsigned);
+};
+void f (std::initializer_list<OptSpecifier>);
+int main()
+{
+  f({1});
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist132.C b/gcc/testsuite/g++.dg/cpp0x/initlist132.C
new file mode 100644
index 00000000000..34e0307cbbc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist132.C
@@ -0,0 +1,30 @@ 
+// PR c++/108071
+// { dg-do compile { target c++11 } }
+
+#include <initializer_list>
+
+template< typename T1, typename T2 = void >
+struct ConstCharArrayDetector
+{
+    static const bool ok = false;
+};
+template< std::size_t N, typename T >
+struct ConstCharArrayDetector< const char[ N ], T >
+{
+    typedef T Type;
+};
+
+struct Dummy { };
+
+struct OUString
+{
+  template<typename T>
+    OUString(T&, typename ConstCharArrayDetector<T, Dummy>::Type = Dummy())
+    { }
+};
+
+struct Sequence {
+  Sequence(std::initializer_list<OUString>);
+};
+
+Sequence s = {""};
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist133.C b/gcc/testsuite/g++.dg/cpp0x/initlist133.C
new file mode 100644
index 00000000000..08da5bebd0b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist133.C
@@ -0,0 +1,25 @@ 
+// PR c++/108071
+// { dg-do compile { target c++14 } }
+
+#include <initializer_list>
+
+template<bool> struct enable_if { };
+template<> struct enable_if<true> { using type = void; };
+
+template<typename T> constexpr bool is_array_v = false;
+template<typename T, std::size_t N> constexpr bool is_array_v<T[N]> = true;
+
+struct OUString
+{
+  template<typename T, typename = typename enable_if<is_array_v<T>>::type>
+  OUString(T&) { }
+};
+
+struct vector
+{
+  vector(std::initializer_list<OUString>) { }
+  template<typename Iter>
+  vector(Iter i, Iter j) { if (i != j) OUString(*i); }
+};
+
+vector v = { "" };