Index: include/clang/AST/PrettyPrinter.h =================================================================== --- include/clang/AST/PrettyPrinter.h +++ include/clang/AST/PrettyPrinter.h @@ -52,7 +52,7 @@ Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true), MSVCFormatting(false), ConstantsAsWritten(false), SuppressImplicitBase(false), - FullyQualifiedName(false) { } + FullyQualifiedName(false), NotForCompilation(false) { } /// Adjust this printing policy for cases where it's known that we're /// printing C++ code (for instance, if AST dumping reaches a C++-only @@ -225,6 +225,10 @@ /// When true, print the fully qualified name of function declarations. /// This is the opposite of SuppressScope and thus overrules it. bool FullyQualifiedName : 1; + + /// When true, the print result will not be used as compiler input, so do not + /// make things like breaking digraphs and '>>' in template parameters. + bool NotForCompilation : 1; }; } // end namespace clang Index: lib/AST/TypePrinter.cpp =================================================================== --- lib/AST/TypePrinter.cpp +++ lib/AST/TypePrinter.cpp @@ -1540,9 +1540,13 @@ bool NeedSpace = false; bool FirstArg = true; for (const auto &Arg : Args) { - // Print the argument into a string. - SmallString<128> Buf; - llvm::raw_svector_ostream ArgOS(Buf); + SmallString<0> Buffer; + std::unique_ptr BufOS; + if (!Policy.NotForCompilation) { + // Print the argument into a string. + BufOS.reset(new llvm::raw_svector_ostream(Buffer)); + } + llvm::raw_ostream &ArgOS = Policy.NotForCompilation ? OS : *BufOS; const TemplateArgument &Argument = getArgument(Arg); if (Argument.getKind() == TemplateArgument::Pack) { if (Argument.pack_size() && !FirstArg) @@ -1553,17 +1557,19 @@ OS << Comma; Argument.print(Policy, ArgOS); } - StringRef ArgString = ArgOS.str(); + if (!Policy.NotForCompilation) { + StringRef ArgString = BufOS->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 (FirstArg && !ArgString.empty() && ArgString[0] == ':') - OS << ' '; + // 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 (FirstArg && !ArgString.empty() && ArgString[0] == ':') + OS << ' '; - OS << ArgString; + OS << ArgString; - NeedSpace = (!ArgString.empty() && ArgString.back() == '>'); + NeedSpace = (!ArgString.empty() && ArgString.back() == '>'); + } FirstArg = false; } Index: lib/CodeGen/CodeGenTypes.cpp =================================================================== --- lib/CodeGen/CodeGenTypes.cpp +++ lib/CodeGen/CodeGenTypes.cpp @@ -26,6 +26,7 @@ #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Module.h" +#include "llvm/Support/raw_abbrev_ostream.h" using namespace clang; using namespace CodeGen; @@ -51,28 +52,38 @@ void CodeGenTypes::addRecordTypeName(const RecordDecl *RD, llvm::StructType *Ty, StringRef suffix) { - SmallString<256> TypeName; - llvm::raw_svector_ostream OS(TypeName); + PrintingPolicy Policy = RD->getASTContext().getPrintingPolicy(); + Policy.NotForCompilation = true; + llvm::raw_abbrev_ostream OS; + OS.setHash().setTrunc().setBeginMarker("..."); + + // Set truncation limit. Long value helps in debugging but can result in + // higher memory consumption. + OS.setLimit(400); + OS << RD->getKindName() << '.'; - + // Name the codegen type after the typedef name // if there is no tag type name available if (RD->getIdentifier()) { + OS.startAbbrev(); // FIXME: We should not have to check for a null decl context here. // Right now we do it because the implicit Obj-C decls don't have one. if (RD->getDeclContext()) - RD->printQualifiedName(OS); + RD->printQualifiedName(OS, Policy); else RD->printName(OS); } else if (const TypedefNameDecl *TDD = RD->getTypedefNameForAnonDecl()) { + OS.startAbbrev(); // FIXME: We should not have to check for a null decl context here. // Right now we do it because the implicit Obj-C decls don't have one. if (TDD->getDeclContext()) - TDD->printQualifiedName(OS); + TDD->printQualifiedName(OS, Policy); else TDD->printName(OS); } else OS << "anon"; + OS.stopAbbrev(); if (!suffix.empty()) OS << suffix; Index: test/CodeGenCXX/template-types.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/template-types.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -std=c++11 -triple i686-linux-gnu -S -emit-llvm %s -o - | FileCheck %s + +// Taken from the test pr29160.cpp +template +struct Foo { + template + static void ignore() {} + Foo() { ignore(); } + struct Inner {}; +}; + +struct Base { + Base(); + ~Base(); +}; + +#define STAMP(thiz, prev) using thiz = Foo< \ + prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, \ + prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, \ + prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, prev \ + >; +STAMP(A, Base); +STAMP(B, A); +STAMP(C, B); + +int main() { + C::Inner val_1; +} + +// CHECK: %"struct.Foo