From: Jason Merrill Date: Wed, 14 Dec 2022 22:42:52 +0000 (-0500) Subject: c++: fix initializer_list transformation [PR108071] X-Git-Tag: upstream/13.1.0~2532 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4ef521bbc63f8a3883d507a8b6c1f95f442df3fe;p=platform%2Fupstream%2Fgcc.git c++: fix initializer_list transformation [PR108071] 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. --- diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 33b5e7f8..c25df17 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 0000000..a714215 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist131.C @@ -0,0 +1,14 @@ +// PR c++/108071 +// { dg-do compile { target c++11 } } + +#include + +struct OptSpecifier { + explicit OptSpecifier(bool); + OptSpecifier(unsigned); +}; +void f (std::initializer_list); +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 0000000..34e0307 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist132.C @@ -0,0 +1,30 @@ +// PR c++/108071 +// { dg-do compile { target c++11 } } + +#include + +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 + OUString(T&, typename ConstCharArrayDetector::Type = Dummy()) + { } +}; + +struct Sequence { + Sequence(std::initializer_list); +}; + +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 0000000..08da5be --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist133.C @@ -0,0 +1,25 @@ +// PR c++/108071 +// { dg-do compile { target c++14 } } + +#include + +template struct enable_if { }; +template<> struct enable_if { using type = void; }; + +template constexpr bool is_array_v = false; +template constexpr bool is_array_v = true; + +struct OUString +{ + template>::type> + OUString(T&) { } +}; + +struct vector +{ + vector(std::initializer_list) { } + template + vector(Iter i, Iter j) { if (i != j) OUString(*i); } +}; + +vector v = { "" };