Skip to content

Commit bc728d3

Browse files
Vipul-Cariappavgvassilev
authored andcommitted
fix: codegen for templates with multiple parameter packs
adapted from cling
1 parent 887b646 commit bc728d3

File tree

2 files changed

+55
-2
lines changed

2 files changed

+55
-2
lines changed

lib/CppInterOp/CppInterOp.cpp

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -616,8 +616,6 @@ static Decl* GetScopeFromType(QualType QT) {
616616
Type = Type->getUnqualifiedDesugaredType();
617617
if (auto* ET = llvm::dyn_cast<EnumType>(Type))
618618
return ET->getDecl();
619-
if (auto* FnType = llvm::dyn_cast<FunctionProtoType>(Type))
620-
Type = const_cast<clang::Type*>(FnType->getReturnType().getTypePtr());
621619
return Type->getAsCXXRecordDecl();
622620
}
623621
return 0;
@@ -1689,6 +1687,10 @@ std::string GetTypeAsString(TCppType_t var) {
16891687
PrintingPolicy Policy((LangOptions()));
16901688
Policy.Bool = true; // Print bool instead of _Bool.
16911689
Policy.SuppressTagKeyword = true; // Do not print `class std::string`.
1690+
#if CLANG_VERSION_MAJOR > 16
1691+
Policy.SuppressElaboration = true;
1692+
#endif
1693+
Policy.FullyQualifiedName = true;
16921694
return compat::FixTypeName(QT.getAsString(Policy));
16931695
}
16941696

@@ -2103,6 +2105,30 @@ void make_narg_call(const FunctionDecl* FD, const std::string& return_type,
21032105
std::string template_args = complete_name.substr(idx);
21042106
name = name_without_template_args +
21052107
(template_args.empty() ? "" : " " + template_args);
2108+
2109+
// If a template has consecutive parameter packs, then it is impossible to
2110+
// use the explicit name in the wrapper, since the type deduction is what
2111+
// determines the split of the packs. Instead, we'll revert to the
2112+
// non-templated function name and hope that the type casts in the wrapper
2113+
// will suffice.
2114+
if (FD->isTemplateInstantiation() && FD->getPrimaryTemplate()) {
2115+
const FunctionTemplateDecl* FTDecl =
2116+
llvm::dyn_cast<FunctionTemplateDecl>(FD->getPrimaryTemplate());
2117+
if (FTDecl) {
2118+
auto* templateParms = FTDecl->getTemplateParameters();
2119+
int numPacks = 0;
2120+
for (size_t iParam = 0, nParams = templateParms->size();
2121+
iParam < nParams; ++iParam) {
2122+
if (templateParms->getParam(iParam)->isTemplateParameterPack())
2123+
numPacks += 1;
2124+
else
2125+
numPacks = 0;
2126+
}
2127+
if (numPacks > 1) {
2128+
name = name_without_template_args;
2129+
}
2130+
}
2131+
}
21062132
}
21072133
if (op_flag || N <= 1)
21082134
callbuf << name;
@@ -3422,6 +3448,8 @@ static Decl* InstantiateTemplate(TemplateDecl* TemplateD,
34223448
// This will instantiate tape<T> type and return it.
34233449
SourceLocation noLoc;
34243450
QualType TT = S.CheckTemplateIdType(TemplateName(TemplateD), noLoc, TLI);
3451+
if (TT.isNull())
3452+
return nullptr;
34253453

34263454
// Perhaps we can extract this into a new interface.
34273455
S.RequireCompleteType(fakeLoc, TT, diag::err_tentative_def_incomplete_type);

unittests/CppInterOp/FunctionReflectionTest.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1969,6 +1969,31 @@ TEST(FunctionReflectionTest, GetFunctionCallWrapper) {
19691969
EXPECT_TRUE(err_msg.find("instantiation with no body") != std::string::npos);
19701970
EXPECT_EQ(instantiation_in_host_callable.getKind(),
19711971
Cpp::JitCall::kUnknown); // expect to fail
1972+
1973+
Interp->process(R"(
1974+
template<typename ...T>
1975+
struct tuple {};
1976+
1977+
template<typename ...Ts, typename ...TTs>
1978+
void tuple_tuple(tuple<Ts...> one, tuple<TTs...> two) { return; }
1979+
1980+
tuple<int, double> tuple_one;
1981+
tuple<char, char> tuple_two;
1982+
)");
1983+
1984+
unresolved_candidate_methods.clear();
1985+
Cpp::GetClassTemplatedMethods("tuple_tuple", Cpp::GetGlobalScope(),
1986+
unresolved_candidate_methods);
1987+
EXPECT_EQ(unresolved_candidate_methods.size(), 1);
1988+
1989+
Cpp::TCppScope_t tuple_tuple = Cpp::BestOverloadFunctionMatch(
1990+
unresolved_candidate_methods, {},
1991+
{Cpp::GetVariableType(Cpp::GetNamed("tuple_one")),
1992+
Cpp::GetVariableType(Cpp::GetNamed("tuple_two"))});
1993+
EXPECT_TRUE(tuple_tuple);
1994+
1995+
auto tuple_tuple_callable = Cpp::MakeFunctionCallable(tuple_tuple);
1996+
EXPECT_EQ(tuple_tuple_callable.getKind(), Cpp::JitCall::kGenericCall);
19721997
}
19731998

19741999
TEST(FunctionReflectionTest, IsConstMethod) {

0 commit comments

Comments
 (0)