1 | // RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple i386-apple-darwin -print-ivar-layout -emit-llvm -o /dev/null %s > %t-32.layout |
2 | // RUN: FileCheck --input-file=%t-32.layout %s |
3 | // rdar://12184410 |
4 | // rdar://12752901 |
5 | |
6 | void x(id y) {} |
7 | void y(int a) {} |
8 | |
9 | extern id opaque_id(); |
10 | |
11 | void f() { |
12 | __weak id wid; |
13 | __block int byref_int = 0; |
14 | char ch = 'a'; |
15 | char ch1 = 'b'; |
16 | char ch2 = 'c'; |
17 | short sh = 2; |
18 | const id bar = (id) opaque_id(); |
19 | id baz = 0; |
20 | __strong id strong_void_sta; |
21 | __block id byref_bab = (id)0; |
22 | __block id bl_var1; |
23 | int i; double dob; |
24 | |
25 | // The patterns here are a sequence of bytes, each saying first how |
26 | // many sizeof(void*) chunks to skip (high nibble) and then how many |
27 | // to scan (low nibble). A zero byte says that we've reached the end |
28 | // of the pattern. |
29 | // |
30 | // All of these patterns start with 01 3x because the block header on |
31 | // LP64 consists of an isa pointer (which we're supposed to scan for |
32 | // some reason) followed by three words (2 ints, a function pointer, |
33 | // and a descriptor pointer). |
34 | |
35 | // Test 1 |
36 | // CHECK: Inline block variable layout: 0x0320, BL_STRONG:3, BL_BYREF:2, BL_OPERATOR:0 |
37 | void (^b)() = ^{ |
38 | byref_int = sh + ch+ch1+ch2 ; |
39 | x(bar); |
40 | x(baz); |
41 | x((id)strong_void_sta); |
42 | x(byref_bab); |
43 | }; |
44 | b(); |
45 | |
46 | // Test 2 |
47 | // CHECK: Inline block variable layout: 0x0331, BL_STRONG:3, BL_BYREF:3, BL_WEAK:1, BL_OPERATOR:0 |
48 | void (^c)() = ^{ |
49 | byref_int = sh + ch+ch1+ch2 ; |
50 | x(bar); |
51 | x(baz); |
52 | x((id)strong_void_sta); |
53 | x(wid); |
54 | bl_var1 = 0; |
55 | x(byref_bab); |
56 | }; |
57 | } |
58 | |
59 | @class NSString, NSNumber; |
60 | void g() { |
61 | NSString *foo; |
62 | NSNumber *bar; |
63 | unsigned int bletch; |
64 | __weak id weak_delegate; |
65 | unsigned int i; |
66 | NSString *y; |
67 | NSString *z; |
68 | // CHECK: Inline block variable layout: 0x0401, BL_STRONG:4, BL_WEAK:1, BL_OPERATOR:0 |
69 | void (^c)() = ^{ |
70 | int j = i + bletch; |
71 | x(foo); |
72 | x(bar); |
73 | x(weak_delegate); |
74 | x(y); |
75 | x(z); |
76 | }; |
77 | c(); |
78 | } |
79 | |
80 | // Test 5 (unions/structs and their nesting): |
81 | void h() { |
82 | struct S5 { |
83 | int i1; |
84 | __unsafe_unretained id o1; |
85 | struct V { |
86 | int i2; |
87 | __unsafe_unretained id o2; |
88 | } v1; |
89 | int i3; |
90 | union UI { |
91 | void * i1; |
92 | __unsafe_unretained id o1; |
93 | int i3; |
94 | __unsafe_unretained id o3; |
95 | }ui; |
96 | }; |
97 | |
98 | union U { |
99 | void * i1; |
100 | __unsafe_unretained id o1; |
101 | int i3; |
102 | __unsafe_unretained id o3; |
103 | }ui; |
104 | |
105 | struct S5 s2; |
106 | union U u2; |
107 | __block id block_id; |
108 | |
109 | /** |
110 | block variable layout: BL_NON_OBJECT_WORD:1, BL_UNRETAINE:1, BL_NON_OBJECT_WORD:1, |
111 | BL_UNRETAINE:1, BL_NON_OBJECT_WORD:3, BL_BYREF:1, BL_OPERATOR:0 |
112 | */ |
113 | // CHECK: Block variable layout: BL_BYREF:1, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_OPERATOR:0 |
114 | void (^c)() = ^{ |
115 | x(s2.ui.o1); |
116 | x(u2.o1); |
117 | block_id = 0; |
118 | }; |
119 | c(); |
120 | } |
121 | |
122 | // Test for array of stuff. |
123 | void arr1() { |
124 | struct S { |
125 | __unsafe_unretained id unsafe_unretained_var[4]; |
126 | } imported_s; |
127 | |
128 | // CHECK: Block variable layout: BL_UNRETAINED:4, BL_OPERATOR:0 |
129 | void (^c)() = ^{ |
130 | x(imported_s.unsafe_unretained_var[2]); |
131 | }; |
132 | |
133 | c(); |
134 | } |
135 | |
136 | // Test2 for array of stuff. |
137 | void arr2() { |
138 | struct S { |
139 | int a; |
140 | __unsafe_unretained id unsafe_unretained_var[4]; |
141 | } imported_s; |
142 | |
143 | // CHECK: Block variable layout: BL_NON_OBJECT_WORD:1, BL_UNRETAINED:4, BL_OPERATOR:0 |
144 | void (^c)() = ^{ |
145 | x(imported_s.unsafe_unretained_var[2]); |
146 | }; |
147 | |
148 | c(); |
149 | } |
150 | |
151 | // Test3 for array of stuff. |
152 | void arr3() { |
153 | struct S { |
154 | int a; |
155 | __unsafe_unretained id unsafe_unretained_var[0]; |
156 | } imported_s; |
157 | |
158 | // CHECK: Block variable layout: BL_OPERATOR:0 |
159 | void (^c)() = ^{ |
160 | int i = imported_s.a; |
161 | }; |
162 | |
163 | c(); |
164 | } |
165 | |
166 | |
167 | // Test4 for array of stuff. |
168 | @class B; |
169 | void arr4() { |
170 | struct S { |
171 | struct s0 { |
172 | __unsafe_unretained id s_f0; |
173 | __unsafe_unretained id s_f1; |
174 | } f0; |
175 | |
176 | __unsafe_unretained id f1; |
177 | |
178 | struct s1 { |
179 | int *f0; |
180 | __unsafe_unretained B *f1; |
181 | } f4[2][2]; |
182 | } captured_s; |
183 | |
184 | // CHECK: Block variable layout: BL_UNRETAINED:3, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_OPERATOR:0 |
185 | void (^c)() = ^{ |
186 | id i = captured_s.f0.s_f1; |
187 | }; |
188 | |
189 | c(); |
190 | } |
191 | |
192 | // Test1 bitfield in cpatured aggregate. |
193 | void bf1() { |
194 | struct S { |
195 | int flag : 25; |
196 | int flag1: 7; |
197 | int flag2 :1; |
198 | int flag3: 7; |
199 | int flag4: 24; |
200 | } s; |
201 | |
202 | // CHECK: Block variable layout: BL_OPERATOR:0 |
203 | int (^c)() = ^{ |
204 | return s.flag; |
205 | }; |
206 | c(); |
207 | } |
208 | |
209 | // Test2 bitfield in cpatured aggregate. |
210 | void bf2() { |
211 | struct S { |
212 | int flag : 1; |
213 | } s; |
214 | |
215 | // CHECK: Block variable layout: BL_OPERATOR:0 |
216 | int (^c)() = ^{ |
217 | return s.flag; |
218 | }; |
219 | c(); |
220 | } |
221 | |
222 | // Test3 bitfield in cpatured aggregate. |
223 | void bf3() { |
224 | |
225 | struct { |
226 | unsigned short _reserved : 16; |
227 | |
228 | unsigned char _draggedNodesAreDeletable: 1; |
229 | unsigned char _draggedOutsideOutlineView : 1; |
230 | unsigned char _adapterRespondsTo_addRootPaths : 1; |
231 | unsigned char _adapterRespondsTo_moveDataNodes : 1; |
232 | unsigned char _adapterRespondsTo_removeRootDataNode : 1; |
233 | unsigned char _adapterRespondsTo_doubleClickDataNode : 1; |
234 | unsigned char _adapterRespondsTo_selectDataNode : 1; |
235 | unsigned char _adapterRespondsTo_textDidEndEditing : 1; |
236 | unsigned char _adapterRespondsTo_updateAndSaveRoots : 1; |
237 | unsigned char _adapterRespondsTo_askToDeleteRootNodes : 1; |
238 | unsigned char _adapterRespondsTo_contextMenuForSelectedNodes : 1; |
239 | unsigned char _adapterRespondsTo_pasteboardFilenamesForNodes : 1; |
240 | unsigned char _adapterRespondsTo_writeItemsToPasteboard : 1; |
241 | unsigned char _adapterRespondsTo_writeItemsToPasteboardXXXX : 1; |
242 | |
243 | unsigned int _filler : 32; |
244 | } _flags; |
245 | |
246 | // CHECK: Block variable layout: BL_OPERATOR:0 |
247 | unsigned char (^c)() = ^{ |
248 | return _flags._draggedNodesAreDeletable; |
249 | }; |
250 | |
251 | c(); |
252 | } |
253 | |
254 | // Test4 unnamed bitfield |
255 | void bf4() { |
256 | |
257 | struct { |
258 | unsigned short _reserved : 16; |
259 | |
260 | unsigned char _draggedNodesAreDeletable: 1; |
261 | unsigned char _draggedOutsideOutlineView : 1; |
262 | unsigned char _adapterRespondsTo_addRootPaths : 1; |
263 | unsigned char _adapterRespondsTo_moveDataNodes : 1; |
264 | unsigned char _adapterRespondsTo_removeRootDataNode : 1; |
265 | unsigned char _adapterRespondsTo_doubleClickDataNode : 1; |
266 | unsigned char _adapterRespondsTo_selectDataNode : 1; |
267 | unsigned char _adapterRespondsTo_textDidEndEditing : 1; |
268 | |
269 | unsigned long long : 64; |
270 | |
271 | unsigned char _adapterRespondsTo_updateAndSaveRoots : 1; |
272 | unsigned char _adapterRespondsTo_askToDeleteRootNodes : 1; |
273 | unsigned char _adapterRespondsTo_contextMenuForSelectedNodes : 1; |
274 | unsigned char _adapterRespondsTo_pasteboardFilenamesForNodes : 1; |
275 | unsigned char _adapterRespondsTo_writeItemsToPasteboard : 1; |
276 | unsigned char _adapterRespondsTo_writeItemsToPasteboardXXXX : 1; |
277 | |
278 | unsigned int _filler : 32; |
279 | } _flags; |
280 | |
281 | // CHECK: Block variable layout: BL_OPERATOR:0 |
282 | unsigned char (^c)() = ^{ |
283 | return _flags._draggedNodesAreDeletable; |
284 | }; |
285 | |
286 | c(); |
287 | } |
288 | |
289 | |
290 | |
291 | // Test5 unnamed bitfield. |
292 | void bf5() { |
293 | struct { |
294 | unsigned char flag : 1; |
295 | unsigned int : 32; |
296 | unsigned char flag1 : 1; |
297 | } _flags; |
298 | |
299 | // CHECK: Block variable layout: BL_OPERATOR:0 |
300 | unsigned char (^c)() = ^{ |
301 | return _flags.flag; |
302 | }; |
303 | |
304 | c(); |
305 | } |
306 | |
307 | |
308 | // Test6 0 length bitfield. |
309 | void bf6() { |
310 | struct { |
311 | unsigned char flag : 1; |
312 | unsigned int : 0; |
313 | unsigned char flag1 : 1; |
314 | } _flags; |
315 | |
316 | // CHECK: Block variable layout: BL_OPERATOR:0 |
317 | unsigned char (^c)() = ^{ |
318 | return _flags.flag; |
319 | }; |
320 | |
321 | c(); |
322 | } |
323 | |
324 | // Test7 large number of captured variables. |
325 | void Test7() { |
326 | __weak id wid; |
327 | __weak id wid1, wid2, wid3, wid4; |
328 | __weak id wid5, wid6, wid7, wid8; |
329 | __weak id wid9, wid10, wid11, wid12; |
330 | __weak id wid13, wid14, wid15, wid16; |
331 | const id bar = (id) opaque_id(); |
332 | // CHECK: Block variable layout: BL_STRONG:1, BL_WEAK:16, BL_OPERATOR:0 |
333 | void (^b)() = ^{ |
334 | x(bar); |
335 | x(wid1); |
336 | x(wid2); |
337 | x(wid3); |
338 | x(wid4); |
339 | x(wid5); |
340 | x(wid6); |
341 | x(wid7); |
342 | x(wid8); |
343 | x(wid9); |
344 | x(wid10); |
345 | x(wid11); |
346 | x(wid12); |
347 | x(wid13); |
348 | x(wid14); |
349 | x(wid15); |
350 | x(wid16); |
351 | }; |
352 | } |
353 | |
354 | |
355 | // Test 8 very large number of captured variables. |
356 | void Test8() { |
357 | __weak id wid; |
358 | __weak id wid1, wid2, wid3, wid4; |
359 | __weak id wid5, wid6, wid7, wid8; |
360 | __weak id wid9, wid10, wid11, wid12; |
361 | __weak id wid13, wid14, wid15, wid16; |
362 | __weak id w1, w2, w3, w4; |
363 | __weak id w5, w6, w7, w8; |
364 | __weak id w9, w10, w11, w12; |
365 | __weak id w13, w14, w15, w16; |
366 | const id bar = (id) opaque_id(); |
367 | // CHECK: Block variable layout: BL_STRONG:1, BL_WEAK:16, BL_WEAK:16, BL_WEAK:1, BL_OPERATOR:0 |
368 | void (^b)() = ^{ |
369 | x(bar); |
370 | x(wid1); |
371 | x(wid2); |
372 | x(wid3); |
373 | x(wid4); |
374 | x(wid5); |
375 | x(wid6); |
376 | x(wid7); |
377 | x(wid8); |
378 | x(wid9); |
379 | x(wid10); |
380 | x(wid11); |
381 | x(wid12); |
382 | x(wid13); |
383 | x(wid14); |
384 | x(wid15); |
385 | x(wid16); |
386 | x(w1); |
387 | x(w2); |
388 | x(w3); |
389 | x(w4); |
390 | x(w5); |
391 | x(w6); |
392 | x(w7); |
393 | x(w8); |
394 | x(w9); |
395 | x(w10); |
396 | x(w11); |
397 | x(w12); |
398 | x(w13); |
399 | x(w14); |
400 | x(w15); |
401 | x(w16); |
402 | x(wid); |
403 | }; |
404 | } |
405 | |