diff --git a/clang/include/clang/AST/Mangle.h b/clang/include/clang/AST/Mangle.h --- a/clang/include/clang/AST/Mangle.h +++ b/clang/include/clang/AST/Mangle.h @@ -241,6 +241,8 @@ ArrayRef BasePath, raw_ostream &Out) = 0; + virtual unsigned getLambdaNumber(const CXXRecordDecl *Lambda) = 0; + static bool classof(const MangleContext *C) { return C->getKind() == MK_Microsoft; } diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -228,6 +228,18 @@ return true; } + unsigned getLambdaNumber(const CXXRecordDecl *Lambda) override { + unsigned LambdaManglingNumber = Lambda->getLambdaManglingNumber(); + unsigned LambdaId; + + if (LambdaManglingNumber) + LambdaId = LambdaManglingNumber; + else + LambdaId = getLambdaId(Lambda); + + return LambdaId; + } + unsigned getLambdaId(const CXXRecordDecl *RD) { assert(RD->isLambda() && "RD must be a lambda!"); assert(!RD->isExternallyVisible() && "RD must not be visible!"); diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -262,7 +262,6 @@ // evaluating the size impact. bool UseQualifiedName = DebugKind == codegenoptions::DebugLineTablesOnly && CGM.getCodeGenOpts().EmitCodeView; - if (!Info && FII && !UseQualifiedName) return FII->getName(); @@ -270,8 +269,32 @@ llvm::raw_svector_ostream OS(NS); if (!UseQualifiedName) FD->printName(OS); - else + else { FD->printQualifiedName(OS, getPrintingPolicy()); + const CXXMethodDecl *Method = dyn_cast(FD); + bool isLambda = false; + if (Method && Method->getParent()->isLambda()) { + MangleContext &MC = CGM.getCXXABI().getMangleContext(); + if (auto *MMC = dyn_cast(&MC)) { + unsigned LambdaNumber = MMC->getLambdaNumber(Method->getParent()); + OS << "::"; + isLambda = true; + } + } else { + OS << '('; + unsigned NumParams = FD->getNumParams(); + for (unsigned i = 0; i < NumParams; ++i) { + if (i) + OS << ", "; + OS << FD->getParamDecl(i)->getType().stream(getPrintingPolicy()); + } + OS << ')'; + + if (const CXXMethodDecl *Method = dyn_cast(FD)) + if (Method->isConst()) + OS << " const"; + } + } // Add any template specialization args. if (Info) { diff --git a/clang/test/CodeGenCXX/debug-info-codeview-display-name.cpp b/clang/test/CodeGenCXX/debug-info-codeview-display-name.cpp --- a/clang/test/CodeGenCXX/debug-info-codeview-display-name.cpp +++ b/clang/test/CodeGenCXX/debug-info-codeview-display-name.cpp @@ -1,59 +1,64 @@ // RUN: %clang_cc1 -fblocks -debug-info-kind=limited -gcodeview -emit-llvm %s \ // RUN: -o - -triple=x86_64-pc-win32 -Wno-new-returns-null -std=c++98 | \ // RUN: grep -E 'DISubprogram|DICompositeType' | sed -e 's/.*name: "\([^"]*\)".*/"\1"/' | \ -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=UNQUAL +// RUN: FileCheck %s --check-prefixes=CHECK,UNQUAL // RUN: %clang_cc1 -fblocks -debug-info-kind=line-tables-only -gcodeview -emit-llvm %s \ // RUN: -o - -triple=x86_64-pc-win32 -Wno-new-returns-null -std=c++98 | \ // RUN: grep 'DISubprogram' | sed -e 's/.*name: "\([^"]*\)".*/"\1"/' | \ -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=QUAL +// RUN: FileCheck %s --check-prefixes=CHECK,QUAL // RUN: %clang_cc1 -fblocks -debug-info-kind=limited -gcodeview -emit-llvm %s \ // RUN: -o - -triple=x86_64-pc-win32 -Wno-new-returns-null -std=c++11 | \ // RUN: grep -E 'DISubprogram|DICompositeType' | sed -e 's/.*name: "\([^"]*\)".*/"\1"/' | \ -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=UNQUAL +// RUN: FileCheck %s --check-prefixes=CHECK,UNQUAL,UNQUAL11 +// RUN: %clang_cc1 -fblocks -debug-info-kind=line-tables-only -gcodeview -emit-llvm %s \ +// RUN: -o - -triple=x86_64-pc-win32 -Wno-new-returns-null -std=c++11 | \ +// RUN: grep -E 'DISubprogram|DICompositeType' | sed -e 's/.*name: "\([^"]*\)".*/"\1"/' | \ +// RUN: FileCheck %s --check-prefixes=CHECK,QUAL,QUAL11 // RUN: %clang_cc1 -fblocks -debug-info-kind=limited -gcodeview -emit-llvm %s \ // RUN: -o - -triple=x86_64-pc-win32 -Wno-new-returns-null | \ // RUN: grep -E 'DISubprogram|DICompositeType' | sed -e 's/.*name: "\([^"]*\)".*/"\1"/' | \ -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=UNQUAL +// RUN: FileCheck %s --check-prefixes=CHECK,UNQUAL void freefunc() { } -// CHECK-DAG: "freefunc" +// UNQUAL-DAG: "freefunc" +// QUAL-DAG: "freefunc()" namespace N { int b() { return 0; } -// UNQUAL-DAG: "b" -// QUAL-DAG: "N::b" + // UNQUAL-DAG: "b" + // QUAL-DAG: "N::b()" namespace { void func() { } } -// UNQUAL-DAG: "func" -// QUAL-DAG: "N::`anonymous namespace'::func" + // UNQUAL-DAG: "func" + // QUAL-DAG: "N::`anonymous namespace'::func()" } void _c(void) { N::func(); } -// CHECK-DAG: "_c" +// UNQUAL-DAG: "_c" +// QUAL-DAG: "_c()" struct foo { int operator+(int); foo(){} -// UNQUAL-DAG: "foo" -// QUAL-DAG: "foo::foo" + // UNQUAL-DAG: "foo" + // QUAL-DAG: "foo::foo()" ~foo(){} -// UNQUAL-DAG: "~foo" -// QUAL-DAG: "foo::~foo" + // UNQUAL-DAG: "~foo" + // QUAL-DAG: "foo::~foo()" foo(int i){} -// UNQUAL-DAG: "foo" -// QUAL-DAG: "foo::foo" + // UNQUAL-DAG: "foo" + // QUAL-DAG: "foo::foo(int)" foo(char *q){} -// UNQUAL-DAG: "foo" -// QUAL-DAG: "foo::foo" + // UNQUAL-DAG: "foo" + // QUAL-DAG: "foo::foo(char *)" static foo* static_method() { return 0; } -// UNQUAL-DAG: "static_method" -// QUAL-DAG: "foo::static_method" - + // UNQUAL-DAG: "static_method" + // QUAL-DAG: "foo::static_method()" }; void use_foo() { @@ -62,7 +67,7 @@ } // UNQUAL-DAG: "operator+" -// QUAL-DAG: "foo::operator+" +// QUAL-DAG: "foo::operator+(int)" int foo::operator+(int a) { return a; } // PR17371 @@ -87,18 +92,18 @@ // UNQUAL-DAG: "operator delete" // UNQUAL-DAG: "operator delete[]" // UNQUAL-DAG: "operator+" -// QUAL-DAG: "OverloadedNewDelete::operator new" -// QUAL-DAG: "OverloadedNewDelete::operator new[]" -// QUAL-DAG: "OverloadedNewDelete::operator delete" -// QUAL-DAG: "OverloadedNewDelete::operator delete[]" -// QUAL-DAG: "OverloadedNewDelete::operator+" - +// QUAL-DAG: "OverloadedNewDelete::operator new(unsigned long long)" +// QUAL-DAG: "OverloadedNewDelete::operator new[](unsigned long long)" +// QUAL-DAG: "OverloadedNewDelete::operator delete(void *)" +// QUAL-DAG: "OverloadedNewDelete::operator delete[](void *)" +// QUAL-DAG: "OverloadedNewDelete::operator+(int)" template void fn_tmpl() {} template void fn_tmpl(); -// CHECK-DAG: "fn_tmpl" +// UNQUAL-DAG: "fn_tmpl" +// QUAL-DAG: "fn_tmpl()" template struct ClassTemplate { A a; B b; C c; }; ClassTemplate > f; @@ -106,3 +111,15 @@ // important for compatibility with Windows debuggers, so it should always be // there when generating CodeView. // UNQUAL-DAG: "ClassTemplate >" + +#if __cplusplus >= 201103L +void test_lambda() { + int a = [](int x) { return x + 1; }(0); + int b = [](int x) { return x * 2; }(0); +} + +// UNQUAL11-DAG: "operator()" +// UNQUAL11-DAG: "operator()" +// QUAL11-DAG: "test_lambda()::(anonymous class)::operator():: +// QUAL11-DAG: "test_lambda()::(anonymous class)::operator():: +#endif diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -366,9 +366,12 @@ if (I != TypeIndices.end()) return I->second; + StringRef DisplayName = SP->getName(); + // The display name includes function template arguments. Drop them to match - // MSVC. - StringRef DisplayName = SP->getName().split('<').first; + // MSVC, if we're not using line tables only. + if (SP->getUnit()->getEmissionKind() != DICompileUnit::LineTablesOnly) + DisplayName = SP->getName().split('<').first; const DIScope *Scope = SP->getScope(); TypeIndex TI; diff --git a/llvm/test/DebugInfo/COFF/function-display-name.ll b/llvm/test/DebugInfo/COFF/function-display-name.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/COFF/function-display-name.ll @@ -0,0 +1,51 @@ +; RUN: llc -mtriple=i686-pc-win32 -o - -O0 -filetype=obj < %s \ +; RUN: | llvm-readobj --codeview - | FileCheck %s + +; Check that we removed templated args from the display name in full debug mode +; but not with line tables only. + +; CHECK: FuncId (0x1002) { +; CHECK-NEXT: TypeLeafKind: LF_FUNC_ID ({{.*}}) +; CHECK-NEXT: ParentScope: 0x0 +; CHECK-NEXT: FunctionType: void () ({{.*}}) +; CHECK-NEXT: Name: Test() + +; CHECK: FuncId (0x1003) { +; CHECK-NEXT: TypeLeafKind: LF_FUNC_ID ({{.*}}) +; CHECK-NEXT: ParentScope: 0x0 +; CHECK-NEXT: FunctionType: void () ({{.*}}) +; CHECK-NEXT: Name: Test + +; ModuleID = 't.cpp' +source_filename = "t.cpp" +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc" + +define i32 @"?Test1"() !dbg !7 { +entry: + ret i32 0, !dbg !10 +} + +define i32 @"?Test2"() !dbg !13 { +entry: + ret i32 0, !dbg !12 +} + +!llvm.dbg.cu = !{!0, !11} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 12.0.0 (https://github.com/llvm/llvm-project.git b93410cbeaa48fec9a15a23e4770be10abc04d4e)", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "", directory: "C:\\src\\tests", checksumkind: CSK_MD5, checksum: "a28f11090424d4b37acdde65a98985a1") +!2 = !{} +!3 = !{i32 2, !"CodeView", i32 1} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 2} +!6 = !{!"clang version 12.0.0 (https://github.com/llvm/llvm-project.git b93410cbeaa48fec9a15a23e4770be10abc04d4e)"} +!7 = distinct !DISubprogram(name: "Test()", scope: !8, file: !8, line: 19, type: !9, scopeLine: 19, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2) +!8 = !DIFile(filename: "t.cpp", directory: "C:\\src\\tests", checksumkind: CSK_MD5, checksum: "a28f11090424d4b37acdde65a98985a1") +!9 = !DISubroutineType(types: !2) +!10 = !DILocation(line: 25, column: 3, scope: !7) +!11 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!12 = !DILocation(line: 0, column: 0, scope: !13) +!13 = distinct !DISubprogram(name: "Test", scope: !8, file: !8, line: 1, type: !9, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !11, retainedNodes: !2)