Skip to content

Commit 59895ba

Browse files
committed
[Modules][Diagnostic] Improve diagnostics for stale module dependencies
When a module becomes out of date because its dependency has changed, Clang previously reported that the dependency itself was `out of date and needs to be rebuilt`, even when the dependency had just been rebuilt. This was confusing because the real issue is that the importing module is stale due to the dependency change. This patch introduces a new diagnostic that clearly indicates which module is out of date and which dependency has changed, making it easier for users to understand what needs to be rebuilt. Before: `module file 'A.pcm' is out of date and needs to be rebuilt` (even though A.pcm was just rebuilt) After: `module file 'B.pcm' is out of date because dependency 'A.pcm' has changed`
1 parent 834a3cc commit 59895ba

File tree

5 files changed

+65
-5
lines changed

5 files changed

+65
-5
lines changed

clang/include/clang/Basic/DiagnosticSerializationKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ def err_ast_file_not_found : Error<
7171
def err_ast_file_out_of_date : Error<
7272
"%select{PCH|module|precompiled}0 file '%1' is out of date and "
7373
"needs to be rebuilt%select{|: %3}2">, DefaultFatal;
74+
def err_ast_file_dependency_out_of_date : Error<
75+
"%select{PCH|module|AST}0 file '%1' is out of date because "
76+
"dependency '%2' has changed%select{|: %4}3">, DefaultFatal;
7477
def err_ast_file_invalid : Error<
7578
"file '%1' is not a valid %select{PCH|module|precompiled}0 file: %2">, DefaultFatal;
7679
def note_module_file_imported_by : Note<

clang/include/clang/Serialization/ModuleManager.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,10 @@ class ModuleManager {
199199
Missing,
200200

201201
/// The module file is out-of-date.
202-
OutOfDate
202+
OutOfDate,
203+
204+
/// The importer file is out-of-date
205+
ImporterOutOfDate
203206
};
204207

205208
using ASTFileSignatureReader = ASTFileSignature (*)(StringRef);

clang/lib/Serialization/ASTReader.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5139,6 +5139,20 @@ ASTReader::ReadASTCore(StringRef FileName,
51395139
<< moduleKindForDiagnostic(Type) << FileName << !ErrorStr.empty()
51405140
<< ErrorStr;
51415141
return Failure;
5142+
5143+
case ModuleManager::ImporterOutOfDate:
5144+
// We couldn't load the module file because it is out-of-date. If the
5145+
// client can handle out-of-date, return it.
5146+
if (ClientLoadCapabilities & ARR_OutOfDate)
5147+
return OutOfDate;
5148+
5149+
// Otherwise, report that the importer is out of date because the dependency
5150+
// changed.
5151+
if (ImportedBy)
5152+
Diag(diag::err_ast_file_dependency_out_of_date)
5153+
<< moduleKindForDiagnostic(ImportedBy->Kind) << ImportedBy->FileName
5154+
<< FileName << !ErrorStr.empty() << StringRef(ErrorStr);
5155+
return Failure;
51425156
}
51435157

51445158
assert(M && "Missing module file");

clang/lib/Serialization/ModuleManager.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
125125
ErrorStr = IgnoreModTime ? "module file has a different size than expected"
126126
: "module file has a different size or "
127127
"modification time than expected";
128-
return OutOfDate;
128+
return ImporterOutOfDate;
129129
}
130130

