[PATCH] c++: Implement -Wuninitialized for mem-initializers [PR19808]
Martin Sebor
msebor@gmail.com
Fri Nov 20 23:08:50 GMT 2020
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);
}
Martin
PS I think the C++ original dump (below) shows the same problem
despite the Unknown trees that obscure it:
;; Function A::A() (null)
;; enabled by -tree-original
<<cleanup_point <<< Unknown tree: expr_stmt
*(struct A *) this = {CLOBBER} >>>>>;
{
<<cleanup_point <<< Unknown tree: expr_stmt
(void) (((struct A *) this)->b = TARGET_EXPR <D.2389, {.i=((struct A
*) this)->b.i}>) >>>>>;
}
More information about the Gcc-patches
mailing list