]> granicus.if.org Git - clang/commitdiff
Use raw_ostream in TypePrinter and eliminate uses of temporary std::strings.
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Sat, 5 May 2012 04:20:37 +0000 (04:20 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Sat, 5 May 2012 04:20:37 +0000 (04:20 +0000)
Part of rdar://10796159

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@156228 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Decl.h
include/clang/AST/Type.h
include/clang/Basic/IdentifierTable.h
lib/AST/Decl.cpp
lib/AST/DeclPrinter.cpp
lib/AST/Expr.cpp
lib/AST/TypePrinter.cpp
test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp
test/Sema/vector-ops.c

index cc636196e8bc928a7bf3495032fff10f8b4a8acd..1f6b106ee0585f99f402fba59afef624fd672507 100644 (file)
@@ -2603,6 +2603,7 @@ public:
 
   void setCompleteDefinition(bool V) { IsCompleteDefinition = V; }
 
+  // FIXME: Return StringRef;
   const char *getKindName() const {
     return TypeWithKeyword::getTagTypeKindName(getTagKind());
   }
index 32e55e9ef6bb8aa9fc747bef7bb1a0e6afd865a4..3c958b21affbc673621e57ebd7fd1a87ca10ff2b 100644 (file)
@@ -29,6 +29,7 @@
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/PointerIntPair.h"
 #include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/Twine.h"
 #include "clang/Basic/LLVM.h"
 
 namespace clang {
@@ -412,12 +413,11 @@ public:
   }
 
   std::string getAsString() const;
-  std::string getAsString(const PrintingPolicy &Policy) const {
-    std::string Buffer;
-    getAsStringInternal(Buffer, Policy);
-    return Buffer;
-  }
-  void getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const;
+  std::string getAsString(const PrintingPolicy &Policy) const;
+
+  bool isEmptyWhenPrinted(const PrintingPolicy &Policy) const;
+  void print(raw_ostream &OS, const PrintingPolicy &Policy,
+             bool appendSpaceIfNonEmpty = false) const;
 
   void Profile(llvm::FoldingSetNodeID &ID) const {
     ID.AddInteger(Mask);
@@ -829,11 +829,20 @@ public:
   }
   static std::string getAsString(const Type *ty, Qualifiers qs);
 
-  std::string getAsString(const PrintingPolicy &Policy) const {
-    std::string S;
-    getAsStringInternal(S, Policy);
-    return S;
+  std::string getAsString(const PrintingPolicy &Policy) const;
+
+  void print(raw_ostream &OS, const PrintingPolicy &Policy,
+             const Twine &PlaceHolder = Twine()) const {
+    print(split(), OS, Policy, PlaceHolder);
+  }
+  static void print(SplitQualType split, raw_ostream &OS,
+                    const PrintingPolicy &policy, const Twine &PlaceHolder) {
+    return print(split.Ty, split.Quals, OS, policy, PlaceHolder);
   }
+  static void print(const Type *ty, Qualifiers qs,
+                    raw_ostream &OS, const PrintingPolicy &policy,
+                    const Twine &PlaceHolder);
+
   void getAsStringInternal(std::string &Str,
                            const PrintingPolicy &Policy) const {
     return getAsStringInternal(split(), Str, Policy);
@@ -846,6 +855,27 @@ public:
                                   std::string &out,
                                   const PrintingPolicy &policy);
 
+  class StreamedQualTypeHelper {
+    const QualType &T;
+    const PrintingPolicy &Policy;
+    const Twine &PlaceHolder;
+  public:
+    StreamedQualTypeHelper(const QualType &T, const PrintingPolicy &Policy,
+                           const Twine &PlaceHolder)
+      : T(T), Policy(Policy), PlaceHolder(PlaceHolder) { }
+
+    friend raw_ostream &operator<<(raw_ostream &OS,
+                                   const StreamedQualTypeHelper &SQT) {
+      SQT.T.print(OS, SQT.Policy, SQT.PlaceHolder);
+      return OS;
+    }
+  };
+
+  StreamedQualTypeHelper stream(const PrintingPolicy &Policy,
+                                const Twine &PlaceHolder = Twine()) const {
+    return StreamedQualTypeHelper(*this, Policy, PlaceHolder);
+  }
+
   void dump(const char *s) const;
   void dump() const;
 
@@ -2939,8 +2969,11 @@ public:
   bool isSugared() const { return false; }
   QualType desugar() const { return QualType(this, 0); }
 
+  // FIXME: Remove the string version.
   void printExceptionSpecification(std::string &S, 
                                    PrintingPolicy Policy) const;
+  void printExceptionSpecification(raw_ostream &OS, 
+                                   PrintingPolicy Policy) const;
 
   static bool classof(const Type *T) {
     return T->getTypeClass() == FunctionProto;
@@ -3593,6 +3626,7 @@ public:
 
   /// \brief Print a template argument list, including the '<' and '>'
   /// enclosing the template arguments.
+  // FIXME: remove the string ones.
   static std::string PrintTemplateArgumentList(const TemplateArgument *Args,
                                                unsigned NumArgs,
                                                const PrintingPolicy &Policy,
@@ -3605,6 +3639,23 @@ public:
   static std::string PrintTemplateArgumentList(const TemplateArgumentListInfo &,
                                                const PrintingPolicy &Policy);
 
+  /// \brief Print a template argument list, including the '<' and '>'
+  /// enclosing the template arguments.
+  static void PrintTemplateArgumentList(raw_ostream &OS,
+                                        const TemplateArgument *Args,
+                                        unsigned NumArgs,
+                                        const PrintingPolicy &Policy,
+                                        bool SkipBrackets = false);
+
+  static void PrintTemplateArgumentList(raw_ostream &OS,
+                                        const TemplateArgumentLoc *Args,
+                                        unsigned NumArgs,
+                                        const PrintingPolicy &Policy);
+
+  static void PrintTemplateArgumentList(raw_ostream &OS,
+                                        const TemplateArgumentListInfo &,
+                                        const PrintingPolicy &Policy);
+
   /// True if this template specialization type matches a current
   /// instantiation in the context in which it is found.
   bool isCurrentInstantiation() const {
index d79e28b295818e25f85ab85da200975cf0a40e41..dffebebd0c33b639d485c3a908c91e4d71330cd2 100644 (file)
@@ -669,6 +669,7 @@ public:
   
   /// getAsString - Derive the full selector name (e.g. "foo:bar:") and return
   /// it as an std::string.
+  // FIXME: Add a print method that uses a raw_ostream.
   std::string getAsString() const;
 
   /// getMethodFamily - Derive the conventional family of this method.
index 3efa55ea0faab5854733b4f803989d9b7825dd1d..15fa7902031220c5cda89293412b9c377779eb8e 100644 (file)
@@ -861,9 +861,7 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
         for (unsigned i = 0; i < NumParams; ++i) {
           if (i)
             OS << ", ";
-          std::string Param;
-          FD->getParamDecl(i)->getType().getAsStringInternal(Param, P);
-          OS << Param;
+          OS << FD->getParamDecl(i)->getType().stream(P);
         }
 
         if (FT->isVariadic()) {
index 5df0fbe540ec619dc33f47af04d6f77072cb10ea..d65825e395c16e8997322a0052a1ac9e96b72bbe 100644 (file)
@@ -322,15 +322,13 @@ void DeclPrinter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
 }
 
 void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) {
-  std::string S = D->getNameAsString();
-  D->getUnderlyingType().getAsStringInternal(S, Policy);
   if (!Policy.SuppressSpecifiers) {
     Out << "typedef ";
     
     if (D->isModulePrivate())
       Out << "__module_private__ ";
   }
-  Out << S;
+  D->getUnderlyingType().print(Out, Policy, D->getName());
   prettyPrintAttributes(D);
 }
 
@@ -350,11 +348,8 @@ void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
   }
   Out << *D;
 
-  if (D->isFixed()) {
-    std::string Underlying;
-    D->getIntegerType().getAsStringInternal(Underlying, Policy);
-    Out << " : " << Underlying;
-  }
+  if (D->isFixed())
+    Out << " : " << D->getIntegerType().stream(Policy);
 
   if (D->isCompleteDefinition()) {
     Out << " {\n";
@@ -460,9 +455,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
           if (I)
             Proto += ", ";
 
-          std::string ExceptionType;
-          FT->getExceptionType(I).getAsStringInternal(ExceptionType, SubPolicy);
-          Proto += ExceptionType;
+          Proto += FT->getExceptionType(I).getAsString(SubPolicy);;
         }
       Proto += ")";
     } else if (FT && isNoexceptExceptionSpec(FT->getExceptionSpecType())) {
@@ -542,12 +535,11 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
       }
     }
     else
-      AFT->getResultType().getAsStringInternal(Proto, Policy);
+      AFT->getResultType().print(Out, Policy, Proto);
   } else {
-    Ty.getAsStringInternal(Proto, Policy);
+    Ty.print(Out, Policy, Proto);
   }
 
-  Out << Proto;
   prettyPrintAttributes(D);
 
   if (D->isPure())
@@ -581,9 +573,7 @@ void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
   if (!Policy.SuppressSpecifiers && D->isModulePrivate())
     Out << "__module_private__ ";
 
-  std::string Name = D->getNameAsString();
-  D->getType().getAsStringInternal(Name, Policy);
-  Out << Name;
+  Out << D->getType().stream(Policy, D->getName());
 
   if (D->isBitField()) {
     Out << " : ";
@@ -613,12 +603,10 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
   if (!Policy.SuppressSpecifiers && D->isModulePrivate())
     Out << "__module_private__ ";
 
-  std::string Name = D->getNameAsString();
   QualType T = D->getType();
   if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D))
     T = Parm->getOriginalType();
