ClassTemplateDecl instantiation

Consider a simple example:

#pragma once

#include <type_traits>

template <typename T, typename Enabled = void>
struct StructTemplate {
	void method1();
	void method1(T value);
	void method1(StructTemplate<T>& value);
	void method2();
	void method3();
};

template <typename T>
struct StructTemplate<T, std::enable_if_t<std::is_floating_point_v<T>>>
{
	void method1_floating();
	void method2_floating();
	void method3_floating();
};

inline void function(StructTemplate<long double> val) {}

Now when looking up for the clang::FunctionDecl function, the first parameter’s canonical type is a clang::TagType which resolves to a clang::ClassTemplateSpecializationDecl implicitly instantiated.
Of course this is the expected behavior: the parser is even capable of resolving SFINAE with type traits.

The main challenge:

Now consider we want to instantiate StructTemplate<double>, how to go from here?

We assume of course that the example code is parsed without prior knowledge of class template specializations existence.

  1. Using: clang::ClassTemplateDecl::findSpecialization(), clang::ClassTemplateSpecializationDecl::Create(), clang::ClassTemplateDecl::AddSpecialization()
    work great when there are no partial specializations (in our case there is one explicitly defined).
  2. Using: clang::TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization() needs a clang::ClassTemplatePartialSpecializationDecl which we need to find first, if it ever exists of course (clang::ClassTemplateDecl::findPartialSpecialization() isn’t working, or to be precise not sure what clang::TemplateParameterList should we provide).
  3. Using: clang::ASTContext::getTemplateSpecializationType() has a canonical type clang::TemplateSpecializationType() which isn’t a clang::TagType (we can’t resolve to any concrete class template declaration).

What is the correct way to solve such problem, knowing that the parser itself is able to resolve its occurrence in code?

Using:

clang::MultiLevelTemplateArgumentList multi_arg_list;
multi_arg_list.addOuterTemplateArguments(args);
clang::TemplateDeclInstantiator instantiator{CI->getSema(), CTD->getDeclContext(), multi_arg_list};
auto instantiated = instantiator.Visit(CTD);

which returns a ClassTemplateDecl.

This subject is kind of obscure and doesn’t have much documentation.
Does anyone know what to do there, or at least where should I ask and get a solution?

Anyone?
Where should I ask about this issue?

@deadlocklogic, I am not sure what’s your intent. I assume that you want to programatically instantiate a C++ template given a template argument list. You can probably get away with using much higher-level interface in Sema such as Sema::CheckTemplateIdType. You can take a look at this implementation trying to solve maybe a related problem: CppInterOp/lib/Interpreter/CppInterOp.cpp at 5ecc5f19d2539064c18e5bab64cab74f7c3a4ee2 · compiler-research/CppInterOp · GitHub

Thanks for the reply, I really appreciate it, as I have been searching along for a month now.
Yes, what I am trying to do is instantiating a template programmatically(a class template for example).
Things work great when no partial specializations are available.
But when available, I am not able to obtain a correct instantiation. I tried various methods without any success. The main problem is lack of documentation on how things work on the parser side, because the parser is able to instantiate templates written in code.
I will checkout the link you provided and see what goes on.

Probably you mean the desired instantiation because I do not think it is the “correct” from language perspective.

I tried various methods without any success.

I suspect one of the places you could start is Sema::ActOnCallExpr. If you call it with the “right” arguments it will do almost everything you want. However, I am not sure if that covers your intent for the case with the partial template specializations…

What I meant is, using clang::ClassTemplateDecl::findSpecialization() isn’t useful when the arguments match a partial instantiation and visiting the class template with a clang::TemplateDeclInstantiator will return a dummy ClassTemplateDecl with no members. So the result in some cases is incorrect, semantically speaking: it is non existing in the AST (it is created and injected after the call).

I will try the snippet in the link you provided and see what happens.

I don’t know about Sema::ActOnCallExpr but will try searching in clang’s codebase for any hints.

@vvassilev Tried the snipped provided in the link, works like a charm. Instantiates a clang::ClassTemplateDecl while considering full and partial specializations.
Nice! Many thanks!

Just another question if you don’t mind (while I have actually many but will try to ask them later, because of their lower priority): how to parse additional code (from a string for instance) once the AST is formed?

By the way, I am writing a binding generator over clang which will act as modern boosted SWIG harnessing the power of llvm infrastructure.
So far everything is working like a charm, and way better than the handwritten bison parser of SWIG.

You should really look at what CppInterOp is designed for. It allows you to do incremental compilation.

Are you aware of the cppyy project, it probably does something quite similar to your needs. You can find me on discord and we can chat more if you need to…

A

Sent you a message on discord, my nickname is Codester.