Skip to content

Commit 583f127

Browse files
committedSep 18, 2023
fix [SR-14882]: Assertion failed: (!concreteBuffer && "concrete buffer already formed?!")
The problem was that in the by-address emission, we were calling `getAddressForInPlaceInitialization` twice, triggering the assert. The first time in `emitExprInto` for the normal result case. The second time to obtain the address again when generating the catch block to inject a `.none` into that same address. This patch does a light refactoring to more closely mirror `visitOptionalEvaluationExpr`, which avoids calling the asserting method. fixes rdar://80277465
1 parent cda0fd4 commit 583f127

File tree

3 files changed

+132
-19
lines changed

3 files changed

+132
-19
lines changed
 

‎lib/SILGen/SILGenExpr.cpp

+25-19
Original file line numberDiff line numberDiff line change
@@ -1184,18 +1184,27 @@ RValue RValueEmitter::visitOptionalTryExpr(OptionalTryExpr *E, SGFContext C) {
11841184

11851185
// Form the optional using address operations if the type is address-only or
11861186
// if we already have an address to use.
1187-
bool isByAddress = usingProvidedContext || optTL.isAddressOnly();
1187+
bool isByAddress = ((usingProvidedContext || optTL.isAddressOnly()) &&
1188+
SGF.silConv.useLoweredAddresses());
11881189

11891190
std::unique_ptr<TemporaryInitialization> optTemp;
1190-
if (!usingProvidedContext && isByAddress) {
1191+
if (!isByAddress) {
1192+
// If the caller produced a context for us, but we're not going
1193+
// to use it, make sure we don't.
1194+
optInit = nullptr;
1195+
} else if (!usingProvidedContext) {
11911196
// Allocate the temporary for the Optional<T> if we didn't get one from the
1192-
// context.
1197+
// context. This needs to happen outside of the cleanups scope we're about
1198+
// to push.
11931199
optTemp = SGF.emitTemporary(E, optTL);
11941200
optInit = optTemp.get();
1195-
} else if (!usingProvidedContext) {
1196-
// If the caller produced a context for us, but we can't use it, then don't.
1197-
optInit = nullptr;
11981201
}
1202+
assert(isByAddress == (optInit != nullptr));
1203+
1204+
// Acquire the address to emit into outside of the cleanups scope.
1205+
SILValue optAddr;
1206+
if (isByAddress)
1207+
optAddr = optInit->getAddressForInPlaceInitialization(SGF, E);
11991208

12001209
FullExpr localCleanups(SGF.Cleanups, E);
12011210

@@ -1208,8 +1217,7 @@ RValue RValueEmitter::visitOptionalTryExpr(OptionalTryExpr *E, SGFContext C) {
12081217
SILValue branchArg;
12091218
if (shouldWrapInOptional) {
12101219
if (isByAddress) {
1211-
assert(optInit);
1212-
SILValue optAddr = optInit->getAddressForInPlaceInitialization(SGF, E);
1220+
assert(optAddr);
12131221
SGF.emitInjectOptionalValueInto(E, E->getSubExpr(), optAddr, optTL);
12141222
} else {
12151223
ManagedValue subExprValue = SGF.emitRValueAsSingleValue(E->getSubExpr());
@@ -1219,8 +1227,11 @@ RValue RValueEmitter::visitOptionalTryExpr(OptionalTryExpr *E, SGFContext C) {
12191227
}
12201228
else {
12211229
if (isByAddress) {
1222-
assert(optInit);
1223-
SGF.emitExprInto(E->getSubExpr(), optInit);
1230+
assert(optAddr);
1231+
// We've already computed the address where we want the result.
1232+
KnownAddressInitialization normalInit(optAddr);
1233+
SGF.emitExprInto(E->getSubExpr(), &normalInit);
1234+
normalInit.finishInitialization(SGF);
12241235
} else {
12251236
ManagedValue subExprValue = SGF.emitRValueAsSingleValue(E->getSubExpr());
12261237
branchArg = subExprValue.forward(SGF);
@@ -1238,10 +1249,8 @@ RValue RValueEmitter::visitOptionalTryExpr(OptionalTryExpr *E, SGFContext C) {
12381249
if (!isByAddress)
12391250
return RValue(SGF, E,
12401251
SGF.emitManagedRValueWithCleanup(branchArg, optTL));
1241-
1242-
if (shouldWrapInOptional) {
1243-
optInit->finishInitialization(SGF);
1244-
}
1252+
1253+
optInit->finishInitialization(SGF);
12451254

12461255
// If we emitted into the provided context, we're done.
12471256
if (usingProvidedContext)
@@ -1268,8 +1277,7 @@ RValue RValueEmitter::visitOptionalTryExpr(OptionalTryExpr *E, SGFContext C) {
12681277
catchCleanups.pop();
12691278

12701279
if (isByAddress) {
1271-
SGF.emitInjectOptionalNothingInto(E,
1272-
optInit->getAddressForInPlaceInitialization(SGF, E), optTL);
1280+
SGF.emitInjectOptionalNothingInto(E, optAddr, optTL);
12731281
SGF.B.createBranch(E, contBB);
12741282
} else {
12751283
auto branchArg = SGF.getOptionalNoneValue(E, optTL);
@@ -1287,9 +1295,7 @@ RValue RValueEmitter::visitOptionalTryExpr(OptionalTryExpr *E, SGFContext C) {
12871295
return RValue(SGF, E, SGF.emitManagedRValueWithCleanup(arg, optTL));
12881296
}
12891297

1290-
if (shouldWrapInOptional) {
1291-
optInit->finishInitialization(SGF);
1292-
}
1298+
optInit->finishInitialization(SGF);
12931299

12941300
// If we emitted into the provided context, we're done.
12951301
if (usingProvidedContext)

‎test/Runtime/optional_try.swift

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// RUN: %target-run-simple-swift -sil-verify-all | %FileCheck %s
2+
// REQUIRES: executable_test
3+
4+
enum Bad: Error {
5+
case err
6+
case custom(String)
7+
}
8+
9+
func erase<T>(_ val: T) -> Any {
10+
return val as Any
11+
}
12+
13+
class Klass {}
14+
15+
typealias MaybeString = Result<String, Error>
16+
typealias MaybeKlass = Result<Klass, Error>
17+
typealias MaybeInt = Result<Int, Error>
18+
typealias MaybeNumbers = Result<[Int], Error>
19+
20+
////////
21+
// NOTE: Do _not_ heed the warnings about implicit coercions to Any.
22+
// That's an important part of this test's coverage!
23+
////////
24+
// -- throwing --
25+
// CHECK: nil
26+
print( try? MaybeString.failure(Bad.err).get() )
27+
28+
// CHECK: nil
29+
print( try? MaybeKlass.failure(Bad.custom("doggo")).get() )
30+
31+
// CHECK: nil
32+
print( try? MaybeInt.failure(Bad.err).get() )
33+
34+
// CHECK: nil
35+
print( try? MaybeNumbers.failure(Bad.err).get() )
36+
37+
// CHECK: nil
38+
print(erase( try? MaybeNumbers.failure(Bad.err).get() ))
39+
40+
// -- normal --
41+
// CHECK: Optional("catto")
42+
print( try? MaybeString.success("catto").get() )
43+
44+
// CHECK: Optional(main.Klass)
45+
print( try? MaybeKlass.success(Klass()).get() )
46+
47+
// CHECK: Optional(3)
48+
print( try? MaybeInt.success(3).get() )
49+
50+
// CHECK: Optional([4, 8, 15, 16, 23, 42])
51+
print( try? MaybeNumbers.success([4, 8, 15, 16, 23, 42]).get() )
52+
53+
// CHECK: Optional([0, 1, 1, 2, 3])
54+
print(erase( try? MaybeNumbers.success([0, 1, 1, 2, 3]).get() ))

‎test/SILGen/optional.swift

+53
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,56 @@ func implicit_iuo_unwrap_sourceLocation(_ value: Int!) {
161161
use_unwrapped(value)
162162
#sourceLocation() // reset
163163
}
164+
165+
166+
// CHECK-LABEL: sil hidden [ossa] @$s8optional0A20_to_existential_castyyF : $@convention(thin) () -> () {
167+
// CHECK: bb0:
168+
// CHECK: [[MEM:%.*]] = alloc_stack $Any
169+
// CHECK: [[ADDR:%.*]] = init_existential_addr [[MEM]] : $*Any, $Optional<Int>
170+
// CHECK: [[PAYLOAD_ADDR:%.*]] = init_enum_data_addr [[ADDR]] : $*Optional<Int>, #Optional.some!enumelt
171+
// CHECK: [[CLOSURE:%.*]] = function_ref @$s8optional0A20_to_existential_castyyFSiyKXEfU_ : $@convention(thin) () -> (Int, @error any Error)
172+
// CHECK: try_apply [[CLOSURE]]() : $@convention(thin) () -> (Int, @error any Error), normal bb1, error bb3
173+
174+
// CHECK: bb1([[RESULT:%.*]] : $Int):
175+
// CHECK: store [[RESULT]] to [trivial] [[PAYLOAD_ADDR]] : $*Int
176+
// CHECK: inject_enum_addr [[ADDR]] : $*Optional<Int>, #Optional.some!enumelt
177+
// CHECK: br bb2
178+
179+
// CHECK: bb2:
180+
// CHECK-NEXT: destroy_addr [[MEM]] : $*Any
181+
// CHECK-NEXT: dealloc_stack [[MEM]] : $*Any
182+
// CHECK: return
183+
184+
// CHECK: bb3([[ERR:%.*]] : @owned $any Error):
185+
// CHECK: destroy_value [[ERR]] : $any Error
186+
// CHECK: inject_enum_addr [[ADDR]] : $*Optional<Int>, #Optional.none!enumelt
187+
// CHECK: br bb2
188+
// CHECK: }
189+
func optional_to_existential_cast() {
190+
let _: Any = try? {() throws in 3 }()
191+
}
192+
193+
// CHECK-LABEL: sil hidden [ossa] @$s8optional0A29_to_existential_cast_RETURNEDypyF : $@convention(thin) () -> @out Any {
194+
// CHECK: bb0([[MEM:%.*]] : $*Any):
195+
// CHECK: [[ADDR:%.*]] = init_existential_addr [[MEM]] : $*Any, $Optional<Int>
196+
// CHECK: [[PAYLOAD_ADDR:%.*]] = init_enum_data_addr [[ADDR]] : $*Optional<Int>, #Optional.some!enumelt
197+
// CHECK: [[CLOSURE:%.*]] = function_ref @$s8optional0A29_to_existential_cast_RETURNEDypyFSiyKXEfU_ : $@convention(thin) () -> (Int, @error any Error)
198+
// CHECK: try_apply [[CLOSURE]]() : $@convention(thin) () -> (Int, @error any Error), normal bb1, error bb3
199+
200+
// CHECK: bb1([[RESULT:%.*]] : $Int):
201+
// CHECK: store [[RESULT]] to [trivial] [[PAYLOAD_ADDR]] : $*Int
202+
// CHECK: inject_enum_addr [[ADDR]] : $*Optional<Int>, #Optional.some!enumelt
203+
// CHECK: br bb2
204+
205+
// CHECK: bb2:
206+
// CHECK-NEXT: = tuple ()
207+
// CHECK-NEXT: return
208+
209+
// CHECK: bb3([[ERR:%.*]] : @owned $any Error):
210+
// CHECK: destroy_value [[ERR]] : $any Error
211+
// CHECK: inject_enum_addr [[ADDR]] : $*Optional<Int>, #Optional.none!enumelt
212+
// CHECK: br bb2
213+
// CHECK: }
214+
func optional_to_existential_cast_RETURNED() -> Any {
215+
return try? {() throws in 3 }()
216+
}

0 commit comments

Comments
 (0)
Please sign in to comment.