[LLVMdev] [ast-dump] Class template partial specializations missing from an implicit class template instantiation?

Joshua Naismith fakju666 at o2.pl
Thu Sep 5 06:59:47 PDT 2013

I was looking at the ClassTemplatePartialSpecializationDecl::getInstantiatedFromMember documentation, in the included example it says: "(..) the instantiation of Outer<float>::Inner<int*> will end up instantiating the partial specialization Outer<float>::Inner<U*> (...)".

To understand the concept better, I dumped the AST for the following code:

template<typename T>
struct Outer {
  template<typename U> struct Inner {float f(){};};
  template<typename U> struct Inner<U*> {int f(){};};

int main() {
  Outer<float>::Inner<int*> ii;
  Outer<float>::Inner<int> i2;

The tree looks as expected for the template:

|-ClassTemplateDecl 0x38e1de0 <test-src/main.cpp:1:2, line:5:2> Outer
| |-TemplateTypeParmDecl 0x38e1ca0 <line:1:11, col:20> typename T
| |-CXXRecordDecl 0x38e1d50 <line:2:2, line:5:2> struct Outer definition
| | |-CXXRecordDecl 0x390eab0 <line:2:2, col:9> struct Outer
| | |-ClassTemplateDecl 0x390ec80 <line:3:4, col:51> Inner
| | | |-TemplateTypeParmDecl 0x390eb40 <col:13, col:22> typename U
| | | `-CXXRecordDecl 0x390ebf0 <col:25, col:51> struct Inner definition
| | |   |-CXXRecordDecl 0x390ef00 <col:25, col:32> struct Inner
| | |   `-CXXMethodDecl 0x390f010 <col:39, col:49> f 'float (void)'
| | |     `-CompoundStmt 0x390f668 <col:48, col:49>
| | `-ClassTemplatePartialSpecializationDecl 0x390f280 <line:4:4, col:53> struct Inner definition
| |   |-TemplateArgument type 'type-parameter-1-0 *'
| |   |-TemplateTypeParmDecl 0x390f0b0 <col:13, col:22> typename U
| |   |-CXXRecordDecl 0x390f490 <col:25, col:32> struct Inner
| |   `-CXXMethodDecl 0x390f5a0 <col:43, col:51> f 'int (void)'
| |     `-CompoundStmt 0x390f680 <col:50, col:51>

Both ClassTemplateDecl "Inner" and ClassTemplatePartialSpecializationDecl "Inner" are descendants of ClassTemplateDecl "Outer". However, for an instantiation, it looks like this:

| `-ClassTemplateSpecializationDecl 0x390f7d0 <line:1:2, line:5:2> struct Outer definition
|   |-TemplateArgument type 'float'
|   |-CXXRecordDecl 0x3916990 prev 0x390f7d0 <line:2:2, col:9> struct Outer
|   `-ClassTemplateDecl 0x3916b30 <line:3:4, col:32> Inner
|     |-TemplateTypeParmDecl 0x3916a20 <col:13, col:22> typename U
|     |-CXXRecordDecl 0x3916aa0 <col:25, col:32> struct Inner
|     |-ClassTemplateSpecializationDecl 0x3917130 <line:4:4, col:53> struct Inner definition
|     | |-TemplateArgument type 'int *'
|     | |-CXXRecordDecl 0x39174b0 prev 0x3917130 <col:25, col:32> struct Inner
|     | |-CXXMethodDecl 0x3917540 <col:43, col:51> f 'int (void)'
|     | | `-CompoundStmt 0x390f680 <col:50, col:51>
|     | |-CXXConstructorDecl 0x3917610 <col:32> Inner 'void (void)' inline noexcept-unevaluated 0x3917610
|     | | `-CompoundStmt 0x3918370 <col:32>
|     | |-CXXConstructorDecl 0x3917770 <col:32> Inner 'void (const struct Outer<float>::Inner<int *> &)' inline noexcept-unevaluated 0x3917770
|     | | `-ParmVarDecl 0x39178b0 <col:32> 'const struct Outer<float>::Inner<int *> &'
|     | `-CXXConstructorDecl 0x39181d0 <col:32> Inner 'void (struct Outer<float>::Inner<int *> &&)' inline noexcept-unevaluated 0x39181d0
|     |   `-ParmVarDecl 0x3918310 <col:32> 'struct Outer<float>::Inner<int *> &&'
|     `-ClassTemplateSpecializationDecl 0x3918540 <line:3:4, col:32> struct Inner definition
|       |-TemplateArgument type 'int'
|       |-CXXRecordDecl 0x3918840 prev 0x3918540 <col:25, col:32> struct Inner
|       |-CXXMethodDecl 0x39188d0 <col:39, col:49> f 'float (void)'
|       | `-CompoundStmt 0x390f668 <col:48, col:49>
|       |-CXXConstructorDecl 0x39189a0 <col:32> Inner 'void (void)' inline noexcept-unevaluated 0x39189a0
|       | `-CompoundStmt 0x3918e40 <col:32>
|       |-CXXConstructorDecl 0x3918ad0 <col:32> Inner 'void (const struct Outer<float>::Inner<int> &)' inline noexcept-unevaluated 0x3918ad0
|       | `-ParmVarDecl 0x3918c10 <col:32> 'const struct Outer<float>::Inner<int> &'
|       `-CXXConstructorDecl 0x3918ca0 <col:32> Inner 'void (struct Outer<float>::Inner<int> &&)' inline noexcept-unevaluated 0x3918ca0
|         `-ParmVarDecl 0x3918de0 <col:32> 'struct Outer<float>::Inner<int> &&'

Here, both Inner instantiations are descendants of 1 ClassTemplateDecl. I expected that there'd be a node for ClassTemplatePartialSpecializationDecl corresponding to Outer<float>::Inner<U*>, and Outer<float>::Inner<int *> would derive from that.

Which option is true?
1. This is a bug in -ast-dump.
2. This is a bug in the clang AST code.
3. This is expected.

More information about the llvm-dev mailing list