Skip to content

Commit 9d39821

Browse files
authored
Merge pull request #38661 from apple/conformance-failures
[Serialization] Ignore conformance failures when allowing errors
2 parents 598eef3 + bedb434 commit 9d39821

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
@@ -4510,10 +4510,12 @@ llvm::Error DeclDeserializer::deserializeDeclCommon() {
45104510

45114511
Expected<Type> deserialized = MF.getTypeChecked(typeID);
45124512
if (!deserialized) {
4513-
if (deserialized.errorIsA<XRefNonLoadedModuleError>()) {
4513+
if (deserialized.errorIsA<XRefNonLoadedModuleError>() ||
4514+
MF.allowCompilerErrors()) {
45144515
// A custom attribute defined behind an implementation-only import
45154516
// is safe to drop when it can't be deserialized.
4516-
// rdar://problem/56599179
4517+
// rdar://problem/56599179. When allowing errors we're doing a best
4518+
// effort to create a module, so ignore in that case as well.
45174519
consumeError(deserialized.takeError());
45184520
skipAttr = true;
45194521
} else
@@ -6258,9 +6260,15 @@ ModuleFile::loadAllConformances(const Decl *D, uint64_t contextData,
62586260
if (!conformance) {
62596261
auto unconsumedError =
62606262
consumeErrorIfXRefNonLoadedModule(conformance.takeError());
6261-
if (unconsumedError)
6262-
fatal(std::move(unconsumedError));
6263-
return;
6263+
if (unconsumedError) {
6264+
// Ignore if allowing errors, it's just doing a best effort to produce
6265+
// *some* module anyway.
6266+
if (allowCompilerErrors())
6267+
consumeError(std::move(unconsumedError));
6268+
else
6269+
fatal(std::move(unconsumedError));
6270+
}
6271+
continue;
62646272
}
62656273

62666274
if (conformance.get().isConcrete())
@@ -6381,8 +6389,17 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance,
63816389
"serialized conformances do not match requirement signature",
63826390
llvm::inconvertibleErrorCode()));
63836391
}
6384-
while (conformanceCount--)
6385-
reqConformances.push_back(readConformance(DeclTypeCursor));
6392+
while (conformanceCount--) {
6393+
auto conformance = readConformanceChecked(DeclTypeCursor);
6394+
if (conformance) {
6395+
reqConformances.push_back(conformance.get());
6396+
} else if (allowCompilerErrors()) {
6397+
consumeError(conformance.takeError());
6398+
reqConformances.push_back(ProtocolConformanceRef::forInvalid());
6399+
} else {
6400+
fatal(conformance.takeError());
6401+
}
6402+
}
63866403
}
63876404
conformance->setSignatureConformances(reqConformances);
63886405

@@ -6495,8 +6512,11 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance,
64956512
if (!witnessSubstitutions) {
64966513
// Missing module errors are most likely caused by an
64976514
// implementation-only import hiding types and decls.
6498-
// rdar://problem/52837313
6499-
if (witnessSubstitutions.errorIsA<XRefNonLoadedModuleError>()) {
6515+
// rdar://problem/52837313. Ignore completely if allowing
6516+
// errors - we're just doing a best effort to create the
6517+
// module in that case.
6518+
if (witnessSubstitutions.errorIsA<XRefNonLoadedModuleError>() ||
6519+
allowCompilerErrors()) {
65006520
consumeError(witnessSubstitutions.takeError());
65016521
isOpaque = true;
65026522
}
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)