From 7f45156a99efe2ea46f828e35c672e063ba14c0e Mon Sep 17 00:00:00 2001
From: Richard Smith <richard-llvm@metafoo.co.uk>
Date: Wed, 23 Jul 2014 03:17:06 +0000
Subject: [PATCH] When pretty-printing a declaration of a pack, put the
 ellipsis before the name being declared, not at the end. When pretty-printing
 a non-type template parameter, put the name of the parameter in the middle of
 the type, not at the end.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@213718 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/AST/DeclPrinter.cpp           | 30 ++++++++++++++++++------------
 test/Misc/ast-dump-templates.cpp  | 12 ++++++++++++
 test/SemaCXX/cxx11-ast-print.cpp  |  2 +-
 unittests/AST/DeclPrinterTest.cpp | 23 +++++++++++------------
 4 files changed, 42 insertions(+), 25 deletions(-)

diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index e5e5130f695..ec7ba65cb4e 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -87,6 +87,7 @@ namespace {
     void PrintTemplateParameters(const TemplateParameterList *Params,
                                  const TemplateArgumentList *Args = nullptr);
     void prettyPrintAttributes(Decl *D);
+    void printDeclType(QualType T, StringRef DeclName, bool Pack = false);
   };
 }
 
@@ -197,6 +198,17 @@ void DeclPrinter::prettyPrintAttributes(Decl *D) {
   }
 }
 
+void DeclPrinter::printDeclType(QualType T, StringRef DeclName, bool Pack) {
+  // Normally, a PackExpansionType is written as T[3]... (for instance, as a
+  // template argument), but if it is the type of a declaration, the ellipsis
+  // is placed before the name being declared.
+  if (auto *PET = T->getAs<PackExpansionType>()) {
+    Pack = true;
+    T = PET->getPattern();
+  }
+  T.print(Out, Policy, (Pack ? "..." : "") + DeclName);
+}
+
 void DeclPrinter::ProcessDeclGroup(SmallVectorImpl<Decl*>& Decls) {
   this->Indent();
   Decl::printGroup(Decls.data(), Decls.size(), Out, Policy, Indentation);
@@ -647,7 +659,6 @@ void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
   Out << *D << ":";
 }
 
