This is the mail archive of the gdb@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: what parts of GDB handle variables with compound names?


On 15 Nov 2002 01:11:21 -0500, Jim Blandy <jimb@redhat.com> said:
> David Carlton <carlton@math.stanford.edu> writes:

>> Right now, if you're debugging C++ code like this
>> 
>> namespace C {
>> int x;
>> void f();
>> }
>> 
>> then, to get at C::x or C::f from within GDB, you usually enclose them
>> in single quotes.  This (I believe) causes GDB to pretend that you
>> have a variable whose name is 'C::x' or 'C::f', so lookup_symbol (or
>> whatever) eventually gets passed that name.
>> 
>> Eventually, it would be desirable for various reasons (including both
>> cleanliness and correctness) for such lookups to consist of a two-part
>> process: first look up 'C' to get some sort of namespace object, and
>> then look up x in the namespace given by C.

> Can you expand on that "cleanliness and correctness" assertion a
> bit?  I understand the compiler itself simply uses fully qualified
> names in its symbol tables, and it apparently does just fine.  And
> it seems to me that the effect of "using namespace" directives is
> best described in terms of having a list of prefixes one searches
> under; it's hard for me to make sense of Stroustrup TC++PL C.10.1
> otherwise.  These argue that putting fully qualified names in the
> symbol table directly is actualy the right approach.

For now, I think that putting fully qualified names in the symbol
table directly is fine: but I think that it's important for there also
to be symbols in the symbol table corresponding to namespaces.  As far
as correctness goes, consider this example:

// Example of why namespaces in GDB have to be first-class objects:

namespace A {
  int x = 1;
}

namespace B {
  namespace A {
  }

  int f()
  {
    return A::x;
  }
}

If you compile this, you get the following error message:

jackfruit$ g++ test10.cc
test10.cc: In function `int B::f()':
test10.cc:13: `x' undeclared in namespace `B::A'

The point is that f lives in namespace B, so if you're in the body of
f, then you first search for local variables, then search in namespace
B, then search in the global namespace.  When the compiler encounters
the name 'A::x', it first tries to resolve 'A'.  It finds an
unambiguous match for 'A' in namespace B, namely the namespace
'B::A'.  So then it searches for 'x' in that namespace and doesn't
find it, hence the error message.

I can't imagine how to handle this correctly in GDB without having
there be some sort of symbol 'B::A' that says that there really is a
namespace of that name.


I should also confess that I'm not convinced that handling this
correctly in GDB is a high priority.  But I think that there are
strong cleanliness reasons for this to work correctly.  Say a user
wants to get at a variable A::B::x; here A and B could both be classes
or namespaces.  (Though only 3 out of the 4 combinations are valid, of
course.)  Also assume that we aren't going to require the user to do
some sort of quoting to specify which part is the namespace part and
which isn't.  If the namespace case is handled within lookup_symbol
while the class case is handled elsewhere, then the code elsewhere
should be a loop which unrolls to something like this:

* Look up A in STRUCT_NAMESPACE
* Do we find a matching class?  If so, find B::x within that class.
* Look up A::B in STRUCT_NAMESPACE.
* Do we find a matching class?  If so, find x within that class.
* Look up A::B::x in VAR_NAMESPACE.

So, basically, you loop over the initial prefixes, hoping that each of
them gives you a namespace (a C++ namespace, not a GDB namespace!),
and you have to treat the final search at the end differently because
you're looking in VAR_NAMESPACE instead of STRUCT_NAMESPACE.

Note that decode_line_1 currently does something like this, whereas
other parts of GDB aren't, leading to sessions like the following:

(gdb) b C::foo
Breakpoint 1 at 0x8048493: file scope.cc, line 9.
(gdb) p C::foo
No symbol "C" in current context.
(gdb) p 'C::foo'
$1 = {void (void)} 0x8048490 <C::foo()>


But if namespaces are first-class objects living in STRUCT_NAMESPACE,
then the code for dealing with A::B::x becomes, to my eyes,
significantly prettier:

* Look up A in STRUCT_NAMESPACE
* If A is a class, find B::x within that class.
* If A is a namespace, find B::x within that namespace.

So classes and namespaces are treated in a much more parallel fashion.
Of course, the implementations for 'find B::x within that class' and
'find B::x within that namespace' will differ, and the code to do the
latter may well end up calling lookup_symbol with values A::B and
A::B::x, just like the loop would, but it moves the knowledge of how
we're currently implementing namespaces into a namespace-specific
function, rather than leaving it in a function that handles general
compound objects.  That will make the code easier to read and maintain
right now, and it will open the door up to future optimizations if we
decide that's important.


There's another cleanliness issue for me, as well, that makes me want
lookup_symbol not to do anything clever if its argument is a compound
name.  I'm not sure I can explain this too well, but bear with me;
these feelings are growing out of some struggles with symtab.c that
I'm still in the middle of.

My first shot at getting namespaces to work right within GDB involved
accepting the fact that lookup_symbol would get passed compound names,
and then lookup_symbol would tease those names apart, apply using
directives where appropriate, and then do further lookups.  So if
lookup_symbol gets passed 'A::x' and if there's a using directive
active that adds stuff in namespace 'A::B' to namespace 'A', then
lookup_symbol will notice that its argument has a prefix 'A' and end
up searching for the symbols 'A::B::x' and 'A::x'.

I've done this, and it works.  But then the question becomes: how
should we modify the semantics of other similar functions in symtab.c?
(I believe the relevant ones are lookup_transparent_type,
make_symbol_overload_list, and search_symbols, though I haven't looked
too hard.)  Basically, I don't want to have to stick some sort of
namespace parser into every one of them, and I'm not even sure what
the semantics of search_symbols would be if I did want to stick a
namespace parser into it.  But what I'm happy to do is to teach each
of them about the concept of namespace scope, and possibly to provide
variants of each function that searches in a particular namespace.
So, for example, I think I want to add a function
lookup_symbol_namespace whose declaration looks something like this:

lookup_symbol_namespace (const char *name, const char *namespace,
                         struct using_direct_node *using);

(there will be more arguments, and maybe the types are wrong, but
never mind that for now), that looks up the name 'name' in the
namespace 'namespace', applying the using directives given in 'using'.
If 'using' is NULL, this will be currently implemented by doing a
lookup_symbol of namespace::name in the global environment; if 'using'
is non-NULL, it will do more lookups, but it will never try to parse
its argument 'name'.

This function can then be used both by lookup_symbol (when it hits the
namespace scope part of the search order) and by my hypothetical
function referred to above that does a "find B::x within that
namespace".


I hope some of that made sense.  I want to emphasize that I'm not
saying that we have to implement namespaces as some sort of
particularly complex first-class mechanisms, with their own symbol
tables inside them: I feel fairly strongly that, for now, we should
continue to rely on there being symbols in the global symbol table
with names like 'A::B::x' when doing namespace lookups.  (My opinion
on this matter has changed over the last two months.)  But I do want
there to be symbols in the symbol table corresponding to namespaces
themselves, and I don't want to have too much of the knowledge about
namespaces to be buried within lookup_symbol.

David Carlton
carlton@math.stanford.edu


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]