diff mbox

Fix overload resolution involving rvalue references and cv qualifiers.

Message ID 1493328958-8677-1-git-send-email-keiths@redhat.com
State New
Headers show

Commit Message

Keith Seitz April 27, 2017, 9:35 p.m. UTC
The following patch fixes several outstanding overload resolution problems
with rvalue references and cv qualifiers in the test suite. The tests for
these problems typically passed with one compiler version and failed with
another. This behavior occurs because of the ordering of the overloaded
functions in the debug info. So the first best match "won out" over the
a subsequent better match.

One of the bugs addressed by this patch is the failure of rank_one_type to
account for type equality of two overloads based on CV qualifiers.  This was
leading directly to problems evaluating rvalue reference overload quality,
but it is also highlighted in gdb.cp/oranking.exp, where two test KFAIL as
a result of this shortcoming.

I found the overload resolution code committed with the rvalue reference
patch (f9aeb8d49) needlessly over-complicated, and I have greatly simplified
it. This fixes some KFAILing tests in gdb.exp/rvalue-ref-overload.exp.

Note that there is still one KFAILing test in gdb.cp/rvalue-ref-overload.exp,
but I hope to address that next.

If there is still time, I would like to push this to the 8.0 branch, too.

I have tested the patch with GCC 5.2.0 and 7.0.0, and both compilers now
give identical test results.

gdb/ChangeLog

	* gdbtypes.c (LVALUE_REFERENCE_TO_RVALUE_BINDING_BADNESS)
	DIFFERENT_REFERENCE_TYPE_BADNESS): Remove.
	(CV_CONVERSION_BADNESS): Define.
	(rank_one_type): Remove overly restrictive rvalue reference
	rank checks.
	Add cv-qualifier checks and subranks for type equality.
	* gdbtypes.h (REFERENCE_CONVERSION_RVALUE,
	REFERENCE_CONVERSION_CONST_LVALUE, CV_CONVERSION_BADNESS,
	CV_CONVERSION_CONST, CV_CONVERSION_VOLATILE): Declare.

gdb/testsuite/ChangeLog

	* gdb.cp/oranking.cc (test15): New function.
	(main): Call test15 and declare additional variables for testing.
	* gdb.cp/oranking.exp: Remove kfail status for "p foo4(&a)" and
	"p foo101('abc')" tests.
	* gdb.cp/rvalue-ref-overloads.exp: Remove kfail status for
	"lvalue reference overload" test.
	* gdb.cp/rvalue-ref-params.exp: Remove kfail status for
	"print value of f1 on Child&& in f2" test.
---
 gdb/ChangeLog                                |  12 +++
 gdb/gdbtypes.c                               | 106 ++++++++++++++-------------
 gdb/gdbtypes.h                               |  13 +++-
 gdb/testsuite/ChangeLog                      |  12 +++
 gdb/testsuite/gdb.cp/oranking.cc             |  22 ++++++
 gdb/testsuite/gdb.cp/oranking.exp            |   9 ++-
 gdb/testsuite/gdb.cp/rvalue-ref-overload.exp |   1 -
 gdb/testsuite/gdb.cp/rvalue-ref-params.exp   |   1 -
 8 files changed, 119 insertions(+), 57 deletions(-)

Comments

Pedro Alves April 27, 2017, 9:59 p.m. UTC | #1
Awesome, thanks much for this.

I didn't really go over the ranking code with a fine-tooth comb,
so if the tests pass, I'm happy.  You probably know this area
better than most by now, anyhow.

On 04/27/2017 10:35 PM, Keith Seitz wrote:

> If there is still time, I would like to push this to the 8.0 branch, too.

Since rvalue references didn't work at all before 8.0, I think
this is pretty safe to put in 8.0.

So OK for master and 8.0.

Thanks,
Pedro Alves
Keith Seitz April 27, 2017, 11:26 p.m. UTC | #2
On 04/27/2017 02:59 PM, Pedro Alves wrote:
> So OK for master and 8.0.
> 

Great. Re-tested on 8.0 and pushed to both master and gdb-8.0-branch.

Thank you,
Keith
Thomas Preud'homme May 2, 2017, 2:33 p.m. UTC | #3
Hi Keith,

After your patch I get the following error when running the testsuite for 
arm-none-eabi target:

p foo101("abc")^M
evaluation of this expression requires the program to have a function "malloc".^M
(gdb) FAIL: gdb.cp/oranking.exp: p foo101("abc")

I believe the approach in 7b2fe205fd75672d5925fe63f3a0896fa3168aaf will need to 
be applied here as well.

Best regards,

Thomas

