[PATCH] c++: Implement -Wuninitialized for mem-initializers [PR19808]

Jason Merrill jason@redhat.com
Tue Nov 24 22:24:37 GMT 2020


On 11/20/20 6:08 PM, Martin Sebor wrote:
> On 11/19/20 11:41 AM, Jason Merrill wrote:
>> On 11/17/20 3:44 AM, Jan Hubicka wrote:
>>>> On Tue, Nov 17, 2020 at 01:33:48AM -0500, Jason Merrill via 
>>>> Gcc-patches wrote:
>>>>>>> Why doesn't the middle-end warning work for inline functions?
>>>>>>
>>>>>> It does but only when they're called (and, as usual, also unless
>>>>>> the uninitialized use is eliminated).
>>>>>
>>>>> Yes, but why?  I assume because we don't bother going through all 
>>>>> the phases
>>>>> of compilation for unused inlines, but couldn't we change that when 
>>>>> we're
>>>>> asking for (certain) warnings?
>>>>
>>>> CCing Richard and Honza on this.
>>>>
>>>> I think for unused functions we don't even gimplify unused 
>>>> functions, the
>>>> cgraph code just throws them away.  Even trying just to run the 
>>>> first few
>>>> passes (gimplification up to uninit1) would have several high costs,
>>> Note that uninit1 is a late pass so it is not just few passes we speak
>>> about.  Late passes are run only on cocde that really lands in .s file
>>> so enabling them would mean splitting the pass queue and running another
>>> unreachable code somewhere.  That would confuse inliner and other IPA
>>> passes since they will have to somehow deal with dead code in their
>>> program size estimate and also affect LTO.
>>>
>>> Even early passes are run only on reachable portion of program, since
>>> functions are analyzed by cgraphunit on demand (only if they are
>>> analyzed by someone else). Simlar logic is also done be C++ FE to decide
>>> what templates.  Changling this would also have quite some compile
>>> time/memory use impact.
>>>
>>> There is -fkeep-inline-functions.
>>
>> OK, thanks for the explanation.  -fkeep-inline-functions seems like an 
>> acceptable answer for people who want a warning audit of their library 
>> header inlines.
>>
>> Martin, I notice that the middle-end warning doesn't currently catch 
>> this:
>>
>> struct B { int i,j; };
>>
>> struct A
>> {
>>    B b;
>>    A(): b({b.i}) { }
>> };
>>
>> A a;
>>
>> It does warn if B only has one member; adding the second wrongly 
>> silences the warning.
> 
> The GIMPLE for A's ctor looks like this:
> 
> A::A (struct A * const this)
> {
>    *this = {CLOBBER};
>    {
>      this->b = {};
>      _1 = this->b.i;
>      this->b.i = _1;
>    }
> }
> 
> so the b member is cleared first before it's read from and there's
> nothing to warn about.  This happens for C structs too:
> 
> void f (void*);
> 
> struct A { int i, j; };
> 
> void g (void)
> {
>    struct A a = { a.i };
>    f (&a);
> }
> 
> The uninitialized read is in the original dump (below) so the zero
> initialization happens in the gimplifier and could be diagnosed
> there.
> 
> ;; enabled by -tree-original
> 
> 
> {
>    struct A a = {.i=a.i};
> 
>      struct A a = {.i=a.i};
>    f ((void *) &a);
> }

Ah, yes, because gimplify_init_constructor leaves the first assignment 
to clear the whole object if there aren't initializers for all the members.

Jason



More information about the Gcc-patches mailing list