[cfe-commits] r110131 - in /cfe/trunk: include/clang/Frontend/ASTUnit.h include/clang/Frontend/PCHWriter.h lib/Frontend/ASTUnit.cpp test/Index/preamble.c tools/libclang/CIndex.cpp

Douglas Gregor dgregor at apple.com
Tue Aug 3 12:06:41 PDT 2010


Author: dgregor
Date: Tue Aug  3 14:06:41 2010
New Revision: 110131

URL: http://llvm.org/viewvc/llvm-project?rev=110131&view=rev
Log:
When using a precompiled preamble, keep track of the top-level
declarations that we saw when creating the precompiled preamble, and
provide those declarations in addition to the declarations parsed in
the main source file when traversing top-level declarations. This
makes the use of precompiled preambles a pure optimization, rather
than changing the semantics of the parsed translation unit.

Modified:
    cfe/trunk/include/clang/Frontend/ASTUnit.h
    cfe/trunk/include/clang/Frontend/PCHWriter.h
    cfe/trunk/lib/Frontend/ASTUnit.cpp
    cfe/trunk/test/Index/preamble.c
    cfe/trunk/tools/libclang/CIndex.cpp

Modified: cfe/trunk/include/clang/Frontend/ASTUnit.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/ASTUnit.h?rev=110131&r1=110130&r2=110131&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/ASTUnit.h (original)
+++ cfe/trunk/include/clang/Frontend/ASTUnit.h Tue Aug  3 14:06:41 2010
@@ -14,12 +14,13 @@
 #ifndef LLVM_CLANG_FRONTEND_ASTUNIT_H
 #define LLVM_CLANG_FRONTEND_ASTUNIT_H
 
+#include "clang/Index/ASTLocation.h"
+#include "clang/Frontend/PCHBitCodes.h"
 #include "clang/Lex/PreprocessingRecord.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/OwningPtr.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Index/ASTLocation.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/System/Path.h"
@@ -168,7 +169,11 @@
 
   /// \brief The group of timers associated with this translation unit.
   llvm::OwningPtr<llvm::TimerGroup> TimerGroup;  
-  
+
+  /// \brief A list of the PCH ID numbers for each of the top-level
+  /// declarations parsed within the precompiled preamble.
+  std::vector<pch::DeclID> TopLevelDeclsInPreamble;
+
   /// \brief The timers we've created from the various parses, reparses, etc.
   /// involved in this translation unit.
   std::vector<llvm::Timer *> Timers;
@@ -185,7 +190,8 @@
   ComputePreamble(CompilerInvocation &Invocation, bool &CreatedBuffer);
   
   llvm::MemoryBuffer *BuildPrecompiledPreamble();
-  
+  void RealizeTopLevelDeclsFromPreamble();
+
 public:
   class ConcurrencyCheck {
     volatile ASTUnit &Self;
@@ -236,16 +242,48 @@
                         
   bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
 
+  /// \brief Retrieve the maximum PCH level of declarations that a
+  /// traversal of the translation unit should consider.
+  unsigned getMaxPCHLevel() const;
+
   void setLastASTLocation(ASTLocation ALoc) { LastLoc = ALoc; }
   ASTLocation getLastASTLocation() const { return LastLoc; }
 
-  std::vector<Decl*> &getTopLevelDecls() {
+  typedef std::vector<Decl *>::iterator top_level_iterator;
+
+  top_level_iterator top_level_begin() {
     assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!");
-    return TopLevelDecls;
+    if (!TopLevelDeclsInPreamble.empty())
+      RealizeTopLevelDeclsFromPreamble();
+    return TopLevelDecls.begin();
   }
-  const std::vector<Decl*> &getTopLevelDecls() const {
+
+  top_level_iterator top_level_end() {
     assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!");
-    return TopLevelDecls;
+    if (!TopLevelDeclsInPreamble.empty())
+      RealizeTopLevelDeclsFromPreamble();
+    return TopLevelDecls.end();
+  }
+
+  std::size_t top_level_size() const {
+    assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!");
+    return TopLevelDeclsInPreamble.size() + TopLevelDecls.size();
+  }
+
+  bool top_level_empty() const {
+    assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!");
+    return TopLevelDeclsInPreamble.empty() && TopLevelDecls.empty();
+  }
+
+  /// \brief Add a new top-level declaration.
+  void addTopLevelDecl(Decl *D) {
+    TopLevelDecls.push_back(D);
+  }
+
+  /// \brief Add a new top-level declaration, identified by its ID in
+  /// the precompiled preamble.
+  void addTopLevelDeclFromPreamble(pch::DeclID D) {
+    TopLevelDeclsInPreamble.push_back(D);
   }
 
   /// \brief Retrieve the mapping from File IDs to the preprocessed entities

Modified: cfe/trunk/include/clang/Frontend/PCHWriter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHWriter.h?rev=110131&r1=110130&r2=110131&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/PCHWriter.h (original)
+++ cfe/trunk/include/clang/Frontend/PCHWriter.h Tue Aug  3 14:06:41 2010
@@ -448,6 +448,10 @@
   llvm::BitstreamWriter Stream;
   PCHWriter Writer;
 
+protected:
+  PCHWriter &getWriter() { return Writer; }
+  const PCHWriter &getWriter() const { return Writer; }
+
 public:
   PCHGenerator(const Preprocessor &PP, bool Chaining,
                const char *isysroot, llvm::raw_ostream *Out);

Modified: cfe/trunk/lib/Frontend/ASTUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/ASTUnit.cpp?rev=110131&r1=110130&r2=110131&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/ASTUnit.cpp (original)
+++ cfe/trunk/lib/Frontend/ASTUnit.cpp Tue Aug  3 14:06:41 2010
@@ -309,7 +309,7 @@
       // fundamental problem in the parser right now.
       if (isa<ObjCMethodDecl>(D))
         continue;
-      Unit.getTopLevelDecls().push_back(D);
+      Unit.addTopLevelDecl(D);
     }
   }
 };
