Skip to content

Commit e5cec5f

Browse files
authored
Merge pull request #17186 from jrose-apple/bridge-over-troubled-imports
[Serialization] Always list the bridging header before any imports rdar://problem/40471329
2 parents 864bf89 + 6dcda93 commit e5cec5f

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
@@ -619,6 +619,13 @@ class ModuleFile
619619
return static_cast<Status>(Bits.Status);
620620
}
621621

622+
/// Transfers ownership of a buffer that might contain source code where
623+
/// other parts of the compiler could have emitted diagnostics, to keep them
624+
/// alive even if the ModuleFile is destroyed.
625+
///
626+
/// Should only be called when getStatus() indicates a failure.
627+
std::unique_ptr<llvm::MemoryBuffer> takeBufferForDiagnostics();
628+
622629
/// Returns the list of modules this module depends on.
623630
ArrayRef<Dependency> getDependencies() const {
624631
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
@@ -1456,6 +1456,17 @@ Status ModuleFile::associateWithFileContext(FileUnit *file,
14561456
return getStatus();
14571457
}
14581458

1459+
std::unique_ptr<llvm::MemoryBuffer> ModuleFile::takeBufferForDiagnostics() {
1460+
assert(getStatus() != Status::Valid);
1461+
1462+
// Today, the only buffer that might have diagnostics in them is the input
1463+
// buffer, and even then only if it has imported module contents.
1464+
if (!importedHeaderInfo.contents.empty())
1465+
return std::move(ModuleInputBuffer);
1466+
1467+
return nullptr;
1468+
}
1469+
14591470
ModuleFile::~ModuleFile() { }
14601471

14611472
void ModuleFile::lookupValue(DeclName name,

lib/Serialization/Serialization.cpp

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

10641064
removeDuplicateImports(allImports);
1065+
10651066
auto clangImporter =
10661067
static_cast<ClangImporter *>(M->getASTContext().getClangModuleLoader());
1067-
ModuleDecl *importedHeaderModule = clangImporter->getImportedHeaderModule();
1068+
ModuleDecl *bridgingHeaderModule = clangImporter->getImportedHeaderModule();
1069+
ModuleDecl::ImportedModule bridgingHeaderImport{{}, bridgingHeaderModule};
1070+
1071+
// Make sure the bridging header module is always at the top of the import
1072+
// list, mimicking how it is processed before any module imports when
1073+
// compiling source files.
1074+
if (llvm::is_contained(allImports, bridgingHeaderImport)) {
1075+
off_t importedHeaderSize = 0;
1076+
time_t importedHeaderModTime = 0;
1077+
std::string contents;
1078+
if (!options.ImportedHeader.empty()) {
1079+
contents = clangImporter->getBridgingHeaderContents(
1080+
options.ImportedHeader, importedHeaderSize, importedHeaderModTime);
1081+
}
1082+
assert(publicImportSet.count(bridgingHeaderImport));
1083+
ImportedHeader.emit(ScratchRecord,
1084+
publicImportSet.count(bridgingHeaderImport),
1085+
importedHeaderSize, importedHeaderModTime,
1086+
options.ImportedHeader);
1087+
if (!contents.empty()) {
1088+
contents.push_back('\0');
1089+
ImportedHeaderContents.emit(ScratchRecord, contents);
1090+
}
1091+
}
1092+
10681093
ModuleDecl *theBuiltinModule = M->getASTContext().TheBuiltinModule;
10691094
for (auto import : allImports) {
1070-
if (import.second == theBuiltinModule)
1071-
continue;
1072-
1073-
if (import.second == importedHeaderModule) {
1074-
off_t importedHeaderSize = 0;
1075-
time_t importedHeaderModTime = 0;
1076-
std::string contents;
1077-
if (!options.ImportedHeader.empty())
1078-
contents = clangImporter->getBridgingHeaderContents(
1079-
options.ImportedHeader, importedHeaderSize, importedHeaderModTime);
1080-
ImportedHeader.emit(ScratchRecord, publicImportSet.count(import),
1081-
importedHeaderSize, importedHeaderModTime,
1082-
options.ImportedHeader);
1083-
if (!contents.empty()) {
1084-
contents.push_back('\0');
1085-
ImportedHeaderContents.emit(ScratchRecord, contents);
1086-
}
1095+
if (import.second == theBuiltinModule ||
1096+
import.second == bridgingHeaderModule) {
10871097
continue;
10881098
}
10891099

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)