зеркало из https://github.com/microsoft/clang.git
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71534 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
06ab044127
Коммит
b64c19365d
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
|
@ -0,0 +1,7 @@
|
|||
// Helper header for preprocess.c PCH test
|
||||
#ifndef PREPROCESS_H
|
||||
#define PREPROCESS_H
|
||||
|
||||
typedef int a_typedef;
|
||||
|
||||
#endif // PREPROCESS_H
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче