#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
#define OBJC_FORWARDING_MIN_OFFSET 0
#endif
\f
-\f
/* 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
#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) ***/
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);
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);
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. */
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);
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);
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) ***/
/* 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"
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];
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
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";
}
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;
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)
/* <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
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;
}
{
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);
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)));
}
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;
}
'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)
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. */
}
}
+/* 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))
{
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;
TREE_STATIC (decl) = 1;
make_decl_rtl (decl, 0);
pushdecl (decl);
+ DECL_ARTIFICIAL (decl) = 1;
}
- DECL_ARTIFICIAL (decl) = 1;
return decl;
}
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);
}
}
synth_module_prologue (void)
{
tree temp_type;
- tree super_p;
/* Defined in `objc.h' */
objc_object_id = get_identifier (TAG_OBJECT);
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. */
/* 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)));
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)));
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,
/* 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[]; */
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
{
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
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 }) */
/* 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)
{
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++);
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;
}
\f
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));
"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);
}
/* 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);
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. */
{
/* 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
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;
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 ();
/* 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));
}
static GTY(()) int selector_reference_idx;
+
static tree
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;
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);
}
static GTY(()) int class_reference_idx;
+
static tree
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;
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;
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;
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);
}
{
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;
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
{
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)
{
fatal_error ("circular inheritance in interface declaration for `%s'",
IDENTIFIER_POINTER (super_name));
- interface = super_interface;
- my_name = CLASS_NAME (interface);
- super_name = CLASS_SUPER_NAME (interface);
+ interface = super_interface;
+ my_name = CLASS_NAME (interface);
+ super_name = CLASS_SUPER_NAME (interface);
+
+ op1 = (raw ? CLASS_RAW_IVARS (interface) : CLASS_OWN_IVARS (interface));
+ if (op1)
+ {
+ tree head = copy_list (op1);
+
+ /* Prepend super class ivars...make a copy of the list, we
+ do not want to alter the original. */
+ chainon (head, ivar_chain);
+ 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);
- op1 = CLASS_OWN_IVARS (interface);
- if (op1)
- {
- tree head = copy_list (op1);
+ /* 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);
- /* Prepend super class ivars...make a copy of the list, we
- do not want to alter the original. */
- chainon (head, ivar_chain);
- ivar_chain = head;
- }
- }
- return ivar_chain;
+ /* 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> {
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);
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);
-
- /* ??? Here we assume that the parm address is indexed
- off the frame pointer or arg pointer.
- If that is not true, we produce meaningless results,
- but do not crash. */
- if (GET_CODE (addr) == PLUS
- && GET_CODE (XEXP (addr, 1)) == CONST_INT)
- offset_in_bytes = INTVAL (XEXP (addr, 1));
- else
- offset_in_bytes = 0;
+ int sz = int_size_in_bytes (type);
- offset_in_bytes += OBJC_FORWARDING_STACK_OFFSET;
- offset_is_register = 0;
- }
- else if (GET_CODE (DECL_INCOMING_RTL (parm)) == REG)
- {
- int regno = REGNO (DECL_INCOMING_RTL (parm));
- offset_in_bytes = apply_args_register_offset (regno);
- offset_is_register = 1;
- }
- else
- return 0;
-
- /* This is the case where the parm is passed as an int or double
- and it is converted to a char, short or float and stored back
- in the parmlist. In this case, describe the parm
- with the variable's declared type, and adjust the address
- if the least significant bytes (which we are using) are not
- the first ones. */
- if (BYTES_BIG_ENDIAN && TREE_TYPE (parm) != DECL_ARG_TYPE (parm))
- offset_in_bytes += (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parm)))
- - GET_MODE_SIZE (GET_MODE (DECL_RTL (parm))));
-
- return offset_in_bytes;
+ /* Make all integer and enum types at least as large
+ as an int. */
+ if (sz > 0 && (TREE_CODE (type) == INTEGER_TYPE
+ || TREE_CODE (type) == BOOLEAN_TYPE
+ || TREE_CODE (type) == ENUMERAL_TYPE))
+ sz = MAX (sz, int_size_in_bytes (integer_type_node));
+ /* Treat arrays as pointers, since that's how they're
+ passed in. */
+ else if (TREE_CODE (type) == ARRAY_TYPE)
+ sz = int_size_in_bytes (ptr_type_node);
+ return sz;
}
static tree
-encode_method_prototype (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);
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)
{
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,
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 ();
{
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);
{
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;
}
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)
{
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; */
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. */
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
{
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)
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))
{
}
}
-/* 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;
- record = start_struct (RECORD_TYPE, get_identifier (UTAG_SUPER));
+ /* Suppress outputting debug symbols, because
+ dbxout_init hasn't been called yet. */
+ enum debug_info_type save_write_symbols = write_symbols;
+ const struct gcc_debug_hooks *save_hooks = debug_hooks;
+
+ write_symbols = NO_DEBUG;
+ debug_hooks = &do_nothing_debug_hooks;
+
+ objc_super_template = start_struct (RECORD_TYPE, get_identifier (UTAG_SUPER));
/* struct objc_object *self; */
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 {
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);
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)
{
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);
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);
/* 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),
struct objc_class *sibling_class;
}
struct objc_protocol_list *protocols;
+ if (flag_next_runtime)
+ void *sel_id;
void *gc_object_type;
}; */
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);
UOBJC_CLASS_METHODS_decl,
protocol_decl);
- TREE_USED (decl) = 1;
finish_decl (decl, initlist, NULL_TREE);
}
{
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)));
}
= 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
len++;
}
- buf = alloca (len + 1);
+ buf = (char *) alloca (len + 1);
/* Start the buffer out as an empty string. */
buf[0] = '\0';
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 ();
#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)
/* 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))
{
}
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;
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);
}
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;
}
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'
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));
-
- if (iface)
- method_prototype = lookup_instance_method_static (iface, sel_name);
+ is_class = TYPE_NAME (rtype) = get_identifier ("Class");
- 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))
- {
- method_prototype
- = lookup_instance_method_static (implementation_template,
- sel_name);
-
- if (! method_prototype && TYPE_PROTOCOL_LIST (ctype))
- method_prototype
- = lookup_method_in_protocol_list (TYPE_PROTOCOL_LIST (ctype),
- sel_name, 0);
-
- if (! method_prototype
- && implementation_template != objc_implementation_context)
- /* The method is not published in the interface. Check
- locally. */
- method_prototype
- = lookup_method (CLASS_NST_METHODS (objc_implementation_context),
- sel_name);
- }
- else
+ tree 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))
{
- tree iface;
-
- if ((iface = lookup_interface (TYPE_NAME (ctype))))
- method_prototype = lookup_instance_method_static (iface, sel_name);
-
- if (! method_prototype)
- {
- tree protocol_list = TYPE_PROTOCOL_LIST (ctype);
- if (protocol_list)
- method_prototype
- = lookup_method_in_protocol_list (protocol_list,
- sel_name, 0);
- }
+ rprotos = TYPE_PROTOCOL_LIST (rtype);
+ rtype = lookup_interface (OBJC_TYPE_NAME (rtype));
}
-
- if (!method_prototype)
- warning ("`%s' does not respond to `%s'",
- IDENTIFIER_POINTER (TYPE_NAME (ctype)),
- IDENTIFIER_POINTER (sel_name));
- }
- else if (class_ident)
- {
- if (objc_implementation_context
- && CLASS_NAME (objc_implementation_context) == class_ident)
+ /* If we could not find an @interface declaration, we must have
+ only seen a @class declaration; so, we cannot say anything
+ more intelligent about which methods the receiver will
+ understand. */
+ if (!rtype)
+ rtype = saved_rtype;
+ else if (TREE_CODE (rtype) == CLASS_INTERFACE_TYPE
+ || TREE_CODE (rtype) == CLASS_IMPLEMENTATION_TYPE)
{
+ /* We have a valid ObjC class name. Look up the method name
+ in the published @interface for the class (and its
+ superclasses). */
method_prototype
- = lookup_class_method_static (implementation_template, sel_name);
+ = lookup_method_static (rtype, sel_name, is_class != NULL_TREE);
- if (!method_prototype
- && implementation_template != objc_implementation_context)
- /* The method is not published in the interface. Check
- locally. */
+ /* If the method was not found in the @interface, it may still
+ exist locally as part of the @implementation. */
+ if (!method_prototype && objc_implementation_context
+ && CLASS_NAME (objc_implementation_context)
+ == OBJC_TYPE_NAME (rtype))
method_prototype
- = lookup_method (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);
+ static bool warn_missing_methods = false;
- if (!hsh)
- /* For various loopholes */
- hsh = hash_lookup (cls_method_hash_list, sel_name);
-
- method_prototype = check_duplicates (hsh);
- if (!method_prototype)
+ if (rtype)
+ warning ("`%s' may not respond to `%c%s'",
+ IDENTIFIER_POINTER (OBJC_TYPE_NAME (rtype)),
+ (is_class ? '+' : '-'),
+ IDENTIFIER_POINTER (sel_name));
+ if (rprotos)
+ warning ("`%c%s' not implemented by protocol(s)",
+ (is_class ? '+' : '-'),
+ IDENTIFIER_POINTER (sel_name));
+ if (!warn_missing_methods)
{
- warning ("cannot find method");
- warning ("return type for `%s' defaults to id",
- IDENTIFIER_POINTER (sel_name));
+ warning ("(Messages without a matching method signature");
+ warning ("will be assumed to return `id' and accept");
+ warning ("`...' as arguments.)");
+ warn_missing_methods = true;
}
}
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;
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,
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)));
}
}
\f
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);
}
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
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;
{
attr obj;
- obj = ggc_alloc (sizeof (struct hashed_attribute));
+ obj = (attr) ggc_alloc (sizeof (struct hashed_attribute));
obj->next = entry->list;
obj->value = value;
}
static tree
-lookup_instance_method_static (tree interface, tree ident)
-{
- tree inter = interface;
- tree chain = CLASS_NST_METHODS (inter);
- tree meth = NULL_TREE;
-
- do
- {
- if ((meth = lookup_method (chain, ident)))
- return meth;
-
- if (CLASS_CATEGORY_LIST (inter))
- {
- tree category = CLASS_CATEGORY_LIST (inter);
- chain = CLASS_NST_METHODS (category);
-
- do
- {
- if ((meth = lookup_method (chain, ident)))
- return meth;
-
- /* Check for instance methods in protocols in categories. */
- if (CLASS_PROTOCOL_LIST (category))
- {
- if ((meth = (lookup_method_in_protocol_list
- (CLASS_PROTOCOL_LIST (category), ident, 0))))
- return meth;
- }
-
- 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))))
- 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)
+lookup_method_static (tree interface, tree ident, int is_class)
{
+ tree meth = NULL_TREE, root_inter = NULL_TREE;
tree inter = interface;
- tree chain = CLASS_CLS_METHODS (inter);
- tree meth = NULL_TREE;
- tree root_inter = 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_CLS_METHODS (category);
+ chain = is_class ? CLASS_CLS_METHODS (category) : CLASS_NST_METHODS (category);
- do
+ /* Check directly in each category. */
+ if ((meth = lookup_method (chain, ident)))
+ return meth;
+
+ /* 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;
-}
-\f
-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;
}
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);
add_instance_variable (tree class, int public, tree declarator,
tree declspecs, tree width)
{
- tree field_decl, raw_decl;
+ 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;
- raw_decl = build_tree_list (declspecs, declarator);
-
- 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)
}
- 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;
}
\f
{
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;
}
|| (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");
{
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");
}
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)
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;
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);
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;
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;
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. */
{
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>; */
{
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);
{
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)
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) /* '@' */
{
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. */
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
{
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;
}
}
}
-/* 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);
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);
}
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];
{
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
return complex_expr;
}
-\f
-/* 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
(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))
(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
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. */
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;
+
+ /* Compare return types. */
+ type1 = groktypename (TREE_TYPE (proto1));
+ type2 = groktypename (TREE_TYPE (proto2));
+
+ if (!objc_types_are_equivalent (type1, type2))
+ return 0;
- /* Install return type. */
- TREE_TYPE (function1_template) = groktypename (TREE_TYPE (proto0));
- TREE_TYPE (function2_template) = groktypename (TREE_TYPE (proto1));
+ /* Compare argument types. */
+ for (type1 = get_arg_type_list (proto1, METHOD_REF, 0),
+ type2 = get_arg_type_list (proto2, METHOD_REF, 0);
+ type1 && type2;
+ type1 = TREE_CHAIN (type1), type2 = TREE_CHAIN (type2))
+ {
+ if (!objc_types_are_equivalent (TREE_VALUE (type1), TREE_VALUE (type2)))
+ return 0;
+ }
- return comptypes (function1_template, function2_template, false);
+ return (!type1 && !type2);
}
/* - Generate an identifier for the function. the format is "_n_cls",
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. */
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))
{
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, ...)
{
{
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);
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
{
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));
}
}
-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;
-
- /* 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, '+');
+/* When exiting a scope, sever links to a 'super' declaration (if any)
+ therein contained. */
- 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;
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)
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");
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");
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)
{
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, " ");
}
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, " ");
}
{
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);
strcat (buf, " ");
strcat (buf, gen_declarator (declarator, declbuf, ""));
}
+ if (width)
+ sprintf (buf + strlen (buf), ": %lu", TREE_INT_CST_LOW (width));
}
else
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);
gcc_obstack_init (&util_obstack);
util_firstobj = (char *) obstack_finish (&util_obstack);
- errbuf = xmalloc (BUFSIZE);
+ errbuf = (char *) xmalloc (BUFSIZE);
hash_init ();
synth_module_prologue ();
}
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)
{
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;
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;
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);
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
}
}
\f
+/* 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)
{