Skip to content

Commit 57b78f5

Browse files
authored
Merge pull request #38701 from apple/cherry-rdar80913216
[5.5][Serialization] Ignore conformance failures when allowing errors
2 parents cc32df9 + 3978f80 commit 57b78f5

File tree

2 files changed

+131
-9
lines changed

2 files changed

+131
-9
lines changed

lib/Serialization/Deserialization.cpp

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4481,10 +4481,12 @@ llvm::Error DeclDeserializer::deserializeDeclCommon() {
44814481

44824482
Expected<Type> deserialized = MF.getTypeChecked(typeID);
44834483
if (!deserialized) {
4484-
if (deserialized.errorIsA<XRefNonLoadedModuleError>()) {
4484+
if (deserialized.errorIsA<XRefNonLoadedModuleError>() ||
4485+
MF.allowCompilerErrors()) {
44854486
// A custom attribute defined behind an implementation-only import
44864487
// is safe to drop when it can't be deserialized.
4487-
// rdar://problem/56599179
4488+
// rdar://problem/56599179. When allowing errors we're doing a best
4489+
// effort to create a module, so ignore in that case as well.
44884490
consumeError(deserialized.takeError());
44894491
skipAttr = true;
44904492
} else
@@ -6244,9 +6246,15 @@ ModuleFile::loadAllConformances(const Decl *D, uint64_t contextData,
62446246
if (!conformance) {
62456247
auto unconsumedError =
62466248
consumeErrorIfXRefNonLoadedModule(conformance.takeError());
6247-
if (unconsumedError)
6248-
fatal(std::move(unconsumedError));
6249-
return;
6249+
if (unconsumedError) {
6250+
// Ignore if allowing errors, it's just doing a best effort to produce
6251+
// *some* module anyway.
6252+
if (allowCompilerErrors())
6253+
consumeError(std::move(unconsumedError));
6254+
else
6255+
fatal(std::move(unconsumedError));
6256+
}
6257+
continue;
62506258
}
62516259

62526260
if (conformance.get().isConcrete())
@@ -6367,8 +6375,17 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance,
63676375
"serialized conformances do not match requirement signature",
63686376
llvm::inconvertibleErrorCode()));
63696377
}
6370-
while (conformanceCount--)
6371-
reqConformances.push_back(readConformance(DeclTypeCursor));
6378+
while (conformanceCount--) {
6379+
auto conformance = readConformanceChecked(DeclTypeCursor);
6380+
if (conformance) {
6381+
reqConformances.push_back(conformance.get());
6382+
} else if (allowCompilerErrors()) {
6383+
consumeError(conformance.takeError());
6384+
reqConformances.push_back(ProtocolConformanceRef::forInvalid());
6385+
} else {
6386+
fatal(conformance.takeError());
6387+
}
6388+
}
63726389
}
63736390
conformance->setSignatureConformances(reqConformances);
63746391

