[cfe-dev] clang and gcc implement __PRETTY_FUNCTION__ differently

Nikola Smiljanic popizdeh at gmail.com
Thu Mar 15 03:46:53 PDT 2012


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.

Anyway this is the new patch. Two things to note here:

1. Since I don't really understand this special case I'm not sure if
my logic for handling it is OK (the tests that I have all pass). I'm
talking about the part inside (TK ==
TK_FunctionTemplateSpecialization) branch.

2. I added the test for compound types and I noticed that pointer
return type is printed like "T *func". I know that we prefer printing
the asterisk like this when it comes to variables, but is this OK for
function return type?

On Thu, Mar 15, 2012 at 12:15 AM, John McCall <rjmccall at apple.com> wrote:
>
> On Mar 14, 2012, at 4:10 PM, Eli Friedman wrote:
> > On Wed, Mar 14, 2012 at 3:34 PM, Nikola Smiljanic <popizdeh at gmail.com> wrote:
> >> Thanks Eli, I was thinking along those lines, but how do I actually get the
> >> other one? FunctionDecl can only be one kind, and this one is
> >> TK_FunctionTemplateSpecialization. I took a look at the one returned by the
> >> getPrimaryTemplate()->getTemplatedDecl(), but that one is
> >> TK_FunctionTemplate.
> >
> > No idea.  I'm not entirely sure we even track that.
>
> This should just be getInstantiatedFromMemberTemplate().
>
> John.
-------------- next part --------------
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp	(revision 152715)
+++ lib/AST/Expr.cpp	(working copy)
@@ -399,39 +399,97 @@
     }
 
     PrintingPolicy Policy(Context.getLangOpts());
-
     std::string Proto = FD->getQualifiedNameAsString(Policy);
+    llvm::raw_string_ostream POut(Proto);
 
-    const FunctionType *AFT = FD->getType()->getAs<FunctionType>();
+    const FunctionDecl *Decl = FD;
+    FunctionDecl::TemplatedKind TK = FD->getTemplatedKind();
+    if (TK == FunctionDecl::TK_FunctionTemplateSpecialization) {
+      FunctionTemplateDecl *Primary = FD->getPrimaryTemplate();
+      FunctionTemplateDecl *TemplatedDecl 
+                                 = Primary->getInstantiatedFromMemberTemplate();
+      Decl = TemplatedDecl ? TemplatedDecl->getTemplatedDecl() 
+                           : Primary->getTemplatedDecl();
+    }
+    else if (TK == FunctionDecl::TK_MemberSpecialization)
+      Decl = FD->getInstantiatedFromMemberFunction();
+
+    const FunctionType *AFT = Decl->getType()->getAs<FunctionType>();
     const FunctionProtoType *FT = 0;
     if (FD->hasWrittenPrototype())
       FT = dyn_cast<FunctionProtoType>(AFT);
 
-    Proto += "(";
+    POut << "(";
     if (FT) {
-      llvm::raw_string_ostream POut(Proto);
-      for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
+      for (unsigned i = 0, e = Decl->getNumParams(); i != e; ++i) {
         if (i) POut << ", ";
         std::string Param;
-        FD->getParamDecl(i)->getType().getAsStringInternal(Param, Policy);
+        Decl->getParamDecl(i)->getType().getAsStringInternal(Param, Policy);
         POut << Param;
-      }
+      } 
 
       if (FT->isVariadic()) {
         if (FD->getNumParams()) POut << ", ";
         POut << "...";
       }
     }
-    Proto += ")";
+    POut << ")";
 
     if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
       Qualifiers ThisQuals = Qualifiers::fromCVRMask(MD->getTypeQualifiers());
       if (ThisQuals.hasConst())
-        Proto += " const";
+        POut << " const";
       if (ThisQuals.hasVolatile())
-        Proto += " volatile";
+        POut << " volatile";
     }
 
