Skip to content

Commit 401cd64

Browse files
committed
[IRGen] Apply correct type to conversion for direct values and erorrs with typed throws
rdar://144719032 When converting the combined result back to the actual types when directly returning typed errors, in case the error or result value was a single value smaller then pointer size and the combined value was larger, the value was converted to the combined type instead of the actual type, making it a no-op, which caused undefined behavior when writing the value to the coerced alloca.
1 parent e066bb2 commit 401cd64

File tree

3 files changed

+85
-7
lines changed

3 files changed

+85
-7
lines changed

lib/IRGen/GenCall.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4534,8 +4534,8 @@ void CallEmission::emitToUnmappedExplosionWithDirectTypedError(
45344534

45354535
Explosion errorExplosion;
45364536
if (!errorSchema.empty()) {
4537-
if (auto *structTy =
4538-
dyn_cast<llvm::StructType>(errorSchema.getExpandedType(IGF.IGM))) {
4537+
auto *expandedType = errorSchema.getExpandedType(IGF.IGM);
4538+
if (auto *structTy = dyn_cast<llvm::StructType>(expandedType)) {
45394539
for (unsigned i = 0, e = structTy->getNumElements(); i < e; ++i) {
45404540
llvm::Value *elt = values[combined.errorValueMapping[i]];
45414541
auto *nativeTy = structTy->getElementType(i);
@@ -4545,7 +4545,7 @@ void CallEmission::emitToUnmappedExplosionWithDirectTypedError(
45454545
} else {
45464546
auto *converted =
45474547
convertForDirectError(IGF, values[combined.errorValueMapping[0]],
4548-
combined.combinedTy, /*forExtraction*/ true);
4548+
expandedType, /*forExtraction*/ true);
45494549
errorExplosion.add(converted);
45504550
}
45514551

@@ -4558,17 +4558,17 @@ void CallEmission::emitToUnmappedExplosionWithDirectTypedError(
45584558
// If the regular result type is void, there is nothing to explode
45594559
if (!nativeSchema.empty()) {
45604560
Explosion resultExplosion;
4561-
if (auto *structTy =
4562-
dyn_cast<llvm::StructType>(nativeSchema.getExpandedType(IGF.IGM))) {
4561+
auto *expandedType = nativeSchema.getExpandedType(IGF.IGM);
4562+
if (auto *structTy = dyn_cast<llvm::StructType>(expandedType)) {
45634563
for (unsigned i = 0, e = structTy->getNumElements(); i < e; ++i) {
45644564
auto *nativeTy = structTy->getElementType(i);
45654565
auto *converted = convertForDirectError(IGF, values[i], nativeTy,
45664566
/*forExtraction*/ true);
45674567
resultExplosion.add(converted);
45684568
}
45694569
} else {
4570-
auto *converted = convertForDirectError(
4571-
IGF, values[0], combined.combinedTy, /*forExtraction*/ true);
4570+
auto *converted = convertForDirectError(IGF, values[0], expandedType,
4571+
/*forExtraction*/ true);
45724572
resultExplosion.add(converted);
45734573
}
45744574
out = nativeSchema.mapFromNative(IGF.IGM, IGF, resultExplosion, resultType);

test/IRGen/typed_throws.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,3 +310,42 @@ func callAsyncIndirectResult<A>(p: any AsyncGenProto<A>, x: Int) async throws(Sm
310310
return try await p.fn(arg: x)
311311
}
312312

313+
@inline(never)
314+
func smallResultLargerError() throws(SmallError) -> Int8? {
315+
return 10
316+
}
317+
318+
// CHECK: [[COERCED:%.*]] = alloca { i16 }, align 2
319+
// CHECK: [[RES:%.*]] = call swiftcc i64 @"$s12typed_throws22smallResultLargerErrors4Int8VSgyAA05SmallF0VYKF"(ptr swiftself undef, ptr noalias nocapture swifterror dereferenceable(8) %swifterror)
320+
// CHECK: [[TRUNC:%.*]] = trunc i64 [[RES]] to i16
321+
// CHECK: [[COERCED_PTR:%.*]] = getelementptr inbounds { i16 }, ptr [[COERCED]], i32 0, i32 0
322+
// CHECK: store i16 [[TRUNC]], ptr [[COERCED_PTR]], align 2
323+
func callSmallResultLargerError() {
324+
let res = try! smallResultLargerError()
325+
precondition(res! == 10)
326+
}
327+
328+
enum UInt8OptSingletonError: Error {
329+
case a(Int8?)
330+
}
331+
332+
@inline(never)
333+
func smallErrorLargerResult() throws(UInt8OptSingletonError) -> Int {
334+
throw .a(10)
335+
}
336+
337+
// CHECK: [[COERCED:%.*]] = alloca { i16 }, align 2
338+
// CHECK: [[RES:%.*]] = call swiftcc i64 @"$s12typed_throws22smallErrorLargerResultSiyAA017UInt8OptSingletonD0OYKF"(ptr swiftself undef, ptr noalias nocapture swifterror dereferenceable(8) %swifterror)
339+
// CHECK: [[TRUNC:%.*]] = trunc i64 [[RES]] to i16
340+
// CHECK: [[COERCED_PTR:%.*]] = getelementptr inbounds { i16 }, ptr [[COERCED]], i32 0, i32 0
341+
// CHECK: store i16 [[TRUNC]], ptr [[COERCED_PTR]], align 2
342+
func callSmallErrorLargerResult() {
343+
do {
344+
_ = try smallErrorLargerResult()
345+
} catch {
346+
switch error {
347+
case .a(let x):
348+
precondition(x! == 10)
349+
}
350+
}
351+
}

test/Interpreter/typed_throws_abi.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,40 @@ func checkAsync() async {
285285
await invoke { try await impl.nonMatching_f1(false) }
286286
}
287287

288+
enum SmallError: Error {
289+
case a(Int)
290+
}
291+
292+
@inline(never)
293+
func smallResultLargerError() throws(SmallError) -> Int8? {
294+
return 10
295+
}
296+
297+
func callSmallResultLargerError() {
298+
let res = try! smallResultLargerError()
299+
print("Result is: \(String(describing: res))")
300+
}
301+
302+
enum UInt8OptSingletonError: Error {
303+
case a(Int8?)
304+
}
305+
306+
@inline(never)
307+
func smallErrorLargerResult() throws(UInt8OptSingletonError) -> Int {
308+
throw .a(10)
309+
}
310+
311+
func callSmallErrorLargerResult() {
312+
do {
313+
_ = try smallErrorLargerResult()
314+
} catch {
315+
switch error {
316+
case .a(let x):
317+
print("Error value is: \(String(describing: x))")
318+
}
319+
}
320+
}
321+
288322
enum MyError: Error {
289323
case x
290324
case y
@@ -315,5 +349,10 @@ public struct Main {
315349
await checkAsync()
316350
// CHECK: Arg is 10
317351
print(try! await callAsyncIndirectResult(p: AsyncGenProtoImpl(), x: 10))
352+
353+
// CHECK: Result is: Optional(10)
354+
callSmallResultLargerError()
355+
// CHECK: Error value is: Optional(10)
356+
callSmallErrorLargerResult()
318357
}
319358
}

0 commit comments

Comments
 (0)