Skip to content

Commit 9a6e99f

Browse files
authored
Merge pull request #10679 from swiftlang/jan_svoboda/release-6.2-sdk-settings-json
🍒[clang][modules] Invalidate module cache when SDKSettings.json changes
2 parents 9765245 + 7bb8a75 commit 9a6e99f

File tree

6 files changed

+160
-16
lines changed

6 files changed

+160
-16
lines changed

clang/lib/Index/IndexingAction.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,10 @@ class ModuleFileIndexDependencyCollector : public IndexDependencyProvider {
919919
// undesirable dependency on an intermediate build byproduct.
920920
if (FE->getName().ends_with("module.modulemap"))
921921
return;
922+
// Ignore SDKSettings.json, they are not important to track for
923+
// indexing.
924+
if (FE->getName().ends_with("SDKSettings.json"))
925+
return;
922926

923927
visitor(*FE, isSystem);
924928
});

clang/lib/Serialization/ASTWriter.cpp

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,6 +1771,29 @@ struct InputFileEntry {
17711771
uint32_t ContentHash[2];
17721772

17731773
InputFileEntry(FileEntryRef File) : File(File) {}
1774+
1775+
void trySetContentHash(
1776+
Preprocessor &PP,
1777+
llvm::function_ref<std::optional<llvm::MemoryBufferRef>()> GetMemBuff) {
1778+
ContentHash[0] = 0;
1779+
ContentHash[1] = 0;
1780+
1781+
if (!PP.getHeaderSearchInfo()
1782+
.getHeaderSearchOpts()
1783+
.ValidateASTInputFilesContent)
1784+
return;
1785+
1786+
auto MemBuff = GetMemBuff();
1787+
if (!MemBuff) {
1788+
PP.Diag(SourceLocation(), diag::err_module_unable_to_hash_content)
1789+
<< File.getName();
1790+
return;
1791+
}
1792+
1793+
uint64_t Hash = xxh3_64bits(MemBuff->getBuffer());
1794+
ContentHash[0] = uint32_t(Hash);
1795+
ContentHash[1] = uint32_t(Hash >> 32);
1796+
}
17741797
};
17751798

17761799
} // namespace
@@ -1843,25 +1866,41 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
18431866
Entry.IsTopLevel = getAffectingIncludeLoc(SourceMgr, File).isInvalid();
18441867
Entry.IsModuleMap = isModuleMap(File.getFileCharacteristic());
18451868

1846-
uint64_t ContentHash = 0;
1847-
if (PP->getHeaderSearchInfo()
1848-
.getHeaderSearchOpts()
1849-
.ValidateASTInputFilesContent) {
1850-
auto MemBuff = Cache->getBufferIfLoaded();
1851-
if (MemBuff)
1852-
ContentHash = xxh3_64bits(MemBuff->getBuffer());
1853-
else
1854-
PP->Diag(SourceLocation(), diag::err_module_unable_to_hash_content)
1855-
<< Entry.File.getName();
1856-
}
1857-
Entry.ContentHash[0] = uint32_t(ContentHash);
1858-
Entry.ContentHash[1] = uint32_t(ContentHash >> 32);
1869+
Entry.trySetContentHash(*PP, [&] { return Cache->getBufferIfLoaded(); });
1870+
18591871
if (Entry.IsSystemFile)
18601872
SystemFiles.push_back(Entry);
18611873
else
18621874
UserFiles.push_back(Entry);
18631875
}
18641876

