Hi Jason,

On 24 Aug 2024, at 15:13, Jason Merrill wrote:

> On 8/23/24 12:44 PM, Simon Martin wrote:
>> We currently emit an incorrect -Woverloaded-virtual warning upon the 
>> following
>> test case
>>
>> === cut here ===
>> struct A {
>>    virtual operator int() { return 42; }
>>    virtual operator char() = 0;
>> };
>> struct B : public A {
>>    operator char() { return 'A'; }
>> };
>> === cut here ===
>>
>> The problem is that warn_hidden relies on get_basefndecls to find the 
>> methods
>> in A possibly hidden B's operator char(), and gets both the 
>> conversion operator
>> to int and to char. It eventually wrongly concludes that the 
>> conversion to int
>> is hidden.
>>
>> This patch fixes this by filtering out conversion operators to 
>> different types
>> from the list returned by get_basefndecls.
>
> Hmm, same_signature_p already tries to handle comparing conversion 
> operators, why isn't that working?
>
It does indeed.

However, `ovl_range (fns)` does not only contain `char B::operator()` - 
for which `any_override` gets true - but also `conv_op_marker` - for 
which `any_override` gets false, causing `seen_non_override` to get to 
true. Because of that, we run the last loop, that will emit a warning 
for all `base_fndecls` (except `char B::operator()` that has been 
removed).

We could test `fndecl` and `base_fndecls[k]` against `conv_op_marker` in 
the loop, but we’d still need to inspect the “converting to” type 
in the last loop (for when `warn_overloaded_virtual` is 2). This would 
make the code much more complex than the current patch.

It would however probably be better if `get_basefndecls` only returned 
the right conversion operator, not all of them. I’ll draft another 
version of the patch that does that and submit it in this thread.

Thanks!
   Simon

>> Successfully tested on x86_64-pc-linux-gnu.
>>
>>      PR c++/109918
>>
>> gcc/cp/ChangeLog:
>>
>>      * class.cc (warn_hidden): Filter out conversion operators to 
>> different
>>      types.
>>
>> gcc/testsuite/ChangeLog:
>>
>>      * g++.dg/warn/Woverloaded-virt5.C: New test.
>>
>> ---
>>   gcc/cp/class.cc                               | 33 
>> ++++++++++++-------
>>   gcc/testsuite/g++.dg/warn/Woverloaded-virt5.C | 12 +++++++
>>   2 files changed, 34 insertions(+), 11 deletions(-)
>>   create mode 100644 gcc/testsuite/g++.dg/warn/Woverloaded-virt5.C
>>
>> diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
>> index fb6c3370950..a8178a31fe8 100644
>> --- a/gcc/cp/class.cc
>> +++ b/gcc/cp/class.cc
>> @@ -3267,18 +3267,29 @@ warn_hidden (tree t)
>>          if (TREE_CODE (fndecl) == FUNCTION_DECL
>>              && DECL_VINDEX (fndecl))
>>            {
>> -            /* If the method from the base class has the same
>> -               signature as the method from the derived class, it
>> -               has been overridden.  Note that we can't move on
>> -               after finding one match: fndecl might override
>> -               multiple base fns.  */
>>              for (size_t k = 0; k < base_fndecls.length (); k++)
>> -              if (base_fndecls[k]
>> -                  && same_signature_p (fndecl, base_fndecls[k]))
>> -                {
>> -                  base_fndecls[k] = NULL_TREE;
>> -                  any_override = true;
>> -                }
>> +              {
>> +                if (!base_fndecls[k])
>> +                  continue;
>> +                /* If FNS is a conversion operator, base_fndecls contains
>> +                   all conversion operators from base classes; we need to
>> +                   remove those converting to a different type.  */
>> +                if (IDENTIFIER_CONV_OP_P (name)
>> +                    && !same_type_p (DECL_CONV_FN_TYPE (fndecl),
>> +                                     DECL_CONV_FN_TYPE (base_fndecls[k])))
>> +                  {
>> +                    base_fndecls[k] = NULL_TREE;
>> +                  }
>> +                /* If the method from the base class has the same signature
>> +                   as the method from the derived class, it has been
>> +                   overriden.  Note that we can't move on after finding
>> +                   one match: fndecl might override multiple base fns.  */
>> +                else if (same_signature_p (fndecl, base_fndecls[k]))
>> +                  {
>> +                    base_fndecls[k] = NULL_TREE;
>> +                    any_override = true;
>> +                  }
>> +              }
>>            }
>>          if (!any_override)
>>            seen_non_override = true;
>> diff --git a/gcc/testsuite/g++.dg/warn/Woverloaded-virt5.C 
>> b/gcc/testsuite/g++.dg/warn/Woverloaded-virt5.C
>> new file mode 100644
>> index 00000000000..ea26569e565
>> --- /dev/null
>> +++ b/gcc/testsuite/g++.dg/warn/Woverloaded-virt5.C
>> @@ -0,0 +1,12 @@
>> +// PR c++/109918
>> +// { dg-do compile }
>> +// { dg-additional-options -Woverloaded-virtual }
>> +
>> +struct A {
>> +  virtual operator int() { return 42; }
>> +  virtual operator char() = 0;
>> +};
>> +
>> +struct B : public A {
>> +  operator char() { return 'A'; }
>> +};

Reply via email to