From 52750c271451e092e77cc5a129ee486b1a63a39e Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Wed, 16 Dec 2015 02:04:40 +0000 Subject: [PATCH] Print qualified display names when emitting CodeView This is what debuggers expect. Words towards fixing PR21528. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@255744 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/PrettyPrinter.h | 7 +- lib/AST/Decl.cpp | 6 +- lib/AST/TemplateBase.cpp | 2 +- lib/AST/TypePrinter.cpp | 19 +++-- lib/CodeGen/CGDebugInfo.cpp | 31 +++++--- .../debug-info-codeview-display-name.cpp | 73 +++++++++++++++++++ 6 files changed, 115 insertions(+), 23 deletions(-) create mode 100644 test/CodeGenCXX/debug-info-codeview-display-name.cpp diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h index f269fb1bf2..8ab3f61703 100644 --- a/include/clang/AST/PrettyPrinter.h +++ b/include/clang/AST/PrettyPrinter.h @@ -42,7 +42,7 @@ struct PrintingPolicy { SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false), Bool(LO.Bool), TerseOutput(false), PolishForDeclaration(false), Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar), - IncludeNewlines(true) { } + IncludeNewlines(true), MSVCFormatting(false) { } /// \brief What language we're printing. LangOptions LangOpts; @@ -163,6 +163,11 @@ struct PrintingPolicy { /// \brief When true, include newlines after statements like "break", etc. unsigned IncludeNewlines : 1; + + /// \brief Use whitespace and punctuation like MSVC does. In particular, this + /// prints anonymous namespaces as `anonymous namespace' and does not insert + /// spaces after template arguments. + bool MSVCFormatting : 1; }; } // end namespace clang diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index edbbc6a8c4..243d405584 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1434,8 +1434,10 @@ void NamedDecl::printQualifiedName(raw_ostream &OS, if (P.SuppressUnwrittenScope && (ND->isAnonymousNamespace() || ND->isInline())) continue; - if (ND->isAnonymousNamespace()) - OS << "(anonymous namespace)"; + if (ND->isAnonymousNamespace()) { + OS << (P.MSVCFormatting ? "`anonymous namespace\'" + : "(anonymous namespace)"); + } else OS << *ND; } else if (const auto *RD = dyn_cast(*I)) { diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp index 8c5a691836..7103ecb5bb 100644 --- a/lib/AST/TemplateBase.cpp +++ b/lib/AST/TemplateBase.cpp @@ -53,7 +53,7 @@ static void printIntegral(const TemplateArgument &TemplArg, } } - if (T->isBooleanType()) { + if (T->isBooleanType() && !Policy.MSVCFormatting) { Out << (Val.getBoolValue() ? "true" : "false"); } else if (T->isCharType()) { const char Ch = Val.getZExtValue(); diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index e360512462..4617e1d380 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -925,12 +925,13 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) { } else { // Make an unambiguous representation for anonymous types, e.g. // (anonymous enum at /usr/include/string.h:120:9) - + OS << (Policy.MSVCFormatting ? '`' : '('); + if (isa(D) && cast(D)->isLambda()) { - OS << "(lambda"; + OS << "lambda"; HasKindDecoration = true; } else { - OS << "(anonymous"; + OS << "anonymous"; } if (Policy.AnonymousTagLocations) { @@ -948,8 +949,8 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) { << ':' << PLoc.getColumn(); } } - - OS << ')'; + + OS << (Policy.MSVCFormatting ? '\'' : ')'); } // If this is a class template specialization, print the template @@ -1401,6 +1402,7 @@ TemplateSpecializationType::PrintTemplateArgumentList( unsigned NumArgs, const PrintingPolicy &Policy, bool SkipBrackets) { + const char *Comma = Policy.MSVCFormatting ? "," : ", "; if (!SkipBrackets) OS << '<'; @@ -1411,14 +1413,14 @@ TemplateSpecializationType::PrintTemplateArgumentList( llvm::raw_svector_ostream ArgOS(Buf); if (Args[Arg].getKind() == TemplateArgument::Pack) { if (Args[Arg].pack_size() && Arg > 0) - OS << ", "; + OS << Comma; PrintTemplateArgumentList(ArgOS, Args[Arg].pack_begin(), Args[Arg].pack_size(), Policy, true); } else { if (Arg > 0) - OS << ", "; + OS << Comma; Args[Arg].print(Policy, ArgOS); } StringRef ArgString = ArgOS.str(); @@ -1450,11 +1452,12 @@ PrintTemplateArgumentList(raw_ostream &OS, const TemplateArgumentLoc *Args, unsigned NumArgs, const PrintingPolicy &Policy) { OS << '<'; + const char *Comma = Policy.MSVCFormatting ? "," : ", "; bool needSpace = false; for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { if (Arg > 0) - OS << ", "; + OS << Comma; // Print the argument into a string. SmallString<128> Buf; diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 29ebfc6238..c2ec03f34e 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -183,22 +183,31 @@ StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) { IdentifierInfo *FII = FD->getIdentifier(); FunctionTemplateSpecializationInfo *Info = FD->getTemplateSpecializationInfo(); - if (!Info && FII) + + if (!Info && FII && !CGM.getCodeGenOpts().EmitCodeView) return FII->getName(); // Otherwise construct human readable name for debug info. SmallString<128> NS; llvm::raw_svector_ostream OS(NS); - FD->printName(OS); - - // Add any template specialization args. - if (Info) { - const TemplateArgumentList *TArgs = Info->TemplateArguments; - const TemplateArgument *Args = TArgs->data(); - unsigned NumArgs = TArgs->size(); - PrintingPolicy Policy(CGM.getLangOpts()); - TemplateSpecializationType::PrintTemplateArgumentList(OS, Args, NumArgs, - Policy); + PrintingPolicy Policy(CGM.getLangOpts()); + + if (CGM.getCodeGenOpts().EmitCodeView) { + // Print a fully qualified name like MSVC would. + Policy.MSVCFormatting = true; + FD->printQualifiedName(OS, Policy); + } else { + // Print the unqualified name with some template arguments. This is what + // DWARF-based debuggers expect. + FD->printName(OS); + // Add any template specialization args. + if (Info) { + const TemplateArgumentList *TArgs = Info->TemplateArguments; + const TemplateArgument *Args = TArgs->data(); + unsigned NumArgs = TArgs->size(); + TemplateSpecializationType::PrintTemplateArgumentList(OS, Args, NumArgs, + Policy); + } } // Copy this name on the side and use its reference. diff --git a/test/CodeGenCXX/debug-info-codeview-display-name.cpp b/test/CodeGenCXX/debug-info-codeview-display-name.cpp new file mode 100644 index 0000000000..1d0300c76c --- /dev/null +++ b/test/CodeGenCXX/debug-info-codeview-display-name.cpp @@ -0,0 +1,73 @@ +// RUN: %clang_cc1 -fblocks -debug-info-kind=limited -gcodeview -emit-llvm %s -o - -triple=x86_64-pc-win32 -std=c++98 | \ +// RUN: grep 'DISubprogram' | sed -e 's/.*name: "\([^"]*\)".*/"\1"/' | FileCheck %s + +void freefunc() { } +// CHECK-DAG: "freefunc" + +namespace N { + int b() { return 0; } +// CHECK-DAG: "N::b" + namespace { void func() { } } +// CHECK-DAG: "N::`anonymous namespace'::func +} + +void _c(void) { + N::func(); +} +// CHECK-DAG: "_c" + +struct foo { + int operator+(int); + foo(){} +// CHECK-DAG: "foo::foo" + + ~foo(){} +// CHECK-DAG: "foo::~foo" + + foo(int i){} +// CHECK-DAG: "foo::foo" + + foo(char *q){} +// CHECK-DAG: "foo::foo" + + static foo* static_method() { return 0; } +// CHECK-DAG: "foo::static_method" + +}; + +void use_foo() { + foo f1, f2(1), f3((char*)0); + foo::static_method(); +} + +// CHECK-DAG: "foo::operator+" +int foo::operator+(int a) { return a; } + +// PR17371 +struct OverloadedNewDelete { + // __cdecl + void *operator new(__SIZE_TYPE__); + void *operator new[](__SIZE_TYPE__); + void operator delete(void *); + void operator delete[](void *); + // __thiscall + int operator+(int); +}; + +void *OverloadedNewDelete::operator new(__SIZE_TYPE__ s) { return 0; } +void *OverloadedNewDelete::operator new[](__SIZE_TYPE__ s) { return 0; } +void OverloadedNewDelete::operator delete(void *) { } +void OverloadedNewDelete::operator delete[](void *) { } +int OverloadedNewDelete::operator+(int x) { return x; }; + +// CHECK-DAG: "OverloadedNewDelete::operator new" +// CHECK-DAG: "OverloadedNewDelete::operator new[]" +// CHECK-DAG: "OverloadedNewDelete::operator delete" +// CHECK-DAG: "OverloadedNewDelete::operator delete[]" +// CHECK-DAG: "OverloadedNewDelete::operator+" + +template +void fn_tmpl() {} + +template void fn_tmpl(); +// CHECK-DAG: "fn_tmpl" -- 2.40.0