diff options
Diffstat (limited to 'gcc/objc')
-rw-r--r-- | gcc/objc/Make-lang.in | 4 | ||||
-rw-r--r-- | gcc/objc/lang-specs.h | 4 | ||||
-rw-r--r-- | gcc/objc/objc-act.c | 3221 | ||||
-rw-r--r-- | gcc/objc/objc-act.h | 91 | ||||
-rw-r--r-- | gcc/objc/objc-tree.def | 4 |
5 files changed, 2110 insertions, 1214 deletions
diff --git a/gcc/objc/Make-lang.in b/gcc/objc/Make-lang.in index 30ec482..c716e73 100644 --- a/gcc/objc/Make-lang.in +++ b/gcc/objc/Make-lang.in @@ -86,8 +86,8 @@ $(parsedir)/objc/objc-parse.c : $(parsedir)/objc/objc-parse.y $(parsedir)/objc/objc-parse.y: $(srcdir)/c-parse.in echo '/*WARNING: This file is automatically generated!*/' >tmp-objc-prs.y - sed -e "/^ifc$$/,/^end ifc$$/d" \ - -e "/^ifobjc$$/d" -e "/^end ifobjc$$/d" \ + sed -e "/^@@ifc.*/,/^@@end_ifc.*/d" \ + -e "/^@@ifobjc.*/d" -e "/^@@end_ifobjc.*/d" \ $(srcdir)/c-parse.in >>tmp-objc-prs.y $(SHELL) $(srcdir)/move-if-change tmp-objc-prs.y $(parsedir)/objc/objc-parse.y diff --git a/gcc/objc/lang-specs.h b/gcc/objc/lang-specs.h index 7c78420..39cbe5c 100644 --- a/gcc/objc/lang-specs.h +++ b/gcc/objc/lang-specs.h @@ -39,8 +39,8 @@ Boston, MA 02111-1307, USA. */ "%{!M:%{!MM:%{!E:cc1obj -fpreprocessed %i %(cc1_options) %{gen-decls}\ %{!fsyntax-only:%(invoke_as)}}}}", 0}, {"@objective-c-header", - "%{E|M|MM:%(trad_capable_cpp)\ - -lang-objc %(cpp_options) %(cpp_debug_options)}\ + "%{E|M|MM:cc1obj -E %{traditional|ftraditional|traditional-cpp:-traditional-cpp}\ + %(cpp_options) %(cpp_debug_options)}\ %{!E:%{!M:%{!MM:\ %{traditional|ftraditional|traditional-cpp:\ %eGNU Objective C no longer supports traditional compilation}\ diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 0c07543..40c7004 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -62,6 +62,8 @@ Boston, MA 02111-1307, USA. */ #include "diagnostic.h" #include "cgraph.h" +#define OBJC_VOID_AT_END build_tree_list (NULL_TREE, void_type_node) + /* This is the default way of generating a method name. */ /* I am not sure it is really correct. Perhaps there's a danger that it will make name conflicts @@ -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 @@ -111,7 +110,7 @@ char *util_firstobj; #define PROTOCOL_VERSION 2 /* (Decide if these can ever be validly changed.) */ -#define OBJC_ENCODE_INLINE_DEFS 0 +#define OBJC_ENCODE_INLINE_DEFS 0 #define OBJC_ENCODE_DONT_INLINE_DEFS 1 /*** Private Interface (procedures) ***/ @@ -127,24 +126,35 @@ 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, 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 build_super_template (void); +static tree lookup_method_in_hash_lists (tree); +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); @@ -172,8 +182,7 @@ 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_instance_method_static (tree, tree); -static tree lookup_class_method_static (tree, tree); +static tree lookup_method_static (tree, tree, int); static tree add_class (tree); static void add_category (tree, tree); @@ -202,15 +211,18 @@ 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_bitfield (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. */ @@ -231,11 +243,12 @@ 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 void build_string_class_template (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); @@ -247,12 +260,11 @@ 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 int forwarding_offset (tree); -static tree encode_method_prototype (tree, tree); +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 tree build_tmp_function_decl (void); -static void hack_method_prototype (tree, tree); static void generate_protocol_references (tree); static void generate_protocols (void); static void check_ivars (tree, tree); @@ -262,25 +274,24 @@ 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 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); -static tree receiver_is_class_object (tree); +static tree check_duplicates (hash, 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 tree encode_method_def (tree); 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 (int, tree, int); static void mark_referenced_methods (void); +static void generate_objc_image_info (void); /*** Private Interface (data) ***/ @@ -309,7 +320,7 @@ static void mark_referenced_methods (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" @@ -317,9 +328,60 @@ 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]; @@ -329,7 +391,8 @@ 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 @@ -444,6 +507,8 @@ objc_init (void) 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"; } @@ -453,6 +518,8 @@ objc_init (void) 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; @@ -491,18 +558,6 @@ define_decl (tree declarator, tree declspecs) 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 (tree rproto_list, tree sel_name, int class_meth) @@ -674,7 +729,7 @@ objc_comptypes (tree lhs, tree rhs, int reflexive) /* <Protocol> = <class> * */ 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 @@ -715,18 +770,18 @@ objc_comptypes (tree lhs, tree rhs, int 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; } /* <Protocol> = id */ - else if (TYPE_NAME (TREE_TYPE (rhs)) == objc_object_id) + else if (OBJC_TYPE_NAME (TREE_TYPE (rhs)) == objc_object_id) { return 1; } /* <Protocol> = Class */ - else if (TYPE_NAME (TREE_TYPE (rhs)) == objc_class_id) + else if (OBJC_TYPE_NAME (TREE_TYPE (rhs)) == objc_class_id) { return 0; } @@ -740,7 +795,7 @@ objc_comptypes (tree lhs, tree rhs, int 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); @@ -781,14 +836,14 @@ objc_comptypes (tree lhs, tree rhs, int reflexive) p); cat = CLASS_CATEGORY_LIST (cat); } - + rinter = lookup_interface (CLASS_SUPER_NAME (rinter)); } - + if (!lproto) warning ("class `%s' does not implement the `%s' protocol", - IDENTIFIER_POINTER (TYPE_NAME + IDENTIFIER_POINTER (OBJC_TYPE_NAME (TREE_TYPE (lhs))), IDENTIFIER_POINTER (PROTOCOL_NAME (p))); } @@ -798,12 +853,12 @@ objc_comptypes (tree lhs, tree rhs, int reflexive) return 0; } /* id = <Protocol> */ - else if (TYPE_NAME (TREE_TYPE (lhs)) == objc_object_id) + else if (OBJC_TYPE_NAME (TREE_TYPE (lhs)) == objc_object_id) { return 1; } /* Class = <Protocol> */ - else if (TYPE_NAME (TREE_TYPE (lhs)) == objc_class_id) + else if (OBJC_TYPE_NAME (TREE_TYPE (lhs)) == objc_class_id) { return 0; } @@ -836,24 +891,24 @@ objc_comptypes (tree lhs, tree rhs, int reflexive) 'Object *o = [[Object alloc] init]; falls in the case <class> * = `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 (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) @@ -880,17 +935,19 @@ objc_comptypes (tree lhs, tree rhs, int reflexive) return -1; } -/* Called from c-decl.c before all calls to rest_of_decl_compilation. */ +/* Called from finish_decl. */ void objc_check_decl (tree decl) { tree type = TREE_TYPE (decl); - if (TREE_CODE (type) == RECORD_TYPE - && TREE_STATIC_TEMPLATE (type) + if (TREE_CODE (type) != RECORD_TYPE) + return; + if (TYPE_NAME (type) && (type = is_class_name (TYPE_NAME (type))) && type != constant_string_type) - error ("%J'%D' cannot be statically allocated", decl, decl); + error ("statically allocated instance of Objective-C class `%s'", + IDENTIFIER_POINTER (type)); } /* Implement static typing. At this point, we know we have an interface. */ @@ -997,12 +1054,14 @@ check_protocol_recursively (tree proto, tree list) } } +/* Look up PROTOCOLS, and return a list of those that are found. + If none are found, return NULL. */ + static tree 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)) { @@ -1010,20 +1069,11 @@ lookup_and_install_protocols (tree 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; @@ -1043,9 +1093,9 @@ create_builtin_decl (enum tree_code code, tree type, const char *name) TREE_STATIC (decl) = 1; make_decl_rtl (decl, 0); pushdecl (decl); + DECL_ARTIFICIAL (decl) = 1; } - DECL_ARTIFICIAL (decl) = 1; return decl; } @@ -1057,7 +1107,17 @@ 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); } } @@ -1077,7 +1137,6 @@ static void synth_module_prologue (void) { tree temp_type; - tree super_p; /* Defined in `objc.h' */ objc_object_id = get_identifier (TAG_OBJECT); @@ -1090,8 +1149,10 @@ synth_module_prologue (void) 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. */ @@ -1103,7 +1164,8 @@ synth_module_prologue (void) /* Forward declare type, or else the prototype for msgSendSuper will complain. */ - 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))); @@ -1128,14 +1190,21 @@ synth_module_prologue (void) pushdecl (umsg_decl); } else - umsg_decl = builtin_function (TAG_MSGSEND, temp_type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); + { + umsg_decl = builtin_function (TAG_MSGSEND, + temp_type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + /* id objc_msgSendNonNil (id, SEL, ...); */ + umsg_nonnil_decl = builtin_function (TAG_MSGSEND_NONNIL, + 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, super_type, tree_cons (NULL_TREE, selector_type, NULL_TREE))); @@ -1143,13 +1212,68 @@ synth_module_prologue (void) temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + /* The NeXT runtime defines the following additional entry points, + used for dispatching calls to methods returning structs: + + #if defined(__cplusplus) + id objc_msgSend_stret(id self, SEL op, ...); + id objc_msgSendSuper_stret(struct objc_super *super, SEL op, ...); + #else + void objc_msgSend_stret(void * stretAddr, id self, SEL op, ...); + void objc_msgSendSuper_stret(void * stretAddr, struct objc_super *super, + SEL op, ...); + #endif + + struct objc_return_struct objc_msgSendNonNil_stret(id self, SEL op, ...); + + These prototypes appear in <objc/objc-runtime.h>; however, they + CANNOT BE USED DIRECTLY. In order to call one of the ..._stret + 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. */ + + if (flag_next_runtime) + { + tree objc_return_struct_type + = xref_tag (RECORD_TYPE, + get_identifier (TAG_RETURN_STRUCT)); + + tree stret_temp_type + = build_function_type (id_type, + tree_cons (NULL_TREE, id_type, + tree_cons (NULL_TREE, selector_type, + NULL_TREE))); + + umsg_stret_decl = builtin_function (TAG_MSGSEND_STRET, + stret_temp_type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + stret_temp_type + = build_function_type (objc_return_struct_type, + tree_cons (NULL_TREE, id_type, + tree_cons (NULL_TREE, selector_type, + NULL_TREE))); + + umsg_nonnil_stret_decl = builtin_function (TAG_MSGSEND_NONNIL_STRET, + stret_temp_type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + + stret_temp_type + = build_function_type (id_type, + tree_cons (NULL_TREE, super_type, + tree_cons (NULL_TREE, selector_type, + NULL_TREE))); + + umsg_super_stret_decl = builtin_function (TAG_MSGSENDSUPER_STRET, + stret_temp_type, 0, NOT_BUILT_IN, 0, + 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, + OBJC_VOID_AT_END)); objc_get_class_decl = builtin_function (TAG_GETCLASS, temp_type, 0, NOT_BUILT_IN, @@ -1158,8 +1282,11 @@ synth_module_prologue (void) /* 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[]; */ @@ -1199,10 +1326,21 @@ synth_module_prologue (void) 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 { @@ -1211,25 +1349,32 @@ synth_module_prologue (void) unsigned int length; }; */ -static void -build_string_class_template (void) +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; + + field_decl = TREE_CHAIN (field_decl); + return AT_LEAST_AS_LARGE_AS (field_decl, unsigned_type_node); - finish_struct (constant_string_type, field_decl_chain, NULL_TREE); +#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 @@ -1238,34 +1383,47 @@ my_build_string (int len, const char *str) return fix_string_type (build_string (len, str)); } -/* Build a static instance of NXConstantString which points at the - string constant STRING. - 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. */ +/* 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. */ tree build_objc_string_object (tree string) { - tree 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); - + /* 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 }) */ @@ -1308,6 +1466,7 @@ build_objc_string_object (tree string) /* Declare a static instance of CLASS_DECL initialized by CONSTRUCTOR. */ static GTY(()) int num_static_inst; + static tree objc_add_static_instance (tree constructor, tree class_decl) { @@ -1322,7 +1481,7 @@ objc_add_static_instance (tree constructor, tree 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++); @@ -1375,6 +1534,11 @@ objc_build_constructor (tree type, tree 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; } @@ -1394,7 +1558,7 @@ objc_build_constructor (tree type, tree elts) static void 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)); @@ -1427,18 +1591,20 @@ build_objc_symtab_template (void) "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); } @@ -1519,7 +1685,7 @@ init_objc_symtab (tree 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); @@ -1532,6 +1698,26 @@ init_objc_symtab (tree 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_<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. */ @@ -1547,16 +1733,15 @@ forward_declare_categories (void) { /* 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))); - TREE_PUBLIC (impent->class_decl) = 0; + /* extern struct objc_category _OBJC_CATEGORY_<name>; */ + 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 @@ -1706,7 +1891,8 @@ build_module_descriptor (void) get_identifier (TAG_EXECCLASS), build_function_type (void_type_node, tree_cons (NULL_TREE, ptr_type_node, - void_list_node_1))); + OBJC_VOID_AT_END))); + DECL_EXTERNAL (execclass_decl) = 1; DECL_ARTIFICIAL (execclass_decl) = 1; TREE_PUBLIC (execclass_decl) = 1; @@ -1720,7 +1906,7 @@ build_module_descriptor (void) start_function (void_list_node_1, build_nt (CALL_EXPR, init_function_name, tree_cons (NULL_TREE, NULL_TREE, - void_list_node_1), + OBJC_VOID_AT_END), NULL_TREE), NULL_TREE); store_parm_decls (); @@ -1821,7 +2007,7 @@ generate_static_references (void) /* 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)); @@ -1920,6 +2106,7 @@ generate_strings (void) } static GTY(()) int selector_reference_idx; + static tree build_selector_reference_decl (void) { @@ -1934,7 +2121,6 @@ build_selector_reference_decl (void) DECL_EXTERNAL (decl) = 1; TREE_PUBLIC (decl) = 0; TREE_USED (decl) = 1; - TREE_READONLY (decl) = 1; DECL_ARTIFICIAL (decl) = 1; DECL_CONTEXT (decl) = 0; @@ -2054,15 +2240,11 @@ 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); @@ -2131,6 +2313,7 @@ build_selector_reference (tree ident) } static GTY(()) int class_reference_idx; + static tree build_class_reference_decl (void) { @@ -2145,7 +2328,6 @@ build_class_reference_decl (void) DECL_EXTERNAL (decl) = 1; TREE_PUBLIC (decl) = 0; TREE_USED (decl) = 1; - TREE_READONLY (decl) = 1; DECL_CONTEXT (decl) = 0; DECL_ARTIFICIAL (decl) = 1; @@ -2189,7 +2371,25 @@ add_class_reference (tree ident) tree 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; @@ -2277,7 +2477,6 @@ build_objc_string_decl (enum string_section section) DECL_EXTERNAL (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; @@ -2292,34 +2491,49 @@ build_objc_string_decl (enum string_section section) void 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 (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 ("%Jprevious declaration of '%D'", decl, decl); - } + 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); } @@ -2331,6 +2545,21 @@ 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; @@ -2349,14 +2578,23 @@ is_class_name (tree 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 (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 @@ -2364,30 +2602,70 @@ 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 (<classname>) 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 (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) { @@ -2411,7 +2689,7 @@ get_class_ivars (tree 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); @@ -2422,9 +2700,691 @@ get_class_ivars (tree interface) ivar_chain = head; } } + return ivar_chain; } +static tree +objc_enter_block (void) +{ + tree block; + +#ifdef OBJCPLUS + block = begin_compound_stmt (0); +#else + block = c_begin_compound_stmt (); + pushlevel (0); + clear_last_expr (); + add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0); +#endif + + objc_exception_block_stack = tree_cons (NULL_TREE, block, + objc_exception_block_stack); + + blk_nesting_count++; + return block; +} + +static tree +objc_exit_block (void) +{ + tree block = TREE_VALUE (objc_exception_block_stack); +#ifndef OBJCPLUS + tree scope_stmt, inner; +#endif + + objc_clear_super_receiver (); +#ifdef OBJCPLUS + finish_compound_stmt (0, block); +#else + scope_stmt = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0); + inner = poplevel (KEEP_MAYBE, 1, 0); + + 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); + + blk_nesting_count--; + return block; +} + +static tree +objc_declare_variable (enum rid scspec, tree name, tree type, tree init) +{ + tree decl; + + 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; +} + +tree +objc_build_throw_stmt (tree throw_expr) +{ + tree func_params; + + if (!flag_objc_exceptions) + fatal_error ("Use `-fobjc-exceptions' to enable Objective-C exception syntax"); + + if (!throw_expr && objc_caught_exception) + throw_expr = TREE_VALUE (objc_caught_exception); + + if (!throw_expr) + { + error ("`@throw;' (rethrow) used outside of a `@catch' block"); + return error_mark_node; + } + + func_params = tree_cons (NULL_TREE, throw_expr, NULL_TREE); + + assemble_external (objc_exception_throw_decl); + return c_expand_expr_stmt (build_function_call (objc_exception_throw_decl, + func_params)); +} + +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; +} + +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 <setjmp.h> 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 (c_common_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 (c_common_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 (c_common_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 () +{ + /* { // 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 (c_common_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 + (c_common_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 = <sync_expr>; + @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 + <setjmp.h> 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 <setjmp.h>, this shall be superceded 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), + OBJC_VOID_AT_END)); + 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), + OBJC_VOID_AT_END)); + 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, + OBJC_VOID_AT_END)); + 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, + OBJC_VOID_AT_END))); + 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 <classname> { struct objc_class *isa; ... @@ -2443,8 +3403,7 @@ build_private_template (tree class) else { uprivate_record = start_struct (RECORD_TYPE, CLASS_NAME (class)); - - ivar_context = get_class_ivars (class); + ivar_context = get_class_ivars (class, 0); finish_struct (uprivate_record, ivar_context, NULL_TREE); @@ -2626,115 +3585,97 @@ build_method_prototype_template (void) 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 (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); + int sz = int_size_in_bytes (type); - /* ??? 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; - - 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 (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)); - - /* Indicate register. */ - if (offset_is_register) - obstack_1grow (&util_obstack, '+'); + sprintf (buf, "%d", parm_offset); + parm_offset += objc_encoded_type_size (type); 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); @@ -2822,103 +3763,6 @@ generate_method_descriptors (tree 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 (void) -{ - tree decl_specs, expr_decl, parms; - char buffer[80]; - tree tmp_decl; - - /* 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); - - tmp_decl = define_decl (expr_decl, decl_specs); - DECL_SOURCE_LINE (tmp_decl) = 0; - - return tmp_decl; -} - -/* 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 (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); - - /* 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 (tree plist) { @@ -2955,7 +3799,7 @@ generate_protocol_references (tree plist) 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, @@ -2978,16 +3822,15 @@ generate_protocol_references (tree 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 (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 (); @@ -3012,8 +3855,7 @@ generate_protocols (void) { 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); @@ -3023,8 +3865,7 @@ generate_protocols (void) { 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; } @@ -3234,9 +4075,16 @@ build_selector_template (void) 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 (void) { @@ -3357,12 +4205,16 @@ build_class_template (void) 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 (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; */ @@ -3379,28 +4231,15 @@ build_class_template (void) static void synth_forward_declarations (void) { - tree sc_spec, decl_specs, an_id; + tree an_id; /* static struct objc_class _OBJC_CLASS_<my_name>; */ - - 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; - TREE_PUBLIC (UOBJC_CLASS_decl) = 0; + UOBJC_CLASS_decl = build_metadata_decl ("_OBJC_CLASS", + objc_class_template); /* static struct objc_class _OBJC_METACLASS_<my_name>; */ - - an_id = synth_id_with_class_suffix ("_OBJC_METACLASS", - objc_implementation_context); - - UOBJC_METACLASS_decl = define_decl (an_id, decl_specs); - TREE_USED (UOBJC_METACLASS_decl) = 1; - DECL_ARTIFICIAL (UOBJC_METACLASS_decl) = 1; - TREE_PUBLIC (UOBJC_METACLASS_decl) = 0; + UOBJC_METACLASS_decl = build_metadata_decl ("_OBJC_METACLASS", + objc_class_template); /* Pre-build the following entities - for speed/convenience. */ @@ -3412,7 +4251,9 @@ synth_forward_declarations (void) static void error_with_ivar (const char *message, tree decl, tree rawdecl) { - error ("%J%s `%s'", decl, message, gen_declaration (rawdecl, errbuf)); + error ("%J%s `%s'", decl, + message, gen_declaration (rawdecl, errbuf)); + } static void @@ -3427,6 +4268,10 @@ check_ivars (tree inter, tree 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) @@ -3437,7 +4282,9 @@ check_ivars (tree inter, tree imp) t1 = TREE_TYPE (intdecls); t2 = TREE_TYPE (impdecls); - if (!comptypes (t1, t2, false)) + 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)) { @@ -3468,16 +4315,23 @@ check_ivars (tree inter, tree 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 +static void build_super_template (void) { - tree record, decl_specs, field_decl, field_decl_chain; + tree decl_specs, field_decl, field_decl_chain; + + /* 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; - record = start_struct (RECORD_TYPE, get_identifier (UTAG_SUPER)); + 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; */ @@ -3496,14 +4350,10 @@ build_super_template (void) 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 { @@ -3672,8 +4522,9 @@ build_ivar_list_initializer (tree type, tree field_decl) 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); @@ -3702,6 +4553,20 @@ generate_ivars_list (tree type, const char *name, int size, tree list) return decl; } +/* Count only the fields occurring in T. */ +static int +ivar_list_length (t) + 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 (void) { @@ -3727,7 +4592,7 @@ generate_ivar_lists (void) 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); @@ -3743,7 +4608,7 @@ generate_ivar_lists (void) 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); @@ -3774,7 +4639,7 @@ build_dispatch_table_initializer (tree type, tree 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), @@ -4106,6 +4971,8 @@ build_category_initializer (tree type, tree cat_name, tree class_name, struct objc_class *sibling_class; } struct objc_protocol_list *protocols; + if (flag_next_runtime) + void *sel_id; void *gc_object_type; }; */ @@ -4187,6 +5054,10 @@ build_shared_structure_initializer (tree type, tree isa, tree super, 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); @@ -4238,7 +5109,6 @@ generate_category (tree cat) UOBJC_CLASS_METHODS_decl, protocol_decl); - TREE_USED (decl) = 1; finish_decl (decl, initlist, NULL_TREE); } @@ -4357,7 +5227,7 @@ synth_id_with_class_suffix (const char *preamble, tree ctxt) { const char *const class_name = IDENTIFIER_POINTER (CLASS_NAME (objc_implementation_context)); - string = alloca (strlen (preamble) + strlen (class_name) + 3); + string = (char *) alloca (strlen (preamble) + strlen (class_name) + 3); sprintf (string, "%s_%s", preamble, IDENTIFIER_POINTER (CLASS_NAME (ctxt))); } @@ -4369,14 +5239,17 @@ synth_id_with_class_suffix (const char *preamble, tree ctxt) = IDENTIFIER_POINTER (CLASS_NAME (objc_implementation_context)); const char *const class_super_name = IDENTIFIER_POINTER (CLASS_SUPER_NAME (objc_implementation_context)); - string = alloca (strlen (preamble) + strlen (class_name) - + strlen (class_super_name) + 3); + string = (char *) alloca (strlen (preamble) + + strlen (class_name) + + strlen (class_super_name) + + 3); sprintf (string, "%s_%s_%s", preamble, class_name, class_super_name); } else if (TREE_CODE (ctxt) == PROTOCOL_INTERFACE_TYPE) { const char *protocol_name = IDENTIFIER_POINTER (PROTOCOL_NAME (ctxt)); - string = alloca (strlen (preamble) + strlen (protocol_name) + 3); + string + = (char *) alloca (strlen (preamble) + strlen (protocol_name) + 3); sprintf (string, "%s_%s", preamble, protocol_name); } else @@ -4492,7 +5365,7 @@ build_keyword_selector (tree selector) len++; } - buf = alloca (len + 1); + buf = (char *) alloca (len + 1); /* Start the buffer out as an empty string. */ buf[0] = '\0'; @@ -4501,7 +5374,13 @@ build_keyword_selector (tree 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 (); @@ -4548,12 +5427,13 @@ build_method_decl (enum tree_code code, tree ret_type, tree selector, #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 (tree meth, int context, int superflag) @@ -4571,6 +5451,11 @@ get_arg_type_list (tree meth, int context, int 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)) { @@ -4590,13 +5475,13 @@ get_arg_type_list (tree meth, int context, int superflag) } else /* finalize the arglist...simulate get_parm_info (1) */ - chainon (arglist, build_tree_list (NULL_TREE, void_type_node)); + chainon (arglist, OBJC_VOID_AT_END); return arglist; } static tree -check_duplicates (hash hsh) +check_duplicates (hash hsh, int methods) { tree meth = NULL_TREE; @@ -4606,14 +5491,16 @@ check_duplicates (hash 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", type, IDENTIFIER_POINTER (METHOD_SEL_NAME (meth))); - warn_with_method ("using", type, meth); + warn_with_method (methods ? "using" : "found", type, meth); for (loop = hsh->list; loop; loop = loop->next) warn_with_method ("also found", type, loop->value); } @@ -4627,51 +5514,53 @@ check_duplicates (hash hsh) used. */ static tree -receiver_is_class_object (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(). Thankfuly, 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; } @@ -4739,9 +5628,29 @@ build_message_expr (tree 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); } +static tree +lookup_method_in_hash_lists (tree sel_name) +{ + hash method_prototype = hash_lookup (nst_method_hash_list, + sel_name); + + if (!method_prototype) + method_prototype = hash_lookup (cls_method_hash_list, + sel_name); + + return check_duplicates (method_prototype, 1); +} + /* 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' @@ -4750,211 +5659,155 @@ build_message_expr (tree mess) tree finish_message_expr (tree receiver, tree sel_name, tree 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, false)) + 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 + = (is_class + ? check_duplicates (hash_lookup (cls_method_hash_list, sel_name), 1) + : lookup_method_in_hash_lists (sel_name)); } - 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); + rprotos = TYPE_PROTOCOL_LIST (rtype); + rtype = lookup_interface (OBJC_TYPE_NAME (rtype)); } - 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); - } - } - - 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 (CLASS_CLS_METHODS (objc_implementation_context), - sel_name); + = 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_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; - - /* 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); + static bool warn_missing_methods = false; - 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; } } @@ -4970,7 +5823,7 @@ finish_message_expr (tree receiver, tree sel_name, tree 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; @@ -4987,73 +5840,68 @@ finish_message_expr (tree receiver, tree sel_name, tree method_params) static tree build_objc_method_call (int super_flag, tree method_prototype, - tree lookup_object, tree object, tree selector, + tree lookup_object, tree selector, tree 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); + 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; - } +#ifdef STRUCT_VALUE + /* 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 ((TREE_CODE (ret_type) == RECORD_TYPE + || TREE_CODE (ret_type) == UNION_TYPE) +#if defined (DEFAULT_PCC_STRUCT_RETURN) && DEFAULT_PCC_STRUCT_RETURN == 0 + && RETURN_IN_MEMORY (ret_type) +#endif + && STRUCT_VALUE == 0) + sender = (super_flag ? umsg_super_stret_decl : + flag_nil_receivers ? umsg_stret_decl : umsg_nonnil_stret_decl); +#endif + 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, @@ -5061,27 +5909,13 @@ build_objc_method_call (int super_flag, tree method_prototype, 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))); } } @@ -5170,7 +6004,7 @@ build_protocol_expr (tree 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); } @@ -5289,8 +6123,10 @@ hash_func (tree sel_name) static void hash_init (void) { - nst_method_hash_list = ggc_calloc (SIZEHASHTABLE, sizeof (hash)); - cls_method_hash_list = 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 @@ -5304,7 +6140,7 @@ hash_enter (hash *hashlist, tree method) hash obj; int slot = hash_func (METHOD_SEL_NAME (method)) % SIZEHASHTABLE; - obj = ggc_alloc (sizeof (struct hashed_entry)); + obj = (hash) ggc_alloc (sizeof (struct hashed_entry)); obj->list = 0; obj->next = hashlist[slot]; obj->key = method; @@ -5334,7 +6170,7 @@ hash_add_attr (hash entry, tree value) { attr obj; - obj = ggc_alloc (sizeof (struct hashed_attribute)); + obj = (attr) ggc_alloc (sizeof (struct hashed_attribute)); obj->next = entry->list; obj->value = value; @@ -5362,189 +6198,108 @@ lookup_method (tree mchain, tree method) } static tree -lookup_instance_method_static (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); + chain = is_class ? CLASS_CLS_METHODS (category) : 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; - } - - 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 (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 (tree class, tree method) +add_method (tree class, tree method, int is_class) { tree mth; hash hsh; - if (!(mth = lookup_method (CLASS_CLS_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_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))); + if (is_class) + { + TREE_CHAIN (method) = CLASS_CLS_METHODS (class); + CLASS_CLS_METHODS (class) = method; + } 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)))) - { - /* Install on a global chain. */ - hash_enter (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); - } - return method; -} - -tree -add_instance_method (tree class, tree method) -{ - tree mth; - hash hsh; - - if (!(mth = lookup_method (CLASS_NST_METHODS (class), method))) - { - /* Put method on list in reverse order. */ - TREE_CHAIN (method) = CLASS_NST_METHODS (class); - CLASS_NST_METHODS (class) = method; + { + 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)))) + if (!(hsh = hash_lookup (is_class + ? cls_method_hash_list + : nst_method_hash_list, METHOD_SEL_NAME (method)))) { /* Install on a global chain. */ - hash_enter (nst_method_hash_list, method); + hash_enter (is_class ? cls_method_hash_list : nst_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); + /* 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; } @@ -5567,7 +6322,11 @@ add_category (tree class, tree category) while (cat) { if (CLASS_SUPER_NAME (cat) == CLASS_SUPER_NAME (category)) +#ifdef OBJCPLUS + error ("duplicate interface declaration for category `%s(%s)'", +#else warning ("duplicate interface declaration for category `%s(%s)'", +#endif IDENTIFIER_POINTER (CLASS_NAME (class)), IDENTIFIER_POINTER (CLASS_SUPER_NAME (category))); cat = CLASS_CATEGORY_LIST (cat); @@ -5586,16 +6345,61 @@ tree 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)) + : "<unnamed>"; + 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 (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) @@ -5620,11 +6424,9 @@ add_instance_variable (tree class, int public, tree declarator, } - 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; } @@ -5666,10 +6468,10 @@ is_public (tree expr, tree 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; } @@ -5687,9 +6489,20 @@ is_public (tree expr, tree 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"); @@ -5911,6 +6724,12 @@ start_class (enum tree_code code, tree class_name, tree super_name, { 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"); @@ -5920,17 +6739,19 @@ start_class (enum tree_code code, tree class_name, tree super_name, } 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 ("%Jprevious declaration of '%D'", decl, decl); + error ("%Jprevious declaration of '%D'", + decl, decl); } if (code == CLASS_IMPLEMENTATION_TYPE) @@ -5949,17 +6770,6 @@ start_class (enum tree_code code, tree class_name, tree super_name, 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; @@ -5998,8 +6808,12 @@ start_class (enum tree_code code, tree class_name, tree super_name, 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); @@ -6032,17 +6846,6 @@ start_class (enum tree_code code, tree class_name, tree super_name, 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; @@ -6083,7 +6886,7 @@ continue_class (tree class) if (!objc_class_template) build_class_template (); - imp_entry = ggc_alloc (sizeof (struct imp_entry)); + imp_entry = (struct imp_entry *) ggc_alloc (sizeof (struct imp_entry)); imp_entry->next = imp_list; imp_entry->imp_context = class; @@ -6105,11 +6908,10 @@ continue_class (tree 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. */ @@ -6178,7 +6980,7 @@ finish_class (tree class) { tree decl_specs; const char *class_name = IDENTIFIER_POINTER (CLASS_NAME (class)); - char *string = alloca (strlen (class_name) + 3); + char *string = (char *) alloca (strlen (class_name) + 3); /* extern struct objc_object *_<my_name>; */ @@ -6220,6 +7022,12 @@ 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); @@ -6243,6 +7051,12 @@ 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) @@ -6320,10 +7134,10 @@ encode_pointer (tree type, int curtype, int format) 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) /* '@' */ { @@ -6361,8 +7175,15 @@ encode_pointer (tree type, int curtype, int 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. */ @@ -6400,117 +7221,68 @@ static void encode_aggregate_within (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); - } - } - + 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 @@ -6522,12 +7294,12 @@ encode_aggregate (tree type, int curtype, int 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; } @@ -6540,18 +7312,11 @@ encode_aggregate (tree type, int curtype, int 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 (int width) +encode_next_bitfield (int width) { char buffer[40]; sprintf (buffer, "b%d", width); @@ -6620,6 +7385,9 @@ encode_type (tree type, int curtype, int format) 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); @@ -6634,7 +7402,7 @@ encode_type (tree type, int curtype, int format) } static void -encode_complete_bitfield (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]; @@ -6694,27 +7462,29 @@ 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 @@ -6728,25 +7498,14 @@ objc_expr_last (tree 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 (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 @@ -6765,6 +7524,23 @@ start_method_def (tree method) (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. */ + pushlevel (0); + + /* Generate prototype declarations for arguments..."new-style". */ + synth_self_and_ucmd_args (); /* Generate argument declarations if a keyword_decl. */ if (METHOD_SEL_ARGS (method)) @@ -6785,8 +7561,10 @@ start_method_def (tree 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 @@ -6820,8 +7598,8 @@ static void warn_with_method (const char *message, int mtype, tree method) { /* Add a readable method name to the warning. */ - warning ("%J%s `%c%s'", method, message, mtype, - gen_method_decl (method, errbuf)); + warning ("%J%s `%c%s'", method, + message, mtype, gen_method_decl (method, errbuf)); } /* Return 1 if METHOD is consistent with PROTO. */ @@ -6843,26 +7621,57 @@ comp_method_with_proto (tree method, tree proto) false); } -/* Return 1 if PROTO1 is consistent with PROTO2. */ +/* Return 1 if TYPE1 is equivalent to TYPE2. */ static int -comp_proto_with_proto (tree proto0, tree 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; - /* 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); + /* The following test is needed in case there are hashing + collisions. */ + if (METHOD_SEL_NAME (proto1) != METHOD_SEL_NAME (proto2)) + return 0; - /* Install return type. */ - TREE_TYPE (function1_template) = groktypename (TREE_TYPE (proto0)); - TREE_TYPE (function2_template) = groktypename (TREE_TYPE (proto1)); + /* Compare return types. */ + type1 = groktypename (TREE_TYPE (proto1)); + type2 = groktypename (TREE_TYPE (proto2)); - return comptypes (function1_template, function2_template, false); + 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 (!type1 && !type2); } /* - Generate an identifier for the function. the format is "_n_cls", @@ -6893,14 +7702,20 @@ really_start_method (tree method, tree parmlist) method_slot++; /* Make sure this is big enough for any plausible method label. */ - buf = alloca (50 + strlen (sel_name) + strlen (class_name) - + (cat_name ? strlen (cat_name) : 0)); + buf = (char *) alloca (50 + strlen (sel_name) + strlen (class_name) + + (cat_name ? strlen (cat_name) : 0)); OBJC_GEN_METHOD_LABEL (buf, TREE_CODE (method) == INSTANCE_METHOD_DECL, class_name, cat_name, sel_name, method_slot); 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. */ @@ -6931,20 +7746,32 @@ really_start_method (tree method, tree 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)) { @@ -6972,34 +7799,18 @@ continue_method_def (void) else parmlist = get_parm_info (1); /* place a `void_at_end' */ +#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); really_start_method (objc_method_context, parmlist); store_parm_decls (); } -/* Called by the parser, from the `pushlevel' production. */ - -void -add_objc_decls (void) -{ - 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, ...) { @@ -7014,6 +7825,22 @@ get_super_receiver (void) { 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); @@ -7049,17 +7876,18 @@ get_super_receiver (void) 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 <objc/objc-class.h>, 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 { @@ -7076,8 +7904,10 @@ get_super_receiver (void) 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)); @@ -7094,72 +7924,44 @@ get_super_receiver (void) } } -static tree -encode_method_def (tree func_decl) -{ - tree parms; - int stack_size; - HOST_WIDE_INT max_parm_end = 0; - char buffer[40]; - tree result; +/* When exiting a scope, sever links to a 'super' declaration (if any) + therein contained. */ - /* 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)); - } - - /* 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 (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 (void) { lang_expand_function_end = objc_expand_function_end; + /* 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; @@ -7402,13 +8204,13 @@ gen_declspecs (tree declspecs, char *buf, int 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) @@ -7435,11 +8237,11 @@ gen_declspecs (tree declspecs, char *buf, int 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"); @@ -7447,11 +8249,11 @@ gen_declspecs (tree declspecs, char *buf, int 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"); @@ -7541,14 +8343,14 @@ gen_declspecs (tree declspecs, char *buf, int 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) { @@ -7575,11 +8377,11 @@ gen_declspecs (tree declspecs, char *buf, int 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, " "); } @@ -7588,11 +8390,11 @@ gen_declspecs (tree declspecs, char *buf, int 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, " "); } @@ -7658,9 +8460,17 @@ gen_declaration_1 (tree atype_or_adecl, char *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); @@ -7669,6 +8479,8 @@ gen_declaration_1 (tree atype_or_adecl, char *buf) strcat (buf, " "); strcat (buf, gen_declarator (declarator, declbuf, "")); } + if (width) + sprintf (buf + strlen (buf), ": %lu", TREE_INT_CST_LOW (width)); } else @@ -7812,7 +8624,7 @@ dump_interface (FILE *fp, tree chain) declaration is so long that it doesn't fit in the buffer. The code and all the related functions should be rewritten to avoid using fixed size buffers. */ - char *buf = xmalloc (1024 * 10); + char *buf = (char *) xmalloc (1024 * 10); const char *my_name = IDENTIFIER_POINTER (CLASS_NAME (chain)); tree ivar_decls = CLASS_RAW_IVARS (chain); tree nst_methods = CLASS_NST_METHODS (chain); @@ -7935,7 +8747,7 @@ init_objc (void) gcc_obstack_init (&util_obstack); util_firstobj = (char *) obstack_finish (&util_obstack); - errbuf = xmalloc (BUFSIZE); + errbuf = (char *) xmalloc (BUFSIZE); hash_init (); synth_module_prologue (); } @@ -8009,6 +8821,9 @@ finish_objc (void) 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) { @@ -8046,36 +8861,12 @@ finish_objc (void) 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); + for (hsh = nst_method_hash_list[slot]; hsh; hsh = hsh->next) + check_duplicates (hsh, 0); + } } warn_missing_braces = save_warn_missing_braces; @@ -8113,7 +8904,7 @@ static void handle_class_ref (tree chain) { const char *name = IDENTIFIER_POINTER (TREE_VALUE (chain)); - char *string = alloca (strlen (name) + 30); + char *string = (char *) alloca (strlen (name) + 30); tree decl; tree exp; @@ -8162,7 +8953,7 @@ handle_impent (struct imp_entry *impent) const char *const class_name = IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context)); - string = alloca (strlen (class_name) + 30); + string = (char *) alloca (strlen (class_name) + 30); sprintf (string, "%sobjc_class_name_%s", (flag_next_runtime ? "." : "__"), class_name); @@ -8174,7 +8965,7 @@ handle_impent (struct imp_entry *impent) const char *const class_super_name = IDENTIFIER_POINTER (CLASS_SUPER_NAME (impent->imp_context)); - string = alloca (strlen (class_name) + string = (char *) alloca (strlen (class_name) + strlen (class_super_name) + 30); /* Do the same for categories. Even though no references to @@ -8211,7 +9002,39 @@ handle_impent (struct imp_entry *impent) } } +/* The Fix-and-Countinue 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 (tree id) { diff --git a/gcc/objc/objc-act.h b/gcc/objc/objc-act.h index e167f8e..0dade33 100644 --- a/gcc/objc/objc-act.h +++ b/gcc/objc/objc-act.h @@ -38,16 +38,26 @@ void continue_method_def (void); void finish_method_def (void); tree start_protocol (enum tree_code, tree, tree); void finish_protocol (tree); -void add_objc_decls (void); + +tree objc_build_throw_stmt (tree); +tree objc_build_try_catch_finally_stmt (int, int); +void objc_build_synchronized_prologue (tree); +tree objc_build_synchronized_epilogue (void); +tree objc_build_try_prologue (void); +void objc_build_try_epilogue (int); +void objc_build_catch_stmt (tree); +void objc_build_catch_epilogue (void); +tree objc_build_finally_prologue (void); +tree objc_build_finally_epilogue (void); tree is_ivar (tree, tree); int is_private (tree); int is_public (tree, tree); tree add_instance_variable (tree, int, tree, tree, tree); -tree add_class_method (tree, tree); -tree add_instance_method (tree, tree); +tree add_method (tree, tree, int); tree get_super_receiver (void); -tree get_class_ivars (tree); +void objc_clear_super_receiver (void); +tree get_class_ivars_from_name (tree); tree get_class_reference (tree); tree get_static_reference (tree, tree); tree get_object_reference (tree); @@ -75,6 +85,9 @@ tree build_encode_expr (tree); /* Objective-C structures */ +#define CLASS_BINFO_ELTS 6 +#define PROTOCOL_BINFO_ELTS 2 + /* KEYWORD_DECL */ #define KEYWORD_KEY_NAME(DECL) ((DECL)->decl.name) #define KEYWORD_ARG_NAME(DECL) ((DECL)->decl.arguments) @@ -105,10 +118,12 @@ tree build_encode_expr (tree); #define PROTOCOL_CLS_METHODS(CLASS) ((CLASS)->type.maxval) #define PROTOCOL_FORWARD_DECL(CLASS) TREE_VEC_ELT (TYPE_BINFO (CLASS), 1) #define PROTOCOL_DEFINED(CLASS) TREE_USED (CLASS) -#define TYPE_PROTOCOL_LIST(TYPE) \ - ((!TYPE_CHECK (TYPE)->type.context \ - || TREE_CODE ((TYPE)->type.context) == TRANSLATION_UNIT_DECL) \ - ? NULL_TREE : (TYPE)->type.context) +/* We need to distinguish TYPE_PROTOCOL_LISTs from TYPE_CONTEXTs, both of which + are stored in the same accessor slot. */ +#define TYPE_PROTOCOL_LIST(TYPE) \ + ((TYPE_CHECK (TYPE)->type.context \ + && TREE_CODE ((TYPE)->type.context) == TREE_LIST) \ + ? (TYPE)->type.context : NULL_TREE) #define SET_TYPE_PROTOCOL_LIST(TYPE, P) (TYPE_CHECK (TYPE)->type.context = (P)) /* Set by `continue_class' and checked by `is_public'. */ @@ -116,15 +131,20 @@ tree build_encode_expr (tree); #define TREE_STATIC_TEMPLATE(record_type) (TREE_PUBLIC (record_type)) #define TYPED_OBJECT(type) \ (TREE_CODE (type) == RECORD_TYPE && TREE_STATIC_TEMPLATE (type)) +#define OBJC_TYPE_NAME(type) TYPE_NAME(type) /* Define the Objective-C or Objective-C++ language-specific tree codes. */ #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) SYM, enum objc_tree_code { -#ifdef OBJCPLUS +#if defined (GCC_CP_TREE_H) LAST_BASE_TREE_CODE = LAST_CPLUS_TREE_CODE, -#else +#else +#if defined (GCC_C_TREE_H) LAST_BASE_TREE_CODE = LAST_C_TREE_CODE, +#else + #error You must include <c-tree.h> or <cp/cp-tree.h> before <objc/objc-act.h> +#endif #endif #include "objc-tree.def" LAST_OBJC_TREE_CODE @@ -182,6 +202,8 @@ enum objc_tree_index OCTI_SELF_DECL, OCTI_UMSG_DECL, OCTI_UMSG_SUPER_DECL, + OCTI_UMSG_STRET_DECL, + OCTI_UMSG_SUPER_STRET_DECL, OCTI_GET_CLASS_DECL, OCTI_GET_MCLASS_DECL, OCTI_SUPER_TYPE, @@ -245,6 +267,24 @@ enum objc_tree_index OCTI_CNST_STR_GLOB_ID, OCTI_STRING_CLASS_DECL, OCTI_SUPER_DECL, + OCTI_UMSG_NONNIL_DECL, + OCTI_UMSG_NONNIL_STRET_DECL, + OCTI_STORAGE_CLS, + OCTI_EXCEPTION_EXTRACT_DECL, + OCTI_EXCEPTION_TRY_ENTER_DECL, + OCTI_EXCEPTION_TRY_EXIT_DECL, + OCTI_EXCEPTION_MATCH_DECL, + OCTI_EXCEPTION_THROW_DECL, + OCTI_SYNC_ENTER_DECL, + OCTI_SYNC_EXIT_DECL, + OCTI_SETJMP_DECL, + OCTI_EXCDATA_TEMPL, + OCTI_STACK_EXCEPTION_DATA_DECL, + OCTI_LOCAL_EXCEPTION_DECL, + OCTI_RETHROW_EXCEPTION_DECL, + OCTI_EVAL_ONCE_DECL, + OCTI_EXCEPTION_BLK_STACK, + OCTI_CATCH_TYPE, OCTI_MAX }; @@ -267,6 +307,8 @@ extern GTY(()) tree objc_global_trees[OCTI_MAX]; #define self_decl objc_global_trees[OCTI_SELF_DECL] #define umsg_decl objc_global_trees[OCTI_UMSG_DECL] #define umsg_super_decl objc_global_trees[OCTI_UMSG_SUPER_DECL] +#define umsg_stret_decl objc_global_trees[OCTI_UMSG_STRET_DECL] +#define umsg_super_stret_decl objc_global_trees[OCTI_UMSG_SUPER_STRET_DECL] #define objc_get_class_decl objc_global_trees[OCTI_GET_CLASS_DECL] #define objc_get_meta_class_decl \ objc_global_trees[OCTI_GET_MCLASS_DECL] @@ -285,7 +327,7 @@ extern GTY(()) tree objc_global_trees[OCTI_MAX]; #define IS_PROTOCOL_QUALIFIED_ID(TYPE) \ (IS_ID (TYPE) && TYPE_PROTOCOL_LIST (TYPE)) #define IS_SUPER(TYPE) \ - (super_type && TYPE_MAIN_VARIANT (TYPE) == TYPE_MAIN_VARIANT (super_type)) + (TREE_CODE (TYPE) == POINTER_TYPE && TREE_TYPE (TYPE) == objc_super_template) #define class_chain objc_global_trees[OCTI_CLS_CHAIN] #define alias_chain objc_global_trees[OCTI_ALIAS_CHAIN] @@ -339,6 +381,33 @@ extern GTY(()) tree objc_global_trees[OCTI_MAX]; #define ucls_super_ref objc_global_trees[OCTI_UCLS_SUPER_REF] #define uucls_super_ref objc_global_trees[OCTI_UUCLS_SUPER_REF] +#define umsg_nonnil_decl objc_global_trees[OCTI_UMSG_NONNIL_DECL] +#define umsg_nonnil_stret_decl objc_global_trees[OCTI_UMSG_NONNIL_STRET_DECL] +#define objc_storage_class objc_global_trees[OCTI_STORAGE_CLS] +#define objc_exception_extract_decl \ + objc_global_trees[OCTI_EXCEPTION_EXTRACT_DECL] +#define objc_exception_try_enter_decl \ + objc_global_trees[OCTI_EXCEPTION_TRY_ENTER_DECL] +#define objc_exception_try_exit_decl \ + objc_global_trees[OCTI_EXCEPTION_TRY_EXIT_DECL] +#define objc_exception_match_decl \ + objc_global_trees[OCTI_EXCEPTION_MATCH_DECL] +#define objc_exception_throw_decl \ + objc_global_trees[OCTI_EXCEPTION_THROW_DECL] +#define objc_sync_enter_decl objc_global_trees[OCTI_SYNC_ENTER_DECL] +#define objc_sync_exit_decl objc_global_trees[OCTI_SYNC_EXIT_DECL] +#define objc_exception_data_template \ + objc_global_trees[OCTI_EXCDATA_TEMPL] +#define objc_setjmp_decl objc_global_trees[OCTI_SETJMP_DECL] +#define objc_stack_exception_data \ + objc_global_trees[OCTI_STACK_EXCEPTION_DATA_DECL] +#define objc_caught_exception objc_global_trees[OCTI_LOCAL_EXCEPTION_DECL] +#define objc_rethrow_exception objc_global_trees[OCTI_RETHROW_EXCEPTION_DECL] +#define objc_eval_once objc_global_trees[OCTI_EVAL_ONCE_DECL] +#define objc_exception_block_stack \ + objc_global_trees[OCTI_EXCEPTION_BLK_STACK] +#define objc_catch_type objc_global_trees[OCTI_CATCH_TYPE] + #define objc_method_template objc_global_trees[OCTI_METH_TEMPL] #define objc_ivar_template objc_global_trees[OCTI_IVAR_TEMPL] #define objc_symtab_template objc_global_trees[OCTI_SYMTAB_TEMPL] diff --git a/gcc/objc/objc-tree.def b/gcc/objc/objc-tree.def index 2d0d337..aa2e40f 100644 --- a/gcc/objc/objc-tree.def +++ b/gcc/objc/objc-tree.def @@ -33,3 +33,7 @@ DEFTREECODE (PROTOCOL_INTERFACE_TYPE, "protocol_interface_type", 't', 0) DEFTREECODE (KEYWORD_DECL, "keyword_decl", 'd', 0) DEFTREECODE (INSTANCE_METHOD_DECL, "instance_method_decl", 'd', 0) DEFTREECODE (CLASS_METHOD_DECL, "class_method_decl", 'd', 0) + +/* Objective-C expressions. */ +DEFTREECODE (MESSAGE_SEND_EXPR, "message_send_expr", 'e', 3) +DEFTREECODE (CLASS_REFERENCE_EXPR, "class_reference_expr", 'e', 1) |