Partial Template Specialization

Hi,

I am writing a pass using ASTConsumer. I find that seems some declarations of partial template specializations are missing from TranslationUnitDecl. For example, given the simple code below:

template<bool, typename>
struct AAA { };

template<typename T>
struct AAA<true, T>
{ };

I get the following result dumped from MyPass::HandleTranslationUnit() function, where MyPass is inherited from ASTConsumer.

(gdb) p Ctx.getTranslationUnitDecl()->dump()
struct __va_list_tag {
    unsigned int gp_offset;
    unsigned int fp_offset;
    void *overflow_arg_area;
    void *reg_save_area;
};
typedef struct __va_list_tag __va_list_tag;
template <typename > struct AAA {
};
$1 = void

In the above output, only template class AAA is presented, but the partial template specialization is missing.

Is this an expected behavior, or is it a Clang bug? Sorry for my vague description. Hopefully I am not missing anything.

- Yang

Hi,

I am writing a pass using ASTConsumer. I find that seems some
declarations of partial template specializations are missing from
TranslationUnitDecl. For example, given the simple code below:

template<bool, typename>
struct AAA { };

template<typename T>
struct AAA<true, T>
{ };

I get the following result dumped from MyPass::HandleTranslationUnit()
function, where MyPass is inherited from ASTConsumer.

(gdb) p Ctx.getTranslationUnitDecl()->dump()
struct __va_list_tag {
   unsigned int gp_offset;
   unsigned int fp_offset;
   void *overflow_arg_area;
   void *reg_save_area;
};
typedef struct __va_list_tag __va_list_tag;
template <typename > struct AAA {
};
$1 = void

In the above output, only template class AAA is presented, but the
partial template specialization is missing.

Yeah, the AST should probably have the class template partial specializations listed here.

Is this an expected behavior, or is it a Clang bug? Sorry for my vague
description. Hopefully I am not missing anything.

You can retrieve class template partial specializations of a ClassTemplateDecl using getPartialSpecializations().

  - Doug

Douglas Gregor wrote:

Hi,

I am writing a pass using ASTConsumer. I find that seems some declarations of partial template specializations are missing from TranslationUnitDecl. For example, given the simple code below:

template<bool, typename>
struct AAA { };

template<typename T>
struct AAA<true, T>
{ };

I get the following result dumped from MyPass::HandleTranslationUnit() function, where MyPass is inherited from ASTConsumer.

(gdb) p Ctx.getTranslationUnitDecl()->dump()
struct __va_list_tag {
   unsigned int gp_offset;
   unsigned int fp_offset;
   void *overflow_arg_area;
   void *reg_save_area;
};
typedef struct __va_list_tag __va_list_tag;
template <typename > struct AAA {
};
$1 = void

In the above output, only template class AAA is presented, but the partial template specialization is missing.
    
Yeah, the AST should probably have the class template partial specializations listed here.

Is this an expected behavior, or is it a Clang bug? Sorry for my vague description. Hopefully I am not missing anything.
    
You can retrieve class template partial specializations of a ClassTemplateDecl using getPartialSpecializations().

  - Doug
  
Doug,

Thanks for the reply.

I tried getPartialSpecializations() on ClassTemplateDecl in the above example, but it returns an empty SmallVector to me, shown as below: (MyVisitor is an inheritance from RecursiveASTVisitor):

bool MyVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D)
{
  llvm::SmallVector<ClassTemplatePartialSpecializationDecl*, 5> ParSpecs;
  D->getPartialSpecializations(ParSpecs);
  unsigned Sz = ParSpecs.size();
  return true;
}

And from gdb:

Breakpoint 1, MyVisitor::VisitClassTemplateDecl (this=0x1c340f0, D=0x1c5ec90) at MyClass.cpp:103
... [skipped]
(gdb) p Sz
$1 = 0
(gdb) p D->dump()
template <typename > struct AAA {
}$2 = void

One more thing is that I assume VisitClassTemplatePartialSpecializationDecl should capture the partial template specialization above, but it doesn't.

Thanks,
- Yang

Something weird is going on, because when I -ast-dump the input source you gave, I see the partial specialization.

  - Doug

Douglas Gregor wrote:

Douglas Gregor wrote:
    

Hi,

I am writing a pass using ASTConsumer. I find that seems some declarations of partial template specializations are missing from TranslationUnitDecl. For example, given the simple code below:

template<bool, typename>
struct AAA { };

template<typename T>
struct AAA<true, T>
{ };

I get the following result dumped from MyPass::HandleTranslationUnit() function, where MyPass is inherited from ASTConsumer.

(gdb) p Ctx.getTranslationUnitDecl()->dump()
struct __va_list_tag {
  unsigned int gp_offset;
  unsigned int fp_offset;
  void *overflow_arg_area;
  void *reg_save_area;
};
typedef struct __va_list_tag __va_list_tag;
template <typename > struct AAA {
};
$1 = void

In the above output, only template class AAA is presented, but the partial template specialization is missing.
   

Yeah, the AST should probably have the class template partial specializations listed here.

Is this an expected behavior, or is it a Clang bug? Sorry for my vague description. Hopefully I am not missing anything.
   

You can retrieve class template partial specializations of a ClassTemplateDecl using getPartialSpecializations().

  - Doug

Doug,

Thanks for the reply.

I tried getPartialSpecializations() on ClassTemplateDecl in the above example, but it returns an empty SmallVector to me, shown as below: (MyVisitor is an inheritance from RecursiveASTVisitor):

bool MyVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D)
{
llvm::SmallVector<ClassTemplatePartialSpecializationDecl*, 5> ParSpecs;
D->getPartialSpecializations(ParSpecs);
unsigned Sz = ParSpecs.size();
return true;
}

And from gdb:

Breakpoint 1, MyVisitor::VisitClassTemplateDecl (this=0x1c340f0, D=0x1c5ec90) at MyClass.cpp:103
... [skipped]
(gdb) p Sz
$1 = 0
(gdb) p D->dump()
template <typename > struct AAA {
}$2 = void

One more thing is that I assume VisitClassTemplatePartialSpecializationDecl should capture the partial template specialization above, but it doesn't.
    
Something weird is going on, because when I -ast-dump the input source you gave, I see the partial specialization.

  - Doug
  
Doug,

I see the partial specialization too:

$ clang -cc1 -ast-print partial.cpp struct __va_list_tag {
    unsigned int gp_offset;
    unsigned int fp_offset;
    void *overflow_arg_area;
    void *reg_save_area;
};
typedef struct __va_list_tag __va_list_tag;
template <bool, typename > struct AAA {
};
struct AAA {
};

The Clang version I am using:

$ clang --version
clang version 3.1 (trunk 152608)
Target: x86_64-unknown-linux-gnu
Thread model: posix

- Yang

You can control some of what the RAV visits by implementing methods
like shouldVisitTemplateInstantiations. I think that should not make a
difference in your example, as yours is an explicit specialization and
the RAV tries to always visit user-written code, but it might as well
be a bug in the RAV. I'm working on adding a unit test on the RAV so
we can find and fix problems like yours more easily.

Cheers,
/Manuel