@@ -1019,3 +1019,90 @@ void swift::conformToCxxVectorIfNeeded(ClangImporter::Implementation &impl,
1019
1019
rawIteratorTy);
1020
1020
impl.addSynthesizedProtocolAttrs (decl, {KnownProtocolKind::CxxVector});
1021
1021
}
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