[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