xref: /aosp_15_r20/external/clang/test/CodeGenCXX/debug-info-static-member.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
1 // RUN: %clangxx -target x86_64-unknown-unknown -g %s -emit-llvm -S -o - | FileCheck %s
2 // RUN: %clangxx -target x86_64-unknown-unknown -g -std=c++98 %s -emit-llvm -S -o - | FileCheck %s
3 // RUN: %clangxx -target x86_64-unknown-unknown -g -std=c++11 %s -emit-llvm -S -o - | FileCheck %s
4 // PR14471
5 
6 enum X {
7   Y
8 };
9 class C
10 {
11   static int a;
12   const static bool const_a = true;
13 protected:
14   static int b;
15 #if __cplusplus >= 201103L
16   constexpr static float const_b = 3.14;
17 #else
18   const static float const_b = 3.14;
19 #endif
20 public:
21   static int c;
22   const static int const_c = 18;
23   int d;
24   static X x_a;
25 };
26 
27 // The definition of C::a drives the emission of class C, which is
28 // why the definition of "a" comes before the declarations while
29 // "b" and "c" come after.
30 
31 // CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, name: "X"{{.*}}, identifier: "_ZTS1X")
32 // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "anon_static_decl_struct"
33 // CHECK: !DIDerivedType(tag: DW_TAG_member, name: "anon_static_decl_var"
34 // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "static_decl_templ<int>"
35 // CHECK-NOT:              DIFlagFwdDecl
36 // CHECK-SAME:             ){{$}}
37 // CHECK: !DIDerivedType(tag: DW_TAG_member, name: "static_decl_templ_var"
38 
39 // CHECK: !DIGlobalVariable(name: "a", {{.*}}variable: i32* @_ZN1C1aE, declaration: ![[DECL_A:[0-9]+]])
40 int C::a = 4;
41 // CHECK: ![[DECL_A]] = !DIDerivedType(tag: DW_TAG_member, name: "a"
42 // CHECK-NOT:                                 size:
43 // CHECK-NOT:                                 align:
44 // CHECK-NOT:                                 offset:
45 // CHECK-SAME:                                flags: DIFlagStaticMember)
46 //
47 // CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "C"{{.*}}, identifier: "_ZTS1C")
48 //
49 // CHECK: !DIDerivedType(tag: DW_TAG_member, name: "const_a"
50 // CHECK-NOT:            size:
51 // CHECK-NOT:            align:
52 // CHECK-NOT:            offset:
53 // CHECK-SAME:           flags: DIFlagStaticMember,
54 // CHECK-SAME:           extraData: i1 true)
55 
56 // CHECK: ![[DECL_B:[0-9]+]] = !DIDerivedType(tag: DW_TAG_member, name: "b"
57 // CHECK-NOT:                                 size:
58 // CHECK-NOT:                                 align:
59 // CHECK-NOT:                                 offset:
60 // CHECK-SAME:                                flags: DIFlagProtected | DIFlagStaticMember)
61 //
62 // CHECK: !DIDerivedType(tag: DW_TAG_member, name: "const_b"
63 // CHECK-NOT:            size:
64 // CHECK-NOT:            align:
65 // CHECK-NOT:            offset:
66 // CHECK-SAME:           flags: DIFlagProtected | DIFlagStaticMember,
67 // CHECK-SAME:           extraData: float 0x{{.*}})
68 
69 // CHECK: ![[DECL_C:[0-9]+]] = !DIDerivedType(tag: DW_TAG_member, name: "c"
70 // CHECK-NOT:                                 size:
71 // CHECK-NOT:                                 align:
72 // CHECK-NOT:                                 offset:
73 // CHECK-SAME:                                flags: DIFlagPublic | DIFlagStaticMember)
74 //
75 // CHECK: !DIDerivedType(tag: DW_TAG_member, name: "const_c"
76 // CHECK-NOT:            size:
77 // CHECK-NOT:            align:
78 // CHECK-NOT:            offset:
79 // CHECK-SAME:           flags: DIFlagPublic | DIFlagStaticMember,
80 // CHECK-SAME:           extraData: i32 18)
81 //
82 // CHECK: !DIDerivedType(tag: DW_TAG_member, name: "x_a"
83 // CHECK-SAME:           flags: DIFlagPublic | DIFlagStaticMember)
84 
85 // CHECK: !DIGlobalVariable(name: "b", {{.*}}variable: i32* @_ZN1C1bE, declaration: ![[DECL_B]])
86 int C::b = 2;
87 // CHECK: !DIGlobalVariable(name: "c", {{.*}}variable: i32* @_ZN1C1cE, declaration: ![[DECL_C]])
88 int C::c = 1;
89 
main()90 int main()
91 {
92         C instance_C;
93         instance_C.d = 8;
94         return C::c;
95 }
96 
97 // CHECK-NOT: !DIGlobalVariable(name: "anon_static_decl_var"
98 
99 // Test this in an anonymous namespace to ensure the type is retained even when
100 // it doesn't get automatically retained by the string type reference machinery.
101 namespace {
102 struct anon_static_decl_struct {
103   static const int anon_static_decl_var = 117;
104 };
105 }
106 
107 
ref()108 int ref() {
109   return anon_static_decl_struct::anon_static_decl_var;
110 }
111 
112 template<typename T>
113 struct static_decl_templ {
114   static const int static_decl_templ_var = 7;
115 };
116 
117 template<typename T>
118 const int static_decl_templ<T>::static_decl_templ_var;
119 
static_decl_templ_ref()120 int static_decl_templ_ref() {
121   return static_decl_templ<int>::static_decl_templ_var;
122 }
123 
124 // Verify that even when a static member declaration is created lazily when
125 // creating the definition, the declaration line is that of the canonical
126 // declaration, not the definition. Also, since we look at the canonical
127 // definition, we should also correctly emit the constant value (42) into the
128 // debug info.
129 struct V {
130   virtual ~V(); // cause the definition of 'V' to be omitted by no-standalone-debug optimization
131   static const int const_va = 42;
132 };
133 // CHECK: !DIDerivedType(tag: DW_TAG_member, name: "const_va",
134 // CHECK-SAME:           line: [[@LINE-3]]
135 // CHECK-SAME:           extraData: i32 42
136 const int V::const_va;
137 
138 namespace x {
139 struct y {
140 // CHECK: !DIGlobalVariable(name: "z",
141 // CHECK-SAME:              scope: [[NS_X:![0-9]+]]
142 // CHECK: [[NS_X]] = !DINamespace(name: "x"
143   static int z;
144 };
145 int y::z;
146 }
147