@@ -1019,3 +1019,90 @@ void swift::conformToCxxVectorIfNeeded(ClangImporter::Implementation &impl,
10191019 rawIteratorTy);
10201020 impl.addSynthesizedProtocolAttrs (decl, {KnownProtocolKind::CxxVector});
10211021}
1022+
1023+ void swift::conformToCxxFunctionIfNeeded (
1024+ ClangImporter::Implementation &impl, NominalTypeDecl *decl,
1025+ const clang::CXXRecordDecl *clangDecl) {
1026+ PrettyStackTraceDecl trace (" conforming to CxxFunction" , decl);
1027+
1028+ assert (decl);
1029+ assert (clangDecl);
1030+ ASTContext &ctx = decl->getASTContext ();
1031+ clang::ASTContext &clangCtx = impl.getClangASTContext ();
1032+ clang::Sema &clangSema = impl.getClangSema ();
1033+
1034+ // Only auto-conform types from the C++ standard library. Custom user types
1035+ // might have a similar interface but different semantics.
1036+ if (!isStdDecl (clangDecl, {" function" }))
1037+ return ;
1038+
1039+ // There is no typealias for the argument types on the C++ side, so to
1040+ // retrieve the argument types we look at the overload of `operator()` that
1041+ // got imported into Swift.
1042+
1043+ auto callAsFunctionDecl = lookupDirectSingleWithoutExtensions<FuncDecl>(
1044+ decl, ctx.getIdentifier (" callAsFunction" ));
1045+ if (!callAsFunctionDecl)
1046+ return ;
1047+
1048+ auto operatorCallDecl = dyn_cast_or_null<clang::CXXMethodDecl>(
1049+ callAsFunctionDecl->getClangDecl ());
1050+ if (!operatorCallDecl)
1051+ return ;
1052+
1053+ std::vector<clang::QualType> operatorCallParamTypes;
1054+ llvm::transform (
1055+ operatorCallDecl->parameters (),
1056+ std::back_inserter (operatorCallParamTypes),
1057+ [](const clang::ParmVarDecl *paramDecl) { return paramDecl->getType (); });
1058+
1059+ auto funcPointerType = clangCtx.getPointerType (clangCtx.getFunctionType (
1060+ operatorCallDecl->getReturnType (), operatorCallParamTypes,
1061+ clang::FunctionProtoType::ExtProtoInfo ()));
1062+
1063+ // Create a fake variable with a function type that matches the type of
1064+ // `operator()`.
1065+ auto fakeFuncPointerVarDecl = clang::VarDecl::Create (
1066+ clangCtx, /* DC*/ clangCtx.getTranslationUnitDecl (),
1067+ clang::SourceLocation (), clang::SourceLocation (), /* Id*/ nullptr ,
1068+ funcPointerType, clangCtx.getTrivialTypeSourceInfo (funcPointerType),
1069+ clang::StorageClass::SC_None);
1070+ auto fakeFuncPointerRefExpr = new (clangCtx) clang::DeclRefExpr (
1071+ clangCtx, fakeFuncPointerVarDecl, false , funcPointerType,
1072+ clang::ExprValueKind::VK_LValue, clang::SourceLocation ());
1073+
1074+ auto clangDeclTyInfo = clangCtx.getTrivialTypeSourceInfo (
1075+ clang::QualType (clangDecl->getTypeForDecl (), 0 ));
1076+ SmallVector<clang::Expr *, 1 > constructExprArgs = {fakeFuncPointerRefExpr};
1077+
1078+ // Instantiate the templated constructor that would accept this fake variable.
1079+ auto constructExprResult = clangSema.BuildCXXTypeConstructExpr (
1080+ clangDeclTyInfo, clangDecl->getLocation (), constructExprArgs,
1081+ clangDecl->getLocation (), /* ListInitialization*/ false );
1082+ if (!constructExprResult.isUsable ())
1083+ return ;
1084+
1085+ auto castExpr = dyn_cast_or_null<clang::CastExpr>(constructExprResult.get ());
1086+ if (!castExpr)
1087+ return ;
1088+
1089+ auto bindTempExpr =
1090+ dyn_cast_or_null<clang::CXXBindTemporaryExpr>(castExpr->getSubExpr ());
1091+ if (!bindTempExpr)
1092+ return ;
1093+
1094+ auto constructExpr =
1095+ dyn_cast_or_null<clang::CXXConstructExpr>(bindTempExpr->getSubExpr ());
1096+ if (!constructExpr)
1097+ return ;
1098+
1099+ auto constructorDecl = constructExpr->getConstructor ();
1100+
1101+ auto importedConstructor =
1102+ impl.importDecl (constructorDecl, impl.CurrentVersion );
1103+ if (!importedConstructor)
1104+ return ;
1105+ decl->addMember (importedConstructor);
1106+
1107+ // TODO: actually conform to some form of CxxFunction protocol
1108+ }
0 commit comments