llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.29k stars 11.68k forks source link

[Clang][DebugInfo] typedef in template class given wrong scope #91451

Open OCHyams opened 4 months ago

OCHyams commented 4 months ago

Clang trunk built at d4cf20ca37160cb062a9db773d0e6255d6bbc31a (19.0)

Godbolt version of example below https://godbolt.org/z/7esxK8dbY

$ cat test.cpp

struct X {
  typedef int inside;
  inside i;
};

template <typename T = int>
struct Y {
  typedef int outside;
  outside o;
};

X x;
Y<> y;

The DIE for outside is scoped to DW_TAG_compile_unit (0x0000000b) while the DIE for inside is scoped to its enclosing DW_TAG_structure_type (0x00000033). outside should be scoped to the DW_TAG_structure_type DIE for Y<int> (0x00000070).

$ clang -O0 -g test.cpp -o - | llvm-dwarfdump -

0x00000000: Compile Unit: length = 0x00000097, format = DWARF32, version = 0x0004, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x0000009b)

0x0000000b: DW_TAG_compile_unit
              DW_AT_producer    ("clang version 19.0.0git (https://github.com/llvm/llvm-project.git d4cf20ca37160cb062a9db773d0e6255d6bbc31a)")
              DW_AT_language    (DW_LANG_C_plus_plus_14)
              DW_AT_name    ("test.cpp")
              DW_AT_stmt_list   (0x00000000)
              DW_AT_comp_dir    ("/")

0x0000001e:   DW_TAG_variable
                DW_AT_name  ("x")
                DW_AT_type  (0x00000033 "X")
                DW_AT_external  (true)
                DW_AT_decl_file ("test.cpp")
                DW_AT_decl_line (12)
                DW_AT_location  (DW_OP_addr 0x0)

0x00000033:   DW_TAG_structure_type
                DW_AT_calling_convention    (DW_CC_pass_by_value)
                DW_AT_name  ("X")
                DW_AT_byte_size (0x04)
                DW_AT_decl_file ("test.cpp")
                DW_AT_decl_line (1)

0x0000003c:     DW_TAG_member
                  DW_AT_name    ("i")
                  DW_AT_type    (0x00000048 "inside")
                  DW_AT_decl_file   ("test.cpp")
                  DW_AT_decl_line   (3)
                  DW_AT_data_member_location    (0x00)

0x00000048:     DW_TAG_typedef
                  DW_AT_type    (0x00000054 "int")
                  DW_AT_name    ("inside")
                  DW_AT_decl_file   ("test.cpp")
                  DW_AT_decl_line   (2)

0x00000053:     NULL

0x00000054:   DW_TAG_base_type
                DW_AT_name  ("int")
                DW_AT_encoding  (DW_ATE_signed)
                DW_AT_byte_size (0x04)

0x0000005b:   DW_TAG_variable
                DW_AT_name  ("y")
                DW_AT_type  (0x00000070 "Y<int>")
                DW_AT_external  (true)
                DW_AT_decl_file ("test.cpp")
                DW_AT_decl_line (13)
                DW_AT_location  (DW_OP_addr 0x0)

0x00000070:   DW_TAG_structure_type
                DW_AT_calling_convention    (DW_CC_pass_by_value)
                DW_AT_name  ("Y<int>")
                DW_AT_byte_size (0x04)
                DW_AT_decl_file ("test.cpp")
                DW_AT_decl_line (7)

0x00000079:     DW_TAG_template_type_parameter
                  DW_AT_type    (0x00000054 "int")
                  DW_AT_name    ("T")
                  DW_AT_default_value   (true)

0x00000082:     DW_TAG_member
                  DW_AT_name    ("o")
                  DW_AT_type    (0x0000008f "outside")
                  DW_AT_decl_file   ("test.cpp")
                  DW_AT_decl_line   (9)
                  DW_AT_data_member_location    (0x00)

0x0000008e:     NULL

0x0000008f:   DW_TAG_typedef
                DW_AT_type  (0x00000054 "int")
                DW_AT_name  ("outside")
                DW_AT_decl_file ("test.cpp")
                DW_AT_decl_line (8)

