diff options
-rw-r--r-- | include/clang/Basic/DiagnosticDriverKinds.td | 2 | ||||
-rw-r--r-- | include/clang/Basic/SourceManager.h | 29 | ||||
-rw-r--r-- | include/clang/Driver/CC1Options.td | 2 | ||||
-rw-r--r-- | include/clang/Frontend/ASTUnit.h | 11 | ||||
-rw-r--r-- | include/clang/Frontend/PreprocessorOptions.h | 19 | ||||
-rw-r--r-- | include/clang/Lex/Lexer.h | 8 | ||||
-rw-r--r-- | include/clang/Lex/Preprocessor.h | 18 | ||||
-rw-r--r-- | lib/Basic/SourceManager.cpp | 25 | ||||
-rw-r--r-- | lib/Frontend/ASTUnit.cpp | 72 | ||||
-rw-r--r-- | lib/Frontend/CompilerInvocation.cpp | 17 | ||||
-rw-r--r-- | lib/Frontend/FrontendActions.cpp | 2 | ||||
-rw-r--r-- | lib/Frontend/InitPreprocessor.cpp | 10 | ||||
-rw-r--r-- | lib/Lex/Lexer.cpp | 15 | ||||
-rw-r--r-- | lib/Lex/Preprocessor.cpp | 9 | ||||
-rw-r--r-- | test/PCH/Inputs/preamble.h | 1 | ||||
-rw-r--r-- | test/PCH/preamble.c | 21 |
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); +} |