[cfe-dev] On instantiations of template declarations.

Enea Zaffanella zaffanella at cs.unipr.it
Tue Jun 1 07:38:22 PDT 2010


Hello.

We have a question regarding the clang AST representation of
   class template / function template / member of class template
instantiations.

If we declare a class or function template and we instantiate it, then 
the template instances will be accessible from the template declaration. 
Namely, we have methods

  llvm::FoldingSet<ClassTemplateSpecializationDecl>&
    getSpecializations();
  Retrieve the set of specializations of this class template.

  llvm::FoldingSet<FunctionTemplateSpecializationInfo>&
    getSpecializations();
  Retrieve the set of function template specializations of this function 
template.


Considering the following example:

template <typename T>
struct S {
   void f() {}
   void g() {}
};

template <>
void S<int>::f() {
   g();
}

Then we will obtain S<int> listed among the implicit instantiations of 
template S; inside S<int> we will find the declaration of method f() -- 
the definition is explicitly given later in the translation unit context 
-- and the implicit instantiation of the definition of g() -- 
instantiated due to the call in the specialized body of S<int>::f().

So far, so good: explicit specialization are lexically found in the 
(translation unit or namespace or ...) DeclContext where they occur, 
whereas implicit instantiations can be found in the list of 
specializations of the corresponding template.

Consider now the following variant, where we have a static data member:

template <typename T>
struct A { static int a; };

template <typename T>
int A<T>::a = 0;

A<int> si;
A<double> sd;

void bar() {
   sd.a = 13;
}

Here, we have two implicit instantiations of the template A.
Each of those declares the corresponding static data member.
For one of those (A<double>), we also have an implicit instantiation of 
the *definition* of the static data member A<double>::a.
This implicit definition is reachable starting from the implicit 
declaration using method:

   VarDecl* VarDecl::getOutOfLineDefinition();
   If this is a static data member, find its out-of-line definition.

Strangely, the very same implicit definition is also listed in the 
context of the translation unit. This can be seen when dumping the AST, 
just after the definition of function bar():

===================
[...]
void bar() (CompoundStmt 0x2151fb0 <var_template.cc:10:12, line:12:1>
   (BinaryOperator 0x216be70 <line:11:3, col:10> 'int' '='
     (MemberExpr 0x216bdf0 <col:3, col:6> 'int' .a 0x216b160
       (DeclRefExpr 0x216bdb0 <col:3> 'A<double>':'struct A<double>' 
Var='sd' 0x216ae10))
     (IntegerLiteral 0x216be30 <col:10> 'int' 13)))


static int a = (IntegerLiteral 0x216a8d0 <var_template.cc:5:15> 'int' 0)
;
===================

So, finally, our question is: why such a difference?

That is, why does the translation unit context contains these 
(implicitly instantiated) definitions of static data members?
It was not containing the (implicitly instantiated) specialization of 
the class template ... or of its methods.

Moreover, why there is not in the VarDecl object corresponding to
   template <typename T> int A<T>::a = 0;
a method for extracting all of its specializations, similarly to what is 
done for class and function templates? That is, something like

   llvm::FoldingSet<VarDecl>& getSpecializations();


Cheers,
Enea.




More information about the cfe-dev mailing list