Skip to content

Commit aae9483

Browse files
authored
Merge pull request #64289 from gottesmm/pr-bad04a239d63b44e8fd169d5bf8f2cd1baf19542
[move-only] Emit a clearer message around deinits.
2 parents 78c431a + 40449a6 commit aae9483

12 files changed

+55
-33
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -422,8 +422,10 @@ ERROR(initializer_result_type,PointsToFirstBadToken,
422422
"initializers cannot have a result type", ())
423423

424424
// Destructor
425-
ERROR(destructor_decl_outside_class,none,
426-
"deinitializers may only be declared within a class or actor", ())
425+
ERROR(destructor_decl_outside_class_or_noncopyable,none,
426+
"deinitializers may only be declared within a class, actor, or noncopyable type", ())
427+
ERROR(destructor_decl_on_objc_enum,none,
428+
"deinitializers cannot be declared on an @objc enum type", ())
427429
ERROR(expected_lbrace_destructor,PointsToFirstBadToken,
428430
"expected '{' for deinitializer", ())
429431
ERROR(destructor_has_name,PointsToFirstBadToken,

lib/Parse/ParseDecl.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9062,14 +9062,23 @@ parseDeclDeinit(ParseDeclOptions Flags, DeclAttributes &Attributes) {
90629062

90639063
DD->getAttrs() = Attributes;
90649064

9065-
// Reject 'destructor' functions outside of structs, enums, and classes.
9065+
// Reject 'destructor' functions outside of structs, enums, classes, or
9066+
// extensions that provide objc implementations.
90669067
//
90679068
// Later in the type checker, we validate that structs/enums only do this if
9068-
// they are move only.
9069-
auto *nom = dyn_cast<NominalTypeDecl>(CurDeclContext);
9070-
if (!nom ||
9071-
(!isa<StructDecl>(nom) && !isa<EnumDecl>(nom) && !isa<ClassDecl>(nom))) {
9072-
diagnose(DestructorLoc, diag::destructor_decl_outside_class);
9069+
// they are move only and that @objcImplementations are main-body.
9070+
auto rejectDestructor = [](DeclContext *dc) {
9071+
if (isa<StructDecl>(dc) || isa<EnumDecl>(dc) ||
9072+
isa<ClassDecl>(dc))
9073+
return false;
9074+
9075+
if (auto *ED = dyn_cast<ExtensionDecl>(dc))
9076+
return !ED->isObjCImplementation();
9077+
9078+
return true;
9079+
};
9080+
if (rejectDestructor(CurDeclContext)) {
9081+
diagnose(DestructorLoc, diag::destructor_decl_outside_class_or_noncopyable);
90739082

90749083
// Tell the type checker not to touch this destructor.
90759084
DD->setInvalid();

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3625,12 +3625,23 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
36253625
}
36263626

36273627
void visitDestructorDecl(DestructorDecl *DD) {
3628-
// Only check again for destructor decl outside of a class if our dstructor
3628+
// Only check again for destructor decl outside of a class if our destructor
36293629
// is not marked as invalid.
36303630
if (!DD->isInvalid()) {
36313631
auto *nom = dyn_cast<NominalTypeDecl>(DD->getDeclContext());
36323632
if (!nom || (!isa<ClassDecl>(nom) && !nom->isMoveOnly())) {
3633-
DD->diagnose(diag::destructor_decl_outside_class);
3633+
DD->diagnose(diag::destructor_decl_outside_class_or_noncopyable);
3634+
}
3635+
3636+
// If we have a noncopyable type, check if we have an @objc enum with a
3637+
// deinit and emit a specialized error. We will have technically already
3638+
// emitted an error since @objc enum cannot be marked noncopyable, but
3639+
// this at least makes it a bit clearer to the user that the deinit is
3640+
// also incorrect.
3641+
if (auto *e = dyn_cast_or_null<EnumDecl>(nom)) {
3642+
if (e->isObjC()) {
3643+
DD->diagnose(diag::destructor_decl_on_objc_enum);
3644+
}
36343645
}
36353646
}
36363647

test/Parse/init_deinit.swift

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ struct FooStructDeinitializerB {
3434
}
3535

3636
struct FooStructDeinitializerC {
37-
deinit {} // expected-error {{deinitializers may only be declared within a class or actor}}
37+
deinit {} // expected-error {{deinitializers may only be declared within a class, actor, or noncopyable type}}
3838
}
3939

4040
class FooClassDeinitializerA {
@@ -53,30 +53,30 @@ init {} // expected-error {{initializers may only be declared within a type}} ex
5353
init() // expected-error {{initializers may only be declared within a type}}
5454
init() {} // expected-error {{initializers may only be declared within a type}}
5555

56-
deinit {} // expected-error {{deinitializers may only be declared within a class or actor}}
56+
deinit {} // expected-error {{deinitializers may only be declared within a class, actor, or noncopyable type}}
5757
deinit // expected-error {{expected '{' for deinitializer}}
58-
deinit {} // expected-error {{deinitializers may only be declared within a class or actor}}
58+
deinit {} // expected-error {{deinitializers may only be declared within a class, actor, or noncopyable type}}
5959

6060
struct BarStruct {
6161
init() {}
62-
deinit {} // expected-error {{deinitializers may only be declared within a class or actor}}
62+
deinit {} // expected-error {{deinitializers may only be declared within a class, actor, or noncopyable type}}
6363
}
6464

6565
extension BarStruct {
6666
init(x : Int) {}
6767

6868
// When/if we allow 'var' in extensions, then we should also allow dtors
69-
deinit {} // expected-error {{deinitializers may only be declared within a class or actor}}
69+
deinit {} // expected-error {{deinitializers may only be declared within a class, actor, or noncopyable type}}
7070
}
7171

7272
enum BarUnion {
7373
init() {}
74-
deinit {} // expected-error {{deinitializers may only be declared within a class or actor}}
74+
deinit {} // expected-error {{deinitializers may only be declared within a class, actor, or noncopyable type}}
7575
}
7676

7777
extension BarUnion {
7878
init(x : Int) {}
79-
deinit {} // expected-error {{deinitializers may only be declared within a class or actor}}
79+
deinit {} // expected-error {{deinitializers may only be declared within a class, actor, or noncopyable type}}
8080
}
8181

8282
class BarClass {
@@ -86,22 +86,22 @@ class BarClass {
8686

8787
extension BarClass {
8888
convenience init(x : Int) { self.init() }
89-
deinit {} // expected-error {{deinitializers may only be declared within a class or actor}}
89+
deinit {} // expected-error {{deinitializers may only be declared within a class, actor, or noncopyable type}}
9090
}
9191

9292
protocol BarProtocol {
9393
init() {} // expected-error {{protocol initializers must not have bodies}}
94-
deinit {} // expected-error {{deinitializers may only be declared within a class or actor}}
94+
deinit {} // expected-error {{deinitializers may only be declared within a class, actor, or noncopyable type}}
9595
}
9696

9797
extension BarProtocol {
9898
init(x : Int) {}
99-
deinit {} // expected-error {{deinitializers may only be declared within a class or actor}}
99+
deinit {} // expected-error {{deinitializers may only be declared within a class, actor, or noncopyable type}}
100100
}
101101

102102
func fooFunc() {
103103
init() {} // expected-error {{initializers may only be declared within a type}}
104-
deinit {} // expected-error {{deinitializers may only be declared within a class or actor}}
104+
deinit {} // expected-error {{deinitializers may only be declared within a class, actor, or noncopyable type}}
105105
}
106106

107107
func barFunc() {
@@ -113,7 +113,7 @@ func barFunc() {
113113

114114
var y : () = { () -> () in
115115
// expected-warning@-1 {{variable 'y' was never used; consider replacing with '_' or removing it}}
116-
deinit {} // expected-error {{deinitializers may only be declared within a class or actor}}
116+
deinit {} // expected-error {{deinitializers may only be declared within a class, actor, or noncopyable type}}
117117
return
118118
} ()
119119
}

test/SIL/parse_swift_decls_in_sil_mode.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
typealias Int = ()
44

5-
deinit // expected-error {{deinitializers may only be declared within a class or actor}}
5+
deinit // expected-error {{deinitializers may only be declared within a class, actor, or noncopyable type}}
66

77
subscript (x : Int, y : Int) -> Int { get }// expected-error{{'subscript' functions may only be declared within a type}}
88

test/Sema/moveonly_objc_enum.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
@_moveOnly
88
@objc enum Foo : Int { // expected-error {{@objc enums cannot be marked as move-only}}
99
case X, Y, Z
10-
deinit {} // objc enums cannot have deinits
10+
deinit {} // expected-error {{deinitializers cannot be declared on an @objc enum type}}
1111
}
1212

1313
@_moveOnly

test/Serialization/AllowErrors/invalid-deinit.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
struct Foo {}
1313

1414
@discardableResult // expected-error{{'@discardableResult' attribute cannot be applied to this declaration}}
15-
deinit {} // expected-error{{deinitializers may only be declared within a class or actor}}
15+
deinit {} // expected-error{{deinitializers may only be declared within a class, actor, or noncopyable type}}
1616

1717
func foo() -> Foo { return Foo() }
1818

test/SourceKit/DocumentStructure/structure.swift.empty.response

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1721,8 +1721,8 @@
17211721
key.line: 147,
17221722
key.column: 1,
17231723
key.severity: source.diagnostic.severity.error,
1724-
key.id: "destructor_decl_outside_class",
1725-
key.description: "deinitializers may only be declared within a class or actor",
1724+
key.id: "destructor_decl_outside_class_or_noncopyable",
1725+
key.description: "deinitializers may only be declared within a class, actor, or noncopyable type",
17261726
key.diagnostic_stage: source.diagnostic.stage.swift.parse
17271727
}
17281728
]

test/SourceKit/DocumentStructure/structure.swift.foobar.response

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1726,8 +1726,8 @@
17261726
key.column: 1,
17271727
key.filepath: "-foobar",
17281728
key.severity: source.diagnostic.severity.error,
1729-
key.id: "destructor_decl_outside_class",
1730-
key.description: "deinitializers may only be declared within a class or actor",
1729+
key.id: "destructor_decl_outside_class_or_noncopyable",
1730+
key.description: "deinitializers may only be declared within a class, actor, or noncopyable type",
17311731
key.diagnostic_stage: source.diagnostic.stage.swift.parse
17321732
}
17331733
]

test/SourceKit/DocumentStructure/structure.swift.response

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1726,8 +1726,8 @@
17261726
key.column: 1,
17271727
key.filepath: main.swift,
17281728
key.severity: source.diagnostic.severity.error,
1729-
key.id: "destructor_decl_outside_class",
1730-
key.description: "deinitializers may only be declared within a class or actor",
1729+
key.id: "destructor_decl_outside_class_or_noncopyable",
1730+
key.description: "deinitializers may only be declared within a class, actor, or noncopyable type",
17311731
key.diagnostic_stage: source.diagnostic.stage.swift.parse
17321732
}
17331733
]

test/decl/ext/extensions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ extension extension_for_invalid_type_3 { // expected-error {{cannot find type 'e
1010
init() {}
1111
}
1212
extension extension_for_invalid_type_4 { // expected-error {{cannot find type 'extension_for_invalid_type_4' in scope}}
13-
deinit {} // expected-error {{deinitializers may only be declared within a class or actor}}
13+
deinit {} // expected-error {{deinitializers may only be declared within a class, actor, or noncopyable type}}
1414
}
1515
extension extension_for_invalid_type_5 { // expected-error {{cannot find type 'extension_for_invalid_type_5' in scope}}
1616
typealias X = Int

test/decl/protocol/protocols.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ protocol EmptyProtocol { }
33

44
protocol DefinitionsInProtocols {
55
init() {} // expected-error {{protocol initializers must not have bodies}}
6-
deinit {} // expected-error {{deinitializers may only be declared within a class or actor}}
6+
deinit {} // expected-error {{deinitializers may only be declared within a class, actor, or noncopyable type}}
77
}
88

99
// Protocol decl.

0 commit comments

Comments
 (0)