diff options
-rw-r--r-- | gdb/ChangeLog | 19 | ||||
-rw-r--r-- | gdb/cp-support.c | 25 | ||||
-rw-r--r-- | gdb/eval.c | 8 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gdb/testsuite/gdb.cp/koenig.cc | 54 | ||||
-rw-r--r-- | gdb/testsuite/gdb.cp/koenig.exp | 36 | ||||
-rw-r--r-- | gdb/testsuite/gdb.cp/operator.cc | 195 | ||||
-rw-r--r-- | gdb/testsuite/gdb.cp/operator.exp | 58 | ||||
-rw-r--r-- | gdb/valarith.c | 68 | ||||
-rw-r--r-- | gdb/valops.c | 148 | ||||
-rw-r--r-- | gdb/value.h | 5 |
11 files changed, 554 insertions, 69 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c64fb08..78d3199 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,22 @@ +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. diff --git a/gdb/cp-support.c b/gdb/cp-support.c index 799b707..d9a59f3 100644 --- a/gdb/cp-support.c +++ b/gdb/cp-support.c @@ -803,21 +803,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); @@ -1535,7 +1535,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); @@ -1572,7 +1572,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); @@ -1642,8 +1642,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/ChangeLog b/gdb/testsuite/ChangeLog index d0bb484..291175b 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,10 @@ +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. diff --git a/gdb/testsuite/gdb.cp/koenig.cc b/gdb/testsuite/gdb.cp/koenig.cc index fb4ecb1..c91dbf9 100644 --- a/gdb/testsuite/gdb.cp/koenig.cc +++ b/gdb/testsuite/gdb.cp/koenig.cc @@ -175,6 +175,7 @@ typedef O::A TOA; typedef TOA TTOA; //------------ + static union { int a; char b; @@ -182,6 +183,49 @@ static union { //------------ +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 () { @@ -245,6 +289,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 57be745..d5e6c3f 100644 --- a/gdb/testsuite/gdb.cp/koenig.exp +++ b/gdb/testsuite/gdb.cp/koenig.exp @@ -13,25 +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 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 { @@ -109,3 +96,22 @@ gdb_test "p foo(ttoa, 'a')" "= 23" #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" 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 745d960..0c40905 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). */ @@ -319,6 +320,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 @@ -459,7 +521,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]) { @@ -557,7 +620,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 6cd66dd..08a64ce 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -2315,6 +2315,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. @@ -2342,16 +2352,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; @@ -2367,9 +2381,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); @@ -2392,10 +2408,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) ? "::" : "", @@ -2403,15 +2422,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); @@ -2454,30 +2491,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) ? "::" : "", @@ -2488,7 +2562,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) ? "::" : "", @@ -2498,21 +2572,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) { @@ -2801,7 +2874,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); |