]>
Commit | Line | Data |
---|---|---|
f027ee7c | 1 | /* Routines dealing with ObjC encoding of types |
99dee823 | 2 | Copyright (C) 1992-2021 Free Software Foundation, Inc. |
f027ee7c NP |
3 | |
4 | This file is part of GCC. | |
5 | ||
6 | GCC is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 3, or (at your option) | |
9 | any later version. | |
10 | ||
11 | GCC is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with GCC; see the file COPYING3. If not see | |
18 | <http://www.gnu.org/licenses/>. */ | |
19 | ||
20 | #include "config.h" | |
21 | #include "system.h" | |
22 | #include "coretypes.h" | |
23 | #include "tree.h" | |
c7131fb2 | 24 | #include "options.h" |
d8a2d370 DN |
25 | #include "stringpool.h" |
26 | #include "stor-layout.h" | |
f027ee7c NP |
27 | |
28 | #ifdef OBJCPLUS | |
d4a10d0a | 29 | #include "cp/cp-tree.h" |
f027ee7c | 30 | #else |
d4a10d0a SB |
31 | #include "c/c-tree.h" |
32 | #include "c/c-lang.h" | |
f027ee7c NP |
33 | #endif |
34 | ||
f027ee7c NP |
35 | #include "c-family/c-objc.h" |
36 | ||
37 | #include "objc-encoding.h" | |
38 | #include "objc-act.h" | |
39 | ||
40 | /* For my_build_string(). */ | |
41 | #include "objc-runtime-shared-support.h" | |
42 | ||
43 | /* For BITS_PER_UNIT. */ | |
f027ee7c NP |
44 | |
45 | /* When building Objective-C++, we are not linking against the C front-end | |
46 | and so need to replicate the C tree-construction functions in some way. */ | |
47 | #ifdef OBJCPLUS | |
48 | #define OBJCP_REMAP_FUNCTIONS | |
49 | #include "objcp-decl.h" | |
50 | #endif /* OBJCPLUS */ | |
51 | ||
52 | /* Set up for use of obstacks. */ | |
f027ee7c | 53 | |
a8f18c40 NP |
54 | /* This obstack is used to accumulate the encoding of a data type. */ |
55 | static struct obstack util_obstack; | |
f027ee7c NP |
56 | |
57 | /* This points to the beginning of obstack contents, so we can free | |
a8f18c40 NP |
58 | the whole contents. */ |
59 | static char *util_firstobj; | |
60 | ||
61 | void objc_encoding_init (void) | |
62 | { | |
63 | gcc_obstack_init (&util_obstack); | |
64 | util_firstobj = (char *) obstack_finish (&util_obstack); | |
65 | } | |
f027ee7c NP |
66 | |
67 | int generating_instance_variables = 0; | |
68 | ||
69 | static void encode_type_qualifiers (tree); | |
70 | static void encode_type (tree, int, int); | |
a8f18c40 | 71 | static void encode_field (tree field_decl, int curtype, int format); |
f027ee7c NP |
72 | |
73 | static tree | |
74 | objc_method_parm_type (tree type) | |
75 | { | |
76 | type = TREE_VALUE (TREE_TYPE (type)); | |
77 | if (TREE_CODE (type) == TYPE_DECL) | |
78 | type = TREE_TYPE (type); | |
79 | return type; | |
80 | } | |
81 | ||
82 | static int | |
83 | objc_encoded_type_size (tree type) | |
84 | { | |
85 | int sz = int_size_in_bytes (type); | |
86 | ||
87 | /* Make all integer and enum types at least as large | |
88 | as an int. */ | |
89 | if (sz > 0 && INTEGRAL_TYPE_P (type)) | |
90 | sz = MAX (sz, int_size_in_bytes (integer_type_node)); | |
91 | /* Treat arrays as pointers, since that's how they're | |
92 | passed in. */ | |
93 | else if (TREE_CODE (type) == ARRAY_TYPE) | |
94 | sz = int_size_in_bytes (ptr_type_node); | |
95 | return sz; | |
96 | } | |
97 | ||
98 | /* Encode a method prototype. */ | |
99 | tree | |
100 | encode_method_prototype (tree method_decl) | |
101 | { | |
102 | tree parms; | |
103 | int parm_offset, i; | |
104 | char buf[40]; | |
105 | tree result; | |
106 | ||
107 | /* ONEWAY and BYCOPY, for remote object are the only method qualifiers. */ | |
108 | encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (method_decl))); | |
109 | ||
110 | /* Encode return type. */ | |
111 | encode_type (objc_method_parm_type (method_decl), | |
112 | obstack_object_size (&util_obstack), | |
113 | OBJC_ENCODE_INLINE_DEFS); | |
114 | ||
115 | /* Stack size. */ | |
116 | /* The first two arguments (self and _cmd) are pointers; account for | |
117 | their size. */ | |
118 | i = int_size_in_bytes (ptr_type_node); | |
119 | parm_offset = 2 * i; | |
120 | for (parms = METHOD_SEL_ARGS (method_decl); parms; | |
121 | parms = DECL_CHAIN (parms)) | |
122 | { | |
123 | tree type = objc_method_parm_type (parms); | |
124 | int sz = objc_encoded_type_size (type); | |
125 | ||
126 | /* If a type size is not known, bail out. */ | |
127 | if (sz < 0) | |
128 | { | |
129 | error_at (DECL_SOURCE_LOCATION (method_decl), | |
130 | "type %qT does not have a known size", | |
131 | type); | |
132 | /* Pretend that the encoding succeeded; the compilation will | |
133 | fail nevertheless. */ | |
134 | goto finish_encoding; | |
135 | } | |
136 | parm_offset += sz; | |
137 | } | |
138 | ||
139 | sprintf (buf, "%d@0:%d", parm_offset, i); | |
140 | obstack_grow (&util_obstack, buf, strlen (buf)); | |
141 | ||
142 | /* Argument types. */ | |
143 | parm_offset = 2 * i; | |
144 | for (parms = METHOD_SEL_ARGS (method_decl); parms; | |
145 | parms = DECL_CHAIN (parms)) | |
146 | { | |
147 | tree type = objc_method_parm_type (parms); | |
148 | ||
149 | /* Process argument qualifiers for user supplied arguments. */ | |
150 | encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (parms))); | |
151 | ||
152 | /* Type. */ | |
153 | encode_type (type, obstack_object_size (&util_obstack), | |
154 | OBJC_ENCODE_INLINE_DEFS); | |
155 | ||
156 | /* Compute offset. */ | |
157 | sprintf (buf, "%d", parm_offset); | |
158 | parm_offset += objc_encoded_type_size (type); | |
159 | ||
160 | obstack_grow (&util_obstack, buf, strlen (buf)); | |
161 | } | |
162 | ||
163 | finish_encoding: | |
164 | obstack_1grow (&util_obstack, '\0'); | |
165 | result = get_identifier (XOBFINISH (&util_obstack, char *)); | |
166 | obstack_free (&util_obstack, util_firstobj); | |
167 | return result; | |
168 | } | |
169 | ||
170 | /* This is used to implement @encode(). */ | |
171 | tree | |
172 | objc_build_encode_expr (tree type) | |
173 | { | |
174 | tree result; | |
175 | const char *string; | |
176 | ||
177 | encode_type (type, obstack_object_size (&util_obstack), | |
178 | OBJC_ENCODE_INLINE_DEFS); | |
179 | obstack_1grow (&util_obstack, 0); /* null terminate string */ | |
180 | string = XOBFINISH (&util_obstack, const char *); | |
181 | ||
182 | /* Synthesize a string that represents the encoded struct/union. */ | |
183 | result = my_build_string (strlen (string) + 1, string); | |
184 | obstack_free (&util_obstack, util_firstobj); | |
185 | return result; | |
186 | } | |
187 | ||
188 | /* "Encode" a data type into a string, which grows in util_obstack. | |
189 | ||
190 | The format is described in gcc/doc/objc.texi, section 'Type | |
191 | encoding'. | |
192 | ||
193 | Most of the encode_xxx functions have a 'type' argument, which is | |
194 | the type to encode, and an integer 'curtype' argument, which is the | |
195 | index in the encoding string of the beginning of the encoding of | |
196 | the current type, and allows you to find what characters have | |
197 | already been written for the current type (they are the ones in the | |
198 | current encoding string starting from 'curtype'). | |
199 | ||
200 | For example, if we are encoding a method which returns 'int' and | |
201 | takes a 'char **' argument, then when we get to the point of | |
202 | encoding the 'char **' argument, the encoded string already | |
203 | contains 'i12@0:4' (assuming a pointer size of 4 bytes). So, | |
204 | 'curtype' will be set to 7 when starting to encode 'char **'. | |
205 | During the whole of the encoding of 'char **', 'curtype' will be | |
206 | fixed at 7, so the routine encoding the second pointer can find out | |
207 | that it's actually encoding a pointer to a pointer by looking | |
208 | backwards at what has already been encoded for the current type, | |
209 | and seeing there is a "^" (meaning a pointer) in there. */ | |
210 | ||
211 | ||
212 | /* Encode type qualifiers encodes one of the "PQ" Objective-C | |
213 | keywords, ie 'in', 'out', 'inout', 'bycopy', 'byref', 'oneway'. | |
214 | 'const', instead, is encoded directly as part of the type. */ | |
215 | static void | |
216 | encode_type_qualifiers (tree declspecs) | |
217 | { | |
218 | tree spec; | |
219 | ||
220 | for (spec = declspecs; spec; spec = TREE_CHAIN (spec)) | |
221 | { | |
222 | /* FIXME: Shouldn't we use token->keyword here ? */ | |
223 | if (ridpointers[(int) RID_IN] == TREE_VALUE (spec)) | |
224 | obstack_1grow (&util_obstack, 'n'); | |
225 | else if (ridpointers[(int) RID_INOUT] == TREE_VALUE (spec)) | |
226 | obstack_1grow (&util_obstack, 'N'); | |
227 | else if (ridpointers[(int) RID_OUT] == TREE_VALUE (spec)) | |
228 | obstack_1grow (&util_obstack, 'o'); | |
229 | else if (ridpointers[(int) RID_BYCOPY] == TREE_VALUE (spec)) | |
230 | obstack_1grow (&util_obstack, 'O'); | |
231 | else if (ridpointers[(int) RID_BYREF] == TREE_VALUE (spec)) | |
232 | obstack_1grow (&util_obstack, 'R'); | |
233 | else if (ridpointers[(int) RID_ONEWAY] == TREE_VALUE (spec)) | |
234 | obstack_1grow (&util_obstack, 'V'); | |
235 | else | |
236 | gcc_unreachable (); | |
237 | } | |
238 | } | |
239 | ||
240 | /* Determine if a pointee is marked read-only. Only used by the NeXT | |
241 | runtime to be compatible with gcc-3.3. */ | |
242 | static bool | |
243 | pointee_is_readonly (tree pointee) | |
244 | { | |
245 | while (POINTER_TYPE_P (pointee)) | |
246 | pointee = TREE_TYPE (pointee); | |
247 | ||
248 | return TYPE_READONLY (pointee); | |
249 | } | |
250 | ||
251 | /* Encode a pointer type. */ | |
252 | static void | |
253 | encode_pointer (tree type, int curtype, int format) | |
254 | { | |
255 | tree pointer_to = TREE_TYPE (type); | |
256 | ||
257 | if (flag_next_runtime) | |
258 | { | |
259 | /* This code is used to be compatible with gcc-3.3. */ | |
260 | /* For historical/compatibility reasons, the read-only qualifier | |
261 | of the pointee gets emitted _before_ the '^'. The read-only | |
262 | qualifier of the pointer itself gets ignored, _unless_ we are | |
263 | looking at a typedef! Also, do not emit the 'r' for anything | |
264 | but the outermost type! */ | |
265 | if (!generating_instance_variables | |
266 | && (obstack_object_size (&util_obstack) - curtype <= 1) | |
267 | && (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL | |
268 | ? TYPE_READONLY (type) | |
269 | : pointee_is_readonly (pointer_to))) | |
270 | obstack_1grow (&util_obstack, 'r'); | |
271 | } | |
272 | ||
273 | if (TREE_CODE (pointer_to) == RECORD_TYPE) | |
274 | { | |
275 | if (OBJC_TYPE_NAME (pointer_to) | |
276 | && TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE) | |
277 | { | |
278 | const char *name = IDENTIFIER_POINTER (OBJC_TYPE_NAME (pointer_to)); | |
279 | ||
280 | if (strcmp (name, TAG_OBJECT) == 0) /* '@' */ | |
281 | { | |
282 | obstack_1grow (&util_obstack, '@'); | |
283 | return; | |
284 | } | |
285 | else if (TYPE_HAS_OBJC_INFO (pointer_to) | |
286 | && TYPE_OBJC_INTERFACE (pointer_to)) | |
287 | { | |
288 | if (generating_instance_variables) | |
289 | { | |
290 | obstack_1grow (&util_obstack, '@'); | |
291 | obstack_1grow (&util_obstack, '"'); | |
292 | obstack_grow (&util_obstack, name, strlen (name)); | |
293 | obstack_1grow (&util_obstack, '"'); | |
294 | return; | |
295 | } | |
296 | else | |
297 | { | |
298 | obstack_1grow (&util_obstack, '@'); | |
299 | return; | |
300 | } | |
301 | } | |
302 | else if (strcmp (name, TAG_CLASS) == 0) /* '#' */ | |
303 | { | |
304 | obstack_1grow (&util_obstack, '#'); | |
305 | return; | |
306 | } | |
307 | else if (strcmp (name, TAG_SELECTOR) == 0) /* ':' */ | |
308 | { | |
309 | obstack_1grow (&util_obstack, ':'); | |
310 | return; | |
311 | } | |
312 | } | |
313 | } | |
314 | else if (TREE_CODE (pointer_to) == INTEGER_TYPE | |
315 | && TYPE_MODE (pointer_to) == QImode) | |
316 | { | |
317 | tree pname = TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE | |
318 | ? OBJC_TYPE_NAME (pointer_to) | |
319 | : DECL_NAME (OBJC_TYPE_NAME (pointer_to)); | |
320 | ||
321 | /* (BOOL *) are an exception and are encoded as ^c, while all | |
322 | other pointers to char are encoded as *. */ | |
323 | if (strcmp (IDENTIFIER_POINTER (pname), "BOOL")) | |
324 | { | |
325 | if (!flag_next_runtime) | |
326 | { | |
327 | /* The NeXT runtime adds the 'r' before getting here. */ | |
328 | ||
329 | /* It appears that "r*" means "const char *" rather than | |
330 | "char *const". "char *const" is encoded as "*", | |
331 | which is identical to "char *", so the "const" is | |
332 | unfortunately lost. */ | |
333 | if (TYPE_READONLY (pointer_to)) | |
334 | obstack_1grow (&util_obstack, 'r'); | |
335 | } | |
336 | ||
337 | obstack_1grow (&util_obstack, '*'); | |
338 | return; | |
339 | } | |
340 | } | |
341 | ||
342 | /* We have a normal pointer type that does not get special treatment. */ | |
343 | obstack_1grow (&util_obstack, '^'); | |
344 | encode_type (pointer_to, curtype, format); | |
345 | } | |
346 | ||
347 | static void | |
348 | encode_array (tree type, int curtype, int format) | |
349 | { | |
350 | tree an_int_cst = TYPE_SIZE (type); | |
351 | tree array_of = TREE_TYPE (type); | |
352 | char buffer[40]; | |
353 | ||
354 | if (an_int_cst == NULL) | |
355 | { | |
356 | /* We are trying to encode an incomplete array. An incomplete | |
357 | array is forbidden as part of an instance variable; but it | |
358 | may occur if the instance variable is a pointer to such an | |
359 | array. */ | |
360 | ||
361 | /* So the only case in which an incomplete array could occur | |
362 | (without being pointed to) is if we are encoding the | |
363 | arguments or return value of a method. In that case, an | |
364 | incomplete array argument or return value (eg, | |
365 | -(void)display: (char[])string) is treated like a pointer | |
366 | because that is how the compiler does the function call. A | |
367 | special, more complicated case, is when the incomplete array | |
368 | is the last member of a struct (eg, if we are encoding | |
369 | "struct { unsigned long int a;double b[];}"), which is again | |
370 | part of a method argument/return value. In that case, we | |
371 | really need to communicate to the runtime that there is an | |
372 | incomplete array (not a pointer!) there. So, we detect that | |
373 | special case and encode it as a zero-length array. | |
374 | ||
375 | Try to detect that we are part of a struct. We do this by | |
376 | searching for '=' in the type encoding for the current type. | |
377 | NB: This hack assumes that you can't use '=' as part of a C | |
378 | identifier. | |
379 | */ | |
380 | { | |
19a9ba64 | 381 | char *enc = (char *) obstack_base (&util_obstack) + curtype; |
f027ee7c NP |
382 | if (memchr (enc, '=', |
383 | obstack_object_size (&util_obstack) - curtype) == NULL) | |
384 | { | |
385 | /* We are not inside a struct. Encode the array as a | |
386 | pointer. */ | |
387 | encode_pointer (type, curtype, format); | |
388 | return; | |
389 | } | |
390 | } | |
391 | ||
392 | /* Else, we are in a struct, and we encode it as a zero-length | |
393 | array. */ | |
394 | sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT)0); | |
395 | } | |
396 | else if (TREE_INT_CST_LOW (TYPE_SIZE (array_of)) == 0) | |
397 | sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT)0); | |
398 | else | |
399 | sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC, | |
400 | TREE_INT_CST_LOW (an_int_cst) | |
401 | / TREE_INT_CST_LOW (TYPE_SIZE (array_of))); | |
402 | ||
403 | obstack_grow (&util_obstack, buffer, strlen (buffer)); | |
404 | encode_type (array_of, curtype, format); | |
405 | obstack_1grow (&util_obstack, ']'); | |
406 | return; | |
407 | } | |
408 | ||
409 | /* Encode a vector. The vector type is a GCC extension to C. */ | |
410 | static void | |
411 | encode_vector (tree type, int curtype, int format) | |
412 | { | |
413 | tree vector_of = TREE_TYPE (type); | |
414 | char buffer[40]; | |
415 | ||
416 | /* Vectors are like simple fixed-size arrays. */ | |
417 | ||
418 | /* Output ![xx,yy,<code>] where xx is the vector_size, yy is the | |
419 | alignment of the vector, and <code> is the base type. Eg, int | |
420 | __attribute__ ((vector_size (16))) gets encoded as ![16,32,i] | |
421 | assuming that the alignment is 32 bytes. We include size and | |
422 | alignment in bytes so that the runtime does not have to have any | |
423 | knowledge of the actual types. | |
424 | */ | |
425 | sprintf (buffer, "![" HOST_WIDE_INT_PRINT_DEC ",%d", | |
426 | /* We want to compute the equivalent of sizeof (<vector>). | |
427 | Code inspired by c_sizeof_or_alignof_type. */ | |
428 | ((TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type)) | |
429 | / (TYPE_PRECISION (char_type_node) / BITS_PER_UNIT))), | |
430 | /* We want to compute the equivalent of __alignof__ | |
431 | (<vector>). Code inspired by | |
432 | c_sizeof_or_alignof_type. */ | |
433 | TYPE_ALIGN_UNIT (type)); | |
434 | obstack_grow (&util_obstack, buffer, strlen (buffer)); | |
435 | encode_type (vector_of, curtype, format); | |
436 | obstack_1grow (&util_obstack, ']'); | |
437 | return; | |
438 | } | |
439 | ||
440 | static void | |
441 | encode_aggregate_fields (tree type, bool pointed_to, int curtype, int format) | |
442 | { | |
443 | tree field = TYPE_FIELDS (type); | |
444 | ||
445 | for (; field; field = DECL_CHAIN (field)) | |
446 | { | |
447 | #ifdef OBJCPLUS | |
448 | /* C++ static members, and things that are not field at all, | |
449 | should not appear in the encoding. */ | |
450 | if (TREE_CODE (field) != FIELD_DECL || TREE_STATIC (field)) | |
451 | continue; | |
452 | #endif | |
453 | ||
454 | /* Recursively encode fields of embedded base classes. */ | |
455 | if (DECL_ARTIFICIAL (field) && !DECL_NAME (field) | |
456 | && TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE) | |
457 | { | |
458 | encode_aggregate_fields (TREE_TYPE (field), | |
459 | pointed_to, curtype, format); | |
460 | continue; | |
461 | } | |
462 | ||
463 | if (generating_instance_variables && !pointed_to) | |
464 | { | |
465 | tree fname = DECL_NAME (field); | |
466 | ||
467 | obstack_1grow (&util_obstack, '"'); | |
468 | ||
469 | if (fname && TREE_CODE (fname) == IDENTIFIER_NODE) | |
470 | obstack_grow (&util_obstack, | |
471 | IDENTIFIER_POINTER (fname), | |
472 | strlen (IDENTIFIER_POINTER (fname))); | |
473 | ||
474 | obstack_1grow (&util_obstack, '"'); | |
475 | } | |
476 | ||
a8f18c40 | 477 | encode_field (field, curtype, format); |
f027ee7c NP |
478 | } |
479 | } | |
480 | ||
481 | static void | |
482 | encode_aggregate_within (tree type, int curtype, int format, int left, | |
483 | int right) | |
484 | { | |
485 | tree name; | |
486 | /* NB: aggregates that are pointed to have slightly different encoding | |
487 | rules in that you never encode the names of instance variables. */ | |
488 | int ob_size = obstack_object_size (&util_obstack); | |
489 | bool inline_contents = false; | |
490 | bool pointed_to = false; | |
491 | ||
492 | if (flag_next_runtime) | |
493 | { | |
c240b3e0 AM |
494 | if (ob_size > 0 |
495 | && *((char *) obstack_next_free (&util_obstack) - 1) == '^') | |
f027ee7c NP |
496 | pointed_to = true; |
497 | ||
498 | if ((format == OBJC_ENCODE_INLINE_DEFS || generating_instance_variables) | |
499 | && (!pointed_to || ob_size - curtype == 1 | |
500 | || (ob_size - curtype == 2 | |
c240b3e0 | 501 | && *((char *) obstack_next_free (&util_obstack) - 2) == 'r'))) |
f027ee7c NP |
502 | inline_contents = true; |
503 | } | |
504 | else | |
505 | { | |
506 | /* c0 and c1 are the last two characters in the encoding of the | |
507 | current type; if the last two characters were '^' or '^r', | |
508 | then we are encoding an aggregate that is "pointed to". The | |
509 | comment above applies: in that case we should avoid encoding | |
510 | the names of instance variables. | |
511 | */ | |
c240b3e0 | 512 | char c0, c1; |
f027ee7c | 513 | |
c240b3e0 AM |
514 | c1 = ob_size > 1 ? *((char *) obstack_next_free (&util_obstack) - 2) : 0; |
515 | c0 = ob_size > 0 ? *((char *) obstack_next_free (&util_obstack) - 1) : 0; | |
f027ee7c NP |
516 | if (c0 == '^' || (c1 == '^' && c0 == 'r')) |
517 | pointed_to = true; | |
518 | ||
519 | if (format == OBJC_ENCODE_INLINE_DEFS || generating_instance_variables) | |
520 | { | |
521 | if (!pointed_to) | |
522 | inline_contents = true; | |
523 | else | |
524 | { | |
525 | /* Note that the check (ob_size - curtype < 2) prevents | |
526 | infinite recursion when encoding a structure which is | |
527 | a linked list (eg, struct node { struct node *next; | |
528 | }). Each time we follow a pointer, we add one | |
529 | character to ob_size, and curtype is fixed, so after | |
530 | at most two pointers we stop inlining contents and | |
531 | break the loop. | |
532 | ||
533 | The other case where we don't inline is "^r", which | |
534 | is a pointer to a constant struct. | |
535 | */ | |
536 | if ((ob_size - curtype <= 2) && !(c0 == 'r')) | |
537 | inline_contents = true; | |
538 | } | |
539 | } | |
540 | } | |
541 | ||
542 | /* Traverse struct aliases; it is important to get the | |
543 | original struct and its tag name (if any). */ | |
544 | type = TYPE_MAIN_VARIANT (type); | |
545 | name = OBJC_TYPE_NAME (type); | |
546 | /* Open parenth/bracket. */ | |
547 | obstack_1grow (&util_obstack, left); | |
548 | ||
549 | /* Encode the struct/union tag name, or '?' if a tag was | |
550 | not provided. Typedef aliases do not qualify. */ | |
551 | #ifdef OBJCPLUS | |
552 | /* For compatibility with the NeXT runtime, ObjC++ encodes template | |
553 | args as a composite struct tag name. */ | |
554 | if (name && TREE_CODE (name) == IDENTIFIER_NODE | |
555 | /* Did this struct have a tag? */ | |
6a7b9203 | 556 | && !TYPE_WAS_UNNAMED (type)) |
f027ee7c NP |
557 | obstack_grow (&util_obstack, |
558 | decl_as_string (type, TFF_DECL_SPECIFIERS | TFF_UNQUALIFIED_NAME), | |
559 | strlen (decl_as_string (type, TFF_DECL_SPECIFIERS | TFF_UNQUALIFIED_NAME))); | |
560 | #else | |
561 | if (name && TREE_CODE (name) == IDENTIFIER_NODE) | |
562 | obstack_grow (&util_obstack, | |
563 | IDENTIFIER_POINTER (name), | |
564 | strlen (IDENTIFIER_POINTER (name))); | |
565 | #endif | |
566 | else | |
567 | obstack_1grow (&util_obstack, '?'); | |
568 | ||
569 | /* Encode the types (and possibly names) of the inner fields, | |
570 | if required. */ | |
571 | if (inline_contents) | |
572 | { | |
573 | obstack_1grow (&util_obstack, '='); | |
574 | encode_aggregate_fields (type, pointed_to, curtype, format); | |
575 | } | |
576 | /* Close parenth/bracket. */ | |
577 | obstack_1grow (&util_obstack, right); | |
578 | } | |
579 | ||
580 | /* Encode a bitfield NeXT-style (i.e., without a bit offset or the underlying | |
581 | field type. */ | |
582 | static void | |
583 | encode_next_bitfield (int width) | |
584 | { | |
585 | char buffer[40]; | |
586 | sprintf (buffer, "b%d", width); | |
587 | obstack_grow (&util_obstack, buffer, strlen (buffer)); | |
588 | } | |
589 | ||
590 | /* Encodes 'type', ignoring type qualifiers (which you should encode | |
591 | beforehand if needed) with the exception of 'const', which is | |
592 | encoded by encode_type. See above for the explanation of | |
593 | 'curtype'. 'format' can be OBJC_ENCODE_INLINE_DEFS or | |
594 | OBJC_ENCODE_DONT_INLINE_DEFS. */ | |
595 | static void | |
596 | encode_type (tree type, int curtype, int format) | |
597 | { | |
598 | enum tree_code code = TREE_CODE (type); | |
599 | ||
600 | /* Ignore type qualifiers other than 'const' when encoding a | |
601 | type. */ | |
602 | ||
603 | if (type == error_mark_node) | |
604 | return; | |
605 | ||
606 | if (!flag_next_runtime) | |
607 | { | |
608 | if (TYPE_READONLY (type)) | |
609 | obstack_1grow (&util_obstack, 'r'); | |
610 | } | |
611 | ||
612 | switch (code) | |
613 | { | |
614 | case ENUMERAL_TYPE: | |
615 | if (flag_next_runtime) | |
616 | { | |
617 | /* Kludge for backwards-compatibility with gcc-3.3: enums | |
618 | are always encoded as 'i' no matter what type they | |
619 | actually are (!). */ | |
620 | obstack_1grow (&util_obstack, 'i'); | |
621 | break; | |
622 | } | |
623 | /* Else, they are encoded exactly like the integer type that is | |
624 | used by the compiler to store them. */ | |
191816a3 | 625 | /* FALLTHRU */ |
f027ee7c NP |
626 | case INTEGER_TYPE: |
627 | { | |
628 | char c; | |
7a504f33 | 629 | switch (GET_MODE_BITSIZE (SCALAR_INT_TYPE_MODE (type))) |
f027ee7c NP |
630 | { |
631 | case 8: c = TYPE_UNSIGNED (type) ? 'C' : 'c'; break; | |
632 | case 16: c = TYPE_UNSIGNED (type) ? 'S' : 's'; break; | |
633 | case 32: | |
634 | { | |
635 | tree int_type = type; | |
636 | if (flag_next_runtime) | |
637 | { | |
587ae1e3 | 638 | /* Another legacy kludge for compatibility with |
f027ee7c NP |
639 | gcc-3.3: 32-bit longs are encoded as 'l' or 'L', |
640 | but not always. For typedefs, we need to use 'i' | |
641 | or 'I' instead if encoding a struct field, or a | |
642 | pointer! */ | |
643 | int_type = ((!generating_instance_variables | |
644 | && (obstack_object_size (&util_obstack) | |
645 | == (unsigned) curtype)) | |
646 | ? TYPE_MAIN_VARIANT (type) | |
647 | : type); | |
648 | } | |
649 | if (int_type == long_unsigned_type_node | |
650 | || int_type == long_integer_type_node) | |
651 | c = TYPE_UNSIGNED (type) ? 'L' : 'l'; | |
652 | else | |
653 | c = TYPE_UNSIGNED (type) ? 'I' : 'i'; | |
654 | } | |
655 | break; | |
656 | case 64: c = TYPE_UNSIGNED (type) ? 'Q' : 'q'; break; | |
657 | case 128: c = TYPE_UNSIGNED (type) ? 'T' : 't'; break; | |
658 | default: gcc_unreachable (); | |
659 | } | |
660 | obstack_1grow (&util_obstack, c); | |
661 | break; | |
662 | } | |
663 | case REAL_TYPE: | |
664 | { | |
665 | char c; | |
666 | /* Floating point types. */ | |
b5f2d801 | 667 | switch (GET_MODE_BITSIZE (SCALAR_FLOAT_TYPE_MODE (type))) |
f027ee7c NP |
668 | { |
669 | case 32: c = 'f'; break; | |
670 | case 64: c = 'd'; break; | |
671 | case 96: | |
672 | case 128: c = 'D'; break; | |
673 | default: gcc_unreachable (); | |
674 | } | |
675 | obstack_1grow (&util_obstack, c); | |
676 | break; | |
677 | } | |
678 | case VOID_TYPE: | |
679 | obstack_1grow (&util_obstack, 'v'); | |
680 | break; | |
681 | ||
682 | case BOOLEAN_TYPE: | |
683 | obstack_1grow (&util_obstack, 'B'); | |
684 | break; | |
685 | ||
686 | case ARRAY_TYPE: | |
687 | encode_array (type, curtype, format); | |
688 | break; | |
689 | ||
690 | case POINTER_TYPE: | |
691 | #ifdef OBJCPLUS | |
692 | case REFERENCE_TYPE: | |
693 | #endif | |
694 | encode_pointer (type, curtype, format); | |
695 | break; | |
696 | ||
697 | case RECORD_TYPE: | |
698 | encode_aggregate_within (type, curtype, format, '{', '}'); | |
699 | break; | |
700 | ||
701 | case UNION_TYPE: | |
702 | encode_aggregate_within (type, curtype, format, '(', ')'); | |
703 | break; | |
704 | ||
705 | case FUNCTION_TYPE: /* '?' means an unknown type. */ | |
706 | obstack_1grow (&util_obstack, '?'); | |
707 | break; | |
708 | ||
709 | case COMPLEX_TYPE: | |
710 | /* A complex is encoded as 'j' followed by the inner type (eg, | |
711 | "_Complex int" is encoded as 'ji'). */ | |
712 | obstack_1grow (&util_obstack, 'j'); | |
713 | encode_type (TREE_TYPE (type), curtype, format); | |
714 | break; | |
715 | ||
716 | case VECTOR_TYPE: | |
717 | encode_vector (type, curtype, format); | |
718 | break; | |
719 | ||
720 | default: | |
721 | warning (0, "unknown type %<%T%> found during Objective-C encoding", | |
722 | TREE_TYPE (type)); | |
723 | obstack_1grow (&util_obstack, '?'); | |
724 | break; | |
725 | } | |
726 | ||
727 | if (flag_next_runtime) | |
728 | { | |
729 | /* Super-kludge. Some ObjC qualifier and type combinations need | |
730 | to be rearranged for compatibility with gcc-3.3. */ | |
731 | if (code == POINTER_TYPE && obstack_object_size (&util_obstack) >= 3) | |
732 | { | |
19a9ba64 | 733 | char *enc = (char *) obstack_base (&util_obstack) + curtype; |
f027ee7c NP |
734 | |
735 | /* Rewrite "in const" from "nr" to "rn". */ | |
736 | if (curtype >= 1 && !strncmp (enc - 1, "nr", 2)) | |
025d57f0 | 737 | memcpy (enc - 1, "rn", 2); |
f027ee7c NP |
738 | } |
739 | } | |
740 | } | |
741 | ||
742 | static void | |
743 | encode_gnu_bitfield (int position, tree type, int size) | |
744 | { | |
745 | enum tree_code code = TREE_CODE (type); | |
746 | char buffer[40]; | |
747 | char charType = '?'; | |
748 | ||
749 | /* This code is only executed for the GNU runtime, so we can ignore | |
750 | the NeXT runtime kludge of always encoding enums as 'i' no matter | |
751 | what integers they actually are. */ | |
752 | if (code == INTEGER_TYPE || code == ENUMERAL_TYPE) | |
753 | { | |
754 | if (integer_zerop (TYPE_MIN_VALUE (type))) | |
755 | /* Unsigned integer types. */ | |
756 | { | |
757 | switch (TYPE_MODE (type)) | |
758 | { | |
4e10a5a7 | 759 | case E_QImode: |
f027ee7c | 760 | charType = 'C'; break; |
4e10a5a7 | 761 | case E_HImode: |
f027ee7c | 762 | charType = 'S'; break; |
4e10a5a7 | 763 | case E_SImode: |
f027ee7c NP |
764 | { |
765 | if (type == long_unsigned_type_node) | |
766 | charType = 'L'; | |
767 | else | |
768 | charType = 'I'; | |
769 | break; | |
770 | } | |
4e10a5a7 | 771 | case E_DImode: |
f027ee7c NP |
772 | charType = 'Q'; break; |
773 | default: | |
774 | gcc_unreachable (); | |
775 | } | |
776 | } | |
777 | else | |
778 | /* Signed integer types. */ | |
779 | { | |
780 | switch (TYPE_MODE (type)) | |
781 | { | |
4e10a5a7 | 782 | case E_QImode: |
f027ee7c | 783 | charType = 'c'; break; |
4e10a5a7 | 784 | case E_HImode: |
f027ee7c | 785 | charType = 's'; break; |
4e10a5a7 | 786 | case E_SImode: |
f027ee7c NP |
787 | { |
788 | if (type == long_integer_type_node) | |
789 | charType = 'l'; | |
790 | else | |
791 | charType = 'i'; | |
792 | break; | |
793 | } | |
4e10a5a7 | 794 | case E_DImode: |
f027ee7c NP |
795 | charType = 'q'; break; |
796 | default: | |
797 | gcc_unreachable (); | |
798 | } | |
799 | } | |
800 | } | |
801 | else | |
802 | { | |
803 | /* Do not do any encoding, produce an error and keep going. */ | |
0ecf545c | 804 | error ("trying to encode non-integer type as a bit-field"); |
f027ee7c NP |
805 | return; |
806 | } | |
807 | ||
808 | sprintf (buffer, "b%d%c%d", position, charType, size); | |
809 | obstack_grow (&util_obstack, buffer, strlen (buffer)); | |
810 | } | |
811 | ||
a8f18c40 NP |
812 | static void |
813 | encode_field (tree field_decl, int curtype, int format) | |
f027ee7c NP |
814 | { |
815 | #ifdef OBJCPLUS | |
816 | /* C++ static members, and things that are not fields at all, | |
817 | should not appear in the encoding. */ | |
818 | if (TREE_CODE (field_decl) != FIELD_DECL || TREE_STATIC (field_decl)) | |
819 | return; | |
820 | #endif | |
821 | ||
822 | /* Generate the bitfield typing information, if needed. Note the difference | |
823 | between GNU and NeXT runtimes. */ | |
824 | if (DECL_BIT_FIELD_TYPE (field_decl)) | |
825 | { | |
ae7e9ddd | 826 | int size = tree_to_uhwi (DECL_SIZE (field_decl)); |
f027ee7c NP |
827 | |
828 | if (flag_next_runtime) | |
829 | encode_next_bitfield (size); | |
830 | else | |
831 | encode_gnu_bitfield (int_bit_position (field_decl), | |
832 | DECL_BIT_FIELD_TYPE (field_decl), size); | |
833 | } | |
834 | else | |
835 | encode_type (TREE_TYPE (field_decl), curtype, format); | |
836 | } | |
837 | ||
a8f18c40 NP |
838 | tree |
839 | encode_field_decl (tree field_decl) | |
840 | { | |
841 | tree result; | |
842 | ||
843 | encode_field (field_decl, | |
844 | obstack_object_size (&util_obstack), | |
845 | OBJC_ENCODE_DONT_INLINE_DEFS); | |
846 | ||
847 | /* Null terminate string. */ | |
848 | obstack_1grow (&util_obstack, 0); | |
849 | ||
850 | /* Get identifier for the string. */ | |
851 | result = get_identifier (XOBFINISH (&util_obstack, char *)); | |
852 | obstack_free (&util_obstack, util_firstobj); | |
853 | ||
854 | return result; | |
855 | } | |
856 | ||
f027ee7c NP |
857 | /* This routine encodes the attribute of the input PROPERTY according |
858 | to following formula: | |
859 | ||
860 | Property attributes are stored as a comma-delimited C string. | |
861 | Simple attributes such as readonly are encoded as single | |
862 | character. The parametrized attributes, getter=name and | |
863 | setter=name, are encoded as a single character followed by an | |
864 | identifier. Property types are also encoded as a parametrized | |
865 | attribute. The characters used to encode these attributes are | |
866 | defined by the following enumeration: | |
867 | ||
868 | enum PropertyAttributes { | |
869 | kPropertyReadOnly = 'R', | |
870 | kPropertyBycopy = 'C', | |
871 | kPropertyByref = '&', | |
872 | kPropertyDynamic = 'D', | |
873 | kPropertyGetter = 'G', | |
874 | kPropertySetter = 'S', | |
875 | kPropertyInstanceVariable = 'V', | |
876 | kPropertyType = 'T', | |
877 | kPropertyWeak = 'W', | |
878 | kPropertyStrong = 'P', | |
879 | kPropertyNonAtomic = 'N' | |
880 | }; */ | |
881 | tree | |
882 | objc_v2_encode_prop_attr (tree property) | |
883 | { | |
884 | const char *string; | |
885 | tree type = TREE_TYPE (property); | |
886 | ||
887 | obstack_1grow (&util_obstack, 'T'); | |
888 | encode_type (type, obstack_object_size (&util_obstack), | |
889 | OBJC_ENCODE_INLINE_DEFS); | |
890 | ||
891 | if (PROPERTY_READONLY (property)) | |
892 | obstack_grow (&util_obstack, ",R", 2); | |
893 | ||
894 | switch (PROPERTY_ASSIGN_SEMANTICS (property)) | |
895 | { | |
896 | case OBJC_PROPERTY_COPY: | |
897 | obstack_grow (&util_obstack, ",C", 2); | |
898 | break; | |
899 | case OBJC_PROPERTY_RETAIN: | |
900 | obstack_grow (&util_obstack, ",&", 2); | |
901 | break; | |
902 | case OBJC_PROPERTY_ASSIGN: | |
903 | default: | |
904 | break; | |
905 | } | |
906 | ||
907 | if (PROPERTY_DYNAMIC (property)) | |
908 | obstack_grow (&util_obstack, ",D", 2); | |
909 | ||
910 | if (PROPERTY_NONATOMIC (property)) | |
911 | obstack_grow (&util_obstack, ",N", 2); | |
912 | ||
913 | /* Here we want to encode the getter name, but only if it's not the | |
914 | standard one. */ | |
915 | if (PROPERTY_GETTER_NAME (property) != PROPERTY_NAME (property)) | |
916 | { | |
917 | obstack_grow (&util_obstack, ",G", 2); | |
918 | string = IDENTIFIER_POINTER (PROPERTY_GETTER_NAME (property)); | |
919 | obstack_grow (&util_obstack, string, strlen (string)); | |
920 | } | |
921 | ||
922 | if (!PROPERTY_READONLY (property)) | |
923 | { | |
924 | /* Here we want to encode the setter name, but only if it's not | |
925 | the standard one. */ | |
926 | tree standard_setter = get_identifier (objc_build_property_setter_name (PROPERTY_NAME (property))); | |
927 | if (PROPERTY_SETTER_NAME (property) != standard_setter) | |
928 | { | |
929 | obstack_grow (&util_obstack, ",S", 2); | |
930 | string = IDENTIFIER_POINTER (PROPERTY_SETTER_NAME (property)); | |
931 | obstack_grow (&util_obstack, string, strlen (string)); | |
932 | } | |
933 | } | |
934 | ||
935 | /* TODO: Encode strong ('P'), weak ('W') for garbage collection. */ | |
936 | ||
937 | if (!PROPERTY_DYNAMIC (property)) | |
938 | { | |
939 | obstack_grow (&util_obstack, ",V", 2); | |
940 | if (PROPERTY_IVAR_NAME (property)) | |
941 | string = IDENTIFIER_POINTER (PROPERTY_IVAR_NAME (property)); | |
942 | else | |
943 | string = IDENTIFIER_POINTER (PROPERTY_NAME (property)); | |
944 | obstack_grow (&util_obstack, string, strlen (string)); | |
945 | } | |
946 | ||
947 | /* NULL-terminate string. */ | |
948 | obstack_1grow (&util_obstack, 0); | |
949 | string = XOBFINISH (&util_obstack, char *); | |
950 | obstack_free (&util_obstack, util_firstobj); | |
951 | return get_identifier (string); | |
952 | } |