Skip to content

Commit efa276a

Browse files
committed
Disallow @_lifetime(borrow) for trivial 'inout' arguments
@_lifetime(borrow holder) // ERROR func test(holder: inout Holder) -> NE Fixes rdar://153040843 ([nonescapable] disallow @_lifetime(borrow) for trivial 'inout' arguments) (cherry picked from commit a389254)
1 parent f0e9d98 commit efa276a

File tree

3 files changed

+69
-23
lines changed

3 files changed

+69
-23
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8232,11 +8232,14 @@ ERROR(lifetime_dependence_immortal_alone, none,
82328232
"cannot specify any other dependence source along with immortal", ())
82338233
ERROR(lifetime_dependence_invalid_inherit_escapable_type, none,
82348234
"cannot copy the lifetime of an Escapable type, use "
8235-
"'@_lifetime(%1%0)' instead",
8235+
"'@_lifetime(%0%1)' instead",
82368236
(StringRef, StringRef))
8237-
ERROR(lifetime_dependence_cannot_use_parsed_borrow_consuming, none,
8237+
ERROR(lifetime_dependence_parsed_borrow_with_ownership, none,
82388238
"invalid use of %0 dependence with %1 ownership",
82398239
(StringRef, StringRef))
8240+
NOTE(lifetime_dependence_parsed_borrow_with_ownership_fix, none,
8241+
"use '@_lifetime(%0%1)' instead",
8242+
(StringRef, StringRef))
82408243
ERROR(lifetime_dependence_cannot_use_default_escapable_consuming, none,
82418244
"invalid lifetime dependence on an Escapable value with %0 ownership",
82428245
(StringRef))

lib/AST/LifetimeDependence.cpp

Lines changed: 34 additions & 20 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;
@@ -653,26 +651,42 @@ class LifetimeDependenceChecker {
653651
case ParsedLifetimeDependenceKind::Inout: {
654652
// @lifetime(borrow x) is valid only for borrowing parameters.
655653
// @lifetime(&x) is valid only for inout parameters.
656-
if (!isCompatibleWithOwnership(parsedLifetimeKind, type, loweredOwnership,
657-
isInterfaceFile())) {
658-
diagnose(
659-
loc,
660-
diag::lifetime_dependence_cannot_use_parsed_borrow_consuming,
661-
getNameForParsedLifetimeDependenceKind(parsedLifetimeKind),
662-
getOwnershipSpelling(loweredOwnership));
663-
return std::nullopt;
654+
auto loweredOwnership = ownership != ValueOwnership::Default
655+
? ownership : getLoweredOwnership(afd);
656+
if (isCompatibleWithOwnership(parsedLifetimeKind, type, loweredOwnership,
657+
isInterfaceFile())) {
658+
return LifetimeDependenceKind::Scope;
664659
}
665-
return LifetimeDependenceKind::Scope;
660+
diagnose(loc,
661+
diag::lifetime_dependence_parsed_borrow_with_ownership,
662+
getNameForParsedLifetimeDependenceKind(parsedLifetimeKind),
663+
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+
}
679+
return std::nullopt;
666680
}
667681
case ParsedLifetimeDependenceKind::Inherit: {
668682
// @lifetime(copy x) is only invalid for Escapable types.
669683
if (type->isEscapable()) {
670684
if (loweredOwnership == ValueOwnership::Shared) {
671685
diagnose(loc, diag::lifetime_dependence_invalid_inherit_escapable_type,
672-
descriptor.getString(), "borrow ");
686+
"borrow ", descriptor.getString());
673687
} else if (loweredOwnership == ValueOwnership::InOut) {
674688
diagnose(loc, diag::lifetime_dependence_invalid_inherit_escapable_type,
675-
descriptor.getString(), "&");
689+
"&", descriptor.getString());
676690
} else {
677691
diagnose(
678692
loc,

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

0 commit comments

Comments
 (0)