Skip to content

Commit c145591

Browse files
committed
Add dependsOn(immortal)
1 parent af1d601 commit c145591

12 files changed

+128
-44
lines changed

include/swift/AST/DiagnosticsSema.def

+2
Original file line numberDiff line numberDiff line change
@@ -7973,6 +7973,8 @@ ERROR(lifetime_dependence_cannot_infer_ambiguous_candidate, none,
79737973
"cannot infer lifetime dependence on a self which is BitwiseCopyable & "
79747974
"Escapable",
79757975
())
7976+
ERROR(lifetime_dependence_immortal_conflict_name, none,
7977+
"conflict between the parameter name and immortal keyword", ())
79767978

79777979
//===----------------------------------------------------------------------===//
79787980
// MARK: Transferring

include/swift/AST/LifetimeDependence.h

+19-6
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ enum class LifetimeDependenceKind : uint8_t { Inherit = 0, Scope };
4343

4444
class LifetimeDependenceSpecifier {
4545
public:
46-
enum class SpecifierKind { Named, Ordered, Self };
46+
enum class SpecifierKind { Named, Ordered, Self, Immortal };
4747

4848
private:
4949
SourceLoc loc;
@@ -76,6 +76,11 @@ class LifetimeDependenceSpecifier {
7676
return {loc, SpecifierKind::Named, kind, name};
7777
}
7878

79+
static LifetimeDependenceSpecifier
80+
getImmortalLifetimeDependenceSpecifier(SourceLoc loc) {
81+
return {loc, SpecifierKind::Immortal, {}, {}};
82+
}
83+
7984
static LifetimeDependenceSpecifier getOrderedLifetimeDependenceSpecifier(
8085
SourceLoc loc, ParsedLifetimeDependenceKind kind, unsigned index) {
8186
return {loc, SpecifierKind::Ordered, kind, index};
@@ -113,6 +118,8 @@ class LifetimeDependenceSpecifier {
113118
return "self";
114119
case SpecifierKind::Ordered:
115120
return std::to_string(value.Ordered.index);
121+
case SpecifierKind::Immortal:
122+
return "immortal";
116123
}
117124
llvm_unreachable("Invalid LifetimeDependenceSpecifier::SpecifierKind");
118125
}
@@ -134,6 +141,7 @@ class LifetimeDependenceSpecifier {
134141
class LifetimeDependenceInfo {
135142
IndexSubset *inheritLifetimeParamIndices;
136143
IndexSubset *scopeLifetimeParamIndices;
144+
bool immortal;
137145

138146
static LifetimeDependenceInfo getForParamIndex(AbstractFunctionDecl *afd,
139147
unsigned index,
@@ -149,12 +157,15 @@ class LifetimeDependenceInfo {
149157
public:
150158
LifetimeDependenceInfo()
151159
: inheritLifetimeParamIndices(nullptr),
152-
scopeLifetimeParamIndices(nullptr) {}
160+
scopeLifetimeParamIndices(nullptr), immortal(false) {}
153161
LifetimeDependenceInfo(IndexSubset *inheritLifetimeParamIndices,
154-
IndexSubset *scopeLifetimeParamIndices)
162+
IndexSubset *scopeLifetimeParamIndices,
163+
bool isImmortal)
155164
: inheritLifetimeParamIndices(inheritLifetimeParamIndices),
156-
scopeLifetimeParamIndices(scopeLifetimeParamIndices) {
157-
assert(!empty());
165+
scopeLifetimeParamIndices(scopeLifetimeParamIndices),
166+
immortal(isImmortal) {
167+
assert(isImmortal || inheritLifetimeParamIndices ||
168+
scopeLifetimeParamIndices);
158169
assert(!inheritLifetimeParamIndices ||
159170
!inheritLifetimeParamIndices->isEmpty());
160171
assert(!scopeLifetimeParamIndices || !scopeLifetimeParamIndices->isEmpty());
@@ -163,10 +174,12 @@ class LifetimeDependenceInfo {
163174
operator bool() const { return !empty(); }
164175

165176
bool empty() const {
166-
return inheritLifetimeParamIndices == nullptr &&
177+
return !immortal && inheritLifetimeParamIndices == nullptr &&
167178
scopeLifetimeParamIndices == nullptr;
168179
}
169180

181+
bool isImmortal() const { return immortal; }
182+
170183
bool hasInheritLifetimeParamIndices() const {
171184
return inheritLifetimeParamIndices != nullptr;
172185
}

lib/AST/LifetimeDependence.cpp

+42-27
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,12 @@ LifetimeDependenceInfo LifetimeDependenceInfo::getForParamIndex(
110110
auto indexSubset = IndexSubset::get(ctx, capacity, {index});
111111
if (kind == LifetimeDependenceKind::Scope) {
112112
return LifetimeDependenceInfo{/*inheritLifetimeParamIndices*/ nullptr,
113-
/*scopeLifetimeParamIndices*/ indexSubset};
113+
/*scopeLifetimeParamIndices*/ indexSubset,
114+
/*isImmortal*/ false};
114115
}
115116
return LifetimeDependenceInfo{/*inheritLifetimeParamIndices*/ indexSubset,
116-
/*scopeLifetimeParamIndices*/ nullptr};
117+
/*scopeLifetimeParamIndices*/ nullptr,
118+
/*isImmortal*/ false};
117119
}
118120

119121
void LifetimeDependenceInfo::getConcatenatedData(
@@ -246,6 +248,18 @@ LifetimeDependenceInfo::fromTypeRepr(AbstractFunctionDecl *afd) {
246248

247249
for (auto specifier : lifetimeDependentRepr->getLifetimeDependencies()) {
248250
switch (specifier.getSpecifierKind()) {
251+
case LifetimeDependenceSpecifier::SpecifierKind::Immortal: {
252+
auto immortalParam =
253+
std::find_if(afd->getParameters()->begin(), afd->getParameters()->end(), [](ParamDecl *param) {
254+
return strcmp(param->getName().get(), "immortal") == 0;
255+
});
256+
if (immortalParam != afd->getParameters()->end()) {
257+
diags.diagnose(*immortalParam,
258+
diag::lifetime_dependence_immortal_conflict_name);
259+
}
260+
261+
return LifetimeDependenceInfo(nullptr, nullptr, /*isImmortal*/ true);
262+
}
249263
case LifetimeDependenceSpecifier::SpecifierKind::Named: {
250264
bool foundParamName = false;
251265
unsigned paramIndex = 0;
@@ -315,7 +329,8 @@ LifetimeDependenceInfo::fromTypeRepr(AbstractFunctionDecl *afd) {
315329
: nullptr,
316330
scopeLifetimeParamIndices.any()
317331
? IndexSubset::get(ctx, scopeLifetimeParamIndices)
318-
: nullptr);
332+
: nullptr,
333+
/*isImmortal*/ false);
319334
}
320335

321336
// This utility is similar to its overloaded version that builds the
@@ -360,18 +375,29 @@ std::optional<LifetimeDependenceInfo> LifetimeDependenceInfo::fromTypeRepr(
360375
};
361376

362377
for (auto specifier : lifetimeDependentRepr->getLifetimeDependencies()) {
363-
assert(specifier.getSpecifierKind() ==
364-
LifetimeDependenceSpecifier::SpecifierKind::Ordered);
365-
auto index = specifier.getIndex();
366-
if (index > capacity) {
367-
diags.diagnose(specifier.getLoc(),
368-
diag::lifetime_dependence_invalid_param_index, index);
369-
return std::nullopt;
378+
switch (specifier.getSpecifierKind()) {
379+
case LifetimeDependenceSpecifier::SpecifierKind::Ordered: {
380+
auto index = specifier.getIndex();
381+
if (index > capacity) {
382+
diags.diagnose(specifier.getLoc(),
383+
diag::lifetime_dependence_invalid_param_index, index);
384+
return std::nullopt;
385+
}
386+
auto param = params[index];
387+
auto paramConvention = param.getConvention();
388+
if (updateLifetimeDependenceInfo(specifier, index, paramConvention)) {
389+
return std::nullopt;
390+
}
391+
break;
370392
}
371-
auto param = params[index];
372-
auto paramConvention = param.getConvention();
373-
if (updateLifetimeDependenceInfo(specifier, index, paramConvention)) {
374-
return std::nullopt;
393+
case LifetimeDependenceSpecifier::SpecifierKind::Immortal: {
394+
return LifetimeDependenceInfo(/*inheritLifetimeParamIndices*/ nullptr,
395+
/*scopeLifetimeParamIndices*/ nullptr,
396+
/*isImmortal*/ true);
397+
}
398+
default:
399+
llvm_unreachable("SIL can only have ordered or immortal lifetime "
400+
"dependence specifier kind");
375401
}
376402
}
377403

@@ -381,7 +407,8 @@ std::optional<LifetimeDependenceInfo> LifetimeDependenceInfo::fromTypeRepr(
381407
: nullptr,
382408
scopeLifetimeParamIndices.any()
383409
? IndexSubset::get(ctx, scopeLifetimeParamIndices)
384-
: nullptr);
410+
: nullptr,
411+
/*isImmortal*/ false);
385412
}
386413

387414
std::optional<LifetimeDependenceInfo>
@@ -510,18 +537,6 @@ LifetimeDependenceInfo::get(AbstractFunctionDecl *afd) {
510537
return LifetimeDependenceInfo::infer(afd);
511538
}
512539

513-
LifetimeDependenceInfo
514-
LifetimeDependenceInfo::get(ASTContext &ctx,
515-
const SmallBitVector &inheritLifetimeIndices,
516-
const SmallBitVector &scopeLifetimeIndices) {
517-
return LifetimeDependenceInfo{
518-
inheritLifetimeIndices.any()
519-
? IndexSubset::get(ctx, inheritLifetimeIndices)
520-
: nullptr,
521-
scopeLifetimeIndices.any() ? IndexSubset::get(ctx, scopeLifetimeIndices)
522-
: nullptr};
523-
}
524-
525540
std::optional<LifetimeDependenceKind>
526541
LifetimeDependenceInfo::getLifetimeDependenceOnParam(unsigned paramIndex) {
527542
if (inheritLifetimeParamIndices) {

lib/Parse/ParseDecl.cpp

+10-4
Original file line numberDiff line numberDiff line change
@@ -5122,10 +5122,16 @@ ParserStatus Parser::parseLifetimeDependenceSpecifiers(
51225122
Identifier paramName;
51235123
auto paramLoc =
51245124
consumeIdentifier(paramName, /*diagnoseDollarPrefix=*/false);
5125-
specifierList.push_back(
5126-
LifetimeDependenceSpecifier::
5127-
getNamedLifetimeDependenceSpecifier(
5128-
paramLoc, lifetimeDependenceKind, paramName));
5125+
if (paramName.is("immortal")) {
5126+
specifierList.push_back(
5127+
LifetimeDependenceSpecifier::
5128+
getImmortalLifetimeDependenceSpecifier(paramLoc));
5129+
} else {
5130+
specifierList.push_back(
5131+
LifetimeDependenceSpecifier::
5132+
getNamedLifetimeDependenceSpecifier(
5133+
paramLoc, lifetimeDependenceKind, paramName));
5134+
}
51295135
break;
51305136
}
51315137
case tok::integer_literal: {

lib/Serialization/Deserialization.cpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -8864,12 +8864,13 @@ ModuleFile::maybeReadLifetimeDependenceInfo(unsigned numParams) {
88648864
return std::nullopt;
88658865
}
88668866

8867+
bool isImmortal;
88678868
bool hasInheritLifetimeParamIndices;
88688869
bool hasScopeLifetimeParamIndices;
88698870
ArrayRef<uint64_t> lifetimeDependenceData;
8870-
LifetimeDependenceLayout::readRecord(scratch, hasInheritLifetimeParamIndices,
8871-
hasScopeLifetimeParamIndices,
8872-
lifetimeDependenceData);
8871+
LifetimeDependenceLayout::readRecord(
8872+
scratch, isImmortal, hasInheritLifetimeParamIndices,
8873+
hasScopeLifetimeParamIndices, lifetimeDependenceData);
88738874

88748875
SmallBitVector inheritLifetimeParamIndices(numParams, false);
88758876
SmallBitVector scopeLifetimeParamIndices(numParams, false);
@@ -8898,5 +8899,6 @@ ModuleFile::maybeReadLifetimeDependenceInfo(unsigned numParams) {
88988899
: nullptr,
88998900
hasScopeLifetimeParamIndices
89008901
? IndexSubset::get(ctx, scopeLifetimeParamIndices)
8901-
: nullptr);
8902+
: nullptr,
8903+
isImmortal);
89028904
}

lib/Serialization/ModuleFormat.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5858
/// describe what change you made. The content of this comment isn't important;
5959
/// it just ensures a conflict if two people change the module format.
6060
/// Don't worry about adhering to the 80-column limit for this line.
61-
const uint16_t SWIFTMODULE_VERSION_MINOR = 877; // extend_lifetime instruction
61+
const uint16_t SWIFTMODULE_VERSION_MINOR =
62+
878; // immortal bit in LifetimeDependence
6263

6364
/// A standard hash seed used for all string hashes in a serialized module.
6465
///
@@ -2212,6 +2213,7 @@ namespace decls_block {
22122213

22132214
using LifetimeDependenceLayout =
22142215
BCRecordLayout<LIFETIME_DEPENDENCE,
2216+
BCFixed<1>, // isImmortal
22152217
BCFixed<1>, // hasInheritLifetimeParamIndices
22162218
BCFixed<1>, // hasScopeLifetimeParamIndices
22172219
BCArray<BCFixed<1>> // concatenated param indices

lib/Serialization/Serialization.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -2579,7 +2579,7 @@ void Serializer::writeLifetimeDependenceInfo(
25792579

25802580
auto abbrCode = DeclTypeAbbrCodes[LifetimeDependenceLayout::Code];
25812581
LifetimeDependenceLayout::emitRecord(
2582-
Out, ScratchRecord, abbrCode,
2582+
Out, ScratchRecord, abbrCode, lifetimeDependenceInfo.isImmortal(),
25832583
lifetimeDependenceInfo.hasInheritLifetimeParamIndices(),
25842584
lifetimeDependenceInfo.hasScopeLifetimeParamIndices(), paramIndices);
25852585
}

test/Parse/explicit_lifetime_dependence_specifiers.swift

+12
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,15 @@ struct Wrapper : ~Escapable {
153153
return view
154154
}
155155
}
156+
157+
enum FakeOptional<Wrapped: ~Escapable>: ~Escapable {
158+
case none, some(Wrapped)
159+
}
160+
161+
extension FakeOptional: Escapable where Wrapped: Escapable {}
162+
163+
extension FakeOptional where Wrapped: ~Escapable {
164+
init(nilLiteral: ()) -> dependsOn(immortal) Self {
165+
self = .none
166+
}
167+
}

test/SILOptimizer/lifetime_dependence.sil

+11-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// REQUIRES: asserts
88
// REQUIRES: swift_in_compiler
99

10-
// Test the SIL representation for lifetime depenence.
10+
// Test the SIL representation for lifetime dependence.
1111

1212
sil_stage raw
1313

@@ -18,6 +18,7 @@ class C {}
1818
struct Nonescapable: ~Escapable {}
1919

2020
sil @c_dependence : $@convention(thin) (@guaranteed C) -> _scope(0) @owned Nonescapable
21+
sil @immortal_dependence : $@convention(thin) () -> _scope(immortal) @owned Nonescapable
2122

2223
// Test that SILType.isEscpable does not crash on a generic box when NoncopyableGenerics is enabled.
2324
sil shared [serialized] [ossa] @testLocalFunc : $@convention(thin) <T, U> (@guaranteed <τ_0_0> { var τ_0_0 } <U>) -> () {
@@ -42,3 +43,12 @@ bb0(%0 : @owned $C):
4243
%28 = tuple ()
4344
return %28 : $()
4445
}
46+
47+
sil [ossa] @test_immortal_dependence : $@convention(thin) () -> () {
48+
bb0:
49+
%f = function_ref @immortal_dependence : $@convention(thin) () -> _scope(immortal) @owned Nonescapable
50+
%c = apply %f() : $@convention(thin) () -> _scope(immortal) @owned Nonescapable
51+
destroy_value %c : $Nonescapable
52+
%t = tuple ()
53+
return %t : $()
54+
}

test/Sema/explicit_lifetime_dependence_specifiers1.swift

+5
Original file line numberDiff line numberDiff line change
@@ -231,3 +231,8 @@ extension RawBufferView {
231231
return BufferView(ptr)
232232
}
233233
}
234+
235+
func immortalConflict(immortal: UnsafeRawBufferPointer ) -> dependsOn(immortal) BufferView { // expected-error{{conflict between the parameter name and immortal keyword}}
236+
return BufferView(immortal)
237+
}
238+

test/Serialization/Inputs/def_explicit_lifetime_dependence.swift

+13
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,16 @@ public struct Wrapper : ~Escapable {
6868
}
6969
}
7070
}
71+
72+
public enum FakeOptional<Wrapped: ~Escapable>: ~Escapable {
73+
case none, some(Wrapped)
74+
}
75+
76+
extension FakeOptional: Escapable where Wrapped: Escapable {}
77+
78+
extension FakeOptional where Wrapped: ~Escapable {
79+
public init(_ nilLiteral: ()) -> dependsOn(immortal) Self {
80+
self = .none
81+
}
82+
}
83+

test/Serialization/explicit_lifetime_dependence.swift

+4
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ func testReadAccessor() {
4444
}
4545
}
4646

47+
func testFakeOptional() {
48+
_ = FakeOptional<Int>(())
49+
}
50+
4751
// CHECK: sil @$s32def_explicit_lifetime_dependence6deriveyAA10BufferViewVADYlsF : $@convention(thin) (@guaranteed BufferView) -> _scope(0) @owned BufferView
4852
// CHECK: sil @$s32def_explicit_lifetime_dependence16consumeAndCreateyAA10BufferViewVADnYliF : $@convention(thin) (@owned BufferView) -> _inherit(0) @owned BufferView
4953
// CHECK: sil @$s32def_explicit_lifetime_dependence15borrowAndCreateyAA10BufferViewVADYlsF : $@convention(thin) (@guaranteed BufferView) -> _scope(0) @owned BufferView

0 commit comments

Comments
 (0)