Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 52 additions & 13 deletions clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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));
Expand Down
53 changes: 53 additions & 0 deletions clang/test/Modules/sdk-settings-json-dep.m
Original file line number Diff line number Diff line change
@@ -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'
12 changes: 10 additions & 2 deletions clang/tools/clang-scan-deps/ClangScanDeps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
}

Expand Down Expand Up @@ -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));
Expand Down