X-Git-Url: https://gcc.gnu.org/git/?a=blobdiff_plain;f=gcc%2Fobjc%2Fobjc-act.c;h=d4ebd6288abb31c4afd660508059ec4d2b5bedbf;hb=4977bab6ed59f01c73f9c8b9e92298706df9b6d5;hp=f059472112a197b0b38e533e473a47b81d3ca35b;hpb=f60b945b39191b1c033618bdc5dbe2c22655a407;p=gcc.git diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index f059472112a1..d4ebd6288abb 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -1,5 +1,5 @@ /* Implement classes and message passing for Objective C. - Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001 + Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. Contributed by Steve Naroff. @@ -41,11 +41,12 @@ Boston, MA 02111-1307, USA. */ #include "config.h" #include "system.h" +#include "coretypes.h" +#include "tm.h" #include "tree.h" #include "rtl.h" #include "expr.h" #include "c-tree.h" -#include "c-lex.h" #include "c-common.h" #include "flags.h" #include "objc-act.h" @@ -55,7 +56,9 @@ Boston, MA 02111-1307, USA. */ #include "output.h" #include "toplev.h" #include "ggc.h" -#include "cpplib.h" +#include "debug.h" +#include "target.h" +#include "diagnostic.h" /* This is the default way of generating a method name. */ /* I am not sure it is really correct. @@ -84,48 +87,11 @@ Boston, MA 02111-1307, USA. */ #define OBJC_FORWARDING_MIN_OFFSET 0 #endif -/* Define the special tree codes that we use. */ - -/* Table indexed by tree code giving a string containing a character - classifying the tree code. */ - -#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE, - -static const char objc_tree_code_type[] = { - 'x', -#include "objc-tree.def" -}; -#undef DEFTREECODE - -/* Table indexed by tree code giving number of expression - operands beyond the fixed part of the node structure. - Not used for types or decls. */ - -#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH, - -static const int objc_tree_code_length[] = { - 0, -#include "objc-tree.def" -}; -#undef DEFTREECODE - -/* Names of tree components. - Used for printing out the tree and error messages. */ -#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME, - -static const char * const objc_tree_code_name[] = { - "@@dummy", -#include "objc-tree.def" -}; -#undef DEFTREECODE /* Set up for use of obstacks. */ #include "obstack.h" -#define obstack_chunk_alloc xmalloc -#define obstack_chunk_free free - /* This obstack is used to accumulate the encoding of a data type. */ static struct obstack util_obstack; /* This points to the beginning of obstack contents, @@ -146,32 +112,24 @@ char *util_firstobj; #define OBJC_ENCODE_INLINE_DEFS 0 #define OBJC_ENCODE_DONT_INLINE_DEFS 1 -/* Needed to help fix missing @end situations. */ -extern tree objc_implementation_context; - /*** Private Interface (procedures) ***/ /* Used by compile_file. */ static void init_objc PARAMS ((void)); static void finish_objc PARAMS ((void)); -static void objc_init PARAMS ((void)); -static void objc_init_options PARAMS ((void)); -static int objc_decode_option PARAMS ((int, char **)); -static void objc_post_options PARAMS ((void)); /* Code generation. */ static void synth_module_prologue PARAMS ((void)); static tree build_constructor PARAMS ((tree, tree)); -static const char *build_module_descriptor PARAMS ((void)); +static rtx build_module_descriptor PARAMS ((void)); static tree init_module_descriptor PARAMS ((tree)); static tree build_objc_method_call PARAMS ((int, tree, tree, tree, tree, tree)); static void generate_strings PARAMS ((void)); static tree get_proto_encoding PARAMS ((tree)); static void build_selector_translation_table PARAMS ((void)); -static tree build_ivar_chain PARAMS ((tree, int)); static tree objc_add_static_instance PARAMS ((tree, tree)); @@ -204,26 +162,14 @@ static int check_methods_accessible PARAMS ((tree, tree, static void encode_aggregate_within PARAMS ((tree, int, int, int, int)); static const char *objc_demangle PARAMS ((const char *)); -static const char *objc_printable_name PARAMS ((tree, int)); static void objc_expand_function_end PARAMS ((void)); -/* Misc. bookkeeping */ - -typedef struct hashed_entry *hash; -typedef struct hashed_attribute *attr; +/* Hash tables to manage the global pool of method prototypes. */ -struct hashed_attribute -{ - attr next; - tree value; -}; -struct hashed_entry -{ - attr list; - hash next; - tree key; -}; +hash *nst_method_hash_list = 0; +hash *cls_method_hash_list = 0; +static size_t hash_func PARAMS ((tree)); static void hash_init PARAMS ((void)); static void hash_enter PARAMS ((hash *, tree)); static hash hash_lookup PARAMS ((hash *, tree)); @@ -252,6 +198,7 @@ static tree build_selector_reference_decl PARAMS ((void)); static tree add_protocol PARAMS ((tree)); static tree lookup_protocol PARAMS ((tree)); +static void check_protocol_recursively PARAMS ((tree, tree)); static tree lookup_and_install_protocols PARAMS ((tree)); /* Type encoding. */ @@ -291,6 +238,7 @@ static tree lookup_protocol_in_reflist PARAMS ((tree, tree)); static tree create_builtin_decl PARAMS ((enum tree_code, tree, const char *)); static void setup_string_decl PARAMS ((void)); +static void build_string_class_template PARAMS ((void)); static tree my_build_string PARAMS ((int, const char *)); static void build_objc_symtab_template PARAMS ((void)); static tree init_def_list PARAMS ((tree)); @@ -302,7 +250,6 @@ static tree build_typed_selector_reference PARAMS ((tree, tree)); static tree build_selector_reference PARAMS ((tree)); static tree build_class_reference_decl PARAMS ((void)); static void add_class_reference PARAMS ((tree)); -static tree objc_copy_list PARAMS ((tree, tree *)); static tree build_protocol_template PARAMS ((void)); static tree build_descriptor_table_initializer PARAMS ((tree, tree)); static tree build_method_prototype_list_template PARAMS ((tree, int)); @@ -335,6 +282,8 @@ static tree check_duplicates PARAMS ((hash)); static tree receiver_is_class_object PARAMS ((tree)); static int check_methods PARAMS ((tree, tree, int)); static int conforms_to_protocol PARAMS ((tree, tree)); +static void check_protocol PARAMS ((tree, const char *, + const char *)); static void check_protocols PARAMS ((tree, const char *, const char *)); static tree encode_method_def PARAMS ((tree)); @@ -343,9 +292,7 @@ static void generate_classref_translation_entry PARAMS ((tree)); static void handle_class_ref PARAMS ((tree)); static void generate_struct_by_value_array PARAMS ((void)) ATTRIBUTE_NORETURN; -static void objc_act_parse_init PARAMS ((void)); -static void ggc_mark_imp_list PARAMS ((void *)); -static void ggc_mark_hash_table PARAMS ((void *)); +static void encode_complete_bitfield PARAMS ((int, tree, int)); /*** Private Interface (data) ***/ @@ -364,232 +311,36 @@ static void ggc_mark_hash_table PARAMS ((void *)); #define UTAG_METHOD_LIST "_objc_method_list" #define UTAG_CATEGORY "_objc_category" #define UTAG_MODULE "_objc_module" -#define UTAG_STATICS "_objc_statics" #define UTAG_SYMTAB "_objc_symtab" #define UTAG_SUPER "_objc_super" #define UTAG_SELECTOR "_objc_selector" #define UTAG_PROTOCOL "_objc_protocol" -#define UTAG_PROTOCOL_LIST "_objc_protocol_list" #define UTAG_METHOD_PROTOTYPE "_objc_method_prototype" #define UTAG_METHOD_PROTOTYPE_LIST "_objc__method_prototype_list" -#ifdef NEXT_OBJC_RUNTIME -#define STRING_OBJECT_CLASS_NAME "NSConstantString" -#else -#define STRING_OBJECT_CLASS_NAME "NXConstantString" -#endif /* Note that the string object global name is only needed for the NeXT runtime. */ #define STRING_OBJECT_GLOBAL_NAME "_NSConstantStringClassReference" #define PROTOCOL_OBJECT_CLASS_NAME "Protocol" -static const char *constant_string_class_name = NULL; - static const char *TAG_GETCLASS; static const char *TAG_GETMETACLASS; static const char *TAG_MSGSEND; static const char *TAG_MSGSENDSUPER; static const char *TAG_EXECCLASS; +static const char *default_constant_string_class_name; -/* Set by `continue_class' and checked by `is_public'. */ - -#define TREE_STATIC_TEMPLATE(record_type) (TREE_PUBLIC (record_type)) -#define TYPED_OBJECT(type) \ - (TREE_CODE (type) == RECORD_TYPE && TREE_STATIC_TEMPLATE (type)) - -tree objc_ellipsis_node; - -enum objc_tree_index -{ - OCTI_STATIC_NST, - OCTI_STATIC_NST_DECL, - OCTI_SELF_ID, - OCTI_UCMD_ID, - OCTI_UNUSED_LIST, - OCTI_SELF_DECL, - OCTI_UMSG_DECL, - OCTI_UMSG_SUPER_DECL, - OCTI_GET_CLASS_DECL, - OCTI_GET_MCLASS_DECL, - OCTI_SUPER_TYPE, - OCTI_SEL_TYPE, - OCTI_ID_TYPE, - OCTI_CLS_TYPE, - OCTI_NST_TYPE, - OCTI_PROTO_TYPE, - - OCTI_CLS_CHAIN, - OCTI_ALIAS_CHAIN, - OCTI_INTF_CHAIN, - OCTI_PROTO_CHAIN, - OCTI_CLS_REF_CHAIN, - OCTI_SEL_REF_CHAIN, - OCTI_CLS_NAMES_CHAIN, - OCTI_METH_VAR_NAMES_CHAIN, - OCTI_METH_VAR_TYPES_CHAIN, - - OCTI_SYMBOLS_DECL, - OCTI_NST_VAR_DECL, - OCTI_CLS_VAR_DECL, - OCTI_NST_METH_DECL, - OCTI_CLS_METH_DECL, - OCTI_CLS_DECL, - OCTI_MCLS_DECL, - OCTI_SEL_TABLE_DECL, - OCTI_MODULES_DECL, - OCTI_STRG_DECL, - - OCTI_IMPL_CTX, - OCTI_IMPL_TEMPL, - - OCTI_CLS_TEMPL, - OCTI_CAT_TEMPL, - OCTI_UPRIV_REC, - OCTI_PROTO_TEMPL, - OCTI_SEL_TEMPL, - OCTI_UCLS_SUPER_REF, - OCTI_UUCLS_SUPER_REF, - OCTI_METH_TEMPL, - OCTI_IVAR_TEMPL, - OCTI_SYMTAB_TEMPL, - OCTI_MODULE_TEMPL, - OCTI_SUPER_TEMPL, - OCTI_OBJ_REF, - OCTI_OBJ_ID, - OCTI_CLS_ID, - OCTI_ID_ID, - OCTI_CNST_STR_ID, - OCTI_CNST_STR_TYPE, - OCTI_CNST_STR_GLOB_ID, - OCTI_STRING_CLASS_DECL, - OCTI_SUPER_DECL, - OCTI_METH_CTX, - - OCTI_MAX -}; - -static tree objc_global_trees[OCTI_MAX]; - -/* List of classes with list of their static instances. */ -#define objc_static_instances objc_global_trees[OCTI_STATIC_NST] - -/* The declaration of the array administrating the static instances. */ -#define static_instances_decl objc_global_trees[OCTI_STATIC_NST_DECL] - -/* Some commonly used instances of "identifier_node". */ - -#define self_id objc_global_trees[OCTI_SELF_ID] -#define ucmd_id objc_global_trees[OCTI_UCMD_ID] -#define unused_list objc_global_trees[OCTI_UNUSED_LIST] - -#define self_decl objc_global_trees[OCTI_SELF_DECL] -#define umsg_decl objc_global_trees[OCTI_UMSG_DECL] -#define umsg_super_decl objc_global_trees[OCTI_UMSG_SUPER_DECL] -#define objc_get_class_decl objc_global_trees[OCTI_GET_CLASS_DECL] -#define objc_get_meta_class_decl \ - objc_global_trees[OCTI_GET_MCLASS_DECL] - -#define super_type objc_global_trees[OCTI_SUPER_TYPE] -#define selector_type objc_global_trees[OCTI_SEL_TYPE] -#define id_type objc_global_trees[OCTI_ID_TYPE] -#define objc_class_type objc_global_trees[OCTI_CLS_TYPE] -#define instance_type objc_global_trees[OCTI_NST_TYPE] -#define protocol_type objc_global_trees[OCTI_PROTO_TYPE] - -/* Type checking macros. */ - -#define IS_ID(TYPE) \ - (TYPE_MAIN_VARIANT (TYPE) == TYPE_MAIN_VARIANT (id_type)) -#define IS_PROTOCOL_QUALIFIED_ID(TYPE) \ - (IS_ID (TYPE) && TYPE_PROTOCOL_LIST (TYPE)) -#define IS_SUPER(TYPE) \ - (super_type && TYPE_MAIN_VARIANT (TYPE) == TYPE_MAIN_VARIANT (super_type)) - -#define class_chain objc_global_trees[OCTI_CLS_CHAIN] -#define alias_chain objc_global_trees[OCTI_ALIAS_CHAIN] -#define interface_chain objc_global_trees[OCTI_INTF_CHAIN] -#define protocol_chain objc_global_trees[OCTI_PROTO_CHAIN] - -/* Chains to manage selectors that are referenced and defined in the - module. */ - -#define cls_ref_chain objc_global_trees[OCTI_CLS_REF_CHAIN] /* Classes referenced. */ -#define sel_ref_chain objc_global_trees[OCTI_SEL_REF_CHAIN] /* Selectors referenced. */ - -/* Chains to manage uniquing of strings. */ - -#define class_names_chain objc_global_trees[OCTI_CLS_NAMES_CHAIN] -#define meth_var_names_chain objc_global_trees[OCTI_METH_VAR_NAMES_CHAIN] -#define meth_var_types_chain objc_global_trees[OCTI_METH_VAR_TYPES_CHAIN] - -/* Hash tables to manage the global pool of method prototypes. */ - -static hash *nst_method_hash_list = 0; -static hash *cls_method_hash_list = 0; - -/* Backend data declarations. */ - -#define UOBJC_SYMBOLS_decl objc_global_trees[OCTI_SYMBOLS_DECL] -#define UOBJC_INSTANCE_VARIABLES_decl objc_global_trees[OCTI_NST_VAR_DECL] -#define UOBJC_CLASS_VARIABLES_decl objc_global_trees[OCTI_CLS_VAR_DECL] -#define UOBJC_INSTANCE_METHODS_decl objc_global_trees[OCTI_NST_METH_DECL] -#define UOBJC_CLASS_METHODS_decl objc_global_trees[OCTI_CLS_METH_DECL] -#define UOBJC_CLASS_decl objc_global_trees[OCTI_CLS_DECL] -#define UOBJC_METACLASS_decl objc_global_trees[OCTI_MCLS_DECL] -#define UOBJC_SELECTOR_TABLE_decl objc_global_trees[OCTI_SEL_TABLE_DECL] -#define UOBJC_MODULES_decl objc_global_trees[OCTI_MODULES_DECL] -#define UOBJC_STRINGS_decl objc_global_trees[OCTI_STRG_DECL] - -/* The following are used when compiling a class implementation. - implementation_template will normally be an interface, however if - none exists this will be equal to implementation_context...it is - set in start_class. */ - -#define implementation_context objc_global_trees[OCTI_IMPL_CTX] -#define implementation_template objc_global_trees[OCTI_IMPL_TEMPL] - -struct imp_entry -{ - struct imp_entry *next; - tree imp_context; - tree imp_template; - tree class_decl; /* _OBJC_CLASS_; */ - tree meta_decl; /* _OBJC_METACLASS_; */ -}; +/* The OCTI_... enumeration itself is in objc/objc-act.h. */ +tree objc_global_trees[OCTI_MAX]; static void handle_impent PARAMS ((struct imp_entry *)); -static struct imp_entry *imp_list = 0; -static int imp_count = 0; /* `@implementation' */ -static int cat_count = 0; /* `@category' */ - -#define objc_class_template objc_global_trees[OCTI_CLS_TEMPL] -#define objc_category_template objc_global_trees[OCTI_CAT_TEMPL] -#define uprivate_record objc_global_trees[OCTI_UPRIV_REC] -#define objc_protocol_template objc_global_trees[OCTI_PROTO_TEMPL] -#define objc_selector_template objc_global_trees[OCTI_SEL_TEMPL] -#define ucls_super_ref objc_global_trees[OCTI_UCLS_SUPER_REF] -#define uucls_super_ref objc_global_trees[OCTI_UUCLS_SUPER_REF] - -#define objc_method_template objc_global_trees[OCTI_METH_TEMPL] -#define objc_ivar_template objc_global_trees[OCTI_IVAR_TEMPL] -#define objc_symtab_template objc_global_trees[OCTI_SYMTAB_TEMPL] -#define objc_module_template objc_global_trees[OCTI_MODULE_TEMPL] -#define objc_super_template objc_global_trees[OCTI_SUPER_TEMPL] -#define objc_object_reference objc_global_trees[OCTI_OBJ_REF] - -#define objc_object_id objc_global_trees[OCTI_OBJ_ID] -#define objc_class_id objc_global_trees[OCTI_CLS_ID] -#define objc_id_id objc_global_trees[OCTI_ID_ID] -#define constant_string_id objc_global_trees[OCTI_CNST_STR_ID] -#define constant_string_type objc_global_trees[OCTI_CNST_STR_TYPE] -#define constant_string_global_id objc_global_trees[OCTI_CNST_STR_GLOB_ID] -#define string_class_decl objc_global_trees[OCTI_STRING_CLASS_DECL] -#define UOBJC_SUPER_decl objc_global_trees[OCTI_SUPER_DECL] - -#define method_context objc_global_trees[OCTI_METH_CTX] +struct imp_entry *imp_list = 0; +int imp_count = 0; /* `@implementation' */ +int cat_count = 0; /* `@category' */ + static int method_slot = 0; /* Used by start_method_def, */ #define BUFSIZE 1024 @@ -604,64 +355,20 @@ extern enum debug_info_type write_symbols; extern const char *dump_base_name; -/* Generate code for GNU or NeXT runtime environment. */ - -#ifdef NEXT_OBJC_RUNTIME -int flag_next_runtime = 1; -#else -int flag_next_runtime = 0; -#endif - -int flag_typed_selectors; - -/* Open and close the file for outputting class declarations, if requested. */ - -int flag_gen_declaration = 0; +static int flag_typed_selectors; FILE *gen_declaration_file; -/* Warn if multiple methods are seen for the same selector, but with - different argument types. */ - -int warn_selector = 0; - -/* Warn if methods required by a protocol are not implemented in the - class adopting it. When turned off, methods inherited to that - class are also considered implemented */ - -int flag_warn_protocol = 1; - /* Tells "encode_pointer/encode_aggregate" whether we are generating type descriptors for instance variables (as opposed to methods). Type descriptors for instance variables contain more information - than methods (for static typing and embedded structures). This - was added to support features being planned for dbkit2. */ + than methods (for static typing and embedded structures). */ static int generating_instance_variables = 0; -/* Tells the compiler that this is a special run. Do not perform - any compiling, instead we are to test some platform dependent - features and output a C header file with appropriate definitions. */ - -static int print_struct_values = 0; - -/* Each front end provides its own. */ -struct lang_hooks lang_hooks = {objc_init, - NULL, /* objc_finish */ - objc_init_options, - objc_decode_option, - objc_post_options}; - -/* Post-switch processing. */ -static void -objc_post_options () -{ - cpp_post_options (parse_in); -} - -/* Some platforms pass small structures through registers versus through - an invisible pointer. Determine at what size structure is the - transition point between the two possibilities. */ +/* Some platforms pass small structures through registers versus + through an invisible pointer. Determine at what size structure is + the transition point between the two possibilities. */ static void generate_struct_by_value_array () @@ -672,7 +379,7 @@ generate_struct_by_value_array () int aggregate_in_mem[32]; int found = 0; - /* Presumably no platform passes 32 byte structures in a register. */ + /* Presumably no platform passes 32 byte structures in a register. */ for (i = 1; i < 32; i++) { char buffer[5]; @@ -702,7 +409,7 @@ generate_struct_by_value_array () } /* We found some structures that are returned in registers instead of memory - so output the necessary data. */ + so output the necessary data. */ if (found) { for (i = 31; i >= 0; i--) @@ -722,26 +429,19 @@ generate_struct_by_value_array () exit (0); } -static void -objc_init_options () +const char * +objc_init (filename) + const char *filename; { - /* Make identifier nodes long enough for the language-specific slots. */ - set_identifier_size (sizeof (struct lang_identifier)); - - parse_in = cpp_create_reader (ident_hash, CLK_OBJC); - c_language = clk_objective_c; -} + filename = c_objc_common_init (filename); + if (filename == NULL) + return filename; -static void -objc_init () -{ /* Force the line number back to 0; check_newline will have raised it to 1, which will make the builtin functions appear not to be built in. */ lineno = 0; - c_common_lang_init (); - /* If gen_declaration desired, open the output file. */ if (flag_gen_declaration) { @@ -759,6 +459,7 @@ objc_init () TAG_MSGSEND = "objc_msgSend"; TAG_MSGSENDSUPER = "objc_msgSendSuper"; TAG_EXECCLASS = "__objc_execClass"; + default_constant_string_class_name = "NSConstantString"; } else { @@ -767,6 +468,7 @@ objc_init () TAG_MSGSEND = "objc_msg_lookup"; TAG_MSGSENDSUPER = "objc_msg_lookup_super"; TAG_EXECCLASS = "__objc_exec_class"; + default_constant_string_class_name = "NXConstantString"; flag_typed_selectors = 1; } @@ -777,82 +479,29 @@ objc_init () if (print_struct_values) generate_struct_by_value_array (); - objc_act_parse_init (); - c_parse_init (); + return filename; } void finish_file () { - finish_objc (); /* Objective-C finalization */ + c_objc_common_finish_file (); + + /* Finalize Objective-C runtime data. No need to generate tables + and code if only checking syntax. */ + if (!flag_syntax_only) + finish_objc (); if (gen_declaration_file) fclose (gen_declaration_file); } - -const char * -lang_identify () -{ - return "objc"; -} - -static int -objc_decode_option (argc, argv) - int argc; - char **argv; -{ - const char *p = argv[0]; - - if (!strcmp (p, "-gen-decls")) - flag_gen_declaration = 1; - else if (!strcmp (p, "-Wselector")) - warn_selector = 1; - else if (!strcmp (p, "-Wno-selector")) - warn_selector = 0; - else if (!strcmp (p, "-Wprotocol")) - flag_warn_protocol = 1; - else if (!strcmp (p, "-Wno-protocol")) - flag_warn_protocol = 0; - else if (!strcmp (p, "-fgnu-runtime")) - flag_next_runtime = 0; - else if (!strcmp (p, "-fno-next-runtime")) - flag_next_runtime = 0; - else if (!strcmp (p, "-fno-gnu-runtime")) - flag_next_runtime = 1; - else if (!strcmp (p, "-fnext-runtime")) - flag_next_runtime = 1; - else if (!strcmp (p, "-print-objc-runtime-info")) - print_struct_values = 1; -#define CSTSTRCLASS "-fconstant-string-class=" - else if (!strncmp (p, CSTSTRCLASS, sizeof(CSTSTRCLASS) - 2)) { - if (strlen (argv[0]) <= strlen (CSTSTRCLASS)) - error ("no class name specified as argument to -fconstant-string-class"); - constant_string_class_name = xstrdup(argv[0] + sizeof(CSTSTRCLASS) - 1); - } -#undef CSTSTRCLASS - else - return c_decode_option (argc, argv); - - return 1; -} - -/* used by print-tree.c */ - -void -lang_print_xnode (file, node, indent) - FILE *file ATTRIBUTE_UNUSED; - tree node ATTRIBUTE_UNUSED; - int indent ATTRIBUTE_UNUSED; -{ -} - static tree define_decl (declarator, declspecs) tree declarator; tree declspecs; { - tree decl = start_decl (declarator, declspecs, 0, NULL_TREE, NULL_TREE); + tree decl = start_decl (declarator, declspecs, 0, NULL_TREE); finish_decl (decl, NULL_TREE, NULL_TREE); return decl; } @@ -869,14 +518,6 @@ define_decl (declarator, declspecs) `a' and `b' are the same class type, or `a' and `b' are of class types A and B such that B is a descendant of A. */ -int -maybe_objc_comptypes (lhs, rhs, reflexive) - tree lhs, rhs; - int reflexive; -{ - return objc_comptypes (lhs, rhs, reflexive); -} - static tree lookup_method_in_protocol_list (rproto_list, sel_name, class_meth) tree rproto_list; @@ -914,44 +555,58 @@ lookup_method_in_protocol_list (rproto_list, sel_name, class_meth) static tree lookup_protocol_in_reflist (rproto_list, lproto) - tree rproto_list; - tree lproto; + tree rproto_list; + tree lproto; { - tree rproto, p; + tree rproto, p; - /* Make sure the protocol is supported by the object on the rhs. */ - if (TREE_CODE (lproto) == PROTOCOL_INTERFACE_TYPE) - { - tree fnd = 0; - for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto)) - { - p = TREE_VALUE (rproto); + /* Make sure the protocol is supported by the object on the rhs. */ + if (TREE_CODE (lproto) == PROTOCOL_INTERFACE_TYPE) + { + tree fnd = 0; + for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto)) + { + p = TREE_VALUE (rproto); - if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) - { - if (lproto == p) - fnd = lproto; + if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) + { + if (lproto == p) + fnd = lproto; - else if (PROTOCOL_LIST (p)) - fnd = lookup_protocol_in_reflist (PROTOCOL_LIST (p), lproto); - } + else if (PROTOCOL_LIST (p)) + fnd = lookup_protocol_in_reflist (PROTOCOL_LIST (p), lproto); + } - if (fnd) - return fnd; - } - } - else - { - ; /* An identifier...if we could not find a protocol. */ - } + if (fnd) + return fnd; + } + } + else + { + ; /* An identifier...if we could not find a protocol. */ + } - return 0; + return 0; } -/* Return 1 if LHS and RHS are compatible types for assignment - or various other operations. Return 0 if they are incompatible, - and return -1 if we choose to not decide. When the operation - is REFLEXIVE, check for compatibility in either direction. */ +/* Return 1 if LHS and RHS are compatible types for assignment or + various other operations. Return 0 if they are incompatible, and + return -1 if we choose to not decide (because the types are really + just C types, not ObjC specific ones). When the operation is + REFLEXIVE (typically comparisons), check for compatibility in + either direction; when it's not (typically assignments), don't. + + This function is called in two cases: when both lhs and rhs are + pointers to records (in which case we check protocols too), and + when both lhs and rhs are records (in which case we check class + inheritance only). + + Warnings about classes/protocols not implementing a protocol are + emitted here (multiple of those warnings might be emitted for a + single line!); generic warnings about incompatible assignments and + lacks of casts in comparisons are/must be emitted by the caller if + we return 0. +*/ int objc_comptypes (lhs, rhs, reflexive) @@ -961,6 +616,8 @@ objc_comptypes (lhs, rhs, reflexive) { /* New clause for protocols. */ + /* Here we manage the case of a POINTER_TYPE = POINTER_TYPE. We only + manage the ObjC ones, and leave the rest to the C code. */ if (TREE_CODE (lhs) == POINTER_TYPE && TREE_CODE (TREE_TYPE (lhs)) == RECORD_TYPE && TREE_CODE (rhs) == POINTER_TYPE @@ -975,29 +632,75 @@ objc_comptypes (lhs, rhs, reflexive) tree rproto, rproto_list; tree p; + /* = */ if (rhs_is_proto) { rproto_list = TYPE_PROTOCOL_LIST (rhs); - - /* Make sure the protocol is supported by the object - on the rhs. */ - for (lproto = lproto_list; lproto; lproto = TREE_CHAIN (lproto)) + + if (!reflexive) { - p = TREE_VALUE (lproto); - rproto = lookup_protocol_in_reflist (rproto_list, p); + /* An assignment between objects of type 'id + '; make sure the protocol on the lhs is + supported by the object on the rhs. */ + for (lproto = lproto_list; lproto; + lproto = TREE_CHAIN (lproto)) + { + p = TREE_VALUE (lproto); + rproto = lookup_protocol_in_reflist (rproto_list, p); - if (!rproto) - warning ("object does not conform to the `%s' protocol", - IDENTIFIER_POINTER (PROTOCOL_NAME (p))); + if (!rproto) + warning + ("object does not conform to the `%s' protocol", + IDENTIFIER_POINTER (PROTOCOL_NAME (p))); + } + return 1; + } + else + { + /* Obscure case - a comparison between two objects + of type 'id '. Check that either the + protocol on the lhs is supported by the object on + the rhs, or viceversa. */ + + /* Check if the protocol on the lhs is supported by the + object on the rhs. */ + for (lproto = lproto_list; lproto; + lproto = TREE_CHAIN (lproto)) + { + p = TREE_VALUE (lproto); + rproto = lookup_protocol_in_reflist (rproto_list, p); + + if (!rproto) + { + /* Check failed - check if the protocol on the rhs + is supported by the object on the lhs. */ + for (rproto = rproto_list; rproto; + rproto = TREE_CHAIN (rproto)) + { + p = TREE_VALUE (rproto); + lproto = lookup_protocol_in_reflist (lproto_list, + p); + + if (!lproto) + { + /* This check failed too: incompatible */ + return 0; + } + } + return 1; + } + } + return 1; } } + /* = * */ else if (TYPED_OBJECT (TREE_TYPE (rhs))) { tree rname = TYPE_NAME (TREE_TYPE (rhs)); tree rinter; - /* Make sure the protocol is supported by the object - on the rhs. */ + /* Make sure the protocol is supported by the object on + the rhs. */ for (lproto = lproto_list; lproto; lproto = TREE_CHAIN (lproto)) { p = TREE_VALUE (lproto); @@ -1010,6 +713,15 @@ objc_comptypes (lhs, rhs, reflexive) rproto_list = CLASS_PROTOCOL_LIST (rinter); rproto = lookup_protocol_in_reflist (rproto_list, p); + /* If the underlying ObjC class does not have + the protocol we're looking for, check for "one-off" + protocols (e.g., `NSObject *foo;') attached + to the rhs. */ + if (!rproto) + { + rproto_list = TYPE_PROTOCOL_LIST (TREE_TYPE (rhs)); + rproto = lookup_protocol_in_reflist (rproto_list, p); + } /* Check for protocols adopted by categories. */ cat = CLASS_CATEGORY_LIST (rinter); @@ -1017,7 +729,6 @@ objc_comptypes (lhs, rhs, reflexive) { rproto_list = CLASS_PROTOCOL_LIST (cat); rproto = lookup_protocol_in_reflist (rproto_list, p); - cat = CLASS_CATEGORY_LIST (cat); } @@ -1026,31 +737,127 @@ objc_comptypes (lhs, rhs, reflexive) if (!rproto) warning ("class `%s' does not implement the `%s' protocol", - IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (rhs))), - IDENTIFIER_POINTER (PROTOCOL_NAME (p))); + IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (rhs))), + IDENTIFIER_POINTER (PROTOCOL_NAME (p))); } + return 1; } - - /* May change...based on whether there was any mismatch */ - return 1; + /* = id */ + else if (TYPE_NAME (TREE_TYPE (rhs)) == objc_object_id) + { + return 1; + } + /* = Class */ + else if (TYPE_NAME (TREE_TYPE (rhs)) == objc_class_id) + { + return 0; + } + /* = ?? : let comptypes decide. */ + return -1; } else if (rhs_is_proto) - /* Lhs is not a protocol...warn if it is statically typed */ - return (TYPED_OBJECT (TREE_TYPE (lhs)) != 0); + { + /* * = */ + if (TYPED_OBJECT (TREE_TYPE (lhs))) + { + if (reflexive) + { + tree rname = TYPE_NAME (TREE_TYPE (lhs)); + tree rinter; + tree rproto, rproto_list = TYPE_PROTOCOL_LIST (rhs); + + /* Make sure the protocol is supported by the object on + the lhs. */ + for (rproto = rproto_list; rproto; + rproto = TREE_CHAIN (rproto)) + { + tree p = TREE_VALUE (rproto); + tree lproto = 0; + rinter = lookup_interface (rname); + while (rinter && !lproto) + { + tree cat; + + tree lproto_list = CLASS_PROTOCOL_LIST (rinter); + lproto = lookup_protocol_in_reflist (lproto_list, p); + /* If the underlying ObjC class does not + have the protocol we're looking for, + check for "one-off" protocols (e.g., + `NSObject *foo;') attached to the + lhs. */ + if (!lproto) + { + lproto_list = TYPE_PROTOCOL_LIST + (TREE_TYPE (lhs)); + lproto = lookup_protocol_in_reflist + (lproto_list, p); + } + + /* Check for protocols adopted by categories. */ + cat = CLASS_CATEGORY_LIST (rinter); + while (cat && !lproto) + { + lproto_list = CLASS_PROTOCOL_LIST (cat); + lproto = lookup_protocol_in_reflist (lproto_list, + p); + cat = CLASS_CATEGORY_LIST (cat); + } + + rinter = lookup_interface (CLASS_SUPER_NAME + (rinter)); + } + + if (!lproto) + warning ("class `%s' does not implement the `%s' protocol", + IDENTIFIER_POINTER (TYPE_NAME + (TREE_TYPE (lhs))), + IDENTIFIER_POINTER (PROTOCOL_NAME (p))); + } + return 1; + } + else + return 0; + } + /* id = */ + else if (TYPE_NAME (TREE_TYPE (lhs)) == objc_object_id) + { + return 1; + } + /* Class = */ + else if (TYPE_NAME (TREE_TYPE (lhs)) == objc_class_id) + { + return 0; + } + /* ??? = : let comptypes decide */ + else + { + return -1; + } + } else - /* Defer to comptypes. */ - return -1; + { + /* Attention: we shouldn't defer to comptypes here. One bad + side effect would be that we might loose the REFLEXIVE + information. + */ + lhs = TREE_TYPE (lhs); + rhs = TREE_TYPE (rhs); + } } - else if (TREE_CODE (lhs) == RECORD_TYPE && TREE_CODE (rhs) == RECORD_TYPE) - ; /* Fall thru. This is the case we have been handling all along */ - else - /* Defer to comptypes. */ - return -1; - - /* `id' = ` *', ` *' = `id' */ + if (TREE_CODE (lhs) != RECORD_TYPE || TREE_CODE (rhs) != RECORD_TYPE) + { + /* Nothing to do with ObjC - let immediately comptypes take + responsibility for checking. */ + return -1; + } + /* `id' = ` *' ` *' = `id': always allow it. + Please note that + 'Object *o = [[Object alloc] init]; falls + in the case * = `id'. + */ if ((TYPE_NAME (lhs) == objc_object_id && TYPED_OBJECT (rhs)) || (TYPE_NAME (rhs) == objc_object_id && TYPED_OBJECT (lhs))) return 1; @@ -1091,7 +898,7 @@ objc_comptypes (lhs, rhs, reflexive) return 0; } else - /* Defer to comptypes. */ + /* Not an ObjC type - let comptypes do the check. */ return -1; } @@ -1109,13 +916,6 @@ objc_check_decl (decl) error_with_decl (decl, "`%s' cannot be statically allocated"); } -void -maybe_objc_check_decl (decl) - tree decl; -{ - objc_check_decl (decl); -} - /* Implement static typing. At this point, we know we have an interface. */ tree @@ -1130,7 +930,6 @@ get_static_reference (interface, protocols) tree t, m = TYPE_MAIN_VARIANT (type); t = copy_node (type); - TYPE_BINFO (t) = make_tree_vec (2); /* Add this type to the chain of variants of TYPE. */ TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m); @@ -1163,12 +962,12 @@ get_object_reference (protocols) { type = TREE_TYPE (type_decl); if (TYPE_MAIN_VARIANT (type) != id_type) - warning ("Unexpected type for `id' (%s)", + warning ("unexpected type for `id' (%s)", gen_declaration (type, errbuf)); } else { - error ("Undefined type `id', please import "); + error ("undefined type `id', please import "); return error_mark_node; } @@ -1181,7 +980,6 @@ get_object_reference (protocols) tree t, m = TYPE_MAIN_VARIANT (type); t = copy_node (type); - TYPE_BINFO (t) = make_tree_vec (2); /* Add this type to the chain of variants of TYPE. */ TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m); @@ -1201,6 +999,32 @@ get_object_reference (protocols) return type; } +/* Check for circular dependencies in protocols. The arguments are + PROTO, the protocol to check, and LIST, a list of protocol it + conforms to. */ + +static void +check_protocol_recursively (proto, list) + tree proto; + tree list; +{ + tree p; + + for (p = list; p; p = TREE_CHAIN (p)) + { + tree pp = TREE_VALUE (p); + + if (TREE_CODE (pp) == IDENTIFIER_NODE) + pp = lookup_protocol (pp); + + if (pp == proto) + fatal_error ("protocol `%s' has circular dependency", + IDENTIFIER_POINTER (PROTOCOL_NAME (pp))); + if (pp) + check_protocol_recursively (proto, PROTOCOL_LIST (pp)); + } +} + static tree lookup_and_install_protocols (protocols) tree protocols; @@ -1216,7 +1040,7 @@ lookup_and_install_protocols (protocols) if (!p) { - error ("Cannot find protocol declaration for `%s'", + error ("cannot find protocol declaration for `%s'", IDENTIFIER_POINTER (ident)); if (prev) TREE_CHAIN (prev) = TREE_CHAIN (proto); @@ -1332,14 +1156,12 @@ synth_module_prologue () DECL_INLINE (umsg_decl) = 1; DECL_ARTIFICIAL (umsg_decl) = 1; - if (flag_traditional && TAG_MSGSEND[0] != '_') - DECL_BUILT_IN_NONANSI (umsg_decl) = 1; - make_decl_rtl (umsg_decl, NULL); pushdecl (umsg_decl); } else - umsg_decl = builtin_function (TAG_MSGSEND, temp_type, 0, NOT_BUILT_IN, 0); + umsg_decl = builtin_function (TAG_MSGSEND, temp_type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); /* id objc_msgSendSuper (struct objc_super *, SEL, ...); */ @@ -1350,7 +1172,8 @@ synth_module_prologue () NULL_TREE))); umsg_super_decl = builtin_function (TAG_MSGSENDSUPER, - temp_type, 0, NOT_BUILT_IN, 0); + temp_type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); /* id objc_getClass (const char *); */ @@ -1361,12 +1184,14 @@ synth_module_prologue () NULL_TREE))); objc_get_class_decl - = builtin_function (TAG_GETCLASS, temp_type, 0, NOT_BUILT_IN, 0); + = builtin_function (TAG_GETCLASS, temp_type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); /* id objc_getMetaClass (const char *); */ objc_get_meta_class_decl - = builtin_function (TAG_GETMETACLASS, temp_type, 0, NOT_BUILT_IN, 0); + = builtin_function (TAG_GETMETACLASS, temp_type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); /* static SEL _OBJC_SELECTOR_TABLE[]; */ @@ -1377,12 +1202,15 @@ synth_module_prologue () /* Suppress outputting debug symbols, because dbxout_init hasn'r been called yet. */ enum debug_info_type save_write_symbols = write_symbols; + const struct gcc_debug_hooks *const save_hooks = debug_hooks; write_symbols = NO_DEBUG; + debug_hooks = &do_nothing_debug_hooks; build_selector_template (); temp_type = build_array_type (objc_selector_template, NULL_TREE); write_symbols = save_write_symbols; + debug_hooks = save_hooks; } else temp_type = build_array_type (selector_type, NULL_TREE); @@ -1400,12 +1228,40 @@ synth_module_prologue () /* Forward declare constant_string_id and constant_string_type. */ if (!constant_string_class_name) - constant_string_class_name = STRING_OBJECT_CLASS_NAME; - + constant_string_class_name = default_constant_string_class_name; + constant_string_id = get_identifier (constant_string_class_name); constant_string_type = xref_tag (RECORD_TYPE, constant_string_id); } +/* Predefine the following data type: + + struct STRING_OBJECT_CLASS_NAME + { + Object isa; + char *cString; + unsigned int length; + }; */ + +static void +build_string_class_template () +{ + tree field_decl, field_decl_chain; + + field_decl = create_builtin_decl (FIELD_DECL, id_type, "isa"); + field_decl_chain = field_decl; + + field_decl = create_builtin_decl (FIELD_DECL, + build_pointer_type (char_type_node), + "cString"); + chainon (field_decl_chain, field_decl); + + field_decl = create_builtin_decl (FIELD_DECL, unsigned_type_node, "length"); + chainon (field_decl_chain, field_decl); + + finish_struct (constant_string_type, field_decl_chain, NULL_TREE); +} + /* Custom build_string which sets TREE_TYPE! */ static tree @@ -1413,21 +1269,7 @@ my_build_string (len, str) int len; const char *str; { - int wide_flag = 0; - tree a_string = build_string (len, str); - - /* Some code from combine_strings, which is local to c-parse.y. */ - if (TREE_TYPE (a_string) == int_array_type_node) - wide_flag = 1; - - TREE_TYPE (a_string) - = build_array_type (wide_flag ? integer_type_node : char_type_node, - build_index_type (build_int_2 (len - 1, 0))); - - TREE_CONSTANT (a_string) = 1; /* Puts string in the readonly segment */ - TREE_STATIC (a_string) = 1; - - return a_string; + return fix_string_type (build_string (len, str)); } /* Given a chain of STRING_CST's, build a static instance of @@ -1446,18 +1288,37 @@ build_objc_string_object (strings) if (lookup_interface (constant_string_id) == NULL_TREE) { - error ("Cannot find interface declaration for `%s'", + error ("cannot find interface declaration for `%s'", IDENTIFIER_POINTER (constant_string_id)); return error_mark_node; } add_class_reference (constant_string_id); - string = combine_strings (strings); + if (TREE_CHAIN (strings)) + { + varray_type vstrings; + VARRAY_TREE_INIT (vstrings, 32, "strings"); + + for (; strings ; strings = TREE_CHAIN (strings)) + VARRAY_PUSH_TREE (vstrings, strings); + + string = combine_strings (vstrings); + } + else + string = strings; + + string = fix_string_type (string); + TREE_SET_CODE (string, STRING_CST); length = TREE_STRING_LENGTH (string) - 1; - /* & ((NXConstantString) {0, string, length}) */ + /* We could not properly create NXConstantString in synth_module_prologue, + because that's called before debugging is initialized. Do it now. */ + if (TYPE_FIELDS (constant_string_type) == NULL_TREE) + build_string_class_template (); + + /* & ((NXConstantString) { NULL, string, length }) */ if (flag_next_runtime) { @@ -1466,7 +1327,7 @@ build_objc_string_object (strings) setup_string_decl (); if (string_class_decl == NULL_TREE) { - error ("Cannot find reference tag for class `%s'", + error ("cannot find reference tag for class `%s'", IDENTIFIER_POINTER (constant_string_id)); return error_mark_node; } @@ -1541,8 +1402,27 @@ static tree build_constructor (type, elts) tree type, elts; { - tree constructor = build (CONSTRUCTOR, type, NULL_TREE, elts); + tree constructor, f, e; + + /* ??? Most of the places that we build constructors, we don't fill in + the type of integers properly. Convert them all en masse. */ + if (TREE_CODE (type) == ARRAY_TYPE) + { + f = TREE_TYPE (type); + if (TREE_CODE (f) == POINTER_TYPE || TREE_CODE (f) == INTEGER_TYPE) + for (e = elts; e ; e = TREE_CHAIN (e)) + TREE_VALUE (e) = convert (f, TREE_VALUE (e)); + } + else + { + f = TYPE_FIELDS (type); + for (e = elts; e && f; e = TREE_CHAIN (e), f = TREE_CHAIN (f)) + if (TREE_CODE (TREE_TYPE (f)) == POINTER_TYPE + || TREE_CODE (TREE_TYPE (f)) == INTEGER_TYPE) + TREE_VALUE (e) = convert (TREE_TYPE (f), TREE_VALUE (e)); + } + constructor = build (CONSTRUCTOR, type, NULL_TREE, elts); TREE_CONSTANT (constructor) = 1; TREE_STATIC (constructor) = 1; TREE_READONLY (constructor) = 1; @@ -1706,27 +1586,27 @@ init_objc_symtab (type) return build_constructor (type, nreverse (initlist)); } -/* Push forward-declarations of all the categories - so that init_def_list can use them in a CONSTRUCTOR. */ +/* Push forward-declarations of all the categories so that + init_def_list can use them in a CONSTRUCTOR. */ static void forward_declare_categories () { struct imp_entry *impent; - tree sav = implementation_context; + tree sav = objc_implementation_context; for (impent = imp_list; impent; impent = impent->next) { if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE) { /* Set an invisible arg to synth_id_with_class_suffix. */ - implementation_context = impent->imp_context; + objc_implementation_context = impent->imp_context; impent->class_decl = create_builtin_decl (VAR_DECL, objc_category_template, - IDENTIFIER_POINTER (synth_id_with_class_suffix ("_OBJC_CATEGORY", implementation_context))); + IDENTIFIER_POINTER (synth_id_with_class_suffix ("_OBJC_CATEGORY", objc_implementation_context))); } } - implementation_context = sav; + objc_implementation_context = sav; } /* Create the declaration of _OBJC_SYMBOLS, with type `strict _objc_symtab' @@ -1753,7 +1633,7 @@ generate_objc_symtab_decl () tree_cons (NULL_TREE, objc_symtab_template, sc_spec), 1, - NULL_TREE, NULL_TREE); + NULL_TREE); TREE_USED (UOBJC_SYMBOLS_decl) = 1; DECL_IGNORED_P (UOBJC_SYMBOLS_decl) = 1; @@ -1797,13 +1677,12 @@ init_module_descriptor (type) /* Write out the data structures to describe Objective C classes defined. If appropriate, compile and output a setup function to initialize them. - Return a string which is the name of a function to call to initialize - the Objective C data structures for this file (and perhaps for other files - also). + Return a symbol_ref to the function to call to initialize the Objective C + data structures for this file (and perhaps for other files also). struct objc_module { ... } _OBJC_MODULE = { ... }; */ -static const char * +static rtx build_module_descriptor () { tree decl_specs, field_decl, field_decl_chain; @@ -1853,7 +1732,7 @@ build_module_descriptor () ridpointers[(int) RID_STATIC])); UOBJC_MODULES_decl = start_decl (get_identifier ("_OBJC_MODULES"), - decl_specs, 1, NULL_TREE, NULL_TREE); + decl_specs, 1, NULL_TREE); DECL_ARTIFICIAL (UOBJC_MODULES_decl) = 1; DECL_IGNORED_P (UOBJC_MODULES_decl) = 1; @@ -1872,64 +1751,57 @@ build_module_descriptor () way of generating the requisite code. */ if (flag_next_runtime) - return 0; + return NULL_RTX; { - tree parms, function_decl, decelerator, void_list_node_1; - tree function_type; - tree init_function_name = get_file_function_name ('I'); + tree parms, execclass_decl, decelerator, void_list_node_1; + tree init_function_name, init_function_decl; /* Declare void __objc_execClass (void *); */ void_list_node_1 = build_tree_list (NULL_TREE, void_type_node); - function_type - = build_function_type (void_type_node, - tree_cons (NULL_TREE, ptr_type_node, - void_list_node_1)); - function_decl = build_decl (FUNCTION_DECL, - get_identifier (TAG_EXECCLASS), - function_type); - DECL_EXTERNAL (function_decl) = 1; - DECL_ARTIFICIAL (function_decl) = 1; - TREE_PUBLIC (function_decl) = 1; - - pushdecl (function_decl); - rest_of_decl_compilation (function_decl, 0, 0, 0); - - parms - = build_tree_list (NULL_TREE, - build_unary_op (ADDR_EXPR, UOBJC_MODULES_decl, 0)); - decelerator = build_function_call (function_decl, parms); + execclass_decl = build_decl (FUNCTION_DECL, + get_identifier (TAG_EXECCLASS), + build_function_type (void_type_node, + tree_cons (NULL_TREE, ptr_type_node, + void_list_node_1))); + DECL_EXTERNAL (execclass_decl) = 1; + DECL_ARTIFICIAL (execclass_decl) = 1; + TREE_PUBLIC (execclass_decl) = 1; + pushdecl (execclass_decl); + rest_of_decl_compilation (execclass_decl, 0, 0, 0); + assemble_external (execclass_decl); /* void _GLOBAL_$I$ () {objc_execClass (&L_OBJC_MODULES);} */ + init_function_name = get_file_function_name ('I'); start_function (void_list_node_1, build_nt (CALL_EXPR, init_function_name, - /* This has the format of the output - of get_parm_info. */ tree_cons (NULL_TREE, NULL_TREE, void_list_node_1), NULL_TREE), - NULL_TREE, NULL_TREE); -#if 0 /* This should be turned back on later - for the systems where collect is not needed. */ - /* Make these functions nonglobal - so each file can use the same name. */ - TREE_PUBLIC (current_function_decl) = 0; -#endif - TREE_USED (current_function_decl) = 1; + NULL_TREE); store_parm_decls (); - assemble_external (function_decl); - c_expand_expr_stmt (decelerator); + init_function_decl = current_function_decl; + TREE_PUBLIC (init_function_decl) = ! targetm.have_ctors_dtors; + TREE_USED (init_function_decl) = 1; + /* Don't let this one be deferred. */ + DECL_INLINE (init_function_decl) = 0; + DECL_UNINLINABLE (init_function_decl) = 1; + current_function_cannot_inline + = "static constructors and destructors cannot be inlined"; + + parms + = build_tree_list (NULL_TREE, + build_unary_op (ADDR_EXPR, UOBJC_MODULES_decl, 0)); + decelerator = build_function_call (execclass_decl, parms); - TREE_PUBLIC (current_function_decl) = 1; + c_expand_expr_stmt (decelerator); - function_decl = current_function_decl; - finish_function (0); + finish_function (0, 0); - /* Return the name of the constructor function. */ - return XSTR (XEXP (DECL_RTL (function_decl), 0), 0); + return XEXP (DECL_RTL (init_function_decl), 0); } } @@ -1967,7 +1839,7 @@ get_objc_string_decl (ident, section) else abort (); - for (; chain != 0; chain = TREE_VALUE (chain)) + for (; chain != 0; chain = TREE_CHAIN (chain)) if (TREE_VALUE (chain) == ident) return (TREE_PURPOSE (chain)); @@ -2003,7 +1875,7 @@ generate_static_references () decl_spec = tree_cons (NULL_TREE, build_pointer_type (void_type_node), build_tree_list (NULL_TREE, ridpointers[(int) RID_STATIC])); - decl = start_decl (expr_decl, decl_spec, 1, NULL_TREE, NULL_TREE); + decl = start_decl (expr_decl, decl_spec, 1, NULL_TREE); DECL_CONTEXT (decl) = 0; DECL_ARTIFICIAL (decl) = 1; @@ -2043,7 +1915,7 @@ generate_static_references () build_tree_list (NULL_TREE, ridpointers[(int) RID_STATIC])); static_instances_decl - = start_decl (expr_decl, decl_spec, 1, NULL_TREE, NULL_TREE); + = start_decl (expr_decl, decl_spec, 1, NULL_TREE); TREE_USED (static_instances_decl) = 1; DECL_CONTEXT (static_instances_decl) = 0; DECL_ARTIFICIAL (static_instances_decl) = 1; @@ -2069,7 +1941,7 @@ generate_strings () = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE); decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec); expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE); - decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE, NULL_TREE); + decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE); DECL_CONTEXT (decl) = NULL_TREE; string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1, IDENTIFIER_POINTER (string)); @@ -2084,7 +1956,7 @@ generate_strings () = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE); decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec); expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE); - decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE, NULL_TREE); + decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE); DECL_CONTEXT (decl) = NULL_TREE; string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1, IDENTIFIER_POINTER (string)); @@ -2099,7 +1971,7 @@ generate_strings () = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE); decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec); expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE); - decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE, NULL_TREE); + decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE); DECL_CONTEXT (decl) = NULL_TREE; string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1, IDENTIFIER_POINTER (string)); @@ -2157,6 +2029,32 @@ build_selector_translation_table () { tree expr; + if (warn_selector && objc_implementation_context) + { + tree method_chain; + bool found = false; + for (method_chain = meth_var_names_chain; + method_chain; + method_chain = TREE_CHAIN (method_chain)) + { + if (TREE_VALUE (method_chain) == TREE_VALUE (chain)) + { + found = true; + break; + } + } + if (!found) + { + /* Adjust line number for warning message. */ + int save_lineno = lineno; + if (flag_next_runtime && TREE_PURPOSE (chain)) + lineno = DECL_SOURCE_LINE (TREE_PURPOSE (chain)); + warning ("creating selector for non existant method %s", + IDENTIFIER_POINTER (TREE_VALUE (chain))); + lineno = save_lineno; + } + } + expr = build_selector (TREE_VALUE (chain)); if (flag_next_runtime) @@ -2172,7 +2070,7 @@ build_selector_translation_table () /* The `decl' that is returned from start_decl is the one that we forward declared in `build_selector_reference' */ - decl = start_decl (var_decl, decl_specs, 1, NULL_TREE, NULL_TREE); + decl = start_decl (var_decl, decl_specs, 1, NULL_TREE ); } /* add one for the '\0' character */ @@ -2240,8 +2138,8 @@ get_proto_encoding (proto) identifier_node that represent the selector. */ static tree -build_typed_selector_reference (ident, proto) - tree ident, proto; +build_typed_selector_reference (ident, prototype) + tree ident, prototype; { tree *chain = &sel_ref_chain; tree expr; @@ -2249,14 +2147,14 @@ build_typed_selector_reference (ident, proto) while (*chain) { - if (TREE_PURPOSE (*chain) == ident && TREE_VALUE (*chain) == proto) + if (TREE_PURPOSE (*chain) == prototype && TREE_VALUE (*chain) == ident) goto return_at_index; index++; chain = &TREE_CHAIN (*chain); } - *chain = tree_cons (proto, ident, NULL_TREE); + *chain = tree_cons (prototype, ident, NULL_TREE); return_at_index: expr = build_unary_op (ADDR_EXPR, @@ -2355,7 +2253,7 @@ add_class_reference (ident) tree get_class_reference (ident) - tree ident; + tree ident; { if (flag_next_runtime) { @@ -2465,9 +2363,9 @@ objc_declare_alias (alias_ident, class_ident) tree class_ident; { if (is_class_name (class_ident) != class_ident) - warning ("Cannot find class `%s'", IDENTIFIER_POINTER (class_ident)); + warning ("cannot find class `%s'", IDENTIFIER_POINTER (class_ident)); else if (is_class_name (alias_ident)) - warning ("Class `%s' already exists", IDENTIFIER_POINTER (alias_ident)); + warning ("class `%s' already exists", IDENTIFIER_POINTER (alias_ident)); else alias_chain = tree_cons (class_ident, alias_ident, alias_chain); } @@ -2523,6 +2421,17 @@ is_class_name (ident) return 0; } +tree +objc_is_id (ident) + tree ident; +{ + /* NB: This function may be called before the ObjC front-end + has been initialized, in which case ID_TYPE will be NULL. */ + return (id_type && ident && TYPE_P (ident) && IS_ID (ident)) + ? id_type + : NULL_TREE; +} + tree lookup_interface (ident) tree ident; @@ -2537,51 +2446,23 @@ lookup_interface (ident) return NULL_TREE; } -static tree -objc_copy_list (list, head) - tree list; - tree *head; -{ - tree newlist = NULL_TREE, tail = NULL_TREE; - - while (list) - { - tail = copy_node (list); - - /* The following statement fixes a bug when inheriting instance - variables that are declared to be bitfields. finish_struct - expects to find the width of the bitfield in DECL_INITIAL. */ - if (DECL_BIT_FIELD (tail) && DECL_INITIAL (tail) == 0) - DECL_INITIAL (tail) = DECL_SIZE (tail); - - newlist = chainon (newlist, tail); - list = TREE_CHAIN (list); - } - - *head = newlist; - return tail; -} - -/* Used by: build_private_template, get_class_ivars, and - continue_class. COPY is 1 when called from @defs. In this case - copy all fields. Otherwise don't copy leaf ivars since we rely on - them being side-effected exactly once by finish_struct. */ +/* Used by: build_private_template, continue_class, + and for @defs constructs. */ -static tree -build_ivar_chain (interface, copy) +tree +get_class_ivars (interface) tree interface; - int copy; { tree my_name, super_name, ivar_chain; my_name = CLASS_NAME (interface); super_name = CLASS_SUPER_NAME (interface); + ivar_chain = CLASS_IVARS (interface); - /* Possibly copy leaf ivars. */ - if (copy) - objc_copy_list (CLASS_IVARS (interface), &ivar_chain); - else - ivar_chain = CLASS_IVARS (interface); + /* Save off a pristine copy of the leaf ivars (i.e, those not + inherited from a super class). */ + if (!CLASS_OWN_IVARS (interface)) + CLASS_OWN_IVARS (interface) = copy_list (ivar_chain); while (super_name) { @@ -2591,28 +2472,28 @@ build_ivar_chain (interface, copy) if (!super_interface) { /* fatal did not work with 2 args...should fix */ - error ("Cannot find interface declaration for `%s', superclass of `%s'", + error ("cannot find interface declaration for `%s', superclass of `%s'", IDENTIFIER_POINTER (super_name), IDENTIFIER_POINTER (my_name)); exit (FATAL_EXIT_CODE); } if (super_interface == interface) - fatal_error ("Circular inheritance in interface declaration for `%s'", + fatal_error ("circular inheritance in interface declaration for `%s'", IDENTIFIER_POINTER (super_name)); interface = super_interface; my_name = CLASS_NAME (interface); super_name = CLASS_SUPER_NAME (interface); - op1 = CLASS_IVARS (interface); + op1 = CLASS_OWN_IVARS (interface); if (op1) { - tree head, tail = objc_copy_list (op1, &head); + tree head = copy_list (op1); /* Prepend super class ivars...make a copy of the list, we do not want to alter the original. */ - TREE_CHAIN (tail) = ivar_chain; + chainon (head, ivar_chain); ivar_chain = head; } } @@ -2639,7 +2520,7 @@ build_private_template (class) { uprivate_record = start_struct (RECORD_TYPE, CLASS_NAME (class)); - ivar_context = build_ivar_chain (class, 0); + ivar_context = get_class_ivars (class); finish_struct (uprivate_record, ivar_context, NULL_TREE); @@ -2967,7 +2848,7 @@ generate_descriptor_table (type, name, size, list, proto) decl_specs = tree_cons (NULL_TREE, type, sc_spec); decl = start_decl (synth_id_with_class_suffix (name, proto), - decl_specs, 1, NULL_TREE, NULL_TREE); + decl_specs, 1, NULL_TREE); DECL_CONTEXT (decl) = NULL_TREE; initlist = build_tree_list (NULL_TREE, build_int_2 (size, 0)); @@ -2980,19 +2861,15 @@ generate_descriptor_table (type, name, size, list, proto) } static void -generate_method_descriptors (protocol) /* generate_dispatch_tables */ - tree protocol; +generate_method_descriptors (protocol) + tree protocol; { - static tree objc_method_prototype_template; tree initlist, chain, method_list_template; tree cast, variable_length_type; int size; if (!objc_method_prototype_template) - { - objc_method_prototype_template = build_method_prototype_template (); - ggc_add_tree_root (&objc_method_prototype_template, 1); - } + objc_method_prototype_template = build_method_prototype_template (); cast = build_tree_list (build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE, get_identifier (UTAG_METHOD_PROTOTYPE_LIST))), @@ -3060,14 +2937,14 @@ build_tmp_function_decl () (build_tree_list (decl_specs, build1 (INDIRECT_REF, NULL_TREE, NULL_TREE)), - build_tree_list (NULL_TREE, NULL_TREE))); + NULL_TREE)); decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE, get_identifier (TAG_SELECTOR))); expr_decl = build1 (INDIRECT_REF, NULL_TREE, NULL_TREE); push_parm_decl (build_tree_list (build_tree_list (decl_specs, expr_decl), - build_tree_list (NULL_TREE, NULL_TREE))); + NULL_TREE)); parms = get_parm_info (0); poplevel (0, 0, 0); @@ -3109,6 +2986,9 @@ hack_method_prototype (nst_methods, tmp_decl) /* Usually called from store_parm_decls -> init_function_start. */ DECL_ARGUMENTS (tmp_decl) = TREE_PURPOSE (parms); + + if (current_function_decl) + abort (); current_function_decl = tmp_decl; { @@ -3132,6 +3012,7 @@ hack_method_prototype (nst_methods, tmp_decl) /* install return type */ TREE_TYPE (TREE_TYPE (tmp_decl)) = groktypename (TREE_TYPE (nst_methods)); + current_function_decl = NULL; } static void @@ -3157,6 +3038,43 @@ generate_protocol_references (plist) } } +/* For each protocol which was referenced either from a @protocol() + expression, or because a class/category implements it (then a + pointer to the protocol is stored in the struct describing the + class/category), we create a statically allocated instance of the + Protocol class. The code is written in such a way as to generate + as few Protocol objects as possible; we generate a unique Protocol + instance for each protocol, and we don't generate a Protocol + instance if the protocol is never referenced (either from a + @protocol() or from a class/category implementation). These + statically allocated objects can be referred to via the static + (that is, private to this module) symbols _OBJC_PROTOCOL_n. + + The statically allocated Protocol objects that we generate here + need to be fixed up at runtime in order to be used: the 'isa' + pointer of the objects need to be set up to point to the 'Protocol' + class, as known at runtime. + + The NeXT runtime fixes up all protocols at program startup time, + before main() is entered. It uses a low-level trick to look up all + those symbols, then loops on them and fixes them up. + + The GNU runtime as well fixes up all protocols before user code + from the module is executed; it requires pointers to those symbols + to be put in the objc_symtab (which is then passed as argument to + the function __objc_exec_class() which the compiler sets up to be + executed automatically when the module is loaded); setup of those + Protocol objects happen in two ways in the GNU runtime: all + Protocol objects referred to by a class or category implementation + are fixed up when the class/category is loaded; all Protocol + objects referred to by a @protocol() expression are added by the + compiler to the list of statically allocated instances to fixup + (the same list holding the statically allocated constant string + objects). Because, as explained above, the compiler generates as + few Protocol objects as possible, some Protocol object might end up + being referenced multiple times when compiled with the GNU runtime, + and end up being fixed up multiple times at runtime inizialization. + But that doesn't hurt, it's just a little inefficient. */ static void generate_protocols () { @@ -3223,7 +3141,7 @@ generate_protocols () decl_specs = tree_cons (NULL_TREE, objc_protocol_template, sc_spec); decl = start_decl (synth_id_with_class_suffix ("_OBJC_PROTOCOL", p), - decl_specs, 1, NULL_TREE, NULL_TREE); + decl_specs, 1, NULL_TREE); DECL_CONTEXT (decl) = NULL_TREE; @@ -3588,7 +3506,7 @@ synth_forward_declarations () /* extern struct objc_class _OBJC_CLASS_; */ - an_id = synth_id_with_class_suffix ("_OBJC_CLASS", implementation_context); + an_id = synth_id_with_class_suffix ("_OBJC_CLASS", objc_implementation_context); sc_spec = build_tree_list (NULL_TREE, ridpointers[(int) RID_EXTERN]); decl_specs = tree_cons (NULL_TREE, objc_class_template, sc_spec); @@ -3599,7 +3517,7 @@ synth_forward_declarations () /* extern struct objc_class _OBJC_METACLASS_; */ an_id = synth_id_with_class_suffix ("_OBJC_METACLASS", - implementation_context); + objc_implementation_context); UOBJC_METACLASS_decl = define_decl (an_id, decl_specs); TREE_USED (UOBJC_METACLASS_decl) = 1; @@ -3618,9 +3536,9 @@ error_with_ivar (message, decl, rawdecl) tree decl; tree rawdecl; { - count_error (0); + diagnostic_count_diagnostic (global_dc, DK_ERROR); - report_error_function (DECL_SOURCE_FILE (decl)); + diagnostic_report_current_function (global_dc); error_with_file_and_line (DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl), @@ -3629,10 +3547,6 @@ error_with_ivar (message, decl, rawdecl) } -#define USERTYPE(t) \ - (TREE_CODE (t) == RECORD_TYPE || TREE_CODE (t) == UNION_TYPE \ - || TREE_CODE (t) == ENUMERAL_TYPE) - static void check_ivars (inter, imp) tree inter; @@ -3903,7 +3817,7 @@ build_ivar_list_initializer (type, field_decl) ivar); obstack_free (&util_obstack, util_firstobj); - /* Set offset. */ + /* Set offset. */ ivar = tree_cons (NULL_TREE, byte_position (field_decl), ivar); initlist = tree_cons (NULL_TREE, build_constructor (type, nreverse (ivar)), @@ -3928,8 +3842,8 @@ generate_ivars_list (type, name, size, list) sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE); decl_specs = tree_cons (NULL_TREE, type, sc_spec); - decl = start_decl (synth_id_with_class_suffix (name, implementation_context), - decl_specs, 1, NULL_TREE, NULL_TREE); + decl = start_decl (synth_id_with_class_suffix (name, objc_implementation_context), + decl_specs, 1, NULL_TREE); initlist = build_tree_list (NULL_TREE, build_int_2 (size, 0)); initlist = tree_cons (NULL_TREE, list, initlist); @@ -4012,6 +3926,11 @@ build_dispatch_table_initializer (type, entries) build_selector (METHOD_SEL_NAME (entries)), NULL_TREE); + /* Generate the method encoding if we don't have one already. */ + if (! METHOD_ENCODING (entries)) + METHOD_ENCODING (entries) = + encode_method_def (METHOD_DEFINITION (entries)); + elemlist = tree_cons (NULL_TREE, add_objc_string (METHOD_ENCODING (entries), meth_var_types), @@ -4093,8 +4012,8 @@ generate_dispatch_table (type, name, size, list) sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE); decl_specs = tree_cons (NULL_TREE, type, sc_spec); - decl = start_decl (synth_id_with_class_suffix (name, implementation_context), - decl_specs, 1, NULL_TREE, NULL_TREE); + decl = start_decl (synth_id_with_class_suffix (name, objc_implementation_context), + decl_specs, 1, NULL_TREE); initlist = build_tree_list (NULL_TREE, build_int_2 (0, 0)); initlist = tree_cons (NULL_TREE, build_int_2 (size, 0), initlist); @@ -4126,7 +4045,7 @@ generate_dispatch_tables () variable_length_type = groktypename (cast); - chain = CLASS_CLS_METHODS (implementation_context); + chain = CLASS_CLS_METHODS (objc_implementation_context); if (chain) { size = list_length (chain); @@ -4138,7 +4057,7 @@ generate_dispatch_tables () UOBJC_CLASS_METHODS_decl = generate_dispatch_table (method_list_template, - ((TREE_CODE (implementation_context) + ((TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE) ? "_OBJC_CLASS_METHODS" : "_OBJC_CATEGORY_CLASS_METHODS"), @@ -4148,7 +4067,7 @@ generate_dispatch_tables () else UOBJC_CLASS_METHODS_decl = 0; - chain = CLASS_NST_METHODS (implementation_context); + chain = CLASS_NST_METHODS (objc_implementation_context); if (chain) { size = list_length (chain); @@ -4158,7 +4077,7 @@ generate_dispatch_tables () initlist = build_dispatch_table_initializer (objc_method_template, chain); - if (TREE_CODE (implementation_context) == CLASS_IMPLEMENTATION_TYPE) + if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE) UOBJC_INSTANCE_METHODS_decl = generate_dispatch_table (method_list_template, "_OBJC_INSTANCE_METHODS", @@ -4252,7 +4171,7 @@ generate_protocol_list (i_or_p) expr_decl = build1 (INDIRECT_REF, NULL_TREE, expr_decl); - refs_decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE, NULL_TREE); + refs_decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE); DECL_CONTEXT (refs_decl) = NULL_TREE; finish_decl (refs_decl, build_constructor (TREE_TYPE (refs_decl), @@ -4461,8 +4380,8 @@ generate_category (cat) decl_specs = tree_cons (NULL_TREE, objc_category_template, sc_spec); decl = start_decl (synth_id_with_class_suffix ("_OBJC_CATEGORY", - implementation_context), - decl_specs, 1, NULL_TREE, NULL_TREE); + objc_implementation_context), + decl_specs, 1, NULL_TREE); initlist = build_category_initializer (TREE_TYPE (decl), cat_name_expr, class_name_expr, @@ -4545,7 +4464,7 @@ generate_shared_structures () decl_specs = tree_cons (NULL_TREE, objc_class_template, sc_spec); decl = start_decl (DECL_NAME (UOBJC_METACLASS_decl), decl_specs, 1, - NULL_TREE, NULL_TREE); + NULL_TREE); initlist = build_shared_structure_initializer @@ -4562,7 +4481,7 @@ generate_shared_structures () /* static struct objc_class _OBJC_CLASS_Foo={ ... }; */ decl = start_decl (DECL_NAME (UOBJC_CLASS_decl), decl_specs, 1, - NULL_TREE, NULL_TREE); + NULL_TREE); initlist = build_shared_structure_initializer @@ -4589,8 +4508,8 @@ synth_id_with_class_suffix (preamble, ctxt) if (TREE_CODE (ctxt) == CLASS_IMPLEMENTATION_TYPE || TREE_CODE (ctxt) == CLASS_INTERFACE_TYPE) { - const char *class_name - = IDENTIFIER_POINTER (CLASS_NAME (implementation_context)); + const char *const class_name + = IDENTIFIER_POINTER (CLASS_NAME (objc_implementation_context)); string = (char *) alloca (strlen (preamble) + strlen (class_name) + 3); sprintf (string, "%s_%s", preamble, IDENTIFIER_POINTER (CLASS_NAME (ctxt))); @@ -4599,10 +4518,10 @@ synth_id_with_class_suffix (preamble, ctxt) || TREE_CODE (ctxt) == CATEGORY_INTERFACE_TYPE) { /* We have a category. */ - const char *class_name - = IDENTIFIER_POINTER (CLASS_NAME (implementation_context)); - const char *class_super_name - = IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_context)); + const char *const class_name + = IDENTIFIER_POINTER (CLASS_NAME (objc_implementation_context)); + const char *const class_super_name + = IDENTIFIER_POINTER (CLASS_SUPER_NAME (objc_implementation_context)); string = (char *) alloca (strlen (preamble) + strlen (class_name) + strlen (class_super_name) @@ -4657,6 +4576,10 @@ adjust_type_for_id_default (type) chain; chain = TREE_CHAIN (chain)) { + if (TYPED_OBJECT (TREE_VALUE (chain)) + && !(TREE_VALUE (type) + && TREE_CODE (TREE_VALUE (type)) == INDIRECT_REF)) + error ("can not use an object as parameter to a method\n"); if (!is_objc_type_qualifier (TREE_VALUE (chain))) return type; } @@ -4790,8 +4713,8 @@ build_method_decl (code, ret_type, selector, add_args) #define METHOD_DEF 0 #define METHOD_REF 1 -/* Used by `build_message_expr' and `comp_method_types'. Return an - argument list for method METH. CONTEXT is either METHOD_DEF or +/* Used by `build_objc_method_call' and `comp_method_types'. Return + an argument list for method METH. CONTEXT is either METHOD_DEF or METHOD_REF, saying whether we are trying to define a method or call one. SUPERFLAG says this is for a send to super; this makes a difference for the NeXT calling sequence in which the lookup and @@ -4867,18 +4790,29 @@ check_duplicates (hsh) return meth; } -/* If RECEIVER is a class reference, return the identifier node for the - referenced class. RECEIVER is created by get_class_reference, so we - check the exact form created depending on which runtimes are used. */ +/* If RECEIVER is a class reference, return the identifier node for + the referenced class. RECEIVER is created by get_class_reference, + so we check the exact form created depending on which runtimes are + used. */ static tree receiver_is_class_object (receiver) tree receiver; { tree chain, exp, arg; + + /* The receiver is 'self' in the context of a class method. */ + if (objc_method_context + && receiver == self_decl + && TREE_CODE (objc_method_context) == CLASS_METHOD_DECL) + { + return CLASS_NAME (objc_implementation_context); + } + if (flag_next_runtime) { - /* The receiver is a variable created by build_class_reference_decl. */ + /* The receiver is a variable created by + build_class_reference_decl. */ if (TREE_CODE (receiver) == VAR_DECL && TREE_TYPE (receiver) == objc_class_type) /* Look up the identifier. */ @@ -4890,12 +4824,13 @@ receiver_is_class_object (receiver) { /* The receiver is a function call that returns an id. Check if it is a call to objc_getClass, if so, pick up the class name. */ - if ((exp = TREE_OPERAND (receiver, 0)) + if (TREE_CODE (receiver) == CALL_EXPR + && (exp = TREE_OPERAND (receiver, 0)) && TREE_CODE (exp) == ADDR_EXPR && (exp = TREE_OPERAND (exp, 0)) && TREE_CODE (exp) == FUNCTION_DECL && exp == objc_get_class_decl - /* we have a call to objc_getClass! */ + /* We have a call to objc_getClass! */ && (arg = TREE_OPERAND (receiver, 1)) && TREE_CODE (arg) == TREE_LIST && (arg = TREE_VALUE (arg))) @@ -4915,12 +4850,12 @@ receiver_is_class_object (receiver) the identifier of the selector of the message. This is used when printing warnings about argument mismatches. */ -static tree building_objc_message_expr = 0; +static tree current_objc_message_selector = 0; tree -maybe_building_objc_message_expr () +objc_message_selector () { - return building_objc_message_expr; + return current_objc_message_selector; } /* Construct an expression for sending a message. @@ -4935,57 +4870,14 @@ build_message_expr (mess) tree mess; { tree receiver = TREE_PURPOSE (mess); - tree selector, self_object; - tree rtype, sel_name; + tree sel_name; tree args = TREE_VALUE (mess); tree method_params = NULL_TREE; - tree method_prototype = NULL_TREE; - tree retval; - int statically_typed = 0, statically_allocated = 0; - tree class_ident = 0; - - /* 1 if this is sending to the superclass. */ - int super; if (TREE_CODE (receiver) == ERROR_MARK) return error_mark_node; - /* Determine receiver type. */ - rtype = TREE_TYPE (receiver); - super = IS_SUPER (rtype); - - if (! super) - { - if (TREE_STATIC_TEMPLATE (rtype)) - statically_allocated = 1; - else if (TREE_CODE (rtype) == POINTER_TYPE - && TREE_STATIC_TEMPLATE (TREE_TYPE (rtype))) - statically_typed = 1; - else if ((flag_next_runtime - || (TREE_CODE (receiver) == CALL_EXPR && IS_ID (rtype))) - && (class_ident = receiver_is_class_object (receiver))) - ; - else if (! IS_ID (rtype) - /* Allow any type that matches objc_class_type. */ - && ! comptypes (rtype, objc_class_type)) - { - warning ("invalid receiver type `%s'", - gen_declaration (rtype, errbuf)); - } - - if (statically_allocated) - receiver = build_unary_op (ADDR_EXPR, receiver, 0); - - /* Don't evaluate the receiver twice. */ - receiver = save_expr (receiver); - self_object = receiver; - } - else - /* If sending to `super', use current self as the object. */ - self_object = self_decl; - /* Obtain the full selector name. */ - if (TREE_CODE (args) == IDENTIFIER_NODE) /* A unary selector. */ sel_name = args; @@ -4995,8 +4887,6 @@ build_message_expr (mess) abort (); /* Build the parameter list to give to the method. */ - - method_params = NULL_TREE; if (TREE_CODE (args) == TREE_LIST) { tree chain = args, prev = NULL_TREE; @@ -5020,9 +4910,58 @@ build_message_expr (mess) method_params = args; } + return finish_message_expr (receiver, sel_name, method_params); +} + +/* The 'finish_message_expr' routine is called from within + 'build_message_expr' for non-template functions. In the case of + C++ template functions, it is called from 'build_expr_from_tree' + (in decl2.c) after RECEIVER and METHOD_PARAMS have been expanded. */ + +tree +finish_message_expr (receiver, sel_name, method_params) + tree receiver, sel_name, method_params; +{ + tree method_prototype = NULL_TREE, class_ident = NULL_TREE; + tree selector, self_object, retval; + int statically_typed = 0, statically_allocated = 0; + + /* Determine receiver type. */ + tree rtype = TREE_TYPE (receiver); + int super = IS_SUPER (rtype); + + if (! super) + { + if (TREE_STATIC_TEMPLATE (rtype)) + statically_allocated = 1; + else if (TREE_CODE (rtype) == POINTER_TYPE + && TREE_STATIC_TEMPLATE (TREE_TYPE (rtype))) + statically_typed = 1; + else if ((flag_next_runtime + || (IS_ID (rtype))) + && (class_ident = receiver_is_class_object (receiver))) + ; + else if (! IS_ID (rtype) + /* Allow any type that matches objc_class_type. */ + && ! comptypes (rtype, objc_class_type)) + { + warning ("invalid receiver type `%s'", + gen_declaration (rtype, errbuf)); + } + if (statically_allocated) + receiver = build_unary_op (ADDR_EXPR, receiver, 0); + + /* Don't evaluate the receiver twice. */ + receiver = save_expr (receiver); + self_object = receiver; + } + else + /* If sending to `super', use current self as the object. */ + self_object = self_decl; + /* Determine operation return type. */ - if (IS_SUPER (rtype)) + if (super) { tree iface; @@ -5031,7 +4970,7 @@ build_message_expr (mess) iface = lookup_interface (CLASS_SUPER_NAME (implementation_template)); - if (TREE_CODE (method_context) == INSTANCE_METHOD_DECL) + if (TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL) method_prototype = lookup_instance_method_static (iface, sel_name); else method_prototype = lookup_class_method_static (iface, sel_name); @@ -5057,7 +4996,7 @@ build_message_expr (mess) if (iface) method_prototype = lookup_instance_method_static (iface, sel_name); - if (! method_prototype && TYPE_PROTOCOL_LIST (ctype)) + if (! method_prototype && ctype && TYPE_PROTOCOL_LIST (ctype)) method_prototype = lookup_method_in_protocol_list (TYPE_PROTOCOL_LIST (ctype), sel_name, 0); @@ -5073,8 +5012,8 @@ build_message_expr (mess) /* `self' is now statically_typed. All methods should be visible within the context of the implementation. */ - if (implementation_context - && CLASS_NAME (implementation_context) == TYPE_NAME (ctype)) + if (objc_implementation_context + && CLASS_NAME (objc_implementation_context) == TYPE_NAME (ctype)) { method_prototype = lookup_instance_method_static (implementation_template, @@ -5086,11 +5025,11 @@ build_message_expr (mess) sel_name, 0); if (! method_prototype - && implementation_template != implementation_context) + && implementation_template != objc_implementation_context) /* The method is not published in the interface. Check locally. */ method_prototype - = lookup_method (CLASS_NST_METHODS (implementation_context), + = lookup_method (CLASS_NST_METHODS (objc_implementation_context), sel_name); } else @@ -5117,18 +5056,18 @@ build_message_expr (mess) } else if (class_ident) { - if (implementation_context - && CLASS_NAME (implementation_context) == class_ident) + if (objc_implementation_context + && CLASS_NAME (objc_implementation_context) == class_ident) { method_prototype = lookup_class_method_static (implementation_template, sel_name); if (!method_prototype - && implementation_template != implementation_context) + && implementation_template != objc_implementation_context) /* The method is not published in the interface. Check locally. */ method_prototype - = lookup_method (CLASS_CLS_METHODS (implementation_context), + = lookup_method (CLASS_CLS_METHODS (objc_implementation_context), sel_name); } else @@ -5141,7 +5080,7 @@ build_message_expr (mess) if (!method_prototype) { - warning ("cannot find class (factory) method."); + warning ("cannot find class (factory) method"); warning ("return type for `%s' defaults to id", IDENTIFIER_POINTER (sel_name)); } @@ -5159,7 +5098,7 @@ build_message_expr (mess) { hash hsh; - warning ("method `%s' not implemented by protocol.", + warning ("method `%s' not implemented by protocol", IDENTIFIER_POINTER (sel_name)); /* Try and find the method signature in the global pools. */ @@ -5177,22 +5116,22 @@ build_message_expr (mess) /* We think we have an instance...loophole: extern id Object; */ hsh = hash_lookup (nst_method_hash_list, sel_name); + if (!hsh) - /* For various loopholes, like sending messages to self in a - factory context. */ + /* For various loopholes */ hsh = hash_lookup (cls_method_hash_list, sel_name); method_prototype = check_duplicates (hsh); if (!method_prototype) { - warning ("cannot find method."); + warning ("cannot find method"); warning ("return type for `%s' defaults to id", IDENTIFIER_POINTER (sel_name)); } } /* Save the selector name for printing error messages. */ - building_objc_message_expr = sel_name; + current_objc_message_selector = sel_name; /* Build the parameters list for looking up the method. These are the object itself and the selector. */ @@ -5206,7 +5145,7 @@ build_message_expr (mess) receiver, self_object, selector, method_params); - building_objc_message_expr = 0; + current_objc_message_selector = 0; return retval; } @@ -5246,12 +5185,12 @@ build_objc_method_call (super_flag, method_prototype, lookup_object, object, Clobber the data type of SENDER temporarily to accept all the arguments for this operation, and to return whatever this operation returns. */ - tree arglist = NULL_TREE; - tree retval; + tree arglist = NULL_TREE, retval, savarg, savret; + tree ret_type = groktypename (TREE_TYPE (method_prototype)); /* Save the proper contents of SENDER's data type. */ - tree savarg = TYPE_ARG_TYPES (TREE_TYPE (sender)); - tree savret = TREE_TYPE (TREE_TYPE (sender)); + savarg = TYPE_ARG_TYPES (TREE_TYPE (sender)); + savret = TREE_TYPE (TREE_TYPE (sender)); /* Install this method's argument types. */ arglist = get_arg_type_list (method_prototype, METHOD_REF, @@ -5259,8 +5198,7 @@ build_objc_method_call (super_flag, method_prototype, lookup_object, object, TYPE_ARG_TYPES (TREE_TYPE (sender)) = arglist; /* Install this method's return type. */ - TREE_TYPE (TREE_TYPE (sender)) - = groktypename (TREE_TYPE (method_prototype)); + TREE_TYPE (TREE_TYPE (sender)) = ret_type; /* Call SENDER with all the parameters. This will do type checking using the arg types for this method. */ @@ -5351,6 +5289,8 @@ build_protocol_reference (p) PROTOCOL_FORWARD_DECL (p) = decl; } +/* This function is called by the parser when (and only when) a + @protocol() expression is found, in order to compile it. */ tree build_protocol_expr (protoname) tree protoname; @@ -5360,7 +5300,7 @@ build_protocol_expr (protoname) if (!p) { - error ("Cannot find protocol declaration for `%s'", + error ("cannot find protocol declaration for `%s'", IDENTIFIER_POINTER (protoname)); return error_mark_node; } @@ -5372,9 +5312,56 @@ build_protocol_expr (protoname) TREE_TYPE (expr) = protocol_type; + /* The @protocol() expression is being compiled into a pointer to a + statically allocated instance of the Protocol class. To become + usable at runtime, the 'isa' pointer of the instance need to be + fixed up at runtime by the runtime library, to point to the + actual 'Protocol' class. */ + + /* For the GNU runtime, put the static Protocol instance in the list + of statically allocated instances, so that we make sure that its + 'isa' pointer is fixed up at runtime by the GNU runtime library + to point to the Protocol class (at runtime, when loading the + module, the GNU runtime library loops on the statically allocated + instances (as found in the defs field in objc_symtab) and fixups + all the 'isa' pointers of those objects). */ + if (! flag_next_runtime) + { + /* This type is a struct containing the fields of a Protocol + object. (Cfr. protocol_type instead is the type of a pointer + to such a struct). */ + tree protocol_struct_type = xref_tag + (RECORD_TYPE, get_identifier (PROTOCOL_OBJECT_CLASS_NAME)); + tree *chain; + + /* Look for the list of Protocol statically allocated instances + to fixup at runtime. Create a new list to hold Protocol + statically allocated instances, if the list is not found. At + present there is only another list, holding NSConstantString + static instances to be fixed up at runtime. */ + for (chain = &objc_static_instances; + *chain && TREE_VALUE (*chain) != protocol_struct_type; + chain = &TREE_CHAIN (*chain)); + if (!*chain) + { + *chain = tree_cons (NULL_TREE, protocol_struct_type, NULL_TREE); + add_objc_string (TYPE_NAME (protocol_struct_type), + class_names); + } + + /* Add this statically allocated instance to the Protocol list. */ + TREE_PURPOSE (*chain) = tree_cons (NULL_TREE, + PROTOCOL_FORWARD_DECL (p), + TREE_PURPOSE (*chain)); + } + + return expr; } +/* This function is called by the parser when a @selector() expression + is found, in order to compile it. It is only called by the parser + and only to compile a @selector(). */ tree build_selector_expr (selnamelist) tree selnamelist; @@ -5390,6 +5377,32 @@ build_selector_expr (selnamelist) else abort (); + /* If we are required to check @selector() expressions as they + are found, check that the selector has been declared. */ + if (warn_undeclared_selector) + { + /* Look the selector up in the list of all known class and + instance methods (up to this line) to check that the selector + exists. */ + hash hsh; + + /* First try with instance methods. */ + hsh = hash_lookup (nst_method_hash_list, selname); + + /* If not found, try with class methods. */ + if (!hsh) + { + hsh = hash_lookup (cls_method_hash_list, selname); + } + + /* If still not found, print out a warning. */ + if (!hsh) + { + warning ("undeclared selector `%s'", IDENTIFIER_POINTER (selname)); + } + } + + if (flag_typed_selectors) return build_typed_selector_reference (selname, 0); else @@ -5418,7 +5431,7 @@ tree build_ivar_reference (id) tree id; { - if (TREE_CODE (method_context) == CLASS_METHOD_DECL) + if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL) { /* Historically, a class method that produced objects (factory method) would assign `self' to the instance that it @@ -5437,18 +5450,26 @@ build_ivar_reference (id) return build_component_ref (build_indirect_ref (self_decl, "->"), id); } -#define HASH_ALLOC_LIST_SIZE 170 -#define ATTR_ALLOC_LIST_SIZE 170 -#define SIZEHASHTABLE 257 - -/* make positive */ -#define HASHFUNCTION(key) ((HOST_WIDE_INT) key & 0x7fffffff) +/* Compute a hash value for a given method SEL_NAME. */ +static size_t +hash_func (sel_name) + tree sel_name; +{ + const unsigned char *s + = (const unsigned char *)IDENTIFIER_POINTER (sel_name); + size_t h = 0; + + while (*s) + h = h * 67 + *s++ - 113; + return h; +} + static void hash_init () { - nst_method_hash_list = (hash *) xcalloc (SIZEHASHTABLE, sizeof (hash)); - cls_method_hash_list = (hash *) xcalloc (SIZEHASHTABLE, sizeof (hash)); + nst_method_hash_list = (hash *) ggc_calloc (SIZEHASHTABLE, sizeof (hash)); + cls_method_hash_list = (hash *) ggc_calloc (SIZEHASHTABLE, sizeof (hash)); } /* WARNING!!!! hash_enter is called with a method, and will peek @@ -5461,18 +5482,10 @@ hash_enter (hashlist, method) hash *hashlist; tree method; { - static hash hash_alloc_list = 0; - static int hash_alloc_index = 0; hash obj; - int slot = HASHFUNCTION (METHOD_SEL_NAME (method)) % SIZEHASHTABLE; + int slot = hash_func (METHOD_SEL_NAME (method)) % SIZEHASHTABLE; - if (! hash_alloc_list || hash_alloc_index >= HASH_ALLOC_LIST_SIZE) - { - hash_alloc_index = 0; - hash_alloc_list = (hash) xmalloc (sizeof (struct hashed_entry) - * HASH_ALLOC_LIST_SIZE); - } - obj = &hash_alloc_list[hash_alloc_index++]; + obj = (hash) ggc_alloc (sizeof (struct hashed_entry)); obj->list = 0; obj->next = hashlist[slot]; obj->key = method; @@ -5487,7 +5500,7 @@ hash_lookup (hashlist, sel_name) { hash target; - target = hashlist[HASHFUNCTION (sel_name) % SIZEHASHTABLE]; + target = hashlist[hash_func (sel_name) % SIZEHASHTABLE]; while (target) { @@ -5504,17 +5517,9 @@ hash_add_attr (entry, value) hash entry; tree value; { - static attr attr_alloc_list = 0; - static int attr_alloc_index = 0; attr obj; - if (! attr_alloc_list || attr_alloc_index >= ATTR_ALLOC_LIST_SIZE) - { - attr_alloc_index = 0; - attr_alloc_list = (attr) xmalloc (sizeof (struct hashed_attribute) - * ATTR_ALLOC_LIST_SIZE); - } - obj = &attr_alloc_list[attr_alloc_index++]; + obj = (attr) ggc_alloc (sizeof (struct hashed_attribute)); obj->next = entry->list; obj->value = value; @@ -5537,6 +5542,7 @@ lookup_method (mchain, method) { if (METHOD_SEL_NAME (mchain) == key) return mchain; + mchain = TREE_CHAIN (mchain); } return NULL_TREE; @@ -5648,7 +5654,9 @@ lookup_class_method_static (interface, ident) } while (inter); - /* Simulate wrap around. */ + /* If no class (factory) method was found, check if an _instance_ + method of the same name exists in the root class. This is what + the Objective-C runtime will do. */ return lookup_instance_method_static (root_inter, ident); } @@ -5669,13 +5677,13 @@ add_class_method (class, method) else { if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE) - error ("duplicate definition of class method `%s'.", + error ("duplicate definition of class method `%s'", IDENTIFIER_POINTER (METHOD_SEL_NAME (mth))); else { /* Check types; if different, complain. */ if (!comp_proto_with_proto (method, mth)) - error ("duplicate declaration of class method `%s'.", + error ("duplicate declaration of class method `%s'", IDENTIFIER_POINTER (METHOD_SEL_NAME (mth))); } } @@ -5711,13 +5719,13 @@ add_instance_method (class, method) else { if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE) - error ("duplicate definition of instance method `%s'.", + error ("duplicate definition of instance method `%s'", IDENTIFIER_POINTER (METHOD_SEL_NAME (mth))); else { /* Check types; if different, complain. */ if (!comp_proto_with_proto (method, mth)) - error ("duplicate declaration of instance method `%s'.", + error ("duplicate declaration of instance method `%s'", IDENTIFIER_POINTER (METHOD_SEL_NAME (mth))); } } @@ -5868,7 +5876,7 @@ is_public (expr, identifier) { if (!lookup_interface (TYPE_NAME (basetype))) { - error ("Cannot find interface declaration for `%s'", + error ("cannot find interface declaration for `%s'", IDENTIFIER_POINTER (TYPE_NAME (basetype))); return 0; } @@ -5881,12 +5889,12 @@ is_public (expr, identifier) /* Important difference between the Stepstone translator: all instance variables should be public within the context of the implementation. */ - if (implementation_context - && (((TREE_CODE (implementation_context) + if (objc_implementation_context + && (((TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE) - || (TREE_CODE (implementation_context) + || (TREE_CODE (objc_implementation_context) == CATEGORY_IMPLEMENTATION_TYPE)) - && (CLASS_NAME (implementation_context) + && (CLASS_NAME (objc_implementation_context) == TYPE_NAME (basetype)))) return ! is_private (decl); @@ -5897,7 +5905,7 @@ is_public (expr, identifier) } } - else if (implementation_context && (basetype == objc_object_reference)) + else if (objc_implementation_context && (basetype == objc_object_reference)) { TREE_TYPE (expr) = uprivate_record; warning ("static access to object of type `id'"); @@ -5906,18 +5914,6 @@ is_public (expr, identifier) return 1; } - -/* Implement @defs () within struct bodies. */ - -tree -get_class_ivars (interface) - tree interface; -{ - /* Make sure we copy the leaf ivars in case @defs is used in a local - context. Otherwise finish_struct will overwrite the layout info - using temporary storage. */ - return build_ivar_chain (interface, 1); -} /* Make sure all entries in CHAIN are also in LIST. */ @@ -5935,14 +5931,14 @@ check_methods (chain, list, mtype) { if (first) { - if (TREE_CODE (implementation_context) + if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE) warning ("incomplete implementation of class `%s'", - IDENTIFIER_POINTER (CLASS_NAME (implementation_context))); - else if (TREE_CODE (implementation_context) + IDENTIFIER_POINTER (CLASS_NAME (objc_implementation_context))); + else if (TREE_CODE (objc_implementation_context) == CATEGORY_IMPLEMENTATION_TYPE) warning ("incomplete implementation of category `%s'", - IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_context))); + IDENTIFIER_POINTER (CLASS_SUPER_NAME (objc_implementation_context))); first = 0; } @@ -5956,16 +5952,17 @@ check_methods (chain, list, mtype) return first; } +/* Check if CLASS, or its superclasses, explicitly conforms to PROTOCOL. */ + static int conforms_to_protocol (class, protocol) tree class; tree protocol; { - while (protocol) + if (TREE_CODE (protocol) == PROTOCOL_INTERFACE_TYPE) { tree p = CLASS_PROTOCOL_LIST (class); - - while (p && TREE_VALUE (p) != TREE_VALUE (protocol)) + while (p && TREE_VALUE (p) != protocol) p = TREE_CHAIN (p); if (!p) @@ -5977,8 +5974,6 @@ conforms_to_protocol (class, protocol) if (!tmp) return 0; } - - protocol = TREE_CHAIN (protocol); } return 1; @@ -6029,16 +6024,16 @@ check_methods_accessible (chain, context, mtype) { if (first) { - if (TREE_CODE (implementation_context) + if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE) warning ("incomplete implementation of class `%s'", IDENTIFIER_POINTER - (CLASS_NAME (implementation_context))); - else if (TREE_CODE (implementation_context) + (CLASS_NAME (objc_implementation_context))); + else if (TREE_CODE (objc_implementation_context) == CATEGORY_IMPLEMENTATION_TYPE) warning ("incomplete implementation of category `%s'", IDENTIFIER_POINTER - (CLASS_SUPER_NAME (implementation_context))); + (CLASS_SUPER_NAME (objc_implementation_context))); first = 0; } warning ("method definition for `%c%s' not found", @@ -6047,60 +6042,85 @@ check_methods_accessible (chain, context, mtype) chain = TREE_CHAIN (chain); /* next method... */ } - return first; + return first; } +/* Check whether the current interface (accessible via + 'objc_implementation_context') actually implements protocol P, along + with any protocols that P inherits. */ + static void -check_protocols (proto_list, type, name) - tree proto_list; +check_protocol (p, type, name) + tree p; const char *type; const char *name; { - for ( ; proto_list; proto_list = TREE_CHAIN (proto_list)) + if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) { - tree p = TREE_VALUE (proto_list); + int f1, f2; - if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) + /* Ensure that all protocols have bodies! */ + if (warn_protocol) { - int f1, f2; - - /* Ensure that all protocols have bodies. */ - if (flag_warn_protocol) { - f1 = check_methods (PROTOCOL_CLS_METHODS (p), - CLASS_CLS_METHODS (implementation_context), - '+'); - f2 = check_methods (PROTOCOL_NST_METHODS (p), - CLASS_NST_METHODS (implementation_context), - '-'); - } else { - f1 = check_methods_accessible (PROTOCOL_CLS_METHODS (p), - implementation_context, - '+'); - f2 = check_methods_accessible (PROTOCOL_NST_METHODS (p), - implementation_context, - '-'); - } - - if (!f1 || !f2) - warning ("%s `%s' does not fully implement the `%s' protocol", - type, name, IDENTIFIER_POINTER (PROTOCOL_NAME (p))); - + f1 = check_methods (PROTOCOL_CLS_METHODS (p), + CLASS_CLS_METHODS (objc_implementation_context), + '+'); + f2 = check_methods (PROTOCOL_NST_METHODS (p), + CLASS_NST_METHODS (objc_implementation_context), + '-'); } else - { - ; /* An identifier if we could not find a protocol. */ - } + { + f1 = check_methods_accessible (PROTOCOL_CLS_METHODS (p), + objc_implementation_context, + '+'); + f2 = check_methods_accessible (PROTOCOL_NST_METHODS (p), + objc_implementation_context, + '-'); + } - /* Check protocols recursively. */ - if (PROTOCOL_LIST (p)) + if (!f1 || !f2) + warning ("%s `%s' does not fully implement the `%s' protocol", + type, name, IDENTIFIER_POINTER (PROTOCOL_NAME (p))); + } + + /* Check protocols recursively. */ + if (PROTOCOL_LIST (p)) + { + tree subs = PROTOCOL_LIST (p); + tree super_class = + lookup_interface (CLASS_SUPER_NAME (implementation_template)); + + while (subs) { - tree super_class - = lookup_interface (CLASS_SUPER_NAME (implementation_template)); - if (! conforms_to_protocol (super_class, PROTOCOL_LIST (p))) - check_protocols (PROTOCOL_LIST (p), type, name); + tree sub = TREE_VALUE (subs); + + /* If the superclass does not conform to the protocols + inherited by P, then we must! */ + if (!super_class || !conforms_to_protocol (super_class, sub)) + check_protocol (sub, type, name); + subs = TREE_CHAIN (subs); } } } + +/* Check whether the current interface (accessible via + 'objc_implementation_context') actually implements the protocols listed + in PROTO_LIST. */ + +static void +check_protocols (proto_list, type, name) + tree proto_list; + const char *type; + const char *name; +{ + for ( ; proto_list; proto_list = TREE_CHAIN (proto_list)) + { + tree p = TREE_VALUE (proto_list); + + check_protocol (p, type, name); + } +} /* Make sure that the class CLASS_NAME is defined CODE says which kind of thing CLASS_NAME ought to be. @@ -6125,7 +6145,7 @@ start_class (code, class_name, super_name, protocol_list) } class = make_node (code); - TYPE_BINFO (class) = make_tree_vec (5); + TYPE_BINFO (class) = make_tree_vec (6); CLASS_NAME (class) = class_name; CLASS_SUPER_NAME (class) = super_name; @@ -6141,11 +6161,8 @@ start_class (code, class_name, super_name, protocol_list) if (code == CLASS_IMPLEMENTATION_TYPE) { { - static tree implemented_classes = 0; tree chain; - if (!implemented_classes) - ggc_add_tree_root (&implemented_classes, 1); for (chain = implemented_classes; chain; chain = TREE_CHAIN (chain)) if (TREE_VALUE (chain) == class_name) { @@ -6171,15 +6188,15 @@ start_class (code, class_name, super_name, protocol_list) /* Reset for multiple classes per file. */ method_slot = 0; - implementation_context = class; + objc_implementation_context = class; /* Lookup the interface for this implementation. */ if (!(implementation_template = lookup_interface (class_name))) { - warning ("Cannot find interface declaration for `%s'", + warning ("cannot find interface declaration for `%s'", IDENTIFIER_POINTER (class_name)); - add_class (implementation_template = implementation_context); + add_class (implementation_template = objc_implementation_context); } /* If a super class has been specified in the implementation, @@ -6189,7 +6206,7 @@ start_class (code, class_name, super_name, protocol_list) && (super_name != CLASS_SUPER_NAME (implementation_template))) { tree previous_name = CLASS_SUPER_NAME (implementation_template); - const char *name = + const char *const name = previous_name ? IDENTIFIER_POINTER (previous_name) : ""; error ("conflicting super class name `%s'", IDENTIFIER_POINTER (super_name)); @@ -6198,7 +6215,7 @@ start_class (code, class_name, super_name, protocol_list) else if (! super_name) { - CLASS_SUPER_NAME (implementation_context) + CLASS_SUPER_NAME (objc_implementation_context) = CLASS_SUPER_NAME (implementation_template); } } @@ -6226,7 +6243,7 @@ start_class (code, class_name, super_name, protocol_list) if (!(class_category_is_assoc_with = lookup_interface (class_name))) { - error ("Cannot find interface declaration for `%s'", + error ("cannot find interface declaration for `%s'", IDENTIFIER_POINTER (class_name)); exit (FATAL_EXIT_CODE); } @@ -6254,7 +6271,7 @@ start_class (code, class_name, super_name, protocol_list) /* Reset for multiple classes per file. */ method_slot = 0; - implementation_context = class; + objc_implementation_context = class; /* For a category, class_name is really the name of the class that the following set of methods will be associated with. We must @@ -6262,7 +6279,7 @@ start_class (code, class_name, super_name, protocol_list) if (!(implementation_template = lookup_interface (class_name))) { - error ("Cannot find interface declaration for `%s'", + error ("cannot find interface declaration for `%s'", IDENTIFIER_POINTER (class_name)); exit (FATAL_EXIT_CODE); } @@ -6292,7 +6309,7 @@ continue_class (class) if (!objc_class_template) build_class_template (); - imp_entry = (struct imp_entry *) xmalloc (sizeof (struct imp_entry)); + imp_entry = (struct imp_entry *) ggc_alloc (sizeof (struct imp_entry)); imp_entry->next = imp_list; imp_entry->imp_context = class; @@ -6318,7 +6335,7 @@ continue_class (class) if (!TYPE_FIELDS (record)) { - finish_struct (record, build_ivar_chain (class, 0), NULL_TREE); + finish_struct (record, get_class_ivars (class), NULL_TREE); CLASS_STATIC_TEMPLATE (class) = record; /* Mark this record as a class template for static typing. */ @@ -6342,18 +6359,18 @@ finish_class (class) { /* All code generation is done in finish_objc. */ - if (implementation_template != implementation_context) + if (implementation_template != objc_implementation_context) { /* Ensure that all method listed in the interface contain bodies. */ check_methods (CLASS_CLS_METHODS (implementation_template), - CLASS_CLS_METHODS (implementation_context), '+'); + CLASS_CLS_METHODS (objc_implementation_context), '+'); check_methods (CLASS_NST_METHODS (implementation_template), - CLASS_NST_METHODS (implementation_context), '-'); + CLASS_NST_METHODS (objc_implementation_context), '-'); if (CLASS_PROTOCOL_LIST (implementation_template)) check_protocols (CLASS_PROTOCOL_LIST (implementation_template), "class", - IDENTIFIER_POINTER (CLASS_NAME (implementation_context))); + IDENTIFIER_POINTER (CLASS_NAME (objc_implementation_context))); } } @@ -6373,14 +6390,14 @@ finish_class (class) { /* Ensure all method listed in the interface contain bodies. */ check_methods (CLASS_CLS_METHODS (category), - CLASS_CLS_METHODS (implementation_context), '+'); + CLASS_CLS_METHODS (objc_implementation_context), '+'); check_methods (CLASS_NST_METHODS (category), - CLASS_NST_METHODS (implementation_context), '-'); + CLASS_NST_METHODS (objc_implementation_context), '-'); if (CLASS_PROTOCOL_LIST (category)) check_protocols (CLASS_PROTOCOL_LIST (category), "category", - IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_context))); + IDENTIFIER_POINTER (CLASS_SUPER_NAME (objc_implementation_context))); } } @@ -6418,14 +6435,39 @@ lookup_protocol (ident) tree chain; for (chain = protocol_chain; chain; chain = TREE_CHAIN (chain)) - { - if (ident == PROTOCOL_NAME (chain)) - return chain; - } + if (ident == PROTOCOL_NAME (chain)) + return chain; return NULL_TREE; } +/* This function forward declares the protocols named by NAMES. If + they are already declared or defined, the function has no effect. */ + +void +objc_declare_protocols (names) + tree names; +{ + tree list; + + for (list = names; list; list = TREE_CHAIN (list)) + { + tree name = TREE_VALUE (list); + + if (lookup_protocol (name) == NULL_TREE) + { + tree protocol = make_node (PROTOCOL_INTERFACE_TYPE); + + TYPE_BINFO (protocol) = make_tree_vec (2); + PROTOCOL_NAME (protocol) = name; + PROTOCOL_LIST (protocol) = NULL_TREE; + add_protocol (protocol); + PROTOCOL_DEFINED (protocol) = 0; + PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE; + } + } +} + tree start_protocol (code, name, list) enum tree_code code; @@ -6434,32 +6476,44 @@ start_protocol (code, name, list) { tree protocol; - /* This is as good a place as any. Need to invoke push_tag_toplevel. */ + /* This is as good a place as any. Need to invoke + push_tag_toplevel. */ if (!objc_protocol_template) objc_protocol_template = build_protocol_template (); - protocol = make_node (code); - TYPE_BINFO (protocol) = make_tree_vec (2); - - PROTOCOL_NAME (protocol) = name; - PROTOCOL_LIST (protocol) = list; + protocol = lookup_protocol (name); - lookup_and_install_protocols (list); + if (!protocol) + { + protocol = make_node (code); + TYPE_BINFO (protocol) = make_tree_vec (2); - if (lookup_protocol (name)) - warning ("duplicate declaration for protocol `%s'", - IDENTIFIER_POINTER (name)); - else - add_protocol (protocol); + PROTOCOL_NAME (protocol) = name; + PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list); + add_protocol (protocol); + PROTOCOL_DEFINED (protocol) = 1; + PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE; - PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE; + check_protocol_recursively (protocol, list); + } + else if (! PROTOCOL_DEFINED (protocol)) + { + PROTOCOL_DEFINED (protocol) = 1; + PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list); + check_protocol_recursively (protocol, list); + } + else + { + warning ("duplicate declaration for protocol `%s'", + IDENTIFIER_POINTER (name)); + } return protocol; } void finish_protocol (protocol) - tree protocol ATTRIBUTE_UNUSED; + tree protocol ATTRIBUTE_UNUSED; { } @@ -6591,17 +6645,22 @@ encode_aggregate_within (type, curtype, format, left, right) int left; int right; { + /* The RECORD_TYPE may in fact be a typedef! For purposes + of encoding, we need the real underlying enchilada. */ + if (TYPE_MAIN_VARIANT (type)) + type = TYPE_MAIN_VARIANT (type); + if (obstack_object_size (&util_obstack) > 0 && *(obstack_next_free (&util_obstack) - 1) == '^') { tree name = TYPE_NAME (type); - /* we have a reference; this is a NeXT extension. */ + /* we have a reference; this is a NeXT extension. */ if (obstack_object_size (&util_obstack) - curtype == 1 && format == OBJC_ENCODE_INLINE_DEFS) { - /* Output format of struct for first level only. */ + /* Output format of struct for first level only. */ tree fields = TYPE_FIELDS (type); if (name && TREE_CODE (name) == IDENTIFIER_NODE) @@ -6635,7 +6694,7 @@ encode_aggregate_within (type, curtype, format, left, right) else { - /* We have an untagged structure or a typedef. */ + /* We have an untagged structure or a typedef. */ obstack_1grow (&util_obstack, left); obstack_1grow (&util_obstack, '?'); obstack_1grow (&util_obstack, right); @@ -6691,7 +6750,7 @@ encode_aggregate_within (type, curtype, format, left, right) IDENTIFIER_POINTER (name), strlen (IDENTIFIER_POINTER (name))); else - /* We have an untagged structure or a typedef. */ + /* We have an untagged structure or a typedef. */ obstack_1grow (&util_obstack, '?'); obstack_1grow (&util_obstack, right); @@ -6827,7 +6886,10 @@ encode_type (type, curtype, format) } static void -encode_complete_bitfield (int position, tree type, int size) +encode_complete_bitfield (position, type, size) + int position; + tree type; + int size; { enum tree_code code = TREE_CODE (type); char buffer[40]; @@ -6873,7 +6935,8 @@ encode_complete_bitfield (int position, tree type, int size) charType = 'q'; } } - + else if (code == ENUMERAL_TYPE) + charType = 'i'; else abort (); @@ -6896,14 +6959,14 @@ encode_field_decl (field_decl, curtype, format) the bitfield typing information. */ if (flag_next_runtime) { - if (DECL_BIT_FIELD (field_decl)) + if (DECL_BIT_FIELD_TYPE (field_decl)) encode_bitfield (tree_low_cst (DECL_SIZE (field_decl), 1)); else encode_type (TREE_TYPE (field_decl), curtype, format); } else { - if (DECL_BIT_FIELD (field_decl)) + if (DECL_BIT_FIELD_TYPE (field_decl)) encode_complete_bitfield (int_bit_position (field_decl), DECL_BIT_FIELD_TYPE (field_decl), tree_low_cst (DECL_SIZE (field_decl), 1)); @@ -6935,7 +6998,7 @@ start_method_def (method) tree decl_specs; /* Required to implement _msgSuper. */ - method_context = method; + objc_method_context = method; UOBJC_SUPER_decl = NULL_TREE; /* Must be called BEFORE start_function. */ @@ -6943,7 +7006,7 @@ start_method_def (method) /* Generate prototype declarations for arguments..."new-style". */ - if (TREE_CODE (method_context) == INSTANCE_METHOD_DECL) + if (TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL) decl_specs = build_tree_list (NULL_TREE, uprivate_record); else /* Really a `struct objc_class *'. However, we allow people to @@ -6953,7 +7016,7 @@ start_method_def (method) push_parm_decl (build_tree_list (build_tree_list (decl_specs, build1 (INDIRECT_REF, NULL_TREE, self_id)), - build_tree_list (unused_list, NULL_TREE))); + unused_list)); decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE, @@ -6961,7 +7024,7 @@ start_method_def (method) push_parm_decl (build_tree_list (build_tree_list (decl_specs, build1 (INDIRECT_REF, NULL_TREE, ucmd_id)), - build_tree_list (unused_list, NULL_TREE))); + unused_list)); /* Generate argument declarations if a keyword_decl. */ if (METHOD_SEL_ARGS (method)) @@ -6980,7 +7043,7 @@ start_method_def (method) TREE_OPERAND (last_expr, 0) = KEYWORD_ARG_NAME (arglist); push_parm_decl (build_tree_list (build_tree_list (arg_spec, arg_decl), - build_tree_list (NULL_TREE, NULL_TREE))); + NULL_TREE)); /* Unhook: restore the abstract declarator. */ TREE_OPERAND (last_expr, 0) = NULL_TREE; @@ -6990,7 +7053,7 @@ start_method_def (method) push_parm_decl (build_tree_list (build_tree_list (arg_spec, KEYWORD_ARG_NAME (arglist)), - build_tree_list (NULL_TREE, NULL_TREE))); + NULL_TREE)); arglist = TREE_CHAIN (arglist); } @@ -7019,10 +7082,10 @@ warn_with_method (message, mtype, method) int mtype; tree method; { - if (count_error (1) == 0) + if (!diagnostic_count_diagnostic (global_dc, DK_WARNING)) return; - report_error_function (DECL_SOURCE_FILE (method)); + diagnostic_report_current_function (global_dc); /* Add a readable method name to the warning. */ warning_with_file_and_line (DECL_SOURCE_FILE (method), @@ -7038,22 +7101,17 @@ static int comp_method_with_proto (method, proto) tree method, proto; { - static tree function_type = 0; - - /* Create a function_type node once. */ - if (!function_type) - { - function_type = make_node (FUNCTION_TYPE); - ggc_add_tree_root (&function_type, 1); - } + /* Create a function template node at most once. */ + if (!function1_template) + function1_template = make_node (FUNCTION_TYPE); /* Install argument types - normally set by build_function_type. */ - TYPE_ARG_TYPES (function_type) = get_arg_type_list (proto, METHOD_DEF, 0); + TYPE_ARG_TYPES (function1_template) = get_arg_type_list (proto, METHOD_DEF, 0); /* install return type */ - TREE_TYPE (function_type) = groktypename (TREE_TYPE (proto)); + TREE_TYPE (function1_template) = groktypename (TREE_TYPE (proto)); - return comptypes (TREE_TYPE (METHOD_DEFINITION (method)), function_type); + return comptypes (TREE_TYPE (METHOD_DEFINITION (method)), function1_template); } /* Return 1 if PROTO1 is consistent with PROTO2. */ @@ -7062,25 +7120,21 @@ static int comp_proto_with_proto (proto0, proto1) tree proto0, proto1; { - static tree function_type[2]; - - /* Create a couple function_type node's once. */ - if (!function_type[0]) - { - function_type[0] = make_node (FUNCTION_TYPE); - function_type[1] = make_node (FUNCTION_TYPE); - ggc_add_tree_root (function_type, 2); - } + /* Create a couple of function_template nodes at most once. */ + if (!function1_template) + function1_template = make_node (FUNCTION_TYPE); + if (!function2_template) + function2_template = make_node (FUNCTION_TYPE); /* Install argument types; normally set by build_function_type. */ - TYPE_ARG_TYPES (function_type[0]) = get_arg_type_list (proto0, METHOD_REF, 0); - TYPE_ARG_TYPES (function_type[1]) = get_arg_type_list (proto1, METHOD_REF, 0); + TYPE_ARG_TYPES (function1_template) = get_arg_type_list (proto0, METHOD_REF, 0); + TYPE_ARG_TYPES (function2_template) = get_arg_type_list (proto1, METHOD_REF, 0); /* Install return type. */ - TREE_TYPE (function_type[0]) = groktypename (TREE_TYPE (proto0)); - TREE_TYPE (function_type[1]) = groktypename (TREE_TYPE (proto1)); + TREE_TYPE (function1_template) = groktypename (TREE_TYPE (proto0)); + TREE_TYPE (function2_template) = groktypename (TREE_TYPE (proto1)); - return comptypes (function_type[0], function_type[1]); + return comptypes (function1_template, function2_template); } /* - Generate an identifier for the function. the format is "_n_cls", @@ -7104,11 +7158,11 @@ really_start_method (method, parmlist) decl_specs = chainon (sc_spec, ret_spec); sel_name = IDENTIFIER_POINTER (METHOD_SEL_NAME (method)); - class_name = IDENTIFIER_POINTER (CLASS_NAME (implementation_context)); - cat_name = ((TREE_CODE (implementation_context) + class_name = IDENTIFIER_POINTER (CLASS_NAME (objc_implementation_context)); + cat_name = ((TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE) ? NULL - : IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_context))); + : IDENTIFIER_POINTER (CLASS_SUPER_NAME (objc_implementation_context))); method_slot++; /* Make sure this is big enough for any plausible method label. */ @@ -7133,7 +7187,7 @@ really_start_method (method, parmlist) method_decl = ret_decl; /* Fool the parser into thinking it is starting a function. */ - start_function (decl_specs, method_decl, NULL_TREE, NULL_TREE); + start_function (decl_specs, method_decl, NULL_TREE); /* Unhook: this has the effect of restoring the abstract declarator. */ TREE_OPERAND (save_expr, 0) = NULL_TREE; @@ -7144,7 +7198,7 @@ really_start_method (method, parmlist) TREE_VALUE (TREE_TYPE (method)) = method_decl; /* Fool the parser into thinking it is starting a function. */ - start_function (decl_specs, method_decl, NULL_TREE, NULL_TREE); + start_function (decl_specs, method_decl, NULL_TREE); /* Unhook: this has the effect of restoring the abstract declarator. */ TREE_VALUE (TREE_TYPE (method)) = NULL_TREE; @@ -7154,7 +7208,7 @@ really_start_method (method, parmlist) /* Check consistency...start_function, pushdecl, duplicate_decls. */ - if (implementation_template != implementation_context) + if (implementation_template != objc_implementation_context) { tree proto; @@ -7185,7 +7239,7 @@ continue_method_def () { tree parmlist; - if (METHOD_ADD_ARGS (method_context) == objc_ellipsis_node) + if (METHOD_ADD_ARGS (objc_method_context) == objc_ellipsis_node) /* We have a `, ...' immediately following the selector. */ parmlist = get_parm_info (0); else @@ -7196,7 +7250,7 @@ continue_method_def () self_decl = TREE_PURPOSE (parmlist); poplevel (0, 0, 0); - really_start_method (method_context, parmlist); + really_start_method (objc_method_context, parmlist); store_parm_decls (); } @@ -7210,7 +7264,7 @@ add_objc_decls () UOBJC_SUPER_decl = start_decl (get_identifier (UTAG_SUPER), build_tree_list (NULL_TREE, objc_super_template), - 0, NULL_TREE, NULL_TREE); + 0, NULL_TREE); finish_decl (UOBJC_SUPER_decl, NULL_TREE, NULL_TREE); @@ -7229,7 +7283,7 @@ add_objc_decls () tree get_super_receiver () { - if (method_context) + if (objc_method_context) { tree super_expr, super_expr_list; @@ -7242,13 +7296,13 @@ get_super_receiver () super_expr = build_component_ref (UOBJC_SUPER_decl, get_identifier ("class")); - if (TREE_CODE (implementation_context) == CLASS_IMPLEMENTATION_TYPE) + if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE) { /* [_cls, __cls]Super are "pre-built" in synth_forward_declarations. */ super_expr = build_modify_expr (super_expr, NOP_EXPR, - ((TREE_CODE (method_context) + ((TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL) ? ucls_super_ref : uucls_super_ref)); @@ -7260,7 +7314,7 @@ get_super_receiver () tree super_name = CLASS_SUPER_NAME (implementation_template); tree super_class; - /* Barf if super used in a category of Object. */ + /* Barf if super used in a category of Object. */ if (!super_name) { error ("no super class declared in interface for `%s'", @@ -7271,15 +7325,19 @@ get_super_receiver () if (flag_next_runtime) { super_class = get_class_reference (super_name); - if (TREE_CODE (method_context) == CLASS_METHOD_DECL) + if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL) + /* Cast the super class to 'id', since the user may not have + included , leaving 'struct objc_class' + an incomplete type. */ super_class - = build_component_ref (build_indirect_ref (super_class, "->"), - get_identifier ("isa")); + = build_component_ref (build_indirect_ref + (build_c_cast (id_type, super_class), "->"), + get_identifier ("isa")); } else { add_class_reference (super_name); - super_class = (TREE_CODE (method_context) == INSTANCE_METHOD_DECL + super_class = (TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL ? objc_get_class_decl : objc_get_meta_class_decl); assemble_external (super_class); super_class @@ -7369,19 +7427,19 @@ encode_method_def (func_decl) static void objc_expand_function_end () { - METHOD_ENCODING (method_context) = encode_method_def (current_function_decl); + METHOD_ENCODING (objc_method_context) = encode_method_def (current_function_decl); } void finish_method_def () { lang_expand_function_end = objc_expand_function_end; - finish_function (0); + finish_function (0, 1); lang_expand_function_end = NULL; /* Required to implement _msgSuper. This must be done AFTER finish_function, since the optimizer may find "may be used before set" errors. */ - method_context = NULL_TREE; + objc_method_context = NULL_TREE; } #if 0 @@ -7389,10 +7447,10 @@ int lang_report_error_function (decl) tree decl; { - if (method_context) + if (objc_method_context) { fprintf (stderr, "In method `%s'\n", - IDENTIFIER_POINTER (METHOD_SEL_NAME (method_context))); + IDENTIFIER_POINTER (METHOD_SEL_NAME (objc_method_context))); return 1; } @@ -7939,7 +7997,7 @@ gen_declaration_1 (atype_or_adecl, buf) || TREE_CODE (atype_or_adecl) == PARM_DECL || TREE_CODE (atype_or_adecl) == FUNCTION_DECL) { - const char *decl_name = + const char *const decl_name = (DECL_NAME (atype_or_adecl) ? IDENTIFIER_POINTER (DECL_NAME (atype_or_adecl)) : ""); @@ -8032,12 +8090,21 @@ gen_method_decl (method, buf) /* Debug info. */ + +/* Dump an @interface declaration of the supplied class CHAIN to the + supplied file FP. Used to implement the -gen-decls option (which + prints out an @interface declaration of all classes compiled in + this run); potentially useful for debugging the compiler too. */ static void dump_interface (fp, chain) FILE *fp; tree chain; { - char *buf = (char *)xmalloc (256); + /* FIXME: A heap overflow here whenever a method (or ivar) + declaration is so long that it doesn't fit in the buffer. The + code and all the related functions should be rewritten to avoid + using fixed size buffers. */ + char *buf = (char *) xmalloc (1024 * 10); const char *my_name = IDENTIFIER_POINTER (CLASS_NAME (chain)); tree ivar_decls = CLASS_RAW_IVARS (chain); tree nst_methods = CLASS_NST_METHODS (chain); @@ -8045,14 +8112,26 @@ dump_interface (fp, chain) fprintf (fp, "\n@interface %s", my_name); + /* CLASS_SUPER_NAME is used to store the superclass name for + classes, and the category name for categories. */ if (CLASS_SUPER_NAME (chain)) { - const char *super_name = IDENTIFIER_POINTER (CLASS_SUPER_NAME (chain)); - fprintf (fp, " : %s\n", super_name); + const char *name = IDENTIFIER_POINTER (CLASS_SUPER_NAME (chain)); + + if (TREE_CODE (chain) == CATEGORY_IMPLEMENTATION_TYPE + || TREE_CODE (chain) == CATEGORY_INTERFACE_TYPE) + { + fprintf (fp, " (%s)\n", name); + } + else + { + fprintf (fp, " : %s\n", name); + } } else fprintf (fp, "\n"); + /* FIXME - the following doesn't seem to work at the moment. */ if (ivar_decls) { fprintf (fp, "{\n"); @@ -8076,7 +8155,8 @@ dump_interface (fp, chain) fprintf (fp, "+ %s;\n", gen_method_decl (cls_methods, buf)); cls_methods = TREE_CHAIN (cls_methods); } - fprintf (fp, "\n@end"); + + fprintf (fp, "@end\n"); } /* Demangle function for Objective-C */ @@ -8136,7 +8216,7 @@ objc_demangle (mangled) return mangled; /* not an objc mangled name */ } -static const char * +const char * objc_printable_name (decl, kind) tree decl; int kind ATTRIBUTE_UNUSED; @@ -8147,34 +8227,12 @@ objc_printable_name (decl, kind) static void init_objc () { - /* Add the special tree codes of Objective C to the tables. */ - -#define LAST_CODE LAST_C_TREE_CODE - gcc_obstack_init (&util_obstack); util_firstobj = (char *) obstack_finish (&util_obstack); - memcpy (tree_code_type + (int) LAST_CODE, - objc_tree_code_type, - (int) LAST_OBJC_TREE_CODE - (int) LAST_CODE); - memcpy (tree_code_length + (int) LAST_CODE, - objc_tree_code_length, - (((int) LAST_OBJC_TREE_CODE - (int) LAST_CODE) * sizeof (int))); - memcpy (tree_code_name + (int) LAST_CODE, - objc_tree_code_name, - (((int) LAST_OBJC_TREE_CODE - (int) LAST_CODE) * sizeof (char *))); - - errbuf = (char *)xmalloc (BUFSIZE); + errbuf = (char *) xmalloc (BUFSIZE); hash_init (); synth_module_prologue (); - - /* Change the default error function */ - save_lang_status = &push_c_function_context; - restore_lang_status = &pop_c_function_context; - mark_lang_status = &mark_c_function_context; - decl_printable_name = objc_printable_name; - lang_expand_expr = c_expand_expr; - lang_expand_decl_stmt = c_expand_decl_stmt; } static void @@ -8191,7 +8249,7 @@ finish_objc () if (objc_implementation_context) { warning ("`@end' missing in implementation context"); - finish_class (implementation_context); + finish_class (objc_implementation_context); objc_ivar_chain = NULL_TREE; objc_implementation_context = NULL_TREE; } @@ -8203,23 +8261,32 @@ finish_objc () #endif /* Process the static instances here because initialization of objc_symtab - depends on them. */ + depends on them. */ if (objc_static_instances) generate_static_references (); - if (implementation_context || class_names_chain + if (imp_list || class_names_chain || meth_var_names_chain || meth_var_types_chain || sel_ref_chain) generate_objc_symtab_decl (); for (impent = imp_list; impent; impent = impent->next) { - implementation_context = impent->imp_context; + objc_implementation_context = impent->imp_context; implementation_template = impent->imp_template; UOBJC_CLASS_decl = impent->class_decl; UOBJC_METACLASS_decl = impent->meta_decl; - - if (TREE_CODE (implementation_context) == CLASS_IMPLEMENTATION_TYPE) + + /* Dump the @interface of each class as we compile it, if the + -gen-decls option is in use. TODO: Dump the classes in the + order they were found, rather than in reverse order as we + are doing now. */ + if (flag_gen_declaration) + { + dump_interface (gen_declaration_file, objc_implementation_context); + } + + if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE) { /* all of the following reference the string pool... */ generate_ivar_lists (); @@ -8229,7 +8296,7 @@ finish_objc () else { generate_dispatch_tables (); - generate_category (implementation_context); + generate_category (objc_implementation_context); } } @@ -8241,13 +8308,13 @@ finish_objc () if (protocol_chain) generate_protocols (); - if (implementation_context || class_names_chain || objc_static_instances + if (objc_implementation_context || class_names_chain || objc_static_instances || meth_var_names_chain || meth_var_types_chain || sel_ref_chain) { - /* Arrange for Objc data structures to be initialized at run time. */ - const char *init_name = build_module_descriptor (); - if (init_name) - assemble_constructor (init_name); + /* Arrange for ObjC data structures to be initialized at run time. */ + rtx init_sym = build_module_descriptor (); + if (init_sym && targetm.have_ctors_dtors) + (* targetm.asm_out.constructor) (init_sym, DEFAULT_INIT_PRIORITY); } /* Dump the class references. This forces the appropriate classes @@ -8269,12 +8336,6 @@ finish_objc () generate_strings (); - if (flag_gen_declaration) - { - add_class (implementation_context); - dump_interface (gen_declaration_file, implementation_context); - } - if (warn_selector) { int slot; @@ -8323,7 +8384,7 @@ finish_objc () static void generate_classref_translation_entry (chain) - tree chain; + tree chain; { tree expr, name, decl_specs, decl, sc_spec; tree type; @@ -8342,7 +8403,7 @@ generate_classref_translation_entry (chain) /* The decl that is returned from start_decl is the one that we forward declared in build_class_reference. */ - decl = start_decl (name, decl_specs, 1, NULL_TREE, NULL_TREE); + decl = start_decl (name, decl_specs, 1, NULL_TREE); DECL_CONTEXT (decl) = NULL_TREE; finish_decl (decl, expr, NULL_TREE); return; @@ -8383,6 +8444,7 @@ handle_class_ref (chain) decl = build_decl (VAR_DECL, get_identifier (string), string_type_node); DECL_INITIAL (decl) = exp; TREE_STATIC (decl) = 1; + TREE_USED (decl) = 1; pushdecl (decl); rest_of_decl_compilation (decl, 0, 0, 0); @@ -8394,24 +8456,24 @@ handle_impent (impent) { char *string; - implementation_context = impent->imp_context; + objc_implementation_context = impent->imp_context; implementation_template = impent->imp_template; if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE) { - const char *class_name = + const char *const class_name = IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context)); string = (char *) alloca (strlen (class_name) + 30); - sprintf (string, "*%sobjc_class_name_%s", + sprintf (string, "%sobjc_class_name_%s", (flag_next_runtime ? "." : "__"), class_name); } else if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE) { - const char *class_name = + const char *const class_name = IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context)); - const char *class_super_name = + const char *const class_super_name = IDENTIFIER_POINTER (CLASS_SUPER_NAME (impent->imp_context)); string = (char *) alloca (strlen (class_name) @@ -8419,7 +8481,7 @@ handle_impent (impent) /* Do the same for categories. Even though no references to these symbols are generated automatically by the compiler, it - gives you a handle to pull them into an archive by hand. */ + gives you a handle to pull them into an archive by hand. */ sprintf (string, "*%sobjc_category_name_%s_%s", (flag_next_runtime ? "." : "__"), class_name, class_super_name); } @@ -8432,67 +8494,25 @@ handle_impent (impent) ASM_DECLARE_CLASS_REFERENCE (asm_out_file, string); return; } + else #endif - - /* (Should this be a routine in varasm.c?) */ - readonly_data_section (); - assemble_global (string); - assemble_align (UNITS_PER_WORD); - assemble_label (string); - assemble_zeros (UNITS_PER_WORD); -} - -void -print_lang_statistics () -{ -} - -static void -ggc_mark_imp_list (arg) - void *arg; -{ - struct imp_entry *impent; - - for (impent = *(struct imp_entry **)arg; impent; impent = impent->next) { - ggc_mark_tree (impent->imp_context); - ggc_mark_tree (impent->imp_template); - ggc_mark_tree (impent->class_decl); - ggc_mark_tree (impent->meta_decl); - } -} - -static void -ggc_mark_hash_table (arg) - void *arg; -{ - hash *hash_table = *(hash **)arg; - hash hst; - attr list; - int i; + tree decl, init; - if (hash_table == NULL) - return; - for (i = 0; i < SIZEHASHTABLE; i++) - for (hst = hash_table [i]; hst; hst = hst->next) - { - ggc_mark_tree (hst->key); - for (list = hst->list; list; list = list->next) - ggc_mark_tree (list->value); - } -} - -/* Add GC roots for variables local to this file. */ -static void -objc_act_parse_init () -{ - ggc_add_tree_root (&objc_ellipsis_node, 1); - ggc_add_tree_root (objc_global_trees, OCTI_MAX); - ggc_add_root (&imp_list, 1, sizeof imp_list, ggc_mark_imp_list); - ggc_add_root (&nst_method_hash_list, 1, sizeof nst_method_hash_list, ggc_mark_hash_table); - ggc_add_root (&cls_method_hash_list, 1, sizeof cls_method_hash_list, ggc_mark_hash_table); + init = build_int_2 (0, 0); + TREE_TYPE (init) = c_common_type_for_size (BITS_PER_WORD, 1); + decl = build_decl (VAR_DECL, get_identifier (string), TREE_TYPE (init)); + TREE_PUBLIC (decl) = 1; + TREE_READONLY (decl) = 1; + TREE_USED (decl) = 1; + TREE_CONSTANT (decl) = 1; + DECL_CONTEXT (decl) = 0; + DECL_ARTIFICIAL (decl) = 1; + DECL_INITIAL (decl) = init; + assemble_variable (decl, 1, 0, 0); + } } - + /* Look up ID as an instance variable. */ tree lookup_objc_ivar (id) @@ -8500,8 +8520,8 @@ lookup_objc_ivar (id) { tree decl; - if (objc_receiver_context && !strcmp (IDENTIFIER_POINTER (id), "super")) - /* we have a message to super */ + if (objc_method_context && !strcmp (IDENTIFIER_POINTER (id), "super")) + /* We have a message to super. */ return get_super_receiver (); else if (objc_method_context && (decl = is_ivar (objc_ivar_chain, id))) { @@ -8513,3 +8533,5 @@ lookup_objc_ivar (id) else return 0; } + +#include "gtype-objc.h"