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"
 
