Skip to content

Commit 10e0d5d

Browse files
fix JITcall codegen to handle move semantics (#657)
Required for std::unique_ptr Taken from Cling
1 parent 55c93cd commit 10e0d5d

File tree

2 files changed

+46
-0
lines changed

2 files changed

+46
-0
lines changed

lib/CppInterOp/CppInterOp.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2151,12 +2151,33 @@ void make_narg_call(const FunctionDecl* FD, const std::string& return_type,
21512151
}
21522152
}
21532153

2154+
CXXRecordDecl* rtdecl = QT->getAsCXXRecordDecl();
21542155
if (refType != kNotReference) {
21552156
callbuf << "(" << type_name.c_str()
21562157
<< (refType == kLValueReference ? "&" : "&&") << ")*("
21572158
<< type_name.c_str() << "*)args[" << i << "]";
21582159
} else if (isPointer) {
21592160
callbuf << "*(" << type_name.c_str() << "**)args[" << i << "]";
2161+
} else if (rtdecl &&
2162+
(rtdecl->hasTrivialCopyConstructor() &&
2163+
!rtdecl->hasSimpleCopyConstructor()) &&
2164+
rtdecl->hasMoveConstructor()) {
2165+
// By-value construction; this may either copy or move, but there is no
2166+
// information here in terms of intent. Thus, simply assume that the
2167+
// intent is to move if there is no viable copy constructor (ie. if the
2168+
// code would otherwise fail to even compile). There does not appear to be
2169+
// a simple way of determining whether a viable copy constructor exists,
2170+
// so check for the most common case: the trivial one, but not uniquely
2171+
// available, while there is a move constructor.
2172+
2173+
// include utility header if not already included for std::move
2174+
DeclarationName DMove = &getASTContext().Idents.get("move");
2175+
auto result = getSema().getStdNamespace()->lookup(DMove);
2176+
if (result.empty())
2177+
Cpp::Declare("#include <utility>");
2178+
2179+
// move construction as needed for classes (note that this is implicit)
2180+
callbuf << "std::move(*(" << type_name.c_str() << "*)args[" << i << "])";
21602181
} else {
21612182
// pointer falls back to non-pointer case; the argument preserves
21622183
// the "pointerness" (i.e. doesn't reference the value).

unittests/CppInterOp/FunctionReflectionTest.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2003,6 +2003,31 @@ TEST(FunctionReflectionTest, GetFunctionCallWrapper) {
20032003

20042004
auto bar_callable = Cpp::MakeFunctionCallable(bar);
20052005
EXPECT_EQ(bar_callable.getKind(), Cpp::JitCall::kGenericCall);
2006+
2007+
Cpp::Declare(R"(
2008+
struct A {
2009+
A() {}
2010+
A(A&& other) {};
2011+
};
2012+
2013+
A consumable;
2014+
2015+
template<typename T>
2016+
void consume(T t) {}
2017+
)");
2018+
2019+
unresolved_candidate_methods.clear();
2020+
Cpp::GetClassTemplatedMethods("consume", Cpp::GetGlobalScope(),
2021+
unresolved_candidate_methods);
2022+
EXPECT_EQ(unresolved_candidate_methods.size(), 1);
2023+
2024+
Cpp::TCppScope_t consume = Cpp::BestOverloadFunctionMatch(
2025+
unresolved_candidate_methods, {},
2026+
{Cpp::GetVariableType(Cpp::GetNamed("consumable"))});
2027+
EXPECT_TRUE(consume);
2028+
2029+
auto consume_callable = Cpp::MakeFunctionCallable(consume);
2030+
EXPECT_EQ(consume_callable.getKind(), Cpp::JitCall::kGenericCall);
20062031
}
20072032

20082033
TEST(FunctionReflectionTest, IsConstMethod) {

0 commit comments

Comments
 (0)