Skip to content

Commit 3f93370

Browse files
committed
[SIL] improve SILType::isMoveOnly
We were missing some of the "artificial" types in the TypeBase::isNoncopyable implementation. Rather than add them to the frontend, I just check for those special SIL-only types in SILType::isMoveOnly. resolves rdar://117282929
1 parent 098460b commit 3f93370

File tree

3 files changed

+101
-4
lines changed

3 files changed

+101
-4
lines changed

lib/SIL/IR/SILType.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,10 +1044,20 @@ SILType::getSingletonAggregateFieldType(SILModule &M,
10441044
}
10451045

10461046
bool SILType::isMoveOnly() const {
1047-
// Nominal types are move-only if declared as such.
1048-
if (getASTType()->isNoncopyable())
1047+
// Legacy check.
1048+
if (!getASTContext().LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
1049+
return getASTType()->isNoncopyable() || isMoveOnlyWrapped();
1050+
}
1051+
1052+
// Anything within the move-only wrapper is move-only.
1053+
if (isMoveOnlyWrapped())
10491054
return true;
10501055

1056+
auto ty = getASTType();
1057+
1058+
// All kinds of references are copyable.
1059+
if (isa<ReferenceStorageType>(ty))
1060+
return false;
10511061

10521062
// TODO: Nonescaping closures ought to be treated as move-only in SIL.
10531063
// They aren't marked move-only now, because the necessary move-only passes
@@ -1060,7 +1070,19 @@ bool SILType::isMoveOnly() const {
10601070
return fnTy->isTrivialNoEscape();
10611071
}
10621072
*/
1063-
return isMoveOnlyWrapped();
1073+
if (isa<SILFunctionType>(ty))
1074+
return false;
1075+
1076+
// Treat all other SIL-specific types as Copyable.
1077+
if (isa<SILBlockStorageType,
1078+
SILBoxType,
1079+
SILPackType,
1080+
SILTokenType>(ty)) {
1081+
return false;
1082+
}
1083+
1084+
// Finally, for other ordinary types, ask the AST type.
1085+
return ty->isNoncopyable();
10641086
}
10651087

10661088

test/SILOptimizer/moveonly_computed_property.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
// RUN: %target-swift-frontend -emit-sil -verify %s
1+
// RUN: %target-swift-frontend -emit-sil -verify %s > /dev/null
2+
// RUN: %target-swift-frontend -enable-experimental-feature NoncopyableGenerics -emit-sil -verify %s > /dev/null
3+
4+
// REQUIRES: asserts
25

36
// Applying a computed property to a move-only field in a class should occur
47
// entirely within a formal access to the class property. rdar://105794506
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// RUN: %target-swift-frontend %s -sil-verify-all -verify -emit-sil -enable-experimental-feature MoveOnlyPartialConsumption -enable-experimental-feature NoncopyableGenerics
2+
3+
// REQUIRES: asserts
4+
5+
/// MARK: types
6+
7+
struct FileDescriptor: ~Copyable { let fd: Int = 0 }
8+
9+
struct Wrap<T: ~Copyable>: ~Copyable {
10+
var item: T
11+
init(_ t: consuming T) { self.item = t }
12+
}
13+
extension Wrap: Copyable where T: Copyable {}
14+
15+
/// MARK: utilities
16+
17+
func borrowAny<T: ~Copyable>(_ t: borrowing T) {}
18+
19+
/// MARK: tests
20+
21+
func barebones() {
22+
let nc = FileDescriptor() // expected-error {{'nc' consumed more than once}}
23+
borrowAny(nc)
24+
let _ = nc // expected-note {{consumed}}
25+
let _ = nc // expected-note {{consumed}}
26+
27+
let cpWrap = Wrap(100)
28+
borrowAny(cpWrap)
29+
let _ = cpWrap
30+
let _ = cpWrap
31+
32+
let ncWrap = Wrap(FileDescriptor()) // expected-error {{'ncWrap' consumed more than once}}
33+
borrowAny(ncWrap)
34+
let _ = ncWrap // expected-note {{consumed}}
35+
let _ = ncWrap // expected-note {{consumed}}
36+
}
37+
38+
func test1<T: ~Copyable>(_ t: consuming T, // expected-error {{'t' consumed more than once}}
39+
// expected-error@-1 {{'t' used after consume}}
40+
_ borrowArg: borrowing T) -> Wrap<T> {
41+
// expected-error@-1 {{'borrowArg' is borrowed and cannot be consumed}}
42+
borrowAny(t)
43+
borrowAny(borrowArg)
44+
45+
let wrap1 = Wrap(t) // expected-note {{consumed}}
46+
let _ = Wrap(t) // expected-note 2{{consumed}}
47+
48+
let _ = Wrap(borrowArg) // expected-note {{consumed}}
49+
50+
borrowAny(t) // expected-note {{used}}
51+
borrowAny(borrowArg)
52+
53+
return wrap1
54+
}
55+
56+
func testWrap<T: ~Copyable>(_ x: borrowing Wrap<T>,
57+
// expected-error@-1 {{'x' is borrowed and cannot be consumed}}
58+
_ y: consuming Wrap<T>,
59+
_ new: () -> T) -> T {
60+
_ = x.item // expected-note {{consumed}}
61+
62+
// expected-error@+1 {{'result' consumed more than once}}
63+
let result = { (v: inout Wrap<T>) -> T in
64+
let result = v.item
65+
v.item = new()
66+
return result
67+
}(&y)
68+
69+
let _ = result // expected-note {{consumed}}
70+
71+
return result // expected-note {{consumed}}
72+
}

0 commit comments

Comments
 (0)