]> granicus.if.org Git - clang/commitdiff
Make sure to properly track the anonymous namespace that lives inside
authorDouglas Gregor <dgregor@apple.com>
Wed, 24 Mar 2010 00:46:35 +0000 (00:46 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 24 Mar 2010 00:46:35 +0000 (00:46 +0000)
each namespace, even when the outer namespace has multiple
definitions. As part of this, collapsed two pointers worth of storage
(original namespace and inner anonymous namespace) into a single
pointer with a distinguishing bit, since the two are mutually
exclusive, saving a pointer per NamespaceDecl. Fixes PR6620.

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

include/clang/AST/Decl.h
lib/Sema/SemaDeclCXX.cpp
test/SemaCXX/namespace.cpp

index e23811d8f9c0f93abbea3a92974fb09ba5c4c4c8..5e06f05624ec2f5c67ad50ace9047a358233505d 100644 (file)
@@ -224,18 +224,26 @@ class NamespaceDecl : public NamedDecl, public DeclContext {
   // NextNamespace points to the next extended declaration.
   // OrigNamespace points to the original namespace declaration.
   // OrigNamespace of the first namespace decl points to itself.
-  NamespaceDecl *OrigNamespace, *NextNamespace;
+  NamespaceDecl *NextNamespace;
 
-  // The (most recently entered) anonymous namespace inside this
-  // namespace.
-  NamespaceDecl *AnonymousNamespace;
+  /// \brief A pointer to either the original namespace definition for
+  /// this namespace (if the boolean value is false) or the anonymous
+  /// namespace that lives just inside this namespace (if the boolean
+  /// value is true).
+  ///
+  /// We can combine these two notions because the anonymous namespace
+  /// must only be stored in one of the namespace declarations (so all
+  /// of the namespace declarations can find it). We therefore choose
+  /// the original namespace declaration, since all of the namespace
+  /// declarations have a link directly to it; the original namespace
+  /// declaration itself only needs to know that it is the original
+  /// namespace declaration (which the boolean indicates).
+  llvm::PointerIntPair<NamespaceDecl *, 1, bool> OrigOrAnonNamespace;
 
   NamespaceDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id)
-    : NamedDecl(Namespace, DC, L, Id), DeclContext(Namespace) {
-    OrigNamespace = this;
-    NextNamespace = 0;
-    AnonymousNamespace = 0;
-  }
+    : NamedDecl(Namespace, DC, L, Id), DeclContext(Namespace),
+      NextNamespace(0), OrigOrAnonNamespace(0, true) { }
+
 public:
   static NamespaceDecl *Create(ASTContext &C, DeclContext *DC,
                                SourceLocation L, IdentifierInfo *Id);
@@ -258,22 +266,33 @@ public:
   void setNextNamespace(NamespaceDecl *ND) { NextNamespace = ND; }
 
   NamespaceDecl *getOriginalNamespace() const {
-    return OrigNamespace;
+    if (OrigOrAnonNamespace.getInt())
+      return const_cast<NamespaceDecl *>(this);
+
+    return OrigOrAnonNamespace.getPointer();
+  }
+
+  void setOriginalNamespace(NamespaceDecl *ND) { 
+    if (ND != this) {
+      OrigOrAnonNamespace.setPointer(ND);
+      OrigOrAnonNamespace.setInt(false);
+    }
   }
-  void setOriginalNamespace(NamespaceDecl *ND) { OrigNamespace = ND; }
 
   NamespaceDecl *getAnonymousNamespace() const {
-    return AnonymousNamespace;
+    return getOriginalNamespace()->OrigOrAnonNamespace.getPointer();
   }
 
   void setAnonymousNamespace(NamespaceDecl *D) {
     assert(!D || D->isAnonymousNamespace());
     assert(!D || D->getParent() == this);
-    AnonymousNamespace = D;
+    getOriginalNamespace()->OrigOrAnonNamespace.setPointer(D);
   }
 
-  virtual NamespaceDecl *getCanonicalDecl() { return OrigNamespace; }
-  const NamespaceDecl *getCanonicalDecl() const { return OrigNamespace; }
+  virtual NamespaceDecl *getCanonicalDecl() { return getOriginalNamespace(); }
+  const NamespaceDecl *getCanonicalDecl() const { 
+    return getOriginalNamespace(); 
+  }
 
   virtual SourceRange getSourceRange() const {
     return SourceRange(getLocation(), RBracLoc);
index 3e97b6bf71ae439332ac2347392e7318a4994c37..76875c97739300ee10b17d86b08252f057377a27 100644 (file)
@@ -2955,7 +2955,6 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
   } else {
     // Anonymous namespaces.
     assert(Namespc->isAnonymousNamespace());
-    CurContext->addDecl(Namespc);
 
     // Link the anonymous namespace into its parent.
     NamespaceDecl *PrevDecl;
@@ -2977,6 +2976,8 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
       PrevDecl->setNextNamespace(Namespc);
     }
 
+    CurContext->addDecl(Namespc);
+
     // C++ [namespace.unnamed]p1.  An unnamed-namespace-definition
     //   behaves as if it were replaced by
     //     namespace unique { /* empty body */ }
index 2a9d31fa945a59600078679e75ca228da99d3ab1..d47b7076cec2ea8919b4d66dd34617d76ba11b43 100644 (file)
@@ -68,3 +68,25 @@ namespace foo {
 static foo::x  test1;  // ok
 
 static foo::X  test2;  // typo: expected-error {{no type named 'X' in}}
+
+namespace PR6620 {
+  namespace numeric {
+    namespace op {
+      struct greater {};
+    }
+    namespace {
+      extern op::greater const greater;
+    }
+  }
+
+  namespace numeric {
+    namespace {
+      op::greater const greater = op::greater();
+    }
+
+    template<typename T, typename U>
+    int f(T& l, U& r)
+    { numeric::greater(l, r); }
+
+  }
+}