[clang] [modules] Add diagnostic about performed input file validation when encounter unrecoverable changed input file. (PR #180899)

Volodymyr Sapsai via cfe-commits cfe-commits at lists.llvm.org
Wed Feb 11 00:30:51 PST 2026


https://github.com/vsapsai created https://github.com/llvm/llvm-project/pull/180899

The expected behavior for implicitly built modules is to validate input files and to rebuild a module if there are any input file changes. But if for some reason a module hasn't been rebuilt, it is useful to know if the validation has been done and what kind of validation.

The goal is to make investigations for fixes like f2a3079a1b48033a92d0a7d9f03251ebeb4a0c30 and ada79f4c2691ab6546d379a144377162fd4f5191 easier.

rdar://159857416

>From ecc157d0da064e02ed4ebb14ef67a3b2c831f7e4 Mon Sep 17 00:00:00 2001
From: Volodymyr Sapsai <vsapsai at apple.com>
Date: Tue, 10 Feb 2026 22:32:14 -0800
Subject: [PATCH] [modules] Add diagnostic about performed input file
 validation when encounter unrecoverable changed input file.

The expected behavior for implicitly built modules is to validate input
files and to rebuild a module if there are any input file changes. But if
for some reason a module hasn't been rebuilt, it is useful to know if
the validation has been done and what kind of validation.

The goal is to make investigations for fixes like
f2a3079a1b48033a92d0a7d9f03251ebeb4a0c30 and
ada79f4c2691ab6546d379a144377162fd4f5191 easier.

rdar://159857416
---
 .../Basic/DiagnosticSerializationKinds.td     |  4 ++++
 .../include/clang/Serialization/ModuleFile.h  | 23 +++++++++++++++++++
 clang/lib/Serialization/ASTReader.cpp         | 14 ++++++++++-
 clang/test/Modules/module-file-modified.c     |  1 +
 4 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/DiagnosticSerializationKinds.td b/clang/include/clang/Basic/DiagnosticSerializationKinds.td
index 229f0bacbd796..3edf5415809c0 100644
--- a/clang/include/clang/Basic/DiagnosticSerializationKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSerializationKinds.td
@@ -29,6 +29,10 @@ def note_ast_file_rebuild_required
     : Note<"please rebuild precompiled file '%0'">;
 def note_module_cache_path : Note<
     "after modifying system headers, please delete the module cache at '%0'">;
+def note_ast_file_input_files_validation_status : Note<"input file validation "
+    "%select{has not been started|is disabled for this kind of module|"
+    "has already been done in the current build session|"
+    "has covered only user files|has covered all files}0">;
 
 def err_ast_file_targetopt_mismatch : Error<
     "precompiled file '%0' was compiled for the %1 '%2' but the current translation "
diff --git a/clang/include/clang/Serialization/ModuleFile.h b/clang/include/clang/Serialization/ModuleFile.h
index 783e2ba7a1f94..03015580217ef 100644
--- a/clang/include/clang/Serialization/ModuleFile.h
+++ b/clang/include/clang/Serialization/ModuleFile.h
@@ -120,6 +120,21 @@ class InputFile {
   bool isNotFound() const { return Val.getInt() == NotFound; }
 };
 
+/// Specifies the high-level result of validating input files.
+enum class InputFilesValidation {
+  /// Initial value, before the validation has been performed.
+  NotStarted = 0,
+  /// When the validation is disabled. For example, for a precompiled header.
+  Disabled,
+  /// When the validation is skipped because it was already done in the current
+  /// build session.
+  SkippedInBuildSession,
+  /// When the validation is done only for user files as an optimization.
+  UserFiles,
+  /// When the validation is done both for user files and system files.
+  AllFiles,
+};
+
 /// Information about a module that has been loaded by the ASTReader.
 ///
 /// Each instance of the Module class corresponds to a single AST file, which
@@ -276,6 +291,14 @@ class ModuleFile {
   /// The time is specified in seconds since the start of the Epoch.
   uint64_t InputFilesValidationTimestamp = 0;
 
+  /// Captures the high-level result of validating input files.
+  ///
+  /// Useful when encounter an invalid input file. This way can check what kind
+  /// of validation has been done already and can try to figure out why an
+  /// invalid file hasn't been discovered earlier.
+  InputFilesValidation InputFilesValidationStatus =
+      InputFilesValidation::NotStarted;
+
   // === Source Locations ===
 
   /// Cursor used to read source location entries.
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index f3902d57e3d1f..55efe355c433a 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -3000,6 +3000,8 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
       }
 
       Diag(diag::note_ast_file_rebuild_required) << TopLevelASTFileName;
+      Diag(diag::note_ast_file_input_files_validation_status)
+          << F.InputFilesValidationStatus;
     }
 
     IsOutOfDate = true;
@@ -3228,10 +3230,18 @@ ASTReader::ReadControlBlock(ModuleFile &F,
         // files.
 
         unsigned N = ValidateSystemInputs ? NumInputs : NumUserInputs;
+        F.InputFilesValidationStatus = ValidateSystemInputs
+                                           ? InputFilesValidation::AllFiles
+                                           : InputFilesValidation::UserFiles;
         if (HSOpts.ModulesValidateOncePerBuildSession &&
             F.InputFilesValidationTimestamp > HSOpts.BuildSessionTimestamp &&
-            F.Kind == MK_ImplicitModule)
+            F.Kind == MK_ImplicitModule) {
           N = ForceValidateUserInputs ? NumUserInputs : 0;
+          F.InputFilesValidationStatus =
+              ForceValidateUserInputs
+                  ? InputFilesValidation::UserFiles
+                  : InputFilesValidation::SkippedInBuildSession;
+        }
 
         if (N != 0)
           Diag(diag::remark_module_validation)
@@ -3242,6 +3252,8 @@ ASTReader::ReadControlBlock(ModuleFile &F,
           if (!IF.getFile() || IF.isOutOfDate())
             return OutOfDate;
         }
+      } else {
+        F.InputFilesValidationStatus = InputFilesValidation::Disabled;
       }
 
       if (Listener)
diff --git a/clang/test/Modules/module-file-modified.c b/clang/test/Modules/module-file-modified.c
index 1a02b3fa511b3..8ef574872b801 100644
--- a/clang/test/Modules/module-file-modified.c
+++ b/clang/test/Modules/module-file-modified.c
@@ -9,3 +9,4 @@
 int foo = 0; // redefinition of 'foo'
 // CHECK: fatal error: file {{.*}} has been modified since the module file {{.*}} was built
 // CHECK: note: please rebuild precompiled file
+// CHECK: note: input file validation is disabled for this kind of module



More information about the cfe-commits mailing list