diff options
| -rw-r--r-- | clang/include/clang/Frontend/PCHBitCodes.h | 6 | ||||
| -rw-r--r-- | clang/include/clang/Frontend/PCHReader.h | 14 | ||||
| -rw-r--r-- | clang/include/clang/Frontend/PCHWriter.h | 2 | ||||
| -rw-r--r-- | clang/lib/Frontend/PCHReader.cpp | 85 | ||||
| -rw-r--r-- | clang/lib/Frontend/PCHWriter.cpp | 51 | ||||
| -rw-r--r-- | clang/test/PCH/preprocess.c | 5 | ||||
| -rw-r--r-- | clang/test/PCH/preprocess.h | 7 | ||||
| -rw-r--r-- | clang/tools/clang-cc/clang-cc.cpp | 19 | 
8 files changed, 173 insertions, 16 deletions
diff --git a/clang/include/clang/Frontend/PCHBitCodes.h b/clang/include/clang/Frontend/PCHBitCodes.h index 29f408316ba..0862cd6390f 100644 --- a/clang/include/clang/Frontend/PCHBitCodes.h +++ b/clang/include/clang/Frontend/PCHBitCodes.h @@ -214,7 +214,11 @@ namespace clang {        /// \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. diff --git a/clang/include/clang/Frontend/PCHReader.h b/clang/include/clang/Frontend/PCHReader.h index e5591fe6311..1e00ae34137 100644 --- a/clang/include/clang/Frontend/PCHReader.h +++ b/clang/include/clang/Frontend/PCHReader.h @@ -216,6 +216,10 @@ private:    /// 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 @@ public:    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. diff --git a/clang/include/clang/Frontend/PCHWriter.h b/clang/include/clang/Frontend/PCHWriter.h index 3c2d5ff1aff..5cb939547f2 100644 --- a/clang/include/clang/Frontend/PCHWriter.h +++ b/clang/include/clang/Frontend/PCHWriter.h @@ -160,7 +160,7 @@ private:    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,  diff --git a/clang/lib/Frontend/PCHReader.cpp b/clang/lib/Frontend/PCHReader.cpp index 759865c7eb7..ab7ad04e9d9 100644 --- a/clang/lib/Frontend/PCHReader.cpp +++ b/clang/lib/Frontend/PCHReader.cpp @@ -1218,6 +1218,10 @@ PCHReader::ReadPCHBlock() {        }        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 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {    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.  /// diff --git a/clang/lib/Frontend/PCHWriter.cpp b/clang/lib/Frontend/PCHWriter.cpp index fc6aa4709ed..dbe0e536e55 100644 --- a/clang/lib/Frontend/PCHWriter.cpp +++ b/clang/lib/Frontend/PCHWriter.cpp @@ -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 @@ void PCHWriter::WriteBlockInfoBlock() {  /// \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 @@ void PCHWriter::WriteMetadata(const TargetInfo &Target) {    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 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls) {    // 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); diff --git a/clang/test/PCH/preprocess.c b/clang/test/PCH/preprocess.c new file mode 100644 index 00000000000..128cc0acb97 --- /dev/null +++ b/clang/test/PCH/preprocess.c @@ -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; diff --git a/clang/test/PCH/preprocess.h b/clang/test/PCH/preprocess.h new file mode 100644 index 00000000000..39fa006181f --- /dev/null +++ b/clang/test/PCH/preprocess.h @@ -0,0 +1,7 @@ +// Helper header for preprocess.c PCH test +#ifndef PREPROCESS_H +#define PREPROCESS_H + +typedef int a_typedef; + +#endif // PREPROCESS_H diff --git a/clang/tools/clang-cc/clang-cc.cpp b/clang/tools/clang-cc/clang-cc.cpp index ca8d6e51172..a948f843e47 100644 --- a/clang/tools/clang-cc/clang-cc.cpp +++ b/clang/tools/clang-cc/clang-cc.cpp @@ -1267,7 +1267,8 @@ void InitializePreprocessorInitOptions(PreprocessorInitOptions &InitOpts)    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 @@ void InitializePreprocessorInitOptions(PreprocessorInitOptions &InitOpts)      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 @@ void InitializePreprocessorInitOptions(PreprocessorInitOptions &InitOpts)            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(); +        }        }      }    }  | 

