Implement (de-)serialization of the buffer contents for an overridden
file in the source manager. This allows us to properly create and use
modules described by module map files without umbrella headers (or
with incompletely umbrella headers). More generally, we can actually
build a PCH file that makes use of file -> buffer remappings, which
could be useful in libclang in the future.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@144830 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index 5555557..cfd0430 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -102,8 +102,15 @@
/// NumLines - The number of lines in this ContentCache. This is only valid
/// if SourceLineCache is non-null.
- unsigned NumLines;
+ unsigned NumLines : 31;
+ /// \brief Indicates whether the buffer itself was provided to override
+ /// the actual file contents.
+ ///
+ /// When true, the original entry may be a virtual file that does not
+ /// exist.
+ unsigned BufferOverridden : 1;
+
/// getBuffer - Returns the memory buffer for the associated content.
///
/// \param Diag Object through which diagnostics will be emitted if the
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index e3a1020..53d970b 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -452,7 +452,8 @@
SM_SLOC_BUFFER_ENTRY = 2,
/// \brief Describes a blob that contains the data for a buffer
/// entry. This kind of record always directly follows a
- /// SM_SLOC_BUFFER_ENTRY record.
+ /// SM_SLOC_BUFFER_ENTRY record or a SM_SLOC_FILE_ENTRY with an
+ /// overridden buffer.
SM_SLOC_BUFFER_BLOB = 3,
/// \brief Describes a source location entry (SLocEntry) for a
/// macro expansion.
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index ddb1f39..cdaff2f 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -580,6 +580,7 @@
assert(IR && "getOrCreateContentCache() cannot return NULL");
const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(Buffer, DoNotFree);
+ const_cast<SrcMgr::ContentCache *>(IR)->BufferOverridden = true;
}
void SourceManager::overrideFileContents(const FileEntry *SourceFile,
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 8961974..0b2a884 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -1081,9 +1081,18 @@
return Failure;
case SM_SLOC_FILE_ENTRY: {
- std::string Filename(BlobStart, BlobStart + BlobLen);
+ if (Record.size() < 7) {
+ Error("source location entry is incorrect");
+ return Failure;
+ }
+
+ bool OverriddenBuffer = Record[6];
+
+ std::string OrigFilename(BlobStart, BlobStart + BlobLen);
+ std::string Filename = OrigFilename;
MaybeAddSystemRootToFilename(Filename);
- const FileEntry *File = FileMgr.getFile(Filename);
+ const FileEntry *File = FileMgr.getFile(Filename, /*OpenFile=*/false,
+ /*CacheFailure=*/!OverriddenBuffer);
if (File == 0 && !OriginalDir.empty() && !CurrentDir.empty() &&
OriginalDir != CurrentDir) {
std::string resolved = resolveFileRelativeToOriginalDir(Filename,
@@ -1103,11 +1112,6 @@
return Failure;
}
- if (Record.size() < 6) {
- Error("source location entry is incorrect");
- return Failure;
- }
-
if (!DisableValidation &&
((off_t)Record[4] != File->getSize()
#if !defined(LLVM_ON_WIN32)
@@ -1131,18 +1135,35 @@
ID, BaseOffset + Record[0]);
SrcMgr::FileInfo &FileInfo =
const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile());
- FileInfo.NumCreatedFIDs = Record[6];
+ FileInfo.NumCreatedFIDs = Record[7];
if (Record[3])
FileInfo.setHasLineDirectives();
- const DeclID *FirstDecl = F->FileSortedDecls + Record[7];
- unsigned NumFileDecls = Record[8];
+ const DeclID *FirstDecl = F->FileSortedDecls + Record[8];
+ unsigned NumFileDecls = Record[9];
if (NumFileDecls) {
assert(F->FileSortedDecls && "FILE_SORTED_DECLS not encountered yet ?");
FileDeclIDs[FID] = FileDeclsInfo(F, llvm::makeArrayRef(FirstDecl,
NumFileDecls));
}
+ if (OverriddenBuffer &&
+ !SourceMgr.getOrCreateContentCache(File)->BufferOverridden) {
+ unsigned Code = SLocEntryCursor.ReadCode();
+ Record.clear();
+ unsigned RecCode
+ = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen);
+
+ if (RecCode != SM_SLOC_BUFFER_BLOB) {
+ Error("AST record has invalid code");
+ return Failure;
+ }
+
+ llvm::MemoryBuffer *Buffer
+ = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1),
+ Filename);
+ SourceMgr.overrideFileContents(File, Buffer);
+ }
break;
}
@@ -1160,8 +1181,8 @@
}
llvm::MemoryBuffer *Buffer
- = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1),
- Name);
+ = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1),
+ Name);
FileID BufferID = SourceMgr.createFileIDForMemBuffer(Buffer, ID,
BaseOffset + Offset);
@@ -2341,6 +2362,10 @@
return Failure;
case SM_SLOC_FILE_ENTRY: {
+ // If the buffer was overridden, the file need not exist.
+ if (Record[6])
+ break;
+
StringRef Filename(BlobStart, BlobLen);
const FileEntry *File = getFileEntry(Filename);
@@ -2352,7 +2377,7 @@
return IgnorePCH;
}
- if (Record.size() < 6) {
+ if (Record.size() < 7) {
Error("source location entry is incorrect");
return Failure;
}
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 6893dbd..51aadb3 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -1174,6 +1174,7 @@
// FileEntry fields.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // BufferOverridden
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumCreatedFIDs
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 24)); // FirstDeclIndex
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumDecls
@@ -1421,7 +1422,8 @@
// Figure out which record code to use.
unsigned Code;
if (SLoc->isFile()) {
- if (SLoc->getFile().getContentCache()->OrigEntry) {
+ const SrcMgr::ContentCache *Cache = SLoc->getFile().getContentCache();
+ if (Cache->OrigEntry) {
Code = SM_SLOC_FILE_ENTRY;
SLocFileEntryOffsets.push_back(Stream.GetCurrentBitNo());
} else
@@ -1442,7 +1444,7 @@
const SrcMgr::ContentCache *Content = File.getContentCache();
if (Content->OrigEntry) {
assert(Content->OrigEntry == Content->ContentsEntry &&
- "Writing to AST an overriden file is not supported");
+ "Writing to AST an overridden file is not supported");
// The source location entry is a file. The blob associated
// with this entry is the file name.
@@ -1450,7 +1452,7 @@
// Emit size/modification time for this file.
Record.push_back(Content->OrigEntry->getSize());
Record.push_back(Content->OrigEntry->getModificationTime());
-
+ Record.push_back(Content->BufferOverridden);
Record.push_back(File.NumCreatedFIDs);
FileDeclIDsTy::iterator FDI = FileDeclIDs.find(SLoc);
@@ -1461,7 +1463,7 @@
Record.push_back(0);
Record.push_back(0);
}
-
+
// Turn the file name into an absolute path, if it isn't already.
const char *Filename = Content->OrigEntry->getName();
llvm::SmallString<128> FilePath(Filename);
@@ -1477,6 +1479,16 @@
Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
Stream.EmitRecordWithBlob(SLocFileAbbrv, Record, Filename);
+
+ if (Content->BufferOverridden) {
+ Record.clear();
+ Record.push_back(SM_SLOC_BUFFER_BLOB);
+ const llvm::MemoryBuffer *Buffer
+ = Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager());
+ Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record,
+ StringRef(Buffer->getBufferStart(),
+ Buffer->getBufferSize() + 1));
+ }
} else {
// The source location entry is a buffer. The blob associated
// with this entry contains the contents of the buffer.
diff --git a/test/Modules/normal-module-map.cpp b/test/Modules/normal-module-map.cpp
index 9e9f315..c8338b7 100644
--- a/test/Modules/normal-module-map.cpp
+++ b/test/Modules/normal-module-map.cpp
@@ -1,4 +1,8 @@
// RUN: rm -rf %t
+// FIXME: Eventually, we should be able to remove these explicit module creation lines
+// RUN: %clang_cc1 -x objective-c -fmodule-cache-path %t -fmodule-name=libA -emit-module-from-map %S/Inputs/normal-module-map/module.map
+// RUN: %clang_cc1 -x objective-c -fmodule-cache-path %t -fmodule-name=libB -emit-module-from-map %S/Inputs/normal-module-map/module.map
+// RUN: %clang_cc1 -x objective-c -fmodule-cache-path %t -fmodule-name=libNested -emit-module-from-map %S/Inputs/normal-module-map/nested/module.map
// RUN: %clang_cc1 -x objective-c -fmodule-cache-path %t -fauto-module-import -I %S/Inputs/normal-module-map %s -verify
#include "Umbrella/Umbrella.h"
@@ -8,9 +12,7 @@
__import_module__ Umbrella2;
-// FIXME: The expected error here is temporary, since we don't yet have the
-// logic to build a module from a module map.
-#include "a1.h" // expected-error{{module 'libA' not found}}
+#include "a1.h"
#include "b1.h"
#include "nested/nested2.h"