0x0000009a:   NULL

Looking at the IR produced by Clang:

$ clang -O0 -g test.cpp -emit-llvm -S -o -

source_filename = "test.cpp"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

%struct.X = type { i32 }
%struct.Y = type { i32 }

@x = dso_local global %struct.X zeroinitializer, align 4, !dbg !0
@y = dso_local global %struct.Y zeroinitializer, align 4, !dbg !5

!llvm.dbg.cu = !{!2}
!llvm.module.flags = !{!19, !20, !21, !22, !23, !24, !25}
!llvm.ident = !{!26}

!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!1 = distinct !DIGlobalVariable(name: "x", scope: !2, file: !7, line: 12, type: !15, isLocal: false, isDefinition: true)
!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 19.0.0git (https://github.com/llvm/llvm-project.git d4cf20ca37160cb062a9db773d0e6255d6bbc31a)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
!3 = !DIFile(filename: "test.cpp")
!4 = !{!0, !5}
!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
!6 = distinct !DIGlobalVariable(name: "y", scope: !2, file: !7, line: 13, type: !8, isLocal: false, isDefinition: true)
!7 = !DIFile(filename: "example.cpp"test.cpp)
!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Y<int>", file: !7, line: 7, size: 32, flags: DIFlagTypePassByValue, elements: !9, templateParams: !13, identifier: "_ZTS1YIiE")
!9 = !{!10}
!10 = !DIDerivedType(tag: DW_TAG_member, name: "o", scope: !8, file: !7, line: 9, baseType: !11, size: 32)
!11 = !DIDerivedType(tag: DW_TAG_typedef, name: "outside", file: !7, line: 8, baseType: !12)
!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!13 = !{!14}
!14 = !DITemplateTypeParameter(name: "T", type: !12, defaulted: true)
!15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "X", file: !7, line: 1, size: 32, flags: DIFlagTypePassByValue, elements: !16, identifier: "_ZTS1X")
!16 = !{!17}
!17 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !15, file: !7, line: 3, baseType: !18, size: 32)
!18 = !DIDerivedType(tag: DW_TAG_typedef, name: "inside", scope: !15, file: !7, line: 2, baseType: !12)
!19 = !{i32 7, !"Dwarf Version", i32 4}
!20 = !{i32 2, !"Debug Info Version", i32 3}
!21 = !{i32 1, !"wchar_size", i32 4}
!22 = !{i32 8, !"PIC Level", i32 2}
!23 = !{i32 7, !"PIE Level", i32 2}
!24 = !{i32 7, !"uwtable", i32 2}
!25 = !{i32 7, !"frame-pointer", i32 2}
!26 = !{!"clang version 19.0.0git (https://github.com/llvm/llvm-project.git d4cf20ca37160cb062a9db773d0e6255d6bbc31a)"}

inside has a scope field pointing to X.

!15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "X", ...)
!18 = !DIDerivedType(tag: DW_TAG_typedef, name: "inside", scope: !15, file: !7, line: 2, baseType: !12)

outside has no scope field.

!11 = !DIDerivedType(tag: DW_TAG_typedef, name: "outside", file: !7, line: 8, baseType: !12)
OCHyams commented 4 months ago

Unknown if it has the same root cause as #44229

llvmbot commented 4 months ago

@llvm/issue-subscribers-debuginfo

Author: Orlando Cazalet-Hyams (OCHyams)