On 27/04/17 22:35, Keith Seitz wrote:
> The following patch fixes several outstanding overload resolution problems
> with rvalue references and cv qualifiers in the test suite. The tests for
> these problems typically passed with one compiler version and failed with
> another. This behavior occurs because of the ordering of the overloaded
> functions in the debug info. So the first best match "won out" over the
> a subsequent better match.
>
> One of the bugs addressed by this patch is the failure of rank_one_type to
> account for type equality of two overloads based on CV qualifiers.  This was
> leading directly to problems evaluating rvalue reference overload quality,
> but it is also highlighted in gdb.cp/oranking.exp, where two test KFAIL as
> a result of this shortcoming.
>
> I found the overload resolution code committed with the rvalue reference
> patch (f9aeb8d49) needlessly over-complicated, and I have greatly simplified
> it. This fixes some KFAILing tests in gdb.exp/rvalue-ref-overload.exp.
>
> Note that there is still one KFAILing test in gdb.cp/rvalue-ref-overload.exp,
> but I hope to address that next.
>
> If there is still time, I would like to push this to the 8.0 branch, too.
>
> I have tested the patch with GCC 5.2.0 and 7.0.0, and both compilers now
> give identical test results.
>
> gdb/ChangeLog
>
> 	* gdbtypes.c (LVALUE_REFERENCE_TO_RVALUE_BINDING_BADNESS)
> 	DIFFERENT_REFERENCE_TYPE_BADNESS): Remove.
> 	(CV_CONVERSION_BADNESS): Define.
> 	(rank_one_type): Remove overly restrictive rvalue reference
> 	rank checks.
> 	Add cv-qualifier checks and subranks for type equality.
> 	* gdbtypes.h (REFERENCE_CONVERSION_RVALUE,
> 	REFERENCE_CONVERSION_CONST_LVALUE, CV_CONVERSION_BADNESS,
> 	CV_CONVERSION_CONST, CV_CONVERSION_VOLATILE): Declare.
>
> gdb/testsuite/ChangeLog
>
> 	* gdb.cp/oranking.cc (test15): New function.
> 	(main): Call test15 and declare additional variables for testing.
> 	* gdb.cp/oranking.exp: Remove kfail status for "p foo4(&a)" and
> 	"p foo101('abc')" tests.
> 	* gdb.cp/rvalue-ref-overloads.exp: Remove kfail status for
> 	"lvalue reference overload" test.
> 	* gdb.cp/rvalue-ref-params.exp: Remove kfail status for
> 	"print value of f1 on Child&& in f2" test.
> ---
>  gdb/ChangeLog                                |  12 +++
>  gdb/gdbtypes.c                               | 106 ++++++++++++++-------------
>  gdb/gdbtypes.h                               |  13 +++-
>  gdb/testsuite/ChangeLog                      |  12 +++
>  gdb/testsuite/gdb.cp/oranking.cc             |  22 ++++++
>  gdb/testsuite/gdb.cp/oranking.exp            |   9 ++-
>  gdb/testsuite/gdb.cp/rvalue-ref-overload.exp |   1 -
>  gdb/testsuite/gdb.cp/rvalue-ref-params.exp   |   1 -
>  8 files changed, 119 insertions(+), 57 deletions(-)
>
> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index 8381b8e..7ce2c35 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,3 +1,15 @@
> +2017-MM-DD  Keith Seitz  <keiths@redhat.com>
> +
> +	* gdbtypes.c (LVALUE_REFERENCE_TO_RVALUE_BINDING_BADNESS)
> +	DIFFERENT_REFERENCE_TYPE_BADNESS): Remove.
> +	(CV_CONVERSION_BADNESS): Define.
> +	(rank_one_type): Remove overly restrictive rvalue reference
> +	rank checks.
> +	Add cv-qualifier checks and subranks for type equality.
> +	* gdbtypes.h (REFERENCE_CONVERSION_RVALUE,
> +	REFERENCE_CONVERSION_CONST_LVALUE, CV_CONVERSION_BADNESS,
> +	CV_CONVERSION_CONST, CV_CONVERSION_VOLATILE): Declare.
> +
>  2017-04-27  Sangamesh Mallayya  <sangamesh.swamy@in.ibm.com>
>  	    Ulrich Weigand  <uweigand@de.ibm.com>
>
> diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
> index dd3992c..c9a9b3d 100644
> --- a/gdb/gdbtypes.c
> +++ b/gdb/gdbtypes.c
> @@ -51,6 +51,7 @@ const struct rank EXACT_MATCH_BADNESS = {0,0};
>  const struct rank INTEGER_PROMOTION_BADNESS = {1,0};
>  const struct rank FLOAT_PROMOTION_BADNESS = {1,0};
>  const struct rank BASE_PTR_CONVERSION_BADNESS = {1,0};
> +const struct rank CV_CONVERSION_BADNESS = {1, 0};
>  const struct rank INTEGER_CONVERSION_BADNESS = {2,0};
>  const struct rank FLOAT_CONVERSION_BADNESS = {2,0};
>  const struct rank INT_FLOAT_CONVERSION_BADNESS = {2,0};
> @@ -58,8 +59,6 @@ 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 LVALUE_REFERENCE_TO_RVALUE_BINDING_BADNESS = {5,0};
> -const struct rank DIFFERENT_REFERENCE_TYPE_BADNESS = {6,0};
>  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};
> @@ -3619,57 +3618,51 @@ rank_one_type (struct type *parm, struct type *arg, struct value *value)
>    if (TYPE_CODE (arg) == TYPE_CODE_TYPEDEF)
>      arg = check_typedef (arg);
>
> -  if (value != NULL)
> +  if (TYPE_IS_REFERENCE (parm) && value != NULL)
>      {
> -      /* An rvalue argument cannot be bound to a non-const lvalue
> -         reference parameter...  */
> -      if (VALUE_LVAL (value) == not_lval
> -          && TYPE_CODE (parm) == TYPE_CODE_REF
> -          && !TYPE_CONST (parm->main_type->target_type))
> -        return INCOMPATIBLE_TYPE_BADNESS;
> -
> -      /* ... and an lvalue argument cannot be bound to an rvalue
> -         reference parameter.  [C++ 13.3.3.1.4p3]  */
> -      if (VALUE_LVAL (value) != not_lval
> -          && TYPE_CODE (parm) == TYPE_CODE_RVALUE_REF)
> -        return INCOMPATIBLE_TYPE_BADNESS;
> +      if (VALUE_LVAL (value) == not_lval)
> +	{
> +	  /* Rvalues should preferably bind to rvalue references or const
> +	     lvalue references.  */
> +	  if (TYPE_CODE (parm) == TYPE_CODE_RVALUE_REF)
> +	    rank.subrank = REFERENCE_CONVERSION_RVALUE;
> +	  else if (TYPE_CONST (TYPE_TARGET_TYPE (parm)))
> +	    rank.subrank = REFERENCE_CONVERSION_CONST_LVALUE;
> +	  else
> +	    return INCOMPATIBLE_TYPE_BADNESS;
> +	  return sum_ranks (rank, REFERENCE_CONVERSION_BADNESS);
> +	}
> +      else
> +	{
> +	  /* Lvalues should prefer lvalue overloads.  */
> +	  if (TYPE_CODE (parm) == TYPE_CODE_RVALUE_REF)
> +	    {
> +	      rank.subrank = REFERENCE_CONVERSION_RVALUE;
> +	      return sum_ranks (rank, REFERENCE_CONVERSION_BADNESS);
> +	    }
> +	}
>      }
>
>    if (types_equal (parm, arg))
> -    return EXACT_MATCH_BADNESS;
> -
> -  /* An lvalue reference to a function should get higher priority than an
> -     rvalue reference to a function.  */
> -
> -  if (value != NULL && TYPE_CODE (arg) == TYPE_CODE_RVALUE_REF
> -      && TYPE_CODE (TYPE_TARGET_TYPE (arg)) == TYPE_CODE_FUNC)
> -    {
> -      return (sum_ranks (rank_one_type (parm,
> -              lookup_pointer_type (TYPE_TARGET_TYPE (arg)), NULL),
> -              DIFFERENT_REFERENCE_TYPE_BADNESS));
> -    }
> -
> -  /* If a conversion to one type of reference is an identity conversion, and a
> -     conversion to the second type of reference is a non-identity conversion,
> -     choose the first type.  */
> -
> -  if (value != NULL && TYPE_IS_REFERENCE (parm) && TYPE_IS_REFERENCE (arg)
> -     && TYPE_CODE (parm) != TYPE_CODE (arg))
>      {
> -      return (sum_ranks (rank_one_type (TYPE_TARGET_TYPE (parm),
> -              TYPE_TARGET_TYPE (arg), NULL), DIFFERENT_REFERENCE_TYPE_BADNESS));
> -    }
> +      struct type *t1 = parm;
> +      struct type *t2 = arg;
>
> -  /* An rvalue should be first tried to bind to an rvalue reference, and then to
> -     an lvalue reference.  */
> +      /* For pointers and references, compare target type.  */
> +      if (TYPE_CODE (parm) == TYPE_CODE_PTR || TYPE_IS_REFERENCE (parm))
> +	{
> +	  t1 = TYPE_TARGET_TYPE (parm);
> +	  t2 = TYPE_TARGET_TYPE (arg);
> +	}
>
> -  if (value != NULL && TYPE_CODE (parm) == TYPE_CODE_REF
> -      && VALUE_LVAL (value) == not_lval)
> -    {
> -      if (TYPE_IS_REFERENCE (arg))
> -	arg = TYPE_TARGET_TYPE (arg);
> -      return (sum_ranks (rank_one_type (TYPE_TARGET_TYPE (parm), arg, NULL),
> -			 LVALUE_REFERENCE_TO_RVALUE_BINDING_BADNESS));
> +      /* Make sure they are CV equal, too.  */
> +      if (TYPE_CONST (t1) != TYPE_CONST (t2))
> +	rank.subrank |= CV_CONVERSION_CONST;
> +      if (TYPE_VOLATILE (t1) != TYPE_VOLATILE (t2))
> +	rank.subrank |= CV_CONVERSION_VOLATILE;
> +      if (rank.subrank != 0)
> +	return sum_ranks (CV_CONVERSION_BADNESS, rank);
> +      return EXACT_MATCH_BADNESS;
>      }
>
>    /* See through references, since we can almost make non-references
> @@ -3711,10 +3704,23 @@ rank_one_type (struct type *parm, struct type *arg, struct value *value)
>
>  	  return INCOMPATIBLE_TYPE_BADNESS;
>  	case TYPE_CODE_ARRAY:
> -	  if (types_equal (TYPE_TARGET_TYPE (parm),
> -	                   TYPE_TARGET_TYPE (arg)))
> -	    return EXACT_MATCH_BADNESS;
> -	  return INCOMPATIBLE_TYPE_BADNESS;
> +	  {
> +	    struct type *t1 = TYPE_TARGET_TYPE (parm);
> +	    struct type *t2 = TYPE_TARGET_TYPE (arg);
> +
> +	    if (types_equal (t1, t2))
> +	      {
> +		/* Make sure they are CV equal.  */
> +		if (TYPE_CONST (t1) != TYPE_CONST (t2))
> +		  rank.subrank |= CV_CONVERSION_CONST;
> +		if (TYPE_VOLATILE (t1) != TYPE_VOLATILE (t2))
> +		  rank.subrank |= CV_CONVERSION_VOLATILE;
> +		if (rank.subrank != 0)
> +		  return sum_ranks (CV_CONVERSION_BADNESS, rank);
> +		return EXACT_MATCH_BADNESS;
> +	      }
> +	    return INCOMPATIBLE_TYPE_BADNESS;
> +	  }
>  	case TYPE_CODE_FUNC:
>  	  return rank_one_type (TYPE_TARGET_TYPE (parm), arg, NULL);
>  	case TYPE_CODE_INT:
> diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
> index f6b4de9..6f896db 100644
> --- a/gdb/gdbtypes.h
> +++ b/gdb/gdbtypes.h
> @@ -1891,10 +1891,21 @@ extern const struct rank VOID_PTR_CONVERSION_BADNESS;
>  extern const struct rank BOOL_CONVERSION_BADNESS;
>  /* * Badness of converting derived to base class.  */
>  extern const struct rank BASE_CONVERSION_BADNESS;
> -/* * Badness of converting from non-reference to reference.  */
> +/* * Badness of converting from non-reference to reference.  Subrank
> +   is the type of reference conversion being done.  */
>  extern const struct rank REFERENCE_CONVERSION_BADNESS;
> +/* * Conversion to rvalue reference.  */
> +#define REFERENCE_CONVERSION_RVALUE 1
> +/* * Conversion to const lvalue reference.  */
> +#define REFERENCE_CONVERSION_CONST_LVALUE 2
> +
>  /* * Badness of converting integer 0 to NULL pointer.  */
>  extern const struct rank NULL_POINTER_CONVERSION;
> +/* * Badness of cv-conversion.  Subrank is a flag describing the conversions
> +   being done.  */
> +extern const struct rank CV_CONVERSION_BADNESS;
> +#define CV_CONVERSION_CONST 1
> +#define CV_CONVERSION_VOLATILE 2
>
>  /* Non-standard conversions allowed by the debugger */
>
> diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
> index c4d5b79..9909e75 100644
> --- a/gdb/testsuite/ChangeLog
> +++ b/gdb/testsuite/ChangeLog
> @@ -1,3 +1,15 @@
> +2017-MM-DD  Keith Seitz  <keiths@redhat.com>
> +
> +	* gdb.cp/oranking.cc (test15): New function.
> +	(main): Call test15 and declare additional variables for testing.
> +	* gdb.cp/oranking.exp: Remove kfail status for "p foo4(&a)" and
> +	"p foo101('abc')" tests.
> +	Add tests for cv qualifier overloads.
> +	* gdb.cp/rvalue-ref-overloads.exp: Remove kfail status for
> +	"lvalue reference overload" test.
> +	* gdb.cp/rvalue-ref-params.exp: Remove kfail status for
> +	"print value of f1 on Child&& in f2" test.
> +
>  2017-04-19  Pedro Alves  <palves@redhat.com>
>
>  	* gdb.threads/threadapply.exp (kill_and_remove_inferior): New
> diff --git a/gdb/testsuite/gdb.cp/oranking.cc b/gdb/testsuite/gdb.cp/oranking.cc
> index dc1972a..bd2f51b 100644
> --- a/gdb/testsuite/gdb.cp/oranking.cc
> +++ b/gdb/testsuite/gdb.cp/oranking.cc
> @@ -147,6 +147,23 @@ int test14 (){
>    return foo14(e); // 46
>  }
>
> +/* Test cv qualifier overloads.  */
> +int foo15 (char *arg) { return 47; }
> +int foo15 (const char *arg) { return 48; }
> +int foo15 (volatile char *arg) { return 49; }
> +int foo15 (const volatile char *arg) { return 50; }
> +static int
> +test15 ()
> +{
> +  char *c = 0;
> +  const char *cc = 0;
> +  volatile char *vc = 0;
> +  const volatile char *cvc = 0;
> +
> +  // 47 + 48 + 49 + 50 = 194
> +  return foo15 (c) + foo15 (cc) + foo15 (vc)  + foo15 (cvc);
> +}
> +
>  int main() {
>    B b;
>    foo0(b);
> @@ -203,5 +220,10 @@ int main() {
>    foo14(e);
>    test14();
>
> +  const char *cc = 0;
> +  volatile char *vc = 0;
> +  const volatile char *cvc = 0;
> +  test15 ();
> +
>    return 0; // end of main
>  }
> diff --git a/gdb/testsuite/gdb.cp/oranking.exp b/gdb/testsuite/gdb.cp/oranking.exp
> index 69efb0c..dc7c78b 100644
> --- a/gdb/testsuite/gdb.cp/oranking.exp
> +++ b/gdb/testsuite/gdb.cp/oranking.exp
> @@ -48,7 +48,6 @@ gdb_test "p test3()"    "21"
>  gdb_test "p foo3(1.0f)" "21"
>
>  gdb_test "p test4()"  "24"
> -setup_kfail "gdb/12098" *-*-*
>  gdb_test "p foo4(&a)" "24"
>
>  gdb_test "p test5()" "26"
> @@ -71,7 +70,6 @@ setup_kfail "gdb/12098" *-*-*
>  gdb_test "p foo10(amp)" "216"
>
>  gdb_test "p test101()"   "218"
> -setup_kfail "gdb/12098" *-*-*
>  gdb_test "p foo101(\"abc\")" "218"
>
>  gdb_test "p test11()"   "32"
> @@ -91,5 +89,8 @@ gdb_test "p test14()" "46"
>  setup_kfail "gdb/12096" *-*-*
>  gdb_test "p foo14(e)" "46"
>
> -
> -
> +gdb_test "p test15 ()" "194"
> +gdb_test "p foo15 (c)" "47"
> +gdb_test "p foo15 (cc)" "48"
> +gdb_test "p foo15 (vc)" "49"
> +gdb_test "p foo15 (cvc)" "50"
> diff --git a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
> index e729209..5cfd34e 100644
> --- a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
> +++ b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
> @@ -60,7 +60,6 @@ gdb_test "print foo_rr_instance1.overload1arg(static_cast<foo&&>(arg))" \
>      "print call overloaded func foo && arg"
>
>  # Test lvalue vs rvalue function overloads
> -setup_kfail "c++/15372" "*-*-*"
>  gdb_test "print f (i)" "= 1" "lvalue reference overload"
>
>  gdb_test "print f (ci)" "= 2" "lvalue reference to const overload"
> diff --git a/gdb/testsuite/gdb.cp/rvalue-ref-params.exp b/gdb/testsuite/gdb.cp/rvalue-ref-params.exp
> index 303b447..611b592 100644
> --- a/gdb/testsuite/gdb.cp/rvalue-ref-params.exp
> +++ b/gdb/testsuite/gdb.cp/rvalue-ref-params.exp
> @@ -48,7 +48,6 @@ set t "print value of Child&& in f2"
>  gdb_start_again "marker2 here" $t
>  gdb_test "print C" ".*id = 42.*" $t
>
> -setup_kfail "c++/15372" "*-*-*"
>  gdb_test "print f1 (static_cast<Child&&> (C))" ".* = 42.*" \
>      "print value of f1 on Child&& in f2"
>
>
diff mbox

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 8381b8e..7ce2c35 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,15 @@ 
+2017-MM-DD  Keith Seitz  <keiths@redhat.com>
+
+	* gdbtypes.c (LVALUE_REFERENCE_TO_RVALUE_BINDING_BADNESS)
+	DIFFERENT_REFERENCE_TYPE_BADNESS): Remove.
+	(CV_CONVERSION_BADNESS): Define.
+	(rank_one_type): Remove overly restrictive rvalue reference
+	rank checks.
+	Add cv-qualifier checks and subranks for type equality.
+	* gdbtypes.h (REFERENCE_CONVERSION_RVALUE,
+	REFERENCE_CONVERSION_CONST_LVALUE, CV_CONVERSION_BADNESS,
+	CV_CONVERSION_CONST, CV_CONVERSION_VOLATILE): Declare.
+
 2017-04-27  Sangamesh Mallayya  <sangamesh.swamy@in.ibm.com>
 	    Ulrich Weigand  <uweigand@de.ibm.com>
 
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index dd3992c..c9a9b3d 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -51,6 +51,7 @@  const struct rank EXACT_MATCH_BADNESS = {0,0};
 const struct rank INTEGER_PROMOTION_BADNESS = {1,0};
 const struct rank FLOAT_PROMOTION_BADNESS = {1,0};
 const struct rank BASE_PTR_CONVERSION_BADNESS = {1,0};
