111
|
1 /* Routines dealing with ObjC encoding of types
|
145
|
2 Copyright (C) 1992-2020 Free Software Foundation, Inc.
|
111
|
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 (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 {
|
|
381 char *enc = (char *) obstack_base (&util_obstack) + curtype;
|
|
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
|
|
477 encode_field (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 (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. */
|
|
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, '{', '}');
|
|
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 {
|
|
733 char *enc = (char *) obstack_base (&util_obstack) + curtype;
|
|
734
|
|
735 /* Rewrite "in const" from "nr" to "rn". */
|
|
736 if (curtype >= 1 && !strncmp (enc - 1, "nr", 2))
|
131
|
737 memcpy (enc - 1, "rn", 2);
|
111
|
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. */
|
145
|
804 error ("trying to encode non-integer type as a bit-field");
|
111
|
805 return;
|
|
806 }
|
|
807
|
|
808 sprintf (buffer, "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 (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
|
|
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 }
|