diff --git a/lib/CppInterOp/CppInterOp.cpp b/lib/CppInterOp/CppInterOp.cpp index e619750e3..b80f66fe6 100755 --- a/lib/CppInterOp/CppInterOp.cpp +++ b/lib/CppInterOp/CppInterOp.cpp @@ -1260,10 +1260,8 @@ TCppFuncAddr_t GetFunctionAddress(const char* mangled_name) { return nullptr; } -TCppFuncAddr_t GetFunctionAddress(TCppFunction_t method) { - auto* D = (Decl*)method; - - const auto get_mangled_name = [](FunctionDecl* FD) { +static TCppFuncAddr_t GetFunctionAddress(const FunctionDecl* FD) { + const auto get_mangled_name = [](const FunctionDecl* FD) { auto MangleCtxt = getASTContext().createMangleContext(); if (!MangleCtxt->shouldMangleDeclName(FD)) { @@ -1281,12 +1279,20 @@ TCppFuncAddr_t GetFunctionAddress(TCppFunction_t method) { return mangled_name; }; - if (auto* FD = llvm::dyn_cast_or_null(D)) + // Constructor and Destructors needs to be handled differently + if (!llvm::isa(FD) && !llvm::isa(FD)) return GetFunctionAddress(get_mangled_name(FD).c_str()); return 0; } +TCppFuncAddr_t GetFunctionAddress(TCppFunction_t method) { + auto* D = static_cast(method); + if (auto* FD = llvm::dyn_cast_or_null(D)) + return GetFunctionAddress(FD); + return nullptr; +} + bool IsVirtualMethod(TCppFunction_t method) { auto* D = (Decl*)method; if (auto* CXXMD = llvm::dyn_cast_or_null(D)) { @@ -2386,15 +2392,17 @@ int get_wrapper_code(compat::Interpreter& I, const FunctionDecl* FD, // header file. break; } - if (!Pattern->hasBody()) { - llvm::errs() << "TClingCallFunc::make_wrapper" - << ":" - << "Cannot make wrapper for a function template" - "instantiation with no body!"; - return 0; - } - if (FD->isImplicitlyInstantiable()) { - needInstantiation = true; + if (!GetFunctionAddress(FD)) { + if (!Pattern->hasBody()) { + llvm::errs() << "TClingCallFunc::make_wrapper" + << ":" + << "Cannot make wrapper for a function template " + << "instantiation with no body!"; + return 0; + } + if (FD->isImplicitlyInstantiable()) { + needInstantiation = true; + } } } break; case FunctionDecl::TK_DependentFunctionTemplateSpecialization: { diff --git a/unittests/CppInterOp/FunctionReflectionTest.cpp b/unittests/CppInterOp/FunctionReflectionTest.cpp index a4baee5a5..38d6e5462 100644 --- a/unittests/CppInterOp/FunctionReflectionTest.cpp +++ b/unittests/CppInterOp/FunctionReflectionTest.cpp @@ -1421,6 +1421,8 @@ TEST(FunctionReflectionTest, GetFunctionAddress) { std::stringstream address; address << Cpp::GetFunctionAddress(Decls[0]); EXPECT_EQ(address.str(), output); + + EXPECT_FALSE(Cpp::GetFunctionAddress(Cpp::GetGlobalScope())); } TEST(FunctionReflectionTest, IsVirtualMethod) { @@ -1489,6 +1491,15 @@ TEST(FunctionReflectionTest, JitCallAdvanced) { clang_Interpreter_dispose(I); } +template T instantiation_in_host() { return T(0); } +#if defined(_WIN32) +template __declspec(dllexport) int instantiation_in_host(); +#elif defined(__GNUC__) +template __attribute__((__visibility__("default"))) int +instantiation_in_host(); +#else +template int instantiation_in_host(); +#endif TEST(FunctionReflectionTest, GetFunctionCallWrapper) { #ifdef EMSCRIPTEN @@ -1824,6 +1835,35 @@ TEST(FunctionReflectionTest, GetFunctionCallWrapper) { auto fn_callable = Cpp::MakeFunctionCallable(fn); EXPECT_EQ(fn_callable.getKind(), Cpp::JitCall::kGenericCall); + + // instantiation in host, no template function body + Interp->process("template T instantiation_in_host();"); + + unresolved_candidate_methods.clear(); + Cpp::GetClassTemplatedMethods("instantiation_in_host", Cpp::GetGlobalScope(), + unresolved_candidate_methods); + EXPECT_EQ(unresolved_candidate_methods.size(), 1); + + Cpp::TCppScope_t instantiation_in_host = Cpp::BestOverloadFunctionMatch( + unresolved_candidate_methods, {Cpp::GetType("int")}, {}); + EXPECT_TRUE(instantiation_in_host); + + Cpp::JitCall instantiation_in_host_callable = + Cpp::MakeFunctionCallable(instantiation_in_host); + EXPECT_EQ(instantiation_in_host_callable.getKind(), + Cpp::JitCall::kGenericCall); + + instantiation_in_host = Cpp::BestOverloadFunctionMatch( + unresolved_candidate_methods, {Cpp::GetType("double")}, {}); + EXPECT_TRUE(instantiation_in_host); + + Cpp::BeginStdStreamCapture(Cpp::CaptureStreamKind::kStdErr); + instantiation_in_host_callable = + Cpp::MakeFunctionCallable(instantiation_in_host); + std::string err_msg = Cpp::EndStdStreamCapture(); + EXPECT_TRUE(err_msg.find("instantiation with no body") != std::string::npos); + EXPECT_EQ(instantiation_in_host_callable.getKind(), + Cpp::JitCall::kUnknown); // expect to fail } TEST(FunctionReflectionTest, IsConstMethod) {