aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td2
-rw-r--r--include/clang/Basic/SourceManager.h29
-rw-r--r--include/clang/Driver/CC1Options.td2
-rw-r--r--include/clang/Frontend/ASTUnit.h11
-rw-r--r--include/clang/Frontend/PreprocessorOptions.h19
-rw-r--r--include/clang/Lex/Lexer.h8
-rw-r--r--include/clang/Lex/Preprocessor.h18
-rw-r--r--lib/Basic/SourceManager.cpp25
-rw-r--r--lib/Frontend/ASTUnit.cpp72
-rw-r--r--lib/Frontend/CompilerInvocation.cpp17
-rw-r--r--lib/Frontend/FrontendActions.cpp2
-rw-r--r--lib/Frontend/InitPreprocessor.cpp10
-rw-r--r--lib/Lex/Lexer.cpp15
-rw-r--r--lib/Lex/Preprocessor.cpp9
-rw-r--r--test/PCH/Inputs/preamble.h1
-rw-r--r--test/PCH/preamble.c21
16 files changed, 217 insertions, 44 deletions
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index f4a31cc576..34cd6004ed 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -68,6 +68,8 @@ def err_drv_invalid_gcc_output_type : Error<
"invalid output type '%0' for use with gcc tool">;
def err_drv_cc_print_options_failure : Error<
"unable to open CC_PRINT_OPTIONS file: %0">;
+def err_drv_preamble_format : Error<
+ "incorrect format for -preamble-bytes=N,END">;
def warn_drv_input_file_unused : Warning<
"%0: '%1' input unused when '%2' is present">;
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index 5d98fb9253..b6a1ac4492 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -53,10 +53,17 @@ namespace SrcMgr {
/// ContentCache - Once instance of this struct is kept for every file
/// loaded or used. This object owns the MemoryBuffer object.
class ContentCache {
+ enum CCFlags {
+ /// \brief Whether the buffer is invalid.
+ InvalidFlag = 0x01,
+ /// \brief Whether the buffer should not be freed on destruction.
+ DoNotFreeFlag = 0x02
+ };
+
/// Buffer - The actual buffer containing the characters from the input
/// file. This is owned by the ContentCache object.
- /// The bit indicates whether the buffer is invalid.
- mutable llvm::PointerIntPair<const llvm::MemoryBuffer *, 1, bool> Buffer;
+ /// The bits indicate indicates whether the buffer is invalid.
+ mutable llvm::PointerIntPair<const llvm::MemoryBuffer *, 2> Buffer;
public:
/// Reference to the file entry. This reference does not own
@@ -106,8 +113,18 @@ namespace SrcMgr {
/// \brief Replace the existing buffer (which will be deleted)
/// with the given buffer.
- void replaceBuffer(const llvm::MemoryBuffer *B);
+ void replaceBuffer(const llvm::MemoryBuffer *B, bool DoNotFree = false);
+ /// \brief Determine whether the buffer itself is invalid.
+ bool isBufferInvalid() const {
+ return Buffer.getInt() & InvalidFlag;
+ }
+
+ /// \brief Determine whether the buffer should be freed.
+ bool shouldFreeBuffer() const {
+ return (Buffer.getInt() & DoNotFreeFlag) == 0;
+ }
+
ContentCache(const FileEntry *Ent = 0)
: Buffer(0, false), Entry(Ent), SourceLineCache(0), NumLines(0) {}
@@ -490,9 +507,13 @@ public:
/// \param Buffer the memory buffer whose contents will be used as the
/// data in the given source file.
///
+ /// \param DoNotFree If true, then the buffer will not be freed when the
+ /// source manager is destroyed.
+ ///
/// \returns true if an error occurred, false otherwise.
bool overrideFileContents(const FileEntry *SourceFile,
- const llvm::MemoryBuffer *Buffer);
+ const llvm::MemoryBuffer *Buffer,
+ bool DoNotFree = false);
//===--------------------------------------------------------------------===//
// FileID manipulation methods.
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index b17af4b8c8..b813fea75c 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -505,7 +505,7 @@ def include_pch : Separate<"-include-pch">, MetaVarName<"<file>">,
HelpText<"Include precompiled header file">;
def include_pth : Separate<"-include-pth">, MetaVarName<"<file>">,
HelpText<"Include file before parsing">;
-def use_preamble_EQ : Joined<"-use-preamble=">,
+def preamble_bytes_EQ : Joined<"-preamble-bytes=">,
HelpText<"Assume that the precompiled header is a precompiled preamble "
"covering the first N bytes of the main file">;
def token_cache : Separate<"-token-cache">, MetaVarName<"<path>">,
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 9a4b4c6cb3..d0202dfe28 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -125,6 +125,12 @@ private:
/// \c PreambleFile.
std::vector<char> Preamble;
+ /// \brief Whether the preamble ends at the start of a new line.
+ ///
+ /// Used to inform the lexer as to whether it's starting at the beginning of
+ /// a line after skipping the preamble.
+ bool PreambleEndsAtStartOfLine;
+
/// \brief The size of the source buffer that we've reserved for the main
/// file within the precompiled preamble.
unsigned PreambleReservedSize;
@@ -137,9 +143,8 @@ private:
void CleanTemporaryFiles();
bool Parse(llvm::MemoryBuffer *OverrideMainBuffer);
- std::pair<llvm::MemoryBuffer *, unsigned> ComputePreamble(
- CompilerInvocation &Invocation,
- bool &CreatedBuffer);
+ std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> >
+ ComputePreamble(CompilerInvocation &Invocation, bool &CreatedBuffer);
llvm::MemoryBuffer *BuildPrecompiledPreamble();
diff --git a/include/clang/Frontend/PreprocessorOptions.h b/include/clang/Frontend/PreprocessorOptions.h
index 05159335ad..f2154955c2 100644
--- a/include/clang/Frontend/PreprocessorOptions.h
+++ b/include/clang/Frontend/PreprocessorOptions.h
@@ -43,6 +43,13 @@ public:
/// The implicit PCH included at the start of the translation unit, or empty.
std::string ImplicitPCHInclude;
+ /// \brief If non-zero, the implicit PCH include is actually a precompiled
+ /// preamble that covers this number of bytes in the main source file.
+ ///
+ /// The boolean indicates whether the preamble ends at the start of a new
+ /// line.
+ std::pair<unsigned, bool> PrecompiledPreambleBytes;
+
/// The implicit PTH input included at the start of the translation unit, or
/// empty.
std::string ImplicitPTHInclude;
@@ -62,6 +69,14 @@ public:
std::vector<std::pair<std::string, const llvm::MemoryBuffer *> >
RemappedFileBuffers;
+ /// \brief Whether the compiler instance should retain (i.e., not free)
+ /// the buffers associated with remapped files.
+ ///
+ /// This flag defaults to false; it can be set true only through direct
+ /// manipulation of the compiler invocation object, in cases where the
+ /// compiler invocation and its buffers will be reused.
+ bool RetainRemappedFileBuffers;
+
typedef std::vector<std::pair<std::string, std::string> >::iterator
remapped_file_iterator;
typedef std::vector<std::pair<std::string, std::string> >::const_iterator
@@ -97,7 +112,9 @@ public:
}
public:
- PreprocessorOptions() : UsePredefines(true), DetailedRecord(false) {}
+ PreprocessorOptions() : UsePredefines(true), DetailedRecord(false),
+ PrecompiledPreambleBytes(0, true),
+ RetainRemappedFileBuffers(false) { }
void addMacroDef(llvm::StringRef Name) {
Macros.push_back(std::make_pair(Name, false));
diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h
index 8dd37d0348..66a33f24f6 100644
--- a/include/clang/Lex/Lexer.h
+++ b/include/clang/Lex/Lexer.h
@@ -238,8 +238,10 @@ public:
/// \param Buffer The memory buffer containing the file's contents.
///
/// \returns The offset into the file where the preamble ends and the rest
- /// of the file begins.
- static unsigned ComputePreamble(const llvm::MemoryBuffer *Buffer);
+ /// of the file begins along with a boolean value indicating whether
+ /// the preamble ends at the beginning of a new line.
+ static std::pair<unsigned, bool>
+ ComputePreamble(const llvm::MemoryBuffer *Buffer);
//===--------------------------------------------------------------------===//
// Internal implementation interfaces.
@@ -383,6 +385,8 @@ private:
//===--------------------------------------------------------------------===//
// Other lexer functions.
+ void SkipBytes(unsigned Bytes, bool StartOfLine);
+
// Helper functions to lex the remainder of a token of the specific type.
void LexIdentifier (Token &Result, const char *CurPtr);
void LexNumericConstant (Token &Result, const char *CurPtr);
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 1ee4bb6351..380f788d22 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -134,6 +134,12 @@ class Preprocessor {
/// \brief The file that we're performing code-completion for, if any.
const FileEntry *CodeCompletionFile;
+ /// \brief The number of bytes that we will initially skip when entering the
+ /// main file, which is used when loading a precompiled preamble, along
+ /// with a flag that indicates whether skipping this number of bytes will
+ /// place the lexer at the start of a line.
+ std::pair<unsigned, bool> SkipMainFilePreamble;
+
/// CurLexer - This is the current top of the stack that we're lexing from if
/// not expanding a macro and we are lexing directly from source code.
/// Only one of CurLexer, CurPTHLexer, or CurTokenLexer will be non-null.
@@ -556,6 +562,18 @@ public:
/// for which we are performing code completion.
bool isCodeCompletionFile(SourceLocation FileLoc) const;
+ /// \brief Instruct the preprocessor to skip part of the main
+ /// the main source file.
+ ///
+ /// \brief Bytes The number of bytes in the preamble to skip.
+ ///
+ /// \brief StartOfLine Whether skipping these bytes puts the lexer at the
+ /// start of a line.
+ void setSkipMainFilePreamble(unsigned Bytes, bool StartOfLine) {
+ SkipMainFilePreamble.first = Bytes;
+ SkipMainFilePreamble.second = StartOfLine;
+ }
+
/// Diag - Forwarding function for diagnostics. This emits a diagnostic at
/// the specified Token's location, translating the token's start
/// position in the current buffer into a SourcePosition object for rendering.
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index e6d9785e15..4a1eb3096d 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -32,7 +32,8 @@ using llvm::MemoryBuffer;
//===----------------------------------------------------------------------===//
ContentCache::~ContentCache() {
- delete Buffer.getPointer();
+ if (shouldFreeBuffer())
+ delete Buffer.getPointer();
}
/// getSizeBytesMapped - Returns the number of bytes actually mapped for
@@ -51,12 +52,14 @@ unsigned ContentCache::getSize() const {
: (unsigned) Entry->getSize();
}
-void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) {
+void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B,
+ bool DoNotFree) {
assert(B != Buffer.getPointer());
- delete Buffer.getPointer();
+ if (shouldFreeBuffer())
+ delete Buffer.getPointer();
Buffer.setPointer(B);
- Buffer.setInt(false);
+ Buffer.setInt(DoNotFree? DoNotFreeFlag : 0);
}
const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
@@ -72,7 +75,6 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
struct stat FileInfo;
Buffer.setPointer(MemoryBuffer::getFile(Entry->getName(), &ErrorStr,
Entry->getSize(), &FileInfo));
- Buffer.setInt(false);
// If we were unable to open the file, then we are in an inconsistent
// situation where the content cache referenced a file which no longer
@@ -99,7 +101,7 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
Diag.Report(FullSourceLoc(Loc, SM), diag::err_cannot_open_file)
<< Entry->getName() << ErrorStr;
- Buffer.setInt(true);
+ Buffer.setInt(Buffer.getInt() | InvalidFlag);
// FIXME: This conditionalization is horrible, but we see spurious failures
// in the test suite due to this warning and no one has had time to hunt it
@@ -119,14 +121,14 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
Diag.Report(FullSourceLoc(Loc, SM), diag::err_file_modified)
<< Entry->getName();
- Buffer.setInt(true);
+ Buffer.setInt(Buffer.getInt() | InvalidFlag);
#endif
}
// If the buffer is valid, check to see if it has a UTF Byte Order Mark
// (BOM). We only support UTF-8 without a BOM right now. See
// http://en.wikipedia.org/wiki/Byte_order_mark for more information.
- if (!Buffer.getInt()) {
+ if (!isBufferInvalid()) {
llvm::StringRef BufStr = Buffer.getPointer()->getBuffer();
const char *BOM = 0;
if (BufStr.startswith("\xFE\xBB\xBF"))
@@ -161,7 +163,7 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
}
if (Invalid)
- *Invalid = Buffer.getInt();
+ *Invalid = isBufferInvalid();
return Buffer.getPointer();
}
@@ -521,12 +523,13 @@ SourceManager::getMemoryBufferForFile(const FileEntry *File,
}
bool SourceManager::overrideFileContents(const FileEntry *SourceFile,
- const llvm::MemoryBuffer *Buffer) {
+ const llvm::MemoryBuffer *Buffer,
+ bool DoNotFree) {
const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile);
if (IR == 0)
return true;
- const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(Buffer);
+ const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(Buffer, DoNotFree);
return false;
}
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 77a414772a..7ff3cdc5b9 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -46,6 +46,20 @@ ASTUnit::~ASTUnit() {
CleanTemporaryFiles();
if (!PreambleFile.empty())
PreambleFile.eraseFromDisk();
+
+ // Free the buffers associated with remapped files. We are required to
+ // perform this operation here because we explicitly request that the
+ // compiler instance *not* free these buffers for each invocation of the
+ // parser.
+ if (Invocation.get()) {
+ PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts();
+ for (PreprocessorOptions::remapped_file_buffer_iterator
+ FB = PPOpts.remapped_file_buffer_begin(),
+ FBEnd = PPOpts.remapped_file_buffer_end();
+ FB != FBEnd;
+ ++FB)
+ delete FB->second;
+ }
}
void ASTUnit::CleanTemporaryFiles() {
@@ -371,6 +385,17 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
// Create the source manager.
Clang.setSourceManager(&getSourceManager());
+ // If the main file has been overridden due to the use of a preamble,
+ // make that override happen and introduce the preamble.
+ PreprocessorOptions &PreprocessorOpts = Clang.getPreprocessorOpts();
+ if (OverrideMainBuffer) {
+ PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer);
+ PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
+ PreprocessorOpts.PrecompiledPreambleBytes.second
+ = PreambleEndsAtStartOfLine;
+ PreprocessorOpts.ImplicitPCHInclude = PreambleFile.str();
+ }
+
llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
Act.reset(new TopLevelDeclTrackerAction(*this));
if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
@@ -388,6 +413,11 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
Target.reset(Clang.takeTarget());
Act->EndSourceFile();
+
+ // Remove the overridden buffer we used for the preamble.
+ if (OverrideMainBuffer)
+ PreprocessorOpts.eraseRemappedFile(
+ PreprocessorOpts.remapped_file_buffer_end() - 1);
Clang.takeDiagnosticClient();
@@ -395,6 +425,11 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
return false;
error:
+ // Remove the overridden buffer we used for the preamble.
+ if (OverrideMainBuffer)
+ PreprocessorOpts.eraseRemappedFile(
+ PreprocessorOpts.remapped_file_buffer_end() - 1);
+
Clang.takeSourceManager();
Clang.takeFileManager();
Clang.takeDiagnosticClient();
@@ -424,8 +459,10 @@ static std::string GetPreamblePCHPath() {
return P.str();
}
-/// \brief Compute the preamble for the main file, providing
-std::pair<llvm::MemoryBuffer *, unsigned>
+/// \brief Compute the preamble for the main file, providing the source buffer
+/// that corresponds to the main file along with a pair (bytes, start-of-line)
+/// that describes the preamble.
+std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> >
ASTUnit::ComputePreamble(CompilerInvocation &Invocation, bool &CreatedBuffer) {
FrontendOptions &FrontendOpts = Invocation.getFrontendOpts();
PreprocessorOptions &PreprocessorOpts
@@ -455,7 +492,8 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation, bool &CreatedBuffer) {
Buffer = llvm::MemoryBuffer::getFile(M->second);
if (!Buffer)
- return std::make_pair((llvm::MemoryBuffer*)0, 0);
+ return std::make_pair((llvm::MemoryBuffer*)0,
+ std::make_pair(0, true));
CreatedBuffer = true;
// Remove this remapping. We've captured the buffer already.
@@ -495,7 +533,7 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation, bool &CreatedBuffer) {
if (!Buffer) {
Buffer = llvm::MemoryBuffer::getFile(FrontendOpts.Inputs[0].second);
if (!Buffer)
- return std::make_pair((llvm::MemoryBuffer*)0, 0);
+ return std::make_pair((llvm::MemoryBuffer*)0, std::make_pair(0, true));
CreatedBuffer = true;
}
@@ -512,9 +550,8 @@ static llvm::MemoryBuffer *CreatePaddedMainFileBuffer(llvm::MemoryBuffer *Old,
memcpy(const_cast<char*>(Result->getBufferStart()),
Old->getBufferStart(), Old->getBufferSize());
memset(const_cast<char*>(Result->getBufferStart()) + Old->getBufferSize(),
- ' ', NewSize - Old->getBufferSize() - 2);
- const_cast<char*>(Result->getBufferEnd())[-2] = '\n';
- const_cast<char*>(Result->getBufferEnd())[-1] = 0;
+ ' ', NewSize - Old->getBufferSize() - 1);
+ const_cast<char*>(Result->getBufferEnd())[-1] = '\n';
if (DeleteOld)
delete Old;
@@ -542,10 +579,10 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() {
= PreambleInvocation.getPreprocessorOpts();
bool CreatedPreambleBuffer = false;
- std::pair<llvm::MemoryBuffer *, unsigned> NewPreamble
+ std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> > NewPreamble
= ComputePreamble(PreambleInvocation, CreatedPreambleBuffer);
- if (!NewPreamble.second) {
+ if (!NewPreamble.second.first) {
// We couldn't find a preamble in the main source. Clear out the current
// preamble, if we have one. It's obviously no good any more.
Preamble.clear();
@@ -564,10 +601,11 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() {
// preamble now that we did before, and that there's enough space in
// the main-file buffer within the precompiled preamble to fit the
// new main file.
- if (Preamble.size() == NewPreamble.second &&
+ if (Preamble.size() == NewPreamble.second.first &&
+ PreambleEndsAtStartOfLine == NewPreamble.second.second &&
NewPreamble.first->getBufferSize() < PreambleReservedSize-2 &&
memcmp(&Preamble[0], NewPreamble.first->getBufferStart(),
- NewPreamble.second) == 0) {
+ NewPreamble.second.first) == 0) {
// The preamble has not changed. We may be able to re-use the precompiled
// preamble.
// FIXME: Check that none of the files used by the preamble have changed.
@@ -593,7 +631,7 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() {
// grows.
PreambleReservedSize = NewPreamble.first->getBufferSize();
if (PreambleReservedSize < 4096)
- PreambleReservedSize = 8192;
+ PreambleReservedSize = 8191;
else
PreambleReservedSize *= 2;
@@ -603,14 +641,15 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() {
memcpy(const_cast<char*>(PreambleBuffer->getBufferStart()),
NewPreamble.first->getBufferStart(), Preamble.size());
memset(const_cast<char*>(PreambleBuffer->getBufferStart()) + Preamble.size(),
- ' ', PreambleReservedSize - Preamble.size() - 2);
- const_cast<char*>(PreambleBuffer->getBufferEnd())[-1] = 0;
- const_cast<char*>(PreambleBuffer->getBufferEnd())[-2] = '\n';
+ ' ', PreambleReservedSize - Preamble.size() - 1);
+ const_cast<char*>(PreambleBuffer->getBufferEnd())[-1] = '\n';
// Save the preamble text for later; we'll need to compare against it for
// subsequent reparses.
Preamble.assign(NewPreamble.first->getBufferStart(),
- NewPreamble.first->getBufferStart() + NewPreamble.second);
+ NewPreamble.first->getBufferStart()
+ + NewPreamble.second.first);
+ PreambleEndsAtStartOfLine = NewPreamble.second.second;
// Remap the main source file to the preamble buffer.
llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].second);
@@ -734,6 +773,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
AST->CaptureDiagnostics = CaptureDiagnostics;
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->Invocation.reset(CI);
+ CI->getPreprocessorOpts().RetainRemappedFileBuffers = true;
llvm::MemoryBuffer *OverrideMainBuffer = 0;
if (PrecompilePreamble)
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index a0c7c7c76d..68703c22fb 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -1353,6 +1353,23 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Opts.TokenCache = Opts.ImplicitPTHInclude;
Opts.UsePredefines = !Args.hasArg(OPT_undef);
Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record);
+
+ if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) {
+ llvm::StringRef Value(A->getValue(Args));
+ size_t Comma = Value.find(',');
+ unsigned Bytes = 0;
+ unsigned EndOfLine = 0;
+
+ if (Comma == llvm::StringRef::npos ||
+ Value.substr(0, Comma).getAsInteger(10, Bytes) ||
+ Value.substr(Comma + 1).getAsInteger(10, EndOfLine))
+ Diags.Report(diag::err_drv_preamble_format);
+ else {
+ Opts.PrecompiledPreambleBytes.first = Bytes;
+ Opts.PrecompiledPreambleBytes.second = (EndOfLine != 0);
+ }
+ }
+
// Add macros from the command line.
for (arg_iterator it = Args.filtered_begin(OPT_D, OPT_U),
ie = Args.filtered_end(); it != ie; ++it) {
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 2c0132ad2d..2d1287f85b 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -195,7 +195,7 @@ void PrintPreambleAction::ExecuteAction() {
llvm::MemoryBuffer *Buffer = llvm::MemoryBuffer::getFile(getCurrentFile());
if (Buffer) {
- unsigned Preamble = Lexer::ComputePreamble(Buffer);
+ unsigned Preamble = Lexer::ComputePreamble(Buffer).first;
llvm::outs().write(Buffer->getBufferStart(), Preamble);
delete Buffer;
}
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 15d804f7b4..9990fc42ba 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -489,13 +489,15 @@ static void InitializeFileRemapping(Diagnostic &Diags,
if (!FromFile) {
Diags.Report(diag::err_fe_remap_missing_from_file)
<< Remap->first;
- delete Remap->second;
+ if (!InitOpts.RetainRemappedFileBuffers)
+ delete Remap->second;
continue;
}
// Override the contents of the "from" file with the contents of
// the "to" file.
- SourceMgr.overrideFileContents(FromFile, Remap->second);
+ SourceMgr.overrideFileContents(FromFile, Remap->second,
+ InitOpts.RetainRemappedFileBuffers);
}
// Remap files in the source manager (with other files).
@@ -596,6 +598,10 @@ void clang::InitializePreprocessor(Preprocessor &PP,
if (!PP.getLangOptions().AsmPreprocessor)
Builder.append("# 1 \"<built-in>\" 2");
+ // Instruct the preprocessor to skip the preamble.
+ PP.setSkipMainFilePreamble(InitOpts.PrecompiledPreambleBytes.first,
+ InitOpts.PrecompiledPreambleBytes.second);
+
// Copy PredefinedBuffer into the Preprocessor.
PP.setPredefines(Predefines.str());
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index b23122cbcc..5e435908be 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -310,7 +310,8 @@ namespace {
};
}
-unsigned Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer) {
+std::pair<unsigned, bool>
+Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer) {
// Create a lexer starting at the beginning of the file. Note that we use a
// "fake" file source location at offset 1 so that the lexer will track our
// position within the file.
@@ -422,7 +423,9 @@ unsigned Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer) {
} while (true);
SourceLocation End = IfCount? IfStartTok.getLocation() : TheTok.getLocation();
- return End.getRawEncoding() - StartLoc.getRawEncoding();
+ return std::make_pair(End.getRawEncoding() - StartLoc.getRawEncoding(),
+ IfCount? IfStartTok.isAtStartOfLine()
+ : TheTok.isAtStartOfLine());
}
//===----------------------------------------------------------------------===//
@@ -825,6 +828,14 @@ Slash:
// Helper methods for lexing.
//===----------------------------------------------------------------------===//
+/// \brief Routine that indiscriminately skips bytes in the source file.
+void Lexer::SkipBytes(unsigned Bytes, bool StartOfLine) {
+ BufferPtr += Bytes;
+ if (BufferPtr > BufferEnd)
+ BufferPtr = BufferEnd;
+ IsAtStartOfLine = StartOfLine;
+}
+
void Lexer::LexIdentifier(Token &Result, const char *CurPtr) {
// Match [_A-Za-z0-9]*, we have already matched [_A-Za-z$]
unsigned Size;
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 51f729334c..fc1418ffef 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -54,7 +54,8 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
: Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()),
SourceMgr(SM), HeaderInfo(Headers), ExternalSource(0),
Identifiers(opts, IILookup), BuiltinInfo(Target), CodeCompletionFile(0),
- CurPPLexer(0), CurDirLookup(0), Callbacks(0), MacroArgCache(0), Record(0) {
+ SkipMainFilePreamble(0, true), CurPPLexer(0), CurDirLookup(0), Callbacks(0),
+ MacroArgCache(0), Record(0) {
ScratchBuf = new ScratchBuffer(SourceMgr);
CounterValue = 0; // __COUNTER__ starts at 0.
OwnsHeaderSearch = OwnsHeaders;
@@ -508,6 +509,12 @@ void Preprocessor::EnterMainSourceFile() {
// Enter the main file source buffer.
EnterSourceFile(MainFileID, 0, SourceLocation());
+ // If we've been asked to skip bytes in the main file (e.g., as part of a
+ // precompiled preamble), do so now.
+ if (SkipMainFilePreamble.first > 0)
+ CurLexer->SkipBytes(SkipMainFilePreamble.first,
+ SkipMainFilePreamble.second);
+
// Tell the header info that the main file was entered. If the file is later
// #imported, it won't be re-entered.
if (const FileEntry *FE = SourceMgr.getFileEntryForID(MainFileID))
diff --git a/test/PCH/Inputs/preamble.h b/test/PCH/Inputs/preamble.h
new file mode 100644
index 0000000000..aee330a3f9
--- /dev/null
+++ b/test/PCH/Inputs/preamble.h
@@ -0,0 +1 @@
+int f(int);
diff --git a/test/PCH/preamble.c b/test/PCH/preamble.c
new file mode 100644
index 0000000000..bdc0aea656
--- /dev/null
+++ b/test/PCH/preamble.c
@@ -0,0 +1,21 @@
+// Check that using the preamble option actually skips the preamble.
+
+// RUN: %clang_cc1 -emit-pch -o %t %S/Inputs/preamble.h
+// RUN: %clang_cc1 -include-pch %t -preamble-bytes=278,1 -DFOO=f -verify %s
+
+float f(int); // Not an error, because we skip this via the preamble!
+
+
+
+
+
+
+
+
+
+
+
+
+int g(int x) {
+ return FOO(x);
+}