@@ -1398,6 +1398,25 @@ getManagedSubobject(SILGenFunction &SGF, SILValue value,
1398
1398
llvm_unreachable (" covered switch" );
1399
1399
}
1400
1400
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
+
1401
1420
static ConsumableManagedValue
1402
1421
emitReabstractedSubobject (SILGenFunction &SGF, SILLocation loc,
1403
1422
ConsumableManagedValue value,
@@ -2064,29 +2083,34 @@ void PatternMatchEmission::emitEnumElementDispatch(
2064
2083
}
2065
2084
2066
2085
// 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 (),
2069
2089
blocks.getCaseBlocks (), blocks.getCounts (),
2070
2090
defaultCaseCount);
2071
2091
2072
2092
// Okay, now emit all the cases.
2073
- blocks.forEachCase ([&](EnumElementDecl *elt , SILBasicBlock *caseBB,
2093
+ blocks.forEachCase ([&](EnumElementDecl *eltDecl , SILBasicBlock *caseBB,
2074
2094
const CaseInfo &caseInfo) {
2075
2095
SILLocation loc = caseInfo.FirstMatcher ;
2076
2096
auto &specializedRows = caseInfo.SpecializedRows ;
2077
2097
2078
2098
SGF.B .setInsertionPoint (caseBB);
2079
2099
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
+
2080
2105
// We're in conditionally-executed code; enter a scope.
2081
2106
Scope scope (SGF.Cleanups , CleanupLocation::get (loc));
2082
-
2107
+
2083
2108
// Create a BB argument or 'unchecked_take_enum_data_addr'
2084
2109
// instruction to receive the enum case data if it has any.
2085
-
2086
2110
SILType eltTy;
2087
2111
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 ,
2090
2114
SGF.getTypeExpansionContext ());
2091
2115
hasElt = !eltTy.getASTType ()->isVoid ();
2092
2116
}
@@ -2108,6 +2132,15 @@ void PatternMatchEmission::emitEnumElementDispatch(
2108
2132
}
2109
2133
}
2110
2134
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
+
2111
2144
SILValue result;
2112
2145
if (hasNonAny) {
2113
2146
result = SGF.emitEmptyTuple (loc);
@@ -2132,16 +2165,18 @@ void PatternMatchEmission::emitEnumElementDispatch(
2132
2165
eltConsumption = CastConsumptionKind::TakeAlways;
2133
2166
}
2134
2167
2135
- SILValue eltValue;
2168
+ ManagedValue eltValue;
2136
2169
// We can only project destructively from an address-only enum, so
2137
2170
// copy the value if we can't consume it.
2138
2171
// TODO: Should have a more efficient way to copy payload
2139
2172
// nondestructively from an enum.
2140
2173
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);
2144
2178
break ;
2179
+ }
2145
2180
case CastConsumptionKind::BorrowAlways:
2146
2181
// If we reach this point, we know that we have a loadable
2147
2182
// element type from an enum with mixed address
@@ -2150,11 +2185,15 @@ void PatternMatchEmission::emitEnumElementDispatch(
2150
2185
// address only types do not support BorrowAlways.
2151
2186
llvm_unreachable (" not allowed" );
2152
2187
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
+
2155
2193
// We can always take from the copy.
2156
2194
eltConsumption = CastConsumptionKind::TakeAlways;
2157
- eltValue = SGF.B .createUncheckedTakeEnumDataAddr (loc, copy, elt, eltTy);
2195
+ eltValue = SGF.B .createUncheckedTakeEnumDataAddr (
2196
+ loc, temp->getManagedAddress (), eltDecl, eltTy);
2158
2197
break ;
2159
2198
}
2160
2199
@@ -2170,23 +2209,22 @@ void PatternMatchEmission::emitEnumElementDispatch(
2170
2209
if (eltTL->isLoadable ()) {
2171
2210
// If we do not have a loadable value, just use getManagedSubObject
2172
2211
// Load a loadable data value.
2173
- auto managedEltValue = ManagedValue::forUnmanaged (eltValue);
2174
2212
if (eltConsumption == CastConsumptionKind::CopyOnSuccess) {
2175
- managedEltValue = SGF.B .createLoadBorrow (loc, managedEltValue );
2213
+ eltValue = SGF.B .createLoadBorrow (loc, eltValue );
2176
2214
eltConsumption = CastConsumptionKind::BorrowAlways;
2177
2215
} else {
2178
2216
assert (eltConsumption == CastConsumptionKind::TakeAlways);
2179
- managedEltValue = SGF.B .createLoadTake (loc, managedEltValue );
2217
+ eltValue = SGF.B .createLoadTake (loc, eltValue );
2180
2218
}
2181
- origCMV = {managedEltValue , eltConsumption};
2219
+ origCMV = {eltValue , eltConsumption};
2182
2220
} else {
2183
- origCMV = getManagedSubobject (SGF, eltValue, *eltTL, eltConsumption);
2221
+ origCMV = getManagedSubobject (SGF, eltValue, eltConsumption);
2184
2222
}
2185
2223
2186
2224
eltCMV = origCMV;
2187
2225
2188
2226
// If the payload is boxed, project it.
2189
- if (elt ->isIndirect () || elt ->getParentEnum ()->isIndirect ()) {
2227
+ if (eltDecl ->isIndirect () || eltDecl ->getParentEnum ()->isIndirect ()) {
2190
2228
ManagedValue boxedValue =
2191
2229
SGF.B .createProjectBox (loc, origCMV.getFinalManagedValue (), 0 );
2192
2230
eltTL = &SGF.getTypeLowering (boxedValue.getType ());
@@ -2202,14 +2240,14 @@ void PatternMatchEmission::emitEnumElementDispatch(
2202
2240
2203
2241
// Reabstract to the substituted type, if needed.
2204
2242
CanType substEltTy =
2205
- sourceType->getTypeOfMember (SGF.SGM .M .getSwiftModule (), elt ,
2206
- elt ->getArgumentInterfaceType ())
2243
+ sourceType->getTypeOfMember (SGF.SGM .M .getSwiftModule (), eltDecl ,
2244
+ eltDecl ->getArgumentInterfaceType ())
2207
2245
->getCanonicalType ();
2208
2246
2209
2247
AbstractionPattern origEltTy =
2210
- (elt ->getParentEnum ()->isOptionalDecl ()
2248
+ (eltDecl ->getParentEnum ()->isOptionalDecl ()
2211
2249
? AbstractionPattern (substEltTy)
2212
- : SGF.SGM .M .Types .getAbstractionPattern (elt ));
2250
+ : SGF.SGM .M .Types .getAbstractionPattern (eltDecl ));
2213
2251
2214
2252
eltCMV = emitReabstractedSubobject (SGF, loc, eltCMV, *eltTL,
2215
2253
origEltTy, substEltTy);
0 commit comments