1 // RUN: %clang_cc1 --std=c++20 -fexceptions -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck -check-prefixes=EH %s
2 // RUN: %clang_cc1 --std=c++20 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck -check-prefixes=NOEH,CHECK %s
5 Printy(const char *name
) : name(name
) {}
10 int foo() { return 2; }
19 // CHECK-LABEL: define dso_local void @_Z9ParenInitv()
20 // CHECK: [[CLEANUP_DEST:%.+]] = alloca i32, align 4
21 Printies
ps(Printy("a"),
22 // CHECK: call void @_ZN6PrintyC1EPKc
26 // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST]], align 4
27 // CHECK-NEXT: br label %cleanup
30 // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
34 // CHECK: if.then{{.*}}:
35 // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST]], align 4
36 // CHECK-NEXT: call void @_ZN6PrintyD1Ev
37 // CHECK-NEXT: br label %cleanup
39 // CHECK: if.end{{.*}}:
40 // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
41 // CHECK-NEXT: call void @_ZN8PrintiesD1Ev
42 // CHECK-NEXT: br label %return
45 // CHECK-NEXT: call void @_ZN6PrintyD1Ev
46 // CHECK-NEXT: br label %return
49 void break_in_stmt_expr() {
50 // Verify that the "break" in "if.then".calls dtor before jumping to "for.end".
52 // CHECK-LABEL: define dso_local void @_Z18break_in_stmt_exprv()
53 Printies p
{Printy("a"),
54 // CHECK: call void @_ZN6PrintyC1EPKc
60 // CHECK: call void @_ZN6PrintyC1EPKc
65 // CHECK-NEXT: call void @_ZN6PrintyD1Ev
66 // CHECK-NEXT: br label %for.end
70 // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
73 // CHECK: call void @_ZN6PrintyC1EPKc
74 // CHECK-NEXT: call void @_ZN8PrintiesD1Ev
75 // CHECK-NEXT: br label %for.cond
79 // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
82 // CHECK: call void @_ZN6PrintyC1EPKc
83 // CHECK-NEXT: call void @_ZN8PrintiesD1Ev
86 void goto_in_stmt_expr() {
88 // - correct branch fixups for deactivated normal cleanups are generated correctly.
90 // CHECK-LABEL: define dso_local void @_Z17goto_in_stmt_exprv()
91 // CHECK: [[CLEANUP_DEST_SLOT:%cleanup.dest.slot.*]] = alloca i32, align 4
93 Printies p1
{Printy("a"), // CHECK: call void @_ZN6PrintyC1EPKc
96 Printies p2
{Printy("b"),
97 // CHECK: call void @_ZN6PrintyC1EPKc
102 // CHECK-NEXT: store i32 2, ptr [[CLEANUP_DEST_SLOT]], align 4
103 // CHECK-NEXT: br label %[[CLEANUP1:.+]]
107 // CHECK: if.then{{.*}}:
108 // CHECK-NEXT: store i32 3, ptr [[CLEANUP_DEST_SLOT]], align 4
109 // CHECK-NEXT: br label %[[CLEANUP1]]
112 // CHECK: if.end{{.*}}:
113 // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
116 // CHECK: call void @_ZN6PrintyC1EPKc
117 // CHECK-NEXT: call void @_ZN8PrintiesD1Ev
118 // CHECK-NEXT: br label %in
123 // CHECK: in: ; preds = %if.end{{.*}}, %[[CLEANUP1]]
124 // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
127 // CHECK: call void @_ZN6PrintyC1EPKc
128 // CHECK-NEXT: call void @_ZN8PrintiesD1Ev
129 // CHECK-NEXT: br label %out
134 // CHECK-NEXT: ret void
136 // CHECK: [[CLEANUP1]]: ; preds = %if.then{{.*}}, %if.then
137 // CHECK-NEXT: call void @_ZN6PrintyD1Ev
138 // CHECK-NEXT: %cleanup.dest = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4
139 // CHECK-NEXT: switch i32 %cleanup.dest, label %[[CLEANUP2:.+]] [
140 // CHECK-NEXT: i32 2, label %in
143 // CHECK: [[CLEANUP2]]: ; preds = %[[CLEANUP1]]
144 // CHECK-NEXT: call void @_ZN6PrintyD1Ev
145 // CHECK-NEXT: %cleanup.dest{{.*}} = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4
146 // CHECK-NEXT: switch i32 %cleanup.dest{{.*}}, label %unreachable [
147 // CHECK-NEXT: i32 3, label %out
152 // Printy arr[4] = {ctorA, ctorB, stmt-exprC, stmt-exprD};
154 // - We do the necessary stores for array cleanups (endOfInit and last constructed element).
155 // - We update the array init element correctly for ctorA, ctorB and stmt-exprC.
156 // - stmt-exprC and stmt-exprD share the array body dtor code (see %cleanup).
158 // CHECK-LABEL: define dso_local void @_Z9ArrayInitv()
159 // CHECK: %arrayinit.endOfInit = alloca ptr, align 8
160 // CHECK: %cleanup.dest.slot = alloca i32, align 4
161 // CHECK: store ptr %arr, ptr %arrayinit.endOfInit, align 8
164 // CHECK: call void @_ZN6PrintyC1EPKc(ptr noundef nonnull align 8 dereferenceable(8) %arr, ptr noundef @.str)
165 // CHECK: [[ARRAYINIT_ELEMENT1:%.+]] = getelementptr inbounds %struct.Printy, ptr %arr, i64 1
166 // CHECK: store ptr [[ARRAYINIT_ELEMENT1]], ptr %arrayinit.endOfInit, align 8
168 // CHECK: call void @_ZN6PrintyC1EPKc(ptr noundef nonnull align 8 dereferenceable(8) [[ARRAYINIT_ELEMENT1]], ptr noundef @.str.1)
169 // CHECK: [[ARRAYINIT_ELEMENT2:%.+]] = getelementptr inbounds %struct.Printy, ptr %arr, i64 2
170 // CHECK: store ptr [[ARRAYINIT_ELEMENT2]], ptr %arrayinit.endOfInit, align 8
172 // CHECK: br i1 {{.*}}, label %if.then, label %if.end
176 // CHECK-NEXT: store i32 1, ptr %cleanup.dest.slot, align 4
177 // CHECK-NEXT: br label %cleanup
181 // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
182 // CHECK-NEXT: %arrayinit.element2 = getelementptr inbounds %struct.Printy, ptr %arr, i64 3
183 // CHECK-NEXT: store ptr %arrayinit.element2, ptr %arrayinit.endOfInit, align 8
186 // CHECK: br i1 {{%.+}} label %[[IF_THEN2:.+]], label %[[IF_END2:.+]]
189 // CHECK: [[IF_THEN2]]:
190 // CHECK-NEXT: store i32 1, ptr %cleanup.dest.slot, align 4
191 // CHECK-NEXT: br label %cleanup
193 // CHECK: [[IF_END2]]:
195 // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
196 // CHECK-NEXT: %array.begin = getelementptr inbounds [4 x %struct.Printy], ptr %arr, i32 0, i32 0
197 // CHECK-NEXT: %0 = getelementptr inbounds %struct.Printy, ptr %array.begin, i64 4
198 // CHECK-NEXT: br label %[[ARRAY_DESTROY_BODY1:.+]]
202 // CHECK: [[ARRAY_DESTROY_BODY1]]:
203 // CHECK-NEXT: %arraydestroy.elementPast{{.*}} = phi ptr [ %0, %[[IF_END2]] ], [ %arraydestroy.element{{.*}}, %[[ARRAY_DESTROY_BODY1]] ]
204 // CHECK-NEXT: %arraydestroy.element{{.*}} = getelementptr inbounds %struct.Printy, ptr %arraydestroy.elementPast{{.*}}, i64 -1
205 // CHECK-NEXT: call void @_ZN6PrintyD1Ev
206 // CHECK-NEXT: %arraydestroy.done{{.*}} = icmp eq ptr %arraydestroy.element{{.*}}, %array.begin
207 // CHECK-NEXT: br i1 %arraydestroy.done{{.*}}, label %[[ARRAY_DESTROY_DONE1:.+]], label %[[ARRAY_DESTROY_BODY1]]
209 // CHECK: [[ARRAY_DESTROY_DONE1]]:
210 // CHECK-NEXT: ret void
213 // CHECK-NEXT: %1 = load ptr, ptr %arrayinit.endOfInit, align 8
214 // CHECK-NEXT: %arraydestroy.isempty = icmp eq ptr %arr, %1
215 // CHECK-NEXT: br i1 %arraydestroy.isempty, label %[[ARRAY_DESTROY_DONE2:.+]], label %[[ARRAY_DESTROY_BODY2:.+]]
217 // CHECK: [[ARRAY_DESTROY_BODY2]]:
218 // CHECK-NEXT: %arraydestroy.elementPast = phi ptr [ %1, %cleanup ], [ %arraydestroy.element, %[[ARRAY_DESTROY_BODY2]] ]
219 // CHECK-NEXT: %arraydestroy.element = getelementptr inbounds %struct.Printy, ptr %arraydestroy.elementPast, i64 -1
220 // CHECK-NEXT: call void @_ZN6PrintyD1Ev(ptr noundef nonnull align 8 dereferenceable(8) %arraydestroy.element)
221 // CHECK-NEXT: %arraydestroy.done = icmp eq ptr %arraydestroy.element, %arr
222 // CHECK-NEXT: br i1 %arraydestroy.done, label %[[ARRAY_DESTROY_DONE2]], label %[[ARRAY_DESTROY_BODY2]]
224 // CHECK: [[ARRAY_DESTROY_DONE2]]:
225 // CHECK-NEXT: br label %[[ARRAY_DESTROY_DONE1]]
228 void ArraySubobjects() {
234 // CHECK-LABEL: define dso_local void @_Z15ArraySubobjectsv()
235 // CHECK: %arrayinit.endOfInit = alloca ptr, align 8
236 S s
{{Printy("a"), Printy("b")},
237 // CHECK: call void @_ZN6PrintyC1EPKc
238 // CHECK: call void @_ZN6PrintyC1EPKc
240 // CHECK: store ptr %arr2, ptr %arrayinit.endOfInit, align 8
241 // CHECK: call void @_ZN6PrintyC1EPKc
242 // CHECK: [[ARRAYINIT_ELEMENT:%.+]] = getelementptr inbounds %struct.Printy
243 // CHECK: store ptr [[ARRAYINIT_ELEMENT]], ptr %arrayinit.endOfInit, align 8
248 // CHECK-NEXT: [[V0:%.+]] = load ptr, ptr %arrayinit.endOfInit, align 8
249 // CHECK-NEXT: %arraydestroy.isempty = icmp eq ptr %arr2, [[V0]]
250 // CHECK-NEXT: br i1 %arraydestroy.isempty, label %[[ARRAY_DESTROY_DONE:.+]], label %[[ARRAY_DESTROY_BODY:.+]]
257 // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
258 // CHECK: call void @_ZN6PrintyC1EPKc
259 // CHECK-NEXT: call void @_ZZ15ArraySubobjectsvEN1SD1Ev
260 // CHECK-NEXT: br label %return
263 // CHECK-NEXT: ret void
265 // CHECK: [[ARRAY_DESTROY_BODY]]:
266 // CHECK-NEXT: %arraydestroy.elementPast = phi ptr [ %0, %if.then ], [ %arraydestroy.element, %[[ARRAY_DESTROY_BODY]] ]
267 // CHECK-NEXT: %arraydestroy.element = getelementptr inbounds %struct.Printy, ptr %arraydestroy.elementPast, i64 -1
268 // CHECK-NEXT: call void @_ZN6PrintyD1Ev(ptr noundef nonnull align 8 dereferenceable(8) %arraydestroy.element)
269 // CHECK-NEXT: %arraydestroy.done = icmp eq ptr %arraydestroy.element, %arr2
270 // CHECK-NEXT: br i1 %arraydestroy.done, label %[[ARRAY_DESTROY_DONE]], label %[[ARRAY_DESTROY_BODY]]
272 // CHECK: [[ARRAY_DESTROY_DONE]]
273 // CHECK-NEXT: [[ARRAY_BEGIN:%.+]] = getelementptr inbounds [2 x %struct.Printy], ptr %arr1, i32 0, i32 0
274 // CHECK-NEXT: [[V1:%.+]] = getelementptr inbounds %struct.Printy, ptr [[ARRAY_BEGIN]], i64 2
275 // CHECK-NEXT: br label %[[ARRAY_DESTROY_BODY2:.+]]
277 // CHECK: [[ARRAY_DESTROY_BODY2]]:
278 // CHECK-NEXT: %arraydestroy.elementPast4 = phi ptr [ %1, %[[ARRAY_DESTROY_DONE]] ], [ %arraydestroy.element5, %[[ARRAY_DESTROY_BODY2]] ]
279 // CHECK-NEXT: %arraydestroy.element5 = getelementptr inbounds %struct.Printy, ptr %arraydestroy.elementPast4, i64 -1
280 // CHECK-NEXT: call void @_ZN6PrintyD1Ev(ptr noundef nonnull align 8 dereferenceable(8) %arraydestroy.element5)
281 // CHECK-NEXT: %arraydestroy.done6 = icmp eq ptr %arraydestroy.element5, [[ARRAY_BEGIN]]
282 // CHECK-NEXT: br i1 %arraydestroy.done6, label %[[ARRAY_DESTROY_DONE2:.+]], label %[[ARRAY_DESTROY_BODY2]]
285 // CHECK: [[ARRAY_DESTROY_DONE2]]:
286 // CHECK-NEXT: br label %return
290 // CHECK-LABEL: define dso_local void @_Z10LambdaInitv()
291 auto S
= [a
= Printy("a"), b
= ({
295 // CHECK-NEXT: call void @_ZN6PrintyD1Ev
296 // CHECK-NEXT: br label %return
302 struct PrintyRefBind
{
312 Printy
CreatePrinty();
313 Printy
CreatePrinty(const Temp
&);
315 void LifetimeExtended() {
316 // CHECK-LABEL: define dso_local void @_Z16LifetimeExtendedv
317 PrintyRefBind ps
= {Printy("a"), ({
321 // CHECK-NEXT: call void @_ZN6PrintyD1Ev
322 // CHECK-NEXT: br label %return
328 void ConditionalLifetimeExtended() {
329 // CHECK-LABEL: @_Z27ConditionalLifetimeExtendedv()
331 // Verify that we create two cleanup flags.
332 // 1. First for the cleanup which is deactivated after full expression.
333 // 2. Second for the life-ext cleanup which is activated if the branch is taken.
335 // Note: We use `CreateTemp()` to ensure that life-ext destroy cleanup is not at
336 // the top of EHStack on deactivation. This ensures using active flags.
338 Printy
* p1
= nullptr;
339 // CHECK: store i1 false, ptr [[BRANCH1_DEFERRED:%cleanup.cond]], align 1
340 // CHECK-NEXT: store i1 false, ptr [[BRANCH1_LIFEEXT:%cleanup.cond.*]], align 1
342 p1
!= nullptr ? static_cast<const Printy
&>(CreatePrinty())
344 // CHECK-NEXT: call void @_Z12CreatePrintyv
345 // CHECK-NEXT: store i1 true, ptr [[BRANCH1_DEFERRED]], align 1
346 // CHECK-NEXT: store i1 true, ptr [[BRANCH1_LIFEEXT]], align 1
347 // CHECK-NEXT: br label %{{.*}}
348 : foo() ? static_cast<const Printy
&>(CreatePrinty(CreateTemp()))
354 // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
355 // CHECK-NEXT: store ptr
357 // CHECK-NEXT: store i1 false, ptr [[BRANCH1_DEFERRED]], align 1
358 // CHECK-NEXT: store i32 0, ptr %cleanup.dest.slot, align 4
359 // CHECK-NEXT: br label %cleanup
363 void NewArrayInit() {
364 // CHECK-LABEL: define dso_local void @_Z12NewArrayInitv()
365 // CHECK: %array.init.end = alloca ptr, align 8
366 // CHECK: store ptr %0, ptr %array.init.end, align 8
367 Printy
*array
= new Printy
[3]{
369 // CHECK: call void @_ZN6PrintyC1EPKc
370 // CHECK: store ptr %array.exp.next, ptr %array.init.end, align 8
372 // CHECK: call void @_ZN6PrintyC1EPKc
373 // CHECK: store ptr %array.exp.next1, ptr %array.init.end, align 8
378 // CHECK: br i1 %arraydestroy.isempty, label %arraydestroy.done{{.*}}, label %arraydestroy.body
382 // CHECK: call void @_ZN6PrintyC1EPKc
384 // CHECK: arraydestroy.body:
385 // CHECK-NEXT: %arraydestroy.elementPast = phi ptr [ %{{.*}}, %if.then ], [ %arraydestroy.element, %arraydestroy.body ]
386 // CHECK-NEXT: %arraydestroy.element = getelementptr inbounds %struct.Printy, ptr %arraydestroy.elementPast, i64 -1
387 // CHECK-NEXT: call void @_ZN6PrintyD1Ev(ptr noundef nonnull align 8 dereferenceable(8) %arraydestroy.element)
388 // CHECK-NEXT: %arraydestroy.done = icmp eq ptr %arraydestroy.element, %0
389 // CHECK-NEXT: br i1 %arraydestroy.done, label %arraydestroy.done{{.*}}, label %arraydestroy.body
391 // CHECK: arraydestroy.done{{.*}}: ; preds = %arraydestroy.body, %if.then
392 // CHECK-NEXT: br label %return
395 void DestroyInConditionalCleanup() {
396 // EH-LABEL: DestroyInConditionalCleanupv()
397 // NOEH-LABEL: DestroyInConditionalCleanupv()
412 // Verify we use conditional cleanups.
413 (void)(foo() ? V2
{A(), A()} : V2
{A(), A()});
415 // NOEH: call void @_ZZ27DestroyInConditionalCleanupvEN1AC1Ev
416 // NOEH: store ptr %{{.*}}, ptr %cond-cleanup.save
419 // EH: invoke void @_ZZ27DestroyInConditionalCleanupvEN1AC1Ev
420 // EH: store ptr %{{.*}}, ptr %cond-cleanup.save
423 void ArrayInitWithContinue() {
424 // CHECK-LABEL: @_Z21ArrayInitWithContinuev
425 // Verify that we start to emit the array destructor.
426 // CHECK: %arrayinit.endOfInit = alloca ptr, align 8
427 for (int i
= 0; i
< 1; ++i
) {
428 Printy arr
[2] = {"a", ({
437 struct [[clang::trivial_abi
]] HasTrivialABI
{
441 void AcceptTrivialABI(HasTrivialABI
, int);
443 // CHECK-LABEL: define dso_local void @_Z10TrivialABIv()
444 AcceptTrivialABI(HasTrivialABI(), ({
447 // CHECK-NEXT: call void @_ZN13HasTrivialABID1Ev
448 // CHECK-NEXT: br label %return
453 namespace CleanupFlag
{
472 void Accept2(int x
, int y
);
474 void InactiveNormalCleanup() {
475 // CHECK-LABEL: define {{.*}}InactiveNormalCleanupEv()
477 // The first A{} below is an inactive normal cleanup which
478 // is not popped from EHStack on deactivation. This needs an
479 // "active" cleanup flag.
481 // CHECK: [[ACTIVE:%cleanup.isactive.*]] = alloca i1, align 1
482 // CHECK: call void [[A_CTOR:@.*AC1Ev]]
483 // CHECK: store i1 true, ptr [[ACTIVE]], align 1
484 // CHECK: call void [[A_CTOR]]
485 // CHECK: call void [[B_CTOR:@.*BC1ERKNS_1AE]]
486 // CHECK: store i1 false, ptr [[ACTIVE]], align 1
487 // CHECK: call noundef i32 [[ACCEPTS:@.*AcceptSENS_1SE]]
488 Accept2(AcceptS({.a
= A
{}, .b
= A
{}}), ({
491 // CHECK: br label %cleanup
494 // CHECK: call void [[ACCEPT2:@.*Accept2Eii]]
495 // CHECK: br label %cleanup
498 // CHECK: call void [[S_DTOR:@.*SD1Ev]]
499 // CHECK: call void [[A_DTOR:@.*AD1Ev]]
500 // CHECK: %cleanup.is_active = load i1, ptr [[ACTIVE]]
501 // CHECK: br i1 %cleanup.is_active, label %cleanup.action, label %cleanup.done
503 // CHECK: cleanup.action:
504 // CHECK: call void [[A_DTOR]]
506 // The "active" cleanup flag is not required for unused cleanups.
507 Accept2(AcceptS({.a
= A
{}, .b
= A
{}}), 0);
508 // CHECK: cleanup.cont:
509 // CHECK: call void [[A_CTOR]]
510 // CHECK-NOT: store i1 true
511 // CHECK: call void [[A_CTOR]]
512 // CHECK: call void [[B_CTOR]]
513 // CHECK-NOT: store i1 false
514 // CHECK: call noundef i32 [[ACCEPTS]]
515 // CHECK: call void [[ACCEPT2]]
516 // CHECK: call void [[S_DTOR]]
517 // CHECK: call void [[A_DTOR]]
518 // CHECK: br label %return
520 } // namespace CleanupFlag