Clang trunk built at d4cf20ca37160cb062a9db773d0e6255d6bbc31a (19.0) Godbolt version of example below https://godbolt.org/z/7esxK8dbY $ cat test.cpp ``` struct X { typedef int inside; inside i; }; template <typename T = int> struct Y { typedef int outside; outside o; }; X x; Y<> y; ``` The DIE for `outside` is scoped to `DW_TAG_compile_unit (0x0000000b)` while the DIE for `inside` is scoped to its enclosing `DW_TAG_structure_type (0x00000033)`. `outside` should be scoped to the `DW_TAG_structure_type` DIE for `Y<int>` (`0x00000070`). $ clang -O0 -g test.cpp -o - | llvm-dwarfdump - ``` 0x00000000: Compile Unit: length = 0x00000097, format = DWARF32, version = 0x0004, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x0000009b) 0x0000000b: DW_TAG_compile_unit DW_AT_producer ("clang version 19.0.0git (https://github.com/llvm/llvm-project.git d4cf20ca37160cb062a9db773d0e6255d6bbc31a)") DW_AT_language (DW_LANG_C_plus_plus_14) DW_AT_name ("test.cpp") DW_AT_stmt_list (0x00000000) DW_AT_comp_dir ("/") 0x0000001e: DW_TAG_variable DW_AT_name ("x") DW_AT_type (0x00000033 "X") DW_AT_external (true) DW_AT_decl_file ("test.cpp") DW_AT_decl_line (12) DW_AT_location (DW_OP_addr 0x0) 0x00000033: DW_TAG_structure_type DW_AT_calling_convention (DW_CC_pass_by_value) DW_AT_name ("X") DW_AT_byte_size (0x04) DW_AT_decl_file ("test.cpp") DW_AT_decl_line (1) 0x0000003c: DW_TAG_member DW_AT_name ("i") DW_AT_type (0x00000048 "inside") DW_AT_decl_file ("test.cpp") DW_AT_decl_line (3) DW_AT_data_member_location (0x00) 0x00000048: DW_TAG_typedef DW_AT_type (0x00000054 "int") DW_AT_name ("inside") DW_AT_decl_file ("test.cpp") DW_AT_decl_line (2) 0x00000053: NULL 0x00000054: DW_TAG_base_type DW_AT_name ("int") DW_AT_encoding (DW_ATE_signed) DW_AT_byte_size (0x04) 0x0000005b: DW_TAG_variable DW_AT_name ("y") DW_AT_type (0x00000070 "Y<int>") DW_AT_external (true) DW_AT_decl_file ("test.cpp") DW_AT_decl_line (13) DW_AT_location (DW_OP_addr 0x0) 0x00000070: DW_TAG_structure_type DW_AT_calling_convention (DW_CC_pass_by_value) DW_AT_name ("Y<int>") DW_AT_byte_size (0x04) DW_AT_decl_file ("test.cpp") DW_AT_decl_line (7) 0x00000079: DW_TAG_template_type_parameter DW_AT_type (0x00000054 "int") DW_AT_name ("T") DW_AT_default_value (true) 0x00000082: DW_TAG_member DW_AT_name ("o") DW_AT_type (0x0000008f "outside") DW_AT_decl_file ("test.cpp") DW_AT_decl_line (9) DW_AT_data_member_location (0x00) 0x0000008e: NULL 0x0000008f: DW_TAG_typedef DW_AT_type (0x00000054 "int") DW_AT_name ("outside") DW_AT_decl_file ("test.cpp") DW_AT_decl_line (8) 0x0000009a: NULL ``` Looking at the IR produced by Clang: $ clang -O0 -g test.cpp -emit-llvm -S -o - ``` source_filename = "test.cpp" target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" %struct.X = type { i32 } %struct.Y = type { i32 } @x = dso_local global %struct.X zeroinitializer, align 4, !dbg !0 @y = dso_local global %struct.Y zeroinitializer, align 4, !dbg !5 !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!19, !20, !21, !22, !23, !24, !25} !llvm.ident = !{!26} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "x", scope: !2, file: !7, line: 12, type: !15, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 19.0.0git (https://github.com/llvm/llvm-project.git d4cf20ca37160cb062a9db773d0e6255d6bbc31a)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) !3 = !DIFile(filename: "test.cpp") !4 = !{!0, !5} !5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression()) !6 = distinct !DIGlobalVariable(name: "y", scope: !2, file: !7, line: 13, type: !8, isLocal: false, isDefinition: true) !7 = !DIFile(filename: "example.cpp"test.cpp) !8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Y<int>", file: !7, line: 7, size: 32, flags: DIFlagTypePassByValue, elements: !9, templateParams: !13, identifier: "_ZTS1YIiE") !9 = !{!10} !10 = !DIDerivedType(tag: DW_TAG_member, name: "o", scope: !8, file: !7, line: 9, baseType: !11, size: 32) !11 = !DIDerivedType(tag: DW_TAG_typedef, name: "outside", file: !7, line: 8, baseType: !12) !12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !13 = !{!14} !14 = !DITemplateTypeParameter(name: "T", type: !12, defaulted: true) !15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "X", file: !7, line: 1, size: 32, flags: DIFlagTypePassByValue, elements: !16, identifier: "_ZTS1X") !16 = !{!17} !17 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !15, file: !7, line: 3, baseType: !18, size: 32) !18 = !DIDerivedType(tag: DW_TAG_typedef, name: "inside", scope: !15, file: !7, line: 2, baseType: !12) !19 = !{i32 7, !"Dwarf Version", i32 4} !20 = !{i32 2, !"Debug Info Version", i32 3} !21 = !{i32 1, !"wchar_size", i32 4} !22 = !{i32 8, !"PIC Level", i32 2} !23 = !{i32 7, !"PIE Level", i32 2} !24 = !{i32 7, !"uwtable", i32 2} !25 = !{i32 7, !"frame-pointer", i32 2} !26 = !{!"clang version 19.0.0git (https://github.com/llvm/llvm-project.git d4cf20ca37160cb062a9db773d0e6255d6bbc31a)"} ``` `inside` has a `scope` field pointing to `X`. ``` !15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "X", ...) !18 = !DIDerivedType(tag: DW_TAG_typedef, name: "inside", scope: !15, file: !7, line: 2, baseType: !12) ``` `outside` has no scope field. ``` !11 = !DIDerivedType(tag: DW_TAG_typedef, name: "outside", file: !7, line: 8, baseType: !12) ```
llvmbot commented 4 months ago

