1d72146f4SUtkarsh Saxena // RUN: %clang_cc1 --std=c++20 -fexceptions -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck -check-prefixes=EH %s
2d72146f4SUtkarsh Saxena // RUN: %clang_cc1 --std=c++20 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck -check-prefixes=NOEH,CHECK %s
3d72146f4SUtkarsh Saxena
4d72146f4SUtkarsh Saxena struct Printy {
PrintyPrinty5d72146f4SUtkarsh Saxena Printy(const char *name) : name(name) {}
~PrintyPrinty6d72146f4SUtkarsh Saxena ~Printy() {}
7d72146f4SUtkarsh Saxena const char *name;
8d72146f4SUtkarsh Saxena };
9d72146f4SUtkarsh Saxena
foo()10d72146f4SUtkarsh Saxena int foo() { return 2; }
11d72146f4SUtkarsh Saxena
12d72146f4SUtkarsh Saxena struct Printies {
13d72146f4SUtkarsh Saxena Printy a;
14d72146f4SUtkarsh Saxena Printy b;
15d72146f4SUtkarsh Saxena Printy c;
16d72146f4SUtkarsh Saxena };
17d72146f4SUtkarsh Saxena
ParenInit()18d72146f4SUtkarsh Saxena void ParenInit() {
19d72146f4SUtkarsh Saxena // CHECK-LABEL: define dso_local void @_Z9ParenInitv()
20d72146f4SUtkarsh Saxena // CHECK: [[CLEANUP_DEST:%.+]] = alloca i32, align 4
21d72146f4SUtkarsh Saxena Printies ps(Printy("a"),
22d72146f4SUtkarsh Saxena // CHECK: call void @_ZN6PrintyC1EPKc
23d72146f4SUtkarsh Saxena ({
24d72146f4SUtkarsh Saxena if (foo()) return;
25d72146f4SUtkarsh Saxena // CHECK: if.then:
26d72146f4SUtkarsh Saxena // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST]], align 4
27d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %cleanup
28d72146f4SUtkarsh Saxena Printy("b");
29d72146f4SUtkarsh Saxena // CHECK: if.end:
30d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
31d72146f4SUtkarsh Saxena }),
32d72146f4SUtkarsh Saxena ({
33d72146f4SUtkarsh Saxena if (foo()) return;
34d72146f4SUtkarsh Saxena // CHECK: if.then{{.*}}:
35d72146f4SUtkarsh Saxena // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST]], align 4
36d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN6PrintyD1Ev
37d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %cleanup
38d72146f4SUtkarsh Saxena Printy("c");
39d72146f4SUtkarsh Saxena // CHECK: if.end{{.*}}:
40d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
41d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN8PrintiesD1Ev
42d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %return
43d72146f4SUtkarsh Saxena }));
44d72146f4SUtkarsh Saxena // CHECK: cleanup:
45d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN6PrintyD1Ev
46d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %return
47d72146f4SUtkarsh Saxena }
48d72146f4SUtkarsh Saxena
break_in_stmt_expr()49d72146f4SUtkarsh Saxena void break_in_stmt_expr() {
50d72146f4SUtkarsh Saxena // Verify that the "break" in "if.then".calls dtor before jumping to "for.end".
51d72146f4SUtkarsh Saxena
52d72146f4SUtkarsh Saxena // CHECK-LABEL: define dso_local void @_Z18break_in_stmt_exprv()
53d72146f4SUtkarsh Saxena Printies p{Printy("a"),
54d72146f4SUtkarsh Saxena // CHECK: call void @_ZN6PrintyC1EPKc
55d72146f4SUtkarsh Saxena ({
56d72146f4SUtkarsh Saxena for (;;) {
57d72146f4SUtkarsh Saxena Printies ps{
58d72146f4SUtkarsh Saxena Printy("b"),
59d72146f4SUtkarsh Saxena // CHECK: for.cond:
60d72146f4SUtkarsh Saxena // CHECK: call void @_ZN6PrintyC1EPKc
61d72146f4SUtkarsh Saxena ({
62d72146f4SUtkarsh Saxena if (foo()) {
63d72146f4SUtkarsh Saxena break;
64d72146f4SUtkarsh Saxena // CHECK: if.then:
65d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN6PrintyD1Ev
66d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %for.end
67d72146f4SUtkarsh Saxena }
68d72146f4SUtkarsh Saxena Printy("c");
69d72146f4SUtkarsh Saxena // CHECK: if.end:
70d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
71d72146f4SUtkarsh Saxena }),
72d72146f4SUtkarsh Saxena Printy("d")};
73d72146f4SUtkarsh Saxena // CHECK: call void @_ZN6PrintyC1EPKc
74d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN8PrintiesD1Ev
75d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %for.cond
76d72146f4SUtkarsh Saxena }
77d72146f4SUtkarsh Saxena Printy("e");
78d72146f4SUtkarsh Saxena // CHECK: for.end:
79d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
80d72146f4SUtkarsh Saxena }),
81d72146f4SUtkarsh Saxena Printy("f")};
82d72146f4SUtkarsh Saxena // CHECK: call void @_ZN6PrintyC1EPKc
83d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN8PrintiesD1Ev
84d72146f4SUtkarsh Saxena }
85d72146f4SUtkarsh Saxena
goto_in_stmt_expr()86d72146f4SUtkarsh Saxena void goto_in_stmt_expr() {
87d72146f4SUtkarsh Saxena // Verify that:
88d72146f4SUtkarsh Saxena // - correct branch fixups for deactivated normal cleanups are generated correctly.
89d72146f4SUtkarsh Saxena
90d72146f4SUtkarsh Saxena // CHECK-LABEL: define dso_local void @_Z17goto_in_stmt_exprv()
91d72146f4SUtkarsh Saxena // CHECK: [[CLEANUP_DEST_SLOT:%cleanup.dest.slot.*]] = alloca i32, align 4
92d72146f4SUtkarsh Saxena {
93d72146f4SUtkarsh Saxena Printies p1{Printy("a"), // CHECK: call void @_ZN6PrintyC1EPKc
94d72146f4SUtkarsh Saxena ({
95d72146f4SUtkarsh Saxena {
96d72146f4SUtkarsh Saxena Printies p2{Printy("b"),
97d72146f4SUtkarsh Saxena // CHECK: call void @_ZN6PrintyC1EPKc
98d72146f4SUtkarsh Saxena ({
99d72146f4SUtkarsh Saxena if (foo() == 1) {
100d72146f4SUtkarsh Saxena goto in;
101d72146f4SUtkarsh Saxena // CHECK: if.then:
102d72146f4SUtkarsh Saxena // CHECK-NEXT: store i32 2, ptr [[CLEANUP_DEST_SLOT]], align 4
103d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %[[CLEANUP1:.+]]
104d72146f4SUtkarsh Saxena }
105d72146f4SUtkarsh Saxena if (foo() == 2) {
106d72146f4SUtkarsh Saxena goto out;
107d72146f4SUtkarsh Saxena // CHECK: if.then{{.*}}:
108d72146f4SUtkarsh Saxena // CHECK-NEXT: store i32 3, ptr [[CLEANUP_DEST_SLOT]], align 4
109d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %[[CLEANUP1]]
110d72146f4SUtkarsh Saxena }
111d72146f4SUtkarsh Saxena Printy("c");
112d72146f4SUtkarsh Saxena // CHECK: if.end{{.*}}:
113d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
114d72146f4SUtkarsh Saxena }),
115d72146f4SUtkarsh Saxena Printy("d")};
116d72146f4SUtkarsh Saxena // CHECK: call void @_ZN6PrintyC1EPKc
117d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN8PrintiesD1Ev
118d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %in
119d72146f4SUtkarsh Saxena
120d72146f4SUtkarsh Saxena }
121d72146f4SUtkarsh Saxena in:
122d72146f4SUtkarsh Saxena Printy("e");
123d72146f4SUtkarsh Saxena // CHECK: in: ; preds = %if.end{{.*}}, %[[CLEANUP1]]
124d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
125d72146f4SUtkarsh Saxena }),
126d72146f4SUtkarsh Saxena Printy("f")};
127d72146f4SUtkarsh Saxena // CHECK: call void @_ZN6PrintyC1EPKc
128d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN8PrintiesD1Ev
129d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %out
130d72146f4SUtkarsh Saxena }
131d72146f4SUtkarsh Saxena out:
132d72146f4SUtkarsh Saxena return;
133d72146f4SUtkarsh Saxena // CHECK: out:
134d72146f4SUtkarsh Saxena // CHECK-NEXT: ret void
135d72146f4SUtkarsh Saxena
136d72146f4SUtkarsh Saxena // CHECK: [[CLEANUP1]]: ; preds = %if.then{{.*}}, %if.then
137d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN6PrintyD1Ev
138d72146f4SUtkarsh Saxena // CHECK-NEXT: %cleanup.dest = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4
139d72146f4SUtkarsh Saxena // CHECK-NEXT: switch i32 %cleanup.dest, label %[[CLEANUP2:.+]] [
140d72146f4SUtkarsh Saxena // CHECK-NEXT: i32 2, label %in
141d72146f4SUtkarsh Saxena // CHECK-NEXT: ]
142d72146f4SUtkarsh Saxena
143d72146f4SUtkarsh Saxena // CHECK: [[CLEANUP2]]: ; preds = %[[CLEANUP1]]
144d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN6PrintyD1Ev
145d72146f4SUtkarsh Saxena // CHECK-NEXT: %cleanup.dest{{.*}} = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4
146d72146f4SUtkarsh Saxena // CHECK-NEXT: switch i32 %cleanup.dest{{.*}}, label %unreachable [
147d72146f4SUtkarsh Saxena // CHECK-NEXT: i32 3, label %out
148d72146f4SUtkarsh Saxena // CHECK-NEXT: ]
149d72146f4SUtkarsh Saxena }
150d72146f4SUtkarsh Saxena
ArrayInit()151d72146f4SUtkarsh Saxena void ArrayInit() {
152d72146f4SUtkarsh Saxena // Printy arr[4] = {ctorA, ctorB, stmt-exprC, stmt-exprD};
153d72146f4SUtkarsh Saxena // Verify that:
154d72146f4SUtkarsh Saxena // - We do the necessary stores for array cleanups (endOfInit and last constructed element).
155d72146f4SUtkarsh Saxena // - We update the array init element correctly for ctorA, ctorB and stmt-exprC.
156d72146f4SUtkarsh Saxena // - stmt-exprC and stmt-exprD share the array body dtor code (see %cleanup).
157d72146f4SUtkarsh Saxena
158d72146f4SUtkarsh Saxena // CHECK-LABEL: define dso_local void @_Z9ArrayInitv()
159d72146f4SUtkarsh Saxena // CHECK: %arrayinit.endOfInit = alloca ptr, align 8
160d72146f4SUtkarsh Saxena // CHECK: %cleanup.dest.slot = alloca i32, align 4
161*12d24e0cSNikita Popov // CHECK: store ptr %arr, ptr %arrayinit.endOfInit, align 8
162d72146f4SUtkarsh Saxena Printy arr[4] = {
163d72146f4SUtkarsh Saxena Printy("a"),
164*12d24e0cSNikita Popov // CHECK: call void @_ZN6PrintyC1EPKc(ptr noundef nonnull align 8 dereferenceable(8) %arr, ptr noundef @.str)
165*12d24e0cSNikita Popov // CHECK: [[ARRAYINIT_ELEMENT1:%.+]] = getelementptr inbounds %struct.Printy, ptr %arr, i64 1
166d72146f4SUtkarsh Saxena // CHECK: store ptr [[ARRAYINIT_ELEMENT1]], ptr %arrayinit.endOfInit, align 8
167d72146f4SUtkarsh Saxena Printy("b"),
168d72146f4SUtkarsh Saxena // CHECK: call void @_ZN6PrintyC1EPKc(ptr noundef nonnull align 8 dereferenceable(8) [[ARRAYINIT_ELEMENT1]], ptr noundef @.str.1)
169*12d24e0cSNikita Popov // CHECK: [[ARRAYINIT_ELEMENT2:%.+]] = getelementptr inbounds %struct.Printy, ptr %arr, i64 2
170d72146f4SUtkarsh Saxena // CHECK: store ptr [[ARRAYINIT_ELEMENT2]], ptr %arrayinit.endOfInit, align 8
171d72146f4SUtkarsh Saxena ({
172d72146f4SUtkarsh Saxena // CHECK: br i1 {{.*}}, label %if.then, label %if.end
173d72146f4SUtkarsh Saxena if (foo()) {
174d72146f4SUtkarsh Saxena return;
175d72146f4SUtkarsh Saxena // CHECK: if.then:
176d72146f4SUtkarsh Saxena // CHECK-NEXT: store i32 1, ptr %cleanup.dest.slot, align 4
177d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %cleanup
178d72146f4SUtkarsh Saxena }
179d72146f4SUtkarsh Saxena // CHECK: if.end:
180d72146f4SUtkarsh Saxena Printy("c");
181d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
182*12d24e0cSNikita Popov // CHECK-NEXT: %arrayinit.element2 = getelementptr inbounds %struct.Printy, ptr %arr, i64 3
183d72146f4SUtkarsh Saxena // CHECK-NEXT: store ptr %arrayinit.element2, ptr %arrayinit.endOfInit, align 8
184d72146f4SUtkarsh Saxena }),
185d72146f4SUtkarsh Saxena ({
186d72146f4SUtkarsh Saxena // CHECK: br i1 {{%.+}} label %[[IF_THEN2:.+]], label %[[IF_END2:.+]]
187d72146f4SUtkarsh Saxena if (foo()) {
188d72146f4SUtkarsh Saxena return;
189d72146f4SUtkarsh Saxena // CHECK: [[IF_THEN2]]:
190d72146f4SUtkarsh Saxena // CHECK-NEXT: store i32 1, ptr %cleanup.dest.slot, align 4
191d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %cleanup
192d72146f4SUtkarsh Saxena }
193d72146f4SUtkarsh Saxena // CHECK: [[IF_END2]]:
194d72146f4SUtkarsh Saxena Printy("d");
195d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
196d72146f4SUtkarsh Saxena // CHECK-NEXT: %array.begin = getelementptr inbounds [4 x %struct.Printy], ptr %arr, i32 0, i32 0
197d72146f4SUtkarsh Saxena // CHECK-NEXT: %0 = getelementptr inbounds %struct.Printy, ptr %array.begin, i64 4
198d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %[[ARRAY_DESTROY_BODY1:.+]]
199d72146f4SUtkarsh Saxena }),
200d72146f4SUtkarsh Saxena };
201d72146f4SUtkarsh Saxena
202d72146f4SUtkarsh Saxena // CHECK: [[ARRAY_DESTROY_BODY1]]:
203d72146f4SUtkarsh Saxena // CHECK-NEXT: %arraydestroy.elementPast{{.*}} = phi ptr [ %0, %[[IF_END2]] ], [ %arraydestroy.element{{.*}}, %[[ARRAY_DESTROY_BODY1]] ]
204d72146f4SUtkarsh Saxena // CHECK-NEXT: %arraydestroy.element{{.*}} = getelementptr inbounds %struct.Printy, ptr %arraydestroy.elementPast{{.*}}, i64 -1
205d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN6PrintyD1Ev
206d72146f4SUtkarsh Saxena // CHECK-NEXT: %arraydestroy.done{{.*}} = icmp eq ptr %arraydestroy.element{{.*}}, %array.begin
207d72146f4SUtkarsh Saxena // CHECK-NEXT: br i1 %arraydestroy.done{{.*}}, label %[[ARRAY_DESTROY_DONE1:.+]], label %[[ARRAY_DESTROY_BODY1]]
208d72146f4SUtkarsh Saxena
209d72146f4SUtkarsh Saxena // CHECK: [[ARRAY_DESTROY_DONE1]]:
210d72146f4SUtkarsh Saxena // CHECK-NEXT: ret void
211d72146f4SUtkarsh Saxena
212d72146f4SUtkarsh Saxena // CHECK: cleanup:
213d72146f4SUtkarsh Saxena // CHECK-NEXT: %1 = load ptr, ptr %arrayinit.endOfInit, align 8
214*12d24e0cSNikita Popov // CHECK-NEXT: %arraydestroy.isempty = icmp eq ptr %arr, %1
215d72146f4SUtkarsh Saxena // CHECK-NEXT: br i1 %arraydestroy.isempty, label %[[ARRAY_DESTROY_DONE2:.+]], label %[[ARRAY_DESTROY_BODY2:.+]]
216d72146f4SUtkarsh Saxena
217d72146f4SUtkarsh Saxena // CHECK: [[ARRAY_DESTROY_BODY2]]:
218d72146f4SUtkarsh Saxena // CHECK-NEXT: %arraydestroy.elementPast = phi ptr [ %1, %cleanup ], [ %arraydestroy.element, %[[ARRAY_DESTROY_BODY2]] ]
219d72146f4SUtkarsh Saxena // CHECK-NEXT: %arraydestroy.element = getelementptr inbounds %struct.Printy, ptr %arraydestroy.elementPast, i64 -1
220d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN6PrintyD1Ev(ptr noundef nonnull align 8 dereferenceable(8) %arraydestroy.element)
221*12d24e0cSNikita Popov // CHECK-NEXT: %arraydestroy.done = icmp eq ptr %arraydestroy.element, %arr
222d72146f4SUtkarsh Saxena // CHECK-NEXT: br i1 %arraydestroy.done, label %[[ARRAY_DESTROY_DONE2]], label %[[ARRAY_DESTROY_BODY2]]
223d72146f4SUtkarsh Saxena
224d72146f4SUtkarsh Saxena // CHECK: [[ARRAY_DESTROY_DONE2]]:
225d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %[[ARRAY_DESTROY_DONE1]]
226d72146f4SUtkarsh Saxena }
227d72146f4SUtkarsh Saxena
ArraySubobjects()228d72146f4SUtkarsh Saxena void ArraySubobjects() {
229d72146f4SUtkarsh Saxena struct S {
230d72146f4SUtkarsh Saxena Printy arr1[2];
231d72146f4SUtkarsh Saxena Printy arr2[2];
232d72146f4SUtkarsh Saxena Printy p;
233d72146f4SUtkarsh Saxena };
234d72146f4SUtkarsh Saxena // CHECK-LABEL: define dso_local void @_Z15ArraySubobjectsv()
235d72146f4SUtkarsh Saxena // CHECK: %arrayinit.endOfInit = alloca ptr, align 8
236d72146f4SUtkarsh Saxena S s{{Printy("a"), Printy("b")},
237d72146f4SUtkarsh Saxena // CHECK: call void @_ZN6PrintyC1EPKc
238d72146f4SUtkarsh Saxena // CHECK: call void @_ZN6PrintyC1EPKc
239d72146f4SUtkarsh Saxena {Printy("a"),
240*12d24e0cSNikita Popov // CHECK: store ptr %arr2, ptr %arrayinit.endOfInit, align 8
241d72146f4SUtkarsh Saxena // CHECK: call void @_ZN6PrintyC1EPKc
242d72146f4SUtkarsh Saxena // CHECK: [[ARRAYINIT_ELEMENT:%.+]] = getelementptr inbounds %struct.Printy
243d72146f4SUtkarsh Saxena // CHECK: store ptr [[ARRAYINIT_ELEMENT]], ptr %arrayinit.endOfInit, align 8
244d72146f4SUtkarsh Saxena ({
245d72146f4SUtkarsh Saxena if (foo()) {
246d72146f4SUtkarsh Saxena return;
247d72146f4SUtkarsh Saxena // CHECK: if.then:
248d72146f4SUtkarsh Saxena // CHECK-NEXT: [[V0:%.+]] = load ptr, ptr %arrayinit.endOfInit, align 8
249*12d24e0cSNikita Popov // CHECK-NEXT: %arraydestroy.isempty = icmp eq ptr %arr2, [[V0]]
250d72146f4SUtkarsh Saxena // CHECK-NEXT: br i1 %arraydestroy.isempty, label %[[ARRAY_DESTROY_DONE:.+]], label %[[ARRAY_DESTROY_BODY:.+]]
251d72146f4SUtkarsh Saxena }
252d72146f4SUtkarsh Saxena Printy("b");
253d72146f4SUtkarsh Saxena })
254d72146f4SUtkarsh Saxena },
255d72146f4SUtkarsh Saxena Printy("c")
256d72146f4SUtkarsh Saxena // CHECK: if.end:
257d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
258d72146f4SUtkarsh Saxena // CHECK: call void @_ZN6PrintyC1EPKc
259d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZZ15ArraySubobjectsvEN1SD1Ev
260d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %return
261d72146f4SUtkarsh Saxena };
262d72146f4SUtkarsh Saxena // CHECK: return:
263d72146f4SUtkarsh Saxena // CHECK-NEXT: ret void
264d72146f4SUtkarsh Saxena
265d72146f4SUtkarsh Saxena // CHECK: [[ARRAY_DESTROY_BODY]]:
266d72146f4SUtkarsh Saxena // CHECK-NEXT: %arraydestroy.elementPast = phi ptr [ %0, %if.then ], [ %arraydestroy.element, %[[ARRAY_DESTROY_BODY]] ]
267d72146f4SUtkarsh Saxena // CHECK-NEXT: %arraydestroy.element = getelementptr inbounds %struct.Printy, ptr %arraydestroy.elementPast, i64 -1
268d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN6PrintyD1Ev(ptr noundef nonnull align 8 dereferenceable(8) %arraydestroy.element)
269*12d24e0cSNikita Popov // CHECK-NEXT: %arraydestroy.done = icmp eq ptr %arraydestroy.element, %arr2
270d72146f4SUtkarsh Saxena // CHECK-NEXT: br i1 %arraydestroy.done, label %[[ARRAY_DESTROY_DONE]], label %[[ARRAY_DESTROY_BODY]]
271d72146f4SUtkarsh Saxena
272d72146f4SUtkarsh Saxena // CHECK: [[ARRAY_DESTROY_DONE]]
273d72146f4SUtkarsh Saxena // CHECK-NEXT: [[ARRAY_BEGIN:%.+]] = getelementptr inbounds [2 x %struct.Printy], ptr %arr1, i32 0, i32 0
274d72146f4SUtkarsh Saxena // CHECK-NEXT: [[V1:%.+]] = getelementptr inbounds %struct.Printy, ptr [[ARRAY_BEGIN]], i64 2
275d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %[[ARRAY_DESTROY_BODY2:.+]]
276d72146f4SUtkarsh Saxena
277d72146f4SUtkarsh Saxena // CHECK: [[ARRAY_DESTROY_BODY2]]:
278*12d24e0cSNikita Popov // CHECK-NEXT: %arraydestroy.elementPast4 = phi ptr [ %1, %[[ARRAY_DESTROY_DONE]] ], [ %arraydestroy.element5, %[[ARRAY_DESTROY_BODY2]] ]
279*12d24e0cSNikita Popov // CHECK-NEXT: %arraydestroy.element5 = getelementptr inbounds %struct.Printy, ptr %arraydestroy.elementPast4, i64 -1
280*12d24e0cSNikita Popov // CHECK-NEXT: call void @_ZN6PrintyD1Ev(ptr noundef nonnull align 8 dereferenceable(8) %arraydestroy.element5)
281*12d24e0cSNikita Popov // CHECK-NEXT: %arraydestroy.done6 = icmp eq ptr %arraydestroy.element5, [[ARRAY_BEGIN]]
282*12d24e0cSNikita Popov // CHECK-NEXT: br i1 %arraydestroy.done6, label %[[ARRAY_DESTROY_DONE2:.+]], label %[[ARRAY_DESTROY_BODY2]]
283d72146f4SUtkarsh Saxena
284d72146f4SUtkarsh Saxena
285d72146f4SUtkarsh Saxena // CHECK: [[ARRAY_DESTROY_DONE2]]:
286d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %return
287d72146f4SUtkarsh Saxena }
288d72146f4SUtkarsh Saxena
LambdaInit()289d72146f4SUtkarsh Saxena void LambdaInit() {
290d72146f4SUtkarsh Saxena // CHECK-LABEL: define dso_local void @_Z10LambdaInitv()
291d72146f4SUtkarsh Saxena auto S = [a = Printy("a"), b = ({
292d72146f4SUtkarsh Saxena if (foo()) {
293d72146f4SUtkarsh Saxena return;
294d72146f4SUtkarsh Saxena // CHECK: if.then:
295d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN6PrintyD1Ev
296d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %return
297d72146f4SUtkarsh Saxena }
298d72146f4SUtkarsh Saxena Printy("b");
299d72146f4SUtkarsh Saxena })]() { return a; };
300d72146f4SUtkarsh Saxena }
301d72146f4SUtkarsh Saxena
302d72146f4SUtkarsh Saxena struct PrintyRefBind {
303d72146f4SUtkarsh Saxena const Printy &a;
304d72146f4SUtkarsh Saxena const Printy &b;
305d72146f4SUtkarsh Saxena };
306d72146f4SUtkarsh Saxena
307d72146f4SUtkarsh Saxena struct Temp {
308d72146f4SUtkarsh Saxena Temp();
309d72146f4SUtkarsh Saxena ~Temp();
310d72146f4SUtkarsh Saxena };
311d72146f4SUtkarsh Saxena Temp CreateTemp();
312d72146f4SUtkarsh Saxena Printy CreatePrinty();
313d72146f4SUtkarsh Saxena Printy CreatePrinty(const Temp&);
314d72146f4SUtkarsh Saxena
LifetimeExtended()315d72146f4SUtkarsh Saxena void LifetimeExtended() {
316d72146f4SUtkarsh Saxena // CHECK-LABEL: define dso_local void @_Z16LifetimeExtendedv
317d72146f4SUtkarsh Saxena PrintyRefBind ps = {Printy("a"), ({
318d72146f4SUtkarsh Saxena if (foo()) {
319d72146f4SUtkarsh Saxena return;
320d72146f4SUtkarsh Saxena // CHECK: if.then:
321d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN6PrintyD1Ev
322d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %return
323d72146f4SUtkarsh Saxena }
324d72146f4SUtkarsh Saxena Printy("b");
325d72146f4SUtkarsh Saxena })};
326d72146f4SUtkarsh Saxena }
327d72146f4SUtkarsh Saxena
ConditionalLifetimeExtended()328d72146f4SUtkarsh Saxena void ConditionalLifetimeExtended() {
329d72146f4SUtkarsh Saxena // CHECK-LABEL: @_Z27ConditionalLifetimeExtendedv()
330d72146f4SUtkarsh Saxena
331d72146f4SUtkarsh Saxena // Verify that we create two cleanup flags.
332d72146f4SUtkarsh Saxena // 1. First for the cleanup which is deactivated after full expression.
333d72146f4SUtkarsh Saxena // 2. Second for the life-ext cleanup which is activated if the branch is taken.
334d72146f4SUtkarsh Saxena
335d72146f4SUtkarsh Saxena // Note: We use `CreateTemp()` to ensure that life-ext destroy cleanup is not at
336d72146f4SUtkarsh Saxena // the top of EHStack on deactivation. This ensures using active flags.
337d72146f4SUtkarsh Saxena
338d72146f4SUtkarsh Saxena Printy* p1 = nullptr;
339d72146f4SUtkarsh Saxena // CHECK: store i1 false, ptr [[BRANCH1_DEFERRED:%cleanup.cond]], align 1
340d72146f4SUtkarsh Saxena // CHECK-NEXT: store i1 false, ptr [[BRANCH1_LIFEEXT:%cleanup.cond.*]], align 1
341d72146f4SUtkarsh Saxena PrintyRefBind ps = {
342d72146f4SUtkarsh Saxena p1 != nullptr ? static_cast<const Printy&>(CreatePrinty())
343d72146f4SUtkarsh Saxena // CHECK: cond.true:
344d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_Z12CreatePrintyv
345d72146f4SUtkarsh Saxena // CHECK-NEXT: store i1 true, ptr [[BRANCH1_DEFERRED]], align 1
346d72146f4SUtkarsh Saxena // CHECK-NEXT: store i1 true, ptr [[BRANCH1_LIFEEXT]], align 1
347d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %{{.*}}
348d72146f4SUtkarsh Saxena : foo() ? static_cast<const Printy&>(CreatePrinty(CreateTemp()))
349d72146f4SUtkarsh Saxena : *p1,
350d72146f4SUtkarsh Saxena ({
351d72146f4SUtkarsh Saxena if (foo()) return;
352d72146f4SUtkarsh Saxena Printy("c");
353d72146f4SUtkarsh Saxena // CHECK: if.end:
354d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
355d72146f4SUtkarsh Saxena // CHECK-NEXT: store ptr
356d72146f4SUtkarsh Saxena })};
357d72146f4SUtkarsh Saxena // CHECK-NEXT: store i1 false, ptr [[BRANCH1_DEFERRED]], align 1
358d72146f4SUtkarsh Saxena // CHECK-NEXT: store i32 0, ptr %cleanup.dest.slot, align 4
359d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %cleanup
360d72146f4SUtkarsh Saxena
361d72146f4SUtkarsh Saxena }
362d72146f4SUtkarsh Saxena
NewArrayInit()363d72146f4SUtkarsh Saxena void NewArrayInit() {
364d72146f4SUtkarsh Saxena // CHECK-LABEL: define dso_local void @_Z12NewArrayInitv()
365d72146f4SUtkarsh Saxena // CHECK: %array.init.end = alloca ptr, align 8
366d72146f4SUtkarsh Saxena // CHECK: store ptr %0, ptr %array.init.end, align 8
367d72146f4SUtkarsh Saxena Printy *array = new Printy[3]{
368d72146f4SUtkarsh Saxena "a",
369d72146f4SUtkarsh Saxena // CHECK: call void @_ZN6PrintyC1EPKc
370d72146f4SUtkarsh Saxena // CHECK: store ptr %array.exp.next, ptr %array.init.end, align 8
371d72146f4SUtkarsh Saxena "b",
372d72146f4SUtkarsh Saxena // CHECK: call void @_ZN6PrintyC1EPKc
373d72146f4SUtkarsh Saxena // CHECK: store ptr %array.exp.next1, ptr %array.init.end, align 8
374d72146f4SUtkarsh Saxena ({
375d72146f4SUtkarsh Saxena if (foo()) {
376d72146f4SUtkarsh Saxena return;
377d72146f4SUtkarsh Saxena // CHECK: if.then:
378d72146f4SUtkarsh Saxena // CHECK: br i1 %arraydestroy.isempty, label %arraydestroy.done{{.*}}, label %arraydestroy.body
379d72146f4SUtkarsh Saxena }
380d72146f4SUtkarsh Saxena "b";
381d72146f4SUtkarsh Saxena // CHECK: if.end:
382d72146f4SUtkarsh Saxena // CHECK: call void @_ZN6PrintyC1EPKc
383d72146f4SUtkarsh Saxena })};
384d72146f4SUtkarsh Saxena // CHECK: arraydestroy.body:
385d72146f4SUtkarsh Saxena // CHECK-NEXT: %arraydestroy.elementPast = phi ptr [ %{{.*}}, %if.then ], [ %arraydestroy.element, %arraydestroy.body ]
386d72146f4SUtkarsh Saxena // CHECK-NEXT: %arraydestroy.element = getelementptr inbounds %struct.Printy, ptr %arraydestroy.elementPast, i64 -1
387d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN6PrintyD1Ev(ptr noundef nonnull align 8 dereferenceable(8) %arraydestroy.element)
388d72146f4SUtkarsh Saxena // CHECK-NEXT: %arraydestroy.done = icmp eq ptr %arraydestroy.element, %0
389d72146f4SUtkarsh Saxena // CHECK-NEXT: br i1 %arraydestroy.done, label %arraydestroy.done{{.*}}, label %arraydestroy.body
390d72146f4SUtkarsh Saxena
391d72146f4SUtkarsh Saxena // CHECK: arraydestroy.done{{.*}}: ; preds = %arraydestroy.body, %if.then
392d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %return
393d72146f4SUtkarsh Saxena }
394d72146f4SUtkarsh Saxena
DestroyInConditionalCleanup()395d72146f4SUtkarsh Saxena void DestroyInConditionalCleanup() {
396d72146f4SUtkarsh Saxena // EH-LABEL: DestroyInConditionalCleanupv()
397d72146f4SUtkarsh Saxena // NOEH-LABEL: DestroyInConditionalCleanupv()
398d72146f4SUtkarsh Saxena struct A {
399d72146f4SUtkarsh Saxena A() {}
400d72146f4SUtkarsh Saxena ~A() {}
401d72146f4SUtkarsh Saxena };
402d72146f4SUtkarsh Saxena
403d72146f4SUtkarsh Saxena struct Value {
404d72146f4SUtkarsh Saxena Value(A) {}
405d72146f4SUtkarsh Saxena ~Value() {}
406d72146f4SUtkarsh Saxena };
407d72146f4SUtkarsh Saxena
408d72146f4SUtkarsh Saxena struct V2 {
409d72146f4SUtkarsh Saxena Value K;
410d72146f4SUtkarsh Saxena Value V;
411d72146f4SUtkarsh Saxena };
412d72146f4SUtkarsh Saxena // Verify we use conditional cleanups.
413d72146f4SUtkarsh Saxena (void)(foo() ? V2{A(), A()} : V2{A(), A()});
414d72146f4SUtkarsh Saxena // NOEH: cond.true:
415d72146f4SUtkarsh Saxena // NOEH: call void @_ZZ27DestroyInConditionalCleanupvEN1AC1Ev
416d72146f4SUtkarsh Saxena // NOEH: store ptr %{{.*}}, ptr %cond-cleanup.save
417d72146f4SUtkarsh Saxena
418d72146f4SUtkarsh Saxena // EH: cond.true:
419d72146f4SUtkarsh Saxena // EH: invoke void @_ZZ27DestroyInConditionalCleanupvEN1AC1Ev
420d72146f4SUtkarsh Saxena // EH: store ptr %{{.*}}, ptr %cond-cleanup.save
421d72146f4SUtkarsh Saxena }
422d72146f4SUtkarsh Saxena
ArrayInitWithContinue()423d72146f4SUtkarsh Saxena void ArrayInitWithContinue() {
424d72146f4SUtkarsh Saxena // CHECK-LABEL: @_Z21ArrayInitWithContinuev
425d72146f4SUtkarsh Saxena // Verify that we start to emit the array destructor.
426d72146f4SUtkarsh Saxena // CHECK: %arrayinit.endOfInit = alloca ptr, align 8
427d72146f4SUtkarsh Saxena for (int i = 0; i < 1; ++i) {
428d72146f4SUtkarsh Saxena Printy arr[2] = {"a", ({
429d72146f4SUtkarsh Saxena if (foo()) {
430d72146f4SUtkarsh Saxena continue;
431d72146f4SUtkarsh Saxena }
432d72146f4SUtkarsh Saxena "b";
433d72146f4SUtkarsh Saxena })};
434d72146f4SUtkarsh Saxena }
435d72146f4SUtkarsh Saxena }
436d72146f4SUtkarsh Saxena
437d72146f4SUtkarsh Saxena struct [[clang::trivial_abi]] HasTrivialABI {
438d72146f4SUtkarsh Saxena HasTrivialABI();
439d72146f4SUtkarsh Saxena ~HasTrivialABI();
440d72146f4SUtkarsh Saxena };
441d72146f4SUtkarsh Saxena void AcceptTrivialABI(HasTrivialABI, int);
TrivialABI()442d72146f4SUtkarsh Saxena void TrivialABI() {
443d72146f4SUtkarsh Saxena // CHECK-LABEL: define dso_local void @_Z10TrivialABIv()
444d72146f4SUtkarsh Saxena AcceptTrivialABI(HasTrivialABI(), ({
445d72146f4SUtkarsh Saxena if (foo()) return;
446d72146f4SUtkarsh Saxena // CHECK: if.then:
447d72146f4SUtkarsh Saxena // CHECK-NEXT: call void @_ZN13HasTrivialABID1Ev
448d72146f4SUtkarsh Saxena // CHECK-NEXT: br label %return
449d72146f4SUtkarsh Saxena 0;
450d72146f4SUtkarsh Saxena }));
451d72146f4SUtkarsh Saxena }
452d72146f4SUtkarsh Saxena
453d72146f4SUtkarsh Saxena namespace CleanupFlag {
454d72146f4SUtkarsh Saxena struct A {
ACleanupFlag::A455d72146f4SUtkarsh Saxena A() {}
~ACleanupFlag::A456d72146f4SUtkarsh Saxena ~A() {}
457d72146f4SUtkarsh Saxena };
458d72146f4SUtkarsh Saxena
459d72146f4SUtkarsh Saxena struct B {
BCleanupFlag::B460d72146f4SUtkarsh Saxena B(const A&) {}
BCleanupFlag::B461d72146f4SUtkarsh Saxena B() {}
~BCleanupFlag::B462d72146f4SUtkarsh Saxena ~B() {}
463d72146f4SUtkarsh Saxena };
464d72146f4SUtkarsh Saxena
465d72146f4SUtkarsh Saxena struct S {
466d72146f4SUtkarsh Saxena A a;
467d72146f4SUtkarsh Saxena B b;
468d72146f4SUtkarsh Saxena };
469d72146f4SUtkarsh Saxena
470d72146f4SUtkarsh Saxena int AcceptS(S s);
471d72146f4SUtkarsh Saxena
472d72146f4SUtkarsh Saxena void Accept2(int x, int y);
473d72146f4SUtkarsh Saxena
InactiveNormalCleanup()474d72146f4SUtkarsh Saxena void InactiveNormalCleanup() {
475d72146f4SUtkarsh Saxena // CHECK-LABEL: define {{.*}}InactiveNormalCleanupEv()
476d72146f4SUtkarsh Saxena
477d72146f4SUtkarsh Saxena // The first A{} below is an inactive normal cleanup which
478d72146f4SUtkarsh Saxena // is not popped from EHStack on deactivation. This needs an
479d72146f4SUtkarsh Saxena // "active" cleanup flag.
480d72146f4SUtkarsh Saxena
481d72146f4SUtkarsh Saxena // CHECK: [[ACTIVE:%cleanup.isactive.*]] = alloca i1, align 1
482d72146f4SUtkarsh Saxena // CHECK: call void [[A_CTOR:@.*AC1Ev]]
483d72146f4SUtkarsh Saxena // CHECK: store i1 true, ptr [[ACTIVE]], align 1
484d72146f4SUtkarsh Saxena // CHECK: call void [[A_CTOR]]
485d72146f4SUtkarsh Saxena // CHECK: call void [[B_CTOR:@.*BC1ERKNS_1AE]]
486d72146f4SUtkarsh Saxena // CHECK: store i1 false, ptr [[ACTIVE]], align 1
487d72146f4SUtkarsh Saxena // CHECK: call noundef i32 [[ACCEPTS:@.*AcceptSENS_1SE]]
488d72146f4SUtkarsh Saxena Accept2(AcceptS({.a = A{}, .b = A{}}), ({
489d72146f4SUtkarsh Saxena if (foo()) return;
490d72146f4SUtkarsh Saxena // CHECK: if.then:
491d72146f4SUtkarsh Saxena // CHECK: br label %cleanup
492d72146f4SUtkarsh Saxena 0;
493d72146f4SUtkarsh Saxena // CHECK: if.end:
494d72146f4SUtkarsh Saxena // CHECK: call void [[ACCEPT2:@.*Accept2Eii]]
495d72146f4SUtkarsh Saxena // CHECK: br label %cleanup
496d72146f4SUtkarsh Saxena }));
497d72146f4SUtkarsh Saxena // CHECK: cleanup:
498d72146f4SUtkarsh Saxena // CHECK: call void [[S_DTOR:@.*SD1Ev]]
499d72146f4SUtkarsh Saxena // CHECK: call void [[A_DTOR:@.*AD1Ev]]
500d72146f4SUtkarsh Saxena // CHECK: %cleanup.is_active = load i1, ptr [[ACTIVE]]
501d72146f4SUtkarsh Saxena // CHECK: br i1 %cleanup.is_active, label %cleanup.action, label %cleanup.done
502d72146f4SUtkarsh Saxena
503d72146f4SUtkarsh Saxena // CHECK: cleanup.action:
504d72146f4SUtkarsh Saxena // CHECK: call void [[A_DTOR]]
505d72146f4SUtkarsh Saxena
506d72146f4SUtkarsh Saxena // The "active" cleanup flag is not required for unused cleanups.
507d72146f4SUtkarsh Saxena Accept2(AcceptS({.a = A{}, .b = A{}}), 0);
508d72146f4SUtkarsh Saxena // CHECK: cleanup.cont:
509d72146f4SUtkarsh Saxena // CHECK: call void [[A_CTOR]]
510d72146f4SUtkarsh Saxena // CHECK-NOT: store i1 true
511d72146f4SUtkarsh Saxena // CHECK: call void [[A_CTOR]]
512d72146f4SUtkarsh Saxena // CHECK: call void [[B_CTOR]]
513d72146f4SUtkarsh Saxena // CHECK-NOT: store i1 false
514d72146f4SUtkarsh Saxena // CHECK: call noundef i32 [[ACCEPTS]]
515d72146f4SUtkarsh Saxena // CHECK: call void [[ACCEPT2]]
516d72146f4SUtkarsh Saxena // CHECK: call void [[S_DTOR]]
517d72146f4SUtkarsh Saxena // CHECK: call void [[A_DTOR]]
518d72146f4SUtkarsh Saxena // CHECK: br label %return
519d72146f4SUtkarsh Saxena }
520d72146f4SUtkarsh Saxena } // namespace CleanupFlag
521