Skip to content

Commit fad6484

Browse files
committed
emit error if _forget is used on a type with no deinit
rdar://108877261 (cherry picked from commit 4943beb)
1 parent 343b8b1 commit fad6484

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
@@ -4594,9 +4594,16 @@ ERROR(opaque_type_var_no_underlying_type,none,
45944594
"property declares an opaque return type, but cannot infer the "
45954595
"underlying type from its initializer expression", ())
45964596

4597+
4598+
//------------------------------------------------------------------------------
4599+
// MARK: Forget Statement
4600+
//------------------------------------------------------------------------------
45974601
ERROR(forget_wrong_context_decl,none,
45984602
"'forget' statement cannot appear in %0",
45994603
(DescriptiveDeclKind))
4604+
ERROR(forget_no_deinit,none,
4605+
"'forget' has no effect for type %0 unless it has a deinitializer",
4606+
(Type))
46004607
ERROR(forget_wrong_context_closure,none,
46014608
"'forget' statement cannot appear in closure",
46024609
())

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)