@@ -6481,8 +6498,11 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance,
64816498
if (!witnessSubstitutions) {
64826499
// Missing module errors are most likely caused by an
64836500
// implementation-only import hiding types and decls.
6484-
// rdar://problem/52837313
6485-
if (witnessSubstitutions.errorIsA<XRefNonLoadedModuleError>()) {
6501+
// rdar://problem/52837313. Ignore completely if allowing
6502+
// errors - we're just doing a best effort to create the
6503+
// module in that case.
6504+
if (witnessSubstitutions.errorIsA<XRefNonLoadedModuleError>() ||
6505+
allowCompilerErrors()) {
64866506
consumeError(witnessSubstitutions.takeError());
64876507
isOpaque = true;
64886508
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// REQUIRES: objc_interop
2+
3+
// RUN: %empty-directory(%t)
4+
// RUN: mkdir -p %t/swiftmods %t/objcmods %t/objc
5+
// RUN: %{python} %utils/split_file.py -o %t %s
6+
7+
// Create a module A, then B that depends on A, replace A with an empty module,
8+
// and then try make a C that depends on B
9+
10+
// RUN: %target-swift-frontend -module-name A -emit-module -o %t/swiftmods/A.swiftmodule %t/a.swift
11+
// RUN: %target-swift-frontend -module-name B -emit-module -o %t/swiftmods/B.swiftmodule -I %t/swiftmods %t/b.swift
12+
// RUN: %target-swift-frontend -module-name A -emit-module -o %t/swiftmods/A.swiftmodule %t/bada.swift
13+
// RUN: %target-swift-frontend -wmo -module-name C -emit-module -o %t/swiftmods/C.swiftmodule -I %t/swiftmods -experimental-allow-module-with-compiler-errors -index-store-path %t/idx %t/c.swift
14+
// RUN: not --crash %target-swift-frontend -module-name C -emit-module -o %t/swiftmods/C.swiftmodule -I %t/swiftmods %t/c.swift
15+
16+
// Now do a similar thing but just use different headers instead (ie. to test
17+
// loading from a PCM rather than swiftmodule)
18+
19+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -module-name B -emit-module -o %t/objcmods/B.swiftmodule -I %t/objc -module-cache-path %t/mcp %t/b.swift
20+
// RUN: mv %t/objc/bada.h %t/objc/a.h
21+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -module-name C -emit-module -o %t/objcmods/C.swiftmodule -I %t/objcmods -I %t/objc -module-cache-path %t/mcp -experimental-allow-module-with-compiler-errors -index-store-path %t/idx %t/c.swift
22+
// RUN: not --crash %target-swift-frontend(mock-sdk: %clang-importer-sdk) -module-name C -emit-module -o %t/objcmods/C.swiftmodule -I %t/objcmods -I %t/objc -module-cache-path %t/mcp %t/c.swift
23+
24+
// BEGIN a.swift
25+
public protocol ProtoA {}
26+
public protocol MissingProto {}
27+
open class MissingClass: ProtoA {}
28+
29+
// BEGIN bada.swift
30+
public protocol ProtoA {}
31+
32+
// BEGIN objc/a.h
33+
@import Foundation;
34+
@protocol ProtoA
35+
@end
36+
@protocol MissingProto
37+
@end
38+
@interface MissingClass <ProtoA>
39+
@end
40+
41+
// BEGIN objc/bada.h
42+
@import Foundation;
43+
@protocol ProtoA
44+
@end
45+
46+
// BEGIN objc/module.modulemap
47+
module A {
48+
header "a.h"
49+
}
50+
51+
// BEGIN b.swift
52+
import A
53+
54+
public protocol ProtoB: MissingProto {}
55+
open class ClassB: MissingProto {}
56+
open class InheritingClassB: MissingClass {}
57+
58+
public protocol ATProto {
59+
associatedtype Value
60+
}
61+
public protocol ReqProto: ATProto {
62+
static func thing(_ value: Value)
63+
}
64+
extension ReqProto where Value: ProtoA {
65+
public static func thing(_ value: Value) {}
66+
}
67+
public enum EnumB: ReqProto {
68+
public typealias Value = MissingClass
69+
case a
70+
}
71+
72+
// BEGIN c.swift
73+
import B
74+
75+
func useB(p: ProtoB, c: ClassB, i: InheritingClassB, e: EnumB) {
76+
print("p:\(p) c:\(c) i:\(i) e:\(e)")
77+
EnumB.thing(i)
78+
}
79+
80+
public protocol ProtoC: ProtoB {}
81+
public class ClassC: ClassB {}
82+
public class ClassC2: InheritingClassB {}
83+
84+
public struct AllAsMembers {
85+
let p: ProtoB
86+
let c: ClassB
87+
let i: InheritingClassB
88+
let e: EnumB
89+
}
90+
91+
extension ProtoB {
92+
func newProtoBMethod() {}
93+
}
94+
extension ClassB {
95+
func newClassBMethod() {}
96+
}
97+
extension InheritingClassB {
98+
func newInheritingClassBMethod() {}
99+
}
100+
extension EnumB {
101+
func newEnumBMethod() {}
102+
}

0 commit comments

Comments
 (0)