Skip to content

[MRE] successive Declare fails if InstantiateFunctionDefinition fails in MakeFunctionCallable #616

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion include/CppInterOp/CppInterOp.h
Original file line number Diff line number Diff line change
Expand Up @@ -743,11 +743,12 @@ struct TemplateArgInfo {
/// in the \c TemplateArgInfo struct
///\param[in] template_args_size - Size of the vector of template arguments
/// passed as \c template_args
///\param[in] instantiate_body - also instantiate/define the body
///
///\returns Instantiated templated class/function/variable pointer
CPPINTEROP_API TCppScope_t
InstantiateTemplate(TCppScope_t tmpl, const TemplateArgInfo* template_args,
size_t template_args_size);
size_t template_args_size, bool instantiate_body = false);

/// Sets the class template instantiation arguments of \c templ_instance.
///
Expand Down
3 changes: 2 additions & 1 deletion lib/CppInterOp/CXCppInterOp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,8 @@ bool clang_existsFunctionTemplate(const char* name, CXScope parent) {
namespace Cpp {
TCppScope_t InstantiateTemplate(compat::Interpreter& I, TCppScope_t tmpl,
const TemplateArgInfo* template_args,
size_t template_args_size);
size_t template_args_size,
bool instantiate_body = false);
} // namespace Cpp

CXScope clang_instantiateTemplate(CXScope tmpl,
Expand Down
19 changes: 19 additions & 0 deletions lib/CppInterOp/Compatibility.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ namespace compat {

using Interpreter = cling::Interpreter;

class PushTransactionRAII : public Interpreter::PushTransactionRAII {
public:
PushTransactionRAII(Interpreter* i) : Interpreter::PushTransactionRAII(i) {}
};

inline void maybeMangleDeclName(const clang::GlobalDecl& GD,
std::string& mangledName) {
cling::utils::Analyze::maybeMangleDeclName(GD, mangledName);
Expand Down Expand Up @@ -376,6 +381,20 @@ namespace Cpp_utils = Cpp::utils;

namespace compat {
using Interpreter = Cpp::Interpreter;

class PushTransactionRAII {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: class 'PushTransactionRAII' defines a non-default destructor but does not define a copy constructor, a copy assignment operator, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]

class PushTransactionRAII {
      ^

private:
Interpreter* m_Interpreter;

public:
PushTransactionRAII(Interpreter* i) : m_Interpreter(i) {}
~PushTransactionRAII() {
auto GeneratedPTU = m_Interpreter->Parse("");
if (!GeneratedPTU)
llvm::logAllUnhandledErrors(GeneratedPTU.takeError(), llvm::errs(),
"Failed to generate PTU:");
}
};
}

#endif // CPPINTEROP_USE_REPL
Expand Down
46 changes: 26 additions & 20 deletions lib/CppInterOp/CppInterOp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/Version.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Interpreter/Interpreter.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Overload.h"
#include "clang/Sema/Ownership.h"
Expand Down Expand Up @@ -222,6 +223,15 @@

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

static void InstantiateFunctionDefinition(Decl* D) {
compat::PushTransactionRAII RAII(&getInterp());
if (auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D)) {
getSema().InstantiateFunctionDefinition(SourceLocation(), FD,
/*Recursive=*/true,
/*DefinitionRequired=*/true);
}
}

bool IsAggregate(TCppScope_t scope) {
Decl* D = static_cast<Decl*>(scope);

Expand Down Expand Up @@ -923,11 +933,7 @@
}

if (needInstantiation) {
#ifdef CPPINTEROP_USE_CLING
cling::Interpreter::PushTransactionRAII RAII(&getInterp());
#endif
getSema().InstantiateFunctionDefinition(SourceLocation(), FD, true,
true);
InstantiateFunctionDefinition(FD);
}
Type = FD->getReturnType();
}
Expand Down Expand Up @@ -2482,14 +2488,8 @@
}
if (needInstantiation) {
clang::FunctionDecl* FDmod = const_cast<clang::FunctionDecl*>(FD);
clang::Sema& S = I.getCI()->getSema();
// Could trigger deserialization of decls.
#ifdef CPPINTEROP_USE_CLING
cling::Interpreter::PushTransactionRAII RAII(&I);
#endif
S.InstantiateFunctionDefinition(SourceLocation(), FDmod,
/*Recursive=*/true,
/*DefinitionRequired=*/true);
InstantiateFunctionDefinition(FDmod);

if (!FD->isDefined(Definition)) {
llvm::errs() << "TClingCallFunc::make_wrapper"
<< ":"
Expand Down Expand Up @@ -3294,7 +3294,8 @@
}

static Decl* InstantiateTemplate(TemplateDecl* TemplateD,
TemplateArgumentListInfo& TLI, Sema& S) {
TemplateArgumentListInfo& TLI, Sema& S,
bool instantiate_body) {
// This is not right but we don't have a lot of options to choose from as a
// template instantiation requires a valid source location.
SourceLocation fakeLoc = GetValidSLoc(S);
Expand All @@ -3308,6 +3309,8 @@
// FIXME: Diagnose what happened.
(void)Result;
}
if (instantiate_body)
InstantiateFunctionDefinition(Specialization);

Check warning on line 3313 in lib/CppInterOp/CppInterOp.cpp

View check run for this annotation

Codecov / codecov/patch

lib/CppInterOp/CppInterOp.cpp#L3313

Added line #L3313 was not covered by tests
return Specialization;
}

Expand Down Expand Up @@ -3339,19 +3342,21 @@
}

Decl* InstantiateTemplate(TemplateDecl* TemplateD,
ArrayRef<TemplateArgument> TemplateArgs, Sema& S) {
ArrayRef<TemplateArgument> TemplateArgs, Sema& S,
bool instantiate_body) {
// Create a list of template arguments.
TemplateArgumentListInfo TLI{};
for (auto TA : TemplateArgs)
TLI.addArgument(
S.getTrivialTemplateArgumentLoc(TA, QualType(), SourceLocation()));

return InstantiateTemplate(TemplateD, TLI, S);
return InstantiateTemplate(TemplateD, TLI, S, instantiate_body);
}

TCppScope_t InstantiateTemplate(compat::Interpreter& I, TCppScope_t tmpl,
const TemplateArgInfo* template_args,
size_t template_args_size) {
size_t template_args_size,
bool instantiate_body) {
auto& S = I.getSema();
auto& C = S.getASTContext();

Expand All @@ -3376,14 +3381,15 @@
#ifdef CPPINTEROP_USE_CLING
cling::Interpreter::PushTransactionRAII RAII(&I);
#endif
return InstantiateTemplate(TmplD, TemplateArgs, S);
return InstantiateTemplate(TmplD, TemplateArgs, S, instantiate_body);
}

TCppScope_t InstantiateTemplate(TCppScope_t tmpl,
const TemplateArgInfo* template_args,
size_t template_args_size) {
size_t template_args_size,
bool instantiate_body) {
return InstantiateTemplate(getInterp(), tmpl, template_args,
template_args_size);
template_args_size, instantiate_body);
}

void GetClassTemplateInstantiationArgs(TCppScope_t templ_instance,
Expand Down
35 changes: 35 additions & 0 deletions unittests/CppInterOp/FunctionReflectionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2133,3 +2133,38 @@ TEST(FunctionReflectionTest, UndoTest) {
#endif
#endif
}

TEST(FunctionReflectionTest, FailingTest1) {
#ifdef _WIN32
GTEST_SKIP() << "Disabled on Windows. Needs fixing.";
#endif
#ifdef EMSCRIPTEN
GTEST_SKIP() << "Test fails for Emscipten builds";
#endif
Cpp::CreateInterpreter();
EXPECT_FALSE(Cpp::Declare(R"(
class WithOutEqualOp1 {};
class WithOutEqualOp2 {};

WithOutEqualOp1 o1;
WithOutEqualOp2 o2;

template<class C1, class C2>
bool is_equal(const C1& c1, const C2& c2) { return (bool)(c1 == c2); }
)"));

Cpp::TCppType_t o1 = Cpp::GetTypeFromScope(Cpp::GetNamed("o1"));
Cpp::TCppType_t o2 = Cpp::GetTypeFromScope(Cpp::GetNamed("o2"));
std::vector<Cpp::TCppFunction_t> fns;
Cpp::GetClassTemplatedMethods("is_equal", Cpp::GetGlobalScope(), fns);
EXPECT_EQ(fns.size(), 1);

Cpp::TemplateArgInfo args[2] = {{o1}, {o2}};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not declare C-style arrays, use std::array<> instead [cppcoreguidelines-avoid-c-arrays]

  Cpp::TemplateArgInfo args[2] = {{o1}, {o2}};
  ^

Cpp::TCppScope_t fn = Cpp::InstantiateTemplate(fns[0], args, 2);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead [cppcoreguidelines-pro-bounds-array-to-pointer-decay]

  Cpp::TCppScope_t fn = Cpp::InstantiateTemplate(fns[0], args, 2);
                                                         ^

EXPECT_TRUE(fn);

Cpp::JitCall jit_call = Cpp::MakeFunctionCallable(fn);
EXPECT_EQ(jit_call.getKind(), Cpp::JitCall::kUnknown); // expected to fail
EXPECT_FALSE(Cpp::Declare("int x = 1;"));
EXPECT_FALSE(Cpp::Declare("int y = x;"));
}
6 changes: 3 additions & 3 deletions unittests/CppInterOp/VariableReflectionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -559,9 +559,9 @@ TEST(VariableReflectionTest, StaticConstExprDatamember) {
std::vector<Cpp::TemplateArgInfo> template_args = {
{C.IntTy.getAsOpaquePtr(), "5"}};

Cpp::TCppFunction_t MyTemplatedClass =
Cpp::InstantiateTemplate(Cpp::GetNamed("MyTemplatedClass"),
template_args.data(), template_args.size());
Cpp::TCppFunction_t MyTemplatedClass = Cpp::InstantiateTemplate(
Cpp::GetNamed("MyTemplatedClass"), template_args.data(),
template_args.size(), true);
EXPECT_TRUE(MyTemplatedClass);

datamembers.clear();
Expand Down
Loading