@llvm/issue-subscribers-clang-codegen

Author: Orlando Cazalet-Hyams (OCHyams)

Clang trunk built at d4cf20ca37160cb062a9db773d0e6255d6bbc31a (19.0) Godbolt version of example below https://godbolt.org/z/7esxK8dbY $ cat test.cpp ``` struct X { typedef int inside; inside i; }; template <typename T = int> struct Y { typedef int outside; outside o; }; X x; Y<> y; ``` The DIE for `outside` is scoped to `DW_TAG_compile_unit (0x0000000b)` while the DIE for `inside` is scoped to its enclosing `DW_TAG_structure_type (0x00000033)`. `outside` should be scoped to the `DW_TAG_structure_type` DIE for `Y<int>` (`0x00000070`). $ clang -O0 -g test.cpp -o - | llvm-dwarfdump - ``` 0x00000000: Compile Unit: length = 0x00000097, format = DWARF32, version = 0x0004, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x0000009b) 0x0000000b: DW_TAG_compile_unit DW_AT_producer ("clang version 19.0.0git (https://github.com/llvm/llvm-project.git d4cf20ca37160cb062a9db773d0e6255d6bbc31a)") DW_AT_language (DW_LANG_C_plus_plus_14) DW_AT_name ("test.cpp") DW_AT_stmt_list (0x00000000) DW_AT_comp_dir ("/") 0x0000001e: DW_TAG_variable DW_AT_name ("x") DW_AT_type (0x00000033 "X") DW_AT_external (true) DW_AT_decl_file ("test.cpp") DW_AT_decl_line (12) DW_AT_location (DW_OP_addr 0x0) 0x00000033: DW_TAG_structure_type DW_AT_calling_convention (DW_CC_pass_by_value) DW_AT_name ("X") DW_AT_byte_size (0x04) DW_AT_decl_file ("test.cpp") DW_AT_decl_line (1) 0x0000003c: DW_TAG_member DW_AT_name ("i") DW_AT_type (0x00000048 "inside") DW_AT_decl_file ("test.cpp") DW_AT_decl_line (3) DW_AT_data_member_location (0x00) 0x00000048: DW_TAG_typedef DW_AT_type (0x00000054 "int") DW_AT_name ("inside") DW_AT_decl_file ("test.cpp") DW_AT_decl_line (2) 0x00000053: NULL 0x00000054: DW_TAG_base_type DW_AT_name ("int") DW_AT_encoding (DW_ATE_signed) DW_AT_byte_size (0x04) 0x0000005b: DW_TAG_variable DW_AT_name ("y") DW_AT_type (0x00000070 "Y<int>") DW_AT_external (true) DW_AT_decl_file ("test.cpp") DW_AT_decl_line (13) DW_AT_location (DW_OP_addr 0x0) 0x00000070: DW_TAG_structure_type DW_AT_calling_convention (DW_CC_pass_by_value) DW_AT_name ("Y<int>") DW_AT_byte_size (0x04) DW_AT_decl_file ("test.cpp") DW_AT_decl_line (7) 0x00000079: DW_TAG_template_type_parameter DW_AT_type (0x00000054 "int") DW_AT_name ("T") DW_AT_default_value (true) 0x00000082: DW_TAG_member DW_AT_name ("o") DW_AT_type (0x0000008f "outside") DW_AT_decl_file ("test.cpp") DW_AT_decl_line (9) DW_AT_data_member_location (0x00) 0x0000008e: NULL 0x0000008f: DW_TAG_typedef DW_AT_type (0x00000054 "int") DW_AT_name ("outside") DW_AT_decl_file ("test.cpp") DW_AT_decl_line (8) 0x0000009a: NULL ``` Looking at the IR produced by Clang: $ clang -O0 -g test.cpp -emit-llvm -S -o - ``` source_filename = "test.cpp" target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" %struct.X = type { i32 } %struct.Y = type { i32 } @x = dso_local global %struct.X zeroinitializer, align 4, !dbg !0 @y = dso_local global %struct.Y zeroinitializer, align 4, !dbg !5 !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!19, !20, !21, !22, !23, !24, !25} !llvm.ident = !{!26} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "x", scope: !2, file: !7, line: 12, type: !15, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 19.0.0git (https://github.com/llvm/llvm-project.git d4cf20ca37160cb062a9db773d0e6255d6bbc31a)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) !3 = !DIFile(filename: "test.cpp") !4 = !{!0, !5} !5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression()) !6 = distinct !DIGlobalVariable(name: "y", scope: !2, file: !7, line: 13, type: !8, isLocal: false, isDefinition: true) !7 = !DIFile(filename: "example.cpp"test.cpp) !8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Y<int>", file: !7, line: 7, size: 32, flags: DIFlagTypePassByValue, elements: !9, templateParams: !13, identifier: "_ZTS1YIiE") !9 = !{!10} !10 = !DIDerivedType(tag: DW_TAG_member, name: "o", scope: !8, file: !7, line: 9, baseType: !11, size: 32) !11 = !DIDerivedType(tag: DW_TAG_typedef, name: "outside", file: !7, line: 8, baseType: !12) !12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !13 = !{!14} !14 = !DITemplateTypeParameter(name: "T", type: !12, defaulted: true) !15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "X", file: !7, line: 1, size: 32, flags: DIFlagTypePassByValue, elements: !16, identifier: "_ZTS1X") !16 = !{!17} !17 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !15, file: !7, line: 3, baseType: !18, size: 32) !18 = !DIDerivedType(tag: DW_TAG_typedef, name: "inside", scope: !15, file: !7, line: 2, baseType: !12) !19 = !{i32 7, !"Dwarf Version", i32 4} !20 = !{i32 2, !"Debug Info Version", i32 3} !21 = !{i32 1, !"wchar_size", i32 4} !22 = !{i32 8, !"PIC Level", i32 2} !23 = !{i32 7, !"PIE Level", i32 2} !24 = !{i32 7, !"uwtable", i32 2} !25 = !{i32 7, !"frame-pointer", i32 2} !26 = !{!"clang version 19.0.0git (https://github.com/llvm/llvm-project.git d4cf20ca37160cb062a9db773d0e6255d6bbc31a)"} ``` `inside` has a `scope` field pointing to `X`. ``` !15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "X", ...) !18 = !DIDerivedType(tag: DW_TAG_typedef, name: "inside", scope: !15, file: !7, line: 2, baseType: !12) ``` `outside` has no scope field. ``` !11 = !DIDerivedType(tag: DW_TAG_typedef, name: "outside", file: !7, line: 8, baseType: !12) ```