+const struct rank CV_CONVERSION_BADNESS = {1, 0};
 const struct rank INTEGER_CONVERSION_BADNESS = {2,0};
 const struct rank FLOAT_CONVERSION_BADNESS = {2,0};
 const struct rank INT_FLOAT_CONVERSION_BADNESS = {2,0};
@@ -58,8 +59,6 @@  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 LVALUE_REFERENCE_TO_RVALUE_BINDING_BADNESS = {5,0};
-const struct rank DIFFERENT_REFERENCE_TYPE_BADNESS = {6,0};
 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};
@@ -3619,57 +3618,51 @@  rank_one_type (struct type *parm, struct type *arg, struct value *value)
   if (TYPE_CODE (arg) == TYPE_CODE_TYPEDEF)
     arg = check_typedef (arg);
 
-  if (value != NULL)
+  if (TYPE_IS_REFERENCE (parm) && value != NULL)
     {
-      /* An rvalue argument cannot be bound to a non-const lvalue
-         reference parameter...  */
-      if (VALUE_LVAL (value) == not_lval
-          && TYPE_CODE (parm) == TYPE_CODE_REF
-          && !TYPE_CONST (parm->main_type->target_type))
-        return INCOMPATIBLE_TYPE_BADNESS;
-
-      /* ... and an lvalue argument cannot be bound to an rvalue
-         reference parameter.  [C++ 13.3.3.1.4p3]  */
-      if (VALUE_LVAL (value) != not_lval
-          && TYPE_CODE (parm) == TYPE_CODE_RVALUE_REF)
-        return INCOMPATIBLE_TYPE_BADNESS;
+      if (VALUE_LVAL (value) == not_lval)
+	{
+	  /* Rvalues should preferably bind to rvalue references or const
+	     lvalue references.  */
+	  if (TYPE_CODE (parm) == TYPE_CODE_RVALUE_REF)
+	    rank.subrank = REFERENCE_CONVERSION_RVALUE;
+	  else if (TYPE_CONST (TYPE_TARGET_TYPE (parm)))
+	    rank.subrank = REFERENCE_CONVERSION_CONST_LVALUE;
+	  else
+	    return INCOMPATIBLE_TYPE_BADNESS;
+	  return sum_ranks (rank, REFERENCE_CONVERSION_BADNESS);
+	}
+      else
+	{
+	  /* Lvalues should prefer lvalue overloads.  */
+	  if (TYPE_CODE (parm) == TYPE_CODE_RVALUE_REF)
+	    {
+	      rank.subrank = REFERENCE_CONVERSION_RVALUE;
+	      return sum_ranks (rank, REFERENCE_CONVERSION_BADNESS);
+	    }
+	}
     }
 
   if (types_equal (parm, arg))
