Skip to content

Commit 462ce05

Browse files
committed
[Serialization] Properly skip invalid destructors when allowing errors
7856f2d only partially skipped writing out destructors when they were invalid, ie. it skipped writing the decl itself but not the records common to all decls. This would cause any records on the destructor to be applied on the next serialized decl. Make sure to skip serializing anything to do with the destructor when it's invalid and does not have a class context.
1 parent b12ab96 commit 462ce05

File tree

3 files changed

+43
-13
lines changed

3 files changed

+43
-13
lines changed

lib/Serialization/Serialization.cpp

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3957,9 +3957,6 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
39573957
using namespace decls_block;
39583958
verifyAttrSerializable(dtor);
39593959

3960-
if (S.allowCompilerErrors() && dtor->isInvalid())
3961-
return;
3962-
39633960
auto contextID = S.addDeclContextRef(dtor->getDeclContext());
39643961

39653962
unsigned abbrCode = S.DeclTypeAbbrCodes[DestructorLayout::Code];
@@ -4001,12 +3998,34 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
40013998
}
40023999
};
40034000

4001+
/// When allowing modules with errors there may be cases where there's little
4002+
/// point in serializing a declaration and doing so would create a maintenance
4003+
/// burden on the deserialization side. Returns \c true if the given declaration
4004+
/// should be skipped and \c false otherwise.
4005+
static bool canSkipWhenInvalid(const Decl *D) {
4006+
// There's no point writing out the deinit when its context is not a class
4007+
// as nothing would be able to reference it
4008+
if (auto *deinit = dyn_cast<DestructorDecl>(D)) {
4009+
if (!isa<ClassDecl>(D->getDeclContext()))
4010+
return true;
4011+
}
4012+
return false;
4013+
}
4014+
40044015
void Serializer::writeASTBlockEntity(const Decl *D) {
40054016
using namespace decls_block;
40064017

40074018
PrettyStackTraceDecl trace("serializing", D);
40084019
assert(DeclsToSerialize.hasRef(D));
40094020

4021+
if (D->isInvalid()) {
4022+
assert(allowCompilerErrors() &&
4023+
"cannot create a module with an invalid decl");
4024+
4025+
if (canSkipWhenInvalid(D))
4026+
return;
4027+
}
4028+
40104029
BitOffset initialOffset = Out.GetCurrentBitNo();
40114030
SWIFT_DEFER {
40124031
// This is important enough to leave on in Release builds.
@@ -4016,8 +4035,6 @@ void Serializer::writeASTBlockEntity(const Decl *D) {
40164035
}
40174036
};
40184037

4019-
assert((allowCompilerErrors() || !D->isInvalid()) &&
4020-
"cannot create a module with an invalid decl");
40214038
if (isDeclXRef(D)) {
40224039
writeCrossReference(D);
40234040
return;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// Serialize and deserialize a deinit with SourceFile context to make sure we
4+
// don't crash
5+
// RUN: %target-swift-frontend -verify -module-name errors -emit-module -o %t/errors.swiftmodule -experimental-allow-module-with-compiler-errors %s
6+
// RUN: %target-swift-ide-test -print-module -module-to-print=errors -source-filename=x -I %t -allow-compiler-errors
7+
8+
// Also check it wasn't serialized
9+
// RUN: llvm-bcanalyzer -dump %t/errors.swiftmodule | %FileCheck %s
10+
// CHECK-NOT: DESTRUCTOR_DECL
11+
12+
struct Foo {}
13+
14+
@discardableResult // expected-error{{'@discardableResult' attribute cannot be applied to this declaration}}
15+
deinit {} // expected-error{{deinitializers may only be declared within a class}}
16+
17+
func foo() -> Foo { return Foo() }
18+
19+
// Make sure @discardableResult isn't added to `foo`, which could be possible
20+
// if the deinit is partially serialized
21+
foo() // expected-warning{{result of call to 'foo()' is unused}}

validation-test/Serialization/AllowErrors/invalid-deinit.swift

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)