[cfe-commits] r125576 - in /cfe/trunk: include/clang/Frontend/FrontendActions.h include/clang/Serialization/ASTBitCodes.h include/clang/Serialization/ASTReader.h include/clang/Serialization/ASTWriter.h lib/Frontend/ASTUnit.cpp lib/Frontend/FrontendActions.cpp lib/Serialization/ASTReader.cpp lib/Serialization/ASTWriter.cpp lib/Serialization/GeneratePCH.cpp test/PCH/headersearch.cpp

Argyrios Kyrtzidis akyrtzi at gmail.com
Tue Feb 15 09:54:22 PST 2011


Author: akirtzidis
Date: Tue Feb 15 11:54:22 2011
New Revision: 125576

URL: http://llvm.org/viewvc/llvm-project?rev=125576&view=rev
Log:
Allow resolving headers from a PCH even after headers+PCH were moved to another path.

Store in PCH the directory that the PCH was originally created in.
If a header file is not found at the path that we expect it to be and the PCH file
was moved from its original location, try to resolve the file by assuming that
header+PCH were moved together and the header is in the same place relative to the PCH.

Added:
    cfe/trunk/test/PCH/headersearch.cpp
Modified:
    cfe/trunk/include/clang/Frontend/FrontendActions.h
    cfe/trunk/include/clang/Serialization/ASTBitCodes.h
    cfe/trunk/include/clang/Serialization/ASTReader.h
    cfe/trunk/include/clang/Serialization/ASTWriter.h
    cfe/trunk/lib/Frontend/ASTUnit.cpp
    cfe/trunk/lib/Frontend/FrontendActions.cpp
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/lib/Serialization/GeneratePCH.cpp

Modified: cfe/trunk/include/clang/Frontend/FrontendActions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendActions.h?rev=125576&r1=125575&r2=125576&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/FrontendActions.h (original)
+++ cfe/trunk/include/clang/Frontend/FrontendActions.h Tue Feb 15 11:54:22 2011
@@ -89,6 +89,7 @@
   static bool ComputeASTConsumerArguments(CompilerInstance &CI,
                                           llvm::StringRef InFile,
                                           std::string &Sysroot,
+                                          std::string &OutputFile,
                                           llvm::raw_ostream *&OS,
                                           bool &Chaining);
 };

Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=125576&r1=125575&r2=125576&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Tue Feb 15 11:54:22 2011
@@ -353,7 +353,10 @@
       CUDA_SPECIAL_DECL_REFS = 39,
       
       /// \brief Record code for header search information.
-      HEADER_SEARCH_TABLE = 40
+      HEADER_SEARCH_TABLE = 40,
+
+      /// \brief The directory that the PCH was originally created in.
+      ORIGINAL_PCH_DIR = 41
     };
 
     /// \brief Record types used within a source manager block.

Modified: cfe/trunk/include/clang/Serialization/ASTReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTReader.h?rev=125576&r1=125575&r2=125576&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTReader.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTReader.h Tue Feb 15 11:54:22 2011
@@ -613,6 +613,13 @@
   /// AST file.
   std::string ActualOriginalFileName;
 
+  /// \brief The directory that the PCH was originally created in. Used to
+  /// allow resolving headers even after headers+PCH was moved to a new path.
+  std::string OriginalDir;
+
+  /// \brief The directory that the PCH we are reading is stored in.
+  std::string CurrentDir;
+
   /// \brief Whether this precompiled header is a relocatable PCH file.
   bool RelocatablePCH;
 

Modified: cfe/trunk/include/clang/Serialization/ASTWriter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTWriter.h?rev=125576&r1=125575&r2=125576&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTWriter.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTWriter.h Tue Feb 15 11:54:22 2011
@@ -309,7 +309,8 @@
   void WriteSubStmt(Stmt *S);
 
   void WriteBlockInfoBlock();
