Skip to content

Commit 7bb23b9

Browse files
fix: codegen need not instantiate func body if it can be resolved (#626)
This is the case where the the instantiated function is present in one of the libraries loaded or the host application.
1 parent f23844b commit 7bb23b9

File tree

2 files changed

+62
-14
lines changed

2 files changed

+62
-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: 40 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,35 @@ 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+
Cpp::BeginStdStreamCapture(Cpp::CaptureStreamKind::kStdErr);
1861+
instantiation_in_host_callable =
1862+
Cpp::MakeFunctionCallable(instantiation_in_host);
1863+
std::string err_msg = Cpp::EndStdStreamCapture();
1864+
EXPECT_TRUE(err_msg.find("instantiation with no body") != std::string::npos);
1865+
EXPECT_EQ(instantiation_in_host_callable.getKind(),
1866+
Cpp::JitCall::kUnknown); // expect to fail
18271867
}
18281868

18291869
TEST(FunctionReflectionTest, IsConstMethod) {

0 commit comments

Comments
 (0)