@@ -808,6 +808,19 @@ static Operand *getProjectedDefOperand(SILValue value) {
808
808
}
809
809
}
810
810
811
+ // / If \p value is lexically borrowed, when it is lowered, it must be stored in
812
+ // / an alloc_stack [lexical] of the same type so that its lifetime is preserved.
813
+ static bool needsLexicalAllocStack (SILValue value) {
814
+ for (auto *use : value->getUses ()) {
815
+ auto *user = use->getUser ();
816
+ if (auto *bbi = dyn_cast<BeginBorrowInst>(user)) {
817
+ if (bbi->isLexical ())
818
+ return true ;
819
+ }
820
+ }
821
+ return false ;
822
+ }
823
+
811
824
// / If \p value is a an existential or enum, then return the existential or enum
812
825
// / operand. These operations are always rewritten by the UseRewriter and always
813
826
// / reuse the same storage as their operand. Note that if the operation's result
@@ -834,6 +847,9 @@ static Operand *getReusedStorageOperand(SILValue value) {
834
847
return &cast<SingleValueInstruction>(value)->getOperandRef (0 );
835
848
836
849
case ValueKind::SILPhiArgument: {
850
+ if (needsLexicalAllocStack (value)) {
851
+ return nullptr ;
852
+ }
837
853
if (auto *term = cast<SILPhiArgument>(value)->getTerminatorForResult ()) {
838
854
if (auto *switchEnum = dyn_cast<SwitchEnumInst>(term)) {
839
855
return &switchEnum->getAllOperands ()[0 ];
@@ -2931,20 +2947,34 @@ void UseRewriter::visitSwitchEnumInst(SwitchEnumInst * switchEnum) {
2931
2947
assert (caseBB->getArguments ().size () == 1 );
2932
2948
SILArgument *caseArg = caseBB->getArguments ()[0 ];
2933
2949
2934
- assert (&switchEnum->getOperandRef (0 ) == getReusedStorageOperand (caseArg));
2935
2950
assert (caseDecl->hasAssociatedValues () && " caseBB has a payload argument" );
2936
2951
2937
2952
SILBuilder caseBuilder = pass.getBuilder (caseBB->begin ());
2938
- auto *caseAddr =
2953
+ auto *enumDataAddr =
2939
2954
caseBuilder.createUncheckedTakeEnumDataAddr (loc, enumAddr, caseDecl);
2955
+
2956
+ SILValue addrToLoad;
2957
+ if (needsLexicalAllocStack (caseArg)) {
2958
+ // This case has a variable bound to its payload. To preserve the lexical
2959
+ // lifetime that variable introduces, it must be moved into the
2960
+ // alloc_stack created for it, which will subsequently be marked lexical.
2961
+ assert (!getReusedStorageOperand (caseArg));
2962
+ auto caseAddr = pass.valueStorageMap .getStorage (caseArg).storageAddress ;
2963
+ caseBuilder.createCopyAddr (loc, enumDataAddr, caseAddr, IsTake,
2964
+ IsInitialization);
2965
+ addrToLoad = caseAddr;
2966
+ } else {
2967
+ assert (&switchEnum->getOperandRef (0 ) == getReusedStorageOperand (caseArg));
2968
+ addrToLoad = enumDataAddr;
2969
+ }
2940
2970
auto *caseLoad = caseBuilder.createTrivialLoadOr (
2941
- loc, caseAddr , LoadOwnershipQualifier::Take);
2971
+ loc, addrToLoad , LoadOwnershipQualifier::Take);
2942
2972
caseArg->replaceAllUsesWith (caseLoad);
2943
2973
if (caseArg->getType ().isAddressOnly (*pass.function )) {
2944
2974
// Remap caseArg to the new dummy load which will be deleted during
2945
2975
// deleteRewrittenInstructions.
2946
2976
pass.valueStorageMap .replaceValue (caseArg, caseLoad);
2947
- markRewritten (caseLoad, caseAddr );
2977
+ markRewritten (caseLoad, addrToLoad );
2948
2978
}
2949
2979
caseBB->eraseArgument (0 );
2950
2980
};
0 commit comments