-  void WriteMetadata(ASTContext &Context, const char *isysroot);
+  void WriteMetadata(ASTContext &Context, const char *isysroot,
+                     const std::string &OutputFile);
   void WriteLanguageOptions(const LangOptions &LangOpts);
   void WriteStatCache(MemorizeStatCalls &StatCalls);
   void WriteSourceManagerBlock(SourceManager &SourceMgr,
@@ -339,7 +340,7 @@
   void WriteDecl(ASTContext &Context, Decl *D);
 
   void WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
-                    const char* isysroot);
+                    const char* isysroot, const std::string &OutputFile);
   void WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
                      const char* isysroot);
   
@@ -368,6 +369,7 @@
   /// \param PPRec Record of the preprocessing actions that occurred while
   /// preprocessing this file, e.g., macro instantiations
   void WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
+                const std::string &OutputFile,
                 const char* isysroot);
 
   /// \brief Emit a source location.
@@ -575,6 +577,7 @@
 /// precompiled header from the parsed source code.
 class PCHGenerator : public SemaConsumer {
   const Preprocessor &PP;
+  std::string OutputFile;
   const char *isysroot;
   llvm::raw_ostream *Out;
   Sema *SemaPtr;
@@ -589,7 +592,7 @@
   const ASTWriter &getWriter() const { return Writer; }
 
 public:
-  PCHGenerator(const Preprocessor &PP, bool Chaining,
+  PCHGenerator(const Preprocessor &PP, const std::string &OutputFile, bool Chaining,
                const char *isysroot, llvm::raw_ostream *Out);
   virtual void InitializeSema(Sema &S) { SemaPtr = &S; }
   virtual void HandleTranslationUnit(ASTContext &Ctx);

Modified: cfe/trunk/lib/Frontend/ASTUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/ASTUnit.cpp?rev=125576&r1=125575&r2=125576&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/ASTUnit.cpp (original)
+++ cfe/trunk/lib/Frontend/ASTUnit.cpp Tue Feb 15 11:54:22 2011
@@ -653,7 +653,7 @@
   PrecompilePreambleConsumer(ASTUnit &Unit,
                              const Preprocessor &PP, bool Chaining,
                              const char *isysroot, llvm::raw_ostream *Out)
-    : PCHGenerator(PP, Chaining, isysroot, Out), Unit(Unit) { }
+    : PCHGenerator(PP, "", Chaining, isysroot, Out), Unit(Unit) { }
 
   virtual void HandleTopLevelDecl(DeclGroupRef D) {
     for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) {
@@ -700,9 +700,11 @@
   virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
                                          llvm::StringRef InFile) {
     std::string Sysroot;
+    std::string OutputFile;
     llvm::raw_ostream *OS = 0;
     bool Chaining;
-    if (GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot, 
+    if (GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot,
+                                                       OutputFile,
                                                        OS, Chaining))
       return 0;
     
@@ -2008,7 +2010,7 @@
   std::vector<unsigned char> Buffer;
   llvm::BitstreamWriter Stream(Buffer);
   ASTWriter Writer(Stream);
-  Writer.WriteAST(getSema(), 0, 0);
+  Writer.WriteAST(getSema(), 0, std::string(), 0);
   
   // Write the generated bitstream to "Out".
   if (!Buffer.empty())

Modified: cfe/trunk/lib/Frontend/FrontendActions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendActions.cpp?rev=125576&r1=125575&r2=125576&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/FrontendActions.cpp (original)
+++ cfe/trunk/lib/Frontend/FrontendActions.cpp Tue Feb 15 11:54:22 2011
@@ -83,19 +83,21 @@
 ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI,
                                                   llvm::StringRef InFile) {
   std::string Sysroot;
+  std::string OutputFile;
   llvm::raw_ostream *OS = 0;
   bool Chaining;
-  if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OS, Chaining))
+  if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, OS, Chaining))
     return 0;
 
   const char *isysroot = CI.getFrontendOpts().RelocatablePCH ?
                              Sysroot.c_str() : 0;  
