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