Skip to content

Commit 47b068d

Browse files
committed
[Serialization] Emit an error on deserializing an invalid declaration
When running in the allow errors mode (-experimental-allow-module-with-compiler-errors), modules may contain invalid declarations. The rest of the compiler pipeline, however, expects to have valid declarations unless diagnostics have emitted an error. Emit an error while deserializing to maintain this assumption. Note that these errors will not have a useful location, unless there's a corresponding `.swiftsourceinfo`. This isn't a problem for the intended use case in IDEs, where diagnostics outside the current file would be ignored anyway. Since reading declarations is lazy, SILGen (and thus SIL diagnostics) can still run as long as any invalid declarations weren't referenced in the compiling module. Resolves rdar://74325388
1 parent 9c6c9a5 commit 47b068d

File tree

3 files changed

+124
-4
lines changed

3 files changed

+124
-4
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,13 @@ NOTE(serialization_compatibility_version_mismatch,none,
779779
"(this is supported but may expose additional compiler issues)",
780780
(StringRef, StringRef, StringRef))
781781

782+
ERROR(serialization_allowing_invalid_decl,none,
783+
"allowing deserialization of invalid declaration %0 from module '%1'",
784+
(DeclName, StringRef))
785+
ERROR(serialization_invalid_decl,Fatal,
786+
"invalid declaration %0 read from module '%1'; "
787+
SWIFT_BUG_REPORT_MESSAGE, ())
788+
782789
ERROR(reserved_member_name,none,
783790
"type member must not be named %0, since it would conflict with the"
784791
" 'foo.%1' expression", (DeclName, StringRef))

