From 3280562c989edf092248878e80dbee33f2bc5c9f Mon Sep 17 00:00:00 2001 From: Vassil Vassilev Date: Tue, 8 Aug 2023 18:41:50 +0000 Subject: [PATCH] Consolidate the template instantiation logic. 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). --- include/clang/Interpreter/CppInterOp.h | 7 ++- lib/Interpreter/CppInterOp.cpp | 50 ++++++++++----- unittests/CppInterOp/ScopeReflectionTest.cpp | 64 +++++++++++++++----- 3 files changed, 88 insertions(+), 33 deletions(-) diff --git a/include/clang/Interpreter/CppInterOp.h b/include/clang/Interpreter/CppInterOp.h index 4392950b2..522c37b3a 100644 --- a/include/clang/Interpreter/CppInterOp.h +++ b/include/clang/Interpreter/CppInterOp.h @@ -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 diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index 578f3882f..ecad986a2 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -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" @@ -2768,18 +2769,36 @@ namespace Cpp { return getInterp().toString(type, obj); } - static QualType InstantiateTemplate(TemplateDecl* ClassDecl, - TemplateArgumentListInfo& TLI, Sema &S) { - // This will instantiate tape 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(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(TemplateD)) { + DeclResult R = S.CheckVarTemplateId(VarTemplate, fakeLoc, fakeLoc, TLI); + if (R.isInvalid()) { + // FIXME: Diagnose + } + return R.get(); + } + + // This will instantiate tape 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::. @@ -2792,21 +2811,21 @@ namespace Cpp { // return C.getElaboratedType(ETK_None, NS, TT); } - static QualType InstantiateTemplate(TemplateDecl* ClassDecl, - ArrayRef TemplateArgs, - Sema &S) { + static Decl* InstantiateTemplate(TemplateDecl* TemplateD, + ArrayRef 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 TemplateArgs; @@ -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, diff --git a/unittests/CppInterOp/ScopeReflectionTest.cpp b/unittests/CppInterOp/ScopeReflectionTest.cpp index 7549cdaef..2a1b15f1b 100644 --- a/unittests/CppInterOp/ScopeReflectionTest.cpp +++ b/unittests/CppInterOp/ScopeReflectionTest.cpp @@ -750,8 +750,48 @@ TEST(ScopeReflectionTest, InstantiateNNTPClassTemplate) { ASTContext &C = Interp->getCI()->getASTContext(); Cpp::TCppType_t IntTy = C.IntTy.getAsOpaquePtr(); std::vector 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 Decls; + std::string code = R"( +template constexpr T pi = T(3.1415926535897932385L); +)"; + + GetAllTopLevelDecls(code, Decls); + ASTContext& C = Interp->getCI()->getASTContext(); + + std::vector args1 = {C.IntTy.getAsOpaquePtr()}; + auto Instance1 = Cpp::InstantiateTemplate(Decls[0], args1.data(), + /*type_size*/ args1.size()); + EXPECT_TRUE(isa((Decl*)Instance1)); + auto* VD = cast((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 Decls; + std::string code = R"( +template T TrivialFnTemplate() { return T(); } +)"; + + GetAllTopLevelDecls(code, Decls); + ASTContext& C = Interp->getCI()->getASTContext(); + + std::vector args1 = {C.IntTy.getAsOpaquePtr()}; + auto Instance1 = Cpp::InstantiateTemplate(Decls[0], args1.data(), + /*type_size*/ args1.size()); + EXPECT_TRUE(isa((Decl*)Instance1)); + FunctionDecl* FD = cast((Decl*)Instance1); + FunctionDecl* FnTD1 = FD->getTemplateInstantiationPattern(); + EXPECT_TRUE(FnTD1->isThisDeclarationADefinition()); + TemplateArgument TA1 = FD->getTemplateSpecializationArgs()->get(0); + EXPECT_TRUE(TA1.getAsType()->isIntegerType()); } TEST(ScopeReflectionTest, InstantiateTemplateFunctionFromString) { @@ -807,9 +847,8 @@ TEST(ScopeReflectionTest, InstantiateClassTemplate) { ASTContext &C = Interp->getCI()->getASTContext(); std::vector 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((Decl*)Instance1)); auto *CTSD1 = static_cast(Instance1); EXPECT_TRUE(CTSD1->hasDefinition()); @@ -817,9 +856,8 @@ TEST(ScopeReflectionTest, InstantiateClassTemplate) { 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((Decl*)Instance2)); auto *CTSD2 = static_cast(Instance2); EXPECT_TRUE(CTSD2->hasDefinition()); @@ -827,9 +865,8 @@ TEST(ScopeReflectionTest, InstantiateClassTemplate) { EXPECT_TRUE(TA2.getAsType()->isIntegerType()); std::vector 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((Decl*)Instance3)); auto *CTSD3 = static_cast(Instance3); EXPECT_TRUE(CTSD3->hasDefinition()); @@ -844,9 +881,8 @@ TEST(ScopeReflectionTest, InstantiateClassTemplate) { std::vector 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((Decl*)Instance4)); auto *CTSD4 = static_cast(Instance4);