1/* Routines dealing with ObjC encoding of types
2 Copyright (C) 1992-2024 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 3, or (at your option)
9any later version.
10
11GCC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along 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. */
55static struct obstack util_obstack;
56
57/* This points to the beginning of obstack contents, so we can free
58 the whole contents. */
59static char *util_firstobj;
60
61void objc_encoding_init (void)
62{
63 gcc_obstack_init (&util_obstack);
64 util_firstobj = (char *) obstack_finish (&util_obstack);
65}
66
67int generating_instance_variables = 0;
68
69static void encode_type_qualifiers (tree);
70static void encode_type (tree, int, int);
71static void encode_field (tree field_decl, int curtype, int format);
72
73static tree
74objc_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
82static int
83objc_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. */
99tree
100encode_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(). */
171tree
172objc_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. */
215static void
216encode_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. */
242static bool
243pointee_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. */
252static void
253encode_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
347static void
348encode_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. */
410static void
411encode_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
440static void
441encode_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
481static void
482encode_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. */
582static void
583encode_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. */
595static void
596encode_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
742static void
743encode_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
812static void
813encode_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
838tree
839encode_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 }; */
881tree
882objc_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

source code of gcc/objc/objc-encoding.cc