Skip to content

Commit 31c1dc7

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 011b5bf commit 31c1dc7

12 files changed

+385
-479
lines changed

include/swift/AST/Attr.h

+8-13
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

+1-1
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

+2-2
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

+111-64
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

+7-25
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

+5-4
Original file line numberDiff line numberDiff line change
@@ -1166,6 +1166,10 @@ class Parser {
11661166
ParserResult<LifetimeAttr> parseLifetimeAttribute(SourceLoc AtLoc,
11671167
SourceLoc Loc);
11681168

1169+
/// Common utility to parse swift @lifetime decl attribute and SIL @lifetime
1170+
/// type modifier.
1171+
ParserResult<LifetimeEntry> parseLifetimeEntry(SourceLoc loc);
1172+
11691173
/// Parse a specific attribute.
11701174
ParserStatus parseDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
11711175
SourceLoc AtEndLoc,
@@ -1251,9 +1255,6 @@ class Parser {
12511255
ConventionTypeAttr *&result,
12521256
bool justChecking);
12531257

1254-
ParserStatus
1255-
parseLifetimeEntries(SmallVectorImpl<LifetimeEntry> &specifierList);
1256-
12571258
ParserResult<ImportDecl> parseDeclImport(ParseDeclOptions Flags,
12581259
DeclAttributes &Attributes);
12591260

@@ -1455,7 +1456,7 @@ class Parser {
14551456
SourceLoc ConstLoc;
14561457
SourceLoc SendingLoc;
14571458
SmallVector<TypeOrCustomAttr> Attributes;
1458-
SmallVector<LifetimeEntry> lifetimeEntries;
1459+
LifetimeEntry *lifetimeEntry = nullptr;
14591460

14601461
ParsedTypeAttributeList(ParseTypeReason reason) : ParseReason(reason) {}
14611462

lib/AST/ASTDumper.cpp

+6-7
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)