]> granicus.if.org Git - clang/commitdiff
Successive anonymous namespaces name the same scope. I misinterpreted the
authorJohn McCall <rjmccall@apple.com>
Wed, 16 Dec 2009 02:06:49 +0000 (02:06 +0000)
committerJohn McCall <rjmccall@apple.com>
Wed, 16 Dec 2009 02:06:49 +0000 (02:06 +0000)
standard the last time.  Fixes PR5766.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91493 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Decl.h
lib/Sema/SemaDeclCXX.cpp
test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.unnamed/p1.cpp

index d226f64b3e95e92bd8a9f3bf843cd72b1409bbf0..40603516ffffc839f3075a1cc43d8ab7f9b9218f 100644 (file)
@@ -85,13 +85,20 @@ public:
 class TranslationUnitDecl : public Decl, public DeclContext {
   ASTContext &Ctx;
 
+  /// The (most recently entered) anonymous namespace for this
+  /// translation unit, if one has been created.
+  NamespaceDecl *AnonymousNamespace;
+
   explicit TranslationUnitDecl(ASTContext &ctx)
     : Decl(TranslationUnit, 0, SourceLocation()),
       DeclContext(TranslationUnit),
-      Ctx(ctx) {}
+      Ctx(ctx), AnonymousNamespace(0) {}
 public:
   ASTContext &getASTContext() const { return Ctx; }
 
+  NamespaceDecl *getAnonymousNamespace() const { return AnonymousNamespace; }
+  void setAnonymousNamespace(NamespaceDecl *D) { AnonymousNamespace = D; }
+
   static TranslationUnitDecl *Create(ASTContext &C);
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) { return D->getKind() == TranslationUnit; }
@@ -247,10 +254,15 @@ class NamespaceDecl : public NamedDecl, public DeclContext {
   // OrigNamespace of the first namespace decl points to itself.
   NamespaceDecl *OrigNamespace, *NextNamespace;
 
+  // The (most recently entered) anonymous namespace inside this
+  // namespace.
+  NamespaceDecl *AnonymousNamespace;
+
   NamespaceDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id)
     : NamedDecl(Namespace, DC, L, Id), DeclContext(Namespace) {
     OrigNamespace = this;
     NextNamespace = 0;
+    AnonymousNamespace = 0;
   }
 public:
   static NamespaceDecl *Create(ASTContext &C, DeclContext *DC,
@@ -278,6 +290,16 @@ public:
   }
   void setOriginalNamespace(NamespaceDecl *ND) { OrigNamespace = ND; }
 
+  NamespaceDecl *getAnonymousNamespace() const {
+    return AnonymousNamespace;
+  }
+
+  void setAnonymousNamespace(NamespaceDecl *D) {
+    assert(D->isAnonymousNamespace());
+    assert(D->getParent() == this);
+    AnonymousNamespace = D;
+  }
+
   virtual NamespaceDecl *getCanonicalDecl() { return OrigNamespace; }
   const NamespaceDecl *getCanonicalDecl() const { return OrigNamespace; }
 
index a70841f536dcb33ffdebc1667299792c8eb65f05..08edb117e8777fd4834efec5111db806329acff9 100644 (file)
@@ -2748,6 +2748,28 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
     PushOnScopeChains(Namespc, DeclRegionScope);
   } else {
     // Anonymous namespaces.
+    assert(Namespc->isAnonymousNamespace());
+    CurContext->addDecl(Namespc);
+
+    // Link the anonymous namespace into its parent.
+    NamespaceDecl *PrevDecl;
+    DeclContext *Parent = CurContext->getLookupContext();
+    if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(Parent)) {
+      PrevDecl = TU->getAnonymousNamespace();
+      TU->setAnonymousNamespace(Namespc);
+    } else {
+      NamespaceDecl *ND = cast<NamespaceDecl>(Parent);
+      PrevDecl = ND->getAnonymousNamespace();
+      ND->setAnonymousNamespace(Namespc);
+    }
+
+    // Link the anonymous namespace with its previous declaration.
+    if (PrevDecl) {
+      assert(PrevDecl->isAnonymousNamespace());
+      assert(!PrevDecl->getNextNamespace());
+      Namespc->setOriginalNamespace(PrevDecl->getOriginalNamespace());
+      PrevDecl->setNextNamespace(Namespc);
+    }
 
     // C++ [namespace.unnamed]p1.  An unnamed-namespace-definition
     //   behaves as if it were replaced by
@@ -2765,20 +2787,19 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
     // declarations semantically contained within an anonymous
     // namespace internal linkage.
 
-    assert(Namespc->isAnonymousNamespace());
-    CurContext->addDecl(Namespc);
-
-    UsingDirectiveDecl* UD
-      = UsingDirectiveDecl::Create(Context, CurContext,
-                                   /* 'using' */ LBrace,
-                                   /* 'namespace' */ SourceLocation(),
-                                   /* qualifier */ SourceRange(),
-                                   /* NNS */ NULL,
-                                   /* identifier */ SourceLocation(),
-                                   Namespc,
-                                   /* Ancestor */ CurContext);
-    UD->setImplicit();
-    CurContext->addDecl(UD);
+    if (!PrevDecl) {
+      UsingDirectiveDecl* UD
+        = UsingDirectiveDecl::Create(Context, CurContext,
+                                     /* 'using' */ LBrace,
+                                     /* 'namespace' */ SourceLocation(),
+                                     /* qualifier */ SourceRange(),
+                                     /* NNS */ NULL,
+                                     /* identifier */ SourceLocation(),
+                                     Namespc,
+                                     /* Ancestor */ CurContext);
+      UD->setImplicit();
+      CurContext->addDecl(UD);
+    }
   }
 
   // Although we could have an invalid decl (i.e. the namespace name is a
index 09f291c4dd5d05c74d66c5546b78e02f750522a8..b4ec585e48e35c36181e1c851f1f1528a79ca0eb 100644 (file)
@@ -1,7 +1,6 @@
 // RUN: %clang_cc1 -emit-llvm-only -verify %s
 
 // This lame little test was ripped straight from the standard.
-
 namespace {
   int i; // expected-note {{candidate}}
 }
@@ -22,3 +21,22 @@ void test2() {
   A::i++;
   j++;
 }
+
+
+// Test that all anonymous namespaces in a translation unit are
+// considered the same context.
+namespace {
+  class Test3 {}; // expected-note {{previous definition}}
+}
+namespace {
+  class Test3 {}; // expected-error {{redefinition of 'Test3'}}
+}
+
+namespace test4 {
+  namespace {
+    class Test4 {}; // expected-note {{previous definition}}
+  }
+  namespace {
+    class Test4 {}; // expected-error {{redefinition of 'Test4'}}
+  }
+}