OSDN Git Service

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