Skip to content

Commit 6240435

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 e84be85 commit 6240435

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
@@ -3929,9 +3929,6 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
39293929
using namespace decls_block;
39303930
verifyAttrSerializable(dtor);
39313931

3932-
if (S.allowCompilerErrors() && dtor->isInvalid())
3933-
return;
3934-
39353932
auto contextID = S.addDeclContextRef(dtor->getDeclContext());
39363933

39373934
unsigned abbrCode = S.DeclTypeAbbrCodes[DestructorLayout::Code];
@@ -3973,12 +3970,34 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
39733970
}
39743971
};
39753972

3973+
/// When allowing modules with errors there may be cases where there's little
3974+
/// point in serializing a declaration and doing so would create a maintenance
3975+
/// burden on the deserialization side. Returns \c true if the given declaration
3976+
/// should be skipped and \c false otherwise.
3977+
static bool canSkipWhenInvalid(const Decl *D) {
3978+
// There's no point writing out the deinit when its context is not a class
3979+
// as nothing would be able to reference it
3980+
if (auto *deinit = dyn_cast<DestructorDecl>(D)) {
3981+
if (!isa<ClassDecl>(D->getDeclContext()))
3982+
return true;
3983+
}
3984+
return false;
3985+
}
3986+
39763987
void Serializer::writeASTBlockEntity(const Decl *D) {
39773988
using namespace decls_block;
39783989

39793990
PrettyStackTraceDecl trace("serializing", D);
39803991
assert(DeclsToSerialize.hasRef(D));
39813992

3993+
if (D->isInvalid()) {
3994+
assert(allowCompilerErrors() &&
3995+
"cannot create a module with an invalid decl");
3996+
3997+
if (canSkipWhenInvalid(D))
3998+
return;
3999+
}
4000+
39824001
BitOffset initialOffset = Out.GetCurrentBitNo();
39834002
SWIFT_DEFER {
39844003
// This is important enough to leave on in Release builds.
@@ -3988,8 +4007,6 @@ void Serializer::writeASTBlockEntity(const Decl *D) {
39884007
}
39894008
};
39904009

3991-
assert((allowCompilerErrors() || !D->isInvalid()) &&
3992-
"cannot create a module with an invalid decl");
39934010
if (isDeclXRef(D)) {
39944011
writeCrossReference(D);
39954012
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)