* 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.
+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 Daniel Jacobowitz <drow@mvista.com>
* stack.c: Include "reggroups.h".
.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)
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)
#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;
%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 */
{
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));
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));
{ $$ = 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
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 */
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)
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
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);
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;
+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.
+
2003-09-25 Richard Earnshaw <rearnsha@arm.com>
* lib/java.exp (java_init): Import target_alias before using it.
namespace G
{
int Xg = 10;
+
+ namespace
+ {
+ int XgX = 11;
+ }
}
}
namespace F
{
int cXf = 7;
+
+ namespace
+ {
+ int cXfX = 8;
+ }
}
}
int cc = 2;
}
+ namespace E
+ {
+ int ce = 4;
+ }
+
namespace D
{
int cd = 3;
//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;
}
# 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
# 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'" }
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"
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"
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"
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"
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."
#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. */
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 *);
return check_field_in (t, name);
}
+/* 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
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;
+}
+
/* Given a pointer value V, find the real (RTTI) type
of the object it points to.
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);