[cfe-commits] r99368 - in /cfe/trunk: include/clang/AST/Decl.h lib/Sema/SemaDeclCXX.cpp test/SemaCXX/namespace.cpp

Douglas Gregor dgregor at apple.com
Tue Mar 23 17:46:36 PDT 2010


Author: dgregor
Date: Tue Mar 23 19:46:35 2010
New Revision: 99368

URL: http://llvm.org/viewvc/llvm-project?rev=99368&view=rev
Log:
Make sure to properly track the anonymous namespace that lives inside
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.


Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/test/SemaCXX/namespace.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=99368&r1=99367&r2=99368&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Tue Mar 23 19:46:35 2010
@@ -224,18 +224,26 @@
   // 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 @@
   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);

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=99368&r1=99367&r2=99368&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Mar 23 19:46:35 2010
@@ -2955,7 +2955,6 @@
   } else {
     // Anonymous namespaces.
     assert(Namespc->isAnonymousNamespace());
-    CurContext->addDecl(Namespc);
 
     // Link the anonymous namespace into its parent.
     NamespaceDecl *PrevDecl;
@@ -2977,6 +2976,8 @@
       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 */ }

Modified: cfe/trunk/test/SemaCXX/namespace.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/namespace.cpp?rev=99368&r1=99367&r2=99368&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/namespace.cpp (original)
+++ cfe/trunk/test/SemaCXX/namespace.cpp Tue Mar 23 19:46:35 2010
@@ -68,3 +68,25 @@
 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); }
+
+  }
+}





More information about the cfe-commits mailing list