-    return EXACT_MATCH_BADNESS;
-
-  /* An lvalue reference to a function should get higher priority than an
-     rvalue reference to a function.  */
-
-  if (value != NULL && TYPE_CODE (arg) == TYPE_CODE_RVALUE_REF
-      && TYPE_CODE (TYPE_TARGET_TYPE (arg)) == TYPE_CODE_FUNC)
-    {
-      return (sum_ranks (rank_one_type (parm,
-              lookup_pointer_type (TYPE_TARGET_TYPE (arg)), NULL),
-              DIFFERENT_REFERENCE_TYPE_BADNESS));
-    }
-
-  /* If a conversion to one type of reference is an identity conversion, and a
-     conversion to the second type of reference is a non-identity conversion,
-     choose the first type.  */
-
-  if (value != NULL && TYPE_IS_REFERENCE (parm) && TYPE_IS_REFERENCE (arg)
-     && TYPE_CODE (parm) != TYPE_CODE (arg))
     {
-      return (sum_ranks (rank_one_type (TYPE_TARGET_TYPE (parm),
-              TYPE_TARGET_TYPE (arg), NULL), DIFFERENT_REFERENCE_TYPE_BADNESS));
-    }
+      struct type *t1 = parm;
+      struct type *t2 = arg;
 
-  /* An rvalue should be first tried to bind to an rvalue reference, and then to
-     an lvalue reference.  */
+      /* For pointers and references, compare target type.  */
+      if (TYPE_CODE (parm) == TYPE_CODE_PTR || TYPE_IS_REFERENCE (parm))
+	{
+	  t1 = TYPE_TARGET_TYPE (parm);
+	  t2 = TYPE_TARGET_TYPE (arg);
+	}
 
