Skip to content

Commit 49e6f4c

Browse files
fix: successive Declare fails if InstantiateFunctionDefinition fails in MakeFunctionCallable (#616)
* [MRE] successive Declare fails if InstantiateFunctionDefinition fails in MakeFunctionCallable * fix: by forcing to compile an empty code block * fix test to use `InstantiateTemplate` instead of `BestOverloadFunctionMatch` * add `SynthesizingCodeRAII` that works with both clang & cling add `InstantiateFunctionDefinition` function
1 parent cce6bac commit 49e6f4c

File tree

5 files changed

+85
-23
lines changed

5 files changed

+85
-23
lines changed

include/CppInterOp/CppInterOp.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -743,11 +743,12 @@ struct TemplateArgInfo {
743743
/// in the \c TemplateArgInfo struct
744744
///\param[in] template_args_size - Size of the vector of template arguments
745745
/// passed as \c template_args
746+
///\param[in] instantiate_body - also instantiate/define the body
746747
///
747748
///\returns Instantiated templated class/function/variable pointer
748749
CPPINTEROP_API TCppScope_t
749750
InstantiateTemplate(TCppScope_t tmpl, const TemplateArgInfo* template_args,
750-
size_t template_args_size);
751+
size_t template_args_size, bool instantiate_body = false);
751752

752753
/// Sets the class template instantiation arguments of \c templ_instance.
753754
///

lib/CppInterOp/CXCppInterOp.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,8 @@ bool clang_existsFunctionTemplate(const char* name, CXScope parent) {
571571
namespace Cpp {
572572
TCppScope_t InstantiateTemplate(compat::Interpreter& I, TCppScope_t tmpl,
573573
const TemplateArgInfo* template_args,
574-
size_t template_args_size);
574+
size_t template_args_size,
575+
bool instantiate_body = false);
575576
} // namespace Cpp
576577

577578
CXScope clang_instantiateTemplate(CXScope tmpl,

lib/CppInterOp/Compatibility.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ namespace compat {
9999

100100
using Interpreter = cling::Interpreter;
101101

102+
class SynthesizingCodeRAII : public Interpreter::PushTransactionRAII {
103+
public:
104+
SynthesizingCodeRAII(Interpreter* i) : Interpreter::PushTransactionRAII(i) {}
105+
};
106+
102107
inline void maybeMangleDeclName(const clang::GlobalDecl& GD,
103108
std::string& mangledName) {
104109
cling::utils::Analyze::maybeMangleDeclName(GD, mangledName);
@@ -376,6 +381,20 @@ namespace Cpp_utils = Cpp::utils;
376381

377382
namespace compat {
378383
using Interpreter = Cpp::Interpreter;
384+
385+
class SynthesizingCodeRAII {
386+
private:
387+
Interpreter* m_Interpreter;
388+
389+
public:
390+
SynthesizingCodeRAII(Interpreter* i) : m_Interpreter(i) {}
391+
~SynthesizingCodeRAII() {
392+
auto GeneratedPTU = m_Interpreter->Parse("");
393+
if (!GeneratedPTU)
394+
llvm::logAllUnhandledErrors(GeneratedPTU.takeError(), llvm::errs(),
395+
"Failed to generate PTU:");
396+
}
397+
};
379398
}
380399

381400
#endif // CPPINTEROP_USE_REPL

lib/CppInterOp/CppInterOp.cpp

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "clang/Basic/Specifiers.h"
3434
#include "clang/Basic/Version.h"
3535
#include "clang/Frontend/CompilerInstance.h"
36+
#include "clang/Interpreter/Interpreter.h"
3637
#include "clang/Sema/Lookup.h"
3738
#include "clang/Sema/Overload.h"
3839
#include "clang/Sema/Ownership.h"
@@ -222,6 +223,15 @@ void EnableDebugOutput(bool value /* =true*/) { llvm::DebugFlag = value; }
222223

223224
bool IsDebugOutputEnabled() { return llvm::DebugFlag; }
224225

226+
static void InstantiateFunctionDefinition(Decl* D) {
227+
compat::SynthesizingCodeRAII RAII(&getInterp());
228+
if (auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D)) {
229+
getSema().InstantiateFunctionDefinition(SourceLocation(), FD,
230+
/*Recursive=*/true,
231+
/*DefinitionRequired=*/true);
232+
}
233+
}
234+
225235
bool IsAggregate(TCppScope_t scope) {
226236
Decl* D = static_cast<Decl*>(scope);
227237

@@ -923,11 +933,7 @@ TCppType_t GetFunctionReturnType(TCppFunction_t func) {
923933
}
924934

925935
if (needInstantiation) {
926-
#ifdef CPPINTEROP_USE_CLING
927-
cling::Interpreter::PushTransactionRAII RAII(&getInterp());
928-
#endif
929-
getSema().InstantiateFunctionDefinition(SourceLocation(), FD, true,
930-
true);
936+
InstantiateFunctionDefinition(FD);
931937
}
932938
Type = FD->getReturnType();
933939
}
@@ -2491,14 +2497,8 @@ int get_wrapper_code(compat::Interpreter& I, const FunctionDecl* FD,
24912497
}
24922498
if (needInstantiation) {
24932499
clang::FunctionDecl* FDmod = const_cast<clang::FunctionDecl*>(FD);
2494-
clang::Sema& S = I.getCI()->getSema();
2495-
// Could trigger deserialization of decls.
2496-
#ifdef CPPINTEROP_USE_CLING
2497-
cling::Interpreter::PushTransactionRAII RAII(&I);
2498-
#endif
2499-
S.InstantiateFunctionDefinition(SourceLocation(), FDmod,
2500-
/*Recursive=*/true,
2501-
/*DefinitionRequired=*/true);
2500+
InstantiateFunctionDefinition(FDmod);
2501+
25022502
if (!FD->isDefined(Definition)) {
25032503
llvm::errs() << "TClingCallFunc::make_wrapper"
25042504
<< ":"
@@ -3303,7 +3303,8 @@ std::string ObjToString(const char* type, void* obj) {
33033303
}
33043304

33053305
static Decl* InstantiateTemplate(TemplateDecl* TemplateD,
3306-
TemplateArgumentListInfo& TLI, Sema& S) {
3306+
TemplateArgumentListInfo& TLI, Sema& S,
3307+
bool instantiate_body) {
33073308
// This is not right but we don't have a lot of options to choose from as a
33083309
// template instantiation requires a valid source location.
33093310
SourceLocation fakeLoc = GetValidSLoc(S);
@@ -3317,6 +3318,8 @@ static Decl* InstantiateTemplate(TemplateDecl* TemplateD,
33173318
// FIXME: Diagnose what happened.
33183319
(void)Result;
33193320
}
3321+
if (instantiate_body)
3322+
InstantiateFunctionDefinition(Specialization);
33203323
return Specialization;
33213324
}
33223325

@@ -3348,19 +3351,21 @@ static Decl* InstantiateTemplate(TemplateDecl* TemplateD,
33483351
}
33493352

33503353
Decl* InstantiateTemplate(TemplateDecl* TemplateD,
3351-
ArrayRef<TemplateArgument> TemplateArgs, Sema& S) {
3354+
ArrayRef<TemplateArgument> TemplateArgs, Sema& S,
3355+
bool instantiate_body) {
33523356
// Create a list of template arguments.
33533357
TemplateArgumentListInfo TLI{};
33543358
for (auto TA : TemplateArgs)
33553359
TLI.addArgument(
33563360
S.getTrivialTemplateArgumentLoc(TA, QualType(), SourceLocation()));
33573361

3358-
return InstantiateTemplate(TemplateD, TLI, S);
3362+
return InstantiateTemplate(TemplateD, TLI, S, instantiate_body);
33593363
}
33603364

33613365
TCppScope_t InstantiateTemplate(compat::Interpreter& I, TCppScope_t tmpl,
33623366
const TemplateArgInfo* template_args,
3363-
size_t template_args_size) {
3367+
size_t template_args_size,
3368+
bool instantiate_body) {
33643369
auto& S = I.getSema();
33653370
auto& C = S.getASTContext();
33663371

@@ -3385,14 +3390,15 @@ TCppScope_t InstantiateTemplate(compat::Interpreter& I, TCppScope_t tmpl,
33853390
#ifdef CPPINTEROP_USE_CLING
33863391
cling::Interpreter::PushTransactionRAII RAII(&I);
33873392
#endif
3388-
return InstantiateTemplate(TmplD, TemplateArgs, S);
3393+
return InstantiateTemplate(TmplD, TemplateArgs, S, instantiate_body);
33893394
}
33903395

33913396
TCppScope_t InstantiateTemplate(TCppScope_t tmpl,
33923397
const TemplateArgInfo* template_args,
3393-
size_t template_args_size) {
3398+
size_t template_args_size,
3399+
bool instantiate_body) {
33943400
return InstantiateTemplate(getInterp(), tmpl, template_args,
3395-
template_args_size);
3401+
template_args_size, instantiate_body);
33963402
}
33973403

33983404
void GetClassTemplateInstantiationArgs(TCppScope_t templ_instance,

unittests/CppInterOp/FunctionReflectionTest.cpp

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -905,7 +905,7 @@ TEST(FunctionReflectionTest, InstantiateVariadicFunction) {
905905

906906
// instantiate VariadicFnExtended
907907
auto Instance2 =
908-
Cpp::InstantiateTemplate(Decls[2], args2.data(), args2.size());
908+
Cpp::InstantiateTemplate(Decls[2], args2.data(), args2.size(), true);
909909
EXPECT_TRUE(Cpp::IsTemplatedFunction(Instance2));
910910

911911
FunctionDecl* FD2 = cast<FunctionDecl>((Decl*)Instance2);
@@ -2193,3 +2193,38 @@ TEST(FunctionReflectionTest, UndoTest) {
21932193
#endif
21942194
#endif
21952195
}
2196+
2197+
TEST(FunctionReflectionTest, FailingTest1) {
2198+
#ifdef _WIN32
2199+
GTEST_SKIP() << "Disabled on Windows. Needs fixing.";
2200+
#endif
2201+
#ifdef EMSCRIPTEN
2202+
GTEST_SKIP() << "Test fails for Emscipten builds";
2203+
#endif
2204+
Cpp::CreateInterpreter();
2205+
EXPECT_FALSE(Cpp::Declare(R"(
2206+
class WithOutEqualOp1 {};
2207+
class WithOutEqualOp2 {};
2208+
2209+
WithOutEqualOp1 o1;
2210+
WithOutEqualOp2 o2;
2211+
2212+
template<class C1, class C2>
2213+
bool is_equal(const C1& c1, const C2& c2) { return (bool)(c1 == c2); }
2214+
)"));
2215+
2216+
Cpp::TCppType_t o1 = Cpp::GetTypeFromScope(Cpp::GetNamed("o1"));
2217+
Cpp::TCppType_t o2 = Cpp::GetTypeFromScope(Cpp::GetNamed("o2"));
2218+
std::vector<Cpp::TCppFunction_t> fns;
2219+
Cpp::GetClassTemplatedMethods("is_equal", Cpp::GetGlobalScope(), fns);
2220+
EXPECT_EQ(fns.size(), 1);
2221+
2222+
Cpp::TemplateArgInfo args[2] = {{o1}, {o2}};
2223+
Cpp::TCppScope_t fn = Cpp::InstantiateTemplate(fns[0], args, 2);
2224+
EXPECT_TRUE(fn);
2225+
2226+
Cpp::JitCall jit_call = Cpp::MakeFunctionCallable(fn);
2227+
EXPECT_EQ(jit_call.getKind(), Cpp::JitCall::kUnknown); // expected to fail
2228+
EXPECT_FALSE(Cpp::Declare("int x = 1;"));
2229+
EXPECT_FALSE(Cpp::Declare("int y = x;"));
2230+
}

0 commit comments

Comments
 (0)