Skip to content

Commit 6cf1c06

Browse files
fix GetFunctionAddress for templated functions (#702)
1 parent d373d42 commit 6cf1c06

File tree

2 files changed

+68
-34
lines changed

2 files changed

+68
-34
lines changed

lib/CppInterOp/CppInterOp.cpp

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "Compatibility.h"
1313

14+
#include "clang/AST/Attrs.inc"
1415
#include "clang/AST/CXXInheritance.h"
1516
#include "clang/AST/Decl.h"
1617
#include "clang/AST/DeclAccessPair.h"
@@ -48,12 +49,14 @@
4849
#include "llvm/ADT/StringRef.h"
4950
#include "llvm/Demangle/Demangle.h"
5051
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
52+
#include "llvm/IR/GlobalValue.h"
5153
#include "llvm/Support/Casting.h"
5254
#include "llvm/Support/CommandLine.h"
5355
#include "llvm/Support/Debug.h"
56+
#include "llvm/Support/Error.h"
5457
#include "llvm/Support/ManagedStatic.h"
5558
#include "llvm/Support/Path.h"
56-
#include "llvm/Support/raw_os_ostream.h"
59+
#include "llvm/Support/raw_ostream.h"
5760

5861
#include <algorithm>
5962
#include <cassert>
@@ -66,6 +69,7 @@
6669
#include <sstream>
6770
#include <stack>
6871
#include <string>
72+
#include <utility>
6973

7074
// Stream redirect.
7175
#ifdef _WIN32
@@ -136,6 +140,42 @@ static compat::Interpreter& getInterp() {
136140
static clang::Sema& getSema() { return getInterp().getCI()->getSema(); }
137141
static clang::ASTContext& getASTContext() { return getSema().getASTContext(); }
138142

143+
static void ForceCodeGen(Decl* D, compat::Interpreter& I) {
144+
// The decl was deferred by CodeGen. Force its emission.
145+
// FIXME: In ASTContext::DeclMustBeEmitted we should check if the
146+
// Decl::isUsed is set or we should be able to access CodeGen's
147+
// addCompilerUsedGlobal.
148+
ASTContext& C = I.getSema().getASTContext();
149+
150+
D->addAttr(UsedAttr::CreateImplicit(C));
151+
#ifdef CPPINTEROP_USE_CLING
152+
cling::Interpreter::PushTransactionRAII RAII(&I);
153+
I.getCI()->getASTConsumer().HandleTopLevelDecl(DeclGroupRef(D));
154+
#else // CLANG_REPL
155+
I.getCI()->getASTConsumer().HandleTopLevelDecl(DeclGroupRef(D));
156+
// Take the newest llvm::Module produced by CodeGen and send it to JIT.
157+
auto GeneratedPTU = I.Parse("");
158+
if (!GeneratedPTU)
159+
llvm::logAllUnhandledErrors(GeneratedPTU.takeError(), llvm::errs(),
160+
"[ForceCodeGen] Failed to generate PTU:");
161+
162+
// From cling's BackendPasses.cpp
163+
// FIXME: We need to upstream this code in IncrementalExecutor::addModule
164+
for (auto& GV : GeneratedPTU->TheModule->globals()) {
165+
llvm::GlobalValue::LinkageTypes LT = GV.getLinkage();
166+
if (GV.isDeclaration() || !GV.hasName() ||
167+
GV.getName().starts_with(".str") ||
168+
!llvm::GlobalVariable::isDiscardableIfUnused(LT) ||
169+
LT != llvm::GlobalValue::InternalLinkage)
170+
continue; // nothing to do
171+
GV.setLinkage(llvm::GlobalValue::WeakAnyLinkage);
172+
}
173+
if (auto Err = I.Execute(*GeneratedPTU))
174+
llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(),
175+
"[ForceCodeGen] Failed to execute PTU:");
176+
#endif
177+
}
178+
139179
#define DEBUG_TYPE "jitcall"
140180
bool JitCall::AreArgumentsValid(void* result, ArgList args, void* self,
141181
size_t nary) const {
@@ -1335,8 +1375,16 @@ static TCppFuncAddr_t GetFunctionAddress(const FunctionDecl* FD) {
13351375

13361376
TCppFuncAddr_t GetFunctionAddress(TCppFunction_t method) {
13371377
auto* D = static_cast<Decl*>(method);
1338-
if (auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D))
1378+
if (auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D)) {
1379+
if ((IsTemplateInstantiationOrSpecialization(FD) ||
1380+
FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization) &&
1381+
!FD->getDefinition())
1382+
InstantiateFunctionDefinition(D);
1383+
ASTContext& C = getASTContext();
1384+
if (isDiscardableGVALinkage(C.GetGVALinkageForFunction(FD)))
1385+
ForceCodeGen(FD, getInterp());
13391386
return GetFunctionAddress(FD);
1387+
}
13401388
return nullptr;
13411389
}
13421390

@@ -1554,39 +1602,8 @@ intptr_t GetVariableOffset(compat::Interpreter& I, Decl* D,
15541602
}
15551603
if (!address) {
15561604
auto Linkage = C.GetGVALinkageForVariable(VD);
1557-
// The decl was deferred by CodeGen. Force its emission.
1558-
// FIXME: In ASTContext::DeclMustBeEmitted we should check if the
1559-
// Decl::isUsed is set or we should be able to access CodeGen's
1560-
// addCompilerUsedGlobal.
15611605
if (isDiscardableGVALinkage(Linkage))
1562-
VD->addAttr(UsedAttr::CreateImplicit(C));
1563-
#ifdef CPPINTEROP_USE_CLING
1564-
cling::Interpreter::PushTransactionRAII RAII(&I);
1565-
I.getCI()->getASTConsumer().HandleTopLevelDecl(DeclGroupRef(VD));
1566-
#else // CLANG_REPL
1567-
I.getCI()->getASTConsumer().HandleTopLevelDecl(DeclGroupRef(VD));
1568-
// Take the newest llvm::Module produced by CodeGen and send it to JIT.
1569-
auto GeneratedPTU = I.Parse("");
1570-
if (!GeneratedPTU)
1571-
llvm::logAllUnhandledErrors(
1572-
GeneratedPTU.takeError(), llvm::errs(),
1573-
"[GetVariableOffset] Failed to generate PTU:");
1574-
1575-
// From cling's BackendPasses.cpp
1576-
// FIXME: We need to upstream this code in IncrementalExecutor::addModule
1577-
for (auto& GV : GeneratedPTU->TheModule->globals()) {
1578-
llvm::GlobalValue::LinkageTypes LT = GV.getLinkage();
1579-
if (GV.isDeclaration() || !GV.hasName() ||
1580-
GV.getName().starts_with(".str") || !GV.isDiscardableIfUnused(LT) ||
1581-
LT != llvm::GlobalValue::InternalLinkage)
1582-
continue; // nothing to do
1583-
GV.setLinkage(llvm::GlobalValue::WeakAnyLinkage);
1584-
}
1585-
if (auto Err = I.Execute(*GeneratedPTU))
1586-
llvm::logAllUnhandledErrors(
1587-
std::move(Err), llvm::errs(),
1588-
"[GetVariableOffset] Failed to execute PTU:");
1589-
#endif
1606+
ForceCodeGen(VD, I);
15901607
}
15911608
auto VDAorErr = compat::getSymbolAddress(I, StringRef(mangledName));
15921609
if (!VDAorErr) {

unittests/CppInterOp/FunctionReflectionTest.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1469,6 +1469,23 @@ TEST(FunctionReflectionTest, GetFunctionAddress) {
14691469
EXPECT_EQ(address.str(), output);
14701470

14711471
EXPECT_FALSE(Cpp::GetFunctionAddress(Cpp::GetGlobalScope()));
1472+
1473+
Interp->declare(R"(
1474+
template <typename T>
1475+
T add1(T t) { return t + 1; }
1476+
)");
1477+
1478+
std::vector<Cpp::TCppFunction_t> funcs;
1479+
Cpp::GetClassTemplatedMethods("add1", Cpp::GetGlobalScope(), funcs);
1480+
EXPECT_EQ(funcs.size(), 1);
1481+
1482+
ASTContext& C = Interp->getCI()->getASTContext();
1483+
std::vector<Cpp::TemplateArgInfo> argument = {C.DoubleTy.getAsOpaquePtr()};
1484+
Cpp::TCppScope_t add1_double =
1485+
Cpp::InstantiateTemplate(funcs[0], argument.data(), argument.size());
1486+
EXPECT_TRUE(add1_double);
1487+
1488+
EXPECT_TRUE(Cpp::GetFunctionAddress(add1_double));
14721489
}
14731490

14741491
TEST(FunctionReflectionTest, IsVirtualMethod) {

0 commit comments

Comments
 (0)