-
 void DeclPrinter::VisitVarDecl(VarDecl *D) {
   if (!Policy.SuppressSpecifiers) {
     StorageClass SC = D->getStorageClass();
@@ -675,7 +686,7 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
   QualType T = D->getTypeSourceInfo()
     ? D->getTypeSourceInfo()->getType()
     : D->getASTContext().getUnqualifiedObjCPointerType(D->getType());
-  T.print(Out, Policy, D->getName());
+  printDeclType(T, D->getName());
   Expr *Init = D->getInit();
   if (!Policy.SuppressInitializers && Init) {
     bool ImplicitInit = false;
@@ -830,7 +841,7 @@ void DeclPrinter::PrintTemplateParameters(const TemplateParameterList *Params,
         Out << "class ";
 
       if (TTP->isParameterPack())
-        Out << "... ";
+        Out << "...";
 
       Out << *TTP;
 
@@ -843,15 +854,10 @@ void DeclPrinter::PrintTemplateParameters(const TemplateParameterList *Params,
       };
     } else if (const NonTypeTemplateParmDecl *NTTP =
                  dyn_cast<NonTypeTemplateParmDecl>(Param)) {
-      Out << NTTP->getType().getAsString(Policy);
-
-      if (NTTP->isParameterPack() && !isa<PackExpansionType>(NTTP->getType()))
-        Out << "...";
-        
-      if (IdentifierInfo *Name = NTTP->getIdentifier()) {
-        Out << ' ';
-        Out << Name->getName();
-      }
+      StringRef Name;
+      if (IdentifierInfo *II = NTTP->getIdentifier())
+        Name = II->getName();
+      printDeclType(NTTP->getType(), Name, NTTP->isParameterPack());
 
       if (Args) {
         Out << " = ";
diff --git a/test/Misc/ast-dump-templates.cpp b/test/Misc/ast-dump-templates.cpp
index b7aeca8d55d..022d5c41127 100644
--- a/test/Misc/ast-dump-templates.cpp
+++ b/test/Misc/ast-dump-templates.cpp
@@ -39,6 +39,18 @@ void baz() {
 // CHECK1: template <int A, typename B> B bar()
 // CHECK2: template <int A, typename B> B bar()
 
+// CHECK1-LABEL: template <typename ...T> struct A {
+// CHECK1-NEXT:    template <T ...x[3]> struct B {
+template <typename ...T> struct A {
+  template <T ...x[3]> struct B {};
+};
+
+// CHECK1-LABEL: template <typename ...T> void f(T ...[3]) {
+// CHECK1-NEXT:    A<T [3]...> a;
+template <typename ...T> void f(T ...[3]) {
+  A<T [3]...> a;
+}
+
 namespace test2 {
 void func(int);
 void func(float);
diff --git a/test/SemaCXX/cxx11-ast-print.cpp b/test/SemaCXX/cxx11-ast-print.cpp
index f7bfc1123a7..5604374c561 100644
--- a/test/SemaCXX/cxx11-ast-print.cpp
+++ b/test/SemaCXX/cxx11-ast-print.cpp
@@ -15,7 +15,7 @@ decltype(4.5_baz) operator"" _baz(char);
 // CHECK: const char *operator "" _quux(const char *);
 const char *operator"" _quux(const char *);
 
-// CHECK: template <char...> const char *operator "" _fritz();
+// CHECK: template <char ...> const char *operator "" _fritz();
 template<char...> const char *operator"" _fritz();
 
 // CHECK: const char *p1 = "bar1"_foo;
diff --git a/unittests/AST/DeclPrinterTest.cpp b/unittests/AST/DeclPrinterTest.cpp
index 5340756c03d..9ba597994bc 100644
--- a/unittests/AST/DeclPrinterTest.cpp
+++ b/unittests/AST/DeclPrinterTest.cpp
@@ -544,6 +544,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl10) {
     "};",
     constructorDecl(ofClass(hasName("A"))).bind("id"),
     "A<T...>(const A<T...> &a)"));
+    // WRONG; Should be: "A(const A<T...> &a);"
 }
 
 TEST(DeclPrinter, TestCXXConstructorDecl11) {
@@ -553,8 +554,8 @@ TEST(DeclPrinter, TestCXXConstructorDecl11) {
     "  A(T&&... ts) : T(ts)... {}"
     "};",
     constructorDecl(ofClass(hasName("A"))).bind("id"),
-    "A<T...>(T &&ts...) : T(ts)..."));
-    // WRONG; Should be: "A(T&&... ts) : T(ts)..."
+    "A<T...>(T &&...ts) : T(ts)..."));
+    // WRONG; Should be: "A(T &&...ts) : T(ts)... {}"
 }
 
 TEST(DeclPrinter, TestCXXDestructorDecl1) {
@@ -1011,8 +1012,8 @@ TEST(DeclPrinter, TestClassTemplateDecl10) {
     "template<typename... T>"
     "struct A { int a; };",
     classTemplateDecl(hasName("A")).bind("id"),
-    "template <typename ... T> struct A {\n}"));
-    // Should be: with semicolon, with { ... }, without spaces before '...'
+    "template <typename ...T> struct A {\n}"));
+    // Should be: with semicolon, with { ... }
 }
 
 TEST(DeclPrinter, TestClassTemplateDecl11) {
@@ -1020,8 +1021,8 @@ TEST(DeclPrinter, TestClassTemplateDecl11) {
     "template<typename... T>"
     "struct A : public T... { int a; };",
     classTemplateDecl(hasName("A")).bind("id"),
-    "template <typename ... T> struct A : public T... {\n}"));
-    // Should be: with semicolon, with { ... }, without spaces before '...'
+    "template <typename ...T> struct A : public T... {\n}"));
+    // Should be: with semicolon, with { ... }
 }
 
 TEST(DeclPrinter, TestClassTemplatePartialSpecializationDecl1) {
@@ -1080,9 +1081,7 @@ TEST(DeclPrinter, TestFunctionTemplateDecl3) {
     "template<typename... T>"
     "void A(T... a);",
     functionTemplateDecl(hasName("A")).bind("id"),
-    "template <typename ... T> void A(T a...)"));
-    // WRONG; Should be: "template <typename ... T> void A(T... a)"
-    //        (not "T a...")
+    "template <typename ...T> void A(T ...a)"));
     // Should be: with semicolon.
 }
 
@@ -1239,7 +1238,7 @@ TEST(DeclPrinter, TestTemplateArgumentList13) {
     "};",
     "A",
     "Z<T...> A"));
-    // Should be: with semicolon, without extra space in "> >"
+    // Should be: with semicolon
 }
 
 TEST(DeclPrinter, TestTemplateArgumentList14) {
@@ -1251,7 +1250,7 @@ TEST(DeclPrinter, TestTemplateArgumentList14) {
     "};",
     "A",
     "Z<Y<T>...> A"));
-    // Should be: with semicolon, without extra space in "> >"
+    // Should be: with semicolon
 }
 
 TEST(DeclPrinter, TestTemplateArgumentList15) {
@@ -1262,7 +1261,7 @@ TEST(DeclPrinter, TestTemplateArgumentList15) {
     "};",
     "A",
     "Z<sizeof...(T)> A"));
-    // Should be: with semicolon, without extra space in "> >"
+    // Should be: with semicolon
 }
 
 TEST(DeclPrinter, TestObjCMethod1) {
-- 
GitLab