[clang] 989a40c - [clang][modules] Invalidate module cache when SDKSettings.json changes (#139751)
via cfe-commits
cfe-commits at lists.llvm.org
Tue May 13 14:00:35 PDT 2025
Author: Jan Svoboda
Date: 2025-05-13T14:00:31-07:00
New Revision: 989a40cba889630a916a4f815a8cabca1e14242a
URL: https://github.com/llvm/llvm-project/commit/989a40cba889630a916a4f815a8cabca1e14242a
DIFF: https://github.com/llvm/llvm-project/commit/989a40cba889630a916a4f815a8cabca1e14242a.diff
LOG: [clang][modules] Invalidate module cache when SDKSettings.json changes (#139751)
This PR adds the `%sdk/SDKSettings.json` file to the PCM input file
table, so that the PCM gets invalidated when the file changes. This is
necessary for availability checks to work correctly.
Added:
clang/test/Modules/sdk-settings-json-dep.m
Modified:
clang/lib/Serialization/ASTWriter.cpp
clang/tools/clang-scan-deps/ClangScanDeps.cpp
Removed:
################################################################################
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 7de510c85bfed..1b3d3c22aa9f5 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -1774,6 +1774,29 @@ struct InputFileEntry {
uint32_t ContentHash[2];
InputFileEntry(FileEntryRef File) : File(File) {}
+
+ void trySetContentHash(
+ Preprocessor &PP,
+ llvm::function_ref<std::optional<llvm::MemoryBufferRef>()> GetMemBuff) {
+ ContentHash[0] = 0;
+ ContentHash[1] = 0;
+
+ if (!PP.getHeaderSearchInfo()
+ .getHeaderSearchOpts()
+ .ValidateASTInputFilesContent)
+ return;
+
+ auto MemBuff = GetMemBuff();
+ if (!MemBuff) {
+ PP.Diag(SourceLocation(), diag::err_module_unable_to_hash_content)
+ << File.getName();
+ return;
+ }
+
+ uint64_t Hash = xxh3_64bits(MemBuff->getBuffer());
+ ContentHash[0] = uint32_t(Hash);
+ ContentHash[1] = uint32_t(Hash >> 32);
+ }
};
} // namespace
@@ -1848,25 +1871,41 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr) {
!IsSLocFileEntryAffecting[IncludeFileID.ID];
Entry.IsModuleMap = isModuleMap(File.getFileCharacteristic());
- uint64_t ContentHash = 0;
- if (PP->getHeaderSearchInfo()
- .getHeaderSearchOpts()
- .ValidateASTInputFilesContent) {
- auto MemBuff = Cache->getBufferIfLoaded();
- if (MemBuff)
- ContentHash = xxh3_64bits(MemBuff->getBuffer());
- else
- PP->Diag(SourceLocation(), diag::err_module_unable_to_hash_content)
- << Entry.File.getName();
- }
- Entry.ContentHash[0] = uint32_t(ContentHash);
- Entry.ContentHash[1] = uint32_t(ContentHash >> 32);
+ Entry.trySetContentHash(*PP, [&] { return Cache->getBufferIfLoaded(); });
+
if (Entry.IsSystemFile)
SystemFiles.push_back(Entry);
else
UserFiles.push_back(Entry);
}
+ // FIXME: Make providing input files not in the SourceManager more flexible.
+ // The SDKSettings.json file is necessary for correct evaluation of
+ // availability annotations.
+ StringRef Sysroot = PP->getHeaderSearchInfo().getHeaderSearchOpts().Sysroot;
+ if (!Sysroot.empty()) {
+ SmallString<128> SDKSettingsJSON = Sysroot;
+ llvm::sys::path::append(SDKSettingsJSON, "SDKSettings.json");
+ FileManager &FM = PP->getFileManager();
+ if (auto FE = FM.getOptionalFileRef(SDKSettingsJSON)) {
+ InputFileEntry Entry(*FE);
+ Entry.IsSystemFile = true;
+ Entry.IsTransient = false;
+ Entry.BufferOverridden = false;
+ Entry.IsTopLevel = true;
+ Entry.IsModuleMap = false;
+ std::unique_ptr<MemoryBuffer> MB;
+ Entry.trySetContentHash(*PP, [&]() -> std::optional<MemoryBufferRef> {
+ if (auto MBOrErr = FM.getBufferForFile(Entry.File)) {
+ MB = std::move(*MBOrErr);
+ return MB->getMemBufferRef();
+ }
+ return std::nullopt;
+ });
+ SystemFiles.push_back(Entry);
+ }
+ }
+
// User files go at the front, system files at the back.
auto SortedFiles = llvm::concat<InputFileEntry>(std::move(UserFiles),
std::move(SystemFiles));
diff --git a/clang/test/Modules/sdk-settings-json-dep.m b/clang/test/Modules/sdk-settings-json-dep.m
new file mode 100644
index 0000000000000..196f4219bd989
--- /dev/null
+++ b/clang/test/Modules/sdk-settings-json-dep.m
@@ -0,0 +1,53 @@
+// This test checks that the module cache gets invalidated when the SDKSettings.json file changes.
+
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+
+//--- AppleTVOS15.0.sdk/SDKSettings-old.json
+{
+ "DisplayName": "tvOS 15.0",
+ "Version": "15.0",
+ "CanonicalName": "appletvos15.0",
+ "MaximumDeploymentTarget": "15.0.99",
+ "PropertyConditionFallbackNames": []
+}
+//--- AppleTVOS15.0.sdk/SDKSettings-new.json
+{
+ "DisplayName": "tvOS 15.0",
+ "Version": "15.0",
+ "CanonicalName": "appletvos15.0",
+ "MaximumDeploymentTarget": "15.0.99",
+ "PropertyConditionFallbackNames": [],
+ "VersionMap": {
+ "iOS_tvOS": {
+ "13.2": "13.1"
+ },
+ "tvOS_iOS": {
+ "13.1": "13.2"
+ }
+ }
+}
+//--- module.modulemap
+module M { header "M.h" }
+//--- M.h
+void foo(void) __attribute__((availability(iOS, obsoleted = 13.2)));
+void test() { foo(); }
+
+//--- tu.m
+#include "M.h"
+
+// Compiling for tvOS 13.1 without "VersionMap" should succeed, since by default iOS 13.2 gets mapped to tvOS 13.2,
+// and \c foo is therefore **not** deprecated.
+// RUN: cp %t/AppleTVOS15.0.sdk/SDKSettings-old.json %t/AppleTVOS15.0.sdk/SDKSettings.json
+// RUN: %clang -target x86_64-apple-tvos13.1 -isysroot %t/AppleTVOS15.0.sdk \
+// RUN: -fsyntax-only %t/tu.m -o %t/tu.o -fmodules -Xclang -fdisable-module-hash -fmodules-cache-path=%t/cache
+
+// Compiling for tvOS 13.1 with "VersionMap" saying it maps to iOS 13.2 should fail, since \c foo is now deprecated.
+// RUN: sleep 1
+// RUN: cp %t/AppleTVOS15.0.sdk/SDKSettings-new.json %t/AppleTVOS15.0.sdk/SDKSettings.json
+// RUN: not %clang -target x86_64-apple-tvos13.1 -isysroot %t/AppleTVOS15.0.sdk \
+// RUN: -fsyntax-only %t/tu.m -o %t/tu.o -fmodules -Xclang -fdisable-module-hash -fmodules-cache-path=%t/cache 2>&1 \
+// RUN: | FileCheck %s
+// CHECK: M.h:2:15: error: 'foo' is unavailable: obsoleted in tvOS 13.1
+// CHECK: M.h:1:6: note: 'foo' has been explicitly marked unavailable here
+// CHECK: tu.m:1:10: fatal error: could not build module 'M'
diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index dae2b9a9fe683..3b42267f4d5f4 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -346,7 +346,10 @@ template <typename Container>
static auto toJSONStrings(llvm::json::OStream &JOS, Container &&Strings) {
return [&JOS, Strings = std::forward<Container>(Strings)] {
for (StringRef Str : Strings)
- JOS.value(Str);
+ // Not reporting SDKSettings.json so that test checks can remain (mostly)
+ // platform-agnostic.
+ if (!Str.ends_with("SDKSettings.json"))
+ JOS.value(Str);
};
}
@@ -498,7 +501,12 @@ class FullDeps {
toJSONStrings(JOS, MD.getBuildArguments()));
JOS.attribute("context-hash", StringRef(MD.ID.ContextHash));
JOS.attributeArray("file-deps", [&] {
- MD.forEachFileDep([&](StringRef FileDep) { JOS.value(FileDep); });
+ MD.forEachFileDep([&](StringRef FileDep) {
+ // Not reporting SDKSettings.json so that test checks can remain
+ // (mostly) platform-agnostic.
+ if (!FileDep.ends_with("SDKSettings.json"))
+ JOS.value(FileDep);
+ });
});
JOS.attributeArray("link-libraries",
toJSONSorted(JOS, MD.LinkLibraries));
More information about the cfe-commits
mailing list