@@ -331,6 +331,7 @@
 
 class PrecompilePreambleConsumer : public PCHGenerator {
   ASTUnit &Unit;
+  std::vector<Decl *> TopLevelDecls;
 
 public:
   PrecompilePreambleConsumer(ASTUnit &Unit,
@@ -338,7 +339,7 @@
                              const char *isysroot, llvm::raw_ostream *Out)
     : PCHGenerator(PP, Chaining, isysroot, Out), Unit(Unit) { }
 
-  void HandleTopLevelDecl(DeclGroupRef D) {
+  virtual void HandleTopLevelDecl(DeclGroupRef D) {
     for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) {
       Decl *D = *it;
       // FIXME: Currently ObjC method declarations are incorrectly being
@@ -347,7 +348,20 @@
       // fundamental problem in the parser right now.
       if (isa<ObjCMethodDecl>(D))
         continue;
-      Unit.getTopLevelDecls().push_back(D);
+      TopLevelDecls.push_back(D);
+    }
+  }
+
+  virtual void HandleTranslationUnit(ASTContext &Ctx) {
+    PCHGenerator::HandleTranslationUnit(Ctx);
+    if (!Unit.getDiagnostics().hasErrorOccurred()) {
+      // Translate the top-level declarations we captured during
+      // parsing into declaration IDs in the precompiled
+      // preamble. This will allow us to deserialize those top-level
+      // declarations when requested.
+      for (unsigned I = 0, N = TopLevelDecls.size(); I != N; ++I)
+        Unit.addTopLevelDeclFromPreamble(
+                                      getWriter().getDeclID(TopLevelDecls[I]));
     }
   }
 };
@@ -855,7 +869,9 @@
   
   // Clear out old caches and data.
   StoredDiagnostics.clear();
-  
+  TopLevelDecls.clear();
+  TopLevelDeclsInPreamble.clear();
+
   // Capture any diagnostics that would otherwise be dropped.
   CaptureDroppedDiagnostics Capture(CaptureDiagnostics, 
                                     getDiagnostics(),
@@ -867,7 +883,6 @@
   // Create the source manager.
   Clang.setSourceManager(new SourceManager(getDiagnostics()));
   
-  // FIXME: Eventually, we'll have to track top-level declarations here, too.
   llvm::OwningPtr<PrecompilePreambleAction> Act;
   Act.reset(new PrecompilePreambleAction(*this));
   if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
@@ -889,7 +904,7 @@
   Clang.takeDiagnosticClient();
   Clang.takeInvocation();
   
-  if (Diagnostics->getNumErrors() > 0) {
+  if (Diagnostics->hasErrorOccurred()) {
     // There were errors parsing the preamble, so no precompiled header was
     // generated. Forget that we even tried.
     // FIXME: Should we leave a note for ourselves to try again?
@@ -899,7 +914,7 @@
       delete NewPreamble.first;
     if (PreambleTimer)
       PreambleTimer->stopTimer();
-
+    TopLevelDeclsInPreamble.clear();
     return 0;
   }
   
@@ -935,6 +950,31 @@
                                     FrontendOpts.Inputs[0].second);
 }
 
