Skip to content

Commit 0f2b945

Browse files
authored
Merge pull request #71828 from meg-gupta/tupleld
Ban explicit lifetime dependence specifiers on the element of a tuple result
2 parents 104ee13 + 9acc1a2 commit 0f2b945

File tree

6 files changed

+48
-32
lines changed

6 files changed

+48
-32
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7849,6 +7849,8 @@ ERROR(lifetime_dependence_cannot_infer_implicit_init, none,
78497849
"cannot infer lifetime dependence on implicit initializer of ~Escapable"
78507850
" type, define an initializer with explicit lifetime dependence"
78517851
" specifiers", ())
7852+
ERROR(lifetime_dependence_cannot_be_applied_to_tuple_elt, none,
7853+
"lifetime dependence specifiers cannot be applied to tuple elements", ())
78527854

78537855
//===----------------------------------------------------------------------===//
78547856
// MARK: Transferring

lib/SIL/IR/SILInstruction.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1825,7 +1825,7 @@ static bool visitRecursivelyLifetimeEndingUses(
18251825
// separately checked in the verifier. It is the only check that verifies
18261826
// the structural requirements of on-stack partial_apply uses.
18271827
auto *user = use->getUser();
1828-
if (user->getNumResults() != 1) {
1828+
if (user->getNumResults() == 0) {
18291829
llvm::errs() << "partial_apply [on_stack] use:\n";
18301830
user->printInContext(llvm::errs());
18311831
if (isa<BranchInst>(user)) {
@@ -1834,9 +1834,10 @@ static bool visitRecursivelyLifetimeEndingUses(
18341834
llvm::report_fatal_error("partial_apply [on_stack] must be directly "
18351835
"forwarded to a destroy_value");
18361836
}
1837-
if (!visitRecursivelyLifetimeEndingUses(use->getUser()->getResult(0),
1838-
noUsers, func)) {
1839-
return false;
1837+
for (auto res : use->getUser()->getResults()) {
1838+
if (!visitRecursivelyLifetimeEndingUses(res, noUsers, func)) {
1839+
return false;
1840+
}
18401841
}
18411842
}
18421843
return true;

lib/Sema/TypeCheckType.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5048,6 +5048,11 @@ TypeResolver::resolveResultDependsOnTypeRepr(ResultDependsOnTypeRepr *repr,
50485048

50495049
NeverNullType TypeResolver::resolveLifetimeDependentReturnTypeRepr(
50505050
LifetimeDependentReturnTypeRepr *repr, TypeResolutionOptions options) {
5051+
if (options.is(TypeResolverContext::TupleElement)) {
5052+
diagnoseInvalid(repr, repr->getSpecifierLoc(),
5053+
diag::lifetime_dependence_cannot_be_applied_to_tuple_elt);
5054+
return ErrorType::get(getASTContext());
5055+
}
50515056
if (!options.is(TypeResolverContext::FunctionResult)) {
50525057
diagnoseInvalid(
50535058
repr, repr->getSpecifierLoc(),

test/SIL/implicit_lifetime_dependence.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,9 @@ struct GenericBufferView<Element> : ~Escapable {
160160
}
161161
}
162162
}
163+
164+
// CHECK: sil hidden @$s28implicit_lifetime_dependence23tupleLifetimeDependenceyAA10BufferViewV_ADtADYlsF : $@convention(thin) (@guaranteed BufferView) -> _scope(1) (@owned BufferView, @owned BufferView) {
165+
func tupleLifetimeDependence(_ x: borrowing BufferView) -> (BufferView, BufferView) {
166+
return (BufferView(x.ptr, x.c), BufferView(x.ptr, x.c))
167+
}
168+

test/SILOptimizer/lifetime_dependence_scope_fixup.swift

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,6 @@ struct NCContainer : ~Copyable {
1919
}
2020
}
2121

22-
struct NEContainer : ~Escapable {
23-
let ptr: UnsafeRawBufferPointer
24-
let c: Int
25-
@_unsafeNonescapableResult
26-
init(_ ptr: UnsafeRawBufferPointer, _ c: Int) {
27-
self.ptr = ptr
28-
self.c = c
29-
}
30-
}
31-
3222
struct View : ~Escapable {
3323
let ptr: UnsafeRawBufferPointer
3424
let c: Int
@@ -45,7 +35,7 @@ struct View : ~Escapable {
4535
self.ptr = k.ptr
4636
self.c = k.c
4737
}
48-
init(_ k: consuming NEContainer) {
38+
init(_ k: consuming View) {
4939
self.ptr = k.ptr
5040
self.c = k.c
5141
}
@@ -67,24 +57,15 @@ struct MutableView : ~Copyable, ~Escapable {
6757
self.ptr = k.ptr
6858
self.c = k.c
6959
}
70-
init(_ k: consuming NEContainer) {
71-
self.ptr = k.ptr
72-
self.c = k.c
73-
}
7460
}
7561

7662
func use(_ o : borrowing View) {}
7763
func mutate(_ x: inout NCContainer) { }
7864
func mutate(_ x: inout View) { }
79-
func mutate(_ x: inout NEContainer) { }
8065
func consume(_ o : consuming View) {}
8166
func use(_ o : borrowing MutableView) {}
8267
func consume(_ o : consuming MutableView) {}
8368

84-
func getConsumingView(_ x: consuming NEContainer) -> _consume(x) View {
85-
return View(x)
86-
}
87-
8869
func getConsumingView(_ x: consuming View) -> _consume(x) View {
8970
return View(x.ptr, x.c)
9071
}
@@ -97,13 +78,9 @@ func getBorrowingView(_ x: borrowing NCContainer) -> _borrow(x) View {
9778
return View(x.ptr, x.c)
9879
}
9980

100-
func getBorrowingView(_ x: borrowing NEContainer) -> _borrow(x) View {
101-
return View(x.ptr, x.c)
102-
}
103-
10481
func test1(_ a: Array<Int>) {
10582
a.withUnsafeBytes {
106-
var x = NEContainer($0, a.count)
83+
var x = View($0, a.count)
10784
mutate(&x)
10885
let view = getConsumingView(x)
10986
let newView = View(view)
@@ -161,7 +138,7 @@ func test4(_ a: Array<Int>) {
161138

162139
func test5(_ a: Array<Int>) {
163140
a.withUnsafeBytes {
164-
let x = NEContainer($0, a.count)
141+
let x = View($0, a.count)
165142
let view = getBorrowingView(x)
166143
let anotherView = getConsumingView(view)
167144
use(anotherView)
@@ -192,23 +169,27 @@ func test6(_ a: Array<Int>) {
192169
// CHECK: end_access [[BA]] : $*NEContainer
193170
// CHECK-LABEL: } // end sil function '$s31lifetime_dependence_scope_fixup5test7yySWF'
194171
func test7(_ a: UnsafeRawBufferPointer) {
195-
var x = NEContainer(a, a.count)
172+
var x = View(a, a.count)
196173
do {
197174
let view = getBorrowingView(x)
198175
use(view)
199176
}
200177
mutate(&x)
201178
}
202179

180+
/*
181+
// Currently fails because the lifetime dependence util isn't analyzing a
182+
// def-use chain involving a stack temporary
203183
func test8(_ a: Array<Int>) {
204184
a.withUnsafeBytes {
205-
var x = NEContainer($0, a.count)
185+
var x = View($0, a.count)
206186
mutate(&x)
207187
let view = MutableView(x)
208188
use(view)
209189
consume(view)
210190
}
211191
}
192+
*/
212193

213194
struct Wrapper : ~Escapable {
214195
var _view: View
@@ -235,3 +216,19 @@ func test9() {
235216
}
236217
}
237218

219+
func getViewTuple(_ x: borrowing View) -> (View, View) {
220+
return (View(x.ptr, x.c), View(x.ptr, x.c))
221+
}
222+
223+
public func test10() {
224+
let a = [Int](repeating: 0, count: 4)
225+
a.withUnsafeBytes {
226+
var x = View($0, a.count)
227+
mutate(&x)
228+
let view = getBorrowingView(x)
229+
let tuple = getViewTuple(view)
230+
use(tuple.0)
231+
use(tuple.1)
232+
}
233+
}
234+

test/Sema/explicit_lifetime_dependence_specifiers.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-experimental-feature NonescapableTypes -disable-experimental-parser-round-trip -enable-experimental-feature NoncopyableGenerics -enable-builtin-module -enable-experimental-feature BitwiseCopyable
2+
// REQUIRES: asserts
23
// REQUIRES: noncopyable_generics
34
import Builtin
45

@@ -97,6 +98,10 @@ func invalidSpecifierPosition2(_ x: borrowing BufferView) -> BufferView {
9798
return BufferView(y.ptr)
9899
}
99100

101+
func invalidTupleLifetimeDependence(_ x: inout BufferView) -> (_mutate(x) BufferView, BufferView) { // expected-error{{lifetime dependence specifiers cannot be applied to tuple elements}}
102+
return (BufferView(x.ptr), BufferView(x.ptr))
103+
}
104+
100105
struct Wrapper : ~Escapable {
101106
let view: BufferView
102107
init(_ view: consuming BufferView) {

0 commit comments

Comments
 (0)