[cfe-commits] r71534 - in /cfe/trunk: include/clang/Frontend/PCHBitCodes.h include/clang/Frontend/PCHReader.h include/clang/Frontend/PCHWriter.h lib/Frontend/PCHReader.cpp lib/Frontend/PCHWriter.cpp test/PCH/preprocess.c test/PCH/preprocess.h tools/clang-cc/clang-cc.cpp

Douglas Gregor dgregor at apple.com
Mon May 11 18:31:06 PDT 2009


Author: dgregor
Date: Mon May 11 20:31:05 2009
New Revision: 71534

URL: http://llvm.org/viewvc/llvm-project?rev=71534&view=rev
Log:
Make precompiled headers work with -E. When we're only preprocessing
(with -E), we turn the PCH include into an implicit include of the
file from which the PCH file was generated.

Added:
    cfe/trunk/test/PCH/preprocess.c   (with props)
    cfe/trunk/test/PCH/preprocess.h   (with props)
Modified:
    cfe/trunk/include/clang/Frontend/PCHBitCodes.h
    cfe/trunk/include/clang/Frontend/PCHReader.h
    cfe/trunk/include/clang/Frontend/PCHWriter.h
    cfe/trunk/lib/Frontend/PCHReader.cpp
    cfe/trunk/lib/Frontend/PCHWriter.cpp
    cfe/trunk/tools/clang-cc/clang-cc.cpp

Modified: cfe/trunk/include/clang/Frontend/PCHBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHBitCodes.h?rev=71534&r1=71533&r2=71534&view=diff

==============================================================================
--- cfe/trunk/include/clang/Frontend/PCHBitCodes.h (original)
+++ cfe/trunk/include/clang/Frontend/PCHBitCodes.h Mon May 11 20:31:05 2009
@@ -214,7 +214,11 @@
 
       /// \brief Record code for the set of Objective-C category
       /// implementations.
-      OBJC_CATEGORY_IMPLEMENTATIONS = 19
+      OBJC_CATEGORY_IMPLEMENTATIONS = 19,
+
+      /// \brief Record code for the original file that was used to
+      /// generate the precompiled header.
+      ORIGINAL_FILE_NAME = 20
     };
 
     /// \brief Record types used within a source manager block.

Modified: cfe/trunk/include/clang/Frontend/PCHReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHReader.h?rev=71534&r1=71533&r2=71534&view=diff

==============================================================================
--- cfe/trunk/include/clang/Frontend/PCHReader.h (original)
+++ cfe/trunk/include/clang/Frontend/PCHReader.h Mon May 11 20:31:05 2009
@@ -216,6 +216,10 @@
   /// the PCH file.
   llvm::SmallVector<uint64_t, 4> ObjCCategoryImpls;
 
+  /// \brief The original file name that was used to build the PCH
+  /// file.
+  std::string OriginalFileName;
+
   /// \brief Mapping from switch-case IDs in the PCH file to
   /// switch-case statements.
   std::map<unsigned, SwitchCase *> SwitchCaseStmts;
@@ -327,8 +331,18 @@
   explicit PCHReader(Preprocessor &PP, ASTContext *Context);
   ~PCHReader();
 
+  /// \brief Load the precompiled header designated by the given file
+  /// name.
   PCHReadResult ReadPCH(const std::string &FileName);
 
+  /// \brief Retrieve the name of the original source file name 
+  const std::string &getOriginalSourceFile() { return OriginalFileName; }
+
+  /// \brief Retrieve the name of the original source file name
+  /// directly from the PCH file, without actually loading the PCH
+  /// file.
+  static std::string getOriginalSourceFile(const std::string &PCHFileName);
+
   /// \brief Returns the suggested contents of the predefines buffer,
   /// which contains a (typically-empty) subset of the predefines
   /// build prior to including the precompiled header.

Modified: cfe/trunk/include/clang/Frontend/PCHWriter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHWriter.h?rev=71534&r1=71533&r2=71534&view=diff

==============================================================================
--- cfe/trunk/include/clang/Frontend/PCHWriter.h (original)
+++ cfe/trunk/include/clang/Frontend/PCHWriter.h Mon May 11 20:31:05 2009
@@ -160,7 +160,7 @@
   unsigned NumVisibleDeclContexts;
 
   void WriteBlockInfoBlock();
-  void WriteMetadata(const TargetInfo &Target);
+  void WriteMetadata(ASTContext &Context);
   void WriteLanguageOptions(const LangOptions &LangOpts);
   void WriteStatCache(MemorizeStatCalls &StatCalls);
   void WriteSourceManagerBlock(SourceManager &SourceMgr, 

Modified: cfe/trunk/lib/Frontend/PCHReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReader.cpp?rev=71534&r1=71533&r2=71534&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/PCHReader.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHReader.cpp Mon May 11 20:31:05 2009
@@ -1218,6 +1218,10 @@
       }
       ObjCCategoryImpls.swap(Record);
       break;
+
+    case pch::ORIGINAL_FILE_NAME:
+      OriginalFileName.assign(BlobStart, BlobLen);
+      break;
     }
   }
   Error("premature end of bitstream in PCH file");
