1 | // RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fexceptions -fcxx-exceptions -fno-rtti | FileCheck -check-prefix WIN32 -check-prefix WIN32-O0 %s |
2 | // RUN: %clang_cc1 -std=c++11 -emit-llvm -O3 -disable-llvm-passes %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fexceptions -fcxx-exceptions -fno-rtti | FileCheck -check-prefix WIN32 -check-prefix WIN32-O3 -check-prefix WIN32-LIFETIME %s |
3 | |
4 | struct A { |
5 | A(); |
6 | ~A(); |
7 | int a; |
8 | }; |
9 | |
10 | A getA(); |
11 | |
12 | int TakesTwo(A a, A b); |
13 | void HasEHCleanup() { |
14 | TakesTwo(getA(), getA()); |
15 | } |
16 | |
17 | // With exceptions, we need to clean up at least one of these temporaries. |
18 | // WIN32-LABEL: define dso_local void @"?HasEHCleanup@@YAXXZ"() {{.*}} { |
19 | // WIN32: %[[base:.*]] = call i8* @llvm.stacksave() |
20 | // If this call throws, we have to restore the stack. |
21 | // WIN32: call void @"?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}}) |
22 | // If this call throws, we have to cleanup the first temporary. |
23 | // WIN32: invoke void @"?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}}) |
24 | // If this call throws, we have to cleanup the stacksave. |
25 | // WIN32: call i32 @"?TakesTwo@@YAHUA@@0@Z" |
26 | // WIN32: call void @llvm.stackrestore |
27 | // WIN32: ret void |
28 | // |
29 | // There should be one dtor call for unwinding from the second getA. |
30 | // WIN32: cleanuppad |
31 | // WIN32: call x86_thiscallcc void @"??1A@@QAE@XZ"({{.*}}) |
32 | // WIN32-NOT: @"??1A@@QAE@XZ" |
33 | // WIN32: } |
34 | |
35 | void TakeRef(const A &a); |
36 | int HasDeactivatedCleanups() { |
37 | return TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A())); |
38 | } |
39 | |
40 | // WIN32-LABEL: define dso_local i32 @"?HasDeactivatedCleanups@@YAHXZ"() {{.*}} { |
41 | // WIN32: %[[isactive:.*]] = alloca i1 |
42 | // WIN32: call i8* @llvm.stacksave() |
43 | // WIN32: %[[argmem:.*]] = alloca inalloca [[argmem_ty:<{ %struct.A, %struct.A }>]] |
44 | // WIN32: %[[arg1:.*]] = getelementptr inbounds [[argmem_ty]], [[argmem_ty]]* %[[argmem]], i32 0, i32 1 |
45 | // WIN32: call x86_thiscallcc %struct.A* @"??0A@@QAE@XZ" |
46 | // WIN32: invoke void @"?TakeRef@@YAXABUA@@@Z" |
47 | // |
48 | // WIN32: invoke x86_thiscallcc %struct.A* @"??0A@@QAE@XZ"(%struct.A* %[[arg1]]) |
49 | // WIN32: store i1 true, i1* %[[isactive]] |
50 | // |
51 | // WIN32: %[[arg0:.*]] = getelementptr inbounds [[argmem_ty]], [[argmem_ty]]* %[[argmem]], i32 0, i32 0 |
52 | // WIN32: invoke x86_thiscallcc %struct.A* @"??0A@@QAE@XZ" |
53 | // WIN32: invoke void @"?TakeRef@@YAXABUA@@@Z" |
54 | // WIN32: invoke x86_thiscallcc %struct.A* @"??0A@@QAE@XZ" |
55 | // WIN32: store i1 false, i1* %[[isactive]] |
56 | // |
57 | // WIN32: invoke i32 @"?TakesTwo@@YAHUA@@0@Z"([[argmem_ty]]* inalloca %[[argmem]]) |
58 | // Destroy the two const ref temporaries. |
59 | // WIN32: call x86_thiscallcc void @"??1A@@QAE@XZ"({{.*}}) |
60 | // WIN32: call x86_thiscallcc void @"??1A@@QAE@XZ"({{.*}}) |
61 | // WIN32: ret i32 |
62 | // |
63 | // Conditionally destroy arg1. |
64 | // WIN32: %[[cond:.*]] = load i1, i1* %[[isactive]] |
65 | // WIN32: br i1 %[[cond]] |
66 | // WIN32: call x86_thiscallcc void @"??1A@@QAE@XZ"(%struct.A* %[[arg1]]) |
67 | // WIN32: } |
68 | |
69 | // Test putting the cleanups inside a conditional. |
70 | int CouldThrow(); |
71 | int HasConditionalCleanup(bool cond) { |
72 | return (cond ? TakesTwo(A(), A()) : CouldThrow()); |
73 | } |
74 | |
75 | // WIN32-LABEL: define dso_local i32 @"?HasConditionalCleanup@@YAH_N@Z"(i1 zeroext %{{.*}}) {{.*}} { |
76 | // WIN32: store i1 false |
77 | // WIN32: br i1 |
78 | // WIN32: call i8* @llvm.stacksave() |
79 | // WIN32: call x86_thiscallcc %struct.A* @"??0A@@QAE@XZ"(%struct.A* %{{.*}}) |
80 | // WIN32: store i1 true |
81 | // WIN32: invoke x86_thiscallcc %struct.A* @"??0A@@QAE@XZ"(%struct.A* %{{.*}}) |
82 | // WIN32: call i32 @"?TakesTwo@@YAHUA@@0@Z" |
83 | // |
84 | // WIN32: call void @llvm.stackrestore |
85 | // |
86 | // WIN32: call i32 @"?CouldThrow@@YAHXZ"() |
87 | // |
88 | // Only one dtor in the invoke for arg1 |
89 | // WIN32: call x86_thiscallcc void @"??1A@@QAE@XZ"({{.*}}) |
90 | // WIN32-NOT: invoke x86_thiscallcc void @"??1A@@QAE@XZ" |
91 | // WIN32: } |
92 | |
93 | // Now test both. |
94 | int HasConditionalDeactivatedCleanups(bool cond) { |
95 | return (cond ? TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A())) : CouldThrow()); |
96 | } |
97 | |
98 | // WIN32-O0-LABEL: define dso_local i32 @"?HasConditionalDeactivatedCleanups@@YAH_N@Z"{{.*}} { |
99 | // WIN32-O0: alloca i1 |
100 | // WIN32-O0: %[[arg1_cond:.*]] = alloca i1 |
101 | // Start all four cleanups as deactivated. |
102 | // WIN32-O0: store i1 false |
103 | // WIN32-O0: store i1 false |
104 | // WIN32-O0: store i1 false |
105 | // WIN32-O0: store i1 false |
106 | // WIN32-O0: br i1 |
107 | // True condition. |
108 | // WIN32-O0: call x86_thiscallcc %struct.A* @"??0A@@QAE@XZ" |
109 | // WIN32-O0: store i1 true |
110 | // WIN32-O0: invoke void @"?TakeRef@@YAXABUA@@@Z" |
111 | // WIN32-O0: invoke x86_thiscallcc %struct.A* @"??0A@@QAE@XZ" |
112 | // WIN32-O0: store i1 true, i1* %[[arg1_cond]] |
113 | // WIN32-O0: invoke x86_thiscallcc %struct.A* @"??0A@@QAE@XZ" |
114 | // WIN32-O0: store i1 true |
115 | // WIN32-O0: invoke void @"?TakeRef@@YAXABUA@@@Z" |
116 | // WIN32-O0: invoke x86_thiscallcc %struct.A* @"??0A@@QAE@XZ" |
117 | // WIN32-O0: store i1 true |
118 | // WIN32-O0: store i1 false, i1* %[[arg1_cond]] |
119 | // WIN32-O0: invoke i32 @"?TakesTwo@@YAHUA@@0@Z" |
120 | // False condition. |
121 | // WIN32-O0: invoke i32 @"?CouldThrow@@YAHXZ"() |
122 | // Two normal cleanups for TakeRef args. |
123 | // WIN32-O0: call x86_thiscallcc void @"??1A@@QAE@XZ"({{.*}}) |
124 | // WIN32-O0-NOT: invoke x86_thiscallcc void @"??1A@@QAE@XZ" |
125 | // WIN32-O0: ret i32 |
126 | // |
127 | // Somewhere in the landing pad soup, we conditionally destroy arg1. |
128 | // WIN32-O0: %[[isactive:.*]] = load i1, i1* %[[arg1_cond]] |
129 | // WIN32-O0: br i1 %[[isactive]] |
130 | // WIN32-O0: call x86_thiscallcc void @"??1A@@QAE@XZ"({{.*}}) |
131 | // WIN32-O0: } |
132 | |
133 | // WIN32-O3-LABEL: define dso_local i32 @"?HasConditionalDeactivatedCleanups@@YAH_N@Z"{{.*}} { |
134 | // WIN32-O3: alloca i1 |
135 | // WIN32-O3: alloca i1 |
136 | // WIN32-O3: %[[arg1_cond:.*]] = alloca i1 |
137 | // Start all four cleanups as deactivated. |
138 | // WIN32-O3: store i1 false |
139 | // WIN32-O3: store i1 false |
140 | // WIN32-O3: store i1 false |
141 | // WIN32-O3: store i1 false |
142 | // WIN32-O3: store i1 false |
143 | // WIN32-O3: store i1 false |
144 | // WIN32-O3: br i1 |
145 | // True condition. |
146 | // WIN32-O3: call x86_thiscallcc %struct.A* @"??0A@@QAE@XZ" |
147 | // WIN32-O3: store i1 true |
148 | // WIN32-O3: invoke void @"?TakeRef@@YAXABUA@@@Z" |
149 | // WIN32-O3: invoke x86_thiscallcc %struct.A* @"??0A@@QAE@XZ" |
150 | // WIN32-O3: store i1 true, i1* %[[arg1_cond]] |
151 | // WIN32-O3: invoke x86_thiscallcc %struct.A* @"??0A@@QAE@XZ" |
152 | // WIN32-O3: store i1 true |
153 | // WIN32-O3: invoke void @"?TakeRef@@YAXABUA@@@Z" |
154 | // WIN32-O3: invoke x86_thiscallcc %struct.A* @"??0A@@QAE@XZ" |
155 | // WIN32-O3: store i1 true |
156 | // WIN32-O3: store i1 false, i1* %[[arg1_cond]] |
157 | // WIN32-O3: invoke i32 @"?TakesTwo@@YAHUA@@0@Z" |
158 | // False condition. |
159 | // WIN32-O3: invoke i32 @"?CouldThrow@@YAHXZ"() |
160 | // Two normal cleanups for TakeRef args. |
161 | // WIN32-O3: call x86_thiscallcc void @"??1A@@QAE@XZ"({{.*}}) |
162 | // WIN32-O3-NOT: invoke x86_thiscallcc void @"??1A@@QAE@XZ" |
163 | // WIN32-O3: ret i32 |
164 | // |
165 | // Somewhere in the landing pad soup, we conditionally destroy arg1. |
166 | // WIN32-O3: %[[isactive:.*]] = load i1, i1* %[[arg1_cond]] |
167 | // WIN32-O3: br i1 %[[isactive]] |
168 | // WIN32-O3: call x86_thiscallcc void @"??1A@@QAE@XZ"({{.*}}) |
169 | // WIN32-O3: } |
170 | |
171 | namespace crash_on_partial_destroy { |
172 | struct A { |
173 | virtual ~A(); |
174 | }; |
175 | |
176 | struct B : virtual A { |
177 | // Has an implicit destructor. |
178 | }; |
179 | |
180 | struct C : B { |
181 | C(); |
182 | }; |
183 | |
184 | void foo(); |
185 | // We used to crash when emitting this. |
186 | C::C() { foo(); } |
187 | |
188 | // Verify that we don't bother with a vbtable lookup when adjusting the this |
189 | // pointer to call a base destructor from a constructor while unwinding. |
190 | // WIN32-LABEL: define dso_local {{.*}} @"??0C@crash_on_partial_destroy@@QAE@XZ"{{.*}} { |
191 | // WIN32: cleanuppad |
192 | // |
193 | // We shouldn't do any vbptr loads, just constant GEPs. |
194 | // WIN32-NOT: load |
195 | // WIN32: getelementptr i8, i8* %{{.*}}, i32 4 |
196 | // WIN32-NOT: load |
197 | // WIN32: bitcast i8* %{{.*}} to %"struct.crash_on_partial_destroy::B"* |
198 | // WIN32: call x86_thiscallcc void @"??1B@crash_on_partial_destroy@@UAE@XZ" |
199 | // |
200 | // WIN32-NOT: load |
201 | // WIN32: bitcast %"struct.crash_on_partial_destroy::C"* %{{.*}} to i8* |
202 | // WIN32-NOT: load |
203 | // WIN32: getelementptr inbounds i8, i8* %{{.*}}, i32 4 |
204 | // WIN32-NOT: load |
205 | // WIN32: bitcast i8* %{{.*}} to %"struct.crash_on_partial_destroy::A"* |
206 | // WIN32: call x86_thiscallcc void @"??1A@crash_on_partial_destroy@@UAE@XZ"({{.*}}) |
207 | // WIN32: } |
208 | } |
209 | |
210 | namespace dont_call_terminate { |
211 | struct C { |
212 | ~C(); |
213 | }; |
214 | void g(); |
215 | void f() { |
216 | C c; |
217 | g(); |
218 | } |
219 | |
220 | // WIN32-LABEL: define dso_local void @"?f@dont_call_terminate@@YAXXZ"() |
221 | // WIN32: invoke void @"?g@dont_call_terminate@@YAXXZ"() |
222 | // WIN32-NEXT: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] |
223 | // |
224 | // WIN32: [[cont]] |
225 | // WIN32: call x86_thiscallcc void @"??1C@dont_call_terminate@@QAE@XZ"({{.*}}) |
226 | // |
227 | // WIN32: [[lpad]] |
228 | // WIN32-NEXT: cleanuppad |
229 | // WIN32: call x86_thiscallcc void @"??1C@dont_call_terminate@@QAE@XZ"({{.*}}) |
230 | } |
231 | |
232 | namespace noexcept_false_dtor { |
233 | struct D { |
234 | ~D() noexcept(false); |
235 | }; |
236 | void f() { |
237 | D d; |
238 | CouldThrow(); |
239 | } |
240 | } |
241 | |
242 | // WIN32-LABEL: define dso_local void @"?f@noexcept_false_dtor@@YAXXZ"() |
243 | // WIN32: invoke i32 @"?CouldThrow@@YAHXZ"() |
244 | // WIN32: call x86_thiscallcc void @"??1D@noexcept_false_dtor@@QAE@XZ"(%"struct.noexcept_false_dtor::D"* %{{.*}}) |
245 | // WIN32: cleanuppad |
246 | // WIN32: call x86_thiscallcc void @"??1D@noexcept_false_dtor@@QAE@XZ"(%"struct.noexcept_false_dtor::D"* %{{.*}}) |
247 | // WIN32: cleanupret |
248 | |
249 | namespace lifetime_marker { |
250 | struct C { |
251 | ~C(); |
252 | }; |
253 | void g(); |
254 | void f() { |
255 | C c; |
256 | g(); |
257 | } |
258 | |
259 | // WIN32-LIFETIME-LABEL: define dso_local void @"?f@lifetime_marker@@YAXXZ"() |
260 | // WIN32-LIFETIME: %[[c:.*]] = alloca %"struct.lifetime_marker::C" |
261 | // WIN32-LIFETIME: %[[bc0:.*]] = bitcast %"struct.lifetime_marker::C"* %c to i8* |
262 | // WIN32-LIFETIME: call void @llvm.lifetime.start.p0i8(i64 1, i8* %[[bc0]]) |
263 | // WIN32-LIFETIME: invoke void @"?g@lifetime_marker@@YAXXZ"() |
264 | // WIN32-LIFETIME-NEXT: to label %[[cont:[^ ]*]] unwind label %[[lpad0:[^ ]*]] |
265 | // |
266 | // WIN32-LIFETIME: [[cont]] |
267 | // WIN32-LIFETIME: call x86_thiscallcc void @"??1C@lifetime_marker@@QAE@XZ"({{.*}}) |
268 | // WIN32-LIFETIME: %[[bc1:.*]] = bitcast %"struct.lifetime_marker::C"* %[[c]] to i8* |
269 | // WIN32-LIFETIME: call void @llvm.lifetime.end.p0i8(i64 1, i8* %[[bc1]]) |
270 | // |
271 | // WIN32-LIFETIME: [[lpad0]] |
272 | // WIN32-LIFETIME-NEXT: cleanuppad |
273 | // WIN32-LIFETIME: call x86_thiscallcc void @"??1C@lifetime_marker@@QAE@XZ"({{.*}}) |
274 | // WIN32-LIFETIME: cleanupret {{.*}} unwind label %[[lpad1:[^ ]*]] |
275 | // |
276 | // WIN32-LIFETIME: [[lpad1]] |
277 | // WIN32-LIFETIME-NEXT: cleanuppad |
278 | // WIN32-LIFETIME: %[[bc2:.*]] = bitcast %"struct.lifetime_marker::C"* %[[c]] to i8* |
279 | // WIN32-LIFETIME: call void @llvm.lifetime.end.p0i8(i64 1, i8* %[[bc2]]) |
280 | } |
281 | |
282 | struct class_2 { |
283 | class_2(); |
284 | virtual ~class_2(); |
285 | }; |
286 | struct class_1 : virtual class_2 { |
287 | class_1(){throw "Unhandled exception";} |
288 | virtual ~class_1() {} |
289 | }; |
290 | struct class_0 : class_1 { |
291 | class_0() ; |
292 | virtual ~class_0() {} |
293 | }; |
294 | |
295 | class_0::class_0() { |
296 | // WIN32: define dso_local x86_thiscallcc %struct.class_0* @"??0class_0@@QAE@XZ"(%struct.class_0* returned %this, i32 %is_most_derived) |
297 | // WIN32: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4 |
298 | // WIN32: %[[IS_MOST_DERIVED_VAL:.*]] = load i32, i32* %[[IS_MOST_DERIVED_VAR]] |
299 | // WIN32: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0 |
300 | // WIN32: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]] |
301 | // WIN32: [[INIT_VBASES]] |
302 | // WIN32: br label %[[SKIP_VBASES]] |
303 | // WIN32: [[SKIP_VBASES]] |
304 | // ehcleanup: |
305 | // WIN32: %[[CLEANUPPAD:.*]] = cleanuppad within none [] |
306 | // WIN32-NEXT: bitcast %{{.*}}* %{{.*}} to i8* |
307 | // WIN32-NEXT: getelementptr inbounds i8, i8* %{{.*}}, i{{.*}} {{.}} |
308 | // WIN32-NEXT: bitcast i8* %{{.*}} to %{{.*}}* |
309 | // WIN32-NEXT: %[[SHOULD_CALL_VBASE_DTOR:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0 |
310 | // WIN32-NEXT: br i1 %[[SHOULD_CALL_VBASE_DTOR]], label %[[DTOR_VBASE:.*]], label %[[SKIP_VBASE:.*]] |
311 | // WIN32: [[DTOR_VBASE]] |
312 | // WIN32-NEXT: call x86_thiscallcc void @"??1class_2@@UAE@XZ" |
313 | // WIN32: br label %[[SKIP_VBASE]] |
314 | // WIN32: [[SKIP_VBASE]] |
315 | } |
316 | |
317 | namespace PR37146 { |
318 | // Check that IRGen doesn't emit calls to synthesized destructors for |
319 | // non-trival C structs. |
320 | |
321 | // WIN32: define dso_local void @"?test@PR37146@@YAXXZ"() |
322 | // WIN32: call void @llvm.memset.p0i8.i32( |
323 | // WIN32: call i32 @"?getS@PR37146@@YA?AUS@1@XZ"( |
324 | // WIN32: call void @"?func@PR37146@@YAXUS@1@0@Z"( |
325 | // WIN32-NEXT: ret void |
326 | // WIN32-NEXT: {{^}$}} |
327 | |
328 | struct S { |
329 | int f; |
330 | }; |
331 | |
332 | void func(S, S); |
333 | S getS(); |
334 | |
335 | void test() { |
336 | func(getS(), S()); |
337 | } |
338 | |
339 | } |
340 | |