X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fobjc%2Fobjc-act.c;h=8c65f08257b6180c6a57f4f7fc700eec1c86f171;hb=78a8ed037318d1db259d761729af92e1f4697a0b;hp=5cb7c1db6f292d2b3115489b0917d3e102f3f65d;hpb=b8e0d3c33e851d55cd940e423040c35630c9fbba;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 5cb7c1db6f2..8c65f08257b 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -45,10 +45,12 @@ Boston, MA 02111-1307, USA. */ #include "tm.h" #include "tree.h" #include "rtl.h" +#include "tm_p.h" #include "expr.h" #include "c-tree.h" #include "c-common.h" #include "flags.h" +#include "langhooks.h" #include "objc-act.h" #include "input.h" #include "except.h" @@ -89,19 +91,16 @@ Boston, MA 02111-1307, USA. */ #define OBJC_FORWARDING_MIN_OFFSET 0 #endif - /* Set up for use of obstacks. */ #include "obstack.h" /* 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, - so we can free the whole contents. */ -char *util_firstobj; -/* for encode_method_def */ -#include "rtl.h" +/* This points to the beginning of obstack contents, so we can free + the whole contents. */ +char *util_firstobj; /* The version identifies which language generation and runtime the module (file) was compiled for, and is recorded in the @@ -118,69 +117,75 @@ char *util_firstobj; /* Used by compile_file. */ -static void init_objc PARAMS ((void)); -static void finish_objc PARAMS ((void)); +static void init_objc (void); +static void finish_objc (void); /* Code generation. */ -static void synth_module_prologue PARAMS ((void)); -static tree objc_build_constructor PARAMS ((tree, tree)); -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 objc_add_static_instance PARAMS ((tree, tree)); - -static tree build_ivar_template PARAMS ((void)); -static tree build_method_template PARAMS ((void)); -static tree build_private_template PARAMS ((tree)); -static void build_class_template PARAMS ((void)); -static void build_selector_template PARAMS ((void)); -static void build_category_template PARAMS ((void)); -static tree build_super_template PARAMS ((void)); -static tree build_category_initializer PARAMS ((tree, tree, tree, - tree, tree, tree)); -static tree build_protocol_initializer PARAMS ((tree, tree, tree, - tree, tree)); - -static void synth_forward_declarations PARAMS ((void)); -static void generate_ivar_lists PARAMS ((void)); -static void generate_dispatch_tables PARAMS ((void)); -static void generate_shared_structures PARAMS ((void)); -static tree generate_protocol_list PARAMS ((tree)); -static void generate_forward_declaration_to_string_table PARAMS ((void)); -static void build_protocol_reference PARAMS ((tree)); - -static tree build_keyword_selector PARAMS ((tree)); -static tree synth_id_with_class_suffix PARAMS ((const char *, tree)); - -static void generate_static_references PARAMS ((void)); -static int check_methods_accessible PARAMS ((tree, tree, - int)); -static void encode_aggregate_within PARAMS ((tree, int, int, - int, int)); -static const char *objc_demangle PARAMS ((const char *)); -static void objc_expand_function_end PARAMS ((void)); +static void synth_module_prologue (void); +static tree objc_build_constructor (tree, tree); +static rtx build_module_descriptor (void); +static tree init_module_descriptor (tree); +static tree build_objc_method_call (int, tree, tree, tree, tree); +static void generate_strings (void); +static tree get_proto_encoding (tree); +static void build_selector_translation_table (void); + +static tree objc_add_static_instance (tree, tree); + +static void build_objc_exception_stuff (void); +static tree objc_declare_variable (enum rid, tree, tree, tree); +static tree objc_enter_block (void); +static tree objc_exit_block (void); +static void objc_build_try_enter_fragment (void); +static void objc_build_try_exit_fragment (void); +static void objc_build_extract_fragment (void); +static tree objc_build_extract_expr (void); + +static tree build_ivar_template (void); +static tree build_method_template (void); +static tree build_private_template (tree); +static void build_class_template (void); +static void build_selector_template (void); +static void build_category_template (void); +static tree lookup_method_in_hash_lists (tree, int); +static void build_super_template (void); +static tree build_category_initializer (tree, tree, tree, tree, tree, tree); +static tree build_protocol_initializer (tree, tree, tree, tree, tree); +static void synth_forward_declarations (void); +static int ivar_list_length (tree); +static tree get_class_ivars (tree, int); +static void generate_ivar_lists (void); +static void generate_dispatch_tables (void); +static void generate_shared_structures (void); +static tree generate_protocol_list (tree); +static void build_protocol_reference (tree); + +static tree build_keyword_selector (tree); +static tree synth_id_with_class_suffix (const char *, tree); + +static void generate_static_references (void); +static int check_methods_accessible (tree, tree, int); +static void encode_aggregate_within (tree, int, int, int, int); +static const char *objc_demangle (const char *); +static void objc_expand_function_end (void); /* Hash tables to manage the global pool of method prototypes. */ 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)); -static void hash_add_attr PARAMS ((hash, tree)); -static tree lookup_method PARAMS ((tree, tree)); -static tree lookup_instance_method_static PARAMS ((tree, tree)); -static tree lookup_class_method_static PARAMS ((tree, tree)); -static tree add_class PARAMS ((tree)); -static void add_category PARAMS ((tree, tree)); +static size_t hash_func (tree); +static void hash_init (void); +static void hash_enter (hash *, tree); +static hash hash_lookup (hash *, tree); +static void hash_add_attr (hash, tree); +static tree lookup_method (tree, tree); +static tree lookup_method_static (tree, tree, int); +static void add_method_to_hash_list (hash *, tree); +static tree add_class (tree); +static void add_category (tree, tree); +static inline tree lookup_category (tree, tree); enum string_section { @@ -189,113 +194,105 @@ enum string_section meth_var_types /* method and variable type descriptors */ }; -static tree add_objc_string PARAMS ((tree, - enum string_section)); -static tree get_objc_string_decl PARAMS ((tree, - enum string_section)); -static tree build_objc_string_decl PARAMS ((enum string_section)); -static tree build_selector_reference_decl PARAMS ((void)); +static tree add_objc_string (tree, enum string_section); +static tree get_objc_string_decl (tree, enum string_section); +static tree build_objc_string_decl (enum string_section); +static tree build_selector_reference_decl (void); /* Protocol additions. */ -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)); +static tree add_protocol (tree); +static tree lookup_protocol (tree); +static void check_protocol_recursively (tree, tree); +static tree lookup_and_install_protocols (tree); /* Type encoding. */ -static void encode_type_qualifiers PARAMS ((tree)); -static void encode_pointer PARAMS ((tree, int, int)); -static void encode_array PARAMS ((tree, int, int)); -static void encode_aggregate PARAMS ((tree, int, int)); -static void encode_bitfield PARAMS ((int)); -static void encode_type PARAMS ((tree, int, int)); -static void encode_field_decl PARAMS ((tree, int, int)); - -static void really_start_method PARAMS ((tree, tree)); -static int comp_method_with_proto PARAMS ((tree, tree)); -static int comp_proto_with_proto PARAMS ((tree, tree)); -static tree get_arg_type_list PARAMS ((tree, int, int)); -static tree expr_last PARAMS ((tree)); +static void encode_type_qualifiers (tree); +static void encode_pointer (tree, int, int); +static void encode_array (tree, int, int); +static void encode_aggregate (tree, int, int); +static void encode_next_bitfield (int); +static void encode_gnu_bitfield (int, tree, int); +static void encode_type (tree, int, int); +static void encode_field_decl (tree, int, int); + +static void really_start_method (tree, tree); +static int comp_method_with_proto (tree, tree); +static int objc_types_are_equivalent (tree, tree); +static int comp_proto_with_proto (tree, tree); +static tree get_arg_type_list (tree, int, int); +static tree objc_expr_last (tree); +static void synth_self_and_ucmd_args (void); /* Utilities for debugging and error diagnostics. */ -static void warn_with_method PARAMS ((const char *, int, tree)); -static void error_with_ivar PARAMS ((const char *, tree, tree)); -static char *gen_method_decl PARAMS ((tree, char *)); -static char *gen_declaration PARAMS ((tree, char *)); -static void gen_declaration_1 PARAMS ((tree, char *)); -static char *gen_declarator PARAMS ((tree, char *, - const char *)); -static int is_complex_decl PARAMS ((tree)); -static void adorn_decl PARAMS ((tree, char *)); -static void dump_interface PARAMS ((FILE *, tree)); +static void warn_with_method (const char *, int, tree); +static void error_with_ivar (const char *, tree, tree); +static char *gen_method_decl (tree, char *); +static char *gen_declaration (tree, char *); +static void gen_declaration_1 (tree, char *); +static char *gen_declarator (tree, char *, const char *); +static int is_complex_decl (tree); +static void adorn_decl (tree, char *); +static void dump_interface (FILE *, tree); /* Everything else. */ -static tree define_decl PARAMS ((tree, tree)); -static tree lookup_method_in_protocol_list PARAMS ((tree, tree, int)); -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)); -static tree init_objc_symtab PARAMS ((tree)); -static void forward_declare_categories PARAMS ((void)); -static void generate_objc_symtab_decl PARAMS ((void)); -static tree build_selector PARAMS ((tree)); -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 build_protocol_template PARAMS ((void)); -static tree build_descriptor_table_initializer PARAMS ((tree, tree)); -static tree build_method_prototype_list_template PARAMS ((tree, int)); -static tree build_method_prototype_template PARAMS ((void)); -static int forwarding_offset PARAMS ((tree)); -static tree encode_method_prototype PARAMS ((tree, tree)); -static tree generate_descriptor_table PARAMS ((tree, const char *, - int, tree, tree)); -static void generate_method_descriptors PARAMS ((tree)); -static tree build_tmp_function_decl PARAMS ((void)); -static void hack_method_prototype PARAMS ((tree, tree)); -static void generate_protocol_references PARAMS ((tree)); -static void generate_protocols PARAMS ((void)); -static void check_ivars PARAMS ((tree, tree)); -static tree build_ivar_list_template PARAMS ((tree, int)); -static tree build_method_list_template PARAMS ((tree, int)); -static tree build_ivar_list_initializer PARAMS ((tree, tree)); -static tree generate_ivars_list PARAMS ((tree, const char *, - int, tree)); -static tree build_dispatch_table_initializer PARAMS ((tree, tree)); -static tree generate_dispatch_table PARAMS ((tree, const char *, - int, tree)); -static tree build_shared_structure_initializer PARAMS ((tree, tree, tree, tree, - tree, int, tree, tree, - tree)); -static void generate_category PARAMS ((tree)); -static int is_objc_type_qualifier PARAMS ((tree)); -static tree adjust_type_for_id_default PARAMS ((tree)); -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)); -static void gen_declspecs PARAMS ((tree, char *, int)); -static void generate_classref_translation_entry PARAMS ((tree)); -static void handle_class_ref PARAMS ((tree)); -static void generate_struct_by_value_array PARAMS ((void)) +static tree define_decl (tree, tree); +static tree lookup_method_in_protocol_list (tree, tree, int); +static tree lookup_protocol_in_reflist (tree, tree); +static tree create_builtin_decl (enum tree_code, tree, const char *); +static void setup_string_decl (void); +static int check_string_class_template (void); +static tree my_build_string (int, const char *); +static void build_objc_symtab_template (void); +static tree init_def_list (tree); +static tree init_objc_symtab (tree); +static tree build_metadata_decl (const char *, tree); +static void forward_declare_categories (void); +static void generate_objc_symtab_decl (void); +static tree build_selector (tree); +static tree build_typed_selector_reference (tree, tree); +static tree build_selector_reference (tree); +static tree build_class_reference_decl (void); +static void add_class_reference (tree); +static tree build_protocol_template (void); +static tree build_descriptor_table_initializer (tree, tree); +static tree build_method_prototype_list_template (tree, int); +static tree build_method_prototype_template (void); +static tree objc_method_parm_type (tree); +static int objc_encoded_type_size (tree); +static tree encode_method_prototype (tree); +static tree generate_descriptor_table (tree, const char *, int, tree, tree); +static void generate_method_descriptors (tree); +static void generate_protocol_references (tree); +static void generate_protocols (void); +static void check_ivars (tree, tree); +static tree build_ivar_list_template (tree, int); +static tree build_method_list_template (tree, int); +static tree build_ivar_list_initializer (tree, tree); +static tree generate_ivars_list (tree, const char *, int, tree); +static tree build_dispatch_table_initializer (tree, tree); +static tree generate_dispatch_table (tree, const char *, int, tree); +static tree build_shared_structure_initializer (tree, tree, tree, tree, + tree, int, tree, tree, tree); +static void generate_category (tree); +static int is_objc_type_qualifier (tree); +static tree adjust_type_for_id_default (tree); +static tree check_duplicates (hash, int, int); +static tree receiver_is_class_object (tree, int, int); +static int check_methods (tree, tree, int); +static int conforms_to_protocol (tree, tree); +static void check_protocol (tree, const char *, const char *); +static void check_protocols (tree, const char *, const char *); +static void gen_declspecs (tree, char *, int); +static void generate_classref_translation_entry (tree); +static void handle_class_ref (tree); +static void generate_struct_by_value_array (void) ATTRIBUTE_NORETURN; -static void encode_complete_bitfield PARAMS ((int, tree, int)); -static void mark_referenced_methods PARAMS ((void)); +static void mark_referenced_methods (void); +static void generate_objc_image_info (void); /*** Private Interface (data) ***/ @@ -324,7 +321,7 @@ static void mark_referenced_methods PARAMS ((void)); /* Note that the string object global name is only needed for the NeXT runtime. */ -#define STRING_OBJECT_GLOBAL_NAME "_NSConstantStringClassReference" +#define STRING_OBJECT_GLOBAL_FORMAT "_%sClassReference" #define PROTOCOL_OBJECT_CLASS_NAME "Protocol" @@ -332,19 +329,71 @@ static const char *TAG_GETCLASS; static const char *TAG_GETMETACLASS; static const char *TAG_MSGSEND; static const char *TAG_MSGSENDSUPER; +/* The NeXT Objective-C messenger may have two extra entry points, for use + when returning a structure. */ +static const char *TAG_MSGSEND_STRET; +static const char *TAG_MSGSENDSUPER_STRET; static const char *TAG_EXECCLASS; static const char *default_constant_string_class_name; +/* Runtime metadata flags. */ +#define CLS_FACTORY 0x0001L +#define CLS_META 0x0002L + +#define OBJC_MODIFIER_STATIC 0x00000001 +#define OBJC_MODIFIER_FINAL 0x00000002 +#define OBJC_MODIFIER_PUBLIC 0x00000004 +#define OBJC_MODIFIER_PRIVATE 0x00000008 +#define OBJC_MODIFIER_PROTECTED 0x00000010 +#define OBJC_MODIFIER_NATIVE 0x00000020 +#define OBJC_MODIFIER_SYNCHRONIZED 0x00000040 +#define OBJC_MODIFIER_ABSTRACT 0x00000080 +#define OBJC_MODIFIER_VOLATILE 0x00000100 +#define OBJC_MODIFIER_TRANSIENT 0x00000200 +#define OBJC_MODIFIER_NONE_SPECIFIED 0x80000000 + +#define TAG_MSGSEND_NONNIL "objc_msgSendNonNil" +#define TAG_MSGSEND_NONNIL_STRET "objc_msgSendNonNil_stret" +#define TAG_EXCEPTIONEXTRACT "objc_exception_extract" +#define TAG_EXCEPTIONTRYENTER "objc_exception_try_enter" +#define TAG_EXCEPTIONTRYEXIT "objc_exception_try_exit" +#define TAG_EXCEPTIONMATCH "objc_exception_match" +#define TAG_EXCEPTIONTHROW "objc_exception_throw" +#define TAG_SYNCENTER "objc_sync_enter" +#define TAG_SYNCEXIT "objc_sync_exit" +#define TAG_SETJMP "_setjmp" +#define TAG_RETURN_STRUCT "objc_return_struct" + +#define UTAG_EXCDATA "_objc_exception_data" +#define UTAG_EXCDATA_VAR "_stackExceptionData" +#define UTAG_CAUGHTEXC_VAR "_caughtException" +#define UTAG_RETHROWEXC_VAR "_rethrowException" +#define UTAG_EVALONCE_VAR "_eval_once" + +struct val_stack { + long val; + struct val_stack *next; +}; +static struct val_stack *catch_count_stack, *exc_binding_stack; + +/* useful for debugging */ +static int if_nesting_count; +static int blk_nesting_count; + +static void val_stack_push (struct val_stack **, long); +static void val_stack_pop (struct val_stack **); + /* 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 void handle_impent (struct imp_entry *); 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, */ +/* Use to generate method labels. */ +static int method_slot = 0; #define BUFSIZE 1024 @@ -374,7 +423,7 @@ static int generating_instance_variables = 0; the transition point between the two possibilities. */ static void -generate_struct_by_value_array () +generate_struct_by_value_array (void) { tree type; tree field_decl, field_decl_chain; @@ -405,12 +454,12 @@ generate_struct_by_value_array () chainon (field_decl_chain, field_decl); } finish_struct (type, field_decl_chain, NULL_TREE); - - aggregate_in_mem[i] = aggregate_value_p (type); + + aggregate_in_mem[i] = aggregate_value_p (type, 0); if (!aggregate_in_mem[i]) found = 1; } - + /* We found some structures that are returned in registers instead of memory so output the necessary data. */ if (found) @@ -419,21 +468,21 @@ generate_struct_by_value_array () if (!aggregate_in_mem[i]) break; printf ("#define OBJC_MAX_STRUCT_BY_VALUE %d\n\n", i); - + /* The first member of the structure is always 0 because we don't handle structures with 0 members */ printf ("static int struct_forward_array[] = {\n 0"); - + for (j = 1; j <= i; j++) printf (", %d", aggregate_in_mem[j]); printf ("\n};\n"); } - + exit (0); } bool -objc_init () +objc_init (void) { if (c_objc_common_init () == false) return false; @@ -449,7 +498,7 @@ objc_init () register char * const dumpname = concat (dump_base_name, ".decl", NULL); gen_declaration_file = fopen (dumpname, "w"); if (gen_declaration_file == 0) - fatal_io_error ("can't open %s", dumpname); + fatal_error ("can't open %s: %m", dumpname); free (dumpname); } @@ -459,6 +508,8 @@ objc_init () TAG_GETMETACLASS = "objc_getMetaClass"; TAG_MSGSEND = "objc_msgSend"; TAG_MSGSENDSUPER = "objc_msgSendSuper"; + TAG_MSGSEND_STRET = "objc_msgSend_stret"; + TAG_MSGSENDSUPER_STRET = "objc_msgSendSuper_stret"; TAG_EXECCLASS = "__objc_execClass"; default_constant_string_class_name = "NSConstantString"; } @@ -468,6 +519,8 @@ objc_init () TAG_GETMETACLASS = "objc_get_meta_class"; TAG_MSGSEND = "objc_msg_lookup"; TAG_MSGSENDSUPER = "objc_msg_lookup_super"; + /* GNU runtime does not provide special functions to support + structure-returning methods. */ TAG_EXECCLASS = "__objc_exec_class"; default_constant_string_class_name = "NXConstantString"; flag_typed_selectors = 1; @@ -484,7 +537,7 @@ objc_init () } void -finish_file () +finish_file (void) { mark_referenced_methods (); c_objc_common_finish_file (); @@ -499,32 +552,16 @@ finish_file () } static tree -define_decl (declarator, declspecs) - tree declarator; - tree declspecs; +define_decl (tree declarator, tree declspecs) { tree decl = start_decl (declarator, declspecs, 0, NULL_TREE); finish_decl (decl, NULL_TREE, NULL_TREE); return decl; } -/* 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. - - For statically typed objects, an assignment of the form `a' = `b' - is permitted if: - - `a' is of type "id", - `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. */ - static tree -lookup_method_in_protocol_list (rproto_list, sel_name, class_meth) - tree rproto_list; - tree sel_name; - int class_meth; +lookup_method_in_protocol_list (tree rproto_list, tree sel_name, + int class_meth) { tree rproto, p; tree fnd = 0; @@ -556,9 +593,7 @@ 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; +lookup_protocol_in_reflist (tree rproto_list, tree lproto) { tree rproto, p; @@ -611,10 +646,7 @@ lookup_protocol_in_reflist (rproto_list, lproto) */ int -objc_comptypes (lhs, rhs, reflexive) - tree lhs; - tree rhs; - int reflexive; +objc_comptypes (tree lhs, tree rhs, int reflexive) { /* New clause for protocols. */ @@ -638,20 +670,20 @@ objc_comptypes (lhs, rhs, reflexive) if (rhs_is_proto) { rproto_list = TYPE_PROTOCOL_LIST (rhs); - + if (!reflexive) { /* 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; + for (lproto = lproto_list; lproto; lproto = TREE_CHAIN (lproto)) { p = TREE_VALUE (lproto); rproto = lookup_protocol_in_reflist (rproto_list, p); if (!rproto) - warning + warning ("object does not conform to the `%s' protocol", IDENTIFIER_POINTER (PROTOCOL_NAME (p))); } @@ -663,20 +695,20 @@ objc_comptypes (lhs, rhs, reflexive) 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; + 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; + for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto)) { p = TREE_VALUE (rproto); @@ -698,7 +730,7 @@ objc_comptypes (lhs, rhs, reflexive) /* = * */ else if (TYPED_OBJECT (TREE_TYPE (rhs))) { - tree rname = TYPE_NAME (TREE_TYPE (rhs)); + tree rname = OBJC_TYPE_NAME (TREE_TYPE (rhs)); tree rinter; /* Make sure the protocol is supported by the object on @@ -739,18 +771,18 @@ 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 (OBJC_TYPE_NAME (TREE_TYPE (rhs))), IDENTIFIER_POINTER (PROTOCOL_NAME (p))); } return 1; } /* = id */ - else if (TYPE_NAME (TREE_TYPE (rhs)) == objc_object_id) + else if (OBJC_TYPE_NAME (TREE_TYPE (rhs)) == objc_object_id) { return 1; } /* = Class */ - else if (TYPE_NAME (TREE_TYPE (rhs)) == objc_class_id) + else if (OBJC_TYPE_NAME (TREE_TYPE (rhs)) == objc_class_id) { return 0; } @@ -764,13 +796,13 @@ objc_comptypes (lhs, rhs, reflexive) { if (reflexive) { - tree rname = TYPE_NAME (TREE_TYPE (lhs)); + tree rname = OBJC_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; + for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto)) { tree p = TREE_VALUE (rproto); @@ -790,9 +822,9 @@ objc_comptypes (lhs, rhs, reflexive) lhs. */ if (!lproto) { - lproto_list = TYPE_PROTOCOL_LIST + lproto_list = TYPE_PROTOCOL_LIST (TREE_TYPE (lhs)); - lproto = lookup_protocol_in_reflist + lproto = lookup_protocol_in_reflist (lproto_list, p); } @@ -805,14 +837,14 @@ objc_comptypes (lhs, rhs, reflexive) p); cat = CLASS_CATEGORY_LIST (cat); } - - rinter = lookup_interface (CLASS_SUPER_NAME + + rinter = lookup_interface (CLASS_SUPER_NAME (rinter)); } - + if (!lproto) warning ("class `%s' does not implement the `%s' protocol", - IDENTIFIER_POINTER (TYPE_NAME + IDENTIFIER_POINTER (OBJC_TYPE_NAME (TREE_TYPE (lhs))), IDENTIFIER_POINTER (PROTOCOL_NAME (p))); } @@ -822,12 +854,12 @@ objc_comptypes (lhs, rhs, reflexive) return 0; } /* id = */ - else if (TYPE_NAME (TREE_TYPE (lhs)) == objc_object_id) + else if (OBJC_TYPE_NAME (TREE_TYPE (lhs)) == objc_object_id) { return 1; } /* Class = */ - else if (TYPE_NAME (TREE_TYPE (lhs)) == objc_class_id) + else if (OBJC_TYPE_NAME (TREE_TYPE (lhs)) == objc_class_id) { return 0; } @@ -856,28 +888,33 @@ objc_comptypes (lhs, rhs, reflexive) } /* `id' = ` *' ` *' = `id': always allow it. - Please note that + 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))) + if ((OBJC_TYPE_NAME (lhs) == objc_object_id && TYPED_OBJECT (rhs)) + || (OBJC_TYPE_NAME (rhs) == objc_object_id && TYPED_OBJECT (lhs))) return 1; /* `id' = `Class', `Class' = `id' */ - else if ((TYPE_NAME (lhs) == objc_object_id - && TYPE_NAME (rhs) == objc_class_id) - || (TYPE_NAME (lhs) == objc_class_id - && TYPE_NAME (rhs) == objc_object_id)) + else if ((OBJC_TYPE_NAME (lhs) == objc_object_id + && OBJC_TYPE_NAME (rhs) == objc_class_id) + || (OBJC_TYPE_NAME (lhs) == objc_class_id + && OBJC_TYPE_NAME (rhs) == objc_object_id)) return 1; + /* `Class' != ` *' && ` *' != `Class'! */ + else if ((OBJC_TYPE_NAME (lhs) == objc_class_id && TYPED_OBJECT (rhs)) + || (OBJC_TYPE_NAME (rhs) == objc_class_id && TYPED_OBJECT (lhs))) + return 0; + /* ` *' = ` *' */ else if (TYPED_OBJECT (lhs) && TYPED_OBJECT (rhs)) { - tree lname = TYPE_NAME (lhs); - tree rname = TYPE_NAME (rhs); + tree lname = OBJC_TYPE_NAME (lhs); + tree rname = OBJC_TYPE_NAME (rhs); tree inter; if (lname == rname) @@ -904,26 +941,24 @@ objc_comptypes (lhs, rhs, reflexive) return -1; } -/* Called from c-decl.c before all calls to rest_of_decl_compilation. */ +/* Called from finish_decl. */ void -objc_check_decl (decl) - tree decl; +objc_check_decl (tree decl) { tree type = TREE_TYPE (decl); - if (TREE_CODE (type) == RECORD_TYPE - && TREE_STATIC_TEMPLATE (type) - && type != constant_string_type) - error_with_decl (decl, "`%s' cannot be statically allocated"); + if (TREE_CODE (type) != RECORD_TYPE) + return; + if (TYPE_NAME (type) && (type = is_class_name (TYPE_NAME (type)))) + error ("statically allocated instance of Objective-C class `%s'", + IDENTIFIER_POINTER (type)); } /* Implement static typing. At this point, we know we have an interface. */ tree -get_static_reference (interface, protocols) - tree interface; - tree protocols; +get_static_reference (tree interface, tree protocols) { tree type = xref_tag (RECORD_TYPE, interface); @@ -939,7 +974,7 @@ get_static_reference (interface, protocols) /* Look up protocols and install in lang specific list. Note that the protocol list can have a different lifetime than T! */ - TYPE_PROTOCOL_LIST (t) = lookup_and_install_protocols (protocols); + SET_TYPE_PROTOCOL_LIST (t, lookup_and_install_protocols (protocols)); /* This forces a new pointer type to be created later (in build_pointer_type)...so that the new template @@ -954,8 +989,7 @@ get_static_reference (interface, protocols) } tree -get_object_reference (protocols) - tree protocols; +get_object_reference (tree protocols) { tree type_decl = lookup_name (objc_id_id); tree type; @@ -988,7 +1022,7 @@ get_object_reference (protocols) TYPE_NEXT_VARIANT (m) = t; /* Look up protocols...and install in lang specific list */ - TYPE_PROTOCOL_LIST (t) = lookup_and_install_protocols (protocols); + SET_TYPE_PROTOCOL_LIST (t, lookup_and_install_protocols (protocols)); /* This forces a new pointer type to be created later (in build_pointer_type)...so that the new template @@ -1005,10 +1039,8 @@ get_object_reference (protocols) 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; +static void +check_protocol_recursively (tree proto, tree list) { tree p; @@ -1021,19 +1053,20 @@ check_protocol_recursively (proto, list) if (pp == proto) fatal_error ("protocol `%s' has circular dependency", - IDENTIFIER_POINTER (PROTOCOL_NAME (pp))); + IDENTIFIER_POINTER (PROTOCOL_NAME (pp))); if (pp) check_protocol_recursively (proto, PROTOCOL_LIST (pp)); } } +/* Look up PROTOCOLS, and return a list of those that are found. + If none are found, return NULL. */ + static tree -lookup_and_install_protocols (protocols) - tree protocols; +lookup_and_install_protocols (tree protocols) { tree proto; - tree prev = NULL; - tree return_value = protocols; + tree return_value = NULL_TREE; for (proto = protocols; proto; proto = TREE_CHAIN (proto)) { @@ -1041,20 +1074,11 @@ lookup_and_install_protocols (protocols) tree p = lookup_protocol (ident); if (!p) - { - error ("cannot find protocol declaration for `%s'", - IDENTIFIER_POINTER (ident)); - if (prev) - TREE_CHAIN (prev) = TREE_CHAIN (proto); - else - return_value = TREE_CHAIN (proto); - } + error ("cannot find protocol declaration for `%s'", + IDENTIFIER_POINTER (ident)); else - { - /* Replace identifier with actual protocol node. */ - TREE_VALUE (proto) = p; - prev = proto; - } + return_value = chainon (return_value, + build_tree_list (NULL_TREE, p)); } return return_value; @@ -1065,10 +1089,7 @@ lookup_and_install_protocols (protocols) TYPE is its data type. */ static tree -create_builtin_decl (code, type, name) - enum tree_code code; - tree type; - const char *name; +create_builtin_decl (enum tree_code code, tree type, const char *name) { tree decl = build_decl (code, get_identifier (name), type); @@ -1077,21 +1098,31 @@ create_builtin_decl (code, type, name) TREE_STATIC (decl) = 1; make_decl_rtl (decl, 0); pushdecl (decl); + DECL_ARTIFICIAL (decl) = 1; } - DECL_ARTIFICIAL (decl) = 1; return decl; } /* Find the decl for the constant string class. */ static void -setup_string_decl () +setup_string_decl (void) { if (!string_class_decl) { if (!constant_string_global_id) - constant_string_global_id = get_identifier (STRING_OBJECT_GLOBAL_NAME); + { + char *name; + size_t length; + /* %s in format will provide room for terminating null */ + length = strlen (STRING_OBJECT_GLOBAL_FORMAT) + + strlen (constant_string_class_name); + name = xmalloc (length); + sprintf (name, STRING_OBJECT_GLOBAL_FORMAT, + constant_string_class_name); + constant_string_global_id = get_identifier (name); + } string_class_decl = lookup_name (constant_string_global_id); } } @@ -1101,17 +1132,16 @@ setup_string_decl () Model: - type_spec--------->sc_spec - (tree_list) (tree_list) - | | - | | - identifier_node identifier_node */ + type_spec--------->sc_spec + (tree_list) (tree_list) + | | + | | + identifier_node identifier_node */ static void -synth_module_prologue () +synth_module_prologue (void) { tree temp_type; - tree super_p; /* Defined in `objc.h' */ objc_object_id = get_identifier (TAG_OBJECT); @@ -1124,66 +1154,114 @@ synth_module_prologue () objc_class_id = get_identifier (TAG_CLASS); objc_class_type = build_pointer_type (xref_tag (RECORD_TYPE, objc_class_id)); + temp_type = get_identifier (PROTOCOL_OBJECT_CLASS_NAME); + objc_declare_class (tree_cons (NULL_TREE, temp_type, NULL_TREE)); protocol_type = build_pointer_type (xref_tag (RECORD_TYPE, - get_identifier (PROTOCOL_OBJECT_CLASS_NAME))); + temp_type)); /* Declare type of selector-objects that represent an operation name. */ - /* `struct objc_selector *' */ - selector_type - = build_pointer_type (xref_tag (RECORD_TYPE, - get_identifier (TAG_SELECTOR))); + if (flag_next_runtime) + /* `struct objc_selector *' */ + selector_type + = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier (TAG_SELECTOR))); + else + /* `const struct objc_selector *' */ + selector_type + = build_pointer_type + (build_qualified_type (xref_tag (RECORD_TYPE, + get_identifier (TAG_SELECTOR)), + TYPE_QUAL_CONST)); - /* Forward declare type, or else the prototype for msgSendSuper will - complain. */ + /* Declare receiver type used for dispatching messages to 'super'. */ - super_p = build_pointer_type (xref_tag (RECORD_TYPE, + /* `struct objc_super *' */ + super_type = build_pointer_type (xref_tag (RECORD_TYPE, get_identifier (TAG_SUPER))); - - /* id objc_msgSend (id, SEL, ...); */ - - temp_type - = build_function_type (id_type, - tree_cons (NULL_TREE, id_type, - tree_cons (NULL_TREE, selector_type, - NULL_TREE))); - - if (! flag_next_runtime) + if (flag_next_runtime) { - umsg_decl = build_decl (FUNCTION_DECL, - get_identifier (TAG_MSGSEND), temp_type); - DECL_EXTERNAL (umsg_decl) = 1; - TREE_PUBLIC (umsg_decl) = 1; - DECL_INLINE (umsg_decl) = 1; - DECL_ARTIFICIAL (umsg_decl) = 1; - - make_decl_rtl (umsg_decl, NULL); - pushdecl (umsg_decl); + /* NB: In order to call one of the ..._stret (struct-returning) + functions, the function *MUST* first be cast to a signature that + corresponds to the actual ObjC method being invoked. This is + what is done by the build_objc_method_call() routine below. */ + + /* id objc_msgSend (id, SEL, ...); */ + /* id objc_msgSendNonNil (id, SEL, ...); */ + /* id objc_msgSend_stret (id, SEL, ...); */ + /* id objc_msgSendNonNil_stret (id, SEL, ...); */ + temp_type + = build_function_type (id_type, + tree_cons (NULL_TREE, id_type, + tree_cons (NULL_TREE, selector_type, + NULL_TREE))); + umsg_decl = builtin_function (TAG_MSGSEND, + temp_type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + umsg_nonnil_decl = builtin_function (TAG_MSGSEND_NONNIL, + temp_type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + umsg_stret_decl = builtin_function (TAG_MSGSEND_STRET, + temp_type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + umsg_nonnil_stret_decl = builtin_function (TAG_MSGSEND_NONNIL_STRET, + temp_type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + + /* id objc_msgSendSuper (struct objc_super *, SEL, ...); */ + /* id objc_msgSendSuper_stret (struct objc_super *, SEL, ...); */ + temp_type + = build_function_type (id_type, + tree_cons (NULL_TREE, super_type, + tree_cons (NULL_TREE, selector_type, + NULL_TREE))); + umsg_super_decl = builtin_function (TAG_MSGSENDSUPER, + temp_type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + umsg_super_stret_decl = builtin_function (TAG_MSGSENDSUPER_STRET, + temp_type, 0, NOT_BUILT_IN, 0, + NULL_TREE); } else - umsg_decl = builtin_function (TAG_MSGSEND, temp_type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); - - /* id objc_msgSendSuper (struct objc_super *, SEL, ...); */ - - temp_type - = build_function_type (id_type, - tree_cons (NULL_TREE, super_p, - tree_cons (NULL_TREE, selector_type, - NULL_TREE))); - - umsg_super_decl = builtin_function (TAG_MSGSENDSUPER, - temp_type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); + { + /* GNU runtime messenger entry points. */ + + /* typedef id (*IMP)(id, SEL, ...); */ + tree IMP_type + = build_pointer_type + (build_function_type (id_type, + tree_cons (NULL_TREE, id_type, + tree_cons (NULL_TREE, selector_type, + NULL_TREE)))); + + /* IMP objc_msg_lookup (id, SEL); */ + temp_type + = build_function_type (IMP_type, + tree_cons (NULL_TREE, id_type, + tree_cons (NULL_TREE, selector_type, + void_list_node))); + umsg_decl = builtin_function (TAG_MSGSEND, + temp_type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + + /* IMP objc_msg_lookup_super (struct objc_super *, SEL); */ + temp_type + = build_function_type (IMP_type, + tree_cons (NULL_TREE, super_type, + tree_cons (NULL_TREE, selector_type, + void_list_node))); + umsg_super_decl = builtin_function (TAG_MSGSENDSUPER, + temp_type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + } /* id objc_getClass (const char *); */ temp_type = build_function_type (id_type, - tree_cons (NULL_TREE, - const_string_type_node, - tree_cons (NULL_TREE, void_type_node, - NULL_TREE))); + tree_cons (NULL_TREE, + const_string_type_node, + void_list_node)); objc_get_class_decl = builtin_function (TAG_GETCLASS, temp_type, 0, NOT_BUILT_IN, @@ -1192,8 +1270,11 @@ synth_module_prologue () /* id objc_getMetaClass (const char *); */ objc_get_meta_class_decl - = builtin_function (TAG_GETMETACLASS, temp_type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); + = builtin_function (TAG_GETMETACLASS, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + + build_super_template (); + if (flag_next_runtime) + build_objc_exception_stuff (); /* static SEL _OBJC_SELECTOR_TABLE[]; */ @@ -1226,99 +1307,109 @@ synth_module_prologue () TREE_USED (UOBJC_SELECTOR_TABLE_decl) = 1; } - generate_forward_declaration_to_string_table (); - /* Forward declare constant_string_id and constant_string_type. */ if (!constant_string_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); + objc_declare_class (tree_cons (NULL_TREE, constant_string_id, NULL_TREE)); + + /* Pre-build the following entities - for speed/convenience. */ + self_id = get_identifier ("self"); + ucmd_id = get_identifier ("_cmd"); +#ifndef OBJCPLUS + /* The C++ front-end does not appear to grok __attribute__((__unused__)). */ + unused_list = build_tree_list (get_identifier ("__unused__"), NULL_TREE); +#endif } -/* Predefine the following data type: +/* Ensure that the ivar list for NSConstantString/NXConstantString + (or whatever was specified via `-fconstant-string-class') + contains fields at least as large as the following three, so that + the runtime can stomp on them with confidence: - struct STRING_OBJECT_CLASS_NAME + struct STRING_OBJECT_CLASS_NAME { Object isa; char *cString; unsigned int length; }; */ -static void -build_string_class_template () +static int +check_string_class_template (void) { - tree field_decl, field_decl_chain; + tree field_decl = TYPE_FIELDS (constant_string_type); - field_decl = create_builtin_decl (FIELD_DECL, id_type, "isa"); - field_decl_chain = field_decl; +#define AT_LEAST_AS_LARGE_AS(F, T) \ + (F && TREE_CODE (F) == FIELD_DECL \ + && (TREE_INT_CST_LOW (DECL_SIZE (F)) \ + >= TREE_INT_CST_LOW (TYPE_SIZE (T)))) - field_decl = create_builtin_decl (FIELD_DECL, - build_pointer_type (char_type_node), - "cString"); - chainon (field_decl_chain, field_decl); + if (!AT_LEAST_AS_LARGE_AS (field_decl, ptr_type_node)) + return 0; - field_decl = create_builtin_decl (FIELD_DECL, unsigned_type_node, "length"); - chainon (field_decl_chain, field_decl); + field_decl = TREE_CHAIN (field_decl); + if (!AT_LEAST_AS_LARGE_AS (field_decl, ptr_type_node)) + return 0; - finish_struct (constant_string_type, field_decl_chain, NULL_TREE); + field_decl = TREE_CHAIN (field_decl); + return AT_LEAST_AS_LARGE_AS (field_decl, unsigned_type_node); + +#undef AT_LEAST_AS_LARGE_AS } +/* Avoid calling `check_string_class_template ()' more than once. */ +static GTY(()) int string_layout_checked; + /* Custom build_string which sets TREE_TYPE! */ static tree -my_build_string (len, str) - int len; - const char *str; +my_build_string (int len, const char *str) { return fix_string_type (build_string (len, str)); } /* Given a chain of STRING_CST's, build a static instance of - NXConstantString which points at the concatenation of those strings. - We place the string object in the __string_objects section of the - __OBJC segment. The Objective-C runtime will initialize the isa - pointers of the string objects to point at the NXConstantString - class object. */ + NXConstantString which points at the concatenation of those + strings. We place the string object in the __string_objects + section of the __OBJC segment. The Objective-C runtime will + initialize the isa pointers of the string objects to point at the + NXConstantString class object. */ tree -build_objc_string_object (strings) - tree strings; +build_objc_string_object (tree string) { - tree string, initlist, constructor; + tree initlist, constructor, constant_string_class; int length; - if (lookup_interface (constant_string_id) == NULL_TREE) + string = fix_string_type (string); + + constant_string_class = lookup_interface (constant_string_id); + if (!constant_string_class + || !(constant_string_type + = CLASS_STATIC_TEMPLATE (constant_string_class))) { error ("cannot find interface declaration for `%s'", IDENTIFIER_POINTER (constant_string_id)); return error_mark_node; } - add_class_reference (constant_string_id); - - 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); - + /* Call to 'combine_strings' has been moved above. */ TREE_SET_CODE (string, STRING_CST); length = TREE_STRING_LENGTH (string) - 1; - /* 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 (); + if (!string_layout_checked) + { + /* The NSConstantString/NXConstantString ivar layout is now + known. */ + if (!check_string_class_template ()) + { + error ("interface `%s' does not have valid constant string layout", + IDENTIFIER_POINTER (constant_string_id)); + return error_mark_node; + } + add_class_reference (constant_string_id); + } /* & ((NXConstantString) { NULL, string, length }) */ @@ -1361,9 +1452,9 @@ build_objc_string_object (strings) /* Declare a static instance of CLASS_DECL initialized by CONSTRUCTOR. */ static GTY(()) int num_static_inst; + static tree -objc_add_static_instance (constructor, class_decl) - tree constructor, class_decl; +objc_add_static_instance (tree constructor, tree class_decl) { tree *chain, decl; char buf[256]; @@ -1376,7 +1467,7 @@ objc_add_static_instance (constructor, class_decl) if (!*chain) { *chain = tree_cons (NULL_TREE, class_decl, NULL_TREE); - add_objc_string (TYPE_NAME (class_decl), class_names); + add_objc_string (OBJC_TYPE_NAME (class_decl), class_names); } sprintf (buf, "_OBJC_INSTANCE_%d", num_static_inst++); @@ -1402,8 +1493,7 @@ objc_add_static_instance (constructor, class_decl) with type TYPE and elements ELTS. */ static tree -objc_build_constructor (type, elts) - tree type, elts; +objc_build_constructor (tree type, tree elts) { tree constructor, f, e; @@ -1430,6 +1520,11 @@ objc_build_constructor (type, elts) TREE_STATIC (constructor) = 1; TREE_READONLY (constructor) = 1; +#ifdef OBJCPLUS + /* zlaski 2001-Apr-02: mark this as a call to a constructor, as required by + build_unary_op (wasn't true in 2.7.2.1 days) */ + TREE_HAS_CONSTRUCTOR (constructor) = 1; +#endif return constructor; } @@ -1447,9 +1542,9 @@ objc_build_constructor (type, elts) }; */ static void -build_objc_symtab_template () +build_objc_symtab_template (void) { - tree field_decl, field_decl_chain, index; + tree field_decl, field_decl_chain; objc_symtab_template = start_struct (RECORD_TYPE, get_identifier (UTAG_SYMTAB)); @@ -1482,18 +1577,20 @@ build_objc_symtab_template () "cat_def_cnt"); chainon (field_decl_chain, field_decl); - /* void *defs[cls_def_cnt + cat_def_cnt]; */ - - if (!flag_next_runtime) - index = build_index_type (build_int_2 (imp_count + cat_count, 0)); - else - index = build_index_type (build_int_2 (imp_count + cat_count - 1, - imp_count == 0 && cat_count == 0 - ? -1 : 0)); - field_decl = create_builtin_decl (FIELD_DECL, - build_array_type (ptr_type_node, index), - "defs"); - chainon (field_decl_chain, field_decl); + if (imp_count || cat_count || !flag_next_runtime) + { + /* void *defs[imp_count + cat_count (+ 1)]; */ + /* NB: The index is one less than the size of the array. */ + int index = imp_count + cat_count + + (flag_next_runtime? -1: 0); + field_decl = create_builtin_decl + (FIELD_DECL, + build_array_type + (ptr_type_node, + build_index_type (build_int_2 (index, 0))), + "defs"); + chainon (field_decl_chain, field_decl); + } finish_struct (objc_symtab_template, field_decl_chain, NULL_TREE); } @@ -1502,8 +1599,7 @@ build_objc_symtab_template () This is a CONSTRUCTOR. */ static tree -init_def_list (type) - tree type; +init_def_list (tree type) { tree expr, initlist = NULL_TREE; struct imp_entry *impent; @@ -1547,8 +1643,7 @@ init_def_list (type) /* Construct the initial value for all of _objc_symtab. */ static tree -init_objc_symtab (type) - tree type; +init_objc_symtab (tree type) { tree initlist; @@ -1576,7 +1671,7 @@ init_objc_symtab (type) /* cls_def = { ..., { &Foo, &Bar, ...}, ... } */ - if (imp_count || cat_count || static_instances_decl) + if (imp_count || cat_count || !flag_next_runtime) { tree field = TYPE_FIELDS (type); @@ -1589,11 +1684,31 @@ init_objc_symtab (type) return objc_build_constructor (type, nreverse (initlist)); } +/* Generate forward declarations for metadata such as + 'OBJC_CLASS_...'. */ + +static tree +build_metadata_decl (const char *name, tree type) +{ + tree decl, decl_specs; + /* extern struct TYPE NAME_; */ + decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_EXTERN]); + decl_specs = tree_cons (NULL_TREE, type, decl_specs); + decl = define_decl (synth_id_with_class_suffix + (name, + objc_implementation_context), + decl_specs); + TREE_USED (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + TREE_PUBLIC (decl) = 0; + return decl; +} + /* Push forward-declarations of all the categories so that init_def_list can use them in a CONSTRUCTOR. */ static void -forward_declare_categories () +forward_declare_categories (void) { struct imp_entry *impent; tree sav = objc_implementation_context; @@ -1604,19 +1719,19 @@ forward_declare_categories () { /* Set an invisible arg to synth_id_with_class_suffix. */ 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", objc_implementation_context))); + /* extern struct objc_category _OBJC_CATEGORY_; */ + impent->class_decl = build_metadata_decl ("_OBJC_CATEGORY", + objc_category_template); } } objc_implementation_context = sav; } -/* Create the declaration of _OBJC_SYMBOLS, with type `strict _objc_symtab' +/* Create the declaration of _OBJC_SYMBOLS, with type `struct _objc_symtab' and initialized appropriately. */ static void -generate_objc_symtab_decl () +generate_objc_symtab_decl (void) { tree sc_spec; @@ -1647,8 +1762,7 @@ generate_objc_symtab_decl () } static tree -init_module_descriptor (type) - tree type; +init_module_descriptor (tree type) { tree initlist, expr; @@ -1686,7 +1800,7 @@ init_module_descriptor (type) struct objc_module { ... } _OBJC_MODULE = { ... }; */ static rtx -build_module_descriptor () +build_module_descriptor (void) { tree decl_specs, field_decl, field_decl_chain; @@ -1697,24 +1811,21 @@ build_module_descriptor () decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_LONG]); field_decl = get_identifier ("version"); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); field_decl_chain = field_decl; /* long size; */ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_LONG]); field_decl = get_identifier ("size"); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); /* char *name; */ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("name")); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); /* struct objc_symtab *symtab; */ @@ -1722,8 +1833,7 @@ build_module_descriptor () decl_specs = get_identifier (UTAG_SYMTAB); decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE, decl_specs)); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("symtab")); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); finish_struct (objc_module_template, field_decl_chain, NULL_TREE); @@ -1767,7 +1877,8 @@ build_module_descriptor () get_identifier (TAG_EXECCLASS), build_function_type (void_type_node, tree_cons (NULL_TREE, ptr_type_node, - void_list_node_1))); + void_list_node))); + DECL_EXTERNAL (execclass_decl) = 1; DECL_ARTIFICIAL (execclass_decl) = 1; TREE_PUBLIC (execclass_decl) = 1; @@ -1781,7 +1892,7 @@ build_module_descriptor () start_function (void_list_node_1, build_nt (CALL_EXPR, init_function_name, tree_cons (NULL_TREE, NULL_TREE, - void_list_node_1), + void_list_node), NULL_TREE), NULL_TREE); store_parm_decls (); @@ -1802,34 +1913,16 @@ build_module_descriptor () c_expand_expr_stmt (decelerator); - finish_function (0, 0); + finish_function (); return XEXP (DECL_RTL (init_function_decl), 0); } } -/* extern const char _OBJC_STRINGS[]; */ - -static void -generate_forward_declaration_to_string_table () -{ - tree sc_spec, decl_specs, expr_decl; - - sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_EXTERN], NULL_TREE); - decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec); - - expr_decl - = build_nt (ARRAY_REF, get_identifier ("_OBJC_STRINGS"), NULL_TREE); - - UOBJC_STRINGS_decl = define_decl (expr_decl, decl_specs); -} - /* Return the DECL of the string IDENT in the SECTION. */ static tree -get_objc_string_decl (ident, section) - tree ident; - enum string_section section; +get_objc_string_decl (tree ident, enum string_section section) { tree chain; @@ -1854,7 +1947,7 @@ get_objc_string_decl (ident, section) for the array built. */ static void -generate_static_references () +generate_static_references (void) { tree decls = NULL_TREE, ident, decl_spec, expr_decl, expr = NULL_TREE; tree class_name, class, decl, initlist; @@ -1884,7 +1977,7 @@ generate_static_references () /* Output {class_name, ...}. */ class = TREE_VALUE (cl_chain); - class_name = get_objc_string_decl (TYPE_NAME (class), class_names); + class_name = get_objc_string_decl (OBJC_TYPE_NAME (class), class_names); initlist = build_tree_list (NULL_TREE, build_unary_op (ADDR_EXPR, class_name, 1)); @@ -1930,7 +2023,7 @@ generate_static_references () /* Output all strings. */ static void -generate_strings () +generate_strings (void) { tree sc_spec, decl_specs, expr_decl; tree chain, string_expr; @@ -1983,8 +2076,9 @@ generate_strings () } static GTY(()) int selector_reference_idx; + static tree -build_selector_reference_decl () +build_selector_reference_decl (void) { tree decl, ident; char buf[256]; @@ -1995,9 +2089,8 @@ build_selector_reference_decl () decl = build_decl (VAR_DECL, ident, selector_type); DECL_EXTERNAL (decl) = 1; - TREE_PUBLIC (decl) = 1; + TREE_PUBLIC (decl) = 0; TREE_USED (decl) = 1; - TREE_READONLY (decl) = 1; DECL_ARTIFICIAL (decl) = 1; DECL_CONTEXT (decl) = 0; @@ -2010,8 +2103,7 @@ build_selector_reference_decl () /* Just a handy wrapper for add_objc_string. */ static tree -build_selector (ident) - tree ident; +build_selector (tree ident) { tree expr = add_objc_string (ident, meth_var_names); if (flag_typed_selectors) @@ -2021,7 +2113,7 @@ build_selector (ident) } static void -build_selector_translation_table () +build_selector_translation_table (void) { tree sc_spec, decl_specs; tree chain, initlist = NULL_TREE; @@ -2081,7 +2173,7 @@ build_selector_translation_table () if (flag_next_runtime) finish_decl (decl, expr, NULL_TREE); - else + else { if (flag_typed_selectors) { @@ -2093,7 +2185,7 @@ build_selector_translation_table () nreverse (eltlist)); } initlist = tree_cons (NULL_TREE, expr, initlist); - + } } @@ -2113,21 +2205,16 @@ build_selector_translation_table () } static tree -get_proto_encoding (proto) - tree proto; +get_proto_encoding (tree proto) { tree encoding; if (proto) { - tree tmp_decl; - if (! METHOD_ENCODING (proto)) { - tmp_decl = build_tmp_function_decl (); - hack_method_prototype (proto, tmp_decl); - encoding = encode_method_prototype (proto, tmp_decl); - METHOD_ENCODING (proto) = encoding; - } + encoding = encode_method_prototype (proto); + METHOD_ENCODING (proto) = encoding; + } else encoding = METHOD_ENCODING (proto); @@ -2141,8 +2228,7 @@ get_proto_encoding (proto) identifier_node that represent the selector. */ static tree -build_typed_selector_reference (ident, prototype) - tree ident, prototype; +build_typed_selector_reference (tree ident, tree prototype) { tree *chain = &sel_ref_chain; tree expr; @@ -2168,8 +2254,7 @@ build_typed_selector_reference (ident, prototype) } static tree -build_selector_reference (ident) - tree ident; +build_selector_reference (tree ident) { tree *chain = &sel_ref_chain; tree expr; @@ -2198,8 +2283,9 @@ build_selector_reference (ident) } static GTY(()) int class_reference_idx; + static tree -build_class_reference_decl () +build_class_reference_decl (void) { tree decl, ident; char buf[256]; @@ -2210,9 +2296,8 @@ build_class_reference_decl () decl = build_decl (VAR_DECL, ident, objc_class_type); DECL_EXTERNAL (decl) = 1; - TREE_PUBLIC (decl) = 1; + TREE_PUBLIC (decl) = 0; TREE_USED (decl) = 1; - TREE_READONLY (decl) = 1; DECL_CONTEXT (decl) = 0; DECL_ARTIFICIAL (decl) = 1; @@ -2226,8 +2311,7 @@ build_class_reference_decl () it. */ static void -add_class_reference (ident) - tree ident; +add_class_reference (tree ident) { tree chain; @@ -2255,10 +2339,27 @@ add_class_reference (ident) reference variable. */ tree -get_class_reference (ident) - tree ident; +get_class_reference (tree ident) { - if (flag_next_runtime) + tree orig_ident; + +#ifdef OBJCPLUS + if (processing_template_decl) + /* Must wait until template instantiation time. */ + return build_min_nt (CLASS_REFERENCE_EXPR, ident); + if (TREE_CODE (ident) == TYPE_DECL) + ident = DECL_NAME (ident); +#endif + orig_ident = ident; + + if (!(ident = is_class_name (ident))) + { + error ("`%s' is not an Objective-C class name or alias", + IDENTIFIER_POINTER (orig_ident)); + return error_mark_node; + } + + if (flag_next_runtime && !flag_zero_link) { tree *chain; tree decl; @@ -2295,9 +2396,7 @@ get_class_reference (ident) to decls for the strings. */ static tree -add_objc_string (ident, section) - tree ident; - enum string_section section; +add_objc_string (tree ident, enum string_section section) { tree *chain, decl; @@ -2330,8 +2429,7 @@ static GTY(()) int meth_var_names_idx; static GTY(()) int meth_var_types_idx; static tree -build_objc_string_decl (section) - enum string_section section; +build_objc_string_decl (enum string_section section) { tree decl, ident; char buf[256]; @@ -2347,13 +2445,12 @@ build_objc_string_decl (section) decl = build_decl (VAR_DECL, ident, build_array_type (char_type_node, 0)); DECL_EXTERNAL (decl) = 1; - TREE_PUBLIC (decl) = 1; + TREE_PUBLIC (decl) = 0; TREE_USED (decl) = 1; - TREE_READONLY (decl) = 1; TREE_CONSTANT (decl) = 1; DECL_CONTEXT (decl) = 0; DECL_ARTIFICIAL (decl) = 1; - + make_decl_rtl (decl, 0); pushdecl_top_level (decl); @@ -2362,39 +2459,51 @@ build_objc_string_decl (section) void -objc_declare_alias (alias_ident, class_ident) - tree alias_ident; - tree class_ident; +objc_declare_alias (tree alias_ident, tree class_ident) { - if (is_class_name (class_ident) != class_ident) + tree underlying_class; + +#ifdef OBJCPLUS + if (current_namespace != global_namespace) { + error ("Objective-C declarations may only appear in global scope"); + } +#endif /* OBJCPLUS */ + + if (!(underlying_class = is_class_name (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)); else - alias_chain = tree_cons (class_ident, alias_ident, alias_chain); + alias_chain = tree_cons (underlying_class, alias_ident, alias_chain); } void -objc_declare_class (ident_list) - tree ident_list; +objc_declare_class (tree ident_list) { tree list; +#ifdef OBJCPLUS + if (current_namespace != global_namespace) { + error ("Objective-C declarations may only appear in global scope"); + } +#endif /* OBJCPLUS */ for (list = ident_list; list; list = TREE_CHAIN (list)) { tree ident = TREE_VALUE (list); - tree decl; - if ((decl = lookup_name (ident))) + if (! is_class_name (ident)) { - error ("`%s' redeclared as different kind of symbol", - IDENTIFIER_POINTER (ident)); - error_with_decl (decl, "previous declaration of `%s'"); - } + tree record = lookup_name (ident); + + if (record && ! TREE_STATIC_TEMPLATE (record)) + { + error ("`%s' redeclared as different kind of symbol", + IDENTIFIER_POINTER (ident)); + error ("%Jprevious declaration of '%D'", + record, record); + } - if (! is_class_name (ident)) - { - tree record = xref_tag (RECORD_TYPE, ident); + record = xref_tag (RECORD_TYPE, ident); TREE_STATIC_TEMPLATE (record) = 1; class_chain = tree_cons (NULL_TREE, ident, class_chain); } @@ -2402,11 +2511,25 @@ objc_declare_class (ident_list) } tree -is_class_name (ident) - tree ident; +is_class_name (tree ident) { tree chain; + if (ident && TREE_CODE (ident) == IDENTIFIER_NODE + && identifier_global_value (ident)) + ident = identifier_global_value (ident); + while (ident && TREE_CODE (ident) == TYPE_DECL && DECL_ORIGINAL_TYPE (ident)) + ident = TYPE_NAME (DECL_ORIGINAL_TYPE (ident)); + +#ifdef OBJCPLUS + if (ident && TREE_CODE (ident) == RECORD_TYPE) + ident = TYPE_NAME (ident); + if (ident && TREE_CODE (ident) == TYPE_DECL) + ident = DECL_NAME (ident); +#endif + if (!ident || TREE_CODE (ident) != IDENTIFIER_NODE) + return NULL_TREE; + if (lookup_interface (ident)) return ident; @@ -2425,48 +2548,94 @@ is_class_name (ident) return 0; } +/* Check whether TYPE is either 'id', 'Class', or a pointer to an ObjC + class instance. This is needed by other parts of the compiler to + handle ObjC types gracefully. */ + tree -objc_is_id (ident) - tree ident; +objc_is_object_ptr (tree type) { - /* 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; + type = TYPE_MAIN_VARIANT (type); + if (!type || TREE_CODE (type) != POINTER_TYPE) + return 0; + /* NB: This function may be called before the ObjC front-end has + been initialized, in which case ID_TYPE will be NULL. */ + if (id_type && type && TYPE_P (type) + && (IS_ID (type) + || TREE_TYPE (type) == TREE_TYPE (objc_class_type))) + return type; + return is_class_name (OBJC_TYPE_NAME (TREE_TYPE (type))); } tree -lookup_interface (ident) - tree ident; +lookup_interface (tree ident) { tree chain; +#ifdef OBJCPLUS + if (ident && TREE_CODE (ident) == TYPE_DECL) + ident = DECL_NAME (ident); +#endif for (chain = interface_chain; chain; chain = TREE_CHAIN (chain)) { if (ident == CLASS_NAME (chain)) - return chain; + return chain; } return NULL_TREE; } +/* Implement @defs () within struct bodies. */ + +tree +get_class_ivars_from_name (tree class_name) +{ + tree interface = lookup_interface (class_name); + tree field, fields = NULL_TREE; + + if (interface) + { + tree raw_ivar = get_class_ivars (interface, 1); + + /* Regenerate the FIELD_DECLs for the enclosing struct. */ + for (; raw_ivar; raw_ivar = TREE_CHAIN (raw_ivar)) + { + field = grokfield (TREE_PURPOSE (TREE_VALUE (raw_ivar)), + TREE_PURPOSE (raw_ivar), + TREE_VALUE (TREE_VALUE (raw_ivar))); +#ifdef OBJCPLUS + finish_member_declaration (field); +#else + fields = chainon (fields, field); +#endif + } + } + else + error ("cannot find interface declaration for `%s'", + IDENTIFIER_POINTER (class_name)); + + return fields; +} + /* Used by: build_private_template, continue_class, and for @defs constructs. */ -tree -get_class_ivars (interface) - tree interface; +static tree +get_class_ivars (tree interface, int raw) { tree my_name, super_name, ivar_chain; my_name = CLASS_NAME (interface); super_name = CLASS_SUPER_NAME (interface); - 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); + if (raw) + ivar_chain = CLASS_RAW_IVARS (interface); + 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) { @@ -2490,7 +2659,7 @@ get_class_ivars (interface) my_name = CLASS_NAME (interface); super_name = CLASS_SUPER_NAME (interface); - op1 = CLASS_OWN_IVARS (interface); + op1 = (raw ? CLASS_RAW_IVARS (interface) : CLASS_OWN_IVARS (interface)); if (op1) { tree head = copy_list (op1); @@ -2501,103 +2670,779 @@ get_class_ivars (interface) ivar_chain = head; } } + return ivar_chain; } -/* struct { - struct objc_class *isa; - ... - }; */ - static tree -build_private_template (class) - tree class; +objc_enter_block (void) { - tree ivar_context; - - if (CLASS_STATIC_TEMPLATE (class)) - { - uprivate_record = CLASS_STATIC_TEMPLATE (class); - ivar_context = TYPE_FIELDS (CLASS_STATIC_TEMPLATE (class)); - } - else - { - uprivate_record = start_struct (RECORD_TYPE, CLASS_NAME (class)); + tree block; - ivar_context = get_class_ivars (class); +#ifdef OBJCPLUS + block = begin_compound_stmt (0); +#else + block = c_begin_compound_stmt (); + push_scope (); + clear_last_expr (); + add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0); +#endif - finish_struct (uprivate_record, ivar_context, NULL_TREE); + objc_exception_block_stack = tree_cons (NULL_TREE, block, + objc_exception_block_stack); - CLASS_STATIC_TEMPLATE (class) = uprivate_record; + blk_nesting_count++; + return block; +} - /* mark this record as class template - for class type checking */ - TREE_STATIC_TEMPLATE (uprivate_record) = 1; - } +static tree +objc_exit_block (void) +{ + tree block = TREE_VALUE (objc_exception_block_stack); +#ifndef OBJCPLUS + tree scope_stmt, inner; +#endif - instance_type - = groktypename (build_tree_list (build_tree_list (NULL_TREE, - uprivate_record), - build1 (INDIRECT_REF, NULL_TREE, - NULL_TREE))); + objc_clear_super_receiver (); +#ifdef OBJCPLUS + finish_compound_stmt (0, block); +#else + scope_stmt = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0); + inner = pop_scope (); + + SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmt)) + = SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmt)) + = inner; + RECHAIN_STMTS (block, COMPOUND_BODY (block)); +#endif + last_expr_type = NULL_TREE; + objc_exception_block_stack = TREE_CHAIN (objc_exception_block_stack); - return ivar_context; + blk_nesting_count--; + return block; } - -/* Begin code generation for protocols... */ - -/* struct objc_protocol { - char *protocol_name; - struct objc_protocol **protocol_list; - struct objc_method_desc *instance_methods; - struct objc_method_desc *class_methods; - }; */ static tree -build_protocol_template () +objc_declare_variable (enum rid scspec, tree name, tree type, tree init) { - tree decl_specs, field_decl, field_decl_chain; - tree template; + tree decl; - template = start_struct (RECORD_TYPE, get_identifier (UTAG_PROTOCOL)); + type = tree_cons (NULL_TREE, type, + tree_cons (NULL_TREE, ridpointers[(int) scspec], + NULL_TREE)); + TREE_STATIC (type) = 1; + decl = start_decl (name, type, (init != NULL_TREE), NULL_TREE); + finish_decl (decl, init, NULL_TREE); + /* This prevents `unused variable' warnings when compiling with -Wall. */ + TREE_USED (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + return decl; +} - /* struct objc_class *isa; */ +tree +objc_build_throw_stmt (tree throw_expr) +{ + tree func_params; - decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE, - get_identifier (UTAG_CLASS))); - field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("isa")); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); - field_decl_chain = field_decl; + if (!flag_objc_exceptions) + fatal_error ("Use `-fobjc-exceptions' to enable Objective-C exception syntax"); - /* char *protocol_name; */ + if (!throw_expr && objc_caught_exception) + throw_expr = TREE_VALUE (objc_caught_exception); - decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]); - field_decl - = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("protocol_name")); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); - chainon (field_decl_chain, field_decl); + if (!throw_expr) + { + error ("`@throw;' (rethrow) used outside of a `@catch' block"); + return error_mark_node; + } - /* struct objc_protocol **protocol_list; */ + func_params = tree_cons (NULL_TREE, throw_expr, NULL_TREE); - decl_specs = build_tree_list (NULL_TREE, template); - field_decl - = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("protocol_list")); - field_decl = build1 (INDIRECT_REF, NULL_TREE, field_decl); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); - chainon (field_decl_chain, field_decl); + assemble_external (objc_exception_throw_decl); + return c_expand_expr_stmt (build_function_call (objc_exception_throw_decl, + func_params)); +} - /* struct objc_method_list *instance_methods; */ +static void +val_stack_push (struct val_stack **nc, long val) +{ + struct val_stack *new_elem = xmalloc (sizeof (struct val_stack)); + new_elem->val = val; + new_elem->next = *nc; + *nc = new_elem; +} - decl_specs +static void +val_stack_pop (struct val_stack **nc) +{ + struct val_stack *old_elem = *nc; + *nc = old_elem->next; + free (old_elem); +} + +static void +objc_build_try_enter_fragment (void) +{ + /* objc_exception_try_enter(&_stackExceptionData); + if (!_setjmp(&_stackExceptionData.buf)) { */ + + tree func_params, if_stmt, cond; + + func_params + = tree_cons (NULL_TREE, + build_unary_op (ADDR_EXPR, + TREE_VALUE (objc_stack_exception_data), + 0), + NULL_TREE); + + assemble_external (objc_exception_try_enter_decl); + c_expand_expr_stmt (build_function_call + (objc_exception_try_enter_decl, func_params)); + + if_stmt = c_begin_if_stmt (); + if_nesting_count++; + /* If has been included, the _setjmp prototype has + acquired a real, breathing type for its parameter. Cast our + argument to that type. */ + func_params + = tree_cons (NULL_TREE, + build_c_cast (TYPE_ARG_TYPES (TREE_TYPE (objc_setjmp_decl)) + ? TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (objc_setjmp_decl))) + : ptr_type_node, + build_unary_op + (ADDR_EXPR, + build_component_ref (TREE_VALUE (objc_stack_exception_data), + get_identifier ("buf")), 0)), + NULL_TREE); + assemble_external (objc_setjmp_decl); + cond = build_unary_op (TRUTH_NOT_EXPR, + build_function_call (objc_setjmp_decl, func_params), + 0); + c_expand_start_cond ((*lang_hooks.truthvalue_conversion) (cond), + 0, if_stmt); + objc_enter_block (); +} + +static tree +objc_build_extract_expr (void) +{ + /* ... = objc_exception_extract(&_stackExceptionData); */ + + tree func_params + = tree_cons (NULL_TREE, + build_unary_op (ADDR_EXPR, + TREE_VALUE (objc_stack_exception_data), 0), + NULL_TREE); + + assemble_external (objc_exception_extract_decl); + return build_function_call (objc_exception_extract_decl, func_params); +} + +static void +objc_build_try_exit_fragment (void) +{ + /* objc_exception_try_exit(&_stackExceptionData); */ + + tree func_params + = tree_cons (NULL_TREE, + build_unary_op (ADDR_EXPR, + TREE_VALUE (objc_stack_exception_data), 0), + NULL_TREE); + + assemble_external (objc_exception_try_exit_decl); + c_expand_expr_stmt (build_function_call (objc_exception_try_exit_decl, + func_params)); +} + +static void +objc_build_extract_fragment (void) +{ + /* } else { + _rethrowException = objc_exception_extract(&_stackExceptionData); + } */ + + objc_exit_block (); + c_finish_then (); + + c_expand_start_else (); + objc_enter_block (); + c_expand_expr_stmt (build_modify_expr + (TREE_VALUE (objc_rethrow_exception), + NOP_EXPR, + objc_build_extract_expr ())); + objc_exit_block (); + c_finish_else (); + c_expand_end_cond (); + if_nesting_count--; +} + +tree +objc_build_try_prologue (void) +{ + /* { // new scope + struct _objc_exception_data _stackExceptionData; + volatile id _rethrowException = nil; + { // begin TRY-CATCH scope + objc_exception_try_enter(&_stackExceptionData); + if (!_setjmp(&_stackExceptionData.buf)) { */ + + tree try_catch_block; + + if (!flag_objc_exceptions) + fatal_error ("Use `-fobjc-exceptions' to enable Objective-C exception syntax"); + + objc_mark_locals_volatile ((void *)(exc_binding_stack + ? exc_binding_stack->val + : 0)); + objc_enter_block (); + objc_stack_exception_data + = tree_cons (NULL_TREE, + objc_declare_variable (RID_AUTO, + get_identifier (UTAG_EXCDATA_VAR), + xref_tag (RECORD_TYPE, + get_identifier (UTAG_EXCDATA)), + NULL_TREE), + objc_stack_exception_data); + objc_rethrow_exception = tree_cons (NULL_TREE, + objc_declare_variable (RID_VOLATILE, + get_identifier (UTAG_RETHROWEXC_VAR), + id_type, + build_int_2 (0, 0)), + objc_rethrow_exception); + + try_catch_block = objc_enter_block (); + val_stack_push (&exc_binding_stack, (long) get_current_scope ()); + objc_build_try_enter_fragment (); + + return try_catch_block; +} + +void +objc_build_try_epilogue (int also_catch_prologue) +{ + if (also_catch_prologue) + { + /* } else { + register id _caughtException = objc_exception_extract( &_stackExceptionData); + objc_exception_try_enter(&_stackExceptionData); + if(!_setjmp(&_stackExceptionData.buf)) { + if (0) { */ + + tree if_stmt; + + objc_exit_block (); + c_finish_then (); + + c_expand_start_else (); + objc_enter_block (); + objc_caught_exception + = tree_cons (NULL_TREE, + objc_declare_variable (RID_REGISTER, + get_identifier (UTAG_CAUGHTEXC_VAR), + id_type, + objc_build_extract_expr ()), + objc_caught_exception); + objc_build_try_enter_fragment (); + val_stack_push (&catch_count_stack, 1); + if_stmt = c_begin_if_stmt (); + if_nesting_count++; + c_expand_start_cond ((*lang_hooks.truthvalue_conversion) (boolean_false_node), + 0, if_stmt); + objc_enter_block (); + + /* Start a new chain of @catch statements for this @try. */ + objc_catch_type = tree_cons (objc_catch_type, NULL_TREE, NULL_TREE); + } + else + { /* !also_catch_prologue */ + + /* } else { + _rethrowException = objc_exception_extract( &_stackExceptionData); + } + } */ + objc_build_extract_fragment (); + objc_exit_block (); + } +} + +void +objc_build_catch_stmt (tree catch_expr) +{ + /* } else if (objc_exception_match(objc_get_class("SomeClass"), _caughtException)) { + register SomeClass *e = _caughtException; */ + + tree if_stmt, cond, func_params, prev_catch, var_name, var_type; + int catch_id; + +#ifndef OBJCPLUS + /* Yet another C/C++ impedance mismatch. */ + catch_expr = TREE_PURPOSE (catch_expr); +#endif + + var_name = TREE_VALUE (catch_expr); + var_type = TREE_VALUE (TREE_PURPOSE (catch_expr)); + if (TREE_CODE (var_name) == INDIRECT_REF) + var_name = TREE_OPERAND (var_name, 0); + if (TREE_CODE (var_type) == TYPE_DECL + || TREE_CODE (var_type) == POINTER_TYPE) + var_type = TREE_TYPE (var_type); + catch_id = (var_type == TREE_TYPE (id_type)); + + if (!flag_objc_exceptions) + fatal_error ("Use `-fobjc-exceptions' to enable Objective-C exception syntax"); + + if (!(catch_id || TYPED_OBJECT (var_type))) + fatal_error ("`@catch' parameter is not a known Objective-C class type"); + + /* Examine previous @catch clauses for the current @try block for + superclasses of the 'var_type' class. */ + for (prev_catch = objc_catch_type; TREE_VALUE (prev_catch); + prev_catch = TREE_CHAIN (prev_catch)) + { + if (TREE_VALUE (prev_catch) == TREE_TYPE (id_type)) + { + warning ("Exception already handled by preceding `@catch(id)'"); + break; + } + else if (!catch_id + && objc_comptypes (TREE_VALUE (prev_catch), var_type, 0) == 1) + warning ("Exception of type `%s *' already handled by `@catch (%s *)'", + IDENTIFIER_POINTER (OBJC_TYPE_NAME (var_type)), + IDENTIFIER_POINTER (OBJC_TYPE_NAME (TREE_VALUE (prev_catch)))); + } + + objc_catch_type = tree_cons (NULL_TREE, var_type, objc_catch_type); + + objc_exit_block (); + c_finish_then (); + + c_expand_start_else (); + catch_count_stack->val++; + if_stmt = c_begin_if_stmt (); + if_nesting_count++; + + if (catch_id) + cond = integer_one_node; + else + { + cond = get_class_reference (OBJC_TYPE_NAME (var_type)); + + func_params + = tree_cons (NULL_TREE, cond, + tree_cons (NULL_TREE, + TREE_VALUE (objc_caught_exception), + NULL_TREE)); + assemble_external (objc_exception_match_decl); + cond = build_function_call (objc_exception_match_decl, func_params); + } + + c_expand_start_cond ((*lang_hooks.truthvalue_conversion) (cond), + 0, if_stmt); + objc_enter_block (); + objc_declare_variable (RID_REGISTER, var_name, + build_pointer_type (var_type), + TREE_VALUE (objc_caught_exception)); +} + +void +objc_build_catch_epilogue (void) +{ + /* } else { + _rethrowException = _caughtException; + objc_exception_try_exit(&_stackExceptionData); + } + } else { + _rethrowException = objc_exception_extract(&_stackExceptionData); + } + } + } // end TRY-CATCH scope + */ + + objc_exit_block (); + c_finish_then (); + + c_expand_start_else (); + objc_enter_block (); + c_expand_expr_stmt + (build_modify_expr + (TREE_VALUE (objc_rethrow_exception), + NOP_EXPR, + TREE_VALUE (objc_caught_exception))); + objc_build_try_exit_fragment (); + objc_exit_block (); + while (catch_count_stack->val--) + { + c_finish_else (); /* close off all the nested ifs ! */ + c_expand_end_cond (); + if_nesting_count--; + } + val_stack_pop (&catch_count_stack); + objc_caught_exception = TREE_CHAIN (objc_caught_exception); + + objc_build_extract_fragment (); + + objc_exit_block (); + c_finish_else (); + c_expand_end_cond (); + if_nesting_count--; + objc_exit_block (); + + /* Return to enclosing chain of @catch statements (if any). */ + while (TREE_VALUE (objc_catch_type)) + objc_catch_type = TREE_CHAIN (objc_catch_type); + objc_catch_type = TREE_PURPOSE (objc_catch_type); +} + +tree +objc_build_finally_prologue (void) +{ + /* { // begin FINALLY scope + if (!_rethrowException) { + objc_exception_try_exit(&_stackExceptionData); + } */ + + tree blk = objc_enter_block (); + + tree if_stmt = c_begin_if_stmt (); + if_nesting_count++; + + c_expand_start_cond ((*lang_hooks.truthvalue_conversion) + (build_unary_op + (TRUTH_NOT_EXPR, + TREE_VALUE (objc_rethrow_exception), 0)), + 0, if_stmt); + objc_enter_block (); + objc_build_try_exit_fragment (); + objc_exit_block (); + c_finish_then (); + c_expand_end_cond (); + if_nesting_count--; + + return blk; +} + +tree +objc_build_finally_epilogue (void) +{ + /* if (_rethrowException) { + objc_exception_throw(_rethrowException); + } + } // end FINALLY scope + } */ + + tree if_stmt = c_begin_if_stmt (); + if_nesting_count++; + + c_expand_start_cond + ((*lang_hooks.truthvalue_conversion) (TREE_VALUE (objc_rethrow_exception)), + 0, if_stmt); + objc_enter_block (); + objc_build_throw_stmt (TREE_VALUE (objc_rethrow_exception)); + objc_exit_block (); + c_finish_then (); + c_expand_end_cond (); + if_nesting_count--; + + objc_exit_block (); + objc_rethrow_exception = TREE_CHAIN (objc_rethrow_exception); + objc_stack_exception_data = TREE_CHAIN (objc_stack_exception_data); + + val_stack_pop (&exc_binding_stack); + return objc_exit_block (); +} + +tree +objc_build_try_catch_finally_stmt (int has_catch, int has_finally) +{ + /* NB: The operative assumption here is that TRY_FINALLY_EXPR will + deal with all exits from 'try_catch_blk' and route them through + 'finally_blk'. */ + tree outer_blk = objc_build_finally_epilogue (); + tree prec_stmt = TREE_CHAIN (TREE_CHAIN (COMPOUND_BODY (outer_blk))); + tree try_catch_blk = TREE_CHAIN (prec_stmt), try_catch_expr; + tree finally_blk = TREE_CHAIN (try_catch_blk), finally_expr; + tree succ_stmt = TREE_CHAIN (finally_blk); + tree try_finally_stmt, try_finally_expr; + + if (!flag_objc_exceptions) + fatal_error ("Use `-fobjc-exceptions' to enable Objective-C exception syntax"); + + /* It is an error to have a @try block without a @catch and/or @finally + (even though sensible code can be generated nonetheless). */ + + if (!has_catch && !has_finally) + error ("`@try' without `@catch' or `@finally'"); + + /* We shall now do something truly disgusting. We shall remove the + 'try_catch_blk' and 'finally_blk' from the 'outer_blk' statement + chain, and replace them with a TRY_FINALLY_EXPR statement! If + this doesn't work, we will have to learn (from Per/gcj) how to + construct the 'outer_blk' lazily. */ + + TREE_CHAIN (try_catch_blk) = TREE_CHAIN (finally_blk) = NULL_TREE; + try_catch_expr = build1 (STMT_EXPR, void_type_node, try_catch_blk); + TREE_SIDE_EFFECTS (try_catch_expr) = 1; + finally_expr = build1 (STMT_EXPR, void_type_node, finally_blk); + TREE_SIDE_EFFECTS (finally_expr) = 1; + try_finally_expr = build (TRY_FINALLY_EXPR, void_type_node, try_catch_expr, + finally_expr); + TREE_SIDE_EFFECTS (try_finally_expr) = 1; + try_finally_stmt = build_stmt (EXPR_STMT, try_finally_expr); + TREE_CHAIN (prec_stmt) = try_finally_stmt; + TREE_CHAIN (try_finally_stmt) = succ_stmt; + + return outer_blk; /* the whole enchilada */ +} + +void +objc_build_synchronized_prologue (tree sync_expr) +{ + /* { + id _eval_once = ; + @try { + objc_sync_enter( _eval_once ); */ + + tree func_params; + + if (!flag_objc_exceptions) + fatal_error ("Use `-fobjc-exceptions' to enable Objective-C exception syntax"); + + objc_enter_block (); + objc_eval_once + = tree_cons (NULL_TREE, + objc_declare_variable (RID_AUTO, + get_identifier (UTAG_EVALONCE_VAR), + id_type, + sync_expr), + objc_eval_once); + objc_build_try_prologue (); + objc_enter_block (); + func_params = tree_cons (NULL_TREE, + TREE_VALUE (objc_eval_once), + NULL_TREE); + + assemble_external (objc_sync_enter_decl); + c_expand_expr_stmt (build_function_call + (objc_sync_enter_decl, func_params)); +} + +tree +objc_build_synchronized_epilogue (void) +{ + /* } + @finally { + objc_sync_exit( _eval_once ); + } + } */ + + tree func_params; + + objc_exit_block (); + objc_build_try_epilogue (0); + objc_build_finally_prologue (); + func_params = tree_cons (NULL_TREE, TREE_VALUE (objc_eval_once), + NULL_TREE); + + assemble_external (objc_sync_exit_decl); + c_expand_expr_stmt (build_function_call (objc_sync_exit_decl, + func_params)); + objc_build_try_catch_finally_stmt (0, 1); + + return objc_exit_block (); +} + +/* Predefine the following data type: + + struct _objc_exception_data + { + int buf[_JBLEN]; + void *pointers[4]; + }; */ + +/* The following yuckiness should prevent users from having to #include + in their code... */ + +#ifdef TARGET_POWERPC +/* snarfed from /usr/include/ppc/setjmp.h */ +#define _JBLEN (26 + 36 + 129 + 1) +#else +/* snarfed from /usr/include/i386/{setjmp,signal}.h */ +#define _JBLEN 18 +#endif + +static void +build_objc_exception_stuff (void) +{ + tree field_decl, field_decl_chain, index, temp_type; + + /* Suppress outputting debug symbols, because + dbxout_init hasn't been called yet. */ + enum debug_info_type save_write_symbols = write_symbols; + const struct gcc_debug_hooks *save_hooks = debug_hooks; + + write_symbols = NO_DEBUG; + debug_hooks = &do_nothing_debug_hooks; + objc_exception_data_template + = start_struct (RECORD_TYPE, get_identifier (UTAG_EXCDATA)); + + /* int buf[_JBLEN]; */ + + index = build_index_type (build_int_2 (_JBLEN - 1, 0)); + field_decl = create_builtin_decl (FIELD_DECL, + build_array_type (integer_type_node, index), + "buf"); + field_decl_chain = field_decl; + + /* void *pointers[4]; */ + + index = build_index_type (build_int_2 (4 - 1, 0)); + field_decl = create_builtin_decl (FIELD_DECL, + build_array_type (ptr_type_node, index), + "pointers"); + chainon (field_decl_chain, field_decl); + + finish_struct (objc_exception_data_template, field_decl_chain, NULL_TREE); + + /* int _setjmp(...); */ + /* If the user includes , this shall be superseded by + 'int _setjmp(jmp_buf);' */ + temp_type = build_function_type (integer_type_node, NULL_TREE); + objc_setjmp_decl + = builtin_function (TAG_SETJMP, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + + /* id objc_exception_extract(struct _objc_exception_data *); */ + temp_type + = build_function_type (id_type, + tree_cons (NULL_TREE, + build_pointer_type (objc_exception_data_template), + void_list_node)); + objc_exception_extract_decl + = builtin_function (TAG_EXCEPTIONEXTRACT, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + /* void objc_exception_try_enter(struct _objc_exception_data *); */ + /* void objc_exception_try_exit(struct _objc_exception_data *); */ + temp_type + = build_function_type (void_type_node, + tree_cons (NULL_TREE, + build_pointer_type (objc_exception_data_template), + void_list_node)); + objc_exception_try_enter_decl + = builtin_function (TAG_EXCEPTIONTRYENTER, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + objc_exception_try_exit_decl + = builtin_function (TAG_EXCEPTIONTRYEXIT, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + /* void objc_exception_throw(id) __attribute__((noreturn)); */ + /* void objc_sync_enter(id); */ + /* void objc_sync_exit(id); */ + temp_type = build_function_type (void_type_node, + tree_cons (NULL_TREE, id_type, + void_list_node)); + objc_exception_throw_decl + = builtin_function (TAG_EXCEPTIONTHROW, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + DECL_ATTRIBUTES (objc_exception_throw_decl) + = tree_cons (get_identifier ("noreturn"), NULL_TREE, NULL_TREE); + objc_sync_enter_decl + = builtin_function (TAG_SYNCENTER, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + objc_sync_exit_decl + = builtin_function (TAG_SYNCEXIT, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + /* int objc_exception_match(id, id); */ + temp_type = build_function_type (integer_type_node, + tree_cons (NULL_TREE, id_type, + tree_cons (NULL_TREE, id_type, + void_list_node))); + objc_exception_match_decl + = builtin_function (TAG_EXCEPTIONMATCH, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + + write_symbols = save_write_symbols; + debug_hooks = save_hooks; +} + +/* struct { + struct objc_class *isa; + ... + }; */ + +static tree +build_private_template (tree class) +{ + tree ivar_context; + + if (CLASS_STATIC_TEMPLATE (class)) + { + uprivate_record = CLASS_STATIC_TEMPLATE (class); + ivar_context = TYPE_FIELDS (CLASS_STATIC_TEMPLATE (class)); + } + else + { + uprivate_record = start_struct (RECORD_TYPE, CLASS_NAME (class)); + ivar_context = get_class_ivars (class, 0); + + finish_struct (uprivate_record, ivar_context, NULL_TREE); + + CLASS_STATIC_TEMPLATE (class) = uprivate_record; + + /* mark this record as class template - for class type checking */ + TREE_STATIC_TEMPLATE (uprivate_record) = 1; + } + + instance_type + = groktypename (build_tree_list (build_tree_list (NULL_TREE, + uprivate_record), + build1 (INDIRECT_REF, NULL_TREE, + NULL_TREE))); + + return ivar_context; +} + +/* Begin code generation for protocols... */ + +/* struct objc_protocol { + char *protocol_name; + struct objc_protocol **protocol_list; + struct objc_method_desc *instance_methods; + struct objc_method_desc *class_methods; + }; */ + +static tree +build_protocol_template (void) +{ + tree decl_specs, field_decl, field_decl_chain; + tree template; + + template = start_struct (RECORD_TYPE, get_identifier (UTAG_PROTOCOL)); + + /* struct objc_class *isa; */ + + decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE, + get_identifier (UTAG_CLASS))); + field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("isa")); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); + field_decl_chain = field_decl; + + /* char *protocol_name; */ + + decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]); + field_decl + = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("protocol_name")); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); + chainon (field_decl_chain, field_decl); + + /* struct objc_protocol **protocol_list; */ + + decl_specs = build_tree_list (NULL_TREE, template); + field_decl + = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("protocol_list")); + field_decl = build1 (INDIRECT_REF, NULL_TREE, field_decl); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); + chainon (field_decl_chain, field_decl); + + /* struct objc_method_list *instance_methods; */ + + decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE, get_identifier (UTAG_METHOD_PROTOTYPE_LIST))); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("instance_methods")); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); /* struct objc_method_list *class_methods; */ @@ -2608,17 +3453,14 @@ build_protocol_template () get_identifier (UTAG_METHOD_PROTOTYPE_LIST))); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("class_methods")); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); return finish_struct (template, field_decl_chain, NULL_TREE); } static tree -build_descriptor_table_initializer (type, entries) - tree type; - tree entries; +build_descriptor_table_initializer (tree type, tree entries) { tree initlist = NULL_TREE; @@ -2651,15 +3493,13 @@ build_descriptor_table_initializer (type, entries) /* struct objc_method_prototype_list { int count; struct objc_method_prototype { - SEL name; - char *types; + SEL name; + char *types; } list[1]; }; */ static tree -build_method_prototype_list_template (list_type, size) - tree list_type; - int size; +build_method_prototype_list_template (tree list_type, int size) { tree objc_ivar_list_record; tree decl_specs, field_decl, field_decl_chain; @@ -2672,8 +3512,7 @@ build_method_prototype_list_template (list_type, size) decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_INT]); field_decl = get_identifier ("method_count"); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); field_decl_chain = field_decl; /* struct objc_method method_list[]; */ @@ -2681,8 +3520,7 @@ build_method_prototype_list_template (list_type, size) decl_specs = build_tree_list (NULL_TREE, list_type); field_decl = build_nt (ARRAY_REF, get_identifier ("method_list"), build_int_2 (size, 0)); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); finish_struct (objc_ivar_list_record, field_decl_chain, NULL_TREE); @@ -2691,7 +3529,7 @@ build_method_prototype_list_template (list_type, size) } static tree -build_method_prototype_template () +build_method_prototype_template (void) { tree proto_record; tree decl_specs, field_decl, field_decl_chain; @@ -2703,15 +3541,13 @@ build_method_prototype_template () decl_specs = tree_cons (NULL_TREE, xref_tag (RECORD_TYPE, get_identifier (TAG_SELECTOR)), NULL_TREE); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("_cmd")); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); field_decl_chain = field_decl; decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], NULL_TREE); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("method_types")); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); finish_struct (proto_record, field_decl_chain, NULL_TREE); @@ -2719,118 +3555,97 @@ build_method_prototype_template () return proto_record; } -/* True if last call to forwarding_offset yielded a register offset. */ -static int offset_is_register; +static tree +objc_method_parm_type (tree type) +{ + type = groktypename (TREE_TYPE (type)); + if (TREE_CODE (type) == TYPE_DECL) + type = TREE_TYPE (type); + return TYPE_MAIN_VARIANT (type); +} static int -forwarding_offset (parm) - tree parm; +objc_encoded_type_size (tree type) { - int offset_in_bytes; - - if (GET_CODE (DECL_INCOMING_RTL (parm)) == MEM) - { - rtx addr = XEXP (DECL_INCOMING_RTL (parm), 0); - - /* ??? Here we assume that the parm address is indexed - off the frame pointer or arg pointer. - If that is not true, we produce meaningless results, - but do not crash. */ - if (GET_CODE (addr) == PLUS - && GET_CODE (XEXP (addr, 1)) == CONST_INT) - offset_in_bytes = INTVAL (XEXP (addr, 1)); - else - offset_in_bytes = 0; + int sz = int_size_in_bytes (type); - offset_in_bytes += OBJC_FORWARDING_STACK_OFFSET; - offset_is_register = 0; - } - else if (GET_CODE (DECL_INCOMING_RTL (parm)) == REG) - { - int regno = REGNO (DECL_INCOMING_RTL (parm)); - offset_in_bytes = apply_args_register_offset (regno); - offset_is_register = 1; - } - else - return 0; - - /* This is the case where the parm is passed as an int or double - and it is converted to a char, short or float and stored back - in the parmlist. In this case, describe the parm - with the variable's declared type, and adjust the address - if the least significant bytes (which we are using) are not - the first ones. */ - if (BYTES_BIG_ENDIAN && TREE_TYPE (parm) != DECL_ARG_TYPE (parm)) - offset_in_bytes += (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parm))) - - GET_MODE_SIZE (GET_MODE (DECL_RTL (parm)))); - - return offset_in_bytes; + /* Make all integer and enum types at least as large + as an int. */ + if (sz > 0 && (TREE_CODE (type) == INTEGER_TYPE + || TREE_CODE (type) == BOOLEAN_TYPE + || TREE_CODE (type) == ENUMERAL_TYPE)) + sz = MAX (sz, int_size_in_bytes (integer_type_node)); + /* Treat arrays as pointers, since that's how they're + passed in. */ + else if (TREE_CODE (type) == ARRAY_TYPE) + sz = int_size_in_bytes (ptr_type_node); + return sz; } static tree -encode_method_prototype (method_decl, func_decl) - tree method_decl; - tree func_decl; +encode_method_prototype (tree method_decl) { tree parms; - int stack_size, i; - tree user_args; - HOST_WIDE_INT max_parm_end = 0; + int parm_offset, i; char buf[40]; tree result; /* ONEWAY and BYCOPY, for remote object are the only method qualifiers. */ encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (method_decl))); - /* C type. */ - encode_type (TREE_TYPE (TREE_TYPE (func_decl)), + /* Encode return type. */ + encode_type (objc_method_parm_type (method_decl), obstack_object_size (&util_obstack), OBJC_ENCODE_INLINE_DEFS); /* Stack size. */ - for (parms = DECL_ARGUMENTS (func_decl); parms; + /* The first two arguments (self and _cmd) are pointers; account for + their size. */ + i = int_size_in_bytes (ptr_type_node); + parm_offset = 2 * i; + for (parms = METHOD_SEL_ARGS (method_decl); parms; parms = TREE_CHAIN (parms)) { - HOST_WIDE_INT parm_end = (forwarding_offset (parms) - + int_size_in_bytes (TREE_TYPE (parms))); + tree type = objc_method_parm_type (parms); + int sz = objc_encoded_type_size (type); - if (!offset_is_register && max_parm_end < parm_end) - max_parm_end = parm_end; + /* If a type size is not known, bail out. */ + if (sz < 0) + { + error ("%Jtype '%D' does not have a known size", + type, type); + /* Pretend that the encoding succeeded; the compilation will + fail nevertheless. */ + goto finish_encoding; + } + parm_offset += sz; } - stack_size = max_parm_end - OBJC_FORWARDING_MIN_OFFSET; - - sprintf (buf, "%d", stack_size); + sprintf (buf, "%d@0:%d", parm_offset, i); obstack_grow (&util_obstack, buf, strlen (buf)); - user_args = METHOD_SEL_ARGS (method_decl); - /* Argument types. */ - for (parms = DECL_ARGUMENTS (func_decl), i = 0; parms; - parms = TREE_CHAIN (parms), i++) + parm_offset = 2 * i; + for (parms = METHOD_SEL_ARGS (method_decl); parms; + parms = TREE_CHAIN (parms)) { + tree type = objc_method_parm_type (parms); + /* Process argument qualifiers for user supplied arguments. */ - if (i > 1) - { - encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (user_args))); - user_args = TREE_CHAIN (user_args); - } + encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (parms))); /* Type. */ - encode_type (TREE_TYPE (parms), - obstack_object_size (&util_obstack), + encode_type (type, obstack_object_size (&util_obstack), OBJC_ENCODE_INLINE_DEFS); /* Compute offset. */ - sprintf (buf, "%d", forwarding_offset (parms)); + sprintf (buf, "%d", parm_offset); + parm_offset += objc_encoded_type_size (type); - /* Indicate register. */ - if (offset_is_register) - obstack_1grow (&util_obstack, '+'); - obstack_grow (&util_obstack, buf, strlen (buf)); } + finish_encoding: obstack_1grow (&util_obstack, '\0'); result = get_identifier (obstack_finish (&util_obstack)); obstack_free (&util_obstack, util_firstobj); @@ -2838,12 +3653,8 @@ encode_method_prototype (method_decl, func_decl) } static tree -generate_descriptor_table (type, name, size, list, proto) - tree type; - const char *name; - int size; - tree list; - tree proto; +generate_descriptor_table (tree type, const char *name, int size, tree list, + tree proto) { tree sc_spec, decl_specs, decl, initlist; @@ -2864,8 +3675,7 @@ generate_descriptor_table (type, name, size, list, proto) } static void -generate_method_descriptors (protocol) - tree protocol; +generate_method_descriptors (tree protocol) { tree initlist, chain, method_list_template; tree cast, variable_length_type; @@ -2888,7 +3698,7 @@ generate_method_descriptors (protocol) = build_method_prototype_list_template (objc_method_prototype_template, size); - initlist + initlist = build_descriptor_table_initializer (objc_method_prototype_template, chain); @@ -2923,104 +3733,8 @@ generate_method_descriptors (protocol) UOBJC_INSTANCE_METHODS_decl = 0; } -/* Generate a temporary FUNCTION_DECL node to be used in - hack_method_prototype below. */ - -static GTY(()) int build_tmp_function_decl_xxx; -static tree -build_tmp_function_decl () -{ - tree decl_specs, expr_decl, parms; - char buffer[80]; - - /* struct objc_object *objc_xxx (id, SEL, ...); */ - pushlevel (0); - decl_specs = build_tree_list (NULL_TREE, objc_object_reference); - push_parm_decl (build_tree_list - (build_tree_list (decl_specs, - build1 (INDIRECT_REF, 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), - NULL_TREE)); - parms = get_parm_info (0); - poplevel (0, 0, 0); - - decl_specs = build_tree_list (NULL_TREE, objc_object_reference); - sprintf (buffer, "__objc_tmp_%x", build_tmp_function_decl_xxx++); - expr_decl = build_nt (CALL_EXPR, get_identifier (buffer), parms, NULL_TREE); - expr_decl = build1 (INDIRECT_REF, NULL_TREE, expr_decl); - - return define_decl (expr_decl, decl_specs); -} - -/* Generate the prototypes for protocol methods. This is used to - generate method encodings for these. - - NST_METHODS is the method to generate a _DECL node for TMP_DECL is - a decl node to be used. This is also where the return value is - given. */ - -static void -hack_method_prototype (nst_methods, tmp_decl) - tree nst_methods; - tree tmp_decl; -{ - tree parms; - tree parm; - - /* Hack to avoid problem with static typing of self arg. */ - TREE_SET_CODE (nst_methods, CLASS_METHOD_DECL); - start_method_def (nst_methods); - TREE_SET_CODE (nst_methods, INSTANCE_METHOD_DECL); - - if (METHOD_ADD_ARGS (nst_methods) == objc_ellipsis_node) - parms = get_parm_info (0); /* we have a `, ...' */ - else - parms = get_parm_info (1); /* place a `void_at_end' */ - - poplevel (0, 0, 0); /* Must be called BEFORE start_function. */ - - /* 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; - - { - /* Code taken from start_function. */ - tree restype = TREE_TYPE (TREE_TYPE (tmp_decl)); - /* Promote the value to int before returning it. */ - if (TREE_CODE (restype) == INTEGER_TYPE - && TYPE_PRECISION (restype) < TYPE_PRECISION (integer_type_node)) - restype = integer_type_node; - DECL_RESULT (tmp_decl) = build_decl (RESULT_DECL, 0, restype); - } - - for (parm = DECL_ARGUMENTS (tmp_decl); parm; parm = TREE_CHAIN (parm)) - DECL_CONTEXT (parm) = tmp_decl; - - init_function_start (tmp_decl, "objc-act", 0); - - /* Typically called from expand_function_start for function definitions. */ - assign_parms (tmp_decl); - - /* install return type */ - TREE_TYPE (TREE_TYPE (tmp_decl)) = groktypename (TREE_TYPE (nst_methods)); - - current_function_decl = NULL; -} - static void -generate_protocol_references (plist) - tree plist; +generate_protocol_references (tree plist) { tree lproto; @@ -3052,10 +3766,10 @@ generate_protocol_references (plist) @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' + 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, @@ -3078,16 +3792,15 @@ generate_protocol_references (plist) 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 () +generate_protocols (void) { - tree p, tmp_decl, encoding; + tree p, encoding; tree sc_spec, decl_specs, decl; tree initlist, protocol_name_expr, refs_decl, refs_expr; tree cast_type2; - tmp_decl = build_tmp_function_decl (); - if (! objc_protocol_template) objc_protocol_template = build_protocol_template (); @@ -3112,8 +3825,7 @@ generate_protocols () { if (! METHOD_ENCODING (nst_methods)) { - hack_method_prototype (nst_methods, tmp_decl); - encoding = encode_method_prototype (nst_methods, tmp_decl); + encoding = encode_method_prototype (nst_methods); METHOD_ENCODING (nst_methods) = encoding; } nst_methods = TREE_CHAIN (nst_methods); @@ -3123,8 +3835,7 @@ generate_protocols () { if (! METHOD_ENCODING (cls_methods)) { - hack_method_prototype (cls_methods, tmp_decl); - encoding = encode_method_prototype (cls_methods, tmp_decl); + encoding = encode_method_prototype (cls_methods); METHOD_ENCODING (cls_methods) = encoding; } @@ -3180,13 +3891,9 @@ generate_protocols () } static tree -build_protocol_initializer (type, protocol_name, protocol_list, - instance_methods, class_methods) - tree type; - tree protocol_name; - tree protocol_list; - tree instance_methods; - tree class_methods; +build_protocol_initializer (tree type, tree protocol_name, + tree protocol_list, tree instance_methods, + tree class_methods) { tree initlist = NULL_TREE, expr; tree cast_type; @@ -3235,7 +3942,7 @@ build_protocol_initializer (type, protocol_name, protocol_list, }; */ static void -build_category_template () +build_category_template (void) { tree decl_specs, field_decl, field_decl_chain; @@ -3246,16 +3953,14 @@ build_category_template () decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("category_name")); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); field_decl_chain = field_decl; /* char *class_name; */ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("class_name")); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); /* struct objc_method_list *instance_methods; */ @@ -3265,8 +3970,7 @@ build_category_template () get_identifier (UTAG_METHOD_LIST))); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("instance_methods")); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); /* struct objc_method_list *class_methods; */ @@ -3276,8 +3980,7 @@ build_category_template () get_identifier (UTAG_METHOD_LIST))); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("class_methods")); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); /* struct objc_protocol **protocol_list; */ @@ -3288,8 +3991,7 @@ build_category_template () field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("protocol_list")); field_decl = build1 (INDIRECT_REF, NULL_TREE, field_decl); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); finish_struct (objc_category_template, field_decl_chain, NULL_TREE); @@ -3301,28 +4003,26 @@ build_category_template () }; */ static void -build_selector_template () +build_selector_template (void) { tree decl_specs, field_decl, field_decl_chain; - objc_selector_template + objc_selector_template = start_struct (RECORD_TYPE, get_identifier (UTAG_SELECTOR)); /* void *sel_id; */ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_VOID]); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("sel_id")); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); field_decl_chain = field_decl; /* char *sel_type; */ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("sel_type")); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); finish_struct (objc_selector_template, field_decl_chain, NULL_TREE); @@ -3345,11 +4045,18 @@ build_selector_template () struct objc_class *sibling_class; } struct objc_protocol_list *protocols; + if (flag_next_runtime) + void *sel_id; void *gc_object_type; }; */ +/* NB: The 'sel_id' and 'gc_object_type' fields are not being used by + the NeXT/Apple runtime; still, the compiler must generate them to + maintain backward binary compatibility (and to allow for future + expansion). */ + static void -build_class_template () +build_class_template (void) { tree decl_specs, field_decl, field_decl_chain; @@ -3360,8 +4067,7 @@ build_class_template () decl_specs = build_tree_list (NULL_TREE, objc_class_template); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("isa")); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); field_decl_chain = field_decl; /* struct objc_class *super_class; */ @@ -3369,40 +4075,35 @@ build_class_template () decl_specs = build_tree_list (NULL_TREE, objc_class_template); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("super_class")); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); /* char *name; */ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("name")); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); /* long version; */ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_LONG]); field_decl = get_identifier ("version"); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); /* long info; */ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_LONG]); field_decl = get_identifier ("info"); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); /* long instance_size; */ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_LONG]); field_decl = get_identifier ("instance_size"); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); /* struct objc_ivar_list *ivars; */ @@ -3411,8 +4112,7 @@ build_class_template () xref_tag (RECORD_TYPE, get_identifier (UTAG_IVAR_LIST))); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("ivars")); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); /* struct objc_method_list *methods; */ @@ -3421,8 +4121,7 @@ build_class_template () xref_tag (RECORD_TYPE, get_identifier (UTAG_METHOD_LIST))); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("methods")); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); if (flag_next_runtime) @@ -3433,8 +4132,7 @@ build_class_template () xref_tag (RECORD_TYPE, get_identifier ("objc_cache"))); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("cache")); - field_decl = grokfield (input_filename, input_line, field_decl, - decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); } else @@ -3445,8 +4143,7 @@ build_class_template () xref_tag (RECORD_TYPE, get_identifier ("sarray"))); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("dtable")); - field_decl = grokfield (input_filename, input_line, field_decl, - decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); /* struct objc_class *subclass_list; */ @@ -3454,8 +4151,7 @@ build_class_template () decl_specs = build_tree_list (NULL_TREE, objc_class_template); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("subclass_list")); - field_decl = grokfield (input_filename, input_line, field_decl, - decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); /* struct objc_class *sibling_class; */ @@ -3463,38 +4159,38 @@ build_class_template () decl_specs = build_tree_list (NULL_TREE, objc_class_template); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("sibling_class")); - field_decl = grokfield (input_filename, input_line, field_decl, - decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); } /* struct objc_protocol **protocol_list; */ - decl_specs = build_tree_list (NULL_TREE, + decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE, get_identifier (UTAG_PROTOCOL))); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("protocol_list")); field_decl = build1 (INDIRECT_REF, NULL_TREE, field_decl); - field_decl = grokfield (input_filename, input_line, field_decl, - decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); - /* void *sel_id; */ + if (flag_next_runtime) + { + /* void *sel_id; */ - decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_VOID]); - field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("sel_id")); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); - chainon (field_decl_chain, field_decl); + decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_VOID]); + field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("sel_id")); + field_decl + = grokfield (field_decl, decl_specs, NULL_TREE); + chainon (field_decl_chain, field_decl); + } /* void *gc_object_type; */ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_VOID]); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("gc_object_type")); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); finish_struct (objc_class_template, field_decl_chain, NULL_TREE); @@ -3503,28 +4199,17 @@ build_class_template () /* Generate appropriate forward declarations for an implementation. */ static void -synth_forward_declarations () +synth_forward_declarations (void) { - tree sc_spec, decl_specs, an_id; - - /* extern struct objc_class _OBJC_CLASS_; */ - - 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); - UOBJC_CLASS_decl = define_decl (an_id, decl_specs); - TREE_USED (UOBJC_CLASS_decl) = 1; - DECL_ARTIFICIAL (UOBJC_CLASS_decl) = 1; - - /* extern struct objc_class _OBJC_METACLASS_; */ + tree an_id; - an_id = synth_id_with_class_suffix ("_OBJC_METACLASS", - objc_implementation_context); + /* static struct objc_class _OBJC_CLASS_; */ + UOBJC_CLASS_decl = build_metadata_decl ("_OBJC_CLASS", + objc_class_template); - UOBJC_METACLASS_decl = define_decl (an_id, decl_specs); - TREE_USED (UOBJC_METACLASS_decl) = 1; - DECL_ARTIFICIAL(UOBJC_METACLASS_decl) = 1; + /* static struct objc_class _OBJC_METACLASS_; */ + UOBJC_METACLASS_decl = build_metadata_decl ("_OBJC_METACLASS", + objc_class_template); /* Pre-build the following entities - for speed/convenience. */ @@ -3534,24 +4219,15 @@ synth_forward_declarations () } static void -error_with_ivar (message, decl, rawdecl) - const char *message; - tree decl; - tree rawdecl; +error_with_ivar (const char *message, tree decl, tree rawdecl) { - diagnostic_count_diagnostic (global_dc, DK_ERROR); - - diagnostic_report_current_function (global_dc); - - error ("%H%s `%s'", &DECL_SOURCE_LOCATION (decl), + error ("%J%s `%s'", decl, message, gen_declaration (rawdecl, errbuf)); } static void -check_ivars (inter, imp) - tree inter; - tree imp; +check_ivars (tree inter, tree imp) { tree intdecls = CLASS_IVARS (inter); tree impdecls = CLASS_IVARS (imp); @@ -3562,6 +4238,10 @@ check_ivars (inter, imp) { tree t1, t2; +#ifdef OBJCPLUS + if (intdecls && TREE_CODE (intdecls) == TYPE_DECL) + intdecls = TREE_CHAIN (intdecls); +#endif if (intdecls == 0 && impdecls == 0) break; if (intdecls == 0 || impdecls == 0) @@ -3572,7 +4252,9 @@ check_ivars (inter, imp) t1 = TREE_TYPE (intdecls); t2 = TREE_TYPE (impdecls); - if (!comptypes (t1, t2)) + if (!comptypes (t1, t2, false) + || !tree_int_cst_equal (TREE_VALUE (TREE_VALUE (rawintdecls)), + TREE_VALUE (TREE_VALUE (rawimpdecls)))) { if (DECL_NAME (intdecls) == DECL_NAME (impdecls)) { @@ -3603,44 +4285,53 @@ check_ivars (inter, imp) } } -/* Set super_type to the data type node for struct objc_super *, - first defining struct objc_super itself. +/* Set 'objc_super_template' to the data type node for 'struct _objc_super'. This needs to be done just once per compilation. */ -static tree -build_super_template () +static void +build_super_template (void) { - tree record, decl_specs, field_decl, field_decl_chain; + tree decl_specs, field_decl, field_decl_chain; - record = start_struct (RECORD_TYPE, get_identifier (UTAG_SUPER)); + /* Suppress outputting debug symbols, because + dbxout_init hasn't been called yet. */ + enum debug_info_type save_write_symbols = write_symbols; + const struct gcc_debug_hooks *save_hooks = debug_hooks; + + write_symbols = NO_DEBUG; + debug_hooks = &do_nothing_debug_hooks; + + objc_super_template = start_struct (RECORD_TYPE, get_identifier (UTAG_SUPER)); /* struct objc_object *self; */ decl_specs = build_tree_list (NULL_TREE, objc_object_reference); field_decl = get_identifier ("self"); field_decl = build1 (INDIRECT_REF, NULL_TREE, field_decl); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); field_decl_chain = field_decl; +#ifdef OBJCPLUS + /* struct objc_class *super_class; */ +#else /* struct objc_class *class; */ +#endif decl_specs = get_identifier (UTAG_CLASS); decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE, decl_specs)); +#ifdef OBJCPLUS + field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("super_class")); +#else field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("class")); +#endif - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); - finish_struct (record, field_decl_chain, NULL_TREE); + finish_struct (objc_super_template, field_decl_chain, NULL_TREE); - /* `struct objc_super *' */ - super_type = groktypename (build_tree_list (build_tree_list (NULL_TREE, - record), - build1 (INDIRECT_REF, - NULL_TREE, NULL_TREE))); - return record; + write_symbols = save_write_symbols; + debug_hooks = save_hooks; } /* struct objc_ivar { @@ -3650,7 +4341,7 @@ build_super_template () }; */ static tree -build_ivar_template () +build_ivar_template (void) { tree objc_ivar_id, objc_ivar_record; tree decl_specs, field_decl, field_decl_chain; @@ -3663,8 +4354,7 @@ build_ivar_template () decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("ivar_name")); - field_decl = grokfield (input_filename, input_line, field_decl, - decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); field_decl_chain = field_decl; /* char *ivar_type; */ @@ -3672,8 +4362,7 @@ build_ivar_template () decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("ivar_type")); - field_decl = grokfield (input_filename, input_line, field_decl, - decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); /* int ivar_offset; */ @@ -3681,8 +4370,7 @@ build_ivar_template () decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_INT]); field_decl = get_identifier ("ivar_offset"); - field_decl = grokfield (input_filename, input_line, field_decl, - decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); finish_struct (objc_ivar_record, field_decl_chain, NULL_TREE); @@ -3696,9 +4384,7 @@ build_ivar_template () }; */ static tree -build_ivar_list_template (list_type, size) - tree list_type; - int size; +build_ivar_list_template (tree list_type, int size) { tree objc_ivar_list_record; tree decl_specs, field_decl, field_decl_chain; @@ -3710,8 +4396,7 @@ build_ivar_list_template (list_type, size) decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_INT]); field_decl = get_identifier ("ivar_count"); - field_decl = grokfield (input_filename, input_line, field_decl, - decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); field_decl_chain = field_decl; /* struct objc_ivar ivar_list[]; */ @@ -3720,8 +4405,7 @@ build_ivar_list_template (list_type, size) field_decl = build_nt (ARRAY_REF, get_identifier ("ivar_list"), build_int_2 (size, 0)); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); finish_struct (objc_ivar_list_record, field_decl_chain, NULL_TREE); @@ -3736,9 +4420,7 @@ build_ivar_list_template (list_type, size) }; */ static tree -build_method_list_template (list_type, size) - tree list_type; - int size; +build_method_list_template (tree list_type, int size) { tree objc_ivar_list_record; tree decl_specs, field_decl, field_decl_chain; @@ -3749,13 +4431,12 @@ build_method_list_template (list_type, size) decl_specs = build_tree_list - (NULL_TREE, + (NULL_TREE, xref_tag (RECORD_TYPE, get_identifier (UTAG_METHOD_PROTOTYPE_LIST))); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("method_next")); - field_decl = grokfield (input_filename, input_line, field_decl, - decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); field_decl_chain = field_decl; /* int method_count; */ @@ -3763,8 +4444,7 @@ build_method_list_template (list_type, size) decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_INT]); field_decl = get_identifier ("method_count"); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); /* struct objc_method method_list[]; */ @@ -3773,8 +4453,7 @@ build_method_list_template (list_type, size) field_decl = build_nt (ARRAY_REF, get_identifier ("method_list"), build_int_2 (size, 0)); - field_decl = grokfield (input_filename, input_line, - field_decl, decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); finish_struct (objc_ivar_list_record, field_decl_chain, NULL_TREE); @@ -3783,9 +4462,7 @@ build_method_list_template (list_type, size) } static tree -build_ivar_list_initializer (type, field_decl) - tree type; - tree field_decl; +build_ivar_list_initializer (tree type, tree field_decl) { tree initlist = NULL_TREE; @@ -3820,11 +4497,12 @@ build_ivar_list_initializer (type, field_decl) /* Set offset. */ ivar = tree_cons (NULL_TREE, byte_position (field_decl), ivar); - initlist = tree_cons (NULL_TREE, + initlist = tree_cons (NULL_TREE, objc_build_constructor (type, nreverse (ivar)), initlist); - - field_decl = TREE_CHAIN (field_decl); + do + field_decl = TREE_CHAIN (field_decl); + while (field_decl && TREE_CODE (field_decl) != FIELD_DECL); } while (field_decl); @@ -3833,11 +4511,7 @@ build_ivar_list_initializer (type, field_decl) } static tree -generate_ivars_list (type, name, size, list) - tree type; - const char *name; - int size; - tree list; +generate_ivars_list (tree type, const char *name, int size, tree list) { tree sc_spec, decl_specs, decl, initlist; @@ -3857,8 +4531,21 @@ generate_ivars_list (type, name, size, list) return decl; } +/* Count only the fields occurring in T. */ +static int +ivar_list_length (tree t) +{ + int count = 0; + + for (; t; t = TREE_CHAIN (t)) + if (TREE_CODE (t) == FIELD_DECL) + ++count; + + return count; +} + static void -generate_ivar_lists () +generate_ivar_lists (void) { tree initlist, ivar_list_template, chain; tree cast, variable_length_type; @@ -3882,7 +4569,7 @@ generate_ivar_lists () if (CLASS_SUPER_NAME (implementation_template) == NULL_TREE && (chain = TYPE_FIELDS (objc_class_template))) { - size = list_length (chain); + size = ivar_list_length (chain); ivar_list_template = build_ivar_list_template (objc_ivar_template, size); initlist = build_ivar_list_initializer (objc_ivar_template, chain); @@ -3898,7 +4585,7 @@ generate_ivar_lists () chain = CLASS_IVARS (implementation_template); if (chain) { - size = list_length (chain); + size = ivar_list_length (chain); ivar_list_template = build_ivar_list_template (objc_ivar_template, size); initlist = build_ivar_list_initializer (objc_ivar_template, chain); @@ -3914,9 +4601,7 @@ generate_ivar_lists () } static tree -build_dispatch_table_initializer (type, entries) - tree type; - tree entries; +build_dispatch_table_initializer (tree type, tree entries) { tree initlist = NULL_TREE; @@ -3931,19 +4616,19 @@ build_dispatch_table_initializer (type, entries) /* Generate the method encoding if we don't have one already. */ if (! METHOD_ENCODING (entries)) METHOD_ENCODING (entries) = - encode_method_def (METHOD_DEFINITION (entries)); + encode_method_prototype (entries); elemlist = tree_cons (NULL_TREE, add_objc_string (METHOD_ENCODING (entries), meth_var_types), elemlist); - elemlist = tree_cons (NULL_TREE, + elemlist = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, METHOD_DEFINITION (entries), 1), elemlist); - initlist = tree_cons (NULL_TREE, + initlist = tree_cons (NULL_TREE, objc_build_constructor (type, nreverse (elemlist)), initlist); @@ -3959,12 +4644,12 @@ build_dispatch_table_initializer (type, entries) inane warnings, the definition of the dispatch table entries were changed from: - struct objc_method { SEL _cmd; ...; id (*_imp)(); }; + struct objc_method { SEL _cmd; ...; id (*_imp)(); }; to: - struct objc_method { SEL _cmd; ...; void *_imp; }; */ + struct objc_method { SEL _cmd; ...; void *_imp; }; */ static tree -build_method_template () +build_method_template (void) { tree _SLT_record; tree decl_specs, field_decl, field_decl_chain; @@ -3978,23 +4663,20 @@ build_method_template () NULL_TREE); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("_cmd")); - field_decl = grokfield (input_filename, input_line, field_decl, - decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); field_decl_chain = field_decl; decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], NULL_TREE); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("method_types")); - field_decl = grokfield (input_filename, input_line, field_decl, - decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); /* void *_imp; */ decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_VOID], NULL_TREE); field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("_imp")); - field_decl = grokfield (input_filename, input_line, field_decl, - decl_specs, NULL_TREE); + field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); finish_struct (_SLT_record, field_decl_chain, NULL_TREE); @@ -4004,11 +4686,7 @@ build_method_template () static tree -generate_dispatch_table (type, name, size, list) - tree type; - const char *name; - int size; - tree list; +generate_dispatch_table (tree type, const char *name, int size, tree list) { tree sc_spec, decl_specs, decl, initlist; @@ -4030,7 +4708,7 @@ generate_dispatch_table (type, name, size, list) } static void -mark_referenced_methods () +mark_referenced_methods (void) { struct imp_entry *impent; tree chain; @@ -4040,20 +4718,21 @@ mark_referenced_methods () chain = CLASS_CLS_METHODS (impent->imp_context); while (chain) { - cgraph_mark_needed_node (cgraph_node (METHOD_DEFINITION (chain)), 1); + cgraph_mark_needed_node (cgraph_node (METHOD_DEFINITION (chain))); chain = TREE_CHAIN (chain); } + chain = CLASS_NST_METHODS (impent->imp_context); while (chain) { - cgraph_mark_needed_node (cgraph_node (METHOD_DEFINITION (chain)), 1); + cgraph_mark_needed_node (cgraph_node (METHOD_DEFINITION (chain))); chain = TREE_CHAIN (chain); } } } static void -generate_dispatch_tables () +generate_dispatch_tables (void) { tree initlist, chain, method_list_template; tree cast, variable_length_type; @@ -4121,8 +4800,7 @@ generate_dispatch_tables () } static tree -generate_protocol_list (i_or_p) - tree i_or_p; +generate_protocol_list (tree i_or_p) { tree initlist, decl_specs, sc_spec; tree refs_decl, expr_decl, lproto, e, plist; @@ -4208,14 +4886,9 @@ generate_protocol_list (i_or_p) } static tree -build_category_initializer (type, cat_name, class_name, - instance_methods, class_methods, protocol_list) - tree type; - tree cat_name; - tree class_name; - tree instance_methods; - tree class_methods; - tree protocol_list; +build_category_initializer (tree type, tree cat_name, tree class_name, + tree instance_methods, tree class_methods, + tree protocol_list) { tree initlist = NULL_TREE, expr; @@ -4275,21 +4948,16 @@ build_category_initializer (type, cat_name, class_name, struct objc_class *sibling_class; } struct objc_protocol_list *protocols; + if (flag_next_runtime) + void *sel_id; void *gc_object_type; }; */ static tree -build_shared_structure_initializer (type, isa, super, name, size, status, - dispatch_table, ivar_list, protocol_list) - tree type; - tree isa; - tree super; - tree name; - tree size; - int status; - tree dispatch_table; - tree ivar_list; - tree protocol_list; +build_shared_structure_initializer (tree type, tree isa, tree super, + tree name, tree size, int status, + tree dispatch_table, tree ivar_list, + tree protocol_list) { tree initlist = NULL_TREE, expr; @@ -4363,17 +5031,32 @@ build_shared_structure_initializer (type, isa, super, name, size, status, initlist = tree_cons (NULL_TREE, expr, initlist); } + if (flag_next_runtime) + /* sel_id = NULL */ + initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist); + /* gc_object_type = NULL */ initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist); return objc_build_constructor (type, nreverse (initlist)); } +/* Retrieve category interface CAT_NAME (if any) associated with CLASS. */ + +static inline tree +lookup_category (tree class, tree cat_name) +{ + tree category = CLASS_CATEGORY_LIST (class); + + while (category && CLASS_SUPER_NAME (category) != cat_name) + category = CLASS_CATEGORY_LIST (category); + return category; +} + /* static struct objc_category _OBJC_CATEGORY_ = { ... }; */ static void -generate_category (cat) - tree cat; +generate_category (tree cat) { tree sc_spec, decl_specs, decl; tree initlist, cat_name_expr, class_name_expr; @@ -4384,15 +5067,8 @@ generate_category (cat) class_name_expr = add_objc_string (CLASS_NAME (cat), class_names); - category = CLASS_CATEGORY_LIST (implementation_template); - - /* find the category interface from the class it is associated with */ - while (category) - { - if (CLASS_SUPER_NAME (cat) == CLASS_SUPER_NAME (category)) - break; - category = CLASS_CATEGORY_LIST (category); - } + category = lookup_category (implementation_template, + CLASS_SUPER_NAME (cat)); if (category && CLASS_PROTOCOL_LIST (category)) { @@ -4415,7 +5091,6 @@ generate_category (cat) UOBJC_CLASS_METHODS_decl, protocol_decl); - TREE_USED (decl) = 1; finish_decl (decl, initlist, NULL_TREE); } @@ -4423,7 +5098,7 @@ generate_category (cat) static struct objc_class _OBJC_CLASS_Foo={ ... }; */ static void -generate_shared_structures () +generate_shared_structures (void) { tree sc_spec, decl_specs, decl; tree name_expr, super_expr, root_expr; @@ -4526,9 +5201,7 @@ generate_shared_structures () } static tree -synth_id_with_class_suffix (preamble, ctxt) - const char *preamble; - tree ctxt; +synth_id_with_class_suffix (const char *preamble, tree ctxt) { char *string; if (TREE_CODE (ctxt) == CLASS_IMPLEMENTATION_TYPE @@ -4563,13 +5236,12 @@ synth_id_with_class_suffix (preamble, ctxt) } else abort (); - + return get_identifier (string); } static int -is_objc_type_qualifier (node) - tree node; +is_objc_type_qualifier (tree node) { return (TREE_CODE (node) == IDENTIFIER_NODE && (node == ridpointers [(int) RID_CONST] @@ -4586,8 +5258,7 @@ is_objc_type_qualifier (node) type of id (otherwise grokdeclarator will default to int). */ static tree -adjust_type_for_id_default (type) - tree type; +adjust_type_for_id_default (tree type) { tree declspecs, chain; @@ -4603,7 +5274,7 @@ adjust_type_for_id_default (type) chain = TREE_CHAIN (chain)) { if (TYPED_OBJECT (TREE_VALUE (chain)) - && !(TREE_VALUE (type) + && !(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))) @@ -4616,28 +5287,25 @@ adjust_type_for_id_default (type) } /* Usage: - keyworddecl: - selector ':' '(' typename ')' identifier - + keyworddecl: + selector ':' '(' typename ')' identifier + Purpose: - Transform an Objective-C keyword argument into - the C equivalent parameter declarator. - + Transform an Objective-C keyword argument into + the C equivalent parameter declarator. + In: key_name, an "identifier_node" (optional). - arg_type, a "tree_list" (optional). - arg_name, an "identifier_node". - + arg_type, a "tree_list" (optional). + arg_name, an "identifier_node". + Note: It would be really nice to strongly type the preceding - arguments in the function prototype; however, then I - could not use the "accessor" macros defined in "tree.h". - + arguments in the function prototype; however, then I + could not use the "accessor" macros defined in "tree.h". + Out: an instance of "keyword_decl". */ tree -build_keyword_decl (key_name, arg_type, arg_name) - tree key_name; - tree arg_type; - tree arg_name; +build_keyword_decl (tree key_name, tree arg_type, tree arg_name) { tree keyword_decl; @@ -4656,8 +5324,7 @@ build_keyword_decl (key_name, arg_type, arg_name) /* Given a chain of keyword_decl's, synthesize the full keyword selector. */ static tree -build_keyword_selector (selector) - tree selector; +build_keyword_selector (tree selector) { int len = 0; tree key_chain, key_name; @@ -4689,7 +5356,13 @@ build_keyword_selector (selector) if (TREE_CODE (selector) == KEYWORD_DECL) key_name = KEYWORD_KEY_NAME (key_chain); else if (TREE_CODE (selector) == TREE_LIST) - key_name = TREE_PURPOSE (key_chain); + { + key_name = TREE_PURPOSE (key_chain); + /* The keyword decl chain will later be used as a function argument + chain. Unhook the selector itself so as to not confuse other + parts of the compiler. */ + TREE_PURPOSE (key_chain) = NULL_TREE; + } else abort (); @@ -4704,11 +5377,8 @@ build_keyword_selector (selector) /* Used for declarations and definitions. */ tree -build_method_decl (code, ret_type, selector, add_args) - enum tree_code code; - tree ret_type; - tree selector; - tree add_args; +build_method_decl (enum tree_code code, tree ret_type, tree selector, + tree add_args) { tree method_decl; @@ -4739,18 +5409,16 @@ build_method_decl (code, ret_type, selector, add_args) #define METHOD_DEF 0 #define METHOD_REF 1 -/* Used by `build_objc_method_call' and `comp_method_types'. Return +/* Used by `build_objc_method_call' and `comp_proto_with_proto'. 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 - the method call are done together. */ + the method call are done together. If METH is null, user-defined + arguments (i.e., beyond self and _cmd) shall be represented by `...'. */ static tree -get_arg_type_list (meth, context, superflag) - tree meth; - int context; - int superflag; +get_arg_type_list (tree meth, int context, int superflag) { tree arglist, akey; @@ -4765,6 +5433,11 @@ get_arg_type_list (meth, context, superflag) /* Selector type - will eventually change to `int'. */ chainon (arglist, build_tree_list (NULL_TREE, selector_type)); + /* No actual method prototype given -- assume that remaining arguments + are `...'. */ + if (!meth) + return arglist; + /* Build a list of argument types. */ for (akey = METHOD_SEL_ARGS (meth); akey; akey = TREE_CHAIN (akey)) { @@ -4774,7 +5447,7 @@ get_arg_type_list (meth, context, superflag) if (METHOD_ADD_ARGS (meth) == objc_ellipsis_node) /* We have a `, ...' immediately following the selector, - finalize the arglist...simulate get_parm_info (0). */ + finalize the arglist...simulate get_parm_info (true). */ ; else if (METHOD_ADD_ARGS (meth)) { @@ -4783,15 +5456,14 @@ get_arg_type_list (meth, context, superflag) chainon (arglist, add_arg_list); } else - /* finalize the arglist...simulate get_parm_info (1) */ - chainon (arglist, build_tree_list (NULL_TREE, void_type_node)); + /* finalize the arglist...simulate get_parm_info (false) */ + chainon (arglist, void_list_node); return arglist; } static tree -check_duplicates (hsh) - hash hsh; +check_duplicates (hash hsh, int methods, int is_class) { tree meth = NULL_TREE; @@ -4801,16 +5473,26 @@ check_duplicates (hsh) if (hsh->list) { - /* We have two methods with the same name and different types. */ + /* We have two or more methods with the same name but + different types. */ attr loop; - char type = (TREE_CODE (meth) == INSTANCE_METHOD_DECL) ? '-' : '+'; - warning ("multiple declarations for method `%s'", + warning ("multiple %s named `%c%s' found", + methods ? "methods" : "selectors", + (is_class ? '+' : '-'), IDENTIFIER_POINTER (METHOD_SEL_NAME (meth))); - warn_with_method ("using", type, meth); + warn_with_method (methods ? "using" : "found", + ((TREE_CODE (meth) == INSTANCE_METHOD_DECL) + ? '-' + : '+'), + meth); for (loop = hsh->list; loop; loop = loop->next) - warn_with_method ("also found", type, loop->value); + warn_with_method ("also found", + ((TREE_CODE (loop->value) == INSTANCE_METHOD_DECL) + ? '-' + : '+'), + loop->value); } } return meth; @@ -4822,52 +5504,53 @@ check_duplicates (hsh) used. */ static tree -receiver_is_class_object (receiver) - tree receiver; +receiver_is_class_object (tree receiver, int self, int super) { tree chain, exp, arg; - /* The receiver is 'self' in the context of a class method. */ + /* The receiver is 'self' or 'super' 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); - } - + && TREE_CODE (objc_method_context) == CLASS_METHOD_DECL + && (self || super)) + return (super + ? CLASS_SUPER_NAME (implementation_template) + : CLASS_NAME (implementation_template)); + if (flag_next_runtime) { /* 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. */ + && TREE_TYPE (TREE_TYPE (receiver)) == TREE_TYPE (objc_class_type)) + /* Look up the identifier. */ for (chain = cls_ref_chain; chain; chain = TREE_CHAIN (chain)) if (TREE_PURPOSE (chain) == receiver) - return TREE_VALUE (chain); - } - else - { - /* 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 (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! */ - && (arg = TREE_OPERAND (receiver, 1)) - && TREE_CODE (arg) == TREE_LIST - && (arg = TREE_VALUE (arg))) - { - STRIP_NOPS (arg); - if (TREE_CODE (arg) == ADDR_EXPR - && (arg = TREE_OPERAND (arg, 0)) - && TREE_CODE (arg) == STRING_CST) - /* Finally, we have the class name. */ - return get_identifier (TREE_STRING_POINTER (arg)); - } + return TREE_VALUE (chain); + } + + /* 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 (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 + /* For some reason, we sometimes wind up with multiple FUNCTION_DECL + prototypes for objc_get_class(). Thankfully, they seem to share the + same function type. */ + && TREE_TYPE (exp) == TREE_TYPE (objc_get_class_decl) + && !strcmp (IDENTIFIER_POINTER (DECL_NAME (exp)), TAG_GETCLASS) + /* We have a call to objc_get_class/objc_getClass! */ + && (arg = TREE_OPERAND (receiver, 1)) + && TREE_CODE (arg) == TREE_LIST + && (arg = TREE_VALUE (arg))) + { + STRIP_NOPS (arg); + if (TREE_CODE (arg) == ADDR_EXPR + && (arg = TREE_OPERAND (arg, 0)) + && TREE_CODE (arg) == STRING_CST) + /* Finally, we have the class name. */ + return get_identifier (TREE_STRING_POINTER (arg)); } return 0; } @@ -4879,7 +5562,7 @@ receiver_is_class_object (receiver) static tree current_objc_message_selector = 0; tree -objc_message_selector () +objc_message_selector (void) { return current_objc_message_selector; } @@ -4892,8 +5575,7 @@ objc_message_selector () (*((*)())_msgSuper)(receiver, selTransTbl[n], ...); */ tree -build_message_expr (mess) - tree mess; +build_message_expr (tree mess) { tree receiver = TREE_PURPOSE (mess); tree sel_name; @@ -4936,223 +5618,195 @@ build_message_expr (mess) method_params = args; } +#ifdef OBJCPLUS + if (processing_template_decl) + /* Must wait until template instantiation time. */ + return build_min_nt (MESSAGE_SEND_EXPR, receiver, sel_name, + method_params); +#endif + return finish_message_expr (receiver, sel_name, method_params); } +/* Look up method SEL_NAME that would be suitable for receiver + of type 'id' (if IS_CLASS is zero) or 'Class' (if IS_CLASS is + nonzero), and report on any duplicates. */ + +static tree +lookup_method_in_hash_lists (tree sel_name, int is_class) +{ + hash method_prototype = NULL; + + if (!is_class) + method_prototype = hash_lookup (nst_method_hash_list, + sel_name); + + if (!method_prototype) + { + method_prototype = hash_lookup (cls_method_hash_list, + sel_name); + is_class = 1; + } + + return check_duplicates (method_prototype, 1, is_class); +} + /* 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)) +finish_message_expr (tree receiver, tree sel_name, tree method_params) +{ + tree method_prototype = NULL_TREE, rprotos = NULL_TREE, rtype; + tree selector, retval, is_class; + int self, super, have_cast; + + /* Extract the receiver of the message, as well as its type + (where the latter may take the form of a cast or be inferred + from the implementation context). */ + rtype = receiver; + while (TREE_CODE (rtype) == COMPOUND_EXPR + || TREE_CODE (rtype) == MODIFY_EXPR + || TREE_CODE (rtype) == NOP_EXPR + || TREE_CODE (rtype) == COMPONENT_REF) + rtype = TREE_OPERAND (rtype, 0); + self = (rtype == self_decl); + super = (rtype == UOBJC_SUPER_decl); + rtype = TREE_TYPE (receiver); + have_cast = (TREE_CODE (receiver) == NOP_EXPR + || (TREE_CODE (receiver) == COMPOUND_EXPR + && !IS_SUPER (rtype))); + + /* If the receiver is a class object, retrieve the corresponding + @interface, if one exists. */ + is_class = receiver_is_class_object (receiver, self, super); + + /* Now determine the receiver type (if an explicit cast has not been + provided). */ + if (!have_cast) + { + if (is_class) + rtype = lookup_interface (is_class); + /* Handle `self' and `super'. */ + else if (super) { - warning ("invalid receiver type `%s'", - gen_declaration (rtype, errbuf)); + if (!CLASS_SUPER_NAME (implementation_template)) + { + error ("no super class declared in @interface for `%s'", + IDENTIFIER_POINTER (CLASS_NAME (implementation_template))); + return error_mark_node; + } + rtype = lookup_interface (CLASS_SUPER_NAME (implementation_template)); } - 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 (self) + rtype = lookup_interface (CLASS_NAME (implementation_template)); } - else - /* If sending to `super', use current self as the object. */ - self_object = self_decl; - - /* Determine operation return type. */ - if (super) + /* If receiver is of type `id' or `Class' (or if the @interface for a + class is not visible), we shall be satisfied with the existence of + any instance or class method. */ + if (!rtype || IS_ID (rtype) + || TREE_TYPE (rtype) == TREE_TYPE (objc_class_type)) { - tree iface; - - if (CLASS_SUPER_NAME (implementation_template)) + if (!rtype) + rtype = xref_tag (RECORD_TYPE, is_class); + else if (IS_ID (rtype)) { - iface - = lookup_interface (CLASS_SUPER_NAME (implementation_template)); - - 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); - - if (iface && !method_prototype) - warning ("`%s' does not respond to `%s'", - IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_template)), - IDENTIFIER_POINTER (sel_name)); + rprotos = TYPE_PROTOCOL_LIST (rtype); + rtype = NULL_TREE; } else - { - error ("no super class declared in interface for `%s'", - IDENTIFIER_POINTER (CLASS_NAME (implementation_template))); - return error_mark_node; - } - - } - else if (statically_allocated) - { - tree ctype = TREE_TYPE (rtype); - tree iface = lookup_interface (TYPE_NAME (rtype)); + is_class = TYPE_NAME (rtype) = get_identifier ("Class"); - if (iface) - method_prototype = lookup_instance_method_static (iface, sel_name); - - if (! method_prototype && ctype && TYPE_PROTOCOL_LIST (ctype)) + if (rprotos) method_prototype - = lookup_method_in_protocol_list (TYPE_PROTOCOL_LIST (ctype), - sel_name, 0); - - if (!method_prototype) - warning ("`%s' does not respond to `%s'", - IDENTIFIER_POINTER (TYPE_NAME (rtype)), - IDENTIFIER_POINTER (sel_name)); + = lookup_method_in_protocol_list (rprotos, sel_name, + is_class != NULL_TREE); + if (!method_prototype && !rprotos) + method_prototype + = lookup_method_in_hash_lists (sel_name, + is_class != NULL_TREE); } - else if (statically_typed) + else { - tree ctype = TREE_TYPE (rtype); - - /* `self' is now statically_typed. All methods should be visible - within the context of the implementation. */ - if (objc_implementation_context - && CLASS_NAME (objc_implementation_context) == TYPE_NAME (ctype)) + tree orig_rtype = rtype, saved_rtype; + + if (TREE_CODE (rtype) == POINTER_TYPE) + rtype = TREE_TYPE (rtype); + /* Traverse typedef aliases */ + while (TREE_CODE (rtype) == RECORD_TYPE && TYPE_NAME (rtype) + && TREE_CODE (TYPE_NAME (rtype)) == TYPE_DECL + && DECL_ORIGINAL_TYPE (TYPE_NAME (rtype))) + rtype = DECL_ORIGINAL_TYPE (TYPE_NAME (rtype)); + saved_rtype = rtype; + if (TYPED_OBJECT (rtype)) { - method_prototype - = lookup_instance_method_static (implementation_template, - sel_name); - - if (! method_prototype && TYPE_PROTOCOL_LIST (ctype)) - method_prototype - = lookup_method_in_protocol_list (TYPE_PROTOCOL_LIST (ctype), - sel_name, 0); - - if (! method_prototype - && implementation_template != objc_implementation_context) - /* The method is not published in the interface. Check - locally. */ - method_prototype - = lookup_method (CLASS_NST_METHODS (objc_implementation_context), - sel_name); - } - else - { - tree iface; - - if ((iface = lookup_interface (TYPE_NAME (ctype)))) - method_prototype = lookup_instance_method_static (iface, sel_name); - - if (! method_prototype) - { - tree protocol_list = TYPE_PROTOCOL_LIST (ctype); - if (protocol_list) - method_prototype - = lookup_method_in_protocol_list (protocol_list, - sel_name, 0); - } + rprotos = TYPE_PROTOCOL_LIST (rtype); + rtype = lookup_interface (OBJC_TYPE_NAME (rtype)); } - - if (!method_prototype) - warning ("`%s' does not respond to `%s'", - IDENTIFIER_POINTER (TYPE_NAME (ctype)), - IDENTIFIER_POINTER (sel_name)); - } - else if (class_ident) - { - if (objc_implementation_context - && CLASS_NAME (objc_implementation_context) == class_ident) + /* If we could not find an @interface declaration, we must have + only seen a @class declaration; so, we cannot say anything + more intelligent about which methods the receiver will + understand. */ + if (!rtype) + rtype = saved_rtype; + else if (TREE_CODE (rtype) == CLASS_INTERFACE_TYPE + || TREE_CODE (rtype) == CLASS_IMPLEMENTATION_TYPE) { + /* We have a valid ObjC class name. Look up the method name + in the published @interface for the class (and its + superclasses). */ method_prototype - = lookup_class_method_static (implementation_template, sel_name); + = lookup_method_static (rtype, sel_name, is_class != NULL_TREE); - if (!method_prototype - && implementation_template != objc_implementation_context) - /* The method is not published in the interface. Check - locally. */ + /* If the method was not found in the @interface, it may still + exist locally as part of the @implementation. */ + if (!method_prototype && objc_implementation_context + && CLASS_NAME (objc_implementation_context) + == OBJC_TYPE_NAME (rtype)) + method_prototype + = lookup_method + ((is_class + ? CLASS_CLS_METHODS (objc_implementation_context) + : CLASS_NST_METHODS (objc_implementation_context)), + sel_name); + + /* If we haven't found a candidate method by now, try looking for + it in the protocol list. */ + if (!method_prototype && rprotos) method_prototype - = lookup_method (CLASS_CLS_METHODS (objc_implementation_context), - sel_name); + = lookup_method_in_protocol_list (rprotos, sel_name, + is_class != NULL_TREE); } else { - tree iface; - - if ((iface = lookup_interface (class_ident))) - method_prototype = lookup_class_method_static (iface, sel_name); - } - - if (!method_prototype) - { - warning ("cannot find class (factory) method"); - warning ("return type for `%s' defaults to id", - IDENTIFIER_POINTER (sel_name)); + warning ("invalid receiver type `%s'", + gen_declaration (orig_rtype, errbuf)); + rtype = rprotos = NULL_TREE; } - } - else if (IS_PROTOCOL_QUALIFIED_ID (rtype)) - { - /* An anonymous object that has been qualified with a protocol. */ - - tree protocol_list = TYPE_PROTOCOL_LIST (rtype); - - method_prototype = lookup_method_in_protocol_list (protocol_list, - sel_name, 0); - - if (!method_prototype) - { - hash hsh; - - warning ("method `%s' not implemented by protocol", - IDENTIFIER_POINTER (sel_name)); - - /* Try and find the method signature in the global pools. */ - - if (!(hsh = hash_lookup (nst_method_hash_list, sel_name))) - hsh = hash_lookup (cls_method_hash_list, sel_name); + } - if (!(method_prototype = check_duplicates (hsh))) - warning ("return type defaults to id"); - } - } - else + if (!method_prototype) { - hash hsh; + static bool warn_missing_methods = false; - /* We think we have an instance...loophole: extern id Object; */ - hsh = hash_lookup (nst_method_hash_list, sel_name); - - if (!hsh) - /* For various loopholes */ - hsh = hash_lookup (cls_method_hash_list, sel_name); - - method_prototype = check_duplicates (hsh); - if (!method_prototype) + if (rtype) + warning ("`%s' may not respond to `%c%s'", + IDENTIFIER_POINTER (OBJC_TYPE_NAME (rtype)), + (is_class ? '+' : '-'), + IDENTIFIER_POINTER (sel_name)); + if (rprotos) + warning ("`%c%s' not implemented by protocol(s)", + (is_class ? '+' : '-'), + IDENTIFIER_POINTER (sel_name)); + if (!warn_missing_methods) { - warning ("cannot find method"); - warning ("return type for `%s' defaults to id", - IDENTIFIER_POINTER (sel_name)); + warning ("(Messages without a matching method signature"); + warning ("will be assumed to return `id' and accept"); + warning ("`...' as arguments.)"); + warn_missing_methods = true; } } @@ -5168,7 +5822,7 @@ finish_message_expr (receiver, sel_name, method_params) selector = build_selector_reference (sel_name); retval = build_objc_method_call (super, method_prototype, - receiver, self_object, + receiver, selector, method_params); current_objc_message_selector = 0; @@ -5184,75 +5838,66 @@ finish_message_expr (receiver, sel_name, method_params) If SUPER_FLAG is nonzero, we look up the superclass's method. */ static tree -build_objc_method_call (super_flag, method_prototype, lookup_object, object, - selector, method_params) - int super_flag; - tree method_prototype, lookup_object, object, selector, method_params; -{ - tree sender = (super_flag ? umsg_super_decl : umsg_decl); - tree rcv_p = (super_flag - ? build_pointer_type (xref_tag (RECORD_TYPE, - get_identifier (TAG_SUPER))) - : id_type); +build_objc_method_call (int super_flag, tree method_prototype, + tree lookup_object, tree selector, + tree method_params) +{ + tree sender = (super_flag ? umsg_super_decl : + (!flag_next_runtime || flag_nil_receivers + ? umsg_decl + : umsg_nonnil_decl)); + tree rcv_p = (super_flag ? super_type : id_type); + + /* If a prototype for the method to be called exists, then cast + the sender's return type and arguments to match that of the method. + Otherwise, leave sender as is. */ + tree ret_type + = (method_prototype + ? groktypename (TREE_TYPE (method_prototype)) + : id_type); + tree sender_cast + = build_pointer_type + (build_function_type + (ret_type, + get_arg_type_list + (method_prototype, METHOD_REF, super_flag))); + + lookup_object = build_c_cast (rcv_p, lookup_object); if (flag_next_runtime) { - if (! method_prototype) - { - method_params = tree_cons (NULL_TREE, lookup_object, - tree_cons (NULL_TREE, selector, - method_params)); - assemble_external (sender); - return build_function_call (sender, method_params); - } - else - { - /* This is a real kludge, but it is used only for the Next. - 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, retval, savarg, savret; - tree ret_type = groktypename (TREE_TYPE (method_prototype)); - - /* Save the proper contents of SENDER's data type. */ - 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, - super_flag); - TYPE_ARG_TYPES (TREE_TYPE (sender)) = arglist; - - /* Install this method's return type. */ - 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. */ - method_params = tree_cons (NULL_TREE, lookup_object, - tree_cons (NULL_TREE, selector, - method_params)); - assemble_external (sender); - retval = build_function_call (sender, method_params); - - /* Restore SENDER's return/argument types. */ - TYPE_ARG_TYPES (TREE_TYPE (sender)) = savarg; - TREE_TYPE (TREE_TYPE (sender)) = savret; - return retval; - } + /* If we are returning a struct in memory, and the address + of that memory location is passed as a hidden first + argument, then change which messenger entry point this + expr will call. NB: Note that sender_cast remains + unchanged (it already has a struct return type). */ + if (!targetm.calls.struct_value_rtx (0, 0) + && (TREE_CODE (ret_type) == RECORD_TYPE + || TREE_CODE (ret_type) == UNION_TYPE) + && targetm.calls.return_in_memory (ret_type, 0)) + sender = (super_flag ? umsg_super_stret_decl : + flag_nil_receivers ? umsg_stret_decl : umsg_nonnil_stret_decl); + + method_params = tree_cons (NULL_TREE, lookup_object, + tree_cons (NULL_TREE, selector, + method_params)); + TREE_USED (sender) = 1; + assemble_external (sender); + /* We want to cast the sender, not convert it. */ + return build_function_call (build_c_cast (sender_cast, sender), + method_params); } else { - /* This is the portable way. - First call the lookup function to get a pointer to the method, - then cast the pointer, then call it with the method arguments. */ - tree method; - - /* Avoid trouble since we may evaluate each of these twice. */ - object = save_expr (object); - selector = save_expr (selector); - - lookup_object = build_c_cast (rcv_p, lookup_object); + /* This is the portable (GNU) way. */ + tree method, object; + /* First, call the lookup function to get a pointer to the method, + then cast the pointer, then call it with the method arguments. + Use SAVE_EXPR to avoid evaluating the receiver twice. */ + lookup_object = save_expr (lookup_object); + object = (super_flag ? self_decl : lookup_object); + TREE_USED (sender) = 1; assemble_external (sender); method = build_function_call (sender, @@ -5260,37 +5905,22 @@ build_objc_method_call (super_flag, method_prototype, lookup_object, object, tree_cons (NULL_TREE, selector, NULL_TREE))); - /* If we have a method prototype, construct the data type this - method needs, and cast what we got from SENDER into a pointer - to that type. */ - if (method_prototype) - { - tree arglist = get_arg_type_list (method_prototype, METHOD_REF, - super_flag); - tree valtype = groktypename (TREE_TYPE (method_prototype)); - tree fake_function_type = build_function_type (valtype, arglist); - TREE_TYPE (method) = build_pointer_type (fake_function_type); - } - else - TREE_TYPE (method) - = build_pointer_type (build_function_type (ptr_type_node, NULL_TREE)); - /* Pass the object to the method. */ + TREE_USED (method) = 1; assemble_external (method); - return build_function_call (method, - tree_cons (NULL_TREE, object, - tree_cons (NULL_TREE, selector, - method_params))); + return build_function_call + (build_c_cast (sender_cast, method), + tree_cons (NULL_TREE, object, + tree_cons (NULL_TREE, selector, method_params))); } } static void -build_protocol_reference (p) - tree p; +build_protocol_reference (tree p) { tree decl, ident, ptype; - /* extern struct objc_protocol _OBJC_PROTOCOL_; */ + /* static struct objc_protocol _OBJC_PROTOCOL_; */ ident = synth_id_with_class_suffix ("_OBJC_PROTOCOL", p); ptype @@ -5304,7 +5934,7 @@ build_protocol_reference (p) { decl = build_decl (VAR_DECL, ident, ptype); DECL_EXTERNAL (decl) = 1; - TREE_PUBLIC (decl) = 1; + TREE_PUBLIC (decl) = 0; TREE_USED (decl) = 1; DECL_ARTIFICIAL (decl) = 1; @@ -5318,8 +5948,7 @@ build_protocol_reference (p) /* 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; +build_protocol_expr (tree protoname) { tree expr; tree p = lookup_protocol (protoname); @@ -5356,10 +5985,10 @@ build_protocol_expr (protoname) /* 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 + 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 @@ -5371,16 +6000,16 @@ build_protocol_expr (protoname) if (!*chain) { *chain = tree_cons (NULL_TREE, protocol_struct_type, NULL_TREE); - add_objc_string (TYPE_NAME (protocol_struct_type), + add_objc_string (OBJC_TYPE_NAME (protocol_struct_type), class_names); } - + /* Add this statically allocated instance to the Protocol list. */ - TREE_PURPOSE (*chain) = tree_cons (NULL_TREE, + TREE_PURPOSE (*chain) = tree_cons (NULL_TREE, PROTOCOL_FORWARD_DECL (p), TREE_PURPOSE (*chain)); } - + return expr; } @@ -5389,8 +6018,7 @@ build_protocol_expr (protoname) 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; +build_selector_expr (tree selnamelist) { tree selname; @@ -5414,20 +6042,20 @@ build_selector_expr (selnamelist) /* 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); @@ -5436,8 +6064,7 @@ build_selector_expr (selnamelist) } tree -build_encode_expr (type) - tree type; +build_encode_expr (tree type) { tree result; const char *string; @@ -5454,8 +6081,7 @@ build_encode_expr (type) } tree -build_ivar_reference (id) - tree id; +build_ivar_reference (tree id) { if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL) { @@ -5479,23 +6105,24 @@ build_ivar_reference (id) /* Compute a hash value for a given method SEL_NAME. */ static size_t -hash_func (sel_name) - tree sel_name; +hash_func (tree sel_name) { - const unsigned char *s + const unsigned char *s = (const unsigned char *)IDENTIFIER_POINTER (sel_name); size_t h = 0; - + while (*s) h = h * 67 + *s++ - 113; - return h; + return h; } - + static void -hash_init () +hash_init (void) { - nst_method_hash_list = (hash *) ggc_calloc (SIZEHASHTABLE, sizeof (hash)); - cls_method_hash_list = (hash *) ggc_calloc (SIZEHASHTABLE, sizeof (hash)); + nst_method_hash_list + = (hash *) ggc_alloc_cleared (SIZEHASHTABLE * sizeof (hash)); + cls_method_hash_list + = (hash *) ggc_alloc_cleared (SIZEHASHTABLE * sizeof (hash)); } /* WARNING!!!! hash_enter is called with a method, and will peek @@ -5504,9 +6131,7 @@ hash_init () entry's key (method) for comparison. */ static void -hash_enter (hashlist, method) - hash *hashlist; - tree method; +hash_enter (hash *hashlist, tree method) { hash obj; int slot = hash_func (METHOD_SEL_NAME (method)) % SIZEHASHTABLE; @@ -5520,9 +6145,7 @@ hash_enter (hashlist, method) } static hash -hash_lookup (hashlist, sel_name) - hash *hashlist; - tree sel_name; +hash_lookup (hash *hashlist, tree sel_name) { hash target; @@ -5539,9 +6162,7 @@ hash_lookup (hashlist, sel_name) } static void -hash_add_attr (entry, value) - hash entry; - tree value; +hash_add_attr (hash entry, tree value) { attr obj; @@ -5553,9 +6174,7 @@ hash_add_attr (entry, value) } static tree -lookup_method (mchain, method) - tree mchain; - tree method; +lookup_method (tree mchain, tree method) { tree key; @@ -5575,204 +6194,138 @@ lookup_method (mchain, method) } static tree -lookup_instance_method_static (interface, ident) - tree interface; - tree ident; +lookup_method_static (tree interface, tree ident, int is_class) { + tree meth = NULL_TREE, root_inter = NULL_TREE; tree inter = interface; - tree chain = CLASS_NST_METHODS (inter); - tree meth = NULL_TREE; - do + while (inter) { + tree chain = is_class ? CLASS_CLS_METHODS (inter) : CLASS_NST_METHODS (inter); + tree category = inter; + + /* First, look up the method in the class itself. */ if ((meth = lookup_method (chain, ident))) return meth; - if (CLASS_CATEGORY_LIST (inter)) + /* Failing that, look for the method in each category of the class. */ + while ((category = CLASS_CATEGORY_LIST (category))) { - tree category = CLASS_CATEGORY_LIST (inter); - chain = CLASS_NST_METHODS (category); - - do - { - if ((meth = lookup_method (chain, ident))) - return meth; - - /* Check for instance methods in protocols in categories. */ - if (CLASS_PROTOCOL_LIST (category)) - { - if ((meth = (lookup_method_in_protocol_list - (CLASS_PROTOCOL_LIST (category), ident, 0)))) - return meth; - } + chain = is_class ? CLASS_CLS_METHODS (category) : CLASS_NST_METHODS (category); - if ((category = CLASS_CATEGORY_LIST (category))) - chain = CLASS_NST_METHODS (category); - } - while (category); - } - - if (CLASS_PROTOCOL_LIST (inter)) - { - if ((meth = (lookup_method_in_protocol_list - (CLASS_PROTOCOL_LIST (inter), ident, 0)))) + /* Check directly in each category. */ + if ((meth = lookup_method (chain, ident))) return meth; - } - - if ((inter = lookup_interface (CLASS_SUPER_NAME (inter)))) - chain = CLASS_NST_METHODS (inter); - } - while (inter); - - return meth; -} - -static tree -lookup_class_method_static (interface, ident) - tree interface; - tree ident; -{ - tree inter = interface; - tree chain = CLASS_CLS_METHODS (inter); - tree meth = NULL_TREE; - tree root_inter = NULL_TREE; - - do - { - if ((meth = lookup_method (chain, ident))) - return meth; - - if (CLASS_CATEGORY_LIST (inter)) - { - tree category = CLASS_CATEGORY_LIST (inter); - chain = CLASS_CLS_METHODS (category); - do + /* Failing that, check in each category's protocols. */ + if (CLASS_PROTOCOL_LIST (category)) { - if ((meth = lookup_method (chain, ident))) + if ((meth = (lookup_method_in_protocol_list + (CLASS_PROTOCOL_LIST (category), ident, is_class)))) return meth; - - /* Check for class methods in protocols in categories. */ - if (CLASS_PROTOCOL_LIST (category)) - { - if ((meth = (lookup_method_in_protocol_list - (CLASS_PROTOCOL_LIST (category), ident, 1)))) - return meth; - } - - if ((category = CLASS_CATEGORY_LIST (category))) - chain = CLASS_CLS_METHODS (category); } - while (category); } - /* Check for class methods in protocols. */ + /* If not found in categories, check in protocols of the main class. */ if (CLASS_PROTOCOL_LIST (inter)) { if ((meth = (lookup_method_in_protocol_list - (CLASS_PROTOCOL_LIST (inter), ident, 1)))) + (CLASS_PROTOCOL_LIST (inter), ident, is_class)))) return meth; } + /* Failing that, climb up the inheritance hierarchy. */ root_inter = inter; - if ((inter = lookup_interface (CLASS_SUPER_NAME (inter)))) - chain = CLASS_CLS_METHODS (inter); + inter = lookup_interface (CLASS_SUPER_NAME (inter)); } while (inter); /* 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); + the Objective-C runtime will do. If an instance method was not + found, return 0. */ + return is_class ? lookup_method_static (root_inter, ident, 0): NULL_TREE; } -tree -add_class_method (class, method) - tree class; - tree method; +/* Add the method to the hash list if it doesn't contain an identical + method already. */ +static void +add_method_to_hash_list (hash *hash_list, tree method) { - tree mth; hash hsh; - if (!(mth = lookup_method (CLASS_CLS_METHODS (class), method))) - { - /* put method on list in reverse order */ - TREE_CHAIN (method) = CLASS_CLS_METHODS (class); - CLASS_CLS_METHODS (class) = method; - } - else - { - if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE) - 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'", - IDENTIFIER_POINTER (METHOD_SEL_NAME (mth))); - } - } - - if (!(hsh = hash_lookup (cls_method_hash_list, METHOD_SEL_NAME (method)))) + if (!(hsh = hash_lookup (hash_list, METHOD_SEL_NAME (method)))) { /* Install on a global chain. */ - hash_enter (cls_method_hash_list, method); + hash_enter (hash_list, method); } else { - /* Check types; if different, add to a list. */ - if (!comp_proto_with_proto (method, hsh->key)) - hash_add_attr (hsh, method); + /* Check types against those; if different, add to a list. */ + attr loop; + int already_there = comp_proto_with_proto (method, hsh->key); + for (loop = hsh->list; !already_there && loop; loop = loop->next) + already_there |= comp_proto_with_proto (method, loop->value); + if (!already_there) + hash_add_attr (hsh, method); } - return method; } - + tree -add_instance_method (class, method) - tree class; - tree method; +objc_add_method (tree class, tree method, int is_class) { tree mth; - hash hsh; - if (!(mth = lookup_method (CLASS_NST_METHODS (class), method))) + if (!(mth = lookup_method (is_class ? CLASS_CLS_METHODS (class) : CLASS_NST_METHODS (class), method))) { - /* Put method on list in reverse order. */ - TREE_CHAIN (method) = CLASS_NST_METHODS (class); - CLASS_NST_METHODS (class) = method; + /* put method on list in reverse order */ + if (is_class) + { + TREE_CHAIN (method) = CLASS_CLS_METHODS (class); + CLASS_CLS_METHODS (class) = method; + } + else + { + TREE_CHAIN (method) = CLASS_NST_METHODS (class); + CLASS_NST_METHODS (class) = method; + } } else { - if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE) - 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'", - IDENTIFIER_POINTER (METHOD_SEL_NAME (mth))); - } + /* When processing an @interface for a class or category, give hard + errors on methods with identical selectors but differing argument + and/or return types. We do not do this for @implementations, because + C/C++ will do it for us (i.e., there will be duplicate function + definition errors). */ + if ((TREE_CODE (class) == CLASS_INTERFACE_TYPE + || TREE_CODE (class) == CATEGORY_INTERFACE_TYPE) + && !comp_proto_with_proto (method, mth)) + error ("duplicate declaration of method `%c%s'", + is_class ? '+' : '-', IDENTIFIER_POINTER (METHOD_SEL_NAME (mth))); } - if (!(hsh = hash_lookup (nst_method_hash_list, METHOD_SEL_NAME (method)))) - { - /* Install on a global chain. */ - hash_enter (nst_method_hash_list, method); - } + if (is_class) + add_method_to_hash_list (cls_method_hash_list, method); else { - /* Check types; if different, add to a list. */ - if (!comp_proto_with_proto (method, hsh->key)) - hash_add_attr (hsh, method); + add_method_to_hash_list (nst_method_hash_list, method); + + /* Instance methods in root classes (and categories thereof) + may acts as class methods as a last resort. */ + if (TREE_CODE (class) == CATEGORY_INTERFACE_TYPE + || TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE) + class = lookup_interface (CLASS_NAME (class)); + + if (TREE_CODE (class) != PROTOCOL_INTERFACE_TYPE + && !CLASS_SUPER_NAME (class)) + add_method_to_hash_list (cls_method_hash_list, method); } + return method; } static tree -add_class (class) - tree class; +add_class (tree class) { /* Put interfaces on list in reverse order. */ TREE_CHAIN (class) = interface_chain; @@ -5781,24 +6334,22 @@ add_class (class) } static void -add_category (class, category) - tree class; - tree category; +add_category (tree class, tree category) { /* Put categories on list in reverse order. */ - tree cat = CLASS_CATEGORY_LIST (class); + tree cat = lookup_category (class, CLASS_SUPER_NAME (category)); - while (cat) + if (cat) { - if (CLASS_SUPER_NAME (cat) == CLASS_SUPER_NAME (category)) - warning ("duplicate interface declaration for category `%s(%s)'", - IDENTIFIER_POINTER (CLASS_NAME (class)), - IDENTIFIER_POINTER (CLASS_SUPER_NAME (category))); - cat = CLASS_CATEGORY_LIST (cat); + warning ("duplicate interface declaration for category `%s(%s)'", + IDENTIFIER_POINTER (CLASS_NAME (class)), + IDENTIFIER_POINTER (CLASS_SUPER_NAME (category))); + } + else + { + CLASS_CATEGORY_LIST (category) = CLASS_CATEGORY_LIST (class); + CLASS_CATEGORY_LIST (class) = category; } - - CLASS_CATEGORY_LIST (category) = CLASS_CATEGORY_LIST (class); - CLASS_CATEGORY_LIST (class) = category; } /* Called after parsing each instance variable declaration. Necessary to @@ -5807,24 +6358,64 @@ add_category (class, category) PUBLIC is 1 for public, 0 for protected, and 2 for private. */ tree -add_instance_variable (class, public, declarator, declspecs, width) - tree class; - int public; - tree declarator; - tree declspecs; - tree width; +add_instance_variable (tree class, int public, tree declarator, + tree declspecs, tree width) { - tree field_decl, raw_decl; - - raw_decl = build_tree_list (declspecs, declarator); + tree field_decl = grokfield (declarator, declspecs, width); + tree field_type = TREE_TYPE (field_decl); + const char *ivar_name = DECL_NAME (field_decl) + ? IDENTIFIER_POINTER (DECL_NAME (field_decl)) + : ""; + tree raw_decl; - if (CLASS_RAW_IVARS (class)) - chainon (CLASS_RAW_IVARS (class), raw_decl); - else - CLASS_RAW_IVARS (class) = raw_decl; +#ifdef OBJCPLUS + if (TREE_CODE (field_type) == REFERENCE_TYPE) + { + error ("illegal reference type specified for instance variable `%s'", + ivar_name); + /* Return class as is without adding this ivar. */ + return class; + } +#endif - field_decl = grokfield (input_filename, input_line, - declarator, declspecs, width); + if (field_type == error_mark_node || !TYPE_SIZE (field_type) + || TYPE_SIZE (field_type) == error_mark_node + /* 'type[0]' is allowed, but 'type[]' is not! */ +#ifdef OBJCPLUS + || (TYPE_SIZE (field_type) == bitsize_zero_node + && !TREE_OPERAND (declarator, 1)) +#endif + ) + { + error ("instance variable `%s' has unknown size", ivar_name); + /* Return class as is without adding this ivar. */ + return class; + } + +#ifdef OBJCPLUS + /* zlaski 2001-Apr-24: C++ classes with non-trivial constructors and/or destructors + cannot be ivars; ditto for classes with vtables. */ + if(IS_AGGR_TYPE (field_type) && (TYPE_NEEDS_CONSTRUCTING (field_type) + || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type) || TYPE_POLYMORPHIC_P (field_type))) + { + const char *type_name = IDENTIFIER_POINTER (OBJC_TYPE_NAME (field_type)); + if(TYPE_POLYMORPHIC_P (field_type)) { + /* vtable pointers are Real Bad(tm), since Obj-C cannot initialize them */ + error ("type `%s' has virtual member functions", type_name); + error ("illegal aggregate type `%s' specified for instance variable `%s'", + type_name, ivar_name); + /* Return class as is without adding this ivar. */ + return class; + } + /* user-defined constructors and destructors are not known to Obj-C and + hence will not be called. This may or may not be a problem. */ + if (TYPE_NEEDS_CONSTRUCTING (field_type)) + warning ("type `%s' has a user-defined constructor", type_name); + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type)) + warning ("type `%s' has a user-defined destructor", type_name); + warning ("C++ constructors and destructors will not be invoked for Objective-C fields"); + } +#endif /* Overload the public attribute, it is not used for FIELD_DECLs. */ switch (public) @@ -5849,18 +6440,14 @@ add_instance_variable (class, public, declarator, declspecs, width) } - if (CLASS_IVARS (class)) - chainon (CLASS_IVARS (class), field_decl); - else - CLASS_IVARS (class) = field_decl; - + raw_decl = build_tree_list (declspecs, build_tree_list (declarator, width)); + CLASS_RAW_IVARS (class) = chainon (CLASS_RAW_IVARS (class), raw_decl); + CLASS_IVARS (class) = chainon (CLASS_IVARS (class), field_decl); return class; } tree -is_ivar (decl_chain, ident) - tree decl_chain; - tree ident; +is_ivar (tree decl_chain, tree ident) { for ( ; decl_chain; decl_chain = TREE_CHAIN (decl_chain)) if (DECL_NAME (decl_chain) == ident) @@ -5871,8 +6458,7 @@ is_ivar (decl_chain, ident) /* True if the ivar is private and we are not in its implementation. */ int -is_private (decl) - tree decl; +is_private (tree decl) { if (TREE_PRIVATE (decl) && ! is_ivar (CLASS_IVARS (implementation_template), DECL_NAME (decl))) @@ -5888,9 +6474,7 @@ is_private (decl) /* We have an instance variable reference;, check to see if it is public. */ int -is_public (expr, identifier) - tree expr; - tree identifier; +is_public (tree expr, tree identifier) { tree basetype = TREE_TYPE (expr); enum tree_code code = TREE_CODE (basetype); @@ -5900,10 +6484,10 @@ is_public (expr, identifier) { if (TREE_STATIC_TEMPLATE (basetype)) { - if (!lookup_interface (TYPE_NAME (basetype))) + if (!lookup_interface (OBJC_TYPE_NAME (basetype))) { error ("cannot find interface declaration for `%s'", - IDENTIFIER_POINTER (TYPE_NAME (basetype))); + IDENTIFIER_POINTER (OBJC_TYPE_NAME (basetype))); return 0; } @@ -5921,9 +6505,20 @@ is_public (expr, identifier) || (TREE_CODE (objc_implementation_context) == CATEGORY_IMPLEMENTATION_TYPE)) && (CLASS_NAME (objc_implementation_context) - == TYPE_NAME (basetype)))) + == OBJC_TYPE_NAME (basetype)))) return ! is_private (decl); + /* The 2.95.2 compiler sometimes allowed C functions to access + non-@public ivars. We will let this slide for now... */ + if (!objc_method_context) + { + warning ("instance variable `%s' is %s; " + "this will be a hard error in the future", + IDENTIFIER_POINTER (identifier), + TREE_PRIVATE (decl) ? "@private" : "@protected"); + return 1; + } + error ("instance variable `%s' is declared %s", IDENTIFIER_POINTER (identifier), TREE_PRIVATE (decl) ? "private" : "protected"); @@ -5944,10 +6539,7 @@ is_public (expr, identifier) /* Make sure all entries in CHAIN are also in LIST. */ static int -check_methods (chain, list, mtype) - tree chain; - tree list; - int mtype; +check_methods (tree chain, tree list, int mtype) { int first = 1; @@ -5981,9 +6573,7 @@ check_methods (chain, list, mtype) /* Check if CLASS, or its superclasses, explicitly conforms to PROTOCOL. */ static int -conforms_to_protocol (class, protocol) - tree class; - tree protocol; +conforms_to_protocol (tree class, tree protocol) { if (TREE_CODE (protocol) == PROTOCOL_INTERFACE_TYPE) { @@ -6005,14 +6595,11 @@ conforms_to_protocol (class, protocol) return 1; } -/* Make sure all methods in CHAIN are accessible as MTYPE methods in +/* Make sure all methods in CHAIN are accessible as MTYPE methods in CONTEXT. This is one of two mechanisms to check protocol integrity. */ static int -check_methods_accessible (chain, context, mtype) - tree chain; - tree context; - int mtype; +check_methods_accessible (tree chain, tree context, int mtype) { int first = 1; tree list; @@ -6029,17 +6616,17 @@ check_methods_accessible (chain, context, mtype) list = CLASS_NST_METHODS (context); if (lookup_method (list, chain)) - break; + break; else if (TREE_CODE (context) == CLASS_IMPLEMENTATION_TYPE || TREE_CODE (context) == CLASS_INTERFACE_TYPE) - context = (CLASS_SUPER_NAME (context) + context = (CLASS_SUPER_NAME (context) ? lookup_interface (CLASS_SUPER_NAME (context)) : NULL_TREE); else if (TREE_CODE (context) == CATEGORY_IMPLEMENTATION_TYPE || TREE_CODE (context) == CATEGORY_INTERFACE_TYPE) - context = (CLASS_NAME (context) + context = (CLASS_NAME (context) ? lookup_interface (CLASS_NAME (context)) : NULL_TREE); else @@ -6074,12 +6661,9 @@ check_methods_accessible (chain, context, mtype) /* Check whether the current interface (accessible via 'objc_implementation_context') actually implements protocol P, along with any protocols that P inherits. */ - + static void -check_protocol (p, type, name) - tree p; - const char *type; - const char *name; +check_protocol (tree p, const char *type, const char *name) { if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) { @@ -6109,7 +6693,7 @@ check_protocol (p, type, name) warning ("%s `%s' does not fully implement the `%s' protocol", type, name, IDENTIFIER_POINTER (PROTOCOL_NAME (p))); } - + /* Check protocols recursively. */ if (PROTOCOL_LIST (p)) { @@ -6117,7 +6701,7 @@ check_protocol (p, type, name) tree super_class = lookup_interface (CLASS_SUPER_NAME (implementation_template)); - while (subs) + while (subs) { tree sub = TREE_VALUE (subs); @@ -6129,16 +6713,13 @@ check_protocol (p, type, name) } } } - + /* 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; +check_protocols (tree proto_list, const char *type, const char *name) { for ( ; proto_list; proto_list = TREE_CHAIN (proto_list)) { @@ -6154,14 +6735,17 @@ check_protocols (proto_list, type, name) CATEGORY_INTERFACE_TYPE, or CATEGORY_IMPLEMENTATION_TYPE. */ tree -start_class (code, class_name, super_name, protocol_list) - enum tree_code code; - tree class_name; - tree super_name; - tree protocol_list; +start_class (enum tree_code code, tree class_name, tree super_name, + tree protocol_list) { tree class, decl; +#ifdef OBJCPLUS + if (current_namespace != global_namespace) { + error ("Objective-C declarations may only appear in global scope"); + } +#endif /* OBJCPLUS */ + if (objc_implementation_context) { warning ("`@end' missing in implementation context"); @@ -6171,17 +6755,19 @@ start_class (code, class_name, super_name, protocol_list) } class = make_node (code); - TYPE_BINFO (class) = make_tree_vec (BINFO_ELTS); + TYPE_BINFO (class) = make_tree_vec (CLASS_BINFO_ELTS); CLASS_NAME (class) = class_name; CLASS_SUPER_NAME (class) = super_name; CLASS_CLS_METHODS (class) = NULL_TREE; - if (! is_class_name (class_name) && (decl = lookup_name (class_name))) + if (! is_class_name (class_name) + && (decl = lookup_name (class_name))) { error ("`%s' redeclared as different kind of symbol", IDENTIFIER_POINTER (class_name)); - error_with_decl (decl, "previous declaration of `%s'"); + error ("%Jprevious declaration of '%D'", + decl, decl); } if (code == CLASS_IMPLEMENTATION_TYPE) @@ -6200,17 +6786,6 @@ start_class (code, class_name, super_name, protocol_list) implemented_classes); } - /* Pre-build the following entities - for speed/convenience. */ - if (!self_id) - self_id = get_identifier ("self"); - if (!ucmd_id) - ucmd_id = get_identifier ("_cmd"); - if (!unused_list) - unused_list - = build_tree_list (get_identifier ("__unused__"), NULL_TREE); - if (!objc_super_template) - objc_super_template = build_super_template (); - /* Reset for multiple classes per file. */ method_slot = 0; @@ -6241,7 +6816,7 @@ start_class (code, class_name, super_name, protocol_list) else if (! super_name) { - CLASS_SUPER_NAME (objc_implementation_context) + CLASS_SUPER_NAME (objc_implementation_context) = CLASS_SUPER_NAME (implementation_template); } } @@ -6249,8 +6824,12 @@ start_class (code, class_name, super_name, protocol_list) else if (code == CLASS_INTERFACE_TYPE) { if (lookup_interface (class_name)) - warning ("duplicate interface declaration for class `%s'", - IDENTIFIER_POINTER (class_name)); +#ifdef OBJCPLUS + error ("duplicate interface declaration for class `%s'", +#else + warning ("duplicate interface declaration for class `%s'", +#endif + IDENTIFIER_POINTER (class_name)); else add_class (class); @@ -6283,17 +6862,6 @@ start_class (code, class_name, super_name, protocol_list) else if (code == CATEGORY_IMPLEMENTATION_TYPE) { - /* Pre-build the following entities for speed/convenience. */ - if (!self_id) - self_id = get_identifier ("self"); - if (!ucmd_id) - ucmd_id = get_identifier ("_cmd"); - if (!unused_list) - unused_list - = build_tree_list (get_identifier ("__unused__"), NULL_TREE); - if (!objc_super_template) - objc_super_template = build_super_template (); - /* Reset for multiple classes per file. */ method_slot = 0; @@ -6314,8 +6882,7 @@ start_class (code, class_name, super_name, protocol_list) } tree -continue_class (class) - tree class; +continue_class (tree class) { if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE || TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE) @@ -6357,11 +6924,10 @@ continue_class (class) else if (TREE_CODE (class) == CLASS_INTERFACE_TYPE) { - tree record = xref_tag (RECORD_TYPE, CLASS_NAME (class)); - - if (!TYPE_FIELDS (record)) + if (!CLASS_STATIC_TEMPLATE (class)) { - finish_struct (record, get_class_ivars (class), NULL_TREE); + tree record = start_struct (RECORD_TYPE, CLASS_NAME (class)); + finish_struct (record, get_class_ivars (class, 0), NULL_TREE); CLASS_STATIC_TEMPLATE (class) = record; /* Mark this record as a class template for static typing. */ @@ -6378,8 +6944,7 @@ continue_class (class) /* This is called once we see the "@end" in an interface/implementation. */ void -finish_class (class) - tree class; +finish_class (tree class) { if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE) { @@ -6402,15 +6967,7 @@ finish_class (class) else if (TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE) { - tree category = CLASS_CATEGORY_LIST (implementation_template); - - /* Find the category interface from the class it is associated with. */ - while (category) - { - if (CLASS_SUPER_NAME (class) == CLASS_SUPER_NAME (category)) - break; - category = CLASS_CATEGORY_LIST (category); - } + tree category = lookup_category (implementation_template, CLASS_SUPER_NAME (class)); if (category) { @@ -6445,8 +7002,7 @@ finish_class (class) } static tree -add_protocol (protocol) - tree protocol; +add_protocol (tree protocol) { /* Put protocol on list in reverse order. */ TREE_CHAIN (protocol) = protocol_chain; @@ -6455,8 +7011,7 @@ add_protocol (protocol) } static tree -lookup_protocol (ident) - tree ident; +lookup_protocol (tree ident) { tree chain; @@ -6471,11 +7026,16 @@ lookup_protocol (ident) they are already declared or defined, the function has no effect. */ void -objc_declare_protocols (names) - tree names; +objc_declare_protocols (tree names) { tree list; +#ifdef OBJCPLUS + if (current_namespace != global_namespace) { + error ("Objective-C declarations may only appear in global scope"); + } +#endif /* OBJCPLUS */ + for (list = names; list; list = TREE_CHAIN (list)) { tree name = TREE_VALUE (list); @@ -6495,13 +7055,16 @@ objc_declare_protocols (names) } tree -start_protocol (code, name, list) - enum tree_code code; - tree name; - tree list; +start_protocol (enum tree_code code, tree name, tree list) { tree protocol; +#ifdef OBJCPLUS + if (current_namespace != global_namespace) { + error ("Objective-C declarations may only appear in global scope"); + } +#endif /* OBJCPLUS */ + /* This is as good a place as any. Need to invoke push_tag_toplevel. */ if (!objc_protocol_template) @@ -6538,8 +7101,7 @@ start_protocol (code, name, list) } void -finish_protocol (protocol) - tree protocol ATTRIBUTE_UNUSED; +finish_protocol (tree protocol ATTRIBUTE_UNUSED) { } @@ -6548,8 +7110,7 @@ finish_protocol (protocol) ??? What is the FORMAT? Someone please document this! */ static void -encode_type_qualifiers (declspecs) - tree declspecs; +encode_type_qualifiers (tree declspecs) { tree spec; @@ -6575,19 +7136,16 @@ encode_type_qualifiers (declspecs) /* Encode a pointer type. */ static void -encode_pointer (type, curtype, format) - tree type; - int curtype; - int format; +encode_pointer (tree type, int curtype, int format) { tree pointer_to = TREE_TYPE (type); if (TREE_CODE (pointer_to) == RECORD_TYPE) { - if (TYPE_NAME (pointer_to) - && TREE_CODE (TYPE_NAME (pointer_to)) == IDENTIFIER_NODE) + if (OBJC_TYPE_NAME (pointer_to) + && TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE) { - const char *name = IDENTIFIER_POINTER (TYPE_NAME (pointer_to)); + const char *name = IDENTIFIER_POINTER (OBJC_TYPE_NAME (pointer_to)); if (strcmp (name, TAG_OBJECT) == 0) /* '@' */ { @@ -6625,8 +7183,15 @@ encode_pointer (type, curtype, format) else if (TREE_CODE (pointer_to) == INTEGER_TYPE && TYPE_MODE (pointer_to) == QImode) { - obstack_1grow (&util_obstack, '*'); - return; + tree pname = TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE + ? OBJC_TYPE_NAME (pointer_to) + : DECL_NAME (OBJC_TYPE_NAME (pointer_to)); + + if (!flag_next_runtime || strcmp (IDENTIFIER_POINTER (pname), "BOOL")) + { + obstack_1grow (&util_obstack, '*'); + return; + } } /* We have a type that does not get special treatment. */ @@ -6637,10 +7202,7 @@ encode_pointer (type, curtype, format) } static void -encode_array (type, curtype, format) - tree type; - int curtype; - int format; +encode_array (tree type, int curtype, int format) { tree an_int_cst = TYPE_SIZE (type); tree array_of = TREE_TYPE (type); @@ -6664,131 +7226,75 @@ encode_array (type, curtype, format) } static void -encode_aggregate_within (type, curtype, format, left, right) - tree type; - int curtype; - int format; - 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. */ - - if (obstack_object_size (&util_obstack) - curtype == 1 - && format == OBJC_ENCODE_INLINE_DEFS) - { - /* Output format of struct for first level only. */ - tree fields = TYPE_FIELDS (type); - - if (name && TREE_CODE (name) == IDENTIFIER_NODE) - { - obstack_1grow (&util_obstack, left); - obstack_grow (&util_obstack, - IDENTIFIER_POINTER (name), - strlen (IDENTIFIER_POINTER (name))); - obstack_1grow (&util_obstack, '='); - } - else - { - obstack_1grow (&util_obstack, left); - obstack_grow (&util_obstack, "?=", 2); - } - - for ( ; fields; fields = TREE_CHAIN (fields)) - encode_field_decl (fields, curtype, format); - - obstack_1grow (&util_obstack, right); - } - - else if (name && TREE_CODE (name) == IDENTIFIER_NODE) - { - obstack_1grow (&util_obstack, left); - obstack_grow (&util_obstack, - IDENTIFIER_POINTER (name), - strlen (IDENTIFIER_POINTER (name))); - obstack_1grow (&util_obstack, right); - } - - else - { - /* We have an untagged structure or a typedef. */ - obstack_1grow (&util_obstack, left); - obstack_1grow (&util_obstack, '?'); - obstack_1grow (&util_obstack, right); - } - } - +encode_aggregate_within (tree type, int curtype, int format, int left, + int right) +{ + tree name; + /* NB: aggregates that are pointed to have slightly different encoding + rules in that you never encode the names of instance variables. */ + int pointed_to + = (obstack_object_size (&util_obstack) > 0 + && *(obstack_next_free (&util_obstack) - 1) == '^'); + int inline_contents + = ((format == OBJC_ENCODE_INLINE_DEFS || generating_instance_variables) + && (!pointed_to || obstack_object_size (&util_obstack) - curtype == 1)); + + /* Traverse struct aliases; it is important to get the + original struct and its tag name (if any). */ + type = TYPE_MAIN_VARIANT (type); + name = OBJC_TYPE_NAME (type); + /* Open parenth/bracket. */ + obstack_1grow (&util_obstack, left); + + /* Encode the struct/union tag name, or '?' if a tag was + not provided. Typedef aliases do not qualify. */ + if (name && TREE_CODE (name) == IDENTIFIER_NODE +#ifdef OBJCPLUS + /* Did this struct have a tag? */ + && !TYPE_WAS_ANONYMOUS (type) +#endif + ) + obstack_grow (&util_obstack, + IDENTIFIER_POINTER (name), + strlen (IDENTIFIER_POINTER (name))); else + obstack_1grow (&util_obstack, '?'); + + /* Encode the types (and possibly names) of the inner fields, + if required. */ + if (inline_contents) { - tree name = TYPE_NAME (type); tree fields = TYPE_FIELDS (type); - if (format == OBJC_ENCODE_INLINE_DEFS - || generating_instance_variables) + obstack_1grow (&util_obstack, '='); + for (; fields; fields = TREE_CHAIN (fields)) { - obstack_1grow (&util_obstack, left); - if (name && TREE_CODE (name) == IDENTIFIER_NODE) - obstack_grow (&util_obstack, - IDENTIFIER_POINTER (name), - strlen (IDENTIFIER_POINTER (name))); - else - obstack_1grow (&util_obstack, '?'); - - obstack_1grow (&util_obstack, '='); - - for (; fields; fields = TREE_CHAIN (fields)) +#ifdef OBJCPLUS + /* C++ static members, and things that are not fields at all, + should not appear in the encoding. */ + if (TREE_CODE (fields) != FIELD_DECL || TREE_STATIC (fields)) + continue; +#endif + if (generating_instance_variables && !pointed_to) { - if (generating_instance_variables) - { - tree fname = DECL_NAME (fields); - - obstack_1grow (&util_obstack, '"'); - if (fname && TREE_CODE (fname) == IDENTIFIER_NODE) - { - obstack_grow (&util_obstack, - IDENTIFIER_POINTER (fname), - strlen (IDENTIFIER_POINTER (fname))); - } - - obstack_1grow (&util_obstack, '"'); - } - - encode_field_decl (fields, curtype, format); + tree fname = DECL_NAME (fields); + + obstack_1grow (&util_obstack, '"'); + if (fname && TREE_CODE (fname) == IDENTIFIER_NODE) + obstack_grow (&util_obstack, + IDENTIFIER_POINTER (fname), + strlen (IDENTIFIER_POINTER (fname))); + obstack_1grow (&util_obstack, '"'); } - - obstack_1grow (&util_obstack, right); - } - - else - { - obstack_1grow (&util_obstack, left); - if (name && TREE_CODE (name) == IDENTIFIER_NODE) - obstack_grow (&util_obstack, - IDENTIFIER_POINTER (name), - strlen (IDENTIFIER_POINTER (name))); - else - /* We have an untagged structure or a typedef. */ - obstack_1grow (&util_obstack, '?'); - - obstack_1grow (&util_obstack, right); + encode_field_decl (fields, curtype, format); } } + /* Close parenth/bracket. */ + obstack_1grow (&util_obstack, right); } static void -encode_aggregate (type, curtype, format) - tree type; - int curtype; - int format; +encode_aggregate (tree type, int curtype, int format) { enum tree_code code = TREE_CODE (type); @@ -6796,12 +7302,12 @@ encode_aggregate (type, curtype, format) { case RECORD_TYPE: { - encode_aggregate_within(type, curtype, format, '{', '}'); + encode_aggregate_within (type, curtype, format, '{', '}'); break; } case UNION_TYPE: { - encode_aggregate_within(type, curtype, format, '(', ')'); + encode_aggregate_within (type, curtype, format, '(', ')'); break; } @@ -6814,19 +7320,11 @@ encode_aggregate (type, curtype, format) } } -/* Support bitfields. The current version of Objective-C does not support - them. The string will consist of one or more "b:n"'s where n is an - integer describing the width of the bitfield. Currently, classes in - the kit implement a method "-(char *)describeBitfieldStruct:" that - simulates this. If they do not implement this method, the archiver - assumes the bitfield is 16 bits wide (padded if necessary) and packed - according to the GNU compiler. After looking at the "kit", it appears - that all classes currently rely on this default behavior, rather than - hand generating this string (which is tedious). */ +/* Encode a bitfield NeXT-style (i.e., without a bit offset or the underlying + field type. */ static void -encode_bitfield (width) - int width; +encode_next_bitfield (int width) { char buffer[40]; sprintf (buffer, "b%d", width); @@ -6834,70 +7332,50 @@ encode_bitfield (width) } /* FORMAT will be OBJC_ENCODE_INLINE_DEFS or OBJC_ENCODE_DONT_INLINE_DEFS. */ - static void -encode_type (type, curtype, format) - tree type; - int curtype; - int format; +encode_type (tree type, int curtype, int format) { enum tree_code code = TREE_CODE (type); + char c; if (code == INTEGER_TYPE) { - if (integer_zerop (TYPE_MIN_VALUE (type))) - { - /* Unsigned integer types. */ - - if (TYPE_MODE (type) == QImode) - obstack_1grow (&util_obstack, 'C'); - else if (TYPE_MODE (type) == HImode) - obstack_1grow (&util_obstack, 'S'); - else if (TYPE_MODE (type) == SImode) - { - if (type == long_unsigned_type_node) - obstack_1grow (&util_obstack, 'L'); - else - obstack_1grow (&util_obstack, 'I'); - } - else if (TYPE_MODE (type) == DImode) - obstack_1grow (&util_obstack, 'Q'); - } - - else - /* Signed integer types. */ + switch (GET_MODE_BITSIZE (TYPE_MODE (type))) { - if (TYPE_MODE (type) == QImode) - obstack_1grow (&util_obstack, 'c'); - else if (TYPE_MODE (type) == HImode) - obstack_1grow (&util_obstack, 's'); - else if (TYPE_MODE (type) == SImode) - { - if (type == long_integer_type_node) - obstack_1grow (&util_obstack, 'l'); - else - obstack_1grow (&util_obstack, 'i'); - } - - else if (TYPE_MODE (type) == DImode) - obstack_1grow (&util_obstack, 'q'); + case 8: c = TYPE_UNSIGNED (type) ? 'C' : 'c'; break; + case 16: c = TYPE_UNSIGNED (type) ? 'S' : 's'; break; + case 32: + if (type == long_unsigned_type_node + || type == long_integer_type_node) + c = TYPE_UNSIGNED (type) ? 'L' : 'l'; + else + c = TYPE_UNSIGNED (type) ? 'I' : 'i'; + break; + case 64: c = TYPE_UNSIGNED (type) ? 'Q' : 'q'; break; + default: abort (); } + obstack_1grow (&util_obstack, c); } else if (code == REAL_TYPE) { /* Floating point types. */ - - if (TYPE_MODE (type) == SFmode) - obstack_1grow (&util_obstack, 'f'); - else if (TYPE_MODE (type) == DFmode - || TYPE_MODE (type) == TFmode) - obstack_1grow (&util_obstack, 'd'); + switch (GET_MODE_BITSIZE (TYPE_MODE (type))) + { + case 32: c = 'f'; break; + case 64: + case 128: c = 'd'; break; + default: abort (); + } + obstack_1grow (&util_obstack, c); } else if (code == VOID_TYPE) obstack_1grow (&util_obstack, 'v'); + else if (code == BOOLEAN_TYPE) + obstack_1grow (&util_obstack, 'B'); + else if (code == ARRAY_TYPE) encode_array (type, curtype, format); @@ -6912,10 +7390,7 @@ encode_type (type, curtype, format) } static void -encode_complete_bitfield (position, type, size) - int position; - tree type; - int size; +encode_gnu_bitfield (int position, tree type, int size) { enum tree_code code = TREE_CODE (type); char buffer[40]; @@ -6971,39 +7446,37 @@ encode_complete_bitfield (position, type, size) } static void -encode_field_decl (field_decl, curtype, format) - tree field_decl; - int curtype; - int format; +encode_field_decl (tree field_decl, int curtype, int format) { tree type; +#ifdef OBJCPLUS + /* C++ static members, and things that are not fields at all, + should not appear in the encoding. */ + if (TREE_CODE (field_decl) != FIELD_DECL || TREE_STATIC (field_decl)) + return; +#endif + type = TREE_TYPE (field_decl); - /* If this field is obviously a bitfield, or is a bitfield that has been - clobbered to look like a ordinary integer mode, go ahead and generate - the bitfield typing information. */ - if (flag_next_runtime) + /* Generate the bitfield typing information, if needed. Note the difference + between GNU and NeXT runtimes. */ + if (DECL_BIT_FIELD_TYPE (field_decl)) { - if (DECL_BIT_FIELD_TYPE (field_decl)) - encode_bitfield (tree_low_cst (DECL_SIZE (field_decl), 1)); + int size = tree_low_cst (DECL_SIZE (field_decl), 1); + + if (flag_next_runtime) + encode_next_bitfield (size); else - encode_type (TREE_TYPE (field_decl), curtype, format); + encode_gnu_bitfield (int_bit_position (field_decl), + DECL_BIT_FIELD_TYPE (field_decl), size); } else - { - 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)); - else - encode_type (TREE_TYPE (field_decl), curtype, format); - } + encode_type (TREE_TYPE (field_decl), curtype, format); } static tree -expr_last (complex_expr) - tree complex_expr; +objc_expr_last (tree complex_expr) { tree next; @@ -7013,26 +7486,14 @@ expr_last (complex_expr) return complex_expr; } - -/* Transform a method definition into a function definition as follows: - - synthesize the first two arguments, "self" and "_cmd". */ -void -start_method_def (method) - tree method; +static void +synth_self_and_ucmd_args (void) { tree decl_specs; - /* Required to implement _msgSuper. */ - objc_method_context = method; - UOBJC_SUPER_decl = NULL_TREE; - - /* Must be called BEFORE start_function. */ - pushlevel (0); - - /* Generate prototype declarations for arguments..."new-style". */ - - if (TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL) + if (objc_method_context + && 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 @@ -7044,13 +7505,29 @@ start_method_def (method) build1 (INDIRECT_REF, NULL_TREE, self_id)), unused_list)); - decl_specs = build_tree_list (NULL_TREE, - xref_tag (RECORD_TYPE, - get_identifier (TAG_SELECTOR))); + decl_specs = build_tree_list (NULL_TREE, TREE_TYPE (selector_type)); push_parm_decl (build_tree_list (build_tree_list (decl_specs, build1 (INDIRECT_REF, NULL_TREE, ucmd_id)), unused_list)); +} + +/* Transform a method definition into a function definition as follows: + - synthesize the first two arguments, "self" and "_cmd". */ + +void +start_method_def (tree method) +{ + /* Required to implement _msgSuper. */ + objc_method_context = method; + UOBJC_SUPER_decl = NULL_TREE; + + /* Must be called BEFORE start_function. */ + push_scope (); + declare_parm_level (); + + /* Generate prototype declarations for arguments..."new-style". */ + synth_self_and_ucmd_args (); /* Generate argument declarations if a keyword_decl. */ if (METHOD_SEL_ARGS (method)) @@ -7063,7 +7540,7 @@ start_method_def (method) if (arg_decl) { - tree last_expr = expr_last (arg_decl); + tree last_expr = objc_expr_last (arg_decl); /* Unite the abstract decl with its name. */ TREE_OPERAND (last_expr, 0) = KEYWORD_ARG_NAME (arglist); @@ -7071,8 +7548,10 @@ start_method_def (method) (build_tree_list (arg_spec, arg_decl), NULL_TREE)); +#ifndef OBJCPLUS /* Unhook: restore the abstract declarator. */ TREE_OPERAND (last_expr, 0) = NULL_TREE; +#endif } else @@ -7103,26 +7582,17 @@ start_method_def (method) } static void -warn_with_method (message, mtype, method) - const char *message; - int mtype; - tree method; +warn_with_method (const char *message, int mtype, tree method) { - if (!diagnostic_count_diagnostic (global_dc, DK_WARNING)) - return; - - diagnostic_report_current_function (global_dc); - /* Add a readable method name to the warning. */ - warning ("%H%s `%c%s'", &DECL_SOURCE_LOCATION (method), + warning ("%J%s `%c%s'", method, message, mtype, gen_method_decl (method, errbuf)); } /* Return 1 if METHOD is consistent with PROTO. */ static int -comp_method_with_proto (method, proto) - tree method, proto; +comp_method_with_proto (tree method, tree proto) { /* Create a function template node at most once. */ if (!function1_template) @@ -7134,30 +7604,61 @@ comp_method_with_proto (method, proto) /* install return type */ TREE_TYPE (function1_template) = groktypename (TREE_TYPE (proto)); - return comptypes (TREE_TYPE (METHOD_DEFINITION (method)), function1_template); + return comptypes (TREE_TYPE (METHOD_DEFINITION (method)), function1_template, + false); } -/* Return 1 if PROTO1 is consistent with PROTO2. */ +/* Return 1 if TYPE1 is equivalent to TYPE2. */ static int -comp_proto_with_proto (proto0, proto1) - tree proto0, proto1; +objc_types_are_equivalent (tree type1, tree type2) { - /* 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); + if (type1 == type2) + return 1; + if (TYPE_MAIN_VARIANT (type1) != TYPE_MAIN_VARIANT (type2)) + return 0; + type1 = TYPE_PROTOCOL_LIST (type1); + type2 = TYPE_PROTOCOL_LIST (type2); + if (list_length (type1) == list_length (type2)) + { + for (; type2; type2 = TREE_CHAIN (type2)) + if (!lookup_protocol_in_reflist (type1, TREE_VALUE (type2))) + return 0; + return 1; + } + return 0; +} + +/* Return 1 if PROTO1 is equivalent to PROTO2. */ + +static int +comp_proto_with_proto (tree proto1, tree proto2) +{ + tree type1, type2; + + /* The following test is needed in case there are hashing + collisions. */ + if (METHOD_SEL_NAME (proto1) != METHOD_SEL_NAME (proto2)) + return 0; - /* Install argument types; normally set by build_function_type. */ - 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); + /* Compare return types. */ + type1 = groktypename (TREE_TYPE (proto1)); + type2 = groktypename (TREE_TYPE (proto2)); - /* Install return type. */ - TREE_TYPE (function1_template) = groktypename (TREE_TYPE (proto0)); - TREE_TYPE (function2_template) = groktypename (TREE_TYPE (proto1)); + if (!objc_types_are_equivalent (type1, type2)) + return 0; + + /* Compare argument types. */ + for (type1 = get_arg_type_list (proto1, METHOD_REF, 0), + type2 = get_arg_type_list (proto2, METHOD_REF, 0); + type1 && type2; + type1 = TREE_CHAIN (type1), type2 = TREE_CHAIN (type2)) + { + if (!objc_types_are_equivalent (TREE_VALUE (type1), TREE_VALUE (type2))) + return 0; + } - return comptypes (function1_template, function2_template); + return (!type1 && !type2); } /* - Generate an identifier for the function. the format is "_n_cls", @@ -7167,8 +7668,7 @@ comp_proto_with_proto (proto0, proto1) - If we have a prototype, check for type consistency. */ static void -really_start_method (method, parmlist) - tree method, parmlist; +really_start_method (tree method, tree parmlist) { tree sc_spec, ret_spec, ret_decl, decl_specs; tree method_decl, method_id; @@ -7197,6 +7697,12 @@ really_start_method (method, parmlist) method_id = get_identifier (buf); +#ifdef OBJCPLUS + /* Objective-C methods cannot be overloaded, so we don't need + the type encoding appended. It looks bad anyway... */ + push_lang_context (lang_name_c); +#endif + method_decl = build_nt (CALL_EXPR, method_id, parmlist, NULL_TREE); /* Check the declarator portion of the return type for the method. */ @@ -7204,7 +7710,7 @@ really_start_method (method, parmlist) { /* Unite the complex decl (specified in the abstract decl) with the function decl just synthesized..(int *), (int (*)()), (int (*)[]). */ - tree save_expr = expr_last (ret_decl); + tree save_expr = objc_expr_last (ret_decl); TREE_OPERAND (save_expr, 0) = method_decl; method_decl = ret_decl; @@ -7227,75 +7733,93 @@ really_start_method (method, parmlist) TREE_VALUE (TREE_TYPE (method)) = NULL_TREE; } +#ifdef OBJCPLUS + /* set self_decl from the first argument...this global is used by + * build_ivar_reference().build_indirect_ref(). + */ + self_decl = DECL_ARGUMENTS (current_function_decl); + + /* snaroff (3/28/96): when compiling with -Wall, this suppresses + * the following: warning:unused parameter `struct objc_selector * _cmd' + */ + TREE_USED (self_decl) = 1; + TREE_USED (TREE_CHAIN (self_decl)) = 1; + /* Ditto for the underlying (static) C function. */ + TREE_USED (current_function_decl) = 1; + pop_lang_context (); +#endif + METHOD_DEFINITION (method) = current_function_decl; /* Check consistency...start_function, pushdecl, duplicate_decls. */ if (implementation_template != objc_implementation_context) { - tree proto; - - if (TREE_CODE (method) == INSTANCE_METHOD_DECL) - proto = lookup_instance_method_static (implementation_template, - METHOD_SEL_NAME (method)); - else - proto = lookup_class_method_static (implementation_template, - METHOD_SEL_NAME (method)); + tree proto + = lookup_method_static (implementation_template, + METHOD_SEL_NAME (method), + TREE_CODE (method) == CLASS_METHOD_DECL); - if (proto && ! comp_method_with_proto (method, proto)) + if (proto) { - char type = (TREE_CODE (method) == INSTANCE_METHOD_DECL ? '-' : '+'); + if (!comp_method_with_proto (method, proto)) + { + char type = (TREE_CODE (method) == INSTANCE_METHOD_DECL ? '-' : '+'); - warn_with_method ("conflicting types for", type, method); - warn_with_method ("previous declaration of", type, proto); + warn_with_method ("conflicting types for", type, method); + warn_with_method ("previous declaration of", type, proto); + } + } + else + { + /* We have a method @implementation even though we did not + see a corresponding @interface declaration (which is allowed + by Objective-C rules). Go ahead and place the method in + the @interface anyway, so that message dispatch lookups + will see it. */ + tree interface = implementation_template; + + if (TREE_CODE (objc_implementation_context) + == CATEGORY_IMPLEMENTATION_TYPE) + interface = lookup_category + (interface, + CLASS_SUPER_NAME (objc_implementation_context)); + + if (interface) + objc_add_method (interface, copy_node (method), + TREE_CODE (method) == CLASS_METHOD_DECL); } } } /* The following routine is always called...this "architecture" is to accommodate "old-style" variable length selectors. - + - a:a b:b // prototype ; id c; id d; // old-style. */ void -continue_method_def () +continue_method_def (void) { tree parmlist; if (METHOD_ADD_ARGS (objc_method_context) == objc_ellipsis_node) /* We have a `, ...' immediately following the selector. */ - parmlist = get_parm_info (0); + parmlist = get_parm_info (/*ellipsis=*/true); else - parmlist = get_parm_info (1); /* place a `void_at_end' */ + parmlist = get_parm_info (/*ellipsis=*/false); +#ifndef OBJCPLUS /* Set self_decl from the first argument...this global is used by build_ivar_reference calling build_indirect_ref. */ self_decl = TREE_PURPOSE (parmlist); +#endif /* !OBJCPLUS */ - poplevel (0, 0, 0); + pop_scope (); really_start_method (objc_method_context, parmlist); store_parm_decls (); } -/* Called by the parser, from the `pushlevel' production. */ - -void -add_objc_decls () -{ - if (!UOBJC_SUPER_decl) - { - UOBJC_SUPER_decl = start_decl (get_identifier (UTAG_SUPER), - build_tree_list (NULL_TREE, - objc_super_template), - 0, NULL_TREE); - - finish_decl (UOBJC_SUPER_decl, NULL_TREE, NULL_TREE); - - /* This prevents `unused variable' warnings when compiling with -Wall. */ - TREE_USED (UOBJC_SUPER_decl) = 1; - DECL_ARTIFICIAL (UOBJC_SUPER_decl) = 1; - } -} +static void *UOBJC_SUPER_scope = 0; /* _n_Method (id self, SEL sel, ...) { @@ -7304,20 +7828,41 @@ add_objc_decls () } */ tree -get_super_receiver () +get_super_receiver (void) { if (objc_method_context) { tree super_expr, super_expr_list; + if (!UOBJC_SUPER_decl) + { + UOBJC_SUPER_decl = start_decl (get_identifier (TAG_SUPER), + build_tree_list (NULL_TREE, + objc_super_template), + 0, NULL_TREE); + + finish_decl (UOBJC_SUPER_decl, NULL_TREE, NULL_TREE); + + /* This prevents `unused variable' warnings when compiling with -Wall. */ + TREE_USED (UOBJC_SUPER_decl) = 1; + DECL_ARTIFICIAL (UOBJC_SUPER_decl) = 1; + + UOBJC_SUPER_scope = get_current_scope (); + } + /* Set receiver to self. */ super_expr = build_component_ref (UOBJC_SUPER_decl, self_id); super_expr = build_modify_expr (super_expr, NOP_EXPR, self_decl); super_expr_list = build_tree_list (NULL_TREE, super_expr); /* Set class to begin searching. */ +#ifdef OBJCPLUS + super_expr = build_component_ref (UOBJC_SUPER_decl, + get_identifier ("super_class")); +#else super_expr = build_component_ref (UOBJC_SUPER_decl, get_identifier ("class")); +#endif if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE) { @@ -7345,17 +7890,18 @@ get_super_receiver () return error_mark_node; } - if (flag_next_runtime) + if (flag_next_runtime && !flag_zero_link) { super_class = get_class_reference (super_name); 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. */ + /* If we are in a class method, we must retrieve the + _metaclass_ for the current class, pointed at by + the class's "isa" pointer. The following assumes that + "isa" is the first ivar in a class (which it must be). */ super_class - = build_component_ref (build_indirect_ref - (build_c_cast (id_type, super_class), "->"), - get_identifier ("isa")); + = build_indirect_ref + (build_c_cast (build_pointer_type (objc_class_type), + super_class), "unary *"); } else { @@ -7372,8 +7918,10 @@ get_super_receiver () IDENTIFIER_POINTER (super_name)))); } - TREE_TYPE (super_class) = TREE_TYPE (ucls_super_ref); - super_expr = build_modify_expr (super_expr, NOP_EXPR, super_class); + super_expr + = build_modify_expr (super_expr, NOP_EXPR, + build_c_cast (TREE_TYPE (super_expr), + super_class)); } chainon (super_expr_list, build_tree_list (NULL_TREE, super_expr)); @@ -7390,74 +7938,45 @@ get_super_receiver () } } -static tree -encode_method_def (func_decl) - tree func_decl; -{ - tree parms; - int stack_size; - HOST_WIDE_INT max_parm_end = 0; - char buffer[40]; - tree result; - - /* Return type. */ - encode_type (TREE_TYPE (TREE_TYPE (func_decl)), - obstack_object_size (&util_obstack), - OBJC_ENCODE_INLINE_DEFS); - - /* Stack size. */ - for (parms = DECL_ARGUMENTS (func_decl); parms; - parms = TREE_CHAIN (parms)) - { - HOST_WIDE_INT parm_end = (forwarding_offset (parms) - + int_size_in_bytes (TREE_TYPE (parms))); - - if (! offset_is_register && parm_end > max_parm_end) - max_parm_end = parm_end; - } - - stack_size = max_parm_end - OBJC_FORWARDING_MIN_OFFSET; - - sprintf (buffer, "%d", stack_size); - obstack_grow (&util_obstack, buffer, strlen (buffer)); - - /* Argument types. */ - for (parms = DECL_ARGUMENTS (func_decl); parms; - parms = TREE_CHAIN (parms)) - { - /* Type. */ - encode_type (TREE_TYPE (parms), - obstack_object_size (&util_obstack), - OBJC_ENCODE_INLINE_DEFS); - - /* Compute offset. */ - sprintf (buffer, "%d", forwarding_offset (parms)); - - /* Indicate register. */ - if (offset_is_register) - obstack_1grow (&util_obstack, '+'); - - obstack_grow (&util_obstack, buffer, strlen (buffer)); - } +/* When exiting a scope, sever links to a 'super' declaration (if any) + therein contained. */ - /* Null terminate string. */ - obstack_1grow (&util_obstack, 0); - result = get_identifier (obstack_finish (&util_obstack)); - obstack_free (&util_obstack, util_firstobj); - return result; +void +objc_clear_super_receiver (void) +{ + if (objc_method_context + && UOBJC_SUPER_scope == get_current_scope ()) { + UOBJC_SUPER_decl = 0; + UOBJC_SUPER_scope = 0; + } } static void -objc_expand_function_end () +objc_expand_function_end (void) { - METHOD_ENCODING (objc_method_context) = encode_method_def (current_function_decl); + /* This routine may also get called for C functions, including those + nested within ObjC methods. In such cases, method encoding is + meaningless. */ + if (objc_method_context == NULL_TREE + || DECL_INITIAL (objc_method_context) != current_function_decl) + return; + + METHOD_ENCODING (objc_method_context) + = encode_method_prototype (objc_method_context); } void -finish_method_def () +finish_method_def (void) { lang_expand_function_end = objc_expand_function_end; - finish_function (0, 1); + /* We cannot validly inline ObjC methods, at least not without a language + extension to declare that a method need not be dynamically + dispatched, so suppress all thoughts of doing so. */ + DECL_INLINE (current_function_decl) = 0; + DECL_UNINLINABLE (current_function_decl) = 1; + current_function_cannot_inline = "methods cannot be inlined"; + + finish_function (); lang_expand_function_end = NULL; /* Required to implement _msgSuper. This must be done AFTER finish_function, @@ -7467,8 +7986,7 @@ finish_method_def () #if 0 int -lang_report_error_function (decl) - tree decl; +lang_report_error_function (tree decl) { if (objc_method_context) { @@ -7483,8 +8001,7 @@ lang_report_error_function (decl) #endif static int -is_complex_decl (type) - tree type; +is_complex_decl (tree type) { return (TREE_CODE (type) == ARRAY_TYPE || TREE_CODE (type) == FUNCTION_TYPE @@ -7497,9 +8014,7 @@ is_complex_decl (type) static char tmpbuf[256]; static void -adorn_decl (decl, str) - tree decl; - char *str; +adorn_decl (tree decl, char *str) { enum tree_code code = TREE_CODE (decl); @@ -7599,10 +8114,7 @@ adorn_decl (decl, str) } static char * -gen_declarator (decl, buf, name) - tree decl; - char *buf; - const char *name; +gen_declarator (tree decl, char *buf, const char *name) { if (decl) { @@ -7691,10 +8203,7 @@ gen_declarator (decl, buf, name) } static void -gen_declspecs (declspecs, buf, raw) - tree declspecs; - char *buf; - int raw; +gen_declspecs (tree declspecs, char *buf, int raw) { if (raw) { @@ -7709,13 +8218,13 @@ gen_declspecs (declspecs, buf, raw) strcat (buf, IDENTIFIER_POINTER (aspec)); else if (TREE_CODE (aspec) == RECORD_TYPE) { - if (TYPE_NAME (aspec)) + if (OBJC_TYPE_NAME (aspec)) { tree protocol_list = TYPE_PROTOCOL_LIST (aspec); if (! TREE_STATIC_TEMPLATE (aspec)) strcat (buf, "struct "); - strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (aspec))); + strcat (buf, IDENTIFIER_POINTER (OBJC_TYPE_NAME (aspec))); /* NEW!!! */ if (protocol_list) @@ -7742,11 +8251,11 @@ gen_declspecs (declspecs, buf, raw) else if (TREE_CODE (aspec) == UNION_TYPE) { - if (TYPE_NAME (aspec)) + if (OBJC_TYPE_NAME (aspec)) { if (! TREE_STATIC_TEMPLATE (aspec)) strcat (buf, "union "); - strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (aspec))); + strcat (buf, IDENTIFIER_POINTER (OBJC_TYPE_NAME (aspec))); } else strcat (buf, "untagged union"); @@ -7754,11 +8263,11 @@ gen_declspecs (declspecs, buf, raw) else if (TREE_CODE (aspec) == ENUMERAL_TYPE) { - if (TYPE_NAME (aspec)) + if (OBJC_TYPE_NAME (aspec)) { if (! TREE_STATIC_TEMPLATE (aspec)) strcat (buf, "enum "); - strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (aspec))); + strcat (buf, IDENTIFIER_POINTER (OBJC_TYPE_NAME (aspec))); } else strcat (buf, "untagged enum"); @@ -7848,14 +8357,14 @@ gen_declspecs (declspecs, buf, raw) break; case RECORD_TYPE: - if (TYPE_NAME (declspecs) - && TREE_CODE (TYPE_NAME (declspecs)) == IDENTIFIER_NODE) + if (OBJC_TYPE_NAME (declspecs) + && TREE_CODE (OBJC_TYPE_NAME (declspecs)) == IDENTIFIER_NODE) { tree protocol_list = TYPE_PROTOCOL_LIST (declspecs); if (! TREE_STATIC_TEMPLATE (declspecs)) strcat (buf, "struct "); - strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (declspecs))); + strcat (buf, IDENTIFIER_POINTER (OBJC_TYPE_NAME (declspecs))); if (protocol_list) { @@ -7882,11 +8391,11 @@ gen_declspecs (declspecs, buf, raw) break; case UNION_TYPE: - if (TYPE_NAME (declspecs) - && TREE_CODE (TYPE_NAME (declspecs)) == IDENTIFIER_NODE) + if (OBJC_TYPE_NAME (declspecs) + && TREE_CODE (OBJC_TYPE_NAME (declspecs)) == IDENTIFIER_NODE) { strcat (buf, "union "); - strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (declspecs))); + strcat (buf, IDENTIFIER_POINTER (OBJC_TYPE_NAME (declspecs))); strcat (buf, " "); } @@ -7895,11 +8404,11 @@ gen_declspecs (declspecs, buf, raw) break; case ENUMERAL_TYPE: - if (TYPE_NAME (declspecs) - && TREE_CODE (TYPE_NAME (declspecs)) == IDENTIFIER_NODE) + if (OBJC_TYPE_NAME (declspecs) + && TREE_CODE (OBJC_TYPE_NAME (declspecs)) == IDENTIFIER_NODE) { strcat (buf, "enum "); - strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (declspecs))); + strcat (buf, IDENTIFIER_POINTER (OBJC_TYPE_NAME (declspecs))); strcat (buf, " "); } @@ -7935,7 +8444,7 @@ gen_declspecs (declspecs, buf, raw) } } break; - + default: break; } @@ -7946,9 +8455,7 @@ gen_declspecs (declspecs, buf, raw) buffer, overwriting the buffer. */ static char * -gen_declaration (atype_or_adecl, buf) - tree atype_or_adecl; - char *buf; +gen_declaration (tree atype_or_adecl, char *buf) { buf[0] = '\0'; gen_declaration_1 (atype_or_adecl, buf); @@ -7959,9 +8466,7 @@ gen_declaration (atype_or_adecl, buf) given buffer. */ static void -gen_declaration_1 (atype_or_adecl, buf) - tree atype_or_adecl; - char *buf; +gen_declaration_1 (tree atype_or_adecl, char *buf) { char declbuf[256]; @@ -7969,9 +8474,17 @@ gen_declaration_1 (atype_or_adecl, buf) { tree declspecs; /* "identifier_node", "record_type" */ tree declarator; /* "array_ref", "indirect_ref", "call_expr"... */ + tree width = NULL_TREE; /* for bitfields */ /* We have a "raw", abstract declarator (typename). */ declarator = TREE_VALUE (atype_or_adecl); + /* In the case of raw ivars, the declarator itself is a list, + and contains bitfield widths. */ + if (declarator && TREE_CODE (declarator) == TREE_LIST) + { + width = TREE_VALUE (declarator); + declarator = TREE_PURPOSE (declarator); + } declspecs = TREE_PURPOSE (atype_or_adecl); gen_declspecs (declspecs, buf, 1); @@ -7980,6 +8493,9 @@ gen_declaration_1 (atype_or_adecl, buf) strcat (buf, " "); strcat (buf, gen_declarator (declarator, declbuf, "")); } + if (width) + sprintf (buf + strlen (buf), ": " HOST_WIDE_INT_PRINT_UNSIGNED, + TREE_INT_CST_LOW (width)); } else @@ -8050,9 +8566,7 @@ gen_declaration_1 (atype_or_adecl, buf) buffer (overwriting) and return a pointer to the buffer. */ static char * -gen_method_decl (method, buf) - tree method; - char *buf; +gen_method_decl (tree method, char *buf) { tree chain; @@ -8119,9 +8633,7 @@ gen_method_decl (method, buf) 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; +dump_interface (FILE *fp, tree chain) { /* FIXME: A heap overflow here whenever a method (or ivar) declaration is so long that it doesn't fit in the buffer. The @@ -8135,13 +8647,13 @@ dump_interface (fp, chain) fprintf (fp, "\n@interface %s", my_name); - /* CLASS_SUPER_NAME is used to store the superclass name for + /* 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 *name = IDENTIFIER_POINTER (CLASS_SUPER_NAME (chain)); - - if (TREE_CODE (chain) == CATEGORY_IMPLEMENTATION_TYPE + + if (TREE_CODE (chain) == CATEGORY_IMPLEMENTATION_TYPE || TREE_CODE (chain) == CATEGORY_INTERFACE_TYPE) { fprintf (fp, " (%s)\n", name); @@ -8184,8 +8696,7 @@ dump_interface (fp, chain) /* Demangle function for Objective-C */ static const char * -objc_demangle (mangled) - const char *mangled; +objc_demangle (const char *mangled) { char *demangled, *cp; @@ -8240,15 +8751,13 @@ objc_demangle (mangled) } const char * -objc_printable_name (decl, kind) - tree decl; - int kind ATTRIBUTE_UNUSED; +objc_printable_name (tree decl, int kind ATTRIBUTE_UNUSED) { return objc_demangle (IDENTIFIER_POINTER (DECL_NAME (decl))); } static void -init_objc () +init_objc (void) { gcc_obstack_init (&util_obstack); util_firstobj = (char *) obstack_finish (&util_obstack); @@ -8259,7 +8768,7 @@ init_objc () } static void -finish_objc () +finish_objc (void) { struct imp_entry *impent; tree chain; @@ -8277,12 +8786,6 @@ finish_objc () objc_implementation_context = NULL_TREE; } - generate_forward_declaration_to_string_table (); - -#ifdef OBJC_PROLOGUE - OBJC_PROLOGUE; -#endif - /* Process the static instances here because initialization of objc_symtab depends on them. */ if (objc_static_instances) @@ -8299,7 +8802,7 @@ finish_objc () UOBJC_CLASS_decl = impent->class_decl; UOBJC_METACLASS_decl = impent->meta_decl; - + /* 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 @@ -8308,7 +8811,7 @@ finish_objc () { 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... */ @@ -8331,6 +8834,9 @@ finish_objc () if (protocol_chain) generate_protocols (); + if (flag_replace_objc_classes && imp_list) + generate_objc_image_info (); + if (objc_implementation_context || class_names_chain || objc_static_instances || meth_var_names_chain || meth_var_types_chain || sel_ref_chain) { @@ -8368,36 +8874,12 @@ finish_objc () selector which has multiple methods. */ for (slot = 0; slot < SIZEHASHTABLE; slot++) - for (hsh = cls_method_hash_list[slot]; hsh; hsh = hsh->next) - if (hsh->list) - { - tree meth = hsh->key; - char type = (TREE_CODE (meth) == INSTANCE_METHOD_DECL - ? '-' : '+'); - attr loop; - - warning ("potential selector conflict for method `%s'", - IDENTIFIER_POINTER (METHOD_SEL_NAME (meth))); - warn_with_method ("found", type, meth); - for (loop = hsh->list; loop; loop = loop->next) - warn_with_method ("found", type, loop->value); - } - - for (slot = 0; slot < SIZEHASHTABLE; slot++) - for (hsh = nst_method_hash_list[slot]; hsh; hsh = hsh->next) - if (hsh->list) - { - tree meth = hsh->key; - char type = (TREE_CODE (meth) == INSTANCE_METHOD_DECL - ? '-' : '+'); - attr loop; - - warning ("potential selector conflict for method `%s'", - IDENTIFIER_POINTER (METHOD_SEL_NAME (meth))); - warn_with_method ("found", type, meth); - for (loop = hsh->list; loop; loop = loop->next) - warn_with_method ("found", type, loop->value); - } + { + for (hsh = cls_method_hash_list[slot]; hsh; hsh = hsh->next) + check_duplicates (hsh, 0, 1); + for (hsh = nst_method_hash_list[slot]; hsh; hsh = hsh->next) + check_duplicates (hsh, 0, 1); + } } warn_missing_braces = save_warn_missing_braces; @@ -8406,8 +8888,7 @@ finish_objc () /* Subroutines of finish_objc. */ static void -generate_classref_translation_entry (chain) - tree chain; +generate_classref_translation_entry (tree chain) { tree expr, name, decl_specs, decl, sc_spec; tree type; @@ -8433,8 +8914,7 @@ generate_classref_translation_entry (chain) } static void -handle_class_ref (chain) - tree chain; +handle_class_ref (tree chain) { const char *name = IDENTIFIER_POINTER (TREE_VALUE (chain)); char *string = (char *) alloca (strlen (name) + 30); @@ -8474,8 +8954,7 @@ handle_class_ref (chain) } static void -handle_impent (impent) - struct imp_entry *impent; +handle_impent (struct imp_entry *impent) { char *string; @@ -8536,10 +9015,41 @@ handle_impent (impent) } } +/* The Fix-and-Continue functionality available in Mac OS X 10.3 and + later requires that ObjC translation units participating in F&C be + specially marked. The following routine accomplishes this. */ + +/* static int _OBJC_IMAGE_INFO[2] = { 0, 1 }; */ + +static void +generate_objc_image_info (void) +{ + tree sc_spec, decl, initlist; + + sc_spec = build_tree_list (NULL_TREE, ridpointers[(int) RID_STATIC]); + decl + = start_decl (get_identifier ("_OBJC_IMAGE_INFO"), + tree_cons (NULL_TREE, + build_array_type + (integer_type_node, + build_index_type (build_int_2 (1, 0))), + sc_spec), + 1, + NULL_TREE); + + initlist = build_tree_list (NULL_TREE, build_int_2 (0, 0)); + initlist = tree_cons (NULL_TREE, build_int_2 (1, 0), initlist); + initlist = build_constructor (TREE_TYPE (decl), nreverse (initlist)); + + TREE_USED (decl) = DECL_IGNORED_P (decl) = DECL_ARTIFICIAL (decl) = 1; + TREE_CONSTANT (initlist) = TREE_STATIC (initlist) = 1; + finish_decl (decl, initlist, NULL_TREE); +} + /* Look up ID as an instance variable. */ + tree -lookup_objc_ivar (id) - tree id; +lookup_objc_ivar (tree id) { tree decl;