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