Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 22 additions & 14 deletions lib/CppInterOp/CppInterOp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand All @@ -1281,12 +1279,20 @@ TCppFuncAddr_t GetFunctionAddress(TCppFunction_t method) {
return mangled_name;
};

if (auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D))
// Constructor and Destructors needs to be handled differently
if (!llvm::isa<CXXConstructorDecl>(FD) && !llvm::isa<CXXDestructorDecl>(FD))
return GetFunctionAddress(get_mangled_name(FD).c_str());

return 0;
}

TCppFuncAddr_t GetFunctionAddress(TCppFunction_t method) {
auto* D = static_cast<Decl*>(method);
if (auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D))
return GetFunctionAddress(FD);
return nullptr;
}

bool IsVirtualMethod(TCppFunction_t method) {
auto* D = (Decl*)method;
if (auto* CXXMD = llvm::dyn_cast_or_null<CXXMethodDecl>(D)) {
Expand Down Expand Up @@ -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: {
Expand Down
40 changes: 40 additions & 0 deletions unittests/CppInterOp/FunctionReflectionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -1489,6 +1491,15 @@ TEST(FunctionReflectionTest, JitCallAdvanced) {
clang_Interpreter_dispose(I);
}

template <typename T> T instantiation_in_host() { return T(0); }
#if defined(_WIN32)
template __declspec(dllexport) int instantiation_in_host<int>();
#elif defined(__GNUC__)
template __attribute__((__visibility__("default"))) int
instantiation_in_host<int>();
#else
template int instantiation_in_host<int>();
#endif

TEST(FunctionReflectionTest, GetFunctionCallWrapper) {
#ifdef EMSCRIPTEN
Expand Down Expand Up @@ -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<typename T> 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) {
Expand Down
Loading