[cfe-commits] r138490 - in /cfe/trunk: include/clang/Serialization/ASTReader.h lib/Serialization/ASTReader.cpp test/Modules/lookup.cpp

Douglas Gregor dgregor at apple.com
Wed Aug 24 14:27:34 PDT 2011


Author: dgregor
Date: Wed Aug 24 16:27:34 2011
New Revision: 138490

URL: http://llvm.org/viewvc/llvm-project?rev=138490&view=rev
Log:
Introduce a depth-first search of modules into the module manager,
which supports both pre-order and post-order traversal via a visitor
mechanism. Use this depth-first search with a post-order traversal to
give predictable ordering semantics when walking all of the lexical
declarations in the translation unit.

Eventually, module imports will occur in the source code rather than
at the beginning, and we'll have to revisit this walk.

Modified:
    cfe/trunk/include/clang/Serialization/ASTReader.h
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/test/Modules/lookup.cpp

Modified: cfe/trunk/include/clang/Serialization/ASTReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTReader.h?rev=138490&r1=138489&r2=138490&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTReader.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTReader.h Wed Aug 24 16:27:34 2011
@@ -552,6 +552,26 @@
   /// \param UserData User data associated with the visitor object, which
   /// will be passed along to the visitor.
   void visit(bool (*Visitor)(Module &M, void *UserData), void *UserData);
+
+  /// \brief Visit each of the modules with a depth-first traversal.
+  ///
+  /// This routine visits each of the modules known to the module
+  /// manager using a depth-first search, starting with the first
+  /// loaded module. The traversal invokes the callback both before
+  /// traversing the children (preorder traversal) and after
+  /// traversing the children (postorder traversal).
+  ///
+  /// \param Visitor A visitor function that will be invoked with each
+  /// module and given a \c Preorder flag that indicates whether we're
+  /// visiting the module before or after visiting its children.  The
+  /// visitor may return true at any time to abort the depth-first
+  /// visitation.
+  ///
+  /// \param UserData User data ssociated with the visitor object,
+  /// which will be passed along to the user.
+  void visitDepthFirst(bool (*Visitor)(Module &M, bool Preorder, 
+                                       void *UserData), 
+                       void *UserData);
 };
 
 } // end namespace serialization

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=138490&r1=138489&r2=138490&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Wed Aug 24 16:27:34 2011
@@ -4264,34 +4264,69 @@
   return ReadStmtFromStream(*Loc.F);
 }
 
+namespace {
+  class FindExternalLexicalDeclsVisitor {
+    ASTReader &Reader;
+    const DeclContext *DC;
+    bool (*isKindWeWant)(Decl::Kind);
+    SmallVectorImpl<Decl*> &Decls;
+    bool PredefsVisited[NUM_PREDEF_DECL_IDS];
+
+  public:
+    FindExternalLexicalDeclsVisitor(ASTReader &Reader, const DeclContext *DC,
+                                    bool (*isKindWeWant)(Decl::Kind),
+                                    SmallVectorImpl<Decl*> &Decls)
+      : Reader(Reader), DC(DC), isKindWeWant(isKindWeWant), Decls(Decls) 
+    {
+      for (unsigned I = 0; I != NUM_PREDEF_DECL_IDS; ++I)
+        PredefsVisited[I] = false;
+    }
+
+    static bool visit(Module &M, bool Preorder, void *UserData) {
+      if (Preorder)
+        return false;
+
+      FindExternalLexicalDeclsVisitor *This
+        = static_cast<FindExternalLexicalDeclsVisitor *>(UserData);
+
+      Module::DeclContextInfosMap::iterator Info
+        = M.DeclContextInfos.find(This->DC);
+      if (Info == M.DeclContextInfos.end() || !Info->second.LexicalDecls)
+        return false;
+
+      // Load all of the declaration IDs
+      for (const KindDeclIDPair *ID = Info->second.LexicalDecls,
+                               *IDE = ID + Info->second.NumLexicalDecls; 
+           ID != IDE; ++ID) {
+        if (This->isKindWeWant && !This->isKindWeWant((Decl::Kind)ID->first))
+          continue;
+
+        // Don't add predefined declarations to the lexical context more
+        // than once.
+        if (ID->second < NUM_PREDEF_DECL_IDS) {
+          if (This->PredefsVisited[ID->second])
+            continue;
+
+          This->PredefsVisited[ID->second] = true;
+        }
+
+        Decl *D = This->Reader.GetLocalDecl(M, ID->second);
+        assert(D && "Null decl in lexical decls");
+        This->Decls.push_back(D);
+      }
+
+      return false;
+    }
+  };
+}
+
 ExternalLoadResult ASTReader::FindExternalLexicalDecls(const DeclContext *DC,
                                          bool (*isKindWeWant)(Decl::Kind),
                                          SmallVectorImpl<Decl*> &Decls) {
   // There might be lexical decls in multiple modules, for the TU at
-  // least.
-  // FIXME: We might want a faster way to zero
-  // FIXME: Going backwards through the chain does the right thing for
-  // chained PCH; for modules, it isn't clear what the right thing is.
-  for (ModuleReverseIterator M = ModuleMgr.rbegin(), MEnd = ModuleMgr.rend();
-       M != MEnd; ++M) {
-    Module::DeclContextInfosMap::iterator Info
-      = (*M)->DeclContextInfos.find(DC);
-    if (Info == (*M)->DeclContextInfos.end() || !Info->second.LexicalDecls)
-      continue;
-
-    // Load all of the declaration IDs
-    for (const KindDeclIDPair *ID = Info->second.LexicalDecls,
-                              *IDE = ID + Info->second.NumLexicalDecls; 
-         ID != IDE; ++ID) {
-      if (isKindWeWant && !isKindWeWant((Decl::Kind)ID->first))
-        continue;
-      
-      Decl *D = GetLocalDecl(**M, ID->second);
-      assert(D && "Null decl in lexical decls");
-      Decls.push_back(D);
-    }
-  }
-
+  // least. Walk all of the modules in the order they were loaded.
+  FindExternalLexicalDeclsVisitor Visitor(*this, DC, isKindWeWant, Decls);
+  ModuleMgr.visitDepthFirst(&FindExternalLexicalDeclsVisitor::visit, &Visitor);
   ++NumLexicalDeclContextsRead;
   return ELR_Success;
 }
