diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index fc053208df9d3..7ac5a2f7788bc 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -6503,3 +6503,46 @@ llvm::FunctionType *FunctionPointer::getFunctionType() const { return Sig.getType(); } + +void irgen::buildDirectError(IRGenFunction &IGF, + const CombinedResultAndErrorType &combined, + const NativeConventionSchema &errorSchema, + SILType silErrorTy, Explosion &errorResult, + bool forAsync, Explosion &out) { + if (combined.combinedTy->isVoidTy()) { + return; + } + + llvm::Value *expandedResult = llvm::UndefValue::get(combined.combinedTy); + auto *structTy = dyn_cast(combined.combinedTy); + + if (!errorSchema.getExpandedType(IGF.IGM)->isVoidTy()) { + auto nativeError = + errorSchema.mapIntoNative(IGF.IGM, IGF, errorResult, silErrorTy, false); + + if (structTy) { + for (unsigned i : combined.errorValueMapping) { + llvm::Value *elt = nativeError.claimNext(); + auto *nativeTy = structTy->getElementType(i); + elt = convertForDirectError(IGF, elt, nativeTy, + /*forExtraction*/ false); + expandedResult = IGF.Builder.CreateInsertValue(expandedResult, elt, i); + } + if (forAsync) { + IGF.emitAllExtractValues(expandedResult, structTy, out); + } else { + out = expandedResult; + } + } else if (!errorSchema.getExpandedType(IGF.IGM)->isVoidTy()) { + out = convertForDirectError(IGF, nativeError.claimNext(), + combined.combinedTy, + /*forExtraction*/ false); + } + } else { + if (forAsync && structTy) { + IGF.emitAllExtractValues(expandedResult, structTy, out); + } else { + out = expandedResult; + } + } +} diff --git a/lib/IRGen/GenCall.h b/lib/IRGen/GenCall.h index 84b68041a0efd..8584d7c35f8fa 100644 --- a/lib/IRGen/GenCall.h +++ b/lib/IRGen/GenCall.h @@ -278,6 +278,11 @@ namespace irgen { llvm::Value *convertForDirectError(IRGenFunction &IGF, llvm::Value *value, llvm::Type *toTy, bool forExtraction); + void buildDirectError(IRGenFunction &IGF, + const CombinedResultAndErrorType &combined, + const NativeConventionSchema &errorSchema, + SILType silErrorTy, Explosion &errorResult, + bool forAsync, Explosion &out); } // end namespace irgen } // end namespace swift diff --git a/lib/IRGen/GenThunk.cpp b/lib/IRGen/GenThunk.cpp index 82e1e1829eb8c..ff93d672be400 100644 --- a/lib/IRGen/GenThunk.cpp +++ b/lib/IRGen/GenThunk.cpp @@ -153,7 +153,8 @@ void IRGenThunk::prepareArguments() { auto &resultSchema = resultTI.nativeReturnValueSchema(IGF.IGM); if (resultSchema.requiresIndirect() || - errorSchema.shouldReturnTypedErrorIndirectly()) { + errorSchema.shouldReturnTypedErrorIndirectly() || + conv.hasIndirectSILResults()) { auto directTypedErrorAddr = original.takeLast(); IGF.setCalleeTypedErrorResultSlot(Address(directTypedErrorAddr, errorTI.getStorageType(), @@ -405,7 +406,21 @@ void IRGenThunk::emit() { errorArgValues.add(errorValue); emitAsyncReturn(IGF, *asyncLayout, origTy, errorArgValues.claimAll()); } else { - IGF.emitScalarReturn(IGF.CurFn->getReturnType(), *error); + if (!error->empty()) { + // Map the direct error explosion from the call back to the native + // explosion for the return. + SILType silErrorTy = conv.getSILErrorType(expansionContext); + auto &errorTI = IGF.IGM.getTypeInfo(silErrorTy); + auto &errorSchema = errorTI.nativeReturnValueSchema(IGF.IGM); + auto combined = + combineResultAndTypedErrorType(IGF.IGM, schema, errorSchema); + Explosion nativeAgg; + buildDirectError(IGF, combined, errorSchema, silErrorTy, *error, + /*forAsync*/ false, nativeAgg); + IGF.emitScalarReturn(IGF.CurFn->getReturnType(), nativeAgg); + } else { + IGF.emitScalarReturn(IGF.CurFn->getReturnType(), *error); + } } IGF.Builder.emitBlock(successBB); } else { diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 7c674e1ba9a1b..16e9c7086a427 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -4419,48 +4419,6 @@ void IRGenSILFunction::visitThrowInst(swift::ThrowInst *i) { getSILModule()); assert(!conv.hasIndirectSILErrorResults()); - auto buildDirectError = [=](const CombinedResultAndErrorType &combined, - const NativeConventionSchema &errorSchema, - SILType silErrorTy, Explosion &errorResult, - bool forAsync, Explosion &out) { - if (combined.combinedTy->isVoidTy()) { - return; - } - - llvm::Value *expandedResult = llvm::UndefValue::get(combined.combinedTy); - auto *structTy = dyn_cast(combined.combinedTy); - - if (!errorSchema.getExpandedType(IGM)->isVoidTy()) { - auto nativeError = - errorSchema.mapIntoNative(IGM, *this, errorResult, silErrorTy, false); - - if (structTy) { - for (unsigned i : combined.errorValueMapping) { - llvm::Value *elt = nativeError.claimNext(); - auto *nativeTy = structTy->getElementType(i); - elt = convertForDirectError(*this, elt, nativeTy, - /*forExtraction*/ false); - expandedResult = Builder.CreateInsertValue(expandedResult, elt, i); - } - if (forAsync) { - emitAllExtractValues(expandedResult, structTy, out); - } else { - out = expandedResult; - } - } else if (!errorSchema.getExpandedType(IGM)->isVoidTy()) { - out = - convertForDirectError(*this, nativeError.claimNext(), - combined.combinedTy, /*forExtraction*/ false); - } - } else { - if (forAsync && structTy) { - emitAllExtractValues(expandedResult, structTy, out); - } else { - out = expandedResult; - } - } - }; - if (!isAsync()) { auto fnTy = CurFn->getFunctionType(); auto retTy = fnTy->getReturnType(); @@ -4493,7 +4451,8 @@ void IRGenSILFunction::visitThrowInst(swift::ThrowInst *i) { auto combined = combineResultAndTypedErrorType(IGM, resultSchema, errorSchema); Explosion nativeAgg; - buildDirectError(combined, errorSchema, silErrorTy, errorResult, + buildDirectError(*this, combined, errorSchema, silErrorTy, + errorResult, /*forAsync*/ false, nativeAgg); emitScalarReturn(combined.combinedTy, nativeAgg); @@ -4543,7 +4502,7 @@ void IRGenSILFunction::visitThrowInst(swift::ThrowInst *i) { Explosion nativeAgg; auto combined = combineResultAndTypedErrorType(IGM, resultSchema, errorSchema); - buildDirectError(combined, errorSchema, silErrorTy, exn, + buildDirectError(*this, combined, errorSchema, silErrorTy, exn, /*forAsync*/ true, nativeAgg); assert(exn.empty() && "Unclaimed typed error results"); diff --git a/test/IRGen/typed_throws.swift b/test/IRGen/typed_throws.swift index c4fd0a260f701..65871c5d31b01 100644 --- a/test/IRGen/typed_throws.swift +++ b/test/IRGen/typed_throws.swift @@ -4,6 +4,8 @@ // RUN: %target-swift-frontend -primary-file %s -emit-ir | %FileCheck %s --check-prefix=CHECK +// RUN: %target-swift-frontend -primary-file %s -emit-ir -enable-library-evolution + // XFAIL: CPU=arm64e // REQUIRES: PTRSIZE=64 @@ -216,3 +218,17 @@ func mayThrowEmptyErrorAsync(x: Bool) async throws(EmptyError) -> String? { return "" } + + +enum SP: Error { + case a + case b(Int32) +} + +protocol Proto { + // This used to crash. + static func f() throws(SP) -> Self + + // This used to crash. + static func f2() throws(SP) -> Int64 +}