gdb: fix overload resolution for see-through references
authorTankut Baris Aktemur <tankut.baris.aktemur@intel.com>
Tue, 12 Nov 2019 14:12:43 +0000 (15:12 +0100)
committerTankut Baris Aktemur <tankut.baris.aktemur@intel.com>
Fri, 6 Dec 2019 07:01:18 +0000 (08:01 +0100)
commit06acc08f0aa81d0053e9a60bc3bdc1ea3321962e
tree95cb7b35042212a65b4428015da39a829b8f164f
parente0fad1eadfcb68d543cdd96f44dca86364778fa2
gdb: fix overload resolution for see-through references

The overload resolution mechanism assigns badness values to the
necessary conversions to be made on types to pick a champion.  A
badness value consists of a "rank" that scores the conversion and a
"subrank" to differentiate conversions of the same kind.

An auxiliary function, 'sum_ranks', is used for adding two badness
values.  In all of its uses, except two, 'sum_ranks' is used for
populating the subrank of a badness value.  The two exceptions are in
'rank_one_type':

~~~
  /* See through references, since we can almost make non-references
     references.  */

  if (TYPE_IS_REFERENCE (arg))
    return (sum_ranks (rank_one_type (parm, TYPE_TARGET_TYPE (arg), NULL),
       REFERENCE_CONVERSION_BADNESS));
  if (TYPE_IS_REFERENCE (parm))
    return (sum_ranks (rank_one_type (TYPE_TARGET_TYPE (parm), arg, NULL),
       REFERENCE_CONVERSION_BADNESS));
~~~

Here, the result of a recursive call is combined with
REFERENCE_CONVERSION_BADNESS.  This leads to the problem of
over-punishment by combining two ranks.  Consider this:

    void an_overloaded_function (const foo &);
    void an_overloaded_function (const foo &&);
    ...
    foo arg;
    an_overloaded_function(arg);

When ranking 'an_overloaded_function (const foo &)', the badness
values REFERENCE_CONVERSION_BADNESS and CV_CONVERSION_BADNESS are
combined, whereas 'rank_one_type' assigns only the
REFERENCE_CONVERSION_BADNESS value to 'an_overloaded_function (const
foo &&)' (there is a different execution flow for that).  This yields
in GDB picking the latter function as the overload champion instead of
the former.

In fact, the 'rank_one_type' function should have given
'an_overloaded_function (const foo &)' the CV_CONVERSION_BADNESS
value, with the see-through referencing increasing the subrank a
little bit.  This can be achieved by introducing a new badness value,
REFERENCE_SEE_THROUGH_BADNESS, which bumps up the subrank only, and
using it in the two "exceptional" cases of 'sum_ranks'.

gdb/ChangeLog:
2019-12-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

* gdbtypes.h: Define the REFERENCE_SEE_THROUGH_BADNESS value.
* gdbtypes.c (rank_one_type): Use REFERENCE_SEE_THROUGH_BADNESS
for ranking see-through reference cases.

gdb/testsuite/ChangeLog:
2019-12-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

* gdb.cp/rvalue-ref-overload.cc: Add a case that involves both
CV and reference conversion for overload resolution.
* gdb.cp/rvalue-ref-overload.exp: Test it.

Change-Id: I39ae6505ab85ad0bd21915368c82540ceeb3aae9
gdb/ChangeLog
gdb/gdbtypes.c
gdb/gdbtypes.h
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.cp/rvalue-ref-overload.cc
gdb/testsuite/gdb.cp/rvalue-ref-overload.exp