C++ namespaces support

Hi,

The attached patch adds support for parsing C++ namespaces and resolving name lookups based on them.

This test indicates what is possible (added in the patch):

namespaces.patch (47.6 KB)

Wow, this is really cool!

Two high level thoughts before the details:

+/// NamespaceDecl - Represent a C++ namespace.
+class NamespaceDecl : public ScopedDecl {
+ llvm::SmallVector<ScopedDecl *, 16> Decls;
+ SourceLocation LBracLoc, RBracLoc;

Chris Lattner wrote:

Two high level thoughts before the details:

+/// NamespaceDecl - Represent a C++ namespace.
+class NamespaceDecl : public ScopedDecl {
+ llvm::SmallVector<ScopedDecl *, 16> Decls;
+ SourceLocation LBracLoc, RBracLoc;
+
+ // The Scope that is associated with this namespace
+ Scope *NSScope;

"Scope" is an artifact of the parser, which is transiently live when parsing is happening. Is it possible to move this to Sema instead of being in the AST?

I've added the concept of a "named scope" which is a scope that can be associated with declarations like namespaces.
Local scopes are transient but not named scopes. For example:

namespace A {
    int x;
}

namespace B {
    int b;
}

namespace A {
    void f() { x = 1; }
}

The first time namespace A is declared, a scope is created and x is added in this scope. When the namespace is exited, the scope is not destroyed but rather A
gets ownership of it. The second time A is declared, the previous created scope is entered (by getting it from NSScope), so it's like we are continuing the
declaration of A because the scope has 'x' already in it:

namespace A {
    int x;
    void f() { x = 1; }
}

A "named scope" is supposed to be a scope that can be referred to by a name, its declarations should be accessible by other scopes, and can be re-entered.
I thought it'd be useful not to destroy such a scope upon exiting, and keep the declarations that it contains associated with it, is this reasonable ?

Another "named scope" could be that of a class definition. So for example we could have:

namespace A {
    class B {
       class C {
          void m();
       }
    }
}

with scope chain: namespace A -> class B -> class C
and when later on:

void A::b::C::m() {
}

it will enter the already created 'class C' scope, push a new function scope and have this scope chain: namespace A -> class B -> class C -> function m
with all the declarations already included in the various scopes.

A ScopedDecl is also associated with the scope that it was created in (for named scopes) so that you can get its namespace/class like this:

NamedDecl *D = ScopedDecl->getParentScope()->getNamedDecl();

D could be NamespaceDecl or ClassDecl.

But I see that it's not intuitive to have Scope in the AST. Maybe there should be some kind of AST node in place of the 'named scope' that can be shared
by a namespace or a class ? Or rather just associate NamespaceDecl 'A' with a ScopeDecl that was created in namespace 'A' and let thinking how
classes will fit in for another time ?

+++ include/clang/Parse/Parser.h (working copy)
@@ -16,6 +16,7 @@

#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/Action.h"
+#include <stack>

namespace clang {
   class DeclSpec;
@@ -49,6 +50,7 @@
   enum { ScopeCacheSize = 16 };
   unsigned NumCachedScopes;
   Scope *ScopeCache[ScopeCacheSize];
+ std::stack<Scope*> ScopeStack;
public:

Why do you need an explicit stack of scopes here? Aren't the current scope chains enough?

If we can have 'named scopes' that are kept around, perhaps it should be possible to enter one without entering each one of its parents.
For example for

void A::b::C::m() {
}

we just do
create 'function m scope' with 'namespace C scope' as parent
EnterScope('namespace C scope') which sets the scope chain namespace A -> namespace B -> namespace C
EnterScope() for the function
ExitScope() out of the function
ExitScope() which goes from "namespace A -> namespace B -> namespace C" back to the translation unit scope.

For this to work an explicit stack must be used.

I'd be very interested to hear your thoughts on how its the best way to handle such issues.
I hope I was somewhat comprehensible :slight_smile:

-Argiris