1877+
// FIXME: Make providing input files not in the SourceManager more flexible.
1878+
// The SDKSettings.json file is necessary for correct evaluation of
1879+
// availability annotations.
1880+
StringRef Sysroot = PP->getHeaderSearchInfo().getHeaderSearchOpts().Sysroot;
1881+
if (!Sysroot.empty()) {
1882+
SmallString<128> SDKSettingsJSON = Sysroot;
1883+
llvm::sys::path::append(SDKSettingsJSON, "SDKSettings.json");
1884+
FileManager &FM = PP->getFileManager();
1885+
if (auto FE = FM.getOptionalFileRef(SDKSettingsJSON)) {
1886+
InputFileEntry Entry(*FE);
1887+
Entry.IsSystemFile = true;
1888+
Entry.IsTransient = false;
1889+
Entry.BufferOverridden = false;
1890+
Entry.IsTopLevel = true;
1891+
Entry.IsModuleMap = false;
1892+
std::unique_ptr<MemoryBuffer> MB;
1893+
Entry.trySetContentHash(*PP, [&]() -> std::optional<MemoryBufferRef> {
1894+
if (auto MBOrErr = FM.getBufferForFile(Entry.File)) {
1895+
MB = std::move(*MBOrErr);
1896+
return MB->getMemBufferRef();
1897+
}
1898+
return std::nullopt;
1899+
});
1900+
SystemFiles.push_back(Entry);
1901+
}
1902+
}
1903+
18651904
// User files go at the front, system files at the back.
18661905
auto SortedFiles = llvm::concat<InputFileEntry>(std::move(UserFiles),
18671906
std::move(SystemFiles));
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// This test checks that the module cache gets invalidated when the
2+
// SDKSettings.json file changes. This prevents "file changed during build"
3+
// errors when the TU does get rescanned and recompiled.
4+
5+
// REQUIRES: ondisk_cas
6+
7+
// RUN: rm -rf %t
8+
// RUN: split-file %s %t
9+
10+
//--- sdk/SDKSettings.json
11+
{
12+
"Version": "11.0",
13+
"MaximumDeploymentTarget": "11.0.99"
14+
}
15+
16+
//--- module.modulemap
17+
module M { header "M.h" }
18+
//--- M.h
19+
//--- tu.c
20+
#include "M.h"
21+
22+
// RUN: clang-scan-deps -format experimental-include-tree-full -cas-path %t/cas -o %t/deps_clean.json \
23+
// RUN: -- %clang -target x86_64-apple-macos11 -isysroot %t/sdk \
24+
// RUN: -c %t/tu.c -o %t/tu.o -fmodules -fmodules-cache-path=%t/cache
25+
26+
// RUN: sleep 1
27+
// RUN: echo " " >> %t/sdk/SDKSettings.json
28+
// RUN: echo " " >> %t/tu.c
29+
30+
// RUN: clang-scan-deps -format experimental-include-tree-full -cas-path %t/cas -o %t/deps_incremental.json \
31+
// RUN: -- %clang -target x86_64-apple-macos11 -isysroot %t/sdk \
32+
// RUN: -c %t/tu.c -o %t/tu.o -fmodules -fmodules-cache-path=%t/cache
33+
34+
// RUN: %deps-to-rsp %t/deps_incremental.json --module-name M > %t/M.rsp
35+
// RUN: %deps-to-rsp %t/deps_incremental.json --tu-index 0 > %t/tu.rsp
36+
// RUN: %clang @%t/M.rsp
37+
// RUN: %clang @%t/tu.rsp
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// This test checks that the module cache gets invalidated when the SDKSettings.json file changes.
2+
3+
// RUN: rm -rf %t
4+
// RUN: split-file %s %t
5+
6+
//--- AppleTVOS15.0.sdk/SDKSettings-old.json
7+
{
8+
"DisplayName": "tvOS 15.0",
9+
"Version": "15.0",
10+
"CanonicalName": "appletvos15.0",
11+
"MaximumDeploymentTarget": "15.0.99",
12+
"PropertyConditionFallbackNames": []
13+
}
14+
//--- AppleTVOS15.0.sdk/SDKSettings-new.json
15+
{
16+
"DisplayName": "tvOS 15.0",
17+
"Version": "15.0",
18+
"CanonicalName": "appletvos15.0",
19+
"MaximumDeploymentTarget": "15.0.99",
20+
"PropertyConditionFallbackNames": [],
21+
"VersionMap": {
22+
"iOS_tvOS": {
23+
"13.2": "13.1"
24+
},
25+
"tvOS_iOS": {
26+
"13.1": "13.2"
27+
}
28+
}
29+
}
30+
//--- module.modulemap
31+
module M { header "M.h" }
32+
//--- M.h
33+
void foo(void) __attribute__((availability(iOS, obsoleted = 13.2)));
34+
void test() { foo(); }
35+
36+
//--- tu.m
37+
#include "M.h"
38+
39+
// Compiling for tvOS 13.1 without "VersionMap" should succeed, since by default iOS 13.2 gets mapped to tvOS 13.2,
40+
// and \c foo is therefore **not** deprecated.
41+
// RUN: cp %t/AppleTVOS15.0.sdk/SDKSettings-old.json %t/AppleTVOS15.0.sdk/SDKSettings.json
42+
// RUN: %clang -target x86_64-apple-tvos13.1 -isysroot %t/AppleTVOS15.0.sdk \
43+
// RUN: -fsyntax-only %t/tu.m -o %t/tu.o -fmodules -Xclang -fdisable-module-hash -fmodules-cache-path=%t/cache
44+
45+
// Compiling for tvOS 13.1 with "VersionMap" saying it maps to iOS 13.2 should fail, since \c foo is now deprecated.
46+
// RUN: sleep 1
47+
// RUN: cp %t/AppleTVOS15.0.sdk/SDKSettings-new.json %t/AppleTVOS15.0.sdk/SDKSettings.json
48+
// RUN: not %clang -target x86_64-apple-tvos13.1 -isysroot %t/AppleTVOS15.0.sdk \
49+
// RUN: -fsyntax-only %t/tu.m -o %t/tu.o -fmodules -Xclang -fdisable-module-hash -fmodules-cache-path=%t/cache 2>&1 \
50+
// RUN: | FileCheck %s
51+
// CHECK: M.h:2:15: error: 'foo' is unavailable: obsoleted in tvOS 13.1
52+
// CHECK: M.h:1:6: note: 'foo' has been explicitly marked unavailable here
53+
// CHECK: tu.m:1:10: fatal error: could not build module 'M'

