[PATCH] avoid -Wnonull for dynamic_cast (PR 99251)

Jason Merrill jason@redhat.com
Tue Mar 2 02:31:34 GMT 2021


On 3/1/21 7:44 PM, Martin Sebor wrote:
> On 3/1/21 1:33 PM, Jason Merrill wrote:
>> On 3/1/21 12:10 PM, Martin Sebor wrote:
>>> On 2/24/21 8:13 PM, Jason Merrill wrote:
>>>> On 2/24/21 5:25 PM, Martin Sebor wrote:
>>>>> In r11-6900 (PR 98646 - static_cast confuses -Wnonnull) we decided
>>>>> that issuing -Wnonnull for dereferencing the result of dynamic_cast
>>>>> was helpful despite the false positives it causes when the pointer
>>>>> is guaranteed not to be null because of a prior test.
>>>>>
>>>>> The test case in PR 99251 along with the feedback I got from Martin
>>>>> Liska have convinced me it was not the right decision.
>>>>>
>>>>> The attached patch arranges for dynamic_cast to also suppress 
>>>>> -Wnonnull
>>>>> analogously to static_cast.  Since there already is a helper function
>>>>> that builds the if-not-null test (ifnonnull) and sets TREE_NO_WARNING,
>>>>> I factored out the corresponding code from build_base_path that sets
>>>>> the additional TREE_NO_WARNING bit for static_cast into the function
>>>>> and called it from both places.  I also renamed the function to make
>>>>> its purpose clearer and for consistency with other build_xxx APIs.
>>>>
>>>> Let's call it build_if_nonnull, as it builds the COND_EXPR as well 
>>>> as the test.
>>>
>>> Done.
>>>
>>>>
>>>>> +  /* The dynamic_cast might fail but so a warning might be justified
>>>>> +     but not when the operand is guarded.  See pr99251.  */
>>>>> +  if (B *q = p->bptr ())
>>>>> +    dynamic_cast<C*>(q)->g ();                // { dg-bogus 
>>>>> "\\\[-Wnonnull" }
>>>>
>>>> This guard is no more necessary than it is for static_cast; both 
>>>> cases deal with null arguments.  Let's not add these checks to the 
>>>> testcases.
>>>
>>> Done.
>>>
>>>>
>>>> This guard doesn't check for the mentioned case of dynamic_cast 
>>>> failing because the B* does not in fact point to a C.
>>>>
>>>> I think we can just change the dg-warning to dg-bogus.  Sure, 
>>>> dynamic_cast might fail, but AFAICT -Wnonnull isn't supposed to warn 
>>>> about arguments that *might* be null, only arguments that are 
>>>> *known* to be null.
>>>
>>> Done.
>>>
>>> I had added the 'if' to the test to make it clear why the warning
>>> isn't expected.  I replaced it with a comment to that effect.
>>
>>> FWIW, I do think a warning for dynamic_cast to a pointer would be
>>> helpful in the absence of an if statement in these cases:
>>>
>>>    void f (B *p)
>>>    {
>>>      dynamic_cast<D*>(p)->g ();
>>>    }
>>>
>>> Not because p may be null but because the result of the cast may be
>>> for a nonnull p.  If it's f's precondition that D is derived from B
>>> (in addition to p being nonnull) the cast would be better written as
>>> one to a reference to D.
>>
>> Agreed, or if it isn't a precondition,
>>
>> if (D* dp = dynamic_cast<D*>(p))
>>    dp->g();
>>
>>> Such a warning would need to be issued by the middle end and although
>>> it could be controlled by a new option (say -Wdynamic-cast, along with
>>> the cases discussed in PR 12277)
>>
>> Sounds good.
>>
>>> I don't think issuing -Wnonnull in this case would be inappropriate.
>>
>> I disagree; issuing -Wnonnull for this case would be wrong.  Again, 
>> -Wnonnull is supposed to warn when an argument *is* null, not when it 
>> *might* be null.
>>
>> I think warning about this case is a good idea, just not as part of 
>> -Wnonnull.
>>
>>> Anyway, that's something to consider for GCC 12.  For now, please see
>>> the revised patch.
>>
>>>     * rtti.c (ifnonnull): Rename...
>>>     (build_nonnull_test): ...to this.  Set no-warning bit on COND_EXPR.
>>
>> The ChangeLog needs updating.
>>
>>> +  /* Unlike static_cast, dynamic cast may fail for a nonnull operand 
>>> but
>>
>> Yes, but...
>>
>>> +     since the front end can't see if the cast is guarded against being
>>> +     invoked with a null
>>
>> No; my point was that whether the cast is guarded against being 
>> invoked with a null is no more relevant for dynamic_cast than it is 
>> for static_cast, as both casts give a null result for a null argument.
>>
>> For this test, dynamic_cast is not significantly different from 
>> static_cast.  For both casts, the bug was the compiler warning about a 
>> nullptr that it introduced itself.
> 
> It seems like splitting hairs.  The comment (much as the original
> if guard) is just meant to explain why -Wnonnull isn't expected in
> case a new warning is added that detects the bad assumption above.
> I want to make it clear that if/when that happens a failure here
> doesn't mislead the author into thinking we don't want any warning
> there at all.
> 
> I have reworded the comments yet again.
> 
>>
>>> verify there's no warning.  See also pr99251.  */
>>
>> Yes.
>>
>>> -  dynamic_cast<const C*>(p->bptr ())->g ();   // { dg-warning 
>>> "\\\[-Wnonnull" }
>>> +  dynamic_cast<const C*>(p)->g ();            // { dg-bogus 
>>> "\\\[-Wnonnull" }
>>
>> Please put back the ->bptr()s.
> 
> Done.

OK, thanks.

Jason



More information about the Gcc-patches mailing list