Skip to content

Commit 3a28941

Browse files
authored
Merge pull request #83108 from meg-gupta/lifediag2
Fix getLoweredOwnership() for setters of ~Escapable types
2 parents 7ada71b + 8387b7d commit 3a28941

File tree

2 files changed

+59
-37
lines changed

2 files changed

+59
-37
lines changed

lib/AST/LifetimeDependence.cpp

Lines changed: 43 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -186,15 +186,18 @@ void LifetimeDependenceInfo::Profile(llvm::FoldingSetNodeID &ID) const {
186186
}
187187
}
188188

189-
// Warning: this is incorrect for Setter 'newValue' parameters. It should only
190-
// be called for a Setter's 'self'.
191-
static ValueOwnership getLoweredOwnership(AbstractFunctionDecl *afd) {
189+
static ValueOwnership getLoweredOwnership(ParamDecl *param,
190+
AbstractFunctionDecl *afd) {
192191
if (isa<ConstructorDecl>(afd)) {
193192
return ValueOwnership::Owned;
194193
}
195194
if (auto *ad = dyn_cast<AccessorDecl>(afd)) {
196-
if (ad->getAccessorKind() == AccessorKind::Set ||
197-
isYieldingMutableAccessor(ad->getAccessorKind())) {
195+
if (ad->getAccessorKind() == AccessorKind::Set) {
196+
return param->isSelfParameter() ? ValueOwnership::InOut
197+
: ValueOwnership::Owned;
198+
}
199+
if (isYieldingMutableAccessor(ad->getAccessorKind())) {
200+
assert(param->isSelfParameter());
198201
return ValueOwnership::InOut;
199202
}
200203
}
@@ -565,17 +568,25 @@ class LifetimeDependenceChecker {
565568
}
566569
}
567570

568-
bool isCompatibleWithOwnership(ParsedLifetimeDependenceKind kind, Type type,
569-
ValueOwnership loweredOwnership,
571+
bool isCompatibleWithOwnership(ParsedLifetimeDependenceKind kind,
572+
ParamDecl *param,
570573
bool isInterfaceFile = false) const {
571574
if (kind == ParsedLifetimeDependenceKind::Inherit) {
572575
return true;
573576
}
577+
578+
auto *afd = cast<AbstractFunctionDecl>(decl);
579+
auto paramType = param->getTypeInContext();
580+
auto ownership = param->getValueOwnership();
581+
auto loweredOwnership = ownership != ValueOwnership::Default
582+
? ownership
583+
: getLoweredOwnership(param, afd);
584+
574585
if (kind == ParsedLifetimeDependenceKind::Borrow) {
575586
// An owned/consumed BitwiseCopyable value can be effectively borrowed
576587
// because its lifetime can be indefinitely extended.
577-
if (loweredOwnership == ValueOwnership::Owned
578-
&& isBitwiseCopyable(type, ctx)) {
588+
if (loweredOwnership == ValueOwnership::Owned &&
589+
isBitwiseCopyable(paramType, ctx)) {
579590
return true;
580591
}
581592
if (isInterfaceFile) {
@@ -588,21 +599,23 @@ class LifetimeDependenceChecker {
588599
return loweredOwnership == ValueOwnership::InOut;
589600
}
590601

591-
bool isCompatibleWithOwnership(LifetimeDependenceKind kind, Type type,
592-
ValueOwnership ownership) const {
593-
auto *afd = cast<AbstractFunctionDecl>(decl);
602+
bool isCompatibleWithOwnership(LifetimeDependenceKind kind,
603+
ParamDecl *param) const {
594604
if (kind == LifetimeDependenceKind::Inherit) {
595605
return true;
596606
}
607+
608+
auto *afd = cast<AbstractFunctionDecl>(decl);
609+
auto paramType = param->getTypeInContext();
610+
auto ownership = param->getValueOwnership();
611+
auto loweredOwnership = ownership != ValueOwnership::Default
612+
? ownership
613+
: getLoweredOwnership(param, afd);
597614
// Lifetime dependence always propagates through temporary BitwiseCopyable
598615
// values, even if the dependence is scoped.
599-
if (isBitwiseCopyable(type, ctx)) {
616+
if (isBitwiseCopyable(paramType, ctx)) {
600617
return true;
601618
}
602-
auto loweredOwnership = ownership != ValueOwnership::Default
603-
? ownership
604-
: getLoweredOwnership(afd);
605-
606619
assert(kind == LifetimeDependenceKind::Scope);
607620
return loweredOwnership == ValueOwnership::Shared ||
608621
loweredOwnership == ValueOwnership::InOut;
@@ -690,7 +703,7 @@ class LifetimeDependenceChecker {
690703
auto ownership = paramDecl->getValueOwnership();
691704
auto loweredOwnership = ownership != ValueOwnership::Default
692705
? ownership
693-
: getLoweredOwnership(afd);
706+
: getLoweredOwnership(paramDecl, afd);
694707

695708
switch (parsedLifetimeKind) {
696709
case ParsedLifetimeDependenceKind::Default: {
@@ -717,9 +730,7 @@ class LifetimeDependenceChecker {
717730
case ParsedLifetimeDependenceKind::Inout: {
718731
// @lifetime(borrow x) is valid only for borrowing parameters.
719732
// @lifetime(&x) is valid only for inout parameters.
720-
auto loweredOwnership = ownership != ValueOwnership::Default
721-
? ownership : getLoweredOwnership(afd);
722-
if (isCompatibleWithOwnership(parsedLifetimeKind, type, loweredOwnership,
733+
if (isCompatibleWithOwnership(parsedLifetimeKind, paramDecl,
723734
isInterfaceFile())) {
724735
return LifetimeDependenceKind::Scope;
725736
}
@@ -1039,8 +1050,7 @@ class LifetimeDependenceChecker {
10391050
}
10401051
// Infer based on ownership if possible for either explicit accessors or
10411052
// methods as long as they pass preceding ambiguity checks.
1042-
auto kind = inferLifetimeDependenceKind(
1043-
selfTypeInContext, afd->getImplicitSelfDecl()->getValueOwnership());
1053+
auto kind = inferLifetimeDependenceKind(afd->getImplicitSelfDecl());
10441054
if (!kind) {
10451055
// Special diagnostic for an attempt to depend on a consuming parameter.
10461056
diagnose(returnLoc,
@@ -1054,19 +1064,21 @@ class LifetimeDependenceChecker {
10541064
// Infer the kind of dependence that makes sense for reading or writing a
10551065
// stored property (for getters or initializers).
10561066
std::optional<LifetimeDependenceKind>
1057-
inferLifetimeDependenceKind(Type sourceType, ValueOwnership ownership) {
1067+
inferLifetimeDependenceKind(ParamDecl *param) {
10581068
auto *afd = cast<AbstractFunctionDecl>(decl);
1059-
if (!sourceType->isEscapable()) {
1069+
Type paramType = param->getTypeInContext();
1070+
ValueOwnership ownership = param->getValueOwnership();
1071+
if (!paramType->isEscapable()) {
10601072
return LifetimeDependenceKind::Inherit;
10611073
}
10621074
// Lifetime dependence always propagates through temporary BitwiseCopyable
10631075
// values, even if the dependence is scoped.
1064-
if (isBitwiseCopyable(sourceType, ctx)) {
1076+
if (isBitwiseCopyable(paramType, ctx)) {
10651077
return LifetimeDependenceKind::Scope;
10661078
}
10671079
auto loweredOwnership = ownership != ValueOwnership::Default
10681080
? ownership
1069-
: getLoweredOwnership(afd);
1081+
: getLoweredOwnership(param, afd);
10701082
// It is impossible to depend on a consumed Escapable value (unless it is
10711083
// BitwiseCopyable as checked above).
10721084
if (loweredOwnership == ValueOwnership::Owned) {
@@ -1114,8 +1126,7 @@ class LifetimeDependenceChecker {
11141126
return;
11151127
}
11161128
// A single Escapable parameter must be borrowed.
1117-
auto kind = inferLifetimeDependenceKind(paramTypeInContext,
1118-
param->getValueOwnership());
1129+
auto kind = inferLifetimeDependenceKind(param);
11191130
if (!kind) {
11201131
diagnose(returnLoc,
11211132
diag::lifetime_dependence_cannot_infer_scope_ownership,
@@ -1172,9 +1183,7 @@ class LifetimeDependenceChecker {
11721183
return;
11731184
}
11741185
auto kind = LifetimeDependenceKind::Scope;
1175-
auto paramOwnership = param->getValueOwnership();
1176-
if (!isCompatibleWithOwnership(kind, paramTypeInContext, paramOwnership))
1177-
{
1186+
if (!isCompatibleWithOwnership(kind, param)) {
11781187
diagnose(returnLoc,
11791188
diag::lifetime_dependence_cannot_infer_scope_ownership,
11801189
param->getParameterName().str(), diagnosticQualifier());
@@ -1207,8 +1216,7 @@ class LifetimeDependenceChecker {
12071216
}
12081217
}
12091218

1210-
candidateLifetimeKind =
1211-
inferLifetimeDependenceKind(paramTypeInContext, paramOwnership);
1219+
candidateLifetimeKind = inferLifetimeDependenceKind(param);
12121220
if (!candidateLifetimeKind) {
12131221
continue;
12141222
}
@@ -1383,11 +1391,9 @@ class LifetimeDependenceChecker {
13831391
}
13841392
}
13851393
}
1386-
auto *afd = cast<AbstractFunctionDecl>(decl);
13871394
// Either a Get or Modify without any wrapped accessor. Handle these like a
13881395
// read of the stored property.
1389-
return inferLifetimeDependenceKind(
1390-
selfTypeInContext, afd->getImplicitSelfDecl()->getValueOwnership());
1396+
return inferLifetimeDependenceKind(accessor->getImplicitSelfDecl());
13911397
}
13921398

13931399
// Infer 'inout' parameter dependency when the only parameter is

test/Sema/lifetime_attr.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,20 @@ struct Wrapper : ~Escapable {
125125
nonmutating _modify {// expected-error{{lifetime-dependent parameter 'self' must be 'inout'}}
126126
}
127127
}
128+
129+
var otherNE: NE {
130+
@_lifetime(copy self)
131+
get {
132+
_ne
133+
}
134+
@_lifetime(self: borrow newValue)
135+
set {
136+
self._ne = newValue
137+
}
138+
@_lifetime(&self)
139+
_modify {
140+
yield &self._ne
141+
}
142+
}
128143
}
144+

0 commit comments

Comments
 (0)