[PATCH] avoid user-constructible types in reshape_init_array (PR 90938)

Martin Sebor msebor@gmail.com
Wed Feb 12 00:38:00 GMT 2020


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



More information about the Gcc-patches mailing list