Skip to content

Commit 4943beb

Browse files
committed
emit error if _forget is used on a type with no deinit
rdar://108877261
1 parent 7ac3ea0 commit 4943beb

File tree

9 files changed

+57
-13
lines changed

9 files changed

+57
-13
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4599,9 +4599,16 @@ ERROR(opaque_type_var_no_underlying_type,none,
45994599
"property declares an opaque return type, but cannot infer the "
46004600
"underlying type from its initializer expression", ())
46014601

4602+
4603+
//------------------------------------------------------------------------------
4604+
// MARK: Forget Statement
4605+
//------------------------------------------------------------------------------
46024606
ERROR(forget_wrong_context_decl,none,
46034607
"'forget' statement cannot appear in %0",
46044608
(DescriptiveDeclKind))
4609+
ERROR(forget_no_deinit,none,
4610+
"'forget' has no effect for type %0 unless it has a deinitializer",
4611+
(Type))
46054612
ERROR(forget_wrong_context_closure,none,
46064613
"'forget' statement cannot appear in closure",
46074614
())

lib/Sema/TypeCheckStmt.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,15 +1259,25 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
12591259
}
12601260
}
12611261

1262-
// This member function/accessor/etc has to be within a noncopyable type.
1262+
// check the kind of type this forget statement appears within.
12631263
if (!diagnosed) {
1264-
Type nominalType =
1265-
fn->getDeclContext()->getSelfNominalTypeDecl()->getDeclaredType();
1264+
auto *nominalDecl = fn->getDeclContext()->getSelfNominalTypeDecl();
1265+
Type nominalType = nominalDecl->getDeclaredType();
1266+
1267+
// must be noncopyable
12661268
if (!nominalType->isPureMoveOnly()) {
12671269
ctx.Diags.diagnose(FS->getForgetLoc(),
12681270
diag::forget_wrong_context_copyable,
12691271
fn->getDescriptiveKind());
12701272
diagnosed = true;
1273+
1274+
// has to have a deinit or else it's pointless.
1275+
} else if (!nominalDecl->getValueTypeDestructor()) {
1276+
ctx.Diags.diagnose(FS->getForgetLoc(),
1277+
diag::forget_no_deinit,
1278+
nominalType)
1279+
.fixItRemove(FS->getSourceRange());
1280+
diagnosed = true;
12711281
} else {
12721282
// Set the contextual type for the sub-expression before we typecheck.
12731283
contextualInfo = {nominalType, CTP_ForgetStmt};

test/SILGen/forget.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ func invokedDeinit() {}
77
case some(File)
88
case none
99

10+
deinit {}
11+
1012
// NOTE: we can't pattern match on self since
1113
// that would consume it before we can forget self!
1214
var test: Int {

test/SILOptimizer/moveonly_forget.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -sil-verify-all -verify -emit-sil %s
1+
// RUN: %target-swift-frontend -sil-verify-all -verify -emit-sil -enable-experimental-feature MoveOnlyEnumDeinits %s
22

33
func posix_close(_ t: Int) {}
44

@@ -29,6 +29,8 @@ struct GoodFileDescriptor {
2929
struct BadFileDescriptor {
3030
let _fd: Int = 0
3131

32+
deinit {}
33+
3234
var rawFileDescriptor: Int {
3335
__consuming get { // expected-error {{'self' consumed more than once}}
3436
_forget self // expected-note {{consuming use here}}
@@ -90,4 +92,6 @@ final class Wallet {
9092
}
9193
}
9294

95+
deinit {}
96+
9397
}

test/Sema/Inputs/forget_module_adjacent.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
public extension Regular {
22
__consuming func shutdownParty() {
3-
_forget self // ok; same module
3+
// FIXME: rdar://108933330 (cannot define struct deinit with -enable-library-evolution)
4+
// _forget self // ok; same module
45
}
56
}
67

test/Sema/Inputs/forget_module_defining.swift

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
@_moveOnly
22
public struct Regular {
33
private let sorry = 0
4+
// FIXME: rdar://108933330 (cannot define struct deinit with -enable-library-evolution)
5+
// deinit {}
46
}
57

6-
@_moveOnly
7-
@frozen public struct Frozen {
8-
private let lotfan = 0
9-
}
10-
11-
128
public extension Regular {
139
__consuming func endParty() {
14-
_forget self
10+
// FIXME: rdar://108933330 (cannot define struct deinit with -enable-library-evolution)
11+
// _forget self
1512
}
1613
}
1714

15+
@_moveOnly
16+
@frozen public struct Frozen {
17+
private let lotfan = 0
18+
deinit {}
19+
}
20+
1821
public extension Frozen {
1922
__consuming func endParty() {
2023
_forget self

test/Sema/forget.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,17 @@ enum E: Error { case err }
147147
try? take().close()
148148
}
149149
}
150+
151+
struct NoDeinitStruct: ~Copyable {
152+
consuming func blah() {
153+
_forget self // expected-error {{'forget' has no effect for type 'NoDeinitStruct' unless it has a deinitializer}}{{5-18=}}
154+
}
155+
}
156+
157+
enum NoDeinitEnum: ~Copyable {
158+
case whatever
159+
160+
consuming func blah() {
161+
_forget self // expected-error {{'forget' has no effect for type 'NoDeinitEnum' unless it has a deinitializer}}{{5-18=}}
162+
}
163+
}

test/Sema/forget_module.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import SorryModule
1313

1414
extension Regular {
1515
__consuming func delete() {
16-
_forget self // expected-error {{can only 'forget' from the same module defining type 'Regular'}}
16+
// FIXME: rdar://108933330 (cannot define struct deinit with -enable-library-evolution)
17+
// _forget self // DISABLED-error {{can only 'forget' from the same module defining type 'Regular'}}
1718
}
1819
}
1920

test/expr/print/forget.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ struct S {
55
__consuming func c() {
66
_forget self
77
}
8+
9+
deinit {}
810
}
911

1012
// CHECK: @_moveOnly internal struct S {

0 commit comments

Comments
 (0)