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/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();
+}