[cfe-dev] clang and gcc implement __PRETTY_FUNCTION__ differently

John McCall rjmccall at apple.com
Thu Mar 15 12:27:17 PDT 2012


On Mar 15, 2012, at 3:46 AM, Nikola Smiljanic wrote:
> That did the trick, but I don't understand why, what is the difference
> between getTemplatedDecl (underlying template declaration) and
> getInstantiatedFromMemberTemplate (previous declaration of this
> template). And then there is also getPreviousDecl (previous
> declaration of this function template). Doxygen comments aren't very
> revealing here, and I'm sure that knowing the terminology from the
> standard would help, but can somebody please explain.

This comes up a lot, and I might as well give a definitive answer
on the mailing list.

Redeclaration is pretty much independent of all the others, so I'll
get it out of the way first.  In C/C++, in certain contexts, you can just
declare something multiple times, and it's still considered to be
the same entity.  For example:
  class A;
  class A;
That's all that the "previous declaration" links and redeclaration
iterators are doing:  walking this list of redeclarations.  Redeclarations
are "mostly" all semantically equivalent, but sometimes later
declarations can add extra information, like new attributes or
default arguments.

All the other links have to do with templates, one way or another.

Every template declaration is implemented as two separate nodes in
the AST:  the template (ClassTemplateDecl or FunctionTemplateDecl)
and its pattern (CXXRecordDecl or FunctionDecl, respectively).
This is a 1-1 relationship, and you map back and forth with
getTemplatedDecl() and getDescribed{Class,Function}Template().
The former is only provided on template declarations;  the latter is
only meaningful for declarations that are being used as the pattern
declaration for some template declaration.

For example, if you have:
  template <class T> class A { ... };
you can think of the ClassTemplateDecl (the template) as being the
"template <class T>" part and the CXXRecordDecl (the pattern)
as being the "class A { ... }" part.

A specialization is just some specific application of template
arguments to a template, something like std::vector<int>.  It
doesn't even necessarily have a definition:  for example, if you
write std::vector<int> somewhere, but don't do anything that
requires it to be a complete type, it just stays an incomplete
specialization.  The template<->specialization relationship
is many-to-1;  templates have hashtables of their known
specializations, and specializations can get back to their
template through the specialization info.  For functions, you
get that with getTemplateSpecializationInfo() (which returns
null to indicate that this function is not a specialization).  For
classes, you get that by dyn_cast<>ing to
ClassTemplateSpecializationDecl (which produces null
to indicate that this class is not a specialization).

For example, if you have:
  template <class T> class A { ... };
  A<int> foo;
the type of 'foo' is ultimately a RecordType whose decl is
a ClassTemplateSpecializationDecl whose template is A.

The final kind of relationship is instantiation.  Usually, when
you do need a definition for a template specialization, you
get it by instantiating a definition provided by some template
declaration.  This basically just means copying that template's
pattern declaration while substituting in the template arguments
as necessary.  When a specialization has a definition, the
specialization info will tell you where it came from.

Copying the pattern usually entails copying some number of
declarations;  we say that the new declarations are instantiated
from the old ones.  The AST doesn't track *every* such
relationship, but for certain class members (basically everything
but fields) we do.  In these cases, you can get from the instantiated
declaration back to the pattern declaration it was instantiated
from using methods like getInstantiatedFromMemberDecl().

For example, if you have:
  template <class T> class A {
    T create() { return T(); }
  };
  A<int> foo;
the CXXMethodDecl "int A<int>::create()" will point back to the
CXXMethodDecl "T A<T>::create()".

This can all get a little confusing in the case of nested templates.
If you've got this:
  template <class T> class A {
    template <class U> U create(T);
  };
Then:
  char A<int>::create<char>(int)
is a specialization of the member function template
  template <class U> U A<int>::create(int)
which was instantiated from the member function template
  template <class T> template <class U> U A<T>::create(T).

Note that class templates can be arbitrarily nested, so if you're trying
to get all the back to the original source code, you might have to chase
an arbitrary number of these "instantiated from" links.

John.



More information about the cfe-dev mailing list