lib/Serialization/Deserialization.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4083,6 +4083,22 @@ ModuleFile::getDeclChecked(
40834083
matchAttributes);
40844084
if (!deserialized)
40854085
return deserialized;
4086+
4087+
auto *decl = declOrOffset.get();
4088+
if (decl->isInvalid()) {
4089+
if (!isAllowModuleWithCompilerErrorsEnabled()) {
4090+
getContext().Diags.diagnose(SourceLoc(),
4091+
diag::serialization_invalid_decl);
4092+
} else if (!isa<ParamDecl>(decl) && !decl->isImplicit()) {
4093+
// The parent function will be invalid if the parameter is invalid,
4094+
// implicits should have an invalid explicit as well
4095+
if (auto *VD = dyn_cast<ValueDecl>(decl)) {
4096+
getContext().Diags.diagnose(
4097+
VD->getLoc(), diag::serialization_allowing_invalid_decl,
4098+
VD->getName(), VD->getModuleContext()->getNameStr());
4099+
}
4100+
}
4101+
}
40864102
} else if (matchAttributes) {
40874103
// Decl was cached but we may need to filter it
40884104
if (!matchAttributes(declOrOffset.get()->getAttrs()))

test/Frontend/allow-errors.swift

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,111 @@
11
// RUN: %empty-directory(%t)
22

33
// The module should be generated regardless of errors and diagnostic should still be output
4-
// RUN: %target-swift-frontend -verify -emit-module -o %t/errors.swiftmodule -experimental-allow-module-with-compiler-errors %s
4+
// RUN: %target-swift-frontend -verify -emit-module -o %t/errors.swiftmodule -experimental-allow-module-with-compiler-errors -D ERROR_MODULE %s
55
// RUN: llvm-bcanalyzer %t/errors.swiftmodule | %FileCheck -check-prefix=CHECK-BC %s
66
// CHECK-BC-NOT: UnknownCode
7+
#if ERROR_MODULE
8+
public struct ValidStructInvalidMember {
9+
public var member: String
10+
public let memberMissingType: undefined // expected-error {{cannot find type 'undefined'}}
711

8-
struct InvalidStruct {
9-
let memberMissingType: undefined // expected-error {{cannot find type 'undefined'}}
12+
public var memberMissingTypeValidSets: undefined { // expected-error {{cannot find type 'undefined'}}
13+
willSet {
14+
print("Setting value \(newValue)")
15+
}
16+
didSet {
17+
print("Set value \(oldValue)")
18+
}
19+
}
20+
public var memberInvalidSets: Int {
21+
willSet {
22+
undefined // expected-error {{cannot find 'undefined'}}
23+
}
24+
didSet {
25+
undefined // expected-error {{cannot find 'undefined'}}
26+
}
27+
}
28+
29+
public lazy var lazyMemberMissingTypeValidBody: undefined = { // expected-error {{cannot find type 'undefined'}}
30+
return ""
31+
}()
32+
public lazy var lazyMemberInvalidBody: String = {
33+
return undefined // expected-error {{cannot find 'undefined'}}
34+
}()
35+
36+
public var memberMissingTypeValidGetSets: String {
37+
get { member }
38+
set { member = "" }
39+
}
40+
public var memberInvalidGetSet: String {
41+
get { undefined } // expected-error {{cannot find 'undefined'}}
42+
set { undefined = "" } // expected-error {{cannot find 'undefined'}}
43+
}
44+
45+
public func funcBadArg(_ arg: undefined? = nil) {} // expected-error {{cannot find type 'undefined'}}
1046
}
1147

12-
func invalidFunc() -> InvalidStruct {
48+
public func validFunc() -> String { "" }
49+
50+
public func invalidFuncBody() -> ValidStructInvalidMember {
1351
ret // expected-error {{cannot find 'ret'}}
1452
}
53+
54+
public func invalidFunc() -> undefined {} // expected-error {{cannot find type 'undefined'}}
55+
#endif
56+
57+
// RUN: %target-swift-frontend -emit-module -o %t/validUses.swiftmodule -experimental-allow-module-with-compiler-errors -I%t -D VALID_USES %s 2>&1 | %FileCheck -check-prefix=CHECK-VALID %s
58+
// RUN: llvm-bcanalyzer %t/validUses.swiftmodule | %FileCheck -check-prefix=CHECK-BC %s
59+
#if VALID_USES
60+
import errors
61+
func test(s: ValidStructInvalidMember) {
62+
print(s.member)
63+
print(validFunc())
64+
print(invalidFuncBody())
65+
}
66+
67+
// Check SIL diagnostics are still output (no reason not to output SIL since
68+
// there were no errors)
69+
func other() -> Int {}
70+
// CHECK-VALID: allow-errors.swift:[[@LINE-1]]:22: error: missing return in a function expected to return 'Int'
71+
#endif
72+
73+
// All invalid uses should have no errors in the file itself, all referenced
74+
// invalid declarations should have an error elsewhere (but we don't care what
75+
// that location is)
76+
77+
// RUN: %target-swift-frontend -emit-module -o %t/invalidTopUse.swiftmodule -experimental-allow-module-with-compiler-errors -I%t -D INVALID_TOP_LEVEL_USE %s 2>&1 | %FileCheck -check-prefix=CHECK-INVALID-TOP %s
78+
// RUN: llvm-bcanalyzer %t/invalidTopUse.swiftmodule | %FileCheck -check-prefix=CHECK-BC %s
79+
#if INVALID_TOP_LEVEL_USE
80+
import errors
81+
func test() {
82+
invalidFunc()
83+
}
84+
// CHECK-INVALID-TOP-NOT: allow-errors.swift:{{.*}} error:
85+
// CHECK-INVALID-TOP: error: allowing deserialization of invalid declaration 'invalidFunc()' from module 'errors'
86+
// CHECK-INVALID-TOP-NOT: allow-errors.swift:{{.*}} error:
87+
#endif
88+
89+
// RUN: %target-swift-frontend -emit-module -o %t/invalidMemberUse.swiftmodule -experimental-allow-module-with-compiler-errors -I%t -D INVALID_MEMBER_USE %s 2>&1 | %FileCheck -check-prefix=CHECK-INVALID-MEMBER %s
90+
// RUN: llvm-bcanalyzer %t/invalidMemberUse.swiftmodule | %FileCheck -check-prefix=CHECK-BC %s
91+
#if INVALID_MEMBER_USE
92+
import errors
93+
func test(s: ValidStructInvalidMember) {
94+
print(s.memberMissingType)
95+
}
96+
// CHECK-INVALID-MEMBER-NOT: allow-errors.swift:{{.*}} error:
97+
// CHECK-INVALID-MEMBER: error: allowing deserialization of invalid declaration 'memberMissingType' from module 'errors'
98+
// CHECK-INVALID-MEMBER-NOT: allow-errors.swift:{{.*}} error:
99+
#endif
100+
101+
// RUN: %target-swift-frontend -emit-module -o %t/invalidMethodUse.swiftmodule -experimental-allow-module-with-compiler-errors -I%t -D INVALID_METHOD_USE %s 2>&1 | %FileCheck -check-prefix=CHECK-INVALID-METHOD %s
102+
// RUN: llvm-bcanalyzer %t/invalidMethodUse.swiftmodule | %FileCheck -check-prefix=CHECK-BC %s
103+
#if INVALID_METHOD_USE
104+
import errors
105+
func test(s: ValidStructInvalidMember) {
106+
s.funcBadArg()
107+
}
108+
// CHECK-INVALID-METHOD-NOT: allow-errors.swift:{{.*}} error:
109+
// CHECK-INVALID-METHOD: error: allowing deserialization of invalid declaration 'funcBadArg' from module 'errors'
110+
// CHECK-INVALID-METHOD-NOT: allow-errors.swift:{{.*}} error:
111+
#endif

0 commit comments

Comments
 (0)