diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index cae226d28d52a..9c6cc97b657f4 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" @@ -4341,10 +4343,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( @@ -4850,15 +4854,21 @@ static AbstractFunctionDecl *getBridgedFunction(SILDeclRef declRef) { } static AbstractionPattern -getAbstractionPatternForConstant(ASTContext &ctx, SILDeclRef constant, - CanAnyFunctionType fnType, +getAbstractionPatternForConstant(TypeConverter &converter, ASTContext &ctx, + SILDeclRef constant, CanAnyFunctionType fnType, unsigned numParameterLists) { if (!constant.isForeign) return AbstractionPattern(fnType); + if (auto *expr = constant.getAbstractClosureExpr()) { + auto &info = converter.getClosureTypeInfo(expr); + return info.OrigType; + } + auto bridgedFn = getBridgedFunction(constant); if (!bridgedFn) return AbstractionPattern(fnType); + const clang::Decl *clangDecl = bridgedFn->getClangDecl(); if (!clangDecl) return AbstractionPattern(fnType); @@ -4901,9 +4911,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( + *this, Context, constant, fnType, numParameterLists); 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/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index fb0f622b8c050..90b4bf5a78a88 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -4259,10 +4259,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..bc72746067250 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -1315,8 +1315,10 @@ 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() && + SGF.useLoweredAddresses()) { auto tmp = SGF.emitTemporaryAllocation(loc, arg->getType().getObjectType()); SGF.B.createCopyAddr(loc, arg, tmp, IsNotTake, IsInitialization); return tmp; @@ -1453,6 +1455,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() && SGF.useLoweredAddresses()) { + // 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 c6385b4cb2aa4..12671f57241c2 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -46,6 +46,7 @@ #include "swift/Basic/Defer.h" #include "swift/Basic/SourceManager.h" #include "swift/Basic/type_traits.h" +#include "swift/SIL/AbstractionPattern.h" #include "swift/SIL/Consumption.h" #include "swift/SIL/DynamicCasts.h" #include "swift/SIL/SILArgument.h" @@ -751,10 +752,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. @@ -1731,11 +1732,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 @@ -1770,9 +1781,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. @@ -1806,20 +1817,33 @@ 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)) { setLocFromConcreteDeclRef(memberRef->getMember()); } else if (isAnyClosureExpr(semanticExpr)) { - (void) emitAnyClosureExpr(SGF, semanticExpr, - [&](AbstractClosureExpr *closure) { - // Emit the closure body. - SGF.SGM.emitClosure(closure, SGF.getClosureTypeInfo(closure)); - - loc = closure; - return ManagedValue(); - }); + if (auto init = C.getAsConversion()) { + auto conv = init->getConversion(); + auto origParamType = conv.getBridgingOriginalInputType(); + if (origParamType.isClangType()) + destFnType = origParamType.getClangType(); + } + (void)emitAnyClosureExpr( + SGF, semanticExpr, [&](AbstractClosureExpr *closure) { + // Emit the closure body. + auto functionInfo = SGF.getClosureTypeInfo(closure); + if (destFnType) { + functionInfo.OrigType = + AbstractionPattern(functionInfo.OrigType.getType(), destFnType); + SGF.SGM.Types.withClosureTypeInfo(closure, functionInfo, [] {}); + } + SGF.SGM.emitClosure(closure, functionInfo); + loc = closure; + return ManagedValue::forInContext(); + }); } else { llvm_unreachable("c function pointer converted from a non-concrete decl ref"); } @@ -1855,13 +1879,10 @@ 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); + return ManagedValue::forObjectRValueWithoutOwnership(cRef); + }); } // Change the representation without changing the signature or @@ -2118,7 +2139,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. @@ -2128,10 +2149,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/SILGenProlog.cpp b/lib/SILGen/SILGenProlog.cpp index 1424062266d10..182f3da1a220c 100644 --- a/lib/SILGen/SILGenProlog.cpp +++ b/lib/SILGen/SILGenProlog.cpp @@ -1658,7 +1658,8 @@ uint16_t SILGenFunction::emitBasicProlog( emitIndirectResultParameters(*this, resultType, origResultType, DC); std::optional origErrorType; - if (origClosureType && !origClosureType->isTypeParameterOrOpaqueArchetype()) { + if (origClosureType && !origClosureType->isTypeParameterOrOpaqueArchetype() && + !origClosureType->isClangType()) { origErrorType = origClosureType->getFunctionThrownErrorType(); if (origErrorType && !errorType) errorType = origErrorType->getEffectiveThrownErrorType(); diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 1e89fd4a67926..d31abe3450ac5 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -8519,9 +8519,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 e1b149205a6d6..6737027470166 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" @@ -5567,6 +5569,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; @@ -5920,10 +5947,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()); @@ -7005,8 +7045,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..9c84201602da2 100644 --- a/test/Interop/Cxx/class/closure-thunk-macosx.swift +++ b/test/Interop/Cxx/class/closure-thunk-macosx.swift @@ -35,3 +35,96 @@ 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:.*]] = function_ref @$s4main19testConstRefTrivialyyFySo0E0VcfU_ : $@convention(thin) (@in_guaranteed Trivial) -> () +// CHECK: %[[V2:.*]] = apply %[[V1]](%0) : $@convention(thin) (@in_guaranteed Trivial) -> () +// CHECK: return %[[V2]] : $() + +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: %[[V2:.*]] = function_ref @$s4main18testConstRefStrongyyFySo9ARCStrongVcfU_ : $@convention(thin) (@in_guaranteed ARCStrong) -> () +// CHECK: %[[V3:.*]] = apply %[[V2]](%[[V1]]) : $@convention(thin) (@in_guaranteed ARCStrong) -> () +// CHECK: destroy_addr %[[V1]] : $*ARCStrong +// CHECK: dealloc_stack %[[V1]] : $*ARCStrong +// CHECK: return %[[V3]] : $() + +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 ea228ffeb6dc8..4509bc8031d33 100644 --- a/test/Interop/Cxx/stdlib/use-std-function.swift +++ b/test/Interop/Cxx/stdlib/use-std-function.swift @@ -55,12 +55,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 : {}) +} +