Skip to content

Commit 106c470

Browse files
authored
[Serialization] Handle re-export of error enums harder (#21880)
A refinement of Doug's e3207f7 from a year ago to account for trying to reference an import-as-member error enum /through/ an overlay when it's in a Clang module using 'export_as'. The problem is that importing error enums synthesizes a corresponding struct, and that struct doesn't have a Clang node and so when it isn't found in the right module the compiler didn't know to allow it anyway. I know, right? (Looking at the source change might be simpler than trying to read the above paragraph.) I'm still not 100% sure on how this occurred in the original (Apple-internal) projects hitting this, but I think it's just that we handle all import-as-member types at once, and the clients were using something else from a type that contained the error enum, and then that resulted in the error struct's conformances getting written into a serialized swiftmodule. rdar://problem/47152185
1 parent 577e04d commit 106c470

File tree

2 files changed

+27
-13
lines changed

2 files changed

+27
-13
lines changed

lib/Serialization/Deserialization.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,21 +1140,20 @@ getActualCtorInitializerKind(uint8_t raw) {
11401140
return None;
11411141
}
11421142

1143-
/// Determine whether the two modules are re-exported to the same module.
1144-
static bool reExportedToSameModule(const ModuleDecl *fromModule,
1145-
const ModuleDecl *toModule) {
1143+
static bool isReExportedToModule(const ValueDecl *value,
1144+
const ModuleDecl *expectedModule) {
1145+
const DeclContext *valueDC = value->getDeclContext();
11461146
auto fromClangModule
1147-
= dyn_cast<ClangModuleUnit>(fromModule->getFiles().front());
1147+
= dyn_cast<ClangModuleUnit>(valueDC->getModuleScopeContext());
11481148
if (!fromClangModule)
11491149
return false;
1150+
std::string exportedName = fromClangModule->getExportedModuleName();
11501151

11511152
auto toClangModule
1152-
= dyn_cast<ClangModuleUnit>(toModule->getFiles().front());
1153-
if (!toClangModule)
1154-
return false;
1155-
1156-
return fromClangModule->getExportedModuleName() ==
1157-
toClangModule->getExportedModuleName();
1153+
= dyn_cast<ClangModuleUnit>(expectedModule->getFiles().front());
1154+
if (toClangModule)
1155+
return exportedName == toClangModule->getExportedModuleName();
1156+
return exportedName == expectedModule->getName().str();
11581157
}
11591158

11601159
/// Remove values from \p values that don't match the expected type or module.
@@ -1197,7 +1196,7 @@ static void filterValues(Type expectedTy, ModuleDecl *expectedModule,
11971196
// module to the original definition in a base module.
11981197
if (expectedModule && !value->hasClangNode() &&
11991198
value->getModuleContext() != expectedModule &&
1200-
!reExportedToSameModule(value->getModuleContext(), expectedModule))
1199+
!isReExportedToModule(value, expectedModule))
12011200
return true;
12021201

12031202
// If we're expecting a member within a constrained extension with a
@@ -1357,6 +1356,7 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
13571356
if (entry.Kind != llvm::BitstreamEntry::Record)
13581357
return Identifier();
13591358

1359+
scratch.clear();
13601360
unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch,
13611361
&blobData);
13621362
switch (recordID) {

test/ClangImporter/private_frameworks.swift

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil -o /dev/null -F %S/Inputs/privateframeworks/withprivate -swift-version 4 %s -import-objc-header %S/Inputs/privateframeworks/bridging-somekitcore.h -verify
1313

1414
// Use the overlay without private frameworks.
15-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil -o /dev/null -F %S/Inputs/privateframeworks/withoutprivate -I %t -swift-version 4 -import-objc-header %S/Inputs/privateframeworks/bridging-somekit.h %s
15+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil -o /dev/null -F %S/Inputs/privateframeworks/withoutprivate -swift-version 4 -import-objc-header %S/Inputs/privateframeworks/bridging-somekit.h %s
1616

1717
// Build the overlay with public frameworks.
1818
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-module -F %S/Inputs/privateframeworks/withoutprivate -o %t %S/Inputs/privateframeworks/overlay/SomeKit.swift
@@ -21,7 +21,18 @@
2121
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil -o /dev/null -F %S/Inputs/privateframeworks/withprivate -swift-version 4 %s -import-objc-header %S/Inputs/privateframeworks/bridging-somekitcore.h -verify
2222

2323
// Use the overlay without private frameworks.
24-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil -o /dev/null -F %S/Inputs/privateframeworks/withoutprivate -I %t -swift-version 4 %s -import-objc-header %S/Inputs/privateframeworks/bridging-somekit.h
24+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil -o /dev/null -F %S/Inputs/privateframeworks/withoutprivate -swift-version 4 %s -import-objc-header %S/Inputs/privateframeworks/bridging-somekit.h
25+
26+
// Use something that uses the overlay.
27+
// RUN: echo 'import private_frameworks; testErrorConformance()' > %t/main.swift
28+
29+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-module -o %t -F %S/Inputs/privateframeworks/withprivate -swift-version 4 %s -import-objc-header %S/Inputs/privateframeworks/bridging-somekitcore.h
30+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil -o /dev/null -F %S/Inputs/privateframeworks/withprivate %t/main.swift -verify
31+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil -o /dev/null -F %S/Inputs/privateframeworks/withoutprivate %t/main.swift -verify
32+
33+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-module -o %t -F %S/Inputs/privateframeworks/withoutprivate -swift-version 4 %s -import-objc-header %S/Inputs/privateframeworks/bridging-somekit.h
34+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil -o /dev/null -F %S/Inputs/privateframeworks/withprivate %t/main.swift -verify
35+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil -o /dev/null -F %S/Inputs/privateframeworks/withoutprivate %t/main.swift -verify
2536

2637
// REQUIRES: objc_interop
2738

@@ -50,3 +61,6 @@ func testGlobals() {
5061
SomeKit.someKitOtherGlobalFunc()
5162
someKitOtherGlobalFunc()
5263
}
64+
65+
public struct ErrorsOnly<T: Error> {}
66+
public func testErrorConformance(_ code: ErrorsOnly<SKWidget.Error>? = nil) {}

0 commit comments

Comments
 (0)