Skip to content

Commit a32dd95

Browse files
[Modules] Avoid false swift module sharing
When the swiftmodule is built with different clang importer arguments, they can have the same module hash, causing them to be wrongly re-used even they contains different interfaces. Add ReducedExtraArgs to the module hash to disambiguate them. However, some Xcc arguments, most commonly `-D` options do not affect the swiftmodule being generated. Do not pass `-Xcc -DARGS` to swift interface compilation to reduce the amount of module variants in the build. rdar://131408266
1 parent 4993f4b commit a32dd95

File tree

8 files changed

+114
-22
lines changed

8 files changed

+114
-22
lines changed

include/swift/ClangImporter/ClangImporter.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,8 @@ class ClangImporter final : public ClangModuleLoader {
517517
std::string getClangModuleHash() const;
518518

519519
/// Get clang import creation cc1 args for swift explicit module build.
520-
std::vector<std::string> getSwiftExplicitModuleDirectCC1Args() const;
520+
std::vector<std::string>
521+
getSwiftExplicitModuleDirectCC1Args(bool isInterface) const;
521522

522523
/// If we already imported a given decl successfully, return the corresponding
523524
/// Swift decl as an Optional<Decl *>, but if we previously tried and failed

lib/Basic/LangOptions.cpp

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -726,22 +726,23 @@ namespace {
726726
"-working-directory=",
727727
"-working-directory"};
728728

729-
constexpr std::array<std::string_view, 15> knownClangDependencyIgnorablePrefiexes =
730-
{"-I",
731-
"-F",
732-
"-fmodule-map-file=",
733-
"-iquote",
734-
"-idirafter",
735-
"-iframeworkwithsysroot",
736-
"-iframework",
737-
"-iprefix",
738-
"-iwithprefixbefore",
739-
"-iwithprefix",
740-
"-isystemafter",
741-
"-isystem",
742-
"-isysroot",
743-
"-working-directory=",
744-
"-working-directory"};
729+
constexpr std::array<std::string_view, 16>
730+
knownClangDependencyIgnorablePrefiexes = {"-I",
731+
"-F",
732+
"-fmodule-map-file=",
733+
"-iquote",
734+
"-idirafter",
735+
"-iframeworkwithsysroot",
736+
"-iframework",
737+
"-iprefix",
738+
"-iwithprefixbefore",
739+
"-iwithprefix",
740+
"-isystemafter",
741+
"-isystem",
742+
"-isysroot",
743+
"-working-directory=",
744+
"-working-directory",
745+
"-D"};
745746
}
746747

