Skip to content

Commit 6f9cced

Browse files
committed
Add support for specifying target in @Lifetime
@Lifetime(target: source1, source2...) where target can be any parameter or 'self'. We cannot have @Lifetime attributes with duplicate targets. Also, update the internal data structures. Previously LifetimeEntry stored pairwise (target, source) dependencies. Now, LifetimeEntry will store an optional target descriptor and an array of source descriptors.
1 parent 3bf3e0f commit 6f9cced

File tree

12 files changed

+385
-478
lines changed

12 files changed

+385
-478
lines changed

include/swift/AST/Attr.h

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2640,25 +2640,20 @@ class RawLayoutAttr final : public DeclAttribute {
26402640
}
26412641
};
26422642

2643-
class LifetimeAttr final
2644-
: public DeclAttribute,
2645-
private llvm::TrailingObjects<LifetimeAttr, LifetimeEntry> {
2646-
2647-
friend TrailingObjects;
2643+
class LifetimeAttr final : public DeclAttribute {
2644+
LifetimeEntry *entry;
26482645

2649-
unsigned NumEntries = 0;
2650-
2651-
explicit LifetimeAttr(SourceLoc atLoc, SourceRange baseRange, bool implicit,
2652-
ArrayRef<LifetimeEntry> entries);
2646+
LifetimeAttr(SourceLoc atLoc, SourceRange baseRange, bool implicit,
2647+
LifetimeEntry *entry)
2648+
: DeclAttribute(DeclAttrKind::Lifetime, atLoc, baseRange, implicit),
2649+
entry(entry) {}
26532650

26542651
public:
26552652
static LifetimeAttr *create(ASTContext &context, SourceLoc atLoc,
26562653
SourceRange baseRange, bool implicit,
2657-
ArrayRef<LifetimeEntry> entries);
2654+
LifetimeEntry *entry);
26582655

2659-
ArrayRef<LifetimeEntry> getLifetimeEntries() const {
2660-
return {getTrailingObjects<LifetimeEntry>(), NumEntries};
2661-
}
2656+
LifetimeEntry *getLifetimeEntry() const { return entry; }
26622657

26632658
static bool classof(const DeclAttribute *DA) {
26642659
return DA->getKind() == DeclAttrKind::Lifetime;

include/swift/AST/DeclAttr.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,7 @@ SIMPLE_DECL_ATTR(unsafe, Unsafe,
510510
160)
511511

512512
DECL_ATTR(lifetime, Lifetime,
513-
OnAccessor | OnConstructor | OnFunc | OnSubscript | LongAttribute | ABIBreakingToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove,
513+
OnAccessor | OnConstructor | OnFunc | OnSubscript | LongAttribute | ABIBreakingToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove | AllowMultipleAttributes,
514514
161)
515515

516516
LAST_DECL_ATTR(Lifetime)

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7948,9 +7948,9 @@ ERROR(pack_iteration_where_clause_not_supported, none,
79487948
//------------------------------------------------------------------------------
79497949

79507950
ERROR(lifetime_dependence_invalid_param_name, none,
7951-
"invalid parameter name specified %0", (Identifier))
7951+
"invalid parameter name specified '%0'", (StringRef))
79527952
ERROR(lifetime_dependence_invalid_param_index, none,
7953-
"invalid parameter index specified %0", (unsigned))
7953+
"invalid parameter index specified '%0'", (unsigned))
79547954
ERROR(lifetime_dependence_invalid_self_in_static, none,
79557955
"invalid lifetime dependence specifier on non-existent self", ())
79567956
ERROR(lifetime_dependence_invalid_self_in_init, none,

include/swift/AST/LifetimeDependence.h

Lines changed: 111 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -43,102 +43,149 @@ enum class ParsedLifetimeDependenceKind : uint8_t {
4343

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

46-
enum class LifetimeEntryKind { Named, Ordered, Self, Immortal };
47-
48-
class LifetimeEntry {
49-
private:
50-
SourceLoc loc;
51-
LifetimeEntryKind lifetimeEntryKind;
52-
ParsedLifetimeDependenceKind parsedLifetimeDependenceKind;
46+
struct LifetimeDescriptor {
5347
union Value {
5448
struct {
55-
Identifier name;
49+
StringRef name;
5650
} Named;
5751
struct {
5852
unsigned index;
5953
} Ordered;
6054
struct {
61-
} self;
62-
Value(Identifier name) : Named({name}) {}
55+
} Self;
56+
Value(StringRef name) : Named({name}) {}
6357
Value(unsigned index) : Ordered({index}) {}
64-
Value() {}
58+
Value() : Self() {}
6559
} value;
6660

67-
LifetimeEntry(SourceLoc loc, LifetimeEntryKind lifetimeEntryKind,
68-
ParsedLifetimeDependenceKind parsedLifetimeDependenceKind,
69-
Value value)
70-
: loc(loc), lifetimeEntryKind(lifetimeEntryKind),
71-
parsedLifetimeDependenceKind(parsedLifetimeDependenceKind),
72-
value(value) {}
61+
enum class DescriptorKind { Named, Ordered, Self } kind;
7362

74-
public:
75-
static LifetimeEntry
76-
getNamedLifetimeEntry(SourceLoc loc, Identifier name,
77-
ParsedLifetimeDependenceKind kind =
78-
ParsedLifetimeDependenceKind::Default) {
79-
return {loc, LifetimeEntryKind::Named, kind, name};
80-
}
63+
ParsedLifetimeDependenceKind parsedLifetimeDependenceKind;
8164

82-
static LifetimeEntry getImmortalLifetimeEntry(SourceLoc loc) {
83-
return {loc, LifetimeEntryKind::Immortal, {}, {}};
84-
}
65+
SourceLoc loc;
8566

86-
static LifetimeEntry
87-
getOrderedLifetimeEntry(SourceLoc loc, unsigned index,
88-
ParsedLifetimeDependenceKind kind =
89-
ParsedLifetimeDependenceKind::Default) {
90-
return {loc, LifetimeEntryKind::Ordered, kind, index};
91-
}
67+
private:
68+
LifetimeDescriptor(StringRef name,
69+
ParsedLifetimeDependenceKind parsedLifetimeDependenceKind,
70+
SourceLoc loc)
71+
: value{name}, kind(DescriptorKind::Named),
72+
parsedLifetimeDependenceKind(parsedLifetimeDependenceKind), loc(loc) {}
73+
LifetimeDescriptor(unsigned index,
74+
ParsedLifetimeDependenceKind parsedLifetimeDependenceKind,
75+
SourceLoc loc)
76+
: value{index}, kind(DescriptorKind::Ordered),
77+
parsedLifetimeDependenceKind(parsedLifetimeDependenceKind), loc(loc) {}
78+
LifetimeDescriptor(ParsedLifetimeDependenceKind parsedLifetimeDependenceKind,
79+
SourceLoc loc)
80+
: value{}, kind(DescriptorKind::Self),
81+
parsedLifetimeDependenceKind(parsedLifetimeDependenceKind), loc(loc) {}
9282

93-
static LifetimeEntry
94-
getSelfLifetimeEntry(SourceLoc loc,
95-
ParsedLifetimeDependenceKind kind =
96-
ParsedLifetimeDependenceKind::Default) {
97-
return {loc, LifetimeEntryKind::Self, kind, {}};
83+
public:
84+
static LifetimeDescriptor
85+
forNamed(StringRef name,
86+
ParsedLifetimeDependenceKind parsedLifetimeDependenceKind,
87+
SourceLoc loc) {
88+
return {name, parsedLifetimeDependenceKind, loc};
89+
}
90+
static LifetimeDescriptor
91+
forOrdered(unsigned index,
92+
ParsedLifetimeDependenceKind parsedLifetimeDependenceKind,
93+
SourceLoc loc) {
94+
return {index, parsedLifetimeDependenceKind, loc};
95+
}
96+
static LifetimeDescriptor
97+
forSelf(ParsedLifetimeDependenceKind parsedLifetimeDependenceKind,
98+
SourceLoc loc) {
99+
return {parsedLifetimeDependenceKind, loc};
98100
}
99-
100-
SourceLoc getLoc() const { return loc; }
101-
102-
LifetimeEntryKind getLifetimeEntryKind() const { return lifetimeEntryKind; }
103101

104102
ParsedLifetimeDependenceKind getParsedLifetimeDependenceKind() const {
105103
return parsedLifetimeDependenceKind;
106104
}
107105

108-
Identifier getName() const {
109-
assert(lifetimeEntryKind == LifetimeEntryKind::Named);
106+
StringRef getName() const {
107+
assert(kind == DescriptorKind::Named);
110108
return value.Named.name;
111109
}
112110

113111
unsigned getIndex() const {
114-
assert(lifetimeEntryKind == LifetimeEntryKind::Ordered);
112+
assert(kind == DescriptorKind::Ordered);
115113
return value.Ordered.index;
116114
}
117115

118-
std::string getParamString() const {
119-
switch (lifetimeEntryKind) {
120-
case LifetimeEntryKind::Named:
121-
return value.Named.name.str().str();
122-
case LifetimeEntryKind::Self:
116+
DescriptorKind getDescriptorKind() const { return kind; }
117+
118+
SourceLoc getLoc() const { return loc; }
119+
120+
bool isImmortal() const {
121+
if (getDescriptorKind() != LifetimeDescriptor::DescriptorKind::Named) {
122+
return false;
123+
}
124+
return getName() == "immortal";
125+
}
126+
127+
std::string getString() const {
128+
switch (kind) {
129+
case DescriptorKind::Named:
130+
return getName().str();
131+
case DescriptorKind::Ordered:
132+
return std::to_string(getIndex());
133+
case DescriptorKind::Self:
123134
return "self";
124-
case LifetimeEntryKind::Ordered:
125-
return std::to_string(value.Ordered.index);
126-
case LifetimeEntryKind::Immortal:
127-
return "immortal";
128135
}
129-
llvm_unreachable("Invalid LifetimeEntryKind");
136+
llvm_unreachable("Invalid DescriptorKind");
130137
}
138+
};
139+
140+
// TODO: Use TrailingObjects to tail allocate sources
141+
class LifetimeEntry {
142+
private:
143+
SourceLoc startLoc, endLoc;
144+
ArrayRef<LifetimeDescriptor> sources;
145+
std::optional<LifetimeDescriptor> targetDescriptor;
146+
147+
LifetimeEntry(
148+
SourceLoc startLoc, SourceLoc endLoc,
149+
ArrayRef<LifetimeDescriptor> sources,
150+
std::optional<LifetimeDescriptor> targetDescriptor = std::nullopt)
151+
: startLoc(startLoc), endLoc(endLoc), sources(sources),
152+
targetDescriptor(targetDescriptor) {}
153+
154+
public:
155+
/// \p sources should be allocated on the ASTContext
156+
static LifetimeEntry *
157+
create(const ASTContext &ctx, SourceLoc startLoc, SourceLoc endLoc,
158+
ArrayRef<LifetimeDescriptor> sources,
159+
std::optional<LifetimeDescriptor> targetDescriptor = std::nullopt);
160+
161+
SourceLoc getLoc() const { return startLoc; }
162+
SourceLoc getStartLoc() const { return startLoc; }
163+
SourceLoc getEndLoc() const { return endLoc; }
164+
165+
ArrayRef<LifetimeDescriptor> getSources() const { return sources; }
166+
167+
std::optional<LifetimeDescriptor> getTargetDescriptor() const {
168+
return targetDescriptor;
169+
}
170+
171+
bool empty() const { return !sources.empty(); }
172+
173+
std::string getString() const {
174+
std::string result = "@lifetime(";
175+
if (targetDescriptor.has_value()) {
176+
result += targetDescriptor->getString();
177+
result += ": ";
178+
}
131179

132-
std::string getDependsOnString() const {
133-
switch (parsedLifetimeDependenceKind) {
134-
case ParsedLifetimeDependenceKind::Default:
135-
return "dependsOn(" + getParamString() + ")";
136-
case ParsedLifetimeDependenceKind::Scope:
137-
return "dependsOn(scoped " + getParamString() + ")";
138-
case ParsedLifetimeDependenceKind::Inherit:
139-
return "dependsOn(inherited " + getParamString() + ")";
180+
for (auto source : sources) {
181+
if (source.getParsedLifetimeDependenceKind() ==
182+
ParsedLifetimeDependenceKind::Scope) {
183+
result += "borrow ";
184+
}
185+
result += source.getString();
140186
}
141-
llvm_unreachable("Invalid LifetimeEntry::ParsedLifetimeDependenceKind");
187+
result += ")";
188+
return result;
142189
}
143190
};
144191

include/swift/AST/TypeRepr.h

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,6 @@ class alignas(1 << TypeReprAlignInBits) TypeRepr
111111
/// The number of elements contained.
112112
NumElements : 32
113113
);
114-
115-
SWIFT_INLINE_BITFIELD_FULL(LifetimeDependentTypeRepr, TypeRepr, 32,
116-
: NumPadBits,
117-
NumDependencies : 32
118-
);
119114
} Bits;
120115
// clang-format on
121116

@@ -1531,32 +1526,19 @@ class SILBoxTypeRepr final : public TypeRepr,
15311526
friend TypeRepr;
15321527
};
15331528

1534-
class LifetimeDependentTypeRepr final
1535-
: public SpecifierTypeRepr,
1536-
private llvm::TrailingObjects<LifetimeDependentTypeRepr, LifetimeEntry> {
1537-
friend TrailingObjects;
1538-
1539-
size_t numTrailingObjects(OverloadToken<LifetimeDependentTypeRepr>) const {
1540-
return Bits.LifetimeDependentTypeRepr.NumDependencies;
1541-
}
1529+
class LifetimeDependentTypeRepr final : public SpecifierTypeRepr {
1530+
LifetimeEntry *entry;
15421531

15431532
public:
1544-
LifetimeDependentTypeRepr(TypeRepr *base, ArrayRef<LifetimeEntry> specifiers)
1533+
LifetimeDependentTypeRepr(TypeRepr *base, LifetimeEntry *entry)
15451534
: SpecifierTypeRepr(TypeReprKind::LifetimeDependent, base,
1546-
specifiers.front().getLoc()) {
1547-
assert(base);
1548-
Bits.LifetimeDependentTypeRepr.NumDependencies = specifiers.size();
1549-
std::uninitialized_copy(specifiers.begin(), specifiers.end(),
1550-
getTrailingObjects<LifetimeEntry>());
1551-
}
1535+
entry->getLoc()),
1536+
entry(entry) {}
15521537

15531538
static LifetimeDependentTypeRepr *create(ASTContext &C, TypeRepr *base,
1554-
ArrayRef<LifetimeEntry> specifiers);
1539+
LifetimeEntry *entry);
15551540

1556-
ArrayRef<LifetimeEntry> getLifetimeDependencies() const {
1557-
return {getTrailingObjects<LifetimeEntry>(),
1558-
Bits.LifetimeDependentTypeRepr.NumDependencies};
1559-
}
1541+
LifetimeEntry *getLifetimeEntry() const { return entry; }
15601542

15611543
static bool classof(const TypeRepr *T) {
15621544
return T->getKind() == TypeReprKind::LifetimeDependent;

include/swift/Parse/Parser.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,6 +1162,10 @@ class Parser {
11621162
MacroSyntax syntax, SourceLoc AtLoc, SourceLoc Loc
11631163
);
11641164

1165+
// TODO: Make it static
1166+
std::optional<LifetimeDescriptor>
1167+
parseLifetimeDescriptor(Token token,
1168+
ParsedLifetimeDependenceKind lifetimeDependenceKind);
11651169
/// Parse the @lifetime attribute.
11661170
ParserResult<LifetimeAttr> parseLifetimeAttribute(SourceLoc AtLoc,
11671171
SourceLoc Loc);
@@ -1251,8 +1255,8 @@ class Parser {
12511255
ConventionTypeAttr *&result,
12521256
bool justChecking);
12531257

1254-
ParserStatus
1255-
parseLifetimeEntries(SmallVectorImpl<LifetimeEntry> &specifierList);
1258+
// TODO: Make it static
1259+
ParserResult<LifetimeEntry> parseLifetimeEntry(SourceLoc loc);
12561260

12571261
ParserResult<ImportDecl> parseDeclImport(ParseDeclOptions Flags,
12581262
DeclAttributes &Attributes);
@@ -1455,7 +1459,7 @@ class Parser {
14551459
SourceLoc ConstLoc;
14561460
SourceLoc SendingLoc;
14571461
SmallVector<TypeOrCustomAttr> Attributes;
1458-
SmallVector<LifetimeEntry> lifetimeEntries;
1462+
LifetimeEntry *lifetimeEntry = nullptr;
14591463

14601464
ParsedTypeAttributeList(ParseTypeReason reason) : ParseReason(reason) {}
14611465

lib/AST/ASTDumper.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3576,13 +3576,12 @@ class PrintTypeRepr : public TypeReprVisitor<PrintTypeRepr, void, StringRef>,
35763576
void visitLifetimeDependentTypeRepr(LifetimeDependentTypeRepr *T,
35773577
StringRef label) {
35783578
printCommon("type_lifetime_dependent_return", label);
3579-
for (auto &dep : T->getLifetimeDependencies()) {
3580-
printFieldRaw(
3581-
[&](raw_ostream &out) {
3582-
out << " " << dep.getDependsOnString() << " ";
3583-
},
3584-
"");
3585-
}
3579+
3580+
printFieldRaw(
3581+
[&](raw_ostream &out) {
3582+
out << " " << T->getLifetimeEntry()->getString() << " ";
3583+
},
3584+
"");
35863585
printRec(T->getBase());
35873586
printFoot();
35883587
}

0 commit comments

Comments
 (0)