[cfe-dev] How to perform template substitution in the clang library

stewart mackenzie setori88 at gmail.com
Sun Dec 2 05:40:05 PST 2012


Hi John,

Further to the question:

Kenny said:

I've got a partial solution, the only caveat is that, I can't get
std::is_same<N<4>, N<4>>::value to return true. Well I can live with
that, as I could just define a constexpr method which operates on the
values directly. But I hope someone could provide a correct answer for
this.

I have put the complete solution and the modified input to
https://gist.github.com/4178490.

I've found that to substitute arguments into a class template and
instantiate it, one would:

    Use the arguments to turn the ClassTemplateDecl into
ClassTemplateSpecializationDecl, and
    Instantiate the specialization using Sema::InstantiateClass method.

The method Sema::RequireCompleteType does indirectly call
InstantiateClass, and requires less input, so I call this method
instead. Therefore, we would write:

/**
 * Instantiate a class template.
 */
ClassTemplateSpecializationDecl* instantiate(ASTContext& ast, Sema& sema,
                                             DeclContext* parent,
                                             ClassTemplateDecl* decl,
                                             ArrayRef<TemplateArgument> args) {
   void* ins_point;
   auto retval = decl->findSpecialization(args.data(), args.size(), ins_point);
   if (retval == nullptr) {
       retval = ClassTemplateSpecializationDecl::Create(ast, TTK_Class, parent,
                                                        {}, {}, decl,
                                                        args.data(),
args.size(),
                                                        nullptr);
       decl->AddSpecialization(retval, ins_point);
   }
   bool is_incomplete = sema.RequireCompleteType({},
ast.getTypeDeclType(retval),
                                                 diag::err_incomplete_type);
   return is_incomplete ? nullptr : retval;
}

This method only works for ClassTemplateDecl. In the question we also
have a TypeAliasTemplateDecl. For this, I am going to invoke the
TemplateDeclInstantiator directly, since this is the only object which
knows a TypeAliasTemplateDecl. Perhaps this method also works with
ClassTemplateDecl, but I can't be sure as it seems not enough work is
done using TemplateDeclInstantiator alone.

/**
 * Instantiate a template alias (`template <...> using Foo = ...`).
 */
TypeAliasDecl* instantiate(ASTContext& ast, Sema& sema, DeclContext* parent,
                           TypeAliasTemplateDecl* decl,
                           ArrayRef<TemplateArgument> args) {
    auto args_count = static_cast<unsigned>(args.size());
    TemplateArgumentList arg_list {TemplateArgumentList::OnStack,
                                   args.data(), args_count};
    MultiLevelTemplateArgumentList multi_arg_list {arg_list};
    TemplateDeclInstantiator instantiator {sema, parent, multi_arg_list};
    auto instantiated = instantiator.Visit(decl);
    if (auto inst_decl = dyn_cast<TypeAliasTemplateDecl>(instantiated)) {
        return inst_decl->getTemplatedDecl();
    }
    return nullptr;
}

(I skipped FunctionTemplateDecl, it is out of the scope of my question.)

Kind regards
Stewart



More information about the cfe-dev mailing list