@@ -1364,6 +1368,87 @@
   return Success;
 }
 
+/// \brief Retrieve the name of the original source file name
+/// directly from the PCH file, without actually loading the PCH
+/// file.
+std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) {
+  // Open the PCH file.
+  std::string ErrStr;
+  llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
+  Buffer.reset(llvm::MemoryBuffer::getFile(PCHFileName.c_str(), &ErrStr));
+  if (!Buffer) {
+    fprintf(stderr, "error: %s\n", ErrStr.c_str());
+    return std::string();
+  }
+
+  // Initialize the stream
+  llvm::BitstreamReader StreamFile;
+  llvm::BitstreamCursor Stream;
+  StreamFile.init((const unsigned char *)Buffer->getBufferStart(), 
+                  (const unsigned char *)Buffer->getBufferEnd());
+  Stream.init(StreamFile);
+
+  // Sniff for the signature.
+  if (Stream.Read(8) != 'C' ||
+      Stream.Read(8) != 'P' ||
+      Stream.Read(8) != 'C' ||
+      Stream.Read(8) != 'H') {
+    fprintf(stderr, 
+            "error: '%s' does not appear to be a precompiled header file\n",
+            PCHFileName.c_str());
+    return std::string();
+  }
+
+  RecordData Record;
+  while (!Stream.AtEndOfStream()) {
+    unsigned Code = Stream.ReadCode();
+    
+    if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+      unsigned BlockID = Stream.ReadSubBlockID();
+      
+      // We only know the PCH subblock ID.
+      switch (BlockID) {
+      case pch::PCH_BLOCK_ID:
+        if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) {
+          fprintf(stderr, "error: malformed block record in PCH file\n");
+          return std::string();
+        }
+        break;
+        
+      default:
+        if (Stream.SkipBlock()) {
+          fprintf(stderr, "error: malformed block record in PCH file\n");
+          return std::string();
+        }
+        break;
+      }
+      continue;
+    }
+
+    if (Code == llvm::bitc::END_BLOCK) {
+      if (Stream.ReadBlockEnd()) {
+        fprintf(stderr, "error: error at end of module block in PCH file\n");
+        return std::string();
+      }
+      continue;
+    }
+
+    if (Code == llvm::bitc::DEFINE_ABBREV) {
+      Stream.ReadAbbrevRecord();
+      continue;
+    }
+
+    Record.clear();
+    const char *BlobStart = 0;
+    unsigned BlobLen = 0;
+    if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen) 
+          == pch::ORIGINAL_FILE_NAME)
+      return std::string(BlobStart, BlobLen);
+  }  
+
+  return std::string();
+}
+
 /// \brief Parse the record that corresponds to a LangOptions data
 /// structure.
 ///

Modified: cfe/trunk/lib/Frontend/PCHWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriter.cpp?rev=71534&r1=71533&r2=71534&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/PCHWriter.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHWriter.cpp Mon May 11 20:31:05 2009
@@ -33,6 +33,7 @@
 #include "llvm/Bitcode/BitstreamWriter.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include "llvm/System/Path.h"
 #include <cstdio>
 using namespace clang;
 
@@ -442,16 +443,44 @@
 
 
 /// \brief Write the PCH metadata (e.g., i686-apple-darwin9).
-void PCHWriter::WriteMetadata(const TargetInfo &Target) {
+void PCHWriter::WriteMetadata(ASTContext &Context) {
   using namespace llvm;
-  BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
-  Abbrev->Add(BitCodeAbbrevOp(pch::METADATA));
-  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // PCH major
-  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // PCH minor
-  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang major
-  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang minor
-  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Target triple
-  unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
+
+  // Original file name
+  SourceManager &SM = Context.getSourceManager();
+  if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
+    BitCodeAbbrev *FileAbbrev = new BitCodeAbbrev();
+    FileAbbrev->Add(BitCodeAbbrevOp(pch::ORIGINAL_FILE_NAME));
+    FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
+    unsigned FileAbbrevCode = Stream.EmitAbbrev(FileAbbrev);
+
+    llvm::sys::Path MainFilePath(MainFile->getName());
+    std::string MainFileName;
+  
+    if (!MainFilePath.isAbsolute()) {
+      llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory();
+      P.appendComponent(MainFilePath.toString());
+      MainFileName = P.toString();
+    } else {
+      MainFileName = MainFilePath.toString();
+    }
+
+    RecordData Record;
+    Record.push_back(pch::ORIGINAL_FILE_NAME);
+    Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileName.c_str(),
+                              MainFileName.size());
+  }
+
+  // Metadata
+  const TargetInfo &Target = Context.Target;
+  BitCodeAbbrev *MetaAbbrev = new BitCodeAbbrev();
+  MetaAbbrev->Add(BitCodeAbbrevOp(pch::METADATA));
+  MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // PCH major
+  MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // PCH minor
+  MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang major
+  MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang minor
+  MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Target triple
+  unsigned MetaAbbrevCode = Stream.EmitAbbrev(MetaAbbrev);
 
   RecordData Record;
   Record.push_back(pch::METADATA);
