2025-01-28 Jakub Jelinek <ja...@redhat.com>
PR c++/118671
* call.cc (build_list_conv): For RAW_DATA_CST, call
implicit_conversion with INTEGER_CST representing first byte instead
of the whole RAW_DATA_CST. If it is an optimizable trivial
conversion, just save that to subconvs, otherwise allocate an
artificial ck_list for all the RAW_DATA_CST bytes and create
subsubconv for each of them.
(convert_like_internal): For ck_list with RAW_DATA_CST, instead of
doing all the checks for optimizable conversion just check kind and
assert everything else, otherwise use subsubconversions instead of
the subconversion for each element.
* g++.dg/cpp/embed-25.C: New test.
* g++.dg/cpp0x/pr118671.C: New test.
--- gcc/cp/call.cc.jj 2025-01-22 09:22:53.000000000 +0100
+++ gcc/cp/call.cc 2025-01-27 21:36:31.159889633 +0100
@@ -868,6 +868,67 @@ build_list_conv (tree type, tree ctor, i
FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (ctor), i, val)
{
+ if (TREE_CODE (val) == RAW_DATA_CST)
+ {
+ tree elt
+ = build_int_cst (TREE_TYPE (val), RAW_DATA_UCHAR_ELT (val, 0));
+ conversion *sub
+ = implicit_conversion (elttype, TREE_TYPE (val), elt,
+ false, flags, complain);
+ conversion *next;
+ if (sub == NULL)
+ return NULL;
+ /* For conversion to initializer_list<unsigned char> or
+ initializer_list<char> or initializer_list<signed char>
+ we can optimize and keep RAW_DATA_CST with adjusted
+ type if we report narrowing errors if needed.
+ Use just one subconversion for that case. */
+ if (sub->kind == ck_std
+ && sub->type
+ && (TREE_CODE (sub->type) == INTEGER_TYPE
+ || is_byte_access_type (sub->type))
+ && TYPE_PRECISION (sub->type) == CHAR_BIT
+ && (next = next_conversion (sub))
+ && next->kind == ck_identity)
+ {
+ subconvs[i] = sub;
+ continue;
+ }
+ /* Otherwise. build separate subconv for each RAW_DATA_CST
+ byte. Wrap those into an artificial ck_list which convert_like
+ will then handle. */
+ conversion **subsubconvs = alloc_conversions (RAW_DATA_LENGTH (val));
+ unsigned int j;
+ subsubconvs[0] = sub;
+ for (j = 1; j < (unsigned) RAW_DATA_LENGTH (val); ++j)
+ {
+ elt = build_int_cst (TREE_TYPE (val),
+ RAW_DATA_UCHAR_ELT (val, j));
+ sub = implicit_conversion (elttype, TREE_TYPE (val), elt,
+ false, flags, complain);
+ if (sub == NULL)
+ return NULL;
+ subsubconvs[j] = sub;
+ }
+
+ t = alloc_conversion (ck_list);
+ t->type = type;
+ t->u.list = subsubconvs;
+ t->rank = cr_exact;
+ for (j = 0; j < (unsigned) RAW_DATA_LENGTH (val); ++j)
+ {
+ sub = subsubconvs[i];
+ if (sub->rank > t->rank)
+ t->rank = sub->rank;
+ if (sub->user_conv_p)
+ t->user_conv_p = true;
+ if (sub->bad_p)
+ t->bad_p = true;
+ }
+ subconvs[i] = t;
+ continue;
+ }
+
conversion *sub
= implicit_conversion (elttype, TREE_TYPE (val), val,
false, flags, complain);
@@ -8841,22 +8902,22 @@ convert_like_internal (conversion *convs
{
if (TREE_CODE (val) == RAW_DATA_CST)
{
- tree elt_type;
- conversion *next;
/* For conversion to initializer_list<unsigned char> or
initializer_list<char> or initializer_list<signed char>
we can optimize and keep RAW_DATA_CST with adjusted
type if we report narrowing errors if needed, for
others this converts each element separately. */
- if (convs->u.list[ix]->kind == ck_std
- && (elt_type = convs->u.list[ix]->type)
- && (TREE_CODE (elt_type) == INTEGER_TYPE
- || is_byte_access_type (elt_type))
- && TYPE_PRECISION (elt_type) == CHAR_BIT
- && (next = next_conversion (convs->u.list[ix]))
- && next->kind == ck_identity)
+ if (convs->u.list[ix]->kind == ck_std)
{
- if (!TYPE_UNSIGNED (elt_type)
+ tree et = convs->u.list[ix]->type;
+ conversion *next = next_conversion (convs->u.list[ix]);
+ gcc_assert (et
+ && (TREE_CODE (et) == INTEGER_TYPE
+ || is_byte_access_type (et))
+ && TYPE_PRECISION (et) == CHAR_BIT
+ && next
+ && next->kind == ck_identity);
+ if (!TYPE_UNSIGNED (et)
/* For RAW_DATA_CST, TREE_TYPE (val) can be
either integer_type_node (when it has been
created by the lexer from CPP_EMBED) or
@@ -8882,7 +8943,7 @@ convert_like_internal (conversion *convs
"narrowing conversion of "
"%qd from %qH to %qI",
RAW_DATA_UCHAR_ELT (val, i),
- TREE_TYPE (val), elt_type);
+ TREE_TYPE (val), et);
if (errorcount != savederrorcount)
return error_mark_node;
}
@@ -8890,19 +8951,21 @@ convert_like_internal (conversion *convs
return error_mark_node;
}
tree sub = copy_node (val);
- TREE_TYPE (sub) = elt_type;
+ TREE_TYPE (sub) = et;
CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (new_ctor),
NULL_TREE, sub);
}
else
{
+ conversion *conv = convs->u.list[ix];
+ gcc_assert (conv->kind == ck_list);
for (int i = 0; i < RAW_DATA_LENGTH (val); ++i)
{
tree elt
= build_int_cst (TREE_TYPE (val),
RAW_DATA_UCHAR_ELT (val, i));
tree sub
- = convert_like (convs->u.list[ix], elt,
+ = convert_like (conv->u.list[i], elt,
fn, argnum, false, false,
/*nested_p=*/true, complain);
if (sub == error_mark_node)
--- gcc/testsuite/g++.dg/cpp/embed-25.C.jj 2025-01-27 21:51:00.190990295
+0100
+++ gcc/testsuite/g++.dg/cpp/embed-25.C 2025-01-27 21:50:45.954183524 +0100
@@ -0,0 +1,56 @@
+// PR c++/118671
+// { dg-do run { target c++11 } }
+// { dg-options "-O2" }
+
+namespace std {
+template <typename T>
+struct initializer_list {
+private:
+ T *_M_array;
+ decltype (sizeof 0) _M_len;
+public:
+ constexpr decltype (sizeof 0)
+ size () const noexcept { return _M_len; }
+ constexpr const T *
+ begin () const noexcept { return _M_array; }
+ constexpr const T *
+ end () const noexcept { return begin () + size (); }
+};
+}
+
+struct A {} a;
+
+struct B {
+ constexpr B (int x) : B (a, x) {}
+ template <typename... T>
+ constexpr B (A, T... x) : b(x...) {}
+ int b;
+};
+
+struct C {
+ C (std::initializer_list<B> x)
+ {
+ unsigned char buf[] = {
+#embed __FILE__
+ };
+ if (x.size () != sizeof (buf))
+ __builtin_abort ();
+ unsigned int i = 0;
+ for (auto a = x.begin (); a < x.end (); ++a, ++i)
+ if (a->b != buf[i])
+ __builtin_abort ();
+ c = true;
+ }
+ bool c;
+};
+
+C c {
+#embed __FILE__
+};
+
+int
+main ()
+{
+ if (!c.c)
+ __builtin_abort ();
+}
--- gcc/testsuite/g++.dg/cpp0x/pr118671.C.jj 2025-01-27 21:47:01.154242793
+0100
+++ gcc/testsuite/g++.dg/cpp0x/pr118671.C 2025-01-27 21:46:43.379486760
+0100
@@ -0,0 +1,61 @@
+// PR c++/118671
+// { dg-do run { target c++11 } }
+// { dg-options "-O2" }
+
+namespace std {
+template <typename T>
+struct initializer_list {
+private:
+ T *_M_array;
+ decltype (sizeof 0) _M_len;
+public:
+ constexpr decltype (sizeof 0)
+ size () const noexcept { return _M_len; }
+ constexpr const T *
+ begin () const noexcept { return _M_array; }
+ constexpr const T *
+ end () const noexcept { return begin () + size (); }
+};
+}
+
+struct A {} a;
+
+struct B {
+ constexpr B (int x) : B (a, x) {}
+ template <typename... T>
+ constexpr B (A, T... x) : b(x...) {}
+ int b;
+};
+
+struct C {
+ C (std::initializer_list<B> x)
+ {
+ if (x.size () != 130)
+ __builtin_abort ();
+ unsigned int i = 1;
+ for (auto a = x.begin (); a < x.end (); ++a)
+ if (a->b != i)
+ __builtin_abort ();
+ else
+ i = (i & 15) + 1;
+ c = true;
+ }
+ bool c;
+};
+
+C c { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 1, 2 };
+
+int
+main ()
+{
+ if (!c.c)
+ __builtin_abort ();
+}
Jakub