Extend diagnostic for out of date AST input file.

If the size has changed, list the old and new sizes; if the mtime has
changed, list the old and new mtimes (as raw time_t values).
This commit is contained in:
Richard Smith 2021-07-22 17:52:16 -07:00
parent 2de2dbef2a
commit df7b6b9142
4 changed files with 29 additions and 17 deletions

View File

@ -20,7 +20,7 @@ def err_fe_pch_malformed_block : Error<
def err_fe_ast_file_modified : Error< def err_fe_ast_file_modified : Error<
"file '%0' has been modified since the " "file '%0' has been modified since the "
"%select{precompiled header|module file|AST file}1 '%2' was built" "%select{precompiled header|module file|AST file}1 '%2' was built"
": %select{size|mtime|content}3 changed">, ": %select{size|mtime|content}3 changed%select{| (was %5, now %6)}4">,
DefaultFatal; DefaultFatal;
def err_fe_pch_file_overridden : Error< def err_fe_pch_file_overridden : Error<
"file '%0' from the precompiled header has been overridden">; "file '%0' from the precompiled header has been overridden">;

View File

@ -2380,17 +2380,24 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
} }
} }
enum ModificationType { struct Change {
enum ModificationKind {
Size, Size,
ModTime, ModTime,
Content, Content,
None, None,
} Kind;
llvm::Optional<int64_t> Old = llvm::None;
llvm::Optional<int64_t> New = llvm::None;
}; };
auto HasInputFileChanged = [&]() { auto HasInputFileChanged = [&]() {
if (StoredSize != File->getSize()) if (StoredSize != File->getSize())
return ModificationType::Size; return Change{Change::Size, StoredSize, File->getSize()};
if (!shouldDisableValidationForFile(F) && StoredTime && if (!shouldDisableValidationForFile(F) && StoredTime &&
StoredTime != File->getModificationTime()) { StoredTime != File->getModificationTime()) {
Change MTimeChange = {Change::ModTime, StoredTime,
File->getModificationTime()};
// In case the modification time changes but not the content, // In case the modification time changes but not the content,
// accept the cached file as legit. // accept the cached file as legit.
if (ValidateASTInputFilesContent && if (ValidateASTInputFilesContent &&
@ -2398,28 +2405,30 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
auto MemBuffOrError = FileMgr.getBufferForFile(File); auto MemBuffOrError = FileMgr.getBufferForFile(File);
if (!MemBuffOrError) { if (!MemBuffOrError) {
if (!Complain) if (!Complain)
return ModificationType::ModTime; return MTimeChange;
std::string ErrorStr = "could not get buffer for file '"; std::string ErrorStr = "could not get buffer for file '";
ErrorStr += File->getName(); ErrorStr += File->getName();
ErrorStr += "'"; ErrorStr += "'";
Error(ErrorStr); Error(ErrorStr);
return ModificationType::ModTime; return MTimeChange;
} }
// FIXME: hash_value is not guaranteed to be stable!
auto ContentHash = hash_value(MemBuffOrError.get()->getBuffer()); auto ContentHash = hash_value(MemBuffOrError.get()->getBuffer());
if (StoredContentHash == static_cast<uint64_t>(ContentHash)) if (StoredContentHash == static_cast<uint64_t>(ContentHash))
return ModificationType::None; return Change{Change::None};
return ModificationType::Content;
return Change{Change::Content};
} }
return ModificationType::ModTime; return MTimeChange;
} }
return ModificationType::None; return Change{Change::None};
}; };
bool IsOutOfDate = false; bool IsOutOfDate = false;
auto FileChange = HasInputFileChanged(); auto FileChange = HasInputFileChanged();
// For an overridden file, there is nothing to validate. // For an overridden file, there is nothing to validate.
if (!Overridden && FileChange != ModificationType::None) { if (!Overridden && FileChange.Kind != Change::None) {
if (Complain && !Diags.isDiagnosticInFlight()) { if (Complain && !Diags.isDiagnosticInFlight()) {
// Build a list of the PCH imports that got us here (in reverse). // Build a list of the PCH imports that got us here (in reverse).
SmallVector<ModuleFile *, 4> ImportStack(1, &F); SmallVector<ModuleFile *, 4> ImportStack(1, &F);
@ -2430,7 +2439,10 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
StringRef TopLevelPCHName(ImportStack.back()->FileName); StringRef TopLevelPCHName(ImportStack.back()->FileName);
Diag(diag::err_fe_ast_file_modified) Diag(diag::err_fe_ast_file_modified)
<< Filename << moduleKindForDiagnostic(ImportStack.back()->Kind) << Filename << moduleKindForDiagnostic(ImportStack.back()->Kind)
<< TopLevelPCHName << FileChange; << TopLevelPCHName << FileChange.Kind
<< (FileChange.Old && FileChange.New)
<< llvm::itostr(FileChange.Old.getValueOr(0))
<< llvm::itostr(FileChange.New.getValueOr(0));
// Print the import stack. // Print the import stack.
if (ImportStack.size() > 1) { if (ImportStack.size() > 1) {

View File

@ -31,4 +31,4 @@ void g() { f(); }
// CHECK-BITCODE-TIMESTAMP-ON: <INPUT_FILE abbrevid={{.*}} op0={{.*}} op1={{.*}} op2={{[^0]}} // CHECK-BITCODE-TIMESTAMP-ON: <INPUT_FILE abbrevid={{.*}} op0={{.*}} op1={{.*}} op2={{[^0]}}
// CHECK-BITCODE-TIMESTAMP-OFF: <INPUT_FILE abbrevid={{.*}} op0={{.*}} op1={{.*}} op2={{[0]}} // CHECK-BITCODE-TIMESTAMP-OFF: <INPUT_FILE abbrevid={{.*}} op0={{.*}} op1={{.*}} op2={{[0]}}
// CHECK-TIMESTAMP: fatal error: file {{.*}} has been modified since the precompiled header {{.*}} was built // CHECK-TIMESTAMP: fatal error: file {{.*}} has been modified since the precompiled header {{.*}} was built: mtime changed (was {{.*}}, now {{.*}})

View File

@ -17,7 +17,7 @@
// RUN: echo ' ' >> %t.h // RUN: echo ' ' >> %t.h
// RUN: not %clang_cc1 -isystem %t/usr/include -verify-pch %t.pch 2> %t.log.2 // RUN: not %clang_cc1 -isystem %t/usr/include -verify-pch %t.pch 2> %t.log.2
// RUN: FileCheck -check-prefix=CHECK-STALE-DEP %s < %t.log.2 // RUN: FileCheck -check-prefix=CHECK-STALE-DEP %s < %t.log.2
// CHECK-STALE-DEP: file '{{.*}}.h' has been modified since the precompiled header '{{.*}}.pch' was built // CHECK-STALE-DEP: file '{{.*}}.h' has been modified since the precompiled header '{{.*}}.pch' was built: size changed (was {{.*}}, now {{.*}})
// Stale dependency in system header // Stale dependency in system header
// RUN: %clang_cc1 -isystem %t/usr/include -x objective-c-header -emit-pch -o %t.pch %t.h // RUN: %clang_cc1 -isystem %t/usr/include -x objective-c-header -emit-pch -o %t.pch %t.h