Skip to content

Commit b20d0d7

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 b20d0d7

File tree

2 files changed

+61
-14
lines changed

2 files changed

+61
-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: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,6 +1421,8 @@ TEST(FunctionReflectionTest, GetFunctionAddress) {
14211421
std::stringstream address;
14221422
address << Cpp::GetFunctionAddress(Decls[0]);
14231423
EXPECT_EQ(address.str(), output);
1424+
1425+
EXPECT_FALSE(Cpp::GetFunctionAddress(Cpp::GetGlobalScope()));
14241426
}
14251427

14261428
TEST(FunctionReflectionTest, IsVirtualMethod) {
@@ -1489,6 +1491,15 @@ TEST(FunctionReflectionTest, JitCallAdvanced) {
14891491
clang_Interpreter_dispose(I);
14901492
}
14911493

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

14931504
TEST(FunctionReflectionTest, GetFunctionCallWrapper) {
14941505
#ifdef EMSCRIPTEN
@@ -1824,6 +1835,34 @@ TEST(FunctionReflectionTest, GetFunctionCallWrapper) {
18241835

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

18291868
TEST(FunctionReflectionTest, IsConstMethod) {

0 commit comments

Comments
 (0)