-  return new PCHGenerator(CI.getPreprocessor(), Chaining, isysroot, OS);
+  return new PCHGenerator(CI.getPreprocessor(), OutputFile, Chaining, isysroot, OS);
 }
 
 bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
                                                     llvm::StringRef InFile,
                                                     std::string &Sysroot,
+                                                    std::string &OutputFile,
                                                     llvm::raw_ostream *&OS,
                                                     bool &Chaining) {
   Sysroot = CI.getHeaderSearchOpts().Sysroot;
@@ -111,6 +113,7 @@
   if (!OS)
     return true;
 
+  OutputFile = CI.getFrontendOpts().OutputFile;
   Chaining = CI.getInvocation().getFrontendOpts().ChainedPCH &&
              !CI.getPreprocessorOpts().ImplicitPCHInclude.empty();
   return false;

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=125576&r1=125575&r2=125576&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Tue Feb 15 11:54:22 2011
@@ -1181,6 +1181,39 @@
   }
 }
 
+/// \brief If a header file is not found at the path that we expect it to be
+/// and the PCH file was moved from its original location, try to resolve the
+/// file by assuming that header+PCH were moved together and the header is in
+/// the same place relative to the PCH.
+static std::string
+resolveFileRelativeToOriginalDir(const std::string &Filename,
+                                 const std::string &OriginalDir,
+                                 const std::string &CurrDir) {
+  assert(OriginalDir != CurrDir &&
+         "No point trying to resolve the file if the PCH dir didn't change");
+  using namespace llvm::sys;
+  llvm::SmallString<128> filePath(Filename);
+  fs::make_absolute(filePath);
+  assert(path::is_absolute(OriginalDir));
+  llvm::SmallString<128> currPCHPath(CurrDir);
+
+  path::const_iterator fileDirI = path::begin(path::parent_path(filePath)),
+                       fileDirE = path::end(path::parent_path(filePath));
+  path::const_iterator origDirI = path::begin(OriginalDir),
+                       origDirE = path::end(OriginalDir);
+  // Skip the common path components from filePath and OriginalDir.
+  while (fileDirI != fileDirE && origDirI != origDirE &&
+         *fileDirI == *origDirI) {
+    ++fileDirI;
+    ++origDirI;
+  }
+  for (; origDirI != origDirE; ++origDirI)
+    path::append(currPCHPath, "..");
+  path::append(currPCHPath, fileDirI, fileDirE);
+  path::append(currPCHPath, path::filename(Filename));
+  return currPCHPath.str();
+}
+
 /// \brief Get a cursor that's correctly positioned for reading the source
 /// location entry with the given ID.
 ASTReader::PerFileData *ASTReader::SLocCursorForID(unsigned ID) {
@@ -1235,6 +1268,14 @@
     std::string Filename(BlobStart, BlobStart + BlobLen);
     MaybeAddSystemRootToFilename(Filename);
     const FileEntry *File = FileMgr.getFile(Filename);
+    if (File == 0 && !OriginalDir.empty() && !CurrentDir.empty() &&
+        OriginalDir != CurrentDir) {
+      std::string resolved = resolveFileRelativeToOriginalDir(Filename,
+                                                              OriginalDir,
+                                                              CurrentDir);
+      if (!resolved.empty())
+        File = FileMgr.getFile(resolved);
+    }
     if (File == 0)
       File = FileMgr.getVirtualFile(Filename, (off_t)Record[4],
                                     (time_t)Record[5]);
@@ -2179,6 +2220,12 @@
       MaybeAddSystemRootToFilename(OriginalFileName);
       break;
 
+    case ORIGINAL_PCH_DIR:
+      // The primary AST will be the last to get here, so it will be the one
+      // that's used.
+      OriginalDir.assign(BlobStart, BlobLen);
+      break;
+
     case VERSION_CONTROL_BRANCH_REVISION: {
       const std::string &CurBranch = getClangFullRepositoryVersion();
       llvm::StringRef ASTBranch(BlobStart, BlobLen);
@@ -2393,6 +2440,11 @@
   // Set the AST file name.
   F.FileName = FileName;
 
+  if (FileName != "-") {
+    CurrentDir = llvm::sys::path::parent_path(FileName);
+    if (CurrentDir.empty()) CurrentDir = ".";
+  }
+
   // Open the AST file.
   //
   // FIXME: This shouldn't be here, we should just take a raw_ostream.

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=125576&r1=125575&r2=125576&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Tue Feb 15 11:54:22 2011
@@ -899,7 +899,8 @@
 }
 
 /// \brief Write the AST metadata (e.g., i686-apple-darwin9).
-void ASTWriter::WriteMetadata(ASTContext &Context, const char *isysroot) {
+void ASTWriter::WriteMetadata(ASTContext &Context, const char *isysroot,
+                              const std::string &OutputFile) {
   using namespace llvm;
 
   // Metadata
@@ -947,6 +948,23 @@
     Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr);
   }
 
+  // Original PCH directory
+  if (!OutputFile.empty() && OutputFile != "-") {
+    BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+    Abbrev->Add(BitCodeAbbrevOp(ORIGINAL_PCH_DIR));
+    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
+    unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
+
+    llvm::SmallString<128> OutputPath(OutputFile);
+
+    llvm::sys::fs::make_absolute(OutputPath);
+    StringRef origDir = llvm::sys::path::parent_path(OutputPath);
+
+    RecordData Record;
+    Record.push_back(ORIGINAL_PCH_DIR);
+    Stream.EmitRecordWithBlob(AbbrevCode, Record, origDir);
+  }
+
   // Repository branch/version information.
   BitCodeAbbrev *RepoAbbrev = new BitCodeAbbrev();
   RepoAbbrev->Add(BitCodeAbbrevOp(VERSION_CONTROL_BRANCH_REVISION));
@@ -2568,6 +2586,7 @@
 }
 
 void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
