On 2/11/20 5:01 PM, Marek Polacek wrote:
On Tue, Feb 11, 2020 at 01:00:05PM -0700, Martin Sebor wrote:
r270155, committed in GCC 9, introduced a transformation that strips
redundant trailing zero initializers from array initializer lists in
order to support string literals as template arguments.
The transformation neglected to consider the case of array elements
of trivial class types with user-defined conversion ctors and either
defaulted or deleted default ctors. (It didn't occur to me that
those qualify as trivial types despite the user-defined ctors.) As
a result, some valid initialization expressions are rejected when
the explicit zero-initializers are dropped in favor of the (deleted)
default ctor, and others are eliminated in favor of the defaulted
ctor instead of invoking a user-defined conversion ctor, leading to
wrong code.
The attached patch fixes that but avoiding this transformation for
such types.
Tested on x86_64-linux. I'd like to commit the patch to both trunk
and to GCC 9 (with testsuite adjustments if necessary).
Martin
PR c++/90938 - Initializing array with {1} works but not {0}
gcc/cp/ChangeLog:
PR c++/90938
* decl.c (reshape_init_array_1): Avoid types with non-trivial
user-defined ctors.
gcc/testsuite/ChangeLog:
PR c++/90938
* g++.dg/init/array55.C: New test.
* g++.dg/init/array56.C: New test.
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 31a556a0a1f..60731cb3f9d 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6051,11 +6051,14 @@ reshape_init_array_1 (tree elt_type, tree max_index,
reshape_iter *d,
break;
}
- if (sized_array_p && trivial_type_p (elt_type))
+ if (sized_array_p
+ && trivial_type_p (elt_type)
+ && !TYPE_NEEDS_CONSTRUCTING (elt_type))
Looks like this will still do the wrong thing for
struct X
{
X () = delete;
X (int) = delete;
};
X x1[1] { 0 }; // use of deleted function
which should be rejected since we use a deleted function, but
TYPE_NEEDS_CONSTRUCTING will be 0 fox X, so we'd do the truncation
and the initialization would succeed.
And conversely, this should be accepted but isn't, with or without
the patch:
struct X
{
X () = delete;
X (int) = delete;
X (long) { }
};
static_assert (__is_trivial (X));
X x1[1] { 0L }; // okay
but this rejected:
X x2[1] { 0 }; // error: use of deleted X::X(int)
It seems like each initializer in the list needs to be matched against
the right ctor one by one and the transformation only done if none of
them is deleted or non-trivial.
Martin