Parsing of namespaces:

-NamespaceDecl for the AST
-Checks for name clashes between namespaces and tag/normal declarations.

This commit doesn't implement proper name lookup for namespaces.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@50321 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 33d3ce4..37b9805 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -552,6 +552,12 @@
                                 ExprTy *expr, TypeTy *type,
                                 SourceLocation RPLoc);
   
+  // Act on C++ namespaces
+  virtual DeclTy *ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc,
+                                        IdentifierInfo *Ident,
+                                        SourceLocation LBrace);
+  virtual void ActOnFinishNamespaceDef(DeclTy *Dcl, SourceLocation RBrace);
+
   /// ActOnCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's.
   virtual ExprResult ActOnCXXCasts(SourceLocation OpLoc, tok::TokenKind Kind,
                                    SourceLocation LAngleBracketLoc, TypeTy *Ty,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 373aace..61cfa79 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -43,7 +43,7 @@
 }
 
 void Sema::PushDeclContext(DeclContext *DC) {
-  assert( ( (DC->isFunctionOrMethod() && isa<TranslationUnitDecl>(CurContext))
+  assert( ( (isa<ObjCMethodDecl>(DC) && isa<TranslationUnitDecl>(CurContext))
             || DC->getParent() == CurContext ) &&
       "The next DeclContext should be directly contained in the current one.");
   CurContext = DC;
@@ -52,7 +52,7 @@
 void Sema::PopDeclContext() {
   assert(CurContext && "DeclContext imbalance!");
   // If CurContext is a ObjC method, getParent() will return NULL.
-  CurContext = CurContext->isFunctionOrMethod()
+  CurContext = isa<ObjCMethodDecl>(CurContext)
                ? Context.getTranslationUnitDecl()
                  :  CurContext->getParent();
 }
@@ -1332,42 +1332,53 @@
   
   // If this is a named struct, check to see if there was a previous forward
   // declaration or definition.
-  if (TagDecl *PrevDecl = 
-          dyn_cast_or_null<TagDecl>(LookupDecl(Name, Decl::IDNS_Tag, S))) {
+  // Use ScopedDecl instead of TagDecl, because a NamespaceDecl may come up.
+  if (ScopedDecl *PrevDecl = 
+          dyn_cast_or_null<ScopedDecl>(LookupDecl(Name, Decl::IDNS_Tag, S))) {
     
-    // If this is a use of a previous tag, or if the tag is already declared in
-    // the same scope (so that the definition/declaration completes or
-    // rementions the tag), reuse the decl.
-    if (TK == TK_Reference || S->isDeclScope(PrevDecl)) {
-      // Make sure that this wasn't declared as an enum and now used as a struct
-      // or something similar.
-      if (PrevDecl->getKind() != Kind) {
-        Diag(KWLoc, diag::err_use_with_wrong_tag, Name->getName());
-        Diag(PrevDecl->getLocation(), diag::err_previous_use);
-      }
-      
-      // If this is a use or a forward declaration, we're good.
-      if (TK != TK_Definition)
-        return PrevDecl;
+    assert((isa<TagDecl>(PrevDecl) || isa<NamespaceDecl>(PrevDecl)) &&
+            "unexpected Decl type");
+    if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) {
+      // If this is a use of a previous tag, or if the tag is already declared in
+      // the same scope (so that the definition/declaration completes or
+      // rementions the tag), reuse the decl.
+      if (TK == TK_Reference || S->isDeclScope(PrevDecl)) {
+        // Make sure that this wasn't declared as an enum and now used as a struct
+        // or something similar.
+        if (PrevDecl->getKind() != Kind) {
+          Diag(KWLoc, diag::err_use_with_wrong_tag, Name->getName());
+          Diag(PrevDecl->getLocation(), diag::err_previous_use);
+        }
+        
+        // If this is a use or a forward declaration, we're good.
+        if (TK != TK_Definition)
+          return PrevDecl;
 
-      // Diagnose attempts to redefine a tag.
-      if (PrevDecl->isDefinition()) {
-        Diag(NameLoc, diag::err_redefinition, Name->getName());
-        Diag(PrevDecl->getLocation(), diag::err_previous_definition);
-        // If this is a redefinition, recover by making this struct be
-        // anonymous, which will make any later references get the previous
-        // definition.
-        Name = 0;
-      } else {
-        // Okay, this is definition of a previously declared or referenced tag.
-        // Move the location of the decl to be the definition site.
-        PrevDecl->setLocation(NameLoc);
-        return PrevDecl;
+        // Diagnose attempts to redefine a tag.
+        if (PrevTagDecl->isDefinition()) {
+          Diag(NameLoc, diag::err_redefinition, Name->getName());
+          Diag(PrevDecl->getLocation(), diag::err_previous_definition);
+          // If this is a redefinition, recover by making this struct be
+          // anonymous, which will make any later references get the previous
+          // definition.
+          Name = 0;
+        } else {
+          // Okay, this is definition of a previously declared or referenced tag.
+          // Move the location of the decl to be the definition site.
+          PrevDecl->setLocation(NameLoc);
+          return PrevDecl;
+        }
       }
+      // If we get here, this is a definition of a new struct type in a nested
+      // scope, e.g. "struct foo; void bar() { struct foo; }", just create a new
+      // type.
+    } else {
+      // The tag name clashes with a namespace name, issue an error and recover
+      // by making this tag be anonymous.
+      Diag(NameLoc, diag::err_redefinition_different_kind, Name->getName());
+      Diag(PrevDecl->getLocation(), diag::err_previous_definition);
+      Name = 0;
     }
-    // If we get here, this is a definition of a new struct type in a nested
-    // scope, e.g. "struct foo; void bar() { struct foo; }", just create a new
-    // type.
   }
   
   // If there is an identifier, use the location of the identifier as the
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 251fb5e..827c737 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -17,6 +17,7 @@
 #include "clang/AST/Expr.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/AST/Type.h"
+#include "clang/Parse/Scope.h"
 #include "llvm/ADT/OwningPtr.h"
 #include "llvm/Support/Compiler.h"
 
@@ -284,3 +285,79 @@
 
   // FIXME: Attach base class to the record.
 }
+
+
+//===----------------------------------------------------------------------===//
+// Namespace Handling
+//===----------------------------------------------------------------------===//
+
+/// ActOnStartNamespaceDef - This is called at the start of a namespace
+/// definition.
+Sema::DeclTy *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
+                                           SourceLocation IdentLoc,
+                                           IdentifierInfo *II,
+                                           SourceLocation LBrace) {
+  NamespaceDecl *Namespc =
+      NamespaceDecl::Create(Context, CurContext, IdentLoc, II);
+  Namespc->setLBracLoc(LBrace);
+
+  Scope *DeclRegionScope = NamespcScope->getParent();
+
+  if (II) {
+    // C++ [namespace.def]p2:
+    // The identifier in an original-namespace-definition shall not have been
+    // previously defined in the declarative region in which the
+    // original-namespace-definition appears. The identifier in an
+    // original-namespace-definition is the name of the namespace. Subsequently
+    // in that declarative region, it is treated as an original-namespace-name.
+
+    Decl *PrevDecl =
+        LookupDecl(II, Decl::IDNS_Tag | Decl::IDNS_Ordinary, DeclRegionScope,
+                   /*enableLazyBuiltinCreation=*/false);
+
+    if (PrevDecl && DeclRegionScope->isDeclScope(PrevDecl)) {
+      if (NamespaceDecl *OrigNS = dyn_cast<NamespaceDecl>(PrevDecl)) {
+        // This is an extended namespace definition.
+        // Attach this namespace decl to the chain of extended namespace
+        // definitions.
+        NamespaceDecl *NextNS = OrigNS;
+        while (NextNS->getNextNamespace())
+          NextNS = NextNS->getNextNamespace();
+
+        NextNS->setNextNamespace(Namespc);
+        Namespc->setOriginalNamespace(OrigNS);
+
+        // We won't add this decl to the current scope. We want the namespace
+        // name to return the original namespace decl during a name lookup.
+      } else {
+        // This is an invalid name redefinition.
+        Diag(Namespc->getLocation(), diag::err_redefinition_different_kind,
+          Namespc->getName());
+        Diag(PrevDecl->getLocation(), diag::err_previous_definition);
+        Namespc->setInvalidDecl();
+        // Continue on to push Namespc as current DeclContext and return it.
+      }
+    } else {
+      // This namespace name is declared for the first time.
+      PushOnScopeChains(Namespc, DeclRegionScope);
+    }
+  }
+  else {
+    // FIXME: Handle anonymous namespaces
+  }
+
+  // Although we could have an invalid decl (i.e. the namespace name is a
+  // redefinition), push it as current DeclContext and try to continue parsing.
+  PushDeclContext(Namespc->getOriginalNamespace());
+  return Namespc;
+}
+
+/// ActOnFinishNamespaceDef - This callback is called after a namespace is
+/// exited. Decl is the DeclTy returned by ActOnStartNamespaceDef.
+void Sema::ActOnFinishNamespaceDef(DeclTy *D, SourceLocation RBrace) {
+  Decl *Dcl = static_cast<Decl *>(D);
+  NamespaceDecl *Namespc = dyn_cast_or_null<NamespaceDecl>(Dcl);
+  assert(Namespc && "Invalid parameter, expected NamespaceDecl");
+  Namespc->setRBracLoc(RBrace);
+  PopDeclContext();
+}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index e3298f3..edd9284 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -128,6 +128,8 @@
     return Diag(Loc, diag::err_unexpected_typedef, II.getName());
   if (isa<ObjCInterfaceDecl>(D))
     return Diag(Loc, diag::err_unexpected_interface, II.getName());
+  if (isa<NamespaceDecl>(D))
+    return Diag(Loc, diag::err_unexpected_namespace, II.getName());
 
   assert(0 && "Invalid decl");
   abort();
@@ -2313,3 +2315,5 @@
   return isInvalid;
 }
 
+
+