[pushed] c++: fix initializer_list transformation [PR108071]
Checks
Commit Message
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
@@ -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;
new file mode 100644
@@ -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});
+}
new file mode 100644
@@ -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 = {""};
new file mode 100644
@@ -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 = { "" };