clang/tools/c-index-test/core_main.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -850,7 +850,10 @@ static int scanDeps(ArrayRef<const char *> Args, std::string WorkingDirectory,
850850
llvm::outs() << " " << ModuleName << "\n";
851851
llvm::outs() << " file-deps:\n";
852852
for (const auto &FileName : ArrayRef(FileDeps.Strings, FileDeps.Count))
853-
llvm::outs() << " " << FileName << "\n";
853+
// Not reporting SDKSettings.json so that test checks can remain
854+
// (mostly) platform-agnostic.
855+
if (!StringRef(FileName).ends_with("SDKSettings.json"))
856+
llvm::outs() << " " << FileName << "\n";
854857
llvm::outs() << " build-args:";
855858
for (const auto &Arg :
856859
ArrayRef(BuildArguments.Strings, BuildArguments.Count))

clang/tools/clang-scan-deps/ClangScanDeps.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,10 @@ template <typename Container>
597597
static auto toJSONStrings(llvm::json::OStream &JOS, Container &&Strings) {
598598
return [&JOS, Strings = std::forward<Container>(Strings)] {
599599
for (StringRef Str : Strings)
600-
JOS.value(Str);
600+
// Not reporting SDKSettings.json so that test checks can remain (mostly)
601+
// platform-agnostic.
602+
if (!Str.ends_with("SDKSettings.json"))
603+
JOS.value(Str);
601604
};
602605
}
603606

@@ -743,7 +746,12 @@ class FullDeps {
743746
toJSONStrings(JOS, MD.getBuildArguments()));
744747
JOS.attribute("context-hash", StringRef(MD.ID.ContextHash));
745748
JOS.attributeArray("file-deps", [&] {
746-
MD.forEachFileDep([&](StringRef FileDep) { JOS.value(FileDep); });
749+
MD.forEachFileDep([&](StringRef FileDep) {
750+
// Not reporting SDKSettings.json so that test checks can remain
751+
// (mostly) platform-agnostic.
752+
if (!FileDep.ends_with("SDKSettings.json"))
753+
JOS.value(FileDep);
754+
});
747755
});
748756
JOS.attributeArray("link-libraries",
749757
toJSONSorted(JOS, MD.LinkLibraries));

0 commit comments

Comments
 (0)