diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index 7d8e07de69957..19cb7fd47b30e 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -3368,8 +3368,8 @@ class UnresolvedTypeConversionExpr : public ImplicitConversionExpr { class FunctionConversionExpr : public ImplicitConversionExpr { public: FunctionConversionExpr(Expr *subExpr, Type type) - : ImplicitConversionExpr(ExprKind::FunctionConversion, subExpr, type) {} - + : ImplicitConversionExpr(ExprKind::FunctionConversion, subExpr, type) {} + static bool classof(const Expr *E) { return E->getKind() == ExprKind::FunctionConversion; } @@ -4301,19 +4301,19 @@ class ClosureExpr : public AbstractClosureExpr { } public: - ClosureExpr(const DeclAttributes &attributes, - SourceRange bracketRange, VarDecl *capturedSelfDecl, - ParameterList *params, SourceLoc asyncLoc, SourceLoc throwsLoc, - TypeExpr *thrownType, SourceLoc arrowLoc, SourceLoc inLoc, - TypeExpr *explicitResultType, DeclContext *parent) - : AbstractClosureExpr(ExprKind::Closure, Type(), /*Implicit=*/false, - parent), - Attributes(attributes), BracketRange(bracketRange), - CapturedSelfDecl(capturedSelfDecl), - AsyncLoc(asyncLoc), ThrowsLoc(throwsLoc), ArrowLoc(arrowLoc), - InLoc(inLoc), ThrownType(thrownType), - ExplicitResultTypeAndBodyState(explicitResultType, BodyState::Parsed), - Body(nullptr) { + ClosureExpr(const DeclAttributes &attributes, SourceRange bracketRange, + VarDecl *capturedSelfDecl, ParameterList *params, + SourceLoc asyncLoc, SourceLoc throwsLoc, TypeExpr *thrownType, + SourceLoc arrowLoc, SourceLoc inLoc, TypeExpr *explicitResultType, + DeclContext *parent) + : AbstractClosureExpr(ExprKind::Closure, Type(), /*Implicit=*/false, + parent), + Attributes(attributes), BracketRange(bracketRange), + CapturedSelfDecl(capturedSelfDecl), AsyncLoc(asyncLoc), + ThrowsLoc(throwsLoc), ArrowLoc(arrowLoc), InLoc(inLoc), + ThrownType(thrownType), + ExplicitResultTypeAndBodyState(explicitResultType, BodyState::Parsed), + Body(nullptr) { setParameterList(params); Bits.ClosureExpr.HasAnonymousClosureVars = false; Bits.ClosureExpr.ImplicitSelfCapture = false; diff --git a/include/swift/SIL/SILDeclRef.h b/include/swift/SIL/SILDeclRef.h index 97768a65b134e..e5650dfd74961 100644 --- a/include/swift/SIL/SILDeclRef.h +++ b/include/swift/SIL/SILDeclRef.h @@ -261,11 +261,9 @@ struct SILDeclRef { /// for the containing ClassDecl. /// - If 'loc' is a global VarDecl, this returns its GlobalAccessor /// SILDeclRef. - explicit SILDeclRef( - Loc loc, - bool isForeign = false, - bool isDistributed = false, - bool isDistributedLocal = false); + explicit SILDeclRef(Loc loc, bool isForeign = false, + bool isDistributed = false, + bool isDistributedLocal = false); /// See above put produces a prespecialization according to the signature. explicit SILDeclRef(Loc loc, GenericSignature prespecializationSig); diff --git a/include/swift/SIL/SILFunctionBuilder.h b/include/swift/SIL/SILFunctionBuilder.h index c7d946235f424..99929d68cac2b 100644 --- a/include/swift/SIL/SILFunctionBuilder.h +++ b/include/swift/SIL/SILFunctionBuilder.h @@ -87,7 +87,8 @@ class SILFunctionBuilder { llvm::function_ref getOrCreateDeclaration = [](SILLocation loc, SILDeclRef constant) -> SILFunction * { return nullptr; }, - ProfileCounter entryCount = ProfileCounter()); + ProfileCounter entryCount = ProfileCounter(), + const clang::Type *foreignType = nullptr); /// Create a function declaration. /// diff --git a/include/swift/SIL/TypeLowering.h b/include/swift/SIL/TypeLowering.h index 3cf6e735115ba..f450783dc0022 100644 --- a/include/swift/SIL/TypeLowering.h +++ b/include/swift/SIL/TypeLowering.h @@ -875,8 +875,9 @@ class TypeConverter { /// Returns the formal type, lowered AST type, and SILFunctionType /// for a constant reference. - const SILConstantInfo &getConstantInfo(TypeExpansionContext context, - SILDeclRef constant); + const SILConstantInfo & + getConstantInfo(TypeExpansionContext context, SILDeclRef constant, + const clang::Type *foreignType = nullptr); /// Get the generic signature for a constant. GenericSignatureWithCapturedEnvironments @@ -904,11 +905,12 @@ class TypeConverter { } /// Returns the SILFunctionType for the given declaration. - CanSILFunctionType getConstantFunctionType(TypeExpansionContext context, - SILDeclRef constant) { - return getConstantInfo(context, constant).SILFnType; + CanSILFunctionType + getConstantFunctionType(TypeExpansionContext context, SILDeclRef constant, + const clang::Type *foreignType = nullptr) { + return getConstantInfo(context, constant, foreignType).SILFnType; } - + /// Returns the SILParameterInfo for the given declaration's `self` parameter. /// `constant` must refer to a method. SILParameterInfo getConstantSelfParameter(TypeExpansionContext context, @@ -977,8 +979,9 @@ class TypeConverter { }; /// Derive the lowered formal type of the given constant. - LoweredFormalTypes getLoweredFormalTypes(SILDeclRef constant, - CanAnyFunctionType formalType); + LoweredFormalTypes + getLoweredFormalTypes(SILDeclRef constant, CanAnyFunctionType formalType, + const clang::Type *foreignType = nullptr); /// Given a function type, yield its bridged formal type. CanAnyFunctionType getBridgedFunctionType(AbstractionPattern fnPattern, diff --git a/lib/SIL/IR/SILFunctionBuilder.cpp b/lib/SIL/IR/SILFunctionBuilder.cpp index e99d351f65888..4f8c6350e9d7f 100644 --- a/lib/SIL/IR/SILFunctionBuilder.cpp +++ b/lib/SIL/IR/SILFunctionBuilder.cpp @@ -290,10 +290,10 @@ SILFunction *SILFunctionBuilder::getOrCreateFunction( SILLocation loc, SILDeclRef constant, ForDefinition_t forDefinition, llvm::function_ref getOrCreateDeclaration, - ProfileCounter entryCount) { + ProfileCounter entryCount, const clang::Type *foreignType) { auto nameTmp = constant.mangle(); auto constantType = mod.Types.getConstantFunctionType( - TypeExpansionContext::minimal(), constant); + TypeExpansionContext::minimal(), constant, foreignType); SILLinkage linkage = constant.getLinkage(forDefinition); if (auto fn = mod.lookUpFunction(nameTmp)) { diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index ba3b4c7143a87..bb11e9513efba 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -16,6 +16,8 @@ // //===----------------------------------------------------------------------===// +#include "swift/AST/Expr.h" +#include "swift/AST/Type.h" #define DEBUG_TYPE "libsil" #include "swift/AST/AnyFunctionRef.h" @@ -4320,10 +4322,12 @@ static CanSILFunctionType getUncachedSILFunctionTypeForConstant( // The type of the native-to-foreign thunk for a swift closure. if (constant.isForeign && constant.hasClosureExpr() && shouldStoreClangType(TC.getDeclRefRepresentation(constant))) { - auto clangType = TC.Context.getClangFunctionType( - origLoweredInterfaceType->getParams(), - origLoweredInterfaceType->getResult(), - FunctionTypeRepresentation::CFunctionPointer); + auto clangType = extInfoBuilder.getClangTypeInfo().getType(); + if (!clangType) + clangType = TC.Context.getClangFunctionType( + origLoweredInterfaceType->getParams(), + origLoweredInterfaceType->getResult(), + FunctionTypeRepresentation::CFunctionPointer); AbstractionPattern pattern = AbstractionPattern(origLoweredInterfaceType, clangType); return getSILFunctionTypeForAbstractCFunction( @@ -4478,7 +4482,8 @@ getLoweredResultIndices(const SILFunctionType *functionType, const SILConstantInfo & TypeConverter::getConstantInfo(TypeExpansionContext expansion, - SILDeclRef constant) { + SILDeclRef constant, + const clang::Type *foreignType) { if (!DisableConstantInfoCache) { auto found = ConstantTypes.find(std::make_pair(expansion, constant)); if (found != ConstantTypes.end()) @@ -4491,7 +4496,8 @@ TypeConverter::getConstantInfo(TypeExpansionContext expansion, // The lowered type is the formal type, but uncurried and with // parameters automatically turned into their bridged equivalents. - auto bridgedTypes = getLoweredFormalTypes(constant, formalInterfaceType); + auto bridgedTypes = + getLoweredFormalTypes(constant, formalInterfaceType, foreignType); CanAnyFunctionType loweredInterfaceType = bridgedTypes.Uncurried; @@ -4826,16 +4832,19 @@ static AbstractFunctionDecl *getBridgedFunction(SILDeclRef declRef) { llvm_unreachable("bad SILDeclRef kind"); } -static AbstractionPattern -getAbstractionPatternForConstant(ASTContext &ctx, SILDeclRef constant, - CanAnyFunctionType fnType, - unsigned numParameterLists) { +static AbstractionPattern getAbstractionPatternForConstant( + ASTContext &ctx, SILDeclRef constant, CanAnyFunctionType fnType, + unsigned numParameterLists, const clang::Type *foreignType) { if (!constant.isForeign) return AbstractionPattern(fnType); + if (foreignType) + return AbstractionPattern(fnType, foreignType); + auto bridgedFn = getBridgedFunction(constant); if (!bridgedFn) return AbstractionPattern(fnType); + const clang::Decl *clangDecl = bridgedFn->getClangDecl(); if (!clangDecl) return AbstractionPattern(fnType); @@ -4870,7 +4879,8 @@ getAbstractionPatternForConstant(ASTContext &ctx, SILDeclRef constant, TypeConverter::LoweredFormalTypes TypeConverter::getLoweredFormalTypes(SILDeclRef constant, - CanAnyFunctionType fnType) { + CanAnyFunctionType fnType, + const clang::Type *foreignType) { // We always use full bridging when importing a constant because we can // directly bridge its arguments and results when calling it. auto bridging = Bridgeability::Full; @@ -4878,9 +4888,8 @@ TypeConverter::getLoweredFormalTypes(SILDeclRef constant, unsigned numParameterLists = constant.getParameterListCount(); // Form an abstraction pattern for bridging purposes. - AbstractionPattern bridgingFnPattern = - getAbstractionPatternForConstant(Context, constant, fnType, - numParameterLists); + AbstractionPattern bridgingFnPattern = getAbstractionPatternForConstant( + Context, constant, fnType, numParameterLists, foreignType); auto extInfo = fnType->getExtInfo(); SILFunctionTypeRepresentation rep = getDeclRefRepresentation(constant); diff --git a/lib/SILGen/Conversion.h b/lib/SILGen/Conversion.h index 01fe4755a7d27..bd460ecb1b32c 100644 --- a/lib/SILGen/Conversion.h +++ b/lib/SILGen/Conversion.h @@ -17,10 +17,12 @@ #ifndef SWIFT_LOWERING_CONVERSION_H #define SWIFT_LOWERING_CONVERSION_H -#include "swift/Basic/Assertions.h" -#include "swift/Basic/ExternalUnion.h" #include "Initialization.h" #include "SGFContext.h" +#include "swift/Basic/Assertions.h" +#include "swift/Basic/ExternalUnion.h" +#include "swift/SIL/AbstractionPattern.h" +#include namespace swift { namespace Lowering { @@ -115,6 +117,7 @@ class Conversion { struct BridgingStorage { bool IsExplicit; + AbstractionPattern InputOrigType; }; /// The types we store for reabstracting contexts. In general, when @@ -161,11 +164,11 @@ class Conversion { static_assert(decltype(Types)::union_is_trivially_copyable, "define the special members if this changes"); - Conversion(KindTy kind, CanType sourceType, CanType resultType, - SILType loweredResultTy, bool isExplicit) + Conversion(KindTy kind, AbstractionPattern inputOrigType, CanType sourceType, + CanType resultType, SILType loweredResultTy, bool isExplicit) : Kind(kind), SourceType(sourceType), ResultType(resultType), LoweredResultType(loweredResultTy) { - Types.emplaceAggregate(kind, isExplicit); + Types.emplaceAggregate(kind, isExplicit, inputOrigType); } Conversion(AbstractionPattern inputOrigType, CanType inputSubstType, @@ -236,13 +239,19 @@ class Conversion { outputOrigType, outputSubstType, outputLoweredTy); } - static Conversion getBridging(KindTy kind, CanType origType, - CanType resultType, SILType loweredResultTy, - bool isExplicit = false) { + static Conversion + getBridging(KindTy kind, CanType origType, CanType resultType, + SILType loweredResultTy, + std::optional inputOrigType = std::nullopt, + bool isExplicit = false) { assert(isBridgingKind(kind)); assert((kind != Subtype || isAllowedConversion(origType, resultType)) && "disallowed conversion for subtype relationship"); - return Conversion(kind, origType, resultType, loweredResultTy, isExplicit); + if (inputOrigType) + return Conversion(kind, *inputOrigType, origType, resultType, + loweredResultTy, isExplicit); + return Conversion(kind, AbstractionPattern(origType), origType, resultType, + loweredResultTy, isExplicit); } static Conversion getSubtype(CanType origType, CanType substType, @@ -290,6 +299,10 @@ class Conversion { return Types.get(Kind).IsExplicit; } + AbstractionPattern getBridgingOriginalInputType() const { + return Types.get(Kind).InputOrigType; + } + CanType getSourceType() const { return SourceType; } diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 89c843270a319..6000c62864742 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -799,7 +799,8 @@ static ActorIsolation getActorIsolationForFunction(SILFunction &fn) { } SILFunction *SILGenModule::getFunction(SILDeclRef constant, - ForDefinition_t forDefinition) { + ForDefinition_t forDefinition, + const clang::Type *foreignType) { // If we already emitted the function, return it. if (auto emitted = getEmittedFunction(constant, forDefinition)) return emitted; @@ -819,9 +820,11 @@ SILFunction *SILGenModule::getFunction(SILDeclRef constant, auto &IGM = *this; auto *F = builder.getOrCreateFunction( getBestLocation(constant), constant, forDefinition, - [&IGM](SILLocation loc, SILDeclRef constant) -> SILFunction * { - return IGM.getFunction(constant, NotForDefinition); - }); + [&IGM, foreignType](SILLocation loc, + SILDeclRef constant) -> SILFunction * { + return IGM.getFunction(constant, NotForDefinition, foreignType); + }, + ProfileCounter(), foreignType); F->setDeclRef(constant); F->setActorIsolation(getActorIsolationForFunction(*F)); diff --git a/lib/SILGen/SILGen.h b/lib/SILGen/SILGen.h index 2e96cce09b59c..dc7de48a1c133 100644 --- a/lib/SILGen/SILGen.h +++ b/lib/SILGen/SILGen.h @@ -145,8 +145,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor { ForDefinition_t forDefinition); /// Get the function for a SILDeclRef, creating it if necessary. - SILFunction *getFunction(SILDeclRef constant, - ForDefinition_t forDefinition); + SILFunction *getFunction(SILDeclRef constant, ForDefinition_t forDefinition, + const clang::Type *foreignType = nullptr); /// Get the dynamic dispatch thunk for a SILDeclRef. SILFunction *getDynamicThunk(SILDeclRef constant, @@ -348,7 +348,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor { void emitForeignToNativeThunk(SILDeclRef thunk); /// Emits a thunk from a Swift function to the native Swift convention. - void emitNativeToForeignThunk(SILDeclRef thunk); + void emitNativeToForeignThunk(SILDeclRef thunk, + const clang::Type *foreignType = nullptr); /// Emits the distributed actor thunk for the decl if there is one associated /// with it. diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index 0cc19e2c905e6..47015358a8429 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -4258,10 +4258,10 @@ class ArgEmitter { loweredSubstArgType, param.getSILStorageInterfaceType()); case SILFunctionLanguage::C: - return Conversion::getBridging(Conversion::BridgeToObjC, - arg.getSubstRValueType(), - origParamType.getType(), - param.getSILStorageInterfaceType()); + return Conversion::getBridging( + Conversion::BridgeToObjC, arg.getSubstRValueType(), + origParamType.getType(), param.getSILStorageInterfaceType(), + origParamType); } llvm_unreachable("bad language"); }(); diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp index d7cb7c1324009..2579b0e0f013c 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -1315,8 +1315,9 @@ static SILValue emitObjCUnconsumedArgument(SILGenFunction &SGF, SILLocation loc, SILValue arg) { auto &lowering = SGF.getTypeLowering(arg->getType()); - // If address-only, make a +1 copy and operate on that. - if (lowering.isAddressOnly() && SGF.useLoweredAddresses()) { + // If arg is non-trivial and has an address type, make a +1 copy and operate + // on that. + if (!lowering.isTrivial() && arg->getType().isAddress()) { auto tmp = SGF.emitTemporaryAllocation(loc, arg->getType().getObjectType()); SGF.B.createCopyAddr(loc, arg, tmp, IsNotTake, IsInitialization); return tmp; @@ -1453,6 +1454,11 @@ emitObjCThunkArguments(SILGenFunction &SGF, SILLocation loc, SILDeclRef thunk, auto buf = SGF.emitTemporaryAllocation(loc, native.getType()); native.forwardInto(SGF, loc, buf); native = SGF.emitManagedBufferWithCleanup(buf); + } else if (!fnConv.isSILIndirect(nativeInputs[i]) && + native.getType().isAddress()) { + // Load the value if the argument has an address type and the native + // function expects the argument to be passed directly. + native = SGF.emitManagedLoadCopy(loc, native.getValue()); } if (nativeInputs[i].isConsumedInCaller()) { diff --git a/lib/SILGen/SILGenConvert.cpp b/lib/SILGen/SILGenConvert.cpp index a3f2b8ddadd0a..b84f9bb5e5c00 100644 --- a/lib/SILGen/SILGenConvert.cpp +++ b/lib/SILGen/SILGenConvert.cpp @@ -1348,10 +1348,9 @@ Conversion::adjustForInitialOptionalInjection() const { case BridgeFromObjC: case BridgeResultFromObjC: return OptionalInjectionConversion::forInjection( - getBridging(getKind(), getSourceType().getOptionalObjectType(), - getResultType(), getLoweredResultType(), - isBridgingExplicit()) - ); + getBridging(getKind(), getSourceType().getOptionalObjectType(), + getResultType(), getLoweredResultType(), + getBridgingOriginalInputType(), isBridgingExplicit())); } llvm_unreachable("bad kind"); } @@ -1373,9 +1372,9 @@ Conversion::adjustForInitialOptionalConversions(CanType newSourceType) const { case BridgeToObjC: case BridgeFromObjC: case BridgeResultFromObjC: - return Conversion::getBridging(getKind(), newSourceType, - getResultType(), getLoweredResultType(), - isBridgingExplicit()); + return Conversion::getBridging( + getKind(), newSourceType, getResultType(), getLoweredResultType(), + getBridgingOriginalInputType(), isBridgingExplicit()); } llvm_unreachable("bad kind"); } @@ -1394,9 +1393,9 @@ std::optional Conversion::adjustForInitialForceValue() const { case BridgeToObjC: { auto sourceOptType = getSourceType().wrapInOptionalType(); - return Conversion::getBridging(ForceAndBridgeToObjC, - sourceOptType, getResultType(), - getLoweredResultType(), + return Conversion::getBridging(ForceAndBridgeToObjC, sourceOptType, + getResultType(), getLoweredResultType(), + getBridgingOriginalInputType(), isBridgingExplicit()); } } diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index efb9a575e8866..8cd4f43c79516 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -750,10 +750,10 @@ tryEmitAsBridgingConversion(SILGenFunction &SGF, Expr *E, bool isExplicit, auto subExpr = result.SubExpr; CanType resultType = E->getType()->getCanonicalType(); - Conversion conversion = - Conversion::getBridging(kind, subExpr->getType()->getCanonicalType(), - resultType, SGF.getLoweredType(resultType), - isExplicit); + Conversion conversion = Conversion::getBridging( + kind, subExpr->getType()->getCanonicalType(), resultType, + SGF.getLoweredType(resultType), AbstractionPattern(subExpr->getType()), + isExplicit); // Only use this special pattern for AnyErasure conversions when we're // emitting into a peephole. @@ -1730,11 +1730,21 @@ static ManagedValue emitAnyClosureExpr(SILGenFunction &SGF, Expr *e, } } -static ManagedValue convertCFunctionSignature(SILGenFunction &SGF, - FunctionConversionExpr *e, - SILType loweredResultTy, - llvm::function_ref fnEmitter) { - SILType loweredDestTy = SGF.getLoweredType(e->getType()); +static ManagedValue +convertCFunctionSignature(SILGenFunction &SGF, FunctionConversionExpr *e, + SILType loweredResultTy, SGFContext C, + llvm::function_ref fnEmitter) { + SILType loweredDestTy; + auto destTy = e->getType(); + if (const auto init = C.getAsConversion()) { + SILType loweredDestOptTy = init->getConversion().getLoweredResultType(); + if (auto objTy = loweredDestOptTy.getOptionalObjectType()) + loweredDestTy = objTy; + else + loweredDestTy = loweredDestOptTy; + } else + loweredDestTy = SGF.getLoweredType(destTy); + ManagedValue result; // We're converting between C function pointer types. They better be @@ -1769,9 +1779,9 @@ static ManagedValue convertCFunctionSignature(SILGenFunction &SGF, return result; } -static -ManagedValue emitCFunctionPointer(SILGenFunction &SGF, - FunctionConversionExpr *conversionExpr) { +static ManagedValue emitCFunctionPointer(SILGenFunction &SGF, + FunctionConversionExpr *conversionExpr, + SGFContext C) { auto expr = conversionExpr->getSubExpr(); // Look through base-ignored exprs to get to the function ref. @@ -1805,7 +1815,9 @@ ManagedValue emitCFunctionPointer(SILGenFunction &SGF, #endif semanticExpr = conv->getSubExpr()->getSemanticsProvidingExpr(); } - + + const clang::Type *destFnType = nullptr; + if (auto declRef = dyn_cast(semanticExpr)) { setLocFromConcreteDeclRef(declRef->getDeclRef()); } else if (auto memberRef = dyn_cast(semanticExpr)) { @@ -1819,14 +1831,20 @@ ManagedValue emitCFunctionPointer(SILGenFunction &SGF, loc = closure; return ManagedValue(); }); + if (auto init = C.getAsConversion()) { + auto conv = init->getConversion(); + auto origParamType = conv.getBridgingOriginalInputType(); + if (origParamType.isClangType()) + destFnType = origParamType.getClangType(); + } } else { llvm_unreachable("c function pointer converted from a non-concrete decl ref"); } // Produce a reference to the C-compatible entry point for the function. - SILDeclRef constant(loc, /*foreign*/ true); + SILDeclRef constant(loc, /*foreign*/ true, false, false); SILConstantInfo constantInfo = - SGF.getConstantInfo(SGF.getTypeExpansionContext(), constant); + SGF.getConstantInfo(SGF.getTypeExpansionContext(), constant, destFnType); // C function pointers cannot capture anything from their context. auto captures = SGF.SGM.Types.getLoweredLocalCaptures(constant); @@ -1854,13 +1872,12 @@ ManagedValue emitCFunctionPointer(SILGenFunction &SGF, } return convertCFunctionSignature( - SGF, conversionExpr, - constantInfo.getSILType(), - [&]() -> ManagedValue { - SILValue cRef = SGF.emitGlobalFunctionRef(expr, constant); - return ManagedValue::forObjectRValueWithoutOwnership( - cRef); - }); + SGF, conversionExpr, constantInfo.getSILType(), C, [&]() -> ManagedValue { + SILValue cRef = SGF.emitGlobalFunctionRef( + expr, constant, constantInfo, + /*callPreviousDynamicReplaceableImpl=*/false, destFnType); + return ManagedValue::forObjectRValueWithoutOwnership(cRef); + }); } // Change the representation without changing the signature or @@ -2117,7 +2134,7 @@ RValue RValueEmitter::visitFunctionConversionExpr(FunctionConversionExpr *e, FunctionTypeRepresentation::CFunctionPointer) { // A "conversion" of a DeclRef a C function pointer is done by referencing // the thunk (or original C function) with the C calling convention. - result = emitCFunctionPointer(SGF, e); + result = emitCFunctionPointer(SGF, e, C); } else { // Ok, we're converting a C function pointer value to another C function // pointer. @@ -2127,10 +2144,9 @@ RValue RValueEmitter::visitFunctionConversionExpr(FunctionConversionExpr *e, // Possibly bitcast the C function pointer to account for ABI-compatible // parameter and result type conversions - result = convertCFunctionSignature(SGF, e, result.getType(), - [&]() -> ManagedValue { - return result; - }); + result = + convertCFunctionSignature(SGF, e, result.getType(), C, + [&]() -> ManagedValue { return result; }); } return RValue(SGF, e, result); } diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h index f64df12b49090..1237c3c5dace2 100644 --- a/lib/SILGen/SILGenFunction.h +++ b/lib/SILGen/SILGenFunction.h @@ -919,9 +919,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction return getTypeLowering(t).getLoweredType().getCategoryType(t.getCategory()); } - const SILConstantInfo &getConstantInfo(TypeExpansionContext context, - SILDeclRef constant) { - return SGM.Types.getConstantInfo(context, constant); + const SILConstantInfo & + getConstantInfo(TypeExpansionContext context, SILDeclRef constant, + const clang::Type *foreignType = nullptr) { + return SGM.Types.getConstantInfo(context, constant, foreignType); } /// Return the normal local type-lowering information for the given @@ -1952,7 +1953,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction SILValue emitGlobalFunctionRef(SILLocation loc, SILDeclRef constant, SILConstantInfo constantInfo, - bool callPreviousDynamicReplaceableImpl = false); + bool callPreviousDynamicReplaceableImpl = false, + const clang::Type *foreignType = nullptr); /// Returns a reference to a function value that dynamically dispatches /// the function in a runtime-modifiable way. diff --git a/lib/SILGen/SILGenThunk.cpp b/lib/SILGen/SILGenThunk.cpp index a2ba63724f5c3..ddb452f4e769d 100644 --- a/lib/SILGen/SILGenThunk.cpp +++ b/lib/SILGen/SILGenThunk.cpp @@ -106,10 +106,11 @@ void SILGenModule::emitForeignToNativeThunk(SILDeclRef thunk) { emitFunctionDefinition(thunk, getFunction(thunk, ForDefinition)); } -void SILGenModule::emitNativeToForeignThunk(SILDeclRef thunk) { +void SILGenModule::emitNativeToForeignThunk(SILDeclRef thunk, + const clang::Type *foreignType) { // Thunks are always emitted by need, so don't need delayed emission. assert(thunk.isNativeToForeignThunk() && "native-to-foreign thunks only"); - emitFunctionDefinition(thunk, getFunction(thunk, ForDefinition)); + emitFunctionDefinition(thunk, getFunction(thunk, ForDefinition, foreignType)); } void SILGenModule::emitDistributedThunkForDecl( @@ -175,11 +176,11 @@ struct DistributedThunkDiffChecker } // namespace -SILValue -SILGenFunction::emitGlobalFunctionRef(SILLocation loc, SILDeclRef constant, - SILConstantInfo constantInfo, - bool callPreviousDynamicReplaceableImpl) { - assert(constantInfo == getConstantInfo(getTypeExpansionContext(), constant)); +SILValue SILGenFunction::emitGlobalFunctionRef( + SILLocation loc, SILDeclRef constant, SILConstantInfo constantInfo, + bool callPreviousDynamicReplaceableImpl, const clang::Type *foreignType) { + assert(constantInfo == + getConstantInfo(getTypeExpansionContext(), constant, foreignType)); // Builtins must be fully applied at the point of reference. if (constant.hasDecl() && @@ -194,11 +195,11 @@ SILGenFunction::emitGlobalFunctionRef(SILLocation loc, SILDeclRef constant, if (constant.isForeignToNativeThunk()) { SGM.emitForeignToNativeThunk(constant); } else if (constant.isNativeToForeignThunk()) { - SGM.emitNativeToForeignThunk(constant); + SGM.emitNativeToForeignThunk(constant, foreignType); } } - auto f = SGM.getFunction(constant, NotForDefinition); + auto f = SGM.getFunction(constant, NotForDefinition, foreignType); auto constantFnTypeInContext = SGM.Types diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index c356106fea99b..d4013f191890f 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -8508,9 +8508,6 @@ class SwiftToClangBasicReader : llvm::Expected ModuleFile::getClangType(ClangTypeID TID) { - if (!getContext().LangOpts.UseClangFunctionTypes) - return nullptr; - if (TID == 0) return nullptr; diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 7e1a1900c7084..3e69091613ea1 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -17,6 +17,7 @@ #include "swift/AST/ASTMangler.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/AutoDiff.h" +#include "swift/AST/Decl.h" #include "swift/AST/DiagnosticsCommon.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/Expr.h" @@ -41,6 +42,7 @@ #include "swift/AST/SynthesizedFileUnit.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/AST/TypeVisitor.h" +#include "swift/AST/Types.h" #include "swift/Basic/Assertions.h" #include "swift/Basic/Defer.h" #include "swift/Basic/FileSystem.h" @@ -5553,6 +5555,31 @@ static TypeAliasDecl *findTypeAliasForBuiltin(ASTContext &Ctx, Type T) { return cast(CurModuleResults[0]); } +namespace { +struct ImplementationOnlyWalker : TypeWalker { + bool hadImplementationOnlyDecl = false; + const ModuleDecl *currentModule; + ImplementationOnlyWalker(const ModuleDecl *M) : currentModule(M) {} + Action walkToTypePre(Type ty) override { + if (auto *typeAlias = dyn_cast(ty)) { + if (importedImplementationOnly(typeAlias->getDecl())) + return Action::Stop; + } else if (auto *nominal = ty->getAs()) { + if (importedImplementationOnly(nominal->getDecl())) + return Action::Stop; + } + return Action::Continue; + } + bool importedImplementationOnly(const Decl *D) { + if (currentModule->isImportedImplementationOnly(D->getModuleContext())) { + hadImplementationOnlyDecl = true; + return true; + } + return false; + } +}; +} // namespace + class Serializer::TypeSerializer : public TypeVisitor { Serializer &S; @@ -5906,10 +5933,23 @@ class Serializer::TypeSerializer : public TypeVisitor { using namespace decls_block; auto resultType = S.addTypeRef(fnTy->getResult()); - auto clangType = - S.getASTContext().LangOpts.UseClangFunctionTypes - ? S.addClangTypeRef(fnTy->getClangTypeInfo().getType()) - : ClangTypeID(0); + bool shouldSerializeClangType = true; + if (S.hadImplementationOnlyImport && S.M && + S.M->getResilienceStrategy() != ResilienceStrategy::Resilient) { + // Deserializing clang types from implementation only modules could crash + // as the transitive clang module might not be available to retrieve the + // declarations from. In an optimal world we would make the deseriaization + // more resilient to these problems but the failure is in Clang's + // deserialization code path that is not architected with potentially + // missing declarations in mind. + ImplementationOnlyWalker walker{S.M}; + Type(const_cast(fnTy)).walk(walker); + if (walker.hadImplementationOnlyDecl) + shouldSerializeClangType = false; + } + auto clangType = shouldSerializeClangType + ? S.addClangTypeRef(fnTy->getClangTypeInfo().getType()) + : ClangTypeID(0); auto isolation = encodeIsolation(fnTy->getIsolation()); @@ -6991,8 +7031,13 @@ void Serializer::writeAST(ModuleOrSourceFile DC) { nextFile->getTopLevelDeclsWithAuxiliaryDecls(fileDecls); for (auto D : fileDecls) { - if (isa(D) || isa(D) || - isa(D) || isa(D)) { + if (const auto *ID = dyn_cast(D)) { + if (ID->getAttrs().hasAttribute()) + hadImplementationOnlyImport = true; + continue; + } + if (isa(D) || isa(D) || + isa(D)) { continue; } diff --git a/lib/Serialization/Serialization.h b/lib/Serialization/Serialization.h index df68ffb3c8f51..7e3d3f3102388 100644 --- a/lib/Serialization/Serialization.h +++ b/lib/Serialization/Serialization.h @@ -116,6 +116,8 @@ class Serializer : public SerializerBase { /// an error in the AST. bool hadError = false; + bool hadImplementationOnlyImport = false; + /// Helper for serializing entities in the AST block object graph. /// /// Keeps track of assigning IDs to newly-seen entities, and collecting diff --git a/test/Interop/Cxx/class/Inputs/closure.h b/test/Interop/Cxx/class/Inputs/closure.h index b2c968cf12d89..b842401536f5a 100644 --- a/test/Interop/Cxx/class/Inputs/closure.h +++ b/test/Interop/Cxx/class/Inputs/closure.h @@ -10,6 +10,10 @@ struct NonTrivial { int *p; }; +struct Trivial { + int i; +}; + void cfunc(void (^ _Nonnull block)(NonTrivial)) noexcept { block(NonTrivial()); } @@ -75,4 +79,13 @@ inline void releaseSharedRef(SharedRef *_Nonnull x) { } } +void cfuncConstRefNonTrivial(void (*_Nonnull)(const NonTrivial &)); +void cfuncConstRefTrivial(void (*_Nonnull)(const Trivial &)); +void blockConstRefNonTrivial(void (^_Nonnull)(const NonTrivial &)); +void blockConstRefTrivial(void (^_Nonnull)(const Trivial &)); +#if __OBJC__ +void cfuncConstRefStrong(void (*_Nonnull)(const ARCStrong &)); +void blockConstRefStrong(void (^_Nonnull)(const ARCStrong &)); +#endif + #endif // __CLOSURE__ diff --git a/test/Interop/Cxx/class/closure-thunk-macosx.swift b/test/Interop/Cxx/class/closure-thunk-macosx.swift index 01b459b98aee1..56e34d298a418 100644 --- a/test/Interop/Cxx/class/closure-thunk-macosx.swift +++ b/test/Interop/Cxx/class/closure-thunk-macosx.swift @@ -35,3 +35,101 @@ public func testClosureToFuncPtr() { public func testClosureToBlockReturnNonTrivial() { cfuncReturnNonTrivial({() -> NonTrivial in return NonTrivial() }) } + +// CHECK-LABEL: sil private [thunk] [ossa] @$s4main22testConstRefNonTrivialyyFySo0eF0VcfU_To : $@convention(c) (@in_guaranteed NonTrivial) -> () { +// CHECK: bb0(%[[V0:.*]] : $*NonTrivial): +// CHECK: %[[V1:.*]] = alloc_stack $NonTrivial +// CHECK: copy_addr %[[V0]] to [init] %[[V1]] : $*NonTrivial +// CHECK: %[[V3:.*]] = function_ref @$s4main22testConstRefNonTrivialyyFySo0eF0VcfU_ : $@convention(thin) (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V4:.*]] = apply %[[V3]](%[[V1]]) : $@convention(thin) (@in_guaranteed NonTrivial) -> () +// CHECK: destroy_addr %[[V1]] : $*NonTrivial +// CHECK: dealloc_stack %[[V1]] : $*NonTrivial +// CHECK: return %[[V4]] : $() + +public func testConstRefNonTrivial() { + cfuncConstRefNonTrivial({S in }); +} + +// CHECK-LABEL: sil private [thunk] [ossa] @$s4main23testConstRefNonTrivial2yyFySo0E7TrivialVcfU_To : $@convention(c) (@in_guaranteed NonTrivial) -> () { +// CHECK: bb0(%[[V0:.*]] : $*NonTrivial): +// CHECK: %[[V1:.*]] = alloc_stack $NonTrivial +// CHECK: copy_addr %[[V0]] to [init] %[[V1]] : $*NonTrivial +// CHECK: %[[V3:.*]] = function_ref @$s4main23testConstRefNonTrivial2yyFySo0E7TrivialVcfU_ : $@convention(thin) (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V4:.*]] = apply %[[V3]](%[[V1]]) : $@convention(thin) (@in_guaranteed NonTrivial) -> () +// CHECK: destroy_addr %[[V1]] : $*NonTrivial +// CHECK: dealloc_stack %[[V1]] : $*NonTrivial +// CHECK: return %[[V4]] : $() +public func testConstRefNonTrivial2() { + cfuncConstRefNonTrivial(({S in })); +} + +// CHECK-LABEL: sil private [thunk] [ossa] @$s4main19testConstRefTrivialyyFySo0E0VcfU_To : $@convention(c) (@in_guaranteed Trivial) -> () { +// CHECK: bb0(%[[V0:.*]] : $*Trivial): +// CHECK: %[[V1:.*]] = load [trivial] %[[V0]] : $*Trivial +// CHECK: %[[V2:.*]] = function_ref @$s4main19testConstRefTrivialyyFySo0E0VcfU_ : $@convention(thin) (Trivial) -> () +// CHECK: %[[V3:.*]] = apply %[[V2]](%[[V1]]) : $@convention(thin) (Trivial) -> () +// CHECK: return %[[V3]] : $() + +public func testConstRefTrivial() { + cfuncConstRefTrivial({S in }); +} + +// CHECK-LABEL: sil private [thunk] [ossa] @$s4main18testConstRefStrongyyFySo9ARCStrongVcfU_To : $@convention(c) (@in_guaranteed ARCStrong) -> () { +// CHECK: bb0(%[[V0:.*]] : $*ARCStrong): +// CHECK: %[[V1:.*]] = alloc_stack $ARCStrong +// CHECK: copy_addr %[[V0]] to [init] %[[V1]] : $*ARCStrong +// CHECK: %[[V3:.*]] = load [copy] %[[V1]] : $*ARCStrong +// CHECK: %[[V4:.*]] = begin_borrow %[[V3]] : $ARCStrong +// CHECK: %[[V5:.*]] = function_ref @$s4main18testConstRefStrongyyFySo9ARCStrongVcfU_ : $@convention(thin) (@guaranteed ARCStrong) -> () +// CHECK: %[[V6:.*]] = apply %[[V5]](%[[V4]]) : $@convention(thin) (@guaranteed ARCStrong) -> () +// CHECK: end_borrow %[[V4]] : $ARCStrong +// CHECK: destroy_value %[[V3]] : $ARCStrong +// CHECK: destroy_addr %[[V1]] : $*ARCStrong +// CHECK: dealloc_stack %[[V1]] : $*ARCStrong +// CHECK: return %[[V6]] : $() + +public func testConstRefStrong() { + cfuncConstRefStrong({S in }); +} + +// CHECK-LABEL: sil shared [transparent] [serialized] [reabstraction_thunk] [ossa] @$sSo10NonTrivialVIegn_ABIeyBn_TR : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> (), @in_guaranteed NonTrivial) -> () { +// CHECK: bb0(%[[V0:.*]] : $*@block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> (), %[[V1:.*]] : $*NonTrivial): +// CHECK: %[[V2:.*]] = project_block_storage %[[V0]] : $*@block_storage @callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V3:.*]] = load [copy] %[[V2]] : $*@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: %[[V4:.*]] = begin_borrow %[[V3]] : $@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: apply %[[V4]](%[[V1]]) : $@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: end_borrow %[[V4]] : $@callee_guaranteed (@in_guaranteed NonTrivial) -> () +// CHECK: destroy_value %[[V3]] : $@callee_guaranteed (@in_guaranteed NonTrivial) -> () + +public func testBlockConstRefNonTrivial() { + blockConstRefNonTrivial({S in }); +} + +// CHECK-LABEL: sil shared [transparent] [serialized] [reabstraction_thunk] [ossa] @$sSo7TrivialVIegy_ABIeyBn_TR : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed (Trivial) -> (), @in_guaranteed Trivial) -> () { +// CHECK: bb0(%[[V0:.*]] : $*@block_storage @callee_guaranteed (Trivial) -> (), %[[V1:.*]] : $*Trivial): +// CHECK: %[[V2:.*]] = project_block_storage %[[V0]] : $*@block_storage @callee_guaranteed (Trivial) -> () +// CHECK: %[[V3:.*]] = load [copy] %[[V2]] : $*@callee_guaranteed (Trivial) -> () +// CHECK: %[[V4:.*]] = load [trivial] %[[V1]] : $*Trivial +// CHECK: %[[V5:.*]] = begin_borrow %[[V3]] : $@callee_guaranteed (Trivial) -> () +// CHECK: apply %[[V5]](%[[V4]]) : $@callee_guaranteed (Trivial) -> () +// CHECK: end_borrow %[[V5]] : $@callee_guaranteed (Trivial) -> () +// CHECK: destroy_value %[[V3]] : $@callee_guaranteed (Trivial) -> () + +public func testBlockConstRefTrivial() { + blockConstRefTrivial({S in }); +} + +// CHECK-LABEL: sil shared [transparent] [serialized] [reabstraction_thunk] [ossa] @$sSo9ARCStrongVIegg_ABIeyBn_TR : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed (@guaranteed ARCStrong) -> (), @in_guaranteed ARCStrong) -> () { +// CHECK: bb0(%[[V0:.*]] : $*@block_storage @callee_guaranteed (@guaranteed ARCStrong) -> (), %[[V1:.*]] : $*ARCStrong): +// CHECK: %[[V2:.*]] = project_block_storage %[[V0]] : $*@block_storage @callee_guaranteed (@guaranteed ARCStrong) -> () +// CHECK: %[[V3:.*]] = load [copy] %[[V2]] : $*@callee_guaranteed (@guaranteed ARCStrong) -> () +// CHECK: %[[V4:.*]] = load_borrow %[[V1]] : $*ARCStrong +// CHECK: %[[V5:.*]] = begin_borrow %[[V3]] : $@callee_guaranteed (@guaranteed ARCStrong) -> () +// CHECK: apply %[[V5]](%[[V4]]) : $@callee_guaranteed (@guaranteed ARCStrong) -> () +// CHECK: end_borrow %[[V5]] : $@callee_guaranteed (@guaranteed ARCStrong) -> () +// CHECK: end_borrow %[[V4]] : $ARCStrong +// CHECK: destroy_value %[[V3]] : $@callee_guaranteed (@guaranteed ARCStrong) -> () + +public func testBlockConstRefStrong() { + blockConstRefStrong({S in }); +} diff --git a/test/Interop/Cxx/implementation-only-imports/import-implementation-only-cxx-module-transitively.swift b/test/Interop/Cxx/implementation-only-imports/import-implementation-only-cxx-module-transitively.swift new file mode 100644 index 0000000000000..2b216d5284a76 --- /dev/null +++ b/test/Interop/Cxx/implementation-only-imports/import-implementation-only-cxx-module-transitively.swift @@ -0,0 +1,60 @@ +// Crash reproducer from https://github.com/swiftlang/swift/issues/77047#issuecomment-2440103712 +// REQUIRES: OS=macosx + +// RUN: %empty-directory(%t) +// RUN: split-file %s %t +// RUN: mkdir %t/artifacts + +// RUN: %target-swift-frontend -c %t/ChibiStdlib.swift -parse-stdlib -emit-module -emit-module-path %t/sdk/usr/lib/swift/Swift.swiftmodule/%module-target-triple.swiftmodule -module-name Swift -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -o %t/artifacts +// RUN: %target-swift-frontend -c %t/XMLParser.swift -parse-as-library -emit-module -emit-module-path %t/sdk/usr/lib/swift/MyFoundationXML.swiftmodule/%module-target-triple.swiftmodule -module-name MyFoundationXML -module-link-name MyFoundationXML -resource-dir %t/sdk -O -I %t/include -o %t/artifacts -sdk %t/sdk +// RUN: %target-swift-frontend -c %t/Check.swift -o %t/artifacts -index-store-path %t/index-store -index-system-modules -resource-dir %t/sdk -parse-stdlib -sdk %t/sdk + +// RUN: %empty-directory(%t) +// RUN: split-file %s %t +// RUN: mkdir %t/artifacts + +// RUN: %target-swift-frontend -c %t/ChibiStdlib.swift -parse-stdlib -emit-module -emit-module-path %t/sdk/usr/lib/swift/Swift.swiftmodule/%module-target-triple.swiftmodule -module-name Swift -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -o %t/artifacts +// RUN: %target-swift-frontend -c %t/XMLParser.swift -enable-library-evolution -parse-as-library -emit-module -emit-module-path %t/sdk/usr/lib/swift/MyFoundationXML.swiftmodule/%module-target-triple.swiftmodule -module-name MyFoundationXML -module-link-name MyFoundationXML -resource-dir %t/sdk -O -I %t/include -o %t/artifacts -sdk %t/sdk +// RUN: %target-swift-frontend -c %t/Check.swift -o %t/artifacts -index-store-path %t/index-store -index-system-modules -resource-dir %t/sdk -parse-stdlib -sdk %t/sdk + + +//--- Check.swift +import MyFoundationXML + +//--- XMLParser.swift +@_implementationOnly import _MyCFXMLInterface + +func _NSXMLParserExternalEntityWithURL(originalLoaderFunction: _CFXMLInterfaceExternalEntityLoader) {} + +//--- include/module.modulemap +module _MyCFXMLInterface { + header "MyCFXMLInterface.h" +} + +//--- include/MyCFXMLInterface.h +#if !defined(__COREFOUNDATION_CFXMLINTERFACE__) +#define __COREFOUNDATION_CFXMLINTERFACE__ 1 + +typedef struct _xmlParserCtxt *_CFXMLInterfaceParserContext; +typedef void (*_CFXMLInterfaceExternalEntityLoader)(_CFXMLInterfaceParserContext); + +#endif + +//--- ChibiStdlib.swift +precedencegroup AssignmentPrecedence { + assignment: true + associativity: right +} + +public typealias Void = () + +@frozen +public struct OpaquePointer { + @usableFromInline + internal var _rawValue: Builtin.RawPointer + + @usableFromInline @_transparent + internal init(_ v: Builtin.RawPointer) { + self._rawValue = v + } +} diff --git a/test/Interop/Cxx/stdlib/use-std-function.swift b/test/Interop/Cxx/stdlib/use-std-function.swift index 42f9b4964924c..8129ed812cdc1 100644 --- a/test/Interop/Cxx/stdlib/use-std-function.swift +++ b/test/Interop/Cxx/stdlib/use-std-function.swift @@ -69,12 +69,11 @@ StdFunctionTestSuite.test("FunctionStringToString init from closure and pass as expectEqual(std.string("prefixabcabc"), res) } -// FIXME: assertion for address-only closure params (rdar://124501345) -//StdFunctionTestSuite.test("FunctionStringToStringConstRef init from closure and pass as parameter") { -// let res = invokeFunctionTwiceConstRef(.init({ $0 + std.string("abc") }), -// std.string("prefix")) -// expectEqual(std.string("prefixabcabc"), res) -//} +StdFunctionTestSuite.test("FunctionStringToStringConstRef init from closure and pass as parameter") { + let res = invokeFunctionTwiceConstRef(.init({ $0 + std.string("abc") }), + std.string("prefix")) + expectEqual(std.string("prefixabcabc"), res) +} #endif runAllTests() diff --git a/test/Serialization/Inputs/convention_c_function.swift b/test/Serialization/Inputs/convention_c_function.swift new file mode 100644 index 0000000000000..5ae74013b29ec --- /dev/null +++ b/test/Serialization/Inputs/convention_c_function.swift @@ -0,0 +1,3 @@ +public func foo(fn: @convention(c) () -> ()) -> () { + fn() +} diff --git a/test/Serialization/clang-function-types-convention-c.swift b/test/Serialization/clang-function-types-convention-c.swift new file mode 100644 index 0000000000000..0e1a9b2e9710a --- /dev/null +++ b/test/Serialization/clang-function-types-convention-c.swift @@ -0,0 +1,21 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-module -o %t %S/Inputs/convention_c_function.swift +// RUN: llvm-bcanalyzer %t/convention_c_function.swiftmodule | %FileCheck -check-prefix=CHECK-BCANALYZER %s +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-silgen -I %t %s | %FileCheck %s + +import convention_c_function + +// CHECK-BCANALYZER-LABEL: (INDEX_BLOCK): +// CHECK-BCANALYZER: CLANG_TYPE_OFFSETS + +// Test that the assertion in SILDeclRef doesn't fail. + +// CHECK-LABEL: sil [ossa] @$s4main3baryyF : $@convention(thin) () -> () { +// CHECK: %[[V0:.*]] = function_ref @$s4main3baryyFyycfU_To : $@convention(c) () -> () +// CHECK: %[[V1:.*]] = function_ref @$s21convention_c_function3foo2fnyyyXC_tF : $@convention(thin) (@convention(c) () -> ()) -> () +// CHECK: apply %[[V1]](%[[V0]]) : $@convention(thin) (@convention(c) () -> ()) -> () + +public func bar() { + foo(fn : {}) +} +