]>
Commit | Line | Data |
---|---|---|
6c65299b | 1 | /* Implement classes and message passing for Objective C. |
d8d27748 | 2 | Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc. |
4cb8c14b | 3 | Contributed by Steve Naroff. |
6c65299b RS |
4 | |
5 | This file is part of GNU CC. | |
6 | ||
7 | GNU CC is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2, or (at your option) | |
10 | any later version. | |
11 | ||
12 | GNU CC is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with GNU CC; see the file COPYING. If not, write to | |
890edade RK |
19 | the Free Software Foundation, 59 Temple Place - Suite 330, |
20 | Boston, MA 02111-1307, USA. */ | |
6c65299b | 21 | |
e31c7eec TW |
22 | /* Purpose: This module implements the Objective-C 4.0 language. |
23 | ||
24 | compatibility issues (with the Stepstone translator): | |
25 | ||
26 | - does not recognize the following 3.3 constructs. | |
27 | @requires, @classes, @messages, = (...) | |
28 | - methods with variable arguments must conform to ANSI standard. | |
29 | - tagged structure definitions that appear in BOTH the interface | |
30 | and implementation are not allowed. | |
31 | - public/private: all instance variables are public within the | |
32 | context of the implementation...I consider this to be a bug in | |
33 | the translator. | |
34 | - statically allocated objects are not supported. the user will | |
35 | receive an error if this service is requested. | |
36 | ||
37 | code generation `options': | |
38 | ||
39 | - OBJC_INT_SELECTORS */ | |
6c65299b RS |
40 | |
41 | #include <stdio.h> | |
42 | #include "config.h" | |
43 | #include "tree.h" | |
44 | #include "c-tree.h" | |
45 | #include "c-lex.h" | |
46 | #include "flags.h" | |
e58232cd | 47 | #include "objc-act.h" |
6c65299b | 48 | #include "input.h" |
e31c7eec | 49 | #include "function.h" |
187e4b0f | 50 | |
5d0f30f7 | 51 | |
187e4b0f | 52 | /* This is the default way of generating a method name. */ |
7bbc6432 RS |
53 | /* I am not sure it is really correct. |
54 | Perhaps there's a danger that it will make name conflicts | |
55 | if method names contain underscores. -- rms. */ | |
187e4b0f | 56 | #ifndef OBJC_GEN_METHOD_LABEL |
b54b3fb0 RS |
57 | #define OBJC_GEN_METHOD_LABEL(BUF, IS_INST, CLASS_NAME, CAT_NAME, SEL_NAME, NUM) \ |
58 | do { \ | |
59 | char *temp; \ | |
60 | sprintf ((BUF), "_%s_%s_%s_%s", \ | |
61 | ((IS_INST) ? "i" : "c"), \ | |
62 | (CLASS_NAME), \ | |
63 | ((CAT_NAME)? (CAT_NAME) : ""), \ | |
64 | (SEL_NAME)); \ | |
65 | for (temp = (BUF); *temp; temp++) \ | |
66 | if (*temp == ':') *temp = '_'; \ | |
187e4b0f | 67 | } while (0) |
152551c6 | 68 | #endif |
e31c7eec TW |
69 | |
70 | /* These need specifying. */ | |
71 | #ifndef OBJC_FORWARDING_STACK_OFFSET | |
72 | #define OBJC_FORWARDING_STACK_OFFSET 0 | |
73 | #endif | |
74 | ||
75 | #ifndef OBJC_FORWARDING_MIN_OFFSET | |
76 | #define OBJC_FORWARDING_MIN_OFFSET 0 | |
77 | #endif | |
6c65299b RS |
78 | \f |
79 | /* Define the special tree codes that we use. */ | |
80 | ||
81 | /* Table indexed by tree code giving a string containing a character | |
82 | classifying the tree code. Possibilities are | |
83 | t, d, s, c, r, <, 1 and 2. See objc-tree.def for details. */ | |
84 | ||
85 | #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE, | |
86 | ||
87 | char *objc_tree_code_type[] = { | |
88 | "x", | |
89 | #include "objc-tree.def" | |
90 | }; | |
91 | #undef DEFTREECODE | |
92 | ||
93 | /* Table indexed by tree code giving number of expression | |
94 | operands beyond the fixed part of the node structure. | |
95 | Not used for types or decls. */ | |
96 | ||
97 | #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH, | |
98 | ||
99 | int objc_tree_code_length[] = { | |
100 | 0, | |
101 | #include "objc-tree.def" | |
102 | }; | |
103 | #undef DEFTREECODE | |
104 | ||
105 | /* Names of tree components. | |
106 | Used for printing out the tree and error messages. */ | |
107 | #define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME, | |
108 | ||
109 | char *objc_tree_code_name[] = { | |
110 | "@@dummy", | |
111 | #include "objc-tree.def" | |
112 | }; | |
113 | #undef DEFTREECODE | |
114 | \f | |
9dee6758 RS |
115 | /* Set up for use of obstacks. */ |
116 | ||
117 | #include "obstack.h" | |
118 | ||
119 | #define obstack_chunk_alloc xmalloc | |
120 | #define obstack_chunk_free free | |
121 | ||
9dee6758 RS |
122 | /* This obstack is used to accumulate the encoding of a data type. */ |
123 | static struct obstack util_obstack; | |
124 | /* This points to the beginning of obstack contents, | |
125 | so we can free the whole contents. */ | |
126 | char *util_firstobj; | |
127 | ||
4cb8c14b RK |
128 | /* List of classes with list of their static instances. */ |
129 | static tree objc_static_instances; | |
130 | ||
131 | /* The declaration of the array administrating the static instances. */ | |
132 | static tree static_instances_decl; | |
133 | ||
6c65299b RS |
134 | /* for encode_method_def */ |
135 | #include "rtl.h" | |
e31c7eec | 136 | #include "c-parse.h" |
6c65299b | 137 | |
4cb8c14b | 138 | #define OBJC_VERSION (flag_next_runtime ? 5 : 7) |
e31c7eec | 139 | #define PROTOCOL_VERSION 2 |
6c65299b | 140 | |
6c65299b RS |
141 | #define OBJC_ENCODE_INLINE_DEFS 0 |
142 | #define OBJC_ENCODE_DONT_INLINE_DEFS 1 | |
143 | ||
144 | /*** Private Interface (procedures) ***/ | |
145 | ||
0f41302f | 146 | /* Used by compile_file. */ |
e31c7eec TW |
147 | |
148 | static void init_objc PROTO((void)); | |
149 | static void finish_objc PROTO((void)); | |
150 | ||
0f41302f | 151 | /* Code generation. */ |
6c65299b | 152 | |
e31c7eec | 153 | static void synth_module_prologue PROTO((void)); |
89ef1046 | 154 | static tree build_constructor PROTO((tree, tree)); |
e31c7eec | 155 | static char *build_module_descriptor PROTO((void)); |
89ef1046 | 156 | static tree init_module_descriptor PROTO((tree)); |
51900510 RK |
157 | static tree build_objc_method_call PROTO((int, tree, tree, |
158 | tree, tree, tree)); | |
e31c7eec | 159 | static void generate_strings PROTO((void)); |
5d0f30f7 | 160 | static tree get_proto_encoding PROTO((tree)); |
e31c7eec TW |
161 | static void build_selector_translation_table PROTO((void)); |
162 | static tree build_ivar_chain PROTO((tree, int)); | |
163 | ||
4cb8c14b RK |
164 | static tree objc_add_static_instance PROTO((tree, tree)); |
165 | ||
e31c7eec TW |
166 | static tree build_ivar_template PROTO((void)); |
167 | static tree build_method_template PROTO((void)); | |
168 | static tree build_private_template PROTO((tree)); | |
169 | static void build_class_template PROTO((void)); | |
5d0f30f7 | 170 | static void build_selector_template PROTO((void)); |
e31c7eec TW |
171 | static void build_category_template PROTO((void)); |
172 | static tree build_super_template PROTO((void)); | |
51900510 RK |
173 | static tree build_category_initializer PROTO((tree, tree, tree, |
174 | tree, tree, tree)); | |
175 | static tree build_protocol_initializer PROTO((tree, tree, tree, | |
176 | tree, tree)); | |
e31c7eec TW |
177 | |
178 | static void synth_forward_declarations PROTO((void)); | |
179 | static void generate_ivar_lists PROTO((void)); | |
180 | static void generate_dispatch_tables PROTO((void)); | |
181 | static void generate_shared_structures PROTO((void)); | |
182 | static tree generate_protocol_list PROTO((tree)); | |
183 | static void generate_forward_declaration_to_string_table PROTO((void)); | |
184 | static void build_protocol_reference PROTO((tree)); | |
185 | ||
186 | static tree init_selector PROTO((int)); | |
187 | static tree build_keyword_selector PROTO((tree)); | |
188 | static tree synth_id_with_class_suffix PROTO((char *, tree)); | |
6c65299b | 189 | |
51900510 | 190 | /* From expr.c */ |
30c0e2df KKT |
191 | extern int apply_args_register_offset PROTO((int)); |
192 | ||
51900510 | 193 | /* Misc. bookkeeping */ |
6c65299b | 194 | |
e31c7eec TW |
195 | typedef struct hashed_entry *hash; |
196 | typedef struct hashed_attribute *attr; | |
6c65299b | 197 | |
e31c7eec TW |
198 | struct hashed_attribute |
199 | { | |
200 | attr next; | |
201 | tree value; | |
202 | }; | |
203 | struct hashed_entry | |
204 | { | |
205 | attr list; | |
206 | hash next; | |
207 | tree key; | |
6c65299b | 208 | }; |
e31c7eec TW |
209 | |
210 | static void hash_init PROTO((void)); | |
211 | static void hash_enter PROTO((hash *, tree)); | |
212 | static hash hash_lookup PROTO((hash *, tree)); | |
213 | static void hash_add_attr PROTO((hash, tree)); | |
214 | static tree lookup_method PROTO((tree, tree)); | |
215 | static tree lookup_instance_method_static PROTO((tree, tree)); | |
216 | static tree lookup_class_method_static PROTO((tree, tree)); | |
217 | static tree add_class PROTO((tree)); | |
218 | static void add_category PROTO((tree, tree)); | |
219 | ||
220 | enum string_section | |
221 | { | |
222 | class_names, /* class, category, protocol, module names */ | |
223 | meth_var_names, /* method and variable names */ | |
6b7e6ce4 | 224 | meth_var_types /* method and variable type descriptors */ |
6c65299b | 225 | }; |
e31c7eec | 226 | |
51900510 RK |
227 | static tree add_objc_string PROTO((tree, |
228 | enum string_section)); | |
229 | static tree build_objc_string_decl PROTO((tree, | |
230 | enum string_section)); | |
e31c7eec TW |
231 | static tree build_selector_reference_decl PROTO((tree)); |
232 | ||
0f41302f | 233 | /* Protocol additions. */ |
e31c7eec TW |
234 | |
235 | static tree add_protocol PROTO((tree)); | |
236 | static tree lookup_protocol PROTO((tree)); | |
237 | static tree lookup_and_install_protocols PROTO((tree)); | |
6c65299b | 238 | |
0f41302f | 239 | /* Type encoding. */ |
6c65299b | 240 | |
e31c7eec TW |
241 | static void encode_type_qualifiers PROTO((tree)); |
242 | static void encode_pointer PROTO((tree, int, int)); | |
243 | static void encode_array PROTO((tree, int, int)); | |
244 | static void encode_aggregate PROTO((tree, int, int)); | |
245 | static void encode_bitfield PROTO((int, int)); | |
246 | static void encode_type PROTO((tree, int, int)); | |
247 | static void encode_field_decl PROTO((tree, int, int)); | |
6c65299b | 248 | |
e31c7eec TW |
249 | static void really_start_method PROTO((tree, tree)); |
250 | static int comp_method_with_proto PROTO((tree, tree)); | |
251 | static int comp_proto_with_proto PROTO((tree, tree)); | |
252 | static tree get_arg_type_list PROTO((tree, int, int)); | |
253 | static tree expr_last PROTO((tree)); | |
6c65299b | 254 | |
0f41302f | 255 | /* Utilities for debugging and error diagnostics. */ |
6c65299b | 256 | |
e31c7eec TW |
257 | static void warn_with_method PROTO((char *, int, tree)); |
258 | static void error_with_ivar PROTO((char *, tree, tree)); | |
259 | static char *gen_method_decl PROTO((tree, char *)); | |
260 | static char *gen_declaration PROTO((tree, char *)); | |
261 | static char *gen_declarator PROTO((tree, char *, char *)); | |
262 | static int is_complex_decl PROTO((tree)); | |
263 | static void adorn_decl PROTO((tree, char *)); | |
264 | static void dump_interface PROTO((FILE *, tree)); | |
265 | ||
0f41302f | 266 | /* Everything else. */ |
e31c7eec TW |
267 | |
268 | static void objc_fatal PROTO((void)); | |
269 | static tree define_decl PROTO((tree, tree)); | |
270 | static tree lookup_method_in_protocol_list PROTO((tree, tree, int)); | |
271 | static tree lookup_protocol_in_reflist PROTO((tree, tree)); | |
51900510 RK |
272 | static tree create_builtin_decl PROTO((enum tree_code, |
273 | tree, char *)); | |
e31c7eec TW |
274 | static tree my_build_string PROTO((int, char *)); |
275 | static void build_objc_symtab_template PROTO((void)); | |
89ef1046 RS |
276 | static tree init_def_list PROTO((tree)); |
277 | static tree init_objc_symtab PROTO((tree)); | |
e31c7eec TW |
278 | static void forward_declare_categories PROTO((void)); |
279 | static void generate_objc_symtab_decl PROTO((void)); | |
280 | static tree build_selector PROTO((tree)); | |
281 | static tree build_msg_pool_reference PROTO((int)); | |
5d0f30f7 | 282 | static tree build_typed_selector_reference PROTO((tree, tree)); |
e31c7eec TW |
283 | static tree build_selector_reference PROTO((tree)); |
284 | static tree build_class_reference_decl PROTO((tree)); | |
285 | static void add_class_reference PROTO((tree)); | |
286 | static tree objc_copy_list PROTO((tree, tree *)); | |
287 | static tree build_protocol_template PROTO((void)); | |
30c0e2df | 288 | static tree build_descriptor_table_initializer PROTO((tree, tree)); |
e31c7eec TW |
289 | static tree build_method_prototype_list_template PROTO((tree, int)); |
290 | static tree build_method_prototype_template PROTO((void)); | |
291 | static int forwarding_offset PROTO((tree)); | |
292 | static tree encode_method_prototype PROTO((tree, tree)); | |
293 | static tree generate_descriptor_table PROTO((tree, char *, int, tree, tree)); | |
294 | static void generate_method_descriptors PROTO((tree)); | |
295 | static tree build_tmp_function_decl PROTO((void)); | |
296 | static void hack_method_prototype PROTO((tree, tree)); | |
297 | static void generate_protocol_references PROTO((tree)); | |
298 | static void generate_protocols PROTO((void)); | |
299 | static void check_ivars PROTO((tree, tree)); | |
300 | static tree build_ivar_list_template PROTO((tree, int)); | |
301 | static tree build_method_list_template PROTO((tree, int)); | |
30c0e2df | 302 | static tree build_ivar_list_initializer PROTO((tree, tree)); |
51900510 RK |
303 | static tree generate_ivars_list PROTO((tree, char *, |
304 | int, tree)); | |
30c0e2df | 305 | static tree build_dispatch_table_initializer PROTO((tree, tree)); |
51900510 RK |
306 | static tree generate_dispatch_table PROTO((tree, char *, |
307 | int, tree)); | |
308 | static tree build_shared_structure_initializer PROTO((tree, tree, tree, tree, | |
309 | tree, int, tree, tree, | |
310 | tree)); | |
e31c7eec TW |
311 | static void generate_category PROTO((tree)); |
312 | static int is_objc_type_qualifier PROTO((tree)); | |
313 | static tree adjust_type_for_id_default PROTO((tree)); | |
314 | static tree check_duplicates PROTO((hash)); | |
315 | static tree receiver_is_class_object PROTO((tree)); | |
316 | static int check_methods PROTO((tree, tree, int)); | |
317 | static int conforms_to_protocol PROTO((tree, tree)); | |
318 | static void check_protocols PROTO((tree, char *, char *)); | |
319 | static tree encode_method_def PROTO((tree)); | |
320 | static void gen_declspecs PROTO((tree, char *, int)); | |
321 | static void generate_classref_translation_entry PROTO((tree)); | |
322 | static void handle_class_ref PROTO((tree)); | |
6c65299b RS |
323 | |
324 | /*** Private Interface (data) ***/ | |
325 | ||
0f41302f | 326 | /* Reserved tag definitions. */ |
6c65299b RS |
327 | |
328 | #define TYPE_ID "id" | |
329 | #define TAG_OBJECT "objc_object" | |
330 | #define TAG_CLASS "objc_class" | |
331 | #define TAG_SUPER "objc_super" | |
332 | #define TAG_SELECTOR "objc_selector" | |
333 | ||
e31c7eec TW |
334 | #define UTAG_CLASS "_objc_class" |
335 | #define UTAG_IVAR "_objc_ivar" | |
336 | #define UTAG_IVAR_LIST "_objc_ivar_list" | |
337 | #define UTAG_METHOD "_objc_method" | |
338 | #define UTAG_METHOD_LIST "_objc_method_list" | |
339 | #define UTAG_CATEGORY "_objc_category" | |
340 | #define UTAG_MODULE "_objc_module" | |
4cb8c14b | 341 | #define UTAG_STATICS "_objc_statics" |
e31c7eec TW |
342 | #define UTAG_SYMTAB "_objc_symtab" |
343 | #define UTAG_SUPER "_objc_super" | |
5d0f30f7 | 344 | #define UTAG_SELECTOR "_objc_selector" |
e31c7eec TW |
345 | |
346 | #define UTAG_PROTOCOL "_objc_protocol" | |
347 | #define UTAG_PROTOCOL_LIST "_objc_protocol_list" | |
348 | #define UTAG_METHOD_PROTOTYPE "_objc_method_prototype" | |
349 | #define UTAG_METHOD_PROTOTYPE_LIST "_objc__method_prototype_list" | |
350 | ||
351 | #define STRING_OBJECT_CLASS_NAME "NXConstantString" | |
352 | #define PROTOCOL_OBJECT_CLASS_NAME "Protocol" | |
353 | ||
51900510 RK |
354 | static char *TAG_GETCLASS; |
355 | static char *TAG_GETMETACLASS; | |
356 | static char *TAG_MSGSEND; | |
357 | static char *TAG_MSGSENDSUPER; | |
358 | static char *TAG_EXECCLASS; | |
e31c7eec TW |
359 | |
360 | /* Set by `continue_class' and checked by `is_public'. */ | |
361 | ||
362 | #define TREE_STATIC_TEMPLATE(record_type) (TREE_PUBLIC (record_type)) | |
6c65299b RS |
363 | #define TYPED_OBJECT(type) \ |
364 | (TREE_CODE (type) == RECORD_TYPE && TREE_STATIC_TEMPLATE (type)) | |
59ce3fc8 | 365 | |
e31c7eec | 366 | /* Some commonly used instances of "identifier_node". */ |
6c65299b | 367 | |
e31c7eec | 368 | static tree self_id, ucmd_id; |
fc55cc66 | 369 | static tree unused_list; |
6c65299b | 370 | |
e31c7eec TW |
371 | static tree self_decl, umsg_decl, umsg_super_decl; |
372 | static tree objc_get_class_decl, objc_get_meta_class_decl; | |
6c65299b | 373 | |
e31c7eec TW |
374 | static tree super_type, selector_type, id_type, objc_class_type; |
375 | static tree instance_type, protocol_type; | |
6c65299b | 376 | |
59ce3fc8 TW |
377 | /* Type checking macros. */ |
378 | ||
379 | #define IS_ID(TYPE) \ | |
380 | (TYPE_MAIN_VARIANT (TYPE) == TYPE_MAIN_VARIANT (id_type)) | |
381 | #define IS_PROTOCOL_QUALIFIED_ID(TYPE) \ | |
382 | (IS_ID (TYPE) && TYPE_PROTOCOL_LIST (TYPE)) | |
383 | #define IS_SUPER(TYPE) \ | |
384 | (super_type && TYPE_MAIN_VARIANT (TYPE) == TYPE_MAIN_VARIANT (super_type)) | |
385 | ||
51900510 RK |
386 | static tree class_chain = NULL_TREE; |
387 | static tree alias_chain = NULL_TREE; | |
388 | static tree interface_chain = NULL_TREE; | |
389 | static tree protocol_chain = NULL_TREE; | |
6c65299b | 390 | |
0f41302f MS |
391 | /* Chains to manage selectors that are referenced and defined in the |
392 | module. */ | |
6c65299b | 393 | |
0f41302f MS |
394 | static tree cls_ref_chain = NULL_TREE; /* Classes referenced. */ |
395 | static tree sel_ref_chain = NULL_TREE; /* Selectors referenced. */ | |
e31c7eec | 396 | |
0f41302f | 397 | /* Chains to manage uniquing of strings. */ |
e31c7eec | 398 | |
51900510 RK |
399 | static tree class_names_chain = NULL_TREE; |
400 | static tree meth_var_names_chain = NULL_TREE; | |
401 | static tree meth_var_types_chain = NULL_TREE; | |
6c65299b | 402 | |
0f41302f | 403 | /* Hash tables to manage the global pool of method prototypes. */ |
6c65299b RS |
404 | |
405 | static hash *nst_method_hash_list = 0; | |
406 | static hash *cls_method_hash_list = 0; | |
407 | ||
0f41302f | 408 | /* Backend data declarations. */ |
6c65299b | 409 | |
e31c7eec TW |
410 | static tree UOBJC_SYMBOLS_decl; |
411 | static tree UOBJC_INSTANCE_VARIABLES_decl, UOBJC_CLASS_VARIABLES_decl; | |
412 | static tree UOBJC_INSTANCE_METHODS_decl, UOBJC_CLASS_METHODS_decl; | |
413 | static tree UOBJC_CLASS_decl, UOBJC_METACLASS_decl; | |
ba2e2786 | 414 | static tree UOBJC_SELECTOR_TABLE_decl; |
e31c7eec TW |
415 | static tree UOBJC_MODULES_decl; |
416 | static tree UOBJC_STRINGS_decl; | |
417 | ||
418 | /* The following are used when compiling a class implementation. | |
419 | implementation_template will normally be an interface, however if | |
420 | none exists this will be equal to implementation_context...it is | |
421 | set in start_class. */ | |
6c65299b | 422 | |
51900510 RK |
423 | static tree implementation_context = NULL_TREE; |
424 | static tree implementation_template = NULL_TREE; | |
6c65299b | 425 | |
e31c7eec TW |
426 | struct imp_entry |
427 | { | |
6c65299b RS |
428 | struct imp_entry *next; |
429 | tree imp_context; | |
430 | tree imp_template; | |
431 | tree class_decl; /* _OBJC_CLASS_<my_name>; */ | |
432 | tree meta_decl; /* _OBJC_METACLASS_<my_name>; */ | |
433 | }; | |
e31c7eec TW |
434 | |
435 | static void handle_impent PROTO((struct imp_entry *)); | |
436 | ||
6c65299b RS |
437 | static struct imp_entry *imp_list = 0; |
438 | static int imp_count = 0; /* `@implementation' */ | |
439 | static int cat_count = 0; /* `@category' */ | |
440 | ||
e31c7eec | 441 | static tree objc_class_template, objc_category_template, uprivate_record; |
5d0f30f7 | 442 | static tree objc_protocol_template, objc_selector_template; |
e31c7eec | 443 | static tree ucls_super_ref, uucls_super_ref; |
6c65299b RS |
444 | |
445 | static tree objc_method_template, objc_ivar_template; | |
446 | static tree objc_symtab_template, objc_module_template; | |
447 | static tree objc_super_template, objc_object_reference; | |
448 | ||
e31c7eec TW |
449 | static tree objc_object_id, objc_class_id, objc_id_id; |
450 | static tree constant_string_id; | |
451 | static tree constant_string_type; | |
452 | static tree UOBJC_SUPER_decl; | |
6c65299b | 453 | |
51900510 RK |
454 | static tree method_context = NULL_TREE; |
455 | static int method_slot = 0; /* Used by start_method_def, */ | |
6c65299b | 456 | |
e31c7eec | 457 | #define BUFSIZE 1024 |
6c65299b | 458 | |
51900510 | 459 | static char *errbuf; /* Buffer for error diagnostics */ |
6c65299b | 460 | |
0f41302f | 461 | /* Data imported from tree.c. */ |
6c65299b | 462 | |
5d0f30f7 | 463 | extern enum debug_info_type write_symbols; |
6c65299b | 464 | |
51900510 | 465 | /* Data imported from toplev.c. */ |
6c65299b RS |
466 | |
467 | extern char *dump_base_name; | |
468 | \f | |
e31c7eec TW |
469 | /* Generate code for GNU or NeXT runtime environment. */ |
470 | ||
471 | #ifdef NEXT_OBJC_RUNTIME | |
472 | int flag_next_runtime = 1; | |
473 | #else | |
474 | int flag_next_runtime = 0; | |
475 | #endif | |
476 | ||
5d0f30f7 KKT |
477 | int flag_typed_selectors; |
478 | ||
6c65299b RS |
479 | /* Open and close the file for outputting class declarations, if requested. */ |
480 | ||
481 | int flag_gen_declaration = 0; | |
482 | ||
483 | FILE *gen_declaration_file; | |
484 | ||
485 | /* Warn if multiple methods are seen for the same selector, but with | |
0f41302f | 486 | different argument types. */ |
6c65299b RS |
487 | |
488 | int warn_selector = 0; | |
489 | ||
143dc646 KKT |
490 | /* Warn if methods required by a protocol are not implemented in the |
491 | class adopting it. When turned off, methods inherited to that | |
492 | class are also considered implemented */ | |
493 | ||
494 | int flag_warn_protocol = 1; | |
495 | ||
51900510 | 496 | /* Tells "encode_pointer/encode_aggregate" whether we are generating |
e31c7eec TW |
497 | type descriptors for instance variables (as opposed to methods). |
498 | Type descriptors for instance variables contain more information | |
499 | than methods (for static typing and embedded structures). This | |
0f41302f | 500 | was added to support features being planned for dbkit2. */ |
e31c7eec TW |
501 | |
502 | static int generating_instance_variables = 0; | |
503 | ||
6c65299b RS |
504 | void |
505 | lang_init () | |
506 | { | |
51900510 RK |
507 | /* The beginning of the file is a new line; check for #. |
508 | With luck, we discover the real source file's name from that | |
6c65299b RS |
509 | and put it in input_filename. */ |
510 | ungetc (check_newline (), finput); | |
511 | ||
bab5e7d5 RK |
512 | /* The line number can be -1 if we had -g3 and the input file |
513 | had a directive specifying line 0. But we want predefined | |
514 | functions to have a line number of 0, not -1. */ | |
515 | if (lineno == -1) | |
516 | lineno = 0; | |
517 | ||
6c65299b RS |
518 | /* If gen_declaration desired, open the output file. */ |
519 | if (flag_gen_declaration) | |
520 | { | |
521 | int dump_base_name_length = strlen (dump_base_name); | |
522 | register char *dumpname = (char *) xmalloc (dump_base_name_length + 7); | |
523 | strcpy (dumpname, dump_base_name); | |
524 | strcat (dumpname, ".decl"); | |
525 | gen_declaration_file = fopen (dumpname, "w"); | |
526 | if (gen_declaration_file == 0) | |
527 | pfatal_with_name (dumpname); | |
528 | } | |
529 | ||
e31c7eec TW |
530 | if (flag_next_runtime) |
531 | { | |
532 | TAG_GETCLASS = "objc_getClass"; | |
533 | TAG_GETMETACLASS = "objc_getMetaClass"; | |
534 | TAG_MSGSEND = "objc_msgSend"; | |
535 | TAG_MSGSENDSUPER = "objc_msgSendSuper"; | |
536 | TAG_EXECCLASS = "__objc_execClass"; | |
537 | } | |
538 | else | |
539 | { | |
540 | TAG_GETCLASS = "objc_get_class"; | |
541 | TAG_GETMETACLASS = "objc_get_meta_class"; | |
542 | TAG_MSGSEND = "objc_msg_lookup"; | |
543 | TAG_MSGSENDSUPER = "objc_msg_lookup_super"; | |
544 | TAG_EXECCLASS = "__objc_exec_class"; | |
5d0f30f7 | 545 | flag_typed_selectors = 1; |
e31c7eec TW |
546 | } |
547 | ||
6c65299b RS |
548 | if (doing_objc_thang) |
549 | init_objc (); | |
550 | } | |
551 | ||
e31c7eec TW |
552 | static void |
553 | objc_fatal () | |
554 | { | |
555 | fatal ("Objective-C text in C source file"); | |
556 | } | |
557 | ||
6c65299b | 558 | void |
2c5f4139 | 559 | finish_file () |
6c65299b RS |
560 | { |
561 | if (doing_objc_thang) | |
562 | finish_objc (); /* Objective-C finalization */ | |
563 | ||
564 | if (gen_declaration_file) | |
565 | fclose (gen_declaration_file); | |
566 | } | |
567 | ||
568 | void | |
569 | lang_finish () | |
570 | { | |
571 | } | |
572 | ||
d0d4af87 MS |
573 | char * |
574 | lang_identify () | |
575 | { | |
576 | return "objc"; | |
577 | } | |
578 | ||
6c65299b RS |
579 | int |
580 | lang_decode_option (p) | |
581 | char *p; | |
582 | { | |
583 | if (!strcmp (p, "-lang-objc")) | |
584 | doing_objc_thang = 1; | |
585 | else if (!strcmp (p, "-gen-decls")) | |
586 | flag_gen_declaration = 1; | |
587 | else if (!strcmp (p, "-Wselector")) | |
588 | warn_selector = 1; | |
589 | else if (!strcmp (p, "-Wno-selector")) | |
590 | warn_selector = 0; | |
143dc646 KKT |
591 | else if (!strcmp (p, "-Wprotocol")) |
592 | flag_warn_protocol = 1; | |
593 | else if (!strcmp (p, "-Wno-protocol")) | |
594 | flag_warn_protocol = 0; | |
e31c7eec TW |
595 | else if (!strcmp (p, "-fgnu-runtime")) |
596 | flag_next_runtime = 0; | |
597 | else if (!strcmp (p, "-fno-next-runtime")) | |
598 | flag_next_runtime = 0; | |
599 | else if (!strcmp (p, "-fno-gnu-runtime")) | |
600 | flag_next_runtime = 1; | |
601 | else if (!strcmp (p, "-fnext-runtime")) | |
602 | flag_next_runtime = 1; | |
6c65299b RS |
603 | else |
604 | return c_decode_option (p); | |
605 | ||
606 | return 1; | |
607 | } | |
608 | \f | |
609 | static tree | |
610 | define_decl (declarator, declspecs) | |
611 | tree declarator; | |
612 | tree declspecs; | |
613 | { | |
51900510 RK |
614 | tree decl = start_decl (declarator, declspecs, 0, NULL_TREE, NULL_TREE); |
615 | finish_decl (decl, NULL_TREE, NULL_TREE); | |
6c65299b RS |
616 | return decl; |
617 | } | |
618 | ||
392202b0 TW |
619 | /* Return 1 if LHS and RHS are compatible types for assignment or |
620 | various other operations. Return 0 if they are incompatible, and | |
621 | return -1 if we choose to not decide. When the operation is | |
622 | REFLEXIVE, check for compatibility in either direction. | |
e31c7eec | 623 | |
392202b0 TW |
624 | For statically typed objects, an assignment of the form `a' = `b' |
625 | is permitted if: | |
e31c7eec | 626 | |
392202b0 TW |
627 | `a' is of type "id", |
628 | `a' and `b' are the same class type, or | |
629 | `a' and `b' are of class types A and B such that B is a descendant of A. */ | |
6c65299b RS |
630 | |
631 | int | |
e31c7eec | 632 | maybe_objc_comptypes (lhs, rhs, reflexive) |
6c65299b | 633 | tree lhs, rhs; |
e31c7eec | 634 | int reflexive; |
6c65299b RS |
635 | { |
636 | if (doing_objc_thang) | |
e31c7eec | 637 | return objc_comptypes (lhs, rhs, reflexive); |
392202b0 | 638 | return -1; |
e31c7eec TW |
639 | } |
640 | ||
641 | static tree | |
642 | lookup_method_in_protocol_list (rproto_list, sel_name, class_meth) | |
643 | tree rproto_list; | |
644 | tree sel_name; | |
645 | int class_meth; | |
646 | { | |
647 | tree rproto, p; | |
648 | tree fnd = 0; | |
649 | ||
650 | for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto)) | |
651 | { | |
652 | p = TREE_VALUE (rproto); | |
653 | ||
654 | if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) | |
655 | { | |
51900510 RK |
656 | if ((fnd = lookup_method (class_meth |
657 | ? PROTOCOL_CLS_METHODS (p) | |
658 | : PROTOCOL_NST_METHODS (p), sel_name))) | |
659 | ; | |
660 | else if (PROTOCOL_LIST (p)) | |
661 | fnd = lookup_method_in_protocol_list (PROTOCOL_LIST (p), | |
662 | sel_name, class_meth); | |
e31c7eec TW |
663 | } |
664 | else | |
51900510 | 665 | ; /* An identifier...if we could not find a protocol. */ |
e31c7eec TW |
666 | |
667 | if (fnd) | |
668 | return fnd; | |
669 | } | |
51900510 | 670 | |
e31c7eec TW |
671 | return 0; |
672 | } | |
673 | ||
674 | static tree | |
675 | lookup_protocol_in_reflist (rproto_list, lproto) | |
676 | tree rproto_list; | |
677 | tree lproto; | |
678 | { | |
679 | tree rproto, p; | |
680 | ||
0f41302f | 681 | /* Make sure the protocol is support by the object on the rhs. */ |
e31c7eec TW |
682 | if (TREE_CODE (lproto) == PROTOCOL_INTERFACE_TYPE) |
683 | { | |
51900510 RK |
684 | tree fnd = 0; |
685 | for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto)) | |
686 | { | |
687 | p = TREE_VALUE (rproto); | |
e31c7eec | 688 | |
51900510 RK |
689 | if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) |
690 | { | |
691 | if (lproto == p) | |
692 | fnd = lproto; | |
e31c7eec | 693 | |
51900510 RK |
694 | else if (PROTOCOL_LIST (p)) |
695 | fnd = lookup_protocol_in_reflist (PROTOCOL_LIST (p), lproto); | |
696 | } | |
e31c7eec | 697 | |
51900510 RK |
698 | if (fnd) |
699 | return fnd; | |
700 | } | |
e31c7eec TW |
701 | } |
702 | else | |
0f41302f | 703 | ; /* An identifier...if we could not find a protocol. */ |
e31c7eec TW |
704 | |
705 | return 0; | |
6c65299b RS |
706 | } |
707 | ||
392202b0 TW |
708 | /* Return 1 if LHS and RHS are compatible types for assignment |
709 | or various other operations. Return 0 if they are incompatible, | |
710 | and return -1 if we choose to not decide. When the operation | |
711 | is REFLEXIVE, check for compatibility in either direction. */ | |
712 | ||
6c65299b | 713 | int |
e31c7eec | 714 | objc_comptypes (lhs, rhs, reflexive) |
6c65299b RS |
715 | tree lhs; |
716 | tree rhs; | |
e31c7eec | 717 | int reflexive; |
6c65299b | 718 | { |
0f41302f | 719 | /* New clause for protocols. */ |
e31c7eec TW |
720 | |
721 | if (TREE_CODE (lhs) == POINTER_TYPE | |
722 | && TREE_CODE (TREE_TYPE (lhs)) == RECORD_TYPE | |
723 | && TREE_CODE (rhs) == POINTER_TYPE | |
724 | && TREE_CODE (TREE_TYPE (rhs)) == RECORD_TYPE) | |
725 | { | |
59ce3fc8 TW |
726 | int lhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (lhs); |
727 | int rhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (rhs); | |
e31c7eec TW |
728 | |
729 | if (lhs_is_proto) | |
730 | { | |
731 | tree lproto, lproto_list = TYPE_PROTOCOL_LIST (lhs); | |
732 | tree rproto, rproto_list; | |
733 | tree p; | |
734 | ||
735 | if (rhs_is_proto) | |
736 | { | |
737 | rproto_list = TYPE_PROTOCOL_LIST (rhs); | |
738 | ||
739 | /* Make sure the protocol is supported by the object | |
740 | on the rhs. */ | |
741 | for (lproto = lproto_list; lproto; lproto = TREE_CHAIN (lproto)) | |
742 | { | |
743 | p = TREE_VALUE (lproto); | |
744 | rproto = lookup_protocol_in_reflist (rproto_list, p); | |
745 | ||
746 | if (!rproto) | |
747 | warning ("object does not conform to the `%s' protocol", | |
748 | IDENTIFIER_POINTER (PROTOCOL_NAME (p))); | |
749 | } | |
750 | } | |
751 | else if (TYPED_OBJECT (TREE_TYPE (rhs))) | |
752 | { | |
753 | tree rname = TYPE_NAME (TREE_TYPE (rhs)); | |
754 | tree rinter; | |
755 | ||
756 | /* Make sure the protocol is supported by the object | |
757 | on the rhs. */ | |
758 | for (lproto = lproto_list; lproto; lproto = TREE_CHAIN (lproto)) | |
759 | { | |
760 | p = TREE_VALUE (lproto); | |
761 | rproto = 0; | |
762 | rinter = lookup_interface (rname); | |
763 | ||
764 | while (rinter && !rproto) | |
765 | { | |
766 | tree cat; | |
767 | ||
768 | rproto_list = CLASS_PROTOCOL_LIST (rinter); | |
769 | rproto = lookup_protocol_in_reflist (rproto_list, p); | |
770 | ||
0f41302f | 771 | /* Check for protocols adopted by categories. */ |
e31c7eec TW |
772 | cat = CLASS_CATEGORY_LIST (rinter); |
773 | while (cat && !rproto) | |
774 | { | |
775 | rproto_list = CLASS_PROTOCOL_LIST (cat); | |
776 | rproto = lookup_protocol_in_reflist (rproto_list, p); | |
777 | ||
778 | cat = CLASS_CATEGORY_LIST (cat); | |
779 | } | |
780 | ||
781 | rinter = lookup_interface (CLASS_SUPER_NAME (rinter)); | |
782 | } | |
51900510 | 783 | |
e31c7eec TW |
784 | if (!rproto) |
785 | warning ("class `%s' does not implement the `%s' protocol", | |
786 | IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (rhs))), | |
787 | IDENTIFIER_POINTER (PROTOCOL_NAME (p))); | |
788 | } | |
789 | } | |
790 | ||
51900510 RK |
791 | /* May change...based on whether there was any mismatch */ |
792 | return 1; | |
e31c7eec TW |
793 | } |
794 | else if (rhs_is_proto) | |
51900510 RK |
795 | /* Lhs is not a protocol...warn if it is statically typed */ |
796 | return (TYPED_OBJECT (TREE_TYPE (lhs)) != 0); | |
e31c7eec | 797 | |
e31c7eec | 798 | else |
51900510 RK |
799 | /* Defer to comptypes .*/ |
800 | return -1; | |
e31c7eec | 801 | } |
51900510 | 802 | |
e31c7eec | 803 | else if (TREE_CODE (lhs) == RECORD_TYPE && TREE_CODE (rhs) == RECORD_TYPE) |
51900510 | 804 | ; /* Fall thru. This is the case we have been handling all along */ |
e31c7eec | 805 | else |
0f41302f | 806 | /* Defer to comptypes. */ |
51900510 | 807 | return -1; |
e31c7eec | 808 | |
6c65299b RS |
809 | /* `id' = `<class> *', `<class> *' = `id' */ |
810 | ||
811 | if ((TYPE_NAME (lhs) == objc_object_id && TYPED_OBJECT (rhs)) | |
e31c7eec | 812 | || (TYPE_NAME (rhs) == objc_object_id && TYPED_OBJECT (lhs))) |
6c65299b RS |
813 | return 1; |
814 | ||
815 | /* `id' = `Class', `Class' = `id' */ | |
816 | ||
e31c7eec TW |
817 | else if ((TYPE_NAME (lhs) == objc_object_id |
818 | && TYPE_NAME (rhs) == objc_class_id) | |
819 | || (TYPE_NAME (lhs) == objc_class_id | |
820 | && TYPE_NAME (rhs) == objc_object_id)) | |
6c65299b RS |
821 | return 1; |
822 | ||
823 | /* `<class> *' = `<class> *' */ | |
824 | ||
825 | else if (TYPED_OBJECT (lhs) && TYPED_OBJECT (rhs)) | |
826 | { | |
e31c7eec TW |
827 | tree lname = TYPE_NAME (lhs); |
828 | tree rname = TYPE_NAME (rhs); | |
829 | tree inter; | |
6c65299b RS |
830 | |
831 | if (lname == rname) | |
832 | return 1; | |
6c65299b | 833 | |
e31c7eec TW |
834 | /* If the left hand side is a super class of the right hand side, |
835 | allow it. */ | |
836 | for (inter = lookup_interface (rname); inter; | |
837 | inter = lookup_interface (CLASS_SUPER_NAME (inter))) | |
838 | if (lname == CLASS_SUPER_NAME (inter)) | |
839 | return 1; | |
840 | ||
841 | /* Allow the reverse when reflexive. */ | |
842 | if (reflexive) | |
843 | for (inter = lookup_interface (lname); inter; | |
844 | inter = lookup_interface (CLASS_SUPER_NAME (inter))) | |
845 | if (rname == CLASS_SUPER_NAME (inter)) | |
846 | return 1; | |
847 | ||
848 | return 0; | |
6c65299b RS |
849 | } |
850 | else | |
0f41302f | 851 | /* Defer to comptypes. */ |
51900510 | 852 | return -1; |
6c65299b RS |
853 | } |
854 | ||
855 | /* Called from c-decl.c before all calls to rest_of_decl_compilation. */ | |
856 | ||
e31c7eec TW |
857 | void |
858 | objc_check_decl (decl) | |
859 | tree decl; | |
860 | { | |
861 | tree type = TREE_TYPE (decl); | |
862 | ||
863 | if (TREE_CODE (type) == RECORD_TYPE | |
864 | && TREE_STATIC_TEMPLATE (type) | |
865 | && type != constant_string_type) | |
866 | { | |
867 | error_with_decl (decl, "`%s' cannot be statically allocated"); | |
868 | fatal ("statically allocated objects not supported"); | |
869 | } | |
870 | } | |
871 | ||
6c65299b RS |
872 | void |
873 | maybe_objc_check_decl (decl) | |
874 | tree decl; | |
875 | { | |
876 | if (doing_objc_thang) | |
877 | objc_check_decl (decl); | |
878 | } | |
879 | ||
e31c7eec TW |
880 | /* Implement static typing. At this point, we know we have an interface. */ |
881 | ||
882 | tree | |
883 | get_static_reference (interface, protocols) | |
884 | tree interface; | |
885 | tree protocols; | |
6c65299b | 886 | { |
e31c7eec | 887 | tree type = xref_tag (RECORD_TYPE, interface); |
6c65299b | 888 | |
e31c7eec | 889 | if (protocols) |
6c65299b | 890 | { |
e31c7eec | 891 | tree t, m = TYPE_MAIN_VARIANT (type); |
e31c7eec | 892 | |
51900510 RK |
893 | push_obstacks_nochange (); |
894 | end_temporary_allocation (); | |
e31c7eec | 895 | t = copy_node (type); |
5fa63f2a | 896 | TYPE_BINFO (t) = make_tree_vec (2); |
51900510 | 897 | pop_obstacks (); |
e31c7eec TW |
898 | |
899 | /* Add this type to the chain of variants of TYPE. */ | |
900 | TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m); | |
901 | TYPE_NEXT_VARIANT (m) = t; | |
902 | ||
e31c7eec TW |
903 | /* Look up protocols and install in lang specific list. */ |
904 | TYPE_PROTOCOL_LIST (t) = lookup_and_install_protocols (protocols); | |
905 | ||
906 | /* This forces a new pointer type to be created later | |
907 | (in build_pointer_type)...so that the new template | |
908 | we just created will actually be used...what a hack! */ | |
909 | if (TYPE_POINTER_TO (t)) | |
51900510 | 910 | TYPE_POINTER_TO (t) = 0; |
e31c7eec TW |
911 | |
912 | type = t; | |
6c65299b | 913 | } |
6c65299b | 914 | |
e31c7eec TW |
915 | return type; |
916 | } | |
6c65299b RS |
917 | |
918 | tree | |
e31c7eec TW |
919 | get_object_reference (protocols) |
920 | tree protocols; | |
921 | { | |
922 | tree type_decl = lookup_name (objc_id_id); | |
923 | tree type; | |
924 | ||
925 | if (type_decl && TREE_CODE (type_decl) == TYPE_DECL) | |
926 | { | |
927 | type = TREE_TYPE (type_decl); | |
928 | if (TYPE_MAIN_VARIANT (type) != id_type) | |
929 | warning ("Unexpected type for `id' (%s)", | |
930 | gen_declaration (type, errbuf)); | |
931 | } | |
932 | else | |
51900510 | 933 | fatal ("Undefined type `id', please import <objc/objc.h>"); |
e31c7eec TW |
934 | |
935 | /* This clause creates a new pointer type that is qualified with | |
936 | the protocol specification...this info is used later to do more | |
937 | elaborate type checking. */ | |
51900510 | 938 | |
e31c7eec TW |
939 | if (protocols) |
940 | { | |
941 | tree t, m = TYPE_MAIN_VARIANT (type); | |
e31c7eec | 942 | |
51900510 RK |
943 | push_obstacks_nochange (); |
944 | end_temporary_allocation (); | |
e31c7eec | 945 | t = copy_node (type); |
5fa63f2a | 946 | TYPE_BINFO (t) = make_tree_vec (2); |
51900510 | 947 | pop_obstacks (); |
e31c7eec TW |
948 | |
949 | /* Add this type to the chain of variants of TYPE. */ | |
950 | TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m); | |
951 | TYPE_NEXT_VARIANT (m) = t; | |
952 | ||
51900510 | 953 | /* Look up protocols...and install in lang specific list */ |
e31c7eec TW |
954 | TYPE_PROTOCOL_LIST (t) = lookup_and_install_protocols (protocols); |
955 | ||
956 | /* This forces a new pointer type to be created later | |
957 | (in build_pointer_type)...so that the new template | |
958 | we just created will actually be used...what a hack! */ | |
959 | if (TYPE_POINTER_TO (t)) | |
960 | TYPE_POINTER_TO (t) = NULL; | |
961 | ||
962 | type = t; | |
963 | } | |
964 | return type; | |
965 | } | |
966 | ||
967 | static tree | |
968 | lookup_and_install_protocols (protocols) | |
969 | tree protocols; | |
6c65299b | 970 | { |
e31c7eec TW |
971 | tree proto; |
972 | tree prev = NULL; | |
973 | tree return_value = protocols; | |
974 | ||
975 | for (proto = protocols; proto; proto = TREE_CHAIN (proto)) | |
976 | { | |
977 | tree ident = TREE_VALUE (proto); | |
978 | tree p = lookup_protocol (ident); | |
979 | ||
980 | if (!p) | |
981 | { | |
982 | error ("Cannot find protocol declaration for `%s'", | |
983 | IDENTIFIER_POINTER (ident)); | |
984 | if (prev) | |
985 | TREE_CHAIN (prev) = TREE_CHAIN (proto); | |
986 | else | |
987 | return_value = TREE_CHAIN (proto); | |
988 | } | |
989 | else | |
990 | { | |
0f41302f | 991 | /* Replace identifier with actual protocol node. */ |
e31c7eec TW |
992 | TREE_VALUE (proto) = p; |
993 | prev = proto; | |
994 | } | |
995 | } | |
51900510 | 996 | |
e31c7eec | 997 | return return_value; |
6c65299b RS |
998 | } |
999 | ||
af35aeb2 RS |
1000 | /* Create and push a decl for a built-in external variable or field NAME. |
1001 | CODE says which. | |
1002 | TYPE is its data type. */ | |
1003 | ||
1004 | static tree | |
1005 | create_builtin_decl (code, type, name) | |
1006 | enum tree_code code; | |
af35aeb2 | 1007 | tree type; |
6e3f0724 | 1008 | char *name; |
af35aeb2 RS |
1009 | { |
1010 | tree decl = build_decl (code, get_identifier (name), type); | |
51900510 | 1011 | |
af35aeb2 RS |
1012 | if (code == VAR_DECL) |
1013 | { | |
ed9eaf9b | 1014 | TREE_STATIC (decl) = 1; |
af35aeb2 RS |
1015 | make_decl_rtl (decl, 0, 1); |
1016 | pushdecl (decl); | |
1017 | } | |
51900510 RK |
1018 | |
1019 | DECL_ARTIFICIAL (decl) = 1; | |
af35aeb2 RS |
1020 | return decl; |
1021 | } | |
1022 | ||
51900510 | 1023 | /* Purpose: "play" parser, creating/installing representations |
e31c7eec TW |
1024 | of the declarations that are required by Objective-C. |
1025 | ||
51900510 | 1026 | Model: |
e31c7eec TW |
1027 | |
1028 | type_spec--------->sc_spec | |
1029 | (tree_list) (tree_list) | |
1030 | | | | |
1031 | | | | |
1032 | identifier_node identifier_node */ | |
1033 | ||
6c65299b RS |
1034 | static void |
1035 | synth_module_prologue () | |
1036 | { | |
e31c7eec TW |
1037 | tree temp_type; |
1038 | tree super_p; | |
6c65299b | 1039 | |
51900510 | 1040 | /* Defined in `objc.h' */ |
6c65299b RS |
1041 | objc_object_id = get_identifier (TAG_OBJECT); |
1042 | ||
1043 | objc_object_reference = xref_tag (RECORD_TYPE, objc_object_id); | |
1044 | ||
af35aeb2 | 1045 | id_type = build_pointer_type (objc_object_reference); |
6c65299b | 1046 | |
e31c7eec | 1047 | objc_id_id = get_identifier (TYPE_ID); |
6c65299b | 1048 | objc_class_id = get_identifier (TAG_CLASS); |
e31c7eec TW |
1049 | |
1050 | objc_class_type = build_pointer_type (xref_tag (RECORD_TYPE, objc_class_id)); | |
1051 | protocol_type = build_pointer_type (xref_tag (RECORD_TYPE, | |
1052 | get_identifier (PROTOCOL_OBJECT_CLASS_NAME))); | |
6c65299b | 1053 | |
af35aeb2 | 1054 | /* Declare type of selector-objects that represent an operation name. */ |
6c65299b RS |
1055 | |
1056 | #ifdef OBJC_INT_SELECTORS | |
1057 | /* `unsigned int' */ | |
af35aeb2 | 1058 | selector_type = unsigned_type_node; |
6c65299b RS |
1059 | #else |
1060 | /* `struct objc_selector *' */ | |
af35aeb2 RS |
1061 | selector_type |
1062 | = build_pointer_type (xref_tag (RECORD_TYPE, | |
1063 | get_identifier (TAG_SELECTOR))); | |
6c65299b RS |
1064 | #endif /* not OBJC_INT_SELECTORS */ |
1065 | ||
e31c7eec TW |
1066 | /* Forward declare type, or else the prototype for msgSendSuper will |
1067 | complain. */ | |
1068 | ||
1069 | super_p = build_pointer_type (xref_tag (RECORD_TYPE, | |
1070 | get_identifier (TAG_SUPER))); | |
1071 | ||
1072 | ||
1073 | /* id objc_msgSend (id, SEL, ...); */ | |
6c65299b | 1074 | |
af35aeb2 RS |
1075 | temp_type |
1076 | = build_function_type (id_type, | |
1077 | tree_cons (NULL_TREE, id_type, | |
51900510 RK |
1078 | tree_cons (NULL_TREE, selector_type, |
1079 | NULL_TREE))); | |
6c65299b | 1080 | |
e31c7eec TW |
1081 | if (! flag_next_runtime) |
1082 | { | |
1083 | umsg_decl = build_decl (FUNCTION_DECL, | |
1084 | get_identifier (TAG_MSGSEND), temp_type); | |
1085 | DECL_EXTERNAL (umsg_decl) = 1; | |
4f52d290 | 1086 | TREE_PUBLIC (umsg_decl) = 1; |
e31c7eec | 1087 | DECL_INLINE (umsg_decl) = 1; |
51900510 | 1088 | DECL_ARTIFICIAL (umsg_decl) = 1; |
e31c7eec TW |
1089 | |
1090 | if (flag_traditional && TAG_MSGSEND[0] != '_') | |
1091 | DECL_BUILT_IN_NONANSI (umsg_decl) = 1; | |
1092 | ||
1093 | make_decl_rtl (umsg_decl, NULL_PTR, 1); | |
1094 | pushdecl (umsg_decl); | |
1095 | } | |
1096 | else | |
1097 | umsg_decl = builtin_function (TAG_MSGSEND, temp_type, NOT_BUILT_IN, 0); | |
6c65299b | 1098 | |
e31c7eec | 1099 | /* id objc_msgSendSuper (struct objc_super *, SEL, ...); */ |
6c65299b | 1100 | |
af35aeb2 RS |
1101 | temp_type |
1102 | = build_function_type (id_type, | |
e31c7eec | 1103 | tree_cons (NULL_TREE, super_p, |
51900510 RK |
1104 | tree_cons (NULL_TREE, selector_type, |
1105 | NULL_TREE))); | |
6c65299b | 1106 | |
e31c7eec | 1107 | umsg_super_decl = builtin_function (TAG_MSGSENDSUPER, |
af35aeb2 | 1108 | temp_type, NOT_BUILT_IN, 0); |
6c65299b | 1109 | |
e31c7eec | 1110 | /* id objc_getClass (const char *); */ |
6c65299b | 1111 | |
e31c7eec | 1112 | temp_type = build_function_type (id_type, |
51900510 | 1113 | tree_cons (NULL_TREE, |
e31c7eec | 1114 | const_string_type_node, |
51900510 RK |
1115 | tree_cons (NULL_TREE, void_type_node, |
1116 | NULL_TREE))); | |
6c65299b | 1117 | |
e31c7eec TW |
1118 | objc_get_class_decl |
1119 | = builtin_function (TAG_GETCLASS, temp_type, NOT_BUILT_IN, 0); | |
6c65299b | 1120 | |
e31c7eec | 1121 | /* id objc_getMetaClass (const char *); */ |
6c65299b | 1122 | |
e31c7eec TW |
1123 | objc_get_meta_class_decl |
1124 | = builtin_function (TAG_GETMETACLASS, temp_type, NOT_BUILT_IN, 0); | |
6c65299b | 1125 | |
ba2e2786 | 1126 | /* static SEL _OBJC_SELECTOR_TABLE[]; */ |
e31c7eec TW |
1127 | |
1128 | if (! flag_next_runtime) | |
5d0f30f7 KKT |
1129 | { |
1130 | if (flag_typed_selectors) | |
1131 | { | |
51900510 RK |
1132 | /* Suppress outputting debug symbols, because |
1133 | dbxout_init hasn'r been called yet. */ | |
5d0f30f7 KKT |
1134 | enum debug_info_type save_write_symbols = write_symbols; |
1135 | write_symbols = NO_DEBUG; | |
1136 | ||
1137 | build_selector_template (); | |
51900510 | 1138 | temp_type = build_array_type (objc_selector_template, NULL_TREE); |
5d0f30f7 KKT |
1139 | |
1140 | write_symbols = save_write_symbols; | |
1141 | } | |
1142 | else | |
51900510 | 1143 | temp_type = build_array_type (selector_type, NULL_TREE); |
5d0f30f7 KKT |
1144 | |
1145 | layout_type (temp_type); | |
1146 | UOBJC_SELECTOR_TABLE_decl | |
1147 | = create_builtin_decl (VAR_DECL, temp_type, | |
1148 | "_OBJC_SELECTOR_TABLE"); | |
5d0f30f7 | 1149 | |
4cb8c14b RK |
1150 | /* Avoid warning when not sending messages. */ |
1151 | TREE_USED (UOBJC_SELECTOR_TABLE_decl) = 1; | |
1152 | } | |
e31c7eec TW |
1153 | |
1154 | generate_forward_declaration_to_string_table (); | |
1155 | ||
1156 | /* Forward declare constant_string_id and constant_string_type. */ | |
1157 | constant_string_id = get_identifier (STRING_OBJECT_CLASS_NAME); | |
1158 | constant_string_type = xref_tag (RECORD_TYPE, constant_string_id); | |
6c65299b RS |
1159 | } |
1160 | ||
e31c7eec TW |
1161 | /* Custom build_string which sets TREE_TYPE! */ |
1162 | ||
6c65299b RS |
1163 | static tree |
1164 | my_build_string (len, str) | |
1165 | int len; | |
1166 | char *str; | |
1167 | { | |
1168 | int wide_flag = 0; | |
e31c7eec | 1169 | tree a_string = build_string (len, str); |
51900510 | 1170 | |
e31c7eec TW |
1171 | /* Some code from combine_strings, which is local to c-parse.y. */ |
1172 | if (TREE_TYPE (a_string) == int_array_type_node) | |
6c65299b RS |
1173 | wide_flag = 1; |
1174 | ||
51900510 RK |
1175 | TREE_TYPE (a_string) |
1176 | = build_array_type (wide_flag ? integer_type_node : char_type_node, | |
1177 | build_index_type (build_int_2 (len - 1, 0))); | |
6c65299b | 1178 | |
51900510 | 1179 | TREE_CONSTANT (a_string) = 1; /* Puts string in the readonly segment */ |
e31c7eec TW |
1180 | TREE_STATIC (a_string) = 1; |
1181 | ||
1182 | return a_string; | |
1183 | } | |
1184 | ||
1185 | /* Return a newly constructed OBJC_STRING_CST node whose value is | |
1186 | the LEN characters at STR. | |
1187 | The TREE_TYPE is not initialized. */ | |
1188 | ||
1189 | tree | |
1190 | build_objc_string (len, str) | |
1191 | int len; | |
1192 | char *str; | |
1193 | { | |
1194 | tree s = build_string (len, str); | |
1195 | ||
59ce3fc8 | 1196 | TREE_SET_CODE (s, OBJC_STRING_CST); |
e31c7eec TW |
1197 | return s; |
1198 | } | |
1199 | ||
1200 | /* Given a chain of OBJC_STRING_CST's, build a static instance of | |
51900510 | 1201 | NXConstanString which points at the concatenation of those strings. |
e31c7eec TW |
1202 | We place the string object in the __string_objects section of the |
1203 | __OBJC segment. The Objective-C runtime will initialize the isa | |
51900510 RK |
1204 | pointers of the string objects to point at the NXConstandString class |
1205 | object. */ | |
e31c7eec TW |
1206 | |
1207 | tree | |
1208 | build_objc_string_object (strings) | |
1209 | tree strings; | |
1210 | { | |
1211 | tree string, initlist, constructor; | |
1212 | int length; | |
1213 | ||
1214 | if (!doing_objc_thang) | |
1215 | objc_fatal (); | |
1216 | ||
51900510 | 1217 | if (lookup_interface (constant_string_id) == NULL_TREE) |
e31c7eec TW |
1218 | { |
1219 | error ("Cannot find interface declaration for `%s'", | |
51900510 | 1220 | IDENTIFIER_POINTER (constant_string_id)); |
e31c7eec TW |
1221 | return error_mark_node; |
1222 | } | |
1223 | ||
1224 | add_class_reference (constant_string_id); | |
6c65299b | 1225 | |
51900510 | 1226 | /* Combine_strings will work for OBJC_STRING_CST's too. */ |
e31c7eec | 1227 | string = combine_strings (strings); |
59ce3fc8 | 1228 | TREE_SET_CODE (string, STRING_CST); |
e31c7eec TW |
1229 | length = TREE_STRING_LENGTH (string) - 1; |
1230 | ||
51900510 RK |
1231 | if (! flag_next_runtime) |
1232 | { | |
1233 | push_obstacks_nochange (); | |
1234 | end_temporary_allocation (); | |
1235 | if (! TREE_PERMANENT (strings)) | |
1236 | string = my_build_string (length + 1, | |
1237 | TREE_STRING_POINTER (string)); | |
1238 | } | |
1239 | ||
e31c7eec TW |
1240 | /* & ((NXConstantString) {0, string, length}) */ |
1241 | ||
51900510 RK |
1242 | initlist = build_tree_list (NULL_TREE, build_int_2 (0, 0)); |
1243 | initlist | |
1244 | = tree_cons (NULL_TREE, copy_node (build_unary_op (ADDR_EXPR, string, 1)), | |
1245 | initlist); | |
1246 | initlist = tree_cons (NULL_TREE, build_int_2 (length, 0), initlist); | |
1247 | constructor = build_constructor (constant_string_type, nreverse (initlist)); | |
89ef1046 | 1248 | |
4cb8c14b | 1249 | if (!flag_next_runtime) |
51900510 RK |
1250 | { |
1251 | constructor | |
1252 | = objc_add_static_instance (constructor, constant_string_type); | |
1253 | pop_obstacks (); | |
1254 | } | |
1255 | ||
4cb8c14b RK |
1256 | return (build_unary_op (ADDR_EXPR, constructor, 1)); |
1257 | } | |
1258 | ||
1259 | /* Declare a static instance of CLASS_DECL initialized by CONSTRUCTOR. */ | |
51900510 | 1260 | |
4cb8c14b RK |
1261 | static tree |
1262 | objc_add_static_instance (constructor, class_decl) | |
1263 | tree constructor, class_decl; | |
1264 | { | |
1265 | static int num_static_inst; | |
4cb8c14b RK |
1266 | tree *chain, decl, decl_spec, decl_expr; |
1267 | char buf[256]; | |
1268 | ||
51900510 RK |
1269 | push_obstacks_nochange (); |
1270 | end_temporary_allocation (); | |
4cb8c14b RK |
1271 | |
1272 | /* Find the list of static instances for the CLASS_DECL. Create one if | |
1273 | not found. */ | |
1274 | for (chain = &objc_static_instances; | |
1275 | *chain && TREE_VALUE (*chain) != class_decl; | |
1276 | chain = &TREE_CHAIN (*chain)); | |
1277 | if (!*chain) | |
1278 | { | |
51900510 | 1279 | *chain = tree_cons (NULL_TREE, class_decl, NULL_TREE); |
4cb8c14b RK |
1280 | add_objc_string (TYPE_NAME (class_decl), class_names); |
1281 | } | |
1282 | ||
1283 | sprintf (buf, "_OBJC_INSTANCE_%d", num_static_inst++); | |
51900510 RK |
1284 | decl = build_decl (VAR_DECL, get_identifier (buf), class_decl); |
1285 | DECL_COMMON (decl) = 1; | |
1286 | TREE_STATIC (decl) = 1; | |
1287 | DECL_ARTIFICIAL (decl) = 1; | |
1288 | pushdecl_top_level (decl); | |
1289 | rest_of_decl_compilation (decl, 0, 1, 0); | |
4cb8c14b | 1290 | |
51900510 RK |
1291 | /* Do this here so it gets output later instead of possibly |
1292 | inside something else we are writing. */ | |
1293 | DECL_INITIAL (decl) = constructor; | |
4cb8c14b RK |
1294 | |
1295 | /* Add the DECL to the head of this CLASS' list. */ | |
51900510 RK |
1296 | TREE_PURPOSE (*chain) = tree_cons (NULL_TREE, decl, TREE_PURPOSE (*chain)); |
1297 | ||
1298 | pop_obstacks (); | |
1299 | return decl; | |
89ef1046 RS |
1300 | } |
1301 | ||
1302 | /* Build a static constant CONSTRUCTOR | |
1303 | with type TYPE and elements ELTS. */ | |
1304 | ||
1305 | static tree | |
1306 | build_constructor (type, elts) | |
1307 | tree type, elts; | |
1308 | { | |
1309 | tree constructor = build (CONSTRUCTOR, type, NULL_TREE, elts); | |
1310 | ||
e31c7eec TW |
1311 | TREE_CONSTANT (constructor) = 1; |
1312 | TREE_STATIC (constructor) = 1; | |
1313 | TREE_READONLY (constructor) = 1; | |
1314 | ||
89ef1046 | 1315 | return constructor; |
6c65299b | 1316 | } |
af35aeb2 RS |
1317 | \f |
1318 | /* Take care of defining and initializing _OBJC_SYMBOLS. */ | |
1319 | ||
1320 | /* Predefine the following data type: | |
1321 | ||
e31c7eec TW |
1322 | struct _objc_symtab |
1323 | { | |
1324 | long sel_ref_cnt; | |
1325 | SEL *refs; | |
1326 | short cls_def_cnt; | |
1327 | short cat_def_cnt; | |
1328 | void *defs[cls_def_cnt + cat_def_cnt]; | |
1329 | }; */ | |
6c65299b | 1330 | |
6c65299b RS |
1331 | static void |
1332 | build_objc_symtab_template () | |
1333 | { | |
af35aeb2 | 1334 | tree field_decl, field_decl_chain, index; |
6c65299b | 1335 | |
51900510 RK |
1336 | objc_symtab_template |
1337 | = start_struct (RECORD_TYPE, get_identifier (UTAG_SYMTAB)); | |
6c65299b RS |
1338 | |
1339 | /* long sel_ref_cnt; */ | |
1340 | ||
af35aeb2 RS |
1341 | field_decl = create_builtin_decl (FIELD_DECL, |
1342 | long_integer_type_node, | |
1343 | "sel_ref_cnt"); | |
6c65299b RS |
1344 | field_decl_chain = field_decl; |
1345 | ||
af35aeb2 | 1346 | /* SEL *refs; */ |
6c65299b | 1347 | |
af35aeb2 RS |
1348 | field_decl = create_builtin_decl (FIELD_DECL, |
1349 | build_pointer_type (selector_type), | |
1350 | "refs"); | |
6c65299b RS |
1351 | chainon (field_decl_chain, field_decl); |
1352 | ||
1353 | /* short cls_def_cnt; */ | |
1354 | ||
af35aeb2 RS |
1355 | field_decl = create_builtin_decl (FIELD_DECL, |
1356 | short_integer_type_node, | |
1357 | "cls_def_cnt"); | |
6c65299b RS |
1358 | chainon (field_decl_chain, field_decl); |
1359 | ||
1360 | /* short cat_def_cnt; */ | |
1361 | ||
af35aeb2 RS |
1362 | field_decl = create_builtin_decl (FIELD_DECL, |
1363 | short_integer_type_node, | |
1364 | "cat_def_cnt"); | |
6c65299b RS |
1365 | chainon (field_decl_chain, field_decl); |
1366 | ||
1367 | /* void *defs[cls_def_cnt + cat_def_cnt]; */ | |
1368 | ||
f0052887 RK |
1369 | index = build_index_type (build_int_2 (imp_count + cat_count - 1, |
1370 | imp_count == 0 && cat_count == 0 | |
1371 | ? -1 : 0)); | |
af35aeb2 RS |
1372 | field_decl = create_builtin_decl (FIELD_DECL, |
1373 | build_array_type (ptr_type_node, index), | |
1374 | "defs"); | |
6c65299b RS |
1375 | chainon (field_decl_chain, field_decl); |
1376 | ||
51900510 | 1377 | finish_struct (objc_symtab_template, field_decl_chain, NULL_TREE); |
6c65299b RS |
1378 | } |
1379 | ||
af35aeb2 RS |
1380 | /* Create the initial value for the `defs' field of _objc_symtab. |
1381 | This is a CONSTRUCTOR. */ | |
1382 | ||
6c65299b | 1383 | static tree |
89ef1046 RS |
1384 | init_def_list (type) |
1385 | tree type; | |
6c65299b | 1386 | { |
51900510 | 1387 | tree expr, initlist = NULL_TREE; |
6c65299b RS |
1388 | struct imp_entry *impent; |
1389 | ||
1390 | if (imp_count) | |
1391 | for (impent = imp_list; impent; impent = impent->next) | |
1392 | { | |
e31c7eec | 1393 | if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE) |
6c65299b RS |
1394 | { |
1395 | expr = build_unary_op (ADDR_EXPR, impent->class_decl, 0); | |
51900510 | 1396 | initlist = tree_cons (NULL_TREE, expr, initlist); |
6c65299b RS |
1397 | } |
1398 | } | |
1399 | ||
1400 | if (cat_count) | |
1401 | for (impent = imp_list; impent; impent = impent->next) | |
1402 | { | |
e31c7eec | 1403 | if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE) |
6c65299b RS |
1404 | { |
1405 | expr = build_unary_op (ADDR_EXPR, impent->class_decl, 0); | |
51900510 | 1406 | initlist = tree_cons (NULL_TREE, expr, initlist); |
6c65299b RS |
1407 | } |
1408 | } | |
51900510 | 1409 | |
89ef1046 | 1410 | return build_constructor (type, nreverse (initlist)); |
6c65299b RS |
1411 | } |
1412 | ||
af35aeb2 RS |
1413 | /* Construct the initial value for all of _objc_symtab. */ |
1414 | ||
6c65299b | 1415 | static tree |
89ef1046 RS |
1416 | init_objc_symtab (type) |
1417 | tree type; | |
6c65299b RS |
1418 | { |
1419 | tree initlist; | |
1420 | ||
1421 | /* sel_ref_cnt = { ..., 5, ... } */ | |
1422 | ||
51900510 | 1423 | initlist = build_tree_list (NULL_TREE, build_int_2 (0, 0)); |
6c65299b | 1424 | |
ba2e2786 | 1425 | /* refs = { ..., _OBJC_SELECTOR_TABLE, ... } */ |
6c65299b | 1426 | |
e31c7eec | 1427 | if (flag_next_runtime || ! sel_ref_chain) |
51900510 | 1428 | initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist); |
e31c7eec | 1429 | else |
51900510 | 1430 | initlist = tree_cons (NULL_TREE, |
89ef1046 RS |
1431 | build_unary_op (ADDR_EXPR, |
1432 | UOBJC_SELECTOR_TABLE_decl, 1), | |
1433 | initlist); | |
6c65299b RS |
1434 | |
1435 | /* cls_def_cnt = { ..., 5, ... } */ | |
1436 | ||
51900510 | 1437 | initlist = tree_cons (NULL_TREE, build_int_2 (imp_count, 0), initlist); |
6c65299b RS |
1438 | |
1439 | /* cat_def_cnt = { ..., 5, ... } */ | |
1440 | ||
51900510 | 1441 | initlist = tree_cons (NULL_TREE, build_int_2 (cat_count, 0), initlist); |
6c65299b RS |
1442 | |
1443 | /* cls_def = { ..., { &Foo, &Bar, ...}, ... } */ | |
1444 | ||
1445 | if (imp_count || cat_count) | |
89ef1046 RS |
1446 | { |
1447 | tree field = TYPE_FIELDS (type); | |
1448 | field = TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (field)))); | |
1449 | ||
51900510 | 1450 | initlist = tree_cons (NULL_TREE, init_def_list (TREE_TYPE (field)), |
89ef1046 RS |
1451 | initlist); |
1452 | } | |
6c65299b | 1453 | |
89ef1046 | 1454 | return build_constructor (type, nreverse (initlist)); |
6c65299b RS |
1455 | } |
1456 | ||
af35aeb2 RS |
1457 | /* Push forward-declarations of all the categories |
1458 | so that init_def_list can use them in a CONSTRUCTOR. */ | |
1459 | ||
6c65299b RS |
1460 | static void |
1461 | forward_declare_categories () | |
1462 | { | |
1463 | struct imp_entry *impent; | |
1464 | tree sav = implementation_context; | |
51900510 | 1465 | |
6c65299b RS |
1466 | for (impent = imp_list; impent; impent = impent->next) |
1467 | { | |
e31c7eec | 1468 | if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE) |
6c65299b | 1469 | { |
af35aeb2 | 1470 | /* Set an invisible arg to synth_id_with_class_suffix. */ |
6c65299b | 1471 | implementation_context = impent->imp_context; |
af35aeb2 RS |
1472 | impent->class_decl |
1473 | = create_builtin_decl (VAR_DECL, objc_category_template, | |
e31c7eec | 1474 | IDENTIFIER_POINTER (synth_id_with_class_suffix ("_OBJC_CATEGORY", implementation_context))); |
6c65299b RS |
1475 | } |
1476 | } | |
1477 | implementation_context = sav; | |
1478 | } | |
1479 | ||
af35aeb2 RS |
1480 | /* Create the declaration of _OBJC_SYMBOLS, with type `strict _objc_symtab' |
1481 | and initialized appropriately. */ | |
1482 | ||
6c65299b RS |
1483 | static void |
1484 | generate_objc_symtab_decl () | |
1485 | { | |
1486 | tree sc_spec; | |
1487 | ||
1488 | if (!objc_category_template) | |
1489 | build_category_template (); | |
1490 | ||
1491 | /* forward declare categories */ | |
1492 | if (cat_count) | |
1493 | forward_declare_categories (); | |
1494 | ||
1495 | if (!objc_symtab_template) | |
1496 | build_objc_symtab_template (); | |
1497 | ||
51900510 | 1498 | sc_spec = build_tree_list (NULL_TREE, ridpointers[(int) RID_STATIC]); |
6c65299b | 1499 | |
e31c7eec | 1500 | UOBJC_SYMBOLS_decl = start_decl (get_identifier ("_OBJC_SYMBOLS"), |
51900510 RK |
1501 | tree_cons (NULL_TREE, |
1502 | objc_symtab_template, sc_spec), | |
1503 | 1, | |
1504 | NULL_TREE, NULL_TREE); | |
6c65299b | 1505 | |
e31c7eec TW |
1506 | TREE_USED (UOBJC_SYMBOLS_decl) = 1; |
1507 | DECL_IGNORED_P (UOBJC_SYMBOLS_decl) = 1; | |
51900510 | 1508 | DECL_ARTIFICIAL (UOBJC_SYMBOLS_decl) = 1; |
89ef1046 RS |
1509 | finish_decl (UOBJC_SYMBOLS_decl, |
1510 | init_objc_symtab (TREE_TYPE (UOBJC_SYMBOLS_decl)), | |
51900510 | 1511 | NULL_TREE); |
6c65299b | 1512 | } |
af35aeb2 | 1513 | \f |
6c65299b | 1514 | static tree |
89ef1046 RS |
1515 | init_module_descriptor (type) |
1516 | tree type; | |
6c65299b RS |
1517 | { |
1518 | tree initlist, expr; | |
1519 | ||
1520 | /* version = { 1, ... } */ | |
1521 | ||
1522 | expr = build_int_2 (OBJC_VERSION, 0); | |
51900510 | 1523 | initlist = build_tree_list (NULL_TREE, expr); |
6c65299b RS |
1524 | |
1525 | /* size = { ..., sizeof (struct objc_module), ... } */ | |
1526 | ||
c55dc79a | 1527 | expr = size_in_bytes (objc_module_template); |
51900510 | 1528 | initlist = tree_cons (NULL_TREE, expr, initlist); |
6c65299b RS |
1529 | |
1530 | /* name = { ..., "foo.m", ... } */ | |
1531 | ||
e31c7eec | 1532 | expr = add_objc_string (get_identifier (input_filename), class_names); |
51900510 | 1533 | initlist = tree_cons (NULL_TREE, expr, initlist); |
6c65299b | 1534 | |
4cb8c14b RK |
1535 | |
1536 | if (!flag_next_runtime) | |
1537 | { | |
1538 | /* statics = { ..., _OBJC_STATIC_INSTANCES, ... } */ | |
1539 | if (static_instances_decl) | |
1540 | expr = build_unary_op (ADDR_EXPR, static_instances_decl, 0); | |
1541 | else | |
1542 | expr = build_int_2 (0, 0); | |
51900510 | 1543 | initlist = tree_cons (NULL_TREE, expr, initlist); |
4cb8c14b RK |
1544 | } |
1545 | ||
6c65299b RS |
1546 | /* symtab = { ..., _OBJC_SYMBOLS, ... } */ |
1547 | ||
e31c7eec TW |
1548 | if (UOBJC_SYMBOLS_decl) |
1549 | expr = build_unary_op (ADDR_EXPR, UOBJC_SYMBOLS_decl, 0); | |
6c65299b RS |
1550 | else |
1551 | expr = build_int_2 (0, 0); | |
51900510 | 1552 | initlist = tree_cons (NULL_TREE, expr, initlist); |
6c65299b | 1553 | |
89ef1046 | 1554 | return build_constructor (type, nreverse (initlist)); |
6c65299b RS |
1555 | } |
1556 | ||
1557 | /* Write out the data structures to describe Objective C classes defined. | |
1558 | If appropriate, compile and output a setup function to initialize them. | |
1559 | Return a string which is the name of a function to call to initialize | |
1560 | the Objective C data structures for this file (and perhaps for other files | |
e31c7eec TW |
1561 | also). |
1562 | ||
51900510 | 1563 | struct objc_module { ... } _OBJC_MODULE = { ... }; */ |
6c65299b RS |
1564 | |
1565 | static char * | |
1566 | build_module_descriptor () | |
1567 | { | |
1568 | tree decl_specs, field_decl, field_decl_chain; | |
1569 | ||
51900510 RK |
1570 | objc_module_template |
1571 | = start_struct (RECORD_TYPE, get_identifier (UTAG_MODULE)); | |
6c65299b | 1572 | |
51900510 | 1573 | /* Long version; */ |
6c65299b | 1574 | |
51900510 | 1575 | decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_LONG]); |
6c65299b | 1576 | field_decl = get_identifier ("version"); |
51900510 RK |
1577 | field_decl |
1578 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
6c65299b RS |
1579 | field_decl_chain = field_decl; |
1580 | ||
1581 | /* long size; */ | |
1582 | ||
51900510 | 1583 | decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_LONG]); |
6c65299b | 1584 | field_decl = get_identifier ("size"); |
51900510 RK |
1585 | field_decl |
1586 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
6c65299b RS |
1587 | chainon (field_decl_chain, field_decl); |
1588 | ||
1589 | /* char *name; */ | |
1590 | ||
51900510 RK |
1591 | decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]); |
1592 | field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("name")); | |
1593 | field_decl | |
1594 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
6c65299b RS |
1595 | chainon (field_decl_chain, field_decl); |
1596 | ||
4cb8c14b RK |
1597 | |
1598 | if (!flag_next_runtime) | |
1599 | { | |
1600 | /* void *statics */ | |
1601 | ||
1602 | decl_specs = get_identifier (UTAG_STATICS); | |
51900510 RK |
1603 | decl_specs |
1604 | = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE, decl_specs)); | |
1605 | field_decl | |
1606 | = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("statics")); | |
4cb8c14b | 1607 | field_decl = grokfield (input_filename, lineno, field_decl, |
51900510 | 1608 | decl_specs, NULL_TREE); |
4cb8c14b RK |
1609 | chainon (field_decl_chain, field_decl); |
1610 | } | |
1611 | ||
1612 | ||
6c65299b RS |
1613 | /* struct objc_symtab *symtab; */ |
1614 | ||
e31c7eec | 1615 | decl_specs = get_identifier (UTAG_SYMTAB); |
51900510 RK |
1616 | decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE, decl_specs)); |
1617 | field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("symtab")); | |
1618 | field_decl | |
1619 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
6c65299b RS |
1620 | chainon (field_decl_chain, field_decl); |
1621 | ||
51900510 | 1622 | finish_struct (objc_module_template, field_decl_chain, NULL_TREE); |
6c65299b | 1623 | |
0f41302f | 1624 | /* Create an instance of "objc_module". */ |
6c65299b | 1625 | |
51900510 RK |
1626 | decl_specs = tree_cons (NULL_TREE, objc_module_template, |
1627 | build_tree_list (NULL_TREE, | |
1628 | ridpointers[(int) RID_STATIC])); | |
6c65299b | 1629 | |
e31c7eec | 1630 | UOBJC_MODULES_decl = start_decl (get_identifier ("_OBJC_MODULES"), |
51900510 | 1631 | decl_specs, 1, NULL_TREE, NULL_TREE); |
6c65299b | 1632 | |
51900510 | 1633 | DECL_ARTIFICIAL (UOBJC_MODULES_decl) = 1; |
e31c7eec | 1634 | DECL_IGNORED_P (UOBJC_MODULES_decl) = 1; |
89ef1046 RS |
1635 | finish_decl (UOBJC_MODULES_decl, |
1636 | init_module_descriptor (TREE_TYPE (UOBJC_MODULES_decl)), | |
51900510 | 1637 | NULL_TREE); |
6c65299b | 1638 | |
0f41302f | 1639 | /* Mark the decl to avoid "defined but not used" warning. */ |
e31c7eec | 1640 | DECL_IN_SYSTEM_HEADER (UOBJC_MODULES_decl) = 1; |
6c65299b | 1641 | |
e31c7eec | 1642 | /* Generate a constructor call for the module descriptor. |
6c65299b | 1643 | This code was generated by reading the grammar rules |
51900510 | 1644 | of c-parse.in; Therefore, it may not be the most efficient |
0f41302f | 1645 | way of generating the requisite code. */ |
e31c7eec TW |
1646 | |
1647 | if (flag_next_runtime) | |
1648 | return 0; | |
1649 | ||
6c65299b RS |
1650 | { |
1651 | tree parms, function_decl, decelerator, void_list_node; | |
1652 | tree function_type; | |
6b3cf8c6 PB |
1653 | extern tree get_file_function_name (); |
1654 | tree init_function_name = get_file_function_name ('I'); | |
6c65299b | 1655 | |
0f41302f | 1656 | /* Declare void __objc_execClass (void *); */ |
6c65299b RS |
1657 | |
1658 | void_list_node = build_tree_list (NULL_TREE, void_type_node); | |
1659 | function_type | |
e31c7eec TW |
1660 | = build_function_type (void_type_node, |
1661 | tree_cons (NULL_TREE, ptr_type_node, | |
6c65299b | 1662 | void_list_node)); |
e31c7eec TW |
1663 | function_decl = build_decl (FUNCTION_DECL, |
1664 | get_identifier (TAG_EXECCLASS), | |
6c65299b | 1665 | function_type); |
0924ddef | 1666 | DECL_EXTERNAL (function_decl) = 1; |
51900510 | 1667 | DECL_ARTIFICIAL (function_decl) = 1; |
6c65299b | 1668 | TREE_PUBLIC (function_decl) = 1; |
5d0f30f7 | 1669 | |
6c65299b RS |
1670 | pushdecl (function_decl); |
1671 | rest_of_decl_compilation (function_decl, 0, 0, 0); | |
1672 | ||
1673 | parms | |
51900510 | 1674 | = build_tree_list (NULL_TREE, |
e31c7eec | 1675 | build_unary_op (ADDR_EXPR, UOBJC_MODULES_decl, 0)); |
6c65299b RS |
1676 | decelerator = build_function_call (function_decl, parms); |
1677 | ||
e31c7eec | 1678 | /* void _GLOBAL_$I$<gnyf> () {objc_execClass (&L_OBJC_MODULES);} */ |
6c65299b RS |
1679 | |
1680 | start_function (void_list_node, | |
6b3cf8c6 | 1681 | build_parse_node (CALL_EXPR, init_function_name, |
6c65299b RS |
1682 | /* This has the format of the output |
1683 | of get_parm_info. */ | |
1684 | tree_cons (NULL_TREE, NULL_TREE, | |
1685 | void_list_node), | |
1686 | NULL_TREE), | |
0763f3ab | 1687 | NULL_TREE, NULL_TREE, 0); |
6c65299b RS |
1688 | #if 0 /* This should be turned back on later |
1689 | for the systems where collect is not needed. */ | |
1690 | /* Make these functions nonglobal | |
1691 | so each file can use the same name. */ | |
1692 | TREE_PUBLIC (current_function_decl) = 0; | |
1693 | #endif | |
1694 | TREE_USED (current_function_decl) = 1; | |
1695 | store_parm_decls (); | |
1696 | ||
1697 | assemble_external (function_decl); | |
1698 | c_expand_expr_stmt (decelerator); | |
1699 | ||
5d0f30f7 | 1700 | TREE_PUBLIC (current_function_decl) = 1; |
5d0f30f7 | 1701 | |
4d4d7c0e | 1702 | function_decl = current_function_decl; |
6c65299b RS |
1703 | finish_function (0); |
1704 | ||
1705 | /* Return the name of the constructor function. */ | |
4d4d7c0e | 1706 | return XSTR (XEXP (DECL_RTL (function_decl), 0), 0); |
6c65299b | 1707 | } |
6c65299b RS |
1708 | } |
1709 | ||
1710 | /* extern const char _OBJC_STRINGS[]; */ | |
1711 | ||
1712 | static void | |
1713 | generate_forward_declaration_to_string_table () | |
1714 | { | |
1715 | tree sc_spec, decl_specs, expr_decl; | |
1716 | ||
51900510 RK |
1717 | sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_EXTERN], NULL_TREE); |
1718 | decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec); | |
6c65299b | 1719 | |
51900510 RK |
1720 | expr_decl |
1721 | = build_nt (ARRAY_REF, get_identifier ("_OBJC_STRINGS"), NULL_TREE); | |
6c65299b | 1722 | |
e31c7eec | 1723 | UOBJC_STRINGS_decl = define_decl (expr_decl, decl_specs); |
6c65299b RS |
1724 | } |
1725 | ||
4cb8c14b | 1726 | /* Return the DECL of the string IDENT in the SECTION. */ |
51900510 | 1727 | |
4cb8c14b RK |
1728 | static tree |
1729 | get_objc_string_decl (ident, section) | |
1730 | tree ident; | |
1731 | enum string_section section; | |
1732 | { | |
1733 | tree chain, decl; | |
1734 | ||
1735 | if (section == class_names) | |
1736 | chain = class_names_chain; | |
1737 | else if (section == meth_var_names) | |
1738 | chain = meth_var_names_chain; | |
1739 | else if (section == meth_var_types) | |
1740 | chain = meth_var_types_chain; | |
1741 | ||
51900510 RK |
1742 | for (; chain != 0; chain = TREE_VALUE (chain)) |
1743 | if (TREE_VALUE (chain) == ident) | |
1744 | return (TREE_PURPOSE (chain)); | |
4cb8c14b RK |
1745 | |
1746 | abort (); | |
51900510 | 1747 | return NULL_TREE; |
4cb8c14b RK |
1748 | } |
1749 | ||
1750 | /* Output references to all statically allocated objects. Return the DECL | |
1751 | for the array built. */ | |
51900510 | 1752 | |
4cb8c14b RK |
1753 | static tree |
1754 | generate_static_references () | |
1755 | { | |
51900510 | 1756 | tree decls = NULL_TREE, ident, decl_spec, expr_decl, expr = NULL_TREE; |
4cb8c14b RK |
1757 | tree class_name, class, decl, instance, idecl, initlist; |
1758 | tree cl_chain, in_chain, type; | |
1759 | int num_inst, num_class; | |
1760 | char buf[256]; | |
1761 | ||
1762 | if (flag_next_runtime) | |
1763 | abort (); | |
1764 | ||
4cb8c14b RK |
1765 | for (cl_chain = objc_static_instances, num_class = 0; |
1766 | cl_chain; cl_chain = TREE_CHAIN (cl_chain), num_class++) | |
1767 | { | |
1768 | for (num_inst = 0, in_chain = TREE_PURPOSE (cl_chain); | |
1769 | in_chain; num_inst++, in_chain = TREE_CHAIN (in_chain)); | |
1770 | ||
1771 | sprintf (buf, "_OBJC_STATIC_INSTANCES_%d", num_class); | |
1772 | ident = get_identifier (buf); | |
1773 | ||
51900510 RK |
1774 | expr_decl = build_nt (ARRAY_REF, ident, NULL_TREE); |
1775 | decl_spec = tree_cons (NULL_TREE, build_pointer_type (void_type_node), | |
1776 | build_tree_list (NULL_TREE, | |
4cb8c14b | 1777 | ridpointers[(int) RID_STATIC])); |
51900510 RK |
1778 | decl = start_decl (expr_decl, decl_spec, 1, NULL_TREE, NULL_TREE); |
1779 | DECL_CONTEXT (decl) = 0; | |
1780 | DECL_ARTIFICIAL (decl) = 1; | |
4cb8c14b RK |
1781 | |
1782 | /* Output {class_name, ...}. */ | |
1783 | class = TREE_VALUE (cl_chain); | |
1784 | class_name = get_objc_string_decl (TYPE_NAME (class), class_names); | |
51900510 | 1785 | initlist = build_tree_list (NULL_TREE, |
4cb8c14b RK |
1786 | build_unary_op (ADDR_EXPR, class_name, 1)); |
1787 | ||
1788 | /* Output {..., instance, ...}. */ | |
1789 | for (in_chain = TREE_PURPOSE (cl_chain); | |
1790 | in_chain; in_chain = TREE_CHAIN (in_chain)) | |
1791 | { | |
1792 | expr = build_unary_op (ADDR_EXPR, TREE_VALUE (in_chain), 1); | |
51900510 | 1793 | initlist = tree_cons (NULL_TREE, expr, initlist); |
4cb8c14b RK |
1794 | } |
1795 | ||
1796 | /* Output {..., NULL}. */ | |
51900510 | 1797 | initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist); |
4cb8c14b RK |
1798 | |
1799 | expr = build_constructor (TREE_TYPE (decl), nreverse (initlist)); | |
51900510 | 1800 | finish_decl (decl, expr, NULL_TREE); |
4cb8c14b RK |
1801 | TREE_USED (decl) = 1; |
1802 | ||
1803 | type = build_array_type (build_pointer_type (void_type_node), 0); | |
1804 | decl = build_decl (VAR_DECL, ident, type); | |
1805 | make_decl_rtl (decl, 0, 1); | |
1806 | TREE_USED (decl) = 1; | |
51900510 RK |
1807 | decls |
1808 | = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, decl, 1), decls); | |
4cb8c14b | 1809 | } |
51900510 RK |
1810 | |
1811 | decls = tree_cons (NULL_TREE, build_int_2 (0, 0), decls); | |
4cb8c14b | 1812 | ident = get_identifier ("_OBJC_STATIC_INSTANCES"); |
51900510 RK |
1813 | expr_decl = build_nt (ARRAY_REF, ident, NULL_TREE); |
1814 | decl_spec = tree_cons (NULL_TREE, build_pointer_type (void_type_node), | |
1815 | build_tree_list (NULL_TREE, | |
4cb8c14b | 1816 | ridpointers[(int) RID_STATIC])); |
51900510 RK |
1817 | static_instances_decl |
1818 | = start_decl (expr_decl, decl_spec, 1, NULL_TREE, NULL_TREE); | |
1819 | DECL_CONTEXT (static_instances_decl) = 0; | |
1820 | DECL_ARTIFICIAL (static_instances_decl) = 1; | |
4cb8c14b RK |
1821 | end_temporary_allocation (); |
1822 | expr = build_constructor (TREE_TYPE (static_instances_decl), | |
1823 | nreverse (decls)); | |
51900510 | 1824 | finish_decl (static_instances_decl, expr, NULL_TREE); |
4cb8c14b RK |
1825 | } |
1826 | ||
0f41302f | 1827 | /* Output all strings. */ |
6c65299b RS |
1828 | |
1829 | static void | |
e31c7eec | 1830 | generate_strings () |
6c65299b RS |
1831 | { |
1832 | tree sc_spec, decl_specs, expr_decl; | |
1833 | tree chain, string_expr; | |
e31c7eec | 1834 | tree string, decl; |
6c65299b | 1835 | |
e31c7eec | 1836 | for (chain = class_names_chain; chain; chain = TREE_CHAIN (chain)) |
6c65299b | 1837 | { |
e31c7eec TW |
1838 | string = TREE_VALUE (chain); |
1839 | decl = TREE_PURPOSE (chain); | |
51900510 RK |
1840 | sc_spec |
1841 | = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE); | |
1842 | decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec); | |
1843 | expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE); | |
1844 | decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE, NULL_TREE); | |
e31c7eec TW |
1845 | end_temporary_allocation (); |
1846 | string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1, | |
51900510 RK |
1847 | IDENTIFIER_POINTER (string)); |
1848 | finish_decl (decl, string_expr, NULL_TREE); | |
6c65299b RS |
1849 | } |
1850 | ||
e31c7eec TW |
1851 | for (chain = meth_var_names_chain; chain; chain = TREE_CHAIN (chain)) |
1852 | { | |
1853 | string = TREE_VALUE (chain); | |
1854 | decl = TREE_PURPOSE (chain); | |
51900510 RK |
1855 | sc_spec |
1856 | = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE); | |
1857 | decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec); | |
1858 | expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE); | |
1859 | decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE, NULL_TREE); | |
e31c7eec | 1860 | string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1, |
51900510 RK |
1861 | IDENTIFIER_POINTER (string)); |
1862 | finish_decl (decl, string_expr, NULL_TREE); | |
e31c7eec | 1863 | } |
6c65299b | 1864 | |
e31c7eec TW |
1865 | for (chain = meth_var_types_chain; chain; chain = TREE_CHAIN (chain)) |
1866 | { | |
1867 | string = TREE_VALUE (chain); | |
1868 | decl = TREE_PURPOSE (chain); | |
51900510 RK |
1869 | sc_spec |
1870 | = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE); | |
1871 | decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec); | |
1872 | expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE); | |
1873 | decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE, NULL_TREE); | |
e31c7eec TW |
1874 | string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1, |
1875 | IDENTIFIER_POINTER (string)); | |
51900510 | 1876 | finish_decl (decl, string_expr, NULL_TREE); |
e31c7eec | 1877 | } |
6c65299b RS |
1878 | } |
1879 | ||
6c65299b | 1880 | static tree |
e31c7eec TW |
1881 | build_selector_reference_decl (name) |
1882 | tree name; | |
6c65299b | 1883 | { |
e31c7eec TW |
1884 | tree decl, ident; |
1885 | char buf[256]; | |
e31c7eec | 1886 | static int idx = 0; |
6c65299b | 1887 | |
e31c7eec | 1888 | sprintf (buf, "_OBJC_SELECTOR_REFERENCES_%d", idx++); |
6c65299b | 1889 | |
51900510 RK |
1890 | push_obstacks_nochange (); |
1891 | end_temporary_allocation (); | |
1892 | ||
6c65299b RS |
1893 | ident = get_identifier (buf); |
1894 | ||
e31c7eec TW |
1895 | decl = build_decl (VAR_DECL, ident, selector_type); |
1896 | DECL_EXTERNAL (decl) = 1; | |
1897 | TREE_PUBLIC (decl) = 1; | |
1898 | TREE_USED (decl) = 1; | |
1899 | TREE_READONLY (decl) = 1; | |
51900510 RK |
1900 | DECL_ARTIFICIAL (decl) = 1; |
1901 | DECL_CONTEXT (decl) = 0; | |
e31c7eec | 1902 | |
51900510 RK |
1903 | make_decl_rtl (decl, 0, 1); |
1904 | pushdecl_top_level (decl); | |
e31c7eec | 1905 | |
51900510 | 1906 | pop_obstacks (); |
6c65299b RS |
1907 | |
1908 | return decl; | |
1909 | } | |
e31c7eec TW |
1910 | |
1911 | /* Just a handy wrapper for add_objc_string. */ | |
1912 | ||
1913 | static tree | |
1914 | build_selector (ident) | |
1915 | tree ident; | |
1916 | { | |
1917 | tree expr = add_objc_string (ident, meth_var_names); | |
5d0f30f7 KKT |
1918 | if (flag_typed_selectors) |
1919 | return expr; | |
1920 | else | |
1921 | return build_c_cast (selector_type, expr); /* cast! */ | |
e31c7eec TW |
1922 | } |
1923 | ||
1924 | /* Synthesize the following expr: (char *)&_OBJC_STRINGS[<offset>] | |
1925 | The cast stops the compiler from issuing the following message: | |
1926 | grok.m: warning: initialization of non-const * pointer from const * | |
1927 | grok.m: warning: initialization between incompatible pointer types. */ | |
1928 | ||
1929 | static tree | |
1930 | build_msg_pool_reference (offset) | |
1931 | int offset; | |
1932 | { | |
1933 | tree expr = build_int_2 (offset, 0); | |
1934 | tree cast; | |
1935 | ||
1936 | expr = build_array_ref (UOBJC_STRINGS_decl, expr); | |
1937 | expr = build_unary_op (ADDR_EXPR, expr, 0); | |
1938 | ||
51900510 RK |
1939 | cast = build_tree_list (build_tree_list (NULL_TREE, |
1940 | ridpointers[(int) RID_CHAR]), | |
1941 | build1 (INDIRECT_REF, NULL_TREE, NULL_TREE)); | |
e31c7eec TW |
1942 | TREE_TYPE (expr) = groktypename (cast); |
1943 | return expr; | |
1944 | } | |
6c65299b RS |
1945 | |
1946 | static tree | |
1947 | init_selector (offset) | |
1948 | int offset; | |
1949 | { | |
1950 | tree expr = build_msg_pool_reference (offset); | |
51900510 | 1951 | TREE_TYPE (expr) = selector_type; |
6c65299b RS |
1952 | return expr; |
1953 | } | |
1954 | ||
1955 | static void | |
1956 | build_selector_translation_table () | |
1957 | { | |
e31c7eec | 1958 | tree sc_spec, decl_specs; |
51900510 | 1959 | tree chain, initlist = NULL_TREE; |
6c65299b | 1960 | int offset = 0; |
e31c7eec TW |
1961 | tree decl, var_decl, name; |
1962 | ||
55142f01 RS |
1963 | /* The corresponding pop_obstacks is in finish_decl, |
1964 | called at the end of this function. */ | |
e31c7eec TW |
1965 | if (! flag_next_runtime) |
1966 | push_obstacks_nochange (); | |
6c65299b RS |
1967 | |
1968 | for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain)) | |
1969 | { | |
1970 | tree expr; | |
1971 | ||
e31c7eec TW |
1972 | expr = build_selector (TREE_VALUE (chain)); |
1973 | ||
1974 | if (flag_next_runtime) | |
1975 | { | |
1976 | name = DECL_NAME (TREE_PURPOSE (chain)); | |
6c65299b | 1977 | |
51900510 | 1978 | sc_spec = build_tree_list (NULL_TREE, ridpointers[(int) RID_STATIC]); |
6c65299b | 1979 | |
e31c7eec | 1980 | /* static SEL _OBJC_SELECTOR_REFERENCES_n = ...; */ |
51900510 | 1981 | decl_specs = tree_cons (NULL_TREE, selector_type, sc_spec); |
6c65299b | 1982 | |
e31c7eec TW |
1983 | var_decl = name; |
1984 | ||
51900510 | 1985 | /* The `decl' that is returned from start_decl is the one that we |
e31c7eec | 1986 | forward declared in `build_selector_reference' */ |
51900510 | 1987 | decl = start_decl (var_decl, decl_specs, 1, NULL_TREE, NULL_TREE); |
e31c7eec | 1988 | } |
6c65299b RS |
1989 | |
1990 | /* add one for the '\0' character */ | |
1991 | offset += IDENTIFIER_LENGTH (TREE_VALUE (chain)) + 1; | |
1992 | ||
e31c7eec | 1993 | if (flag_next_runtime) |
51900510 | 1994 | finish_decl (decl, expr, NULL_TREE); |
5d0f30f7 KKT |
1995 | else |
1996 | { | |
1997 | if (flag_typed_selectors) | |
1998 | { | |
51900510 | 1999 | tree eltlist = NULL_TREE; |
5d0f30f7 | 2000 | tree encoding = get_proto_encoding (TREE_PURPOSE (chain)); |
51900510 RK |
2001 | eltlist = tree_cons (NULL_TREE, expr, NULL_TREE); |
2002 | eltlist = tree_cons (NULL_TREE, encoding, eltlist); | |
5d0f30f7 KKT |
2003 | expr = build_constructor (objc_selector_template, |
2004 | nreverse (eltlist)); | |
2005 | } | |
51900510 | 2006 | initlist = tree_cons (NULL_TREE, expr, initlist); |
5d0f30f7 KKT |
2007 | |
2008 | } | |
6c65299b RS |
2009 | } |
2010 | ||
e31c7eec TW |
2011 | if (! flag_next_runtime) |
2012 | { | |
2013 | /* Cause the variable and its initial value to be actually output. */ | |
ba2e2786 TW |
2014 | DECL_EXTERNAL (UOBJC_SELECTOR_TABLE_decl) = 0; |
2015 | TREE_STATIC (UOBJC_SELECTOR_TABLE_decl) = 1; | |
0f41302f | 2016 | /* NULL terminate the list and fix the decl for output. */ |
51900510 | 2017 | initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist); |
ba2e2786 | 2018 | DECL_INITIAL (UOBJC_SELECTOR_TABLE_decl) = (tree) 1; |
89ef1046 RS |
2019 | initlist = build_constructor (TREE_TYPE (UOBJC_SELECTOR_TABLE_decl), |
2020 | nreverse (initlist)); | |
51900510 RK |
2021 | finish_decl (UOBJC_SELECTOR_TABLE_decl, initlist, NULL_TREE); |
2022 | current_function_decl = NULL_TREE; | |
e31c7eec TW |
2023 | } |
2024 | } | |
2025 | ||
5d0f30f7 KKT |
2026 | static tree |
2027 | get_proto_encoding (proto) | |
2028 | tree proto; | |
2029 | { | |
2030 | tree encoding; | |
2031 | if (proto) | |
2032 | { | |
2033 | tree tmp_decl; | |
2034 | ||
2035 | if (! METHOD_ENCODING (proto)) | |
2036 | { | |
2037 | tmp_decl = build_tmp_function_decl (); | |
2038 | hack_method_prototype (proto, tmp_decl); | |
2039 | encoding = encode_method_prototype (proto, tmp_decl); | |
2040 | METHOD_ENCODING (proto) = encoding; | |
2041 | } | |
2042 | else | |
2043 | encoding = METHOD_ENCODING (proto); | |
2044 | ||
2045 | return add_objc_string (encoding, meth_var_types); | |
2046 | } | |
2047 | else | |
2048 | return build_int_2 (0, 0); | |
2049 | } | |
2050 | ||
e31c7eec TW |
2051 | /* sel_ref_chain is a list whose "value" fields will be instances of |
2052 | identifier_node that represent the selector. */ | |
2053 | ||
5d0f30f7 KKT |
2054 | static tree |
2055 | build_typed_selector_reference (ident, proto) | |
2056 | tree ident, proto; | |
2057 | { | |
2058 | tree *chain = &sel_ref_chain; | |
2059 | tree expr; | |
2060 | int index = 0; | |
2061 | ||
2062 | while (*chain) | |
2063 | { | |
2064 | if (TREE_PURPOSE (*chain) == ident && TREE_VALUE (*chain) == proto) | |
2065 | goto return_at_index; | |
51900510 | 2066 | |
5d0f30f7 KKT |
2067 | index++; |
2068 | chain = &TREE_CHAIN (*chain); | |
2069 | } | |
2070 | ||
51900510 | 2071 | *chain = perm_tree_cons (proto, ident, NULL_TREE); |
5d0f30f7 KKT |
2072 | |
2073 | return_at_index: | |
2074 | expr = build_unary_op (ADDR_EXPR, | |
2075 | build_array_ref (UOBJC_SELECTOR_TABLE_decl, | |
2076 | build_int_2 (index, 0)), | |
2077 | 1); | |
2078 | return build_c_cast (selector_type, expr); | |
2079 | } | |
2080 | ||
e31c7eec TW |
2081 | static tree |
2082 | build_selector_reference (ident) | |
2083 | tree ident; | |
2084 | { | |
2085 | tree *chain = &sel_ref_chain; | |
5d0f30f7 | 2086 | tree expr; |
e31c7eec TW |
2087 | int index = 0; |
2088 | ||
2089 | while (*chain) | |
2090 | { | |
2091 | if (TREE_VALUE (*chain) == ident) | |
2092 | return (flag_next_runtime | |
2093 | ? TREE_PURPOSE (*chain) | |
ba2e2786 | 2094 | : build_array_ref (UOBJC_SELECTOR_TABLE_decl, |
e31c7eec TW |
2095 | build_int_2 (index, 0))); |
2096 | ||
2097 | index++; | |
2098 | chain = &TREE_CHAIN (*chain); | |
2099 | } | |
2100 | ||
5d0f30f7 | 2101 | expr = build_selector_reference_decl (ident); |
e31c7eec | 2102 | |
51900510 | 2103 | *chain = perm_tree_cons (expr, ident, NULL_TREE); |
e31c7eec TW |
2104 | |
2105 | return (flag_next_runtime | |
5d0f30f7 | 2106 | ? expr |
ba2e2786 | 2107 | : build_array_ref (UOBJC_SELECTOR_TABLE_decl, |
e31c7eec TW |
2108 | build_int_2 (index, 0))); |
2109 | } | |
2110 | ||
2111 | static tree | |
2112 | build_class_reference_decl (name) | |
2113 | tree name; | |
2114 | { | |
2115 | tree decl, ident; | |
2116 | char buf[256]; | |
e31c7eec TW |
2117 | static int idx = 0; |
2118 | ||
2119 | sprintf (buf, "_OBJC_CLASS_REFERENCES_%d", idx++); | |
2120 | ||
51900510 RK |
2121 | push_obstacks_nochange (); |
2122 | end_temporary_allocation (); | |
2123 | ||
e31c7eec TW |
2124 | ident = get_identifier (buf); |
2125 | ||
2126 | decl = build_decl (VAR_DECL, ident, objc_class_type); | |
2127 | DECL_EXTERNAL (decl) = 1; | |
2128 | TREE_PUBLIC (decl) = 1; | |
2129 | TREE_USED (decl) = 1; | |
2130 | TREE_READONLY (decl) = 1; | |
51900510 RK |
2131 | DECL_CONTEXT (decl) = 0; |
2132 | DECL_ARTIFICIAL (decl) = 1; | |
e31c7eec | 2133 | |
51900510 RK |
2134 | make_decl_rtl (decl, 0, 1); |
2135 | pushdecl_top_level (decl); | |
e31c7eec | 2136 | |
51900510 | 2137 | pop_obstacks (); |
e31c7eec TW |
2138 | |
2139 | return decl; | |
6c65299b RS |
2140 | } |
2141 | ||
e31c7eec TW |
2142 | /* Create a class reference, but don't create a variable to reference |
2143 | it. */ | |
2144 | ||
6c65299b RS |
2145 | static void |
2146 | add_class_reference (ident) | |
2147 | tree ident; | |
2148 | { | |
2149 | tree chain; | |
2150 | ||
e31c7eec | 2151 | if ((chain = cls_ref_chain)) |
6c65299b RS |
2152 | { |
2153 | tree tail; | |
2154 | do | |
2155 | { | |
2156 | if (ident == TREE_VALUE (chain)) | |
2157 | return; | |
2158 | ||
2159 | tail = chain; | |
2160 | chain = TREE_CHAIN (chain); | |
2161 | } | |
2162 | while (chain); | |
2163 | ||
51900510 RK |
2164 | /* Append to the end of the list */ |
2165 | TREE_CHAIN (tail) = perm_tree_cons (NULL_TREE, ident, NULL_TREE); | |
6c65299b RS |
2166 | } |
2167 | else | |
51900510 | 2168 | cls_ref_chain = perm_tree_cons (NULL_TREE, ident, NULL_TREE); |
6c65299b RS |
2169 | } |
2170 | ||
e31c7eec TW |
2171 | /* Get a class reference, creating it if necessary. Also create the |
2172 | reference variable. */ | |
2173 | ||
2174 | tree | |
2175 | get_class_reference (ident) | |
2176 | tree ident; | |
6c65299b | 2177 | { |
e31c7eec TW |
2178 | if (flag_next_runtime) |
2179 | { | |
2180 | tree *chain; | |
2181 | tree decl; | |
6c65299b | 2182 | |
e31c7eec TW |
2183 | for (chain = &cls_ref_chain; *chain; chain = &TREE_CHAIN (*chain)) |
2184 | if (TREE_VALUE (*chain) == ident) | |
2185 | { | |
2186 | if (! TREE_PURPOSE (*chain)) | |
2187 | TREE_PURPOSE (*chain) = build_class_reference_decl (ident); | |
51900510 | 2188 | |
e31c7eec TW |
2189 | return TREE_PURPOSE (*chain); |
2190 | } | |
6c65299b | 2191 | |
e31c7eec | 2192 | decl = build_class_reference_decl (ident); |
51900510 | 2193 | *chain = perm_tree_cons (decl, ident, NULL_TREE); |
e31c7eec TW |
2194 | return decl; |
2195 | } | |
2196 | else | |
6c65299b | 2197 | { |
e31c7eec | 2198 | tree params; |
6c65299b | 2199 | |
59ce3fc8 | 2200 | add_class_reference (ident); |
7651f8f7 | 2201 | |
51900510 | 2202 | params = build_tree_list (NULL_TREE, |
e31c7eec TW |
2203 | my_build_string (IDENTIFIER_LENGTH (ident) + 1, |
2204 | IDENTIFIER_POINTER (ident))); | |
6c65299b | 2205 | |
e31c7eec TW |
2206 | assemble_external (objc_get_class_decl); |
2207 | return build_function_call (objc_get_class_decl, params); | |
2208 | } | |
2209 | } | |
2210 | ||
51900510 | 2211 | /* SEL_REFDEF_CHAIN is a list whose "value" fields will be instances |
e31c7eec TW |
2212 | of identifier_node that represent the selector. It returns the |
2213 | offset of the selector from the beginning of the _OBJC_STRINGS | |
2214 | pool. This offset is typically used by init_selector during code | |
2215 | generation. | |
2216 | ||
2217 | For each string section we have a chain which maps identifier nodes | |
0f41302f | 2218 | to decls for the strings. */ |
e31c7eec TW |
2219 | |
2220 | static tree | |
2221 | add_objc_string (ident, section) | |
2222 | tree ident; | |
2223 | enum string_section section; | |
2224 | { | |
2225 | tree *chain, decl; | |
2226 | ||
2227 | if (section == class_names) | |
2228 | chain = &class_names_chain; | |
2229 | else if (section == meth_var_names) | |
2230 | chain = &meth_var_names_chain; | |
2231 | else if (section == meth_var_types) | |
2232 | chain = &meth_var_types_chain; | |
2233 | ||
2234 | while (*chain) | |
2235 | { | |
2236 | if (TREE_VALUE (*chain) == ident) | |
89ef1046 | 2237 | return build_unary_op (ADDR_EXPR, TREE_PURPOSE (*chain), 1); |
e31c7eec TW |
2238 | |
2239 | chain = &TREE_CHAIN (*chain); | |
6c65299b | 2240 | } |
e31c7eec TW |
2241 | |
2242 | decl = build_objc_string_decl (ident, section); | |
2243 | ||
51900510 | 2244 | *chain = perm_tree_cons (decl, ident, NULL_TREE); |
e31c7eec | 2245 | |
89ef1046 | 2246 | return build_unary_op (ADDR_EXPR, decl, 1); |
e31c7eec TW |
2247 | } |
2248 | ||
2249 | static tree | |
2250 | build_objc_string_decl (name, section) | |
2251 | tree name; | |
2252 | enum string_section section; | |
2253 | { | |
2254 | tree decl, ident; | |
2255 | char buf[256]; | |
e31c7eec TW |
2256 | static int class_names_idx = 0; |
2257 | static int meth_var_names_idx = 0; | |
2258 | static int meth_var_types_idx = 0; | |
2259 | ||
2260 | if (section == class_names) | |
2261 | sprintf (buf, "_OBJC_CLASS_NAME_%d", class_names_idx++); | |
2262 | else if (section == meth_var_names) | |
2263 | sprintf (buf, "_OBJC_METH_VAR_NAME_%d", meth_var_names_idx++); | |
2264 | else if (section == meth_var_types) | |
2265 | sprintf (buf, "_OBJC_METH_VAR_TYPE_%d", meth_var_types_idx++); | |
2266 | ||
51900510 RK |
2267 | push_obstacks_nochange (); |
2268 | end_temporary_allocation (); | |
e31c7eec TW |
2269 | ident = get_identifier (buf); |
2270 | ||
2271 | decl = build_decl (VAR_DECL, ident, build_array_type (char_type_node, 0)); | |
2272 | DECL_EXTERNAL (decl) = 1; | |
2273 | TREE_PUBLIC (decl) = 1; | |
2274 | TREE_USED (decl) = 1; | |
2275 | TREE_READONLY (decl) = 1; | |
2276 | TREE_CONSTANT (decl) = 1; | |
51900510 RK |
2277 | DECL_CONTEXT (decl) = 0; |
2278 | DECL_ARTIFICIAL (decl) = 1; | |
4cb8c14b | 2279 | |
51900510 RK |
2280 | make_decl_rtl (decl, 0, 1); |
2281 | pushdecl_top_level (decl); | |
e31c7eec | 2282 | |
51900510 | 2283 | pop_obstacks (); |
e31c7eec TW |
2284 | |
2285 | return decl; | |
2286 | } | |
2287 | ||
2288 | ||
2289 | void | |
2290 | objc_declare_alias (alias_ident, class_ident) | |
2291 | tree alias_ident; | |
2292 | tree class_ident; | |
2293 | { | |
2294 | if (!doing_objc_thang) | |
2295 | objc_fatal (); | |
2296 | ||
2297 | if (is_class_name (class_ident) != class_ident) | |
2298 | warning ("Cannot find class `%s'", IDENTIFIER_POINTER (class_ident)); | |
2299 | else if (is_class_name (alias_ident)) | |
2300 | warning ("Class `%s' already exists", IDENTIFIER_POINTER (alias_ident)); | |
6c65299b | 2301 | else |
e31c7eec TW |
2302 | alias_chain = tree_cons (class_ident, alias_ident, alias_chain); |
2303 | } | |
2304 | ||
2305 | void | |
2306 | objc_declare_class (ident_list) | |
2307 | tree ident_list; | |
2308 | { | |
2309 | tree list; | |
2310 | ||
2311 | if (!doing_objc_thang) | |
2312 | objc_fatal (); | |
6c65299b | 2313 | |
e31c7eec TW |
2314 | for (list = ident_list; list; list = TREE_CHAIN (list)) |
2315 | { | |
2316 | tree ident = TREE_VALUE (list); | |
2317 | tree decl; | |
2318 | ||
2319 | if ((decl = lookup_name (ident))) | |
2320 | { | |
2321 | error ("`%s' redeclared as different kind of symbol", | |
2322 | IDENTIFIER_POINTER (ident)); | |
2323 | error_with_decl (decl, "previous declaration of `%s'"); | |
2324 | } | |
2325 | ||
2326 | if (! is_class_name (ident)) | |
2327 | { | |
2328 | tree record = xref_tag (RECORD_TYPE, ident); | |
2329 | TREE_STATIC_TEMPLATE (record) = 1; | |
51900510 | 2330 | class_chain = tree_cons (NULL_TREE, ident, class_chain); |
e31c7eec TW |
2331 | } |
2332 | } | |
6c65299b RS |
2333 | } |
2334 | ||
e31c7eec TW |
2335 | tree |
2336 | is_class_name (ident) | |
6c65299b RS |
2337 | tree ident; |
2338 | { | |
2339 | tree chain; | |
6c65299b | 2340 | |
e31c7eec TW |
2341 | if (lookup_interface (ident)) |
2342 | return ident; | |
6c65299b | 2343 | |
e31c7eec TW |
2344 | for (chain = class_chain; chain; chain = TREE_CHAIN (chain)) |
2345 | { | |
2346 | if (ident == TREE_VALUE (chain)) | |
2347 | return ident; | |
2348 | } | |
6c65299b | 2349 | |
e31c7eec TW |
2350 | for (chain = alias_chain; chain; chain = TREE_CHAIN (chain)) |
2351 | { | |
2352 | if (ident == TREE_VALUE (chain)) | |
2353 | return TREE_PURPOSE (chain); | |
6c65299b | 2354 | } |
6c65299b | 2355 | |
e31c7eec | 2356 | return 0; |
6c65299b RS |
2357 | } |
2358 | ||
2359 | tree | |
2360 | lookup_interface (ident) | |
2361 | tree ident; | |
2362 | { | |
2363 | tree chain; | |
2364 | ||
2365 | for (chain = interface_chain; chain; chain = TREE_CHAIN (chain)) | |
2366 | { | |
2367 | if (ident == CLASS_NAME (chain)) | |
2368 | return chain; | |
2369 | } | |
51900510 | 2370 | return NULL_TREE; |
6c65299b RS |
2371 | } |
2372 | ||
2373 | static tree | |
2374 | objc_copy_list (list, head) | |
2375 | tree list; | |
2376 | tree *head; | |
2377 | { | |
2378 | tree newlist = NULL_TREE, tail = NULL_TREE; | |
2379 | ||
2380 | while (list) | |
2381 | { | |
2382 | tail = copy_node (list); | |
2383 | ||
e31c7eec TW |
2384 | /* The following statement fixes a bug when inheriting instance |
2385 | variables that are declared to be bitfields. finish_struct | |
2386 | expects to find the width of the bitfield in DECL_INITIAL, | |
2387 | which it nulls out after processing the decl of the super | |
2388 | class...rather than change the way finish_struct works (which | |
2389 | is risky), I create the situation it expects...s.naroff | |
2390 | (7/23/89). */ | |
2391 | ||
6c65299b | 2392 | if (DECL_BIT_FIELD (tail) && DECL_INITIAL (tail) == 0) |
77f934bb | 2393 | DECL_INITIAL (tail) = build_int_2 (DECL_FIELD_SIZE (tail), 0); |
6c65299b RS |
2394 | |
2395 | newlist = chainon (newlist, tail); | |
2396 | list = TREE_CHAIN (list); | |
2397 | } | |
51900510 | 2398 | |
e31c7eec TW |
2399 | *head = newlist; |
2400 | return tail; | |
2401 | } | |
2402 | ||
2403 | /* Used by: build_private_template, get_class_ivars, and | |
2404 | continue_class. COPY is 1 when called from @defs. In this case | |
2405 | copy all fields. Otherwise don't copy leaf ivars since we rely on | |
2406 | them being side-effected exactly once by finish_struct. */ | |
2407 | ||
2408 | static tree | |
2409 | build_ivar_chain (interface, copy) | |
2410 | tree interface; | |
2411 | int copy; | |
2412 | { | |
2413 | tree my_name, super_name, ivar_chain; | |
2414 | ||
2415 | my_name = CLASS_NAME (interface); | |
2416 | super_name = CLASS_SUPER_NAME (interface); | |
2417 | ||
2418 | /* Possibly copy leaf ivars. */ | |
2419 | if (copy) | |
2420 | objc_copy_list (CLASS_IVARS (interface), &ivar_chain); | |
2421 | else | |
2422 | ivar_chain = CLASS_IVARS (interface); | |
2423 | ||
2424 | while (super_name) | |
2425 | { | |
2426 | tree op1; | |
2427 | tree super_interface = lookup_interface (super_name); | |
2428 | ||
2429 | if (!super_interface) | |
2430 | { | |
2431 | /* fatal did not work with 2 args...should fix */ | |
2432 | error ("Cannot find interface declaration for `%s', superclass of `%s'", | |
2433 | IDENTIFIER_POINTER (super_name), | |
2434 | IDENTIFIER_POINTER (my_name)); | |
51900510 | 2435 | exit (FATAL_EXIT_CODE); |
e31c7eec | 2436 | } |
51900510 | 2437 | |
e31c7eec TW |
2438 | if (super_interface == interface) |
2439 | { | |
2440 | fatal ("Circular inheritance in interface declaration for `%s'", | |
2441 | IDENTIFIER_POINTER (super_name)); | |
2442 | } | |
51900510 | 2443 | |
e31c7eec TW |
2444 | interface = super_interface; |
2445 | my_name = CLASS_NAME (interface); | |
2446 | super_name = CLASS_SUPER_NAME (interface); | |
2447 | ||
2448 | op1 = CLASS_IVARS (interface); | |
2449 | if (op1) | |
2450 | { | |
2451 | tree head, tail = objc_copy_list (op1, &head); | |
2452 | ||
2453 | /* Prepend super class ivars...make a copy of the list, we | |
2454 | do not want to alter the original. */ | |
2455 | TREE_CHAIN (tail) = ivar_chain; | |
2456 | ivar_chain = head; | |
2457 | } | |
2458 | } | |
2459 | return ivar_chain; | |
2460 | } | |
2461 | ||
2462 | /* struct <classname> { | |
2463 | struct objc_class *isa; | |
2464 | ... | |
2465 | }; */ | |
2466 | ||
2467 | static tree | |
2468 | build_private_template (class) | |
2469 | tree class; | |
2470 | { | |
2471 | tree ivar_context; | |
2472 | ||
2473 | if (CLASS_STATIC_TEMPLATE (class)) | |
2474 | { | |
2475 | uprivate_record = CLASS_STATIC_TEMPLATE (class); | |
2476 | ivar_context = TYPE_FIELDS (CLASS_STATIC_TEMPLATE (class)); | |
2477 | } | |
2478 | else | |
2479 | { | |
2480 | uprivate_record = start_struct (RECORD_TYPE, CLASS_NAME (class)); | |
2481 | ||
2482 | ivar_context = build_ivar_chain (class, 0); | |
2483 | ||
51900510 | 2484 | finish_struct (uprivate_record, ivar_context, NULL_TREE); |
e31c7eec TW |
2485 | |
2486 | CLASS_STATIC_TEMPLATE (class) = uprivate_record; | |
2487 | ||
2488 | /* mark this record as class template - for class type checking */ | |
2489 | TREE_STATIC_TEMPLATE (uprivate_record) = 1; | |
2490 | } | |
51900510 RK |
2491 | |
2492 | instance_type | |
2493 | = groktypename (build_tree_list (build_tree_list (NULL_TREE, | |
2494 | uprivate_record), | |
2495 | build1 (INDIRECT_REF, NULL_TREE, | |
2496 | NULL_TREE))); | |
2497 | ||
e31c7eec TW |
2498 | return ivar_context; |
2499 | } | |
2500 | \f | |
0f41302f | 2501 | /* Begin code generation for protocols... */ |
e31c7eec TW |
2502 | |
2503 | /* struct objc_protocol { | |
2504 | char *protocol_name; | |
2505 | struct objc_protocol **protocol_list; | |
2506 | struct objc_method_desc *instance_methods; | |
2507 | struct objc_method_desc *class_methods; | |
2508 | }; */ | |
2509 | ||
2510 | static tree | |
2511 | build_protocol_template () | |
2512 | { | |
2513 | tree decl_specs, field_decl, field_decl_chain; | |
2514 | tree template; | |
2515 | ||
2516 | template = start_struct (RECORD_TYPE, get_identifier (UTAG_PROTOCOL)); | |
2517 | ||
2518 | /* struct objc_class *isa; */ | |
2519 | ||
51900510 | 2520 | decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE, |
e31c7eec | 2521 | get_identifier (UTAG_CLASS))); |
51900510 RK |
2522 | field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("isa")); |
2523 | field_decl | |
2524 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
e31c7eec TW |
2525 | field_decl_chain = field_decl; |
2526 | ||
2527 | /* char *protocol_name; */ | |
2528 | ||
51900510 RK |
2529 | decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]); |
2530 | field_decl | |
2531 | = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("protocol_name")); | |
2532 | field_decl | |
2533 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
e31c7eec TW |
2534 | chainon (field_decl_chain, field_decl); |
2535 | ||
2536 | /* struct objc_protocol **protocol_list; */ | |
2537 | ||
51900510 RK |
2538 | decl_specs = build_tree_list (NULL_TREE, template); |
2539 | field_decl | |
2540 | = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("protocol_list")); | |
2541 | field_decl = build1 (INDIRECT_REF, NULL_TREE, field_decl); | |
2542 | field_decl | |
2543 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
e31c7eec TW |
2544 | chainon (field_decl_chain, field_decl); |
2545 | ||
2546 | /* struct objc_method_list *instance_methods; */ | |
2547 | ||
51900510 RK |
2548 | decl_specs |
2549 | = build_tree_list (NULL_TREE, | |
2550 | xref_tag (RECORD_TYPE, | |
2551 | get_identifier (UTAG_METHOD_PROTOTYPE_LIST))); | |
2552 | field_decl | |
2553 | = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("instance_methods")); | |
2554 | field_decl | |
2555 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
e31c7eec TW |
2556 | chainon (field_decl_chain, field_decl); |
2557 | ||
2558 | /* struct objc_method_list *class_methods; */ | |
2559 | ||
51900510 RK |
2560 | decl_specs |
2561 | = build_tree_list (NULL_TREE, | |
2562 | xref_tag (RECORD_TYPE, | |
2563 | get_identifier (UTAG_METHOD_PROTOTYPE_LIST))); | |
2564 | field_decl | |
2565 | = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("class_methods")); | |
2566 | field_decl | |
2567 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
e31c7eec TW |
2568 | chainon (field_decl_chain, field_decl); |
2569 | ||
51900510 | 2570 | return finish_struct (template, field_decl_chain, NULL_TREE); |
e31c7eec TW |
2571 | } |
2572 | ||
2573 | static tree | |
30c0e2df | 2574 | build_descriptor_table_initializer (type, entries) |
89ef1046 | 2575 | tree type; |
e31c7eec | 2576 | tree entries; |
e31c7eec | 2577 | { |
51900510 | 2578 | tree initlist = NULL_TREE; |
e31c7eec TW |
2579 | |
2580 | do | |
2581 | { | |
51900510 | 2582 | tree eltlist = NULL_TREE; |
30c0e2df | 2583 | |
51900510 RK |
2584 | eltlist |
2585 | = tree_cons (NULL_TREE, | |
2586 | build_selector (METHOD_SEL_NAME (entries)), NULL_TREE); | |
2587 | eltlist | |
2588 | = tree_cons (NULL_TREE, | |
2589 | add_objc_string (METHOD_ENCODING (entries), | |
2590 | meth_var_types), | |
2591 | eltlist); | |
e31c7eec | 2592 | |
51900510 RK |
2593 | initlist |
2594 | = tree_cons (NULL_TREE, | |
2595 | build_constructor (type, nreverse (eltlist)), initlist); | |
e31c7eec | 2596 | |
e31c7eec TW |
2597 | entries = TREE_CHAIN (entries); |
2598 | } | |
2599 | while (entries); | |
2600 | ||
30c0e2df | 2601 | return build_constructor (build_array_type (type, 0), nreverse (initlist)); |
e31c7eec TW |
2602 | } |
2603 | ||
2604 | /* struct objc_method_prototype_list { | |
2605 | int count; | |
2606 | struct objc_method_prototype { | |
2607 | SEL name; | |
2608 | char *types; | |
2609 | } list[1]; | |
2610 | }; */ | |
2611 | ||
2612 | static tree | |
2613 | build_method_prototype_list_template (list_type, size) | |
2614 | tree list_type; | |
2615 | int size; | |
2616 | { | |
2617 | tree objc_ivar_list_record; | |
2618 | tree decl_specs, field_decl, field_decl_chain; | |
2619 | ||
0f41302f | 2620 | /* Generate an unnamed struct definition. */ |
e31c7eec | 2621 | |
51900510 | 2622 | objc_ivar_list_record = start_struct (RECORD_TYPE, NULL_TREE); |
e31c7eec TW |
2623 | |
2624 | /* int method_count; */ | |
2625 | ||
51900510 | 2626 | decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_INT]); |
e31c7eec TW |
2627 | field_decl = get_identifier ("method_count"); |
2628 | ||
51900510 RK |
2629 | field_decl |
2630 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
e31c7eec TW |
2631 | field_decl_chain = field_decl; |
2632 | ||
2633 | /* struct objc_method method_list[]; */ | |
2634 | ||
51900510 | 2635 | decl_specs = build_tree_list (NULL_TREE, list_type); |
e31c7eec TW |
2636 | field_decl = build_nt (ARRAY_REF, get_identifier ("method_list"), |
2637 | build_int_2 (size, 0)); | |
2638 | ||
51900510 RK |
2639 | field_decl |
2640 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
e31c7eec TW |
2641 | chainon (field_decl_chain, field_decl); |
2642 | ||
51900510 | 2643 | finish_struct (objc_ivar_list_record, field_decl_chain, NULL_TREE); |
e31c7eec TW |
2644 | |
2645 | return objc_ivar_list_record; | |
2646 | } | |
2647 | ||
2648 | static tree | |
2649 | build_method_prototype_template () | |
2650 | { | |
2651 | tree proto_record; | |
2652 | tree decl_specs, field_decl, field_decl_chain; | |
2653 | ||
51900510 RK |
2654 | proto_record |
2655 | = start_struct (RECORD_TYPE, get_identifier (UTAG_METHOD_PROTOTYPE)); | |
e31c7eec TW |
2656 | |
2657 | #ifdef OBJC_INT_SELECTORS | |
2658 | /* unsigned int _cmd; */ | |
51900510 RK |
2659 | decl_specs |
2660 | = tree_cons (NULL_TREE, ridpointers[(int) RID_UNSIGNED], NULL_TREE); | |
2661 | decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_INT], decl_specs); | |
e31c7eec TW |
2662 | field_decl = get_identifier ("_cmd"); |
2663 | #else /* OBJC_INT_SELECTORS */ | |
2664 | /* struct objc_selector *_cmd; */ | |
51900510 RK |
2665 | decl_specs = tree_cons (NULL_TREE, xref_tag (RECORD_TYPE, |
2666 | get_identifier (TAG_SELECTOR)), NULL_TREE); | |
2667 | field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("_cmd")); | |
e31c7eec TW |
2668 | #endif /* OBJC_INT_SELECTORS */ |
2669 | ||
51900510 RK |
2670 | field_decl |
2671 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
e31c7eec TW |
2672 | field_decl_chain = field_decl; |
2673 | ||
51900510 RK |
2674 | decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], NULL_TREE); |
2675 | field_decl | |
2676 | = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("method_types")); | |
2677 | field_decl | |
2678 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
e31c7eec TW |
2679 | chainon (field_decl_chain, field_decl); |
2680 | ||
51900510 | 2681 | finish_struct (proto_record, field_decl_chain, NULL_TREE); |
e31c7eec TW |
2682 | |
2683 | return proto_record; | |
2684 | } | |
2685 | ||
0f41302f | 2686 | /* True if last call to forwarding_offset yielded a register offset. */ |
30c0e2df KKT |
2687 | static int offset_is_register; |
2688 | ||
e31c7eec TW |
2689 | static int |
2690 | forwarding_offset (parm) | |
2691 | tree parm; | |
2692 | { | |
2693 | int offset_in_bytes; | |
2694 | ||
2695 | if (GET_CODE (DECL_INCOMING_RTL (parm)) == MEM) | |
2696 | { | |
2697 | rtx addr = XEXP (DECL_INCOMING_RTL (parm), 0); | |
2698 | ||
2699 | /* ??? Here we assume that the parm address is indexed | |
2700 | off the frame pointer or arg pointer. | |
2701 | If that is not true, we produce meaningless results, | |
2702 | but do not crash. */ | |
2703 | if (GET_CODE (addr) == PLUS | |
2704 | && GET_CODE (XEXP (addr, 1)) == CONST_INT) | |
2705 | offset_in_bytes = INTVAL (XEXP (addr, 1)); | |
2706 | else | |
2707 | offset_in_bytes = 0; | |
2708 | ||
2709 | offset_in_bytes += OBJC_FORWARDING_STACK_OFFSET; | |
30c0e2df | 2710 | offset_is_register = 0; |
e31c7eec | 2711 | } |
e31c7eec TW |
2712 | else if (GET_CODE (DECL_INCOMING_RTL (parm)) == REG) |
2713 | { | |
2714 | int regno = REGNO (DECL_INCOMING_RTL (parm)); | |
30c0e2df KKT |
2715 | offset_in_bytes = apply_args_register_offset (regno); |
2716 | offset_is_register = 1; | |
e31c7eec | 2717 | } |
e31c7eec TW |
2718 | else |
2719 | return 0; | |
2720 | ||
2721 | /* This is the case where the parm is passed as an int or double | |
51900510 RK |
2722 | and it is converted to a char, short or float and stored back |
2723 | in the parmlist. In this case, describe the parm | |
2724 | with the variable's declared type, and adjust the address | |
2725 | if the least significant bytes (which we are using) are not | |
2726 | the first ones. */ | |
f76b9db2 | 2727 | if (BYTES_BIG_ENDIAN && TREE_TYPE (parm) != DECL_ARG_TYPE (parm)) |
e31c7eec TW |
2728 | offset_in_bytes += (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parm))) |
2729 | - GET_MODE_SIZE (GET_MODE (DECL_RTL (parm)))); | |
e31c7eec TW |
2730 | |
2731 | return offset_in_bytes; | |
2732 | } | |
2733 | ||
2734 | static tree | |
2735 | encode_method_prototype (method_decl, func_decl) | |
2736 | tree method_decl; | |
2737 | tree func_decl; | |
2738 | { | |
2739 | tree parms; | |
2740 | int stack_size, i; | |
2741 | tree user_args; | |
2742 | int max_parm_end = 0; | |
2743 | char buf[40]; | |
2744 | tree result; | |
2745 | ||
0f41302f | 2746 | /* ONEWAY and BYCOPY, for remote object are the only method qualifiers. */ |
e31c7eec TW |
2747 | encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (method_decl))); |
2748 | ||
0f41302f | 2749 | /* C type. */ |
e31c7eec TW |
2750 | encode_type (TREE_TYPE (TREE_TYPE (func_decl)), |
2751 | obstack_object_size (&util_obstack), | |
2752 | OBJC_ENCODE_INLINE_DEFS); | |
2753 | ||
0f41302f | 2754 | /* Stack size. */ |
e31c7eec TW |
2755 | for (parms = DECL_ARGUMENTS (func_decl); parms; |
2756 | parms = TREE_CHAIN (parms)) | |
2757 | { | |
2758 | int parm_end = (forwarding_offset (parms) | |
2759 | + (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (parms))) | |
2760 | / BITS_PER_UNIT)); | |
2761 | ||
30c0e2df | 2762 | if (!offset_is_register && max_parm_end < parm_end) |
e31c7eec TW |
2763 | max_parm_end = parm_end; |
2764 | } | |
2765 | ||
2766 | stack_size = max_parm_end - OBJC_FORWARDING_MIN_OFFSET; | |
2767 | ||
2768 | sprintf (buf, "%d", stack_size); | |
2769 | obstack_grow (&util_obstack, buf, strlen (buf)); | |
2770 | ||
2771 | user_args = METHOD_SEL_ARGS (method_decl); | |
2772 | ||
0f41302f | 2773 | /* Argument types. */ |
e31c7eec TW |
2774 | for (parms = DECL_ARGUMENTS (func_decl), i = 0; parms; |
2775 | parms = TREE_CHAIN (parms), i++) | |
2776 | { | |
0f41302f | 2777 | /* Process argument qualifiers for user supplied arguments. */ |
e31c7eec TW |
2778 | if (i > 1) |
2779 | { | |
2780 | encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (user_args))); | |
2781 | user_args = TREE_CHAIN (user_args); | |
2782 | } | |
2783 | ||
0f41302f | 2784 | /* Type. */ |
e31c7eec TW |
2785 | encode_type (TREE_TYPE (parms), |
2786 | obstack_object_size (&util_obstack), | |
2787 | OBJC_ENCODE_INLINE_DEFS); | |
2788 | ||
0f41302f | 2789 | /* Compute offset. */ |
e31c7eec | 2790 | sprintf (buf, "%d", forwarding_offset (parms)); |
30c0e2df | 2791 | |
0f41302f | 2792 | /* Indicate register. */ |
30c0e2df KKT |
2793 | if (offset_is_register) |
2794 | obstack_1grow (&util_obstack, '+'); | |
2795 | ||
e31c7eec TW |
2796 | obstack_grow (&util_obstack, buf, strlen (buf)); |
2797 | } | |
2798 | ||
2799 | obstack_1grow (&util_obstack, '\0'); | |
2800 | result = get_identifier (obstack_finish (&util_obstack)); | |
2801 | obstack_free (&util_obstack, util_firstobj); | |
2802 | return result; | |
2803 | } | |
2804 | ||
2805 | static tree | |
2806 | generate_descriptor_table (type, name, size, list, proto) | |
2807 | tree type; | |
2808 | char *name; | |
2809 | int size; | |
2810 | tree list; | |
2811 | tree proto; | |
2812 | { | |
2813 | tree sc_spec, decl_specs, decl, initlist; | |
2814 | ||
51900510 RK |
2815 | sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE); |
2816 | decl_specs = tree_cons (NULL_TREE, type, sc_spec); | |
e31c7eec TW |
2817 | |
2818 | decl = start_decl (synth_id_with_class_suffix (name, proto), | |
51900510 | 2819 | decl_specs, 1, NULL_TREE, NULL_TREE); |
e31c7eec | 2820 | |
51900510 RK |
2821 | initlist = build_tree_list (NULL_TREE, build_int_2 (size, 0)); |
2822 | initlist = tree_cons (NULL_TREE, list, initlist); | |
e31c7eec | 2823 | |
89ef1046 | 2824 | finish_decl (decl, build_constructor (type, nreverse (initlist)), |
51900510 | 2825 | NULL_TREE); |
e31c7eec TW |
2826 | |
2827 | return decl; | |
2828 | } | |
2829 | ||
2830 | static void | |
2831 | generate_method_descriptors (protocol) /* generate_dispatch_tables */ | |
2832 | tree protocol; | |
2833 | { | |
2834 | static tree objc_method_prototype_template; | |
2835 | tree initlist, chain, method_list_template; | |
2836 | tree cast, variable_length_type; | |
2837 | int size; | |
2838 | ||
2839 | if (!objc_method_prototype_template) | |
2840 | objc_method_prototype_template = build_method_prototype_template (); | |
2841 | ||
51900510 RK |
2842 | cast = build_tree_list (build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE, |
2843 | get_identifier (UTAG_METHOD_PROTOTYPE_LIST))), | |
2844 | NULL_TREE); | |
e31c7eec TW |
2845 | variable_length_type = groktypename (cast); |
2846 | ||
2847 | chain = PROTOCOL_CLS_METHODS (protocol); | |
2848 | if (chain) | |
2849 | { | |
30c0e2df | 2850 | size = list_length (chain); |
e31c7eec TW |
2851 | |
2852 | method_list_template | |
2853 | = build_method_prototype_list_template (objc_method_prototype_template, | |
2854 | size); | |
2855 | ||
30c0e2df KKT |
2856 | initlist |
2857 | = build_descriptor_table_initializer (objc_method_prototype_template, | |
2858 | chain); | |
89ef1046 | 2859 | |
e31c7eec TW |
2860 | UOBJC_CLASS_METHODS_decl |
2861 | = generate_descriptor_table (method_list_template, | |
2862 | "_OBJC_PROTOCOL_CLASS_METHODS", | |
2863 | size, initlist, protocol); | |
e31c7eec TW |
2864 | TREE_TYPE (UOBJC_CLASS_METHODS_decl) = variable_length_type; |
2865 | } | |
2866 | else | |
2867 | UOBJC_CLASS_METHODS_decl = 0; | |
2868 | ||
2869 | chain = PROTOCOL_NST_METHODS (protocol); | |
2870 | if (chain) | |
2871 | { | |
30c0e2df | 2872 | size = list_length (chain); |
e31c7eec TW |
2873 | |
2874 | method_list_template | |
2875 | = build_method_prototype_list_template (objc_method_prototype_template, | |
2876 | size); | |
30c0e2df KKT |
2877 | initlist |
2878 | = build_descriptor_table_initializer (objc_method_prototype_template, | |
2879 | chain); | |
e31c7eec TW |
2880 | |
2881 | UOBJC_INSTANCE_METHODS_decl | |
2882 | = generate_descriptor_table (method_list_template, | |
2883 | "_OBJC_PROTOCOL_INSTANCE_METHODS", | |
2884 | size, initlist, protocol); | |
e31c7eec TW |
2885 | TREE_TYPE (UOBJC_INSTANCE_METHODS_decl) = variable_length_type; |
2886 | } | |
2887 | else | |
2888 | UOBJC_INSTANCE_METHODS_decl = 0; | |
2889 | } | |
2890 | ||
2891 | static tree | |
2892 | build_tmp_function_decl () | |
2893 | { | |
2894 | tree decl_specs, expr_decl, parms; | |
5d0f30f7 KKT |
2895 | static int xxx = 0; |
2896 | char buffer[80]; | |
e31c7eec TW |
2897 | |
2898 | /* struct objc_object *objc_xxx (id, SEL, ...); */ | |
2899 | pushlevel (0); | |
51900510 | 2900 | decl_specs = build_tree_list (NULL_TREE, objc_object_reference); |
fc55cc66 RK |
2901 | push_parm_decl (build_tree_list |
2902 | (build_tree_list (decl_specs, | |
51900510 RK |
2903 | build1 (INDIRECT_REF, NULL_TREE, |
2904 | NULL_TREE)), | |
fc55cc66 | 2905 | build_tree_list (NULL_TREE, NULL_TREE))); |
e31c7eec | 2906 | |
51900510 | 2907 | decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE, |
e31c7eec | 2908 | get_identifier (TAG_SELECTOR))); |
51900510 | 2909 | expr_decl = build1 (INDIRECT_REF, NULL_TREE, NULL_TREE); |
e31c7eec | 2910 | |
fc55cc66 RK |
2911 | push_parm_decl (build_tree_list (build_tree_list (decl_specs, expr_decl), |
2912 | build_tree_list (NULL_TREE, NULL_TREE))); | |
e31c7eec TW |
2913 | parms = get_parm_info (0); |
2914 | poplevel (0, 0, 0); | |
2915 | ||
51900510 | 2916 | decl_specs = build_tree_list (NULL_TREE, objc_object_reference); |
5d0f30f7 | 2917 | sprintf (buffer, "__objc_tmp_%x", xxx++); |
51900510 RK |
2918 | expr_decl = build_nt (CALL_EXPR, get_identifier (buffer), parms, NULL_TREE); |
2919 | expr_decl = build1 (INDIRECT_REF, NULL_TREE, expr_decl); | |
e31c7eec TW |
2920 | |
2921 | return define_decl (expr_decl, decl_specs); | |
2922 | } | |
2923 | ||
2924 | static void | |
2925 | hack_method_prototype (nst_methods, tmp_decl) | |
2926 | tree nst_methods; | |
2927 | tree tmp_decl; | |
2928 | { | |
2929 | tree parms; | |
f7ca2fe7 | 2930 | tree parm; |
e31c7eec | 2931 | |
0f41302f | 2932 | /* Hack to avoid problem with static typing of self arg. */ |
59ce3fc8 | 2933 | TREE_SET_CODE (nst_methods, CLASS_METHOD_DECL); |
e31c7eec | 2934 | start_method_def (nst_methods); |
59ce3fc8 | 2935 | TREE_SET_CODE (nst_methods, INSTANCE_METHOD_DECL); |
e31c7eec TW |
2936 | |
2937 | if (METHOD_ADD_ARGS (nst_methods) == (tree) 1) | |
2938 | parms = get_parm_info (0); /* we have a `, ...' */ | |
2939 | else | |
2940 | parms = get_parm_info (1); /* place a `void_at_end' */ | |
2941 | ||
2942 | poplevel (0, 0, 0); /* Must be called BEFORE start_function. */ | |
2943 | ||
2944 | /* Usually called from store_parm_decls -> init_function_start. */ | |
2945 | ||
e31c7eec | 2946 | DECL_ARGUMENTS (tmp_decl) = TREE_PURPOSE (parms); |
5d0f30f7 | 2947 | current_function_decl = tmp_decl; |
e31c7eec TW |
2948 | |
2949 | { | |
2950 | /* Code taken from start_function. */ | |
2951 | tree restype = TREE_TYPE (TREE_TYPE (tmp_decl)); | |
2952 | /* Promote the value to int before returning it. */ | |
2953 | if (TREE_CODE (restype) == INTEGER_TYPE | |
2954 | && TYPE_PRECISION (restype) < TYPE_PRECISION (integer_type_node)) | |
2955 | restype = integer_type_node; | |
2956 | DECL_RESULT (tmp_decl) = build_decl (RESULT_DECL, 0, restype); | |
2957 | } | |
2958 | ||
f7ca2fe7 RK |
2959 | for (parm = DECL_ARGUMENTS (tmp_decl); parm; parm = TREE_CHAIN (parm)) |
2960 | DECL_CONTEXT (parm) = tmp_decl; | |
2961 | ||
5d0f30f7 KKT |
2962 | init_function_start (tmp_decl, "objc-act", 0); |
2963 | ||
e31c7eec TW |
2964 | /* Typically called from expand_function_start for function definitions. */ |
2965 | assign_parms (tmp_decl, 0); | |
2966 | ||
2967 | /* install return type */ | |
2968 | TREE_TYPE (TREE_TYPE (tmp_decl)) = groktypename (TREE_TYPE (nst_methods)); | |
5d0f30f7 | 2969 | |
e31c7eec TW |
2970 | } |
2971 | ||
2972 | static void | |
2973 | generate_protocol_references (plist) | |
2974 | tree plist; | |
2975 | { | |
2976 | tree lproto; | |
2977 | ||
0f41302f | 2978 | /* Forward declare protocols referenced. */ |
e31c7eec TW |
2979 | for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto)) |
2980 | { | |
2981 | tree proto = TREE_VALUE (lproto); | |
2982 | ||
2983 | if (TREE_CODE (proto) == PROTOCOL_INTERFACE_TYPE | |
2984 | && PROTOCOL_NAME (proto)) | |
2985 | { | |
2986 | if (! PROTOCOL_FORWARD_DECL (proto)) | |
2987 | build_protocol_reference (proto); | |
2988 | ||
2989 | if (PROTOCOL_LIST (proto)) | |
2990 | generate_protocol_references (PROTOCOL_LIST (proto)); | |
2991 | } | |
2992 | } | |
6c65299b RS |
2993 | } |
2994 | ||
e31c7eec TW |
2995 | static void |
2996 | generate_protocols () | |
6c65299b | 2997 | { |
e31c7eec TW |
2998 | tree p, tmp_decl, encoding; |
2999 | tree sc_spec, decl_specs, decl; | |
3000 | tree initlist, protocol_name_expr, refs_decl, refs_expr; | |
3001 | tree cast_type2 = 0; | |
6c65299b | 3002 | |
e31c7eec | 3003 | tmp_decl = build_tmp_function_decl (); |
6c65299b | 3004 | |
e31c7eec TW |
3005 | if (! objc_protocol_template) |
3006 | objc_protocol_template = build_protocol_template (); | |
6c65299b | 3007 | |
51900510 | 3008 | /* If a protocol was directly referenced, pull in indirect references. */ |
e31c7eec TW |
3009 | for (p = protocol_chain; p; p = TREE_CHAIN (p)) |
3010 | if (PROTOCOL_FORWARD_DECL (p) && PROTOCOL_LIST (p)) | |
3011 | generate_protocol_references (PROTOCOL_LIST (p)); | |
3012 | ||
3013 | for (p = protocol_chain; p; p = TREE_CHAIN (p)) | |
6c65299b | 3014 | { |
e31c7eec TW |
3015 | tree nst_methods = PROTOCOL_NST_METHODS (p); |
3016 | tree cls_methods = PROTOCOL_CLS_METHODS (p); | |
6c65299b | 3017 | |
51900510 | 3018 | /* If protocol wasn't referenced, don't generate any code. */ |
e31c7eec TW |
3019 | if (! PROTOCOL_FORWARD_DECL (p)) |
3020 | continue; | |
6c65299b | 3021 | |
0f41302f | 3022 | /* Make sure we link in the Protocol class. */ |
e31c7eec | 3023 | add_class_reference (get_identifier (PROTOCOL_OBJECT_CLASS_NAME)); |
6c65299b | 3024 | |
e31c7eec TW |
3025 | while (nst_methods) |
3026 | { | |
5d0f30f7 KKT |
3027 | if (! METHOD_ENCODING (nst_methods)) |
3028 | { | |
3029 | hack_method_prototype (nst_methods, tmp_decl); | |
3030 | encoding = encode_method_prototype (nst_methods, tmp_decl); | |
3031 | METHOD_ENCODING (nst_methods) = encoding; | |
3032 | } | |
e31c7eec TW |
3033 | nst_methods = TREE_CHAIN (nst_methods); |
3034 | } | |
3035 | ||
3036 | while (cls_methods) | |
3037 | { | |
5d0f30f7 KKT |
3038 | if (! METHOD_ENCODING (cls_methods)) |
3039 | { | |
3040 | hack_method_prototype (cls_methods, tmp_decl); | |
3041 | encoding = encode_method_prototype (cls_methods, tmp_decl); | |
3042 | METHOD_ENCODING (cls_methods) = encoding; | |
3043 | } | |
e31c7eec TW |
3044 | |
3045 | cls_methods = TREE_CHAIN (cls_methods); | |
3046 | } | |
3047 | generate_method_descriptors (p); | |
3048 | ||
3049 | if (PROTOCOL_LIST (p)) | |
3050 | refs_decl = generate_protocol_list (p); | |
3051 | else | |
3052 | refs_decl = 0; | |
3053 | ||
3054 | /* static struct objc_protocol _OBJC_PROTOCOL_<mumble>; */ | |
3055 | ||
51900510 RK |
3056 | sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], |
3057 | NULL_TREE); | |
3058 | decl_specs = tree_cons (NULL_TREE, objc_protocol_template, sc_spec); | |
e31c7eec TW |
3059 | |
3060 | decl = start_decl (synth_id_with_class_suffix ("_OBJC_PROTOCOL", p), | |
51900510 | 3061 | decl_specs, 1, NULL_TREE, NULL_TREE); |
e31c7eec TW |
3062 | |
3063 | protocol_name_expr = add_objc_string (PROTOCOL_NAME (p), class_names); | |
3064 | ||
3065 | if (refs_decl) | |
3066 | { | |
3067 | if (!cast_type2) | |
3068 | cast_type2 | |
51900510 RK |
3069 | = groktypename |
3070 | (build_tree_list (build_tree_list (NULL_TREE, | |
3071 | objc_protocol_template), | |
3072 | build1 (INDIRECT_REF, NULL_TREE, | |
3073 | build1 (INDIRECT_REF, NULL_TREE, | |
3074 | NULL_TREE)))); | |
e31c7eec TW |
3075 | |
3076 | refs_expr = build_unary_op (ADDR_EXPR, refs_decl, 0); | |
3077 | TREE_TYPE (refs_expr) = cast_type2; | |
3078 | } | |
3079 | else | |
3080 | refs_expr = build_int_2 (0, 0); | |
3081 | ||
3082 | /* UOBJC_INSTANCE_METHODS_decl/UOBJC_CLASS_METHODS_decl are set | |
3083 | by generate_method_descriptors, which is called above. */ | |
89ef1046 RS |
3084 | initlist = build_protocol_initializer (TREE_TYPE (decl), |
3085 | protocol_name_expr, refs_expr, | |
e31c7eec TW |
3086 | UOBJC_INSTANCE_METHODS_decl, |
3087 | UOBJC_CLASS_METHODS_decl); | |
51900510 | 3088 | finish_decl (decl, initlist, NULL_TREE); |
e31c7eec | 3089 | |
0f41302f | 3090 | /* Mark the decl as used to avoid "defined but not used" warning. */ |
e31c7eec | 3091 | TREE_USED (decl) = 1; |
6c65299b | 3092 | } |
6c65299b RS |
3093 | } |
3094 | ||
6c65299b | 3095 | static tree |
89ef1046 | 3096 | build_protocol_initializer (type, protocol_name, protocol_list, |
e31c7eec | 3097 | instance_methods, class_methods) |
89ef1046 | 3098 | tree type; |
e31c7eec TW |
3099 | tree protocol_name; |
3100 | tree protocol_list; | |
3101 | tree instance_methods; | |
3102 | tree class_methods; | |
6c65299b | 3103 | { |
51900510 | 3104 | tree initlist = NULL_TREE, expr; |
e31c7eec | 3105 | static tree cast_type = 0; |
6c65299b | 3106 | |
e31c7eec TW |
3107 | if (!cast_type) |
3108 | cast_type | |
51900510 RK |
3109 | = groktypename |
3110 | (build_tree_list | |
3111 | (build_tree_list (NULL_TREE, | |
3112 | xref_tag (RECORD_TYPE, | |
3113 | get_identifier (UTAG_CLASS))), | |
3114 | build1 (INDIRECT_REF, NULL_TREE, NULL_TREE))); | |
e31c7eec | 3115 | |
51900510 RK |
3116 | /* Filling the "isa" in with one allows the runtime system to |
3117 | detect that the version change...should remove before final release. */ | |
e31c7eec TW |
3118 | |
3119 | expr = build_int_2 (PROTOCOL_VERSION, 0); | |
3120 | TREE_TYPE (expr) = cast_type; | |
51900510 RK |
3121 | initlist = tree_cons (NULL_TREE, expr, initlist); |
3122 | initlist = tree_cons (NULL_TREE, protocol_name, initlist); | |
3123 | initlist = tree_cons (NULL_TREE, protocol_list, initlist); | |
e31c7eec TW |
3124 | |
3125 | if (!instance_methods) | |
51900510 | 3126 | initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist); |
e31c7eec | 3127 | else |
6c65299b | 3128 | { |
e31c7eec | 3129 | expr = build_unary_op (ADDR_EXPR, instance_methods, 0); |
51900510 | 3130 | initlist = tree_cons (NULL_TREE, expr, initlist); |
6c65299b | 3131 | } |
51900510 | 3132 | |
e31c7eec | 3133 | if (!class_methods) |
51900510 | 3134 | initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist); |
6c65299b RS |
3135 | else |
3136 | { | |
e31c7eec | 3137 | expr = build_unary_op (ADDR_EXPR, class_methods, 0); |
51900510 | 3138 | initlist = tree_cons (NULL_TREE, expr, initlist); |
6c65299b | 3139 | } |
51900510 | 3140 | |
89ef1046 | 3141 | return build_constructor (type, nreverse (initlist)); |
6c65299b | 3142 | } |
e31c7eec TW |
3143 | \f |
3144 | /* struct objc_category { | |
3145 | char *category_name; | |
3146 | char *class_name; | |
3147 | struct objc_method_list *instance_methods; | |
3148 | struct objc_method_list *class_methods; | |
3149 | struct objc_protocol_list *protocols; | |
3150 | }; */ | |
6c65299b | 3151 | |
6c65299b RS |
3152 | static void |
3153 | build_category_template () | |
3154 | { | |
3155 | tree decl_specs, field_decl, field_decl_chain; | |
3156 | ||
3157 | objc_category_template = start_struct (RECORD_TYPE, | |
e31c7eec | 3158 | get_identifier (UTAG_CATEGORY)); |
6c65299b RS |
3159 | /* char *category_name; */ |
3160 | ||
51900510 RK |
3161 | decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]); |
3162 | field_decl | |
3163 | = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("category_name")); | |
3164 | field_decl | |
3165 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
6c65299b RS |
3166 | field_decl_chain = field_decl; |
3167 | ||
3168 | /* char *class_name; */ | |
3169 | ||
51900510 RK |
3170 | decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]); |
3171 | field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("class_name")); | |
3172 | field_decl | |
3173 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
6c65299b RS |
3174 | chainon (field_decl_chain, field_decl); |
3175 | ||
3176 | /* struct objc_method_list *instance_methods; */ | |
3177 | ||
51900510 RK |
3178 | decl_specs = build_tree_list (NULL_TREE, |
3179 | xref_tag (RECORD_TYPE, | |
3180 | get_identifier (UTAG_METHOD_LIST))); | |
3181 | field_decl | |
3182 | = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("instance_methods")); | |
3183 | field_decl | |
3184 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
6c65299b RS |
3185 | chainon (field_decl_chain, field_decl); |
3186 | ||
3187 | /* struct objc_method_list *class_methods; */ | |
3188 | ||
51900510 RK |
3189 | decl_specs = build_tree_list (NULL_TREE, |
3190 | xref_tag (RECORD_TYPE, | |
3191 | get_identifier (UTAG_METHOD_LIST))); | |
3192 | field_decl | |
3193 | = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("class_methods")); | |
3194 | field_decl | |
3195 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
6c65299b RS |
3196 | chainon (field_decl_chain, field_decl); |
3197 | ||
e31c7eec TW |
3198 | /* struct objc_protocol **protocol_list; */ |
3199 | ||
51900510 RK |
3200 | decl_specs = build_tree_list (NULL_TREE, |
3201 | xref_tag (RECORD_TYPE, | |
3202 | get_identifier (UTAG_PROTOCOL))); | |
3203 | field_decl | |
3204 | = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("protocol_list")); | |
3205 | field_decl = build1 (INDIRECT_REF, NULL_TREE, field_decl); | |
3206 | field_decl | |
3207 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
e31c7eec TW |
3208 | chainon (field_decl_chain, field_decl); |
3209 | ||
51900510 | 3210 | finish_struct (objc_category_template, field_decl_chain, NULL_TREE); |
6c65299b RS |
3211 | } |
3212 | ||
5d0f30f7 KKT |
3213 | /* struct objc_selector { |
3214 | void *sel_id; | |
3215 | char *sel_type; | |
3216 | }; */ | |
3217 | ||
3218 | static void | |
3219 | build_selector_template () | |
3220 | { | |
3221 | ||
3222 | tree decl_specs, field_decl, field_decl_chain; | |
3223 | ||
3224 | objc_selector_template | |
3225 | = start_struct (RECORD_TYPE, get_identifier (UTAG_SELECTOR)); | |
3226 | ||
3227 | /* void *sel_id; */ | |
3228 | ||
51900510 RK |
3229 | decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_VOID]); |
3230 | field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("sel_id")); | |
3231 | field_decl | |
3232 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
5d0f30f7 KKT |
3233 | field_decl_chain = field_decl; |
3234 | ||
3235 | /* char *sel_type; */ | |
3236 | ||
51900510 RK |
3237 | decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]); |
3238 | field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("sel_type")); | |
3239 | field_decl | |
3240 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
5d0f30f7 KKT |
3241 | chainon (field_decl_chain, field_decl); |
3242 | ||
51900510 | 3243 | finish_struct (objc_selector_template, field_decl_chain, NULL_TREE); |
5d0f30f7 KKT |
3244 | } |
3245 | ||
e31c7eec TW |
3246 | /* struct objc_class { |
3247 | struct objc_class *isa; | |
3248 | struct objc_class *super_class; | |
3249 | char *name; | |
3250 | long version; | |
3251 | long info; | |
3252 | long instance_size; | |
3253 | struct objc_ivar_list *ivars; | |
3254 | struct objc_method_list *methods; | |
3255 | if (flag_next_runtime) | |
3256 | struct objc_cache *cache; | |
3257 | else { | |
3258 | struct sarray *dtable; | |
3259 | struct objc_class *subclass_list; | |
3260 | struct objc_class *sibling_class; | |
3261 | } | |
3262 | struct objc_protocol_list *protocols; | |
3263 | }; */ | |
3264 | ||
6c65299b RS |
3265 | static void |
3266 | build_class_template () | |
3267 | { | |
3268 | tree decl_specs, field_decl, field_decl_chain; | |
3269 | ||
51900510 RK |
3270 | objc_class_template |
3271 | = start_struct (RECORD_TYPE, get_identifier (UTAG_CLASS)); | |
6c65299b RS |
3272 | |
3273 | /* struct objc_class *isa; */ | |
3274 | ||
51900510 RK |
3275 | decl_specs = build_tree_list (NULL_TREE, objc_class_template); |
3276 | field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("isa")); | |
3277 | field_decl | |
3278 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
6c65299b RS |
3279 | field_decl_chain = field_decl; |
3280 | ||
3281 | /* struct objc_class *super_class; */ | |
3282 | ||
51900510 RK |
3283 | decl_specs = build_tree_list (NULL_TREE, objc_class_template); |
3284 | field_decl | |
3285 | = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("super_class")); | |
3286 | field_decl | |
3287 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
6c65299b RS |
3288 | chainon (field_decl_chain, field_decl); |
3289 | ||
3290 | /* char *name; */ | |
3291 | ||
51900510 RK |
3292 | decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]); |
3293 | field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("name")); | |
3294 | field_decl | |
3295 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
6c65299b RS |
3296 | chainon (field_decl_chain, field_decl); |
3297 | ||
3298 | /* long version; */ | |
3299 | ||
51900510 | 3300 | decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_LONG]); |
6c65299b | 3301 | field_decl = get_identifier ("version"); |
51900510 RK |
3302 | field_decl |
3303 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
6c65299b RS |
3304 | chainon (field_decl_chain, field_decl); |
3305 | ||
3306 | /* long info; */ | |
3307 | ||
51900510 | 3308 | decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_LONG]); |
6c65299b | 3309 | field_decl = get_identifier ("info"); |
51900510 RK |
3310 | field_decl |
3311 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
6c65299b RS |
3312 | chainon (field_decl_chain, field_decl); |
3313 | ||
3314 | /* long instance_size; */ | |
3315 | ||
51900510 | 3316 | decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_LONG]); |
6c65299b | 3317 | field_decl = get_identifier ("instance_size"); |
51900510 RK |
3318 | field_decl |
3319 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
6c65299b RS |
3320 | chainon (field_decl_chain, field_decl); |
3321 | ||
3322 | /* struct objc_ivar_list *ivars; */ | |
3323 | ||
51900510 RK |
3324 | decl_specs = build_tree_list (NULL_TREE, |
3325 | xref_tag (RECORD_TYPE, | |
3326 | get_identifier (UTAG_IVAR_LIST))); | |
3327 | field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("ivars")); | |
3328 | field_decl | |
3329 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
6c65299b RS |
3330 | chainon (field_decl_chain, field_decl); |
3331 | ||
3332 | /* struct objc_method_list *methods; */ | |
3333 | ||
51900510 RK |
3334 | decl_specs = build_tree_list (NULL_TREE, |
3335 | xref_tag (RECORD_TYPE, | |
3336 | get_identifier (UTAG_METHOD_LIST))); | |
3337 | field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("methods")); | |
3338 | field_decl | |
3339 | = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE); | |
6c65299b RS |
3340 | chainon (field_decl_chain, field_decl); |
3341 | ||
e31c7eec TW |
3342 | if (flag_next_runtime) |
3343 | { | |
3344 | /* struct objc_cache *cache; */ | |
3345 | ||
51900510 RK |
3346 | decl_specs = build_tree_list (NULL_TREE, |
3347 | xref_tag (RECORD_TYPE, | |
3348 | get_identifier ("objc_cache"))); | |
3349 | field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("cache")); | |
3350 | field_decl = grokfield (input_filename, lineno, field_decl, | |
3351 | decl_specs, NULL_TREE); | |
e31c7eec TW |
3352 | chainon (field_decl_chain, field_decl); |
3353 | } | |
3354 | else | |
3355 | { | |
3356 | /* struct sarray *dtable; */ | |
3357 | ||
51900510 RK |
3358 | decl_specs = build_tree_list (NULL_TREE, |
3359 | xref_tag (RECORD_TYPE, | |
3360 | get_identifier ("sarray"))); | |
3361 | field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("dtable")); | |
3362 | field_decl = grokfield (input_filename, lineno, field_decl, | |
3363 | decl_specs, NULL_TREE); | |
e31c7eec TW |
3364 | chainon (field_decl_chain, field_decl); |
3365 | ||
3366 | /* struct objc_class *subclass_list; */ | |
3367 | ||
51900510 RK |
3368 | decl_specs = build_tree_list (NULL_TREE, objc_class_template); |
3369 | field_decl | |
3370 | = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("subclass_list")); | |
3371 | field_decl = grokfield (input_filename, lineno, field_decl, | |
3372 | decl_specs, NULL_TREE); | |
e31c7eec TW |
3373 | chainon (field_decl_chain, field_decl); |
3374 | ||
3375 | /* struct objc_class *sibling_class; */ | |
3376 | ||
51900510 RK |
3377 | decl_specs = build_tree_list (NULL_TREE, objc_class_template); |
3378 | field_decl | |
3379 | = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("sibling_class")); | |
3380 | field_decl = grokfield (input_filename, lineno, field_decl, | |
3381 | decl_specs, NULL_TREE); | |
e31c7eec TW |
3382 | chainon (field_decl_chain, field_decl); |
3383 | } | |
3384 | ||
3385 | /* struct objc_protocol **protocol_list; */ | |
6c65299b | 3386 | |
51900510 RK |
3387 | decl_specs = build_tree_list (NULL_TREE, |
3388 | xref_tag (RECORD_TYPE, | |
e31c7eec | 3389 | get_identifier (UTAG_PROTOCOL))); |
51900510 RK |
3390 | field_decl |
3391 | = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("protocol_list")); | |
3392 | field_decl | |
3393 | = build1 (INDIRECT_REF, NULL_TREE, field_decl); | |
3394 | field_decl = grokfield (input_filename, lineno, field_decl, | |
3395 | decl_specs, NULL_TREE); | |
6c65299b RS |
3396 | chainon (field_decl_chain, field_decl); |
3397 | ||
e31c7eec | 3398 | |
51900510 | 3399 | finish_struct (objc_class_template, field_decl_chain, NULL_TREE); |
6c65299b RS |
3400 | } |
3401 | ||
e31c7eec TW |
3402 | /* Generate appropriate forward declarations for an implementation. */ |
3403 | ||
6c65299b RS |
3404 | static void |
3405 | synth_forward_declarations () | |
3406 | { | |
e31c7eec | 3407 | tree sc_spec, decl_specs, an_id; |
6c65299b RS |
3408 | |
3409 | /* extern struct objc_class _OBJC_CLASS_<my_name>; */ | |
3410 | ||
e31c7eec | 3411 | an_id = synth_id_with_class_suffix ("_OBJC_CLASS", implementation_context); |
6c65299b | 3412 | |
51900510 RK |
3413 | sc_spec = build_tree_list (NULL_TREE, ridpointers[(int) RID_EXTERN]); |
3414 | decl_specs = tree_cons (NULL_TREE, objc_class_template, sc_spec); | |
e31c7eec TW |
3415 | UOBJC_CLASS_decl = define_decl (an_id, decl_specs); |
3416 | TREE_USED (UOBJC_CLASS_decl) = 1; | |
51900510 | 3417 | DECL_ARTIFICIAL (UOBJC_CLASS_decl) = 1; |
6c65299b RS |
3418 | |
3419 | /* extern struct objc_class _OBJC_METACLASS_<my_name>; */ | |
3420 | ||
e31c7eec TW |
3421 | an_id = synth_id_with_class_suffix ("_OBJC_METACLASS", |
3422 | implementation_context); | |
6c65299b | 3423 | |
e31c7eec TW |
3424 | UOBJC_METACLASS_decl = define_decl (an_id, decl_specs); |
3425 | TREE_USED (UOBJC_METACLASS_decl) = 1; | |
51900510 | 3426 | DECL_ARTIFICIAL(UOBJC_METACLASS_decl) = 1; |
6c65299b | 3427 | |
0f41302f | 3428 | /* Pre-build the following entities - for speed/convenience. */ |
6c65299b | 3429 | |
e31c7eec TW |
3430 | an_id = get_identifier ("super_class"); |
3431 | ucls_super_ref = build_component_ref (UOBJC_CLASS_decl, an_id); | |
3432 | uucls_super_ref = build_component_ref (UOBJC_METACLASS_decl, an_id); | |
6c65299b RS |
3433 | } |
3434 | ||
3435 | static void | |
3436 | error_with_ivar (message, decl, rawdecl) | |
3437 | char *message; | |
3438 | tree decl; | |
3439 | tree rawdecl; | |
3440 | { | |
3441 | count_error (0); | |
e31c7eec TW |
3442 | |
3443 | report_error_function (DECL_SOURCE_FILE (decl)); | |
3444 | ||
6c65299b RS |
3445 | fprintf (stderr, "%s:%d: ", |
3446 | DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl)); | |
3447 | bzero (errbuf, BUFSIZE); | |
3448 | fprintf (stderr, "%s `%s'\n", message, gen_declaration (rawdecl, errbuf)); | |
3449 | } | |
3450 | ||
51900510 RK |
3451 | #define USERTYPE(t) \ |
3452 | (TREE_CODE (t) == RECORD_TYPE || TREE_CODE (t) == UNION_TYPE \ | |
3453 | || TREE_CODE (t) == ENUMERAL_TYPE) | |
6c65299b RS |
3454 | |
3455 | static void | |
3456 | check_ivars (inter, imp) | |
3457 | tree inter; | |
3458 | tree imp; | |
3459 | { | |
3460 | tree intdecls = CLASS_IVARS (inter); | |
3461 | tree impdecls = CLASS_IVARS (imp); | |
3462 | tree rawintdecls = CLASS_RAW_IVARS (inter); | |
3463 | tree rawimpdecls = CLASS_RAW_IVARS (imp); | |
3464 | ||
3465 | while (1) | |
3466 | { | |
3467 | tree t1, t2; | |
3468 | ||
3469 | if (intdecls == 0 && impdecls == 0) | |
3470 | break; | |
3471 | if (intdecls == 0 || impdecls == 0) | |
3472 | { | |
3473 | error ("inconsistent instance variable specification"); | |
3474 | break; | |
3475 | } | |
51900510 | 3476 | |
6c65299b RS |
3477 | t1 = TREE_TYPE (intdecls); t2 = TREE_TYPE (impdecls); |
3478 | ||
3479 | if (!comptypes (t1, t2)) | |
3480 | { | |
3481 | if (DECL_NAME (intdecls) == DECL_NAME (impdecls)) | |
3482 | { | |
3483 | error_with_ivar ("conflicting instance variable type", | |
3484 | impdecls, rawimpdecls); | |
3485 | error_with_ivar ("previous declaration of", | |
3486 | intdecls, rawintdecls); | |
3487 | } | |
3488 | else /* both the type and the name don't match */ | |
3489 | { | |
3490 | error ("inconsistent instance variable specification"); | |
3491 | break; | |
3492 | } | |
3493 | } | |
51900510 | 3494 | |
6c65299b RS |
3495 | else if (DECL_NAME (intdecls) != DECL_NAME (impdecls)) |
3496 | { | |
3497 | error_with_ivar ("conflicting instance variable name", | |
3498 | impdecls, rawimpdecls); | |
3499 | error_with_ivar ("previous declaration of", | |
3500 | intdecls, rawintdecls); | |
3501 | } | |
51900510 | 3502 | |
6c65299b RS |
3503 | intdecls = TREE_CHAIN (intdecls); |
3504 | impdecls = TREE_CHAIN (impdecls); | |
3505 | rawintdecls = TREE_CHAIN (rawintdecls); | |
3506 | rawimpdecls = TREE_CHAIN (rawimpdecls); | |
3507 | } | |
3508 | } | |
3509 | ||
61fab236 RS |
3510 | /* Set super_type to the data type node for struct objc_super *, |
3511 | first defining struct objc_super itself. | |
3512 | This needs to be done just once per compilation. */ | |
3513 | ||
6c65299b RS |
3514 | static tree |
3515 | build_super_template () | |
3516 | { | |
3517 | tree record, decl_specs, field_decl, field_decl_chain; | |
3518 | ||
e31c7eec | 3519 | record = start_struct (RECORD_TYPE, get_identifier (UTAG_SUPER)); |
6c65299b RS |
3520 | |
3521 | /* struct objc_object *self; */ | |
3522 | ||
51900510 | 3523 | decl_specs = build_tree_list (NULL_TREE, objc_object_reference); |
6c65299b | 3524 | field_decl = get_identifier ("self"); |
51900510 | 3525 | field_decl = build1 (INDIRECT_REF, NULL_TREE, field_decl); |
e31c7eec | 3526 | field_decl = grokfield (input_filename, lineno, |
51900510 | 3527 | field_decl, decl_specs, NULL_TREE); |
6c65299b RS |
3528 | field_decl_chain = field_decl; |
3529 | ||
3530 | /* struct objc_class *class; */ | |
3531 | ||
e31c7eec | 3532 | decl_specs = get_identifier (UTAG_CLASS); |
51900510 RK |
3533 | decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE, decl_specs)); |
3534 | field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("class")); | |
6c65299b | 3535 | |
e31c7eec | 3536 | field_decl = grokfield (input_filename, lineno, |
51900510 | 3537 | field_decl, decl_specs, NULL_TREE); |
6c65299b RS |
3538 | chainon (field_decl_chain, field_decl); |
3539 | ||
51900510 | 3540 | finish_struct (record, field_decl_chain, NULL_TREE); |
6c65299b RS |
3541 | |
3542 | /* `struct objc_super *' */ | |
51900510 RK |
3543 | super_type = groktypename (build_tree_list (build_tree_list (NULL_TREE, |
3544 | record), | |
e31c7eec | 3545 | build1 (INDIRECT_REF, |
51900510 | 3546 | NULL_TREE, NULL_TREE))); |
6c65299b RS |
3547 | return record; |
3548 | } | |
3549 | ||
e31c7eec TW |
3550 | /* struct objc_ivar { |
3551 | char *ivar_name; | |
3552 | char *ivar_type; | |
3553 | int ivar_offset; | |
3554 | }; */ | |
3555 | ||
6c65299b RS |
3556 | static tree |
3557 | build_ivar_template () | |
3558 | { | |
3559 | tree objc_ivar_id, objc_ivar_record; | |
3560 | tree decl_specs, field_decl, field_decl_chain; | |
3561 | ||
e31c7eec | 3562 | objc_ivar_id = get_identifier (UTAG_IVAR); |
6c65299b RS |
3563 | objc_ivar_record = start_struct (RECORD_TYPE, objc_ivar_id); |
3564 | ||
3565 | /* char *ivar_name; */ | |
3566 | ||
51900510 RK |
3567 | decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]); |
3568 | field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("ivar_name")); | |
6c65299b | 3569 | |
e31c7eec | 3570 | field_decl = grokfield (input_filename, lineno, field_decl, |
51900510 | 3571 | decl_specs, NULL_TREE); |
6c65299b RS |
3572 | field_decl_chain = field_decl; |
3573 | ||
3574 | /* char *ivar_type; */ | |
3575 | ||
51900510 RK |
3576 | decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]); |
3577 | field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("ivar_type")); | |
6c65299b | 3578 | |
e31c7eec | 3579 | field_decl = grokfield (input_filename, lineno, field_decl, |
51900510 | 3580 | decl_specs, NULL_TREE); |
6c65299b RS |
3581 | chainon (field_decl_chain, field_decl); |
3582 | ||
3583 | /* int ivar_offset; */ | |
3584 | ||
51900510 | 3585 | decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_INT]); |
6c65299b RS |
3586 | field_decl = get_identifier ("ivar_offset"); |
3587 | ||
e31c7eec | 3588 | field_decl = grokfield (input_filename, lineno, field_decl, |
51900510 | 3589 | decl_specs, NULL_TREE); |
6c65299b RS |
3590 | chainon (field_decl_chain, field_decl); |
3591 | ||
51900510 | 3592 | finish_struct (objc_ivar_record, field_decl_chain, NULL_TREE); |
6c65299b RS |
3593 | |
3594 | return objc_ivar_record; | |
3595 | } | |
3596 | ||
e31c7eec TW |
3597 | /* struct { |
3598 | int ivar_count; | |
3599 | struct objc_ivar ivar_list[ivar_count]; | |
3600 | }; */ | |
3601 | ||
6c65299b RS |
3602 | static tree |
3603 | build_ivar_list_template (list_type, size) | |
3604 | tree list_type; | |
3605 | int size; | |
3606 | { | |
e31c7eec | 3607 | tree objc_ivar_list_record; |
6c65299b RS |
3608 | tree decl_specs, field_decl, field_decl_chain; |
3609 | ||
51900510 | 3610 | objc_ivar_list_record = start_struct (RECORD_TYPE, NULL_TREE); |
6c65299b RS |
3611 | |
3612 | /* int ivar_count; */ | |
3613 | ||
51900510 | 3614 | decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_INT]); |
6c65299b RS |
3615 | field_decl = get_identifier ("ivar_count"); |
3616 | ||
e31c7eec | 3617 | field_decl = grokfield (input_filename, lineno, field_decl, |
51900510 | 3618 | decl_specs, NULL_TREE); |
6c65299b RS |
3619 | field_decl_chain = field_decl; |
3620 | ||
3621 | /* struct objc_ivar ivar_list[]; */ | |
3622 | ||
51900510 | 3623 | decl_specs = build_tree_list (NULL_TREE, list_type); |
6c65299b RS |
3624 | field_decl = build_nt (ARRAY_REF, get_identifier ("ivar_list"), |
3625 | build_int_2 (size, 0)); | |
3626 | ||
e31c7eec | 3627 | field_decl = grokfield (input_filename, lineno, |
51900510 | 3628 | field_decl, decl_specs, NULL_TREE); |
6c65299b RS |
3629 | chainon (field_decl_chain, field_decl); |
3630 | ||
51900510 | 3631 | finish_struct (objc_ivar_list_record, field_decl_chain, NULL_TREE); |
6c65299b RS |
3632 | |
3633 | return objc_ivar_list_record; | |
3634 | } | |
3635 | ||
e31c7eec TW |
3636 | /* struct { |
3637 | int method_next; | |
3638 | int method_count; | |
3639 | struct objc_method method_list[method_count]; | |
3640 | }; */ | |
3641 | ||
6c65299b RS |
3642 | static tree |
3643 | build_method_list_template (list_type, size) | |
3644 | tree list_type; | |
3645 | int size; | |
3646 | { | |
e31c7eec | 3647 | tree objc_ivar_list_record; |
6c65299b RS |
3648 | tree decl_specs, field_decl, field_decl_chain; |
3649 | ||
51900510 | 3650 | objc_ivar_list_record = start_struct (RECORD_TYPE, NULL_TREE); |
6c65299b RS |
3651 | |
3652 | /* int method_next; */ | |
3653 | ||
51900510 RK |
3654 | decl_specs |
3655 | = build_tree_list | |
3656 | (NULL_TREE, | |
3657 | xref_tag (RECORD_TYPE, | |
3658 | get_identifier (UTAG_METHOD_PROTOTYPE_LIST))); | |
3659 | field_decl | |
3660 | = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("method_next")); | |
3661 | field_decl = grokfield (input_filename, lineno, field_decl, | |
3662 | decl_specs, NULL_TREE); | |
6c65299b RS |
3663 | field_decl_chain = field_decl; |
3664 | ||
3665 | /* int method_count; */ | |
3666 | ||
51900510 | 3667 | decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_INT]); |
6c65299b RS |
3668 | field_decl = get_identifier ("method_count"); |
3669 | ||
e31c7eec | 3670 | field_decl = grokfield (input_filename, lineno, |
51900510 | 3671 | field_decl, decl_specs, NULL_TREE); |
6c65299b RS |
3672 | chainon (field_decl_chain, field_decl); |
3673 | ||
3674 | /* struct objc_method method_list[]; */ | |
3675 | ||
51900510 | 3676 | decl_specs = build_tree_list (NULL_TREE, list_type); |
6c65299b RS |
3677 | field_decl = build_nt (ARRAY_REF, get_identifier ("method_list"), |
3678 | build_int_2 (size, 0)); | |
3679 | ||
e31c7eec | 3680 | field_decl = grokfield (input_filename, lineno, |
51900510 | 3681 | field_decl, decl_specs, NULL_TREE); |
6c65299b RS |
3682 | chainon (field_decl_chain, field_decl); |
3683 | ||
51900510 | 3684 | finish_struct (objc_ivar_list_record, field_decl_chain, NULL_TREE); |
6c65299b RS |
3685 | |
3686 | return objc_ivar_list_record; | |
3687 | } | |
3688 | ||
3689 | static tree | |
30c0e2df | 3690 | build_ivar_list_initializer (type, field_decl) |
89ef1046 | 3691 | tree type; |
6c65299b | 3692 | tree field_decl; |
6c65299b | 3693 | { |
51900510 | 3694 | tree initlist = NULL_TREE; |
6c65299b RS |
3695 | |
3696 | do | |
3697 | { | |
51900510 | 3698 | tree ivar = NULL_TREE; |
30c0e2df | 3699 | |
0f41302f | 3700 | /* Set name. */ |
e31c7eec | 3701 | if (DECL_NAME (field_decl)) |
51900510 | 3702 | ivar = tree_cons (NULL_TREE, |
30c0e2df KKT |
3703 | add_objc_string (DECL_NAME (field_decl), |
3704 | meth_var_names), | |
3705 | ivar); | |
e31c7eec | 3706 | else |
0f41302f | 3707 | /* Unnamed bit-field ivar (yuck). */ |
51900510 | 3708 | ivar = tree_cons (NULL_TREE, build_int_2 (0, 0), ivar); |
6c65299b | 3709 | |
0f41302f | 3710 | /* Set type. */ |
e31c7eec TW |
3711 | encode_field_decl (field_decl, |
3712 | obstack_object_size (&util_obstack), | |
3713 | OBJC_ENCODE_DONT_INLINE_DEFS); | |
51900510 RK |
3714 | |
3715 | /* Null terminate string. */ | |
3716 | obstack_1grow (&util_obstack, 0); | |
30c0e2df | 3717 | ivar |
e31c7eec | 3718 | = tree_cons |
51900510 | 3719 | (NULL_TREE, |
e31c7eec TW |
3720 | add_objc_string (get_identifier (obstack_finish (&util_obstack)), |
3721 | meth_var_types), | |
30c0e2df | 3722 | ivar); |
9dee6758 | 3723 | obstack_free (&util_obstack, util_firstobj); |
6c65299b | 3724 | |
6c65299b | 3725 | /* set offset */ |
30c0e2df | 3726 | ivar |
e31c7eec | 3727 | = tree_cons |
51900510 | 3728 | (NULL_TREE, |
e31c7eec TW |
3729 | build_int_2 ((TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field_decl)) |
3730 | / BITS_PER_UNIT), | |
3731 | 0), | |
30c0e2df KKT |
3732 | ivar); |
3733 | ||
51900510 | 3734 | initlist = tree_cons (NULL_TREE, |
30c0e2df KKT |
3735 | build_constructor (type, nreverse (ivar)), |
3736 | initlist); | |
3737 | ||
6c65299b RS |
3738 | field_decl = TREE_CHAIN (field_decl); |
3739 | } | |
3740 | while (field_decl); | |
3741 | ||
30c0e2df | 3742 | return build_constructor (build_array_type (type, 0), nreverse (initlist)); |
6c65299b RS |
3743 | } |
3744 | ||
3745 | static tree | |
3746 | generate_ivars_list (type, name, size, list) | |
3747 | tree type; | |
3748 | char *name; | |
3749 | int size; | |
3750 | tree list; | |
3751 | { | |
3752 | tree sc_spec, decl_specs, decl, initlist; | |
3753 | ||
51900510 RK |
3754 | sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE); |
3755 | decl_specs = tree_cons (NULL_TREE, type, sc_spec); | |
6c65299b | 3756 | |
e31c7eec | 3757 | decl = start_decl (synth_id_with_class_suffix (name, implementation_context), |
51900510 | 3758 | decl_specs, 1, NULL_TREE, NULL_TREE); |
6c65299b | 3759 | |
51900510 RK |
3760 | initlist = build_tree_list (NULL_TREE, build_int_2 (size, 0)); |
3761 | initlist = tree_cons (NULL_TREE, list, initlist); | |
6c65299b | 3762 | |
89ef1046 RS |
3763 | finish_decl (decl, |
3764 | build_constructor (TREE_TYPE (decl), nreverse (initlist)), | |
51900510 | 3765 | NULL_TREE); |
6c65299b RS |
3766 | |
3767 | return decl; | |
3768 | } | |
3769 | ||
3770 | static void | |
3771 | generate_ivar_lists () | |
3772 | { | |
3773 | tree initlist, ivar_list_template, chain; | |
3774 | tree cast, variable_length_type; | |
3775 | int size; | |
3776 | ||
e31c7eec TW |
3777 | generating_instance_variables = 1; |
3778 | ||
6c65299b RS |
3779 | if (!objc_ivar_template) |
3780 | objc_ivar_template = build_ivar_template (); | |
3781 | ||
e31c7eec TW |
3782 | cast |
3783 | = build_tree_list | |
51900510 | 3784 | (build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE, |
e31c7eec | 3785 | get_identifier (UTAG_IVAR_LIST))), |
51900510 | 3786 | NULL_TREE); |
6c65299b RS |
3787 | variable_length_type = groktypename (cast); |
3788 | ||
51900510 | 3789 | /* Only generate class variables for the root of the inheritance |
0f41302f | 3790 | hierarchy since these will be the same for every class. */ |
6c65299b | 3791 | |
51900510 | 3792 | if (CLASS_SUPER_NAME (implementation_template) == NULL_TREE |
6c65299b RS |
3793 | && (chain = TYPE_FIELDS (objc_class_template))) |
3794 | { | |
30c0e2df KKT |
3795 | size = list_length (chain); |
3796 | ||
6c65299b | 3797 | ivar_list_template = build_ivar_list_template (objc_ivar_template, size); |
30c0e2df | 3798 | initlist = build_ivar_list_initializer (objc_ivar_template, chain); |
6c65299b | 3799 | |
89ef1046 RS |
3800 | UOBJC_CLASS_VARIABLES_decl |
3801 | = generate_ivars_list (ivar_list_template, "_OBJC_CLASS_VARIABLES", | |
3802 | size, initlist); | |
e31c7eec | 3803 | TREE_TYPE (UOBJC_CLASS_VARIABLES_decl) = variable_length_type; |
6c65299b RS |
3804 | } |
3805 | else | |
e31c7eec | 3806 | UOBJC_CLASS_VARIABLES_decl = 0; |
6c65299b RS |
3807 | |
3808 | chain = CLASS_IVARS (implementation_template); | |
3809 | if (chain) | |
3810 | { | |
30c0e2df | 3811 | size = list_length (chain); |
6c65299b | 3812 | ivar_list_template = build_ivar_list_template (objc_ivar_template, size); |
30c0e2df | 3813 | initlist = build_ivar_list_initializer (objc_ivar_template, chain); |
6c65299b | 3814 | |
89ef1046 RS |
3815 | UOBJC_INSTANCE_VARIABLES_decl |
3816 | = generate_ivars_list (ivar_list_template, "_OBJC_INSTANCE_VARIABLES", | |
3817 | size, initlist); | |
e31c7eec | 3818 | TREE_TYPE (UOBJC_INSTANCE_VARIABLES_decl) = variable_length_type; |
6c65299b RS |
3819 | } |
3820 | else | |
e31c7eec TW |
3821 | UOBJC_INSTANCE_VARIABLES_decl = 0; |
3822 | ||
3823 | generating_instance_variables = 0; | |
6c65299b RS |
3824 | } |
3825 | ||
3826 | static tree | |
30c0e2df | 3827 | build_dispatch_table_initializer (type, entries) |
89ef1046 | 3828 | tree type; |
6c65299b | 3829 | tree entries; |
6c65299b | 3830 | { |
51900510 | 3831 | tree initlist = NULL_TREE; |
6c65299b RS |
3832 | |
3833 | do | |
3834 | { | |
51900510 | 3835 | tree elemlist = NULL_TREE; |
30c0e2df | 3836 | |
51900510 RK |
3837 | elemlist = tree_cons (NULL_TREE, |
3838 | build_selector (METHOD_SEL_NAME (entries)), | |
3839 | NULL_TREE); | |
6c65299b | 3840 | |
51900510 RK |
3841 | elemlist = tree_cons (NULL_TREE, |
3842 | add_objc_string (METHOD_ENCODING (entries), | |
3843 | meth_var_types), | |
30c0e2df | 3844 | elemlist); |
6c65299b | 3845 | |
51900510 RK |
3846 | elemlist = tree_cons (NULL_TREE, |
3847 | build_unary_op (ADDR_EXPR, | |
3848 | METHOD_DEFINITION (entries), 1), | |
30c0e2df KKT |
3849 | elemlist); |
3850 | ||
51900510 | 3851 | initlist = tree_cons (NULL_TREE, |
30c0e2df KKT |
3852 | build_constructor (type, nreverse (elemlist)), |
3853 | initlist); | |
6c65299b | 3854 | |
6c65299b RS |
3855 | entries = TREE_CHAIN (entries); |
3856 | } | |
3857 | while (entries); | |
3858 | ||
30c0e2df | 3859 | return build_constructor (build_array_type (type, 0), nreverse (initlist)); |
6c65299b RS |
3860 | } |
3861 | ||
e31c7eec TW |
3862 | /* To accomplish method prototyping without generating all kinds of |
3863 | inane warnings, the definition of the dispatch table entries were | |
3864 | changed from: | |
3865 | ||
30c0e2df | 3866 | struct objc_method { SEL _cmd; ...; id (*_imp)(); }; |
e31c7eec | 3867 | to: |
30c0e2df | 3868 | struct objc_method { SEL _cmd; ...; void *_imp; }; */ |
e31c7eec | 3869 | |
6c65299b RS |
3870 | static tree |
3871 | build_method_template () | |
3872 | { | |
3873 | tree _SLT_record; | |
e31c7eec | 3874 | tree decl_specs, field_decl, field_decl_chain; |
6c65299b | 3875 | |
e31c7eec | 3876 | _SLT_record = start_struct (RECORD_TYPE, get_identifier (UTAG_METHOD)); |
6c65299b RS |
3877 | |
3878 | #ifdef OBJC_INT_SELECTORS | |
3879 | /* unsigned int _cmd; */ | |
51900510 RK |
3880 | decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_UNSIGNED], |
3881 | NULL_TREE); | |
3882 | decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_INT], decl_specs); | |
6c65299b RS |
3883 | field_decl = get_identifier ("_cmd"); |
3884 | #else /* not OBJC_INT_SELECTORS */ | |
3885 | /* struct objc_selector *_cmd; */ | |
51900510 | 3886 | decl_specs = tree_cons (NULL_TREE, |
6c65299b RS |
3887 | xref_tag (RECORD_TYPE, |
3888 | get_identifier (TAG_SELECTOR)), | |
51900510 RK |
3889 | NULL_TREE); |
3890 | field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("_cmd")); | |
6c65299b RS |
3891 | #endif /* not OBJC_INT_SELECTORS */ |
3892 | ||
51900510 RK |
3893 | field_decl = grokfield (input_filename, lineno, field_decl, |
3894 | decl_specs, NULL_TREE); | |
6c65299b RS |
3895 | field_decl_chain = field_decl; |
3896 | ||
51900510 RK |
3897 | decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], NULL_TREE); |
3898 | field_decl = build1 (INDIRECT_REF, NULL_TREE, | |
3899 | get_identifier ("method_types")); | |
3900 | field_decl = grokfield (input_filename, lineno, field_decl, | |
3901 | decl_specs, NULL_TREE); | |
6c65299b RS |
3902 | chainon (field_decl_chain, field_decl); |
3903 | ||
3904 | /* void *_imp; */ | |
3905 | ||
51900510 RK |
3906 | decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_VOID], NULL_TREE); |
3907 | field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("_imp")); | |
3908 | field_decl = grokfield (input_filename, lineno, field_decl, | |
3909 | decl_specs, NULL_TREE); | |
6c65299b RS |
3910 | chainon (field_decl_chain, field_decl); |
3911 | ||
51900510 | 3912 | finish_struct (_SLT_record, field_decl_chain, NULL_TREE); |
6c65299b RS |
3913 | |
3914 | return _SLT_record; | |
3915 | } | |
3916 | ||
3917 | ||
3918 | static tree | |
3919 | generate_dispatch_table (type, name, size, list) | |
3920 | tree type; | |
3921 | char *name; | |
3922 | int size; | |
3923 | tree list; | |
3924 | { | |
3925 | tree sc_spec, decl_specs, decl, initlist; | |
3926 | ||
51900510 RK |
3927 | sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE); |
3928 | decl_specs = tree_cons (NULL_TREE, type, sc_spec); | |
6c65299b | 3929 | |
e31c7eec | 3930 | decl = start_decl (synth_id_with_class_suffix (name, implementation_context), |
51900510 | 3931 | decl_specs, 1, NULL_TREE, NULL_TREE); |
6c65299b | 3932 | |
51900510 RK |
3933 | initlist = build_tree_list (NULL_TREE, build_int_2 (0, 0)); |
3934 | initlist = tree_cons (NULL_TREE, build_int_2 (size, 0), initlist); | |
3935 | initlist = tree_cons (NULL_TREE, list, initlist); | |
6c65299b | 3936 | |
89ef1046 RS |
3937 | finish_decl (decl, |
3938 | build_constructor (TREE_TYPE (decl), nreverse (initlist)), | |
51900510 | 3939 | NULL_TREE); |
6c65299b RS |
3940 | |
3941 | return decl; | |
3942 | } | |
3943 | ||
3944 | static void | |
3945 | generate_dispatch_tables () | |
3946 | { | |
3947 | tree initlist, chain, method_list_template; | |
3948 | tree cast, variable_length_type; | |
3949 | int size; | |
3950 | ||
3951 | if (!objc_method_template) | |
3952 | objc_method_template = build_method_template (); | |
3953 | ||
e31c7eec TW |
3954 | cast |
3955 | = build_tree_list | |
51900510 RK |
3956 | (build_tree_list (NULL_TREE, |
3957 | xref_tag (RECORD_TYPE, | |
3958 | get_identifier (UTAG_METHOD_LIST))), | |
3959 | NULL_TREE); | |
3960 | ||
6c65299b RS |
3961 | variable_length_type = groktypename (cast); |
3962 | ||
3963 | chain = CLASS_CLS_METHODS (implementation_context); | |
3964 | if (chain) | |
3965 | { | |
30c0e2df | 3966 | size = list_length (chain); |
6c65299b | 3967 | |
51900510 RK |
3968 | method_list_template |
3969 | = build_method_list_template (objc_method_template, size); | |
3970 | initlist | |
3971 | = build_dispatch_table_initializer (objc_method_template, chain); | |
e31c7eec TW |
3972 | |
3973 | UOBJC_CLASS_METHODS_decl | |
3974 | = generate_dispatch_table (method_list_template, | |
3975 | ((TREE_CODE (implementation_context) | |
3976 | == CLASS_IMPLEMENTATION_TYPE) | |
3977 | ? "_OBJC_CLASS_METHODS" | |
3978 | : "_OBJC_CATEGORY_CLASS_METHODS"), | |
3979 | size, initlist); | |
e31c7eec | 3980 | TREE_TYPE (UOBJC_CLASS_METHODS_decl) = variable_length_type; |
6c65299b RS |
3981 | } |
3982 | else | |
e31c7eec | 3983 | UOBJC_CLASS_METHODS_decl = 0; |
6c65299b RS |
3984 | |
3985 | chain = CLASS_NST_METHODS (implementation_context); | |
3986 | if (chain) | |
3987 | { | |
30c0e2df KKT |
3988 | size = list_length (chain); |
3989 | ||
51900510 RK |
3990 | method_list_template |
3991 | = build_method_list_template (objc_method_template, size); | |
3992 | initlist | |
3993 | = build_dispatch_table_initializer (objc_method_template, chain); | |
6c65299b | 3994 | |
e31c7eec | 3995 | if (TREE_CODE (implementation_context) == CLASS_IMPLEMENTATION_TYPE) |
89ef1046 RS |
3996 | UOBJC_INSTANCE_METHODS_decl |
3997 | = generate_dispatch_table (method_list_template, | |
e31c7eec | 3998 | "_OBJC_INSTANCE_METHODS", |
6c65299b RS |
3999 | size, initlist); |
4000 | else | |
0f41302f | 4001 | /* We have a category. */ |
89ef1046 RS |
4002 | UOBJC_INSTANCE_METHODS_decl |
4003 | = generate_dispatch_table (method_list_template, | |
e31c7eec | 4004 | "_OBJC_CATEGORY_INSTANCE_METHODS", |
6c65299b | 4005 | size, initlist); |
e31c7eec | 4006 | TREE_TYPE (UOBJC_INSTANCE_METHODS_decl) = variable_length_type; |
6c65299b RS |
4007 | } |
4008 | else | |
e31c7eec TW |
4009 | UOBJC_INSTANCE_METHODS_decl = 0; |
4010 | } | |
4011 | ||
4012 | static tree | |
4013 | generate_protocol_list (i_or_p) | |
4014 | tree i_or_p; | |
4015 | { | |
4016 | static tree cast_type = 0; | |
4017 | tree initlist, decl_specs, sc_spec; | |
4018 | tree refs_decl, expr_decl, lproto, e, plist; | |
4019 | int size = 0; | |
4020 | ||
4021 | if (TREE_CODE (i_or_p) == CLASS_INTERFACE_TYPE | |
4022 | || TREE_CODE (i_or_p) == CATEGORY_INTERFACE_TYPE) | |
4023 | plist = CLASS_PROTOCOL_LIST (i_or_p); | |
4024 | else if (TREE_CODE (i_or_p) == PROTOCOL_INTERFACE_TYPE) | |
4025 | plist = PROTOCOL_LIST (i_or_p); | |
4026 | else | |
4027 | abort (); | |
4028 | ||
4029 | if (!cast_type) | |
4030 | cast_type | |
4031 | = groktypename | |
4032 | (build_tree_list | |
51900510 | 4033 | (build_tree_list (NULL_TREE, |
e31c7eec TW |
4034 | xref_tag (RECORD_TYPE, |
4035 | get_identifier (UTAG_PROTOCOL))), | |
51900510 | 4036 | build1 (INDIRECT_REF, NULL_TREE, NULL_TREE))); |
e31c7eec | 4037 | |
0f41302f | 4038 | /* Compute size. */ |
e31c7eec TW |
4039 | for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto)) |
4040 | if (TREE_CODE (TREE_VALUE (lproto)) == PROTOCOL_INTERFACE_TYPE | |
4041 | && PROTOCOL_FORWARD_DECL (TREE_VALUE (lproto))) | |
4042 | size++; | |
4043 | ||
0f41302f | 4044 | /* Build initializer. */ |
51900510 | 4045 | initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), NULL_TREE); |
e31c7eec TW |
4046 | |
4047 | e = build_int_2 (size, 0); | |
4048 | TREE_TYPE (e) = cast_type; | |
51900510 | 4049 | initlist = tree_cons (NULL_TREE, e, initlist); |
e31c7eec TW |
4050 | |
4051 | for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto)) | |
4052 | { | |
4053 | tree pval = TREE_VALUE (lproto); | |
4054 | ||
4055 | if (TREE_CODE (pval) == PROTOCOL_INTERFACE_TYPE | |
4056 | && PROTOCOL_FORWARD_DECL (pval)) | |
4057 | { | |
4058 | e = build_unary_op (ADDR_EXPR, PROTOCOL_FORWARD_DECL (pval), 0); | |
51900510 | 4059 | initlist = tree_cons (NULL_TREE, e, initlist); |
e31c7eec TW |
4060 | } |
4061 | } | |
4062 | ||
4063 | /* static struct objc_protocol *refs[n]; */ | |
4064 | ||
51900510 RK |
4065 | sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE); |
4066 | decl_specs = tree_cons (NULL_TREE, xref_tag (RECORD_TYPE, | |
e31c7eec TW |
4067 | get_identifier (UTAG_PROTOCOL)), |
4068 | sc_spec); | |
4069 | ||
4070 | if (TREE_CODE (i_or_p) == PROTOCOL_INTERFACE_TYPE) | |
4071 | expr_decl = build_nt (ARRAY_REF, | |
4072 | synth_id_with_class_suffix ("_OBJC_PROTOCOL_REFS", | |
4073 | i_or_p), | |
4074 | build_int_2 (size + 2, 0)); | |
4075 | else if (TREE_CODE (i_or_p) == CLASS_INTERFACE_TYPE) | |
4076 | expr_decl = build_nt (ARRAY_REF, | |
4077 | synth_id_with_class_suffix ("_OBJC_CLASS_PROTOCOLS", | |
4078 | i_or_p), | |
4079 | build_int_2 (size + 2, 0)); | |
4080 | else if (TREE_CODE (i_or_p) == CATEGORY_INTERFACE_TYPE) | |
51900510 RK |
4081 | expr_decl |
4082 | = build_nt (ARRAY_REF, | |
4083 | synth_id_with_class_suffix ("_OBJC_CATEGORY_PROTOCOLS", | |
4084 | i_or_p), | |
4085 | build_int_2 (size + 2, 0)); | |
e31c7eec | 4086 | |
51900510 | 4087 | expr_decl = build1 (INDIRECT_REF, NULL_TREE, expr_decl); |
e31c7eec | 4088 | |
51900510 | 4089 | refs_decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE, NULL_TREE); |
e31c7eec | 4090 | |
89ef1046 RS |
4091 | finish_decl (refs_decl, build_constructor (TREE_TYPE (refs_decl), |
4092 | nreverse (initlist)), | |
51900510 | 4093 | NULL_TREE); |
e31c7eec TW |
4094 | |
4095 | return refs_decl; | |
6c65299b RS |
4096 | } |
4097 | ||
4098 | static tree | |
89ef1046 | 4099 | build_category_initializer (type, cat_name, class_name, |
e31c7eec | 4100 | instance_methods, class_methods, protocol_list) |
89ef1046 | 4101 | tree type; |
6c65299b RS |
4102 | tree cat_name; |
4103 | tree class_name; | |
4104 | tree instance_methods; | |
4105 | tree class_methods; | |
e31c7eec | 4106 | tree protocol_list; |
6c65299b | 4107 | { |
51900510 | 4108 | tree initlist = NULL_TREE, expr; |
6c65299b | 4109 | |
51900510 RK |
4110 | initlist = tree_cons (NULL_TREE, cat_name, initlist); |
4111 | initlist = tree_cons (NULL_TREE, class_name, initlist); | |
6c65299b RS |
4112 | |
4113 | if (!instance_methods) | |
51900510 | 4114 | initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist); |
6c65299b RS |
4115 | else |
4116 | { | |
4117 | expr = build_unary_op (ADDR_EXPR, instance_methods, 0); | |
51900510 | 4118 | initlist = tree_cons (NULL_TREE, expr, initlist); |
6c65299b RS |
4119 | } |
4120 | if (!class_methods) | |
51900510 | 4121 | initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist); |
6c65299b RS |
4122 | else |
4123 | { | |
4124 | expr = build_unary_op (ADDR_EXPR, class_methods, 0); | |
51900510 | 4125 | initlist = tree_cons (NULL_TREE, expr, initlist); |
6c65299b | 4126 | } |
e31c7eec TW |
4127 | |
4128 | /* protocol_list = */ | |
4129 | if (!protocol_list) | |
51900510 | 4130 | initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist); |
e31c7eec TW |
4131 | else |
4132 | { | |
4133 | static tree cast_type2; | |
4134 | ||
4135 | if (!cast_type2) | |
4136 | cast_type2 | |
4137 | = groktypename | |
4138 | (build_tree_list | |
51900510 | 4139 | (build_tree_list (NULL_TREE, |
e31c7eec TW |
4140 | xref_tag (RECORD_TYPE, |
4141 | get_identifier (UTAG_PROTOCOL))), | |
51900510 RK |
4142 | build1 (INDIRECT_REF, NULL_TREE, |
4143 | build1 (INDIRECT_REF, NULL_TREE, NULL_TREE)))); | |
e31c7eec TW |
4144 | |
4145 | expr = build_unary_op (ADDR_EXPR, protocol_list, 0); | |
4146 | TREE_TYPE (expr) = cast_type2; | |
51900510 | 4147 | initlist = tree_cons (NULL_TREE, expr, initlist); |
e31c7eec TW |
4148 | } |
4149 | ||
89ef1046 | 4150 | return build_constructor (type, nreverse (initlist)); |
6c65299b RS |
4151 | } |
4152 | ||
e31c7eec TW |
4153 | /* struct objc_class { |
4154 | struct objc_class *isa; | |
4155 | struct objc_class *super_class; | |
4156 | char *name; | |
4157 | long version; | |
4158 | long info; | |
4159 | long instance_size; | |
4160 | struct objc_ivar_list *ivars; | |
4161 | struct objc_method_list *methods; | |
4162 | if (flag_next_runtime) | |
4163 | struct objc_cache *cache; | |
4164 | else { | |
4165 | struct sarray *dtable; | |
4166 | struct objc_class *subclass_list; | |
4167 | struct objc_class *sibling_class; | |
4168 | } | |
4169 | struct objc_protocol_list *protocols; | |
4170 | }; */ | |
4171 | ||
6c65299b | 4172 | static tree |
89ef1046 | 4173 | build_shared_structure_initializer (type, isa, super, name, size, status, |
e31c7eec | 4174 | dispatch_table, ivar_list, protocol_list) |
89ef1046 | 4175 | tree type; |
6c65299b RS |
4176 | tree isa; |
4177 | tree super; | |
4178 | tree name; | |
4179 | tree size; | |
4180 | int status; | |
4181 | tree dispatch_table; | |
4182 | tree ivar_list; | |
e31c7eec | 4183 | tree protocol_list; |
6c65299b | 4184 | { |
51900510 | 4185 | tree initlist = NULL_TREE, expr; |
6c65299b RS |
4186 | |
4187 | /* isa = */ | |
51900510 | 4188 | initlist = tree_cons (NULL_TREE, isa, initlist); |
6c65299b RS |
4189 | |
4190 | /* super_class = */ | |
51900510 | 4191 | initlist = tree_cons (NULL_TREE, super, initlist); |
6c65299b RS |
4192 | |
4193 | /* name = */ | |
51900510 | 4194 | initlist = tree_cons (NULL_TREE, default_conversion (name), initlist); |
6c65299b RS |
4195 | |
4196 | /* version = */ | |
51900510 | 4197 | initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist); |
6c65299b RS |
4198 | |
4199 | /* info = */ | |
51900510 | 4200 | initlist = tree_cons (NULL_TREE, build_int_2 (status, 0), initlist); |
6c65299b RS |
4201 | |
4202 | /* instance_size = */ | |
51900510 | 4203 | initlist = tree_cons (NULL_TREE, size, initlist); |
6c65299b RS |
4204 | |
4205 | /* objc_ivar_list = */ | |
4206 | if (!ivar_list) | |
51900510 | 4207 | initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist); |
6c65299b RS |
4208 | else |
4209 | { | |
4210 | expr = build_unary_op (ADDR_EXPR, ivar_list, 0); | |
51900510 | 4211 | initlist = tree_cons (NULL_TREE, expr, initlist); |
6c65299b RS |
4212 | } |
4213 | ||
4214 | /* objc_method_list = */ | |
4215 | if (!dispatch_table) | |
51900510 | 4216 | initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist); |
6c65299b RS |
4217 | else |
4218 | { | |
4219 | expr = build_unary_op (ADDR_EXPR, dispatch_table, 0); | |
51900510 | 4220 | initlist = tree_cons (NULL_TREE, expr, initlist); |
6c65299b RS |
4221 | } |
4222 | ||
e31c7eec TW |
4223 | if (flag_next_runtime) |
4224 | /* method_cache = */ | |
51900510 | 4225 | initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist); |
e31c7eec TW |
4226 | else |
4227 | { | |
4228 | /* dtable = */ | |
51900510 | 4229 | initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist); |
e31c7eec TW |
4230 | |
4231 | /* subclass_list = */ | |
51900510 | 4232 | initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist); |
e31c7eec TW |
4233 | |
4234 | /* sibling_class = */ | |
51900510 | 4235 | initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist); |
e31c7eec TW |
4236 | } |
4237 | ||
4238 | /* protocol_list = */ | |
4239 | if (! protocol_list) | |
51900510 | 4240 | initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist); |
e31c7eec TW |
4241 | else |
4242 | { | |
4243 | static tree cast_type2; | |
4244 | ||
4245 | if (!cast_type2) | |
4246 | cast_type2 | |
4247 | = groktypename | |
4248 | (build_tree_list | |
51900510 | 4249 | (build_tree_list (NULL_TREE, |
e31c7eec TW |
4250 | xref_tag (RECORD_TYPE, |
4251 | get_identifier (UTAG_PROTOCOL))), | |
51900510 RK |
4252 | build1 (INDIRECT_REF, NULL_TREE, |
4253 | build1 (INDIRECT_REF, NULL_TREE, NULL_TREE)))); | |
e31c7eec TW |
4254 | |
4255 | expr = build_unary_op (ADDR_EXPR, protocol_list, 0); | |
4256 | TREE_TYPE (expr) = cast_type2; | |
51900510 | 4257 | initlist = tree_cons (NULL_TREE, expr, initlist); |
e31c7eec | 4258 | } |
6c65299b | 4259 | |
89ef1046 | 4260 | return build_constructor (type, nreverse (initlist)); |
6c65299b RS |
4261 | } |
4262 | ||
e31c7eec | 4263 | /* static struct objc_category _OBJC_CATEGORY_<name> = { ... }; */ |
0f41302f | 4264 | |
6c65299b RS |
4265 | static void |
4266 | generate_category (cat) | |
4267 | tree cat; | |
4268 | { | |
4269 | tree sc_spec, decl_specs, decl; | |
4270 | tree initlist, cat_name_expr, class_name_expr; | |
e31c7eec TW |
4271 | tree protocol_decl, category; |
4272 | ||
4273 | add_class_reference (CLASS_NAME (cat)); | |
4274 | cat_name_expr = add_objc_string (CLASS_SUPER_NAME (cat), class_names); | |
4275 | ||
4276 | class_name_expr = add_objc_string (CLASS_NAME (cat), class_names); | |
4277 | ||
4278 | category = CLASS_CATEGORY_LIST (implementation_template); | |
4279 | ||
4280 | /* find the category interface from the class it is associated with */ | |
4281 | while (category) | |
4282 | { | |
4283 | if (CLASS_SUPER_NAME (cat) == CLASS_SUPER_NAME (category)) | |
4284 | break; | |
4285 | category = CLASS_CATEGORY_LIST (category); | |
4286 | } | |
4287 | ||
4288 | if (category && CLASS_PROTOCOL_LIST (category)) | |
4289 | { | |
4290 | generate_protocol_references (CLASS_PROTOCOL_LIST (category)); | |
4291 | protocol_decl = generate_protocol_list (category); | |
4292 | } | |
4293 | else | |
4294 | protocol_decl = 0; | |
6c65299b | 4295 | |
51900510 RK |
4296 | sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE); |
4297 | decl_specs = tree_cons (NULL_TREE, objc_category_template, sc_spec); | |
6c65299b | 4298 | |
e31c7eec TW |
4299 | decl = start_decl (synth_id_with_class_suffix ("_OBJC_CATEGORY", |
4300 | implementation_context), | |
51900510 | 4301 | decl_specs, 1, NULL_TREE, NULL_TREE); |
6c65299b | 4302 | |
89ef1046 RS |
4303 | initlist = build_category_initializer (TREE_TYPE (decl), |
4304 | cat_name_expr, class_name_expr, | |
e31c7eec TW |
4305 | UOBJC_INSTANCE_METHODS_decl, |
4306 | UOBJC_CLASS_METHODS_decl, | |
4307 | protocol_decl); | |
6c65299b | 4308 | |
e31c7eec | 4309 | TREE_USED (decl) = 1; |
51900510 | 4310 | finish_decl (decl, initlist, NULL_TREE); |
6c65299b RS |
4311 | } |
4312 | ||
e31c7eec TW |
4313 | /* static struct objc_class _OBJC_METACLASS_Foo={ ... }; |
4314 | static struct objc_class _OBJC_CLASS_Foo={ ... }; */ | |
4315 | ||
6c65299b RS |
4316 | static void |
4317 | generate_shared_structures () | |
4318 | { | |
e31c7eec | 4319 | tree sc_spec, decl_specs, decl; |
6c65299b | 4320 | tree name_expr, super_expr, root_expr; |
51900510 | 4321 | tree my_root_id = NULL_TREE, my_super_id = NULL_TREE; |
e31c7eec | 4322 | tree cast_type, initlist, protocol_decl; |
6c65299b RS |
4323 | |
4324 | my_super_id = CLASS_SUPER_NAME (implementation_template); | |
4325 | if (my_super_id) | |
4326 | { | |
4327 | add_class_reference (my_super_id); | |
4328 | ||
e31c7eec TW |
4329 | /* Compute "my_root_id" - this is required for code generation. |
4330 | the "isa" for all meta class structures points to the root of | |
4331 | the inheritance hierarchy (e.g. "__Object")... */ | |
6c65299b RS |
4332 | my_root_id = my_super_id; |
4333 | do | |
4334 | { | |
4335 | tree my_root_int = lookup_interface (my_root_id); | |
4336 | ||
4337 | if (my_root_int && CLASS_SUPER_NAME (my_root_int)) | |
4338 | my_root_id = CLASS_SUPER_NAME (my_root_int); | |
4339 | else | |
4340 | break; | |
4341 | } | |
4342 | while (1); | |
4343 | } | |
51900510 | 4344 | else |
0f41302f | 4345 | /* No super class. */ |
51900510 | 4346 | my_root_id = CLASS_NAME (implementation_template); |
6c65299b | 4347 | |
e31c7eec | 4348 | cast_type |
51900510 | 4349 | = groktypename (build_tree_list (build_tree_list (NULL_TREE, |
e31c7eec | 4350 | objc_class_template), |
51900510 RK |
4351 | build1 (INDIRECT_REF, |
4352 | NULL_TREE, NULL_TREE))); | |
6c65299b | 4353 | |
e31c7eec TW |
4354 | name_expr = add_objc_string (CLASS_NAME (implementation_template), |
4355 | class_names); | |
6c65299b | 4356 | |
0f41302f | 4357 | /* Install class `isa' and `super' pointers at runtime. */ |
6c65299b RS |
4358 | if (my_super_id) |
4359 | { | |
e31c7eec TW |
4360 | super_expr = add_objc_string (my_super_id, class_names); |
4361 | super_expr = build_c_cast (cast_type, super_expr); /* cast! */ | |
6c65299b RS |
4362 | } |
4363 | else | |
4364 | super_expr = build_int_2 (0, 0); | |
4365 | ||
e31c7eec TW |
4366 | root_expr = add_objc_string (my_root_id, class_names); |
4367 | root_expr = build_c_cast (cast_type, root_expr); /* cast! */ | |
4368 | ||
4369 | if (CLASS_PROTOCOL_LIST (implementation_template)) | |
4370 | { | |
51900510 RK |
4371 | generate_protocol_references |
4372 | (CLASS_PROTOCOL_LIST (implementation_template)); | |
e31c7eec TW |
4373 | protocol_decl = generate_protocol_list (implementation_template); |
4374 | } | |
4375 | else | |
4376 | protocol_decl = 0; | |
6c65299b RS |
4377 | |
4378 | /* static struct objc_class _OBJC_METACLASS_Foo = { ... }; */ | |
4379 | ||
51900510 RK |
4380 | sc_spec = build_tree_list (NULL_TREE, ridpointers[(int) RID_STATIC]); |
4381 | decl_specs = tree_cons (NULL_TREE, objc_class_template, sc_spec); | |
6c65299b | 4382 | |
f4f24753 | 4383 | decl = start_decl (DECL_NAME (UOBJC_METACLASS_decl), decl_specs, 1, |
51900510 | 4384 | NULL_TREE, NULL_TREE); |
6c65299b | 4385 | |
e31c7eec TW |
4386 | initlist |
4387 | = build_shared_structure_initializer | |
89ef1046 RS |
4388 | (TREE_TYPE (decl), |
4389 | root_expr, super_expr, name_expr, | |
e31c7eec TW |
4390 | build_int_2 ((TREE_INT_CST_LOW (TYPE_SIZE (objc_class_template)) |
4391 | / BITS_PER_UNIT), | |
4392 | 0), | |
4393 | 2 /*CLS_META*/, | |
4394 | UOBJC_CLASS_METHODS_decl, | |
4395 | UOBJC_CLASS_VARIABLES_decl, | |
4396 | protocol_decl); | |
6c65299b | 4397 | |
51900510 | 4398 | finish_decl (decl, initlist, NULL_TREE); |
6c65299b RS |
4399 | |
4400 | /* static struct objc_class _OBJC_CLASS_Foo={ ... }; */ | |
4401 | ||
f4f24753 | 4402 | decl = start_decl (DECL_NAME (UOBJC_CLASS_decl), decl_specs, 1, |
51900510 | 4403 | NULL_TREE, NULL_TREE); |
e31c7eec TW |
4404 | |
4405 | initlist | |
4406 | = build_shared_structure_initializer | |
89ef1046 RS |
4407 | (TREE_TYPE (decl), |
4408 | build_unary_op (ADDR_EXPR, UOBJC_METACLASS_decl, 0), | |
e31c7eec | 4409 | super_expr, name_expr, |
51900510 RK |
4410 | build_int_2 |
4411 | ((TREE_INT_CST_LOW | |
4412 | (TYPE_SIZE (CLASS_STATIC_TEMPLATE (implementation_template))) | |
4413 | / BITS_PER_UNIT), | |
4414 | 0), | |
e31c7eec TW |
4415 | 1 /*CLS_FACTORY*/, |
4416 | UOBJC_INSTANCE_METHODS_decl, | |
4417 | UOBJC_INSTANCE_VARIABLES_decl, | |
4418 | protocol_decl); | |
6c65299b | 4419 | |
51900510 | 4420 | finish_decl (decl, initlist, NULL_TREE); |
6c65299b RS |
4421 | } |
4422 | ||
4423 | static tree | |
e31c7eec | 4424 | synth_id_with_class_suffix (preamble, ctxt) |
6c65299b | 4425 | char *preamble; |
e31c7eec | 4426 | tree ctxt; |
6c65299b | 4427 | { |
6e3f0724 | 4428 | char *string; |
e31c7eec TW |
4429 | if (TREE_CODE (ctxt) == CLASS_IMPLEMENTATION_TYPE |
4430 | || TREE_CODE (ctxt) == CLASS_INTERFACE_TYPE) | |
6e3f0724 | 4431 | { |
e31c7eec TW |
4432 | char *class_name |
4433 | = IDENTIFIER_POINTER (CLASS_NAME (implementation_context)); | |
4434 | string = (char *) alloca (strlen (preamble) + strlen (class_name) + 3); | |
6e3f0724 | 4435 | sprintf (string, "%s_%s", preamble, |
e31c7eec | 4436 | IDENTIFIER_POINTER (CLASS_NAME (ctxt))); |
6e3f0724 | 4437 | } |
e31c7eec TW |
4438 | else if (TREE_CODE (ctxt) == CATEGORY_IMPLEMENTATION_TYPE |
4439 | || TREE_CODE (ctxt) == CATEGORY_INTERFACE_TYPE) | |
6e3f0724 | 4440 | { |
0f41302f | 4441 | /* We have a category. */ |
e31c7eec TW |
4442 | char *class_name |
4443 | = IDENTIFIER_POINTER (CLASS_NAME (implementation_context)); | |
4444 | char *class_super_name | |
4445 | = IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_context)); | |
6e3f0724 | 4446 | string = (char *) alloca (strlen (preamble) |
e31c7eec TW |
4447 | + strlen (class_name) |
4448 | + strlen (class_super_name) | |
6e3f0724 | 4449 | + 3); |
e31c7eec TW |
4450 | sprintf (string, "%s_%s_%s", preamble, class_name, class_super_name); |
4451 | } | |
4452 | else if (TREE_CODE (ctxt) == PROTOCOL_INTERFACE_TYPE) | |
4453 | { | |
4454 | char *protocol_name = IDENTIFIER_POINTER (PROTOCOL_NAME (ctxt)); | |
51900510 RK |
4455 | string |
4456 | = (char *) alloca (strlen (preamble) + strlen (protocol_name) + 3); | |
e31c7eec | 4457 | sprintf (string, "%s_%s", preamble, protocol_name); |
6e3f0724 RS |
4458 | } |
4459 | return get_identifier (string); | |
6c65299b RS |
4460 | } |
4461 | ||
e31c7eec TW |
4462 | static int |
4463 | is_objc_type_qualifier (node) | |
4464 | tree node; | |
4465 | { | |
4466 | return (TREE_CODE (node) == IDENTIFIER_NODE | |
4467 | && (node == ridpointers [(int) RID_CONST] | |
4468 | || node == ridpointers [(int) RID_VOLATILE] | |
4469 | || node == ridpointers [(int) RID_IN] | |
4470 | || node == ridpointers [(int) RID_OUT] | |
4471 | || node == ridpointers [(int) RID_INOUT] | |
4472 | || node == ridpointers [(int) RID_BYCOPY] | |
4473 | || node == ridpointers [(int) RID_ONEWAY])); | |
4474 | } | |
4475 | ||
4476 | /* If type is empty or only type qualifiers are present, add default | |
4477 | type of id (otherwise grokdeclarator will default to int). */ | |
4478 | ||
4479 | static tree | |
4480 | adjust_type_for_id_default (type) | |
4481 | tree type; | |
4482 | { | |
4483 | tree declspecs, chain; | |
4484 | ||
4485 | if (!type) | |
51900510 RK |
4486 | return build_tree_list (build_tree_list (NULL_TREE, objc_object_reference), |
4487 | build1 (INDIRECT_REF, NULL_TREE, NULL_TREE)); | |
e31c7eec TW |
4488 | |
4489 | declspecs = TREE_PURPOSE (type); | |
4490 | ||
4491 | /* Determine if a typespec is present. */ | |
4492 | for (chain = declspecs; | |
4493 | chain; | |
4494 | chain = TREE_CHAIN (chain)) | |
4495 | { | |
4496 | if (!is_objc_type_qualifier (TREE_VALUE (chain))) | |
4497 | return type; | |
4498 | } | |
4499 | ||
51900510 RK |
4500 | return build_tree_list (tree_cons (NULL_TREE, objc_object_reference, |
4501 | declspecs), | |
4502 | build1 (INDIRECT_REF, NULL_TREE, NULL_TREE)); | |
e31c7eec TW |
4503 | } |
4504 | ||
51900510 | 4505 | /* Usage: |
e31c7eec TW |
4506 | keyworddecl: |
4507 | selector ':' '(' typename ')' identifier | |
4508 | ||
51900510 RK |
4509 | Purpose: |
4510 | Transform an Objective-C keyword argument into | |
e31c7eec TW |
4511 | the C equivalent parameter declarator. |
4512 | ||
51900510 | 4513 | In: key_name, an "identifier_node" (optional). |
e31c7eec TW |
4514 | arg_type, a "tree_list" (optional). |
4515 | arg_name, an "identifier_node". | |
4516 | ||
51900510 RK |
4517 | Note: It would be really nice to strongly type the preceding |
4518 | arguments in the function prototype; however, then I | |
e31c7eec TW |
4519 | could not use the "accessor" macros defined in "tree.h". |
4520 | ||
51900510 | 4521 | Out: an instance of "keyword_decl". */ |
6c65299b RS |
4522 | |
4523 | tree | |
4524 | build_keyword_decl (key_name, arg_type, arg_name) | |
4525 | tree key_name; | |
4526 | tree arg_type; | |
4527 | tree arg_name; | |
4528 | { | |
4529 | tree keyword_decl; | |
4530 | ||
0f41302f | 4531 | /* If no type is specified, default to "id". */ |
e31c7eec | 4532 | arg_type = adjust_type_for_id_default (arg_type); |
6c65299b RS |
4533 | |
4534 | keyword_decl = make_node (KEYWORD_DECL); | |
4535 | ||
4536 | TREE_TYPE (keyword_decl) = arg_type; | |
4537 | KEYWORD_ARG_NAME (keyword_decl) = arg_name; | |
4538 | KEYWORD_KEY_NAME (keyword_decl) = key_name; | |
4539 | ||
4540 | return keyword_decl; | |
4541 | } | |
4542 | ||
e31c7eec | 4543 | /* Given a chain of keyword_decl's, synthesize the full keyword selector. */ |
51900510 | 4544 | |
6c65299b RS |
4545 | static tree |
4546 | build_keyword_selector (selector) | |
4547 | tree selector; | |
4548 | { | |
4549 | int len = 0; | |
4550 | tree key_chain, key_name; | |
4551 | char *buf; | |
4552 | ||
4553 | for (key_chain = selector; key_chain; key_chain = TREE_CHAIN (key_chain)) | |
4554 | { | |
4555 | if (TREE_CODE (selector) == KEYWORD_DECL) | |
4556 | key_name = KEYWORD_KEY_NAME (key_chain); | |
4557 | else if (TREE_CODE (selector) == TREE_LIST) | |
4558 | key_name = TREE_PURPOSE (key_chain); | |
4559 | ||
4560 | if (key_name) | |
4561 | len += IDENTIFIER_LENGTH (key_name) + 1; | |
51900510 | 4562 | else |
0f41302f | 4563 | /* Just a ':' arg. */ |
6c65299b RS |
4564 | len++; |
4565 | } | |
51900510 | 4566 | |
6c65299b RS |
4567 | buf = (char *)alloca (len + 1); |
4568 | bzero (buf, len + 1); | |
4569 | ||
4570 | for (key_chain = selector; key_chain; key_chain = TREE_CHAIN (key_chain)) | |
4571 | { | |
4572 | if (TREE_CODE (selector) == KEYWORD_DECL) | |
4573 | key_name = KEYWORD_KEY_NAME (key_chain); | |
4574 | else if (TREE_CODE (selector) == TREE_LIST) | |
4575 | key_name = TREE_PURPOSE (key_chain); | |
4576 | ||
4577 | if (key_name) | |
4578 | strcat (buf, IDENTIFIER_POINTER (key_name)); | |
4579 | strcat (buf, ":"); | |
4580 | } | |
51900510 | 4581 | |
6c65299b RS |
4582 | return get_identifier (buf); |
4583 | } | |
4584 | ||
0f41302f | 4585 | /* Used for declarations and definitions. */ |
6c65299b RS |
4586 | |
4587 | tree | |
4588 | build_method_decl (code, ret_type, selector, add_args) | |
4589 | enum tree_code code; | |
4590 | tree ret_type; | |
4591 | tree selector; | |
4592 | tree add_args; | |
4593 | { | |
4594 | tree method_decl; | |
4595 | ||
0f41302f | 4596 | /* If no type is specified, default to "id". */ |
e31c7eec | 4597 | ret_type = adjust_type_for_id_default (ret_type); |
6c65299b RS |
4598 | |
4599 | method_decl = make_node (code); | |
4600 | TREE_TYPE (method_decl) = ret_type; | |
4601 | ||
e31c7eec TW |
4602 | /* If we have a keyword selector, create an identifier_node that |
4603 | represents the full selector name (`:' included)... */ | |
6c65299b RS |
4604 | if (TREE_CODE (selector) == KEYWORD_DECL) |
4605 | { | |
4606 | METHOD_SEL_NAME (method_decl) = build_keyword_selector (selector); | |
4607 | METHOD_SEL_ARGS (method_decl) = selector; | |
4608 | METHOD_ADD_ARGS (method_decl) = add_args; | |
4609 | } | |
4610 | else | |
4611 | { | |
4612 | METHOD_SEL_NAME (method_decl) = selector; | |
51900510 RK |
4613 | METHOD_SEL_ARGS (method_decl) = NULL_TREE; |
4614 | METHOD_ADD_ARGS (method_decl) = NULL_TREE; | |
6c65299b RS |
4615 | } |
4616 | ||
4617 | return method_decl; | |
4618 | } | |
4619 | ||
4620 | #define METHOD_DEF 0 | |
4621 | #define METHOD_REF 1 | |
e31c7eec TW |
4622 | |
4623 | /* Used by `build_message_expr' and `comp_method_types'. Return an | |
4624 | argument list for method METH. CONTEXT is either METHOD_DEF or | |
4625 | METHOD_REF, saying whether we are trying to define a method or call | |
4626 | one. SUPERFLAG says this is for a send to super; this makes a | |
4627 | difference for the NeXT calling sequence in which the lookup and | |
4628 | the method call are done together. */ | |
af35aeb2 | 4629 | |
6c65299b RS |
4630 | static tree |
4631 | get_arg_type_list (meth, context, superflag) | |
4632 | tree meth; | |
4633 | int context; | |
4634 | int superflag; | |
4635 | { | |
4636 | tree arglist, akey; | |
4637 | ||
0f41302f | 4638 | /* Receiver type. */ |
e31c7eec | 4639 | if (flag_next_runtime && superflag) |
51900510 | 4640 | arglist = build_tree_list (NULL_TREE, super_type); |
59ce3fc8 | 4641 | else if (context == METHOD_DEF) |
51900510 | 4642 | arglist = build_tree_list (NULL_TREE, TREE_TYPE (self_decl)); |
6c65299b | 4643 | else |
51900510 | 4644 | arglist = build_tree_list (NULL_TREE, id_type); |
6c65299b | 4645 | |
0f41302f | 4646 | /* Selector type - will eventually change to `int'. */ |
51900510 | 4647 | chainon (arglist, build_tree_list (NULL_TREE, selector_type)); |
6c65299b | 4648 | |
0f41302f | 4649 | /* Build a list of argument types. */ |
6c65299b RS |
4650 | for (akey = METHOD_SEL_ARGS (meth); akey; akey = TREE_CHAIN (akey)) |
4651 | { | |
4652 | tree arg_decl = groktypename_in_parm_context (TREE_TYPE (akey)); | |
51900510 | 4653 | chainon (arglist, build_tree_list (NULL_TREE, TREE_TYPE (arg_decl))); |
6c65299b RS |
4654 | } |
4655 | ||
4656 | if (METHOD_ADD_ARGS (meth) == (tree)1) | |
e31c7eec TW |
4657 | /* We have a `, ...' immediately following the selector, |
4658 | finalize the arglist...simulate get_parm_info (0). */ | |
6c65299b RS |
4659 | ; |
4660 | else if (METHOD_ADD_ARGS (meth)) | |
4661 | { | |
4662 | /* we have a variable length selector */ | |
4663 | tree add_arg_list = TREE_CHAIN (METHOD_ADD_ARGS (meth)); | |
4664 | chainon (arglist, add_arg_list); | |
4665 | } | |
e31c7eec TW |
4666 | else |
4667 | /* finalize the arglist...simulate get_parm_info (1) */ | |
51900510 | 4668 | chainon (arglist, build_tree_list (NULL_TREE, void_type_node)); |
6c65299b RS |
4669 | |
4670 | return arglist; | |
4671 | } | |
4672 | ||
4673 | static tree | |
4674 | check_duplicates (hsh) | |
4675 | hash hsh; | |
4676 | { | |
51900510 | 4677 | tree meth = NULL_TREE; |
6c65299b RS |
4678 | |
4679 | if (hsh) | |
4680 | { | |
4681 | meth = hsh->key; | |
4682 | ||
4683 | if (hsh->list) | |
4684 | { | |
0f41302f | 4685 | /* We have two methods with the same name and different types. */ |
6c65299b | 4686 | attr loop; |
e31c7eec | 4687 | char type = (TREE_CODE (meth) == INSTANCE_METHOD_DECL) ? '-' : '+'; |
6c65299b RS |
4688 | |
4689 | warning ("multiple declarations for method `%s'", | |
4690 | IDENTIFIER_POINTER (METHOD_SEL_NAME (meth))); | |
4691 | ||
4692 | warn_with_method ("using", type, meth); | |
4693 | for (loop = hsh->list; loop; loop = loop->next) | |
4694 | warn_with_method ("also found", type, loop->value); | |
4695 | } | |
4696 | } | |
4697 | return meth; | |
4698 | } | |
4699 | ||
59ce3fc8 TW |
4700 | /* If RECEIVER is a class reference, return the identifier node for the |
4701 | referenced class. RECEIVER is created by get_class_reference, so we | |
4702 | check the exact form created depending on which runtimes are used. */ | |
4703 | ||
6c65299b RS |
4704 | static tree |
4705 | receiver_is_class_object (receiver) | |
4706 | tree receiver; | |
4707 | { | |
59ce3fc8 | 4708 | tree chain, exp, arg; |
e31c7eec | 4709 | if (flag_next_runtime) |
6c65299b | 4710 | { |
59ce3fc8 | 4711 | /* The receiver is a variable created by build_class_reference_decl. */ |
e31c7eec TW |
4712 | if (TREE_CODE (receiver) == VAR_DECL |
4713 | && TREE_TYPE (receiver) == objc_class_type) | |
0f41302f | 4714 | /* Look up the identifier. */ |
59ce3fc8 | 4715 | for (chain = cls_ref_chain; chain; chain = TREE_CHAIN (chain)) |
e31c7eec TW |
4716 | if (TREE_PURPOSE (chain) == receiver) |
4717 | return TREE_VALUE (chain); | |
4718 | } | |
4719 | else | |
4720 | { | |
59ce3fc8 TW |
4721 | /* The receiver is a function call that returns an id. Check if |
4722 | it is a call to objc_getClass, if so, pick up the class name. */ | |
e31c7eec TW |
4723 | if ((exp = TREE_OPERAND (receiver, 0)) |
4724 | && TREE_CODE (exp) == ADDR_EXPR | |
4725 | && (exp = TREE_OPERAND (exp, 0)) | |
4726 | && TREE_CODE (exp) == FUNCTION_DECL | |
4727 | && exp == objc_get_class_decl | |
6c65299b | 4728 | /* we have a call to objc_getClass! */ |
e31c7eec TW |
4729 | && (arg = TREE_OPERAND (receiver, 1)) |
4730 | && TREE_CODE (arg) == TREE_LIST | |
59ce3fc8 TW |
4731 | && (arg = TREE_VALUE (arg))) |
4732 | { | |
4733 | STRIP_NOPS (arg); | |
4734 | if (TREE_CODE (arg) == ADDR_EXPR | |
4735 | && (arg = TREE_OPERAND (arg, 0)) | |
4736 | && TREE_CODE (arg) == STRING_CST) | |
51900510 | 4737 | /* Finally, we have the class name. */ |
59ce3fc8 TW |
4738 | return get_identifier (TREE_STRING_POINTER (arg)); |
4739 | } | |
6c65299b RS |
4740 | } |
4741 | return 0; | |
4742 | } | |
4743 | \f | |
4744 | /* If we are currently building a message expr, this holds | |
4745 | the identifier of the selector of the message. This is | |
0f41302f | 4746 | used when printing warnings about argument mismatches. */ |
6c65299b RS |
4747 | |
4748 | static tree building_objc_message_expr = 0; | |
4749 | ||
4750 | tree | |
4751 | maybe_building_objc_message_expr () | |
4752 | { | |
4753 | return building_objc_message_expr; | |
4754 | } | |
4755 | ||
4756 | /* Construct an expression for sending a message. | |
4757 | MESS has the object to send to in TREE_PURPOSE | |
e31c7eec TW |
4758 | and the argument list (including selector) in TREE_VALUE. |
4759 | ||
4760 | (*(<abstract_decl>(*)())_msg)(receiver, selTransTbl[n], ...); | |
4761 | (*(<abstract_decl>(*)())_msgSuper)(receiver, selTransTbl[n], ...); */ | |
6c65299b RS |
4762 | |
4763 | tree | |
4764 | build_message_expr (mess) | |
4765 | tree mess; | |
4766 | { | |
4767 | tree receiver = TREE_PURPOSE (mess); | |
4768 | tree selector, self_object; | |
4769 | tree rtype, sel_name; | |
4770 | tree args = TREE_VALUE (mess); | |
51900510 RK |
4771 | tree method_params = NULL_TREE; |
4772 | tree method_prototype = NULL_TREE; | |
6c65299b RS |
4773 | tree retval; |
4774 | int statically_typed = 0, statically_allocated = 0; | |
4775 | tree class_ident = 0; | |
4776 | ||
4777 | /* 1 if this is sending to the superclass. */ | |
4778 | int super; | |
4779 | ||
4780 | if (!doing_objc_thang) | |
e31c7eec | 4781 | objc_fatal (); |
6c65299b RS |
4782 | |
4783 | if (TREE_CODE (receiver) == ERROR_MARK) | |
4784 | return error_mark_node; | |
4785 | ||
0f41302f | 4786 | /* Determine receiver type. */ |
6c65299b | 4787 | rtype = TREE_TYPE (receiver); |
59ce3fc8 | 4788 | super = IS_SUPER (rtype); |
6c65299b RS |
4789 | |
4790 | if (! super) | |
4791 | { | |
4792 | if (TREE_STATIC_TEMPLATE (rtype)) | |
4793 | statically_allocated = 1; | |
4794 | else if (TREE_CODE (rtype) == POINTER_TYPE | |
4795 | && TREE_STATIC_TEMPLATE (TREE_TYPE (rtype))) | |
4796 | statically_typed = 1; | |
e31c7eec | 4797 | else if ((flag_next_runtime |
59ce3fc8 | 4798 | || (TREE_CODE (receiver) == CALL_EXPR && IS_ID (rtype))) |
6c65299b RS |
4799 | && (class_ident = receiver_is_class_object (receiver))) |
4800 | ; | |
59ce3fc8 TW |
4801 | else if (! IS_ID (rtype) |
4802 | /* Allow any type that matches objc_class_type. */ | |
4803 | && ! comptypes (rtype, objc_class_type)) | |
6c65299b RS |
4804 | { |
4805 | bzero (errbuf, BUFSIZE); | |
e31c7eec TW |
4806 | warning ("invalid receiver type `%s'", |
4807 | gen_declaration (rtype, errbuf)); | |
6c65299b | 4808 | } |
51900510 | 4809 | |
6c65299b RS |
4810 | if (statically_allocated) |
4811 | receiver = build_unary_op (ADDR_EXPR, receiver, 0); | |
4812 | ||
0f41302f | 4813 | /* Don't evaluate the receiver twice. */ |
66a35cea | 4814 | receiver = save_expr (receiver); |
6c65299b RS |
4815 | self_object = receiver; |
4816 | } | |
4817 | else | |
4818 | /* If sending to `super', use current self as the object. */ | |
4819 | self_object = self_decl; | |
4820 | ||
4821 | /* Obtain the full selector name. */ | |
4822 | ||
4823 | if (TREE_CODE (args) == IDENTIFIER_NODE) | |
0f41302f | 4824 | /* A unary selector. */ |
6c65299b RS |
4825 | sel_name = args; |
4826 | else if (TREE_CODE (args) == TREE_LIST) | |
4827 | sel_name = build_keyword_selector (args); | |
4828 | ||
6c65299b RS |
4829 | /* Build the parameter list to give to the method. */ |
4830 | ||
51900510 | 4831 | method_params = NULL_TREE; |
6c65299b RS |
4832 | if (TREE_CODE (args) == TREE_LIST) |
4833 | { | |
51900510 | 4834 | tree chain = args, prev = NULL_TREE; |
6c65299b RS |
4835 | |
4836 | /* We have a keyword selector--check for comma expressions. */ | |
4837 | while (chain) | |
4838 | { | |
4839 | tree element = TREE_VALUE (chain); | |
4840 | ||
4841 | /* We have a comma expression, must collapse... */ | |
4842 | if (TREE_CODE (element) == TREE_LIST) | |
4843 | { | |
4844 | if (prev) | |
4845 | TREE_CHAIN (prev) = element; | |
4846 | else | |
4847 | args = element; | |
4848 | } | |
4849 | prev = chain; | |
4850 | chain = TREE_CHAIN (chain); | |
4851 | } | |
4852 | method_params = args; | |
4853 | } | |
4854 | ||
4855 | /* Determine operation return type. */ | |
4856 | ||
59ce3fc8 | 4857 | if (IS_SUPER (rtype)) |
6c65299b RS |
4858 | { |
4859 | tree iface; | |
4860 | ||
4861 | if (CLASS_SUPER_NAME (implementation_template)) | |
4862 | { | |
51900510 RK |
4863 | iface |
4864 | = lookup_interface (CLASS_SUPER_NAME (implementation_template)); | |
e31c7eec | 4865 | |
6c65299b RS |
4866 | if (TREE_CODE (method_context) == INSTANCE_METHOD_DECL) |
4867 | method_prototype = lookup_instance_method_static (iface, sel_name); | |
4868 | else | |
4869 | method_prototype = lookup_class_method_static (iface, sel_name); | |
e31c7eec | 4870 | |
6c65299b RS |
4871 | if (iface && !method_prototype) |
4872 | warning ("`%s' does not respond to `%s'", | |
4873 | IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_template)), | |
4874 | IDENTIFIER_POINTER (sel_name)); | |
4875 | } | |
4876 | else | |
4877 | { | |
4878 | error ("no super class declared in interface for `%s'", | |
4879 | IDENTIFIER_POINTER (CLASS_NAME (implementation_template))); | |
4880 | return error_mark_node; | |
4881 | } | |
4882 | ||
4883 | } | |
4884 | else if (statically_allocated) | |
4885 | { | |
e31c7eec | 4886 | tree ctype = TREE_TYPE (rtype); |
6c65299b RS |
4887 | tree iface = lookup_interface (TYPE_NAME (rtype)); |
4888 | ||
e31c7eec TW |
4889 | if (iface) |
4890 | method_prototype = lookup_instance_method_static (iface, sel_name); | |
4891 | ||
e31c7eec TW |
4892 | if (! method_prototype && TYPE_PROTOCOL_LIST (ctype)) |
4893 | method_prototype | |
4894 | = lookup_method_in_protocol_list (TYPE_PROTOCOL_LIST (ctype), | |
4895 | sel_name, 0); | |
4896 | ||
4897 | if (!method_prototype) | |
6c65299b RS |
4898 | warning ("`%s' does not respond to `%s'", |
4899 | IDENTIFIER_POINTER (TYPE_NAME (rtype)), | |
4900 | IDENTIFIER_POINTER (sel_name)); | |
4901 | } | |
4902 | else if (statically_typed) | |
4903 | { | |
4904 | tree ctype = TREE_TYPE (rtype); | |
4905 | ||
51900510 RK |
4906 | /* `self' is now statically_typed. All methods should be visible |
4907 | within the context of the implementation. */ | |
6c65299b RS |
4908 | if (implementation_context |
4909 | && CLASS_NAME (implementation_context) == TYPE_NAME (ctype)) | |
4910 | { | |
51900510 RK |
4911 | method_prototype |
4912 | = lookup_instance_method_static (implementation_template, | |
4913 | sel_name); | |
6c65299b | 4914 | |
e31c7eec TW |
4915 | if (! method_prototype && TYPE_PROTOCOL_LIST (ctype)) |
4916 | method_prototype | |
4917 | = lookup_method_in_protocol_list (TYPE_PROTOCOL_LIST (ctype), | |
4918 | sel_name, 0); | |
4919 | ||
4920 | if (! method_prototype | |
4921 | && implementation_template != implementation_context) | |
0f41302f MS |
4922 | /* The method is not published in the interface. Check |
4923 | locally. */ | |
e31c7eec TW |
4924 | method_prototype |
4925 | = lookup_method (CLASS_NST_METHODS (implementation_context), | |
4926 | sel_name); | |
6c65299b RS |
4927 | } |
4928 | else | |
4929 | { | |
4930 | tree iface; | |
4931 | ||
e31c7eec | 4932 | if ((iface = lookup_interface (TYPE_NAME (ctype)))) |
6c65299b | 4933 | method_prototype = lookup_instance_method_static (iface, sel_name); |
e31c7eec TW |
4934 | |
4935 | if (! method_prototype) | |
4936 | { | |
4937 | tree protocol_list = TYPE_PROTOCOL_LIST (ctype); | |
4938 | if (protocol_list) | |
4939 | method_prototype | |
51900510 RK |
4940 | = lookup_method_in_protocol_list (protocol_list, |
4941 | sel_name, 0); | |
e31c7eec | 4942 | } |
6c65299b RS |
4943 | } |
4944 | ||
4945 | if (!method_prototype) | |
4946 | warning ("`%s' does not respond to `%s'", | |
4947 | IDENTIFIER_POINTER (TYPE_NAME (ctype)), | |
4948 | IDENTIFIER_POINTER (sel_name)); | |
4949 | } | |
4950 | else if (class_ident) | |
4951 | { | |
4952 | if (implementation_context | |
4953 | && CLASS_NAME (implementation_context) == class_ident) | |
4954 | { | |
4955 | method_prototype | |
4956 | = lookup_class_method_static (implementation_template, sel_name); | |
e31c7eec | 4957 | |
6c65299b RS |
4958 | if (!method_prototype |
4959 | && implementation_template != implementation_context) | |
0f41302f MS |
4960 | /* The method is not published in the interface. Check |
4961 | locally. */ | |
6c65299b RS |
4962 | method_prototype |
4963 | = lookup_method (CLASS_CLS_METHODS (implementation_context), | |
4964 | sel_name); | |
4965 | } | |
4966 | else | |
4967 | { | |
4968 | tree iface; | |
e31c7eec TW |
4969 | |
4970 | if ((iface = lookup_interface (class_ident))) | |
6c65299b RS |
4971 | method_prototype = lookup_class_method_static (iface, sel_name); |
4972 | } | |
e31c7eec | 4973 | |
6c65299b RS |
4974 | if (!method_prototype) |
4975 | { | |
4976 | warning ("cannot find class (factory) method."); | |
4977 | warning ("return type for `%s' defaults to id", | |
4978 | IDENTIFIER_POINTER (sel_name)); | |
4979 | } | |
4980 | } | |
59ce3fc8 | 4981 | else if (IS_PROTOCOL_QUALIFIED_ID (rtype)) |
e31c7eec TW |
4982 | { |
4983 | /* An anonymous object that has been qualified with a protocol. */ | |
4984 | ||
4985 | tree protocol_list = TYPE_PROTOCOL_LIST (rtype); | |
4986 | ||
4987 | method_prototype = lookup_method_in_protocol_list (protocol_list, | |
4988 | sel_name, 0); | |
4989 | ||
4990 | if (!method_prototype) | |
4991 | { | |
4992 | hash hsh; | |
4993 | ||
4994 | warning ("method `%s' not implemented by protocol.", | |
4995 | IDENTIFIER_POINTER (sel_name)); | |
4996 | ||
0f41302f | 4997 | /* Try and find the method signature in the global pools. */ |
e31c7eec TW |
4998 | |
4999 | if (!(hsh = hash_lookup (nst_method_hash_list, sel_name))) | |
5000 | hsh = hash_lookup (cls_method_hash_list, sel_name); | |
5001 | ||
5002 | if (!(method_prototype = check_duplicates (hsh))) | |
5003 | warning ("return type defaults to id"); | |
5004 | } | |
5005 | } | |
6c65299b RS |
5006 | else |
5007 | { | |
5008 | hash hsh; | |
5009 | ||
51900510 | 5010 | /* We think we have an instance...loophole: extern id Object; */ |
6c65299b RS |
5011 | hsh = hash_lookup (nst_method_hash_list, sel_name); |
5012 | if (!hsh) | |
51900510 | 5013 | /* For various loopholes, like sending messages to self in a |
0f41302f | 5014 | factory context. */ |
6c65299b RS |
5015 | hsh = hash_lookup (cls_method_hash_list, sel_name); |
5016 | ||
5017 | method_prototype = check_duplicates (hsh); | |
5018 | if (!method_prototype) | |
5019 | { | |
5020 | warning ("cannot find method."); | |
5021 | warning ("return type for `%s' defaults to id", | |
5022 | IDENTIFIER_POINTER (sel_name)); | |
5023 | } | |
5024 | } | |
5025 | ||
5026 | /* Save the selector name for printing error messages. */ | |
5027 | building_objc_message_expr = sel_name; | |
5028 | ||
5d0f30f7 KKT |
5029 | /* Build the parameters list for looking up the method. |
5030 | These are the object itself and the selector. */ | |
5031 | ||
5032 | if (flag_typed_selectors) | |
5033 | selector = build_typed_selector_reference (sel_name, method_prototype); | |
5034 | else | |
5035 | selector = build_selector_reference (sel_name); | |
5036 | ||
6c65299b RS |
5037 | retval = build_objc_method_call (super, method_prototype, |
5038 | receiver, self_object, | |
5039 | selector, method_params); | |
5040 | ||
5041 | building_objc_message_expr = 0; | |
5042 | ||
5043 | return retval; | |
5044 | } | |
5045 | \f | |
5046 | /* Build a tree expression to send OBJECT the operation SELECTOR, | |
5047 | looking up the method on object LOOKUP_OBJECT (often same as OBJECT), | |
5048 | assuming the method has prototype METHOD_PROTOTYPE. | |
5049 | (That is an INSTANCE_METHOD_DECL or CLASS_METHOD_DECL.) | |
5050 | Use METHOD_PARAMS as list of args to pass to the method. | |
5051 | If SUPER_FLAG is nonzero, we look up the superclass's method. */ | |
5052 | ||
5053 | static tree | |
5054 | build_objc_method_call (super_flag, method_prototype, lookup_object, object, | |
5055 | selector, method_params) | |
5056 | int super_flag; | |
5057 | tree method_prototype, lookup_object, object, selector, method_params; | |
5058 | { | |
e31c7eec TW |
5059 | tree sender = (super_flag ? umsg_super_decl : umsg_decl); |
5060 | tree rcv_p = (super_flag | |
5061 | ? build_pointer_type (xref_tag (RECORD_TYPE, | |
5062 | get_identifier (TAG_SUPER))) | |
5063 | : id_type); | |
6c65299b | 5064 | |
e31c7eec | 5065 | if (flag_next_runtime) |
6c65299b | 5066 | { |
e31c7eec TW |
5067 | if (! method_prototype) |
5068 | { | |
51900510 RK |
5069 | method_params = tree_cons (NULL_TREE, lookup_object, |
5070 | tree_cons (NULL_TREE, selector, | |
e31c7eec TW |
5071 | method_params)); |
5072 | assemble_external (sender); | |
5073 | return build_function_call (sender, method_params); | |
5074 | } | |
5075 | else | |
5076 | { | |
5077 | /* This is a real kludge, but it is used only for the Next. | |
5078 | Clobber the data type of SENDER temporarily to accept | |
5079 | all the arguments for this operation, and to return | |
5080 | whatever this operation returns. */ | |
51900510 | 5081 | tree arglist = NULL_TREE; |
e31c7eec TW |
5082 | tree retval; |
5083 | ||
5084 | /* Save the proper contents of SENDER's data type. */ | |
5085 | tree savarg = TYPE_ARG_TYPES (TREE_TYPE (sender)); | |
5086 | tree savret = TREE_TYPE (TREE_TYPE (sender)); | |
5087 | ||
5088 | /* Install this method's argument types. */ | |
5089 | arglist = get_arg_type_list (method_prototype, METHOD_REF, | |
5090 | super_flag); | |
5091 | TYPE_ARG_TYPES (TREE_TYPE (sender)) = arglist; | |
5092 | ||
5093 | /* Install this method's return type. */ | |
5094 | TREE_TYPE (TREE_TYPE (sender)) | |
5095 | = groktypename (TREE_TYPE (method_prototype)); | |
5096 | ||
5097 | /* Call SENDER with all the parameters. This will do type | |
5098 | checking using the arg types for this method. */ | |
51900510 RK |
5099 | method_params = tree_cons (NULL_TREE, lookup_object, |
5100 | tree_cons (NULL_TREE, selector, | |
e31c7eec TW |
5101 | method_params)); |
5102 | assemble_external (sender); | |
5103 | retval = build_function_call (sender, method_params); | |
5104 | ||
5105 | /* Restore SENDER's return/argument types. */ | |
5106 | TYPE_ARG_TYPES (TREE_TYPE (sender)) = savarg; | |
5107 | TREE_TYPE (TREE_TYPE (sender)) = savret; | |
5108 | return retval; | |
5109 | } | |
6c65299b RS |
5110 | } |
5111 | else | |
5112 | { | |
e31c7eec TW |
5113 | /* This is the portable way. |
5114 | First call the lookup function to get a pointer to the method, | |
5115 | then cast the pointer, then call it with the method arguments. */ | |
5116 | tree method; | |
5117 | ||
5118 | /* Avoid trouble since we may evaluate each of these twice. */ | |
5119 | object = save_expr (object); | |
5120 | selector = save_expr (selector); | |
5121 | ||
51900510 | 5122 | lookup_object = build_c_cast (rcv_p, lookup_object); |
e31c7eec | 5123 | |
f0052887 | 5124 | assemble_external (sender); |
e31c7eec TW |
5125 | method |
5126 | = build_function_call (sender, | |
51900510 RK |
5127 | tree_cons (NULL_TREE, lookup_object, |
5128 | tree_cons (NULL_TREE, selector, | |
5129 | NULL_TREE))); | |
e31c7eec TW |
5130 | |
5131 | /* If we have a method prototype, construct the data type this | |
5132 | method needs, and cast what we got from SENDER into a pointer | |
5133 | to that type. */ | |
5134 | if (method_prototype) | |
5135 | { | |
5136 | tree arglist = get_arg_type_list (method_prototype, METHOD_REF, | |
5137 | super_flag); | |
5138 | tree valtype = groktypename (TREE_TYPE (method_prototype)); | |
5139 | tree fake_function_type = build_function_type (valtype, arglist); | |
5140 | TREE_TYPE (method) = build_pointer_type (fake_function_type); | |
5141 | } | |
5142 | else | |
5143 | TREE_TYPE (method) | |
51900510 | 5144 | = build_pointer_type (build_function_type (ptr_type_node, NULL_TREE)); |
e31c7eec TW |
5145 | |
5146 | /* Pass the object to the method. */ | |
5147 | assemble_external (method); | |
5148 | return build_function_call (method, | |
51900510 RK |
5149 | tree_cons (NULL_TREE, object, |
5150 | tree_cons (NULL_TREE, selector, | |
e31c7eec | 5151 | method_params))); |
6c65299b | 5152 | } |
e31c7eec TW |
5153 | } |
5154 | \f | |
5155 | static void | |
5156 | build_protocol_reference (p) | |
5157 | tree p; | |
5158 | { | |
5159 | tree decl, ident, ptype; | |
e31c7eec | 5160 | |
51900510 RK |
5161 | push_obstacks_nochange (); |
5162 | end_temporary_allocation (); | |
e31c7eec TW |
5163 | |
5164 | /* extern struct objc_protocol _OBJC_PROTOCOL_<mumble>; */ | |
5165 | ||
5166 | ident = synth_id_with_class_suffix ("_OBJC_PROTOCOL", p); | |
5167 | ptype | |
51900510 | 5168 | = groktypename (build_tree_list (build_tree_list (NULL_TREE, |
e31c7eec | 5169 | objc_protocol_template), |
51900510 | 5170 | NULL_TREE)); |
e31c7eec TW |
5171 | |
5172 | if (IDENTIFIER_GLOBAL_VALUE (ident)) | |
5173 | decl = IDENTIFIER_GLOBAL_VALUE (ident); /* Set by pushdecl. */ | |
6c65299b RS |
5174 | else |
5175 | { | |
e31c7eec TW |
5176 | decl = build_decl (VAR_DECL, ident, ptype); |
5177 | DECL_EXTERNAL (decl) = 1; | |
5178 | TREE_PUBLIC (decl) = 1; | |
5179 | TREE_USED (decl) = 1; | |
51900510 | 5180 | DECL_ARTIFICIAL (decl) = 1; |
e31c7eec | 5181 | |
e31c7eec | 5182 | make_decl_rtl (decl, 0, 1); |
e31c7eec TW |
5183 | pushdecl_top_level (decl); |
5184 | } | |
e31c7eec TW |
5185 | |
5186 | PROTOCOL_FORWARD_DECL (p) = decl; | |
51900510 | 5187 | pop_obstacks (); |
e31c7eec TW |
5188 | } |
5189 | ||
5190 | tree | |
5191 | build_protocol_expr (protoname) | |
5192 | tree protoname; | |
5193 | { | |
5194 | tree expr; | |
5195 | tree p; | |
5196 | ||
5197 | if (!doing_objc_thang) | |
5198 | objc_fatal (); | |
5199 | ||
5200 | p = lookup_protocol (protoname); | |
5201 | ||
5202 | if (!p) | |
5203 | { | |
5204 | error ("Cannot find protocol declaration for `%s'", | |
5205 | IDENTIFIER_POINTER (protoname)); | |
5206 | return error_mark_node; | |
6c65299b | 5207 | } |
e31c7eec TW |
5208 | |
5209 | if (!PROTOCOL_FORWARD_DECL (p)) | |
5210 | build_protocol_reference (p); | |
5211 | ||
5212 | expr = build_unary_op (ADDR_EXPR, PROTOCOL_FORWARD_DECL (p), 0); | |
5213 | ||
5214 | TREE_TYPE (expr) = protocol_type; | |
5215 | ||
5216 | return expr; | |
6c65299b | 5217 | } |
e31c7eec | 5218 | |
6c65299b RS |
5219 | tree |
5220 | build_selector_expr (selnamelist) | |
5221 | tree selnamelist; | |
5222 | { | |
5223 | tree selname; | |
6c65299b RS |
5224 | |
5225 | if (!doing_objc_thang) | |
e31c7eec | 5226 | objc_fatal (); |
6c65299b | 5227 | |
0f41302f | 5228 | /* Obtain the full selector name. */ |
6c65299b | 5229 | if (TREE_CODE (selnamelist) == IDENTIFIER_NODE) |
0f41302f | 5230 | /* A unary selector. */ |
6c65299b RS |
5231 | selname = selnamelist; |
5232 | else if (TREE_CODE (selnamelist) == TREE_LIST) | |
5233 | selname = build_keyword_selector (selnamelist); | |
5234 | ||
5d0f30f7 KKT |
5235 | if (flag_typed_selectors) |
5236 | return build_typed_selector_reference (selname, 0); | |
5237 | else | |
5238 | return build_selector_reference (selname); | |
6c65299b RS |
5239 | } |
5240 | ||
5241 | tree | |
5242 | build_encode_expr (type) | |
5243 | tree type; | |
5244 | { | |
9dee6758 RS |
5245 | tree result; |
5246 | char *string; | |
5247 | ||
6c65299b | 5248 | if (!doing_objc_thang) |
e31c7eec | 5249 | objc_fatal (); |
6c65299b | 5250 | |
e31c7eec TW |
5251 | encode_type (type, obstack_object_size (&util_obstack), |
5252 | OBJC_ENCODE_INLINE_DEFS); | |
b53241dc | 5253 | obstack_1grow (&util_obstack, 0); /* null terminate string */ |
9dee6758 | 5254 | string = obstack_finish (&util_obstack); |
6c65299b | 5255 | |
0f41302f | 5256 | /* Synthesize a string that represents the encoded struct/union. */ |
9dee6758 RS |
5257 | result = my_build_string (strlen (string) + 1, string); |
5258 | obstack_free (&util_obstack, util_firstobj); | |
5259 | return result; | |
6c65299b RS |
5260 | } |
5261 | ||
5262 | tree | |
5263 | build_ivar_reference (id) | |
5264 | tree id; | |
5265 | { | |
5266 | if (TREE_CODE (method_context) == CLASS_METHOD_DECL) | |
a878dab7 TW |
5267 | { |
5268 | /* Historically, a class method that produced objects (factory | |
5269 | method) would assign `self' to the instance that it | |
5270 | allocated. This would effectively turn the class method into | |
5271 | an instance method. Following this assignment, the instance | |
5272 | variables could be accessed. That practice, while safe, | |
5273 | violates the simple rule that a class method should not refer | |
5274 | to an instance variable. It's better to catch the cases | |
5275 | where this is done unknowingly than to support the above | |
5276 | paradigm. */ | |
5277 | warning ("instance variable `%s' accessed in class method", | |
5278 | IDENTIFIER_POINTER (id)); | |
5279 | TREE_TYPE (self_decl) = instance_type; /* cast */ | |
5280 | } | |
6c65299b RS |
5281 | |
5282 | return build_component_ref (build_indirect_ref (self_decl, "->"), id); | |
5283 | } | |
5284 | \f | |
5285 | #define HASH_ALLOC_LIST_SIZE 170 | |
5286 | #define ATTR_ALLOC_LIST_SIZE 170 | |
5287 | #define SIZEHASHTABLE 257 | |
963342ad RK |
5288 | |
5289 | /* make positive */ | |
5290 | #define HASHFUNCTION(key) ((HOST_WIDE_INT) key & 0x7fffffff) | |
6c65299b RS |
5291 | |
5292 | static void | |
5293 | hash_init () | |
5294 | { | |
5295 | nst_method_hash_list = (hash *)xmalloc (SIZEHASHTABLE * sizeof (hash)); | |
5296 | cls_method_hash_list = (hash *)xmalloc (SIZEHASHTABLE * sizeof (hash)); | |
5297 | ||
5298 | if (!nst_method_hash_list || !cls_method_hash_list) | |
5299 | perror ("unable to allocate space in objc-tree.c"); | |
5300 | else | |
5301 | { | |
5302 | int i; | |
5303 | ||
5304 | for (i = 0; i < SIZEHASHTABLE; i++) | |
5305 | { | |
5306 | nst_method_hash_list[i] = 0; | |
5307 | cls_method_hash_list[i] = 0; | |
5308 | } | |
5309 | } | |
5310 | } | |
5311 | ||
5312 | static void | |
5313 | hash_enter (hashlist, method) | |
5314 | hash *hashlist; | |
5315 | tree method; | |
5316 | { | |
5317 | static hash hash_alloc_list = 0; | |
5318 | static int hash_alloc_index = 0; | |
5319 | hash obj; | |
5320 | int slot = HASHFUNCTION (METHOD_SEL_NAME (method)) % SIZEHASHTABLE; | |
5321 | ||
e31c7eec | 5322 | if (! hash_alloc_list || hash_alloc_index >= HASH_ALLOC_LIST_SIZE) |
6c65299b RS |
5323 | { |
5324 | hash_alloc_index = 0; | |
e31c7eec TW |
5325 | hash_alloc_list = (hash) xmalloc (sizeof (struct hashed_entry) |
5326 | * HASH_ALLOC_LIST_SIZE); | |
5327 | if (! hash_alloc_list) | |
6c65299b RS |
5328 | perror ("unable to allocate in objc-tree.c"); |
5329 | } | |
5330 | obj = &hash_alloc_list[hash_alloc_index++]; | |
5331 | obj->list = 0; | |
5332 | obj->next = hashlist[slot]; | |
5333 | obj->key = method; | |
5334 | ||
5335 | hashlist[slot] = obj; /* append to front */ | |
5336 | } | |
5337 | ||
5338 | static hash | |
5339 | hash_lookup (hashlist, sel_name) | |
5340 | hash *hashlist; | |
5341 | tree sel_name; | |
5342 | { | |
5343 | hash target; | |
5344 | ||
5345 | target = hashlist[HASHFUNCTION (sel_name) % SIZEHASHTABLE]; | |
5346 | ||
5347 | while (target) | |
5348 | { | |
5349 | if (sel_name == METHOD_SEL_NAME (target->key)) | |
5350 | return target; | |
5351 | ||
5352 | target = target->next; | |
5353 | } | |
5354 | return 0; | |
5355 | } | |
5356 | ||
5357 | static void | |
5358 | hash_add_attr (entry, value) | |
5359 | hash entry; | |
5360 | tree value; | |
5361 | { | |
5362 | static attr attr_alloc_list = 0; | |
5363 | static int attr_alloc_index = 0; | |
5364 | attr obj; | |
5365 | ||
e31c7eec | 5366 | if (! attr_alloc_list || attr_alloc_index >= ATTR_ALLOC_LIST_SIZE) |
6c65299b RS |
5367 | { |
5368 | attr_alloc_index = 0; | |
e31c7eec TW |
5369 | attr_alloc_list = (attr) xmalloc (sizeof (struct hashed_attribute) |
5370 | * ATTR_ALLOC_LIST_SIZE); | |
5371 | if (! attr_alloc_list) | |
6c65299b RS |
5372 | perror ("unable to allocate in objc-tree.c"); |
5373 | } | |
5374 | obj = &attr_alloc_list[attr_alloc_index++]; | |
5375 | obj->next = entry->list; | |
5376 | obj->value = value; | |
5377 | ||
5378 | entry->list = obj; /* append to front */ | |
5379 | } | |
5380 | \f | |
5381 | static tree | |
5382 | lookup_method (mchain, method) | |
5383 | tree mchain; | |
5384 | tree method; | |
5385 | { | |
5386 | tree key; | |
5387 | ||
5388 | if (TREE_CODE (method) == IDENTIFIER_NODE) | |
5389 | key = method; | |
5390 | else | |
5391 | key = METHOD_SEL_NAME (method); | |
5392 | ||
5393 | while (mchain) | |
5394 | { | |
5395 | if (METHOD_SEL_NAME (mchain) == key) | |
5396 | return mchain; | |
5397 | mchain = TREE_CHAIN (mchain); | |
5398 | } | |
51900510 | 5399 | return NULL_TREE; |
6c65299b RS |
5400 | } |
5401 | ||
5402 | static tree | |
5403 | lookup_instance_method_static (interface, ident) | |
5404 | tree interface; | |
5405 | tree ident; | |
5406 | { | |
5407 | tree inter = interface; | |
5408 | tree chain = CLASS_NST_METHODS (inter); | |
51900510 | 5409 | tree meth = NULL_TREE; |
6c65299b RS |
5410 | |
5411 | do | |
5412 | { | |
e31c7eec | 5413 | if ((meth = lookup_method (chain, ident))) |
6c65299b RS |
5414 | return meth; |
5415 | ||
5416 | if (CLASS_CATEGORY_LIST (inter)) | |
5417 | { | |
5418 | tree category = CLASS_CATEGORY_LIST (inter); | |
5419 | chain = CLASS_NST_METHODS (category); | |
e31c7eec TW |
5420 | |
5421 | do | |
6c65299b | 5422 | { |
e31c7eec | 5423 | if ((meth = lookup_method (chain, ident))) |
6c65299b | 5424 | return meth; |
e31c7eec | 5425 | |
e31c7eec TW |
5426 | /* Check for instance methods in protocols in categories. */ |
5427 | if (CLASS_PROTOCOL_LIST (category)) | |
5428 | { | |
5429 | if ((meth = (lookup_method_in_protocol_list | |
5430 | (CLASS_PROTOCOL_LIST (category), ident, 0)))) | |
5431 | return meth; | |
5432 | } | |
5433 | ||
5434 | if ((category = CLASS_CATEGORY_LIST (category))) | |
6c65299b RS |
5435 | chain = CLASS_NST_METHODS (category); |
5436 | } | |
5437 | while (category); | |
5438 | } | |
5439 | ||
e31c7eec TW |
5440 | if (CLASS_PROTOCOL_LIST (inter)) |
5441 | { | |
5442 | if ((meth = (lookup_method_in_protocol_list | |
5443 | (CLASS_PROTOCOL_LIST (inter), ident, 0)))) | |
5444 | return meth; | |
5445 | } | |
5446 | ||
5447 | if ((inter = lookup_interface (CLASS_SUPER_NAME (inter)))) | |
6c65299b RS |
5448 | chain = CLASS_NST_METHODS (inter); |
5449 | } | |
5450 | while (inter); | |
5451 | ||
5452 | return meth; | |
5453 | } | |
5454 | ||
5455 | static tree | |
5456 | lookup_class_method_static (interface, ident) | |
5457 | tree interface; | |
5458 | tree ident; | |
5459 | { | |
5460 | tree inter = interface; | |
5461 | tree chain = CLASS_CLS_METHODS (inter); | |
51900510 RK |
5462 | tree meth = NULL_TREE; |
5463 | tree root_inter = NULL_TREE; | |
6c65299b RS |
5464 | |
5465 | do | |
5466 | { | |
e31c7eec | 5467 | if ((meth = lookup_method (chain, ident))) |
6c65299b RS |
5468 | return meth; |
5469 | ||
5470 | if (CLASS_CATEGORY_LIST (inter)) | |
5471 | { | |
5472 | tree category = CLASS_CATEGORY_LIST (inter); | |
5473 | chain = CLASS_CLS_METHODS (category); | |
e31c7eec TW |
5474 | |
5475 | do | |
6c65299b | 5476 | { |
e31c7eec | 5477 | if ((meth = lookup_method (chain, ident))) |
6c65299b | 5478 | return meth; |
e31c7eec | 5479 | |
e31c7eec TW |
5480 | /* Check for class methods in protocols in categories. */ |
5481 | if (CLASS_PROTOCOL_LIST (category)) | |
5482 | { | |
5483 | if ((meth = (lookup_method_in_protocol_list | |
5484 | (CLASS_PROTOCOL_LIST (category), ident, 1)))) | |
5485 | return meth; | |
5486 | } | |
5487 | ||
5488 | if ((category = CLASS_CATEGORY_LIST (category))) | |
6c65299b RS |
5489 | chain = CLASS_CLS_METHODS (category); |
5490 | } | |
5491 | while (category); | |
5492 | } | |
5493 | ||
e31c7eec TW |
5494 | /* Check for class methods in protocols. */ |
5495 | if (CLASS_PROTOCOL_LIST (inter)) | |
5496 | { | |
5497 | if ((meth = (lookup_method_in_protocol_list | |
5498 | (CLASS_PROTOCOL_LIST (inter), ident, 1)))) | |
5499 | return meth; | |
5500 | } | |
5501 | ||
5502 | root_inter = inter; | |
5503 | if ((inter = lookup_interface (CLASS_SUPER_NAME (inter)))) | |
6c65299b RS |
5504 | chain = CLASS_CLS_METHODS (inter); |
5505 | } | |
5506 | while (inter); | |
5507 | ||
e31c7eec TW |
5508 | /* Simulate wrap around. */ |
5509 | return lookup_instance_method_static (root_inter, ident); | |
6c65299b RS |
5510 | } |
5511 | ||
5512 | tree | |
5513 | add_class_method (class, method) | |
5514 | tree class; | |
5515 | tree method; | |
5516 | { | |
5517 | tree mth; | |
5518 | hash hsh; | |
5519 | ||
e31c7eec TW |
5520 | /* We will have allocated the method parameter declarations on the |
5521 | maybepermanent_obstack. Need to make sure they stick around! */ | |
5522 | preserve_data (); | |
5523 | ||
6c65299b RS |
5524 | if (!(mth = lookup_method (CLASS_CLS_METHODS (class), method))) |
5525 | { | |
5526 | /* put method on list in reverse order */ | |
5527 | TREE_CHAIN (method) = CLASS_CLS_METHODS (class); | |
5528 | CLASS_CLS_METHODS (class) = method; | |
5529 | } | |
5530 | else | |
5531 | { | |
e31c7eec | 5532 | if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE) |
6c65299b RS |
5533 | error ("duplicate definition of class method `%s'.", |
5534 | IDENTIFIER_POINTER (METHOD_SEL_NAME (mth))); | |
5535 | else | |
5536 | { | |
0f41302f | 5537 | /* Check types; if different, complain. */ |
6c65299b RS |
5538 | if (!comp_proto_with_proto (method, mth)) |
5539 | error ("duplicate declaration of class method `%s'.", | |
5540 | IDENTIFIER_POINTER (METHOD_SEL_NAME (mth))); | |
5541 | } | |
5542 | } | |
5543 | ||
5544 | if (!(hsh = hash_lookup (cls_method_hash_list, METHOD_SEL_NAME (method)))) | |
5545 | { | |
0f41302f | 5546 | /* Install on a global chain. */ |
6c65299b RS |
5547 | hash_enter (cls_method_hash_list, method); |
5548 | } | |
5549 | else | |
5550 | { | |
0f41302f | 5551 | /* Check types; if different, add to a list. */ |
6c65299b RS |
5552 | if (!comp_proto_with_proto (method, hsh->key)) |
5553 | hash_add_attr (hsh, method); | |
5554 | } | |
5555 | return method; | |
5556 | } | |
5557 | \f | |
5558 | tree | |
5559 | add_instance_method (class, method) | |
5560 | tree class; | |
5561 | tree method; | |
5562 | { | |
5563 | tree mth; | |
5564 | hash hsh; | |
5565 | ||
e31c7eec TW |
5566 | /* We will have allocated the method parameter declarations on the |
5567 | maybepermanent_obstack. Need to make sure they stick around! */ | |
5568 | preserve_data (); | |
5569 | ||
6c65299b RS |
5570 | if (!(mth = lookup_method (CLASS_NST_METHODS (class), method))) |
5571 | { | |
51900510 | 5572 | /* Put method on list in reverse order. */ |
6c65299b RS |
5573 | TREE_CHAIN (method) = CLASS_NST_METHODS (class); |
5574 | CLASS_NST_METHODS (class) = method; | |
5575 | } | |
5576 | else | |
5577 | { | |
e31c7eec | 5578 | if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE) |
6c65299b RS |
5579 | error ("duplicate definition of instance method `%s'.", |
5580 | IDENTIFIER_POINTER (METHOD_SEL_NAME (mth))); | |
5581 | else | |
5582 | { | |
0f41302f | 5583 | /* Check types; if different, complain. */ |
6c65299b RS |
5584 | if (!comp_proto_with_proto (method, mth)) |
5585 | error ("duplicate declaration of instance method `%s'.", | |
5586 | IDENTIFIER_POINTER (METHOD_SEL_NAME (mth))); | |
5587 | } | |
5588 | } | |
5589 | ||
5590 | if (!(hsh = hash_lookup (nst_method_hash_list, METHOD_SEL_NAME (method)))) | |
5591 | { | |
0f41302f | 5592 | /* Install on a global chain. */ |
6c65299b RS |
5593 | hash_enter (nst_method_hash_list, method); |
5594 | } | |
5595 | else | |
5596 | { | |
51900510 | 5597 | /* Check types; if different, add to a list. */ |
6c65299b RS |
5598 | if (!comp_proto_with_proto (method, hsh->key)) |
5599 | hash_add_attr (hsh, method); | |
5600 | } | |
5601 | return method; | |
5602 | } | |
5603 | ||
5604 | static tree | |
5605 | add_class (class) | |
5606 | tree class; | |
5607 | { | |
0f41302f | 5608 | /* Put interfaces on list in reverse order. */ |
6c65299b RS |
5609 | TREE_CHAIN (class) = interface_chain; |
5610 | interface_chain = class; | |
5611 | return interface_chain; | |
5612 | } | |
5613 | ||
5614 | static void | |
5615 | add_category (class, category) | |
5616 | tree class; | |
5617 | tree category; | |
5618 | { | |
0f41302f | 5619 | /* Put categories on list in reverse order. */ |
e31c7eec | 5620 | tree cat = CLASS_CATEGORY_LIST (class); |
51900510 | 5621 | |
e31c7eec TW |
5622 | while (cat) |
5623 | { | |
5624 | if (CLASS_SUPER_NAME (cat) == CLASS_SUPER_NAME (category)) | |
5625 | warning ("duplicate interface declaration for category `%s(%s)'", | |
5626 | IDENTIFIER_POINTER (CLASS_NAME (class)), | |
5627 | IDENTIFIER_POINTER (CLASS_SUPER_NAME (category))); | |
5628 | cat = CLASS_CATEGORY_LIST (cat); | |
5629 | } | |
5630 | ||
6c65299b RS |
5631 | CLASS_CATEGORY_LIST (category) = CLASS_CATEGORY_LIST (class); |
5632 | CLASS_CATEGORY_LIST (class) = category; | |
5633 | } | |
5634 | ||
e31c7eec TW |
5635 | /* Called after parsing each instance variable declaration. Necessary to |
5636 | preserve typedefs and implement public/private... | |
5637 | ||
5638 | PUBLIC is 1 for public, 0 for protected, and 2 for private. */ | |
5639 | ||
6c65299b RS |
5640 | tree |
5641 | add_instance_variable (class, public, declarator, declspecs, width) | |
5642 | tree class; | |
5643 | int public; | |
5644 | tree declarator; | |
5645 | tree declspecs; | |
5646 | tree width; | |
5647 | { | |
5648 | tree field_decl, raw_decl; | |
5649 | ||
51900510 | 5650 | raw_decl = build_tree_list (declspecs, declarator); |
6c65299b RS |
5651 | |
5652 | if (CLASS_RAW_IVARS (class)) | |
5653 | chainon (CLASS_RAW_IVARS (class), raw_decl); | |
5654 | else | |
5655 | CLASS_RAW_IVARS (class) = raw_decl; | |
5656 | ||
5657 | field_decl = grokfield (input_filename, lineno, | |
5658 | declarator, declspecs, width); | |
5659 | ||
0f41302f | 5660 | /* Overload the public attribute, it is not used for FIELD_DECLs. */ |
e31c7eec TW |
5661 | switch (public) |
5662 | { | |
5663 | case 0: | |
5664 | TREE_PUBLIC (field_decl) = 0; | |
5665 | TREE_PRIVATE (field_decl) = 0; | |
5666 | TREE_PROTECTED (field_decl) = 1; | |
5667 | break; | |
5668 | ||
5669 | case 1: | |
5670 | TREE_PUBLIC (field_decl) = 1; | |
5671 | TREE_PRIVATE (field_decl) = 0; | |
5672 | TREE_PROTECTED (field_decl) = 0; | |
5673 | break; | |
5674 | ||
5675 | case 2: | |
5676 | TREE_PUBLIC (field_decl) = 0; | |
5677 | TREE_PRIVATE (field_decl) = 1; | |
5678 | TREE_PROTECTED (field_decl) = 0; | |
5679 | break; | |
5680 | ||
5681 | } | |
6c65299b RS |
5682 | |
5683 | if (CLASS_IVARS (class)) | |
5684 | chainon (CLASS_IVARS (class), field_decl); | |
5685 | else | |
5686 | CLASS_IVARS (class) = field_decl; | |
5687 | ||
5688 | return class; | |
5689 | } | |
5690 | \f | |
5691 | tree | |
5692 | is_ivar (decl_chain, ident) | |
5693 | tree decl_chain; | |
5694 | tree ident; | |
5695 | { | |
5696 | for ( ; decl_chain; decl_chain = TREE_CHAIN (decl_chain)) | |
5697 | if (DECL_NAME (decl_chain) == ident) | |
5698 | return decl_chain; | |
5699 | return NULL_TREE; | |
5700 | } | |
5701 | ||
e31c7eec TW |
5702 | /* True if the ivar is private and we are not in its implementation. */ |
5703 | ||
5704 | int | |
5705 | is_private (decl) | |
5706 | tree decl; | |
5707 | { | |
5708 | if (TREE_PRIVATE (decl) | |
5709 | && ! is_ivar (CLASS_IVARS (implementation_template), DECL_NAME (decl))) | |
5710 | { | |
5711 | error ("instance variable `%s' is declared private", | |
5712 | IDENTIFIER_POINTER (DECL_NAME (decl))); | |
5713 | return 1; | |
5714 | } | |
5715 | else | |
5716 | return 0; | |
5717 | } | |
5718 | ||
51900510 | 5719 | /* We have an instance variable reference;, check to see if it is public. */ |
6c65299b RS |
5720 | |
5721 | int | |
5722 | is_public (expr, identifier) | |
5723 | tree expr; | |
5724 | tree identifier; | |
5725 | { | |
5726 | tree basetype = TREE_TYPE (expr); | |
5727 | enum tree_code code = TREE_CODE (basetype); | |
5728 | tree decl; | |
5729 | ||
5730 | if (code == RECORD_TYPE) | |
5731 | { | |
5732 | if (TREE_STATIC_TEMPLATE (basetype)) | |
5733 | { | |
e31c7eec | 5734 | if (!lookup_interface (TYPE_NAME (basetype))) |
6c65299b | 5735 | { |
e31c7eec TW |
5736 | error ("Cannot find interface declaration for `%s'", |
5737 | IDENTIFIER_POINTER (TYPE_NAME (basetype))); | |
5738 | return 0; | |
5739 | } | |
6c65299b | 5740 | |
e31c7eec TW |
5741 | if ((decl = is_ivar (TYPE_FIELDS (basetype), identifier))) |
5742 | { | |
6c65299b RS |
5743 | if (TREE_PUBLIC (decl)) |
5744 | return 1; | |
5745 | ||
51900510 | 5746 | /* Important difference between the Stepstone translator: |
e31c7eec TW |
5747 | all instance variables should be public within the context |
5748 | of the implementation. */ | |
5749 | if (implementation_context | |
5750 | && (((TREE_CODE (implementation_context) | |
5751 | == CLASS_IMPLEMENTATION_TYPE) | |
5752 | || (TREE_CODE (implementation_context) | |
5753 | == CATEGORY_IMPLEMENTATION_TYPE)) | |
5754 | && (CLASS_NAME (implementation_context) | |
5755 | == TYPE_NAME (basetype)))) | |
5756 | return ! is_private (decl); | |
5757 | ||
5758 | error ("instance variable `%s' is declared %s", | |
5759 | IDENTIFIER_POINTER (identifier), | |
5760 | TREE_PRIVATE (decl) ? "private" : "protected"); | |
6c65299b RS |
5761 | return 0; |
5762 | } | |
5763 | } | |
51900510 | 5764 | |
6c65299b RS |
5765 | else if (implementation_context && (basetype == objc_object_reference)) |
5766 | { | |
e31c7eec TW |
5767 | TREE_TYPE (expr) = uprivate_record; |
5768 | warning ("static access to object of type `id'"); | |
6c65299b RS |
5769 | } |
5770 | } | |
51900510 | 5771 | |
6c65299b RS |
5772 | return 1; |
5773 | } | |
5774 | ||
0f41302f | 5775 | /* Implement @defs (<classname>) within struct bodies. */ |
6c65299b RS |
5776 | |
5777 | tree | |
5778 | get_class_ivars (interface) | |
5779 | tree interface; | |
5780 | { | |
5781 | if (!doing_objc_thang) | |
e31c7eec | 5782 | objc_fatal (); |
6c65299b | 5783 | |
e31c7eec | 5784 | return build_ivar_chain (interface, 1); |
6c65299b RS |
5785 | } |
5786 | \f | |
0f41302f | 5787 | /* Make sure all entries in CHAIN are also in LIST. */ |
6c65299b | 5788 | |
e31c7eec | 5789 | static int |
6c65299b RS |
5790 | check_methods (chain, list, mtype) |
5791 | tree chain; | |
5792 | tree list; | |
5793 | int mtype; | |
5794 | { | |
5795 | int first = 1; | |
5796 | ||
5797 | while (chain) | |
5798 | { | |
5799 | if (!lookup_method (list, chain)) | |
5800 | { | |
5801 | if (first) | |
5802 | { | |
51900510 RK |
5803 | if (TREE_CODE (implementation_context) |
5804 | == CLASS_IMPLEMENTATION_TYPE) | |
6c65299b RS |
5805 | warning ("incomplete implementation of class `%s'", |
5806 | IDENTIFIER_POINTER (CLASS_NAME (implementation_context))); | |
51900510 RK |
5807 | else if (TREE_CODE (implementation_context) |
5808 | == CATEGORY_IMPLEMENTATION_TYPE) | |
6c65299b RS |
5809 | warning ("incomplete implementation of category `%s'", |
5810 | IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_context))); | |
5811 | first = 0; | |
5812 | } | |
51900510 | 5813 | |
6c65299b RS |
5814 | warning ("method definition for `%c%s' not found", |
5815 | mtype, IDENTIFIER_POINTER (METHOD_SEL_NAME (chain))); | |
5816 | } | |
51900510 | 5817 | |
6c65299b RS |
5818 | chain = TREE_CHAIN (chain); |
5819 | } | |
51900510 | 5820 | |
e31c7eec TW |
5821 | return first; |
5822 | } | |
5823 | ||
5824 | static int | |
5825 | conforms_to_protocol (class, protocol) | |
51900510 RK |
5826 | tree class; |
5827 | tree protocol; | |
e31c7eec TW |
5828 | { |
5829 | while (protocol) | |
5830 | { | |
5831 | tree p = CLASS_PROTOCOL_LIST (class); | |
51900510 | 5832 | |
e31c7eec TW |
5833 | while (p && TREE_VALUE (p) != TREE_VALUE (protocol)) |
5834 | p = TREE_CHAIN (p); | |
51900510 | 5835 | |
e31c7eec TW |
5836 | if (!p) |
5837 | { | |
5838 | tree super = (CLASS_SUPER_NAME (class) | |
5839 | ? lookup_interface (CLASS_SUPER_NAME (class)) | |
5840 | : NULL_TREE); | |
5841 | int tmp = super ? conforms_to_protocol (super, protocol) : 0; | |
5842 | if (!tmp) | |
5843 | return 0; | |
5844 | } | |
51900510 | 5845 | |
e31c7eec TW |
5846 | protocol = TREE_CHAIN (protocol); |
5847 | } | |
51900510 | 5848 | |
e31c7eec TW |
5849 | return 1; |
5850 | } | |
5851 | ||
143dc646 | 5852 | /* Make sure all methods in CHAIN are accessible as MTYPE methods in |
0f41302f | 5853 | CONTEXT. This is one of two mechanisms to check protocol integrity. */ |
143dc646 KKT |
5854 | |
5855 | static int | |
5856 | check_methods_accessible (chain, context, mtype) | |
5857 | tree chain; | |
51900510 | 5858 | tree context; |
143dc646 KKT |
5859 | int mtype; |
5860 | { | |
5861 | int first = 1; | |
5862 | tree list; | |
415f766a | 5863 | tree base_context = context; |
143dc646 KKT |
5864 | |
5865 | while (chain) | |
5866 | { | |
415f766a | 5867 | context = base_context; |
143dc646 KKT |
5868 | while (context) |
5869 | { | |
5870 | if (mtype == '+') | |
5871 | list = CLASS_CLS_METHODS (context); | |
5872 | else | |
5873 | list = CLASS_NST_METHODS (context); | |
5874 | ||
5875 | if (lookup_method (list, chain)) | |
5876 | break; | |
5877 | ||
266dd517 RS |
5878 | else if (TREE_CODE (context) == CLASS_IMPLEMENTATION_TYPE |
5879 | || TREE_CODE (context) == CLASS_INTERFACE_TYPE) | |
143dc646 KKT |
5880 | context = (CLASS_SUPER_NAME (context) |
5881 | ? lookup_interface (CLASS_SUPER_NAME (context)) | |
5882 | : NULL_TREE); | |
5883 | ||
266dd517 RS |
5884 | else if (TREE_CODE (context) == CATEGORY_IMPLEMENTATION_TYPE |
5885 | || TREE_CODE (context) == CATEGORY_INTERFACE_TYPE) | |
143dc646 KKT |
5886 | context = (CLASS_NAME (context) |
5887 | ? lookup_interface (CLASS_NAME (context)) | |
5888 | : NULL_TREE); | |
5889 | else | |
5890 | abort (); | |
5891 | } | |
5892 | ||
5893 | if (context == NULL_TREE) | |
5894 | { | |
5895 | if (first) | |
5896 | { | |
5897 | if (TREE_CODE (implementation_context) | |
5898 | == CLASS_IMPLEMENTATION_TYPE) | |
5899 | warning ("incomplete implementation of class `%s'", | |
5900 | IDENTIFIER_POINTER | |
5901 | (CLASS_NAME (implementation_context))); | |
5902 | else if (TREE_CODE (implementation_context) | |
5903 | == CATEGORY_IMPLEMENTATION_TYPE) | |
5904 | warning ("incomplete implementation of category `%s'", | |
5905 | IDENTIFIER_POINTER | |
5906 | (CLASS_SUPER_NAME (implementation_context))); | |
5907 | first = 0; | |
5908 | } | |
5909 | warning ("method definition for `%c%s' not found", | |
5910 | mtype, IDENTIFIER_POINTER (METHOD_SEL_NAME (chain))); | |
5911 | } | |
5912 | ||
0f41302f | 5913 | chain = TREE_CHAIN (chain); /* next method... */ |
143dc646 KKT |
5914 | } |
5915 | return first; | |
5916 | } | |
5917 | ||
e31c7eec TW |
5918 | static void |
5919 | check_protocols (proto_list, type, name) | |
5920 | tree proto_list; | |
5921 | char *type; | |
5922 | char *name; | |
5923 | { | |
5924 | for ( ; proto_list; proto_list = TREE_CHAIN (proto_list)) | |
5925 | { | |
5926 | tree p = TREE_VALUE (proto_list); | |
5927 | ||
5928 | if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) | |
5929 | { | |
5930 | int f1, f2; | |
143dc646 | 5931 | |
0f41302f | 5932 | /* Ensure that all protocols have bodies. */ |
143dc646 KKT |
5933 | if (flag_warn_protocol) { |
5934 | f1 = check_methods (PROTOCOL_CLS_METHODS (p), | |
5935 | CLASS_CLS_METHODS (implementation_context), | |
5936 | '+'); | |
5937 | f2 = check_methods (PROTOCOL_NST_METHODS (p), | |
5938 | CLASS_NST_METHODS (implementation_context), | |
5939 | '-'); | |
5940 | } else { | |
5941 | f1 = check_methods_accessible (PROTOCOL_CLS_METHODS (p), | |
5942 | implementation_context, | |
5943 | '+'); | |
5944 | f2 = check_methods_accessible (PROTOCOL_NST_METHODS (p), | |
5945 | implementation_context, | |
5946 | '-'); | |
5947 | } | |
e31c7eec TW |
5948 | |
5949 | if (!f1 || !f2) | |
5950 | warning ("%s `%s' does not fully implement the `%s' protocol", | |
5951 | type, name, IDENTIFIER_POINTER (PROTOCOL_NAME (p))); | |
5952 | ||
5953 | } | |
5954 | else | |
51900510 | 5955 | ; /* An identifier if we could not find a protocol. */ |
e31c7eec | 5956 | |
0f41302f | 5957 | /* Check protocols recursively. */ |
e31c7eec TW |
5958 | if (PROTOCOL_LIST (p)) |
5959 | { | |
5960 | tree super_class | |
5961 | = lookup_interface (CLASS_SUPER_NAME (implementation_template)); | |
5962 | if (! conforms_to_protocol (super_class, PROTOCOL_LIST (p))) | |
5963 | check_protocols (PROTOCOL_LIST (p), type, name); | |
5964 | } | |
5965 | } | |
6c65299b RS |
5966 | } |
5967 | \f | |
f6ba5fe9 RS |
5968 | /* Make sure that the class CLASS_NAME is defined |
5969 | CODE says which kind of thing CLASS_NAME ought to be. | |
e31c7eec TW |
5970 | It can be CLASS_INTERFACE_TYPE, CLASS_IMPLEMENTATION_TYPE, |
5971 | CATEGORY_INTERFACE_TYPE, or CATEGORY_IMPLEMENTATION_TYPE. | |
f6ba5fe9 | 5972 | |
e31c7eec | 5973 | If CODE is CLASS_INTERFACE_TYPE, we also do a push_obstacks_nochange |
f6ba5fe9 RS |
5974 | whose matching pop is in continue_class. */ |
5975 | ||
6c65299b | 5976 | tree |
e31c7eec | 5977 | start_class (code, class_name, super_name, protocol_list) |
6c65299b RS |
5978 | enum tree_code code; |
5979 | tree class_name; | |
5980 | tree super_name; | |
e31c7eec | 5981 | tree protocol_list; |
6c65299b | 5982 | { |
e31c7eec | 5983 | tree class, decl; |
6c65299b | 5984 | |
e31c7eec | 5985 | if (code == CLASS_INTERFACE_TYPE) |
f6ba5fe9 RS |
5986 | { |
5987 | push_obstacks_nochange (); | |
5988 | end_temporary_allocation (); | |
5989 | } | |
5990 | ||
6c65299b | 5991 | if (!doing_objc_thang) |
e31c7eec | 5992 | objc_fatal (); |
6c65299b RS |
5993 | |
5994 | class = make_node (code); | |
5fa63f2a | 5995 | TYPE_BINFO (class) = make_tree_vec (5); |
6c65299b RS |
5996 | |
5997 | CLASS_NAME (class) = class_name; | |
5998 | CLASS_SUPER_NAME (class) = super_name; | |
5999 | CLASS_CLS_METHODS (class) = NULL_TREE; | |
6000 | ||
e31c7eec TW |
6001 | if (! is_class_name (class_name) && (decl = lookup_name (class_name))) |
6002 | { | |
6003 | error ("`%s' redeclared as different kind of symbol", | |
6004 | IDENTIFIER_POINTER (class_name)); | |
6005 | error_with_decl (decl, "previous declaration of `%s'"); | |
6006 | } | |
6007 | ||
6008 | if (code == CLASS_IMPLEMENTATION_TYPE) | |
6c65299b | 6009 | { |
e31c7eec TW |
6010 | { |
6011 | static tree implemented_classes = 0; | |
6012 | tree chain = implemented_classes; | |
6013 | for (chain = implemented_classes; chain; chain = TREE_CHAIN (chain)) | |
6014 | if (TREE_VALUE (chain) == class_name) | |
6015 | { | |
6016 | error ("reimplementation of class `%s'", | |
6017 | IDENTIFIER_POINTER (class_name)); | |
6018 | return error_mark_node; | |
6019 | } | |
51900510 | 6020 | implemented_classes = perm_tree_cons (NULL_TREE, class_name, |
e31c7eec TW |
6021 | implemented_classes); |
6022 | } | |
6023 | ||
0f41302f | 6024 | /* Pre-build the following entities - for speed/convenience. */ |
6c65299b | 6025 | if (!self_id) |
fc55cc66 | 6026 | self_id = get_identifier ("self"); |
e31c7eec TW |
6027 | if (!ucmd_id) |
6028 | ucmd_id = get_identifier ("_cmd"); | |
fc55cc66 RK |
6029 | if (!unused_list) |
6030 | unused_list | |
6031 | = build_tree_list (get_identifier ("__unused__"), NULL_TREE); | |
6c65299b RS |
6032 | if (!objc_super_template) |
6033 | objc_super_template = build_super_template (); | |
6034 | ||
51900510 RK |
6035 | /* Reset for multiple classes per file. */ |
6036 | method_slot = 0; | |
6c65299b RS |
6037 | |
6038 | implementation_context = class; | |
6039 | ||
0f41302f | 6040 | /* Lookup the interface for this implementation. */ |
6c65299b RS |
6041 | |
6042 | if (!(implementation_template = lookup_interface (class_name))) | |
6043 | { | |
6044 | warning ("Cannot find interface declaration for `%s'", | |
6045 | IDENTIFIER_POINTER (class_name)); | |
6046 | add_class (implementation_template = implementation_context); | |
6047 | } | |
6048 | ||
51900510 RK |
6049 | /* If a super class has been specified in the implementation, |
6050 | insure it conforms to the one specified in the interface. */ | |
6c65299b RS |
6051 | |
6052 | if (super_name | |
6053 | && (super_name != CLASS_SUPER_NAME (implementation_template))) | |
6054 | { | |
e31c7eec TW |
6055 | tree previous_name = CLASS_SUPER_NAME (implementation_template); |
6056 | char *name = previous_name ? IDENTIFIER_POINTER (previous_name) : ""; | |
6c65299b RS |
6057 | error ("conflicting super class name `%s'", |
6058 | IDENTIFIER_POINTER (super_name)); | |
e31c7eec | 6059 | error ("previous declaration of `%s'", name); |
6c65299b | 6060 | } |
51900510 | 6061 | |
143dc646 KKT |
6062 | else if (! super_name) |
6063 | { | |
6064 | CLASS_SUPER_NAME (implementation_context) | |
6065 | = CLASS_SUPER_NAME (implementation_template); | |
6066 | } | |
6c65299b | 6067 | } |
51900510 | 6068 | |
e31c7eec | 6069 | else if (code == CLASS_INTERFACE_TYPE) |
6c65299b RS |
6070 | { |
6071 | if (lookup_interface (class_name)) | |
6072 | warning ("duplicate interface declaration for class `%s'", | |
6073 | IDENTIFIER_POINTER (class_name)); | |
6074 | else | |
6075 | add_class (class); | |
e31c7eec TW |
6076 | |
6077 | if (protocol_list) | |
6078 | CLASS_PROTOCOL_LIST (class) | |
6079 | = lookup_and_install_protocols (protocol_list); | |
6c65299b | 6080 | } |
51900510 | 6081 | |
e31c7eec | 6082 | else if (code == CATEGORY_INTERFACE_TYPE) |
6c65299b RS |
6083 | { |
6084 | tree class_category_is_assoc_with; | |
6085 | ||
51900510 RK |
6086 | /* For a category, class_name is really the name of the class that |
6087 | the following set of methods will be associated with. We must | |
6088 | find the interface so that can derive the objects template. */ | |
6c65299b RS |
6089 | |
6090 | if (!(class_category_is_assoc_with = lookup_interface (class_name))) | |
6091 | { | |
6092 | error ("Cannot find interface declaration for `%s'", | |
6093 | IDENTIFIER_POINTER (class_name)); | |
51900510 | 6094 | exit (FATAL_EXIT_CODE); |
6c65299b RS |
6095 | } |
6096 | else | |
6097 | add_category (class_category_is_assoc_with, class); | |
e31c7eec TW |
6098 | |
6099 | if (protocol_list) | |
6100 | CLASS_PROTOCOL_LIST (class) | |
6101 | = lookup_and_install_protocols (protocol_list); | |
6c65299b | 6102 | } |
51900510 | 6103 | |
e31c7eec | 6104 | else if (code == CATEGORY_IMPLEMENTATION_TYPE) |
6c65299b | 6105 | { |
0f41302f | 6106 | /* Pre-build the following entities for speed/convenience. */ |
6c65299b RS |
6107 | if (!self_id) |
6108 | self_id = get_identifier ("self"); | |
e31c7eec TW |
6109 | if (!ucmd_id) |
6110 | ucmd_id = get_identifier ("_cmd"); | |
fc55cc66 RK |
6111 | if (!unused_list) |
6112 | unused_list | |
6113 | = build_tree_list (get_identifier ("__unused__"), NULL_TREE); | |
6c65299b RS |
6114 | if (!objc_super_template) |
6115 | objc_super_template = build_super_template (); | |
6116 | ||
51900510 RK |
6117 | /* Reset for multiple classes per file. */ |
6118 | method_slot = 0; | |
6c65299b RS |
6119 | |
6120 | implementation_context = class; | |
6121 | ||
51900510 RK |
6122 | /* For a category, class_name is really the name of the class that |
6123 | the following set of methods will be associated with. We must | |
0f41302f | 6124 | find the interface so that can derive the objects template. */ |
6c65299b RS |
6125 | |
6126 | if (!(implementation_template = lookup_interface (class_name))) | |
6127 | { | |
6128 | error ("Cannot find interface declaration for `%s'", | |
6129 | IDENTIFIER_POINTER (class_name)); | |
51900510 | 6130 | exit (FATAL_EXIT_CODE); |
6c65299b RS |
6131 | } |
6132 | } | |
6133 | return class; | |
6134 | } | |
6135 | ||
6136 | tree | |
6137 | continue_class (class) | |
6138 | tree class; | |
6139 | { | |
e31c7eec TW |
6140 | if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE |
6141 | || TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE) | |
6c65299b | 6142 | { |
e31c7eec | 6143 | struct imp_entry *imp_entry; |
6c65299b RS |
6144 | tree ivar_context; |
6145 | ||
0f41302f | 6146 | /* Check consistency of the instance variables. */ |
6c65299b RS |
6147 | |
6148 | if (CLASS_IVARS (class)) | |
6149 | check_ivars (implementation_template, class); | |
6150 | ||
6151 | /* code generation */ | |
6152 | ||
6153 | ivar_context = build_private_template (implementation_template); | |
6154 | ||
6155 | if (!objc_class_template) | |
6156 | build_class_template (); | |
6157 | ||
51900510 RK |
6158 | if (!(imp_entry |
6159 | = (struct imp_entry *) xmalloc (sizeof (struct imp_entry)))) | |
6c65299b RS |
6160 | perror ("unable to allocate in objc-tree.c"); |
6161 | ||
e31c7eec TW |
6162 | imp_entry->next = imp_list; |
6163 | imp_entry->imp_context = class; | |
6164 | imp_entry->imp_template = implementation_template; | |
6c65299b RS |
6165 | |
6166 | synth_forward_declarations (); | |
e31c7eec TW |
6167 | imp_entry->class_decl = UOBJC_CLASS_decl; |
6168 | imp_entry->meta_decl = UOBJC_METACLASS_decl; | |
6c65299b | 6169 | |
0f41302f | 6170 | /* Append to front and increment count. */ |
e31c7eec TW |
6171 | imp_list = imp_entry; |
6172 | if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE) | |
6c65299b RS |
6173 | imp_count++; |
6174 | else | |
6175 | cat_count++; | |
6176 | ||
6177 | return ivar_context; | |
6178 | } | |
51900510 | 6179 | |
e31c7eec | 6180 | else if (TREE_CODE (class) == CLASS_INTERFACE_TYPE) |
6c65299b RS |
6181 | { |
6182 | tree record = xref_tag (RECORD_TYPE, CLASS_NAME (class)); | |
6183 | ||
6184 | if (!TYPE_FIELDS (record)) | |
6185 | { | |
51900510 | 6186 | finish_struct (record, build_ivar_chain (class, 0), NULL_TREE); |
6c65299b RS |
6187 | CLASS_STATIC_TEMPLATE (class) = record; |
6188 | ||
51900510 | 6189 | /* Mark this record as a class template for static typing. */ |
6c65299b RS |
6190 | TREE_STATIC_TEMPLATE (record) = 1; |
6191 | } | |
51900510 RK |
6192 | |
6193 | return NULL_TREE; | |
6c65299b | 6194 | } |
51900510 | 6195 | |
6c65299b RS |
6196 | else |
6197 | return error_mark_node; | |
6198 | } | |
6199 | ||
e31c7eec TW |
6200 | /* This is called once we see the "@end" in an interface/implementation. */ |
6201 | ||
6c65299b RS |
6202 | void |
6203 | finish_class (class) | |
6204 | tree class; | |
6205 | { | |
e31c7eec | 6206 | if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE) |
6c65299b | 6207 | { |
0f41302f | 6208 | /* All code generation is done in finish_objc. */ |
6c65299b RS |
6209 | |
6210 | if (implementation_template != implementation_context) | |
6211 | { | |
0f41302f | 6212 | /* Ensure that all method listed in the interface contain bodies. */ |
6c65299b RS |
6213 | check_methods (CLASS_CLS_METHODS (implementation_template), |
6214 | CLASS_CLS_METHODS (implementation_context), '+'); | |
6215 | check_methods (CLASS_NST_METHODS (implementation_template), | |
6216 | CLASS_NST_METHODS (implementation_context), '-'); | |
e31c7eec TW |
6217 | |
6218 | if (CLASS_PROTOCOL_LIST (implementation_template)) | |
6219 | check_protocols (CLASS_PROTOCOL_LIST (implementation_template), | |
6220 | "class", | |
6221 | IDENTIFIER_POINTER (CLASS_NAME (implementation_context))); | |
6c65299b RS |
6222 | } |
6223 | } | |
51900510 | 6224 | |
e31c7eec | 6225 | else if (TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE) |
6c65299b RS |
6226 | { |
6227 | tree category = CLASS_CATEGORY_LIST (implementation_template); | |
e31c7eec | 6228 | |
0f41302f | 6229 | /* Find the category interface from the class it is associated with. */ |
6c65299b RS |
6230 | while (category) |
6231 | { | |
6232 | if (CLASS_SUPER_NAME (class) == CLASS_SUPER_NAME (category)) | |
6233 | break; | |
6234 | category = CLASS_CATEGORY_LIST (category); | |
6235 | } | |
e31c7eec | 6236 | |
6c65299b RS |
6237 | if (category) |
6238 | { | |
0f41302f | 6239 | /* Ensure all method listed in the interface contain bodies. */ |
6c65299b RS |
6240 | check_methods (CLASS_CLS_METHODS (category), |
6241 | CLASS_CLS_METHODS (implementation_context), '+'); | |
6242 | check_methods (CLASS_NST_METHODS (category), | |
6243 | CLASS_NST_METHODS (implementation_context), '-'); | |
e31c7eec TW |
6244 | |
6245 | if (CLASS_PROTOCOL_LIST (category)) | |
6246 | check_protocols (CLASS_PROTOCOL_LIST (category), | |
6247 | "category", | |
6248 | IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_context))); | |
6c65299b | 6249 | } |
e31c7eec | 6250 | } |
51900510 | 6251 | |
e31c7eec | 6252 | else if (TREE_CODE (class) == CLASS_INTERFACE_TYPE) |
6c65299b RS |
6253 | { |
6254 | tree decl_specs; | |
e31c7eec TW |
6255 | char *class_name = IDENTIFIER_POINTER (CLASS_NAME (class)); |
6256 | char *string = (char *) alloca (strlen (class_name) + 3); | |
6c65299b RS |
6257 | |
6258 | /* extern struct objc_object *_<my_name>; */ | |
6259 | ||
e31c7eec | 6260 | sprintf (string, "_%s", class_name); |
6c65299b | 6261 | |
51900510 RK |
6262 | decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_EXTERN]); |
6263 | decl_specs = tree_cons (NULL_TREE, objc_object_reference, decl_specs); | |
6264 | define_decl (build1 (INDIRECT_REF, NULL_TREE, get_identifier (string)), | |
6e3f0724 | 6265 | decl_specs); |
6c65299b RS |
6266 | } |
6267 | } | |
e31c7eec TW |
6268 | |
6269 | static tree | |
6270 | add_protocol (protocol) | |
6271 | tree protocol; | |
6272 | { | |
0f41302f | 6273 | /* Put protocol on list in reverse order. */ |
e31c7eec TW |
6274 | TREE_CHAIN (protocol) = protocol_chain; |
6275 | protocol_chain = protocol; | |
6276 | return protocol_chain; | |
6277 | } | |
6278 | ||
6279 | static tree | |
6280 | lookup_protocol (ident) | |
6281 | tree ident; | |
6282 | { | |
6283 | tree chain; | |
6284 | ||
6285 | for (chain = protocol_chain; chain; chain = TREE_CHAIN (chain)) | |
6286 | { | |
6287 | if (ident == PROTOCOL_NAME (chain)) | |
6288 | return chain; | |
6289 | } | |
51900510 RK |
6290 | |
6291 | return NULL_TREE; | |
e31c7eec TW |
6292 | } |
6293 | ||
6294 | tree | |
6295 | start_protocol (code, name, list) | |
6296 | enum tree_code code; | |
6297 | tree name; | |
6298 | tree list; | |
6299 | { | |
6300 | tree protocol; | |
6301 | ||
6302 | if (!doing_objc_thang) | |
6303 | objc_fatal (); | |
6304 | ||
6305 | /* This is as good a place as any. Need to invoke push_tag_toplevel. */ | |
6306 | if (!objc_protocol_template) | |
6307 | objc_protocol_template = build_protocol_template (); | |
6308 | ||
6309 | protocol = make_node (code); | |
5fa63f2a | 6310 | TYPE_BINFO (protocol) = make_tree_vec (2); |
e31c7eec TW |
6311 | |
6312 | PROTOCOL_NAME (protocol) = name; | |
6313 | PROTOCOL_LIST (protocol) = list; | |
6314 | ||
6315 | lookup_and_install_protocols (list); | |
6316 | ||
6317 | if (lookup_protocol (name)) | |
6318 | warning ("duplicate declaration for protocol `%s'", | |
6319 | IDENTIFIER_POINTER (name)); | |
6320 | else | |
6321 | add_protocol (protocol); | |
6322 | ||
6323 | PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE; | |
6324 | ||
6325 | return protocol; | |
6326 | } | |
6327 | ||
6328 | void | |
6329 | finish_protocol (protocol) | |
6330 | tree protocol; | |
6331 | { | |
6332 | } | |
6333 | ||
6c65299b | 6334 | \f |
e31c7eec | 6335 | /* "Encode" a data type into a string, which grows in util_obstack. |
9dee6758 | 6336 | ??? What is the FORMAT? Someone please document this! */ |
6e3f0724 | 6337 | |
e31c7eec TW |
6338 | static void |
6339 | encode_type_qualifiers (declspecs) | |
6340 | tree declspecs; | |
6341 | { | |
6342 | tree spec; | |
6343 | ||
6344 | for (spec = declspecs; spec; spec = TREE_CHAIN (spec)) | |
6345 | { | |
2a73b0b2 | 6346 | if (ridpointers[(int) RID_CONST] == TREE_VALUE (spec)) |
e31c7eec | 6347 | obstack_1grow (&util_obstack, 'r'); |
2a73b0b2 | 6348 | else if (ridpointers[(int) RID_IN] == TREE_VALUE (spec)) |
e31c7eec | 6349 | obstack_1grow (&util_obstack, 'n'); |
2a73b0b2 | 6350 | else if (ridpointers[(int) RID_INOUT] == TREE_VALUE (spec)) |
e31c7eec | 6351 | obstack_1grow (&util_obstack, 'N'); |
2a73b0b2 | 6352 | else if (ridpointers[(int) RID_OUT] == TREE_VALUE (spec)) |
e31c7eec | 6353 | obstack_1grow (&util_obstack, 'o'); |
2a73b0b2 | 6354 | else if (ridpointers[(int) RID_BYCOPY] == TREE_VALUE (spec)) |
e31c7eec | 6355 | obstack_1grow (&util_obstack, 'O'); |
2a73b0b2 | 6356 | else if (ridpointers[(int) RID_ONEWAY] == TREE_VALUE (spec)) |
e31c7eec TW |
6357 | obstack_1grow (&util_obstack, 'V'); |
6358 | } | |
6359 | } | |
6360 | ||
6e3f0724 RS |
6361 | /* Encode a pointer type. */ |
6362 | ||
6c65299b | 6363 | static void |
e31c7eec | 6364 | encode_pointer (type, curtype, format) |
6c65299b | 6365 | tree type; |
e31c7eec | 6366 | int curtype; |
6c65299b RS |
6367 | int format; |
6368 | { | |
6369 | tree pointer_to = TREE_TYPE (type); | |
6370 | ||
6371 | if (TREE_CODE (pointer_to) == RECORD_TYPE) | |
6372 | { | |
6373 | if (TYPE_NAME (pointer_to) | |
6374 | && TREE_CODE (TYPE_NAME (pointer_to)) == IDENTIFIER_NODE) | |
6375 | { | |
6376 | char *name = IDENTIFIER_POINTER (TYPE_NAME (pointer_to)); | |
6377 | ||
e31c7eec | 6378 | if (strcmp (name, TAG_OBJECT) == 0) /* '@' */ |
6c65299b | 6379 | { |
6e3f0724 | 6380 | obstack_1grow (&util_obstack, '@'); |
6c65299b RS |
6381 | return; |
6382 | } | |
e31c7eec TW |
6383 | else if (TREE_STATIC_TEMPLATE (pointer_to)) |
6384 | { | |
6385 | if (generating_instance_variables) | |
6386 | { | |
6387 | obstack_1grow (&util_obstack, '@'); | |
6388 | obstack_1grow (&util_obstack, '"'); | |
6389 | obstack_grow (&util_obstack, name, strlen (name)); | |
6390 | obstack_1grow (&util_obstack, '"'); | |
6391 | return; | |
6392 | } | |
6393 | else | |
6394 | { | |
6395 | obstack_1grow (&util_obstack, '@'); | |
6396 | return; | |
6397 | } | |
6398 | } | |
6c65299b RS |
6399 | else if (strcmp (name, TAG_CLASS) == 0) /* '#' */ |
6400 | { | |
6e3f0724 | 6401 | obstack_1grow (&util_obstack, '#'); |
6c65299b RS |
6402 | return; |
6403 | } | |
6404 | #ifndef OBJC_INT_SELECTORS | |
6405 | else if (strcmp (name, TAG_SELECTOR) == 0) /* ':' */ | |
6406 | { | |
6e3f0724 | 6407 | obstack_1grow (&util_obstack, ':'); |
6c65299b RS |
6408 | return; |
6409 | } | |
6410 | #endif /* OBJC_INT_SELECTORS */ | |
6411 | } | |
6412 | } | |
6413 | else if (TREE_CODE (pointer_to) == INTEGER_TYPE | |
6414 | && TYPE_MODE (pointer_to) == QImode) | |
6415 | { | |
6e3f0724 | 6416 | obstack_1grow (&util_obstack, '*'); |
6c65299b RS |
6417 | return; |
6418 | } | |
6419 | ||
51900510 | 6420 | /* We have a type that does not get special treatment. */ |
6c65299b RS |
6421 | |
6422 | /* NeXT extension */ | |
6e3f0724 | 6423 | obstack_1grow (&util_obstack, '^'); |
e31c7eec | 6424 | encode_type (pointer_to, curtype, format); |
6c65299b RS |
6425 | } |
6426 | ||
6427 | static void | |
e31c7eec | 6428 | encode_array (type, curtype, format) |
6c65299b | 6429 | tree type; |
e31c7eec | 6430 | int curtype; |
6c65299b RS |
6431 | int format; |
6432 | { | |
e31c7eec | 6433 | tree an_int_cst = TYPE_SIZE (type); |
6c65299b | 6434 | tree array_of = TREE_TYPE (type); |
6e3f0724 | 6435 | char buffer[40]; |
6c65299b RS |
6436 | |
6437 | /* An incomplete array is treated like a pointer. */ | |
e31c7eec | 6438 | if (an_int_cst == NULL) |
6c65299b | 6439 | { |
e31c7eec | 6440 | encode_pointer (type, curtype, format); |
6c65299b RS |
6441 | return; |
6442 | } | |
e31c7eec | 6443 | |
6e3f0724 | 6444 | sprintf (buffer, "[%d", |
e31c7eec TW |
6445 | (TREE_INT_CST_LOW (an_int_cst) |
6446 | / TREE_INT_CST_LOW (TYPE_SIZE (array_of)))); | |
51900510 | 6447 | |
6e3f0724 | 6448 | obstack_grow (&util_obstack, buffer, strlen (buffer)); |
e31c7eec | 6449 | encode_type (array_of, curtype, format); |
6e3f0724 | 6450 | obstack_1grow (&util_obstack, ']'); |
6c65299b RS |
6451 | return; |
6452 | } | |
6453 | \f | |
6454 | static void | |
e31c7eec | 6455 | encode_aggregate (type, curtype, format) |
6c65299b | 6456 | tree type; |
e31c7eec | 6457 | int curtype; |
6c65299b RS |
6458 | int format; |
6459 | { | |
6460 | enum tree_code code = TREE_CODE (type); | |
6461 | ||
6462 | switch (code) | |
6463 | { | |
6464 | case RECORD_TYPE: | |
6465 | { | |
e31c7eec TW |
6466 | if (obstack_object_size (&util_obstack) > 0 |
6467 | && *(obstack_next_free (&util_obstack) - 1) == '^') | |
6468 | { | |
6469 | tree name = TYPE_NAME (type); | |
b53241dc | 6470 | |
0f41302f | 6471 | /* We have a reference; this is a NeXT extension. */ |
b53241dc | 6472 | |
e31c7eec TW |
6473 | if (obstack_object_size (&util_obstack) - curtype == 1 |
6474 | && format == OBJC_ENCODE_INLINE_DEFS) | |
6e3f0724 | 6475 | { |
0f41302f | 6476 | /* Output format of struct for first level only. */ |
e31c7eec TW |
6477 | tree fields = TYPE_FIELDS (type); |
6478 | ||
6479 | if (name && TREE_CODE (name) == IDENTIFIER_NODE) | |
6480 | { | |
6481 | obstack_1grow (&util_obstack, '{'); | |
6482 | obstack_grow (&util_obstack, | |
6483 | IDENTIFIER_POINTER (name), | |
6484 | strlen (IDENTIFIER_POINTER (name))); | |
6485 | obstack_1grow (&util_obstack, '='); | |
6486 | } | |
51900510 | 6487 | |
e31c7eec TW |
6488 | else |
6489 | obstack_grow (&util_obstack, "{?=", 3); | |
6490 | ||
6491 | for ( ; fields; fields = TREE_CHAIN (fields)) | |
6492 | encode_field_decl (fields, curtype, format); | |
51900510 | 6493 | |
e31c7eec TW |
6494 | obstack_1grow (&util_obstack, '}'); |
6495 | } | |
51900510 | 6496 | |
e31c7eec TW |
6497 | else if (name && TREE_CODE (name) == IDENTIFIER_NODE) |
6498 | { | |
6499 | obstack_1grow (&util_obstack, '{'); | |
6500 | obstack_grow (&util_obstack, | |
6501 | IDENTIFIER_POINTER (name), | |
6502 | strlen (IDENTIFIER_POINTER (name))); | |
6503 | obstack_1grow (&util_obstack, '}'); | |
6e3f0724 | 6504 | } |
51900510 RK |
6505 | |
6506 | else | |
0f41302f | 6507 | /* We have an untagged structure or a typedef. */ |
e31c7eec TW |
6508 | obstack_grow (&util_obstack, "{?}", 3); |
6509 | } | |
51900510 | 6510 | |
e31c7eec TW |
6511 | else |
6512 | { | |
6513 | tree name = TYPE_NAME (type); | |
6514 | tree fields = TYPE_FIELDS (type); | |
6515 | ||
6516 | if (format == OBJC_ENCODE_INLINE_DEFS | |
6517 | || generating_instance_variables) | |
6518 | { | |
6519 | obstack_1grow (&util_obstack, '{'); | |
6520 | if (name && TREE_CODE (name) == IDENTIFIER_NODE) | |
6521 | obstack_grow (&util_obstack, | |
6522 | IDENTIFIER_POINTER (name), | |
6523 | strlen (IDENTIFIER_POINTER (name))); | |
51900510 | 6524 | |
e31c7eec TW |
6525 | else |
6526 | obstack_1grow (&util_obstack, '?'); | |
6527 | ||
6528 | obstack_1grow (&util_obstack, '='); | |
6529 | ||
6530 | for (; fields; fields = TREE_CHAIN (fields)) | |
6531 | { | |
6532 | if (generating_instance_variables) | |
6533 | { | |
6534 | tree fname = DECL_NAME (fields); | |
6535 | ||
6536 | obstack_1grow (&util_obstack, '"'); | |
6537 | if (fname && TREE_CODE (fname) == IDENTIFIER_NODE) | |
6538 | { | |
51900510 RK |
6539 | obstack_grow (&util_obstack, |
6540 | IDENTIFIER_POINTER (fname), | |
6541 | strlen (IDENTIFIER_POINTER (fname))); | |
e31c7eec | 6542 | } |
51900510 | 6543 | |
e31c7eec TW |
6544 | obstack_1grow (&util_obstack, '"'); |
6545 | } | |
51900510 | 6546 | |
e31c7eec TW |
6547 | encode_field_decl (fields, curtype, format); |
6548 | } | |
51900510 | 6549 | |
e31c7eec TW |
6550 | obstack_1grow (&util_obstack, '}'); |
6551 | } | |
51900510 | 6552 | |
e31c7eec | 6553 | else |
b53241dc | 6554 | { |
e31c7eec TW |
6555 | obstack_1grow (&util_obstack, '{'); |
6556 | if (name && TREE_CODE (name) == IDENTIFIER_NODE) | |
6557 | obstack_grow (&util_obstack, | |
6558 | IDENTIFIER_POINTER (name), | |
6559 | strlen (IDENTIFIER_POINTER (name))); | |
51900510 | 6560 | else |
0f41302f | 6561 | /* We have an untagged structure or a typedef. */ |
e31c7eec | 6562 | obstack_1grow (&util_obstack, '?'); |
51900510 | 6563 | |
e31c7eec | 6564 | obstack_1grow (&util_obstack, '}'); |
b53241dc RS |
6565 | } |
6566 | } | |
6c65299b RS |
6567 | break; |
6568 | } | |
51900510 | 6569 | |
6c65299b RS |
6570 | case UNION_TYPE: |
6571 | { | |
e31c7eec TW |
6572 | if (*obstack_next_free (&util_obstack) == '^' |
6573 | || format != OBJC_ENCODE_INLINE_DEFS) | |
6c65299b | 6574 | { |
51900510 | 6575 | /* We have a reference (this is a NeXT extension) |
e31c7eec TW |
6576 | or we don't want the details. */ |
6577 | if (TYPE_NAME (type) | |
6578 | && TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) | |
6e3f0724 | 6579 | { |
e31c7eec TW |
6580 | obstack_1grow (&util_obstack, '('); |
6581 | obstack_grow (&util_obstack, | |
6e3f0724 RS |
6582 | IDENTIFIER_POINTER (TYPE_NAME (type)), |
6583 | strlen (IDENTIFIER_POINTER (TYPE_NAME (type)))); | |
e31c7eec | 6584 | obstack_1grow (&util_obstack, ')'); |
6e3f0724 | 6585 | } |
51900510 RK |
6586 | |
6587 | else | |
0f41302f | 6588 | /* We have an untagged structure or a typedef. */ |
e31c7eec | 6589 | obstack_grow (&util_obstack, "(?)", 3); |
6c65299b RS |
6590 | } |
6591 | else | |
6592 | { | |
6593 | tree fields = TYPE_FIELDS (type); | |
e31c7eec | 6594 | obstack_1grow (&util_obstack, '('); |
6e3f0724 | 6595 | for ( ; fields; fields = TREE_CHAIN (fields)) |
e31c7eec | 6596 | encode_field_decl (fields, curtype, format); |
51900510 | 6597 | |
b53241dc | 6598 | obstack_1grow (&util_obstack, ')'); |
6c65299b RS |
6599 | } |
6600 | break; | |
6601 | } | |
6e3f0724 | 6602 | |
6c65299b | 6603 | case ENUMERAL_TYPE: |
6e3f0724 | 6604 | obstack_1grow (&util_obstack, 'i'); |
6c65299b RS |
6605 | break; |
6606 | } | |
6607 | } | |
6608 | ||
51900510 RK |
6609 | /* Support bitfields. The current version of Objective-C does not support |
6610 | them. The string will consist of one or more "b:n"'s where n is an | |
e31c7eec TW |
6611 | integer describing the width of the bitfield. Currently, classes in |
6612 | the kit implement a method "-(char *)describeBitfieldStruct:" that | |
51900510 | 6613 | simulates this. If they do not implement this method, the archiver |
e31c7eec TW |
6614 | assumes the bitfield is 16 bits wide (padded if necessary) and packed |
6615 | according to the GNU compiler. After looking at the "kit", it appears | |
6616 | that all classes currently rely on this default behavior, rather than | |
6617 | hand generating this string (which is tedious). */ | |
6618 | ||
6c65299b | 6619 | static void |
9dee6758 | 6620 | encode_bitfield (width, format) |
6c65299b | 6621 | int width; |
6c65299b RS |
6622 | int format; |
6623 | { | |
9dee6758 RS |
6624 | char buffer[40]; |
6625 | sprintf (buffer, "b%d", width); | |
6626 | obstack_grow (&util_obstack, buffer, strlen (buffer)); | |
6c65299b RS |
6627 | } |
6628 | \f | |
e31c7eec TW |
6629 | /* FORMAT will be OBJC_ENCODE_INLINE_DEFS or OBJC_ENCODE_DONT_INLINE_DEFS. */ |
6630 | ||
6c65299b | 6631 | static void |
e31c7eec | 6632 | encode_type (type, curtype, format) |
6c65299b | 6633 | tree type; |
e31c7eec | 6634 | int curtype; |
6c65299b RS |
6635 | int format; |
6636 | { | |
6637 | enum tree_code code = TREE_CODE (type); | |
6638 | ||
6639 | if (code == INTEGER_TYPE) | |
6640 | { | |
e287a52c RS |
6641 | if (TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)) == 0 |
6642 | && TREE_INT_CST_HIGH (TYPE_MIN_VALUE (type)) == 0) | |
6c65299b | 6643 | { |
0f41302f | 6644 | /* Unsigned integer types. */ |
6c65299b | 6645 | |
51900510 | 6646 | if (TYPE_MODE (type) == QImode) |
9dee6758 | 6647 | obstack_1grow (&util_obstack, 'C'); |
51900510 | 6648 | else if (TYPE_MODE (type) == HImode) |
9dee6758 | 6649 | obstack_1grow (&util_obstack, 'S'); |
6c65299b RS |
6650 | else if (TYPE_MODE (type) == SImode) |
6651 | { | |
6652 | if (type == long_unsigned_type_node) | |
51900510 | 6653 | obstack_1grow (&util_obstack, 'L'); |
6c65299b | 6654 | else |
51900510 | 6655 | obstack_1grow (&util_obstack, 'I'); |
6c65299b | 6656 | } |
51900510 | 6657 | else if (TYPE_MODE (type) == DImode) |
e287a52c | 6658 | obstack_1grow (&util_obstack, 'Q'); |
6c65299b | 6659 | } |
51900510 RK |
6660 | |
6661 | else | |
0f41302f | 6662 | /* Signed integer types. */ |
6c65299b | 6663 | { |
51900510 | 6664 | if (TYPE_MODE (type) == QImode) |
9dee6758 | 6665 | obstack_1grow (&util_obstack, 'c'); |
51900510 | 6666 | else if (TYPE_MODE (type) == HImode) |
9dee6758 | 6667 | obstack_1grow (&util_obstack, 's'); |
51900510 | 6668 | else if (TYPE_MODE (type) == SImode) |
6c65299b RS |
6669 | { |
6670 | if (type == long_integer_type_node) | |
51900510 | 6671 | obstack_1grow (&util_obstack, 'l'); |
6c65299b | 6672 | else |
51900510 | 6673 | obstack_1grow (&util_obstack, 'i'); |
6c65299b | 6674 | } |
51900510 RK |
6675 | |
6676 | else if (TYPE_MODE (type) == DImode) | |
e287a52c | 6677 | obstack_1grow (&util_obstack, 'q'); |
6c65299b RS |
6678 | } |
6679 | } | |
51900510 | 6680 | |
6c65299b RS |
6681 | else if (code == REAL_TYPE) |
6682 | { | |
0f41302f | 6683 | /* Floating point types. */ |
6c65299b | 6684 | |
51900510 | 6685 | if (TYPE_MODE (type) == SFmode) |
9dee6758 | 6686 | obstack_1grow (&util_obstack, 'f'); |
6c65299b | 6687 | else if (TYPE_MODE (type) == DFmode |
51900510 | 6688 | || TYPE_MODE (type) == TFmode) |
9dee6758 | 6689 | obstack_1grow (&util_obstack, 'd'); |
6c65299b RS |
6690 | } |
6691 | ||
51900510 | 6692 | else if (code == VOID_TYPE) |
9dee6758 | 6693 | obstack_1grow (&util_obstack, 'v'); |
6c65299b RS |
6694 | |
6695 | else if (code == ARRAY_TYPE) | |
e31c7eec | 6696 | encode_array (type, curtype, format); |
6c65299b RS |
6697 | |
6698 | else if (code == POINTER_TYPE) | |
e31c7eec | 6699 | encode_pointer (type, curtype, format); |
6c65299b RS |
6700 | |
6701 | else if (code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE) | |
e31c7eec | 6702 | encode_aggregate (type, curtype, format); |
6c65299b RS |
6703 | |
6704 | else if (code == FUNCTION_TYPE) /* '?' */ | |
9dee6758 | 6705 | obstack_1grow (&util_obstack, '?'); |
6c65299b RS |
6706 | } |
6707 | ||
6708 | static void | |
e31c7eec | 6709 | encode_field_decl (field_decl, curtype, format) |
6c65299b | 6710 | tree field_decl; |
e31c7eec | 6711 | int curtype; |
6c65299b RS |
6712 | int format; |
6713 | { | |
e31c7eec TW |
6714 | tree type; |
6715 | ||
6716 | /* If this field is obviously a bitfield, or is a bitfield that has been | |
6717 | clobbered to look like a ordinary integer mode, go ahead and generate | |
0f41302f | 6718 | the bitfield typing information. */ |
e31c7eec | 6719 | type = TREE_TYPE (field_decl); |
6c65299b | 6720 | if (DECL_BIT_FIELD (field_decl)) |
9dee6758 | 6721 | encode_bitfield (DECL_FIELD_SIZE (field_decl), format); |
e31c7eec TW |
6722 | else if (TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST |
6723 | && DECL_FIELD_SIZE (field_decl) | |
6724 | && TYPE_MODE (type) > DECL_MODE (field_decl)) | |
6725 | encode_bitfield (DECL_FIELD_SIZE (field_decl), format); | |
6c65299b | 6726 | else |
e31c7eec | 6727 | encode_type (TREE_TYPE (field_decl), curtype, format); |
6c65299b RS |
6728 | } |
6729 | ||
6730 | static tree | |
6731 | expr_last (complex_expr) | |
6732 | tree complex_expr; | |
6733 | { | |
6734 | tree next; | |
6735 | ||
6736 | if (complex_expr) | |
e31c7eec | 6737 | while ((next = TREE_OPERAND (complex_expr, 0))) |
6c65299b | 6738 | complex_expr = next; |
51900510 | 6739 | |
6c65299b RS |
6740 | return complex_expr; |
6741 | } | |
6742 | \f | |
6743 | /* The selector of the current method, | |
6744 | or NULL if we aren't compiling a method. */ | |
6745 | ||
6746 | tree | |
6747 | maybe_objc_method_name (decl) | |
6748 | tree decl; | |
6749 | { | |
6750 | if (method_context) | |
6751 | return METHOD_SEL_NAME (method_context); | |
6752 | else | |
6753 | return 0; | |
6754 | } | |
6755 | ||
e31c7eec TW |
6756 | /* Transform a method definition into a function definition as follows: |
6757 | - synthesize the first two arguments, "self" and "_cmd". */ | |
6c65299b RS |
6758 | |
6759 | void | |
6760 | start_method_def (method) | |
6761 | tree method; | |
6762 | { | |
6763 | tree decl_specs; | |
6764 | ||
e31c7eec | 6765 | /* Required to implement _msgSuper. */ |
6c65299b | 6766 | method_context = method; |
51900510 | 6767 | UOBJC_SUPER_decl = NULL_TREE; |
6c65299b | 6768 | |
51900510 RK |
6769 | /* Must be called BEFORE start_function. */ |
6770 | pushlevel (0); | |
6c65299b | 6771 | |
e31c7eec | 6772 | /* Generate prototype declarations for arguments..."new-style". */ |
6c65299b RS |
6773 | |
6774 | if (TREE_CODE (method_context) == INSTANCE_METHOD_DECL) | |
51900510 | 6775 | decl_specs = build_tree_list (NULL_TREE, uprivate_record); |
6c65299b | 6776 | else |
51900510 RK |
6777 | /* Really a `struct objc_class *'. However, we allow people to |
6778 | assign to self, which changes its type midstream. */ | |
6779 | decl_specs = build_tree_list (NULL_TREE, objc_object_reference); | |
6c65299b | 6780 | |
fc55cc66 RK |
6781 | push_parm_decl (build_tree_list |
6782 | (build_tree_list (decl_specs, | |
51900510 | 6783 | build1 (INDIRECT_REF, NULL_TREE, self_id)), |
0ad228e6 | 6784 | build_tree_list (unused_list, NULL_TREE))); |
6c65299b RS |
6785 | |
6786 | #ifdef OBJC_INT_SELECTORS | |
51900510 RK |
6787 | decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_UNSIGNED]); |
6788 | decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_INT], decl_specs); | |
fc55cc66 RK |
6789 | push_parm_decl (build_tree_list (build_tree_list (decl_specs, ucmd_id), |
6790 | build_tree_list (unused_list, NULL_TREE))); | |
6c65299b | 6791 | #else /* not OBJC_INT_SELECTORS */ |
51900510 | 6792 | decl_specs = build_tree_list (NULL_TREE, |
6c65299b RS |
6793 | xref_tag (RECORD_TYPE, |
6794 | get_identifier (TAG_SELECTOR))); | |
fc55cc66 RK |
6795 | push_parm_decl (build_tree_list |
6796 | (build_tree_list (decl_specs, | |
51900510 | 6797 | build1 (INDIRECT_REF, NULL_TREE, ucmd_id)), |
fc55cc66 | 6798 | build_tree_list (unused_list, NULL_TREE))); |
6c65299b RS |
6799 | #endif /* not OBJC_INT_SELECTORS */ |
6800 | ||
0f41302f | 6801 | /* Generate argument declarations if a keyword_decl. */ |
6c65299b RS |
6802 | if (METHOD_SEL_ARGS (method)) |
6803 | { | |
6804 | tree arglist = METHOD_SEL_ARGS (method); | |
6805 | do | |
6806 | { | |
6807 | tree arg_spec = TREE_PURPOSE (TREE_TYPE (arglist)); | |
6808 | tree arg_decl = TREE_VALUE (TREE_TYPE (arglist)); | |
6809 | ||
6810 | if (arg_decl) | |
6811 | { | |
6812 | tree last_expr = expr_last (arg_decl); | |
6813 | ||
0f41302f | 6814 | /* Unite the abstract decl with its name. */ |
6c65299b | 6815 | TREE_OPERAND (last_expr, 0) = KEYWORD_ARG_NAME (arglist); |
fc55cc66 RK |
6816 | push_parm_decl (build_tree_list |
6817 | (build_tree_list (arg_spec, arg_decl), | |
6818 | build_tree_list (NULL_TREE, NULL_TREE))); | |
51900510 | 6819 | |
0f41302f | 6820 | /* Unhook: restore the abstract declarator. */ |
51900510 | 6821 | TREE_OPERAND (last_expr, 0) = NULL_TREE; |
6c65299b | 6822 | } |
51900510 | 6823 | |
6c65299b | 6824 | else |
fc55cc66 RK |
6825 | push_parm_decl (build_tree_list |
6826 | (build_tree_list (arg_spec, | |
6827 | KEYWORD_ARG_NAME (arglist)), | |
6828 | build_tree_list (NULL_TREE, NULL_TREE))); | |
6c65299b RS |
6829 | |
6830 | arglist = TREE_CHAIN (arglist); | |
6831 | } | |
6832 | while (arglist); | |
6833 | } | |
6834 | ||
6835 | if (METHOD_ADD_ARGS (method) > (tree)1) | |
6836 | { | |
0f41302f | 6837 | /* We have a variable length selector - in "prototype" format. */ |
6c65299b RS |
6838 | tree akey = TREE_PURPOSE (METHOD_ADD_ARGS (method)); |
6839 | while (akey) | |
6840 | { | |
e31c7eec TW |
6841 | /* This must be done prior to calling pushdecl. pushdecl is |
6842 | going to change our chain on us. */ | |
6c65299b RS |
6843 | tree nextkey = TREE_CHAIN (akey); |
6844 | pushdecl (akey); | |
6845 | akey = nextkey; | |
6846 | } | |
6847 | } | |
6848 | } | |
6849 | ||
6c65299b RS |
6850 | static void |
6851 | warn_with_method (message, mtype, method) | |
6852 | char *message; | |
627c097f | 6853 | int mtype; |
6c65299b RS |
6854 | tree method; |
6855 | { | |
e31c7eec TW |
6856 | if (count_error (1) == 0) |
6857 | return; | |
6858 | ||
6859 | report_error_function (DECL_SOURCE_FILE (method)); | |
6860 | ||
6861 | fprintf (stderr, "%s:%d: warning: ", | |
6c65299b RS |
6862 | DECL_SOURCE_FILE (method), DECL_SOURCE_LINE (method)); |
6863 | bzero (errbuf, BUFSIZE); | |
e31c7eec TW |
6864 | fprintf (stderr, "%s `%c%s'\n", |
6865 | message, mtype, gen_method_decl (method, errbuf)); | |
6c65299b RS |
6866 | } |
6867 | ||
0f41302f | 6868 | /* Return 1 if METHOD is consistent with PROTO. */ |
6c65299b RS |
6869 | |
6870 | static int | |
6871 | comp_method_with_proto (method, proto) | |
6872 | tree method, proto; | |
6873 | { | |
6874 | static tree function_type = 0; | |
6875 | ||
0f41302f | 6876 | /* Create a function_type node once. */ |
6c65299b RS |
6877 | if (!function_type) |
6878 | { | |
51900510 RK |
6879 | push_obstacks_nochange (); |
6880 | end_temporary_allocation (); | |
6c65299b | 6881 | function_type = make_node (FUNCTION_TYPE); |
51900510 | 6882 | pop_obstacks (); |
6c65299b RS |
6883 | } |
6884 | ||
e31c7eec | 6885 | /* Install argument types - normally set by build_function_type. */ |
6c65299b RS |
6886 | TYPE_ARG_TYPES (function_type) = get_arg_type_list (proto, METHOD_DEF, 0); |
6887 | ||
6888 | /* install return type */ | |
6889 | TREE_TYPE (function_type) = groktypename (TREE_TYPE (proto)); | |
6890 | ||
6891 | return comptypes (TREE_TYPE (METHOD_DEFINITION (method)), function_type); | |
6892 | } | |
6893 | ||
0f41302f | 6894 | /* Return 1 if PROTO1 is consistent with PROTO2. */ |
6c65299b RS |
6895 | |
6896 | static int | |
6897 | comp_proto_with_proto (proto1, proto2) | |
6898 | tree proto1, proto2; | |
6899 | { | |
6900 | static tree function_type1 = 0, function_type2 = 0; | |
6901 | ||
0f41302f | 6902 | /* Create a couple function_type node's once. */ |
6c65299b RS |
6903 | if (!function_type1) |
6904 | { | |
51900510 RK |
6905 | push_obstacks_nochange (); |
6906 | end_temporary_allocation (); | |
6c65299b RS |
6907 | function_type1 = make_node (FUNCTION_TYPE); |
6908 | function_type2 = make_node (FUNCTION_TYPE); | |
51900510 | 6909 | pop_obstacks (); |
6c65299b RS |
6910 | } |
6911 | ||
51900510 | 6912 | /* Install argument types; normally set by build_function_type. */ |
6c65299b RS |
6913 | TYPE_ARG_TYPES (function_type1) = get_arg_type_list (proto1, METHOD_REF, 0); |
6914 | TYPE_ARG_TYPES (function_type2) = get_arg_type_list (proto2, METHOD_REF, 0); | |
6915 | ||
0f41302f | 6916 | /* Install return type. */ |
6c65299b RS |
6917 | TREE_TYPE (function_type1) = groktypename (TREE_TYPE (proto1)); |
6918 | TREE_TYPE (function_type2) = groktypename (TREE_TYPE (proto2)); | |
6919 | ||
6920 | return comptypes (function_type1, function_type2); | |
6921 | } | |
6922 | ||
51900510 | 6923 | /* - Generate an identifier for the function. the format is "_n_cls", |
e31c7eec TW |
6924 | where 1 <= n <= nMethods, and cls is the name the implementation we |
6925 | are processing. | |
51900510 RK |
6926 | - Install the return type from the method declaration. |
6927 | - If we have a prototype, check for type consistency. */ | |
e31c7eec | 6928 | |
6c65299b RS |
6929 | static void |
6930 | really_start_method (method, parmlist) | |
6931 | tree method, parmlist; | |
6932 | { | |
6933 | tree sc_spec, ret_spec, ret_decl, decl_specs; | |
6934 | tree method_decl, method_id; | |
e31c7eec | 6935 | char *buf, *sel_name, *class_name, *cat_name; |
6c65299b | 6936 | |
0f41302f | 6937 | /* Synth the storage class & assemble the return type. */ |
51900510 | 6938 | sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE); |
6c65299b RS |
6939 | ret_spec = TREE_PURPOSE (TREE_TYPE (method)); |
6940 | decl_specs = chainon (sc_spec, ret_spec); | |
6941 | ||
e31c7eec TW |
6942 | sel_name = IDENTIFIER_POINTER (METHOD_SEL_NAME (method)); |
6943 | class_name = IDENTIFIER_POINTER (CLASS_NAME (implementation_context)); | |
6944 | cat_name = ((TREE_CODE (implementation_context) | |
6945 | == CLASS_IMPLEMENTATION_TYPE) | |
6946 | ? NULL | |
6947 | : IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_context))); | |
6948 | method_slot++; | |
51900510 | 6949 | |
e31c7eec TW |
6950 | /* Make sure this is big enough for any plausible method label. */ |
6951 | buf = (char *) alloca (50 + strlen (sel_name) + strlen (class_name) | |
6952 | + (cat_name ? strlen (cat_name) : 0)); | |
6953 | ||
6954 | OBJC_GEN_METHOD_LABEL (buf, TREE_CODE (method) == INSTANCE_METHOD_DECL, | |
6955 | class_name, cat_name, sel_name, method_slot); | |
6c65299b RS |
6956 | |
6957 | method_id = get_identifier (buf); | |
6958 | ||
51900510 | 6959 | method_decl = build_nt (CALL_EXPR, method_id, parmlist, NULL_TREE); |
6c65299b | 6960 | |
0f41302f | 6961 | /* Check the declarator portion of the return type for the method. */ |
e31c7eec | 6962 | if ((ret_decl = TREE_VALUE (TREE_TYPE (method)))) |
6c65299b | 6963 | { |
51900510 | 6964 | /* Unite the complex decl (specified in the abstract decl) with the |
e31c7eec | 6965 | function decl just synthesized..(int *), (int (*)()), (int (*)[]). */ |
6c65299b RS |
6966 | tree save_expr = expr_last (ret_decl); |
6967 | ||
6968 | TREE_OPERAND (save_expr, 0) = method_decl; | |
6969 | method_decl = ret_decl; | |
51900510 | 6970 | |
0f41302f | 6971 | /* Fool the parser into thinking it is starting a function. */ |
0763f3ab | 6972 | start_function (decl_specs, method_decl, NULL_TREE, NULL_TREE, 0); |
51900510 | 6973 | |
0f41302f | 6974 | /* Unhook: this has the effect of restoring the abstract declarator. */ |
51900510 | 6975 | TREE_OPERAND (save_expr, 0) = NULL_TREE; |
6c65299b | 6976 | } |
51900510 | 6977 | |
6c65299b RS |
6978 | else |
6979 | { | |
6980 | TREE_VALUE (TREE_TYPE (method)) = method_decl; | |
51900510 | 6981 | |
0f41302f | 6982 | /* Fool the parser into thinking it is starting a function. */ |
0763f3ab | 6983 | start_function (decl_specs, method_decl, NULL_TREE, NULL_TREE, 0); |
51900510 | 6984 | |
0f41302f | 6985 | /* Unhook: this has the effect of restoring the abstract declarator. */ |
51900510 | 6986 | TREE_VALUE (TREE_TYPE (method)) = NULL_TREE; |
6c65299b RS |
6987 | } |
6988 | ||
6989 | METHOD_DEFINITION (method) = current_function_decl; | |
6990 | ||
6c65299b RS |
6991 | if (implementation_template != implementation_context) |
6992 | { | |
e31c7eec | 6993 | tree proto; |
6c65299b RS |
6994 | |
6995 | if (TREE_CODE (method) == INSTANCE_METHOD_DECL) | |
e31c7eec TW |
6996 | proto = lookup_instance_method_static (implementation_template, |
6997 | METHOD_SEL_NAME (method)); | |
6c65299b | 6998 | else |
e31c7eec TW |
6999 | proto = lookup_class_method_static (implementation_template, |
7000 | METHOD_SEL_NAME (method)); | |
6c65299b | 7001 | |
e31c7eec | 7002 | if (proto && ! comp_method_with_proto (method, proto)) |
6c65299b | 7003 | { |
e31c7eec TW |
7004 | char type = (TREE_CODE (method) == INSTANCE_METHOD_DECL ? '-' : '+'); |
7005 | ||
7006 | warn_with_method ("conflicting types for", type, method); | |
7007 | warn_with_method ("previous declaration of", type, proto); | |
6c65299b RS |
7008 | } |
7009 | } | |
7010 | } | |
7011 | ||
e31c7eec TW |
7012 | /* The following routine is always called...this "architecture" is to |
7013 | accommodate "old-style" variable length selectors. | |
7014 | ||
7015 | - a:a b:b // prototype ; id c; id d; // old-style. */ | |
7016 | ||
6c65299b RS |
7017 | void |
7018 | continue_method_def () | |
7019 | { | |
7020 | tree parmlist; | |
7021 | ||
7022 | if (METHOD_ADD_ARGS (method_context) == (tree)1) | |
e31c7eec | 7023 | /* We have a `, ...' immediately following the selector. */ |
6c65299b RS |
7024 | parmlist = get_parm_info (0); |
7025 | else | |
7026 | parmlist = get_parm_info (1); /* place a `void_at_end' */ | |
7027 | ||
e31c7eec TW |
7028 | /* Set self_decl from the first argument...this global is used by |
7029 | build_ivar_reference calling build_indirect_ref. */ | |
6c65299b RS |
7030 | self_decl = TREE_PURPOSE (parmlist); |
7031 | ||
51900510 | 7032 | poplevel (0, 0, 0); |
6c65299b | 7033 | really_start_method (method_context, parmlist); |
51900510 | 7034 | store_parm_decls (); |
6c65299b RS |
7035 | } |
7036 | ||
e31c7eec TW |
7037 | /* Called by the parser, from the `pushlevel' production. */ |
7038 | ||
6c65299b RS |
7039 | void |
7040 | add_objc_decls () | |
7041 | { | |
e31c7eec TW |
7042 | if (!UOBJC_SUPER_decl) |
7043 | { | |
7044 | UOBJC_SUPER_decl = start_decl (get_identifier (UTAG_SUPER), | |
51900510 | 7045 | build_tree_list (NULL_TREE, |
e31c7eec | 7046 | objc_super_template), |
51900510 | 7047 | 0, NULL_TREE, NULL_TREE); |
e31c7eec | 7048 | |
51900510 | 7049 | finish_decl (UOBJC_SUPER_decl, NULL_TREE, NULL_TREE); |
6c65299b | 7050 | |
0f41302f | 7051 | /* This prevents `unused variable' warnings when compiling with -Wall. */ |
51900510 RK |
7052 | TREE_USED (UOBJC_SUPER_decl) = 1; |
7053 | DECL_ARTIFICIAL (UOBJC_SUPER_decl) = 1; | |
e31c7eec | 7054 | } |
6c65299b RS |
7055 | } |
7056 | ||
e31c7eec TW |
7057 | /* _n_Method (id self, SEL sel, ...) |
7058 | { | |
7059 | struct objc_super _S; | |
7060 | _msgSuper ((_S.self = self, _S.class = _cls, &_S), ...); | |
7061 | } */ | |
7062 | ||
6c65299b RS |
7063 | tree |
7064 | get_super_receiver () | |
7065 | { | |
7066 | if (method_context) | |
7067 | { | |
7068 | tree super_expr, super_expr_list; | |
7069 | ||
0f41302f | 7070 | /* Set receiver to self. */ |
e31c7eec | 7071 | super_expr = build_component_ref (UOBJC_SUPER_decl, self_id); |
6c65299b | 7072 | super_expr = build_modify_expr (super_expr, NOP_EXPR, self_decl); |
51900510 | 7073 | super_expr_list = build_tree_list (NULL_TREE, super_expr); |
6c65299b | 7074 | |
0f41302f | 7075 | /* Set class to begin searching. */ |
e31c7eec TW |
7076 | super_expr = build_component_ref (UOBJC_SUPER_decl, |
7077 | get_identifier ("class")); | |
6c65299b | 7078 | |
e31c7eec | 7079 | if (TREE_CODE (implementation_context) == CLASS_IMPLEMENTATION_TYPE) |
6c65299b | 7080 | { |
e31c7eec TW |
7081 | /* [_cls, __cls]Super are "pre-built" in |
7082 | synth_forward_declarations. */ | |
7083 | ||
7084 | super_expr = build_modify_expr (super_expr, NOP_EXPR, | |
7085 | ((TREE_CODE (method_context) | |
7086 | == INSTANCE_METHOD_DECL) | |
7087 | ? ucls_super_ref | |
7088 | : uucls_super_ref)); | |
6c65299b | 7089 | } |
51900510 RK |
7090 | |
7091 | else | |
0f41302f | 7092 | /* We have a category. */ |
6c65299b | 7093 | { |
e31c7eec TW |
7094 | tree super_name = CLASS_SUPER_NAME (implementation_template); |
7095 | tree super_class; | |
6c65299b | 7096 | |
51900510 | 7097 | if (!super_name) |
6c65299b | 7098 | { |
e31c7eec | 7099 | error ("no super class declared in interface for `%s'", |
6c65299b RS |
7100 | IDENTIFIER_POINTER (CLASS_NAME (implementation_template))); |
7101 | return error_mark_node; | |
7102 | } | |
7103 | ||
e31c7eec | 7104 | if (flag_next_runtime) |
f0052887 | 7105 | { |
e31c7eec TW |
7106 | super_class = get_class_reference (super_name); |
7107 | if (TREE_CODE (method_context) == CLASS_METHOD_DECL) | |
7108 | super_class | |
7109 | = build_component_ref (build_indirect_ref (super_class, "->"), | |
7110 | get_identifier ("isa")); | |
f0052887 | 7111 | } |
6c65299b | 7112 | else |
f0052887 | 7113 | { |
e31c7eec TW |
7114 | add_class_reference (super_name); |
7115 | super_class = (TREE_CODE (method_context) == INSTANCE_METHOD_DECL | |
7116 | ? objc_get_class_decl : objc_get_meta_class_decl); | |
7117 | assemble_external (super_class); | |
7118 | super_class | |
7119 | = build_function_call | |
7120 | (super_class, | |
51900510 RK |
7121 | build_tree_list |
7122 | (NULL_TREE, | |
7123 | my_build_string (IDENTIFIER_LENGTH (super_name) + 1, | |
7124 | IDENTIFIER_POINTER (super_name)))); | |
f0052887 | 7125 | } |
6c65299b | 7126 | |
e31c7eec TW |
7127 | TREE_TYPE (super_class) = TREE_TYPE (ucls_super_ref); |
7128 | super_expr = build_modify_expr (super_expr, NOP_EXPR, super_class); | |
6c65299b | 7129 | } |
51900510 | 7130 | |
6c65299b RS |
7131 | chainon (super_expr_list, build_tree_list (NULL_TREE, super_expr)); |
7132 | ||
e31c7eec | 7133 | super_expr = build_unary_op (ADDR_EXPR, UOBJC_SUPER_decl, 0); |
6c65299b RS |
7134 | chainon (super_expr_list, build_tree_list (NULL_TREE, super_expr)); |
7135 | ||
7136 | return build_compound_expr (super_expr_list); | |
7137 | } | |
7138 | else | |
7139 | { | |
7140 | error ("[super ...] must appear in a method context"); | |
7141 | return error_mark_node; | |
7142 | } | |
7143 | } | |
7144 | ||
7145 | static tree | |
7146 | encode_method_def (func_decl) | |
7147 | tree func_decl; | |
7148 | { | |
7149 | tree parms; | |
e31c7eec TW |
7150 | int stack_size; |
7151 | int max_parm_end = 0; | |
9dee6758 RS |
7152 | char buffer[40]; |
7153 | tree result; | |
6c65299b | 7154 | |
0f41302f | 7155 | /* Return type. */ |
9dee6758 | 7156 | encode_type (TREE_TYPE (TREE_TYPE (func_decl)), |
e31c7eec TW |
7157 | obstack_object_size (&util_obstack), |
7158 | OBJC_ENCODE_INLINE_DEFS); | |
51900510 | 7159 | |
0f41302f | 7160 | /* Stack size. */ |
6c65299b RS |
7161 | for (parms = DECL_ARGUMENTS (func_decl); parms; |
7162 | parms = TREE_CHAIN (parms)) | |
e31c7eec TW |
7163 | { |
7164 | int parm_end = (forwarding_offset (parms) | |
7165 | + (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (parms))) | |
7166 | / BITS_PER_UNIT)); | |
7167 | ||
30c0e2df | 7168 | if (!offset_is_register && parm_end > max_parm_end) |
e31c7eec TW |
7169 | max_parm_end = parm_end; |
7170 | } | |
7171 | ||
7172 | stack_size = max_parm_end - OBJC_FORWARDING_MIN_OFFSET; | |
6c65299b | 7173 | |
9dee6758 RS |
7174 | sprintf (buffer, "%d", stack_size); |
7175 | obstack_grow (&util_obstack, buffer, strlen (buffer)); | |
6c65299b | 7176 | |
0f41302f | 7177 | /* Argument types. */ |
6c65299b RS |
7178 | for (parms = DECL_ARGUMENTS (func_decl); parms; |
7179 | parms = TREE_CHAIN (parms)) | |
7180 | { | |
0f41302f | 7181 | /* Type. */ |
e31c7eec TW |
7182 | encode_type (TREE_TYPE (parms), |
7183 | obstack_object_size (&util_obstack), | |
7184 | OBJC_ENCODE_INLINE_DEFS); | |
7185 | ||
0f41302f | 7186 | /* Compute offset. */ |
e31c7eec | 7187 | sprintf (buffer, "%d", forwarding_offset (parms)); |
30c0e2df | 7188 | |
0f41302f | 7189 | /* Indicate register. */ |
30c0e2df KKT |
7190 | if (offset_is_register) |
7191 | obstack_1grow (&util_obstack, '+'); | |
7192 | ||
9dee6758 | 7193 | obstack_grow (&util_obstack, buffer, strlen (buffer)); |
6c65299b RS |
7194 | } |
7195 | ||
51900510 | 7196 | obstack_1grow (&util_obstack, 0); |
9dee6758 RS |
7197 | result = get_identifier (obstack_finish (&util_obstack)); |
7198 | obstack_free (&util_obstack, util_firstobj); | |
7199 | return result; | |
6c65299b RS |
7200 | } |
7201 | ||
7202 | void | |
7203 | finish_method_def () | |
7204 | { | |
e31c7eec | 7205 | METHOD_ENCODING (method_context) = encode_method_def (current_function_decl); |
6c65299b RS |
7206 | |
7207 | finish_function (0); | |
7208 | ||
51900510 RK |
7209 | /* Required to implement _msgSuper. This must be done AFTER finish_function, |
7210 | since the optimizer may find "may be used before set" errors. */ | |
7211 | method_context = NULL_TREE; | |
6c65299b RS |
7212 | } |
7213 | ||
7214 | int | |
7215 | lang_report_error_function (decl) | |
7216 | tree decl; | |
7217 | { | |
7218 | if (method_context) | |
7219 | { | |
7220 | fprintf (stderr, "In method `%s'\n", | |
7221 | IDENTIFIER_POINTER (METHOD_SEL_NAME (method_context))); | |
7222 | return 1; | |
7223 | } | |
51900510 | 7224 | |
6c65299b RS |
7225 | else |
7226 | return 0; | |
7227 | } | |
7228 | ||
7229 | static int | |
7230 | is_complex_decl (type) | |
7231 | tree type; | |
7232 | { | |
7233 | return (TREE_CODE (type) == ARRAY_TYPE | |
7234 | || TREE_CODE (type) == FUNCTION_TYPE | |
59ce3fc8 | 7235 | || (TREE_CODE (type) == POINTER_TYPE && ! IS_ID (type))); |
6c65299b RS |
7236 | } |
7237 | ||
7238 | \f | |
7239 | /* Code to convert a decl node into text for a declaration in C. */ | |
7240 | ||
7241 | static char tmpbuf[256]; | |
7242 | ||
7243 | static void | |
7244 | adorn_decl (decl, str) | |
7245 | tree decl; | |
7246 | char *str; | |
7247 | { | |
7248 | enum tree_code code = TREE_CODE (decl); | |
7249 | ||
7250 | if (code == ARRAY_REF) | |
7251 | { | |
e31c7eec | 7252 | tree an_int_cst = TREE_OPERAND (decl, 1); |
6c65299b | 7253 | |
e31c7eec TW |
7254 | if (an_int_cst && TREE_CODE (an_int_cst) == INTEGER_CST) |
7255 | sprintf (str + strlen (str), "[%d]", TREE_INT_CST_LOW (an_int_cst)); | |
7256 | else | |
7257 | strcat (str, "[]"); | |
6c65299b | 7258 | } |
51900510 | 7259 | |
6c65299b RS |
7260 | else if (code == ARRAY_TYPE) |
7261 | { | |
e31c7eec | 7262 | tree an_int_cst = TYPE_SIZE (decl); |
6c65299b RS |
7263 | tree array_of = TREE_TYPE (decl); |
7264 | ||
e31c7eec TW |
7265 | if (an_int_cst && TREE_CODE (an_int_cst) == INTEGER_TYPE) |
7266 | sprintf (str + strlen (str), "[%d]", | |
7267 | (TREE_INT_CST_LOW (an_int_cst) | |
7268 | / TREE_INT_CST_LOW (TYPE_SIZE (array_of)))); | |
7269 | else | |
7270 | strcat (str, "[]"); | |
6c65299b | 7271 | } |
51900510 | 7272 | |
6c65299b | 7273 | else if (code == CALL_EXPR) |
e31c7eec TW |
7274 | { |
7275 | tree chain = TREE_PURPOSE (TREE_OPERAND (decl, 1)); | |
7276 | ||
7277 | strcat (str, "("); | |
7278 | while (chain) | |
7279 | { | |
7280 | gen_declaration (chain, str); | |
7281 | chain = TREE_CHAIN (chain); | |
7282 | if (chain) | |
7283 | strcat (str, ", "); | |
7284 | } | |
7285 | strcat (str, ")"); | |
7286 | } | |
51900510 | 7287 | |
6c65299b RS |
7288 | else if (code == FUNCTION_TYPE) |
7289 | { | |
51900510 | 7290 | tree chain = TYPE_ARG_TYPES (decl); |
e31c7eec | 7291 | |
6c65299b RS |
7292 | strcat (str, "("); |
7293 | while (chain && TREE_VALUE (chain) != void_type_node) | |
7294 | { | |
7295 | gen_declaration (TREE_VALUE (chain), str); | |
7296 | chain = TREE_CHAIN (chain); | |
7297 | if (chain && TREE_VALUE (chain) != void_type_node) | |
e31c7eec | 7298 | strcat (str, ", "); |
6c65299b RS |
7299 | } |
7300 | strcat (str, ")"); | |
7301 | } | |
51900510 | 7302 | |
e31c7eec TW |
7303 | else if (code == INDIRECT_REF) |
7304 | { | |
7305 | strcpy (tmpbuf, "*"); | |
7306 | if (TREE_TYPE (decl) && TREE_CODE (TREE_TYPE (decl)) == TREE_LIST) | |
7307 | { | |
7308 | tree chain; | |
7309 | ||
7310 | for (chain = nreverse (copy_list (TREE_TYPE (decl))); | |
7311 | chain; | |
7312 | chain = TREE_CHAIN (chain)) | |
7313 | { | |
7314 | if (TREE_CODE (TREE_VALUE (chain)) == IDENTIFIER_NODE) | |
7315 | { | |
7316 | strcat (tmpbuf, " "); | |
7317 | strcat (tmpbuf, IDENTIFIER_POINTER (TREE_VALUE (chain))); | |
7318 | } | |
7319 | } | |
7320 | if (str[0]) | |
7321 | strcat (tmpbuf, " "); | |
7322 | } | |
7323 | strcat (tmpbuf, str); | |
7324 | strcpy (str, tmpbuf); | |
7325 | } | |
51900510 | 7326 | |
e31c7eec | 7327 | else if (code == POINTER_TYPE) |
6c65299b | 7328 | { |
e31c7eec TW |
7329 | strcpy (tmpbuf, "*"); |
7330 | if (TREE_READONLY (decl) || TYPE_VOLATILE (decl)) | |
7331 | { | |
7332 | if (TREE_READONLY (decl)) | |
7333 | strcat (tmpbuf, " const"); | |
7334 | if (TYPE_VOLATILE (decl)) | |
7335 | strcat (tmpbuf, " volatile"); | |
7336 | if (str[0]) | |
7337 | strcat (tmpbuf, " "); | |
7338 | } | |
7339 | strcat (tmpbuf, str); | |
6c65299b RS |
7340 | strcpy (str, tmpbuf); |
7341 | } | |
7342 | } | |
7343 | ||
7344 | static char * | |
7345 | gen_declarator (decl, buf, name) | |
7346 | tree decl; | |
7347 | char *buf; | |
7348 | char *name; | |
7349 | { | |
7350 | if (decl) | |
7351 | { | |
7352 | enum tree_code code = TREE_CODE (decl); | |
7353 | char *str; | |
7354 | tree op; | |
7355 | int wrap = 0; | |
7356 | ||
7357 | switch (code) | |
7358 | { | |
e31c7eec TW |
7359 | case ARRAY_REF: |
7360 | case INDIRECT_REF: | |
7361 | case CALL_EXPR: | |
7362 | op = TREE_OPERAND (decl, 0); | |
6c65299b | 7363 | |
51900510 | 7364 | /* We have a pointer to a function or array...(*)(), (*)[] */ |
e31c7eec TW |
7365 | if ((code == ARRAY_REF || code == CALL_EXPR) |
7366 | && op && TREE_CODE (op) == INDIRECT_REF) | |
7367 | wrap = 1; | |
6c65299b | 7368 | |
e31c7eec | 7369 | str = gen_declarator (op, buf, name); |
6c65299b | 7370 | |
e31c7eec TW |
7371 | if (wrap) |
7372 | { | |
7373 | strcpy (tmpbuf, "("); | |
7374 | strcat (tmpbuf, str); | |
7375 | strcat (tmpbuf, ")"); | |
7376 | strcpy (str, tmpbuf); | |
7377 | } | |
6c65299b | 7378 | |
e31c7eec TW |
7379 | adorn_decl (decl, str); |
7380 | break; | |
6c65299b | 7381 | |
e31c7eec TW |
7382 | case ARRAY_TYPE: |
7383 | case FUNCTION_TYPE: | |
7384 | case POINTER_TYPE: | |
59ce3fc8 TW |
7385 | strcpy (buf, name); |
7386 | str = buf; | |
6c65299b | 7387 | |
0f41302f | 7388 | /* This clause is done iteratively rather than recursively. */ |
e31c7eec TW |
7389 | do |
7390 | { | |
7391 | op = (is_complex_decl (TREE_TYPE (decl)) | |
51900510 | 7392 | ? TREE_TYPE (decl) : NULL_TREE); |
6c65299b | 7393 | |
e31c7eec | 7394 | adorn_decl (decl, str); |
6c65299b | 7395 | |
51900510 | 7396 | /* We have a pointer to a function or array...(*)(), (*)[] */ |
e31c7eec TW |
7397 | if (code == POINTER_TYPE |
7398 | && op && (TREE_CODE (op) == FUNCTION_TYPE | |
7399 | || TREE_CODE (op) == ARRAY_TYPE)) | |
7400 | { | |
7401 | strcpy (tmpbuf, "("); | |
7402 | strcat (tmpbuf, str); | |
7403 | strcat (tmpbuf, ")"); | |
7404 | strcpy (str, tmpbuf); | |
7405 | } | |
7406 | ||
7407 | decl = (is_complex_decl (TREE_TYPE (decl)) | |
51900510 | 7408 | ? TREE_TYPE (decl) : NULL_TREE); |
e31c7eec | 7409 | } |
51900510 RK |
7410 | |
7411 | while (decl && (code = TREE_CODE (decl))) | |
7412 | ; | |
e31c7eec TW |
7413 | |
7414 | break; | |
6c65299b | 7415 | |
6c65299b | 7416 | case IDENTIFIER_NODE: |
0f41302f | 7417 | /* Will only happen if we are processing a "raw" expr-decl. */ |
59ce3fc8 TW |
7418 | strcpy (buf, IDENTIFIER_POINTER (decl)); |
7419 | return buf; | |
6c65299b RS |
7420 | } |
7421 | ||
7422 | return str; | |
7423 | } | |
51900510 RK |
7424 | |
7425 | else | |
0f41302f | 7426 | /* We have an abstract declarator or a _DECL node. */ |
59ce3fc8 TW |
7427 | { |
7428 | strcpy (buf, name); | |
7429 | return buf; | |
7430 | } | |
6c65299b RS |
7431 | } |
7432 | ||
7433 | static void | |
7434 | gen_declspecs (declspecs, buf, raw) | |
7435 | tree declspecs; | |
7436 | char *buf; | |
7437 | int raw; | |
7438 | { | |
7439 | if (raw) | |
7440 | { | |
7441 | tree chain; | |
7442 | ||
e31c7eec TW |
7443 | for (chain = nreverse (copy_list (declspecs)); |
7444 | chain; chain = TREE_CHAIN (chain)) | |
6c65299b RS |
7445 | { |
7446 | tree aspec = TREE_VALUE (chain); | |
7447 | ||
7448 | if (TREE_CODE (aspec) == IDENTIFIER_NODE) | |
7449 | strcat (buf, IDENTIFIER_POINTER (aspec)); | |
7450 | else if (TREE_CODE (aspec) == RECORD_TYPE) | |
7451 | { | |
7452 | if (TYPE_NAME (aspec)) | |
7453 | { | |
e31c7eec TW |
7454 | tree protocol_list = TYPE_PROTOCOL_LIST (aspec); |
7455 | ||
7456 | if (! TREE_STATIC_TEMPLATE (aspec)) | |
6c65299b RS |
7457 | strcat (buf, "struct "); |
7458 | strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (aspec))); | |
e31c7eec TW |
7459 | |
7460 | /* NEW!!! */ | |
7461 | if (protocol_list) | |
7462 | { | |
7463 | tree chain = protocol_list; | |
7464 | ||
7465 | strcat (buf, " <"); | |
7466 | while (chain) | |
7467 | { | |
51900510 RK |
7468 | strcat (buf, |
7469 | IDENTIFIER_POINTER | |
7470 | (PROTOCOL_NAME (TREE_VALUE (chain)))); | |
e31c7eec TW |
7471 | chain = TREE_CHAIN (chain); |
7472 | if (chain) | |
7473 | strcat (buf, ", "); | |
7474 | } | |
7475 | strcat (buf, ">"); | |
7476 | } | |
6c65299b | 7477 | } |
51900510 | 7478 | |
6c65299b RS |
7479 | else |
7480 | strcat (buf, "untagged struct"); | |
7481 | } | |
51900510 | 7482 | |
6c65299b RS |
7483 | else if (TREE_CODE (aspec) == UNION_TYPE) |
7484 | { | |
7485 | if (TYPE_NAME (aspec)) | |
7486 | { | |
e31c7eec | 7487 | if (! TREE_STATIC_TEMPLATE (aspec)) |
6c65299b RS |
7488 | strcat (buf, "union "); |
7489 | strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (aspec))); | |
7490 | } | |
7491 | else | |
7492 | strcat (buf, "untagged union"); | |
7493 | } | |
51900510 | 7494 | |
6c65299b RS |
7495 | else if (TREE_CODE (aspec) == ENUMERAL_TYPE) |
7496 | { | |
7497 | if (TYPE_NAME (aspec)) | |
7498 | { | |
e31c7eec | 7499 | if (! TREE_STATIC_TEMPLATE (aspec)) |
6c65299b RS |
7500 | strcat (buf, "enum "); |
7501 | strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (aspec))); | |
7502 | } | |
7503 | else | |
7504 | strcat (buf, "untagged enum"); | |
7505 | } | |
51900510 | 7506 | |
e31c7eec | 7507 | else if (TREE_CODE (aspec) == TYPE_DECL && DECL_NAME (aspec)) |
51900510 RK |
7508 | strcat (buf, IDENTIFIER_POINTER (DECL_NAME (aspec))); |
7509 | ||
59ce3fc8 | 7510 | else if (IS_ID (aspec)) |
e31c7eec TW |
7511 | { |
7512 | tree protocol_list = TYPE_PROTOCOL_LIST (aspec); | |
7513 | ||
7514 | strcat (buf, "id"); | |
7515 | if (protocol_list) | |
7516 | { | |
7517 | tree chain = protocol_list; | |
7518 | ||
7519 | strcat (buf, " <"); | |
7520 | while (chain) | |
7521 | { | |
51900510 RK |
7522 | strcat (buf, |
7523 | IDENTIFIER_POINTER | |
7524 | (PROTOCOL_NAME (TREE_VALUE (chain)))); | |
e31c7eec TW |
7525 | chain = TREE_CHAIN (chain); |
7526 | if (chain) | |
7527 | strcat (buf, ", "); | |
7528 | } | |
7529 | strcat (buf, ">"); | |
7530 | } | |
7531 | } | |
7532 | if (TREE_CHAIN (chain)) | |
7533 | strcat (buf, " "); | |
6c65299b RS |
7534 | } |
7535 | } | |
7536 | else | |
e31c7eec | 7537 | { |
0f41302f | 7538 | /* Type qualifiers. */ |
51900510 RK |
7539 | if (TREE_READONLY (declspecs)) |
7540 | strcat (buf, "const "); | |
7541 | if (TYPE_VOLATILE (declspecs)) | |
7542 | strcat (buf, "volatile "); | |
e31c7eec | 7543 | |
51900510 RK |
7544 | switch (TREE_CODE (declspecs)) |
7545 | { | |
0f41302f | 7546 | /* Type specifiers. */ |
51900510 RK |
7547 | |
7548 | case INTEGER_TYPE: | |
7549 | declspecs = TYPE_MAIN_VARIANT (declspecs); | |
7550 | ||
7551 | /* Signed integer types. */ | |
7552 | ||
7553 | if (declspecs == short_integer_type_node) | |
7554 | strcat (buf, "short int "); | |
7555 | else if (declspecs == integer_type_node) | |
7556 | strcat (buf, "int "); | |
7557 | else if (declspecs == long_integer_type_node) | |
7558 | strcat (buf, "long int "); | |
7559 | else if (declspecs == long_long_integer_type_node) | |
7560 | strcat (buf, "long long int "); | |
7561 | else if (declspecs == signed_char_type_node | |
7562 | || declspecs == char_type_node) | |
7563 | strcat (buf, "char "); | |
7564 | ||
0f41302f | 7565 | /* Unsigned integer types. */ |
51900510 RK |
7566 | |
7567 | else if (declspecs == short_unsigned_type_node) | |
7568 | strcat (buf, "unsigned short "); | |
7569 | else if (declspecs == unsigned_type_node) | |
7570 | strcat (buf, "unsigned int "); | |
7571 | else if (declspecs == long_unsigned_type_node) | |
7572 | strcat (buf, "unsigned long "); | |
7573 | else if (declspecs == long_long_unsigned_type_node) | |
7574 | strcat (buf, "unsigned long long "); | |
7575 | else if (declspecs == unsigned_char_type_node) | |
7576 | strcat (buf, "unsigned char "); | |
7577 | break; | |
6c65299b | 7578 | |
51900510 RK |
7579 | case REAL_TYPE: |
7580 | declspecs = TYPE_MAIN_VARIANT (declspecs); | |
6c65299b | 7581 | |
51900510 RK |
7582 | if (declspecs == float_type_node) |
7583 | strcat (buf, "float "); | |
7584 | else if (declspecs == double_type_node) | |
7585 | strcat (buf, "double "); | |
7586 | else if (declspecs == long_double_type_node) | |
7587 | strcat (buf, "long double "); | |
7588 | break; | |
6c65299b RS |
7589 | |
7590 | case RECORD_TYPE: | |
51900510 RK |
7591 | if (TYPE_NAME (declspecs) |
7592 | && TREE_CODE (TYPE_NAME (declspecs)) == IDENTIFIER_NODE) | |
7593 | { | |
7594 | tree protocol_list = TYPE_PROTOCOL_LIST (declspecs); | |
7595 | ||
7596 | if (! TREE_STATIC_TEMPLATE (declspecs)) | |
7597 | strcat (buf, "struct "); | |
7598 | strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (declspecs))); | |
7599 | ||
7600 | if (protocol_list) | |
7601 | { | |
7602 | tree chain = protocol_list; | |
7603 | ||
7604 | strcat (buf, " <"); | |
7605 | while (chain) | |
7606 | { | |
7607 | strcat (buf, | |
7608 | IDENTIFIER_POINTER | |
7609 | (PROTOCOL_NAME (TREE_VALUE (chain)))); | |
7610 | chain = TREE_CHAIN (chain); | |
7611 | if (chain) | |
7612 | strcat (buf, ", "); | |
7613 | } | |
7614 | strcat (buf, ">"); | |
7615 | } | |
7616 | } | |
7617 | ||
7618 | else | |
7619 | strcat (buf, "untagged struct"); | |
7620 | ||
7621 | strcat (buf, " "); | |
7622 | break; | |
7623 | ||
7624 | case UNION_TYPE: | |
7625 | if (TYPE_NAME (declspecs) | |
7626 | && TREE_CODE (TYPE_NAME (declspecs)) == IDENTIFIER_NODE) | |
7627 | { | |
7628 | strcat (buf, "union "); | |
7629 | strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (declspecs))); | |
7630 | strcat (buf, " "); | |
7631 | } | |
7632 | ||
7633 | else | |
7634 | strcat (buf, "untagged union "); | |
7635 | break; | |
7636 | ||
7637 | case ENUMERAL_TYPE: | |
7638 | if (TYPE_NAME (declspecs) | |
7639 | && TREE_CODE (TYPE_NAME (declspecs)) == IDENTIFIER_NODE) | |
7640 | { | |
7641 | strcat (buf, "enum "); | |
7642 | strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (declspecs))); | |
7643 | strcat (buf, " "); | |
7644 | } | |
7645 | ||
7646 | else | |
7647 | strcat (buf, "untagged enum "); | |
7648 | break; | |
7649 | ||
7650 | case VOID_TYPE: | |
7651 | strcat (buf, "void "); | |
7652 | break; | |
7653 | ||
7654 | case POINTER_TYPE: | |
6c65299b | 7655 | { |
e31c7eec TW |
7656 | tree protocol_list = TYPE_PROTOCOL_LIST (declspecs); |
7657 | ||
51900510 | 7658 | strcat (buf, "id"); |
e31c7eec TW |
7659 | if (protocol_list) |
7660 | { | |
7661 | tree chain = protocol_list; | |
7662 | ||
7663 | strcat (buf, " <"); | |
7664 | while (chain) | |
7665 | { | |
51900510 RK |
7666 | strcat (buf, |
7667 | IDENTIFIER_POINTER | |
7668 | (PROTOCOL_NAME (TREE_VALUE (chain)))); | |
e31c7eec TW |
7669 | chain = TREE_CHAIN (chain); |
7670 | if (chain) | |
7671 | strcat (buf, ", "); | |
7672 | } | |
51900510 | 7673 | |
e31c7eec TW |
7674 | strcat (buf, ">"); |
7675 | } | |
6c65299b | 7676 | } |
e31c7eec | 7677 | } |
e31c7eec | 7678 | } |
6c65299b RS |
7679 | } |
7680 | ||
7681 | static char * | |
7682 | gen_declaration (atype_or_adecl, buf) | |
7683 | tree atype_or_adecl; | |
7684 | char *buf; | |
7685 | { | |
7686 | char declbuf[256]; | |
7687 | ||
7688 | if (TREE_CODE (atype_or_adecl) == TREE_LIST) | |
7689 | { | |
e31c7eec | 7690 | tree declspecs; /* "identifier_node", "record_type" */ |
0f41302f | 7691 | tree declarator; /* "array_ref", "indirect_ref", "call_expr"... */ |
6c65299b | 7692 | |
0f41302f | 7693 | /* We have a "raw", abstract declarator (typename). */ |
6c65299b RS |
7694 | declarator = TREE_VALUE (atype_or_adecl); |
7695 | declspecs = TREE_PURPOSE (atype_or_adecl); | |
7696 | ||
7697 | gen_declspecs (declspecs, buf, 1); | |
e31c7eec TW |
7698 | if (declarator) |
7699 | { | |
7700 | strcat (buf, " "); | |
7701 | strcat (buf, gen_declarator (declarator, declbuf, "")); | |
7702 | } | |
6c65299b | 7703 | } |
51900510 | 7704 | |
6c65299b RS |
7705 | else |
7706 | { | |
7707 | tree atype; | |
0f41302f MS |
7708 | tree declspecs; /* "integer_type", "real_type", "record_type"... */ |
7709 | tree declarator; /* "array_type", "function_type", "pointer_type". */ | |
6c65299b RS |
7710 | |
7711 | if (TREE_CODE (atype_or_adecl) == FIELD_DECL | |
7712 | || TREE_CODE (atype_or_adecl) == PARM_DECL | |
7713 | || TREE_CODE (atype_or_adecl) == FUNCTION_DECL) | |
7714 | atype = TREE_TYPE (atype_or_adecl); | |
7715 | else | |
0f41302f | 7716 | /* Assume we have a *_type node. */ |
51900510 | 7717 | atype = atype_or_adecl; |
6c65299b RS |
7718 | |
7719 | if (is_complex_decl (atype)) | |
7720 | { | |
7721 | tree chain; | |
7722 | ||
0f41302f | 7723 | /* Get the declaration specifier; it is at the end of the list. */ |
6c65299b RS |
7724 | declarator = chain = atype; |
7725 | do | |
7726 | chain = TREE_TYPE (chain); /* not TREE_CHAIN (chain); */ | |
7727 | while (is_complex_decl (chain)); | |
7728 | declspecs = chain; | |
7729 | } | |
51900510 | 7730 | |
6c65299b RS |
7731 | else |
7732 | { | |
7733 | declspecs = atype; | |
51900510 | 7734 | declarator = NULL_TREE; |
6c65299b RS |
7735 | } |
7736 | ||
7737 | gen_declspecs (declspecs, buf, 0); | |
7738 | ||
7739 | if (TREE_CODE (atype_or_adecl) == FIELD_DECL | |
7740 | || TREE_CODE (atype_or_adecl) == PARM_DECL | |
7741 | || TREE_CODE (atype_or_adecl) == FUNCTION_DECL) | |
7742 | { | |
e31c7eec TW |
7743 | char *decl_name = (DECL_NAME (atype_or_adecl) |
7744 | ? IDENTIFIER_POINTER (DECL_NAME (atype_or_adecl)) | |
7745 | : ""); | |
7746 | ||
6c65299b RS |
7747 | if (declarator) |
7748 | { | |
e31c7eec TW |
7749 | strcat (buf, " "); |
7750 | strcat (buf, gen_declarator (declarator, declbuf, decl_name)); | |
7751 | } | |
51900510 | 7752 | |
e31c7eec TW |
7753 | else if (decl_name[0]) |
7754 | { | |
7755 | strcat (buf, " "); | |
7756 | strcat (buf, decl_name); | |
6c65299b | 7757 | } |
6c65299b | 7758 | } |
e31c7eec | 7759 | else if (declarator) |
6c65299b | 7760 | { |
e31c7eec | 7761 | strcat (buf, " "); |
6c65299b RS |
7762 | strcat (buf, gen_declarator (declarator, declbuf, "")); |
7763 | } | |
7764 | } | |
51900510 | 7765 | |
6c65299b RS |
7766 | return buf; |
7767 | } | |
7768 | ||
7769 | #define RAW_TYPESPEC(meth) (TREE_VALUE (TREE_PURPOSE (TREE_TYPE (meth)))) | |
7770 | ||
7771 | static char * | |
7772 | gen_method_decl (method, buf) | |
7773 | tree method; | |
7774 | char *buf; | |
7775 | { | |
7776 | tree chain; | |
7777 | ||
7778 | if (RAW_TYPESPEC (method) != objc_object_reference) | |
7779 | { | |
7780 | strcpy (buf, "("); | |
7781 | gen_declaration (TREE_TYPE (method), buf); | |
7782 | strcat (buf, ")"); | |
7783 | } | |
7784 | ||
7785 | chain = METHOD_SEL_ARGS (method); | |
7786 | if (chain) | |
51900510 | 7787 | { |
0f41302f | 7788 | /* We have a chain of keyword_decls. */ |
6c65299b RS |
7789 | do |
7790 | { | |
7791 | if (KEYWORD_KEY_NAME (chain)) | |
7792 | strcat (buf, IDENTIFIER_POINTER (KEYWORD_KEY_NAME (chain))); | |
7793 | ||
7794 | strcat (buf, ":"); | |
7795 | if (RAW_TYPESPEC (chain) != objc_object_reference) | |
7796 | { | |
7797 | strcat (buf, "("); | |
7798 | gen_declaration (TREE_TYPE (chain), buf); | |
7799 | strcat (buf, ")"); | |
7800 | } | |
51900510 | 7801 | |
6c65299b | 7802 | strcat (buf, IDENTIFIER_POINTER (KEYWORD_ARG_NAME (chain))); |
e31c7eec | 7803 | if ((chain = TREE_CHAIN (chain))) |
6c65299b RS |
7804 | strcat (buf, " "); |
7805 | } | |
7806 | while (chain); | |
7807 | ||
7808 | if (METHOD_ADD_ARGS (method) == (tree)1) | |
7809 | strcat (buf, ", ..."); | |
7810 | else if (METHOD_ADD_ARGS (method)) | |
e31c7eec | 7811 | { |
51900510 | 7812 | /* We have a tree list node as generate by get_parm_info. */ |
6c65299b | 7813 | chain = TREE_PURPOSE (METHOD_ADD_ARGS (method)); |
51900510 | 7814 | |
0f41302f | 7815 | /* Know we have a chain of parm_decls. */ |
6c65299b RS |
7816 | while (chain) |
7817 | { | |
7818 | strcat (buf, ", "); | |
7819 | gen_declaration (chain, buf); | |
7820 | chain = TREE_CHAIN (chain); | |
7821 | } | |
7822 | } | |
7823 | } | |
51900510 RK |
7824 | |
7825 | else | |
0f41302f | 7826 | /* We have a unary selector. */ |
e31c7eec | 7827 | strcat (buf, IDENTIFIER_POINTER (METHOD_SEL_NAME (method))); |
6c65299b RS |
7828 | |
7829 | return buf; | |
7830 | } | |
51900510 RK |
7831 | \f |
7832 | /* Debug info. */ | |
e31c7eec | 7833 | |
6c65299b RS |
7834 | static void |
7835 | dump_interface (fp, chain) | |
7836 | FILE *fp; | |
7837 | tree chain; | |
7838 | { | |
7839 | char *buf = (char *)xmalloc (256); | |
7840 | char *my_name = IDENTIFIER_POINTER (CLASS_NAME (chain)); | |
7841 | tree ivar_decls = CLASS_RAW_IVARS (chain); | |
7842 | tree nst_methods = CLASS_NST_METHODS (chain); | |
7843 | tree cls_methods = CLASS_CLS_METHODS (chain); | |
7844 | ||
7845 | fprintf (fp, "\n@interface %s", my_name); | |
7846 | ||
7847 | if (CLASS_SUPER_NAME (chain)) | |
7848 | { | |
7849 | char *super_name = IDENTIFIER_POINTER (CLASS_SUPER_NAME (chain)); | |
7850 | fprintf (fp, " : %s\n", super_name); | |
7851 | } | |
7852 | else | |
7853 | fprintf (fp, "\n"); | |
7854 | ||
7855 | if (ivar_decls) | |
7856 | { | |
7857 | fprintf (fp, "{\n"); | |
7858 | do | |
7859 | { | |
7860 | bzero (buf, 256); | |
7861 | fprintf (fp, "\t%s;\n", gen_declaration (ivar_decls, buf)); | |
7862 | ivar_decls = TREE_CHAIN (ivar_decls); | |
7863 | } | |
7864 | while (ivar_decls); | |
7865 | fprintf (fp, "}\n"); | |
7866 | } | |
7867 | ||
7868 | while (nst_methods) | |
7869 | { | |
7870 | bzero (buf, 256); | |
7871 | fprintf (fp, "- %s;\n", gen_method_decl (nst_methods, buf)); | |
7872 | nst_methods = TREE_CHAIN (nst_methods); | |
7873 | } | |
7874 | ||
7875 | while (cls_methods) | |
7876 | { | |
7877 | bzero (buf, 256); | |
7878 | fprintf (fp, "+ %s;\n", gen_method_decl (cls_methods, buf)); | |
7879 | cls_methods = TREE_CHAIN (cls_methods); | |
7880 | } | |
7881 | fprintf (fp, "\n@end"); | |
7882 | } | |
7883 | ||
e31c7eec | 7884 | static void |
6c65299b RS |
7885 | init_objc () |
7886 | { | |
7887 | /* Add the special tree codes of Objective C to the tables. */ | |
7888 | ||
e31c7eec TW |
7889 | #define LAST_CODE LAST_AND_UNUSED_TREE_CODE |
7890 | ||
9dee6758 RS |
7891 | gcc_obstack_init (&util_obstack); |
7892 | util_firstobj = (char *) obstack_finish (&util_obstack); | |
7893 | ||
6c65299b | 7894 | tree_code_type |
f79322f0 RS |
7895 | = (char **) xrealloc (tree_code_type, |
7896 | sizeof (char *) * LAST_OBJC_TREE_CODE); | |
6c65299b | 7897 | tree_code_length |
f79322f0 RS |
7898 | = (int *) xrealloc (tree_code_length, |
7899 | sizeof (int) * LAST_OBJC_TREE_CODE); | |
6c65299b | 7900 | tree_code_name |
f79322f0 RS |
7901 | = (char **) xrealloc (tree_code_name, |
7902 | sizeof (char *) * LAST_OBJC_TREE_CODE); | |
a2991183 RK |
7903 | bcopy ((char *) objc_tree_code_type, |
7904 | (char *) (tree_code_type + (int) LAST_CODE), | |
e31c7eec | 7905 | (((int) LAST_OBJC_TREE_CODE - (int) LAST_CODE) |
6c65299b | 7906 | * sizeof (char *))); |
a2991183 RK |
7907 | bcopy ((char *) objc_tree_code_length, |
7908 | (char *) (tree_code_length + (int) LAST_CODE), | |
e31c7eec | 7909 | (((int) LAST_OBJC_TREE_CODE - (int) LAST_CODE) |
6c65299b | 7910 | * sizeof (int))); |
a2991183 RK |
7911 | bcopy ((char *) objc_tree_code_name, |
7912 | (char *) (tree_code_name + (int) LAST_CODE), | |
e31c7eec | 7913 | (((int) LAST_OBJC_TREE_CODE - (int) LAST_CODE) |
6c65299b RS |
7914 | * sizeof (char *))); |
7915 | ||
7916 | errbuf = (char *)xmalloc (BUFSIZE); | |
6c65299b RS |
7917 | hash_init (); |
7918 | synth_module_prologue (); | |
7919 | } | |
9dee6758 | 7920 | \f |
e31c7eec | 7921 | static void |
6c65299b RS |
7922 | finish_objc () |
7923 | { | |
7924 | struct imp_entry *impent; | |
7925 | tree chain; | |
e31c7eec TW |
7926 | /* The internally generated initializers appear to have missing braces. |
7927 | Don't warn about this. */ | |
7928 | int save_warn_missing_braces = warn_missing_braces; | |
7929 | warn_missing_braces = 0; | |
6c65299b RS |
7930 | |
7931 | generate_forward_declaration_to_string_table (); | |
7932 | ||
7933 | #ifdef OBJC_PROLOGUE | |
7934 | OBJC_PROLOGUE; | |
7935 | #endif | |
7936 | ||
e31c7eec TW |
7937 | if (implementation_context || class_names_chain |
7938 | || meth_var_names_chain || meth_var_types_chain || sel_ref_chain) | |
6c65299b RS |
7939 | generate_objc_symtab_decl (); |
7940 | ||
7941 | for (impent = imp_list; impent; impent = impent->next) | |
7942 | { | |
7943 | implementation_context = impent->imp_context; | |
7944 | implementation_template = impent->imp_template; | |
7945 | ||
e31c7eec TW |
7946 | UOBJC_CLASS_decl = impent->class_decl; |
7947 | UOBJC_METACLASS_decl = impent->meta_decl; | |
6c65299b | 7948 | |
e31c7eec | 7949 | if (TREE_CODE (implementation_context) == CLASS_IMPLEMENTATION_TYPE) |
6c65299b RS |
7950 | { |
7951 | /* all of the following reference the string pool... */ | |
7952 | generate_ivar_lists (); | |
7953 | generate_dispatch_tables (); | |
7954 | generate_shared_structures (); | |
7955 | } | |
7956 | else | |
7957 | { | |
7958 | generate_dispatch_tables (); | |
7959 | generate_category (implementation_context); | |
7960 | } | |
7961 | } | |
7962 | ||
0e9934c8 RS |
7963 | /* If we are using an array of selectors, we must always |
7964 | finish up the array decl even if no selectors were used. */ | |
e31c7eec | 7965 | if (! flag_next_runtime || sel_ref_chain) |
6c65299b RS |
7966 | build_selector_translation_table (); |
7967 | ||
e31c7eec TW |
7968 | if (protocol_chain) |
7969 | generate_protocols (); | |
7970 | ||
4cb8c14b RK |
7971 | if (objc_static_instances) |
7972 | generate_static_references (); | |
7973 | ||
7974 | if (implementation_context || class_names_chain || objc_static_instances | |
e31c7eec | 7975 | || meth_var_names_chain || meth_var_types_chain || sel_ref_chain) |
6c65299b RS |
7976 | { |
7977 | /* Arrange for Objc data structures to be initialized at run time. */ | |
6c65299b | 7978 | char *init_name = build_module_descriptor (); |
b3a5ad9c RS |
7979 | if (init_name) |
7980 | assemble_constructor (init_name); | |
6c65299b RS |
7981 | } |
7982 | ||
51900510 | 7983 | /* Dump the class references. This forces the appropriate classes |
6c65299b | 7984 | to be linked into the executable image, preserving unix archive |
51900510 | 7985 | semantics. This can be removed when we move to a more dynamically |
e31c7eec | 7986 | linked environment. */ |
51900510 | 7987 | |
6c65299b | 7988 | for (chain = cls_ref_chain; chain; chain = TREE_CHAIN (chain)) |
e31c7eec TW |
7989 | { |
7990 | handle_class_ref (chain); | |
7991 | if (TREE_PURPOSE (chain)) | |
7992 | generate_classref_translation_entry (chain); | |
7993 | } | |
6c65299b RS |
7994 | |
7995 | for (impent = imp_list; impent; impent = impent->next) | |
9dee6758 | 7996 | handle_impent (impent); |
6c65299b | 7997 | |
0f41302f | 7998 | /* Dump the string table last. */ |
e31c7eec TW |
7999 | |
8000 | generate_strings (); | |
6c65299b RS |
8001 | |
8002 | if (flag_gen_declaration) | |
8003 | { | |
8004 | add_class (implementation_context); | |
8005 | dump_interface (gen_declaration_file, implementation_context); | |
8006 | } | |
e31c7eec | 8007 | |
6c65299b RS |
8008 | if (warn_selector) |
8009 | { | |
8010 | int slot; | |
e31c7eec TW |
8011 | hash hsh; |
8012 | ||
6c65299b | 8013 | /* Run through the selector hash tables and print a warning for any |
0f41302f | 8014 | selector which has multiple methods. */ |
e31c7eec | 8015 | |
6c65299b | 8016 | for (slot = 0; slot < SIZEHASHTABLE; slot++) |
e31c7eec TW |
8017 | for (hsh = cls_method_hash_list[slot]; hsh; hsh = hsh->next) |
8018 | if (hsh->list) | |
6c65299b | 8019 | { |
e31c7eec TW |
8020 | tree meth = hsh->key; |
8021 | char type = (TREE_CODE (meth) == INSTANCE_METHOD_DECL | |
8022 | ? '-' : '+'); | |
8023 | attr loop; | |
8024 | ||
8025 | warning ("potential selector conflict for method `%s'", | |
8026 | IDENTIFIER_POINTER (METHOD_SEL_NAME (meth))); | |
8027 | warn_with_method ("found", type, meth); | |
8028 | for (loop = hsh->list; loop; loop = loop->next) | |
8029 | warn_with_method ("found", type, loop->value); | |
6c65299b | 8030 | } |
e31c7eec | 8031 | |
6c65299b | 8032 | for (slot = 0; slot < SIZEHASHTABLE; slot++) |
e31c7eec TW |
8033 | for (hsh = nst_method_hash_list[slot]; hsh; hsh = hsh->next) |
8034 | if (hsh->list) | |
6c65299b | 8035 | { |
e31c7eec TW |
8036 | tree meth = hsh->key; |
8037 | char type = (TREE_CODE (meth) == INSTANCE_METHOD_DECL | |
8038 | ? '-' : '+'); | |
8039 | attr loop; | |
8040 | ||
8041 | warning ("potential selector conflict for method `%s'", | |
8042 | IDENTIFIER_POINTER (METHOD_SEL_NAME (meth))); | |
8043 | warn_with_method ("found", type, meth); | |
8044 | for (loop = hsh->list; loop; loop = loop->next) | |
8045 | warn_with_method ("found", type, loop->value); | |
6c65299b | 8046 | } |
6c65299b | 8047 | } |
e31c7eec TW |
8048 | |
8049 | warn_missing_braces = save_warn_missing_braces; | |
6c65299b | 8050 | } |
9dee6758 RS |
8051 | \f |
8052 | /* Subroutines of finish_objc. */ | |
8053 | ||
e31c7eec TW |
8054 | static void |
8055 | generate_classref_translation_entry (chain) | |
8056 | tree chain; | |
8057 | { | |
8058 | tree expr, name, decl_specs, decl, sc_spec; | |
8059 | tree type; | |
8060 | ||
8061 | type = TREE_TYPE (TREE_PURPOSE (chain)); | |
8062 | ||
8063 | expr = add_objc_string (TREE_VALUE (chain), class_names); | |
8064 | expr = build_c_cast (type, expr); /* cast! */ | |
8065 | ||
8066 | name = DECL_NAME (TREE_PURPOSE (chain)); | |
8067 | ||
51900510 | 8068 | sc_spec = build_tree_list (NULL_TREE, ridpointers[(int) RID_STATIC]); |
e31c7eec TW |
8069 | |
8070 | /* static struct objc_class * _OBJC_CLASS_REFERENCES_n = ...; */ | |
51900510 | 8071 | decl_specs = tree_cons (NULL_TREE, type, sc_spec); |
e31c7eec | 8072 | |
51900510 RK |
8073 | /* The decl that is returned from start_decl is the one that we |
8074 | forward declared in build_class_reference. */ | |
8075 | decl = start_decl (name, decl_specs, 1, NULL_TREE, NULL_TREE); | |
8076 | finish_decl (decl, expr, NULL_TREE); | |
e31c7eec TW |
8077 | return; |
8078 | } | |
8079 | ||
8080 | static void | |
9dee6758 RS |
8081 | handle_class_ref (chain) |
8082 | tree chain; | |
8083 | { | |
e31c7eec TW |
8084 | char *name = IDENTIFIER_POINTER (TREE_VALUE (chain)); |
8085 | if (! flag_next_runtime) | |
8086 | { | |
8087 | tree decl; | |
8088 | char *string = (char *) alloca (strlen (name) + 30); | |
4f52d290 | 8089 | tree exp; |
6c65299b | 8090 | |
e31c7eec TW |
8091 | sprintf (string, "%sobjc_class_name_%s", |
8092 | (flag_next_runtime ? "." : "__"), name); | |
9dee6758 | 8093 | |
e31c7eec TW |
8094 | /* Make a decl for this name, so we can use its address in a tree. */ |
8095 | decl = build_decl (VAR_DECL, get_identifier (string), char_type_node); | |
8096 | DECL_EXTERNAL (decl) = 1; | |
8097 | TREE_PUBLIC (decl) = 1; | |
9dee6758 | 8098 | |
e31c7eec TW |
8099 | pushdecl (decl); |
8100 | rest_of_decl_compilation (decl, 0, 0, 0); | |
9dee6758 | 8101 | |
e31c7eec TW |
8102 | /* Make following constant read-only (why not)? */ |
8103 | readonly_data_section (); | |
9dee6758 | 8104 | |
4f52d290 RS |
8105 | exp = build1 (ADDR_EXPR, string_type_node, decl); |
8106 | ||
8107 | /* Align the section properly. */ | |
8108 | assemble_constant_align (exp); | |
8109 | ||
e31c7eec TW |
8110 | /* Inform the assembler about this new external thing. */ |
8111 | assemble_external (decl); | |
d33edda7 | 8112 | |
e31c7eec | 8113 | /* Output a constant to reference this address. */ |
4f52d290 | 8114 | output_constant (exp, int_size_in_bytes (string_type_node)); |
e31c7eec TW |
8115 | } |
8116 | else | |
8117 | { | |
8118 | /* This overreliance on our assembler (i.e. lack of portability) | |
8119 | should be dealt with at some point. The GNU strategy (above) | |
8120 | won't work either, but it is a start. */ | |
8121 | char *string = (char *) alloca (strlen (name) + 30); | |
8122 | sprintf (string, ".reference .objc_class_name_%s", name); | |
8123 | assemble_asm (my_build_string (strlen (string) + 1, string)); | |
8124 | } | |
9dee6758 RS |
8125 | } |
8126 | ||
e31c7eec | 8127 | static void |
9dee6758 RS |
8128 | handle_impent (impent) |
8129 | struct imp_entry *impent; | |
8130 | { | |
8131 | implementation_context = impent->imp_context; | |
8132 | implementation_template = impent->imp_template; | |
8133 | ||
e31c7eec | 8134 | if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE) |
9dee6758 | 8135 | { |
e31c7eec TW |
8136 | char *class_name = IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context)); |
8137 | char *string = (char *) alloca (strlen (class_name) + 30); | |
9dee6758 | 8138 | |
e31c7eec TW |
8139 | if (flag_next_runtime) |
8140 | { | |
8141 | /* Grossly unportable. | |
8142 | People should know better than to assume | |
8143 | such things about assembler syntax! */ | |
8144 | sprintf (string, ".objc_class_name_%s=0", class_name); | |
8145 | assemble_asm (my_build_string (strlen (string) + 1, string)); | |
8146 | ||
8147 | sprintf (string, ".globl .objc_class_name_%s", class_name); | |
8148 | assemble_asm (my_build_string (strlen (string) + 1, string)); | |
8149 | } | |
51900510 | 8150 | |
e31c7eec TW |
8151 | else |
8152 | { | |
8153 | sprintf (string, "%sobjc_class_name_%s", | |
8154 | (flag_next_runtime ? "." : "__"), class_name); | |
8155 | assemble_global (string); | |
8156 | assemble_label (string); | |
8157 | } | |
9dee6758 | 8158 | } |
51900510 | 8159 | |
e31c7eec | 8160 | else if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE) |
9dee6758 | 8161 | { |
e31c7eec TW |
8162 | char *class_name = IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context)); |
8163 | char *class_super_name | |
8164 | = IDENTIFIER_POINTER (CLASS_SUPER_NAME (impent->imp_context)); | |
8165 | char *string = (char *) alloca (strlen (class_name) | |
8166 | + strlen (class_super_name) + 30); | |
9dee6758 RS |
8167 | |
8168 | /* Do the same for categories. Even though no references to these | |
e31c7eec | 8169 | symbols are generated automatically by the compiler, it gives |
0f41302f | 8170 | you a handle to pull them into an archive by hand. */ |
e31c7eec TW |
8171 | if (flag_next_runtime) |
8172 | { | |
8173 | /* Grossly unportable. */ | |
8174 | sprintf (string, ".objc_category_name_%s_%s=0", | |
8175 | class_name, class_super_name); | |
8176 | assemble_asm (my_build_string (strlen (string) + 1, string)); | |
8177 | ||
8178 | sprintf (string, ".globl .objc_category_name_%s_%s", | |
8179 | class_name, class_super_name); | |
8180 | assemble_asm (my_build_string (strlen (string) + 1, string)); | |
8181 | } | |
51900510 | 8182 | |
e31c7eec TW |
8183 | else |
8184 | { | |
8185 | sprintf (string, "%sobjc_category_name_%s_%s", | |
8186 | (flag_next_runtime ? "." : "__"), | |
8187 | class_name, class_super_name); | |
8188 | assemble_global (string); | |
8189 | assemble_label (string); | |
8190 | } | |
9dee6758 RS |
8191 | } |
8192 | } | |
8193 | \f | |
6c65299b RS |
8194 | #ifdef DEBUG |
8195 | ||
8196 | static void | |
8197 | objc_debug (fp) | |
8198 | FILE *fp; | |
8199 | { | |
8200 | char *buf = (char *)xmalloc (256); | |
8201 | ||
8202 | { /* dump function prototypes */ | |
e31c7eec | 8203 | tree loop = UOBJC_MODULES_decl; |
6c65299b RS |
8204 | |
8205 | fprintf (fp, "\n\nfunction prototypes:\n"); | |
8206 | while (loop) | |
8207 | { | |
8208 | if (TREE_CODE (loop) == FUNCTION_DECL && DECL_INITIAL (loop)) | |
8209 | { | |
0f41302f | 8210 | /* We have a function definition: generate prototype. */ |
6c65299b RS |
8211 | bzero (errbuf, BUFSIZE); |
8212 | gen_declaration (loop, errbuf); | |
8213 | fprintf (fp, "%s;\n", errbuf); | |
8214 | } | |
8215 | loop = TREE_CHAIN (loop); | |
8216 | } | |
8217 | } | |
51900510 | 8218 | { |
0f41302f | 8219 | /* Dump global chains. */ |
6c65299b RS |
8220 | tree loop; |
8221 | int i, index = 0, offset = 0; | |
8222 | hash hashlist; | |
8223 | ||
8224 | for (i = 0; i < SIZEHASHTABLE; i++) | |
8225 | { | |
8226 | if (hashlist = nst_method_hash_list[i]) | |
8227 | { | |
8228 | fprintf (fp, "\n\nnst_method_hash_list[%d]:\n", i); | |
8229 | do | |
8230 | { | |
8231 | bzero (buf, 256); | |
8232 | fprintf (fp, "-%s;\n", gen_method_decl (hashlist->key, buf)); | |
8233 | hashlist = hashlist->next; | |
8234 | } | |
8235 | while (hashlist); | |
8236 | } | |
8237 | } | |
51900510 | 8238 | |
6c65299b RS |
8239 | for (i = 0; i < SIZEHASHTABLE; i++) |
8240 | { | |
8241 | if (hashlist = cls_method_hash_list[i]) | |
8242 | { | |
8243 | fprintf (fp, "\n\ncls_method_hash_list[%d]:\n", i); | |
8244 | do | |
8245 | { | |
8246 | bzero (buf, 256); | |
8247 | fprintf (fp, "-%s;\n", gen_method_decl (hashlist->key, buf)); | |
8248 | hashlist = hashlist->next; | |
8249 | } | |
8250 | while (hashlist); | |
8251 | } | |
8252 | } | |
51900510 | 8253 | |
6c65299b RS |
8254 | fprintf (fp, "\nsel_refdef_chain:\n"); |
8255 | for (loop = sel_refdef_chain; loop; loop = TREE_CHAIN (loop)) | |
8256 | { | |
8257 | fprintf (fp, "(index: %4d offset: %4d) %s\n", index, offset, | |
8258 | IDENTIFIER_POINTER (TREE_VALUE (loop))); | |
8259 | index++; | |
8260 | /* add one for the '\0' character */ | |
8261 | offset += IDENTIFIER_LENGTH (TREE_VALUE (loop)) + 1; | |
8262 | } | |
51900510 | 8263 | |
6c65299b RS |
8264 | fprintf (fp, "\n (max_selector_index: %4d.\n", max_selector_index); |
8265 | } | |
8266 | } | |
8267 | #endif | |
8268 | ||
8269 | void | |
8270 | print_lang_statistics () | |
8271 | { | |
8272 | } |