From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 15412 invoked by alias); 1 Sep 2009 18:06:16 -0000 Received: (qmail 15400 invoked by uid 22791); 1 Sep 2009 18:06:14 -0000 X-SWARE-Spam-Status: No, hits=-2.3 required=5.0 tests=AWL,BAYES_00,J_CHICKENPOX_83,SPF_HELO_PASS,SPF_PASS X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 01 Sep 2009 18:06:08 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id n81I66dm021205 for ; Tue, 1 Sep 2009 14:06:06 -0400 Received: from [IPv6:::1] (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id n81I63BZ014277 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Tue, 1 Sep 2009 14:06:05 -0400 Message-ID: <4A9D628B.1070300@redhat.com> Date: Tue, 01 Sep 2009 18:06:00 -0000 From: Keith Seitz User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.1) Gecko/20090814 Fedora/3.0-2.6.b3.fc11 Lightning/1.0pre Thunderbird/3.0b3 MIME-Version: 1.0 To: gdb-patches@sourceware.org Subject: [RFA] Add method overload resolution to expression parser Content-Type: multipart/mixed; boundary="------------000702030006090901060809" X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2009-09/txt/msg00026.txt.bz2 This is a multi-part message in MIME format. --------------000702030006090901060809 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 1712 Hi, The attached patch is the first of several patches which will attempt mitigate the requirement of single-quoting every single C++ expression passed to the parser. This patch specifically adds method overload resolution into parser, so now gdb correctly understands "print foo::flubber(int)". I've added a few basic tests to gdb.cp/overload.exp, but when this series of patches is nearing completion, I will submit my archer "realcpp" tests, which are far more thorough (and currently causes gdb to crash a lot). Tested regression-free on x86 linux. Keith ChangeLog 2009-09-01 Keith Seitz * c-exp.y: Add new rule for resolving method overloads. Add cleanups for nonempty_typelist. Changed all users. * 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. testsuite/ChangeLog 2009-09-01 Keith Seitz * gdb.cp/overload.exp: Add tests for resolving overloaded methods in expression parsing/evaluation. --------------000702030006090901060809 Content-Type: text/plain; name="ovld-expr.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="ovld-expr.patch" Content-length: 12519 Index: c-exp.y =================================================================== RCS file: /cvs/src/src/gdb/c-exp.y,v retrieving revision 1.61 diff -u -p -r1.61 c-exp.y --- c-exp.y 25 Aug 2009 18:40:45 -0000 1.61 +++ c-exp.y 1 Sep 2009 17:41:25 -0000 @@ -117,6 +117,8 @@ static int yylex (void); void yyerror (char *); +/* Cleanup for 'nonempty_typelist' */ +static struct cleanup *typelist_cleanup; %} /* Although the yacc "value" of an expression is not used, @@ -401,6 +403,18 @@ arglist : arglist ',' exp %prec ABOVE_ { 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); + do_cleanups (typelist_cleanup); + } + ; + rcurly : '}' { $$ = end_arglist () - 1; } ; @@ -883,7 +897,7 @@ array_mod: '[' ']' func_mod: '(' ')' { $$ = 0; } | '(' nonempty_typelist ')' - { free ($2); $$ = 0; } + { do_cleanups (typelist_cleanup); $$ = 0; } ; /* We used to try to recognize pointer to member types here, but @@ -1088,12 +1102,15 @@ typename: TYPENAME nonempty_typelist : type { $$ = (struct type **) malloc (sizeof (struct type *) * 2); + typelist_cleanup = make_cleanup (free, $$); $$[0] = 1; /* Number of types in vector */ $$[1] = $1; } | nonempty_typelist ',' type { int len = sizeof (struct type *) * (++($1[0]) + 1); $$ = (struct type **) realloc ((char *) $1, len); + discard_cleanups (typelist_cleanup); + typelist_cleanup = make_cleanup (free, $$); $$[$$[0]] = $3; } ; Index: eval.c =================================================================== RCS file: /cvs/src/src/gdb/eval.c,v retrieving revision 1.119 diff -u -p -r1.119 eval.c --- eval.c 2 Jul 2009 17:04:22 -0000 1.119 +++ eval.c 1 Sep 2009 17:41:25 -0000 @@ -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,39 @@ ptrmath_type_p (struct type *type) } } +static void +free_param_types (void *arg) +{ + struct type *type = (struct type *) arg; + xfree (TYPE_FIELDS (type)); + xfree (TYPE_MAIN_TYPE (type)); + xfree (type); +} + +/* Constructs a fake method with the given parameter types. This is + used to do overload resolution by the expression parser. The + logical counterpart is compare_parameters in valops.c. */ + +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]; + + make_cleanup (free_param_types, type); + return type; +} + struct value * evaluate_subexp_standard (struct type *expect_type, struct expression *exp, int *pos, @@ -684,7 +719,7 @@ evaluate_subexp_standard (struct type *e 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; @@ -1709,6 +1744,16 @@ evaluate_subexp_standard (struct type *e 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; + return evaluate_subexp_standard (expect_type, exp, pos, noside); + case BINOP_CONCAT: arg1 = evaluate_subexp_with_coercion (exp, pos, noside); arg2 = evaluate_subexp_with_coercion (exp, pos, noside); @@ -2591,7 +2636,7 @@ evaluate_subexp_for_address (struct expr (*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; Index: expression.h =================================================================== RCS file: /cvs/src/src/gdb/expression.h,v retrieving revision 1.30 diff -u -p -r1.30 expression.h --- expression.h 3 Jan 2009 05:57:51 -0000 1.30 +++ expression.h 1 Sep 2009 17:41:25 -0000 @@ -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 */ Index: parse.c =================================================================== RCS file: /cvs/src/src/gdb/parse.c,v retrieving revision 1.90 diff -u -p -r1.90 parse.c --- parse.c 2 Jul 2009 17:02:34 -0000 1.90 +++ parse.c 1 Sep 2009 17:41:25 -0000 @@ -837,6 +837,11 @@ operator_length_standard (struct express 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); Index: valops.c =================================================================== RCS file: /cvs/src/src/gdb/valops.c,v retrieving revision 1.225 diff -u -p -r1.225 valops.c --- valops.c 31 Aug 2009 20:18:45 -0000 1.225 +++ valops.c 1 Sep 2009 17:41:26 -0000 @@ -2534,8 +2534,8 @@ check_field (struct type *type, const ch 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)) @@ -2543,7 +2543,7 @@ value_aggregate_elt (struct type *curtyp 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, @@ -2554,6 +2554,57 @@ value_aggregate_elt (struct type *curtyp } } +/* 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 @@ -2631,23 +2682,46 @@ value_struct_elt_for_reference (struct t } 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)) { Index: value.h =================================================================== RCS file: /cvs/src/src/gdb/value.h,v retrieving revision 1.149 diff -u -p -r1.149 value.h --- value.h 31 Aug 2009 20:18:45 -0000 1.149 +++ value.h 1 Sep 2009 17:41:26 -0000 @@ -436,6 +436,7 @@ extern struct value *value_struct_elt (s extern struct value *value_aggregate_elt (struct type *curtype, char *name, + struct type *expect_type, int want_address, enum noside noside); Index: testsuite/gdb.cp/overload.exp =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.cp/overload.exp,v retrieving revision 1.11 diff -u -p -r1.11 overload.exp --- testsuite/gdb.cp/overload.exp 3 Jan 2009 05:58:04 -0000 1.11 +++ testsuite/gdb.cp/overload.exp 1 Sep 2009 17:41:26 -0000 @@ -312,3 +312,24 @@ gdb_test "print overloadNamespace(dummyI # I wonder what this is for? gdb_test "print intToChar(1)" "\\$\[0-9\]+ = 297" + +# Test expression evaluation with overloaded methods +gdb_test "print foo::overload1arg" \ + "non-unique member `overload1arg' requires type instantiation" \ + "print foo::overload1arg" + +gdb_test "print foo::overload1arg(char***)" \ + "no member function matches that type instantiation" \ + "print foo::overload1arg(char***)" + +gdb_test "print foo::overload1arg(void)" \ + "\\$$decimal = {int \\(foo \\* const\\)} $hex " \ + "print foo::overload1arg(void)" + +foreach t [list char "signed char" "unsigned char" "short" \ + "unsigned short" int "unsigned int" long "unsigned long" \ + float double] { + gdb_test "print foo::overload1arg($t)" \ + "\\$$decimal = {int \\(foo \\* const, $t\\)} $hex " \ + "print foo::overload1arg($t)" +} --------------000702030006090901060809--