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:
Douglas Gregor 2009-05-12 01:31:05 +00:00
Родитель 06ab044127
Коммит b64c19365d
8 изменённых файлов: 173 добавлений и 16 удалений

Просмотреть файл

@ -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);

5
test/PCH/preprocess.c Normal file
Просмотреть файл

@ -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;

7
test/PCH/preprocess.h Normal file
Просмотреть файл

@ -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();
}
}
}
}