Skip to content

Commit 1522333

Browse files
authored
[ThinLTO][DebugInfo] Emit full type definitions when importing anonymous types. (#78461)
This fixes some cases of missing debuginfo caused by an interaction between: f0d6655, which drops the identifier from a DICompositeType in the module containing its vtable. and a61f5e3, which causes ThinLTO to import composite types as declarations when they have an identifier. If a virtual class's DICompositeType has no identifier due to the first change, and contains a nested anonymous type which does have an identifier, then the second change can cause ThinLTO to output the classes's DICompositeType as a type definition that links to a non-defining declaration for the nested type. Since the nested anonyous type does not have a name, debuggers are unable to find the definition for the declaration. Repro case: ``` cat > a.h <<EOF class A { public: A(); virtual ~A(); private: union { int val; }; }; EOF cat > a.cc <<EOF #include "a.h" A::A() { asm(""); } A::~A() {} EOF cat > main.cc <<EOF #include "a.h" int main(int argc, char **argv) { A a; return 0; } EOF clang++ -O2 -g -flto=thin -mllvm -force-import-all main.cc a.cc gdb ./a.out -batch -ex 'pt /rmt A' ``` The gdb command outputs: ``` type = class A { private: union { <incomplete type> }; } ``` and dwarfdump -i a.out shows a DW_TAG_class_type for A with an incomplete union type (note that there is also a duplicate entry with the full union type that comes after). ``` < 1><0x0000001e> DW_TAG_class_type DW_AT_containing_type <0x0000001e> DW_AT_calling_convention DW_CC_pass_by_reference DW_AT_name (indexed string: 0x00000007)A DW_AT_byte_size 0x00000010 DW_AT_decl_file 0x00000001 /path/to/./a.h DW_AT_decl_line 0x00000001 ... < 2><0x0000002f> DW_TAG_member DW_AT_type <0x00000037> DW_AT_decl_file 0x00000001 /path/to/./a.h DW_AT_decl_line 0x00000007 DW_AT_data_member_location 8 < 2><0x00000037> DW_TAG_union_type DW_AT_export_symbols yes(1) DW_AT_calling_convention DW_CC_pass_by_value DW_AT_declaration yes(1) ``` This change works around this by making ThinLTO always import full definitions for anonymous types.
1 parent 0ac992e commit 1522333

File tree

2 files changed

+30
-22
lines changed

2 files changed

+30
-22
lines changed

llvm/lib/Bitcode/Reader/MetadataLoader.cpp

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1615,27 +1615,32 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
16151615
Metadata *Annotations = nullptr;
16161616
auto *Identifier = getMDString(Record[15]);
16171617
// If this module is being parsed so that it can be ThinLTO imported
1618-
// into another module, composite types only need to be imported
1619-
// as type declarations (unless full type definitions requested).
1620-
// Create type declarations up front to save memory. Also, buildODRType
1621-
// handles the case where this is type ODRed with a definition needed
1622-
// by the importing module, in which case the existing definition is
1623-
// used.
1624-
if (IsImporting && !ImportFullTypeDefinitions && Identifier &&
1618+
// into another module, composite types only need to be imported as
1619+
// type declarations (unless full type definitions are requested).
1620+
// Create type declarations up front to save memory. This is only
1621+
// done for types which have an Identifier, and are therefore
1622+
// subject to the ODR.
1623+
//
1624+
// buildODRType handles the case where this is type ODRed with a
1625+
// definition needed by the importing module, in which case the
1626+
// existing definition is used.
1627+
//
1628+
// We always import full definitions for anonymous composite types,
1629+
// as without a name, debuggers cannot easily resolve a declaration
1630+
// to its definition.
1631+
if (IsImporting && !ImportFullTypeDefinitions && Identifier && Name &&
16251632
(Tag == dwarf::DW_TAG_enumeration_type ||
16261633
Tag == dwarf::DW_TAG_class_type ||
16271634
Tag == dwarf::DW_TAG_structure_type ||
16281635
Tag == dwarf::DW_TAG_union_type)) {
16291636
Flags = Flags | DINode::FlagFwdDecl;
1630-
if (Name) {
1631-
// This is a hack around preserving template parameters for simplified
1632-
// template names - it should probably be replaced with a
1633-
// DICompositeType flag specifying whether template parameters are
1634-
// required on declarations of this type.
1635-
StringRef NameStr = Name->getString();
1636-
if (!NameStr.contains('<') || NameStr.starts_with("_STN|"))
1637-
TemplateParams = getMDOrNull(Record[14]);
1638-
}
1637+
// This is a hack around preserving template parameters for simplified
1638+
// template names - it should probably be replaced with a
1639+
// DICompositeType flag specifying whether template parameters are
1640+
// required on declarations of this type.
1641+
StringRef NameStr = Name->getString();
1642+
if (!NameStr.contains('<') || NameStr.starts_with("_STN|"))
1643+
TemplateParams = getMDOrNull(Record[14]);
16391644
} else {
16401645
BaseType = getDITypeRefOrNull(Record[6]);
16411646
OffsetInBits = Record[9];

llvm/test/ThinLTO/X86/debuginfo-compositetype-import.ll

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
; CHECK: distinct !DICompositeType(tag: DW_TAG_enumeration_type, name: "enum", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 50, size: 32, flags: DIFlagFwdDecl, identifier: "enum")
1717
; CHECK: distinct !DICompositeType(tag: DW_TAG_class_type, name: "class<>", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 728, size: 448, flags: DIFlagFwdDecl, identifier: "class")
1818
; CHECK: distinct !DICompositeType(tag: DW_TAG_structure_type, name: "struct", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 309, size: 128, flags: DIFlagFwdDecl, templateParams: !{{[0-9]+}}, identifier: "struct_templ_simplified")
19-
; CHECK: distinct !DICompositeType(tag: DW_TAG_union_type, file: !{{[0-9]+}}, line: 115, size: 384, flags: DIFlagFwdDecl, identifier: "union")
19+
; CHECK: distinct !DICompositeType(tag: DW_TAG_union_type, name: "union", file: !{{[0-9]+}}, line: 115, size: 384, flags: DIFlagFwdDecl, identifier: "union")
20+
; CHECK: distinct !DICompositeType(tag: DW_TAG_union_type, file: !{{[0-9]+}}, line: 1, elements: !{{[0-9]+}}, identifier: "anon_union")
2021
; CHECK: distinct !DICompositeType(tag: DW_TAG_structure_type, name: "struct<>", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 309, size: 128, flags: DIFlagFwdDecl, identifier: "struct_templ")
2122
; CHECK: distinct !DICompositeType(tag: DW_TAG_structure_type, name: "_STN|struct|<>", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 309, size: 128, flags: DIFlagFwdDecl, templateParams: !{{[0-9]+}}, identifier: "struct_templ_simplified_mangled")
2223

@@ -32,7 +33,8 @@
3233
; FULL: distinct !DICompositeType(tag: DW_TAG_enumeration_type, name: "enum", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 50, size: 32, elements: !{{[0-9]+}}, identifier: "enum")
3334
; FULL: distinct !DICompositeType(tag: DW_TAG_class_type, name: "class<>", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 728, size: 448, elements: !{{[0-9]+}}, identifier: "class")
3435
; FULL: distinct !DICompositeType(tag: DW_TAG_structure_type, name: "struct", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 309, baseType: !{{[0-9]+}}, size: 128, offset: 64, elements: !{{[0-9]+}}, vtableHolder: !{{[0-9]+}}, templateParams: !{{[0-9]+}}, identifier: "struct_templ_simplified")
35-
; FULL: distinct !DICompositeType(tag: DW_TAG_union_type, file: !{{[0-9]+}}, line: 115, size: 384, elements: !{{[0-9]+}}, identifier: "union")
36+
; FULL: distinct !DICompositeType(tag: DW_TAG_union_type, name: "union", file: !{{[0-9]+}}, line: 115, size: 384, elements: !{{[0-9]+}}, identifier: "union")
37+
; FULL: distinct !DICompositeType(tag: DW_TAG_union_type, file: !{{[0-9]+}}, line: 1, elements: !{{[0-9]+}}, identifier: "anon_union")
3638
; FULL: distinct !DICompositeType(tag: DW_TAG_structure_type, name: "struct<>", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 309, baseType: !{{[0-9]+}}, size: 128, offset: 64, elements: !{{[0-9]+}}, vtableHolder: !{{[0-9]+}}, templateParams: !{{[0-9]+}}, identifier: "struct_templ")
3739
; FULL: distinct !DICompositeType(tag: DW_TAG_structure_type, name: "_STN|struct|<>", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 309, baseType: !{{[0-9]+}}, size: 128, offset: 64, elements: !{{[0-9]+}}, vtableHolder: !{{[0-9]+}}, templateParams: !{{[0-9]+}}, identifier: "struct_templ_simplified_mangled")
3840

@@ -59,10 +61,11 @@ entry:
5961
!5 = !{}
6062
!6 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !7, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: false, unit: !0, retainedNodes: !5)
6163
!7 = !DISubroutineType(types: !8)
62-
!8 = !{!9, !10, !11, !12, !13, !14}
64+
!8 = !{!9, !10, !11, !12, !13, !14, !15}
6365
!9 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "enum", scope: !1, file: !1, line: 50, size: 32, elements: !5, identifier: "enum")
6466
!10 = !DICompositeType(tag: DW_TAG_class_type, name: "class<>", scope: !1, file: !1, line: 728, size: 448, elements: !5, identifier: "class")
6567
!11 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "struct", scope: !1, file: !1, line: 309, baseType: !10, size: 128, offset: 64, elements: !5, vtableHolder: !10, templateParams: !5, identifier: "struct_templ_simplified")
66-
!12 = distinct !DICompositeType(tag: DW_TAG_union_type, file: !1, line: 115, size: 384, elements: !5, identifier: "union")
67-
!13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "struct<>", scope: !1, file: !1, line: 309, baseType: !10, size: 128, offset: 64, elements: !5, vtableHolder: !10, templateParams: !5, identifier: "struct_templ")
68-
!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "_STN|struct|<>", scope: !1, file: !1, line: 309, baseType: !10, size: 128, offset: 64, elements: !5, vtableHolder: !10, templateParams: !5, identifier: "struct_templ_simplified_mangled")
68+
!12 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "union", file: !1, line: 115, size: 384, elements: !5, identifier: "union")
69+
!13 = distinct !DICompositeType(tag: DW_TAG_union_type, file: !1, line: 1, elements: !5, identifier: "anon_union")
70+
!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "struct<>", scope: !1, file: !1, line: 309, baseType: !10, size: 128, offset: 64, elements: !5, vtableHolder: !10, templateParams: !5, identifier: "struct_templ")
71+
!15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "_STN|struct|<>", scope: !1, file: !1, line: 309, baseType: !10, size: 128, offset: 64, elements: !5, vtableHolder: !10, templateParams: !5, identifier: "struct_templ_simplified_mangled")

0 commit comments

Comments
 (0)