Skip to content

Commit 703de04

Browse files
fix: codegen need not instantiate func body if it can be resolved
This is the case where the the instantiated function is present in one of the libraries loaded or the host application.
1 parent d9bf9ab commit 703de04

File tree

2 files changed

+59
-14
lines changed

2 files changed

+59
-14
lines changed

lib/CppInterOp/CppInterOp.cpp

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,10 +1260,8 @@ TCppFuncAddr_t GetFunctionAddress(const char* mangled_name) {
12601260
return nullptr;
12611261
}
12621262

1263-
TCppFuncAddr_t GetFunctionAddress(TCppFunction_t method) {
1264-
auto* D = (Decl*)method;
1265-
1266-
const auto get_mangled_name = [](FunctionDecl* FD) {
1263+
static TCppFuncAddr_t GetFunctionAddress(const FunctionDecl* FD) {
1264+
const auto get_mangled_name = [](const FunctionDecl* FD) {
12671265
auto MangleCtxt = getASTContext().createMangleContext();
12681266

12691267
if (!MangleCtxt->shouldMangleDeclName(FD)) {
@@ -1281,12 +1279,20 @@ TCppFuncAddr_t GetFunctionAddress(TCppFunction_t method) {
12811279
return mangled_name;
12821280
};
12831281

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

12871286
return 0;
12881287
}
12891288

1289+
TCppFuncAddr_t GetFunctionAddress(TCppFunction_t method) {
1290+
auto* D = static_cast<Decl*>(method);
1291+
if (auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D))
1292+
return GetFunctionAddress(FD);
1293+
return nullptr;
1294+
}
1295+
12901296
bool IsVirtualMethod(TCppFunction_t method) {
12911297
auto* D = (Decl*)method;
12921298
if (auto* CXXMD = llvm::dyn_cast_or_null<CXXMethodDecl>(D)) {
@@ -2386,15 +2392,17 @@ int get_wrapper_code(compat::Interpreter& I, const FunctionDecl* FD,
23862392
// header file.
23872393
break;
23882394
}
2389-
if (!Pattern->hasBody()) {
2390-
llvm::errs() << "TClingCallFunc::make_wrapper"
2391-
<< ":"
2392-
<< "Cannot make wrapper for a function template"
2393-
"instantiation with no body!";
2394-
return 0;
2395-
}
2396-
if (FD->isImplicitlyInstantiable()) {
2397-
needInstantiation = true;
2395+
if (!GetFunctionAddress(FD)) {
2396+
if (!Pattern->hasBody()) {
2397+
llvm::errs() << "TClingCallFunc::make_wrapper"
2398+
<< ":"
2399+
<< "Cannot make wrapper for a function template "
2400+
<< "instantiation with no body!";
2401+
return 0;
2402+
}
2403+
if (FD->isImplicitlyInstantiable()) {
2404+
needInstantiation = true;
2405+
}
23982406
}
23992407
} break;
24002408
case FunctionDecl::TK_DependentFunctionTemplateSpecialization: {

unittests/CppInterOp/FunctionReflectionTest.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1489,6 +1489,15 @@ TEST(FunctionReflectionTest, JitCallAdvanced) {
14891489
clang_Interpreter_dispose(I);
14901490
}
14911491

1492+
template <typename T> T instantiation_in_host() { return T(0); }
1493+
#if defined(_WIN32)
1494+
template __declspec(dllexport) int instantiation_in_host<int>();
1495+
#elif defined(__GNUC__)
1496+
template __attribute__((__visibility__("default"))) int
1497+
instantiation_in_host<int>();
1498+
#else
1499+
template int instantiation_in_host<int>();
1500+
#endif
14921501

14931502
TEST(FunctionReflectionTest, GetFunctionCallWrapper) {
14941503
#ifdef EMSCRIPTEN
@@ -1824,6 +1833,34 @@ TEST(FunctionReflectionTest, GetFunctionCallWrapper) {
18241833

18251834
auto fn_callable = Cpp::MakeFunctionCallable(fn);
18261835
EXPECT_EQ(fn_callable.getKind(), Cpp::JitCall::kGenericCall);
1836+
1837+
// instantiation in host, no template function body
1838+
Interp->process("template<typename T> T instantiation_in_host();");
1839+
1840+
unresolved_candidate_methods.clear();
1841+
Cpp::GetClassTemplatedMethods("instantiation_in_host", Cpp::GetGlobalScope(),
1842+
unresolved_candidate_methods);
1843+
EXPECT_EQ(unresolved_candidate_methods.size(), 1);
1844+
1845+
Cpp::TCppScope_t instantiation_in_host = Cpp::BestOverloadFunctionMatch(
1846+
unresolved_candidate_methods, {Cpp::GetType("int")}, {});
1847+
EXPECT_TRUE(instantiation_in_host);
1848+
1849+
Cpp::JitCall instantiation_in_host_callable =
1850+
Cpp::MakeFunctionCallable(instantiation_in_host);
1851+
EXPECT_EQ(instantiation_in_host_callable.getKind(),
1852+
Cpp::JitCall::kGenericCall);
1853+
1854+
instantiation_in_host = Cpp::BestOverloadFunctionMatch(
1855+
unresolved_candidate_methods, {Cpp::GetType("double")}, {});
1856+
EXPECT_TRUE(instantiation_in_host);
1857+
1858+
instantiation_in_host_callable =
1859+
Cpp::MakeFunctionCallable(instantiation_in_host);
1860+
EXPECT_EQ(instantiation_in_host_callable.getKind(),
1861+
Cpp::JitCall::kUnknown); // expect to fail with
1862+
// TClingCallFunc::make_wrapper:
1863+
// instantiation with no body!
18271864
}
18281865

18291866
TEST(FunctionReflectionTest, IsConstMethod) {

0 commit comments

Comments
 (0)