diff options
author | Tankut Baris Aktemur <tankut.baris.aktemur@intel.com> | 2019-11-12 15:12:43 +0100 |
---|---|---|
committer | Tankut Baris Aktemur <tankut.baris.aktemur@intel.com> | 2019-12-06 08:01:18 +0100 |
commit | 06acc08f0aa81d0053e9a60bc3bdc1ea3321962e (patch) | |
tree | 95cb7b35042212a65b4428015da39a829b8f164f /gdb/testsuite/gdb.cp | |
parent | e0fad1eadfcb68d543cdd96f44dca86364778fa2 (diff) | |
download | gdb-06acc08f0aa81d0053e9a60bc3bdc1ea3321962e.zip gdb-06acc08f0aa81d0053e9a60bc3bdc1ea3321962e.tar.gz gdb-06acc08f0aa81d0053e9a60bc3bdc1ea3321962e.tar.bz2 |
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
Diffstat (limited to 'gdb/testsuite/gdb.cp')
-rw-r--r-- | gdb/testsuite/gdb.cp/rvalue-ref-overload.cc | 9 | ||||
-rw-r--r-- | gdb/testsuite/gdb.cp/rvalue-ref-overload.exp | 4 |
2 files changed, 13 insertions, 0 deletions
diff --git a/gdb/testsuite/gdb.cp/rvalue-ref-overload.cc b/gdb/testsuite/gdb.cp/rvalue-ref-overload.cc index fa6cab0..e3111d5 100644 --- a/gdb/testsuite/gdb.cp/rvalue-ref-overload.cc +++ b/gdb/testsuite/gdb.cp/rvalue-ref-overload.cc @@ -35,6 +35,8 @@ public: int overload1arg (foo_lval_ref); int overload1arg (foo_rval_ref); + int overloadConst (const foo &); + int overloadConst (const foo &&); }; void @@ -71,6 +73,11 @@ main () // result = 1 + 2 + 3 + 3 = 9 int result = f (i) + f (ci) + f (0) + f (std::move (i)); + /* Overload resolution below requires both a CV-conversion + and reference conversion. */ + int test_const // = 3 + = foo_rr_instance1.overloadConst (arg); + marker1 (); // marker1-returns-here return result; } @@ -84,3 +91,5 @@ foo::~foo () {} int foo::overload1arg (foo_lval_ref arg) { return 1; } int foo::overload1arg (foo_rval_ref arg) { return 2; } +int foo::overloadConst (const foo &arg) { return 3; } +int foo::overloadConst (const foo &&arg) { return 4; } diff --git a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp index 61f81b4..693c7ca 100644 --- a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp +++ b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp @@ -49,6 +49,8 @@ cp_test_ptype_class "foo_rr_instance1" "" "class" "foo" \ { method public "~foo();" } { method public "int overload1arg(foo_lval_ref);" } { method public "int overload1arg(foo_rval_ref);" } + { method public "int overloadConst(const foo &);" } + { method public "int overloadConst(const foo &&);" } } gdb_test "print foo_rr_instance1.overload1arg(arg)" \ @@ -59,6 +61,8 @@ gdb_test "print foo_rr_instance1.overload1arg(static_cast<foo&&>(arg))" \ "\\$\[0-9\]+ = 2" \ "print call overloaded func foo && arg" +gdb_test "print foo_rr_instance1.overloadConst(arg)" "3" + # Test lvalue vs rvalue function overloads gdb_test "print f (i)" "= 1" "lvalue reference overload" |