Skip to content

Commit 94402b6

Browse files
committedFeb 17, 2025
[ASTGen] Generate LifetimeAttr

File tree

6 files changed

+295
-11
lines changed

6 files changed

+295
-11
lines changed
 

‎include/swift/AST/ASTBridging.h

+74
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class Fingerprint;
4848
class Identifier;
4949
class IfConfigClauseRangeInfo;
5050
struct LabeledStmtInfo;
51+
struct LifetimeDescriptor;
5152
enum class MacroRole : uint32_t;
5253
class MacroIntroducedDeclName;
5354
enum class MacroIntroducedDeclNameKind;
@@ -964,6 +965,79 @@ BridgedInlineAttr BridgedInlineAttr_createParsed(BridgedASTContext cContext,
964965
BridgedSourceRange cRange,
965966
BridgedInlineKind cKind);
966967

968+
enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedParsedLifetimeDependenceKind {
969+
BridgedParsedLifetimeDependenceKindDefault,
970+
BridgedParsedLifetimeDependenceKindScope,
971+
BridgedParsedLifetimeDependenceKindInherit,
972+
};
973+
974+
class BridgedLifetimeDescriptor {
975+
union Value {
976+
BridgedIdentifier name;
977+
unsigned index;
978+
979+
Value(BridgedIdentifier name) : name(name) {}
980+
Value(unsigned index) : index(index) {}
981+
Value() : name() {}
982+
} value;
983+
984+
enum DescriptorKind {
985+
Named,
986+
Ordered,
987+
Self,
988+
} kind;
989+
990+
BridgedParsedLifetimeDependenceKind dependenceKind;
991+
BridgedSourceLoc loc;
992+
993+
BridgedLifetimeDescriptor(Value value, DescriptorKind kind,
994+
BridgedParsedLifetimeDependenceKind dependenceKind,
995+
BridgedSourceLoc loc)
996+
: value(value), kind(kind), dependenceKind(dependenceKind), loc(loc) {}
997+
998+
public:
999+
SWIFT_NAME("forNamed(_:dependenceKind:loc:)")
1000+
static BridgedLifetimeDescriptor
1001+
forNamed(BridgedIdentifier name,
1002+
BridgedParsedLifetimeDependenceKind dependenceKind,
1003+
BridgedSourceLoc loc) {
1004+
return BridgedLifetimeDescriptor(name, DescriptorKind::Named,
1005+
dependenceKind, loc);
1006+
}
1007+
SWIFT_NAME("forOrdered(_:dependenceKind:loc:)")
1008+
static BridgedLifetimeDescriptor
1009+
forOrdered(size_t index, BridgedParsedLifetimeDependenceKind dependenceKind,
1010+
BridgedSourceLoc loc) {
1011+
return BridgedLifetimeDescriptor(index, DescriptorKind::Ordered,
1012+
dependenceKind, loc);
1013+
}
1014+
SWIFT_NAME("forSelf(dependenceKind:loc:)")
1015+
static BridgedLifetimeDescriptor
1016+
forSelf(BridgedParsedLifetimeDependenceKind dependenceKind,
1017+
BridgedSourceLoc loc) {
1018+
return BridgedLifetimeDescriptor({}, DescriptorKind::Self, dependenceKind,
1019+
loc);
1020+
}
1021+
1022+
swift::LifetimeDescriptor unbridged();
1023+
};
1024+
1025+
SWIFT_NAME("BridgedLifetimeEntry.createParsed(_:range:sources:)")
1026+
BridgedLifetimeEntry
1027+
BridgedLifetimeEntry_createParsed(BridgedASTContext cContext,
1028+
BridgedSourceRange cRange,
1029+
BridgedArrayRef cSources);
1030+
1031+
SWIFT_NAME("BridgedLifetimeEntry.createParsed(_:range:sources:target:)")
1032+
BridgedLifetimeEntry BridgedLifetimeEntry_createParsed(
1033+
BridgedASTContext cContext, BridgedSourceRange cRange,
1034+
BridgedArrayRef cSources, BridgedLifetimeDescriptor cTarget);
1035+
1036+
SWIFT_NAME("BridgedLifetimeAttr.createParsed(_:atLoc:range:entry:)")
1037+
BridgedLifetimeAttr BridgedLifetimeAttr_createParsed(
1038+
BridgedASTContext cContext, BridgedSourceLoc cAtLoc,
1039+
BridgedSourceRange cRange, BridgedLifetimeEntry cEntry);
1040+
9671041
enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedMacroSyntax {
9681042
BridgedMacroSyntaxFreestanding,
9691043
BridgedMacroSyntaxAttached,

‎include/swift/AST/ASTBridgingWrappers.def

+1
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ AST_BRIDGING_WRAPPER_NULLABLE(ArgumentList)
115115
AST_BRIDGING_WRAPPER_NULLABLE(AvailabilitySpec)
116116
AST_BRIDGING_WRAPPER_CONST_NONNULL(AvailabilityMacroMap)
117117
AST_BRIDGING_WRAPPER_NONNULL(PoundAvailableInfo)
118+
AST_BRIDGING_WRAPPER_NONNULL(LifetimeEntry)
118119

119120
// Non-AST types to generate wrappers for.
120121
AST_BRIDGING_WRAPPER_NULLABLE(DiagnosticEngine)

‎lib/AST/ASTDumper.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -5120,7 +5120,12 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, Label>,
51205120
}
51215121
void visitLifetimeAttr(LifetimeAttr *Attr, Label label) {
51225122
printCommon(Attr, "lifetime_attr", label);
5123-
// TODO: Implement.
5123+
// FIXME: Improve, more detailed info.
5124+
printFieldRaw(
5125+
[&](raw_ostream &out) {
5126+
out << " " << Attr->getLifetimeEntry()->getString() << " ";
5127+
},
5128+
Label::optional("lifetime_entry"));
51245129
printFoot();
51255130
}
51265131
void visitMacroRoleAttr(MacroRoleAttr *Attr, Label label) {

‎lib/AST/Bridging/DeclAttributeBridging.cpp

+67
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,73 @@ BridgedInlineAttr BridgedInlineAttr_createParsed(BridgedASTContext cContext,
360360
InlineAttr(cAtLoc.unbridged(), cRange.unbridged(), unbridged(cKind));
361361
}
362362

363+
static swift::ParsedLifetimeDependenceKind
364+
unbridged(BridgedParsedLifetimeDependenceKind kind) {
365+
switch (kind) {
366+
case BridgedParsedLifetimeDependenceKindDefault:
367+
return swift::ParsedLifetimeDependenceKind::Default;
368+
case BridgedParsedLifetimeDependenceKindScope:
369+
return swift::ParsedLifetimeDependenceKind::Scope;
370+
case BridgedParsedLifetimeDependenceKindInherit:
371+
return swift::ParsedLifetimeDependenceKind::Inherit;
372+
}
373+
llvm_unreachable("unhandled enum value");
374+
}
375+
376+
swift::LifetimeDescriptor BridgedLifetimeDescriptor::unbridged() {
377+
switch (kind) {
378+
case DescriptorKind::Named:
379+
return LifetimeDescriptor::forNamed(value.name.unbridged().str(),
380+
::unbridged(dependenceKind),
381+
loc.unbridged());
382+
case DescriptorKind::Ordered:
383+
return LifetimeDescriptor::forOrdered(
384+
value.index, ::unbridged(dependenceKind), loc.unbridged());
385+
case DescriptorKind::Self:
386+
return LifetimeDescriptor::forSelf(::unbridged(dependenceKind),
387+
loc.unbridged());
388+
}
389+
llvm_unreachable("unhandled enum value");
390+
}
391+
392+
static BridgedLifetimeEntry BridgedLifetimeEntry_createParsedImpl(
393+
BridgedASTContext cContext, BridgedSourceRange cRange,
394+
BridgedArrayRef cSources,
395+
std::optional<BridgedLifetimeDescriptor> cTarget) {
396+
SmallVector<LifetimeDescriptor> sources;
397+
for (auto cSource : cSources.unbridged<BridgedLifetimeDescriptor>())
398+
sources.push_back(cSource.unbridged());
399+
std::optional<LifetimeDescriptor> target;
400+
if (cTarget)
401+
target = cTarget->unbridged();
402+
403+
return LifetimeEntry::create(cContext.unbridged(), cRange.Start.unbridged(),
404+
cRange.End.unbridged(), sources, target);
405+
}
406+
407+
BridgedLifetimeEntry
408+
BridgedLifetimeEntry_createParsed(BridgedASTContext cContext,
409+
BridgedSourceRange cRange,
410+
BridgedArrayRef cSources) {
411+
return BridgedLifetimeEntry_createParsedImpl(cContext, cRange, cSources,
412+
std::nullopt);
413+
}
414+
415+
BridgedLifetimeEntry BridgedLifetimeEntry_createParsed(
416+
BridgedASTContext cContext, BridgedSourceRange cRange,
417+
BridgedArrayRef cSources, BridgedLifetimeDescriptor cTarget) {
418+
return BridgedLifetimeEntry_createParsedImpl(cContext, cRange, cSources,
419+
cTarget);
420+
}
421+
422+
BridgedLifetimeAttr BridgedLifetimeAttr_createParsed(
423+
BridgedASTContext cContext, BridgedSourceLoc cAtLoc,
424+
BridgedSourceRange cRange, BridgedLifetimeEntry cEntry) {
425+
return LifetimeAttr::create(cContext.unbridged(), cAtLoc.unbridged(),
426+
cRange.unbridged(), /*implicit=*/false,
427+
cEntry.unbridged());
428+
}
429+
363430
BridgedMacroRole BridgedMacroRole_fromString(BridgedStringRef str) {
364431
// Match the role string to the known set of roles.
365432
auto role =

‎lib/ASTGen/Sources/ASTGen/DeclAttrs.swift

+124-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ extension ASTGenVisitor {
146146
case .inline:
147147
return handle(self.generateInlineAttr(attribute: node)?.asDeclAttribute)
148148
case .lifetime:
149-
fatalError("unimplemented")
149+
return handle(self.generateLifetimeAttr(attribute: node)?.asDeclAttribute)
150150
case .macroRole:
151151
return handle(self.generateMacroRoleAttr(attribute: node, attrName: attrName)?.asDeclAttribute)
152152
case .nonSendable:
@@ -880,6 +880,129 @@ extension ASTGenVisitor {
880880
)
881881
}
882882

883+
func generateLifetimeDescriptor(nameToken node: TokenSyntax, lifetimeDependenceKind: BridgedParsedLifetimeDependenceKind = .default) -> BridgedLifetimeDescriptor {
884+
let ident = self.generateIdentifier(node)
885+
let loc = self.generateSourceLoc(node)
886+
if ident == ctx.id_self {
887+
return .forSelf(
888+
dependenceKind: lifetimeDependenceKind,
889+
loc: loc
890+
)
891+
} else {
892+
return .forNamed(
893+
ident,
894+
dependenceKind: lifetimeDependenceKind,
895+
loc: loc
896+
);
897+
}
898+
}
899+
900+
func generateLifetimeDescriptor(expr node: ExprSyntax) -> BridgedLifetimeDescriptor? {
901+
let lifetimeDependenceKind: BridgedParsedLifetimeDependenceKind
902+
let descriptorExpr: ExprSyntax
903+
if let copyExpr = node.as(CopyExprSyntax.self) {
904+
lifetimeDependenceKind = .inherit
905+
descriptorExpr = copyExpr.expression
906+
} else if let borrowExpr = node.as(BorrowExprSyntax.self) {
907+
lifetimeDependenceKind = .scope
908+
descriptorExpr = borrowExpr.expression
909+
} else {
910+
lifetimeDependenceKind = .default
911+
descriptorExpr = node
912+
}
913+
914+
let loc = self.generateSourceLoc(descriptorExpr)
915+
if
916+
let declRefExpr = descriptorExpr.as(DeclReferenceExprSyntax.self),
917+
declRefExpr.argumentNames == nil
918+
{
919+
return generateLifetimeDescriptor(
920+
nameToken: declRefExpr.baseName,
921+
lifetimeDependenceKind: lifetimeDependenceKind
922+
)
923+
}
924+
925+
if let index = descriptorExpr.as(IntegerLiteralExprSyntax.self)?.representedLiteralValue {
926+
return .forOrdered(
927+
index,
928+
dependenceKind: lifetimeDependenceKind,
929+
loc: loc
930+
)
931+
}
932+
933+
// TODO: Diangose
934+
fatalError("expected identifier, 'self', or integer in @lifetime")
935+
}
936+
937+
func generateLifetimeEntry(attribute node: AttributeSyntax) -> BridgedLifetimeEntry? {
938+
self.generateWithLabeledExprListArguments(attribute: node) { args in
939+
guard !args.isEmpty else {
940+
// TODO: Diagnose
941+
fatalError("expected arguments in @lifetime attribute")
942+
}
943+
944+
var target: BridgedLifetimeDescriptor? = nil
945+
var sources: [BridgedLifetimeDescriptor] = []
946+
var first = true
947+
while let arg = args.popFirst() {
948+
if first {
949+
if let targetToken = arg.label {
950+
target = self.generateLifetimeDescriptor(nameToken: targetToken)
951+
}
952+
first = false
953+
} else {
954+
if arg.label != nil {
955+
// TODO: Diagnose.
956+
fatalError("invalid argument label in @lifetime attribute")
957+
}
958+
}
959+
960+
if let src = self.generateLifetimeDescriptor(expr: arg.expression) {
961+
sources.append(src)
962+
}
963+
}
964+
965+
if let target {
966+
return .createParsed(
967+
self.ctx,
968+
range: self.generateAttrSourceRange(node),
969+
sources: sources.lazy.bridgedArray(in: self),
970+
target: target
971+
)
972+
} else {
973+
return .createParsed(
974+
self.ctx,
975+
range: self.generateAttrSourceRange(node),
976+
sources: sources.lazy.bridgedArray(in: self)
977+
)
978+
}
979+
}
980+
}
981+
982+
/// E.g.
983+
/// ```
984+
/// @lifetime(src1, src2)
985+
/// @lifetime(target: borrow src1, copy src2)
986+
/// @lifetime(2)
987+
/// @lifetime(self)
988+
/// ```
989+
func generateLifetimeAttr(attribute node: AttributeSyntax) -> BridgedLifetimeAttr? {
990+
guard self.ctx.langOptsHasFeature(.LifetimeDependence) else {
991+
// TODO: Diagnose
992+
fatalError("@lifetime attribute requires 'LifetimeDependence' feature")
993+
}
994+
guard let entry = self.generateLifetimeEntry(attribute: node) else {
995+
// TODO: Diagnose?
996+
return nil
997+
}
998+
return .createParsed(
999+
self.ctx,
1000+
atLoc: self.generateSourceLoc(node.atSign),
1001+
range: self.generateAttrSourceRange(node),
1002+
entry: entry
1003+
)
1004+
}
1005+
8831006
func generateMacroIntroducedDeclNameKind(declReferenceExpr node: DeclReferenceExprSyntax) -> BridgedMacroIntroducedDeclNameKind? {
8841007
if node.argumentNames != nil {
8851008
// TODO: Diagnose

‎test/ASTGen/attrs.swift

+23-9
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
// RUN: %empty-directory(%t)
22

3-
// RUN: %target-swift-frontend-dump-parse -disable-availability-checking \
4-
// RUN: -enable-experimental-feature SymbolLinkageMarkers \
3+
// RUN: %target-swift-frontend-dump-parse \
54
// RUN: -enable-experimental-feature ABIAttribute \
65
// RUN: -enable-experimental-feature Extern \
6+
// RUN: -enable-experimental-feature LifetimeDependence \
77
// RUN: -enable-experimental-feature NonIsolatedAsyncInheritsIsolationFromContext \
8+
// RUN: -enable-experimental-feature SymbolLinkageMarkers \
89
// RUN: -enable-experimental-move-only \
910
// RUN: -enable-experimental-feature ParserASTGen \
1011
// RUN: | %sanitize-address > %t/astgen.ast
1112

12-
// RUN: %target-swift-frontend-dump-parse -disable-availability-checking \
13-
// RUN: -enable-experimental-feature SymbolLinkageMarkers \
13+
// RUN: %target-swift-frontend-dump-parse \
1414
// RUN: -enable-experimental-feature ABIAttribute \
1515
// RUN: -enable-experimental-feature Extern \
16+
// RUN: -enable-experimental-feature LifetimeDependence \
1617
// RUN: -enable-experimental-feature NonIsolatedAsyncInheritsIsolationFromContext \
18+
// RUN: -enable-experimental-feature SymbolLinkageMarkers \
1719
// RUN: -enable-experimental-move-only \
1820
// RUN: | %sanitize-address > %t/cpp-parser.ast
1921

@@ -22,19 +24,21 @@
2224
// RUN: %target-typecheck-verify-swift \
2325
// RUN: -module-abi-name ASTGen \
2426
// RUN: -enable-experimental-feature ParserASTGen \
25-
// RUN: -enable-experimental-feature SymbolLinkageMarkers \
2627
// RUN: -enable-experimental-feature ABIAttribute \
2728
// RUN: -enable-experimental-feature Extern \
28-
// RUN: -enable-experimental-move-only \
29-
// RUN: -enable-experimental-feature NonIsolatedAsyncInheritsIsolationFromContext
29+
// RUN: -enable-experimental-feature LifetimeDependence \
30+
// RUN: -enable-experimental-feature NonIsolatedAsyncInheritsIsolationFromContext \
31+
// RUN: -enable-experimental-feature SymbolLinkageMarkers \
32+
// RUN: -enable-experimental-move-only
3033

3134
// REQUIRES: executable_test
3235
// REQUIRES: swift_swift_parser
33-
// REQUIRES: swift_feature_SymbolLinkageMarkers
34-
// REQUIRES: swift_feature_Extern
3536
// REQUIRES: swift_feature_ParserASTGen
3637
// REQUIRES: swift_feature_ABIAttribute
38+
// REQUIRES: swift_feature_Extern
39+
// REQUIRES: swift_feature_LifetimeDependence
3740
// REQUIRES: swift_feature_NonIsolatedAsyncInheritsIsolationFromContext
41+
// REQUIRES: swift_feature_SymbolLinkageMarkers
3842

3943
// rdar://116686158
4044
// UNSUPPORTED: asan
@@ -201,3 +205,13 @@ struct OpTest {
201205
func opResult() -> some OpProto { OpStruct() }
202206
typealias Result = @_opaqueReturnTypeOf("$s6ASTGen6OpTestV8opResultQryF", 0) __
203207
}
208+
209+
struct E {}
210+
struct NE : ~Escapable {}
211+
@lifetime(ne) func derive(_ ne: NE) -> NE { ne }
212+
@lifetime(borrow ne1, ne2) func derive(_ ne1: NE, _ ne2: NE) -> NE {
213+
if (Int.random(in: 1..<100) < 50) { return ne1 }
214+
return ne2
215+
}
216+
@lifetime(borrow borrow) func testNameConflict(_ borrow: E) -> NE { NE() }
217+
@lifetime(result: source) func testTarget(_ result: inout NE, _ source: consuming NE) { result = source }

0 commit comments

Comments
 (0)
Please sign in to comment.