Skip to content

Commit 986bd48

Browse files
authored
Merge pull request #17186 from jrose-apple/bridge-over-troubled-imports (#17300)
[Serialization] Always list the bridging header before any imports rdar://problem/40471329 (cherry picked from commit e5cec5f)
1 parent 4625b5a commit 986bd48

File tree

11 files changed

+97
-19
lines changed

11 files changed

+97
-19
lines changed

include/swift/Serialization/ModuleFile.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,13 @@ class ModuleFile
625625
return static_cast<Status>(Bits.Status);
626626
}
627627

628+
/// Transfers ownership of a buffer that might contain source code where
629+
/// other parts of the compiler could have emitted diagnostics, to keep them
630+
/// alive even if the ModuleFile is destroyed.
631+
///
632+
/// Should only be called when getStatus() indicates a failure.
633+
std::unique_ptr<llvm::MemoryBuffer> takeBufferForDiagnostics();
634+
628635
/// Returns the list of modules this module depends on.
629636
ArrayRef<Dependency> getDependencies() const {
630637
return Dependencies;

include/swift/Serialization/SerializedModuleLoader.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ class SerializedModuleLoader : public ModuleLoader {
2929
using LoadedModulePair = std::pair<std::unique_ptr<ModuleFile>, unsigned>;
3030
std::vector<LoadedModulePair> LoadedModuleFiles;
3131

32+
SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 2> OrphanedMemoryBuffers;
33+
3234
explicit SerializedModuleLoader(ASTContext &ctx, DependencyTracker *tracker);
3335

3436
public:

lib/Serialization/ModuleFile.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,6 +1468,17 @@ Status ModuleFile::associateWithFileContext(FileUnit *file,
14681468
return getStatus();
14691469
}
14701470

1471+
std::unique_ptr<llvm::MemoryBuffer> ModuleFile::takeBufferForDiagnostics() {
1472+
assert(getStatus() != Status::Valid);
1473+
1474+
// Today, the only buffer that might have diagnostics in them is the input
1475+
// buffer, and even then only if it has imported module contents.
1476+
if (!importedHeaderInfo.contents.empty())
1477+
return std::move(ModuleInputBuffer);
1478+
1479+
return nullptr;
1480+
}
1481+
14711482
ModuleFile::~ModuleFile() { }
14721483

14731484
void ModuleFile::lookupValue(DeclName name,

lib/Serialization/Serialization.cpp

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,28 +1070,38 @@ void Serializer::writeInputBlock(const SerializationOptions &options) {
10701070
publicImportSet.insert(publicImports.begin(), publicImports.end());
10711071

10721072
removeDuplicateImports(allImports);
1073+
10731074
auto clangImporter =
10741075
static_cast<ClangImporter *>(M->getASTContext().getClangModuleLoader());
1075-
ModuleDecl *importedHeaderModule = clangImporter->getImportedHeaderModule();
1076+
ModuleDecl *bridgingHeaderModule = clangImporter->getImportedHeaderModule();
1077+
ModuleDecl::ImportedModule bridgingHeaderImport{{}, bridgingHeaderModule};
1078+
1079+
// Make sure the bridging header module is always at the top of the import
1080+
// list, mimicking how it is processed before any module imports when
1081+
// compiling source files.
1082+
if (llvm::is_contained(allImports, bridgingHeaderImport)) {
1083+
off_t importedHeaderSize = 0;
1084+
time_t importedHeaderModTime = 0;
1085+
std::string contents;
1086+
if (!options.ImportedHeader.empty()) {
1087+
contents = clangImporter->getBridgingHeaderContents(
1088+
options.ImportedHeader, importedHeaderSize, importedHeaderModTime);
1089+
}
1090+
assert(publicImportSet.count(bridgingHeaderImport));
1091+
ImportedHeader.emit(ScratchRecord,
1092+
publicImportSet.count(bridgingHeaderImport),
1093+
importedHeaderSize, importedHeaderModTime,
1094+
options.ImportedHeader);
1095+
if (!contents.empty()) {
1096+
contents.push_back('\0');
1097+
ImportedHeaderContents.emit(ScratchRecord, contents);
1098+
}
1099+
}
1100+
10761101
ModuleDecl *theBuiltinModule = M->getASTContext().TheBuiltinModule;
10771102
for (auto import : allImports) {
1078-
if (import.second == theBuiltinModule)
1079-
continue;
1080-
1081-
if (import.second == importedHeaderModule) {
1082-
off_t importedHeaderSize = 0;
1083-
time_t importedHeaderModTime = 0;
1084-
std::string contents;
1085-
if (!options.ImportedHeader.empty())
1086-
contents = clangImporter->getBridgingHeaderContents(
1087-
options.ImportedHeader, importedHeaderSize, importedHeaderModTime);
1088-
ImportedHeader.emit(ScratchRecord, publicImportSet.count(import),
1089-
importedHeaderSize, importedHeaderModTime,
1090-
options.ImportedHeader);
1091-
if (!contents.empty()) {
1092-
contents.push_back('\0');
1093-
ImportedHeaderContents.emit(ScratchRecord, contents);
1094-
}
1103+
if (import.second == theBuiltinModule ||
1104+
import.second == bridgingHeaderModule) {
10951105
continue;
10961106
}
10971107

lib/Serialization/SerializedModuleLoader.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,14 @@ FileUnit *SerializedModuleLoader::loadAST(
223223
M.removeFile(*fileUnit);
224224
}
225225

226-
// This is the failure path. If we have a location, diagnose the issue.
226+
// From here on is the failure path.
227+
228+
// Even though the module failed to load, it's possible its contents include
229+
// a source buffer that need to survive because it's already been used for
230+
// diagnostics.
231+
if (auto orphanedBuffer = loadedModuleFile->takeBufferForDiagnostics())
232+
OrphanedMemoryBuffers.push_back(std::move(orphanedBuffer));
233+
227234
if (!diagLoc)
228235
return nullptr;
229236

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@protocol AmbivalentProtocol
2+
@end
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#import <AmbivalentProtocol.h>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module Module {
2+
umbrella header "modular.h"
3+
module * { export * }
4+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#import "AmbivalentProtocol.h"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
$S4main1CCACycfc
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-build-swift -emit-module -emit-executable %s -g -I %S/Inputs/bridging-header-first/ -import-objc-header %S/Inputs/bridging-header-first/bridging.h -o %t/main
4+
// RUN: llvm-bcanalyzer -dump %t/main.swiftmodule | %FileCheck -check-prefix CHECK-DUMP %s
5+
// RUN: %lldb-moduleimport-test %t/main -type-from-mangled %S/Inputs/bridging-header-first/mangled.txt 2>&1 | %FileCheck -check-prefix CHECK-RESOLVED-TYPE %s
6+
7+
// RUN: %target-build-swift -emit-module -emit-executable %s -g -I %S/Inputs/bridging-header-first/ -import-objc-header %S/Inputs/bridging-header-first/bridging.h -o %t/main -whole-module-optimization
8+
// RUN: llvm-bcanalyzer -dump %t/main.swiftmodule | %FileCheck -check-prefix CHECK-DUMP %s
9+
// RUN: %lldb-moduleimport-test %t/main -type-from-mangled %S/Inputs/bridging-header-first/mangled.txt 2>&1 | %FileCheck -check-prefix CHECK-RESOLVED-TYPE %s
10+
11+
// REQUIRES: objc_interop
12+
13+
// CHECK-DUMP-LABEL: CONTROL_BLOCK
14+
// CHECK-DUMP: MODULE_NAME
15+
// CHECK-DUMP-SAME: 'main'
16+
17+
// CHECK-DUMP-LABEL: INPUT_BLOCK
18+
// CHECK-DUMP: IMPORTED_HEADER
19+
// CHECK-DUMP-SAME: '{{.+}}/bridging.h'
20+
// CHECK-DUMP: IMPORTED_MODULE
21+
// CHECK-DUMP-SAME: 'Module'
22+
// CHECK-DUMP: IMPORTED_MODULE
23+
// CHECK-DUMP-SAME: 'Swift'
24+
25+
26+
// CHECK-RESOLVED-TYPE: @convention(method) (C.Type) -> () -> C
27+
28+
import Module
29+
class C {}
30+
extension C: AmbivalentProtocol {
31+
func f() {}
32+
}

0 commit comments

Comments
 (0)