Skip to content

Commit 8db31d5

Browse files
committed
SILGen: Complete initialization of FinalContext in ConversionInitialization::tryPeephole
The callers to ConversionInitialization::tryPeephole assume that, if the conversion peephole succeeded, that the peepholed result was fully emitted into the initialization. However, if the ConversionInitialization sat on top of an in-memory initialization, then tryPeephole would only set the value of the ConversionInitialization, without forwarding the value into the underlying initialization, causing code generation to proceed leaving the underlying memory uninitialized. This problem becomes exposed now when literal closures are emitted with a return value that is indirectly returned and also reabstracted, and the return expression undergoes a ping-pong reabstraction pair: we see through the conversions and peephole away the reabstractions, but fail to emplace the result in the indirect return slot. Fixes rdar://92654098
1 parent 1f5b8ae commit 8db31d5

File tree

3 files changed

+107
-78
lines changed

3 files changed

+107
-78
lines changed

lib/SILGen/Conversion.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -231,13 +231,6 @@ canPeepholeConversions(SILGenFunction &SGF,
231231
const Conversion &outerConversion,
232232
const Conversion &innerConversion);
233233

234-
ManagedValue emitPeepholedConversions(SILGenFunction &SGF, SILLocation loc,
235-
const Conversion &outerConversion,
236-
const Conversion &innerConversion,
237-
ConversionPeepholeHint hint,
238-
SGFContext C,
239-
ValueProducerRef produceValue);
240-
241234
/// An initialization where we ultimately want to apply a conversion to
242235
/// the value before completing the initialization.
243236
///
@@ -354,8 +347,6 @@ class ConvertingInitialization final : public Initialization {
354347
void finishInitialization(SILGenFunction &SGF) override {
355348
assert(getState() == Initialized);
356349
State = Finished;
357-
if (OwnedSubInitialization)
358-
OwnedSubInitialization->finishInitialization(SGF);
359350
}
360351
};
361352

lib/SILGen/SILGenConvert.cpp

Lines changed: 75 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,6 +1074,69 @@ ConvertingInitialization::finishEmission(SILGenFunction &SGF,
10741074
llvm_unreachable("bad state");
10751075
}
10761076