@@ -460,7 +489,7 @@
   Record.push_back(CLANG_VERSION_MAJOR);
   Record.push_back(CLANG_VERSION_MINOR);
   const char *Triple = Target.getTargetTriple();
-  Stream.EmitRecordWithBlob(AbbrevCode, Record, Triple, strlen(Triple));
+  Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, Triple, strlen(Triple));
 }
 
 /// \brief Write the LangOptions structure.
@@ -1672,7 +1701,7 @@
   // Write the remaining PCH contents.
   RecordData Record;
   Stream.EnterSubblock(pch::PCH_BLOCK_ID, 4);
-  WriteMetadata(Context.Target);
+  WriteMetadata(Context);
   WriteLanguageOptions(Context.getLangOptions());
   if (StatCalls)
     WriteStatCache(*StatCalls);

Added: cfe/trunk/test/PCH/preprocess.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/preprocess.c?rev=71534&view=auto

==============================================================================
--- cfe/trunk/test/PCH/preprocess.c (added)
+++ cfe/trunk/test/PCH/preprocess.c Mon May 11 20:31:05 2009
@@ -0,0 +1,5 @@
+// RUN: clang-cc -emit-pch -o %t %S/preprocess.h &&
+// RUN: clang-cc -include-pch %t -E -o - %s | grep -c "a_typedef" | count 1
+#include "preprocess.h"
+
+int a_value;

Propchange: cfe/trunk/test/PCH/preprocess.c

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/PCH/preprocess.c

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/PCH/preprocess.c

------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/PCH/preprocess.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/preprocess.h?rev=71534&view=auto

==============================================================================
--- cfe/trunk/test/PCH/preprocess.h (added)
+++ cfe/trunk/test/PCH/preprocess.h Mon May 11 20:31:05 2009
@@ -0,0 +1,7 @@
+// Helper header for preprocess.c PCH test
+#ifndef PREPROCESS_H
+#define PREPROCESS_H
+
+typedef int a_typedef;
+
+#endif // PREPROCESS_H

Propchange: cfe/trunk/test/PCH/preprocess.h

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/PCH/preprocess.h

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/PCH/preprocess.h

------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/tools/clang-cc/clang-cc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-cc/clang-cc.cpp?rev=71534&r1=71533&r2=71534&view=diff

==============================================================================
--- cfe/trunk/tools/clang-cc/clang-cc.cpp (original)
+++ cfe/trunk/tools/clang-cc/clang-cc.cpp Mon May 11 20:31:05 2009
@@ -1267,7 +1267,8 @@
   for (unsigned i = 0, e = ImplicitMacroIncludes.size(); i != e; ++i)
     InitOpts.addMacroInclude(ImplicitMacroIncludes[i]);
 
-  if (!ImplicitIncludePTH.empty() || !ImplicitIncludes.empty()) {
+  if (!ImplicitIncludePTH.empty() || !ImplicitIncludes.empty() ||
+      (!ImplicitIncludePCH.empty() && ProgAction == PrintPreprocessedInput)) {
     // We want to add these paths to the predefines buffer in order, make a
     // temporary vector to sort by their occurrence.
     llvm::SmallVector<std::pair<unsigned, std::string*>, 8> OrderedPaths;
@@ -1275,6 +1276,9 @@
     if (!ImplicitIncludePTH.empty())
       OrderedPaths.push_back(std::make_pair(ImplicitIncludePTH.getPosition(),
                                             &ImplicitIncludePTH));
+    if (!ImplicitIncludePCH.empty() && ProgAction == PrintPreprocessedInput)
+      OrderedPaths.push_back(std::make_pair(ImplicitIncludePCH.getPosition(),
+                                            &ImplicitIncludePCH));
     for (unsigned i = 0, e = ImplicitIncludes.size(); i != e; ++i)
       OrderedPaths.push_back(std::make_pair(ImplicitIncludes.getPosition(i),
                                             &ImplicitIncludes[i]));
@@ -1288,9 +1292,18 @@
           Ptr >= &ImplicitIncludes[0] &&
           Ptr <= &ImplicitIncludes[ImplicitIncludes.size()-1]) {
         InitOpts.addInclude(*Ptr, false);
-      } else {
-        assert(Ptr == &ImplicitIncludePTH);
+      } else if (Ptr == &ImplicitIncludePTH) {
         InitOpts.addInclude(*Ptr, true);
+      } else {
+        // We end up here when we're producing preprocessed output and
+        // we loaded a PCH file. In this case, just include the header
+        // file that was used to build the precompiled header.
+        assert(Ptr == &ImplicitIncludePCH);
+        std::string OriginalFile = PCHReader::getOriginalSourceFile(*Ptr);
+        if (!OriginalFile.empty()) {
+          InitOpts.addInclude(OriginalFile, false);
+          ImplicitIncludePCH.clear();
+        }
       }
     }
   }





More information about the cfe-commits mailing list