-  if (value != NULL && TYPE_CODE (parm) == TYPE_CODE_REF
-      && VALUE_LVAL (value) == not_lval)
-    {
-      if (TYPE_IS_REFERENCE (arg))
-	arg = TYPE_TARGET_TYPE (arg);
-      return (sum_ranks (rank_one_type (TYPE_TARGET_TYPE (parm), arg, NULL),
-			 LVALUE_REFERENCE_TO_RVALUE_BINDING_BADNESS));
+      /* Make sure they are CV equal, too.  */
+      if (TYPE_CONST (t1) != TYPE_CONST (t2))
+	rank.subrank |= CV_CONVERSION_CONST;
+      if (TYPE_VOLATILE (t1) != TYPE_VOLATILE (t2))
+	rank.subrank |= CV_CONVERSION_VOLATILE;
+      if (rank.subrank != 0)
+	return sum_ranks (CV_CONVERSION_BADNESS, rank);
+      return EXACT_MATCH_BADNESS;
     }
 
   /* See through references, since we can almost make non-references
@@ -3711,10 +3704,23 @@  rank_one_type (struct type *parm, struct type *arg, struct value *value)
 
 	  return INCOMPATIBLE_TYPE_BADNESS;
 	case TYPE_CODE_ARRAY:
-	  if (types_equal (TYPE_TARGET_TYPE (parm),
-	                   TYPE_TARGET_TYPE (arg)))
-	    return EXACT_MATCH_BADNESS;
-	  return INCOMPATIBLE_TYPE_BADNESS;
+	  {
+	    struct type *t1 = TYPE_TARGET_TYPE (parm);
+	    struct type *t2 = TYPE_TARGET_TYPE (arg);
+
+	    if (types_equal (t1, t2))
+	      {
+		/* Make sure they are CV equal.  */
+		if (TYPE_CONST (t1) != TYPE_CONST (t2))
+		  rank.subrank |= CV_CONVERSION_CONST;
+		if (TYPE_VOLATILE (t1) != TYPE_VOLATILE (t2))
+		  rank.subrank |= CV_CONVERSION_VOLATILE;
+		if (rank.subrank != 0)
+		  return sum_ranks (CV_CONVERSION_BADNESS, rank);
+		return EXACT_MATCH_BADNESS;
+	      }
+	    return INCOMPATIBLE_TYPE_BADNESS;
+	  }
 	case TYPE_CODE_FUNC:
 	  return rank_one_type (TYPE_TARGET_TYPE (parm), arg, NULL);
 	case TYPE_CODE_INT:
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index f6b4de9..6f896db 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1891,10 +1891,21 @@  extern const struct rank VOID_PTR_CONVERSION_BADNESS;
 extern const struct rank BOOL_CONVERSION_BADNESS;
 /* * Badness of converting derived to base class.  */
 extern const struct rank BASE_CONVERSION_BADNESS;
