[cfe-dev] C++ namespaces support

Argiris Kirtzidis akyrtzi at gmail.com
Tue Mar 25 18:49:01 PDT 2008

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 
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 :)


More information about the cfe-dev mailing list