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