Skip to content

Commit 70b66ed

Browse files
committed
Add support for @Lifetime(&arg)
1 parent 245915d commit 70b66ed

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 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
@@ -74,6 +74,20 @@ filterEscapableLifetimeDependencies(GenericSignature sig,
7474
return didRemoveLifetimeDependencies;
7575
}
7676

77+
StringRef
78+
getNameForParsedLifetimeDependenceKind(ParsedLifetimeDependenceKind kind) {
79+
switch (kind) {
80+
case ParsedLifetimeDependenceKind::Scope:
81+
return "borrow";
82+
case ParsedLifetimeDependenceKind::Inherit:
83+
return "copy";
84+
case ParsedLifetimeDependenceKind::Inout:
85+
return "inout";
86+
default:
87+
return "";
88+
}
89+
}
90+
7791
std::string LifetimeDependenceInfo::getString() const {
7892
std::string lifetimeDependenceString = "@lifetime(";
7993
auto addressable = getAddressableIndices();
@@ -446,26 +460,43 @@ class LifetimeDependenceChecker {
446460
}
447461
}
448462

449-
bool isCompatibleWithOwnership(LifetimeDependenceKind kind, Type type,
463+
bool isCompatibleWithOwnership(ParsedLifetimeDependenceKind kind, Type type,
450464
ValueOwnership ownership) const {
451-
if (kind == LifetimeDependenceKind::Inherit) {
465+
if (kind == ParsedLifetimeDependenceKind::Inherit) {
452466
return true;
453467
}
454468
// Lifetime dependence always propagates through temporary BitwiseCopyable
455469
// values, even if the dependence is scoped.
456470
if (isBitwiseCopyable(type, ctx)) {
457471
return true;
458472
}
459-
assert(kind == LifetimeDependenceKind::Scope);
460473
auto loweredOwnership = ownership != ValueOwnership::Default
461474
? ownership : getLoweredOwnership(afd);
462475

463-
if (loweredOwnership == ValueOwnership::InOut ||
464-
loweredOwnership == ValueOwnership::Shared) {
476+
if (kind == ParsedLifetimeDependenceKind::Scope) {
477+
return loweredOwnership == ValueOwnership::Shared;
478+
}
479+
assert(kind == ParsedLifetimeDependenceKind::Inout);
480+
return loweredOwnership == ValueOwnership::InOut;
481+
}
482+
483+
bool isCompatibleWithOwnership(LifetimeDependenceKind kind, Type type,
484+
ValueOwnership ownership) const {
485+
if (kind == LifetimeDependenceKind::Inherit) {
465486
return true;
466487
}
467-
assert(loweredOwnership == ValueOwnership::Owned);
468-
return false;
488+
// Lifetime dependence always propagates through temporary BitwiseCopyable
489+
// values, even if the dependence is scoped.
490+
if (isBitwiseCopyable(type, ctx)) {
491+
return true;
492+
}
493+
auto loweredOwnership = ownership != ValueOwnership::Default
494+
? ownership
495+
: getLoweredOwnership(afd);
496+
497+
assert(kind == LifetimeDependenceKind::Scope);
498+
return loweredOwnership == ValueOwnership::Shared ||
499+
loweredOwnership == ValueOwnership::InOut;
469500
}
470501

471502
struct TargetDeps {
@@ -541,44 +572,51 @@ class LifetimeDependenceChecker {
541572
std::optional<LifetimeDependenceKind>
542573
getDependenceKindFromDescriptor(LifetimeDescriptor descriptor,
543574
ParamDecl *decl) {
544-
auto loc = descriptor.getLoc();
545-
546-
auto ownership = decl->getValueOwnership();
575+
auto loc = decl->getLoc();
547576
auto type = decl->getTypeInContext();
577+
auto parsedLifetimeKind = descriptor.getParsedLifetimeDependenceKind();
578+
auto ownership = decl->getValueOwnership();
579+
auto loweredOwnership = ownership != ValueOwnership::Default
580+
? ownership
581+
: getLoweredOwnership(afd);
548582

549-
LifetimeDependenceKind kind;
550-
switch (descriptor.getParsedLifetimeDependenceKind()) {
551-
case ParsedLifetimeDependenceKind::Default:
583+
if (parsedLifetimeKind == ParsedLifetimeDependenceKind::Default) {
552584
if (type->isEscapable()) {
553-
kind = LifetimeDependenceKind::Scope;
585+
if (loweredOwnership == ValueOwnership::Shared ||
586+
loweredOwnership == ValueOwnership::InOut) {
587+
return LifetimeDependenceKind::Scope;
588+
} else {
589+
diagnose(
590+
loc,
591+
diag::lifetime_dependence_cannot_use_default_escapable_consuming,
592+
getOwnershipSpelling(loweredOwnership));
593+
return std::nullopt;
594+
}
554595
} else if (useLazyInference()) {
555-
kind = LifetimeDependenceKind::Inherit;
556-
} else {
557-
diagnose(loc, diag::lifetime_dependence_cannot_infer_kind,
558-
diagnosticQualifier(), descriptor.getString());
559-
return std::nullopt;
596+
return LifetimeDependenceKind::Inherit;
560597
}
561-
break;
562-
case ParsedLifetimeDependenceKind::Scope:
563-
kind = LifetimeDependenceKind::Scope;
564-
break;
565-
case ParsedLifetimeDependenceKind::Inherit:
566-
kind = LifetimeDependenceKind::Inherit;
567-
break;
598+
diagnose(loc, diag::lifetime_dependence_cannot_infer_kind,
599+
diagnosticQualifier(), descriptor.getString());
600+
return std::nullopt;
568601
}
569-
// @lifetime(borrow x) is invalid for consuming parameters.
570-
if (!isCompatibleWithOwnership(kind, type, ownership)) {
602+
603+
// @lifetime(borrow x) is valid only for borrowing parameters.
604+
// @lifetime(inout x) is valid only for inout parameters.
605+
if (!isCompatibleWithOwnership(parsedLifetimeKind, type, ownership)) {
571606
diagnose(loc,
572607
diag::lifetime_dependence_cannot_use_parsed_borrow_consuming);
573608
return std::nullopt;
574609
}
575610
// @lifetime(copy x) is only invalid for Escapable types.
576-
if (kind == LifetimeDependenceKind::Inherit && type->isEscapable()) {
611+
if (parsedLifetimeKind == ParsedLifetimeDependenceKind::Inherit &&
612+
type->isEscapable()) {
577613
diagnose(loc, diag::lifetime_dependence_invalid_inherit_escapable_type,
578614
descriptor.getString());
579615
return std::nullopt;
580616
}
581-
return kind;
617+
return parsedLifetimeKind == ParsedLifetimeDependenceKind::Inherit
618+
? LifetimeDependenceKind::Inherit
619+
: LifetimeDependenceKind::Scope;
582620
}
583621

584622
// 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)