diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index 7d8e07de69957..c0a52121658c2 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -29,6 +29,7 @@ #include "swift/AST/FunctionRefInfo.h" #include "swift/AST/ProtocolConformanceRef.h" #include "swift/AST/ThrownErrorDestination.h" +#include "swift/AST/Type.h" #include "swift/AST/TypeAlignments.h" #include "swift/Basic/Debug.h" #include "swift/Basic/InlineBitfield.h" @@ -3367,9 +3368,8 @@ class UnresolvedTypeConversionExpr : public ImplicitConversionExpr { /// FIXME: This should be a CapturingExpr. class FunctionConversionExpr : public ImplicitConversionExpr { public: - FunctionConversionExpr(Expr *subExpr, Type type) - : ImplicitConversionExpr(ExprKind::FunctionConversion, subExpr, type) {} - + FunctionConversionExpr(Expr *subExpr, Type type); + static bool classof(const Expr *E) { return E->getKind() == ExprKind::FunctionConversion; } @@ -4290,6 +4290,12 @@ class ClosureExpr : public AbstractClosureExpr { /// The body of the closure. BraceStmt *Body; + /// Used when lowering ClosureExprs to C function pointers. + /// This is required to access the ClangType from SILDeclRef. + /// TODO: this will be redundant after we preserve ClangTypes + /// in the canonical types. + FunctionConversionExpr *ConvertedTo; + friend class GlobalActorAttributeRequest; bool hasNoGlobalActorAttribute() const { @@ -4301,19 +4307,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), ConvertedTo(nullptr) { setParameterList(params); Bits.ClosureExpr.HasAnonymousClosureVars = false; Bits.ClosureExpr.ImplicitSelfCapture = false; @@ -4528,6 +4534,9 @@ class ClosureExpr : public AbstractClosureExpr { ExplicitResultTypeAndBodyState.setInt(v); } + const FunctionConversionExpr *getConvertedTo() const { return ConvertedTo; } + void setConvertedTo(FunctionConversionExpr *e) { ConvertedTo = e; } + static bool classof(const Expr *E) { return E->getKind() == ExprKind::Closure; } diff --git a/include/swift/SIL/SILDeclRef.h b/include/swift/SIL/SILDeclRef.h index d19a66d34659f..b5c6ebe5ab819 100644 --- a/include/swift/SIL/SILDeclRef.h +++ b/include/swift/SIL/SILDeclRef.h @@ -34,6 +34,10 @@ namespace llvm { class raw_ostream; } +namespace clang { +class Type; +} + namespace swift { enum class EffectsKind : uint8_t; class AbstractFunctionDecl; @@ -261,11 +265,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/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 8ea959c2e94d8..bfbb65c57da7d 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1456,6 +1456,16 @@ DestructureTupleExpr::create(ASTContext &ctx, srcExpr, dstExpr, ty); } +FunctionConversionExpr::FunctionConversionExpr(Expr *subExpr, Type type) + : ImplicitConversionExpr(ExprKind::FunctionConversion, subExpr, type) { + while (auto *PE = dyn_cast(subExpr)) + subExpr = PE->getSubExpr(); + if (auto *CLE = dyn_cast(subExpr)) + subExpr = CLE->getClosureBody(); + if (auto *CE = dyn_cast(subExpr)) + CE->setConvertedTo(this); +} + SourceRange TupleExpr::getSourceRange() const { auto start = LParenLoc; if (start.isInvalid()) { diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 1e916de1b565c..31d3b0bafac1b 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" @@ -4321,12 +4323,10 @@ 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); - AbstractionPattern pattern = - AbstractionPattern(origLoweredInterfaceType, clangType); + assert(!extInfoBuilder.getClangTypeInfo().empty() && + "clang type not found"); + AbstractionPattern pattern = AbstractionPattern( + origLoweredInterfaceType, extInfoBuilder.getClangTypeInfo().getType()); return getSILFunctionTypeForAbstractCFunction( TC, pattern, origLoweredInterfaceType, extInfoBuilder, constant); } @@ -4834,9 +4834,22 @@ getAbstractionPatternForConstant(ASTContext &ctx, SILDeclRef constant, if (!constant.isForeign) return AbstractionPattern(fnType); + if (const auto *closure = dyn_cast_or_null( + constant.loc.dyn_cast())) { + if (const auto *convertedTo = closure->getConvertedTo()) { + auto clangInfo = convertedTo->getType() + ->castTo() + ->getExtInfo() + .getClangTypeInfo(); + if (!clangInfo.empty()) + return AbstractionPattern(fnType, clangInfo.getType()); + } + } + auto bridgedFn = getBridgedFunction(constant); if (!bridgedFn) return AbstractionPattern(fnType); + const clang::Decl *clangDecl = bridgedFn->getClangDecl(); if (!clangDecl) return AbstractionPattern(fnType); 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/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 148cf3514c80f..94e0f878f8100 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -1733,7 +1733,19 @@ static ManagedValue convertCFunctionSignature(SILGenFunction &SGF, FunctionConversionExpr *e, SILType loweredResultTy, llvm::function_ref fnEmitter) { - SILType loweredDestTy = SGF.getLoweredType(e->getType()); + SILType loweredDestTy; + auto destTy = e->getType(); + auto clangInfo = + destTy->castTo()->getExtInfo().getClangTypeInfo(); + if (clangInfo.empty()) + loweredDestTy = SGF.getLoweredType(destTy); + else + // This won't be necessary after we stop dropping clang types when + // canonicalizing function types. + loweredDestTy = SGF.getLoweredType( + AbstractionPattern(destTy->getCanonicalType(), clangInfo.getType()), + destTy); + ManagedValue result; // We're converting between C function pointer types. They better be @@ -1804,20 +1816,20 @@ ManagedValue emitCFunctionPointer(SILGenFunction &SGF, #endif semanticExpr = conv->getSubExpr()->getSemanticsProvidingExpr(); } - + 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)); + (void)emitAnyClosureExpr( + SGF, semanticExpr, [&](AbstractClosureExpr *closure) { + // Emit the closure body. + SGF.SGM.emitClosure(closure, SGF.getClosureTypeInfo(closure)); - loc = closure; - return ManagedValue(); - }); + loc = closure; + return ManagedValue(); + }); } else { llvm_unreachable("c function pointer converted from a non-concrete decl ref"); } diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 7a1d9a5bb074e..74243998b378f 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -8495,9 +8495,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 59fd3dfef2851..a7751143d4e57 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" @@ -5546,6 +5548,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; @@ -5899,10 +5926,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()); @@ -6984,8 +7024,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 : {}) +} +