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

Jason Merrill jason@redhat.com
Thu Feb 13 22:59:00 GMT 2020


On 2/12/20 9:21 PM, Martin Sebor wrote:
> On 2/11/20 5:28 PM, Jason Merrill wrote:
>> On 2/11/20 9:00 PM, 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,
>>
>> Hmm, a type with only a deleted default constructor is not trivial, 
>> that should have been OK already.
> 
> For Marek's test case:
>    struct A { A () == delete; A (int) = delete; };
> 
> trivial_type_p() returns true (as does __is_trivial (A) in both GCC
> and Clang).
> 
> [class.prop] says that
> 
>    A trivial class is a class that is trivially copyable and has one
>    or more default constructors (10.3.4.1), all of which are either
>    trivial or deleted and at least one of which is not deleted.
> 
> That sounds like A above is not trivial because it doesn't have
> at least one default ctor that's not deleted, but both GCC and
> Clang say it is.  What am I missing?  Is there some other default
> constructor hiding in there that I don't know about?
> 
>>> and others are eliminated in favor of the defaulted
>>> ctor instead of invoking a user-defined conversion ctor, leading to
>>> wrong code.
>>
>> This seems like a bug in type_initializer_zero_p; it shouldn't treat 0 
>> as a zero initializer for any class.
> 
> That does fix it, and it seems like the right solution to me as well.
> Thanks for the suggestion.  I'm a little unsure about the condition
> I put in place though.
> 
> Attached is an updated patch rested on x86_64-linux.

> -  if (sized_array_p && trivial_type_p (elt_type))
> +  if (sized_array_p
> +      && trivial_type_p (elt_type)
> +      && !TYPE_NEEDS_CONSTRUCTING (elt_type))

Do we still need this change?  If so, please add a comment about the 
trivial_type_p bug.

>    if (TREE_CODE (init) != CONSTRUCTOR
I might change this to

  if (!CP_AGGREGATE_TYPE_P (type))
    return initializer_zerop (init);
  else if (TREE_CODE (init) != CONSTRUCTOR)
    return false;

and then remove the

>   if (TYPE_NON_AGGREGATE_CLASS (type))
>     return false;

later in the function.

More generally, this function could recognize when the initializer is 
equivalent to {}-initialization and return true in that case, but that 
sounds probably too tricky for stage 4.

Jason



More information about the Gcc-patches mailing list