summaryrefslogtreecommitdiffstats
path: root/clang/lib/Serialization
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Serialization')
-rw-r--r--clang/lib/Serialization/ASTReader.cpp199
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp150
-rw-r--r--clang/lib/Serialization/GeneratePCH.cpp2
-rw-r--r--clang/lib/Serialization/GlobalModuleIndex.cpp76
4 files changed, 316 insertions, 111 deletions
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 648c7b48ed8..be0cc9ab1a8 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -2163,7 +2163,7 @@ static bool isDiagnosedResult(ASTReader::ASTReadResult ARR, unsigned Caps) {
ASTReader::ASTReadResult ASTReader::ReadOptionsBlock(
BitstreamCursor &Stream, unsigned ClientLoadCapabilities,
bool AllowCompatibleConfigurationMismatch, ASTReaderListener &Listener,
- std::string &SuggestedPredefines, bool ValidateDiagnosticOptions) {
+ std::string &SuggestedPredefines) {
if (Stream.EnterSubBlock(OPTIONS_BLOCK_ID))
return Failure;
@@ -2205,15 +2205,6 @@ ASTReader::ASTReadResult ASTReader::ReadOptionsBlock(
break;
}
- case DIAGNOSTIC_OPTIONS: {
- bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0;
- if (ValidateDiagnosticOptions &&
- !AllowCompatibleConfigurationMismatch &&
- ParseDiagnosticOptions(Record, Complain, Listener))
- return OutOfDate;
- break;
- }
-
case FILE_SYSTEM_OPTIONS: {
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
if (!AllowCompatibleConfigurationMismatch &&
@@ -2254,6 +2245,23 @@ ASTReader::ReadControlBlock(ModuleFile &F,
return Failure;
}
+ // Lambda to read the unhashed control block the first time it's called.
+ //
+ // For PCM files, the unhashed control block cannot be read until after the
+ // MODULE_NAME record. However, PCH files have no MODULE_NAME, and yet still
+ // need to look ahead before reading the IMPORTS record. For consistency,
+ // this block is always read somehow (see BitstreamEntry::EndBlock).
+ bool HasReadUnhashedControlBlock = false;
+ auto readUnhashedControlBlockOnce = [&]() {
+ if (!HasReadUnhashedControlBlock) {
+ HasReadUnhashedControlBlock = true;
+ if (ASTReadResult Result =
+ readUnhashedControlBlock(F, ImportedBy, ClientLoadCapabilities))
+ return Result;
+ }
+ return Success;
+ };
+
// Read all of the records and blocks in the control block.
RecordData Record;
unsigned NumInputs = 0;
@@ -2266,6 +2274,11 @@ ASTReader::ReadControlBlock(ModuleFile &F,
Error("malformed block record in AST file");
return Failure;
case llvm::BitstreamEntry::EndBlock: {
+ // Validate the module before returning. This call catches an AST with
+ // no module name and no imports.
+ if (ASTReadResult Result = readUnhashedControlBlockOnce())
+ return Result;
+
// Validate input files.
const HeaderSearchOptions &HSOpts =
PP.getHeaderSearchInfo().getHeaderSearchOpts();
@@ -2337,13 +2350,10 @@ ASTReader::ReadControlBlock(ModuleFile &F,
// FIXME: Allow this for files explicitly specified with -include-pch.
bool AllowCompatibleConfigurationMismatch =
F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule;
- const HeaderSearchOptions &HSOpts =
- PP.getHeaderSearchInfo().getHeaderSearchOpts();
Result = ReadOptionsBlock(Stream, ClientLoadCapabilities,
AllowCompatibleConfigurationMismatch,
- *Listener, SuggestedPredefines,
- HSOpts.ModulesValidateDiagnosticOptions);
+ *Listener, SuggestedPredefines);
if (Result == Failure) {
Error("malformed block record in AST file");
return Result;
@@ -2417,12 +2427,13 @@ ASTReader::ReadControlBlock(ModuleFile &F,
break;
}
- case SIGNATURE:
- assert((!F.Signature || F.Signature == Record[0]) && "signature changed");
- F.Signature = Record[0];
- break;
-
case IMPORTS: {
+ // Validate the AST before processing any imports (otherwise, untangling
+ // them can be error-prone and expensive). A module will have a name and
+ // will already have been validated, but this catches the PCH case.
+ if (ASTReadResult Result = readUnhashedControlBlockOnce())
+ return Result;
+
// Load each of the imported PCH files.
unsigned Idx = 0, N = Record.size();
while (Idx < N) {
@@ -2435,7 +2446,10 @@ ASTReader::ReadControlBlock(ModuleFile &F,
ReadUntranslatedSourceLocation(Record[Idx++]);
off_t StoredSize = (off_t)Record[Idx++];
time_t StoredModTime = (time_t)Record[Idx++];
- ASTFileSignature StoredSignature = Record[Idx++];
+ ASTFileSignature StoredSignature = {
+ {{(uint32_t)Record[Idx++], (uint32_t)Record[Idx++],
+ (uint32_t)Record[Idx++], (uint32_t)Record[Idx++],
+ (uint32_t)Record[Idx++]}}};
auto ImportedFile = ReadPath(F, Record, Idx);
// If our client can't cope with us being out of date, we can't cope with
@@ -2487,6 +2501,12 @@ ASTReader::ReadControlBlock(ModuleFile &F,
F.ModuleName = Blob;
if (Listener)
Listener->ReadModuleName(F.ModuleName);
+
+ // Validate the AST as soon as we have a name so we can exit early on
+ // failure.
+ if (ASTReadResult Result = readUnhashedControlBlockOnce())
+ return Result;
+
break;
case MODULE_DIRECTORY: {
@@ -3076,14 +3096,6 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
F.ObjCCategories.swap(Record);
break;
- case DIAG_PRAGMA_MAPPINGS:
- if (F.PragmaDiagMappings.empty())
- F.PragmaDiagMappings.swap(Record);
- else
- F.PragmaDiagMappings.insert(F.PragmaDiagMappings.end(),
- Record.begin(), Record.end());
- break;
-
case CUDA_SPECIAL_DECL_REFS:
// Later tables overwrite earlier ones.
// FIXME: Modules will have trouble with this.
@@ -3657,10 +3669,10 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
unsigned NumModules = ModuleMgr.size();
SmallVector<ImportedModule, 4> Loaded;
- switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type, ImportLoc,
- /*ImportedBy=*/nullptr, Loaded,
- 0, 0, 0,
- ClientLoadCapabilities)) {
+ switch (ASTReadResult ReadResult =
+ ReadASTCore(FileName, Type, ImportLoc,
+ /*ImportedBy=*/nullptr, Loaded, 0, 0,
+ ASTFileSignature(), ClientLoadCapabilities)) {
case Failure:
case Missing:
case OutOfDate:
@@ -4021,6 +4033,12 @@ ASTReader::ReadASTCore(StringRef FileName,
Loaded.push_back(ImportedModule(M, ImportedBy, ImportLoc));
return Success;
+ case UNHASHED_CONTROL_BLOCK_ID:
+ // This block is handled using look-ahead during ReadControlBlock. We
+ // shouldn't get here!
+ Error("malformed block record in AST file");
+ return Failure;
+
default:
if (Stream.SkipBlock()) {
Error("malformed block record in AST file");
@@ -4033,6 +4051,93 @@ ASTReader::ReadASTCore(StringRef FileName,
return Success;
}
+ASTReader::ASTReadResult
+ASTReader::readUnhashedControlBlock(ModuleFile &F, bool WasImportedBy,
+ unsigned ClientLoadCapabilities) {
+ const HeaderSearchOptions &HSOpts =
+ PP.getHeaderSearchInfo().getHeaderSearchOpts();
+ bool AllowCompatibleConfigurationMismatch =
+ F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule;
+
+ ASTReadResult Result = readUnhashedControlBlockImpl(
+ &F, F.Data, ClientLoadCapabilities, AllowCompatibleConfigurationMismatch,
+ Listener.get(),
+ WasImportedBy ? false : HSOpts.ModulesValidateDiagnosticOptions);
+
+ if (DisableValidation || WasImportedBy ||
+ (AllowConfigurationMismatch && Result == ConfigurationMismatch))
+ return Success;
+
+ if (Result == Failure)
+ Error("malformed block record in AST file");
+
+ return Result;
+}
+
+ASTReader::ASTReadResult ASTReader::readUnhashedControlBlockImpl(
+ ModuleFile *F, llvm::StringRef StreamData, unsigned ClientLoadCapabilities,
+ bool AllowCompatibleConfigurationMismatch, ASTReaderListener *Listener,
+ bool ValidateDiagnosticOptions) {
+ // Initialize a stream.
+ BitstreamCursor Stream(StreamData);
+
+ // Sniff for the signature.
+ if (!startsWithASTFileMagic(Stream))
+ return Failure;
+
+ // Scan for the UNHASHED_CONTROL_BLOCK_ID block.
+ if (SkipCursorToBlock(Stream, UNHASHED_CONTROL_BLOCK_ID))
+ return Failure;
+
+ // Read all of the records in the options block.
+ RecordData Record;
+ ASTReadResult Result = Success;
+ while (1) {
+ llvm::BitstreamEntry Entry = Stream.advance();
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::Error:
+ case llvm::BitstreamEntry::SubBlock:
+ return Failure;
+
+ case llvm::BitstreamEntry::EndBlock:
+ return Result;
+
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read and process a record.
+ Record.clear();
+ switch (
+ (UnhashedControlBlockRecordTypes)Stream.readRecord(Entry.ID, Record)) {
+ case SIGNATURE: {
+ if (F)
+ std::copy(Record.begin(), Record.end(), F->Signature.data());
+ break;
+ }
+ case DIAGNOSTIC_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0;
+ if (Listener && ValidateDiagnosticOptions &&
+ !AllowCompatibleConfigurationMismatch &&
+ ParseDiagnosticOptions(Record, Complain, *Listener))
+ return OutOfDate;
+ break;
+ }
+ case DIAG_PRAGMA_MAPPINGS:
+ if (!F)
+ break;
+ if (F->PragmaDiagMappings.empty())
+ F->PragmaDiagMappings.swap(Record);
+ else
+ F->PragmaDiagMappings.insert(F->PragmaDiagMappings.end(),
+ Record.begin(), Record.end());
+ break;
+ }
+ }
+}
+
/// Parse a record and blob containing module file extension metadata.
static bool parseModuleFileExtensionMetadata(
const SmallVectorImpl<uint64_t> &Record,
@@ -4249,23 +4354,24 @@ void ASTReader::finalizeForWriting() {
static ASTFileSignature readASTFileSignature(StringRef PCH) {
BitstreamCursor Stream(PCH);
if (!startsWithASTFileMagic(Stream))
- return 0;
+ return ASTFileSignature();
- // Scan for the CONTROL_BLOCK_ID block.
- if (SkipCursorToBlock(Stream, CONTROL_BLOCK_ID))
- return 0;
+ // Scan for the UNHASHED_CONTROL_BLOCK_ID block.
+ if (SkipCursorToBlock(Stream, UNHASHED_CONTROL_BLOCK_ID))
+ return ASTFileSignature();
- // Scan for SIGNATURE inside the control block.
+ // Scan for SIGNATURE inside the diagnostic options block.
ASTReader::RecordData Record;
while (true) {
llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
if (Entry.Kind != llvm::BitstreamEntry::Record)
- return 0;
+ return ASTFileSignature();
Record.clear();
StringRef Blob;
if (SIGNATURE == Stream.readRecord(Entry.ID, Record, &Blob))
- return Record[0];
+ return {{{(uint32_t)Record[0], (uint32_t)Record[1], (uint32_t)Record[2],
+ (uint32_t)Record[3], (uint32_t)Record[4]}}};
}
}
@@ -4384,7 +4490,8 @@ bool ASTReader::readASTFileControlBlock(
}
// Initialize the stream
- BitstreamCursor Stream(PCHContainerRdr.ExtractPCH(**Buffer));
+ StringRef Bytes = PCHContainerRdr.ExtractPCH(**Buffer);
+ BitstreamCursor Stream(Bytes);
// Sniff for the signature.
if (!startsWithASTFileMagic(Stream))
@@ -4412,8 +4519,7 @@ bool ASTReader::readASTFileControlBlock(
std::string IgnoredSuggestedPredefines;
if (ReadOptionsBlock(Stream, ARR_ConfigurationMismatch | ARR_OutOfDate,
/*AllowCompatibleConfigurationMismatch*/ false,
- Listener, IgnoredSuggestedPredefines,
- ValidateDiagnosticOptions) != Success)
+ Listener, IgnoredSuggestedPredefines) != Success)
return true;
break;
}
@@ -4534,6 +4640,7 @@ bool ASTReader::readASTFileControlBlock(
// Look for module file extension blocks, if requested.
if (FindModuleFileExtensions) {
+ BitstreamCursor SavedStream = Stream;
while (!SkipCursorToBlock(Stream, EXTENSION_BLOCK_ID)) {
bool DoneWithExtensionBlock = false;
while (!DoneWithExtensionBlock) {
@@ -4572,8 +4679,16 @@ bool ASTReader::readASTFileControlBlock(
}
}
}
+ Stream = SavedStream;
}
+ // Scan for the UNHASHED_CONTROL_BLOCK_ID block.
+ if (readUnhashedControlBlockImpl(
+ nullptr, Bytes, ARR_ConfigurationMismatch | ARR_OutOfDate,
+ /*AllowCompatibleConfigurationMismatch*/ false, &Listener,
+ ValidateDiagnosticOptions) != Success)
+ return true;
+
return false;
}
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index cdc1cf5bcb0..b13a4e1ff4b 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -18,8 +18,8 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTUnresolvedSet.h"
#include "clang/AST/Decl.h"
-#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
@@ -33,8 +33,8 @@
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemOptions.h"
-#include "clang/Basic/LangOptions.h"
#include "clang/Basic/LLVM.h"
+#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/SourceManager.h"
@@ -64,9 +64,9 @@
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitcode/BitCodes.h"
#include "llvm/Bitcode/BitstreamWriter.h"
@@ -79,6 +79,7 @@
#include "llvm/Support/OnDiskHashTable.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
+#include "llvm/Support/SHA1.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
@@ -1016,7 +1017,6 @@ void ASTWriter::WriteBlockInfoBlock() {
// Control Block.
BLOCK(CONTROL_BLOCK);
RECORD(METADATA);
- RECORD(SIGNATURE);
RECORD(MODULE_NAME);
RECORD(MODULE_DIRECTORY);
RECORD(MODULE_MAP_FILE);
@@ -1029,7 +1029,6 @@ void ASTWriter::WriteBlockInfoBlock() {
BLOCK(OPTIONS_BLOCK);
RECORD(LANGUAGE_OPTIONS);
RECORD(TARGET_OPTIONS);
- RECORD(DIAGNOSTIC_OPTIONS);
RECORD(FILE_SYSTEM_OPTIONS);
RECORD(HEADER_SEARCH_OPTIONS);
RECORD(PREPROCESSOR_OPTIONS);
@@ -1065,7 +1064,6 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(UPDATE_VISIBLE);
RECORD(DECL_UPDATE_OFFSETS);
RECORD(DECL_UPDATES);
- RECORD(DIAG_PRAGMA_MAPPINGS);
RECORD(CUDA_SPECIAL_DECL_REFS);
RECORD(HEADER_SEARCH_TABLE);
RECORD(FP_PRAGMA_OPTIONS);
@@ -1258,6 +1256,11 @@ void ASTWriter::WriteBlockInfoBlock() {
BLOCK(EXTENSION_BLOCK);
RECORD(EXTENSION_METADATA);
+ BLOCK(UNHASHED_CONTROL_BLOCK);
+ RECORD(SIGNATURE);
+ RECORD(DIAGNOSTIC_OPTIONS);
+ RECORD(DIAG_PRAGMA_MAPPINGS);
+
#undef RECORD
#undef BLOCK
Stream.ExitBlock();
@@ -1320,21 +1323,73 @@ adjustFilenameForRelocatableAST(const char *Filename, StringRef BaseDir) {
return Filename + Pos;
}
-static ASTFileSignature getSignature() {
- while (true) {
- if (ASTFileSignature S = llvm::sys::Process::GetRandomNumber())
- return S;
- // Rely on GetRandomNumber to eventually return non-zero...
+ASTFileSignature ASTWriter::createSignature(StringRef Bytes) {
+ // Calculate the hash till start of UNHASHED_CONTROL_BLOCK.
+ llvm::SHA1 Hasher;
+ Hasher.update(ArrayRef<uint8_t>(Bytes.bytes_begin(), Bytes.size()));
+ auto Hash = Hasher.result();
+
+ // Convert to an array [5*i32].
+ ASTFileSignature Signature;
+ auto LShift = [&](unsigned char Val, unsigned Shift) {
+ return (uint32_t)Val << Shift;
+ };
+ for (int I = 0; I != 5; ++I)
+ Signature[I] = LShift(Hash[I * 4 + 0], 24) | LShift(Hash[I * 4 + 1], 16) |
+ LShift(Hash[I * 4 + 2], 8) | LShift(Hash[I * 4 + 3], 0);
+
+ return Signature;
+}
+
+ASTFileSignature ASTWriter::writeUnhashedControlBlock(Preprocessor &PP,
+ ASTContext &Context) {
+ // Flush first to prepare the PCM hash (signature).
+ Stream.FlushToWord();
+ auto StartOfUnhashedControl = Stream.GetCurrentBitNo() >> 3;
+
+ // Enter the block and prepare to write records.
+ RecordData Record;
+ Stream.EnterSubblock(UNHASHED_CONTROL_BLOCK_ID, 5);
+
+ // For implicit modules, write the hash of the PCM as its signature.
+ ASTFileSignature Signature;
+ if (WritingModule &&
+ PP.getHeaderSearchInfo().getHeaderSearchOpts().ModulesHashContent) {
+ Signature = createSignature(StringRef(Buffer.begin(), StartOfUnhashedControl));
+ Record.append(Signature.begin(), Signature.end());
+ Stream.EmitRecord(SIGNATURE, Record);
+ Record.clear();
}
+
+ // Diagnostic options.
+ const auto &Diags = Context.getDiagnostics();
+ const DiagnosticOptions &DiagOpts = Diags.getDiagnosticOptions();
+#define DIAGOPT(Name, Bits, Default) Record.push_back(DiagOpts.Name);
+#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
+ Record.push_back(static_cast<unsigned>(DiagOpts.get##Name()));
+#include "clang/Basic/DiagnosticOptions.def"
+ Record.push_back(DiagOpts.Warnings.size());
+ for (unsigned I = 0, N = DiagOpts.Warnings.size(); I != N; ++I)
+ AddString(DiagOpts.Warnings[I], Record);
+ Record.push_back(DiagOpts.Remarks.size());
+ for (unsigned I = 0, N = DiagOpts.Remarks.size(); I != N; ++I)
+ AddString(DiagOpts.Remarks[I], Record);
+ // Note: we don't serialize the log or serialization file names, because they
+ // are generally transient files and will almost always be overridden.
+ Stream.EmitRecord(DIAGNOSTIC_OPTIONS, Record);
+
+ // Write out the diagnostic/pragma mappings.
+ WritePragmaDiagnosticMappings(Diags, /* IsModule = */ WritingModule);
+
+ // Leave the options block.
+ Stream.ExitBlock();
+ return Signature;
}
/// \brief Write the control block.
-uint64_t ASTWriter::WriteControlBlock(Preprocessor &PP,
- ASTContext &Context,
- StringRef isysroot,
- const std::string &OutputFile) {
- ASTFileSignature Signature = 0;
-
+void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
+ StringRef isysroot,
+ const std::string &OutputFile) {
using namespace llvm;
Stream.EnterSubblock(CONTROL_BLOCK_ID, 5);
RecordData Record;
@@ -1362,15 +1417,6 @@ uint64_t ASTWriter::WriteControlBlock(Preprocessor &PP,
getClangFullRepositoryVersion());
}
if (WritingModule) {
- // For implicit modules we output a signature that we can use to ensure
- // duplicate module builds don't collide in the cache as their output order
- // is non-deterministic.
- // FIXME: Remove this when output is deterministic.
- if (Context.getLangOpts().ImplicitModules) {
- Signature = getSignature();
- RecordData::value_type Record[] = {Signature};
- Stream.EmitRecord(SIGNATURE, Record);
- }
// Module name
auto Abbrev = std::make_shared<BitCodeAbbrev>();
@@ -1443,9 +1489,15 @@ uint64_t ASTWriter::WriteControlBlock(Preprocessor &PP,
Record.push_back((unsigned)M.Kind); // FIXME: Stable encoding
AddSourceLocation(M.ImportLoc, Record);
- Record.push_back(M.File->getSize());
- Record.push_back(getTimestampForOutput(M.File));
- Record.push_back(M.Signature);
+
+ // If we have calculated signature, there is no need to store
+ // the size or timestamp.
+ Record.push_back(M.Signature ? 0 : M.File->getSize());
+ Record.push_back(M.Signature ? 0 : getTimestampForOutput(M.File));
+
+ for (auto I : M.Signature)
+ Record.push_back(I);
+
AddPath(M.FileName, Record);
}
Stream.EmitRecord(IMPORTS, Record);
@@ -1508,24 +1560,6 @@ uint64_t ASTWriter::WriteControlBlock(Preprocessor &PP,
}
Stream.EmitRecord(TARGET_OPTIONS, Record);
- // Diagnostic options.
- Record.clear();
- const DiagnosticOptions &DiagOpts
- = Context.getDiagnostics().getDiagnosticOptions();
-#define DIAGOPT(Name, Bits, Default) Record.push_back(DiagOpts.Name);
-#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
- Record.push_back(static_cast<unsigned>(DiagOpts.get##Name()));
-#include "clang/Basic/DiagnosticOptions.def"
- Record.push_back(DiagOpts.Warnings.size());
- for (unsigned I = 0, N = DiagOpts.Warnings.size(); I != N; ++I)
- AddString(DiagOpts.Warnings[I], Record);
- Record.push_back(DiagOpts.Remarks.size());
- for (unsigned I = 0, N = DiagOpts.Remarks.size(); I != N; ++I)
- AddString(DiagOpts.Remarks[I], Record);
- // Note: we don't serialize the log or serialization file names, because they
- // are generally transient files and will almost always be overridden.
- Stream.EmitRecord(DIAGNOSTIC_OPTIONS, Record);
-
// File system options.
Record.clear();
const FileSystemOptions &FSOpts =
@@ -1639,7 +1673,6 @@ uint64_t ASTWriter::WriteControlBlock(Preprocessor &PP,
PP.getHeaderSearchInfo().getHeaderSearchOpts(),
PP.getLangOpts().Modules);
Stream.ExitBlock();
- return Signature;
}
namespace {
@@ -4267,9 +4300,10 @@ void ASTWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) {
}
ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream,
+ SmallVectorImpl<char> &Buffer,
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
bool IncludeTimestamps)
- : Stream(Stream), IncludeTimestamps(IncludeTimestamps) {
+ : Stream(Stream), Buffer(Buffer), IncludeTimestamps(IncludeTimestamps) {
for (const auto &Ext : Extensions) {
if (auto Writer = Ext->createExtensionWriter(*this))
ModuleFileExtensionWriters.push_back(std::move(Writer));
@@ -4289,9 +4323,10 @@ time_t ASTWriter::getTimestampForOutput(const FileEntry *E) const {
return IncludeTimestamps ? E->getModificationTime() : 0;
}
-uint64_t ASTWriter::WriteAST(Sema &SemaRef, const std::string &OutputFile,
- Module *WritingModule, StringRef isysroot,
- bool hasErrors) {
+ASTFileSignature ASTWriter::WriteAST(Sema &SemaRef,
+ const std::string &OutputFile,
+ Module *WritingModule, StringRef isysroot,
+ bool hasErrors) {
WritingAST = true;
ASTHasCompilerErrors = hasErrors;
@@ -4327,9 +4362,9 @@ static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec,
}
}
-uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
- const std::string &OutputFile,
- Module *WritingModule) {
+ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
+ const std::string &OutputFile,
+ Module *WritingModule) {
using namespace llvm;
bool isModule = WritingModule != nullptr;
@@ -4477,7 +4512,7 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
}
// Write the control block
- uint64_t Signature = WriteControlBlock(PP, Context, isysroot, OutputFile);
+ WriteControlBlock(PP, Context, isysroot, OutputFile);
// Write the remaining AST contents.
Stream.EnterSubblock(AST_BLOCK_ID, 5);
@@ -4694,7 +4729,6 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
WriteOpenCLExtensionTypes(SemaRef);
WriteOpenCLExtensionDecls(SemaRef);
WriteCUDAPragmas(SemaRef);
- WritePragmaDiagnosticMappings(Context.getDiagnostics(), isModule);
// If we're emitting a module, write out the submodule information.
if (WritingModule)
@@ -4823,7 +4857,7 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
for (const auto &ExtWriter : ModuleFileExtensionWriters)
WriteModuleFileExtension(SemaRef, *ExtWriter);
- return Signature;
+ return writeUnhashedControlBlock(PP, Context);
}
void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
diff --git a/clang/lib/Serialization/GeneratePCH.cpp b/clang/lib/Serialization/GeneratePCH.cpp
index 7f1b75055b4..141a5594aed 100644
--- a/clang/lib/Serialization/GeneratePCH.cpp
+++ b/clang/lib/Serialization/GeneratePCH.cpp
@@ -28,7 +28,7 @@ PCHGenerator::PCHGenerator(
bool AllowASTWithErrors, bool IncludeTimestamps)
: PP(PP), OutputFile(OutputFile), isysroot(isysroot.str()),
SemaPtr(nullptr), Buffer(Buffer), Stream(Buffer->Data),
- Writer(Stream, Extensions, IncludeTimestamps),
+ Writer(Stream, Buffer->Data, Extensions, IncludeTimestamps),
AllowASTWithErrors(AllowASTWithErrors) {
Buffer->IsComplete = false;
}
diff --git a/clang/lib/Serialization/GlobalModuleIndex.cpp b/clang/lib/Serialization/GlobalModuleIndex.cpp
index ae5796ede12..6978e7e0977 100644
--- a/clang/lib/Serialization/GlobalModuleIndex.cpp
+++ b/clang/lib/Serialization/GlobalModuleIndex.cpp
@@ -376,6 +376,15 @@ namespace {
/// \brief The set of modules on which this module depends. Each entry is
/// a module ID.
SmallVector<unsigned, 4> Dependencies;
+ ASTFileSignature Signature;
+ };
+
+ struct ImportedModuleFileInfo {
+ off_t StoredSize;
+ time_t StoredModTime;
+ ASTFileSignature StoredSignature;
+ ImportedModuleFileInfo(off_t Size, time_t ModTime, ASTFileSignature Sig)
+ : StoredSize(Size), StoredModTime(ModTime), StoredSignature(Sig) {}
};
/// \brief Builder that generates the global module index file.
@@ -383,12 +392,20 @@ namespace {
FileManager &FileMgr;
const PCHContainerReader &PCHContainerRdr;
- /// \brief Mapping from files to module file information.
+ /// Mapping from files to module file information.
typedef llvm::MapVector<const FileEntry *, ModuleFileInfo> ModuleFilesMap;
- /// \brief Information about each of the known module files.
+ /// Information about each of the known module files.
ModuleFilesMap ModuleFiles;
+ /// \brief Mapping from the imported module file to the imported
+ /// information.
+ typedef std::multimap<const FileEntry *, ImportedModuleFileInfo>
+ ImportedModuleFilesMap;
+
+ /// \brief Information about each importing of a module file.
+ ImportedModuleFilesMap ImportedModuleFiles;
+
/// \brief Mapping from identifiers to the list of module file IDs that
/// consider this identifier to be interesting.
typedef llvm::StringMap<SmallVector<unsigned, 2> > InterestingIdentifierMap;
@@ -424,7 +441,8 @@ namespace {
bool loadModuleFile(const FileEntry *File);
/// \brief Write the index to the given bitstream.
- void writeIndex(llvm::BitstreamWriter &Stream);
+ /// \returns true if an error occurred, false otherwise.
+ bool writeIndex(llvm::BitstreamWriter &Stream);
};
}
@@ -515,7 +533,7 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
unsigned ID = getModuleFileInfo(File).ID;
// Search for the blocks and records we care about.
- enum { Other, ControlBlock, ASTBlock } State = Other;
+ enum { Other, ControlBlock, ASTBlock, DiagnosticOptionsBlock } State = Other;
bool Done = false;
while (!Done) {
llvm::BitstreamEntry Entry = InStream.advance();
@@ -553,6 +571,15 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
continue;
}
+ if (Entry.ID == UNHASHED_CONTROL_BLOCK_ID) {
+ if (InStream.EnterSubBlock(UNHASHED_CONTROL_BLOCK_ID))
+ return true;
+
+ // Found the Diagnostic Options block.
+ State = DiagnosticOptionsBlock;
+ continue;
+ }
+
if (InStream.SkipBlock())
return true;
@@ -587,7 +614,10 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
// Skip the stored signature.
// FIXME: we could read the signature out of the import and validate it.
- Idx++;
+ ASTFileSignature StoredSignature = {
+ {{(uint32_t)Record[Idx++], (uint32_t)Record[Idx++],
+ (uint32_t)Record[Idx++], (uint32_t)Record[Idx++],
+ (uint32_t)Record[Idx++]}}};
// Retrieve the imported file name.
unsigned Length = Record[Idx++];
@@ -599,11 +629,16 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
const FileEntry *DependsOnFile
= FileMgr.getFile(ImportedFile, /*openFile=*/false,
/*cacheFailure=*/false);
- if (!DependsOnFile ||
- (StoredSize != DependsOnFile->getSize()) ||
- (StoredModTime != DependsOnFile->getModificationTime()))
+
+ if (!DependsOnFile)
return true;
+ // Save the information in ImportedModuleFileInfo so we can verify after
+ // loading all pcms.
+ ImportedModuleFiles.insert(std::make_pair(
+ DependsOnFile, ImportedModuleFileInfo(StoredSize, StoredModTime,
+ StoredSignature)));
+
// Record the dependency.
unsigned DependsOnID = getModuleFileInfo(DependsOnFile).ID;
getModuleFileInfo(File).Dependencies.push_back(DependsOnID);
@@ -632,6 +667,12 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
}
}
+ // Get Signature.
+ if (State == DiagnosticOptionsBlock && Code == SIGNATURE)
+ getModuleFileInfo(File).Signature = {
+ {{(uint32_t)Record[0], (uint32_t)Record[1], (uint32_t)Record[2],
+ (uint32_t)Record[3], (uint32_t)Record[4]}}};
+
// We don't care about this record.
}
@@ -680,7 +721,20 @@ public:
}
-void GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) {
+bool GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) {
+ for (auto MapEntry : ImportedModuleFiles) {
+ auto *File = MapEntry.first;
+ ImportedModuleFileInfo &Info = MapEntry.second;
+ if (getModuleFileInfo(File).Signature) {
+ if (getModuleFileInfo(File).Signature != Info.StoredSignature)
+ // Verify Signature.
+ return true;
+ } else if (Info.StoredSize != File->getSize() ||
+ Info.StoredModTime != File->getModificationTime())
+ // Verify Size and ModTime.
+ return true;
+ }
+
using namespace llvm;
// Emit the file header.
@@ -756,6 +810,7 @@ void GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) {
}
Stream.ExitBlock();
+ return false;
}
GlobalModuleIndex::ErrorCode
@@ -816,7 +871,8 @@ GlobalModuleIndex::writeIndex(FileManager &FileMgr,
SmallVector<char, 16> OutputBuffer;
{
llvm::BitstreamWriter OutputStream(OutputBuffer);
- Builder.writeIndex(OutputStream);
+ if (Builder.writeIndex(OutputStream))
+ return EC_IOError;
}
// Write the global index file to a temporary file.
OpenPOWER on IntegriCloud