From: Keith Seitz Date: Tue, 10 Nov 2009 22:17:58 +0000 (+0000) Subject: * c-exp.y: Add new rule for resolving method overloads. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=072bba3b0f3e2ee8d2cfc94e256d0f0ebc627afc;p=binutils-gdb.git * c-exp.y: Add new rule for resolving method overloads. * eval.c (make_params): New function. (free_param_types): New function. (evaluate_subexp_standard): Pass expect_type to value_aggregate_elt. Handle case TYPE_INSTANCE. (evaluate_subexp_for_address): Pass expect_type to value_aggregate_elt. * expression.h (enum exp_opcode): Add TYPE_INSTANCE. (compare_parameters): Add declaration. * parse.c (operator_length_standard): Add TYPE_INSTANCE. * valops.c (value_aggregate_elt): Add new expect_type parameter. Pass expect_type to value_struct_elt_for_reference. (value_struct_elt_for_reference): Add expect_type parameter and use compare_parameters. Check for overload matches with and without artificial parameters. Skip artificial methods. (compare_parameters): New function. * value.h (value_aggregate_elt): Add new expect_type parameter. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 5cd6df921b7..1c8e2238908 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,23 @@ +2009-11-10 Keith Seitz + + * c-exp.y: Add new rule for resolving method overloads. + * eval.c (make_params): New function. + (free_param_types): New function. + (evaluate_subexp_standard): Pass expect_type to value_aggregate_elt. + Handle case TYPE_INSTANCE. + (evaluate_subexp_for_address): Pass expect_type to value_aggregate_elt. + * expression.h (enum exp_opcode): Add TYPE_INSTANCE. + (compare_parameters): Add declaration. + * parse.c (operator_length_standard): Add TYPE_INSTANCE. + * valops.c (value_aggregate_elt): Add new expect_type parameter. + Pass expect_type to value_struct_elt_for_reference. + (value_struct_elt_for_reference): Add expect_type parameter and use + compare_parameters. + Check for overload matches with and without artificial parameters. + Skip artificial methods. + (compare_parameters): New function. + * value.h (value_aggregate_elt): Add new expect_type parameter. + 2009-11-10 Joseph Myers * solib-svr4.c (enable_break): Call diff --git a/gdb/c-exp.y b/gdb/c-exp.y index 6d604c4253f..5dd47fb6da8 100644 --- a/gdb/c-exp.y +++ b/gdb/c-exp.y @@ -401,6 +401,18 @@ arglist : arglist ',' exp %prec ABOVE_COMMA { arglist_len++; } ; +exp : exp '(' nonempty_typelist ')' const_or_volatile + { int i; + write_exp_elt_opcode (TYPE_INSTANCE); + write_exp_elt_longcst ((LONGEST) $3[0]); + for (i = 0; i < $3[0]; ++i) + write_exp_elt_type ($3[i + 1]); + write_exp_elt_longcst((LONGEST) $3[0]); + write_exp_elt_opcode (TYPE_INSTANCE); + free ($3); + } + ; + rcurly : '}' { $$ = end_arglist () - 1; } ; diff --git a/gdb/eval.c b/gdb/eval.c index 2f6ded246ac..90ea2adcb2a 100644 --- a/gdb/eval.c +++ b/gdb/eval.c @@ -40,6 +40,8 @@ #include "regcache.h" #include "user-regs.h" #include "valprint.h" +#include "gdb_obstack.h" +#include "objfiles.h" #include "python/python.h" #include "gdb_assert.h" @@ -651,6 +653,29 @@ ptrmath_type_p (struct type *type) } } +/* Constructs a fake method with the given parameter types. + This function is used by the parser to construct an "expected" + type for method overload resolution. */ + +static struct type * +make_params (int num_types, struct type **param_types) +{ + struct type *type = XZALLOC (struct type); + TYPE_MAIN_TYPE (type) = XZALLOC (struct main_type); + TYPE_LENGTH (type) = 1; + TYPE_CODE (type) = TYPE_CODE_METHOD; + TYPE_VPTR_FIELDNO (type) = -1; + TYPE_CHAIN (type) = type; + TYPE_NFIELDS (type) = num_types; + TYPE_FIELDS (type) = (struct field *) + TYPE_ZALLOC (type, sizeof (struct field) * num_types); + + while (num_types-- > 0) + TYPE_FIELD_TYPE (type, num_types) = param_types[num_types]; + + return type; +} + struct value * evaluate_subexp_standard (struct type *expect_type, struct expression *exp, int *pos, @@ -684,7 +709,7 @@ evaluate_subexp_standard (struct type *expect_type, goto nosideret; arg1 = value_aggregate_elt (exp->elts[pc + 1].type, &exp->elts[pc + 3].string, - 0, noside); + expect_type, 0, noside); if (arg1 == NULL) error (_("There is no field named %s"), &exp->elts[pc + 3].string); return arg1; @@ -1730,6 +1755,20 @@ evaluate_subexp_standard (struct type *expect_type, error (_("non-pointer-to-member value used in pointer-to-member construct")); } + case TYPE_INSTANCE: + nargs = longest_to_int (exp->elts[pc + 1].longconst); + arg_types = (struct type **) alloca (nargs * sizeof (struct type *)); + for (ix = 0; ix < nargs; ++ix) + arg_types[ix] = exp->elts[pc + 1 + ix + 1].type; + + expect_type = make_params (nargs, arg_types); + *(pos) += 3 + nargs; + arg1 = evaluate_subexp_standard (expect_type, exp, pos, noside); + xfree (TYPE_FIELDS (expect_type)); + xfree (TYPE_MAIN_TYPE (expect_type)); + xfree (expect_type); + return arg1; + case BINOP_CONCAT: arg1 = evaluate_subexp_with_coercion (exp, pos, noside); arg2 = evaluate_subexp_with_coercion (exp, pos, noside); @@ -2612,7 +2651,7 @@ evaluate_subexp_for_address (struct expression *exp, int *pos, (*pos) += 5 + BYTES_TO_EXP_ELEM (tem + 1); x = value_aggregate_elt (exp->elts[pc + 1].type, &exp->elts[pc + 3].string, - 1, noside); + NULL, 1, noside); if (x == NULL) error (_("There is no field named %s"), &exp->elts[pc + 3].string); return x; diff --git a/gdb/expression.h b/gdb/expression.h index effe1f042ed..82b9367dd60 100644 --- a/gdb/expression.h +++ b/gdb/expression.h @@ -88,6 +88,13 @@ enum exp_opcode when X is a pointer instead of an aggregate. */ STRUCTOP_MPTR, + /* TYPE_INSTANCE is used when the user specifies a specific + type instantiation for overloaded methods/functions. + + The format is: + TYPE_INSTANCE num_types type0 ... typeN num_types TYPE_INSTANCE */ + TYPE_INSTANCE, + /* end of C++. */ /* For Modula-2 integer division DIV */ diff --git a/gdb/parse.c b/gdb/parse.c index ef938e37d8b..ef611462cc4 100644 --- a/gdb/parse.c +++ b/gdb/parse.c @@ -837,6 +837,11 @@ operator_length_standard (struct expression *expr, int endpos, args = 1 + longest_to_int (expr->elts[endpos - 2].longconst); break; + case TYPE_INSTANCE: + oplen = 4 + longest_to_int (expr->elts[endpos - 2].longconst); + args = 1; + break; + case OP_OBJC_MSGCALL: /* Objective C message (method) call */ oplen = 4; args = 1 + longest_to_int (expr->elts[endpos - 2].longconst); diff --git a/gdb/valops.c b/gdb/valops.c index 012ea6a4297..27716887746 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -2536,8 +2536,8 @@ check_field (struct type *type, const char *name) the comment before value_struct_elt_for_reference. */ struct value * -value_aggregate_elt (struct type *curtype, - char *name, int want_address, +value_aggregate_elt (struct type *curtype, char *name, + struct type *expect_type, int want_address, enum noside noside) { switch (TYPE_CODE (curtype)) @@ -2545,7 +2545,7 @@ value_aggregate_elt (struct type *curtype, case TYPE_CODE_STRUCT: case TYPE_CODE_UNION: return value_struct_elt_for_reference (curtype, 0, curtype, - name, NULL, + name, expect_type, want_address, noside); case TYPE_CODE_NAMESPACE: return value_namespace_elt (curtype, name, @@ -2556,6 +2556,57 @@ value_aggregate_elt (struct type *curtype, } } +/* Compares the two method/function types T1 and T2 for "equality" + with respect to the the methods' parameters. If the types of the + two parameter lists are the same, returns 1; 0 otherwise. This + comparison may ignore any artificial parameters in T1 if + SKIP_ARTIFICIAL is non-zero. This function will ALWAYS skip + the first artificial parameter in T1, assumed to be a 'this' pointer. + + The type T2 is expected to have come from make_params (in eval.c). */ + +static int +compare_parameters (struct type *t1, struct type *t2, int skip_artificial) +{ + int start = 0; + + if (TYPE_FIELD_ARTIFICIAL (t1, 0)) + ++start; + + /* If skipping artificial fields, find the first real field + in T1. */ + if (skip_artificial) + { + while (start < TYPE_NFIELDS (t1) + && TYPE_FIELD_ARTIFICIAL (t1, start)) + ++start; + } + + /* Now compare parameters */ + + /* Special case: a method taking void. T1 will contain no + non-artificial fields, and T2 will contain TYPE_CODE_VOID. */ + if ((TYPE_NFIELDS (t1) - start) == 0 && TYPE_NFIELDS (t2) == 1 + && TYPE_CODE (TYPE_FIELD_TYPE (t2, 0)) == TYPE_CODE_VOID) + return 1; + + if ((TYPE_NFIELDS (t1) - start) == TYPE_NFIELDS (t2)) + { + int i; + for (i = 0; i < TYPE_NFIELDS (t2); ++i) + { + if (rank_one_type (TYPE_FIELD_TYPE (t1, start + i), + TYPE_FIELD_TYPE (t2, i)) + != 0) + return 0; + } + + return 1; + } + + return 0; +} + /* C++: Given an aggregate type CURTYPE, and a member name NAME, return the address of this member as a "pointer to member" type. If INTYPE is non-null, then it will be the type of the member we @@ -2633,23 +2684,46 @@ value_struct_elt_for_reference (struct type *domain, int offset, } if (t_field_name && strcmp (t_field_name, name) == 0) { - int j = TYPE_FN_FIELDLIST_LENGTH (t, i); + int j; + int len = TYPE_FN_FIELDLIST_LENGTH (t, i); struct fn_field *f = TYPE_FN_FIELDLIST1 (t, i); check_stub_method_group (t, i); - if (intype == 0 && j > 1) - error (_("non-unique member `%s' requires type instantiation"), name); if (intype) { - while (j--) - if (TYPE_FN_FIELD_TYPE (f, j) == intype) - break; - if (j < 0) - error (_("no member function matches that type instantiation")); - } + for (j = 0; j < len; ++j) + { + if (compare_parameters (TYPE_FN_FIELD_TYPE (f, j), intype, 0) + || compare_parameters (TYPE_FN_FIELD_TYPE (f, j), intype, 1)) + break; + } + + if (j == len) + error (_("no member function matches that type instantiation")); } else - j = 0; + { + int ii; + /* Skip artificial methods. This is necessary if, for example, + the user wants to "print subclass::subclass" with only + one user-defined constructor. There is no ambiguity in this + case. */ + for (ii = 0; ii < TYPE_FN_FIELDLIST_LENGTH (t, i); + ++ii) + { + if (TYPE_FN_FIELD_ARTIFICIAL (f, ii)) + --len; + } + + /* Desired method is ambiguous if more than one method is + defined. */ + if (len > 1) + error (_("non-unique member `%s' requires type instantiation"), name); + + /* This assumes, of course, that all artificial methods appear + BEFORE any concrete methods. */ + j = TYPE_FN_FIELDLIST_LENGTH (t, i) - 1; + } if (TYPE_FN_FIELD_STATIC_P (f, j)) { diff --git a/gdb/value.h b/gdb/value.h index 51e6960ab81..993f05bd050 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -436,6 +436,7 @@ extern struct value *value_struct_elt (struct value **argp, extern struct value *value_aggregate_elt (struct type *curtype, char *name, + struct type *expect_type, int want_address, enum noside noside);