Re: [PATCH 1/2] Test and support all cpp operator types

sami wagiaalla
2010-05-18T20:23:48Z

[-- Attachment #1: Type: text/plain, Size: 2370 bytes --]

> Sami> @@ -800,21 +800,27 @@ make_symbol_overload_list_using (const char *func_name,
> Sami> const char *namespace)
> [...]
> Sami> - for (current = block_using (get_selected_block (0));
> Sami> - current != NULL;
> Sami> - current = current->next)
> Sami> - {
> Sami> - if (strcmp (namespace, current->import_dest) == 0)
> Sami> - {
> Sami> - make_symbol_overload_list_using (func_name,
> Sami> - current->import_src);
> Sami> - }
> Sami> - }
> Sami> + for (block = get_selected_block (0);
> Sami> + block != NULL;
> Sami> + block = BLOCK_SUPERBLOCK(block))
> Sami> + for (current = block_using (block);
> Sami> + current != NULL;
> Sami> + current = current->next)
> Sami> + {
> [...]
>
> This part seems a little weird to me.
> make_symbol_overload_list_using calls make_symbol_overload_list_namespace,
> which calls make_symbol_overload_list_qualified, which itself
> starts with get_selected_block and iterates over the superblocks.
>
> It seems to me that only one such iteration should be needed.
> I don't have a test case but it seems like this could cause incorrect
> results in some corner case.
>

It is weird but it is due to the nature of the symbol tables. The first
iteration, by make_symbol_overload_list_using, is iteration over the
blocks' import statements. The Second iteration is actually searching
for the symbol.

If we assume that names belonging to namespaces can only be in the
static scope -since namespace symbols are flattened to the nearest
parent- then we can separate the qualified and unqualified searches
and eliminate the nesting of the iterations.

Please see patch 2/2.

> Sami> +# some unary operators for good measure
> Sami> +# Cannot resolve function operator++ to any overloaded instance
> Sami> +gdb_test "p ++q" "= 30"
>
> It would be interesting to know if "q++" would call an overloaded
> postfix operator++. These have a hack in the C++ spec to differentiate
> them from prefix ++.
>

It does work. This is tested in userdef.exp.

> I'm also curious to know if "ADL avoidance" works properly when a
> qualified reference to "operator<whatever>" is used. I didn't see a
> test for that in this patch. (If there is already one in the test
> suite, then of course we don't need a new one...)
>

Yes it does. I have added a test case.

[-- Attachment #2: operators.patch --]
[-- Type: text/plain, Size: 24525 bytes --]

commit 493c3d32944b9b355158a46b300050ff2fdbfb59
Author: Sami Wagiaalla <swagiaal@redhat.com>
Date: Tue May 11 15:39:00 2010 -0400

test and support all cpp operator types

2010-05-18 Sami Wagiaalla <swagiaal@redhat.com>

* value.h: Created oload_search_type enum.
(find_overload_match): Use oload_search_type enum.
* valops.c (find_overload_match): Support combined member and
non-member search.
* eval.c (evaluate_subexp_standard): Calls to
find_overload_match now use oload_search_type enum.
(oload_method_static): Verify index is a proper value.
* valarith.c (value_user_defined_cpp_op): Search for and handle
both member and non-member operators.
(value_user_defined_cpp_op): New function.
(value_user_defined_op): New function.
(value_x_unop): Use value_user_defined_op.
(value_x_binop): Ditto.
* cp-support.c (make_symbol_overload_list_using): Added block
iteration.
Add check for namespace aliases and imported declarations.

2010-05-18 Sami Wagiaalla <swagiaal@redhat.com>

* gdb.cp/koenig.exp: Test for ADL operators.
* gdb.cp/koenig.cc: Added ADL operators.
* gdb.cp/operator.exp: New test.
* gdb.cp/operator.cc: New test.

diff --git a/gdb/cp-support.c b/gdb/cp-support.c
index 8f447ca..0a0f777 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -800,21 +800,26 @@ make_symbol_overload_list_using (const char *func_name,
const char *namespace)
{
const struct using_direct *current;
+ const struct block *block;

/* First, go through the using directives. If any of them apply,
look in the appropriate namespaces for new functions to match
on. */

- for (current = block_using (get_selected_block (0));
- current != NULL;
- current = current->next)
- {
- if (strcmp (namespace, current->import_dest) == 0)
- {
- make_symbol_overload_list_using (func_name,
- current->import_src);
- }
- }
+ for (block = get_selected_block (0);
+ block != NULL;
+ block = BLOCK_SUPERBLOCK (block))
+ for (current = block_using (block);
+ current != NULL;
+ current = current->next)
+ {
+ /* If this is a namespace alias or imported declaration ignore it. */
+ if (current->alias != NULL || current->declaration != NULL)
+ continue;
+
+ if (strcmp (namespace, current->import_dest) == 0)
+ make_symbol_overload_list_using (func_name, current->import_src);
+ }

/* Now, add names for this namespace. */
make_symbol_overload_list_namespace (func_name, namespace);
diff --git a/gdb/eval.c b/gdb/eval.c
index 985e653..4beb1bd 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1512,7 +1512,7 @@ evaluate_subexp_standard (struct type *expect_type,
arg_types[ix - 1] = value_type (argvec[ix]);

find_overload_match (arg_types, nargs, func_name,
- 0 /* not method */ , 0 /* strict match */ ,
+ NON_METHOD /* not method */ , 0 /* strict match */ ,
NULL, NULL /* pass NULL symbol since symbol is unknown */ ,
NULL, &symp, NULL, 0);

@@ -1549,7 +1549,7 @@ evaluate_subexp_standard (struct type *expect_type,
arg_types[ix - 1] = value_type (argvec[ix]);

(void) find_overload_match (arg_types, nargs, tstr,
- 1 /* method */ , 0 /* strict match */ ,
+ METHOD /* method */ , 0 /* strict match */ ,
&arg2 /* the object */ , NULL,
&valp, NULL, &static_memfuncp, 0);

@@ -1618,8 +1618,8 @@ evaluate_subexp_standard (struct type *expect_type,
arg_types[ix - 1] = value_type (argvec[ix]);

(void) find_overload_match (arg_types, nargs, NULL /* no need for name */ ,
- 0 /* not method */ , 0 /* strict match */ ,
- NULL, function /* the function */ ,
+ NON_METHOD /* not method */ , 0 /* strict match */ ,
+ NULL, function /* the function */ ,
NULL, &symp, NULL, no_adl);

if (op == OP_VAR_VALUE)
diff --git a/gdb/testsuite/gdb.cp/koenig.cc b/gdb/testsuite/gdb.cp/koenig.cc
index 6cfa3f5..24b3ae7 100644
--- a/gdb/testsuite/gdb.cp/koenig.cc
+++ b/gdb/testsuite/gdb.cp/koenig.cc
@@ -175,6 +175,49 @@ typedef O::A TOA;
typedef TOA TTOA;

//------------
+
+namespace P {
+ class Q{
+ public:
+ int operator== (int)
+ {
+ return 24;
+ }
+
+ int operator== (float)
+ {
+ return 25;
+ }
+
+ int operator+ (float)
+ {
+ return 26;
+ }
+
+ };
+
+ int operator!= (Q, int)
+ {
+ return 27;
+ }
+
+ int operator!= (Q, double)
+ {
+ return 28;
+ }
+
+ int operator+ (Q, int)
+ {
+ return 29;
+ }
+
+ int operator++ (Q)
+ {
+ return 30;
+ }
+}
+
+//------------
int
main ()
{
@@ -238,6 +281,16 @@ main ()
TTOA ttoa;
foo (ttoa, 'a');

+ P::Q q;
+ q == 5;
+ q == 5.0f;
+ q != 5;
+ q != 5.0f;
+ q + 5;
+ q + 5.0f;
+
+ ++q;
+
return first (0, c) + foo (eo) +
foo (eo, eo) + foo (eo, eo, 1) +
foo (fo, eo) + foo (1 ,fo, eo) +
diff --git a/gdb/testsuite/gdb.cp/koenig.exp b/gdb/testsuite/gdb.cp/koenig.exp
index b13ffbc..12b4ddf 100644
--- a/gdb/testsuite/gdb.cp/koenig.exp
+++ b/gdb/testsuite/gdb.cp/koenig.exp
@@ -13,28 +13,12 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

-if $tracelevel then {
- strace $tracelevel
-}
-
-set prms_id 0
-set bug_id 0
-
set testfile koenig
set srcfile ${testfile}.cc
-set binfile ${objdir}/${subdir}/${testfile}
-if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } {
- untested "Couldn't compile test program"
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug c++}] } {
return -1
}

-# Get things started.
-
-gdb_exit
-gdb_start
-gdb_reinitialize_dir $srcdir/$subdir
-gdb_load ${binfile}
-
############################################

if ![runto_main] then {
@@ -107,3 +91,22 @@ gdb_test "p M::N::bar('a')" "= 22"

#test that lookup supports typedef
gdb_test "p foo(ttoa, 'a')" "= 23"
+
+# test lookup of namespace user-defined operators
+# and overload resolution:
+
+# within class
+gdb_test "p q == 5" "= 24"
+gdb_test "p q == 5.0f" "= 25"
+
+# within namespace
+gdb_test "p q != 5" "= 27"
+gdb_test "p q != 5.0f" "= 28"
+
+# across namespace and class
+gdb_test "p q + 5.0f" "= 26"
+gdb_test "p q + 5" "= 29"
+
+# some unary operators for good measure
+# Cannot resolve function operator++ to any overloaded instance
+gdb_test "p ++q" "= 30"
diff --git a/gdb/testsuite/gdb.cp/operator.cc b/gdb/testsuite/gdb.cp/operator.cc
new file mode 100644
index 0000000..cc925a0
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/operator.cc
@@ -0,0 +1,195 @@
+class A
+{
+};
+
+int operator== (A, int)
+{
+ return 11;
+}
+
+int operator== (A, char)
+{
+ return 12;
+}
+
+//------------------
+
+namespace B
+{
+ class C
+ {
+ };
+
+ int operator== (C, int)
+ {
+ return 22;
+ }
+
+ int operator== (C, char)
+ {
+ return 23;
+ }
+
+ namespace BD
+ {
+ int operator== (C, int)
+ {
+ return 24;
+ }
+ }
+}
+
+//------------------
+
+class D
+{
+};
+namespace
+{
+ int operator== (D, int)
+ {
+ return 33;
+ }
+
+ int operator== (D, char)
+ {
+ return 34;
+ }
+}
+
+int operator== (D, float)
+{
+ return 35;
+}
+
+//------------------
+
+class E
+{
+};
+namespace F
+{
+ int operator== (E, int)
+ {
+ return 44;
+ }
+
+ int operator== (E, char)
+ {
+ return 45;
+ }
+}
+
+int operator== (E, float)
+{
+ return 46;
+}
+
+using namespace F;
+
+//-----------------
+
+class G
+{
+public:
+ int operator== (int)
+ {
+ return 55;
+ }
+};
+
+int operator== (G, char)
+{
+ return 56;
+}
+
+//------------------
+
+class H
+{
+};
+namespace I
+{
+ int operator== (H, int)
+ {
+ return 66;
+ }
+}
+
+namespace ALIAS = I;
+
+//------------------
+
+class J
+{
+};
+
+namespace K
+{
+ int i;
+ int operator== (J, int)
+ {
+ return 77;
+ }
+}
+
+using K::i;
+
+//------------------
+
+class L
+{
+};
+namespace M
+{
+ int operator== (L, int)
+ {
+ return 88;
+ }
+}
+
+namespace N
+{
+ using namespace M;
+}
+
+using namespace N;
+
+//------------------
+
+int main ()
+{
+ A a;
+ a == 1;
+ a == 'a';
+
+ B::C bc;
+ bc == 1;
+ bc == 'a';
+ B::BD::operator== (bc,'a');
+
+ D d;
+ d == 1;
+ d == 'a';
+ d == 1.0f;
+
+ E e;
+ e == 1;
+ e == 'a';
+ e == 1.0f;
+
+ G g;
+ g == 1;
+ g == 'a';
+
+ H h;
+ I::operator== (h, 1);
+
+ J j;
+ K::operator== (j, 1);
+
+ L l;
+ l == 1;
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.cp/operator.exp b/gdb/testsuite/gdb.cp/operator.exp
new file mode 100644
index 0000000..ac89d2b
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/operator.exp
@@ -0,0 +1,58 @@
+# Copyright 2008 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+set testfile operator
+set srcfile ${testfile}.cc
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug c++}] } {
+ return -1
+}
+
+############################################
+
+if ![runto_main] then {
+ perror "couldn't run to breakpoint main"
+ continue
+}
+
+# Test global operator
+gdb_test "p a == 1" "= 11" "global operator"
+gdb_test "p a == 'a'" "= 12" "global operator overload"
+
+# Test ADL operator
+gdb_test "p bc == 1" "= 22" "ADL operator"
+gdb_test "p bc == 'a'" "= 23" "ADL operator overload"
+gdb_test "p B::BD::operator== (bc,'a')" "= 24" "Fully qualified explicit operator call"
+
+# Test operator imported from anonymous namespace
+gdb_test "p d == 1" "= 33" "anonymous namespace operator"
+gdb_test "p d == 'a'" "= 34" "anonymous namespace operator overload"
+gdb_test "p d == 1.0f" "= 35" "anonymous namespace operator overload float"
+
+# Test operator imported by using directive
+gdb_test "p e == 1" "= 44" "imported operator"
+gdb_test "p e == 'a'" "= 45" "imported operator overload"
+gdb_test "p e == 1.0f" "= 46" "imported operator overload float"
+
+# Test member operator
+gdb_test "p g == 1" "= 55" "member operator"
+gdb_test "p g == 'a'" "= 56" "member operator overload"
+
+# Test that operators are not wrongly imported
+# by import declarations and namespace aliases
+gdb_test "p h == 1" "Cannot resolve function operator== to any overloaded instance" "namespace alias"
+gdb_test "p j == 1" "Cannot resolve function operator== to any overloaded instance" "imported declaration"
+
+# Test that indirectly imported operators work
+gdb_test "p l == 1" "= 88"
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 4efe936..fe6cae6 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -31,6 +31,7 @@
#include "dfp.h"
#include <math.h>
#include "infcall.h"
+#include "exceptions.h"

/* Define whether or not the C operator '/' truncates towards zero for
differently signed operands (truncation direction is undefined in C). */
@@ -318,6 +319,67 @@ unop_user_defined_p (enum exp_opcode op, struct value *arg1)
}
}

+/* Try to find an operator named OPERATOR which takes NARGS arguments
+ specified in ARGS. If the operator found is a static member operator
+ *STATIC_MEMFUNP will be set to 1, and otherwise 0.
+ The search if performed through find_overload_match which will handle
+ member operators, non member operators, operators imported implicitly or
+ explicitly, and perform correct overload resolution in all of the above
+ situations or combinations thereof. */
+
+static struct value *
+value_user_defined_cpp_op (struct value **args, int nargs, char *operator,
+ int *static_memfuncp)
+{
+
+ struct symbol *symp = NULL;
+ struct value *valp = NULL;
+ struct type **arg_types;
+ int i;
+
+ arg_types = (struct type **) alloca (nargs * (sizeof (struct type *)));
+ /* Prepare list of argument types for overload resolution */
+ for (i = 0; i < nargs; i++)
+ arg_types[i] = value_type (args[i]);
+
+ find_overload_match (arg_types, nargs, operator, BOTH /* could be method */,
+ 0 /* strict match */, &args[0], /* objp */
+ NULL /* pass NULL symbol since symbol is unknown */,
+ &valp, &symp, static_memfuncp, 0);
+
+ if (valp)
+ return valp;
+
+ if (symp)
+ {
+ /* This is a non member function and does not
+ expect a reference as its first argument
+ rather the explicit structure. */
+ args[0] = value_ind (args[0]);
+ return value_of_variable (symp, 0);
+ }
+
+ error (_("Could not find %s."), operator);
+}
+
+/* Lookup user defined operator NAME. Return a value representing the
+ function, otherwise return NULL. */
+
+static struct value *
+value_user_defined_op (struct value **argp, struct value **args, char *name,
+ int *static_memfuncp, int nargs)
+{
+ struct value *result = NULL;
+
+ if (current_language->la_language == language_cplus)
+ result = value_user_defined_cpp_op (args, nargs, name, static_memfuncp);
+ else
+ result = value_struct_elt (argp, args, name, static_memfuncp,
+ "structure");
+
+ return result;
+}
+
/* We know either arg1 or arg2 is a structure, so try to find the right
user defined function. Create an argument vector that calls
arg1.operator @ (arg1,arg2) and return that value (where '@' is any
@@ -458,7 +520,8 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
error (_("Invalid binary operation specified."));
}

- argvec[0] = value_struct_elt (&arg1, argvec + 1, tstr, &static_memfuncp, "structure");
+ argvec[0] = value_user_defined_op (&arg1, argvec + 1, tstr,
+ &static_memfuncp, 2);

if (argvec[0])
{
@@ -555,7 +618,8 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
error (_("Invalid unary operation specified."));
}

- argvec[0] = value_struct_elt (&arg1, argvec + 1, tstr, &static_memfuncp, "structure");
+ argvec[0] = value_user_defined_op (&arg1, argvec + 1, tstr,
+ &static_memfuncp, nargs);

if (argvec[0])
{
diff --git a/gdb/valops.c b/gdb/valops.c
index 6f5f684..6648bdb 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -2293,6 +2293,16 @@ value_find_oload_method_list (struct value **argp, const char *method,
matches on the argument types according to the overload resolution
rules.

+ METHOD can be one of three values:
+ NON_METHOD for non-member functions.
+ METHOD: for member functions.
+ BOTH: used for overload resolution of operators where the
+ candidates are expected to be either member or non member
+ functions. In this case the first argument ARGTYPES
+ (representing 'this') is expected to be a reference to the
+ target object, and will be dereferenced when attempting the
+ non-member search.
+
In the case of class methods, the parameter OBJ is an object value
in which to search for overloaded methods.

@@ -2320,16 +2330,20 @@ value_find_oload_method_list (struct value **argp, const char *method,

int
find_overload_match (struct type **arg_types, int nargs,
- const char *name, int method, int lax,
- struct value **objp, struct symbol *fsym,
+ const char *name, enum oload_search_type method,
+ int lax, struct value **objp, struct symbol *fsym,
struct value **valp, struct symbol **symp,
int *staticp, const int no_adl)
{
struct value *obj = (objp ? *objp : NULL);
/* Index of best overloaded function. */
- int oload_champ;
+ int func_oload_champ = -1;
+ int method_oload_champ = -1;
+
/* The measure for the current best match. */
- struct badness_vector *oload_champ_bv = NULL;
+ struct badness_vector *method_badness = NULL;
+ struct badness_vector *func_badness = NULL;
+
struct value *temp = obj;
/* For methods, the list of overloaded methods. */
struct fn_field *fns_ptr = NULL;
@@ -2345,9 +2359,11 @@ find_overload_match (struct type **arg_types, int nargs,
const char *obj_type_name = NULL;
const char *func_name = NULL;
enum oload_classification match_quality;
+ enum oload_classification method_match_quality = INCOMPATIBLE;
+ enum oload_classification func_match_quality = INCOMPATIBLE;

/* Get the list of overloaded methods or functions. */
- if (method)
+ if (method == METHOD || method == BOTH)
{
gdb_assert (obj);

@@ -2370,10 +2386,13 @@ find_overload_match (struct type **arg_types, int nargs,
}
}

+ /* Retrieve the list of methods with the name NAME. */
fns_ptr = value_find_oload_method_list (&temp, name,
0, &num_fns,
&basetype, &boffset);
- if (!fns_ptr || !num_fns)
+ /* If this is a method only search, and no methods were found
+ the search has faild. */
+ if (method == METHOD && (!fns_ptr || !num_fns))
error (_("Couldn't find method %s%s%s"),
obj_type_name,
(obj_type_name && *obj_type_name) ? "::" : "",
@@ -2381,15 +2400,33 @@ find_overload_match (struct type **arg_types, int nargs,
/* If we are dealing with stub method types, they should have
been resolved by find_method_list via
value_find_oload_method_list above. */
- gdb_assert (TYPE_DOMAIN_TYPE (fns_ptr[0].type) != NULL);
- oload_champ = find_oload_champ (arg_types, nargs, method,
- num_fns, fns_ptr,
- oload_syms, &oload_champ_bv);
+ if (fns_ptr)
+ {
+ gdb_assert (TYPE_DOMAIN_TYPE (fns_ptr[0].type) != NULL);
+ method_oload_champ = find_oload_champ (arg_types, nargs, method,
+ num_fns, fns_ptr,
+ oload_syms, &method_badness);
+
+ method_match_quality =
+ classify_oload_match (method_badness, nargs,
+ oload_method_static (method, fns_ptr,
+ method_oload_champ));
+
+ make_cleanup (xfree, method_badness);
+ }
+
}
- else
+
+ if (method == NON_METHOD || method == BOTH)
{
const char *qualified_name = NULL;

+ /* If the the overload match is being search for both
+ as a method and non member function, the first argument
+ must now be dereferenced. */
+ if (method == BOTH)
+ arg_types[0] = TYPE_TARGET_TYPE (arg_types[0]);
+
if (fsym)
{
qualified_name = SYMBOL_NATURAL_NAME (fsym);
@@ -2432,30 +2469,67 @@ find_overload_match (struct type **arg_types, int nargs,
return 0;
}

- make_cleanup (xfree, oload_syms);
- make_cleanup (xfree, oload_champ_bv);
+ func_oload_champ = find_oload_champ_namespace (arg_types, nargs,
+ func_name,
+ qualified_name,
+ &oload_syms,
+ &func_badness,
+ no_adl);

- oload_champ = find_oload_champ_namespace (arg_types, nargs,
- func_name,
- qualified_name,
- &oload_syms,
- &oload_champ_bv,
- no_adl);
+ if (func_oload_champ >= 0)
+ func_match_quality = classify_oload_match (func_badness, nargs, 0);
+
+ make_cleanup (xfree, oload_syms);
+ make_cleanup (xfree, func_badness);
}

/* Did we find a match ? */
- if (oload_champ == -1)
+ if (method_oload_champ == -1 && func_oload_champ == -1)
error (_("No symbol \"%s\" in current context."), name);

- /* Check how bad the best match is. */
- match_quality =
- classify_oload_match (oload_champ_bv, nargs,
- oload_method_static (method, fns_ptr,
- oload_champ));
+ /* If we have found both a method match and a function
+ match, find out which one is better, and calculate match
+ quality. */
+ if (method_oload_champ >= 0 && func_oload_champ >= 0)
+ {
+ switch (compare_badness (func_badness, method_badness))
+ {
+ case 0: /* Top two contenders are equally good. */
+ /* FIXME: GDB does not support the general ambiguous
+ case. All candidates should be collected and presented
+ the the user. */
+ error (_("Ambiguous overload resolution"));
+ break;
+ case 1: /* Incomparable top contenders. */
+ /* This is an error incompatible candidates
+ should not have been proposed. */
+ error (_("Internal error: incompatible overload candidates proposed"));
+ break;
+ case 2: /* Function champion. */
+ method_oload_champ = -1;
+ match_quality = func_match_quality;
+ break;
+ case 3: /* Method champion. */
+ func_oload_champ = -1;
+ match_quality = method_match_quality;
+ break;
+ default:
+ error (_("Internal error: unexpected overload comparison result"));
+ break;
+ }
+ }
+ else
+ {
+ /* We have either a method match or a function match. */
+ if (method_oload_champ >= 0)
+ match_quality = method_match_quality;
+ else
+ match_quality = func_match_quality;
+ }

if (match_quality == INCOMPATIBLE)
{
- if (method)
+ if (method == METHOD)
error (_("Cannot resolve method %s%s%s to any overloaded instance"),
obj_type_name,
(obj_type_name && *obj_type_name) ? "::" : "",
@@ -2466,7 +2540,7 @@ find_overload_match (struct type **arg_types, int nargs,
}
else if (match_quality == NON_STANDARD)
{
- if (method)
+ if (method == METHOD)
warning (_("Using non-standard conversion to match method %s%s%s to supplied arguments"),
obj_type_name,
(obj_type_name && *obj_type_name) ? "::" : "",
@@ -2476,21 +2550,20 @@ find_overload_match (struct type **arg_types, int nargs,
func_name);
}

- if (method)
+ if (staticp != NULL)
+ *staticp = oload_method_static (method, fns_ptr, method_oload_champ);
+
+ if (method_oload_champ >= 0)
{
- if (staticp != NULL)
- *staticp = oload_method_static (method, fns_ptr, oload_champ);
- if (TYPE_FN_FIELD_VIRTUAL_P (fns_ptr, oload_champ))
- *valp = value_virtual_fn_field (&temp, fns_ptr, oload_champ,
+ if (TYPE_FN_FIELD_VIRTUAL_P (fns_ptr, method_oload_champ))
+ *valp = value_virtual_fn_field (&temp, fns_ptr, method_oload_champ,
basetype, boffset);
else
- *valp = value_fn_field (&temp, fns_ptr, oload_champ,
+ *valp = value_fn_field (&temp, fns_ptr, method_oload_champ,
basetype, boffset);
}
else
- {
- *symp = oload_syms[oload_champ];
- }
+ *symp = oload_syms[func_oload_champ];

if (objp)
{
@@ -2778,7 +2851,8 @@ find_oload_champ (struct type **arg_types, int nargs, int method,
static int
oload_method_static (int method, struct fn_field *fns_ptr, int index)
{
- if (method && TYPE_FN_FIELD_STATIC_P (fns_ptr, index))
+ if (method && fns_ptr && index >= 0
+ && TYPE_FN_FIELD_STATIC_P (fns_ptr, index))
return 1;
else
return 0;
diff --git a/gdb/value.h b/gdb/value.h
index 57b4dd7..7f71dc4 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -447,8 +447,11 @@ extern struct fn_field *value_find_oload_method_list (struct value **,
int, int *,
struct type **, int *);

+enum oload_search_type { NON_METHOD, METHOD, BOTH };
+
extern int find_overload_match (struct type **arg_types, int nargs,
- const char *name, int method, int lax,
+ const char *name,
+ enum oload_search_type method, int lax,
struct value **objp, struct symbol *fsym,
struct value **valp, struct symbol **symp,
int *staticp, const int no_adl);