Skip to content

Commit 91ad145

Browse files
committed
Add support for @Lifetime(&arg)
1 parent aa3edb4 commit 91ad145

File tree

7 files changed

+84
-31
lines changed

7 files changed

+84
-31
lines changed

include/swift/AST/ASTBridging.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,6 +1088,7 @@ enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedParsedLifetimeDependenceKind {
10881088
BridgedParsedLifetimeDependenceKindDefault,
10891089
BridgedParsedLifetimeDependenceKindScope,
10901090
BridgedParsedLifetimeDependenceKindInherit,
1091+
BridgedParsedLifetimeDependenceKindInout
10911092
};
10921093

10931094
class BridgedLifetimeDescriptor {

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8171,6 +8171,9 @@ ERROR(lifetime_dependence_invalid_inherit_escapable_type, none,
81718171
ERROR(lifetime_dependence_cannot_use_parsed_borrow_consuming, none,
81728172
"invalid use of borrow dependence with consuming ownership",
81738173
())
8174+
ERROR(lifetime_dependence_cannot_use_default_escapable_consuming, none,
8175+
"invalid lifetime dependence on an Escapable value with %0 ownership",
8176+
(StringRef))
81748177
ERROR(lifetime_dependence_cannot_use_parsed_borrow_inout, none,
81758178
"invalid use of borrow dependence on the same inout parameter",
81768179
())

include/swift/AST/LifetimeDependence.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ class SILResultInfo;
3939
enum class ParsedLifetimeDependenceKind : uint8_t {
4040
Default = 0,
4141
Scope,
42-
Inherit // Only used with deserialized decls
42+
Inherit, // Only used with deserialized decls
43+
Inout
4344
};
4445

4546
enum class LifetimeDependenceKind : uint8_t { Inherit = 0, Scope };

lib/AST/Bridging/DeclAttributeBridging.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,8 @@ unbridged(BridgedParsedLifetimeDependenceKind kind) {
474474
return swift::ParsedLifetimeDependenceKind::Scope;
475475
case BridgedParsedLifetimeDependenceKindInherit:
476476
return swift::ParsedLifetimeDependenceKind::Inherit;
477+
case BridgedParsedLifetimeDependenceKindInout:
478+
return swift::ParsedLifetimeDependenceKind::Inout;
477479
}
478480
llvm_unreachable("unhandled enum value");
479481
}

lib/AST/LifetimeDependence.cpp

Lines changed: 68 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,20 @@ filterEscapableLifetimeDependencies(GenericSignature sig,
7979
return didRemoveLifetimeDependencies;
8080
}
8181

82+
StringRef
83+
getNameForParsedLifetimeDependenceKind(ParsedLifetimeDependenceKind kind) {
84+
switch (kind) {
85+
case ParsedLifetimeDependenceKind::Scope:
86+
return "borrow";
87+
case ParsedLifetimeDependenceKind::Inherit:
88+
return "copy";
89+
case ParsedLifetimeDependenceKind::Inout:
90+
return "inout";
91+
default:
92+
return "";
93+
}
94+
}
95+
8296
std::string LifetimeDependenceInfo::getString() const {
8397
std::string lifetimeDependenceString = "@lifetime(";
8498
auto addressable = getAddressableIndices();
@@ -451,26 +465,43 @@ class LifetimeDependenceChecker {
451465
}
452466
}
453467

454-
bool isCompatibleWithOwnership(LifetimeDependenceKind kind, Type type,
468+
bool isCompatibleWithOwnership(ParsedLifetimeDependenceKind kind, Type type,
455469
ValueOwnership ownership) const {
456-
if (kind == LifetimeDependenceKind::Inherit) {
470+
if (kind == ParsedLifetimeDependenceKind::Inherit) {
457471
return true;
458472
}
459473
// Lifetime dependence always propagates through temporary BitwiseCopyable
460474
// values, even if the dependence is scoped.
461475
if (isBitwiseCopyable(type, ctx)) {
462476
return true;
463477
}
464-
assert(kind == LifetimeDependenceKind::Scope);
465478
auto loweredOwnership = ownership != ValueOwnership::Default
466479
? ownership : getLoweredOwnership(afd);
467480

468-
if (loweredOwnership == ValueOwnership::InOut ||
469-
loweredOwnership == ValueOwnership::Shared) {
481+
if (kind == ParsedLifetimeDependenceKind::Scope) {
482+
return loweredOwnership == ValueOwnership::Shared;
483+
}
484+
assert(kind == ParsedLifetimeDependenceKind::Inout);
485+
return loweredOwnership == ValueOwnership::InOut;
486+
}
487+
488+
bool isCompatibleWithOwnership(LifetimeDependenceKind kind, Type type,
489+
ValueOwnership ownership) const {
490+
if (kind == LifetimeDependenceKind::Inherit) {
470491
return true;
471492
}
472-
assert(loweredOwnership == ValueOwnership::Owned);
473-
return false;
493+
// Lifetime dependence always propagates through temporary BitwiseCopyable
494+
// values, even if the dependence is scoped.
495+
if (isBitwiseCopyable(type, ctx)) {
496+
return true;
497+
}
498+
auto loweredOwnership = ownership != ValueOwnership::Default
499+
? ownership
500+
: getLoweredOwnership(afd);
501+
502+
assert(kind == LifetimeDependenceKind::Scope);
503+
return loweredOwnership == ValueOwnership::Shared ||
504+
loweredOwnership == ValueOwnership::InOut;
474505
}
475506

476507
struct TargetDeps {
@@ -546,44 +577,51 @@ class LifetimeDependenceChecker {
546577
std::optional<LifetimeDependenceKind>
547578
getDependenceKindFromDescriptor(LifetimeDescriptor descriptor,
548579
ParamDecl *decl) {
549-
auto loc = descriptor.getLoc();
550-
551-
auto ownership = decl->getValueOwnership();
580+
auto loc = decl->getLoc();
552581
auto type = decl->getTypeInContext();
582+
auto parsedLifetimeKind = descriptor.getParsedLifetimeDependenceKind();
583+
auto ownership = decl->getValueOwnership();
584+
auto loweredOwnership = ownership != ValueOwnership::Default
585+
? ownership
586+
: getLoweredOwnership(afd);
553587

554-
LifetimeDependenceKind kind;
555-
switch (descriptor.getParsedLifetimeDependenceKind()) {
556-
case ParsedLifetimeDependenceKind::Default:
588+
if (parsedLifetimeKind == ParsedLifetimeDependenceKind::Default) {
557589
if (type->isEscapable()) {
558-
kind = LifetimeDependenceKind::Scope;
590+
if (loweredOwnership == ValueOwnership::Shared ||
591+
loweredOwnership == ValueOwnership::InOut) {
592+
return LifetimeDependenceKind::Scope;
593+
} else {
594+
diagnose(
595+
loc,
596+
diag::lifetime_dependence_cannot_use_default_escapable_consuming,
597+
getOwnershipSpelling(loweredOwnership));
598+
return std::nullopt;
599+
}
559600
} else if (useLazyInference()) {
560-
kind = LifetimeDependenceKind::Inherit;
561-
} else {
562-
diagnose(loc, diag::lifetime_dependence_cannot_infer_kind,
563-
diagnosticQualifier(), descriptor.getString());
564-
return std::nullopt;
601+
return LifetimeDependenceKind::Inherit;
565602
}
566-
break;
567-
case ParsedLifetimeDependenceKind::Scope:
568-
kind = LifetimeDependenceKind::Scope;
569-
break;
570-
case ParsedLifetimeDependenceKind::Inherit:
571-
kind = LifetimeDependenceKind::Inherit;
572-
break;
603+
diagnose(loc, diag::lifetime_dependence_cannot_infer_kind,
604+
diagnosticQualifier(), descriptor.getString());
605+
return std::nullopt;
573606
}
574-
// @lifetime(borrow x) is invalid for consuming parameters.
575-
if (!isCompatibleWithOwnership(kind, type, ownership)) {
607+
608+
// @lifetime(borrow x) is valid only for borrowing parameters.
609+
// @lifetime(inout x) is valid only for inout parameters.
610+
if (!isCompatibleWithOwnership(parsedLifetimeKind, type, ownership)) {
576611
diagnose(loc,
577612
diag::lifetime_dependence_cannot_use_parsed_borrow_consuming);
578613
return std::nullopt;
579614
}
580615
// @lifetime(copy x) is only invalid for Escapable types.
581-
if (kind == LifetimeDependenceKind::Inherit && type->isEscapable()) {
616+
if (parsedLifetimeKind == ParsedLifetimeDependenceKind::Inherit &&
617+
type->isEscapable()) {
582618
diagnose(loc, diag::lifetime_dependence_invalid_inherit_escapable_type,
583619
descriptor.getString());
584620
return std::nullopt;
585621
}
586-
return kind;
622+
return parsedLifetimeKind == ParsedLifetimeDependenceKind::Inherit
623+
? LifetimeDependenceKind::Inherit
624+
: LifetimeDependenceKind::Scope;
587625
}
588626

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

lib/ASTGen/Sources/ASTGen/DeclAttrs.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,9 @@ extension ASTGenVisitor {
11061106
} else if let borrowExpr = node.as(BorrowExprSyntax.self) {
11071107
lifetimeDependenceKind = .scope
11081108
descriptorExpr = borrowExpr.expression
1109+
} else if let inoutExpr = node.as(InOutExprSyntax.self) {
1110+
lifetimeDependenceKind = .inout
1111+
descriptorExpr = inoutExpr.expression
11091112
} else {
11101113
lifetimeDependenceKind = .default
11111114
descriptorExpr = node

lib/Parse/ParseDecl.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5021,6 +5021,11 @@ ParserResult<LifetimeEntry> Parser::parseLifetimeEntry(SourceLoc loc) {
50215021
tok::kw_self)) {
50225022
return ParsedLifetimeDependenceKind::Scope;
50235023
}
5024+
if (Tok.is(tok::amp_prefix) &&
5025+
peekToken().isAny(tok::identifier, tok::integer_literal,
5026+
tok::kw_self)) {
5027+
return ParsedLifetimeDependenceKind::Inout;
5028+
}
50245029
return std::nullopt;
50255030
};
50265031

0 commit comments

Comments
 (0)