+    typedef SmallVector<const ClassTemplateSpecializationDecl *, 8> SpecsTy;
+    SpecsTy Specs;
+    const DeclContext *Ctx = FD->getDeclContext();
+    while (Ctx && isa<NamedDecl>(Ctx)) {
+      if (const ClassTemplateSpecializationDecl *Spec
+            = dyn_cast<ClassTemplateSpecializationDecl>(Ctx))
+        Specs.push_back(Spec);
+      Ctx = Ctx->getParent();
+    }
+      
+    std::string TemplateParams;
+    llvm::raw_string_ostream TOut(TemplateParams);
+    for (SpecsTy::reverse_iterator I = Specs.rbegin(), E = Specs.rend();
+         I != E; ++I) {
+      const TemplateParameterList *Params 
+                  = (*I)->getSpecializedTemplate()->getTemplateParameters();
+      const TemplateArgumentList &Args = (*I)->getTemplateArgs();
+      assert(Params->size() == Args.size());
+      for (unsigned i = 0, numParams = Params->size(); i != numParams; ++i) {
+        TOut << Params->getParam(i)->getNameAsString() << " = ";
+        Args.get(i).print(Policy, TOut);
+        TOut << ", ";
+      }
+    }
+
+    if (FunctionTemplateSpecializationInfo *FSI 
+                                        = FD->getTemplateSpecializationInfo()) {
+      const TemplateParameterList* Params 
+                                  = FSI->getTemplate()->getTemplateParameters();
+      const TemplateArgumentList* Args = FSI->TemplateArguments;
+      assert(Params->size() == Args->size());
+      for (unsigned i = 0, e = Params->size(); i != e; ++i) {
+        TOut << Params->getParam(i)->getName() << " = ";
+        Args->get(i).print(Policy, TOut);
+        TOut << ", ";
+      }
+    }
+
+    TOut.flush();
+    if (!TemplateParams.empty()) {
+      // remove the trailing comma and space
+      TemplateParams.resize(TemplateParams.size() - 2);
+      POut << " [" << TemplateParams << "]";
+    }
+
+    POut.flush();
+
     if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD))
       AFT->getResultType().getAsStringInternal(Proto, Policy);
 
Index: test/CodeGenCXX/predefined-expr.cpp
===================================================================
--- test/CodeGenCXX/predefined-expr.cpp	(revision 152715)
+++ test/CodeGenCXX/predefined-expr.cpp	(working copy)
@@ -3,13 +3,23 @@
 // CHECK: private unnamed_addr constant [15 x i8] c"externFunction\00"
 // CHECK: private unnamed_addr constant [26 x i8] c"void NS::externFunction()\00"
 
+// CHECK: private unnamed_addr constant [81 x i8] c"void ClassTemplate<int>::memberFunctionTemplate(T, U) const [T = int, U = float]\00"
+// CHECK: private unnamed_addr constant [57 x i8] c"void NonTypeTemplateParam<42>::size() const [Count = 42]\00"
+// CHECK: private unnamed_addr constant [122 x i8] c"static void ClassWithTemplateTemplateParam<char, NS::ClassTemplate>::staticMember() [T = char, Param = NS::ClassTemplate]\00"
+// CHECK: private unnamed_addr constant [106 x i8] c"void OuterClass<int *>::MiddleClass::InnerClass<float>::memberFunction(T, U) const [T = int *, U = float]\00"
+
+// CHECK: private unnamed_addr constant [52 x i8] c"T *functionTemplateWithCompoundTypes(T *) [T = int]\00" 
+// CHECK: private unnamed_addr constant [54 x i8] c"T functionTemplateWithTemplateReturnType() [T = char]\00"
+// CHECK: private unnamed_addr constant [57 x i8] c"void functionTemplateWithoutParameterList() [T = double]\00"
+// CHECK: private unnamed_addr constant [62 x i8] c"void functionTemplateWithTwoParams(T, U) [T = int, U = float]\00"
+
 // CHECK: private unnamed_addr constant [22 x i8] c"classTemplateFunction\00"
-// CHECK: private unnamed_addr constant [60 x i8] c"void NS::ClassTemplate<NS::Base *>::classTemplateFunction()\00"
-// CHECK: private unnamed_addr constant [53 x i8] c"void NS::ClassTemplate<int>::classTemplateFunction()\00"
+// CHECK: private unnamed_addr constant [77 x i8] c"void NS::ClassTemplate<NS::Base *>::classTemplateFunction() [T = NS::Base *]\00"
+// CHECK: private unnamed_addr constant [63 x i8] c"void NS::ClassTemplate<int>::classTemplateFunction() [T = int]\00"
 
 // CHECK: private unnamed_addr constant [18 x i8] c"functionTemplate1\00"
