From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 8181 invoked by alias); 25 Sep 2003 00:27:34 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 8161 invoked from network); 25 Sep 2003 00:27:31 -0000 Received: from unknown (HELO hawaii.kealia.com) (209.3.10.89) by sources.redhat.com with SMTP; 25 Sep 2003 00:27:31 -0000 Received: by hawaii.kealia.com (Postfix, from userid 2049) id 67ECECB30; Wed, 24 Sep 2003 17:27:31 -0700 (PDT) To: gdb-patches@sources.redhat.com Cc: Daniel Jacobowitz Subject: [rfa] teach parser about C++ nested types From: David Carlton Date: Thu, 25 Sep 2003 00:27:00 -0000 Message-ID: User-Agent: Gnus/5.1002 (Gnus v5.10.2) XEmacs/21.4 (Rational FORTRAN, linux) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-SW-Source: 2003-09/txt/msg00546.txt.bz2 A recap of the state of C++: our main goal is to embrace nested types. So if you have a type (a class, a namespace, a typedef, whatever) D defined within a class or namespace C, then the symbol associated to that type should be called C::D, and our parsers, evaluators, etc. should be happy about that. The current state of affairs is: right now we only generate symbols with the right names if both C and D are namespaces, and the parsers, etc. are fairly ignorant of the situation. So we have two issues to deal with: 1) Generate all the symbols correctly. 2) Tell the parsers, etc. to use them. This patch implements some of issue 2. This seems to be the correct order: if we finish implementing issue 1 before doing any of issue 2, probably the parser will get really confused, but fortunately the fact that we've done just a bit of issue 1 (namely nested namespaces) means that, if we implement issue 2 now, we can test it. Specifically, what this patch does is: * Move parsing of names containing '::' completely out of the lexer, so it's all in the parser. As I comment in the code, this is a lesser-of-two-evils choice; I've tried working on the lexer instead, and it just didn't work as well. * Tell eval.c that, when it encounters an OP_SCOPE, to call a new function value_aggregate_elt instead of value_struct_elt_for_reference. * Teach value_aggregate_elt about namespaces. Some of this code will need to be slightly tweaked when we start generating appropriately-named symbols for other nested types; this gets the infrastructure in place, however. More details available on request. When reading through the code, be alert for possible coding style mistakes I might have made: it's been a few months since I've been immersed in GDB's house style, so I might well have spaces in the wrong place or something. (Fortunately, most of this code is cut and pasted from my branch, and was originally written when I was immersed in GDB's house style.) Tested on i686-pc-linux-gnu, GCC 3.2, with DWARF 2, with a version patched to generate DW_TAG_namespace, and with stabs. In no cases were there any regressions; in both DWARF 2 cases, all the new tests pass, while in the stabs case, all the new tests fail (which is expected). Ok to commit? I think I only need approval from Daniel for this one; it doesn't touch symtab stuff at all. David Carlton carlton@kealia.com 2003-09-24 David Carlton * c-exp.y: Include cp-support.h. Add qualified_type. (yylex): Comment out nested type hack; add comments. * cp-namespace.c (cp_lookup_nested_type): New function. * cp-support.h: Declare cp_lookup_nested_type. * eval.c (evaluate_subexp_standard): Call value_aggregate_elt instead of value_struct_elt_for_reference. * valops.c: Include cp-support.h. (value_aggregate_elt): New function. (value_namespace_elt): Ditto. (value_struct_elt_for_reference): Make static. * value.h: Delete declaration of value_struct_elt_for_reference; add declaration for value_aggregate_elt. * Makefile.in (c-exp.tab.o): Depend on $(cp_support_h). (valops.o): Ditto. 2003-09-24 David Carlton * gdb.cp/namespace.exp: Tweak comments. Add non-quoted versions of some print tests, where appropriate. Add tests for C::D::cd, E::ce, F::cXfX, G::XgX. * gdb.cp/namespace.cc: Add XgX, cXfX, ce. Index: Makefile.in =================================================================== RCS file: /cvs/src/src/gdb/Makefile.in,v retrieving revision 1.445 diff -u -p -r1.445 Makefile.in --- Makefile.in 17 Sep 2003 21:34:29 -0000 1.445 +++ Makefile.in 24 Sep 2003 23:38:31 -0000 @@ -1412,7 +1412,7 @@ ada-lex.c: ada-lex.l .PRECIOUS: c-exp.tab.c c-exp.tab.o: c-exp.tab.c $(defs_h) $(gdb_string_h) $(expression_h) \ $(value_h) $(parser_defs_h) $(language_h) $(c_lang_h) $(bfd_h) \ - $(symfile_h) $(objfiles_h) $(charset_h) $(block_h) + $(symfile_h) $(objfiles_h) $(charset_h) $(block_h) $(cp_support_h) c-exp.tab.c: c-exp.y $(SHELL) $(YLWRAP) "$(YACC)" \ $(srcdir)/c-exp.y y.tab.c c-exp.tmp -- $(YFLAGS) @@ -2417,7 +2417,8 @@ valarith.o: valarith.c $(defs_h) $(value valops.o: valops.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(value_h) $(frame_h) \ $(inferior_h) $(gdbcore_h) $(target_h) $(demangle_h) $(language_h) \ $(gdbcmd_h) $(regcache_h) $(cp_abi_h) $(block_h) $(infcall_h) \ - $(dictionary_h) $(cp_support_h) $(gdb_string_h) $(gdb_assert_h) + $(dictionary_h) $(cp_support_h) $(gdb_string_h) $(gdb_assert_h) \ + $(cp_support_h) valprint.o: valprint.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \ $(value_h) $(gdbcore_h) $(gdbcmd_h) $(target_h) $(language_h) \ $(annotate_h) $(valprint_h) $(floatformat_h) $(doublest_h) Index: c-exp.y =================================================================== RCS file: /cvs/src/src/gdb/c-exp.y,v retrieving revision 1.21 diff -u -p -r1.21 c-exp.y --- c-exp.y 18 May 2003 17:39:45 -0000 1.21 +++ c-exp.y 24 Sep 2003 23:38:31 -0000 @@ -51,6 +51,7 @@ Foundation, Inc., 59 Temple Place - Suit #include "objfiles.h" /* For have_full_symbols and have_partial_symbols */ #include "charset.h" #include "block.h" +#include "cp-support.h" /* Flag indicating we're dealing with HP-compiled objects */ extern int hp_som_som_object_present; @@ -153,7 +154,7 @@ static int parse_number (char *, int, in %type exp exp1 type_exp start variable qualified_name lcurly %type rcurly -%type type typebase +%type type typebase qualified_type %type nonempty_typelist /* %type block */ @@ -595,7 +596,8 @@ qualified_name: typebase COLONCOLON name { struct type *type = $1; if (TYPE_CODE (type) != TYPE_CODE_STRUCT - && TYPE_CODE (type) != TYPE_CODE_UNION) + && TYPE_CODE (type) != TYPE_CODE_UNION + && TYPE_CODE (type) != TYPE_CODE_NAMESPACE) error ("`%s' is not defined as an aggregate type.", TYPE_NAME (type)); @@ -609,7 +611,8 @@ qualified_name: typebase COLONCOLON name struct type *type = $1; struct stoken tmp_token; if (TYPE_CODE (type) != TYPE_CODE_STRUCT - && TYPE_CODE (type) != TYPE_CODE_UNION) + && TYPE_CODE (type) != TYPE_CODE_UNION + && TYPE_CODE (type) != TYPE_CODE_NAMESPACE) error ("`%s' is not defined as an aggregate type.", TYPE_NAME (type)); @@ -888,6 +891,54 @@ typebase /* Implements (approximately): { $$ = follow_types ($2); } | typebase const_or_volatile_or_space_identifier_noopt { $$ = follow_types ($1); } + | qualified_type + ; + +/* FIXME: carlton/2003-09-24: This next bit leads to lots of + reduce-reduce conflicts, because the parser doesn't know whether or + not to use qualified_name or qualified_type. There's no good way + to fix this with the grammar as it stands; as far as I can tell, + some of the problems arise from ambiguities that GDB introduces + ('start' can be either an expression or a type), but some of it is + inherent to the nature of C++ (you want to treat the input "(FOO)" + fairly differently depending on whether FOO is an expression or a + type, and if FOO is a complex expression, this can be hard to + determine at the right time. + + Perhaps we could fix this by making the lexer smarter. Some of + this functionality used to be in the lexer, but in a way that + worked even less well than the current solution: life is much + easier if either the parser always handles '::' or the lexer always + handles it. Ideally, the code in question could be shared by the + lexer and by decode_line_1. I'm not holding my breath waiting for + somebody to get around to cleaning this up, however... */ + +/* FIXME: carlton/2003-09-24: Currently, the only qualified type + symbols that we generate are nested namespaces. Next on my TODO + list is to generate all nested type names properly (or at least as + well as possible, assuming that we're using DWARF-2). */ + +qualified_type: typebase COLONCOLON name + { + struct type *type = $1; + struct type *new_type; + char *ncopy = alloca ($3.length + 1); + + memcpy (ncopy, $3.ptr, $3.length); + ncopy[$3.length] = '\0'; + + if (TYPE_CODE (type) != TYPE_CODE_NAMESPACE) + error ("`%s' is not defined as a namespace.", + TYPE_NAME (type)); + + new_type = cp_lookup_nested_type (type, ncopy, + expression_context_block); + if (new_type == NULL) + error ("No type \"%s\" in namespace \"%s\".", + ncopy, TYPE_NAME (type)); + + $$ = new_type; + } ; typename: TYPENAME @@ -1633,7 +1684,13 @@ yylex () string to get a reasonable class/namespace spec or a fully-qualified name. This is a kludge to get around the HP aCC compiler's generation of symbol names with embedded - colons for namespace and nested classes. */ + colons for namespace and nested classes. */ + + /* NOTE: carlton/2003-09-24: I don't entirely understand the + HP-specific code, either here or in linespec. Having said that, + I suspect that we're actually moving towards their model: we want + symbols whose names are fully qualified, which matches the + description above. */ if (unquoted_expr) { /* Only do it if not inside single quotes */ @@ -1687,7 +1744,16 @@ yylex () if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF) { -#if 1 + /* FIXME: carlton/2003-09-24: I've turned off the code + below, because it seems to me to work better to deal with + nested types in the parser instead of the lexer. See the + comment before qualified_type for more info. If you're + interested in figuring out the code below, be aware that + it dates from a time when we handled nested types very + differently than we do now, and I don't believe the + comments within it had been entirely accurate for a + while. */ +#if 0 /* Despite the following flaw, we need to keep this code enabled. Because we can get called from check_stub_method, if we don't handle nested types then it screws many operations in any Index: cp-namespace.c =================================================================== RCS file: /cvs/src/src/gdb/cp-namespace.c,v retrieving revision 1.4 diff -u -p -r1.4 cp-namespace.c --- cp-namespace.c 11 Sep 2003 19:49:17 -0000 1.4 +++ cp-namespace.c 24 Sep 2003 23:38:31 -0000 @@ -508,6 +508,41 @@ lookup_symbol_file (const char *name, return NULL; } +/* Look up a type named NESTED_NAME that is nested inside the C++ + class or namespace given by PARENT_TYPE, from within the context + given by BLOCK. Return NULL if there is no such nested type. */ + +/* FIXME: carlton/2003-09-24: For now, this only works for nested + namespaces; the patch to make this work on other sorts of nested + types is next on my TODO list. */ + +struct type * +cp_lookup_nested_type (struct type *parent_type, + const char *nested_name, + const struct block *block) +{ + switch (TYPE_CODE (parent_type)) + { + case TYPE_CODE_NAMESPACE: + { + const char *parent_name = TYPE_TAG_NAME (parent_type); + struct symbol *sym = cp_lookup_symbol_namespace (parent_name, + nested_name, + NULL, + block, + VAR_DOMAIN, + NULL); + if (sym == NULL || SYMBOL_CLASS (sym) != LOC_TYPEDEF) + return NULL; + else + return SYMBOL_TYPE (sym); + } + default: + internal_error (__FILE__, __LINE__, + "cp_lookup_nested_type called on a non-namespace."); + } +} + /* Now come functions for dealing with symbols associated to namespaces. (They're used to store the namespaces themselves, not objects that live in the namespaces.) These symbols come in two Index: cp-support.h =================================================================== RCS file: /cvs/src/src/gdb/cp-support.h,v retrieving revision 1.8 diff -u -p -r1.8 cp-support.h --- cp-support.h 14 Sep 2003 02:04:44 -0000 1.8 +++ cp-support.h 24 Sep 2003 23:38:31 -0000 @@ -97,6 +97,10 @@ extern struct symbol *cp_lookup_symbol_n const domain_enum domain, struct symtab **symtab); +extern struct type *cp_lookup_nested_type (struct type *parent_type, + const char *nested_name, + const struct block *block); + extern void cp_check_possible_namespace_symbols (const char *name, struct objfile *objfile); Index: eval.c =================================================================== RCS file: /cvs/src/src/gdb/eval.c,v retrieving revision 1.36 diff -u -p -r1.36 eval.c --- eval.c 16 Sep 2003 18:56:35 -0000 1.36 +++ eval.c 24 Sep 2003 23:38:31 -0000 @@ -406,11 +406,9 @@ evaluate_subexp_standard (struct type *e case OP_SCOPE: tem = longest_to_int (exp->elts[pc + 2].longconst); (*pos) += 4 + BYTES_TO_EXP_ELEM (tem + 1); - arg1 = value_struct_elt_for_reference (exp->elts[pc + 1].type, - 0, - exp->elts[pc + 1].type, - &exp->elts[pc + 3].string, - NULL_TYPE); + arg1 = value_aggregate_elt (exp->elts[pc + 1].type, + &exp->elts[pc + 3].string, + noside); if (arg1 == NULL) error ("There is no field named %s", &exp->elts[pc + 3].string); return arg1; Index: valops.c =================================================================== RCS file: /cvs/src/src/gdb/valops.c,v retrieving revision 1.115 diff -u -p -r1.115 valops.c --- valops.c 16 Sep 2003 18:56:35 -0000 1.115 +++ valops.c 24 Sep 2003 23:38:31 -0000 @@ -41,6 +41,7 @@ #include #include "gdb_string.h" #include "gdb_assert.h" +#include "cp-support.h" /* Flag indicating HP compilers were used; needed to correctly handle some value operations with HP aCC code/runtime. */ @@ -63,6 +64,17 @@ static struct value *search_struct_metho static int check_field_in (struct type *, const char *); + +static struct value *value_struct_elt_for_reference (struct type *domain, + int offset, + struct type *curtype, + char *name, + struct type *intype); + +static struct value *value_namespace_elt (const struct type *curtype, + const char *name, + enum noside noside); + static CORE_ADDR allocate_space_in_inferior (int); static struct value *cast_into_complex (struct type *, struct value *); @@ -2208,6 +2220,29 @@ check_field (struct value *arg1, const c } /* C++: Given an aggregate type CURTYPE, and a member name NAME, + return the appropriate member. This function is used to resolve + user expressions of the form "DOMAIN::NAME". For more details on + what happens, see the comment before + value_struct_elt_for_reference. */ + +struct value * +value_aggregate_elt (struct type *curtype, + char *name, + enum noside noside) +{ + switch (TYPE_CODE (curtype)) + { + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + return value_struct_elt_for_reference (curtype, 0, curtype, name, NULL); + case TYPE_CODE_NAMESPACE: + return value_namespace_elt (curtype, name, noside); + default: + error ("Internal error: non-aggregate type in value_aggregate_elt"); + } +} + +/* 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 are looking for. This will help us resolve @@ -2345,6 +2380,37 @@ value_struct_elt_for_reference (struct t return v; } return 0; +} + +/* C++: Return the member NAME of the namespace given by the type + CURTYPE. */ + +static struct value * +value_namespace_elt (const struct type *curtype, + const char *name, + enum noside noside) +{ + const char *namespace_name = TYPE_TAG_NAME (curtype); + struct symbol *sym; + struct value *retval; + + sym = cp_lookup_symbol_namespace (namespace_name, name, NULL, + get_selected_block (0), VAR_DOMAIN, + NULL); + + if (sym == NULL) + retval = NULL; + else if ((noside == EVAL_AVOID_SIDE_EFFECTS) + && (SYMBOL_CLASS (sym) == LOC_TYPEDEF)) + retval = allocate_value (SYMBOL_TYPE (sym)); + else + retval = value_of_variable (sym, get_selected_block (0)); + + if (retval == NULL) + error ("No symbol \"%s\" in namespace \"%s\".", name, + TYPE_TAG_NAME (curtype)); + + return retval; } Index: value.h =================================================================== RCS file: /cvs/src/src/gdb/value.h,v retrieving revision 1.51 diff -u -p -r1.51 value.h --- value.h 13 Sep 2003 21:31:33 -0000 1.51 +++ value.h 24 Sep 2003 23:38:31 -0000 @@ -379,11 +379,9 @@ extern struct value *value_struct_elt (s char *name, int *static_memfuncp, char *err); -extern struct value *value_struct_elt_for_reference (struct type *domain, - int offset, - struct type *curtype, - char *name, - struct type *intype); +extern struct value *value_aggregate_elt (struct type *curtype, + char *name, + enum noside noside); extern struct value *value_static_field (struct type *type, int fieldno); Index: testsuite/gdb.cp/namespace.cc =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.cp/namespace.cc,v retrieving revision 1.1 diff -u -p -r1.1 namespace.cc --- testsuite/gdb.cp/namespace.cc 23 Aug 2003 03:55:59 -0000 1.1 +++ testsuite/gdb.cp/namespace.cc 24 Sep 2003 23:38:31 -0000 @@ -75,6 +75,11 @@ namespace namespace G { int Xg = 10; + + namespace + { + int XgX = 11; + } } } @@ -90,6 +95,11 @@ namespace C namespace F { int cXf = 7; + + namespace + { + int cXfX = 8; + } } } @@ -98,6 +108,11 @@ namespace C int cc = 2; } + namespace E + { + int ce = 4; + } + namespace D { int cd = 3; @@ -118,14 +133,18 @@ namespace C //cc; C::cc; cd; + //C::D::cd; E::cde; shadow; + //E::ce; cX; F::cXf; + F::cXfX; X; G::Xg; //cXOtherFile; //XOtherFile; + G::XgX; return; } Index: testsuite/gdb.cp/namespace.exp =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.cp/namespace.exp,v retrieving revision 1.2 diff -u -p -r1.2 namespace.exp --- testsuite/gdb.cp/namespace.exp 11 Sep 2003 19:49:20 -0000 1.2 +++ testsuite/gdb.cp/namespace.exp 24 Sep 2003 23:38:31 -0000 @@ -18,11 +18,11 @@ # bug-gdb@prep.ai.mit.edu # tests for namespaces -# Written by Satish Pai 1997-07-23 +# Originally written by Satish Pai 1997-07-23 # This file is part of the gdb testsuite -# Note: These tests are geared to the HP aCC compiler, +# Note: The original tests were geared to the HP aCC compiler, # which has an idiosyncratic way of emitting debug info # for namespaces. # Note: As of 2000-06-03, these pass under g++ - djb @@ -84,6 +84,11 @@ gdb_test "up" ".*main.*" "up from marker # Access a data item inside a namespace using colons and # single quotes :-( +# NOTE: carlton/2003-09-24: the quotes are becoming less necessary (or +# even desirable.) For tests where it should still work with quotes, +# I'm including versions both with and without quotes; for tests that +# shouldn't work with quotes, I'm only including one version. + send_gdb "print 'AAA::c'\n" gdb_expect { -re "\\$\[0-9\]* = 0 '\\\\(0|000)'\r\n$gdb_prompt $" { pass "print 'AAA::c'" } @@ -91,6 +96,13 @@ gdb_expect { timeout { fail "(timeout) print 'AAA::c'" } } +send_gdb "print AAA::c\n" +gdb_expect { + -re "\\$\[0-9\]* = 0 '\\\\(0|000)'\r\n$gdb_prompt $" { pass "print AAA::c" } + -re ".*$gdb_prompt $" { fail "print AAA::c" } + timeout { fail "(timeout) print AAA::c" } +} + # An object declared using "using". send_gdb "print ina\n" @@ -137,6 +149,15 @@ gdb_expect { timeout { fail "(timeout) print 'AAA::xyzq'('x')" } } +send_gdb "print AAA::xyzq('x')\n" +gdb_expect { + -re "\\$\[0-9\]* = 97 'a'\r\n$gdb_prompt $" { + pass "print AAA::xyzq('x')" + } + -re ".*$gdb_prompt $" { fail "print AAA::xyzq('x')" } + timeout { fail "(timeout) print AAA::xyzq('x')" } +} + # Break on a function in a namespace send_gdb "break AAA::xyzq\n" @@ -159,6 +180,15 @@ gdb_expect { timeout { fail "(timeout) print 'BBB::CCC::xyzq'('x')" } } +send_gdb "print BBB::CCC::xyzq('x')\n" +gdb_expect { + -re "\\$\[0-9\]* = 122 'z'\r\n$gdb_prompt $" { + pass "print BBB::CCC::xyzq('x')" + } + -re ".*$gdb_prompt $" { fail "print BBB::CCC::xyzq('x')" } + timeout { fail "(timeout) print BBB::CCC::xyzq('x')" } +} + # Break on a function in a nested namespace send_gdb "break BBB::CCC::xyzq\n" @@ -204,9 +234,13 @@ if ![runto "C::D::marker2"] then { gdb_test "print c" "\\$\[0-9\].* = 1" gdb_test "print cc" "No symbol \"cc\" in current context." gdb_test "print 'C::cc'" "\\$\[0-9\].* = 2" +gdb_test "print C::cc" "\\$\[0-9\].* = 2" gdb_test "print cd" "\\$\[0-9\].* = 3" +gdb_test "print C::D::cd" "No type \"D\" in namespace \"C::C\"." gdb_test "print 'E::cde'" "\\$\[0-9\].* = 5" +gdb_test "print E::cde" "\\$\[0-9\].* = 5" gdb_test "print shadow" "\\$\[0-9\].* = 13" +gdb_test "print E::ce" "No symbol \"ce\" in namespace \"C::D::E\"." gdb_test "print cOtherFile" "\\$\[0-9\].* = 316" gdb_test "ptype C" "type = namespace C::C" gdb_test "ptype E" "type = namespace C::D::E" @@ -215,7 +249,11 @@ gdb_test "ptype E" "type = namespace C:: gdb_test "print cX" "\\$\[0-9\].* = 6" gdb_test "print 'F::cXf'" "\\$\[0-9\].* = 7" +gdb_test "print F::cXf" "\\$\[0-9\].* = 7" +gdb_test "print F::cXfX" "\\$\[0-9\].* = 8" gdb_test "print X" "\\$\[0-9\].* = 9" gdb_test "print 'G::Xg'" "\\$\[0-9\].* = 10" +gdb_test "print G::Xg" "\\$\[0-9\].* = 10" +gdb_test "print G::XgX" "\\$\[0-9\].* = 11" gdb_test "print cXOtherFile" "No symbol \"cXOtherFile\" in current context." gdb_test "print XOtherFile" "No symbol \"XOtherFile\" in current context."