xref: /llvm-project/clang/test/CodeGenCXX/control-flow-in-stmt-expr.cpp (revision 12d24e0c56a154c88247e55c7c352030e4d9073d)
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