+void ASTUnit::RealizeTopLevelDeclsFromPreamble() {
+  std::vector<Decl *> Resolved;
+  Resolved.reserve(TopLevelDeclsInPreamble.size());
+  ExternalASTSource &Source = *getASTContext().getExternalSource();
+  for (unsigned I = 0, N = TopLevelDeclsInPreamble.size(); I != N; ++I) {
+    // Resolve the declaration ID to an actual declaration, possibly
+    // deserializing the declaration in the process.
+    Decl *D = Source.GetExternalDecl(TopLevelDeclsInPreamble[I]);
+    if (D)
+      Resolved.push_back(D);
+  }
+  TopLevelDeclsInPreamble.clear();
+  TopLevelDecls.insert(TopLevelDecls.begin(), Resolved.begin(), Resolved.end());
+}
+
+unsigned ASTUnit::getMaxPCHLevel() const {
+  if (!getOnlyLocalDecls())
+    return Decl::MaxPCHLevel;
+
+  unsigned Result = 0;
+  if (isMainFileAST() || SavedMainFileBuffer)
+    ++Result;
+  return Result;
+}
+
 ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
                                    llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
                                              bool OnlyLocalDecls,

Modified: cfe/trunk/test/Index/preamble.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/preamble.c?rev=110131&r1=110130&r2=110131&view=diff
==============================================================================
--- cfe/trunk/test/Index/preamble.c (original)
+++ cfe/trunk/test/Index/preamble.c Tue Aug  3 14:06:41 2010
@@ -5,6 +5,16 @@
 // RUN: %clang -x c-header -o %t.pch %S/Inputs/prefix.h
 // RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 local -I %S/Inputs -include %t %s 2> %t.stderr.txt | FileCheck %s
 // RUN: FileCheck -check-prefix CHECK-DIAG %s < %t.stderr.txt
+// CHECK: preamble.h:1:12: FunctionDecl=bar:1:12 (Definition) Extent=[1:12 - 6:2]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[1:23 - 6:2]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[2:3 - 2:16]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[3:3 - 3:15]
+// CHECK: preamble.h:4:3: UnexposedExpr= Extent=[4:3 - 4:13]
+// CHECK: preamble.h:4:3: DeclRefExpr=ptr:2:8 Extent=[4:3 - 4:6]
+// CHECK: preamble.h:4:9: UnexposedExpr=ptr1:3:10 Extent=[4:9 - 4:13]
+// CHECK: preamble.h:4:9: DeclRefExpr=ptr1:3:10 Extent=[4:9 - 4:13]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[5:3 - 5:11]
+// CHECK: preamble.h:5:10: UnexposedExpr= Extent=[5:10 - 5:11]
 // CHECK: preamble.c:3:5: FunctionDecl=wibble:3:5 Extent=[3:5 - 3:16]
 // CHECK: preamble.c:3:15: ParmDecl=:3:15 (Definition) Extent=[3:12 - 3:16]
 // CHECK-DIAG: preamble.h:4:7:{4:9-4:13}: warning: incompatible pointer types assigning to 'int *' from 'float *'

Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=110131&r1=110130&r2=110131&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Tue Aug  3 14:06:41 2010
@@ -478,10 +478,10 @@
     ASTUnit *CXXUnit = getCursorASTUnit(Cursor);
     if (!CXXUnit->isMainFileAST() && CXXUnit->getOnlyLocalDecls() &&
         RegionOfInterest.isInvalid()) {
-      const std::vector<Decl*> &TLDs = CXXUnit->getTopLevelDecls();
-      for (std::vector<Decl*>::const_iterator it = TLDs.begin(),
-           ie = TLDs.end(); it != ie; ++it) {
-        if (Visit(MakeCXCursor(*it, CXXUnit), true))
+      for (ASTUnit::top_level_iterator TL = CXXUnit->top_level_begin(),
+                                    TLEnd = CXXUnit->top_level_end();
+           TL != TLEnd; ++TL) {
+        if (Visit(MakeCXCursor(*TL, CXXUnit), true))
           return true;
       }
     } else if (VisitDeclContext(
@@ -1636,18 +1636,8 @@
                              CXClientData client_data) {
   ASTUnit *CXXUnit = getCursorASTUnit(parent);
 
-  unsigned PCHLevel = Decl::MaxPCHLevel;
-
-  // Set the PCHLevel to filter out unwanted decls if requested.
-  if (CXXUnit->getOnlyLocalDecls()) {
-    PCHLevel = 0;
-
-    // If the main input was an AST, bump the level.
-    if (CXXUnit->isMainFileAST())
-      ++PCHLevel;
-  }
-
-  CursorVisitor CursorVis(CXXUnit, visitor, client_data, PCHLevel);
+  CursorVisitor CursorVis(CXXUnit, visitor, client_data, 
+                          CXXUnit->getMaxPCHLevel());
   return CursorVis.VisitChildren(parent);
 }
 





More information about the cfe-commits mailing list