131131
if (!Entry) {
@@ -159,7 +159,7 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
159159
if (implicitModuleNamesMatch(Type, ModuleEntry, *Entry)) {
160160
// Check the stored signature.
161161
if (checkSignature(ModuleEntry->Signature, ExpectedSignature, ErrorStr))
162-
return OutOfDate;
162+
return ImporterOutOfDate;
163163

164164
Module = ModuleEntry;
165165
updateModuleImports(*ModuleEntry, ImportedBy, ImportLoc);
@@ -226,7 +226,7 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
226226
// ReadSignature unless there's something to check though.
227227
if (ExpectedSignature && checkSignature(ReadSignature(NewModule->Data),
228228
ExpectedSignature, ErrorStr))
229-
return OutOfDate;
229+
return ImporterOutOfDate;
230230

231231
// We're keeping this module. Store it everywhere.
232232
Module = Modules[*Entry] = NewModule.get();

clang/test/Modules/explicit-build.cpp

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,46 @@
184184
// CHECK-NO-FILE-INDIRECT-NEXT: note: imported by module 'c' in '{{.*}}c.pcm'
185185
// CHECK-NO-FILE-INDIRECT-NOT: note:
186186

187+
// -------------------------------
188+
// Check that we diagnose stale dependencies correctly when modules change.
189+
//
190+
// Trigger a rebuild of A with a different configuration (-DA_EXTRA_DEFINE) to make B and C out of date
191+
// RUN: mv %t/a.pcm %t/a-tmp.pcm
192+
// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
193+
// RUN: -fmodule-name=a -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/a.pcm \
194+
// RUN: -DA_EXTRA_DEFINE \
195+
// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty
196+
197+
// Try to use C, which depends on B, which depends on the now-changed A.
198+
// RUN: not %clang_cc1 -x c++ -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
199+
// RUN: -I%S/Inputs/explicit-build \
200+
// RUN: -fmodule-file=%t/c.pcm \
201+
// RUN: %s -DHAVE_A -DHAVE_B -DHAVE_C 2>&1 | FileCheck --check-prefix=CHECK-OUT-OF-DATE-INDIRECT %s
202+
//
203+
// CHECK-OUT-OF-DATE-INDIRECT: fatal error: module file '{{.*}}b.pcm' is out of date because dependency '{{.*}}a.pcm' has changed
204+
// CHECK-OUT-OF-DATE-INDIRECT-NEXT: note: imported by module 'b' in '{{.*}}b.pcm'
205+
// CHECK-OUT-OF-DATE-INDIRECT-NEXT: note: imported by module 'c' in '{{.*}}c.pcm'
206+
207+
// Rebuild B with the new A, leaving C out of date.
208+
// RUN: mv %t/b.pcm %t/b-tmp.pcm
209+
// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
210+
// RUN: -fmodule-file=%t/a.pcm \
211+
// RUN: -fmodule-name=b -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/b.pcm \
212+
// RUN: -DA_EXTRA_DEFINE \
213+
// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty
214+
//
215+
// Now only C is out of date. Try to use C.
216+
// RUN: not %clang_cc1 -x c++ -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
217+
// RUN: -I%S/Inputs/explicit-build \
218+
// RUN: -fmodule-file=%t/c.pcm \
219+
// RUN: %s -DHAVE_A -DHAVE_B -DHAVE_C 2>&1 | FileCheck --check-prefix=CHECK-OUT-OF-DATE-DIRECT %s
220+
//
221+
// CHECK-OUT-OF-DATE-DIRECT: fatal error: module file '{{.*}}c.pcm' is out of date because dependency '{{.*}}b.pcm' has changed
222+
// CHECK-OUT-OF-DATE-DIRECT-NOT: fatal error: module file '{{.*}}b.pcm' is out of date
223+
//
224+
// RUN: mv %t/a-tmp.pcm %t/a.pcm
225+
// RUN: mv %t/b-tmp.pcm %t/b.pcm
226+
187227
// -------------------------------
188228
// Check that we don't get upset if B's timestamp is newer than C's.
189229
// RUN: touch %t/b.pcm
@@ -202,6 +242,6 @@
202242
// RUN: -fmodule-file=%t/c.pcm \
203243
// RUN: %s -DHAVE_A -DHAVE_B -DHAVE_C 2>&1 | FileCheck --check-prefix=CHECK-MISMATCHED-B %s
204244
//
205-
// CHECK-MISMATCHED-B: fatal error: module file '{{.*}}b.pcm' is out of date and needs to be rebuilt: module file has a different size than expected
245+
// CHECK-MISMATCHED-B: fatal error: module file '{{.*}}c.pcm' is out of date because dependency '{{.*}}b.pcm' has changed: module file has a different size than expected
206246
// CHECK-MISMATCHED-B-NEXT: note: imported by module 'c'
207247
// CHECK-MISMATCHED-B-NOT: note:

0 commit comments

Comments
 (0)