[cfe-dev] clang and gcc implement __PRETTY_FUNCTION__ differently

Nikola Smiljanic popizdeh at gmail.com
Tue Mar 13 06:23:45 PDT 2012


Here's another shot at this. This version will print template parameter
names instead of actual types used in the instantiation. It covers return
type, function parameters and parameters from the enclosing class/es.

Note that we don't show template parameter names when it comes to classes:

ClassTemplate<int>::memberFunction(T) [T = int] // GCC would show
ClassTemplate<T>

This part of the string is obtained by calling
FunctionDecl::getQualifiedNameAsString. Showing template parameter names
like GCC would require duplicating most of the code
in getQualifiedNameAsString without any significant gain.

I added a few tests to test\CodeGenCXX\predefined-expr.cpp that cover:
 - template parameter as return type
 - function template with two template parameters
 - template parameter that doesn't show up in the function declaration
(used only inside the body)
 - nested classes with template parameters
 - non type template parameter
 - template template parameter

There is also a FIXME that says: "Maybe this should use DeclPrinter with a
special "print predefined expr" policy instead". I'm not really sure what
this means as I am not familiar with printers and policies, but if you
think it makes sense just point me in the right direction and I'll be more
than happy to rework the code.

P.S. Gmail sets the mime type, let's see if changing the extension to .txt
helps
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20120313/4092d0e1/attachment.html>
-------------- next part --------------
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp	(revision 152623)
+++ lib/AST/Expr.cpp	(working copy)
@@ -399,21 +399,26 @@
     }
 
     PrintingPolicy Policy(Context.getLangOpts());
-
     std::string Proto = FD->getQualifiedNameAsString(Policy);
+    llvm::raw_string_ostream POut(Proto);
 
     const FunctionType *AFT = FD->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) {
         if (i) POut << ", ";
         std::string Param;
-        FD->getParamDecl(i)->getType().getAsStringInternal(Param, Policy);
+        QualType Type =	FD->getParamDecl(i)->getType();
+        if (const SubstTemplateTypeParmType *TTP
+                                    = dyn_cast<SubstTemplateTypeParmType>(Type))
+          TTP->getReplacedParameter()->desugar()
+                                            .getAsStringInternal(Param, Policy);
+        else
+          Type.getAsStringInternal(Param, Policy);
         POut << Param;
       }
 
@@ -422,19 +427,73 @@
         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";
     }
 
-    if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD))
-      AFT->getResultType().getAsStringInternal(Proto, Policy);
+    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)) {
+      QualType RT = AFT->getResultType();
+      if (const SubstTemplateTypeParmType *TTP 
+                                      = dyn_cast<SubstTemplateTypeParmType>(RT))
+        TTP->getReplacedParameter()->desugar()
+                                            .getAsStringInternal(Proto, Policy);
+      else
+        RT.getAsStringInternal(Proto, Policy);
+    }
+
     Out << Proto;
 
     Out.flush();
Index: test/CodeGenCXX/predefined-expr.cpp
===================================================================
--- test/CodeGenCXX/predefined-expr.cpp	(revision 152623)
+++ test/CodeGenCXX/predefined-expr.cpp	(working copy)
@@ -3,13 +3,21 @@
 // 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 [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 [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 +86,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 +217,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 +304,68 @@
 
 } // 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>
+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__);
+  }
+};
+
 int main() {
   ClassInAnonymousNamespace anonymousNamespace;
   anonymousNamespace.anonymousNamespaceFunction();
@@ -345,5 +417,19 @@
 
   NS::externFunction();
 
+  // additional tests for __PRETTY_FUNCTION__
+
+  functionTemplateWithTwoParams(0, 0.0f);
+  functionTemplateWithoutParameterList<double>();
+  functionTemplateWithTemplateReturnType<char>();
+
+  OuterClass<int *>::MiddleClass::InnerClass<float> omi;
+  omi.memberFunction(0, 0.0f);
+
+  ClassWithTemplateTemplateParam<char>::staticMember();
+
+  NonTypeTemplateParam<42> ntt;
+  ntt.size();
+
   return 0;
 }


More information about the cfe-dev mailing list