+2010-06-07 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-06-07 Jan Kratochvil <jan.kratochvil@redhat.com>
* breakpoint.h (owner): Extend the comment.
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);
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);
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);
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)
+2010-06-07 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.
+
2010-06-04 Michael Snyder <msnyder@vmware.com>
* gdb.base/attach.exp: Replace gdb_test_multiple with gdb_test.
typedef TOA TTOA;
//------------
+
static union {
int a;
char b;
//------------
+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 ()
{
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) +
# 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 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"
- return -1
+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 {
#test that lookup is not thwarted by anonymous types
gdb_test "p foo (p_union)" \
"Cannot resolve function foo to any overloaded instance"
+
+# 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"
--- /dev/null
+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;
+}
--- /dev/null
+# 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"
#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). */
}
}
+/* 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
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])
{
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])
{
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.
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;
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);
}
}
+ /* 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) ? "::" : "",
/* 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);
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) ? "::" : "",
}
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) ? "::" : "",
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)
{
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;
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);