@@ -1398,6 +1398,25 @@ getManagedSubobject(SILGenFunction &SGF, SILValue value,
13981398 llvm_unreachable (" covered switch" );
13991399}
14001400
1401+ // / Given that we've broken down a source value into this subobject,
1402+ // / and that we were supposed to use the given consumption rules on
1403+ // / it, construct an appropriate managed value.
1404+ static ConsumableManagedValue
1405+ getManagedSubobject (SILGenFunction &SGF, ManagedValue value,
1406+ CastConsumptionKind consumption) {
1407+ switch (consumption) {
1408+ case CastConsumptionKind::BorrowAlways:
1409+ case CastConsumptionKind::CopyOnSuccess:
1410+ return {value.unmanagedBorrow (), consumption};
1411+ case CastConsumptionKind::TakeAlways:
1412+ case CastConsumptionKind::TakeOnSuccess: {
1413+ auto loc = RegularLocation::getAutoGeneratedLocation ();
1414+ return {value.ensurePlusOne (SGF, loc), consumption};
1415+ }
1416+ }
1417+ llvm_unreachable (" covered switch" );
1418+ }
1419+
14011420static ConsumableManagedValue
14021421emitReabstractedSubobject (SILGenFunction &SGF, SILLocation loc,
14031422 ConsumableManagedValue value,
@@ -2064,29 +2083,34 @@ void PatternMatchEmission::emitEnumElementDispatch(
20642083 }
20652084
20662085 // Emit the switch_enum_addr instruction.
2067- SILValue srcValue = src.getFinalManagedValue ().forward (SGF);
2068- SGF.B .createSwitchEnumAddr (loc, srcValue, blocks.getDefaultBlock (),
2086+ //
2087+ // NOTE: switch_enum_addr does not actually consume the underlying value.
2088+ SGF.B .createSwitchEnumAddr (loc, src.getValue (), blocks.getDefaultBlock (),
20692089 blocks.getCaseBlocks (), blocks.getCounts (),
20702090 defaultCaseCount);
20712091
20722092 // Okay, now emit all the cases.
2073- blocks.forEachCase ([&](EnumElementDecl *elt , SILBasicBlock *caseBB,
2093+ blocks.forEachCase ([&](EnumElementDecl *eltDecl , SILBasicBlock *caseBB,
20742094 const CaseInfo &caseInfo) {
20752095 SILLocation loc = caseInfo.FirstMatcher ;
20762096 auto &specializedRows = caseInfo.SpecializedRows ;
20772097
20782098 SGF.B .setInsertionPoint (caseBB);
20792099
2100+ // We need to make sure our cleanup stays around long enough for us to emit
2101+ // our destroy, so setup a cleanup state restoration scope for each case.
2102+ CleanupStateRestorationScope srcScope (SGF.Cleanups );
2103+ forwardIntoIrrefutableSubtree (SGF, srcScope, src);
2104+
20802105 // We're in conditionally-executed code; enter a scope.
20812106 Scope scope (SGF.Cleanups , CleanupLocation::get (loc));
2082-
2107+
20832108 // Create a BB argument or 'unchecked_take_enum_data_addr'
20842109 // instruction to receive the enum case data if it has any.
2085-
20862110 SILType eltTy;
20872111 bool hasElt = false ;
2088- if (elt ->hasAssociatedValues ()) {
2089- eltTy = src.getType ().getEnumElementType (elt , SGF.SGM .M ,
2112+ if (eltDecl ->hasAssociatedValues ()) {
2113+ eltTy = src.getType ().getEnumElementType (eltDecl , SGF.SGM .M ,
20902114 SGF.getTypeExpansionContext ());
20912115 hasElt = !eltTy.getASTType ()->isVoid ();
20922116 }
@@ -2108,6 +2132,15 @@ void PatternMatchEmission::emitEnumElementDispatch(
21082132 }
21092133 }
21102134
2135+ // Forward src along this path so we don't emit a destroy_addr on our
2136+ // subject value for this case.
2137+ //
2138+ // FIXME: Do we actually want to do this? SILGen tests today assume this
2139+ // pattern. It might be worth leaving the destroy_addr there to create
2140+ // additional liveness information. For now though, we maintain the
2141+ // current behavior.
2142+ src.getFinalManagedValue ().forward (SGF);
2143+
21112144 SILValue result;
21122145 if (hasNonAny) {
21132146 result = SGF.emitEmptyTuple (loc);
@@ -2132,16 +2165,18 @@ void PatternMatchEmission::emitEnumElementDispatch(
21322165 eltConsumption = CastConsumptionKind::TakeAlways;
21332166 }
21342167
2135- SILValue eltValue;
2168+ ManagedValue eltValue;
21362169 // We can only project destructively from an address-only enum, so
21372170 // copy the value if we can't consume it.
21382171 // TODO: Should have a more efficient way to copy payload
21392172 // nondestructively from an enum.
21402173 switch (eltConsumption) {
2141- case CastConsumptionKind::TakeAlways:
2142- eltValue =
2143- SGF.B .createUncheckedTakeEnumDataAddr (loc, srcValue, elt, eltTy);
2174+ case CastConsumptionKind::TakeAlways: {
2175+ auto finalValue = src.getFinalManagedValue ();
2176+ eltValue = SGF.B .createUncheckedTakeEnumDataAddr (loc, finalValue,
2177+ eltDecl, eltTy);
21442178 break ;
2179+ }
21452180 case CastConsumptionKind::BorrowAlways:
21462181 // If we reach this point, we know that we have a loadable
21472182 // element type from an enum with mixed address
@@ -2150,11 +2185,15 @@ void PatternMatchEmission::emitEnumElementDispatch(
21502185 // address only types do not support BorrowAlways.
21512186 llvm_unreachable (" not allowed" );
21522187 case CastConsumptionKind::CopyOnSuccess: {
2153- auto copy = SGF.emitTemporaryAllocation (loc, srcValue->getType ());
2154- SGF.B .createCopyAddr (loc, srcValue, copy, IsNotTake, IsInitialization);
2188+ auto temp = SGF.emitTemporary (loc, SGF.getTypeLowering (src.getType ()));
2189+ SGF.B .createCopyAddr (loc, src.getValue (), temp->getAddress (), IsNotTake,
2190+ IsInitialization);
2191+ temp->finishInitialization (SGF);
2192+
21552193 // We can always take from the copy.
21562194 eltConsumption = CastConsumptionKind::TakeAlways;
2157- eltValue = SGF.B .createUncheckedTakeEnumDataAddr (loc, copy, elt, eltTy);
2195+ eltValue = SGF.B .createUncheckedTakeEnumDataAddr (
2196+ loc, temp->getManagedAddress (), eltDecl, eltTy);
21582197 break ;
21592198 }
21602199
@@ -2170,23 +2209,22 @@ void PatternMatchEmission::emitEnumElementDispatch(
21702209 if (eltTL->isLoadable ()) {
21712210 // If we do not have a loadable value, just use getManagedSubObject
21722211 // Load a loadable data value.
2173- auto managedEltValue = ManagedValue::forUnmanaged (eltValue);
21742212 if (eltConsumption == CastConsumptionKind::CopyOnSuccess) {
2175- managedEltValue = SGF.B .createLoadBorrow (loc, managedEltValue );
2213+ eltValue = SGF.B .createLoadBorrow (loc, eltValue );
21762214 eltConsumption = CastConsumptionKind::BorrowAlways;
21772215 } else {
21782216 assert (eltConsumption == CastConsumptionKind::TakeAlways);
2179- managedEltValue = SGF.B .createLoadTake (loc, managedEltValue );
2217+ eltValue = SGF.B .createLoadTake (loc, eltValue );
21802218 }
2181- origCMV = {managedEltValue , eltConsumption};
2219+ origCMV = {eltValue , eltConsumption};
21822220 } else {
2183- origCMV = getManagedSubobject (SGF, eltValue, *eltTL, eltConsumption);
2221+ origCMV = getManagedSubobject (SGF, eltValue, eltConsumption);
21842222 }
21852223
21862224 eltCMV = origCMV;
21872225
21882226 // If the payload is boxed, project it.
2189- if (elt ->isIndirect () || elt ->getParentEnum ()->isIndirect ()) {
2227+ if (eltDecl ->isIndirect () || eltDecl ->getParentEnum ()->isIndirect ()) {
21902228 ManagedValue boxedValue =
21912229 SGF.B .createProjectBox (loc, origCMV.getFinalManagedValue (), 0 );
21922230 eltTL = &SGF.getTypeLowering (boxedValue.getType ());
@@ -2202,14 +2240,14 @@ void PatternMatchEmission::emitEnumElementDispatch(
22022240
22032241 // Reabstract to the substituted type, if needed.
22042242 CanType substEltTy =
2205- sourceType->getTypeOfMember (SGF.SGM .M .getSwiftModule (), elt ,
2206- elt ->getArgumentInterfaceType ())
2243+ sourceType->getTypeOfMember (SGF.SGM .M .getSwiftModule (), eltDecl ,
2244+ eltDecl ->getArgumentInterfaceType ())
22072245 ->getCanonicalType ();
22082246
22092247 AbstractionPattern origEltTy =
2210- (elt ->getParentEnum ()->isOptionalDecl ()
2248+ (eltDecl ->getParentEnum ()->isOptionalDecl ()
22112249 ? AbstractionPattern (substEltTy)
2212- : SGF.SGM .M .Types .getAbstractionPattern (elt ));
2250+ : SGF.SGM .M .Types .getAbstractionPattern (eltDecl ));
22132251
22142252 eltCMV = emitReabstractedSubobject (SGF, loc, eltCMV, *eltTL,
22152253 origEltTy, substEltTy);
0 commit comments