From 9d69b6f1cd1b7bd8686e3750d5a884e4206a6e8c Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 8 Aug 2017 20:30:14 +0000 Subject: [PATCH] [codeview] Emit nested enums and typedefs from classes Previously we limited ourselves to only emitting nested classes, but we need other kinds of types as well. This fixes the Visual Studio STL visualizers, so that users can visualize std::string and other objects. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@310410 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 10 ++- test/DebugInfo/COFF/nested-types.ll | 150 +++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+), 4 deletions(-) create mode 100644 test/DebugInfo/COFF/nested-types.ll diff --git a/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index 833e5bae1cf..4346803738b 100644 --- a/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -1655,7 +1655,7 @@ struct llvm::ClassInfo { TypeIndex VShapeTI; - std::vector NestedClasses; + std::vector NestedTypes; }; void CodeViewDebug::clear() { @@ -1706,12 +1706,14 @@ ClassInfo CodeViewDebug::collectClassInfo(const DICompositeType *Ty) { } else if (DDTy->getTag() == dwarf::DW_TAG_pointer_type && DDTy->getName() == "__vtbl_ptr_type") { Info.VShapeTI = getTypeIndex(DDTy); + } else if (DDTy->getTag() == dwarf::DW_TAG_typedef) { + Info.NestedTypes.push_back(DDTy); } else if (DDTy->getTag() == dwarf::DW_TAG_friend) { // Ignore friend members. It appears that MSVC emitted info about // friends in the past, but modern versions do not. } } else if (auto *Composite = dyn_cast(Element)) { - Info.NestedClasses.push_back(Composite); + Info.NestedTypes.push_back(Composite); } // Skip other unrecognized kinds of elements. } @@ -1920,7 +1922,7 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) { } // Create nested classes. - for (const DICompositeType *Nested : Info.NestedClasses) { + for (const DIType *Nested : Info.NestedTypes) { NestedTypeRecord R(getTypeIndex(DITypeRef(Nested)), Nested->getName()); FLBR.writeMemberType(R); MemberCount++; @@ -1928,7 +1930,7 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) { TypeIndex FieldTI = FLBR.end(true); return std::make_tuple(FieldTI, Info.VShapeTI, MemberCount, - !Info.NestedClasses.empty()); + !Info.NestedTypes.empty()); } TypeIndex CodeViewDebug::getVBPTypeIndex() { diff --git a/test/DebugInfo/COFF/nested-types.ll b/test/DebugInfo/COFF/nested-types.ll new file mode 100644 index 00000000000..8a3ff001f7f --- /dev/null +++ b/test/DebugInfo/COFF/nested-types.ll @@ -0,0 +1,150 @@ +; RUN: llc < %s -filetype=obj | llvm-readobj - -codeview | FileCheck %s + +; C++ source to regenerate: +; struct HasNested { +; enum InnerEnum { _BUF_SIZE = 1 }; +; typedef int InnerTypedef; +; enum { InnerEnumerator = 2 }; +; struct InnerStruct { }; +; }; +; HasNested f; +; $ clang t.cpp -S -emit-llvm -g -gcodeview -o t.ll + +; ModuleID = 't.cpp' +source_filename = "t.cpp" +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc19.0.24215" + +%struct.HasNested = type { i8 } + +@"\01?f@@3UHasNested@@A" = global %struct.HasNested zeroinitializer, align 1, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!17, !18, !19, !20} +!llvm.ident = !{!21} + +!0 = !DIGlobalVariableExpression(var: !1) +!1 = distinct !DIGlobalVariable(name: "f", linkageName: "\01?f@@3UHasNested@@A", scope: !2, file: !3, line: 7, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 6.0.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !16) +!3 = !DIFile(filename: "t.cpp", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "40c412b85e2b27acb30eef53983b1da4") +!4 = !{!5, !10} +!5 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "InnerEnum", scope: !6, file: !3, line: 2, baseType: !9, size: 32, elements: !14, identifier: ".?AW4InnerEnum@HasNested@@") +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "HasNested", file: !3, line: 1, size: 8, elements: !7, identifier: ".?AUHasNested@@") +!7 = !{!5, !8, !10, !13} +!8 = !DIDerivedType(tag: DW_TAG_typedef, name: "InnerTypedef", scope: !6, file: !3, line: 3, baseType: !9) +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DICompositeType(tag: DW_TAG_enumeration_type, scope: !6, file: !3, line: 4, baseType: !9, size: 32, elements: !11, identifier: ".?AW4@HasNested@@") +!11 = !{!12} +!12 = !DIEnumerator(name: "InnerEnumerator", value: 2) +!13 = !DICompositeType(tag: DW_TAG_structure_type, name: "InnerStruct", scope: !6, file: !3, line: 5, flags: DIFlagFwdDecl, identifier: ".?AUInnerStruct@HasNested@@") +!14 = !{!15} +!15 = !DIEnumerator(name: "_BUF_SIZE", value: 1) +!16 = !{!0} +!17 = !{i32 2, !"CodeView", i32 1} +!18 = !{i32 2, !"Debug Info Version", i32 3} +!19 = !{i32 1, !"wchar_size", i32 2} +!20 = !{i32 7, !"PIC Level", i32 2} +!21 = !{!"clang version 6.0.0 "} + +; InnerEnum: + +; CHECK: FieldList ([[INNERENUM_MEMBERS:0x.*]]) { +; CHECK-NEXT: TypeLeafKind: LF_FIELDLIST (0x1203) +; CHECK-NEXT: Enumerator { +; CHECK-NEXT: TypeLeafKind: LF_ENUMERATE (0x1502) +; CHECK-NEXT: AccessSpecifier: Public (0x3) +; CHECK-NEXT: EnumValue: 1 +; CHECK-NEXT: Name: _BUF_SIZE +; CHECK-NEXT: } +; CHECK-NEXT: } +; +; CHECK: Enum ([[INNERENUM:0x.*]]) { +; CHECK-NEXT: TypeLeafKind: LF_ENUM (0x1507) +; CHECK-NEXT: NumEnumerators: 1 +; CHECK-NEXT: Properties [ (0x208) +; CHECK-NEXT: HasUniqueName (0x200) +; CHECK-NEXT: Nested (0x8) +; CHECK-NEXT: ] +; CHECK-NEXT: UnderlyingType: int (0x74) +; CHECK-NEXT: FieldListType: ([[INNERENUM_MEMBERS]]) +; CHECK-NEXT: Name: HasNested::InnerEnum +; CHECK-NEXT: LinkageName: .?AW4InnerEnum@HasNested@@ +; CHECK-NEXT: } + +; CHECK: FieldList ([[UNNAMED_MEMBERS:0x.*]]) { +; CHECK-NEXT: TypeLeafKind: LF_FIELDLIST (0x1203) +; CHECK-NEXT: Enumerator { +; CHECK-NEXT: TypeLeafKind: LF_ENUMERATE (0x1502) +; CHECK-NEXT: AccessSpecifier: Public (0x3) +; CHECK-NEXT: EnumValue: 2 +; CHECK-NEXT: Name: InnerEnumerator +; CHECK-NEXT: } +; CHECK-NEXT: } +; +; CHECK: Enum ([[UNNAMEDENUM:0x.*]]) { +; CHECK-NEXT: TypeLeafKind: LF_ENUM (0x1507) +; CHECK-NEXT: NumEnumerators: 1 +; CHECK-NEXT: Properties [ (0x208) +; CHECK-NEXT: HasUniqueName (0x200) +; CHECK-NEXT: Nested (0x8) +; CHECK-NEXT: ] +; CHECK-NEXT: UnderlyingType: int (0x74) +; CHECK-NEXT: FieldListType: ([[UNNAMED_MEMBERS]]) +; CHECK-NEXT: Name: HasNested:: +; CHECK-NEXT: LinkageName: .?AW4@HasNested@@ +; CHECK-NEXT: } + +; CHECK: Struct ([[INNERSTRUCT:0x.*]]) { +; CHECK-NEXT: TypeLeafKind: LF_STRUCTURE (0x1505) +; CHECK-NEXT: MemberCount: 0 +; CHECK-NEXT: Properties [ (0x288) +; CHECK-NEXT: ForwardReference (0x80) +; CHECK-NEXT: HasUniqueName (0x200) +; CHECK-NEXT: Nested (0x8) +; CHECK-NEXT: ] +; CHECK-NEXT: FieldList: 0x0 +; CHECK-NEXT: DerivedFrom: 0x0 +; CHECK-NEXT: VShape: 0x0 +; CHECK-NEXT: SizeOf: 0 +; CHECK-NEXT: Name: HasNested::InnerStruct +; CHECK-NEXT: LinkageName: .?AUInnerStruct@HasNested@@ +; CHECK-NEXT: } + +; CHECK: FieldList ([[HASNESTED_MEMBERS:0x.*]]) { +; CHECK-NEXT: TypeLeafKind: LF_FIELDLIST (0x1203) +; CHECK-NEXT: NestedType { +; CHECK-NEXT: TypeLeafKind: LF_NESTTYPE (0x1510) +; CHECK-NEXT: Type: HasNested::InnerEnum ([[INNERENUM]]) +; CHECK-NEXT: Name: InnerEnum +; CHECK-NEXT: } +; CHECK-NEXT: NestedType { +; CHECK-NEXT: TypeLeafKind: LF_NESTTYPE (0x1510) +; CHECK-NEXT: Type: int (0x74) +; CHECK-NEXT: Name: InnerTypedef +; CHECK-NEXT: } +; CHECK-NEXT: NestedType { +; CHECK-NEXT: TypeLeafKind: LF_NESTTYPE (0x1510) +; CHECK-NEXT: Type: HasNested:: ([[UNNAMEDENUM]]) +; CHECK-NEXT: Name: {{$}} +; CHECK-NEXT: } +; CHECK-NEXT: NestedType { +; CHECK-NEXT: TypeLeafKind: LF_NESTTYPE (0x1510) +; CHECK-NEXT: Type: HasNested::InnerStruct ([[INNERSTRUCT]]) +; CHECK-NEXT: Name: InnerStruct +; CHECK-NEXT: } +; CHECK-NEXT: } +; +; CHECK: Struct (0x1007) { +; CHECK-NEXT: TypeLeafKind: LF_STRUCTURE (0x1505) +; CHECK-NEXT: MemberCount: 4 +; CHECK-NEXT: Properties [ (0x210) +; CHECK-NEXT: ContainsNestedClass (0x10) +; CHECK-NEXT: HasUniqueName (0x200) +; CHECK-NEXT: ] +; CHECK-NEXT: FieldList: ([[HASNESTED_MEMBERS]]) +; CHECK-NEXT: DerivedFrom: 0x0 +; CHECK-NEXT: VShape: 0x0 +; CHECK-NEXT: SizeOf: 1 +; CHECK-NEXT: Name: HasNested +; CHECK-NEXT: LinkageName: .?AUHasNested@@ +; CHECK-NEXT: } -- 2.11.0