Skip to content

Commit 77feef5

Browse files
Merge pull request #63766 from nate-chandler/lexical_lifetimes/per-function
Add attr to enable lexical lifetime per function.
2 parents 25c2c37 + ec1a5e0 commit 77feef5

18 files changed

+142
-41
lines changed

Diff for: docs/ReferenceGuides/UnderscoredAttributes.md

+11
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,17 @@ recursive function, the attribute is ignored.
534534

535535
This attribute has no effect in debug builds.
536536

537+
## `@_lexicalLifetimes`
538+
539+
Applies lexical lifetime rules within a module built with lexical lifetimes
540+
disabled. Facilitates gradual migration.
541+
542+
In modules built with lexical lifetimes disabled but lexical borrow scopes
543+
enabled--the behavior of `-enable-lexical-lifetimes=false`--all lexical markers
544+
are stripped by the LexicalLifetimeEliminator pass. Functions annotated with
545+
this attribute keep their lexical markers, affecting the optimizations that run
546+
on the function subsequently.
547+
537548
## `@_noEagerMove`
538549

539550
When applied to a value, indicates that the value's lifetime is lexical, that

Diff for: include/swift/SIL/SILFunction.h

+16
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ enum IsRuntimeAccessible_t {
7070
IsRuntimeAccessible
7171
};
7272

