From 06acc08f0aa81d0053e9a60bc3bdc1ea3321962e Mon Sep 17 00:00:00 2001 From: Tankut Baris Aktemur Date: Tue, 12 Nov 2019 15:12:43 +0100 Subject: [PATCH] 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 * 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 * 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 | 6 ++++++ gdb/gdbtypes.c | 5 +++-- gdb/gdbtypes.h | 1 + gdb/testsuite/ChangeLog | 6 ++++++ gdb/testsuite/gdb.cp/rvalue-ref-overload.cc | 9 +++++++++ gdb/testsuite/gdb.cp/rvalue-ref-overload.exp | 4 ++++ 6 files changed, 29 insertions(+), 2 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 7646214ca8a..2d6071271ac 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,9 @@ +2019-12-06 Tankut Baris Aktemur + + * 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. + 2019-12-06 Philippe Waroquiers * stack.c (faas_command): Check a command is provided. * thread.c (taas_command, tfaas_command): Likewise. diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index 4854f49e484..e226cb7f940 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -60,6 +60,7 @@ const struct rank VOID_PTR_CONVERSION_BADNESS = {2,0}; const struct rank BOOL_CONVERSION_BADNESS = {3,0}; const struct rank BASE_CONVERSION_BADNESS = {2,0}; const struct rank REFERENCE_CONVERSION_BADNESS = {2,0}; +const struct rank REFERENCE_SEE_THROUGH_BADNESS = {0,1}; const struct rank NULL_POINTER_CONVERSION_BADNESS = {2,0}; const struct rank NS_POINTER_CONVERSION_BADNESS = {10,0}; const struct rank NS_INTEGER_POINTER_CONVERSION_BADNESS = {3,0}; @@ -4338,10 +4339,10 @@ rank_one_type (struct type *parm, struct type *arg, struct value *value) if (TYPE_IS_REFERENCE (arg)) return (sum_ranks (rank_one_type (parm, TYPE_TARGET_TYPE (arg), NULL), - REFERENCE_CONVERSION_BADNESS)); + REFERENCE_SEE_THROUGH_BADNESS)); if (TYPE_IS_REFERENCE (parm)) return (sum_ranks (rank_one_type (TYPE_TARGET_TYPE (parm), arg, NULL), - REFERENCE_CONVERSION_BADNESS)); + REFERENCE_SEE_THROUGH_BADNESS)); if (overload_debug) /* Debugging only. */ fprintf_filtered (gdb_stderr, diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index 0dd7333371b..a1d95e09deb 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -2105,6 +2105,7 @@ extern const struct rank BASE_CONVERSION_BADNESS; /* * Badness of converting from non-reference to reference. Subrank is the type of reference conversion being done. */ extern const struct rank REFERENCE_CONVERSION_BADNESS; +extern const struct rank REFERENCE_SEE_THROUGH_BADNESS; /* * Conversion to rvalue reference. */ #define REFERENCE_CONVERSION_RVALUE 1 /* * Conversion to const lvalue reference. */ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 79b124b8198..adbbd9c9d85 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2019-12-06 Tankut Baris Aktemur + + * 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. + 2019-12-06 Philippe Waroquiers * gdb.threads/pthreads.exp: Test taas and tfaas without command. diff --git a/gdb/testsuite/gdb.cp/rvalue-ref-overload.cc b/gdb/testsuite/gdb.cp/rvalue-ref-overload.cc index fa6cab03b05..e3111d528bd 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 61f81b4559e..693c7cad20a 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(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" -- 2.30.2