Skip to content

Commit d90903a

Browse files
authored
Merge pull request #82189 from atrick/lifedep-trivial-inout
Disallow @_lifetime(borrow) for trivial 'inout' arguments
2 parents 5e17762 + f6c7524 commit d90903a

11 files changed

+106
-58
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8319,11 +8319,14 @@ ERROR(lifetime_dependence_immortal_alone, none,
83198319
"cannot specify any other dependence source along with immortal", ())
83208320
ERROR(lifetime_dependence_invalid_inherit_escapable_type, none,
83218321
"cannot copy the lifetime of an Escapable type, use "
8322-
"'@_lifetime(%1%0)' instead",
8322+
"'@_lifetime(%0%1)' instead",
83238323
(StringRef, StringRef))
8324-
ERROR(lifetime_dependence_cannot_use_parsed_borrow_consuming, none,
8324+
ERROR(lifetime_dependence_parsed_borrow_with_ownership, none,
83258325
"invalid use of %0 dependence with %1 ownership",
83268326
(StringRef, StringRef))
8327+
NOTE(lifetime_dependence_parsed_borrow_with_ownership_fix, none,
8328+
"use '@_lifetime(%0%1)' instead",
8329+
(StringRef, StringRef))
83278330
ERROR(lifetime_dependence_cannot_use_default_escapable_consuming, none,
83288331
"invalid lifetime dependence on an Escapable value with %0 ownership",
83298332
(StringRef))

lib/AST/LifetimeDependence.cpp

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -504,20 +504,18 @@ class LifetimeDependenceChecker {
504504
}
505505

506506
bool isCompatibleWithOwnership(ParsedLifetimeDependenceKind kind, Type type,
507-
ValueOwnership ownership,
507+
ValueOwnership loweredOwnership,
508508
bool isInterfaceFile = false) const {
509509
if (kind == ParsedLifetimeDependenceKind::Inherit) {
510510
return true;
511511
}
512-
// Lifetime dependence always propagates through temporary BitwiseCopyable
513-
// values, even if the dependence is scoped.
514-
if (isBitwiseCopyable(type, ctx)) {
515-
return true;
516-
}
517-
auto loweredOwnership = ownership != ValueOwnership::Default
518-
? ownership : getLoweredOwnership(afd);
519-
520512
if (kind == ParsedLifetimeDependenceKind::Borrow) {
513+
// An owned/consumed BitwiseCopyable value can be effectively borrowed
514+
// because its lifetime can be indefinitely extended.
515+
if (loweredOwnership == ValueOwnership::Owned
516+
&& isBitwiseCopyable(type, ctx)) {
517+
return true;
518+
}
521519
if (isInterfaceFile) {
522520
return loweredOwnership == ValueOwnership::Shared ||
523521
loweredOwnership == ValueOwnership::InOut;
@@ -651,37 +649,55 @@ class LifetimeDependenceChecker {
651649

652650
case ParsedLifetimeDependenceKind::Borrow: LLVM_FALLTHROUGH;
653651
case ParsedLifetimeDependenceKind::Inout: {
654-
// @lifetime(borrow x) is valid only for borrowing parameters.
655-
// @lifetime(inout x) is valid only for inout parameters.
656-
if (!isCompatibleWithOwnership(parsedLifetimeKind, type, loweredOwnership,
657-
isInterfaceFile())) {
652+
// @lifetime(borrow x) is valid only for borrowing parameters.
653+
// @lifetime(&x) is valid only for inout parameters.
654+
auto loweredOwnership = ownership != ValueOwnership::Default
655+
? ownership : getLoweredOwnership(afd);
656+
if (isCompatibleWithOwnership(parsedLifetimeKind, type, loweredOwnership,
657+
isInterfaceFile())) {
658+
return LifetimeDependenceKind::Scope;
659+
}
658660
diagnose(loc,
659-
diag::lifetime_dependence_cannot_use_parsed_borrow_consuming,
661+
diag::lifetime_dependence_parsed_borrow_with_ownership,
660662
getNameForParsedLifetimeDependenceKind(parsedLifetimeKind),
661663
getOwnershipSpelling(loweredOwnership));
664+
switch (loweredOwnership) {
665+
case ValueOwnership::Shared:
666+
diagnose(loc,
667+
diag::lifetime_dependence_parsed_borrow_with_ownership_fix,
668+
"borrow ", descriptor.getString());
669+
break;
670+
case ValueOwnership::InOut:
671+
diagnose(loc,
672+
diag::lifetime_dependence_parsed_borrow_with_ownership_fix,
673+
"&", descriptor.getString());
674+
break;
675+
case ValueOwnership::Owned:
676+
case ValueOwnership::Default:
677+
break;
678+
}
662679
return std::nullopt;
663680
}
664-
return LifetimeDependenceKind::Scope;
665-
}
666-
case ParsedLifetimeDependenceKind::Inherit:
667-
// @lifetime(copy x) is only invalid for Escapable types.
668-
if (type->isEscapable()) {
669-
if (loweredOwnership == ValueOwnership::Shared) {
670-
diagnose(loc, diag::lifetime_dependence_invalid_inherit_escapable_type,
671-
descriptor.getString(), "borrow ");
672-
} else if (loweredOwnership == ValueOwnership::InOut) {
673-
diagnose(loc, diag::lifetime_dependence_invalid_inherit_escapable_type,
674-
descriptor.getString(), "&");
675-
} else {
676-
diagnose(
681+
case ParsedLifetimeDependenceKind::Inherit: {
682+
// @lifetime(copy x) is only invalid for Escapable types.
683+
if (type->isEscapable()) {
684+
if (loweredOwnership == ValueOwnership::Shared) {
685+
diagnose(loc, diag::lifetime_dependence_invalid_inherit_escapable_type,
686+
"borrow ", descriptor.getString());
687+
} else if (loweredOwnership == ValueOwnership::InOut) {
688+
diagnose(loc, diag::lifetime_dependence_invalid_inherit_escapable_type,
689+
"&", descriptor.getString());
690+
} else {
691+
diagnose(
677692
loc,
678693
diag::lifetime_dependence_cannot_use_default_escapable_consuming,
679694
getOwnershipSpelling(loweredOwnership));
695+
}
696+
return std::nullopt;
680697
}
681-
return std::nullopt;
698+
return LifetimeDependenceKind::Inherit;
699+
}
682700
}
683-
return LifetimeDependenceKind::Inherit;
684-
}
685701
}
686702

687703
// Finds the ParamDecl* and its index from a LifetimeDescriptor

test/SIL/implicit_lifetime_dependence.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ struct Wrapper : ~Escapable {
8989
yield _view
9090
}
9191
// CHECK: sil hidden @$s28implicit_lifetime_dependence7WrapperV4viewAA10BufferViewVvM : $@yield_once @convention(method) (@inout Wrapper) -> @lifetime(borrow 0) @yields @inout BufferView {
92-
@_lifetime(borrow self)
92+
@_lifetime(&self)
9393
_modify {
9494
yield &_view
9595
}

test/SILOptimizer/lifetime_dependence/coroutine.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ struct Wrapper : ~Escapable {
4040
_read {
4141
yield _view
4242
}
43-
@_lifetime(borrow self)
43+
@_lifetime(&self)
4444
_modify {
4545
yield &_view
4646
}

test/SILOptimizer/lifetime_dependence/dependence_insertion.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func pointerDepends(on x: Builtin.RawPointer) -> NERawPointer {
109109
// CHECK: [[NE:%[0-9]+]] = apply %{{.*}}([[PTR]]) : $@convention(thin) (Builtin.RawPointer) -> @lifetime(borrow 0) @owned NERawPointer
110110
// CHECK: mark_dependence [unresolved] [[NE]] on %0
111111
// CHECK-LABEL: } // end sil function '$s4test0A22BuiltinAddressOfBorrow6holderAA12NERawPointerVAA9IntHolderVz_tF'
112-
@_lifetime(borrow holder)
112+
@_lifetime(&holder)
113113
func testBuiltinAddressOfBorrow(holder: inout IntHolder) -> NERawPointer {
114114
pointerDepends(on: Builtin.addressOfBorrow(holder))
115115
}

test/SILOptimizer/lifetime_dependence/lifetime_dependence_inherit.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ struct NEBV : ~Escapable {
5858
_read {
5959
yield bv
6060
}
61-
@_lifetime(borrow self)
61+
@_lifetime(&self)
6262
_modify {
6363
yield &bv
6464
}

test/SILOptimizer/lifetime_dependence/lifetime_dependence_scope_fixup.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ struct Wrapper : ~Escapable {
224224
_read {
225225
yield _view
226226
}
227-
@_lifetime(borrow self)
227+
@_lifetime(&self)
228228
_modify {
229229
yield &_view
230230
}

test/SILOptimizer/lifetime_dependence/semantics.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ struct MutableSpan<T>: ~Escapable, ~Copyable {
6767
let base: UnsafeMutablePointer<T>
6868
let count: Int
6969

70-
@_lifetime(&base)
70+
@_lifetime(borrow base)
7171
init(base: UnsafeMutablePointer<T>, count: Int) {
7272
self.base = base
7373
self.count = count
@@ -404,7 +404,7 @@ public func testTrivialLocalDeadEnd(p: UnsafePointer<Int>) {
404404

405405
// Test dependence on a borrow of a trivial inout. The access scope can be ignored since we don't care about the
406406
// in-memory value.
407-
@_lifetime(borrow p)
407+
@_lifetime(&p)
408408
public func testTrivialInoutBorrow(p: inout UnsafePointer<Int>) -> Span<Int> {
409409
return Span(base: p, count: 1)
410410
}
@@ -591,7 +591,7 @@ func testNonAddressable(arg: Holder) -> Span<Int> {
591591
// expected-note @-3{{it depends on the lifetime of argument 'arg'}}
592592
} // expected-note {{this use causes the lifetime-dependent value to escape}}
593593

594-
@_lifetime(borrow arg)
594+
@_lifetime(&arg)
595595
func test(arg: inout AddressableInt) -> Span<Int> {
596596
arg.span()
597597
}

test/Sema/lifetime_attr.swift

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,36 @@ func invalidDuplicateLifetimeDependence1(_ ne: borrowing NE) -> NE {
3030
class Klass {}
3131

3232
@_lifetime(borrow x) // expected-error{{invalid use of borrow dependence with consuming ownership}}
33-
func invalidDependence(_ x: consuming Klass) -> NE {
33+
func invalidDependenceConsumeKlass(_ x: consuming Klass) -> NE {
34+
NE()
35+
}
36+
37+
@_lifetime(&x) // expected-error{{invalid use of & dependence with borrowing ownership}}
38+
// expected-note @-1{{use '@_lifetime(borrow x)' instead}}
39+
func invalidDependenceBorrowKlass(_ x: borrowing Klass) -> NE {
40+
NE()
41+
}
42+
43+
@_lifetime(borrow x) // expected-error{{invalid use of borrow dependence with inout ownership}}
44+
// expected-note @-1{{use '@_lifetime(&x)' instead}}
45+
func invalidDependenceInoutKlass(_ x: inout Klass) -> NE {
46+
NE()
47+
}
48+
49+
@_lifetime(borrow x) // OK
50+
func invalidDependenceConsumeInt(_ x: consuming Int) -> NE {
51+
NE()
52+
}
53+
54+
@_lifetime(&x) // expected-error{{invalid use of & dependence with borrowing ownership}}
55+
// expected-note @-1{{use '@_lifetime(borrow x)' instead}}
56+
func invalidDependenceBorrowInt(_ x: borrowing Int) -> NE {
57+
NE()
58+
}
59+
60+
@_lifetime(borrow x) // expected-error{{invalid use of borrow dependence with inout ownership}}
61+
// expected-note @-1{{use '@_lifetime(&x)' instead}}
62+
func invalidDependenceInoutInt(_ x: inout Int) -> NE {
3463
NE()
3564
}
3665

test/Sema/lifetime_depend_infer.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ struct NonEscapableSelf: ~Escapable {
4040
@_lifetime(copy self) // OK
4141
mutating func mutatingMethodNoParamCopy() -> NonEscapableSelf { self }
4242

43-
@_lifetime(borrow self) // OK
43+
@_lifetime(&self) // OK
4444
mutating func mutatingMethodNoParamBorrow() -> NonEscapableSelf { self }
4545

4646
func methodOneParam(_: Int) -> NonEscapableSelf { self } // expected-error{{a method with a ~Escapable result requires '@_lifetime(...)'}}
@@ -63,7 +63,7 @@ struct NonEscapableSelf: ~Escapable {
6363
@_lifetime(copy self) // OK
6464
mutating func mutatingMethodOneParamCopy(_: Int) -> NonEscapableSelf { self }
6565

66-
@_lifetime(borrow self) // OK
66+
@_lifetime(&self) // OK
6767
mutating func mutatingMethodOneParamBorrow(_: Int) -> NonEscapableSelf { self }
6868
}
6969

@@ -87,7 +87,7 @@ struct EscapableTrivialSelf {
8787
@_lifetime(copy self) // expected-error{{cannot copy the lifetime of an Escapable type, use '@_lifetime(&self)' instead}}
8888
mutating func mutatingMethodNoParamCopy() -> NEImmortal { NEImmortal() }
8989

90-
@_lifetime(borrow self)
90+
@_lifetime(&self)
9191
mutating func mutatingMethodNoParamBorrow() -> NEImmortal { NEImmortal() }
9292

9393
func methodOneParam(_: Int) -> NEImmortal { NEImmortal() } // expected-error{{a method with a ~Escapable result requires '@_lifetime(...)'}}
@@ -109,7 +109,7 @@ struct EscapableTrivialSelf {
109109
@_lifetime(copy self) // expected-error{{cannot copy the lifetime of an Escapable type, use '@_lifetime(&self)' instead}}
110110
mutating func mutatingMethodOneParamCopy(_: Int) -> NEImmortal { NEImmortal() }
111111

112-
@_lifetime(borrow self)
112+
@_lifetime(&self)
113113
mutating func mutatingMethodOneParamBorrow(_: Int) -> NEImmortal { NEImmortal() }
114114
}
115115

@@ -341,7 +341,7 @@ struct NonescapableSelfAccessors: ~Escapable {
341341
yield ne
342342
}
343343

344-
@_lifetime(borrow self)
344+
@_lifetime(&self)
345345
_modify {
346346
yield &ne
347347
}
@@ -401,7 +401,7 @@ struct NonescapableSelfAccessors: ~Escapable {
401401
ne
402402
}
403403

404-
@_lifetime(borrow self)
404+
@_lifetime(&self)
405405
set {
406406
ne = newValue
407407
}
@@ -413,7 +413,7 @@ struct NonescapableSelfAccessors: ~Escapable {
413413
yield ne
414414
}
415415

416-
@_lifetime(borrow self)
416+
@_lifetime(&self)
417417
_modify {
418418
yield &ne
419419
}
@@ -533,7 +533,7 @@ struct NonEscapableMutableSelf: ~Escapable {
533533
@_lifetime(self: copy self) // OK
534534
mutating func mutatingMethodNoParamCopy() {}
535535

536-
@_lifetime(self: borrow self) // expected-error{{invalid use of borrow dependence on the same inout parameter}}
536+
@_lifetime(self: &self) // expected-error{{invalid use of borrow dependence on the same inout parameter}}
537537
mutating func mutatingMethodNoParamBorrow() {}
538538

539539
mutating func mutatingMethodOneParam(_: NE) {} // expected-error{{a mutating method with a ~Escapable 'self' requires '@_lifetime(self: ...)'}}
@@ -544,6 +544,6 @@ struct NonEscapableMutableSelf: ~Escapable {
544544
@_lifetime(copy self) // OK
545545
mutating func mutatingMethodOneParamCopy(_: NE) {}
546546

547-
@_lifetime(borrow self)
547+
@_lifetime(&self)
548548
mutating func mutatingMethodOneParamBorrow(_: NE) {}
549549
}

test/Sema/lifetime_depend_infer_lazy.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ struct NonEscapableSelf: ~Escapable {
3838
@_lifetime(copy self) // OK
3939
mutating func mutatingMethodNoParamCopy() -> NonEscapableSelf { self }
4040

41-
@_lifetime(borrow self) // OK
41+
@_lifetime(&self) // OK
4242
mutating func mutatingMethodNoParamBorrow() -> NonEscapableSelf { self }
4343

4444
func methodOneParam(_: Int) -> NonEscapableSelf { self } // OK
@@ -58,7 +58,7 @@ struct NonEscapableSelf: ~Escapable {
5858
@_lifetime(copy self) // OK
5959
mutating func mutatingMethodOneParamCopy(_: Int) -> NonEscapableSelf { self }
6060

61-
@_lifetime(borrow self) // OK
61+
@_lifetime(&self) // OK
6262
mutating func mutatingMethodOneParamBorrow(_: Int) -> NonEscapableSelf { self }
6363
}
6464

@@ -72,7 +72,7 @@ struct EscapableTrivialSelf {
7272
@_lifetime(self) // OK
7373
mutating func mutatingMethodNoParamLifetime() -> NEImmortal { NEImmortal() }
7474

75-
@_lifetime(borrow self) // OK
75+
@_lifetime(&self) // OK
7676
mutating func mutatingMethodNoParamBorrow() -> NEImmortal { NEImmortal() }
7777

7878
@_lifetime(self) // OK
@@ -84,7 +84,7 @@ struct EscapableTrivialSelf {
8484
@_lifetime(self) // OK
8585
mutating func mutatingMethodOneParamLifetime(_: Int) -> NEImmortal { NEImmortal() }
8686

87-
@_lifetime(borrow self)
87+
@_lifetime(&self)
8888
mutating func mutatingMethodOneParamBorrow(_: Int) -> NEImmortal { NEImmortal() }
8989
}
9090

@@ -254,7 +254,7 @@ struct NonescapableSelfAccessors: ~Escapable {
254254
yield ne
255255
}
256256

257-
@_lifetime(borrow self)
257+
@_lifetime(&self)
258258
_modify {
259259
yield &ne
260260
}
@@ -314,7 +314,7 @@ struct NonescapableSelfAccessors: ~Escapable {
314314
ne
315315
}
316316

317-
@_lifetime(borrow self)
317+
@_lifetime(&self)
318318
set {
319319
ne = newValue
320320
}
@@ -326,7 +326,7 @@ struct NonescapableSelfAccessors: ~Escapable {
326326
yield ne
327327
}
328328

329-
@_lifetime(borrow self)
329+
@_lifetime(&self)
330330
_modify {
331331
yield &ne
332332
}
@@ -449,6 +449,6 @@ struct NonEscapableMutableSelf: ~Escapable {
449449
@_lifetime(copy self) // OK
450450
mutating func mutatingMethodOneParamCopy(_: NE) {}
451451

452-
@_lifetime(borrow self)
452+
@_lifetime(&self)
453453
mutating func mutatingMethodOneParamBorrow(_: NE) {}
454454
}

0 commit comments

Comments
 (0)