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/FunctionReflectionTest.cpp b/unittests/CppInterOp/FunctionReflectionTest.cpp index 3fcb3533f..7b19d7c32 100644 --- a/unittests/CppInterOp/FunctionReflectionTest.cpp +++ b/unittests/CppInterOp/FunctionReflectionTest.cpp @@ -709,8 +709,8 @@ TEST(FunctionReflectionTest, GetFunctionCallWrapper) { ASTContext& C = Interp->getCI()->getASTContext(); std::vector 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((Decl*)Instance1)); auto* CTSD1 = static_cast(Instance1); auto* Add_D = Cpp::GetNamed("Add",CTSD1); diff --git a/unittests/CppInterOp/ScopeReflectionTest.cpp b/unittests/CppInterOp/ScopeReflectionTest.cpp index 7549cdaef..6df6f8de0 100644 --- a/unittests/CppInterOp/ScopeReflectionTest.cpp +++ b/unittests/CppInterOp/ScopeReflectionTest.cpp @@ -750,8 +750,52 @@ 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()); +#if CLANG_VERSION_MAJOR > 13 + TemplateArgument TA1 = (*VD->getTemplateArgsInfo())[0].getArgument(); +#else + TemplateArgument TA1 = VD->getTemplateArgsInfo()[0].getArgument(); +#endif // CLANG_VERSION_MAJOR + 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 +851,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 +860,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 +869,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 +885,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); @@ -901,4 +941,4 @@ TEST(ScopeReflectionTest, IncludeVector) { #include )"; Interp->process(code); -} \ No newline at end of file +}