From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 18320 invoked by alias); 13 Mar 2009 19:58:39 -0000 Mailing-List: contact archer-help@sourceware.org; run by ezmlm Sender: Precedence: bulk List-Post: List-Help: List-Subscribe: List-Id: Received: (qmail 18309 invoked by uid 22791); 13 Mar 2009 19:58:37 -0000 X-SWARE-Spam-Status: No, hits=-0.4 required=5.0 tests=AWL,BAYES_00,J_CHICKENPOX_26,J_CHICKENPOX_31,J_CHICKENPOX_64,SARE_OBFU_PART_ING,SPF_HELO_PASS,SPF_PASS X-Spam-Check-By: sourceware.org Message-ID: <49BABABE.9080606@redhat.com> Date: Fri, 13 Mar 2009 19:58:00 -0000 From: Sami Wagiaalla User-Agent: Thunderbird 2.0.0.17 (X11/20081009) MIME-Version: 1.0 To: Project Archer Subject: [RFC] Koenig lookup patch Content-Type: multipart/mixed; boundary="------------090306080005060801080408" X-SW-Source: 2009-q1/txt/msg00381.txt.bz2 This is a multi-part message in MIME format. --------------090306080005060801080408 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 1628 Hi, I have attached the patch for koenig lookup. I would like to hear your thoughts on the approach. During lexing the if a name token cannot be looked up, the lexer returns an UNKNOWN_NAME token with the name of the potential symbol. If the parser sees an UNKNOWN_NAME token it creates a shell expression that looks like the one that would be created for a variable except it has a NULL where the symbol would normally be added, and the operator is OP_ADL_FUNCTION instead OP_VAR_VALUE. If UNKNOWN_NAME is followed by '(' 0 or more arguments and ')' a function call is created using the shell expression for symbol that was created. During evaluation when an OP_ADL_FUNCTION operator is encountered then expressions for the arguments are evaluated the prefixes of their types are collected then used to lookup the unknown name. The newly found symbol replaces the place holding NULL and the expression is evaluated as if it was a normal OP_VAR_VALUE. Overloads are resolved, and finally the result is used to perform the inferior function call. Here is a copy and paste demo: namespace A { class C { }; int foo(C arg) { return 11; } } struct X{ A::C theC; }; int main() { A::C theC; X x; foo(theC); foo(x.theC); } (gdb) break main Breakpoint 1 at 0x40056f: file koenig.c, line 20. (gdb) run Breakpoint 1, main () at koenig.c:20 20 foo(theC); Current language: auto; currently c++ (gdb) list 15 16 int main() 17 { 18 A::C theC; 19 X x; 20 foo(theC); 21 foo(x.theC); 22 } (gdb) print foo(theC) $1 = 11 (gdb) print foo(x.theC) $2 = 11 (gdb) Thanks, Sami --------------090306080005060801080408 Content-Type: text/plain; name="koenig.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="koenig.patch" Content-length: 8690 diff --git a/gdb/c-exp.y b/gdb/c-exp.y index 5123042..7b0b299 100644 --- a/gdb/c-exp.y +++ b/gdb/c-exp.y @@ -184,6 +184,7 @@ static int parse_number (char *, int, int, YYSTYPE *); %token STRING %token NAME /* BLOCKNAME defined below to give it higher precedence. */ +%token UNKNOWN_NAME %token COMPLETE %token TYPENAME %type name string_exp @@ -384,6 +385,30 @@ exp : exp '(' write_exp_elt_opcode (OP_FUNCALL); } ; +exp : adl_func '(' + /* This is to save the value of arglist_len + being accumulated by an outer function call. */ + { start_arglist (); } + arglist ')' %prec ARROW + { + + write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst ((LONGEST) end_arglist ()); + write_exp_elt_opcode (OP_FUNCALL); + } + ; + +adl_func : UNKNOWN_NAME + {/* This could potentially be a an argument dependet lookup function (koenig) */ + write_exp_elt_opcode (OP_ADL_FUNC); + write_exp_elt_block (expression_context_block); + write_exp_elt_sym (NULL); /* Place holder */ + write_exp_string ($1.stoken); + write_exp_elt_opcode (OP_ADL_FUNC); + } + ; + + lcurly : '{' { start_arglist (); } ; @@ -796,6 +821,7 @@ variable: name_not_typename ; space_identifier : '@' NAME + | '@' UNKNOWN_NAME { push_type_address_space (copy_name ($2.stoken)); push_type (tp_space_identifier); } @@ -1091,10 +1117,12 @@ name : NAME { $$ = $1.stoken; } | BLOCKNAME { $$ = $1.stoken; } | TYPENAME { $$ = $1.stoken; } | NAME_OR_INT { $$ = $1.stoken; } + | UNKNOWN_NAME { $$ = $1.stoken; } ; name_not_typename : NAME | BLOCKNAME + | UNKNOWN_NAME /* These would be useful if name_not_typename was useful, but it is just a fake for "variable", so these cause reduce/reduce conflicts because the parser can't tell whether NAME_OR_INT is a name_not_typename (=variable, @@ -2016,6 +2044,11 @@ yylex () if (in_parse_field && *lexptr == '\0') saw_name_at_eof = 1; + if (sym == NULL && !lookup_minimal_symbol (tmp, NULL, NULL) && !is_a_field_of_this) + { + return UNKNOWN_NAME; + } + return NAME; } } diff --git a/gdb/eval.c b/gdb/eval.c index 0262b35..3775321 100644 --- a/gdb/eval.c +++ b/gdb/eval.c @@ -672,6 +672,9 @@ evaluate_subexp_standard (struct type *expect_type, struct type **arg_types; int save_pos1; + static char** prefix_array = NULL; + static int prefix_array_size = 0; + pc = (*pos)++; op = exp->elts[pc].opcode; @@ -704,6 +707,57 @@ evaluate_subexp_standard (struct type *expect_type, return value_from_decfloat (exp->elts[pc + 1].type, exp->elts[pc + 2].decfloatconst); + case OP_ADL_FUNC: + { + char *func_name; + char *prefix; + char *concatenated_name; + struct symbol *sym = NULL; + int string_length; + int i = 0; + int string_pc = pc + 3; + + string_length = longest_to_int (exp->elts[string_pc].longconst); + + func_name = (char*) alloca(string_length+1); + strcpy (func_name, &exp->elts[string_pc + 1].string); + sym = exp->elts[pc + 2].symbol; + if (sym == NULL) + { /* Symbol has not been resolved yet. */ + for (i = 0; sym == NULL && i < prefix_array_size; i++) + { + prefix = prefix_array[i]; + concatenated_name = alloca (strlen (prefix) + 1 + strlen (func_name) + 1); + strcpy(concatenated_name, prefix); + strcat(concatenated_name, "::"); + strcat(concatenated_name, func_name); + + sym = lookup_symbol(concatenated_name, + exp->elts[pc + 1].block, VAR_DOMAIN, (int *) NULL); + + if (sym) + { + exp->elts[pc + 2].symbol = sym; + break; + } + } + + /* free prefix_array */ + for (i = 0; i < prefix_array_size; ++i) + { + xfree(prefix_array[i]); + } + xfree(prefix_array); + prefix_array = NULL; + prefix_array_size = 0; + } + + if (sym == NULL) + { + error("No function \"%s\" in specified context.", func_name); + } + } + /* Now fall through for normal symbol evaluation */ case OP_VAR_VALUE: (*pos) += 3; if (noside == EVAL_SKIP) @@ -1276,6 +1330,10 @@ evaluate_subexp_standard (struct type *expect_type, break; case OP_FUNCALL: + { + int adl_func_pos = 0; + int adl_func = 0; + (*pos) += 2; op = exp->elts[*pos].opcode; nargs = longest_to_int (exp->elts[pc + 1].longconst); @@ -1362,8 +1420,21 @@ evaluate_subexp_standard (struct type *expect_type, /* Now, say which argument to start evaluating from */ tem = 2; } - else + else if ( op == OP_ADL_FUNC ) { + int temp; + adl_func_pos = *pos; + tem = 1; + adl_func = 1; + + prefix_array = xzalloc (sizeof(char*) * nargs); + temp = longest_to_int (exp->elts[adl_func_pos + 3].longconst); + (*pos)++; // block + (*pos)++; // symbol + (*pos)++; // strlng + (*pos) += 3 + BYTES_TO_EXP_ELEM (temp + 1); // string + a null terminator + } + else{ /* Non-method function call */ save_pos1 = *pos; argvec[0] = evaluate_subexp_with_coercion (exp, pos, noside); @@ -1386,8 +1457,39 @@ evaluate_subexp_standard (struct type *expect_type, /* Evaluate arguments */ for (; tem <= nargs; tem++) { + /* Ensure that array expressions are coerced into pointer objects. */ argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside); + + if(adl_func) + { + /* save prefixes */ + char* cindex; + char* name; + + name = TYPE_NAME (value_type (argvec[tem])); + cindex = rindex(name, ':'); + if(cindex != NULL){ + prefix_array[prefix_array_size] = savestring(name, (int)(cindex - name) - 1); + prefix_array_size++; + } + } + + } + + if(adl_func){ + struct symbol *symp; + save_pos1 = adl_func_pos; + argvec[0] = evaluate_subexp_with_coercion (exp, &adl_func_pos, noside); + + (void) find_overload_match (argvec, nargs, NULL /* no need for name */ , + 0 /* not method */ , 0 /* strict match */ , + NULL, exp->elts[save_pos1+2].symbol /* the function */ , + NULL, &symp, NULL); + + /* Now fix the expression being evaluated */ + exp->elts[save_pos1+2].symbol = symp; + argvec[0] = evaluate_subexp_with_coercion (exp, &save_pos1, noside); } /* signal end of arglist */ @@ -1502,9 +1604,10 @@ evaluate_subexp_standard (struct type *expect_type, else error (_("Expression of type other than \"Function returning ...\" used as function")); } + return call_function_by_hand (argvec[0], nargs, argvec + 1); /* pai: FIXME save value from call_function_by_hand, then adjust pc by adjust_fn_pc if +ve */ - + } case OP_F77_UNDETERMINED_ARGLIST: /* Remember that in F77, functions, substring ops and diff --git a/gdb/expprint.c b/gdb/expprint.c index 89bae03..fd2e1ce 100644 --- a/gdb/expprint.c +++ b/gdb/expprint.c @@ -799,6 +799,8 @@ op_name_standard (enum exp_opcode opcode) return "OP_TYPE"; case OP_LABELED: return "OP_LABELED"; + case OP_ADL_FUNC: + return "OP_ADL_FUNC"; } } diff --git a/gdb/expression.h b/gdb/expression.h index 12163e3..ec8df4d 100644 --- a/gdb/expression.h +++ b/gdb/expression.h @@ -334,6 +334,10 @@ enum exp_opcode Then comes another OP_DECFLOAT. */ OP_DECFLOAT, + /* OP_ADL_FUNC specifies that the argument is to be looked up in an + Argument Dependent manner (keonig lookup) */ + OP_ADL_FUNC, + /* First extension operator. Individual language modules define extra operators they need as constants with values OP_LANGUAGE_SPECIFIC0 + k, for k >= 0, using a separate diff --git a/gdb/parse.c b/gdb/parse.c index eee1f8e..c6f1c9a 100644 --- a/gdb/parse.c +++ b/gdb/parse.c @@ -811,6 +811,13 @@ operator_length_standard (struct expression *expr, int endpos, args = 1; break; + case OP_ADL_FUNC: + oplen = longest_to_int (expr->elts[endpos - 2].longconst); + oplen = 4 + BYTES_TO_EXP_ELEM (oplen + 1); + oplen++; // block + oplen++; // symbol + break; + case OP_LABELED: case STRUCTOP_STRUCT: case STRUCTOP_PTR: --------------090306080005060801080408--