Skip to content

Commit 39221b9

Browse files
authored
Merge pull request #14679 from jrose-apple/5.0-private-detective
[5.0] [ClangImporter] If a submodule named 'Private' is missing, ask Clang rdar://problem/37553763
2 parents ed6b0c5 + b6f085e commit 39221b9

File tree

11 files changed

+76
-4
lines changed

11 files changed

+76
-4
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,11 +1514,22 @@ ModuleDecl *ClangImporter::loadModule(
15141514

15151515
// Verify that the submodule exists.
15161516
clang::Module *submodule = clangModule;
1517-
for (auto component : path.slice(1)) {
1517+
for (auto &component : path.slice(1)) {
15181518
submodule = submodule->findSubmodule(component.first.str());
1519-
// FIXME: Specialize the error for a missing submodule?
1520-
if (!submodule)
1519+
1520+
// Special case: a submodule named "Foo.Private" can be moved to a top-level
1521+
// module named "Foo_Private". Clang has special support for this.
1522+
// We're limiting this to just submodules named "Private" because this will
1523+
// put the Clang AST in a fatal error state if it /doesn't/ exist.
1524+
if (!submodule && component.first.str() == "Private" &&
1525+
(&component) == (&path[1])) {
1526+
submodule = loadModule(llvm::makeArrayRef(clangPath).slice(0, 2), false);
1527+
}
1528+
1529+
if (!submodule) {
1530+
// FIXME: Specialize the error for a missing submodule?
15211531
return nullptr;
1532+
}
15221533
}
15231534

15241535
// Finally, load the submodule and make it visible.

lib/Sema/NameBinding.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,13 @@ void NameBinder::addImport(
198198
// If we imported a submodule, import the top-level module as well.
199199
Identifier topLevelName = ID->getModulePath().front().first;
200200
topLevelModule = Context.getLoadedModule(topLevelName);
201-
assert(topLevelModule && "top-level module missing");
201+
if (!topLevelModule) {
202+
// Clang can sometimes import top-level modules as if they were
203+
// submodules.
204+
assert(!M->getFiles().empty() &&
205+
isa<ClangModuleUnit>(M->getFiles().front()));
206+
topLevelModule = M;
207+
}
202208
}
203209

204210
auto *testableAttr = ID->getAttrs().getAttribute<TestableAttr>();
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
extern int PPGlobal;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
framework module PrivateAsParallel {
2+
umbrella header "PrivateAsParallel.h"
3+
export *
4+
module * {
5+
export *
6+
}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
framework module PrivateAsParallel_Private {
2+
umbrella header "PrivateAsParallel_Priv.h"
3+
export *
4+
module * {
5+
export *
6+
}
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#include <PrivateAsParallel/PrivateAsParallel.h>
2+
extern int PPPrivateGlobal;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
extern int PSGlobal;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
framework module PrivateAsSubmodule {
2+
umbrella header "PrivateAsSubmodule.h"
3+
export *
4+
module * {
5+
export *
6+
}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
explicit module PrivateAsSubmodule.Private {
2+
umbrella header "PrivateAsSubmodule_Priv.h"
3+
export *
4+
module * {
5+
export *
6+
}
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#include <PrivateAsSubmodule/PrivateAsSubmodule.h>
2+
extern int PSPrivateGlobal;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend -typecheck -F %S/Inputs/frameworks -DOLD -verify %s -Xcc -Wno-private-module
4+
// RUN: %target-swift-frontend -typecheck -F %S/Inputs/frameworks -DNEW -verify %s -Xcc -Wno-private-module
5+
6+
import PrivateAsSubmodule.Private
7+
8+
#if OLD
9+
import PrivateAsParallel.Private
10+
#elseif NEW
11+
import PrivateAsParallel_Private
12+
#else
13+
// This syntax wasn't supported when originally cherry-picked to this branch.
14+
// It's just to catch mistakes updating the test, though.
15+
//#error("OLD or NEW must be defined")
16+
#endif
17+
18+
let _: Bool = PSGlobal // expected-error {{cannot convert value of type 'Int32'}}
19+
let _: Bool = PSPrivateGlobal // expected-error {{cannot convert value of type 'Int32'}}
20+
let _: Bool = PPGlobal // expected-error {{cannot convert value of type 'Int32'}}
21+
let _: Bool = PPPrivateGlobal // expected-error {{cannot convert value of type 'Int32'}}

0 commit comments

Comments
 (0)