-/* * Badness of converting from non-reference to reference.  */
+/* * Badness of converting from non-reference to reference.  Subrank
+   is the type of reference conversion being done.  */
 extern const struct rank REFERENCE_CONVERSION_BADNESS;
+/* * Conversion to rvalue reference.  */
+#define REFERENCE_CONVERSION_RVALUE 1
+/* * Conversion to const lvalue reference.  */
+#define REFERENCE_CONVERSION_CONST_LVALUE 2
+
 /* * Badness of converting integer 0 to NULL pointer.  */
 extern const struct rank NULL_POINTER_CONVERSION;
+/* * Badness of cv-conversion.  Subrank is a flag describing the conversions
+   being done.  */
+extern const struct rank CV_CONVERSION_BADNESS;
+#define CV_CONVERSION_CONST 1
+#define CV_CONVERSION_VOLATILE 2
 
 /* Non-standard conversions allowed by the debugger */
 
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index c4d5b79..9909e75 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,15 @@ 
+2017-MM-DD  Keith Seitz  <keiths@redhat.com>
+
+	* gdb.cp/oranking.cc (test15): New function.
+	(main): Call test15 and declare additional variables for testing.
+	* gdb.cp/oranking.exp: Remove kfail status for "p foo4(&a)" and
+	"p foo101('abc')" tests.
+	Add tests for cv qualifier overloads.
+	* gdb.cp/rvalue-ref-overloads.exp: Remove kfail status for
+	"lvalue reference overload" test.
+	* gdb.cp/rvalue-ref-params.exp: Remove kfail status for
+	"print value of f1 on Child&& in f2" test.
+
 2017-04-19  Pedro Alves  <palves@redhat.com>
 
 	* gdb.threads/threadapply.exp (kill_and_remove_inferior): New
