[LoongArch][Clang] Make the parameters and return value of {x,}vorn.v builti ns ...
[llvm-project.git] / clang / test / CodeGenCXX / control-flow-in-stmt-expr.cpp
blob4eafa720e0cb41b0248835a9475ae2cbb08399a5
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
4 struct Printy {
5 Printy(const char *name) : name(name) {}
6 ~Printy() {}
7 const char *name;
8 };
10 int foo() { return 2; }
12 struct Printies {
13 Printy a;
14 Printy b;
15 Printy c;
18 void ParenInit() {
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
24 if (foo()) return;
25 // CHECK: if.then:
26 // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST]], align 4
27 // CHECK-NEXT: br label %cleanup
28 Printy("b");
29 // CHECK: if.end:
30 // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
31 }),
33 if (foo()) return;
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
38 Printy("c");
39 // CHECK: if.end{{.*}}:
40 // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
41 // CHECK-NEXT: call void @_ZN8PrintiesD1Ev
42 // CHECK-NEXT: br label %return
43 }));
44 // CHECK: cleanup:
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
56 for (;;) {
57 Printies ps{
58 Printy("b"),
59 // CHECK: for.cond:
60 // CHECK: call void @_ZN6PrintyC1EPKc
62 if (foo()) {
63 break;
64 // CHECK: if.then:
65 // CHECK-NEXT: call void @_ZN6PrintyD1Ev
66 // CHECK-NEXT: br label %for.end
68 Printy("c");
69 // CHECK: if.end:
70 // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
71 }),
72 Printy("d")};
73 // CHECK: call void @_ZN6PrintyC1EPKc
74 // CHECK-NEXT: call void @_ZN8PrintiesD1Ev
75 // CHECK-NEXT: br label %for.cond
77 Printy("e");
78 // CHECK: for.end:
79 // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
80 }),
81 Printy("f")};
82 // CHECK: call void @_ZN6PrintyC1EPKc
83 // CHECK-NEXT: call void @_ZN8PrintiesD1Ev
86 void goto_in_stmt_expr() {
87 // Verify that:
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
99 if (foo() == 1) {
100 goto in;
101 // CHECK: if.then:
102 // CHECK-NEXT: store i32 2, ptr [[CLEANUP_DEST_SLOT]], align 4
103 // CHECK-NEXT: br label %[[CLEANUP1:.+]]
105 if (foo() == 2) {
106 goto out;
107 // CHECK: if.then{{.*}}:
108 // CHECK-NEXT: store i32 3, ptr [[CLEANUP_DEST_SLOT]], align 4
109 // CHECK-NEXT: br label %[[CLEANUP1]]
111 Printy("c");
112 // CHECK: if.end{{.*}}:
113 // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
115 Printy("d")};
116 // CHECK: call void @_ZN6PrintyC1EPKc
117 // CHECK-NEXT: call void @_ZN8PrintiesD1Ev
118 // CHECK-NEXT: br label %in
122 Printy("e");
123 // CHECK: in: ; preds = %if.end{{.*}}, %[[CLEANUP1]]
124 // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
126 Printy("f")};
127 // CHECK: call void @_ZN6PrintyC1EPKc
128 // CHECK-NEXT: call void @_ZN8PrintiesD1Ev
129 // CHECK-NEXT: br label %out
131 out:
132 return;
133 // CHECK: 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
141 // CHECK-NEXT: ]
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
148 // CHECK-NEXT: ]
151 void ArrayInit() {
152 // Printy arr[4] = {ctorA, ctorB, stmt-exprC, stmt-exprD};
153 // Verify that:
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
162 Printy arr[4] = {
163 Printy("a"),
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
167 Printy("b"),
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
173 if (foo()) {
174 return;
175 // CHECK: if.then:
176 // CHECK-NEXT: store i32 1, ptr %cleanup.dest.slot, align 4
177 // CHECK-NEXT: br label %cleanup
179 // CHECK: if.end:
180 Printy("c");
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:.+]]
187 if (foo()) {
188 return;
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]]:
194 Printy("d");
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
212 // CHECK: cleanup:
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() {
229 struct S {
230 Printy arr1[2];
231 Printy arr2[2];
232 Printy p;
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
239 {Printy("a"),
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
245 if (foo()) {
246 return;
247 // CHECK: if.then:
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:.+]]
252 Printy("b");
255 Printy("c")
256 // CHECK: if.end:
257 // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
258 // CHECK: call void @_ZN6PrintyC1EPKc
259 // CHECK-NEXT: call void @_ZZ15ArraySubobjectsvEN1SD1Ev
260 // CHECK-NEXT: br label %return
262 // CHECK: 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
289 void LambdaInit() {
290 // CHECK-LABEL: define dso_local void @_Z10LambdaInitv()
291 auto S = [a = Printy("a"), b = ({
292 if (foo()) {
293 return;
294 // CHECK: if.then:
295 // CHECK-NEXT: call void @_ZN6PrintyD1Ev
296 // CHECK-NEXT: br label %return
298 Printy("b");
299 })]() { return a; };
302 struct PrintyRefBind {
303 const Printy &a;
304 const Printy &b;
307 struct Temp {
308 Temp();
309 ~Temp();
311 Temp CreateTemp();
312 Printy CreatePrinty();
313 Printy CreatePrinty(const Temp&);
315 void LifetimeExtended() {
316 // CHECK-LABEL: define dso_local void @_Z16LifetimeExtendedv
317 PrintyRefBind ps = {Printy("a"), ({
318 if (foo()) {
319 return;
320 // CHECK: if.then:
321 // CHECK-NEXT: call void @_ZN6PrintyD1Ev
322 // CHECK-NEXT: br label %return
324 Printy("b");
325 })};
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
341 PrintyRefBind ps = {
342 p1 != nullptr ? static_cast<const Printy&>(CreatePrinty())
343 // CHECK: cond.true:
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()))
349 : *p1,
351 if (foo()) return;
352 Printy("c");
353 // CHECK: if.end:
354 // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
355 // CHECK-NEXT: store ptr
356 })};
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]{
368 "a",
369 // CHECK: call void @_ZN6PrintyC1EPKc
370 // CHECK: store ptr %array.exp.next, ptr %array.init.end, align 8
371 "b",
372 // CHECK: call void @_ZN6PrintyC1EPKc
373 // CHECK: store ptr %array.exp.next1, ptr %array.init.end, align 8
375 if (foo()) {
376 return;
377 // CHECK: if.then:
378 // CHECK: br i1 %arraydestroy.isempty, label %arraydestroy.done{{.*}}, label %arraydestroy.body
380 "b";
381 // CHECK: if.end:
382 // CHECK: call void @_ZN6PrintyC1EPKc
383 })};
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()
398 struct A {
399 A() {}
400 ~A() {}
403 struct Value {
404 Value(A) {}
405 ~Value() {}
408 struct V2 {
409 Value K;
410 Value V;
412 // Verify we use conditional cleanups.
413 (void)(foo() ? V2{A(), A()} : V2{A(), A()});
414 // NOEH: cond.true:
415 // NOEH: call void @_ZZ27DestroyInConditionalCleanupvEN1AC1Ev
416 // NOEH: store ptr %{{.*}}, ptr %cond-cleanup.save
418 // EH: cond.true:
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", ({
429 if (foo()) {
430 continue;
432 "b";
433 })};
437 struct [[clang::trivial_abi]] HasTrivialABI {
438 HasTrivialABI();
439 ~HasTrivialABI();
441 void AcceptTrivialABI(HasTrivialABI, int);
442 void TrivialABI() {
443 // CHECK-LABEL: define dso_local void @_Z10TrivialABIv()
444 AcceptTrivialABI(HasTrivialABI(), ({
445 if (foo()) return;
446 // CHECK: if.then:
447 // CHECK-NEXT: call void @_ZN13HasTrivialABID1Ev
448 // CHECK-NEXT: br label %return
450 }));
453 namespace CleanupFlag {
454 struct A {
455 A() {}
456 ~A() {}
459 struct B {
460 B(const A&) {}
461 B() {}
462 ~B() {}
465 struct S {
466 A a;
467 B b;
470 int AcceptS(S s);
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{}}), ({
489 if (foo()) return;
490 // CHECK: if.then:
491 // CHECK: br label %cleanup
493 // CHECK: if.end:
494 // CHECK: call void [[ACCEPT2:@.*Accept2Eii]]
495 // CHECK: br label %cleanup
496 }));
497 // CHECK: 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