From bd94500d3aa60092fb0f1e90f53fb0d03fa502a8 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 13 Apr 2009 16:31:14 +0000 Subject: [PATCH] Include the SourceManager's line table in the PCH file. We can now properly cope with #line directives in PCH files. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68963 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/SourceManager.h | 18 ++++-- include/clang/Basic/SourceManagerInternals.h | 12 +++- include/clang/Frontend/PCHBitCodes.h | 5 +- lib/Basic/SourceManager.cpp | 11 ++++ lib/Frontend/PCHReader.cpp | 58 +++++++++++++++++++- lib/Frontend/PCHWriter.cpp | 40 +++++++++++++- test/PCH/line-directive.c | 25 +++++++++ test/PCH/line-directive.h | 2 + test/PCH/variables.c | 2 +- 9 files changed, 159 insertions(+), 14 deletions(-) create mode 100644 test/PCH/line-directive.c create mode 100644 test/PCH/line-directive.h diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h index dcf344e412..217640eaa5 100644 --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -589,7 +589,13 @@ public: void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID, bool IsFileEntry, bool IsFileExit, bool IsSystemHeader, bool IsExternCHeader); - + + /// \brief Determine if the source manager has a line table. + bool hasLineTable() const { return LineTable != 0; } + + /// \brief Retrieve the stored line table. + LineTableInfo &getLineTable(); + //===--------------------------------------------------------------------===// // Other miscellaneous methods. //===--------------------------------------------------------------------===// @@ -624,6 +630,11 @@ public: unsigned sloc_entry_size() const { return SLocEntryTable.size(); } + const SrcMgr::SLocEntry &getSLocEntry(FileID FID) const { + assert(FID.ID < SLocEntryTable.size() && "Invalid id"); + return SLocEntryTable[FID.ID]; + } + private: friend class SrcMgr::ContentCache; // Used for deserialization. @@ -654,11 +665,6 @@ private: /// memory buffer. const SrcMgr::ContentCache* createMemBufferContentCache(const llvm::MemoryBuffer *Buf); - - const SrcMgr::SLocEntry &getSLocEntry(FileID FID) const { - assert(FID.ID < SLocEntryTable.size() && "Invalid id"); - return SLocEntryTable[FID.ID]; - } FileID getFileIDSlow(unsigned SLocOffset) const; diff --git a/include/clang/Basic/SourceManagerInternals.h b/include/clang/Basic/SourceManagerInternals.h index 2f90f64b0f..0bcb68e460 100644 --- a/include/clang/Basic/SourceManagerInternals.h +++ b/include/clang/Basic/SourceManagerInternals.h @@ -102,7 +102,8 @@ public: assert(ID < FilenamesByID.size() && "Invalid FilenameID"); return FilenamesByID[ID]->getKeyData(); } - + unsigned getNumFilenames() const { return FilenamesByID.size(); } + void AddLineNote(unsigned FID, unsigned Offset, unsigned LineNo, int FilenameID); void AddLineNote(unsigned FID, unsigned Offset, @@ -113,6 +114,15 @@ public: /// FindNearestLineEntry - Find the line entry nearest to FID that is before /// it. If there is no line entry before Offset in FID, return null. const LineEntry *FindNearestLineEntry(unsigned FID, unsigned Offset); + + // Low-level access + typedef std::map >::iterator iterator; + iterator begin() { return LineEntries.begin(); } + iterator end() { return LineEntries.end(); } + + /// \brief Add a new line entry that has already been encoded into + /// the internal representation of the line table. + void AddEntry(unsigned FID, const std::vector &Entries); }; } // end namespace clang diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index 7782f36f43..79d70c8a61 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -147,7 +147,10 @@ namespace clang { SM_SLOC_BUFFER_BLOB = 3, /// \brief Describes a source location entry (SLocEntry) for a /// macro instantiation. - SM_SLOC_INSTANTIATION_ENTRY = 4 + SM_SLOC_INSTANTIATION_ENTRY = 4, + /// \brief Describes the SourceManager's line table, with + /// information about #line directives. + SM_LINE_TABLE = 5 }; /// \brief Record types used within a preprocessor block. diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index d3fbeeb1bb..ed541bfc6b 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -157,6 +157,12 @@ const LineEntry *LineTableInfo::FindNearestLineEntry(unsigned FID, return &*--I; } +/// \brief Add a new line entry that has already been encoded into +/// the internal representation of the line table. +void LineTableInfo::AddEntry(unsigned FID, + const std::vector &Entries) { + LineEntries[FID] = Entries; +} /// getLineTableFilenameID - Return the uniqued ID for the specified filename. /// @@ -224,6 +230,11 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo, EntryExit, FileKind); } +LineTableInfo &SourceManager::getLineTable() { + if (LineTable == 0) + LineTable = new LineTableInfo(); + return *LineTable; +} //===----------------------------------------------------------------------===// // Private 'Create' methods. diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index fa6ad6f0a0..4998de371f 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -18,6 +18,7 @@ #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceManagerInternals.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/TargetInfo.h" #include "llvm/Bitcode/BitstreamReader.h" @@ -191,6 +192,50 @@ bool PCHReader::CheckPredefinesBuffer(const char *PCHPredef, return true; } +/// \brief Read the line table in the source manager block. +/// \returns true if ther was an error. +static bool ParseLineTable(SourceManager &SourceMgr, + llvm::SmallVectorImpl &Record) { + unsigned Idx = 0; + LineTableInfo &LineTable = SourceMgr.getLineTable(); + + // Parse the file names + for (unsigned I = 0, N = Record[Idx++]; I != N; ++I) { + // Extract the file name + unsigned FilenameLen = Record[Idx++]; + std::string Filename(&Record[Idx], &Record[Idx] + FilenameLen); + Idx += FilenameLen; + unsigned ID = LineTable.getLineTableFilenameID(Filename.c_str(), + Filename.size()); + if (ID != I) + return Error("Filename ID mismatch in PCH line table"); + } + + // Parse the line entries + std::vector Entries; + while (Idx < Record.size()) { + unsigned FID = Record[Idx++]; + + // Extract the line entries + unsigned NumEntries = Record[Idx++]; + Entries.clear(); + Entries.reserve(NumEntries); + for (unsigned I = 0; I != NumEntries; ++I) { + unsigned FileOffset = Record[Idx++]; + unsigned LineNo = Record[Idx++]; + int FilenameID = Record[Idx++]; + SrcMgr::CharacteristicKind FileKind + = (SrcMgr::CharacteristicKind)Record[Idx++]; + unsigned IncludeOffset = Record[Idx++]; + Entries.push_back(LineEntry::get(FileOffset, LineNo, FilenameID, + FileKind, IncludeOffset)); + } + LineTable.AddEntry(FID, Entries); + } + + return false; +} + /// \brief Read the source manager block PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() { using namespace SrcMgr; @@ -242,9 +287,12 @@ PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() { const FileEntry *File = PP.getFileManager().getFile(BlobStart, BlobStart + BlobLen); // FIXME: Error recovery if file cannot be found. - SourceMgr.createFileID(File, - SourceLocation::getFromRawEncoding(Record[1]), - (CharacteristicKind)Record[2]); + FileID ID = SourceMgr.createFileID(File, + SourceLocation::getFromRawEncoding(Record[1]), + (CharacteristicKind)Record[2]); + if (Record[3]) + const_cast(SourceMgr.getSLocEntry(ID).getFile()) + .setHasLineDirectives(); break; } @@ -278,6 +326,10 @@ PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() { break; } + case pch::SM_LINE_TABLE: { + if (ParseLineTable(SourceMgr, Record)) + return Failure; + } } } } diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 2cf932ce9b..6056fbc539 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -21,6 +21,7 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceManagerInternals.h" #include "clang/Basic/TargetInfo.h" #include "llvm/Bitcode/BitstreamWriter.h" #include "llvm/Support/Compiler.h" @@ -503,8 +504,7 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr) { const SrcMgr::FileInfo &File = SLoc->getFile(); Record.push_back(File.getIncludeLoc().getRawEncoding()); Record.push_back(File.getFileCharacteristic()); // FIXME: stable encoding - Record.push_back(File.hasLineDirectives()); // FIXME: encode the - // line directives? + Record.push_back(File.hasLineDirectives()); const SrcMgr::ContentCache *Content = File.getContentCache(); if (Content->Entry) { @@ -550,6 +550,42 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr) { Record.clear(); } + // Write the line table. + if (SourceMgr.hasLineTable()) { + LineTableInfo &LineTable = SourceMgr.getLineTable(); + + // Emit the file names + Record.push_back(LineTable.getNumFilenames()); + for (unsigned I = 0, N = LineTable.getNumFilenames(); I != N; ++I) { + // Emit the file name + const char *Filename = LineTable.getFilename(I); + unsigned FilenameLen = Filename? strlen(Filename) : 0; + Record.push_back(FilenameLen); + if (FilenameLen) + Record.insert(Record.end(), Filename, Filename + FilenameLen); + } + + // Emit the line entries + for (LineTableInfo::iterator L = LineTable.begin(), LEnd = LineTable.end(); + L != LEnd; ++L) { + // Emit the file ID + Record.push_back(L->first); + + // Emit the line entries + Record.push_back(L->second.size()); + for (std::vector::iterator LE = L->second.begin(), + LEEnd = L->second.end(); + LE != LEEnd; ++LE) { + Record.push_back(LE->FileOffset); + Record.push_back(LE->LineNo); + Record.push_back(LE->FilenameID); + Record.push_back((unsigned)LE->FileKind); + Record.push_back(LE->IncludeOffset); + } + S.EmitRecord(pch::SM_LINE_TABLE, Record); + } + } + S.ExitBlock(); } diff --git a/test/PCH/line-directive.c b/test/PCH/line-directive.c new file mode 100644 index 0000000000..87aa4b0a52 --- /dev/null +++ b/test/PCH/line-directive.c @@ -0,0 +1,25 @@ +// Test this without pch. +// RUN: clang-cc -triple=i686-apple-darwin9 -include %S/line-directive.h -fsyntax-only %s 2>&1|grep "25:5" + +// Test with pch. +// RUN: clang-cc -emit-pch -triple=i686-apple-darwin9 -o %t %S/line-directive.h && +// RUN: clang-cc -triple=i686-apple-darwin9 -include-pch %t -fsyntax-only %s 2>&1|grep "25:5" + +double x; // expected-error{{redefinition of 'x' with a different type}} + + + + + + + + + + + + + + + + +// expected-note{{previous definition is here}} diff --git a/test/PCH/line-directive.h b/test/PCH/line-directive.h new file mode 100644 index 0000000000..c5594b420e --- /dev/null +++ b/test/PCH/line-directive.h @@ -0,0 +1,2 @@ +#line 25 "line-directive.c" +int x; diff --git a/test/PCH/variables.c b/test/PCH/variables.c index f725e7d8f0..ec1657617e 100644 --- a/test/PCH/variables.c +++ b/test/PCH/variables.c @@ -1,5 +1,5 @@ // Test this without pch. -// RUN: clang-cc -triple=i686-apple-darwin9 -include %S/variables.h -fsyntax-only -verify %s && +// RUN: clang-cc -triple=i686-apple-darwin9 -include %S/variables.h -fsyntax-only -verify %s // Test with pch. // RUN: clang-cc -emit-pch -triple=i686-apple-darwin9 -o %t %S/variables.h && -- 2.40.0