1 | /* Routines dealing with ObjC encoding of types |
2 | Copyright (C) 1992-2024 Free Software Foundation, Inc. |
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" |
24 | #include "options.h" |
25 | #include "stringpool.h" |
26 | #include "stor-layout.h" |
27 | |
28 | #ifdef OBJCPLUS |
29 | #include "cp/cp-tree.h" |
30 | #else |
31 | #include "c/c-tree.h" |
32 | #include "c/c-lang.h" |
33 | #endif |
34 | |
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. */ |
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. */ |
53 | |
54 | /* This obstack is used to accumulate the encoding of a data type. */ |
55 | static struct obstack util_obstack; |
56 | |
57 | /* This points to the beginning of obstack contents, so we can free |
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 | } |
66 | |
67 | int generating_instance_variables = 0; |
68 | |
69 | static void encode_type_qualifiers (tree); |
70 | static void encode_type (tree, int, int); |
71 | static void encode_field (tree field_decl, int curtype, int format); |
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 (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 (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 (s: buf, format: "%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 (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 (s: buf, format: "%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 (s: 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 (pointee: 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 (s1: 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 (s1: name, TAG_CLASS) == 0) /* '#' */ |
303 | { |
304 | obstack_1grow (&util_obstack, '#'); |
305 | return; |
306 | } |
307 | else if (strcmp (s1: 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), s2: "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 | { |
381 | char *enc = (char *) obstack_base (&util_obstack) + curtype; |
382 | if (memchr (s: enc, c: '=', |
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 (s: buffer, format: "[" HOST_WIDE_INT_PRINT_DEC, HOST_WIDE_INT_0); |
395 | } |
396 | else if (TREE_INT_CST_LOW (TYPE_SIZE (array_of)) == 0) |
397 | sprintf (s: buffer, format: "[" HOST_WIDE_INT_PRINT_DEC, HOST_WIDE_INT_0); |
398 | else |
399 | sprintf (s: buffer, format: "[" 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 (s: buffer, format: "![" 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 | |
477 | encode_field (field_decl: field, curtype, format); |
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 | { |
494 | if (ob_size > 0 |
495 | && *((char *) obstack_next_free (&util_obstack) - 1) == '^') |
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 |
501 | && *((char *) obstack_next_free (&util_obstack) - 2) == 'r'))) |
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 | */ |
512 | char c0, c1; |
513 | |
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; |
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? */ |
556 | && !TYPE_WAS_UNNAMED (type)) |
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 (s: buffer, format: "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. */ |
625 | /* FALLTHRU */ |
626 | case INTEGER_TYPE: |
627 | { |
628 | char c; |
629 | switch (GET_MODE_BITSIZE (SCALAR_INT_TYPE_MODE (type))) |
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 | { |
638 | /* Another legacy kludge for compatibility with |
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. */ |
667 | switch (GET_MODE_BITSIZE (SCALAR_FLOAT_TYPE_MODE (type))) |
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, left: '{', right: '}'); |
699 | break; |
700 | |
701 | case UNION_TYPE: |
702 | encode_aggregate_within (type, curtype, format, left: '(', right: ')'); |
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 | { |
733 | char *enc = (char *) obstack_base (&util_obstack) + curtype; |
734 | |
735 | /* Rewrite "in const" from "nr" to "rn". */ |
736 | if (curtype >= 1 && startswith (str: enc - 1, prefix: "nr" )) |
737 | memcpy (dest: enc - 1, src: "rn" , n: 2); |
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 | { |
759 | case E_QImode: |
760 | charType = 'C'; break; |
761 | case E_HImode: |
762 | charType = 'S'; break; |
763 | case E_SImode: |
764 | { |
765 | if (type == long_unsigned_type_node) |
766 | charType = 'L'; |
767 | else |
768 | charType = 'I'; |
769 | break; |
770 | } |
771 | case E_DImode: |
772 | charType = 'Q'; break; |
773 | default: |
774 | gcc_unreachable (); |
775 | } |
776 | } |
777 | else |
778 | /* Signed integer types. */ |
779 | { |
780 | switch (TYPE_MODE (type)) |
781 | { |
782 | case E_QImode: |
783 | charType = 'c'; break; |
784 | case E_HImode: |
785 | charType = 's'; break; |
786 | case E_SImode: |
787 | { |
788 | if (type == long_integer_type_node) |
789 | charType = 'l'; |
790 | else |
791 | charType = 'i'; |
792 | break; |
793 | } |
794 | case E_DImode: |
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. */ |
804 | error ("trying to encode non-integer type as a bit-field" ); |
805 | return; |
806 | } |
807 | |
808 | sprintf (s: buffer, format: "b%d%c%d" , position, charType, size); |
809 | obstack_grow (&util_obstack, buffer, strlen (buffer)); |
810 | } |
811 | |
812 | static void |
813 | encode_field (tree field_decl, int curtype, int format) |
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 | { |
826 | int size = tree_to_uhwi (DECL_SIZE (field_decl)); |
827 | |
828 | if (flag_next_runtime) |
829 | encode_next_bitfield (width: size); |
830 | else |
831 | encode_gnu_bitfield (position: int_bit_position (field: field_decl), |
832 | DECL_BIT_FIELD_TYPE (field_decl), size); |
833 | } |
834 | else |
835 | encode_type (TREE_TYPE (field_decl), curtype, format); |
836 | } |
837 | |
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 | |
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 | } |
953 | |