73+
enum ForceEnableLexicalLifetimes_t {
74+
DoNotForceEnableLexicalLifetimes,
75+
DoForceEnableLexicalLifetimes
76+
};
77+
7378
enum class PerformanceConstraints : uint8_t {
7479
None = 0,
7580
NoAllocation = 1,
@@ -403,6 +408,9 @@ class SILFunction
403408
/// The function is in a statically linked module.
404409
unsigned IsStaticallyLinked : 1;
405410

411+
/// If true, the function has lexical lifetimes even if the module does not.
412+
unsigned ForceEnableLexicalLifetimes : 1;
413+
406414
static void
407415
validateSubclassScope(SubclassScope scope, IsThunk_t isThunk,
408416
const GenericSpecializationInformation *genericInfo) {
@@ -670,6 +678,14 @@ class SILFunction
670678
IsStaticallyLinked = value;
671679
}
672680

681+
ForceEnableLexicalLifetimes_t forceEnableLexicalLifetimes() const {
682+
return ForceEnableLexicalLifetimes_t(ForceEnableLexicalLifetimes);
683+
}
684+
685+
void setForceEnableLexicalLifetimes(ForceEnableLexicalLifetimes_t value) {
686+
ForceEnableLexicalLifetimes = value;
687+
}
688+
673689
/// Returns true if this is a reabstraction thunk of escaping function type
674690
/// whose single argument is a potentially non-escaping closure. i.e. the
675691
/// thunks' function argument may itself have @inout_aliasable parameters.

Diff for: lib/SIL/IR/SILFunction.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ void SILFunction::init(
205205
this->ExactSelfClass = isExactSelfClass;
206206
this->IsDistributed = isDistributed;
207207
this->IsRuntimeAccessible = isRuntimeAccessible;
208+
this->ForceEnableLexicalLifetimes = DoNotForceEnableLexicalLifetimes;
208209
this->stackProtection = false;
209210
this->Inlined = false;
210211
this->Zombie = false;

Diff for: lib/SIL/IR/SILFunctionBuilder.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,10 @@ void SILFunctionBuilder::addFunctionAttributes(
167167
F->setPerfConstraints(PerformanceConstraints::NoAllocation);
168168
}
169169

170+
if (Attrs.hasAttribute<LexicalLifetimesAttr>()) {
171+
F->setForceEnableLexicalLifetimes(DoForceEnableLexicalLifetimes);
172+
}
173+
170174
// Validate `@differentiable` attributes by calling `getParameterIndices`.
171175
// This is important for:
172176
// - Skipping invalid `@differentiable` attributes in non-primary files.

Diff for: lib/SIL/IR/SILPrinter.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -3094,6 +3094,9 @@ void SILFunction::print(SILPrintContext &PrintCtx) const {
30943094
if (isRuntimeAccessible()) {
30953095
OS << "[runtime_accessible] ";
30963096
}
3097+
if (forceEnableLexicalLifetimes()) {
3098+
OS << "[lexical_lifetimes] ";
3099+
}
30973100

30983101
if (isExactSelfClass()) {
30993102
OS << "[exact_self_class] ";

Diff for: lib/SIL/Parser/ParseSIL.cpp

+20-11
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,7 @@ static bool parseDeclSILOptional(bool *isTransparent,
10041004
IsDynamicallyReplaceable_t *isDynamic,
10051005
IsDistributed_t *isDistributed,
10061006
IsRuntimeAccessible_t *isRuntimeAccessible,
1007+
ForceEnableLexicalLifetimes_t *forceEnableLexicalLifetimes,
10071008
IsExactSelfClass_t *isExactSelfClass,
10081009
SILFunction **dynamicallyReplacedFunction,
10091010
SILFunction **usedAdHocRequirementWitness,
@@ -1042,6 +1043,9 @@ static bool parseDeclSILOptional(bool *isTransparent,
10421043
*isDistributed = IsDistributed;
10431044
else if (isRuntimeAccessible && SP.P.Tok.getText() == "runtime_accessible")
10441045
*isRuntimeAccessible = IsRuntimeAccessible;
1046+
else if (forceEnableLexicalLifetimes &&
1047+
SP.P.Tok.getText() == "lexical_lifetimes")
1048+
*forceEnableLexicalLifetimes = DoForceEnableLexicalLifetimes;
10451049
else if (isExactSelfClass && SP.P.Tok.getText() == "exact_self_class")
10461050
*isExactSelfClass = IsExactSelfClass;
10471051
else if (isCanonical && SP.P.Tok.getText() == "canonical")
@@ -6793,6 +6797,8 @@ bool SILParserState::parseDeclSIL(Parser &P) {
67936797
IsDynamicallyReplaceable_t isDynamic = IsNotDynamic;
67946798
IsDistributed_t isDistributed = IsNotDistributed;
67956799
IsRuntimeAccessible_t isRuntimeAccessible = IsNotRuntimeAccessible;
6800+
ForceEnableLexicalLifetimes_t forceEnableLexicalLifetimes =
6801+
DoNotForceEnableLexicalLifetimes;
67966802
IsExactSelfClass_t isExactSelfClass = IsNotExactSelfClass;
67976803
bool hasOwnershipSSA = false;
67986804
IsThunk_t isThunk = IsNotThunk;
@@ -6815,12 +6821,12 @@ bool SILParserState::parseDeclSIL(Parser &P) {
68156821
parseDeclSILOptional(
68166822
&isTransparent, &isSerialized, &isCanonical, &hasOwnershipSSA,
68176823
&isThunk, &isDynamic, &isDistributed, &isRuntimeAccessible,
6818-
&isExactSelfClass,
6819-
&DynamicallyReplacedFunction, &AdHocWitnessFunction, &objCReplacementFor, &specialPurpose,
6820-
&inlineStrategy, &optimizationMode, &perfConstr, nullptr,
6821-
&isWeakImported, &needStackProtection, &availability,
6822-
&isWithoutActuallyEscapingThunk, &Semantics,
6823-
&SpecAttrs, &ClangDecl, &MRK, FunctionState, M) ||
6824+
&forceEnableLexicalLifetimes, &isExactSelfClass,
6825+
&DynamicallyReplacedFunction, &AdHocWitnessFunction,
6826+
&objCReplacementFor, &specialPurpose, &inlineStrategy,
6827+
&optimizationMode, &perfConstr, nullptr, &isWeakImported,
6828+
&needStackProtection, &availability, &isWithoutActuallyEscapingThunk,
6829+
&Semantics, &SpecAttrs, &ClangDecl, &MRK, FunctionState, M) ||
68246830
P.parseToken(tok::at_sign, diag::expected_sil_function_name) ||
68256831
P.parseIdentifier(FnName, FnNameLoc, /*diagnoseDollarPrefix=*/false,
68266832
diag::expected_sil_function_name) ||
@@ -6852,6 +6858,8 @@ bool SILParserState::parseDeclSIL(Parser &P) {
68526858
FunctionState.F->setIsDynamic(isDynamic);
68536859
FunctionState.F->setIsDistributed(isDistributed);
68546860
FunctionState.F->setIsRuntimeAccessible(isRuntimeAccessible);
6861+
FunctionState.F->setForceEnableLexicalLifetimes(
6862+
forceEnableLexicalLifetimes);
68556863
FunctionState.F->setIsExactSelfClass(isExactSelfClass);
68566864
FunctionState.F->setDynamicallyReplacedFunction(
68576865
DynamicallyReplacedFunction);
@@ -7058,7 +7066,7 @@ bool SILParserState::parseSILGlobal(Parser &P) {
70587066
if (parseSILLinkage(GlobalLinkage, P) ||
70597067
parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr,
70607068
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
7061-
nullptr, nullptr, nullptr, nullptr, nullptr,
7069+
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
70627070
&isLet, nullptr, nullptr, nullptr, nullptr, nullptr,
70637071
nullptr, nullptr, nullptr, State, M) ||
70647072
P.parseToken(tok::at_sign, diag::expected_sil_value_name) ||
@@ -7111,7 +7119,7 @@ bool SILParserState::parseSILProperty(Parser &P) {
71117119
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
71127120
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
71137121
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
7114-
nullptr, nullptr, SP, M))
7122+
nullptr, nullptr, nullptr, SP, M))
71157123
return true;
71167124

71177125
ValueDecl *VD;
@@ -7179,7 +7187,7 @@ bool SILParserState::parseSILVTable(Parser &P) {
71797187
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr,
71807188
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
71817189
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
7182-
nullptr, nullptr, nullptr, nullptr, nullptr,
7190+
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
71837191
nullptr, nullptr, nullptr, VTableState, M))
71847192
return true;
71857193

@@ -7290,7 +7298,8 @@ bool SILParserState::parseSILMoveOnlyDeinit(Parser &parser) {
72907298
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
72917299
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
72927300
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
7293-
nullptr, nullptr, moveOnlyDeinitTableState, M))
7301+
nullptr, nullptr, nullptr, moveOnlyDeinitTableState,
7302+
M))
72947303
return true;
72957304

72967305
// Parse the class name.
@@ -7775,7 +7784,7 @@ bool SILParserState::parseSILWitnessTable(Parser &P) {
77757784
if (parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr,
77767785
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
77777786
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
7778-
nullptr, nullptr, nullptr, nullptr, nullptr,
7787+
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
77797788
nullptr, nullptr, nullptr, WitnessState, M))
77807789
return true;
77817790

Diff for: lib/SILOptimizer/Mandatory/LexicalLifetimeEliminator.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ class LexicalLifetimeEliminatorPass : public SILFunctionTransform {
2222
void run() override {
2323
auto *fn = getFunction();
2424

25+
if (fn->forceEnableLexicalLifetimes())
26+
return;
27+
2528
// If we are already canonical, we do not have any diagnostics to emit.
2629
if (fn->wasDeserializedCanonical())
2730
return;

Diff for: lib/Sema/TypeCheckAttr.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
161161
IGNORED_ATTR(BackDeployed)
162162
IGNORED_ATTR(Documentation)
163163
IGNORED_ATTR(MacroRole)
164+
IGNORED_ATTR(LexicalLifetimes)
164165
#undef IGNORED_ATTR
165166

166167
void visitAlignmentAttr(AlignmentAttr *attr) {

Diff for: lib/Sema/TypeCheckDeclOverride.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -1625,6 +1625,7 @@ namespace {
16251625
UNINTERESTING_ATTR(RuntimeMetadata)
16261626

16271627
UNINTERESTING_ATTR(MacroRole)
1628+
UNINTERESTING_ATTR(LexicalLifetimes)
16281629
#undef UNINTERESTING_ATTR
16291630

16301631
void visitAvailableAttr(AvailableAttr *attr) {

Diff for: lib/Serialization/DeserializeSIL.cpp

+22-20
Original file line numberDiff line numberDiff line change
@@ -534,20 +534,20 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn,
534534
GenericSignatureID genericSigID;
535535
unsigned rawLinkage, isTransparent, isSerialized, isThunk,
536536
isWithoutActuallyEscapingThunk, specialPurpose, inlineStrategy,
537-
optimizationMode, perfConstr,
538-
subclassScope, hasCReferences, effect, numAttrs,
539-
hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available),
540-
isDynamic, isExactSelfClass, isDistributed, isRuntimeAccessible;
537+
optimizationMode, perfConstr, subclassScope, hasCReferences, effect,
538+
numAttrs, hasQualifiedOwnership, isWeakImported,
539+
LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass,
540+
isDistributed, isRuntimeAccessible, forceEnableLexicalLifetimes;
541541
ArrayRef<uint64_t> SemanticsIDs;
542542
SILFunctionLayout::readRecord(
543543
scratch, rawLinkage, isTransparent, isSerialized, isThunk,
544544
isWithoutActuallyEscapingThunk, specialPurpose, inlineStrategy,
545-
optimizationMode, perfConstr,
546-
subclassScope, hasCReferences, effect, numAttrs,
547-
hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available),
548-
isDynamic, isExactSelfClass, isDistributed, isRuntimeAccessible, funcTyID,
549-
replacedFunctionID, usedAdHocWitnessFunctionID,
550-
genericSigID, clangNodeOwnerID, parentModuleID, SemanticsIDs);
545+
optimizationMode, perfConstr, subclassScope, hasCReferences, effect,
546+
numAttrs, hasQualifiedOwnership, isWeakImported,
547+
LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass,
548+
isDistributed, isRuntimeAccessible, forceEnableLexicalLifetimes, funcTyID,
549+
replacedFunctionID, usedAdHocWitnessFunctionID, genericSigID,
550+
clangNodeOwnerID, parentModuleID, SemanticsIDs);
551551

552552
if (funcTyID == 0)
553553
return MF->diagnoseFatal("SILFunction typeID is 0");
@@ -680,6 +680,8 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn,
680680
fn->setIsExactSelfClass(IsExactSelfClass_t(isExactSelfClass));
681681
fn->setIsDistributed(IsDistributed_t(isDistributed));
682682
fn->setIsRuntimeAccessible(IsRuntimeAccessible_t(isRuntimeAccessible));
683+
fn->setForceEnableLexicalLifetimes(
684+
ForceEnableLexicalLifetimes_t(forceEnableLexicalLifetimes));
683685
if (replacedFunction)
684686
fn->setDynamicallyReplacedFunction(replacedFunction);
685687
if (!replacedObjectiveCFunc.empty())
@@ -3204,20 +3206,20 @@ bool SILDeserializer::hasSILFunction(StringRef Name,
32043206
GenericSignatureID genericSigID;
32053207
unsigned rawLinkage, isTransparent, isSerialized, isThunk,
32063208
isWithoutActuallyEscapingThunk, isGlobal, inlineStrategy,
3207-
optimizationMode, perfConstr,
3208-
subclassScope, hasCReferences, effect, numSpecAttrs,
3209-
hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available),
3210-
isDynamic, isExactSelfClass, isDistributed, isRuntimeAccessible;
3209+
optimizationMode, perfConstr, subclassScope, hasCReferences, effect,
3210+
numSpecAttrs, hasQualifiedOwnership, isWeakImported,
3211+
LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass,
3212+
isDistributed, isRuntimeAccessible, forceEnableLexicalLifetimes;
32113213
ArrayRef<uint64_t> SemanticsIDs;
32123214
SILFunctionLayout::readRecord(
32133215
scratch, rawLinkage, isTransparent, isSerialized, isThunk,
32143216
isWithoutActuallyEscapingThunk, isGlobal, inlineStrategy,
3215-
optimizationMode, perfConstr,
3216-
subclassScope, hasCReferences, effect, numSpecAttrs,
3217-
hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available),
3218-
isDynamic, isExactSelfClass, isDistributed, isRuntimeAccessible, funcTyID,
3219-
replacedFunctionID, usedAdHocWitnessFunctionID,
3220-
genericSigID, clangOwnerID, parentModuleID, SemanticsIDs);
3217+
optimizationMode, perfConstr, subclassScope, hasCReferences, effect,
3218+
numSpecAttrs, hasQualifiedOwnership, isWeakImported,
3219+
LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass,
3220+
isDistributed, isRuntimeAccessible, forceEnableLexicalLifetimes, funcTyID,
3221+
replacedFunctionID, usedAdHocWitnessFunctionID, genericSigID,
3222+
clangOwnerID, parentModuleID, SemanticsIDs);
32213223
auto linkage = fromStableSILLinkage(rawLinkage);
32223224
if (!linkage) {
32233225
LLVM_DEBUG(llvm::dbgs() << "invalid linkage code " << rawLinkage

Diff for: lib/Serialization/ModuleFormat.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ 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 = 744; // nonescaping closures are move-only in SIL
61+
const uint16_t SWIFTMODULE_VERSION_MINOR = 745; // _lexicalLifetimes attribute
6262

6363
/// A standard hash seed used for all string hashes in a serialized module.
6464
///

Diff for: lib/Serialization/SILFormat.h

+1
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ namespace sil_block {
297297
BCFixed<1>, // exact self class
298298
BCFixed<1>, // is distributed
299299
BCFixed<1>, // is runtime accessible
300+
BCFixed<1>, // are lexical lifetimes force-enabled
300301
TypeIDField, // SILFunctionType
301302
DeclIDField, // SILFunction name or 0 (replaced function)
302303
DeclIDField, // SILFunction name or 0 (used ad-hoc requirement witness function)

Diff for: lib/Serialization/SerializeSIL.cpp

+8-9
Original file line numberDiff line numberDiff line change
@@ -511,16 +511,15 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) {
511511
(unsigned)F.isThunk(), (unsigned)F.isWithoutActuallyEscapingThunk(),
512512
(unsigned)F.getSpecialPurpose(), (unsigned)F.getInlineStrategy(),
513513
(unsigned)F.getOptimizationMode(), (unsigned)F.getPerfConstraints(),
514-
(unsigned)F.getClassSubclassScope(),
515-
(unsigned)F.hasCReferences(), (unsigned)F.getEffectsKind(),
516-
(unsigned)numAttrs, (unsigned)F.hasOwnership(),
517-
F.isAlwaysWeakImported(), LIST_VER_TUPLE_PIECES(available),
518-
(unsigned)F.isDynamicallyReplaceable(),
519-
(unsigned)F.isExactSelfClass(),
520-
(unsigned)F.isDistributed(),
514+
(unsigned)F.getClassSubclassScope(), (unsigned)F.hasCReferences(),
515+
(unsigned)F.getEffectsKind(), (unsigned)numAttrs,
516+
(unsigned)F.hasOwnership(), F.isAlwaysWeakImported(),
517+
LIST_VER_TUPLE_PIECES(available), (unsigned)F.isDynamicallyReplaceable(),
518+
(unsigned)F.isExactSelfClass(), (unsigned)F.isDistributed(),
521519
(unsigned)F.isRuntimeAccessible(),
522-
FnID, replacedFunctionID, usedAdHocWitnessFunctionID,
523-
genericSigID, clangNodeOwnerID, parentModuleID, SemanticsIDs);
520+
(unsigned)F.forceEnableLexicalLifetimes(), FnID, replacedFunctionID,
521+
usedAdHocWitnessFunctionID, genericSigID, clangNodeOwnerID,
522+
parentModuleID, SemanticsIDs);
524523

525524
F.visitArgEffects(
526525
[&](int effectIdx, int argumentIndex, bool isDerived) {

Diff for: test/SIL/Parser/function_argument_lifetime_annotation.sil

+6
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,9 @@ bb0(%instance : @noImplicitCopy @_lexical @owned $C):
4444
return %retval : $()
4545
}
4646

47+
// CHECK-LABEL: sil [lexical_lifetimes] [ossa] @force_lexical_function : {{.*}} {
48+
// CHECK-LABEL: } // end sil function 'force_lexical_function'
49+
sil [lexical_lifetimes] [ossa] @force_lexical_function : $@convention(thin) () -> () {
50+
%retval = tuple()
51+
return %retval : $()
52+
}

Diff for: test/SIL/Serialization/function_argument_lifetime_annotation.sil

+6
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,9 @@ bb0(%instance : @_lexical @owned $C):
2828
return %retval : $()
2929
}
3030

31+
// CHECK-LABEL: sil [serialized] [lexical_lifetimes] [ossa] @force_lexical_function : {{.*}} {
32+
// CHECK-LABEL: } // end sil function 'force_lexical_function'
33+
sil [serialized] [lexical_lifetimes] [ossa] @force_lexical_function : $@convention(thin) () -> () {
34+
%retval = tuple()
35+
return %retval : $()
36+
}

Diff for: test/SILGen/lexical_lifetime_forced.swift

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// RUN: %target-swift-emit-silgen -enable-lexical-lifetimes=false -module-name borrow -parse-stdlib %s | %FileCheck %s
2+
3+
// CHECK-LABEL: sil {{.*}}[lexical_lifetimes] [ossa] @funky : {{.*}} {
4+
// CHECK-LABEL: } // end sil function 'funky'
5+
@_silgen_name("funky")
6+
@_lexicalLifetimes func funky() {}
7+

Diff for: test/SILOptimizer/lexical_lifetime_force.swift

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %target-swift-frontend -emit-sil -enable-lexical-lifetimes=false -O -module-name=main %s | %FileCheck %s
2+
3+
class C {}
4+
5+
@_silgen_name("borrow")
6+
func borrow(_ c: __shared C)
7+
8+
@_silgen_name("barrier")
9+
func barrier()
10+
11+
// CHECK-LABEL: sil {{.*}} [lexical_lifetimes] @funky : {{.*}} {
12+
// CHECK: [[INSTANCE:%[^,]+]] = alloc_ref $C
13+
// CHECK: [[BORROW:%[^,]+]] = function_ref @borrow
14+
// CHECK: apply [[BORROW]]([[INSTANCE]])
15+
// CHECK: [[BARRIER:%[^,]+]] = function_ref @barrier
16+
// CHECK: apply [[BARRIER]]()
17+
// CHECK: strong_release [[INSTANCE]]
18+
// CHECK-LABEL: } // end sil function 'funky'
19+
@_silgen_name("funky")
20+
@_lexicalLifetimes
21+
func funky() {
22+
let c = C()
23+
borrow(c)
24+
barrier()
25+
}

Diff for: utils/gyb_syntax_support/AttributeKinds.py

+6
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,12 @@ def __init__(self, name, swift_name=None):
616616
OnFunc, OnParam, OnVar, OnNominalType,
617617
code=117),
618618

619+
SimpleDeclAttribute('_lexicalLifetimes', 'LexicalLifetimes',
620+
UserInaccessible,
621+
ABIStableToAdd, ABIStableToRemove,
622+
APIStableToAdd, APIStableToRemove,
623+
OnFunc, code=36),
624+
619625
SimpleDeclAttribute('_noEagerMove', 'NoEagerMove',
620626
UserInaccessible,
621627
ABIStableToAdd, ABIStableToRemove,

0 commit comments

Comments
 (0)