-  T.getAsStringInternal(Name, Policy);
-  Out << Name;
+  T.print(Out, Policy, D->getName());
   Expr *Init = D->getInit();
   if (!Policy.SuppressInitializers && Init) {
     bool ImplicitInit = false;
index fcde5429b394c002c2d972b761401b2db0bfe6c0..afc7410a81edd9a772c1fc891369dcb1bf753068 100644 (file)
@@ -414,9 +414,7 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
     if (FT) {
       for (unsigned i = 0, e = Decl->getNumParams(); i != e; ++i) {
         if (i) POut << ", ";
-        std::string Param;
-        Decl->getParamDecl(i)->getType().getAsStringInternal(Param, Policy);
-        POut << Param;
+        POut << Decl->getParamDecl(i)->getType().stream(Policy);
       }
 
       if (FT->isVariadic()) {
index 5ec548f3f9a076bd6781c673102f4d32a4e7d2d4..111fee9d8820d5ab10849801b0ad29b160f3cfa2 100644 (file)
 #include "clang/AST/PrettyPrinter.h"
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/SaveAndRestore.h"
 using namespace clang;
 
 namespace {
@@ -40,62 +42,124 @@ namespace {
       Policy.SuppressStrongLifetime = Old;
     }
   };
+
+  class ParamPolicyRAII {
+    PrintingPolicy &Policy;
+    bool Old;
+    
+  public:
+    explicit ParamPolicyRAII(PrintingPolicy &Policy) 
+      : Policy(Policy), Old(Policy.SuppressSpecifiers) {
+      Policy.SuppressSpecifiers = false;
+    }
+    
+    ~ParamPolicyRAII() {
+      Policy.SuppressSpecifiers = Old;
+    }
+  };
+
+  class ElaboratedTypePolicyRAII {
+    PrintingPolicy &Policy;
+    bool SuppressTagKeyword;
+    bool SuppressScope;
+    
+  public:
+    explicit ElaboratedTypePolicyRAII(PrintingPolicy &Policy) : Policy(Policy) {
+      SuppressTagKeyword = Policy.SuppressTagKeyword;
+      SuppressScope = Policy.SuppressScope;
+      Policy.SuppressTagKeyword = true;
+      Policy.SuppressScope = true;
+    }
+    
+    ~ElaboratedTypePolicyRAII() {
+      Policy.SuppressTagKeyword = SuppressTagKeyword;
+      Policy.SuppressScope = SuppressScope;
+    }
+  };
   
   class TypePrinter {
     PrintingPolicy Policy;
+    bool HasEmptyPlaceHolder;
 
   public:
-    explicit TypePrinter(const PrintingPolicy &Policy) : Policy(Policy) { }
-
-    void print(const Type *ty, Qualifiers qs, std::string &buffer);
-    void print(QualType T, std::string &S);
-    void AppendScope(DeclContext *DC, std::string &S);
-    void printTag(TagDecl *T, std::string &S);
+    explicit TypePrinter(const PrintingPolicy &Policy)
+      : Policy(Policy), HasEmptyPlaceHolder(false) { }
+
+    void print(const Type *ty, Qualifiers qs, raw_ostream &OS,
+               StringRef PlaceHolder);
+    void print(QualType T, raw_ostream &OS, StringRef PlaceHolder);
+
+    static bool canPrefixQualifiers(const Type *T, bool &NeedARCStrongQualifier);
+    void spaceBeforePlaceHolder(raw_ostream &OS);
+    void printTypeSpec(const NamedDecl *D, raw_ostream &OS);
+
+    void printBefore(const Type *ty, Qualifiers qs, raw_ostream &OS);
+    void printBefore(QualType T, raw_ostream &OS);
+    void printAfter(const Type *ty, Qualifiers qs, raw_ostream &OS);
+    void printAfter(QualType T, raw_ostream &OS);
+    void AppendScope(DeclContext *DC, raw_ostream &OS);
+    void printTag(TagDecl *T, raw_ostream &OS);
 #define ABSTRACT_TYPE(CLASS, PARENT)
 #define TYPE(CLASS, PARENT) \
-    void print##CLASS(const CLASS##Type *T, std::string &S);
+    void print##CLASS##Before(const CLASS##Type *T, raw_ostream &OS); \
+    void print##CLASS##After(const CLASS##Type *T, raw_ostream &OS);
 #include "clang/AST/TypeNodes.def"
   };
 }
 
-static void AppendTypeQualList(std::string &S, unsigned TypeQuals) {
+static void AppendTypeQualList(raw_ostream &OS, unsigned TypeQuals) {
+  bool appendSpace = false;
   if (TypeQuals & Qualifiers::Const) {
-    if (!S.empty()) S += ' ';
-    S += "const";
+    OS << "const";
+    appendSpace = true;
   }
   if (TypeQuals & Qualifiers::Volatile) {
-    if (!S.empty()) S += ' ';
-    S += "volatile";
+    if (appendSpace) OS << ' ';
+    OS << "volatile";
+    appendSpace = true;
   }
   if (TypeQuals & Qualifiers::Restrict) {
-    if (!S.empty()) S += ' ';
-    S += "restrict";
+    if (appendSpace) OS << ' ';
+    OS << "restrict";
   }
 }
 
-void TypePrinter::print(QualType t, std::string &buffer) {
+void TypePrinter::spaceBeforePlaceHolder(raw_ostream &OS) {
+  if (!HasEmptyPlaceHolder)
+    OS << ' ';
+}
+
+void TypePrinter::print(QualType t, raw_ostream &OS, StringRef PlaceHolder) {
   SplitQualType split = t.split();
-  print(split.Ty, split.Quals, buffer);
+  print(split.Ty, split.Quals, OS, PlaceHolder);
 }
 
-void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
+void TypePrinter::print(const Type *T, Qualifiers Quals, raw_ostream &OS,
+                        StringRef PlaceHolder) {
   if (!T) {
-    buffer += "NULL TYPE";
+    OS << "NULL TYPE";
     return;
   }
   
   if (Policy.SuppressSpecifiers && T->isSpecifierType())
     return;
-  
-  // Print qualifiers as appropriate.
-  
+
+  SaveAndRestore<bool> PHVal(HasEmptyPlaceHolder, PlaceHolder.empty());
+
+  printBefore(T, Quals, OS);
+  OS << PlaceHolder;
+  printAfter(T, Quals, OS);
+}
+
+bool TypePrinter::canPrefixQualifiers(const Type *T,
+                                      bool &NeedARCStrongQualifier) {
   // CanPrefixQualifiers - We prefer to print type qualifiers before the type,
   // so that we get "const int" instead of "int const", but we can't do this if
   // the type is complex.  For example if the type is "int*", we *must* print
   // "int * const", printing "const int *" is different.  Only do this when the
   // type expands to a simple string.
   bool CanPrefixQualifiers = false;
-  bool NeedARCStrongQualifier = false;
+  NeedARCStrongQualifier = false;
   Type::TypeClass TC = T->getTypeClass();
   if (const AutoType *AT = dyn_cast<AutoType>(T))
     TC = AT->desugar()->getTypeClass();
@@ -157,493 +221,608 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
       CanPrefixQualifiers = false;
       break;
   }
-  
-  if (!CanPrefixQualifiers && !Quals.empty()) {
-    std::string qualsBuffer;
+
+  return CanPrefixQualifiers;
+}
+
+void TypePrinter::printBefore(QualType t, raw_ostream &OS) {
+  SplitQualType split = t.split();
+  printBefore(split.Ty, split.Quals, OS);
+}
+
+/// \brief Prints the part of the type string before an identifier, e.g. for
+/// "int foo[10]" it prints "int ".
+void TypePrinter::printBefore(const Type *T,Qualifiers Quals, raw_ostream &OS) {
+  if (Policy.SuppressSpecifiers && T->isSpecifierType())
+    return;
+
+  SaveAndRestore<bool> PrevPHIsEmpty(HasEmptyPlaceHolder);
+
+  // Print qualifiers as appropriate.
+
+  bool CanPrefixQualifiers = false;
+  bool NeedARCStrongQualifier = false;
+  CanPrefixQualifiers = canPrefixQualifiers(T, NeedARCStrongQualifier);
+
+  if (CanPrefixQualifiers && !Quals.empty()) {
     if (NeedARCStrongQualifier) {
       IncludeStrongLifetimeRAII Strong(Policy);
-      Quals.getAsStringInternal(qualsBuffer, Policy);
+      Quals.print(OS, Policy, /*appendSpaceIfNonEmpty=*/true);
     } else {
-      Quals.getAsStringInternal(qualsBuffer, Policy);
-    }
-    
-    if (!qualsBuffer.empty()) {
-      if (!buffer.empty()) {
-        qualsBuffer += ' ';
-        qualsBuffer += buffer;
-      }
-      std::swap(buffer, qualsBuffer);
+      Quals.print(OS, Policy, /*appendSpaceIfNonEmpty=*/true);
     }
   }
-  
+
+  bool hasAfterQuals = false;
+  if (!CanPrefixQualifiers && !Quals.empty()) {
+    hasAfterQuals = !Quals.isEmptyWhenPrinted(Policy);
+    if (hasAfterQuals)
+      HasEmptyPlaceHolder = false;
+  }
+
   switch (T->getTypeClass()) {
 #define ABSTRACT_TYPE(CLASS, PARENT)
 #define TYPE(CLASS, PARENT) case Type::CLASS: \
-    print##CLASS(cast<CLASS##Type>(T), buffer); \
+    print##CLASS##Before(cast<CLASS##Type>(T), OS); \
     break;
 #include "clang/AST/TypeNodes.def"
   }
-  
-  // If we're adding the qualifiers as a prefix, do it now.
-  if (CanPrefixQualifiers && !Quals.empty()) {
-    std::string qualsBuffer;
+
+  if (hasAfterQuals) {
     if (NeedARCStrongQualifier) {
       IncludeStrongLifetimeRAII Strong(Policy);
-      Quals.getAsStringInternal(qualsBuffer, Policy);
+      Quals.print(OS, Policy, /*appendSpaceIfNonEmpty=*/!PrevPHIsEmpty.get());
     } else {
-      Quals.getAsStringInternal(qualsBuffer, Policy);
-    }
-
-    if (!qualsBuffer.empty()) {
-      if (!buffer.empty()) {
-        qualsBuffer += ' ';
-        qualsBuffer += buffer;
-      }
-      std::swap(buffer, qualsBuffer);
+      Quals.print(OS, Policy, /*appendSpaceIfNonEmpty=*/!PrevPHIsEmpty.get());
     }
   }
 }
 
-void TypePrinter::printBuiltin(const BuiltinType *T, std::string &S) {
-  if (S.empty()) {
-    S = T->getName(Policy);
-  } else {
-    // Prefix the basic type, e.g. 'int X'.
-    S = ' ' + S;
-    S = T->getNameAsCString(Policy) + S;
+void TypePrinter::printAfter(QualType t, raw_ostream &OS) {
+  SplitQualType split = t.split();
+  printAfter(split.Ty, split.Quals, OS);
+}
+
+/// \brief Prints the part of the type string after an identifier, e.g. for
+/// "int foo[10]" it prints "[10]".
+void TypePrinter::printAfter(const Type *T, Qualifiers Quals, raw_ostream &OS) {
+  switch (T->getTypeClass()) {
+#define ABSTRACT_TYPE(CLASS, PARENT)
+#define TYPE(CLASS, PARENT) case Type::CLASS: \
+    print##CLASS##After(cast<CLASS##Type>(T), OS); \
+    break;
+#include "clang/AST/TypeNodes.def"
   }
 }
 
-void TypePrinter::printComplex(const ComplexType *T, std::string &S) {
-  print(T->getElementType(), S);
-  S = "_Complex " + S;
+void TypePrinter::printBuiltinBefore(const BuiltinType *T, raw_ostream &OS) {
+  OS << T->getName(Policy);
+  spaceBeforePlaceHolder(OS);
 }
+void TypePrinter::printBuiltinAfter(const BuiltinType *T, raw_ostream &OS) { }
 
-void TypePrinter::printPointer(const PointerType *T, std::string &S) { 
-  S = '*' + S;
-  
+void TypePrinter::printComplexBefore(const ComplexType *T, raw_ostream &OS) {
+  OS << "_Complex ";
+  printBefore(T->getElementType(), OS);
+}
+void TypePrinter::printComplexAfter(const ComplexType *T, raw_ostream &OS) {
+  printAfter(T->getElementType(), OS);
+}
+
+void TypePrinter::printPointerBefore(const PointerType *T, raw_ostream &OS) {
+  IncludeStrongLifetimeRAII Strong(Policy);
+  SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+  printBefore(T->getPointeeType(), OS);
   // Handle things like 'int (*A)[4];' correctly.
   // FIXME: this should include vectors, but vectors use attributes I guess.
   if (isa<ArrayType>(T->getPointeeType()))
-    S = '(' + S + ')';
-  
+    OS << '(';
+  OS << '*';
+}
+void TypePrinter::printPointerAfter(const PointerType *T, raw_ostream &OS) {
   IncludeStrongLifetimeRAII Strong(Policy);
-  print(T->getPointeeType(), S);
+  SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+  // Handle things like 'int (*A)[4];' correctly.
+  // FIXME: this should include vectors, but vectors use attributes I guess.
+  if (isa<ArrayType>(T->getPointeeType()))
+    OS << ')';
+  printAfter(T->getPointeeType(), OS);
 }
 
-void TypePrinter::printBlockPointer(const BlockPointerType *T, std::string &S) {
-  S = '^' + S;
-  print(T->getPointeeType(), S);
+void TypePrinter::printBlockPointerBefore(const BlockPointerType *T,
+                                          raw_ostream &OS) {
+  SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+  printBefore(T->getPointeeType(), OS);
+  OS << '^';
+}
+void TypePrinter::printBlockPointerAfter(const BlockPointerType *T,
+                                          raw_ostream &OS) {
+  SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+  printAfter(T->getPointeeType(), OS);
 }
 
-void TypePrinter::printLValueReference(const LValueReferenceType *T, 
-                                       std::string &S) { 
-  S = '&' + S;
-  
+void TypePrinter::printLValueReferenceBefore(const LValueReferenceType *T,
+                                             raw_ostream &OS) {
+  IncludeStrongLifetimeRAII Strong(Policy);
+  SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+  printBefore(T->getPointeeTypeAsWritten(), OS);
   // Handle things like 'int (&A)[4];' correctly.
   // FIXME: this should include vectors, but vectors use attributes I guess.
   if (isa<ArrayType>(T->getPointeeTypeAsWritten()))
-    S = '(' + S + ')';
-  
+    OS << '(';
+  OS << '&';
+}
+void TypePrinter::printLValueReferenceAfter(const LValueReferenceType *T,
+                                            raw_ostream &OS) {
   IncludeStrongLifetimeRAII Strong(Policy);
-  print(T->getPointeeTypeAsWritten(), S);
+  SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+  // Handle things like 'int (&A)[4];' correctly.
+  // FIXME: this should include vectors, but vectors use attributes I guess.
+  if (isa<ArrayType>(T->getPointeeTypeAsWritten()))
+    OS << ')';
+  printAfter(T->getPointeeTypeAsWritten(), OS);
 }
 
-void TypePrinter::printRValueReference(const RValueReferenceType *T, 
-                                       std::string &S) { 
-  S = "&&" + S;
-  
+void TypePrinter::printRValueReferenceBefore(const RValueReferenceType *T,
+                                             raw_ostream &OS) {
+  IncludeStrongLifetimeRAII Strong(Policy);
+  SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+  printBefore(T->getPointeeTypeAsWritten(), OS);
   // Handle things like 'int (&&A)[4];' correctly.
   // FIXME: this should include vectors, but vectors use attributes I guess.
   if (isa<ArrayType>(T->getPointeeTypeAsWritten()))
-    S = '(' + S + ')';
-  
+    OS << '(';
+  OS << "&&";
+}
+void TypePrinter::printRValueReferenceAfter(const RValueReferenceType *T,
+                                            raw_ostream &OS) {
   IncludeStrongLifetimeRAII Strong(Policy);
-  print(T->getPointeeTypeAsWritten(), S);
+  SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+  // Handle things like 'int (&&A)[4];' correctly.
+  // FIXME: this should include vectors, but vectors use attributes I guess.
+  if (isa<ArrayType>(T->getPointeeTypeAsWritten()))
+    OS << ')';
+  printAfter(T->getPointeeTypeAsWritten(), OS);
 }
 
-void TypePrinter::printMemberPointer(const MemberPointerType *T, 
-                                     std::string &S) { 
-  PrintingPolicy InnerPolicy(Policy);
-  Policy.SuppressTag = true;
-  std::string C = QualType(T->getClass(), 0).getAsString(InnerPolicy);
-  C += "::*";
-  S = C + S;
-  
+void TypePrinter::printMemberPointerBefore(const MemberPointerType *T, 
+                                           raw_ostream &OS) { 
+  IncludeStrongLifetimeRAII Strong(Policy);
+  SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+  printBefore(T->getPointeeType(), OS);
   // Handle things like 'int (Cls::*A)[4];' correctly.
   // FIXME: this should include vectors, but vectors use attributes I guess.
   if (isa<ArrayType>(T->getPointeeType()))
-    S = '(' + S + ')';
-  
+    OS << '(';
+
+  PrintingPolicy InnerPolicy(Policy);
+  InnerPolicy.SuppressTag = false;
+  TypePrinter(InnerPolicy).print(QualType(T->getClass(), 0), OS, StringRef());
+
+  OS << "::*";
+}
+void TypePrinter::printMemberPointerAfter(const MemberPointerType *T, 
+                                          raw_ostream &OS) { 
   IncludeStrongLifetimeRAII Strong(Policy);
-  print(T->getPointeeType(), S);
+  SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+  // Handle things like 'int (Cls::*A)[4];' correctly.
+  // FIXME: this should include vectors, but vectors use attributes I guess.
+  if (isa<ArrayType>(T->getPointeeType()))
+    OS << ')';
+  printAfter(T->getPointeeType(), OS);
 }
 
-void TypePrinter::printConstantArray(const ConstantArrayType *T, 
-                                     std::string &S) {
-  S += '[';
-  S += llvm::utostr(T->getSize().getZExtValue());
-  S += ']';
-  
+void TypePrinter::printConstantArrayBefore(const ConstantArrayType *T, 
+                                           raw_ostream &OS) {
   IncludeStrongLifetimeRAII Strong(Policy);
-  print(T->getElementType(), S);
+  SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+  printBefore(T->getElementType(), OS);
+}
+void TypePrinter::printConstantArrayAfter(const ConstantArrayType *T, 
+                                          raw_ostream &OS) {
+  OS << '[' << T->getSize().getZExtValue() << ']';
+  printAfter(T->getElementType(), OS);
 }
 
-void TypePrinter::printIncompleteArray(const IncompleteArrayType *T, 
-                                       std::string &S) {
-  S += "[]";
+void TypePrinter::printIncompleteArrayBefore(const IncompleteArrayType *T, 
+                                             raw_ostream &OS) {
   IncludeStrongLifetimeRAII Strong(Policy);
-  print(T->getElementType(), S);
+  SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+  printBefore(T->getElementType(), OS);
+}
+void TypePrinter::printIncompleteArrayAfter(const IncompleteArrayType *T, 
+                                            raw_ostream &OS) {
+  OS << "[]";
+  printAfter(T->getElementType(), OS);
 }
 
-void TypePrinter::printVariableArray(const VariableArrayType *T, 
-                                     std::string &S) { 
-  S += '[';
-  
+void TypePrinter::printVariableArrayBefore(const VariableArrayType *T, 
+                                           raw_ostream &OS) {
+  IncludeStrongLifetimeRAII Strong(Policy);
+  SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+  printBefore(T->getElementType(), OS);
+}
+void TypePrinter::printVariableArrayAfter(const VariableArrayType *T, 
+                                          raw_ostream &OS) {
+  OS << '[';
   if (T->getIndexTypeQualifiers().hasQualifiers()) {
-    AppendTypeQualList(S, T->getIndexTypeCVRQualifiers());
-    S += ' ';
+    AppendTypeQualList(OS, T->getIndexTypeCVRQualifiers());
+    OS << ' ';
   }
   
   if (T->getSizeModifier() == VariableArrayType::Static)
-    S += "static";
+    OS << "static";
   else if (T->getSizeModifier() == VariableArrayType::Star)
-    S += '*';
-  
-  if (T->getSizeExpr()) {
-    std::string SStr;
-    llvm::raw_string_ostream s(SStr);
-    T->getSizeExpr()->printPretty(s, 0, Policy);
-    S += s.str();
-  }
-  S += ']';
+    OS << '*';
   
-  IncludeStrongLifetimeRAII Strong(Policy);
-  print(T->getElementType(), S);
+  if (T->getSizeExpr())
+    T->getSizeExpr()->printPretty(OS, 0, Policy);
+  OS << ']';
+
+  printAfter(T->getElementType(), OS);
 }
 
-void TypePrinter::printDependentSizedArray(const DependentSizedArrayType *T, 
-                                           std::string &S) {  
-  S += '[';
-  
-  if (T->getSizeExpr()) {
-    std::string SStr;
-    llvm::raw_string_ostream s(SStr);
-    T->getSizeExpr()->printPretty(s, 0, Policy);
-    S += s.str();
-  }
-  S += ']';
-  
+void TypePrinter::printDependentSizedArrayBefore(
+                                               const DependentSizedArrayType *T, 
+                                               raw_ostream &OS) {
   IncludeStrongLifetimeRAII Strong(Policy);
-  print(T->getElementType(), S);
+  SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+  printBefore(T->getElementType(), OS);
+}
+void TypePrinter::printDependentSizedArrayAfter(
+                                               const DependentSizedArrayType *T, 
+                                               raw_ostream &OS) {
+  OS << '[';
+  if (T->getSizeExpr())
+    T->getSizeExpr()->printPretty(OS, 0, Policy);
+  OS << ']';
+  printAfter(T->getElementType(), OS);
 }
 
-void TypePrinter::printDependentSizedExtVector(
+void TypePrinter::printDependentSizedExtVectorBefore(
                                           const DependentSizedExtVectorType *T, 
-                                               std::string &S) { 
-  print(T->getElementType(), S);
-  
-  S += " __attribute__((ext_vector_type(";
-  if (T->getSizeExpr()) {
-    std::string SStr;
-    llvm::raw_string_ostream s(SStr);
-    T->getSizeExpr()->printPretty(s, 0, Policy);
-    S += s.str();
-  }
-  S += ")))";  
+                                          raw_ostream &OS) { 
+  printBefore(T->getElementType(), OS);
+}
+void TypePrinter::printDependentSizedExtVectorAfter(
+                                          const DependentSizedExtVectorType *T, 
+                                          raw_ostream &OS) { 
+  OS << " __attribute__((ext_vector_type(";
+  if (T->getSizeExpr())
+    T->getSizeExpr()->printPretty(OS, 0, Policy);
+  OS << ")))";  
+  printAfter(T->getElementType(), OS);
 }
 
-void TypePrinter::printVector(const VectorType *T, std::string &S) { 
+void TypePrinter::printVectorBefore(const VectorType *T, raw_ostream &OS) { 
   switch (T->getVectorKind()) {
   case VectorType::AltiVecPixel:
-    S = "__vector __pixel " + S;
+    OS << "__vector __pixel ";
     break;
   case VectorType::AltiVecBool:
-    print(T->getElementType(), S);
-    S = "__vector __bool " + S;
+    OS << "__vector __bool ";
+    printBefore(T->getElementType(), OS);
     break;
   case VectorType::AltiVecVector:
-    print(T->getElementType(), S);
-    S = "__vector " + S;
+    OS << "__vector ";
+    printBefore(T->getElementType(), OS);
     break;
   case VectorType::NeonVector:
-    print(T->getElementType(), S);
-    S = ("__attribute__((neon_vector_type(" +
-         llvm::utostr_32(T->getNumElements()) + "))) " + S);
+    OS << "__attribute__((neon_vector_type("
+       << T->getNumElements() << "))) ";
+    printBefore(T->getElementType(), OS);
     break;
   case VectorType::NeonPolyVector:
-    print(T->getElementType(), S);
-    S = ("__attribute__((neon_polyvector_type(" +
-         llvm::utostr_32(T->getNumElements()) + "))) " + S);
+    OS << "__attribute__((neon_polyvector_type(" <<
+          T->getNumElements() << "))) ";
+    printBefore(T->getElementType(), OS);
     break;
   case VectorType::GenericVector: {
     // FIXME: We prefer to print the size directly here, but have no way
     // to get the size of the type.
-    print(T->getElementType(), S);
-    std::string V = "__attribute__((__vector_size__(";
-    V += llvm::utostr_32(T->getNumElements()); // convert back to bytes.
-    std::string ET;
-    print(T->getElementType(), ET);
-    V += " * sizeof(" + ET + ")))) ";
-    S = V + S;
+    OS << "__attribute__((__vector_size__("
+       << T->getNumElements()
+       << " * sizeof(";
+    print(T->getElementType(), OS, StringRef());
+    OS << ")))) "; 
+    printBefore(T->getElementType(), OS);
     break;
   }
   }
 }
+void TypePrinter::printVectorAfter(const VectorType *T, raw_ostream &OS) {
+  printAfter(T->getElementType(), OS);
+} 
 
-void TypePrinter::printExtVector(const ExtVectorType *T, std::string &S) { 
-  S += " __attribute__((ext_vector_type(";
-  S += llvm::utostr_32(T->getNumElements());
-  S += ")))";
-  print(T->getElementType(), S);
+void TypePrinter::printExtVectorBefore(const ExtVectorType *T,
+                                       raw_ostream &OS) { 
+  printBefore(T->getElementType(), OS);
+}
+void TypePrinter::printExtVectorAfter(const ExtVectorType *T, raw_ostream &OS) { 
+  printAfter(T->getElementType(), OS);
+  OS << " __attribute__((ext_vector_type(";
+  OS << T->getNumElements();
+  OS << ")))";
 }
 
 void 
-FunctionProtoType::printExceptionSpecification(std::string &S, 
+FunctionProtoType::printExceptionSpecification(raw_ostream &OS, 
                                                PrintingPolicy Policy) const {
   
   if (hasDynamicExceptionSpec()) {
-    S += " throw(";
+    OS << " throw(";
     if (getExceptionSpecType() == EST_MSAny)
-      S += "...";
+      OS << "...";
     else
       for (unsigned I = 0, N = getNumExceptions(); I != N; ++I) {
         if (I)
-          S += ", ";
+          OS << ", ";
         
-        S += getExceptionType(I).getAsString(Policy);
+        OS << getExceptionType(I).stream(Policy);
       }
-    S += ")";
+    OS << ')';
   } else if (isNoexceptExceptionSpec(getExceptionSpecType())) {
-    S += " noexcept";
+    OS << " noexcept";
     if (getExceptionSpecType() == EST_ComputedNoexcept) {
-      S += "(";
-      llvm::raw_string_ostream EOut(S);
-      getNoexceptExpr()->printPretty(EOut, 0, Policy);
-      EOut.flush();
-      S += EOut.str();
-      S += ")";
+      OS << '(';
+      getNoexceptExpr()->printPretty(OS, 0, Policy);
+      OS << ')';
     }
   }
 }
 
-void TypePrinter::printFunctionProto(const FunctionProtoType *T, 
-                                     std::string &S) { 
+void TypePrinter::printFunctionProtoBefore(const FunctionProtoType *T, 
+                                           raw_ostream &OS) {
+  if (T->hasTrailingReturn()) {
+    OS << "auto ";
+    if (!HasEmptyPlaceHolder)
+      OS << '(';
+  } else {
+    // If needed for precedence reasons, wrap the inner part in grouping parens.
+    SaveAndRestore<bool> PrevPHIsEmpty(HasEmptyPlaceHolder, false);
+    printBefore(T->getResultType(), OS);
+    if (!PrevPHIsEmpty.get())
+      OS << '(';
+  }
+}
+
+void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T, 
+                                          raw_ostream &OS) { 
   // If needed for precedence reasons, wrap the inner part in grouping parens.
-  if (!S.empty())
-    S = "(" + S + ")";
-  
-  S += "(";
-  std::string Tmp;
-  PrintingPolicy ParamPolicy(Policy);
-  ParamPolicy.SuppressSpecifiers = false;
-  for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) {
-    if (i) S += ", ";
-    print(T->getArgType(i), Tmp);
-    S += Tmp;
-    Tmp.clear();
+  if (!HasEmptyPlaceHolder)
+    OS << ')';
+  SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+
+  OS << '(';
+  {
+    ParamPolicyRAII ParamPolicy(Policy);
+    for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) {
+      if (i) OS << ", ";
+      print(T->getArgType(i), OS, StringRef());
+    }
   }
   
   if (T->isVariadic()) {
     if (T->getNumArgs())
-      S += ", ";
-    S += "...";
+      OS << ", ";
+    OS << "...";
   } else if (T->getNumArgs() == 0 && !Policy.LangOpts.CPlusPlus) {
     // Do not emit int() if we have a proto, emit 'int(void)'.
-    S += "void";
+    OS << "void";
   }
   
-  S += ")";
+  OS << ')';
 
   FunctionType::ExtInfo Info = T->getExtInfo();
   switch(Info.getCC()) {
   case CC_Default: break;
   case CC_C:
-    S += " __attribute__((cdecl))";
+    OS << " __attribute__((cdecl))";
     break;
   case CC_X86StdCall:
-    S += " __attribute__((stdcall))";
+    OS << " __attribute__((stdcall))";
     break;
   case CC_X86FastCall:
-    S += " __attribute__((fastcall))";
+    OS << " __attribute__((fastcall))";
     break;
   case CC_X86ThisCall:
-    S += " __attribute__((thiscall))";
+    OS << " __attribute__((thiscall))";
     break;
   case CC_X86Pascal:
-    S += " __attribute__((pascal))";
+    OS << " __attribute__((pascal))";
     break;
   case CC_AAPCS:
-    S += " __attribute__((pcs(\"aapcs\")))";
+    OS << " __attribute__((pcs(\"aapcs\")))";
     break;
   case CC_AAPCS_VFP:
-    S += " __attribute__((pcs(\"aapcs-vfp\")))";
+    OS << " __attribute__((pcs(\"aapcs-vfp\")))";
     break;
   }
   if (Info.getNoReturn())
-    S += " __attribute__((noreturn))";
+    OS << " __attribute__((noreturn))";
   if (Info.getRegParm())
-    S += " __attribute__((regparm (" +
-        llvm::utostr_32(Info.getRegParm()) + ")))";
-  
-  AppendTypeQualList(S, T->getTypeQuals());
+    OS << " __attribute__((regparm ("
+       << Info.getRegParm() << ")))";
+
+  if (unsigned quals = T->getTypeQuals()) {
+    OS << ' ';
+    AppendTypeQualList(OS, quals);
+  }
 
   switch (T->getRefQualifier()) {
   case RQ_None:
     break;
     
   case RQ_LValue:
-    S += " &";
+    OS << " &";
     break;
     
   case RQ_RValue:
-    S += " &&";
+    OS << " &&";
     break;
   }
-  T->printExceptionSpecification(S, Policy);
+  T->printExceptionSpecification(OS, Policy);
+
   if (T->hasTrailingReturn()) {
-    std::string ResultS;
-    print(T->getResultType(), ResultS);
-    S = "auto " + S + " -> " + ResultS;
+    OS << " -> "; 
+    print(T->getResultType(), OS, StringRef());
   } else
-    print(T->getResultType(), S);
+    printAfter(T->getResultType(), OS);
 }
 
-void TypePrinter::printFunctionNoProto(const FunctionNoProtoType *T, 
-                                       std::string &S) { 
+void TypePrinter::printFunctionNoProtoBefore(const FunctionNoProtoType *T, 
+                                             raw_ostream &OS) { 
   // If needed for precedence reasons, wrap the inner part in grouping parens.
-  if (!S.empty())
-    S = "(" + S + ")";
+  SaveAndRestore<bool> PrevPHIsEmpty(HasEmptyPlaceHolder, false);
+  printBefore(T->getResultType(), OS);
+  if (!PrevPHIsEmpty.get())
+    OS << '(';
+}
+void TypePrinter::printFunctionNoProtoAfter(const FunctionNoProtoType *T, 
+                                            raw_ostream &OS) {
+  // If needed for precedence reasons, wrap the inner part in grouping parens.
+  if (!HasEmptyPlaceHolder)
+    OS << ')';
+  SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
   
-  S += "()";
+  OS << "()";
   if (T->getNoReturnAttr())
-    S += " __attribute__((noreturn))";
-  print(T->getResultType(), S);
+    OS << " __attribute__((noreturn))";
+  printAfter(T->getResultType(), OS);
 }
 
-static void printTypeSpec(const NamedDecl *D, std::string &S) {
+void TypePrinter::printTypeSpec(const NamedDecl *D, raw_ostream &OS) {
   IdentifierInfo *II = D->getIdentifier();
-  if (S.empty())
-    S = II->getName().str();
-  else
-    S = II->getName().str() + ' ' + S;
+  OS << II->getName();
+  spaceBeforePlaceHolder(OS);
 }
 
-void TypePrinter::printUnresolvedUsing(const UnresolvedUsingType *T,
-                                       std::string &S) {
-  printTypeSpec(T->getDecl(), S);
+void TypePrinter::printUnresolvedUsingBefore(const UnresolvedUsingType *T,
+                                             raw_ostream &OS) {
+  printTypeSpec(T->getDecl(), OS);
 }
+void TypePrinter::printUnresolvedUsingAfter(const UnresolvedUsingType *T,
+                                             raw_ostream &OS) { }
 
-void TypePrinter::printTypedef(const TypedefType *T, std::string &S) { 
-  printTypeSpec(T->getDecl(), S);
+void TypePrinter::printTypedefBefore(const TypedefType *T, raw_ostream &OS) { 
+  printTypeSpec(T->getDecl(), OS);
 }
+void TypePrinter::printTypedefAfter(const TypedefType *T, raw_ostream &OS) { } 
 
-void TypePrinter::printTypeOfExpr(const TypeOfExprType *T, std::string &S) {
-  if (!S.empty())    // Prefix the basic type, e.g. 'typeof(e) X'.
-    S = ' ' + S;
-  std::string Str;
-  llvm::raw_string_ostream s(Str);
-  T->getUnderlyingExpr()->printPretty(s, 0, Policy);
-  S = "typeof " + s.str() + S;
+void TypePrinter::printTypeOfExprBefore(const TypeOfExprType *T,
+                                        raw_ostream &OS) {
+  OS << "typeof ";
+  T->getUnderlyingExpr()->printPretty(OS, 0, Policy);
+  spaceBeforePlaceHolder(OS);
 }
-
-void TypePrinter::printTypeOf(const TypeOfType *T, std::string &S) { 
-  if (!S.empty())    // Prefix the basic type, e.g. 'typeof(t) X'.
-    S = ' ' + S;
-  std::string Tmp;
-  print(T->getUnderlyingType(), Tmp);
-  S = "typeof(" + Tmp + ")" + S;
+void TypePrinter::printTypeOfExprAfter(const TypeOfExprType *T,
+                                       raw_ostream &OS) { }
+
+void TypePrinter::printTypeOfBefore(const TypeOfType *T, raw_ostream &OS) { 
+  OS << "typeof(";
+  print(T->getUnderlyingType(), OS, StringRef());
+  OS << ')';
+  spaceBeforePlaceHolder(OS);
 }
+void TypePrinter::printTypeOfAfter(const TypeOfType *T, raw_ostream &OS) { } 
 
-void TypePrinter::printDecltype(const DecltypeType *T, std::string &S) { 
-  if (!S.empty())    // Prefix the basic type, e.g. 'decltype(t) X'.
-    S = ' ' + S;
-  std::string Str;
-  llvm::raw_string_ostream s(Str);
-  T->getUnderlyingExpr()->printPretty(s, 0, Policy);
-  S = "decltype(" + s.str() + ")" + S;
+void TypePrinter::printDecltypeBefore(const DecltypeType *T, raw_ostream &OS) { 
+  OS << "decltype(";
+  T->getUnderlyingExpr()->printPretty(OS, 0, Policy);
+  OS << ')';
+  spaceBeforePlaceHolder(OS);
 }
+void TypePrinter::printDecltypeAfter(const DecltypeType *T, raw_ostream &OS) { } 
 
-void TypePrinter::printUnaryTransform(const UnaryTransformType *T,
-                                           std::string &S) {
-  if (!S.empty())
-    S = ' ' + S;
-  std::string Str;
+void TypePrinter::printUnaryTransformBefore(const UnaryTransformType *T,
+                                            raw_ostream &OS) {
   IncludeStrongLifetimeRAII Strong(Policy);
-  print(T->getBaseType(), Str);
 
   switch (T->getUTTKind()) {
     case UnaryTransformType::EnumUnderlyingType:
-      S = "__underlying_type(" + Str + ")" + S;
-      break;
+      OS << "__underlying_type(";
+      print(T->getBaseType(), OS, StringRef());
+      OS << ')';
+      spaceBeforePlaceHolder(OS);
+      return;
+  }
+
+  printBefore(T->getBaseType(), OS);
+}
+void TypePrinter::printUnaryTransformAfter(const UnaryTransformType *T,
+                                           raw_ostream &OS) {
+  IncludeStrongLifetimeRAII Strong(Policy);
+
+  switch (T->getUTTKind()) {
+    case UnaryTransformType::EnumUnderlyingType:
+      return;
   }
+
+  printAfter(T->getBaseType(), OS);
 }
 
-void TypePrinter::printAuto(const AutoType *T, std::string &S) { 
+void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) { 
   // If the type has been deduced, do not print 'auto'.
   if (T->isDeduced()) {
-    print(T->getDeducedType(), S);
+    printBefore(T->getDeducedType(), OS);
   } else {
-    if (!S.empty())    // Prefix the basic type, e.g. 'auto X'.
-      S = ' ' + S;
-    S = "auto" + S;
+    OS << "auto";
+    spaceBeforePlaceHolder(OS);
   }
 }
+void TypePrinter::printAutoAfter(const AutoType *T, raw_ostream &OS) { 
+  // If the type has been deduced, do not print 'auto'.
+  if (T->isDeduced())
+    printAfter(T->getDeducedType(), OS);
+}
 
-void TypePrinter::printAtomic(const AtomicType *T, std::string &S) {
-  if (!S.empty())
-    S = ' ' + S;
-  std::string Str;
+void TypePrinter::printAtomicBefore(const AtomicType *T, raw_ostream &OS) {
   IncludeStrongLifetimeRAII Strong(Policy);
-  print(T->getValueType(), Str);
 
-  S = "_Atomic(" + Str + ")" + S;
+  OS << "_Atomic(";
+  print(T->getValueType(), OS, StringRef());
+  OS << ')';
+  spaceBeforePlaceHolder(OS);
 }
+void TypePrinter::printAtomicAfter(const AtomicType *T, raw_ostream &OS) { }
 
 /// Appends the given scope to the end of a string.
-void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) {
+void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS) {
   if (DC->isTranslationUnit()) return;
-  AppendScope(DC->getParent(), Buffer);
-
-  unsigned OldSize = Buffer.size();
+  AppendScope(DC->getParent(), OS);
 
   if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) {
     if (Policy.SuppressUnwrittenScope && 
         (NS->isAnonymousNamespace() || NS->isInline()))
       return;
     if (NS->getIdentifier())
-      Buffer += NS->getNameAsString();
+      OS << NS->getName() << "::";
     else
-      Buffer += "<anonymous>";
+      OS << "<anonymous>::";
   } else if (ClassTemplateSpecializationDecl *Spec
                = dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
     IncludeStrongLifetimeRAII Strong(Policy);
+    OS << Spec->getIdentifier()->getName();
     const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
-    std::string TemplateArgsStr
-      = TemplateSpecializationType::PrintTemplateArgumentList(
+    TemplateSpecializationType::PrintTemplateArgumentList(OS,
                                             TemplateArgs.data(),
                                             TemplateArgs.size(),
                                             Policy);
-    Buffer += Spec->getIdentifier()->getName();
-    Buffer += TemplateArgsStr;
+    OS << "::";
   } else if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
     if (TypedefNameDecl *Typedef = Tag->getTypedefNameForAnonDecl())
-      Buffer += Typedef->getIdentifier()->getName();
+      OS << Typedef->getIdentifier()->getName() << "::";
     else if (Tag->getIdentifier())
-      Buffer += Tag->getIdentifier()->getName();
+      OS << Tag->getIdentifier()->getName() << "::";
     else
       return;
   }
-
-  if (Buffer.size() != OldSize)
-    Buffer += "::";
 }
 
-void TypePrinter::printTag(TagDecl *D, std::string &InnerString) {
+void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) {
   if (Policy.SuppressTag)
     return;
 
-  std::string Buffer;
   bool HasKindDecoration = false;
 
   // bool SuppressTagKeyword
@@ -654,25 +833,24 @@ void TypePrinter::printTag(TagDecl *D, std::string &InnerString) {
   if (!(Policy.LangOpts.CPlusPlus || Policy.SuppressTagKeyword ||
         D->getTypedefNameForAnonDecl())) {
     HasKindDecoration = true;
-    Buffer += D->getKindName();
-    Buffer += ' ';
+    OS << D->getKindName();
+    OS << ' ';
   }
 
   // Compute the full nested-name-specifier for this type.
   // In C, this will always be empty except when the type
   // being printed is anonymous within other Record.
   if (!Policy.SuppressScope)
-    AppendScope(D->getDeclContext(), Buffer);
+    AppendScope(D->getDeclContext(), OS);
 
   if (const IdentifierInfo *II = D->getIdentifier())
-    Buffer += II->getNameStart();
+    OS << II->getName();
   else if (TypedefNameDecl *Typedef = D->getTypedefNameForAnonDecl()) {
     assert(Typedef->getIdentifier() && "Typedef without identifier?");
-    Buffer += Typedef->getIdentifier()->getNameStart();
+    OS << Typedef->getIdentifier()->getName();
   } else {
     // Make an unambiguous representation for anonymous types, e.g.
     //   <anonymous enum at /usr/include/string.h:120:9>
-    llvm::raw_string_ostream OS(Buffer);
     
     if (isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda()) {
       OS << "<lambda";
@@ -717,219 +895,223 @@ void TypePrinter::printTag(TagDecl *D, std::string &InnerString) {
       NumArgs = TemplateArgs.size();
     }
     IncludeStrongLifetimeRAII Strong(Policy);
-    Buffer += TemplateSpecializationType::PrintTemplateArgumentList(Args,
-                                                                    NumArgs,
-                                                                    Policy);
+    TemplateSpecializationType::PrintTemplateArgumentList(OS,
+                                                          Args, NumArgs,
+                                                          Policy);
   }
 
-  if (!InnerString.empty()) {
-    Buffer += ' ';
-    Buffer += InnerString;
-  }
-
-  std::swap(Buffer, InnerString);
+  spaceBeforePlaceHolder(OS);
 }
 
-void TypePrinter::printRecord(const RecordType *T, std::string &S) {
-  printTag(T->getDecl(), S);
+void TypePrinter::printRecordBefore(const RecordType *T, raw_ostream &OS) {
+  printTag(T->getDecl(), OS);
 }
+void TypePrinter::printRecordAfter(const RecordType *T, raw_ostream &OS) { }
 
-void TypePrinter::printEnum(const EnumType *T, std::string &S) { 
-  printTag(T->getDecl(), S);
+void TypePrinter::printEnumBefore(const EnumType *T, raw_ostream &OS) { 
+  printTag(T->getDecl(), OS);
 }
+void TypePrinter::printEnumAfter(const EnumType *T, raw_ostream &OS) { }
 
-void TypePrinter::printTemplateTypeParm(const TemplateTypeParmType *T, 
-                                        std::string &S) { 
-  if (!S.empty())    // Prefix the basic type, e.g. 'parmname X'.
-    S = ' ' + S;
-
+void TypePrinter::printTemplateTypeParmBefore(const TemplateTypeParmType *T, 
+                                              raw_ostream &OS) { 
   if (IdentifierInfo *Id = T->getIdentifier())
-    S = Id->getName().str() + S;
+    OS << Id->getName();
   else
-    S = "type-parameter-" + llvm::utostr_32(T->getDepth()) + '-' +
-        llvm::utostr_32(T->getIndex()) + S;
+    OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex();
+  spaceBeforePlaceHolder(OS);
 }
+void TypePrinter::printTemplateTypeParmAfter(const TemplateTypeParmType *T, 
+                                             raw_ostream &OS) { } 
 
-void TypePrinter::printSubstTemplateTypeParm(const SubstTemplateTypeParmType *T, 
-                                             std::string &S) { 
+void TypePrinter::printSubstTemplateTypeParmBefore(
+                                             const SubstTemplateTypeParmType *T, 
+                                             raw_ostream &OS) { 
+  IncludeStrongLifetimeRAII Strong(Policy);
+  printBefore(T->getReplacementType(), OS);
+}
+void TypePrinter::printSubstTemplateTypeParmAfter(
+                                             const SubstTemplateTypeParmType *T, 
+                                             raw_ostream &OS) { 
   IncludeStrongLifetimeRAII Strong(Policy);
-  print(T->getReplacementType(), S);
+  printAfter(T->getReplacementType(), OS);
 }
 
-void TypePrinter::printSubstTemplateTypeParmPack(
+void TypePrinter::printSubstTemplateTypeParmPackBefore(
                                         const SubstTemplateTypeParmPackType *T, 
-                                             std::string &S) { 
+                                        raw_ostream &OS) { 
   IncludeStrongLifetimeRAII Strong(Policy);
-  printTemplateTypeParm(T->getReplacedParameter(), S);
+  printTemplateTypeParmBefore(T->getReplacedParameter(), OS);
+}
+void TypePrinter::printSubstTemplateTypeParmPackAfter(
+                                        const SubstTemplateTypeParmPackType *T, 
+                                        raw_ostream &OS) { 
+  IncludeStrongLifetimeRAII Strong(Policy);
+  printTemplateTypeParmAfter(T->getReplacedParameter(), OS);
 }
 
-void TypePrinter::printTemplateSpecialization(
+void TypePrinter::printTemplateSpecializationBefore(
                                             const TemplateSpecializationType *T, 
-                                              std::string &S) { 
+                                            raw_ostream &OS) { 
   IncludeStrongLifetimeRAII Strong(Policy);
-  std::string SpecString;
-  
-  {
-    llvm::raw_string_ostream OS(SpecString);
-    T->getTemplateName().print(OS, Policy);
-  }
+  T->getTemplateName().print(OS, Policy);
   
-  SpecString += TemplateSpecializationType::PrintTemplateArgumentList(
-                                                                  T->getArgs(), 
-                                                                T->getNumArgs(), 
-                                                                      Policy);
-  if (S.empty())
-    S.swap(SpecString);
-  else
-    S = SpecString + ' ' + S;
+  TemplateSpecializationType::PrintTemplateArgumentList(OS,
+                                                        T->getArgs(), 
+                                                        T->getNumArgs(), 
+                                                        Policy);
+  spaceBeforePlaceHolder(OS);
 }
+void TypePrinter::printTemplateSpecializationAfter(
+                                            const TemplateSpecializationType *T, 
+                                            raw_ostream &OS) { } 
 
-void TypePrinter::printInjectedClassName(const InjectedClassNameType *T,
-                                         std::string &S) {
-  printTemplateSpecialization(T->getInjectedTST(), S);
+void TypePrinter::printInjectedClassNameBefore(const InjectedClassNameType *T,
+                                               raw_ostream &OS) {
+  printTemplateSpecializationBefore(T->getInjectedTST(), OS);
 }
-
-void TypePrinter::printElaborated(const ElaboratedType *T, std::string &S) {
-  std::string MyString;
+void TypePrinter::printInjectedClassNameAfter(const InjectedClassNameType *T,
+                                               raw_ostream &OS) { }
+
+void TypePrinter::printElaboratedBefore(const ElaboratedType *T,
+                                        raw_ostream &OS) {
+  OS << TypeWithKeyword::getKeywordName(T->getKeyword());
+  if (T->getKeyword() != ETK_None)
+    OS << " ";
+  NestedNameSpecifier* Qualifier = T->getQualifier();
+  if (Qualifier)
+    Qualifier->print(OS, Policy);
   
-  {
-    llvm::raw_string_ostream OS(MyString);
-    OS << TypeWithKeyword::getKeywordName(T->getKeyword());
-    if (T->getKeyword() != ETK_None)
-      OS << " ";
-    NestedNameSpecifier* Qualifier = T->getQualifier();
-    if (Qualifier)
-      Qualifier->print(OS, Policy);
-  }
-  
-  std::string TypeStr;
-  PrintingPolicy InnerPolicy(Policy);
-  InnerPolicy.SuppressTagKeyword = true;
-  InnerPolicy.SuppressScope = true;
-  TypePrinter(InnerPolicy).print(T->getNamedType(), TypeStr);
-  
-  MyString += TypeStr;
-  if (S.empty())
-    S.swap(MyString);
-  else
-    S = MyString + ' ' + S;  
+  ElaboratedTypePolicyRAII PolicyRAII(Policy);
+  printBefore(T->getNamedType(), OS);
+}
+void TypePrinter::printElaboratedAfter(const ElaboratedType *T,
+                                        raw_ostream &OS) {
+  ElaboratedTypePolicyRAII PolicyRAII(Policy);
+  printAfter(T->getNamedType(), OS);
 }
 
-void TypePrinter::printParen(const ParenType *T, std::string &S) {
-  if (!S.empty() && !isa<FunctionType>(T->getInnerType()))
-    S = '(' + S + ')';
-  print(T->getInnerType(), S);
+void TypePrinter::printParenBefore(const ParenType *T, raw_ostream &OS) {
+  if (!HasEmptyPlaceHolder && !isa<FunctionType>(T->getInnerType())) {
+    printBefore(T->getInnerType(), OS);
+    OS << '(';
+  } else
+    printBefore(T->getInnerType(), OS);
+}
+void TypePrinter::printParenAfter(const ParenType *T, raw_ostream &OS) {
+  if (!HasEmptyPlaceHolder && !isa<FunctionType>(T->getInnerType())) {
+    OS << ')';
+    printAfter(T->getInnerType(), OS);
+  } else
+    printAfter(T->getInnerType(), OS);
 }
 
-void TypePrinter::printDependentName(const DependentNameType *T, std::string &S) { 
-  std::string MyString;
+void TypePrinter::printDependentNameBefore(const DependentNameType *T,
+                                           raw_ostream &OS) { 
+  OS << TypeWithKeyword::getKeywordName(T->getKeyword());
+  if (T->getKeyword() != ETK_None)
+    OS << " ";
   
-  {
-    llvm::raw_string_ostream OS(MyString);
-    OS << TypeWithKeyword::getKeywordName(T->getKeyword());
-    if (T->getKeyword() != ETK_None)
-      OS << " ";
-    
-    T->getQualifier()->print(OS, Policy);
-    
-    OS << T->getIdentifier()->getName();
-  }
+  T->getQualifier()->print(OS, Policy);
   
-  if (S.empty())
-    S.swap(MyString);
-  else
-    S = MyString + ' ' + S;
+  OS << T->getIdentifier()->getName();
+  spaceBeforePlaceHolder(OS);
 }
+void TypePrinter::printDependentNameAfter(const DependentNameType *T,
+                                          raw_ostream &OS) { } 
 
-void TypePrinter::printDependentTemplateSpecialization(
-        const DependentTemplateSpecializationType *T, std::string &S) { 
+void TypePrinter::printDependentTemplateSpecializationBefore(
+        const DependentTemplateSpecializationType *T, raw_ostream &OS) { 
   IncludeStrongLifetimeRAII Strong(Policy);
-  std::string MyString;
-  {
-    llvm::raw_string_ostream OS(MyString);
   
-    OS << TypeWithKeyword::getKeywordName(T->getKeyword());
-    if (T->getKeyword() != ETK_None)
-      OS << " ";
-    
-    if (T->getQualifier())
-      T->getQualifier()->print(OS, Policy);    
-    OS << T->getIdentifier()->getName();
-    OS << TemplateSpecializationType::PrintTemplateArgumentList(
-                                                            T->getArgs(),
-                                                            T->getNumArgs(),
-                                                            Policy);
-  }
+  OS << TypeWithKeyword::getKeywordName(T->getKeyword());
+  if (T->getKeyword() != ETK_None)
+    OS << " ";
   
-  if (S.empty())
-    S.swap(MyString);
-  else
-    S = MyString + ' ' + S;
+  if (T->getQualifier())
+    T->getQualifier()->print(OS, Policy);    
+  OS << T->getIdentifier()->getName();
+  TemplateSpecializationType::PrintTemplateArgumentList(OS,
+                                                        T->getArgs(),
+                                                        T->getNumArgs(),
+                                                        Policy);
+  spaceBeforePlaceHolder(OS);
 }
+void TypePrinter::printDependentTemplateSpecializationAfter(
+        const DependentTemplateSpecializationType *T, raw_ostream &OS) { } 
 
-void TypePrinter::printPackExpansion(const PackExpansionType *T, 
-                                     std::string &S) {
-  print(T->getPattern(), S);
-  S += "...";
+void TypePrinter::printPackExpansionBefore(const PackExpansionType *T, 
+                                           raw_ostream &OS) {
+  printBefore(T->getPattern(), OS);
+}
+void TypePrinter::printPackExpansionAfter(const PackExpansionType *T, 
+                                          raw_ostream &OS) {
+  printAfter(T->getPattern(), OS);
+  OS << "...";
 }
 
-void TypePrinter::printAttributed(const AttributedType *T,
-                                  std::string &S) {
+void TypePrinter::printAttributedBefore(const AttributedType *T,
+                                        raw_ostream &OS) {
   // Prefer the macro forms of the GC and ownership qualifiers.
   if (T->getAttrKind() == AttributedType::attr_objc_gc ||
       T->getAttrKind() == AttributedType::attr_objc_ownership)
-    return print(T->getEquivalentType(), S);
+    return printBefore(T->getEquivalentType(), OS);
 
-  print(T->getModifiedType(), S);
+  printBefore(T->getModifiedType(), OS);
+}
+
+void TypePrinter::printAttributedAfter(const AttributedType *T,
+                                       raw_ostream &OS) {
+  // Prefer the macro forms of the GC and ownership qualifiers.
+  if (T->getAttrKind() == AttributedType::attr_objc_gc ||
+      T->getAttrKind() == AttributedType::attr_objc_ownership)
+    return printAfter(T->getEquivalentType(), OS);
 
   // TODO: not all attributes are GCC-style attributes.
-  S += " __attribute__((";
+  OS << " __attribute__((";
   switch (T->getAttrKind()) {
   case AttributedType::attr_address_space:
-    S += "address_space(";
-    S += T->getEquivalentType().getAddressSpace();
-    S += ")";
+    OS << "address_space(";
+    OS << T->getEquivalentType().getAddressSpace();
+    OS << ')';
     break;
 
   case AttributedType::attr_vector_size: {
-    S += "__vector_size__(";
+    OS << "__vector_size__(";
     if (const VectorType *vector =T->getEquivalentType()->getAs<VectorType>()) {
-      S += vector->getNumElements();
-      S += " * sizeof(";
-
-      std::string tmp;
-      print(vector->getElementType(), tmp);
-      S += tmp;
-      S += ")";
+      OS << vector->getNumElements();
+      OS << " * sizeof(";
+      print(vector->getElementType(), OS, StringRef());
+      OS << ')';
     }
-    S += ")";
+    OS << ')';
     break;
   }
 
   case AttributedType::attr_neon_vector_type:
   case AttributedType::attr_neon_polyvector_type: {
     if (T->getAttrKind() == AttributedType::attr_neon_vector_type)
-      S += "neon_vector_type(";
+      OS << "neon_vector_type(";
     else
-      S += "neon_polyvector_type(";
+      OS << "neon_polyvector_type(";
     const VectorType *vector = T->getEquivalentType()->getAs<VectorType>();
-    S += llvm::utostr_32(vector->getNumElements());
-    S += ")";
+    OS << vector->getNumElements();
+    OS << ')';
     break;
   }
 
   case AttributedType::attr_regparm: {
-    S += "regparm(";
+    OS << "regparm(";
     QualType t = T->getEquivalentType();
     while (!t->isFunctionType())
       t = t->getPointeeType();
-    S += t->getAs<FunctionType>()->getRegParmType();
-    S += ")";
+    OS << t->getAs<FunctionType>()->getRegParmType();
+    OS << ')';
     break;
   }
 
   case AttributedType::attr_objc_gc: {
-    S += "objc_gc(";
+    OS << "objc_gc(";
 
     QualType tmp = T->getEquivalentType();
     while (tmp.getObjCGCAttr() == Qualifiers::GCNone) {
@@ -939,116 +1121,225 @@ void TypePrinter::printAttributed(const AttributedType *T,
     }
 
     if (tmp.isObjCGCWeak())
-      S += "weak";
+      OS << "weak";
     else
-      S += "strong";
-    S += ")";
+      OS << "strong";
+    OS << ')';
     break;
   }
 
   case AttributedType::attr_objc_ownership:
-    S += "objc_ownership(";
+    OS << "objc_ownership(";
     switch (T->getEquivalentType().getObjCLifetime()) {
     case Qualifiers::OCL_None: llvm_unreachable("no ownership!");
-    case Qualifiers::OCL_ExplicitNone: S += "none"; break;
-    case Qualifiers::OCL_Strong: S += "strong"; break;
-    case Qualifiers::OCL_Weak: S += "weak"; break;
-    case Qualifiers::OCL_Autoreleasing: S += "autoreleasing"; break;
+    case Qualifiers::OCL_ExplicitNone: OS << "none"; break;
+    case Qualifiers::OCL_Strong: OS << "strong"; break;
+    case Qualifiers::OCL_Weak: OS << "weak"; break;
+    case Qualifiers::OCL_Autoreleasing: OS << "autoreleasing"; break;
     }
-    S += ")";
+    OS << ')';
     break;
 
-  case AttributedType::attr_noreturn: S += "noreturn"; break;
-  case AttributedType::attr_cdecl: S += "cdecl"; break;
-  case AttributedType::attr_fastcall: S += "fastcall"; break;
-  case AttributedType::attr_stdcall: S += "stdcall"; break;
-  case AttributedType::attr_thiscall: S += "thiscall"; break;
-  case AttributedType::attr_pascal: S += "pascal"; break;
+  case AttributedType::attr_noreturn: OS << "noreturn"; break;
+  case AttributedType::attr_cdecl: OS << "cdecl"; break;
+  case AttributedType::attr_fastcall: OS << "fastcall"; break;
+  case AttributedType::attr_stdcall: OS << "stdcall"; break;
+  case AttributedType::attr_thiscall: OS << "thiscall"; break;
+  case AttributedType::attr_pascal: OS << "pascal"; break;
   case AttributedType::attr_pcs: {
-   S += "pcs(";
+    OS << "pcs(";
    QualType t = T->getEquivalentType();
    while (!t->isFunctionType())
      t = t->getPointeeType();
-   S += (t->getAs<FunctionType>()->getCallConv() == CC_AAPCS ?
+   OS << (t->getAs<FunctionType>()->getCallConv() == CC_AAPCS ?
          "\"aapcs\"" : "\"aapcs-vfp\"");
-   S += ")";
+   OS << ')';
    break;
   }
   }
-  S += "))";
+  OS << "))";
 }
 
-void TypePrinter::printObjCInterface(const ObjCInterfaceType *T, 
-                                     std::string &S) { 
-  if (!S.empty())    // Prefix the basic type, e.g. 'typedefname X'.
-    S = ' ' + S;
-
-  std::string ObjCQIString = T->getDecl()->getNameAsString();
-  S = ObjCQIString + S;
+void TypePrinter::printObjCInterfaceBefore(const ObjCInterfaceType *T, 
+                                           raw_ostream &OS) { 
+  OS << T->getDecl()->getName();
+  spaceBeforePlaceHolder(OS);
 }
+void TypePrinter::printObjCInterfaceAfter(const ObjCInterfaceType *T, 
+                                          raw_ostream &OS) { } 
 
-void TypePrinter::printObjCObject(const ObjCObjectType *T,
-                                  std::string &S) {
+void TypePrinter::printObjCObjectBefore(const ObjCObjectType *T,
+                                        raw_ostream &OS) {
   if (T->qual_empty())
-    return print(T->getBaseType(), S);
+    return printBefore(T->getBaseType(), OS);
 
-  std::string tmp;
-  print(T->getBaseType(), tmp);
-  tmp += '<';
+  print(T->getBaseType(), OS, StringRef());
+  OS << '<';
   bool isFirst = true;
   for (ObjCObjectType::qual_iterator
          I = T->qual_begin(), E = T->qual_end(); I != E; ++I) {
     if (isFirst)
       isFirst = false;
     else
-      tmp += ',';
-    tmp += (*I)->getNameAsString();
-  }
-  tmp += '>';
-
-  if (!S.empty()) {
-    tmp += ' ';
-    tmp += S;
+      OS << ',';
+    OS << (*I)->getName();
   }
-  std::swap(tmp, S);
+  OS << '>';
+  spaceBeforePlaceHolder(OS);
+}
+void TypePrinter::printObjCObjectAfter(const ObjCObjectType *T,
+                                        raw_ostream &OS) {
+  if (T->qual_empty())
+    return printAfter(T->getBaseType(), OS);
 }
 
-void TypePrinter::printObjCObjectPointer(const ObjCObjectPointerType *T, 
-                                         std::string &S) { 
-  std::string ObjCQIString;
-  
-  T->getPointeeType().getLocalQualifiers().getAsStringInternal(ObjCQIString, 
-                                                               Policy);
-  if (!ObjCQIString.empty())
-    ObjCQIString += ' ';
-    
+void TypePrinter::printObjCObjectPointerBefore(const ObjCObjectPointerType *T, 
+                                               raw_ostream &OS) {
+  T->getPointeeType().getLocalQualifiers().print(OS, Policy,
+                                                /*appendSpaceIfNonEmpty=*/true);
+
   if (T->isObjCIdType() || T->isObjCQualifiedIdType())
-    ObjCQIString += "id";
+    OS << "id";
   else if (T->isObjCClassType() || T->isObjCQualifiedClassType())
-    ObjCQIString += "Class";
+    OS << "Class";
   else if (T->isObjCSelType())
-    ObjCQIString += "SEL";
+    OS << "SEL";
   else
-    ObjCQIString += T->getInterfaceDecl()->getNameAsString();
+    OS << T->getInterfaceDecl()->getName();
   
   if (!T->qual_empty()) {
-    ObjCQIString += '<';
+    OS << '<';
     for (ObjCObjectPointerType::qual_iterator I = T->qual_begin(), 
                                               E = T->qual_end();
          I != E; ++I) {
-      ObjCQIString += (*I)->getNameAsString();
+      OS << (*I)->getName();
       if (I+1 != E)
-        ObjCQIString += ',';
+        OS << ',';
     }
-    ObjCQIString += '>';
+    OS << '>';
   }
   
-  if (!T->isObjCIdType() && !T->isObjCQualifiedIdType())
-    ObjCQIString += " *"; // Don't forget the implicit pointer.
-  else if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'.
-    S = ' ' + S;
+  if (!T->isObjCIdType() && !T->isObjCQualifiedIdType()) {
+    OS << " *"; // Don't forget the implicit pointer.
+  } else {
+    spaceBeforePlaceHolder(OS);
+  }
+}
+void TypePrinter::printObjCObjectPointerAfter(const ObjCObjectPointerType *T, 
+                                              raw_ostream &OS) { }
+
+void TemplateSpecializationType::
+  PrintTemplateArgumentList(raw_ostream &OS,
+                            const TemplateArgumentListInfo &Args,
+                            const PrintingPolicy &Policy) {
+  return PrintTemplateArgumentList(OS,
+                                   Args.getArgumentArray(),
+                                   Args.size(),
+                                   Policy);
+}
+
+void
+TemplateSpecializationType::PrintTemplateArgumentList(
+                                                raw_ostream &OS,
+                                                const TemplateArgument *Args,
+                                                unsigned NumArgs,
+                                                  const PrintingPolicy &Policy,
+                                                      bool SkipBrackets) {
+  if (!SkipBrackets)
+    OS << '<';
   
-  S = ObjCQIString + S;  
+  for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+    if (Arg > 0)
+      OS << ", ";
+    
+    // Print the argument into a string.
+    SmallString<128> Buf;
+    llvm::raw_svector_ostream ArgOS(Buf);
+    if (Args[Arg].getKind() == TemplateArgument::Pack) {
+      PrintTemplateArgumentList(ArgOS,
+                                Args[Arg].pack_begin(), 
+                                Args[Arg].pack_size(), 
+                                Policy, true);
+    } else {
+      Args[Arg].print(Policy, ArgOS);
+    }
+    StringRef ArgString = ArgOS.str();
+
+    // If this is the first argument and its string representation
+    // begins with the global scope specifier ('::foo'), add a space
+    // to avoid printing the diagraph '<:'.
+    if (!Arg && !ArgString.empty() && ArgString[0] == ':')
+      OS << ' ';
+    
+    OS << ArgString;
+  }
+
+  if (!SkipBrackets)
+    OS << '>';
+}
+
+// Sadly, repeat all that with TemplateArgLoc.
+void TemplateSpecializationType::
+PrintTemplateArgumentList(raw_ostream &OS,
+                          const TemplateArgumentLoc *Args, unsigned NumArgs,
+                          const PrintingPolicy &Policy) {
+  OS << '<';
+  for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+    if (Arg > 0)
+      OS << ", ";
+    
+    // Print the argument into a string.
+    SmallString<128> Buf;
+    llvm::raw_svector_ostream ArgOS(Buf);
+    if (Args[Arg].getArgument().getKind() == TemplateArgument::Pack) {
+      PrintTemplateArgumentList(ArgOS,
+                                Args[Arg].getArgument().pack_begin(), 
+                                Args[Arg].getArgument().pack_size(), 
+                                Policy, true);
+    } else {
+      Args[Arg].getArgument().print(Policy, ArgOS);
+    }
+    StringRef ArgString = ArgOS.str();
+    
+    // If this is the first argument and its string representation
+    // begins with the global scope specifier ('::foo'), add a space
+    // to avoid printing the diagraph '<:'.
+    if (!Arg && !ArgString.empty() && ArgString[0] == ':')
+      OS << ' ';
+    
+    OS << ArgString;
+  }
+  
+  OS << '>';
+}
+
+void 
+FunctionProtoType::printExceptionSpecification(std::string &S, 
+                                               PrintingPolicy Policy) const {
+  
+  if (hasDynamicExceptionSpec()) {
+    S += " throw(";
+    if (getExceptionSpecType() == EST_MSAny)
+      S += "...";
+    else
+      for (unsigned I = 0, N = getNumExceptions(); I != N; ++I) {
+        if (I)
+          S += ", ";
+        
+        S += getExceptionType(I).getAsString(Policy);
+      }
+    S += ")";
+  } else if (isNoexceptExceptionSpec(getExceptionSpecType())) {
+    S += " noexcept";
+    if (getExceptionSpecType() == EST_ComputedNoexcept) {
+      S += "(";
+      llvm::raw_string_ostream EOut(S);
+      getNoexceptExpr()->printPretty(EOut, 0, Policy);
+      EOut.flush();
+      S += EOut.str();
+      S += ")";
+    }
+  }
 }
 
 std::string TemplateSpecializationType::
@@ -1148,15 +1439,14 @@ PrintTemplateArgumentList(const TemplateArgumentLoc *Args, unsigned NumArgs,
 }
 
 void QualType::dump(const char *msg) const {
-  std::string R = "identifier";
-  LangOptions LO;
-  getAsStringInternal(R, PrintingPolicy(LO));
   if (msg)
     llvm::errs() << msg << ": ";
-  llvm::errs() << R << "\n";
+  LangOptions LO;
+  print(llvm::errs(), PrintingPolicy(LO), "identifier");
+  llvm::errs() << '\n';
 }
 void QualType::dump() const {
-  dump("");
+  dump(0);
 }
 
 void Type::dump() const {
@@ -1171,51 +1461,99 @@ std::string Qualifiers::getAsString() const {
 // Appends qualifiers to the given string, separated by spaces.  Will
 // prefix a space if the string is non-empty.  Will not append a final
 // space.
-void Qualifiers::getAsStringInternal(std::string &S,
-                                     const PrintingPolicy& Policy) const {
-  AppendTypeQualList(S, getCVRQualifiers());
+std::string Qualifiers::getAsString(const PrintingPolicy &Policy) const {
+  SmallString<64> Buf;
+  llvm::raw_svector_ostream StrOS(Buf);
+  print(StrOS, Policy);
+  return StrOS.str();
+}
+
+bool Qualifiers::isEmptyWhenPrinted(const PrintingPolicy &Policy) const {
+  if (getCVRQualifiers())
+    return false;
+
+  if (getAddressSpace())
+    return false;
+
+  if (getObjCGCAttr())
+    return false;
+
+  if (Qualifiers::ObjCLifetime lifetime = getObjCLifetime())
+    if (!(lifetime == Qualifiers::OCL_Strong && Policy.SuppressStrongLifetime))
+      return false;
+
+  return true;
+}
+
+// Appends qualifiers to the given string, separated by spaces.  Will
+// prefix a space if the string is non-empty.  Will not append a final
+// space.
+void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy,
+                       bool appendSpaceIfNonEmpty) const {
+  bool addSpace = false;
+
+  unsigned quals = getCVRQualifiers();
+  if (quals) {
+    AppendTypeQualList(OS, quals);
+    addSpace = true;
+  }
   if (unsigned addrspace = getAddressSpace()) {
-    if (!S.empty()) S += ' ';
+    if (addSpace)
+      OS << ' ';
+    addSpace = true;
     switch (addrspace) {
       case LangAS::opencl_global:
-        S += "__global";
+        OS << "__global";
         break;
       case LangAS::opencl_local:
-        S += "__local";
+        OS << "__local";
         break;
       case LangAS::opencl_constant:
-        S += "__constant";
+        OS << "__constant";
         break;
       default:
-        S += "__attribute__((address_space(";
-        S += llvm::utostr_32(addrspace);
-        S += ")))";
+        OS << "__attribute__((address_space(";
+        OS << addrspace;
+        OS << ")))";
     }
   }
   if (Qualifiers::GC gc = getObjCGCAttr()) {
-    if (!S.empty()) S += ' ';
+    if (addSpace)
+      OS << ' ';
+    addSpace = true;
     if (gc == Qualifiers::Weak)
-      S += "__weak";
+      OS << "__weak";
     else
-      S += "__strong";
+      OS << "__strong";
   }
   if (Qualifiers::ObjCLifetime lifetime = getObjCLifetime()) {
-    if (!S.empty() && 
-        !(lifetime == Qualifiers::OCL_Strong && Policy.SuppressStrongLifetime))
-      S += ' ';
+    if (!(lifetime == Qualifiers::OCL_Strong && Policy.SuppressStrongLifetime)){
+      if (addSpace)
+        OS << ' ';
+      addSpace = true;
+    }
     
     switch (lifetime) {
     case Qualifiers::OCL_None: llvm_unreachable("none but true");
-    case Qualifiers::OCL_ExplicitNone: S += "__unsafe_unretained"; break;
+    case Qualifiers::OCL_ExplicitNone: OS << "__unsafe_unretained"; break;
     case Qualifiers::OCL_Strong: 
       if (!Policy.SuppressStrongLifetime)
-        S += "__strong"; 
+        OS << "__strong"; 
       break;
         
-    case Qualifiers::OCL_Weak: S += "__weak"; break;
-    case Qualifiers::OCL_Autoreleasing: S += "__autoreleasing"; break;
+    case Qualifiers::OCL_Weak: OS << "__weak"; break;
+    case Qualifiers::OCL_Autoreleasing: OS << "__autoreleasing"; break;
     }
   }
+
+  if (appendSpaceIfNonEmpty && addSpace)
+    OS << ' ';
+}
+
+std::string QualType::getAsString(const PrintingPolicy &Policy) const {
+  std::string S;
+  getAsStringInternal(S, Policy);
+  return S;
 }
 
 std::string QualType::getAsString(const Type *ty, Qualifiers qs) {
@@ -1225,8 +1563,25 @@ std::string QualType::getAsString(const Type *ty, Qualifiers qs) {
   return buffer;
 }
 
+void QualType::print(const Type *ty, Qualifiers qs,
+                     raw_ostream &OS, const PrintingPolicy &policy,
+                     const Twine &PlaceHolder) {
+  SmallString<128> PHBuf;
+  StringRef PH;
+  if (PlaceHolder.isSingleStringRef())
+    PH = PlaceHolder.getSingleStringRef();
+  else
+    PH = PlaceHolder.toStringRef(PHBuf);
+
+  TypePrinter(policy).print(ty, qs, OS, PH);
+}
+
 void QualType::getAsStringInternal(const Type *ty, Qualifiers qs,
                                    std::string &buffer,
                                    const PrintingPolicy &policy) {
-  TypePrinter(policy).print(ty, qs, buffer);
+  SmallString<256> Buf;
+  llvm::raw_svector_ostream StrOS(Buf);
+  TypePrinter(policy).print(ty, qs, StrOS, buffer);
+  std::string str = StrOS.str();
+  buffer.swap(str);
 }
index 1c13bffa212f7c2f11f4f181135ca81612e5434e..0c555b53f95e63ddb341ad4a47d0aed1ceab8f48 100644 (file)
@@ -13,9 +13,9 @@ template <class T1, class T2, int N = 17> struct E;
 
 eval<A<int>> eA;
 eval<B<int, float>> eB;
-eval<C<17>> eC; // expected-error{{implicit instantiation of undefined template 'eval<C<17> >'}}
-eval<D<int, 17>> eD; // expected-error{{implicit instantiation of undefined template 'eval<D<int, 17> >'}}
-eval<E<int, float>> eE; // expected-error{{implicit instantiation of undefined template 'eval<E<int, float, 17> >}}
+eval<C<17>> eC; // expected-error{{implicit instantiation of undefined template 'eval<C<17>>'}}
+eval<D<int, 17>> eD; // expected-error{{implicit instantiation of undefined template 'eval<D<int, 17>>'}}
+eval<E<int, float>> eE; // expected-error{{implicit instantiation of undefined template 'eval<E<int, float, 17>>}}
 
 template<template <int ...N> class TT> struct X0 { }; // expected-note{{previous non-type template parameter with type 'int' is here}}
 template<int I, int J, int ...Rest> struct X0a;
index 3ab75d0e11636114a68fae5041897380e2aa5332..652a076c780fa988392db4e5cc847d090f73a9b8 100644 (file)
@@ -13,7 +13,7 @@ void test1(v2u v2ua, v2s v2sa, v2f v2fa) {
   (void)(~v2fa); // expected-error{{invalid argument type 'v2f' to unary}}
 
   // Comparison operators
-  v2ua = (v2ua==v2sa); // expected-warning{{incompatible vector types assigning to 'v2u' from 'int  __attribute__((ext_vector_type(2)))'}}
+  v2ua = (v2ua==v2sa); // expected-warning{{incompatible vector types assigning to 'v2u' from 'int __attribute__((ext_vector_type(2)))'}}
   v2sa = (v2ua==v2sa);
   
   // Arrays