1077+
static ManagedValue
1078+
emitPeepholedConversions(SILGenFunction &SGF, SILLocation loc,
1079+
const Conversion &outerConversion,
1080+
const Conversion &innerConversion,
1081+
ConversionPeepholeHint hint,
1082+
SGFContext C,
1083+
ValueProducerRef produceOrigValue) {
1084+
auto produceValue = [&](SGFContext C) {
1085+
if (!hint.isForced()) {
1086+
return produceOrigValue(SGF, loc, C);
1087+
}
1088+
1089+
auto value = produceOrigValue(SGF, loc, SGFContext());
1090+
auto &optTL = SGF.getTypeLowering(value.getType());
1091+
// isForceUnwrap is hardcoded true because hint.isForced() is only
1092+
// set by implicit force unwraps.
1093+
return SGF.emitCheckedGetOptionalValueFrom(loc, value,
1094+
/*isForceUnwrap*/ true,
1095+
optTL, C);
1096+
};
1097+
1098+
auto getBridgingSourceType = [&] {
1099+
CanType sourceType = innerConversion.getBridgingSourceType();
1100+
if (hint.isForced())
1101+
sourceType = sourceType.getOptionalObjectType();
1102+
return sourceType;
1103+
};
1104+
auto getBridgingResultType = [&] {
1105+
return outerConversion.getBridgingResultType();
1106+
};
1107+
auto getBridgingLoweredResultType = [&] {
1108+
return outerConversion.getBridgingLoweredResultType();
1109+
};
1110+
1111+
switch (hint.getKind()) {
1112+
case ConversionPeepholeHint::Identity:
1113+
return produceValue(C);
1114+
1115+
case ConversionPeepholeHint::BridgeToAnyObject: {
1116+
auto value = produceValue(SGFContext());
1117+
return SGF.emitNativeToBridgedValue(loc, value, getBridgingSourceType(),
1118+
getBridgingResultType(),
1119+
getBridgingLoweredResultType(), C);
1120+
}
1121+
1122+
case ConversionPeepholeHint::Subtype: {
1123+
// Otherwise, emit and convert.
1124+
// TODO: if the context allows +0, use it in more situations.
1125+
auto value = produceValue(SGFContext());
1126+
SILType loweredResultTy = getBridgingLoweredResultType();
1127+
1128+
// Nothing to do if the value already has the right representation.
1129+
if (value.getType().getObjectType() == loweredResultTy.getObjectType())
1130+
return value;
1131+
1132+
CanType sourceType = getBridgingSourceType();
1133+
CanType resultType = getBridgingResultType();
1134+
return SGF.emitTransformedValue(loc, value, sourceType, resultType, C);
1135+
}
1136+
}
1137+
llvm_unreachable("bad kind");
1138+
}
1139+
10771140
bool ConvertingInitialization::tryPeephole(SILGenFunction &SGF,
10781141
SILLocation loc,
10791142
ManagedValue origValue,
@@ -1104,6 +1167,15 @@ bool ConvertingInitialization::tryPeephole(SILGenFunction &SGF, SILLocation loc,
11041167
ManagedValue value = emitPeepholedConversions(SGF, loc, outerConversion,
11051168
innerConversion, *hint,
11061169
FinalContext, produceValue);
1170+
1171+
// The callers to tryPeephole assume that the initialization is ready to be
1172+
// finalized after returning. If this conversion sits on top of another
1173+
// initialization, forward the value into the underlying initialization and
1174+
// report the value as emitted in context.
1175+
if (FinalContext.getEmitInto() && !value.isInContext()) {
1176+
value.ensurePlusOne(SGF, loc).forwardInto(SGF, loc, FinalContext.getEmitInto());
1177+
value = ManagedValue::forInContext();
1178+
}
11071179
setConvertedValue(value);
11081180
return true;
11091181
}
@@ -1117,15 +1189,11 @@ void ConvertingInitialization::copyOrInitValueInto(SILGenFunction &SGF,
11171189
// TODO: take advantage of borrowed inputs?
11181190
if (!isInit) formalValue = formalValue.copy(SGF, loc);
11191191
State = Initialized;
1120-
SGFContext emissionContext = OwnedSubInitialization
1121-
? SGFContext() : FinalContext;
11221192

1123-
Value = TheConversion.emit(SGF, loc, formalValue, emissionContext);
1193+
Value = TheConversion.emit(SGF, loc, formalValue, FinalContext);
11241194

1125-
if (OwnedSubInitialization) {
1126-
OwnedSubInitialization->copyOrInitValueInto(SGF, loc,
1127-
Value,
1128-
isInit);
1195+
if (FinalContext.getEmitInto() && !Value.isInContext()) {
1196+
Value.forwardInto(SGF, loc, FinalContext.getEmitInto());
11291197
Value = ManagedValue::forInContext();
11301198
}
11311199
}
@@ -1512,65 +1580,3 @@ Lowering::canPeepholeConversions(SILGenFunction &SGF,
15121580
llvm_unreachable("bad kind");
15131581
}
15141582

1515-
ManagedValue
1516-
Lowering::emitPeepholedConversions(SILGenFunction &SGF, SILLocation loc,
1517-
const Conversion &outerConversion,
1518-
const Conversion &innerConversion,
1519-
ConversionPeepholeHint hint,
1520-
SGFContext C,
1521-
ValueProducerRef produceOrigValue) {
1522-
auto produceValue = [&](SGFContext C) {
1523-
if (!hint.isForced()) {
1524-
return produceOrigValue(SGF, loc, C);
1525-
}
1526-
1527-
auto value = produceOrigValue(SGF, loc, SGFContext());
1528-
auto &optTL = SGF.getTypeLowering(value.getType());
1529-
// isForceUnwrap is hardcoded true because hint.isForced() is only
1530-
// set by implicit force unwraps.
1531-
return SGF.emitCheckedGetOptionalValueFrom(loc, value,
1532-
/*isForceUnwrap*/ true,
1533-
optTL, C);
1534-
};
1535-
1536-
auto getBridgingSourceType = [&] {
1537-
CanType sourceType = innerConversion.getBridgingSourceType();
1538-
if (hint.isForced())
1539-
sourceType = sourceType.getOptionalObjectType();
1540-
return sourceType;
1541-
};
1542-
auto getBridgingResultType = [&] {
1543-
return outerConversion.getBridgingResultType();
1544-
};
1545-
auto getBridgingLoweredResultType = [&] {
1546-
return outerConversion.getBridgingLoweredResultType();
1547-
};
1548-
1549-
switch (hint.getKind()) {
1550-
case ConversionPeepholeHint::Identity:
1551-
return produceValue(C);
1552-
1553-
case ConversionPeepholeHint::BridgeToAnyObject: {
1554-
auto value = produceValue(SGFContext());
1555-
return SGF.emitNativeToBridgedValue(loc, value, getBridgingSourceType(),
1556-
getBridgingResultType(),
1557-
getBridgingLoweredResultType(), C);
1558-
}
1559-
1560-
case ConversionPeepholeHint::Subtype: {
1561-
// Otherwise, emit and convert.
1562-
// TODO: if the context allows +0, use it in more situations.
1563-
auto value = produceValue(SGFContext());
1564-
SILType loweredResultTy = getBridgingLoweredResultType();
1565-
1566-
// Nothing to do if the value already has the right representation.
1567-
if (value.getType().getObjectType() == loweredResultTy.getObjectType())
1568-
return value;
1569-
1570-
CanType sourceType = getBridgingSourceType();
1571-
CanType resultType = getBridgingResultType();
1572-
return SGF.emitTransformedValue(loc, value, sourceType, resultType, C);
1573-
}
1574-
}
1575-
llvm_unreachable("bad kind");
1576-
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %target-swift-emit-silgen -verify %s
2+
3+
fileprivate typealias Closure = () -> Void
4+
5+
func crash1() {
6+
let closure1: Closure? = nil
7+
let closure2: Closure? = nil
8+
let closure3: Closure? = nil
9+
print("Closures: \(String(describing: closure1)), \(String(describing: closure2)), \(String(describing: closure3))")
10+
11+
let closure = closure1 ?? closure2 ?? closure3
12+
13+
print("\(#line): \(String(describing: closure))")
14+
closure?() // <- EXC_BAD_ACCESS
15+
assert(closure == nil)
16+
}
17+
18+
func crash2() {
19+
let closure1: Closure? = nil
20+
let closure2: Closure? = nil
21+
let closure3: Closure? = { }
22+
print("Closures: \(String(describing: closure1)), \(String(describing: closure2)), \(String(describing: closure3))")
23+
24+
let closure = closure1 ?? closure2 ?? closure3
25+
26+
print("\(#line): \(String(describing: closure))")
27+
closure?() // <- EXC_BAD_ACCESS
28+
assert(closure != nil)
29+
}
30+
31+
crash1()
32+
crash2()

0 commit comments

Comments
 (0)