This is the mail archive of the
gdb-patches@sourceware.cygnus.com
mailing list for the GDB project.
[PATCH] Fix C++ overloading, add support for seeing through references.
- To: GDB Patches <gdb-patches at sourceware dot cygnus dot com>
- Subject: [PATCH] Fix C++ overloading, add support for seeing through references.
- From: Andrew Cagney <ac131313 at cygnus dot com>
- Date: Mon, 13 Mar 2000 21:04:42 +1100
- Organization: Cygnus Solutions
FYI,
I've committed the attatched from Daniel Berlin (except for minor
edits). It has a very interesting effect on the arm-elf -> arm-sim
testsuite results:
==> before
# of expected passes 5715
# of unexpected failures 36
# of unexpected successes 2
# of expected failures 193
# of unresolved testcases 79
# of untested testcases 18
# of unsupported tests 2
==> after
# of expected passes 5716
# of unexpected failures 36
# of unexpected successes 16
# of expected failures 178
# of unresolved testcases 79
# of untested testcases 18
# of unsupported tests 2
where the actual changes are ( ``<'' for old, ``>'' for new):
< XFAIL: gdb.c++/derivation.exp: print value of g_instance.afoo()
< XFAIL: gdb.c++/derivation.exp: print value of g_instance.bfoo()
< XFAIL: gdb.c++/derivation.exp: print value of g_instance.cfoo()
> XPASS: gdb.c++/derivation.exp: print value of g_instance.afoo()
> XPASS: gdb.c++/derivation.exp: print value of g_instance.bfoo()
> XPASS: gdb.c++/derivation.exp: print value of g_instance.cfoo()
< XFAIL: gdb.c++/overload.exp: print call overloaded func 1 arg
< XFAIL: gdb.c++/overload.exp: print call overloaded func 2 args
< XFAIL: gdb.c++/overload.exp: print call overloaded func 3 args
> XPASS: gdb.c++/overload.exp: print call overloaded func 1 arg
> XPASS: gdb.c++/overload.exp: print call overloaded func 2 args
> XPASS: gdb.c++/overload.exp: print call overloaded func 3 args
< XFAIL: gdb.c++/overload.exp: print call overloaded func void arg
> XPASS: gdb.c++/overload.exp: print call overloaded func void arg
< XFAIL: gdb.c++/overload.exp: print call overloaded func signed char
arg
< XFAIL: gdb.c++/overload.exp: print call overloaded func unsigned char
arg
> XPASS: gdb.c++/overload.exp: print call overloaded func signed char arg
> XPASS: gdb.c++/overload.exp: print call overloaded func unsigned char arg
< XFAIL: gdb.c++/overload.exp: print call overloaded func unsigned int
arg
> XPASS: gdb.c++/overload.exp: print call overloaded func unsigned int arg
< XFAIL: gdb.c++/templates.exp: print t5i.value
> PASS: gdb.c++/templates.exp: print t5i.value()
< XFAIL: gdb.c++/virtfunc.exp: print pAe->f()
< XFAIL: gdb.c++/virtfunc.exp: print pAa->f()
> XPASS: gdb.c++/virtfunc.exp: print pAe->f()
> XPASS: gdb.c++/virtfunc.exp: print pAa->f()
< XFAIL: gdb.c++/virtfunc.exp: print pDd->vg()
> XPASS: gdb.c++/virtfunc.exp: print pDd->vg()
< XFAIL: gdb.c++/virtfunc.exp: print pVB->vvb()
> XPASS: gdb.c++/virtfunc.exp: print pVB->vvb()
so fixed some long outstanding bugs.
Andrew
Mon Mar 13 18:54:42 2000 Andrew Cagney <cagney@b1.cygnus.com>
From 2000-03-10 Daniel Berlin <dan@cgsoftware.com> Fix C++
overloading, add support for seeing through references:
* valops.c (find_overload_match): Handle STABS overloading for
C++.
(find_overload_match): Look in right place for function arguments
in the debug info.
(find_overload_match): Rather than giving up when we have >1
perfect match, just choose one, especially since the
recommendation GDB gives ("disambiguate it by specifying function
signature"), is basically impossible.
(check_field_in): STREQ->strcmp_iw
(search_struct_field): STREQ->strcmp_iw
(find_method_list): STREQ->strcmp_iw
* gdbtypes.c (rank_one_type): Add ability to see through
references.
(rank_one_type): strcmp->strcmp_iw, because the whitespace could
be different.
(rank_function): Rank function properly (was doing it wrong
before, comparing the wrong parts of the arrays)
(rank_one_type): Change #if 0 to #ifdef DEBUG_OLOAD.
* gdbtypes.h: Add REFERENCE_CONVERSION_BADNESS for "badness"
associated with converting a non-reference to a reference.
* gdbtypes.c (rank_one_type): Add comment on how to eliminate the
#ifdef DEBUG_OLOAD.
Index: gdbtypes.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbtypes.c,v
retrieving revision 1.3
diff -p -r1.3 gdbtypes.c
*** gdbtypes.c 2000/03/13 07:30:00 1.3
--- gdbtypes.c 2000/03/13 08:47:00
*************** lookup_struct_elt_type (type, name, noer
*** 994,1000 ****
{
char *t_field_name = TYPE_FIELD_NAME (type, i);
! if (t_field_name && STREQ (t_field_name, name))
{
return TYPE_FIELD_TYPE (type, i);
}
--- 994,1000 ----
{
char *t_field_name = TYPE_FIELD_NAME (type, i);
! if (t_field_name && (strcmp_iw (t_field_name, name) == 0))
{
return TYPE_FIELD_TYPE (type, i);
}
*************** rank_function (parms, nparms, args, narg
*** 2136,2143 ****
LENGTH_MATCH (bv) = (nargs != nparms) ? LENGTH_MISMATCH_BADNESS : 0;
/* Now rank all the parameters of the candidate function */
! for (i = 1; i <= min_len; i++)
! bv->rank[i] = rank_one_type (parms[i - 1], args[i - 1]);
/* If more arguments than parameters, add dummy entries */
for (i = min_len + 1; i <= nargs; i++)
--- 2136,2143 ----
LENGTH_MATCH (bv) = (nargs != nparms) ? LENGTH_MISMATCH_BADNESS : 0;
/* Now rank all the parameters of the candidate function */
! for (i = 1; i < min_len; i++)
! bv->rank[i] = rank_one_type (parms[i], args[i]);
/* If more arguments than parameters, add dummy entries */
for (i = min_len + 1; i <= nargs; i++)
*************** rank_one_type (parm, arg)
*** 2178,2185 ****
if (parm == arg)
return 0;
! #if 0
! /* Debugging only */
printf ("------ Arg is %s [%d], parm is %s [%d]\n",
TYPE_NAME (arg), TYPE_CODE (arg), TYPE_NAME (parm), TYPE_CODE (parm));
#endif
--- 2178,2198 ----
if (parm == arg)
return 0;
! /* See through references, since we can almost make non-references
! references. */
! if (TYPE_CODE (arg) == TYPE_CODE_REF)
! return (rank_one_type (TYPE_TARGET_TYPE (arg), parm)
! + REFERENCE_CONVERSION_BADNESS);
! if (TYPE_CODE (parm) == TYPE_CODE_REF)
! return (rank_one_type (arg, TYPE_TARGET_TYPE (parm))
! + REFERENCE_CONVERSION_BADNESS);
!
! #ifdef DEBUG_OLOAD
! /* Debugging only. */
! /* FIXME/FYI: cagney/2000-03-13: No need to #ifdef this sort of
! thing. Instead add a command like ``set debug gdbtypes <int>''.
! (A predicate to this is the addition of the ``set debug''). Also,
! send the output to gdb_stderr and don't use printf. */
printf ("------ Arg is %s [%d], parm is %s [%d]\n",
TYPE_NAME (arg), TYPE_CODE (arg), TYPE_NAME (parm), TYPE_CODE (parm));
#endif
*************** rank_one_type (parm, arg)
*** 2246,2261 ****
{
if (TYPE_UNSIGNED (arg))
{
! if (!strcmp (TYPE_NAME (parm), TYPE_NAME (arg)))
return 0; /* unsigned int -> unsigned int, or unsigned long -> unsigned long */
! else if (!strcmp (TYPE_NAME (arg), "int") && !strcmp (TYPE_NAME (parm), "long"))
return INTEGER_PROMOTION_BADNESS; /* unsigned int -> unsigned long */
else
return INTEGER_COERCION_BADNESS; /* unsigned long -> unsigned int */
}
else
{
! if (!strcmp (TYPE_NAME (arg), "long") && !strcmp (TYPE_NAME (parm), "int"))
return INTEGER_COERCION_BADNESS; /* signed long -> unsigned int */
else
return INTEGER_CONVERSION_BADNESS; /* signed int/long -> unsigned int/long */
--- 2259,2274 ----
{
if (TYPE_UNSIGNED (arg))
{
! if (!strcmp_iw (TYPE_NAME (parm), TYPE_NAME (arg)))
return 0; /* unsigned int -> unsigned int, or unsigned long -> unsigned long */
! else if (!strcmp_iw (TYPE_NAME (arg), "int") && !strcmp_iw (TYPE_NAME (parm), "long"))
return INTEGER_PROMOTION_BADNESS; /* unsigned int -> unsigned long */
else
return INTEGER_COERCION_BADNESS; /* unsigned long -> unsigned int */
}
else
{
! if (!strcmp_iw (TYPE_NAME (arg), "long") && !strcmp_iw (TYPE_NAME (parm), "int"))
return INTEGER_COERCION_BADNESS; /* signed long -> unsigned int */
else
return INTEGER_CONVERSION_BADNESS; /* signed int/long -> unsigned int/long */
*************** rank_one_type (parm, arg)
*** 2263,2271 ****
}
else if (!TYPE_NOSIGN (arg) && !TYPE_UNSIGNED (arg))
{
! if (!strcmp (TYPE_NAME (parm), TYPE_NAME (arg)))
return 0;
! else if (!strcmp (TYPE_NAME (arg), "int") && !strcmp (TYPE_NAME (parm), "long"))
return INTEGER_PROMOTION_BADNESS;
else
return INTEGER_COERCION_BADNESS;
--- 2276,2284 ----
}
else if (!TYPE_NOSIGN (arg) && !TYPE_UNSIGNED (arg))
{
! if (!strcmp_iw (TYPE_NAME (parm), TYPE_NAME (arg)))
return 0;
! else if (!strcmp_iw (TYPE_NAME (arg), "int") && !strcmp_iw (TYPE_NAME (parm), "long"))
return INTEGER_PROMOTION_BADNESS;
else
return INTEGER_COERCION_BADNESS;
Index: gdbtypes.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbtypes.h,v
retrieving revision 1.3
diff -p -r1.3 gdbtypes.h
*** gdbtypes.h 2000/03/13 07:30:00 1.3
--- gdbtypes.h 2000/03/13 08:47:03
*************** count_virtual_fns PARAMS ((struct type *
*** 1129,1136 ****
#define POINTER_CONVERSION_BADNESS 2
/* Badness of conversion of pointer to void pointer */
#define VOID_PTR_CONVERSION_BADNESS 2
! /* Badness of convering derived to base class */
#define BASE_CONVERSION_BADNESS 2
/* Non-standard conversions allowed by the debugger */
/* Converting a pointer to an int is usually OK */
--- 1129,1138 ----
#define POINTER_CONVERSION_BADNESS 2
/* Badness of conversion of pointer to void pointer */
#define VOID_PTR_CONVERSION_BADNESS 2
! /* Badness of converting derived to base class */
#define BASE_CONVERSION_BADNESS 2
+ /* Badness of converting from non-reference to reference */
+ #define REFERENCE_CONVERSION_BADNESS 2
/* Non-standard conversions allowed by the debugger */
/* Converting a pointer to an int is usually OK */
Index: valops.c
===================================================================
RCS file: /cvs/src/src/gdb/valops.c,v
retrieving revision 1.5
diff -p -r1.5 valops.c
*** valops.c 2000/03/13 07:30:00 1.5
--- valops.c 2000/03/13 08:47:19
*************** search_struct_field (name, arg1, offset,
*** 2068,2074 ****
{
char *t_field_name = TYPE_FIELD_NAME (type, i);
! if (t_field_name && STREQ (t_field_name, name))
{
value_ptr v;
if (TYPE_FIELD_STATIC (type, i))
--- 2068,2074 ----
{
char *t_field_name = TYPE_FIELD_NAME (type, i);
! if (t_field_name && (strcmp_iw (t_field_name, name) == 0))
{
value_ptr v;
if (TYPE_FIELD_STATIC (type, i))
*************** search_struct_field (name, arg1, offset,
*** 2083,2089 ****
if (t_field_name
&& (t_field_name[0] == '\0'
|| (TYPE_CODE (type) == TYPE_CODE_UNION
! && STREQ (t_field_name, "else"))))
{
struct type *field_type = TYPE_FIELD_TYPE (type, i);
if (TYPE_CODE (field_type) == TYPE_CODE_UNION
--- 2083,2089 ----
if (t_field_name
&& (t_field_name[0] == '\0'
|| (TYPE_CODE (type) == TYPE_CODE_UNION
! && (strcmp_iw (t_field_name, "else") == 0))))
{
struct type *field_type = TYPE_FIELD_TYPE (type, i);
if (TYPE_CODE (field_type) == TYPE_CODE_UNION
*************** search_struct_field (name, arg1, offset,
*** 2128,2134 ****
is not yet filled in. */
int found_baseclass = (looking_for_baseclass
&& TYPE_BASECLASS_NAME (type, i) != NULL
! && STREQ (name, TYPE_BASECLASS_NAME (type, i)));
if (BASETYPE_VIA_VIRTUAL (type, i))
{
--- 2128,2134 ----
is not yet filled in. */
int found_baseclass = (looking_for_baseclass
&& TYPE_BASECLASS_NAME (type, i) != NULL
! && (strcmp_iw (name, TYPE_BASECLASS_NAME (type, i)) == 0));
if (BASETYPE_VIA_VIRTUAL (type, i))
{
*************** search_struct_method (name, arg1p, args,
*** 2314,2320 ****
else if (cplus_demangle_opname (t_field_name, dem_opname, 0))
t_field_name = dem_opname;
}
! if (t_field_name && STREQ (t_field_name, name))
{
int j = TYPE_FN_FIELDLIST_LENGTH (type, i) - 1;
struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
--- 2314,2320 ----
else if (cplus_demangle_opname (t_field_name, dem_opname, 0))
t_field_name = dem_opname;
}
! if (t_field_name && (strcmp_iw (t_field_name, name) == 0))
{
int j = TYPE_FN_FIELDLIST_LENGTH (type, i) - 1;
struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
*************** find_method_list (argp, method, offset,
*** 2570,2576 ****
{
/* pai: FIXME What about operators and type conversions? */
char *fn_field_name = TYPE_FN_FIELDLIST_NAME (type, i);
! if (fn_field_name && STREQ (fn_field_name, method))
{
*num_fns = TYPE_FN_FIELDLIST_LENGTH (type, i);
*basetype = type;
--- 2570,2576 ----
{
/* pai: FIXME What about operators and type conversions? */
char *fn_field_name = TYPE_FN_FIELDLIST_NAME (type, i);
! if (fn_field_name && (strcmp_iw (fn_field_name, method) == 0))
{
*num_fns = TYPE_FN_FIELDLIST_LENGTH (type, i);
*basetype = type;
*************** find_overload_match (arg_types, nargs, n
*** 2740,2745 ****
--- 2740,2748 ----
/* Get the list of overloaded methods or functions */
if (method)
{
+ int i;
+ int len;
+ struct type *domain;
obj_type_name = TYPE_NAME (VALUE_TYPE (obj));
/* Hack: evaluate_subexp_standard often passes in a pointer
value rather than the object itself, so try again */
*************** find_overload_match (arg_types, nargs, n
*** 2756,2761 ****
--- 2759,2784 ----
obj_type_name,
(obj_type_name && *obj_type_name) ? "::" : "",
name);
+ domain = TYPE_DOMAIN_TYPE (fns_ptr[0].type);
+ len = TYPE_NFN_FIELDS (domain);
+ /* NOTE: dan/2000-03-10: This stuff is for STABS, which won't
+ give us the info we need directly in the types. We have to
+ use the method stub conversion to get it. Be aware that this
+ is by no means perfect, and if you use STABS, please move to
+ DWARF-2, or something like it, because trying to improve
+ overloading using STABS is really a waste of time. */
+ for (i = 0; i < len; i++)
+ {
+ int j;
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (domain, i);
+ int len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
+
+ for (j = 0; j < len2; j++)
+ {
+ if (TYPE_FN_FIELD_STUB (f, j))
+ check_stub_method (domain, i, j);
+ }
+ }
}
else
{
*************** find_overload_match (arg_types, nargs, n
*** 2782,2795 ****
/* Consider each candidate in turn */
for (ix = 0; ix < num_fns; ix++)
{
! /* Number of parameters for current candidate */
! nparms = method ? TYPE_NFIELDS (fns_ptr[ix].type)
! : TYPE_NFIELDS (SYMBOL_TYPE (oload_syms[ix]));
/* Prepare array of parameter types */
parm_types = (struct type **) xmalloc (nparms * (sizeof (struct type *)));
for (jj = 0; jj < nparms; jj++)
! parm_types[jj] = method ? TYPE_FIELD_TYPE (fns_ptr[ix].type, jj)
: TYPE_FIELD_TYPE (SYMBOL_TYPE (oload_syms[ix]), jj);
/* Compare parameter types to supplied argument types */
--- 2805,2832 ----
/* Consider each candidate in turn */
for (ix = 0; ix < num_fns; ix++)
{
! if (method)
! {
! /* For static member functions, we won't have a this pointer, but nothing
! else seems to handle them right now, so we just pretend ourselves */
! nparms=0;
+ if (TYPE_FN_FIELD_ARGS(fns_ptr,ix))
+ {
+ while (TYPE_CODE(TYPE_FN_FIELD_ARGS(fns_ptr,ix)[nparms]) != TYPE_CODE_VOID)
+ nparms++;
+ }
+ }
+ else
+ {
+ /* If it's not a method, this is the proper place */
+ nparms=TYPE_NFIELDS(SYMBOL_TYPE(oload_syms[ix]));
+ }
+
/* Prepare array of parameter types */
parm_types = (struct type **) xmalloc (nparms * (sizeof (struct type *)));
for (jj = 0; jj < nparms; jj++)
! parm_types[jj] = method ? (TYPE_FN_FIELD_ARGS(fns_ptr,ix)[jj])
: TYPE_FIELD_TYPE (SYMBOL_TYPE (oload_syms[ix]), jj);
/* Compare parameter types to supplied argument types */
*************** find_overload_match (arg_types, nargs, n
*** 2826,2841 ****
}
free (parm_types);
#ifdef DEBUG_OLOAD
if (method)
printf ("Overloaded method instance %s, # of parms %d\n", fns_ptr[ix].physname, nparms);
else
printf ("Overloaded function instance %s # of parms %d\n", SYMBOL_DEMANGLED_NAME (oload_syms[ix]), nparms);
! for (jj = 0; jj <= nargs; jj++)
printf ("...Badness @ %d : %d\n", jj, bv->rank[jj]);
printf ("Overload resolution champion is %d, ambiguous? %d\n", oload_champ, oload_ambiguous);
#endif
} /* end loop over all candidates */
if (oload_ambiguous)
{
if (method)
--- 2863,2885 ----
}
free (parm_types);
#ifdef DEBUG_OLOAD
+ /* FIXME: cagney/2000-03-12: Send the output to gdb_stderr. See
+ comments above about adding a ``set debug'' command. */
if (method)
printf ("Overloaded method instance %s, # of parms %d\n", fns_ptr[ix].physname, nparms);
else
printf ("Overloaded function instance %s # of parms %d\n", SYMBOL_DEMANGLED_NAME (oload_syms[ix]), nparms);
! for (jj = 0; jj < nargs; jj++)
printf ("...Badness @ %d : %d\n", jj, bv->rank[jj]);
printf ("Overload resolution champion is %d, ambiguous? %d\n", oload_champ, oload_ambiguous);
#endif
} /* end loop over all candidates */
+ /* NOTE: dan/2000-03-10: Seems to be a better idea to just pick one
+ if they have the exact same goodness. This is because there is no
+ way to differentiate based on return type, which we need to in
+ cases like overloads of .begin() <It's both const and non-const> */
+ #if 0
if (oload_ambiguous)
{
if (method)
*************** find_overload_match (arg_types, nargs, n
*** 2847,2852 ****
--- 2891,2897 ----
error ("Cannot resolve overloaded function %s to unique instance; disambiguate by specifying function signature",
func_name);
}
+ #endif
/* Check how bad the best match is */
for (ix = 1; ix <= nargs; ix++)
*************** check_field_in (type, name)
*** 2943,2949 ****
for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--)
{
char *t_field_name = TYPE_FIELD_NAME (type, i);
! if (t_field_name && STREQ (t_field_name, name))
return 1;
}
--- 2988,2994 ----
for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--)
{
char *t_field_name = TYPE_FIELD_NAME (type, i);
! if (t_field_name && (strcmp_iw (t_field_name, name) == 0))
return 1;
}
*************** check_field_in (type, name)
*** 2960,2966 ****
for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; --i)
{
! if (STREQ (TYPE_FN_FIELDLIST_NAME (type, i), name))
return 1;
}
--- 3005,3011 ----
for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; --i)
{
! if (strcmp_iw (TYPE_FN_FIELDLIST_NAME (type, i), name) == 0)
return 1;
}