summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Driver/ToolChains/Clang.cpp8
-rw-r--r--clang/lib/Frontend/CompilerInstance.cpp4
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp2
-rw-r--r--clang/lib/Serialization/ASTReader.cpp86
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp59
5 files changed, 136 insertions, 23 deletions
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index dfb3f336086..b897eb6ab5d 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -2777,6 +2777,10 @@ static void RenderModulesOptions(Compilation &C, const Driver &D,
std::string("-fprebuilt-module-path=") + A->getValue()));
A->claim();
}
+ if (Args.hasFlag(options::OPT_fmodules_validate_input_files_content,
+ options::OPT_fno_modules_validate_input_files_content,
+ false))
+ CmdArgs.push_back("-fvalidate-ast-input-files-content");
}
// -fmodule-name specifies the module that is currently being built (or
@@ -4899,6 +4903,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Std && (Std->containsValue("c++2a") || Std->containsValue("c++latest"));
RenderModulesOptions(C, D, Args, Input, Output, CmdArgs, HaveModules);
+ if (Args.hasFlag(options::OPT_fpch_validate_input_files_content,
+ options::OPT_fno_pch_validate_input_files_content, false))
+ CmdArgs.push_back("-fvalidate-ast-input-files-content");
+
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_new_pass_manager,
options::OPT_fno_experimental_new_pass_manager);
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index a7b7114f791..97b92667416 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -510,7 +510,8 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource(
PP, ModuleCache, &Context, PCHContainerRdr, Extensions,
Sysroot.empty() ? "" : Sysroot.data(), DisablePCHValidation,
AllowPCHWithCompilerErrors, /*AllowConfigurationMismatch*/ false,
- HSOpts.ModulesValidateSystemHeaders, UseGlobalModuleIndex));
+ HSOpts.ModulesValidateSystemHeaders, HSOpts.ValidateASTInputFilesContent,
+ UseGlobalModuleIndex));
// We need the external source to be set up before we read the AST, because
// eagerly-deserialized declarations may use it.
@@ -1492,6 +1493,7 @@ void CompilerInstance::createModuleManager() {
/*AllowASTWithCompilerErrors=*/false,
/*AllowConfigurationMismatch=*/false,
HSOpts.ModulesValidateSystemHeaders,
+ HSOpts.ValidateASTInputFilesContent,
getFrontendOpts().UseGlobalModuleIndex, std::move(ReadTimer));
if (hasASTConsumer()) {
ModuleManager->setDeserializationListener(
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 9d5987f07f1..0aa44252c6c 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -2081,6 +2081,8 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args,
getLastArgUInt64Value(Args, OPT_fbuild_session_timestamp, 0);
Opts.ModulesValidateSystemHeaders =
Args.hasArg(OPT_fmodules_validate_system_headers);
+ Opts.ValidateASTInputFilesContent =
+ Args.hasArg(OPT_fvalidate_ast_input_files_content);
if (const Arg *A = Args.getLastArg(OPT_fmodule_format_EQ))
Opts.ModuleFormat = A->getValue();
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 60be1570bda..20c6cbec572 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -1247,6 +1247,12 @@ void ASTReader::Error(unsigned DiagID,
Diag(DiagID) << Arg1 << Arg2;
}
+void ASTReader::Error(unsigned DiagID, StringRef Arg1, StringRef Arg2,
+ unsigned Select) const {
+ if (!Diags.isDiagnosticInFlight())
+ Diag(DiagID) << Arg1 << Arg2 << Select;
+}
+
void ASTReader::Error(llvm::Error &&Err) const {
Error(toString(std::move(Err)));
}
@@ -2241,6 +2247,24 @@ ASTReader::readInputFileInfo(ModuleFile &F, unsigned ID) {
R.TopLevelModuleMap = static_cast<bool>(Record[5]);
R.Filename = Blob;
ResolveImportedPath(F, R.Filename);
+
+ Expected<llvm::BitstreamEntry> MaybeEntry = Cursor.advance();
+ if (!MaybeEntry) // FIXME this drops errors on the floor.
+ consumeError(MaybeEntry.takeError());
+ llvm::BitstreamEntry Entry = MaybeEntry.get();
+ assert(Entry.Kind == llvm::BitstreamEntry::Record &&
+ "expected record type for input file hash");
+
+ Record.clear();
+ if (Expected<unsigned> Maybe = Cursor.readRecord(Entry.ID, Record))
+ assert(static_cast<InputFileRecordTypes>(Maybe.get()) == INPUT_FILE_HASH &&
+ "invalid record type for input file hash");
+ else {
+ // FIXME this drops errors on the floor.
+ consumeError(Maybe.takeError());
+ }
+ R.ContentHash = (static_cast<uint64_t>(Record[1]) << 32) |
+ static_cast<uint64_t>(Record[0]);
return R;
}
@@ -2271,6 +2295,7 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
bool Overridden = FI.Overridden;
bool Transient = FI.Transient;
StringRef Filename = FI.Filename;
+ uint64_t StoredContentHash = FI.ContentHash;
const FileEntry *File = nullptr;
if (auto FE = FileMgr.getFile(Filename, /*OpenFile=*/false))
@@ -2325,14 +2350,46 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
}
}
- bool IsOutOfDate = false;
+ enum ModificationType {
+ Size,
+ ModTime,
+ Content,
+ None,
+ };
+ auto HasInputFileChanged = [&]() {
+ if (StoredSize != File->getSize())
+ return ModificationType::Size;
+ if (!DisableValidation && StoredTime &&
+ StoredTime != File->getModificationTime()) {
+ // In case the modification time changes but not the content,
+ // accept the cached file as legit.
+ if (ValidateASTInputFilesContent &&
+ StoredContentHash != static_cast<uint64_t>(llvm::hash_code(-1))) {
+ auto MemBuffOrError = FileMgr.getBufferForFile(File);
+ if (!MemBuffOrError) {
+ if (!Complain)
+ return ModificationType::ModTime;
+ std::string ErrorStr = "could not get buffer for file '";
+ ErrorStr += File->getName();
+ ErrorStr += "'";
+ Error(ErrorStr);
+ return ModificationType::ModTime;
+ }
+ auto ContentHash = hash_value(MemBuffOrError.get()->getBuffer());
+ if (StoredContentHash == static_cast<uint64_t>(ContentHash))
+ return ModificationType::None;
+ return ModificationType::Content;
+ }
+ return ModificationType::ModTime;
+ }
+ return ModificationType::None;
+ };
+
+ bool IsOutOfDate = false;
+ auto FileChange = HasInputFileChanged();
// For an overridden file, there is nothing to validate.
- if (!Overridden && //
- (StoredSize != File->getSize() ||
- (StoredTime && StoredTime != File->getModificationTime() &&
- !DisableValidation)
- )) {
+ if (!Overridden && FileChange != ModificationType::None) {
if (Complain) {
// Build a list of the PCH imports that got us here (in reverse).
SmallVector<ModuleFile *, 4> ImportStack(1, &F);
@@ -2341,13 +2398,17 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
// The top-level PCH is stale.
StringRef TopLevelPCHName(ImportStack.back()->FileName);
- unsigned DiagnosticKind = moduleKindForDiagnostic(ImportStack.back()->Kind);
+ unsigned DiagnosticKind =
+ moduleKindForDiagnostic(ImportStack.back()->Kind);
if (DiagnosticKind == 0)
- Error(diag::err_fe_pch_file_modified, Filename, TopLevelPCHName);
+ Error(diag::err_fe_pch_file_modified, Filename, TopLevelPCHName,
+ (unsigned)FileChange);
else if (DiagnosticKind == 1)
- Error(diag::err_fe_module_file_modified, Filename, TopLevelPCHName);
+ Error(diag::err_fe_module_file_modified, Filename, TopLevelPCHName,
+ (unsigned)FileChange);
else
- Error(diag::err_fe_ast_file_modified, Filename, TopLevelPCHName);
+ Error(diag::err_fe_ast_file_modified, Filename, TopLevelPCHName,
+ (unsigned)FileChange);
// Print the import stack.
if (ImportStack.size() > 1 && !Diags.isDiagnosticInFlight()) {
@@ -5192,6 +5253,8 @@ bool ASTReader::readASTFileControlBlock(
consumeError(MaybeRecordType.takeError());
}
switch ((InputFileRecordTypes)MaybeRecordType.get()) {
+ case INPUT_FILE_HASH:
+ break;
case INPUT_FILE:
bool Overridden = static_cast<bool>(Record[3]);
std::string Filename = Blob;
@@ -12153,7 +12216,7 @@ ASTReader::ASTReader(Preprocessor &PP, InMemoryModuleCache &ModuleCache,
StringRef isysroot, bool DisableValidation,
bool AllowASTWithCompilerErrors,
bool AllowConfigurationMismatch, bool ValidateSystemInputs,
- bool UseGlobalIndex,
+ bool ValidateASTInputFilesContent, bool UseGlobalIndex,
std::unique_ptr<llvm::Timer> ReadTimer)
: Listener(DisableValidation
? cast<ASTReaderListener>(new SimpleASTReaderListener(PP))
@@ -12167,6 +12230,7 @@ ASTReader::ASTReader(Preprocessor &PP, InMemoryModuleCache &ModuleCache,
AllowASTWithCompilerErrors(AllowASTWithCompilerErrors),
AllowConfigurationMismatch(AllowConfigurationMismatch),
ValidateSystemInputs(ValidateSystemInputs),
+ ValidateASTInputFilesContent(ValidateASTInputFilesContent),
UseGlobalIndex(UseGlobalIndex), CurrSwitchCaseStmts(&SwitchCaseStmts) {
SourceMgr.setExternalSLocEntrySource(this);
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 3badff45fb4..5e9e650fce8 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -1099,6 +1099,7 @@ void ASTWriter::WriteBlockInfoBlock() {
BLOCK(INPUT_FILES_BLOCK);
RECORD(INPUT_FILE);
+ RECORD(INPUT_FILE_HASH);
// AST Top-Level Block.
BLOCK(AST_BLOCK);
@@ -1764,6 +1765,7 @@ struct InputFileEntry {
bool IsTransient;
bool BufferOverridden;
bool IsTopLevelModuleMap;
+ uint32_t ContentHash[2];
};
} // namespace
@@ -1787,6 +1789,13 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
unsigned IFAbbrevCode = Stream.EmitAbbrev(std::move(IFAbbrev));
+ // Create input file hash abbreviation.
+ auto IFHAbbrev = std::make_shared<BitCodeAbbrev>();
+ IFHAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE_HASH));
+ IFHAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ IFHAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ unsigned IFHAbbrevCode = Stream.EmitAbbrev(std::move(IFHAbbrev));
+
// Get all ContentCache objects for files, sorted by whether the file is a
// system one or not. System files go at the back, users files at the front.
std::deque<InputFileEntry> SortedFiles;
@@ -1810,6 +1819,25 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
Entry.BufferOverridden = Cache->BufferOverridden;
Entry.IsTopLevelModuleMap = isModuleMap(File.getFileCharacteristic()) &&
File.getIncludeLoc().isInvalid();
+
+ auto ContentHash = hash_code(-1);
+ if (PP->getHeaderSearchInfo()
+ .getHeaderSearchOpts()
+ .ValidateASTInputFilesContent) {
+ auto *MemBuff = Cache->getRawBuffer();
+ if (MemBuff)
+ ContentHash = hash_value(MemBuff->getBuffer());
+ else
+ // FIXME: The path should be taken from the FileEntryRef.
+ PP->Diag(SourceLocation(), diag::err_module_unable_to_hash_content)
+ << Entry.File->getName();
+ }
+ auto CH = llvm::APInt(64, ContentHash);
+ Entry.ContentHash[0] =
+ static_cast<uint32_t>(CH.getLoBits(32).getZExtValue());
+ Entry.ContentHash[1] =
+ static_cast<uint32_t>(CH.getHiBits(32).getZExtValue());
+
if (Entry.IsSystemFile)
SortedFiles.push_back(Entry);
else
@@ -1834,17 +1862,26 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
// Emit size/modification time for this file.
// And whether this file was overridden.
- RecordData::value_type Record[] = {
- INPUT_FILE,
- InputFileOffsets.size(),
- (uint64_t)Entry.File->getSize(),
- (uint64_t)getTimestampForOutput(Entry.File),
- Entry.BufferOverridden,
- Entry.IsTransient,
- Entry.IsTopLevelModuleMap};
-
- // FIXME: The path should be taken from the FileEntryRef.
- EmitRecordWithPath(IFAbbrevCode, Record, Entry.File->getName());
+ {
+ RecordData::value_type Record[] = {
+ INPUT_FILE,
+ InputFileOffsets.size(),
+ (uint64_t)Entry.File->getSize(),
+ (uint64_t)getTimestampForOutput(Entry.File),
+ Entry.BufferOverridden,
+ Entry.IsTransient,
+ Entry.IsTopLevelModuleMap};
+
+ // FIXME: The path should be taken from the FileEntryRef.
+ EmitRecordWithPath(IFAbbrevCode, Record, Entry.File->getName());
+ }
+
+ // Emit content hash for this file.
+ {
+ RecordData::value_type Record[] = {INPUT_FILE_HASH, Entry.ContentHash[0],
+ Entry.ContentHash[1]};
+ Stream.EmitRecordWithAbbrev(IFHAbbrevCode, Record);
+ }
}
Stream.ExitBlock();
OpenPOWER on IntegriCloud