1// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
2void *f();
3
4template <typename T> T* g() {
5 if (T* t = f())
6   return t;
7
8 return 0;
9}
10
11void h() {
12 void *a = g<void>();
13}
14
15struct X {
16  X();
17  X(const X&);
18  ~X();
19  operator bool();
20};
21
22struct Y {
23  Y();
24  ~Y();
25};
26
27X getX();
28
29// CHECK-LABEL: define void @_Z11if_destructi(
30void if_destruct(int z) {
31  // Verify that the condition variable is destroyed at the end of the
32  // "if" statement.
33  // CHECK: call void @_ZN1XC1Ev
34  // CHECK: call zeroext i1 @_ZN1XcvbEv
35  if (X x = X()) {
36    // CHECK: store i32 18
37    z = 18;
38  }
39  // CHECK: call void @_ZN1XD1Ev
40  // CHECK: store i32 17
41  z = 17;
42
43  // CHECK: call void @_ZN1XC1Ev
44  if (X x = X())
45    Y y;
46  // CHECK: br
47  // CHECK: call  void @_ZN1YC1Ev
48  // CHECK: call  void @_ZN1YD1Ev
49  // CHECK: br
50  // CHECK: call  void @_ZN1XD1Ev
51
52  // CHECK: call void @_Z4getXv
53  // CHECK: call zeroext i1 @_ZN1XcvbEv
54  // CHECK: call void @_ZN1XD1Ev
55  // CHECK: br
56  if (getX()) { }
57
58  // CHECK: ret
59}
60
61struct ConvertibleToInt {
62  ConvertibleToInt();
63  ~ConvertibleToInt();
64  operator int();
65};
66
67ConvertibleToInt getConvToInt();
68
69void switch_destruct(int z) {
70  // CHECK: call void @_ZN16ConvertibleToIntC1Ev
71  switch (ConvertibleToInt conv = ConvertibleToInt()) {
72  case 0:
73    break;
74
75  default:
76    // CHECK: store i32 19
77    z = 19;
78    break;
79  }
80  // CHECK: call void @_ZN16ConvertibleToIntD1Ev
81  // CHECK: store i32 20
82  z = 20;
83
84  // CHECK: call void @_Z12getConvToIntv
85  // CHECK: call i32 @_ZN16ConvertibleToIntcviEv
86  // CHECK: call void @_ZN16ConvertibleToIntD1Ev
87  switch(getConvToInt()) {
88  case 0:
89    break;
90  }
91  // CHECK: store i32 27
92  z = 27;
93  // CHECK: ret
94}
95
96int foo();
97
98// CHECK-LABEL: define void @_Z14while_destructi
99void while_destruct(int z) {
100  // CHECK: [[Z:%.*]] = alloca i32
101  // CHECK: [[CLEANUPDEST:%.*]] = alloca i32
102  while (X x = X()) {
103    // CHECK: call void @_ZN1XC1Ev
104    // CHECK-NEXT: [[COND:%.*]] = call zeroext i1 @_ZN1XcvbEv
105    // CHECK-NEXT: br i1 [[COND]]
106
107    // Loop-exit staging block.
108    // CHECK: store i32 3, i32* [[CLEANUPDEST]]
109    // CHECK-NEXT: br
110
111    // While body.
112    // CHECK: store i32 21, i32* [[Z]]
113    // CHECK: store i32 0, i32* [[CLEANUPDEST]]
114    // CHECK-NEXT: br
115    z = 21;
116
117    // Cleanup.
118    // CHECK: call void @_ZN1XD1Ev
119    // CHECK-NEXT: [[DEST:%.*]] = load i32, i32* [[CLEANUPDEST]]
120    // CHECK-NEXT: switch i32 [[DEST]]
121  }
122
123  // CHECK: store i32 22, i32* [[Z]]
124  z = 22;
125
126  // CHECK: call void @_Z4getXv
127  // CHECK-NEXT: call zeroext i1 @_ZN1XcvbEv
128  // CHECK-NEXT: call void @_ZN1XD1Ev
129  // CHECK-NEXT: br
130  while(getX()) { }
131
132  // CHECK: store i32 25, i32* [[Z]]
133  z = 25;
134
135  // CHECK: ret
136}
137
138// CHECK-LABEL: define void @_Z12for_destructi(
139void for_destruct(int z) {
140  // CHECK: [[Z:%.*]] = alloca i32
141  // CHECK: [[CLEANUPDEST:%.*]] = alloca i32
142  // CHECK: [[I:%.*]] = alloca i32
143  // CHECK: call void @_ZN1YC1Ev
144  // CHECK-NEXT: br
145  // -> %for.cond
146
147  for(Y y = Y(); X x = X(); ++z) {
148    // %for.cond: The loop condition.
149    // CHECK: call void @_ZN1XC1Ev
150    // CHECK-NEXT: [[COND:%.*]] = call zeroext i1 @_ZN1XcvbEv(
151    // CHECK-NEXT: br i1 [[COND]]
152    // -> %for.body, %for.cond.cleanup
153
154    // %for.cond.cleanup: Exit cleanup staging.
155    // CHECK: store i32 2, i32* [[CLEANUPDEST]]
156    // CHECK-NEXT: br
157    // -> %cleanup
158
159    // %for.body:
160    // CHECK: store i32 23, i32* [[Z]]
161    // CHECK-NEXT: br
162    // -> %for.inc
163    z = 23;
164
165    // %for.inc:
166    // CHECK: [[TMP:%.*]] = load i32, i32* [[Z]]
167    // CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP]], 1
168    // CHECK-NEXT: store i32 [[INC]], i32* [[Z]]
169    // CHECK-NEXT: store i32 0, i32* [[CLEANUPDEST]]
170    // CHECK-NEXT: br
171    // -> %cleanup
172
173    // %cleanup:  Destroys X.
174    // CHECK: call void @_ZN1XD1Ev
175    // CHECK-NEXT: [[YDESTTMP:%.*]] = load i32, i32* [[CLEANUPDEST]]
176    // CHECK-NEXT: switch i32 [[YDESTTMP]]
177    // 0 -> %cleanup.cont, default -> %cleanup1
178
179    // %cleanup.cont:  (eliminable)
180    // CHECK: br
181    // -> %for.cond
182
183    // %cleanup1: Destroys Y.
184    // CHECK: call void @_ZN1YD1Ev(
185    // CHECK-NEXT: br
186    // -> %for.end
187  }
188
189  // %for.end:
190  // CHECK: store i32 24
191  z = 24;
192
193  // CHECK-NEXT: store i32 0, i32* [[I]]
194  // CHECK-NEXT: br
195  // -> %for.cond6
196
197  // %for.cond6:
198  // CHECK: call void @_Z4getXv
199  // CHECK-NEXT: call zeroext i1 @_ZN1XcvbEv
200  // CHECK-NEXT: call void @_ZN1XD1Ev
201  // CHECK-NEXT: br
202  // -> %for.body10, %for.end16
203
204  // %for.body10:
205  // CHECK: br
206  // -> %for.inc11
207
208  // %for.inc11:
209  // CHECK: call void @_Z4getXv
210  // CHECK-NEXT: load i32, i32* [[I]]
211  // CHECK-NEXT: add
212  // CHECK-NEXT: store
213  // CHECK-NEXT: call void @_ZN1XD1Ev
214  // CHECK-NEXT: br
215  // -> %for.cond6
216  int i = 0;
217  for(; getX(); getX(), ++i) { }
218
219  // %for.end16
220  // CHECK: store i32 26
221  z = 26;
222
223  // CHECK-NEXT: ret void
224}
225
226void do_destruct(int z) {
227  // CHECK-LABEL: define void @_Z11do_destruct
228  do {
229    // CHECK: store i32 77
230    z = 77;
231    // CHECK: call void @_Z4getXv
232    // CHECK: call zeroext i1 @_ZN1XcvbEv
233    // CHECK: call void @_ZN1XD1Ev
234    // CHECK: br
235  } while (getX());
236  // CHECK: store i32 99
237  z = 99;
238  // CHECK: ret
239}
240
241int f(X);
242
243template<typename T>
244int instantiated(T x) {
245  int result;
246
247  // CHECK: call void @_ZN1XC1ERKS_
248  // CHECK: call i32 @_Z1f1X
249  // CHECK: call void @_ZN1XD1Ev
250  // CHECK: br
251  // CHECK: store i32 2
252  // CHECK: br
253  // CHECK: store i32 3
254  if (f(x)) { result = 2; } else { result = 3; }
255
256  // CHECK: call void @_ZN1XC1ERKS_
257  // CHECK: call i32 @_Z1f1X
258  // CHECK: call void @_ZN1XD1Ev
259  // CHECK: br
260  // CHECK: store i32 4
261  // CHECK: br
262  while (f(x)) { result = 4; }
263
264  // CHECK: call void @_ZN1XC1ERKS_
265  // CHECK: call i32 @_Z1f1X
266  // CHECK: call void @_ZN1XD1Ev
267  // CHECK: br
268  // CHECK: store i32 6
269  // CHECK: br
270  // CHECK: call void @_ZN1XC1ERKS_
271  // CHECK: call i32 @_Z1f1X
272  // CHECK: store i32 5
273  // CHECK: call void @_ZN1XD1Ev
274  // CHECK: br
275  for (; f(x); f(x), result = 5) {
276    result = 6;
277  }
278
279  // CHECK: call void @_ZN1XC1ERKS_
280  // CHECK: call i32 @_Z1f1X
281  // CHECK: call void @_ZN1XD1Ev
282  // CHECK: switch i32
283  // CHECK: store i32 7
284  // CHECK: store i32 8
285  switch (f(x)) {
286  case 0:
287    result = 7;
288    break;
289
290  case 1:
291    result = 8;
292  }
293
294  // CHECK: store i32 9
295  // CHECK: br
296  // CHECK: call void @_ZN1XC1ERKS_
297  // CHECK: call i32 @_Z1f1X
298  // CHECK: call void @_ZN1XD1Ev
299  // CHECK: br
300  do {
301    result = 9;
302  } while (f(x));
303
304  // CHECK: store i32 10
305  // CHECK: call void @_ZN1XC1ERKS_
306  // CHECK: call zeroext i1 @_ZN1XcvbEv
307  // CHECK: call void @_ZN1XD1Ev
308  // CHECK: br
309  do {
310    result = 10;
311  } while (X(x));
312
313  // CHECK: ret i32
314  return result;
315}
316
317template int instantiated(X);
318