Test and support all cpp operator types.

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  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.
This commit is contained in:
Sami Wagiaalla 2010-06-07 16:11:35 +00:00
parent 0f32ea4ce3
commit 4c3376c849
11 changed files with 554 additions and 69 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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)

View File

@ -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.

View File

@ -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) +

View File

@ -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"

View File

@ -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;
}

View File

@ -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"

View File

@ -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])
{

View File

@ -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;

View File

@ -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);