aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbtypes.c
diff options
context:
space:
mode:
authorKeith Seitz <keiths@redhat.com>2017-04-27 15:55:26 -0700
committerKeith Seitz <keiths@redhat.com>2017-04-27 15:58:54 -0700
commite15c3eb45bdc8bd5717fd5ceddcc30c3de07b58f (patch)
tree56889ea84864e52062ebec7bfa090119c52ff871 /gdb/gdbtypes.c
parent5b66fac4bad619766fb1a5f5179c08b67d48a8c5 (diff)
downloadgdb-e15c3eb45bdc8bd5717fd5ceddcc30c3de07b58f.zip
gdb-e15c3eb45bdc8bd5717fd5ceddcc30c3de07b58f.tar.gz
gdb-e15c3eb45bdc8bd5717fd5ceddcc30c3de07b58f.tar.bz2
Fix overload resolution involving rvalue references and cv qualifiers.
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. 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.
Diffstat (limited to 'gdb/gdbtypes.c')
-rw-r--r--gdb/gdbtypes.c106
1 files changed, 56 insertions, 50 deletions
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: