Skip to content

Commit

Permalink
Consolidate the template instantiation logic.
Browse files Browse the repository at this point in the history
This patch offers a single interface for instantiation of class, function and
variable templates. That would simplify user code where we do not need to care
what is the underlying template pattern (most of the time).
  • Loading branch information
vgvassilev committed Apr 4, 2024
1 parent 23973b8 commit 81bde3d
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 35 deletions.
7 changes: 4 additions & 3 deletions include/clang/Interpreter/CppInterOp.h
Original file line number Diff line number Diff line change
Expand Up @@ -534,9 +534,10 @@ namespace Cpp {
TemplateArgInfo(TCppScope_t type, const char* integral_value = nullptr)
: m_Type(type), m_IntegralValue(integral_value) {}
};
CPPINTEROP_API TCppScope_t
InstantiateClassTemplate(TCppScope_t tmpl, TemplateArgInfo* template_args,
size_t template_args_size);
/// Builds a template instantiation for a given templated declaration.
CPPINTEROP_API TCppScope_t InstantiateTemplate(TCppScope_t tmpl,
TemplateArgInfo* template_args,
size_t template_args_size);

/// Returns the class template instantiation arguments of \c templ_instance.
CPPINTEROP_API void
Expand Down
50 changes: 34 additions & 16 deletions lib/Interpreter/CppInterOp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/TemplateDeduction.h"

#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
Expand Down Expand Up @@ -2768,18 +2769,36 @@ namespace Cpp {
return getInterp().toString(type, obj);
}