diff --git a/gdb/testsuite/gdb.cp/oranking.cc b/gdb/testsuite/gdb.cp/oranking.cc
index dc1972a..bd2f51b 100644
--- a/gdb/testsuite/gdb.cp/oranking.cc
+++ b/gdb/testsuite/gdb.cp/oranking.cc
@@ -147,6 +147,23 @@  int test14 (){
   return foo14(e); // 46
 }
 
+/* Test cv qualifier overloads.  */
+int foo15 (char *arg) { return 47; }
+int foo15 (const char *arg) { return 48; }
+int foo15 (volatile char *arg) { return 49; }
+int foo15 (const volatile char *arg) { return 50; }
+static int
+test15 ()
+{
+  char *c = 0;
+  const char *cc = 0;
+  volatile char *vc = 0;
+  const volatile char *cvc = 0;
+
+  // 47 + 48 + 49 + 50 = 194
+  return foo15 (c) + foo15 (cc) + foo15 (vc)  + foo15 (cvc);
+}
+
 int main() {
   B b;
   foo0(b);
@@ -203,5 +220,10 @@  int main() {
   foo14(e);
   test14();
 
+  const char *cc = 0;
+  volatile char *vc = 0;
+  const volatile char *cvc = 0;
+  test15 ();
+
   return 0; // end of main
 }
diff --git a/gdb/testsuite/gdb.cp/oranking.exp b/gdb/testsuite/gdb.cp/oranking.exp
index 69efb0c..dc7c78b 100644
--- a/gdb/testsuite/gdb.cp/oranking.exp
+++ b/gdb/testsuite/gdb.cp/oranking.exp
@@ -48,7 +48,6 @@  gdb_test "p test3()"    "21"
 gdb_test "p foo3(1.0f)" "21"
 
 gdb_test "p test4()"  "24"
-setup_kfail "gdb/12098" *-*-*
 gdb_test "p foo4(&a)" "24"
 
 gdb_test "p test5()" "26"
@@ -71,7 +70,6 @@  setup_kfail "gdb/12098" *-*-*
 gdb_test "p foo10(amp)" "216"
 
 gdb_test "p test101()"   "218"
-setup_kfail "gdb/12098" *-*-*
 gdb_test "p foo101(\"abc\")" "218"
 
 gdb_test "p test11()"   "32"
@@ -91,5 +89,8 @@  gdb_test "p test14()" "46"
 setup_kfail "gdb/12096" *-*-*
 gdb_test "p foo14(e)" "46"
 
-
-
+gdb_test "p test15 ()" "194"
+gdb_test "p foo15 (c)" "47"
+gdb_test "p foo15 (cc)" "48"
+gdb_test "p foo15 (vc)" "49"
+gdb_test "p foo15 (cvc)" "50"
diff --git a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
index e729209..5cfd34e 100644
--- a/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
+++ b/gdb/testsuite/gdb.cp/rvalue-ref-overload.exp
@@ -60,7 +60,6 @@  gdb_test "print foo_rr_instance1.overload1arg(static_cast<foo&&>(arg))" \
     "print call overloaded func foo && arg"
 
 # Test lvalue vs rvalue function overloads
-setup_kfail "c++/15372" "*-*-*"
 gdb_test "print f (i)" "= 1" "lvalue reference overload"
 
 gdb_test "print f (ci)" "= 2" "lvalue reference to const overload"
diff --git a/gdb/testsuite/gdb.cp/rvalue-ref-params.exp b/gdb/testsuite/gdb.cp/rvalue-ref-params.exp
index 303b447..611b592 100644
--- a/gdb/testsuite/gdb.cp/rvalue-ref-params.exp
+++ b/gdb/testsuite/gdb.cp/rvalue-ref-params.exp
@@ -48,7 +48,6 @@  set t "print value of Child&& in f2"
 gdb_start_again "marker2 here" $t
 gdb_test "print C" ".*id = 42.*" $t
 
-setup_kfail "c++/15372" "*-*-*"
 gdb_test "print f1 (static_cast<Child&&> (C))" ".* = 42.*" \
     "print value of f1 on Child&& in f2"