On instantiations of template declarations.

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():

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.

Definitely a bug. Implicit instantiations should not show up in the translation unit context.

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();

We're trying to save memory. One can find the specialization for a static data member just be looking up the name in the instantiation of its class.

  - Doug

The attached patch should fix this, right? Should I commit it?

ImplicitInst_Static_VarDecl.patch (444 Bytes)

Ping.

This looks fine to me.

John.

Committed in r105465.