static QualType InstantiateTemplate(TemplateDecl* ClassDecl,
TemplateArgumentListInfo& TLI, Sema &S) {
// This will instantiate tape<T> type and return it.
SourceLocation noLoc;
QualType TT = S.CheckTemplateIdType(TemplateName(ClassDecl), noLoc, TLI);

static Decl* InstantiateTemplate(TemplateDecl* TemplateD,
TemplateArgumentListInfo& TLI, Sema& S) {
// 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);
if (auto* FunctionTemplate = dyn_cast<FunctionTemplateDecl>(TemplateD)) {
FunctionDecl* Specialization = nullptr;
clang::sema::TemplateDeductionInfo Info(fakeLoc);
if (Sema::TemplateDeductionResult Result = S.DeduceTemplateArguments(
FunctionTemplate, &TLI, Specialization, Info,
/*IsAddressOfFunction*/ true)) {
// FIXME: Diagnose what happened.
(void)Result;
}
return Specialization;
} else if (auto* VarTemplate = dyn_cast<VarTemplateDecl>(TemplateD)) {
DeclResult R = S.CheckVarTemplateId(VarTemplate, fakeLoc, fakeLoc, TLI);
if (R.isInvalid()) {
// FIXME: Diagnose
}
return R.get();
}

// This will instantiate tape<T> type and return it.
SourceLocation noLoc;
QualType TT = S.CheckTemplateIdType(TemplateName(TemplateD), noLoc, TLI);

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

// ASTContext &C = S.getASTContext();
// // Get clad namespace and its identifier clad::.
Expand All @@ -2792,21 +2811,21 @@ namespace Cpp {
// return C.getElaboratedType(ETK_None, NS, TT);
}

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

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

TCppScope_t InstantiateClassTemplate(TCppScope_t tmpl,
TemplateArgInfo* template_args,
size_t template_args_size) {
TCppScope_t InstantiateTemplate(TCppScope_t tmpl,
TemplateArgInfo* template_args,
size_t template_args_size) {
ASTContext &C = getASTContext();

llvm::SmallVector<TemplateArgument> TemplateArgs;
Expand All @@ -2830,8 +2849,7 @@ namespace Cpp {
#ifdef USE_CLING
cling::Interpreter::PushTransactionRAII RAII(&getInterp());
#endif
QualType Instance = InstantiateTemplate(TmplD, TemplateArgs, getSema());
return GetScopeFromType(Instance);
return InstantiateTemplate(TmplD, TemplateArgs, getSema());
}

void GetClassTemplateInstantiationArgs(TCppScope_t templ_instance,
Expand Down
4 changes: 2 additions & 2 deletions unittests/CppInterOp/FunctionReflectionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -709,8 +709,8 @@ TEST(FunctionReflectionTest, GetFunctionCallWrapper) {
ASTContext& C = Interp->getCI()->getASTContext();

std::vector<Cpp::TemplateArgInfo> argument = {C.IntTy.getAsOpaquePtr()};
auto Instance1 = Cpp::InstantiateClassTemplate(Decls1[0], argument.data(),
/*type_size*/ argument.size());
auto Instance1 = Cpp::InstantiateTemplate(Decls1[0], argument.data(),
/*type_size*/ argument.size());
EXPECT_TRUE(isa<ClassTemplateSpecializationDecl>((Decl*)Instance1));
auto* CTSD1 = static_cast<ClassTemplateSpecializationDecl*>(Instance1);
auto* Add_D = Cpp::GetNamed("Add",CTSD1);
Expand Down
64 changes: 50 additions & 14 deletions unittests/CppInterOp/ScopeReflectionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -750,8 +750,48 @@ TEST(ScopeReflectionTest, InstantiateNNTPClassTemplate) {
ASTContext &C = Interp->getCI()->getASTContext();
Cpp::TCppType_t IntTy = C.IntTy.getAsOpaquePtr();
std::vector<Cpp::TemplateArgInfo> args1 = {{IntTy, "5"}};
EXPECT_TRUE(Cpp::InstantiateClassTemplate(Decls[0], args1.data(),
/*type_size*/ args1.size()));
EXPECT_TRUE(Cpp::InstantiateTemplate(Decls[0], args1.data(),
/*type_size*/ args1.size()));
}

TEST(ScopeReflectionTest, InstantiateVarTemplate) {
std::vector<Decl*> Decls;
std::string code = R"(
template<class T> constexpr T pi = T(3.1415926535897932385L);
)";

GetAllTopLevelDecls(code, Decls);
ASTContext& C = Interp->getCI()->getASTContext();

std::vector<Cpp::TemplateArgInfo> args1 = {C.IntTy.getAsOpaquePtr()};
auto Instance1 = Cpp::InstantiateTemplate(Decls[0], args1.data(),
/*type_size*/ args1.size());
EXPECT_TRUE(isa<VarDecl>((Decl*)Instance1));
auto* VD = cast<VarTemplateSpecializationDecl>((Decl*)Instance1);
VarTemplateDecl* VDTD1 = VD->getSpecializedTemplate();
EXPECT_TRUE(VDTD1->isThisDeclarationADefinition());
TemplateArgument TA1 = (*VD->getTemplateArgsInfo())[0].getArgument();
EXPECT_TRUE(TA1.getAsType()->isIntegerType());
}

TEST(ScopeReflectionTest, InstantiateFunctionTemplate) {
std::vector<Decl*> Decls;
std::string code = R"(
template<typename T> T TrivialFnTemplate() { return T(); }
)";

GetAllTopLevelDecls(code, Decls);
ASTContext& C = Interp->getCI()->getASTContext();

std::vector<Cpp::TemplateArgInfo> args1 = {C.IntTy.getAsOpaquePtr()};
auto Instance1 = Cpp::InstantiateTemplate(Decls[0], args1.data(),
/*type_size*/ args1.size());
EXPECT_TRUE(isa<FunctionDecl>((Decl*)Instance1));
FunctionDecl* FD = cast<FunctionDecl>((Decl*)Instance1);
FunctionDecl* FnTD1 = FD->getTemplateInstantiationPattern();
EXPECT_TRUE(FnTD1->isThisDeclarationADefinition());
TemplateArgument TA1 = FD->getTemplateSpecializationArgs()->get(0);
EXPECT_TRUE(TA1.getAsType()->isIntegerType());
}

TEST(ScopeReflectionTest, InstantiateTemplateFunctionFromString) {
Expand Down Expand Up @@ -807,29 +847,26 @@ TEST(ScopeReflectionTest, InstantiateClassTemplate) {
ASTContext &C = Interp->getCI()->getASTContext();

std::vector<Cpp::TemplateArgInfo> args1 = {C.IntTy.getAsOpaquePtr()};
auto Instance1 = Cpp::InstantiateClassTemplate(Decls[0],
args1.data(),
/*type_size*/args1.size());
auto Instance1 = Cpp::InstantiateTemplate(Decls[0], args1.data(),
/*type_size*/ args1.size());
EXPECT_TRUE(isa<ClassTemplateSpecializationDecl>((Decl*)Instance1));
auto *CTSD1 = static_cast<ClassTemplateSpecializationDecl*>(Instance1);
EXPECT_TRUE(CTSD1->hasDefinition());
TemplateArgument TA1 = CTSD1->getTemplateArgs().get(0);
EXPECT_TRUE(TA1.getAsType()->isIntegerType());
EXPECT_TRUE(CTSD1->hasDefinition());

auto Instance2 = Cpp::InstantiateClassTemplate(Decls[1],
nullptr,
/*type_size*/0);
auto Instance2 = Cpp::InstantiateTemplate(Decls[1], nullptr,
/*type_size*/ 0);
EXPECT_TRUE(isa<ClassTemplateSpecializationDecl>((Decl*)Instance2));
auto *CTSD2 = static_cast<ClassTemplateSpecializationDecl*>(Instance2);
EXPECT_TRUE(CTSD2->hasDefinition());
TemplateArgument TA2 = CTSD2->getTemplateArgs().get(0);
EXPECT_TRUE(TA2.getAsType()->isIntegerType());

std::vector<Cpp::TemplateArgInfo> args3 = {C.IntTy.getAsOpaquePtr()};
auto Instance3 = Cpp::InstantiateClassTemplate(Decls[2],
args3.data(),
/*type_size*/args3.size());
auto Instance3 = Cpp::InstantiateTemplate(Decls[2], args3.data(),
/*type_size*/ args3.size());
EXPECT_TRUE(isa<ClassTemplateSpecializationDecl>((Decl*)Instance3));
auto *CTSD3 = static_cast<ClassTemplateSpecializationDecl*>(Instance3);
EXPECT_TRUE(CTSD3->hasDefinition());
Expand All @@ -844,9 +881,8 @@ TEST(ScopeReflectionTest, InstantiateClassTemplate) {

std::vector<Cpp::TemplateArgInfo> args4 = {C.IntTy.getAsOpaquePtr(),
{C.IntTy.getAsOpaquePtr(), "3"}};
auto Instance4 = Cpp::InstantiateClassTemplate(Decls[3],
args4.data(),
/*type_size*/args4.size());
auto Instance4 = Cpp::InstantiateTemplate(Decls[3], args4.data(),
/*type_size*/ args4.size());

EXPECT_TRUE(isa<ClassTemplateSpecializationDecl>((Decl*)Instance4));
auto *CTSD4 = static_cast<ClassTemplateSpecializationDecl*>(Instance4);
Expand Down

0 comments on commit 81bde3d

Please sign in to comment.