Skip to content

Commit 725bb46

Browse files
fix JITcall codegen to handle move semantics
Required for std::unique_ptr Taken from Cling
1 parent 98e07e7 commit 725bb46

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
@@ -2160,12 +2160,33 @@ void make_narg_call(const FunctionDecl* FD, const std::string& return_type,
21602160
}
21612161
}
21622162

2163+
CXXRecordDecl* rtdecl = QT->getAsCXXRecordDecl();
21632164
if (refType != kNotReference) {
21642165
callbuf << "(" << type_name.c_str()
21652166
<< (refType == kLValueReference ? "&" : "&&") << ")*("
21662167
<< type_name.c_str() << "*)args[" << i << "]";
21672168
} else if (isPointer) {
21682169
callbuf << "*(" << type_name.c_str() << "**)args[" << i << "]";
2170+
} else if (rtdecl &&
2171+
(rtdecl->hasTrivialCopyConstructor() &&
2172+
!rtdecl->hasSimpleCopyConstructor()) &&
2173+
rtdecl->hasMoveConstructor()) {
2174+
// By-value construction; this may either copy or move, but there is no
2175+
// information here in terms of intent. Thus, simply assume that the
2176+
// intent is to move if there is no viable copy constructor (ie. if the
2177+
// code would otherwise fail to even compile). There does not appear to be
2178+
// a simple way of determining whether a viable copy constructor exists,
2179+
// so check for the most common case: the trivial one, but not uniquely
2180+
// available, while there is a move constructor.
2181+
2182+
// include utility header if not already included for std::move
2183+
DeclarationName DMove = &getASTContext().Idents.get("move");
2184+
auto result = getSema().getStdNamespace()->lookup(DMove);
2185+
if (result.empty())
2186+
Cpp::Declare("#include <utility>");
2187+
2188+
// move construction as needed for classes (note that this is implicit)
2189+
callbuf << "std::move(*(" << type_name.c_str() << "*)args[" << i << "])";
21692190
} else {
21702191
// pointer falls back to non-pointer case; the argument preserves
21712192
// 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
@@ -2009,6 +2009,31 @@ TEST(FunctionReflectionTest, GetFunctionCallWrapper) {
20092009

20102010
auto bar_callable = Cpp::MakeFunctionCallable(bar);
20112011
EXPECT_EQ(bar_callable.getKind(), Cpp::JitCall::kGenericCall);
2012+
2013+
Cpp::Declare(R"(
2014+
struct A {
2015+
A() {}
2016+
A(A&& other) {};
2017+
};
2018+
2019+
A consumable;
2020+
2021+
template<typename T>
2022+
void consume(T t) {}
2023+
)");
2024+
2025+
unresolved_candidate_methods.clear();
2026+
Cpp::GetClassTemplatedMethods("consume", Cpp::GetGlobalScope(),
2027+
unresolved_candidate_methods);
2028+
EXPECT_EQ(unresolved_candidate_methods.size(), 1);
2029+
2030+
Cpp::TCppScope_t consume = Cpp::BestOverloadFunctionMatch(
2031+
unresolved_candidate_methods, {},
2032+
{Cpp::GetVariableType(Cpp::GetNamed("consumable"))});
2033+
EXPECT_TRUE(consume);
2034+
2035+
auto consume_callable = Cpp::MakeFunctionCallable(consume);
2036+
EXPECT_EQ(consume_callable.getKind(), Cpp::JitCall::kGenericCall);
20122037
}
20132038

20142039
TEST(FunctionReflectionTest, IsConstMethod) {

0 commit comments

Comments
 (0)