Skip to content

Commit 2a8fd72

Browse files
committed
[Clang Importer] Defer module imports to end of bridging-header parse.
There is a subtle incompatibility between the way bridging headers handle module imports and the way clang's normal module-loading works (as done by -emit-pch in bridging PCH, in particular). When importing a submodule, Swift implicitly imports its supermodule. This is part of Swift's treatment of modules and fine, we're not changing it here. But if client code imports a submodule, then tries to use a type that is only defined in its supermodule, not the submodule, this _should_ cause a parse error (and does in clang alone, or when generating a PCH). Unfortunately Swift's "implicit parent import" currently happens eagerly, so the supermodule is imported and its type is defined as soon as the submodule is imported, which in turn suppresses the error. This in turn means that client code thinks their code "works" and then "breaks" when they turn on bridging PCH. What _should_ happen here is that the (actually broken) client code should not be accepted in the first place, neither bridging PCH nor textual bridging-header import. This commit merely changes textual bridging-header import from eager import to deferred parent-import, like bridging PCH does. This reconciles the difference in behaviour between the two, at the cost of a source-compat break. rdar://30615193
1 parent 49231a3 commit 2a8fd72

File tree

2 files changed

+32
-13
lines changed

2 files changed

+32
-13
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,7 @@ namespace {
8383
void handleImport(const clang::Module *imported) {
8484
if (!imported)
8585
return;
86-
ModuleDecl *nativeImported = Impl.finishLoadingClangModule(imported,
87-
/*preferAdapter=*/true);
88-
Impl.ImportedHeaderExports.push_back({ /*filter=*/{}, nativeImported });
86+
Impl.DeferredHeaderImports.push_back(imported);
8987
}
9088

9189
void InclusionDirective(clang::SourceLocation HashLoc,
@@ -963,6 +961,9 @@ bool ClangImporter::Implementation::importHeader(
963961
// Add any defined macros to the bridging header lookup table.
964962
addMacrosToLookupTable(*BridgingHeaderLookupTable, getNameImporter());
965963

964+
// Finish loading any extra modules that were (transitively) imported.
965+
handleDeferredImports();
966+
966967
// Wrap all Clang imports under a Swift import decl.
967968
for (auto &Import : BridgeHeaderTopLevelImports) {
968969
if (auto *ClangImport = Import.dyn_cast<clang::ImportDecl*>()) {
@@ -1008,16 +1009,11 @@ bool ClangImporter::importBridgingHeader(StringRef header, ModuleDecl *adapter,
10081009
bool trackParsedSymbols,
10091010
bool implicitImport) {
10101011
if (llvm::sys::path::extension(header).endswith(PCH_EXTENSION)) {
1011-
// We already imported this with -include-pch above, so we should have
1012-
// collected a bunch of PCH-encoded module imports that we need to
1013-
// replay to the HeaderImportCallbacks for processing.
10141012
Impl.ImportedHeaderOwners.push_back(adapter);
1015-
clang::ASTReader &R = *Impl.Instance->getModuleManager();
1016-
HeaderImportCallbacks CB(*this, Impl);
1017-
for (auto ID : Impl.PCHImportedSubmodules) {
1018-
CB.handleImport(R.getSubmodule(ID));
1019-
}
1020-
Impl.PCHImportedSubmodules.clear();
1013+
// We already imported this with -include-pch above, so we should have
1014+
// collected a bunch of PCH-encoded module imports that we just need to
1015+
// replay in handleDeferredImports.
1016+
Impl.handleDeferredImports();
10211017
return false;
10221018
}
10231019
clang::FileManager &fileManager = Impl.Instance->getFileManager();
@@ -1037,7 +1033,6 @@ bool ClangImporter::importBridgingHeader(StringRef header, ModuleDecl *adapter,
10371033
llvm::MemoryBuffer::getMemBufferCopy(
10381034
importLine, Implementation::bridgingHeaderBufferName)
10391035
};
1040-
10411036
return Impl.importHeader(adapter, header, diagLoc, trackParsedSymbols,
10421037
std::move(sourceBuffer), implicitImport);
10431038
}
@@ -1293,6 +1288,25 @@ ModuleDecl *ClangImporter::Implementation::finishLoadingClangModule(
12931288
return result;
12941289
}
12951290

1291+
// Run through the set of deferred imports -- either those referenced by
1292+
// submodule ID from a bridging PCH, or those already loaded as clang::Modules
1293+
// in response to an import directive in a bridging header -- and call
1294+
// finishLoadingClangModule on each.
1295+
void ClangImporter::Implementation::handleDeferredImports()
1296+
{
1297+
clang::ASTReader &R = *Instance->getModuleManager();
1298+
for (clang::serialization::SubmoduleID ID : PCHImportedSubmodules) {
1299+
DeferredHeaderImports.push_back(R.getSubmodule(ID));
1300+
}
1301+
PCHImportedSubmodules.clear();
1302+
for (const clang::Module *M : DeferredHeaderImports) {
1303+
ModuleDecl *nativeImported =
1304+
finishLoadingClangModule(M, /*preferAdapter=*/true);
1305+
ImportedHeaderExports.push_back({ /*filter=*/{}, nativeImported });
1306+
}
1307+
DeferredHeaderImports.clear();
1308+
}
1309+
12961310
ModuleDecl *ClangImporter::getImportedHeaderModule() const {
12971311
return Impl.ImportedHeaderUnit->getParentModule();
12981312
}

lib/ClangImporter/ImporterImpl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
275275

276276
bool IsReadingBridgingPCH;
277277
llvm::SmallVector<clang::serialization::SubmoduleID, 2> PCHImportedSubmodules;
278+
llvm::SmallVector<const clang::Module*, 2> DeferredHeaderImports;
278279

279280
const Version CurrentVersion;
280281

@@ -821,6 +822,10 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
821822
ModuleDecl *finishLoadingClangModule(const clang::Module *clangModule,
822823
bool preferAdapter);
823824

825+
/// \brief Call finishLoadingClangModule on each deferred import collected
826+
/// while scanning a bridging header or PCH.
827+
void handleDeferredImports();
828+
824829
/// \brief Retrieve the named Swift type, e.g., Int32.
825830
///
826831
/// \param moduleName The name of the module in which the type should occur.

0 commit comments

Comments
 (0)