-// CHECK: private unnamed_addr constant [45 x i8] c"void NS::Base::functionTemplate1(NS::Base *)\00"
-// CHECK: private unnamed_addr constant [38 x i8] c"void NS::Base::functionTemplate1(int)\00"
+// CHECK: private unnamed_addr constant [53 x i8] c"void NS::Base::functionTemplate1(T) [T = NS::Base *]\00"
+// CHECK: private unnamed_addr constant [46 x i8] c"void NS::Base::functionTemplate1(T) [T = int]\00"
 
 // CHECK: private unnamed_addr constant [23 x i8] c"anonymousUnionFunction\00"
 // CHECK: private unnamed_addr constant [83 x i8] c"void NS::ContainerForAnonymousRecords::<anonymous union>::anonymousUnionFunction()\00"
@@ -78,6 +88,8 @@
 // CHECK: private unnamed_addr constant [19 x i8] c"localClassFunction\00"
 // CHECK: private unnamed_addr constant [59 x i8] c"void NS::localClass(int)::LocalClass::localClassFunction()\00"
 
+
+
 int printf(const char * _Format, ...);
 
 class ClassInTopLevelNamespace {
@@ -207,7 +219,7 @@
 
 class Derived : public Base {
 public:
-  // Virtual function without being explicitally written.
+  // Virtual function without being explicitly written.
   void virtualFunction() {
     printf("__func__ %s\n", __func__);
     printf("__FUNCTION__ %s\n", __FUNCTION__);
@@ -294,6 +306,87 @@
 
 } // end NS namespace
 
+// additional tests for __PRETTY_FUNCTION__
+template <typename T, typename U>
+void functionTemplateWithTwoParams(T, U)
+{
+  printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+}
+
+template <typename T>
+void functionTemplateWithoutParameterList()
+{
+  T t = T();
+
+  printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+}
+
+template <typename T>
+T functionTemplateWithTemplateReturnType()
+{
+  printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+
+  return T();
+}
+
+template <typename T>
+T * functionTemplateWithCompoundTypes(T a[])
+{
+  printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+
+  return 0;
+}
+
+template <typename T>
+class OuterClass
+{
+public:
+  class MiddleClass
+  {
+  public:
+    template <typename U>
+    class InnerClass
+    {
+    public:
+      void memberFunction(T x, U y) const
+      {
+        printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+      }
+    };
+  };
+};
+
+template <typename T, template <typename> class Param = NS::ClassTemplate>
+class ClassWithTemplateTemplateParam
+{
+public:
+  static void staticMember()
+  {
+    printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+  }
+};
+
+template <int Count>
+class NonTypeTemplateParam
+{
+public:
+  void size() const
+  {
+    printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+  }
+};
+
+template <typename T>
+class ClassTemplate
+{
+public:
+  template <typename U>
+  void memberFunctionTemplate(T t, U u) const
+  {
+    printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+  }
+};
+
 int main() {
   ClassInAnonymousNamespace anonymousNamespace;
   anonymousNamespace.anonymousNamespaceFunction();
@@ -345,5 +438,24 @@
 
   NS::externFunction();
 
+  // additional tests for __PRETTY_FUNCTION__
+
+  functionTemplateWithTwoParams(0, 0.0f);
+  functionTemplateWithoutParameterList<double>();
+  functionTemplateWithTemplateReturnType<char>();
+  int array[] = { 1, 2, 3 };
+  functionTemplateWithCompoundTypes(array);
+
+  OuterClass<int *>::MiddleClass::InnerClass<float> omi;
+  omi.memberFunction(0, 0.0f);
+
+  ClassWithTemplateTemplateParam<char>::staticMember();
+
+  NonTypeTemplateParam<42> ntt;
+  ntt.size();
+
+  ClassTemplate<int> ct;
+  ct.memberFunctionTemplate(0, 0.0f);
+
   return 0;
 }


More information about the cfe-dev mailing list