747748
std::vector<std::string> ClangImporterOptions::getRemappedExtraArgs(

lib/ClangImporter/ClangImporter.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4070,7 +4070,7 @@ std::string ClangImporter::getClangModuleHash() const {
40704070
}
40714071

40724072
std::vector<std::string>
4073-
ClangImporter::getSwiftExplicitModuleDirectCC1Args() const {
4073+
ClangImporter::getSwiftExplicitModuleDirectCC1Args(bool isInterface) const {
40744074
llvm::SmallVector<const char*> clangArgs;
40754075
clangArgs.reserve(Impl.ClangArgs.size());
40764076
llvm::for_each(Impl.ClangArgs, [&](const std::string &Arg) {
@@ -4120,6 +4120,14 @@ ClangImporter::getSwiftExplicitModuleDirectCC1Args() const {
41204120
PPOpts.MacroIncludes.clear();
41214121
PPOpts.Includes.clear();
41224122

4123+
// Clear specific options that will not affect swiftinterface compilation, but
4124+
// might affect main Module.
4125+
if (isInterface) {
4126+
// Interfacefile should not need `-D` but pass to main module in case it
4127+
// needs to directly import clang headers.
4128+
PPOpts.Macros.clear();
4129+
}
4130+
41234131
if (Impl.SwiftContext.ClangImporterOpts.UseClangIncludeTree) {
41244132
// FileSystemOptions.
41254133
auto &FSOpts = instance.getFileSystemOpts();

lib/DependencyScan/ModuleDependencyScanner.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,8 @@ ModuleDependencyScanner::getMainModuleDependencyInfo(ModuleDecl *mainModule) {
381381
std::vector<std::string> buildArgs;
382382
if (ScanASTContext.ClangImporterOpts.ClangImporterDirectCC1Scan) {
383383
buildArgs.push_back("-direct-clang-cc1-module-build");
384-
for (auto &arg : clangImporter->getSwiftExplicitModuleDirectCC1Args()) {
384+
for (auto &arg : clangImporter->getSwiftExplicitModuleDirectCC1Args(
385+
/*isInterface=*/false)) {
385386
buildArgs.push_back("-Xcc");
386387
buildArgs.push_back(arg);
387388
}

lib/Frontend/ModuleInterfaceLoader.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,6 +2072,8 @@ InterfaceSubContextDelegateImpl::getCacheHash(StringRef useInterfacePath,
20722072
auto normalizedTargetTriple =
20732073
getTargetSpecificModuleTriple(genericSubInvocation.getLangOptions().Target);
20742074
std::string sdkBuildVersion = getSDKBuildVersion(sdkPath);
2075+
const auto ExtraArgs = genericSubInvocation.getClangImporterOptions()
2076+
.getReducedExtraArgsForSwiftModuleDependency();
20752077

20762078
llvm::hash_code H = hash_combine(
20772079
// Start with the compiler version (which will be either tag names or
@@ -2113,6 +2115,10 @@ InterfaceSubContextDelegateImpl::getCacheHash(StringRef useInterfacePath,
21132115
// correctly load the dependencies.
21142116
genericSubInvocation.getCASOptions().getModuleScanningHashComponents(),
21152117

2118+
// Clang ExtraArgs that affects how clang types are imported into swift
2119+
// module.
2120+
llvm::hash_combine_range(ExtraArgs.begin(), ExtraArgs.end()),
2121+
21162122
// Whether or not OSSA modules are enabled.
21172123
//
21182124
// If OSSA modules are enabled, we use a separate namespace of modules to

lib/Serialization/ScanningLoaders.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,8 @@ SwiftModuleScanner::scanInterfaceFile(Twine moduleInterfacePath,
186186
Args.push_back("-direct-clang-cc1-module-build");
187187
auto *importer =
188188
static_cast<ClangImporter *>(Ctx.getClangModuleLoader());
189-
for (auto &Arg : importer->getSwiftExplicitModuleDirectCC1Args()) {
189+
for (auto &Arg : importer->getSwiftExplicitModuleDirectCC1Args(
190+
/*isInterface=*/true)) {
190191
Args.push_back("-Xcc");
191192
Args.push_back(Arg);
192193
}

test/CAS/Xcc_args.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
private import _Macro
3737

3838
public func test() {
39-
let _ = VERSION
39+
// Check the VERSION is from command-line, thus a Int32, not string.
40+
let _ : Int32 = VERSION
4041
}
4142

4243
//--- include/module.modulemap
@@ -49,7 +50,7 @@ module _Macro {
4950
#if defined(_VERSION)
5051
#define VERSION _VERSION
5152
#else
52-
#define VERSION 0
53+
#define VERSION "not available"
5354
#endif
5455

5556
//--- hmap.json
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// REQUIRES: objc_interop
2+
// RUN: %empty-directory(%t)
3+
// RUN: split-file %s %t
4+
5+
// RUN: %target-swift-frontend -scan-dependencies -module-name Test %t/main.swift -module-cache-path %t/clang-module-cache \
6+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -O \
7+
// RUN: -o %t/deps-1.json -I %t/include
8+
9+
// RUN: %target-swift-frontend -scan-dependencies -module-name Test %t/main.swift -module-cache-path %t/clang-module-cache \
10+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -O \
11+
// RUN: -o %t/deps-2.json -Xcc -DHAS_FOO=1 -I %t/include
12+
13+
// RUN: %target-swift-frontend -scan-dependencies -module-name Test %t/main.swift -module-cache-path %t/clang-module-cache \
14+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -O \
15+
// RUN: -o %t/deps-3.json -Xcc -fapplication-extension -I %t/include
16+
17+
/// Check module hash for the swiftmodule. 1 and 2 should match, but not 3.
18+
// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps-1.json Library modulePath > %t/path-1
19+
// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps-2.json Library modulePath > %t/path-2
20+
// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps-3.json Library modulePath > %t/path-3
21+
// RUN: diff %t/path-1 %t/path-2
22+
// RUN: not diff %t/path-1 %t/path-3
23+
24+
/// Check build command (exclude dependency module file path). 1 and 2 should match, but not 3.
25+
// RUN: %{python} %S/../CAS/Inputs/BuildCommandExtractor.py %t/deps-1.json Library | grep -v fmodule-file= > %t/lib-1.cmd
26+
// RUN: %{python} %S/../CAS/Inputs/BuildCommandExtractor.py %t/deps-2.json Library | grep -v fmodule-file= > %t/lib-2.cmd
27+
// RUN: %{python} %S/../CAS/Inputs/BuildCommandExtractor.py %t/deps-3.json Library | grep -v fmodule-file= > %t/lib-3.cmd
28+
// RUN: diff %t/lib-1.cmd %t/lib-2.cmd
29+
// RUN: not diff %t/lib-1.cmd %t/lib-3.cmd
30+
31+
/// Test direct-cc1 mode.
32+
// RUN: %target-swift-frontend -scan-dependencies -module-name Test %t/main.swift -module-cache-path %t/clang-module-cache \
33+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -O \
34+
// RUN: -o %t/deps-4.json -I %t/include -experimental-clang-importer-direct-cc1-scan
35+
// RUN: %target-swift-frontend -scan-dependencies -module-name Test %t/main.swift -module-cache-path %t/clang-module-cache \
36+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -O \
37+
// RUN: -o %t/deps-5.json -Xcc -DHAS_FOO=1 -I %t/include -experimental-clang-importer-direct-cc1-scan
38+
// RUN: %target-swift-frontend -scan-dependencies -module-name Test %t/main.swift -module-cache-path %t/clang-module-cache \
39+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -O \
40+
// RUN: -o %t/deps-6.json -Xcc -fapplication-extension -I %t/include -experimental-clang-importer-direct-cc1-scan
41+
42+
// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps-4.json Library modulePath > %t/path-4
43+
// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps-5.json Library modulePath > %t/path-5
44+
// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps-6.json Library modulePath > %t/path-6
45+
// RUN: diff %t/path-4 %t/path-5
46+
// RUN: not diff %t/path-4 %t/path-6
47+
// RUN: %{python} %S/../CAS/Inputs/BuildCommandExtractor.py %t/deps-4.json Library | grep -v fmodule-file= > %t/lib-4.cmd
48+
// RUN: %{python} %S/../CAS/Inputs/BuildCommandExtractor.py %t/deps-5.json Library | grep -v fmodule-file= > %t/lib-5.cmd
49+
// RUN: %{python} %S/../CAS/Inputs/BuildCommandExtractor.py %t/deps-6.json Library | grep -v fmodule-file= > %t/lib-6.cmd
50+
// RUN: diff %t/lib-4.cmd %t/lib-5.cmd
51+
// RUN: not diff %t/lib-4.cmd %t/lib-6.cmd
52+
53+
//--- main.swift
54+
import Library
55+
56+
//--- include/Library.swiftinterface
57+
// swift-interface-format-version: 1.0
58+
// swift-module-flags: -module-name Library -O -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -user-module-version 1.0
59+
import Swift
60+
@_exported import A
61+
public func test() {}
62+
63+
//--- include/a.h
64+
#ifdef HAS_FOO
65+
void foo(void);
66+
#endif
67+
void bar(void);
68+
69+
//--- include/module.modulemap
70+
module A {
71+
header "a.h"
72+
export *
73+
}

0 commit comments

Comments
 (0)