+                         const std::string &OutputFile,
                          const char *isysroot) {
   // Emit the file header.
   Stream.Emit((unsigned)'C', 8);
@@ -2580,11 +2599,12 @@
   if (Chain)
     WriteASTChain(SemaRef, StatCalls, isysroot);
   else
-    WriteASTCore(SemaRef, StatCalls, isysroot);
+    WriteASTCore(SemaRef, StatCalls, isysroot, OutputFile);
 }
 
 void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
-                             const char *isysroot) {
+                             const char *isysroot,
+                             const std::string &OutputFile) {
   using namespace llvm;
 
   ASTContext &Context = SemaRef.Context;
@@ -2692,7 +2712,7 @@
   // Write the remaining AST contents.
   RecordData Record;
   Stream.EnterSubblock(AST_BLOCK_ID, 5);
-  WriteMetadata(Context, isysroot);
+  WriteMetadata(Context, isysroot, OutputFile);
   WriteLanguageOptions(Context.getLangOptions());
   if (StatCalls && !isysroot)
     WriteStatCache(*StatCalls);
@@ -2827,7 +2847,7 @@
 
   RecordData Record;
   Stream.EnterSubblock(AST_BLOCK_ID, 5);
-  WriteMetadata(Context, isysroot);
+  WriteMetadata(Context, isysroot, "");
   if (StatCalls && !isysroot)
     WriteStatCache(*StatCalls);
   // FIXME: Source manager block should only write new stuff, which could be

Modified: cfe/trunk/lib/Serialization/GeneratePCH.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/GeneratePCH.cpp?rev=125576&r1=125575&r2=125576&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/GeneratePCH.cpp (original)
+++ cfe/trunk/lib/Serialization/GeneratePCH.cpp Tue Feb 15 11:54:22 2011
@@ -27,10 +27,11 @@
 using namespace clang;
 
 PCHGenerator::PCHGenerator(const Preprocessor &PP,
+                           const std::string &OutputFile,
                            bool Chaining,
                            const char *isysroot,
                            llvm::raw_ostream *OS)
-  : PP(PP), isysroot(isysroot), Out(OS), SemaPtr(0),
+  : PP(PP), OutputFile(OutputFile), isysroot(isysroot), Out(OS), SemaPtr(0),
     StatCalls(0), Stream(Buffer), Writer(Stream), Chaining(Chaining) {
   // Install a stat() listener to keep track of all of the stat()
   // calls.
@@ -50,7 +51,7 @@
   
   // Emit the PCH file
   assert(SemaPtr && "No Sema?");
-  Writer.WriteAST(*SemaPtr, StatCalls, isysroot);
+  Writer.WriteAST(*SemaPtr, StatCalls, OutputFile, isysroot);
 
   // Write the generated bitstream to "Out".
   Out->write((char *)&Buffer.front(), Buffer.size());

Added: cfe/trunk/test/PCH/headersearch.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/headersearch.cpp?rev=125576&view=auto
==============================================================================
--- cfe/trunk/test/PCH/headersearch.cpp (added)
+++ cfe/trunk/test/PCH/headersearch.cpp Tue Feb 15 11:54:22 2011
@@ -0,0 +1,43 @@
+// Test reading of PCH with changed location of original input files,
+// i.e. invoking header search.
+
+// Generate the original files:
+// RUN: mkdir -p %t_orig/sub %t_orig/sub2
+// RUN: echo 'struct orig_sub{char c; int i; };' > %t_orig/sub/orig_sub.h
+// RUN: echo 'void orig_sub2_1();' > %t_orig/sub2/orig_sub2_1.h
+// RUN: echo '#include "orig_sub2_1.h"' > %t_orig/sub2/orig_sub2.h
+// RUN: echo 'template <typename T> void tf() { orig_sub2_1(); T::foo(); }' >> %t_orig/sub2/orig_sub2.h
+// RUN: echo 'void foo() {}' > %t_orig/tmp2.h
+// RUN: echo '#include "tmp2.h"' > %t_orig/all.h
+// RUN: echo '#include "sub/orig_sub.h"' >> %t_orig/all.h
+// RUN: echo '#include "orig_sub2.h"' >> %t_orig/all.h
+// RUN: echo 'int all();' >> %t_orig/all.h
+
+// Generate the PCH:
+// RUN: cd %t_orig && %clang_cc1 -x c++ -emit-pch -o all.h.pch -Isub2 all.h
+// RUN: rm -rf %t_moved
+// RUN: mv %t_orig %t_moved
+
+// Check diagnostic with location in original source:
+// RUN: %clang_cc1 -include-pch all.h.pch -I%t_moved -I%t_moved/sub2 -Wpadded -emit-obj -o %t.o %s 2> %t.stderr
+// RUN: grep 'struct orig_sub' %t.stderr
+
+// Check diagnostic with 2nd location in original source:
+// RUN: not %clang_cc1 -DREDECL -include-pch all.h.pch -I%t_moved -I%t_moved/sub2 -emit-obj -o %t.o %s 2> %t.stderr
+// RUN: grep 'void foo' %t.stderr
+
+// Check diagnostic with instantiation location in original source:
+// RUN: not %clang_cc1 -DINSTANTIATION -include-pch all.h.pch -I%t_moved -I%t_moved/sub2 -emit-obj -o %t.o %s 2> %t.stderr
+// RUN: grep 'orig_sub2_1' %t.stderr
+
+void qq(orig_sub*) {all();}
+
+#ifdef REDECL
+float foo() {return 0;}
+#endif
+
+#ifdef INSTANTIATION
+void f() {
+  tf<int>();
+}
+#endif





More information about the cfe-commits mailing list