@@ -5888,3 +5923,41 @@
     }
   }
 }
+
+/// \brief Perform a depth-first visit of the current module.
+static bool visitDepthFirst(Module &M, 
+                            bool (*Visitor)(Module &M, bool Preorder, 
+                                            void *UserData), 
+                            void *UserData,
+                            llvm::SmallPtrSet<Module *, 4> &Visited) {
+  // Preorder visitation
+  if (Visitor(M, /*Preorder=*/true, UserData))
+    return true;
+
+  // Visit children
+  for (llvm::SetVector<Module *>::iterator IM = M.Imports.begin(),
+                                        IMEnd = M.Imports.end();
+       IM != IMEnd; ++IM) {
+    if (!Visited.insert(*IM))
+      continue;
+
+    if (visitDepthFirst(**IM, Visitor, UserData, Visited))
+      return true;
+  }  
+
+  // Postorder visitation
+  return Visitor(M, /*Preorder=*/false, UserData);
+}
+
+void ModuleManager::visitDepthFirst(bool (*Visitor)(Module &M, bool Preorder, 
+                                                    void *UserData), 
+                                    void *UserData) {
+  llvm::SmallPtrSet<Module *, 4> Visited;
+  for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
+    if (!Visited.insert(Chain[I]))
+      continue;
+
+    if (::visitDepthFirst(*Chain[I], Visitor, UserData, Visited))
+      return;
+  }
+}

Modified: cfe/trunk/test/Modules/lookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/lookup.cpp?rev=138490&r1=138489&r2=138490&view=diff
==============================================================================
--- cfe/trunk/test/Modules/lookup.cpp (original)
+++ cfe/trunk/test/Modules/lookup.cpp Wed Aug 24 16:27:34 2011
@@ -9,6 +9,12 @@
   ::f0(&f);
 }
 
-// RUN: %clang_cc1 -emit-pch -o %t_lookup_left.h.pch %S/Inputs/lookup_left.hpp
-// RUN: %clang_cc1 -emit-pch -o %t_lookup_right.h.pch %S/Inputs/lookup_right.hpp
-// RUN: %clang_cc1 -import-module %t_lookup_left.h.pch -import-module %t_lookup_right.h.pch -verify %s
+// RUN: %clang_cc1 -emit-pch -x c++ -o %t_lookup_left.h.pch %S/Inputs/lookup_left.hpp
+// RUN: %clang_cc1 -emit-pch -x c++ -o %t_lookup_right.h.pch %S/Inputs/lookup_right.hpp
+// RUN: %clang_cc1 -x c++ -import-module %t_lookup_left.h.pch -import-module %t_lookup_right.h.pch -verify %s
+// RUN: %clang_cc1 -ast-print -x c++ -import-module %t_lookup_left.h.pch -import-module %t_lookup_right.h.pch %s | FileCheck -check-prefix=CHECK-PRINT %s
+
+// CHECK-PRINT: int *f0(int *);
+// CHECK-PRINT: float *f0(float *);
+// CHECK-PRINT: void test(int i, float f)
+





More information about the cfe-commits mailing list