* [rfa] teach parser about C++ nested types
@ 2003-09-25 0:27 David Carlton
2003-09-25 15:49 ` Daniel Jacobowitz
0 siblings, 1 reply; 4+ messages in thread
From: David Carlton @ 2003-09-25 0:27 UTC (permalink / raw)
To: gdb-patches; +Cc: Daniel Jacobowitz
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 <carlton@kealia.com>
* 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 <carlton@kealia.com>
* 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 <voidval> exp exp1 type_exp start variable qualified_name lcurly
%type <lval> rcurly
-%type <tval> type typebase
+%type <tval> type typebase qualified_type
%type <tvec> nonempty_typelist
/* %type <bval> 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 <errno.h>
#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 <pai@apollo.hp.com> 1997-07-23
+# Originally written by Satish Pai <pai@apollo.hp.com> 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."
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [rfa] teach parser about C++ nested types
2003-09-25 0:27 [rfa] teach parser about C++ nested types David Carlton
@ 2003-09-25 15:49 ` Daniel Jacobowitz
2003-09-25 16:02 ` David Carlton
0 siblings, 1 reply; 4+ messages in thread
From: Daniel Jacobowitz @ 2003-09-25 15:49 UTC (permalink / raw)
To: David Carlton; +Cc: gdb-patches
On Wed, Sep 24, 2003 at 05:27:31PM -0700, David Carlton wrote:
> 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.
For content, it's mostly fine. My only concern is about the
reduce-reduce conflicts. How can this work without breaking one of the
existing path or the new path?
From the bison manual:
Bison resolves a reduce/reduce conflict by choosing to use the rule
that appears first in the grammar, but it is very risky to rely on
this.
It took me quite a while to work out why this works at all, so a
comment, please. The reason it works (roughly; please don't point out
flaws in my grasp of parsing, which I know is shaky :) is that we don't
know whether we want a qualified name or a qualified type, so we choose
a qualified name per the rule above. Then to the left of the final
colon we know we need a type so we choose qualified_type. But for the
first item, qualified_type or qualified_name should work.
I'm uncomfortable about how AAA::inA and the AAA::inA portion of
AAA::inA::fum get parsed differently.
I wonder if sharing the parser with GCC some day is workable... without
being a maintenance problem for GCC. It seems dubious and the reaction
when I suggested it involved a lot of sniggering. Maybe at first
forking said parser.
[One reason I'd like to do this is to parse statements. Which puts us
on extremely shaky ground. But macros can expand to gcc
statement-expressions, and it would be really, really cool to be able
to handle that.]
For style, two small problems:
> @@ -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
I'm a big deleter-of-code. What about leaving a comment here and
getting rid of the old code? It's not like we'll want it back.
Something mentioning how qualified names used to be handled here.
> + default:
> + error ("Internal error: non-aggregate type in value_aggregate_elt");
Please use internal_error.
With the style corrections and another big fat comment in the parser
about why the reduce/reduce conflict is almost OK, this is approved.
--
Daniel Jacobowitz
MontaVista Software Debian GNU/Linux Developer
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [rfa] teach parser about C++ nested types
2003-09-25 15:49 ` Daniel Jacobowitz
@ 2003-09-25 16:02 ` David Carlton
2003-09-25 16:40 ` David Carlton
0 siblings, 1 reply; 4+ messages in thread
From: David Carlton @ 2003-09-25 16:02 UTC (permalink / raw)
To: gdb-patches
On Thu, 25 Sep 2003 11:49:01 -0400, Daniel Jacobowitz <drow@mvista.com> said:
> For content, it's mostly fine. My only concern is about the
> reduce-reduce conflicts. How can this work without breaking one of the
> existing path or the new path?
> From the bison manual:
> Bison resolves a reduce/reduce conflict by choosing to use the rule
> that appears first in the grammar, but it is very risky to rely on
> this.
> It took me quite a while to work out why this works at all, so a
> comment, please. The reason it works (roughly; please don't point out
> flaws in my grasp of parsing, which I know is shaky :) is that we don't
> know whether we want a qualified name or a qualified type, so we choose
> a qualified name per the rule above. Then to the left of the final
> colon we know we need a type so we choose qualified_type. But for the
> first item, qualified_type or qualified_name should work.
That's my understanding, too.
> I'm uncomfortable about how AAA::inA and the AAA::inA portion of
> AAA::inA::fum get parsed differently.
Yeah, really. I should also mention in the comment another aspect of
the reason why this works: we already have this handy 'noside'
variable floating around in the evaluator, which basically tells us
whether we're only looking for type info or really need an actual
expression, so as long as we pay attention to that, it doesn't really
matter too much if, in 'ptype AAA::inA', the parser thinks that
AAA::inA is an expression or a type. (I can't figure out how much of
this is good design and how much of this is a hack to get around bad
design, but it works pretty well either way.)
> For style, two small problems:
>> @@ -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
> I'm a big deleter-of-code. What about leaving a comment here and
> getting rid of the old code? It's not like we'll want it back.
> Something mentioning how qualified names used to be handled here.
Sure. I'm just so used to having Elena in charge of approving my
patches that my reflex is to never delete code any more. :-)
>> + default:
>> + error ("Internal error: non-aggregate type in value_aggregate_elt");
> Please use internal_error.
Right, will do.
> With the style corrections and another big fat comment in the parser
> about why the reduce/reduce conflict is almost OK, this is approved.
Thanks! Geez, now I'll feel guilty if I don't generate my next patch
quickly. :-)
David Carlton
carlton@kealia.com
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [rfa] teach parser about C++ nested types
2003-09-25 16:02 ` David Carlton
@ 2003-09-25 16:40 ` David Carlton
0 siblings, 0 replies; 4+ messages in thread
From: David Carlton @ 2003-09-25 16:40 UTC (permalink / raw)
To: gdb-patches
On Thu, 25 Sep 2003 09:02:51 -0700, David Carlton <carlton@kealia.com> said:
> On Thu, 25 Sep 2003 11:49:01 -0400, Daniel Jacobowitz <drow@mvista.com> said:
>> With the style corrections and another big fat comment in the parser
>> about why the reduce/reduce conflict is almost OK, this is approved.
> Thanks! Geez, now I'll feel guilty if I don't generate my next patch
> quickly. :-)
It's in. Big fat comment is right: if you see a 40-line comment
before a rule in your parser, you know something is wrong somewhere...
David Carlton
carlton@kealia.com
2003-09-25 David Carlton <carlton@kealia.com>
* c-exp.y: Include cp-support.h. Add qualified_type.
(yylex): Delete 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-25 David Carlton <carlton@kealia.com>
* 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.447
diff -u -p -r1.447 Makefile.in
--- Makefile.in 25 Sep 2003 09:10:29 -0000 1.447
+++ Makefile.in 25 Sep 2003 16:30:13 -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)
@@ -2418,7 +2418,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 25 Sep 2003 16:30:13 -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 <voidval> exp exp1 type_exp start variable qualified_name lcurly
%type <lval> rcurly
-%type <tval> type typebase
+%type <tval> type typebase qualified_type
%type <tvec> nonempty_typelist
/* %type <bval> 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,80 @@ typebase /* Implements (approximately):
{ $$ = follow_types ($2); }
| typebase const_or_volatile_or_space_identifier_noopt
{ $$ = follow_types ($1); }
+ | qualified_type
+ ;
+
+/* FIXME: carlton/2003-09-25: 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: the rules are
+ identical. If the parser is parsing 'A::B::x', then, when it sees
+ the second '::', it knows that the expression to the left of it has
+ to be a type, so it uses qualified_type. But if it is parsing just
+ 'A::B', then it doesn't have any way of knowing which rule to use,
+ so there's a reduce-reduce conflict; it picks qualified_name, since
+ that occurs earlier in this file than 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). Fortunately, it works
+ pretty well in most cases. For example, if you do 'ptype A::B',
+ where A::B is a nested type, then the parser will mistakenly
+ misidentify it as an expression; but evaluate_subexp will get
+ called with 'noside' set to EVAL_AVOID_SIDE_EFFECTS, and everything
+ will work out anyways. But there are situations where the parser
+ will get confused: the most common one that I've run into is when
+ you want to do
+
+ print *((A::B *) x)"
+
+ where the parser doesn't realize that A::B has to be a type until
+ it hits the first right paren, at which point it's too late. (The
+ workaround is to type "print *(('A::B' *) x)" instead.) (And
+ another solution is to fix our symbol-handling code so that the
+ user never wants to type something like that in the first place,
+ because we get all the types right without the user's help!)
+
+ 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: that attempt
+ involved having the parser sometimes handle '::' and having the
+ lexer sometimes handle it, and without a clear division of
+ responsibility, it quickly degenerated into a big mess. Probably
+ the eventual correct solution will give more of a role to the lexer
+ (ideally via code that is shared between the lexer and
+ decode_line_1), but I'm not holding my breath waiting for somebody
+ to get around to cleaning this up... */
+
+/* FIXME: carlton/2003-09-25: 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 +1710,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,92 +1770,10 @@ yylex ()
if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
{
-#if 1
- /* 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
- program which uses nested types. */
- /* In "A::x", if x is a member function of A and there happens
- to be a type (nested or not, since the stabs don't make that
- distinction) named x, then this code incorrectly thinks we
- are dealing with nested types rather than a member function. */
-
- char *p;
- char *namestart;
- struct symbol *best_sym;
-
- /* Look ahead to detect nested types. This probably should be
- done in the grammar, but trying seemed to introduce a lot
- of shift/reduce and reduce/reduce conflicts. It's possible
- that it could be done, though. Or perhaps a non-grammar, but
- less ad hoc, approach would work well. */
-
- /* Since we do not currently have any way of distinguishing
- a nested type from a non-nested one (the stabs don't tell
- us whether a type is nested), we just ignore the
- containing type. */
-
- p = lexptr;
- best_sym = sym;
- while (1)
- {
- /* Skip whitespace. */
- while (*p == ' ' || *p == '\t' || *p == '\n')
- ++p;
- if (*p == ':' && p[1] == ':')
- {
- /* Skip the `::'. */
- p += 2;
- /* Skip whitespace. */
- while (*p == ' ' || *p == '\t' || *p == '\n')
- ++p;
- namestart = p;
- while (*p == '_' || *p == '$' || (*p >= '0' && *p <= '9')
- || (*p >= 'a' && *p <= 'z')
- || (*p >= 'A' && *p <= 'Z'))
- ++p;
- if (p != namestart)
- {
- struct symbol *cur_sym;
- /* As big as the whole rest of the expression, which is
- at least big enough. */
- char *ncopy = alloca (strlen (tmp)+strlen (namestart)+3);
- char *tmp1;
-
- tmp1 = ncopy;
- memcpy (tmp1, tmp, strlen (tmp));
- tmp1 += strlen (tmp);
- memcpy (tmp1, "::", 2);
- tmp1 += 2;
- memcpy (tmp1, namestart, p - namestart);
- tmp1[p - namestart] = '\0';
- cur_sym = lookup_symbol (ncopy, expression_context_block,
- VAR_DOMAIN, (int *) NULL,
- (struct symtab **) NULL);
- if (cur_sym)
- {
- if (SYMBOL_CLASS (cur_sym) == LOC_TYPEDEF)
- {
- best_sym = cur_sym;
- lexptr = p;
- }
- else
- break;
- }
- else
- break;
- }
- else
- break;
- }
- else
- break;
- }
-
- yylval.tsym.type = SYMBOL_TYPE (best_sym);
-#else /* not 0 */
+ /* NOTE: carlton/2003-09-25: There used to be code here to
+ handle nested types. It didn't work very well. See the
+ comment before qualified_type for more info. */
yylval.tsym.type = SYMBOL_TYPE (sym);
-#endif /* not 0 */
return TYPENAME;
}
if ((yylval.tsym.type = lookup_primitive_typename (tmp)) != 0)
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 25 Sep 2003 16:30:13 -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 25 Sep 2003 16:30:13 -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.37
diff -u -p -r1.37 eval.c
--- eval.c 25 Sep 2003 08:40:45 -0000 1.37
+++ eval.c 25 Sep 2003 16:30:14 -0000
@@ -408,11 +408,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 25 Sep 2003 16:30:14 -0000
@@ -41,6 +41,7 @@
#include <errno.h>
#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,30 @@ 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:
+ internal_error (__FILE__, __LINE__,
+ "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 +2381,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 25 Sep 2003 16:30:14 -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 25 Sep 2003 16:30:14 -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 25 Sep 2003 16:30:14 -0000
@@ -18,11 +18,11 @@
# bug-gdb@prep.ai.mit.edu
# tests for namespaces
-# Written by Satish Pai <pai@apollo.hp.com> 1997-07-23
+# Originally written by Satish Pai <pai@apollo.hp.com> 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."
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2003-09-25 16:40 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-09-25 0:27 [rfa] teach parser about C++ nested types David Carlton
2003-09-25 15:49 ` Daniel Jacobowitz
2003-09-25 16:02 ` David Carlton
2003-09-25 16:40 ` David Carlton
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox