[cfe-commits] r147729 - in /cfe/trunk: include/clang/AST/Decl.h include/clang/AST/DeclBase.h lib/AST/ASTImporter.cpp lib/AST/DeclBase.cpp lib/AST/DeclCXX.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaLookup.cpp lib/Serialization/ASTReaderDecl.cpp lib/Serialization/ASTWriterDecl.cpp test/Modules/Inputs/module.map test/Modules/Inputs/namespaces-left.h test/Modules/Inputs/namespaces-right.h test/Modules/Inputs/namespaces-top.h test/Modules/namespaces.cpp

Douglas Gregor dgregor at apple.com
Sat Jan 7 01:11:48 PST 2012


Author: dgregor
Date: Sat Jan  7 03:11:48 2012
New Revision: 147729

URL: http://llvm.org/viewvc/llvm-project?rev=147729&view=rev
Log:
Switch NamespaceDecl from its own hand-rolled redeclaration chain over
to Redeclarable<NamespaceDecl>, so that we benefit from the improveed
redeclaration deserialization and merging logic provided by
Redeclarable<T>. Otherwise, no functionality change.

As a drive-by fix, collapse the "inline" bit into the low bit of the
original namespace/anonymous namespace, saving 8 bytes per
NamespaceDecl on x86_64.

Added:
    cfe/trunk/test/Modules/Inputs/namespaces-left.h   (with props)
    cfe/trunk/test/Modules/Inputs/namespaces-right.h   (with props)
    cfe/trunk/test/Modules/Inputs/namespaces-top.h   (with props)
    cfe/trunk/test/Modules/namespaces.cpp   (with props)
Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/AST/DeclBase.h
    cfe/trunk/lib/AST/ASTImporter.cpp
    cfe/trunk/lib/AST/DeclBase.cpp
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaLookup.cpp
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
    cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
    cfe/trunk/test/Modules/Inputs/module.map

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=147729&r1=147728&r2=147729&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Sat Jan  7 03:11:48 2012
@@ -351,9 +351,10 @@
 };
 
 /// NamespaceDecl - Represent a C++ namespace.
-class NamespaceDecl : public NamedDecl, public DeclContext {
+class NamespaceDecl : public NamedDecl, public DeclContext, 
+                      public Redeclarable<NamespaceDecl> 
+{
   virtual void anchor();
-  bool IsInline : 1;
 
   /// LocStart - The starting location of the source range, pointing
   /// to either the namespace or the inline keyword.
@@ -361,44 +362,37 @@
   /// RBraceLoc - The ending location of the source range.
   SourceLocation RBraceLoc;
 
-  // For extended namespace definitions:
-  //
-  // namespace A { int x; }
-  // namespace A { int y; }
-  //
-  // there will be one NamespaceDecl for each declaration.
-  // NextNamespace points to the next extended declaration.
-  // OrigNamespace points to the original namespace declaration.
-  // OrigNamespace of the first namespace decl points to its anonymous namespace
-  LazyDeclPtr NextNamespace;
-
-  /// \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 StartLoc,
-                SourceLocation IdLoc, IdentifierInfo *Id)
-    : NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace),
-      IsInline(false), LocStart(StartLoc), RBraceLoc(),
-      NextNamespace(), OrigOrAnonNamespace(0, true) { }
+  /// \brief A pointer to either the anonymous namespace that lives just inside
+  /// this namespace or to the first namespace in the chain (the latter case
+  /// only when this is not the first in the chain), along with a 
+  /// boolean value indicating whether this is an inline namespace.
+  llvm::PointerIntPair<NamespaceDecl *, 1, bool> AnonOrFirstNamespaceAndInline;
+
+  NamespaceDecl(DeclContext *DC, bool Inline, SourceLocation StartLoc,
+                SourceLocation IdLoc, IdentifierInfo *Id,
+                NamespaceDecl *PrevDecl);
+  
+  typedef Redeclarable<NamespaceDecl> redeclarable_base;
+  virtual NamespaceDecl *getNextRedeclaration() {
+    return RedeclLink.getNext();
+  }
 
 public:
   static NamespaceDecl *Create(ASTContext &C, DeclContext *DC,
-                               SourceLocation StartLoc,
-                               SourceLocation IdLoc, IdentifierInfo *Id);
+                               bool Inline, SourceLocation StartLoc,
+                               SourceLocation IdLoc, IdentifierInfo *Id,
+                               NamespaceDecl *PrevDecl);
 
   static NamespaceDecl *CreateDeserialized(ASTContext &C, unsigned ID);
   
+  typedef redeclarable_base::redecl_iterator redecl_iterator;
+  redecl_iterator redecls_begin() const {
+    return redeclarable_base::redecls_begin();
+  }
+  redecl_iterator redecls_end() const {
+    return redeclarable_base::redecls_end();
+  }
+
   /// \brief Returns true if this is an anonymous namespace declaration.
   ///
   /// For example:
@@ -414,62 +408,55 @@
 
   /// \brief Returns true if this is an inline namespace declaration.
   bool isInline() const {
-    return IsInline;
+    return AnonOrFirstNamespaceAndInline.getInt();
   }
 
   /// \brief Set whether this is an inline namespace declaration.
   void setInline(bool Inline) {
-    IsInline = Inline;
+    AnonOrFirstNamespaceAndInline.setInt(Inline);
   }
 
-  /// \brief Return the next extended namespace declaration or null if there
-  /// is none.
-  NamespaceDecl *getNextNamespace();
-  const NamespaceDecl *getNextNamespace() const {
-    return const_cast<NamespaceDecl *>(this)->getNextNamespace();
+  /// \brief Get the original (first) namespace declaration.
+  NamespaceDecl *getOriginalNamespace() {
+    return getCanonicalDecl();
   }
 
-  /// \brief Set the next extended namespace declaration.
-  void setNextNamespace(NamespaceDecl *ND) { NextNamespace = ND; }
-
   /// \brief Get the original (first) namespace declaration.
-  NamespaceDecl *getOriginalNamespace() const {
-    if (OrigOrAnonNamespace.getInt())
-      return const_cast<NamespaceDecl *>(this);
-
-    return OrigOrAnonNamespace.getPointer();
+  const NamespaceDecl *getOriginalNamespace() const {
+    return getCanonicalDecl();
   }
 
   /// \brief Return true if this declaration is an original (first) declaration
   /// of the namespace. This is false for non-original (subsequent) namespace
   /// declarations and anonymous namespaces.
   bool isOriginalNamespace() const {
-    return getOriginalNamespace() == this;
-  }
-
-  /// \brief Set the original (first) namespace declaration.
-  void setOriginalNamespace(NamespaceDecl *ND) {
-    if (ND != this) {
-      OrigOrAnonNamespace.setPointer(ND);
-      OrigOrAnonNamespace.setInt(false);
-    }
+    return isFirstDeclaration();
   }
 
+  /// \brief Retrieve the anonymous namespace nested inside this namespace,
+  /// if any.
   NamespaceDecl *getAnonymousNamespace() const {
-    return getOriginalNamespace()->OrigOrAnonNamespace.getPointer();
+    return getOriginalNamespace()->AnonOrFirstNamespaceAndInline.getPointer();
   }
 
   void setAnonymousNamespace(NamespaceDecl *D) {
-    assert(!D || D->isAnonymousNamespace());
-    assert(!D || D->getParent()->getRedeclContext() == this);
-    getOriginalNamespace()->OrigOrAnonNamespace.setPointer(D);
+    getOriginalNamespace()->AnonOrFirstNamespaceAndInline.setPointer(D);
   }
 
-  virtual NamespaceDecl *getCanonicalDecl() { return getOriginalNamespace(); }
+  /// Retrieves the canonical declaration of this namespace.
+  NamespaceDecl *getCanonicalDecl() {
+    if (isFirstDeclaration())
+      return this;
+    
+    return AnonOrFirstNamespaceAndInline.getPointer();
+  }
   const NamespaceDecl *getCanonicalDecl() const {
-    return getOriginalNamespace();
+    if (isFirstDeclaration())
+      return this;
+    
+    return AnonOrFirstNamespaceAndInline.getPointer();
   }
-
+  
   virtual SourceRange getSourceRange() const {
     return SourceRange(LocStart, RBraceLoc);
   }

Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=147729&r1=147728&r2=147729&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Sat Jan  7 03:11:48 2012
@@ -1082,24 +1082,30 @@
   /// inline, its enclosing namespace, recursively.
   bool InEnclosingNamespaceSetOf(const DeclContext *NS) const;
 
-  /// getNextContext - If this is a DeclContext that may have other
-  /// DeclContexts that are semantically connected but syntactically
-  /// different, such as C++ namespaces, this routine retrieves the
-  /// next DeclContext in the link. Iteration through the chain of
-  /// DeclContexts should begin at the primary DeclContext and
-  /// continue until this function returns NULL. For example, given:
-  /// @code
+  /// \\brief Collects all of the declaration contexts that are semantically
+  /// connected to this declaration context.
+  ///
+  /// For declaration contexts that have multiple semantically connected but
+  /// syntactically distinct contexts, such as C++ namespaces, this routine 
+  /// retrieves the complete set of such declaration contexts in source order.
+  /// For example, given:
+  ///
+  /// \code
   /// namespace N {
   ///   int x;
   /// }
   /// namespace N {
   ///   int y;
   /// }
-  /// @endcode
-  /// The first occurrence of namespace N will be the primary
-  /// DeclContext. Its getNextContext will return the second
-  /// occurrence of namespace N.
-  DeclContext *getNextContext();
+  /// \endcode
+  ///
+  /// The \c Contexts parameter will contain both definitions of N.
+  ///
+  /// \param Contexts Will be cleared and set to the set of declaration
+  /// contexts that are semanticaly connected to this declaration context,
+  /// in source order, including this context (which may be the only result,
+  /// for non-namespace contexts).
+  void collectAllContexts(llvm::SmallVectorImpl<DeclContext *> &Contexts);
 
   /// decl_iterator - Iterates through the declarations stored
   /// within this context.

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=147729&r1=147728&r2=147729&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Sat Jan  7 03:11:48 2012
@@ -2083,8 +2083,10 @@
   NamespaceDecl *ToNamespace = MergeWithNamespace;
   if (!ToNamespace) {
     ToNamespace = NamespaceDecl::Create(Importer.getToContext(), DC,
+                                        D->isInline(),
                                         Importer.Import(D->getLocStart()),
-                                        Loc, Name.getAsIdentifierInfo());
+                                        Loc, Name.getAsIdentifierInfo(),
+                                        /*PrevDecl=*/0);
     ToNamespace->setLexicalDeclContext(LexicalDC);
     LexicalDC->addDeclInternal(ToNamespace);
     

Modified: cfe/trunk/lib/AST/DeclBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=147729&r1=147728&r2=147729&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclBase.cpp (original)
+++ cfe/trunk/lib/AST/DeclBase.cpp Sat Jan  7 03:11:48 2012
@@ -839,15 +839,21 @@
   }
 }
 
-DeclContext *DeclContext::getNextContext() {
-  switch (DeclKind) {
-  case Decl::Namespace:
-    // Return the next namespace
-    return static_cast<NamespaceDecl*>(this)->getNextNamespace();
-
-  default:
-    return 0;
+void 
+DeclContext::collectAllContexts(llvm::SmallVectorImpl<DeclContext *> &Contexts){
+  Contexts.clear();
+  
+  if (DeclKind != Decl::Namespace) {
+    Contexts.push_back(this);
+    return;
   }
+  
+  NamespaceDecl *Self = static_cast<NamespaceDecl *>(this);
+  for (NamespaceDecl *N = Self->getMostRecentDeclaration(); N;
+       N = N->getPreviousDeclaration())
+    Contexts.push_back(N);
+  
+  std::reverse(Contexts.begin(), Contexts.end());
 }
 
 std::pair<Decl *, Decl *>
@@ -1067,15 +1073,17 @@
 /// declarations in DCtx (and any other contexts linked to it or
 /// transparent contexts nested within it).
 void DeclContext::buildLookup(DeclContext *DCtx) {
-  for (; DCtx; DCtx = DCtx->getNextContext()) {
-    for (decl_iterator D = DCtx->decls_begin(),
-                    DEnd = DCtx->decls_end();
+  llvm::SmallVector<DeclContext *, 2> Contexts;
+  DCtx->collectAllContexts(Contexts);
+  for (unsigned I = 0, N = Contexts.size(); I != N; ++I) {
+    for (decl_iterator D = Contexts[I]->decls_begin(),
+                    DEnd = Contexts[I]->decls_end();
          D != DEnd; ++D) {
       // Insert this declaration into the lookup structure, but only
       // if it's semantically in its decl context.  During non-lazy
       // lookup building, this is implicitly enforced by addDecl.
       if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
-        if (D->getDeclContext() == DCtx)
+        if (D->getDeclContext() == Contexts[I])
           makeDeclVisibleInContextImpl(ND, false);
 
       // If this declaration is itself a transparent declaration context or

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=147729&r1=147728&r2=147729&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Sat Jan  7 03:11:48 2012
@@ -1767,20 +1767,30 @@
 
 void NamespaceDecl::anchor() { }
 
+NamespaceDecl::NamespaceDecl(DeclContext *DC, bool Inline, 
+                             SourceLocation StartLoc,
+                             SourceLocation IdLoc, IdentifierInfo *Id,
+                             NamespaceDecl *PrevDecl)
+  : NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace),
+    LocStart(StartLoc), RBraceLoc(), AnonOrFirstNamespaceAndInline(0, Inline) 
+{
+  setPreviousDeclaration(PrevDecl);
+  
+  if (PrevDecl)
+    AnonOrFirstNamespaceAndInline.setPointer(PrevDecl->getOriginalNamespace());
+}
+
 NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
-                                     SourceLocation StartLoc,
-                                     SourceLocation IdLoc, IdentifierInfo *Id) {
-  return new (C) NamespaceDecl(DC, StartLoc, IdLoc, Id);
+                                     bool Inline, SourceLocation StartLoc,
+                                     SourceLocation IdLoc, IdentifierInfo *Id,
+                                     NamespaceDecl *PrevDecl) {
+  return new (C) NamespaceDecl(DC, Inline, StartLoc, IdLoc, Id, PrevDecl);
 }
 
 NamespaceDecl *NamespaceDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
   void *Mem = AllocateDeserializedDecl(C, ID, sizeof(NamespaceDecl));
-  return new (Mem) NamespaceDecl(0, SourceLocation(), SourceLocation(), 0);
-}
-
-NamespaceDecl *NamespaceDecl::getNextNamespace() {
-  return dyn_cast_or_null<NamespaceDecl>(
-                                         NextNamespace.get(getASTContext().getExternalSource()));
+  return new (Mem) NamespaceDecl(0, false, SourceLocation(), SourceLocation(), 
+                                 0, 0);
 }
 
 void NamespaceAliasDecl::anchor() { }

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=147729&r1=147728&r2=147729&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sat Jan  7 03:11:48 2012
@@ -5531,17 +5531,13 @@
   SourceLocation StartLoc = InlineLoc.isValid() ? InlineLoc : NamespaceLoc;
   // For anonymous namespace, take the location of the left brace.
   SourceLocation Loc = II ? IdentLoc : LBrace;
-  NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext,
-                                                 StartLoc, Loc, II);
-  Namespc->setInline(InlineLoc.isValid());
-
+  bool IsInline = InlineLoc.isValid();
+  bool IsInvalid = false;
+  bool IsStd = false;
+  bool AddToKnown = false;
   Scope *DeclRegionScope = NamespcScope->getParent();
 
-  ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList);
-
-  if (const VisibilityAttr *Attr = Namespc->getAttr<VisibilityAttr>())
-    PushNamespaceVisibilityAttr(Attr);
-
+  NamespaceDecl *PrevNS = 0;
   if (II) {
     // C++ [namespace.def]p2:
     //   The identifier in an original-namespace-definition shall not
@@ -5555,11 +5551,11 @@
     // look through using directives, just look for any ordinary names.
     
     const unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Member | 
-      Decl::IDNS_Type | Decl::IDNS_Using | Decl::IDNS_Tag | 
-      Decl::IDNS_Namespace;
+    Decl::IDNS_Type | Decl::IDNS_Using | Decl::IDNS_Tag | 
+    Decl::IDNS_Namespace;
     NamedDecl *PrevDecl = 0;
     for (DeclContext::lookup_result R 
-            = CurContext->getRedeclContext()->lookup(II);
+         = CurContext->getRedeclContext()->lookup(II);
          R.first != R.second; ++R.first) {
       if ((*R.first)->getIdentifierNamespace() & IDNS) {
         PrevDecl = *R.first;
@@ -5567,100 +5563,90 @@
       }
     }
     
-    if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) {
+    PrevNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl);
+    
+    if (PrevNS) {
       // This is an extended namespace definition.
-      if (Namespc->isInline() != OrigNS->isInline()) {
+      if (IsInline != PrevNS->isInline()) {
         // inline-ness must match
-        if (OrigNS->isInline()) {
+        if (PrevNS->isInline()) {
           // The user probably just forgot the 'inline', so suggest that it
           // be added back.
-          Diag(Namespc->getLocation(), 
-               diag::warn_inline_namespace_reopened_noninline)
+          Diag(Loc, diag::warn_inline_namespace_reopened_noninline)
             << FixItHint::CreateInsertion(NamespaceLoc, "inline ");
         } else {
-          Diag(Namespc->getLocation(), diag::err_inline_namespace_mismatch)
-            << Namespc->isInline();
+          Diag(Loc, diag::err_inline_namespace_mismatch)
+            << IsInline;
         }
-        Diag(OrigNS->getLocation(), diag::note_previous_definition);
-
-        // Recover by ignoring the new namespace's inline status.
-        Namespc->setInline(OrigNS->isInline());
-      }
-
-      // Attach this namespace decl to the chain of extended namespace
-      // definitions.
-      OrigNS->setNextNamespace(Namespc);
-      Namespc->setOriginalNamespace(OrigNS->getOriginalNamespace());
-
-      // Remove the previous declaration from the scope.
-      if (DeclRegionScope->isDeclScope(OrigNS)) {
-        IdResolver.RemoveDecl(OrigNS);
-        DeclRegionScope->RemoveDecl(OrigNS);
-      }
+        Diag(PrevNS->getLocation(), diag::note_previous_definition);
+        
+        IsInline = PrevNS->isInline();
+      }      
     } else if (PrevDecl) {
       // This is an invalid name redefinition.
-      Diag(Namespc->getLocation(), diag::err_redefinition_different_kind)
-       << Namespc->getDeclName();
+      Diag(Loc, diag::err_redefinition_different_kind)
+        << II;
       Diag(PrevDecl->getLocation(), diag::note_previous_definition);
-      Namespc->setInvalidDecl();
+      IsInvalid = true;
       // Continue on to push Namespc as current DeclContext and return it.
-    } else if (II->isStr("std") && 
+    } else if (II->isStr("std") &&
                CurContext->getRedeclContext()->isTranslationUnit()) {
       // This is the first "real" definition of the namespace "std", so update
       // our cache of the "std" namespace to point at this definition.
-      if (NamespaceDecl *StdNS = getStdNamespace()) {
-        // We had already defined a dummy namespace "std". Link this new 
-        // namespace definition to the dummy namespace "std".
-        StdNS->setNextNamespace(Namespc);
-        StdNS->setLocation(IdentLoc);
-        Namespc->setOriginalNamespace(StdNS->getOriginalNamespace());
-      }
-      
-      // Make our StdNamespace cache point at the first real definition of the
-      // "std" namespace.
-      StdNamespace = Namespc;
-
-      // Add this instance of "std" to the set of known namespaces
-      KnownNamespaces[Namespc] = false;
-    } else if (!Namespc->isInline()) {
-      // Since this is an "original" namespace, add it to the known set of
-      // namespaces if it is not an inline namespace.
-      KnownNamespaces[Namespc] = false;
+      PrevNS = getStdNamespace();
+      IsStd = true;
+      AddToKnown = !IsInline;
+    } else {
+      // We've seen this namespace for the first time.
+      AddToKnown = !IsInline;
     }
-
-    PushOnScopeChains(Namespc, DeclRegionScope);
   } else {
     // Anonymous namespaces.
-    assert(Namespc->isAnonymousNamespace());
-
-    // Link the anonymous namespace into its parent.
-    NamespaceDecl *PrevDecl;
+    
+    // Determine whether the parent already has an anonymous namespace.
     DeclContext *Parent = CurContext->getRedeclContext();
     if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(Parent)) {
-      PrevDecl = TU->getAnonymousNamespace();
-      TU->setAnonymousNamespace(Namespc);
+      PrevNS = TU->getAnonymousNamespace();
     } else {
       NamespaceDecl *ND = cast<NamespaceDecl>(Parent);
-      PrevDecl = ND->getAnonymousNamespace();
-      ND->setAnonymousNamespace(Namespc);
+      PrevNS = ND->getAnonymousNamespace();
     }
 
-    // Link the anonymous namespace with its previous declaration.
-    if (PrevDecl) {
-      assert(PrevDecl->isAnonymousNamespace());
-      assert(!PrevDecl->getNextNamespace());
-      Namespc->setOriginalNamespace(PrevDecl->getOriginalNamespace());
-      PrevDecl->setNextNamespace(Namespc);
+    if (PrevNS && IsInline != PrevNS->isInline()) {
+      // inline-ness must match
+      Diag(Loc, diag::err_inline_namespace_mismatch)
+        << IsInline;
+      Diag(PrevNS->getLocation(), diag::note_previous_definition);
+      IsInvalid = true;
+      
+      // Recover by ignoring the new namespace's inline status.
+      IsInline = PrevNS->isInline();
+    }
+  }
+  
+  NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, IsInline,
+                                                 StartLoc, Loc, II, PrevNS);
+  
+  ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList);
 
-      if (Namespc->isInline() != PrevDecl->isInline()) {
-        // inline-ness must match
-        Diag(Namespc->getLocation(), diag::err_inline_namespace_mismatch)
-          << Namespc->isInline();
-        Diag(PrevDecl->getLocation(), diag::note_previous_definition);
-        Namespc->setInvalidDecl();
-        // Recover by ignoring the new namespace's inline status.
-        Namespc->setInline(PrevDecl->isInline());
-      }
+  // FIXME: Should we be merging attributes?
+  if (const VisibilityAttr *Attr = Namespc->getAttr<VisibilityAttr>())
+    PushNamespaceVisibilityAttr(Attr);
+
+  if (IsStd)
+    StdNamespace = Namespc;
+  if (AddToKnown)
+    KnownNamespaces[Namespc] = false;
+  
+  if (II) {
+    PushOnScopeChains(Namespc, DeclRegionScope);
+  } else {
+    // Link the anonymous namespace into its parent.
+    DeclContext *Parent = CurContext->getRedeclContext();
+    if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(Parent)) {
+      TU->setAnonymousNamespace(Namespc);
+    } else {
+      cast<NamespaceDecl>(Parent)->setAnonymousNamespace(Namespc);
     }
 
     CurContext->addDecl(Namespc);
@@ -5681,7 +5667,7 @@
     // declarations semantically contained within an anonymous
     // namespace internal linkage.
 
-    if (!PrevDecl) {
+    if (!PrevNS) {
       UsingDirectiveDecl* UD
         = UsingDirectiveDecl::Create(Context, CurContext,
                                      /* 'using' */ LBrace,
@@ -5740,8 +5726,10 @@
     // The "std" namespace has not yet been defined, so build one implicitly.
     StdNamespace = NamespaceDecl::Create(Context, 
                                          Context.getTranslationUnitDecl(),
+                                         /*Inline=*/false,
                                          SourceLocation(), SourceLocation(),
-                                         &PP.getIdentifierTable().get("std"));
+                                         &PP.getIdentifierTable().get("std"),
+                                         /*PrevDecl=*/0);
     getStdNamespace()->setImplicit(true);
   }
   

Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=147729&r1=147728&r2=147729&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Sat Jan  7 03:11:48 2012
@@ -2740,8 +2740,10 @@
     Result.getSema().ForceDeclarationOfImplicitMembers(Class);
 
   // Enumerate all of the results in this context.
-  for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx;
-       CurCtx = CurCtx->getNextContext()) {
+  llvm::SmallVector<DeclContext *, 2> Contexts;
+  Ctx->collectAllContexts(Contexts);
+  for (unsigned I = 0, N = Contexts.size(); I != N; ++I) {
+    DeclContext *CurCtx = Contexts[I];
     for (DeclContext::decl_iterator D = CurCtx->decls_begin(),
                                  DEnd = CurCtx->decls_end();
          D != DEnd; ++D) {

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=147729&r1=147728&r2=147729&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Sat Jan  7 03:11:48 2012
@@ -967,17 +967,22 @@
 
 
 void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
+  RedeclarableResult Redecl = VisitRedeclarable(D);
   VisitNamedDecl(D);
-  D->IsInline = Record[Idx++];
+  D->setInline(Record[Idx++]);
   D->LocStart = ReadSourceLocation(Record, Idx);
   D->RBraceLoc = ReadSourceLocation(Record, Idx);
-  D->NextNamespace = Record[Idx++];
-
-  bool IsOriginal = Record[Idx++];
-  // FIXME: Modules will likely have trouble with pointing directly at
-  // the original namespace.
-  D->OrigOrAnonNamespace.setInt(IsOriginal);
-  D->OrigOrAnonNamespace.setPointer(ReadDeclAs<NamespaceDecl>(Record, Idx));
+  
+  if (Redecl.getFirstID() == ThisDeclID) {
+    // FIXME: If there's already an anonymous namespace, do we merge it with
+    // this one? Or do we, when loading modules, just forget about anonymous
+    // namespace entirely?
+    D->setAnonymousNamespace(ReadDeclAs<NamespaceDecl>(Record, Idx));
+  } else {
+    // Link this namespace back to the first declaration, which has already
+    // been deserialized.
+    D->AnonOrFirstNamespaceAndInline.setPointer(D->getFirstDeclaration());
+  }
 }
 
 void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
@@ -1772,6 +1777,8 @@
     ID->RedeclLink.setPointer(cast<ObjCInterfaceDecl>(previous));
   } else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
     PD->RedeclLink.setPointer(cast<ObjCProtocolDecl>(previous));
+  } else if (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D)) {
+    ND->RedeclLink.setPointer(cast<NamespaceDecl>(previous));
   } else {
     RedeclarableTemplateDecl *TD = cast<RedeclarableTemplateDecl>(D);
     TD->CommonOrPrev = cast<RedeclarableTemplateDecl>(previous);
@@ -1801,6 +1808,10 @@
     PD->RedeclLink
       = Redeclarable<ObjCProtocolDecl>::LatestDeclLink(
                                                 cast<ObjCProtocolDecl>(Latest));
+  } else if (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D)) {
+    ND->RedeclLink
+      = Redeclarable<NamespaceDecl>::LatestDeclLink(
+                                                   cast<NamespaceDecl>(Latest));
   } else {
     RedeclarableTemplateDecl *TD = cast<RedeclarableTemplateDecl>(D);
     TD->getCommonPtr()->Latest = cast<RedeclarableTemplateDecl>(Latest);
@@ -2216,6 +2227,8 @@
     return ID->getPreviousDeclaration();
   if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D))
     return PD->getPreviousDeclaration();
+  if (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D))
+    return ND->getPreviousDeclaration();
   
   return cast<RedeclarableTemplateDecl>(D)->getPreviousDeclaration();
 }
@@ -2234,7 +2247,9 @@
     return ID->getMostRecentDeclaration();
   if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D))
     return PD->getMostRecentDeclaration();
-  
+  if (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D))
+    return ND->getMostRecentDeclaration();
+
   return cast<RedeclarableTemplateDecl>(D)->getMostRecentDeclaration();
 }
 
@@ -2446,15 +2461,10 @@
     case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: {
       NamespaceDecl *Anon
         = Reader.ReadDeclAs<NamespaceDecl>(ModuleFile, Record, Idx);
-      // Guard against these being loaded out of original order. Don't use
-      // getNextNamespace(), since it tries to access the context and can't in
-      // the middle of deserialization.
-      if (!Anon->NextNamespace) {
-        if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(D))
-          TU->setAnonymousNamespace(Anon);
-        else
-          cast<NamespaceDecl>(D)->OrigOrAnonNamespace.setPointer(Anon);
-      }
+      if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(D))
+        TU->setAnonymousNamespace(Anon);
+      else
+        cast<NamespaceDecl>(D)->setAnonymousNamespace(Anon);
       break;
     }
 

Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=147729&r1=147728&r2=147729&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Sat Jan  7 03:11:48 2012
@@ -802,18 +802,14 @@
 
 
 void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
+  VisitRedeclarable(D);
   VisitNamedDecl(D);
   Record.push_back(D->isInline());
   Writer.AddSourceLocation(D->getLocStart(), Record);
   Writer.AddSourceLocation(D->getRBraceLoc(), Record);
-  Writer.AddDeclRef(D->getNextNamespace(), Record);
 
-  // Only write one reference--original or anonymous
-  Record.push_back(D->isOriginalNamespace());
   if (D->isOriginalNamespace())
     Writer.AddDeclRef(D->getAnonymousNamespace(), Record);
-  else
-    Writer.AddDeclRef(D->getOriginalNamespace(), Record);
   Code = serialization::DECL_NAMESPACE;
 
   if (Writer.hasChain() && !D->isOriginalNamespace() &&
@@ -836,7 +832,8 @@
     }
   }
 
-  if (Writer.hasChain() && D->isAnonymousNamespace() && !D->getNextNamespace()){
+  if (Writer.hasChain() && D->isAnonymousNamespace() && 
+      D == D->getMostRecentDeclaration()) {
     // This is a most recent reopening of the anonymous namespace. If its parent
     // is in a previous PCH (or is the TU), mark that parent for update, because
     // the original namespace always points to the latest re-opening of its

Modified: cfe/trunk/test/Modules/Inputs/module.map
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/module.map?rev=147729&r1=147728&r2=147729&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/module.map (original)
+++ cfe/trunk/test/Modules/Inputs/module.map Sat Jan  7 03:11:48 2012
@@ -63,3 +63,15 @@
   header "redecl-merge-bottom.h" 
   export *
 }
+module namespaces_top { 
+  header "namespaces-top.h"
+  export *
+}
+module namespaces_left { 
+  header "namespaces-left.h"
+  export *
+}
+module namespaces_right { 
+  header "namespaces-right.h"
+  export *
+}

Added: cfe/trunk/test/Modules/Inputs/namespaces-left.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/namespaces-left.h?rev=147729&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/namespaces-left.h (added)
+++ cfe/trunk/test/Modules/Inputs/namespaces-left.h Sat Jan  7 03:11:48 2012
@@ -0,0 +1,11 @@
+ at import namespaces_top;
+
+namespace N1 { }
+
+namespace N1 { 
+  float& f(float);
+}
+
+namespace N2 { 
+  float& f(float);
+}

Propchange: cfe/trunk/test/Modules/Inputs/namespaces-left.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/Modules/Inputs/namespaces-left.h
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/Modules/Inputs/namespaces-left.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/Modules/Inputs/namespaces-right.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/namespaces-right.h?rev=147729&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/namespaces-right.h (added)
+++ cfe/trunk/test/Modules/Inputs/namespaces-right.h Sat Jan  7 03:11:48 2012
@@ -0,0 +1,18 @@
+ at import namespaces_top;
+
+namespace N2 { }
+
+namespace N2 { }
+
+namespace N2 { }
+
+namespace N2 { }
+
+namespace N2 { 
+  double& f(double);
+}
+
+namespace N3 { 
+  double& f(double);
+}
+

Propchange: cfe/trunk/test/Modules/Inputs/namespaces-right.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/Modules/Inputs/namespaces-right.h
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/Modules/Inputs/namespaces-right.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/Modules/Inputs/namespaces-top.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/namespaces-top.h?rev=147729&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/namespaces-top.h (added)
+++ cfe/trunk/test/Modules/Inputs/namespaces-top.h Sat Jan  7 03:11:48 2012
@@ -0,0 +1,11 @@
+namespace N1 { 
+  int& f(int);
+}
+
+namespace N2 { 
+  int& f(int);
+}
+
+namespace N3 { 
+  int& f(int);
+}

Propchange: cfe/trunk/test/Modules/Inputs/namespaces-top.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/Modules/Inputs/namespaces-top.h
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/Modules/Inputs/namespaces-top.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/Modules/namespaces.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/namespaces.cpp?rev=147729&view=auto
==============================================================================
--- cfe/trunk/test/Modules/namespaces.cpp (added)
+++ cfe/trunk/test/Modules/namespaces.cpp Sat Jan  7 03:11:48 2012
@@ -0,0 +1,15 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodule-cache-path %t -I %S/Inputs %s -verify
+
+ at import namespaces_left;
+ at import namespaces_right;
+
+void test() {
+  int &ir1 = N1::f(1);
+  int &ir2 = N2::f(1);
+  int &ir3 = N3::f(1);
+  float &fr1 = N1::f(1.0f);
+  float &fr2 = N2::f(1.0f);
+  double &dr1 = N2::f(1.0);
+  double &dr2 = N3::f(1.0);
+}

Propchange: cfe/trunk/test/Modules/namespaces.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/Modules/namespaces.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/Modules/namespaces.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain





More information about the cfe-commits mailing list