/* Implement classes and message passing for Objective C.
- Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001
- Free Software Foundation, Inc.
+ Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000,
+ 2001, 2002, 2003 Free Software Foundation, Inc.
Contributed by Steve Naroff.
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC is free software; you can redistribute it and/or modify
+GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-GNU CC is distributed in the hope that it will be useful,
+GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
+along with GCC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "tree.h"
#include "rtl.h"
#include "expr.h"
#include "c-tree.h"
-#include "c-lex.h"
#include "c-common.h"
#include "flags.h"
#include "objc-act.h"
#include "output.h"
#include "toplev.h"
#include "ggc.h"
-#include "cpplib.h"
+#include "varray.h"
#include "debug.h"
#include "target.h"
-#include "varray.h"
-#include "langhooks.h"
-#include "langhooks-def.h"
+#include "diagnostic.h"
/* This is the default way of generating a method name. */
/* I am not sure it is really correct.
#define OBJC_FORWARDING_MIN_OFFSET 0
#endif
\f
-/* Define the special tree codes that we use. */
-
-/* Table indexed by tree code giving a string containing a character
- classifying the tree code. */
-
-#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
-
-static const char objc_tree_code_type[] = {
- 'x',
-#include "objc-tree.def"
-};
-#undef DEFTREECODE
-
-/* Table indexed by tree code giving number of expression
- operands beyond the fixed part of the node structure.
- Not used for types or decls. */
-
-#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,
-
-static const int objc_tree_code_length[] = {
- 0,
-#include "objc-tree.def"
-};
-#undef DEFTREECODE
-
-/* Names of tree components.
- Used for printing out the tree and error messages. */
-#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
-
-static const char * const objc_tree_code_name[] = {
- "@@dummy",
-#include "objc-tree.def"
-};
-#undef DEFTREECODE
\f
/* Set up for use of obstacks. */
#include "obstack.h"
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
-
/* This obstack is used to accumulate the encoding of a data type. */
static struct obstack util_obstack;
/* This points to the beginning of obstack contents,
static void init_objc PARAMS ((void));
static void finish_objc PARAMS ((void));
-static const char *objc_init PARAMS ((const char *));
-static void objc_init_options PARAMS ((void));
-static int objc_decode_option PARAMS ((int, char **));
-static void objc_post_options PARAMS ((void));
/* Code generation. */
static void generate_strings PARAMS ((void));
static tree get_proto_encoding PARAMS ((tree));
static void build_selector_translation_table PARAMS ((void));
-static tree build_ivar_chain PARAMS ((tree, int));
static tree objc_add_static_instance PARAMS ((tree, tree));
static void encode_aggregate_within PARAMS ((tree, int, int,
int, int));
static const char *objc_demangle PARAMS ((const char *));
-static const char *objc_printable_name PARAMS ((tree, int));
static void objc_expand_function_end PARAMS ((void));
/* Hash tables to manage the global pool of method prototypes. */
hash *nst_method_hash_list = 0;
hash *cls_method_hash_list = 0;
+static size_t hash_func PARAMS ((tree));
static void hash_init PARAMS ((void));
static void hash_enter PARAMS ((hash *, tree));
static hash hash_lookup PARAMS ((hash *, tree));
static tree create_builtin_decl PARAMS ((enum tree_code,
tree, const char *));
static void setup_string_decl PARAMS ((void));
+static void build_string_class_template PARAMS ((void));
static tree my_build_string PARAMS ((int, const char *));
static void build_objc_symtab_template PARAMS ((void));
static tree init_def_list PARAMS ((tree));
static tree build_selector_reference PARAMS ((tree));
static tree build_class_reference_decl PARAMS ((void));
static void add_class_reference PARAMS ((tree));
-static tree objc_copy_list PARAMS ((tree, tree *));
static tree build_protocol_template PARAMS ((void));
static tree build_descriptor_table_initializer PARAMS ((tree, tree));
static tree build_method_prototype_list_template PARAMS ((tree, int));
static void handle_class_ref PARAMS ((tree));
static void generate_struct_by_value_array PARAMS ((void))
ATTRIBUTE_NORETURN;
-static void objc_act_parse_init PARAMS ((void));
-static void ggc_mark_imp_list PARAMS ((void *));
-static void ggc_mark_hash_table PARAMS ((void *));
+static void encode_complete_bitfield PARAMS ((int, tree, int));
/*** Private Interface (data) ***/
#define UTAG_METHOD_LIST "_objc_method_list"
#define UTAG_CATEGORY "_objc_category"
#define UTAG_MODULE "_objc_module"
-#define UTAG_STATICS "_objc_statics"
#define UTAG_SYMTAB "_objc_symtab"
#define UTAG_SUPER "_objc_super"
#define UTAG_SELECTOR "_objc_selector"
#define UTAG_PROTOCOL "_objc_protocol"
-#define UTAG_PROTOCOL_LIST "_objc_protocol_list"
#define UTAG_METHOD_PROTOTYPE "_objc_method_prototype"
#define UTAG_METHOD_PROTOTYPE_LIST "_objc__method_prototype_list"
-#ifdef NEXT_OBJC_RUNTIME
-#define STRING_OBJECT_CLASS_NAME "NSConstantString"
-#else
-#define STRING_OBJECT_CLASS_NAME "NXConstantString"
-#endif
/* Note that the string object global name is only needed for the
NeXT runtime. */
#define STRING_OBJECT_GLOBAL_NAME "_NSConstantStringClassReference"
#define PROTOCOL_OBJECT_CLASS_NAME "Protocol"
-static const char *constant_string_class_name = NULL;
-
static const char *TAG_GETCLASS;
static const char *TAG_GETMETACLASS;
static const char *TAG_MSGSEND;
static const char *TAG_MSGSENDSUPER;
static const char *TAG_EXECCLASS;
+static const char *default_constant_string_class_name;
-/* The OCTI_... enumeration itself in in objc/objc-act.h. */
+/* The OCTI_... enumeration itself is in objc/objc-act.h. */
tree objc_global_trees[OCTI_MAX];
-int objc_receiver_context;
-
static void handle_impent PARAMS ((struct imp_entry *));
struct imp_entry *imp_list = 0;
extern const char *dump_base_name;
\f
-/* Generate code for GNU or NeXT runtime environment. */
-
-#ifdef NEXT_OBJC_RUNTIME
-int flag_next_runtime = 1;
-#else
-int flag_next_runtime = 0;
-#endif
-
-int flag_typed_selectors;
-
-/* Open and close the file for outputting class declarations, if requested. */
-
-int flag_gen_declaration = 0;
+static int flag_typed_selectors;
FILE *gen_declaration_file;
-/* Warn if multiple methods are seen for the same selector, but with
- different argument types. */
-
-int warn_selector = 0;
-
-/* Warn if methods required by a protocol are not implemented in the
- class adopting it. When turned off, methods inherited to that
- class are also considered implemented */
-
-int flag_warn_protocol = 1;
-
/* Tells "encode_pointer/encode_aggregate" whether we are generating
type descriptors for instance variables (as opposed to methods).
Type descriptors for instance variables contain more information
- than methods (for static typing and embedded structures). This
- was added to support features being planned for dbkit2. */
+ than methods (for static typing and embedded structures). */
static int generating_instance_variables = 0;
-/* Tells the compiler that this is a special run. Do not perform
- any compiling, instead we are to test some platform dependent
- features and output a C header file with appropriate definitions. */
-
-static int print_struct_values = 0;
-
-#undef LANG_HOOKS_NAME
-#define LANG_HOOKS_NAME "GNU Objective-C"
-#undef LANG_HOOKS_INIT
-#define LANG_HOOKS_INIT objc_init
-#undef LANG_HOOKS_FINISH
-#define LANG_HOOKS_FINISH c_common_finish
-#undef LANG_HOOKS_INIT_OPTIONS
-#define LANG_HOOKS_INIT_OPTIONS objc_init_options
-#undef LANG_HOOKS_DECODE_OPTION
-#define LANG_HOOKS_DECODE_OPTION objc_decode_option
-#undef LANG_HOOKS_POST_OPTIONS
-#define LANG_HOOKS_POST_OPTIONS objc_post_options
-#undef LANG_HOOKS_PRINT_IDENTIFIER
-#define LANG_HOOKS_PRINT_IDENTIFIER c_print_identifier
-#undef LANG_HOOKS_SET_YYDEBUG
-#define LANG_HOOKS_SET_YYDEBUG c_set_yydebug
-/* Inlining hooks same as the C front end. */
-#undef LANG_HOOKS_TREE_INLINING_CANNOT_INLINE_TREE_FN
-#define LANG_HOOKS_TREE_INLINING_CANNOT_INLINE_TREE_FN \
- c_cannot_inline_tree_fn
-#undef LANG_HOOKS_TREE_INLINING_DISREGARD_INLINE_LIMITS
-#define LANG_HOOKS_TREE_INLINING_DISREGARD_INLINE_LIMITS \
- c_disregard_inline_limits
-#undef LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P
-#define LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P \
- anon_aggr_type_p
-
-/* Each front end provides its own. */
-const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
-
-static varray_type deferred_fns;
-
-/* Post-switch processing. */
-static void
-objc_post_options ()
-{
- c_common_post_options ();
-}
-
-/* Some platforms pass small structures through registers versus through
- an invisible pointer. Determine at what size structure is the
- transition point between the two possibilities. */
+/* Some platforms pass small structures through registers versus
+ through an invisible pointer. Determine at what size structure is
+ the transition point between the two possibilities. */
static void
generate_struct_by_value_array ()
int aggregate_in_mem[32];
int found = 0;
- /* Presumably no platform passes 32 byte structures in a register. */
+ /* Presumably no platform passes 32 byte structures in a register. */
for (i = 1; i < 32; i++)
{
char buffer[5];
}
/* We found some structures that are returned in registers instead of memory
- so output the necessary data. */
+ so output the necessary data. */
if (found)
{
for (i = 31; i >= 0; i--)
exit (0);
}
-static void
-objc_init_options ()
-{
- c_common_init_options (clk_objective_c);
-}
-
-static const char *
+const char *
objc_init (filename)
const char *filename;
{
filename = c_objc_common_init (filename);
-
- decl_printable_name = objc_printable_name;
+ if (filename == NULL)
+ return filename;
/* Force the line number back to 0; check_newline will have
raised it to 1, which will make the builtin functions appear
TAG_MSGSEND = "objc_msgSend";
TAG_MSGSENDSUPER = "objc_msgSendSuper";
TAG_EXECCLASS = "__objc_execClass";
+ default_constant_string_class_name = "NSConstantString";
}
else
{
TAG_MSGSEND = "objc_msg_lookup";
TAG_MSGSENDSUPER = "objc_msg_lookup_super";
TAG_EXECCLASS = "__objc_exec_class";
+ default_constant_string_class_name = "NXConstantString";
flag_typed_selectors = 1;
}
if (print_struct_values)
generate_struct_by_value_array ();
- objc_act_parse_init ();
-
- VARRAY_TREE_INIT (deferred_fns, 32, "deferred_fns");
- ggc_add_tree_varray_root (&deferred_fns, 1);
-
return filename;
}
-/* Register a function tree, so that its optimization and conversion
- to RTL is only done at the end of the compilation. */
-
-int
-defer_fn (fn)
- tree fn;
-{
- VARRAY_PUSH_TREE (deferred_fns, fn);
-
- return 1;
-}
-
void
finish_file ()
{
- int i;
+ c_objc_common_finish_file ();
- for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_fns); i++)
- /* Don't output the same function twice. We may run into such
- situations when an extern inline function is later given a
- non-extern-inline definition. */
- if (! TREE_ASM_WRITTEN (VARRAY_TREE (deferred_fns, i)))
- c_expand_deferred_function (VARRAY_TREE (deferred_fns, i));
- VARRAY_FREE (deferred_fns);
-
- finish_objc (); /* Objective-C finalization */
+ /* Finalize Objective-C runtime data. No need to generate tables
+ and code if only checking syntax. */
+ if (!flag_syntax_only)
+ finish_objc ();
if (gen_declaration_file)
fclose (gen_declaration_file);
}
-
-static int
-objc_decode_option (argc, argv)
- int argc;
- char **argv;
-{
- const char *p = argv[0];
-
- if (!strcmp (p, "-gen-decls"))
- flag_gen_declaration = 1;
- else if (!strcmp (p, "-Wselector"))
- warn_selector = 1;
- else if (!strcmp (p, "-Wno-selector"))
- warn_selector = 0;
- else if (!strcmp (p, "-Wprotocol"))
- flag_warn_protocol = 1;
- else if (!strcmp (p, "-Wno-protocol"))
- flag_warn_protocol = 0;
- else if (!strcmp (p, "-fgnu-runtime"))
- flag_next_runtime = 0;
- else if (!strcmp (p, "-fno-next-runtime"))
- flag_next_runtime = 0;
- else if (!strcmp (p, "-fno-gnu-runtime"))
- flag_next_runtime = 1;
- else if (!strcmp (p, "-fnext-runtime"))
- flag_next_runtime = 1;
- else if (!strcmp (p, "-print-objc-runtime-info"))
- print_struct_values = 1;
-#define CSTSTRCLASS "-fconstant-string-class="
- else if (!strncmp (p, CSTSTRCLASS, sizeof(CSTSTRCLASS) - 2)) {
- if (strlen (argv[0]) <= strlen (CSTSTRCLASS))
- error ("no class name specified as argument to -fconstant-string-class");
- constant_string_class_name = xstrdup(argv[0] + sizeof(CSTSTRCLASS) - 1);
- }
-#undef CSTSTRCLASS
- else
- return c_decode_option (argc, argv);
-
- return 1;
-}
-
\f
static tree
define_decl (declarator, declspecs)
`a' and `b' are the same class type, or
`a' and `b' are of class types A and B such that B is a descendant of A. */
-int
-maybe_objc_comptypes (lhs, rhs, reflexive)
- tree lhs, rhs;
- int reflexive;
-{
- return objc_comptypes (lhs, rhs, reflexive);
-}
-
static tree
lookup_method_in_protocol_list (rproto_list, sel_name, class_meth)
tree rproto_list;
static tree
lookup_protocol_in_reflist (rproto_list, lproto)
- tree rproto_list;
- tree lproto;
+ tree rproto_list;
+ tree lproto;
{
- tree rproto, p;
+ tree rproto, p;
- /* Make sure the protocol is supported by the object on the rhs. */
- if (TREE_CODE (lproto) == PROTOCOL_INTERFACE_TYPE)
- {
- tree fnd = 0;
- for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto))
- {
- p = TREE_VALUE (rproto);
+ /* Make sure the protocol is supported by the object on the rhs. */
+ if (TREE_CODE (lproto) == PROTOCOL_INTERFACE_TYPE)
+ {
+ tree fnd = 0;
+ for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto))
+ {
+ p = TREE_VALUE (rproto);
- if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE)
- {
- if (lproto == p)
- fnd = lproto;
+ if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE)
+ {
+ if (lproto == p)
+ fnd = lproto;
- else if (PROTOCOL_LIST (p))
- fnd = lookup_protocol_in_reflist (PROTOCOL_LIST (p), lproto);
- }
+ else if (PROTOCOL_LIST (p))
+ fnd = lookup_protocol_in_reflist (PROTOCOL_LIST (p), lproto);
+ }
- if (fnd)
- return fnd;
- }
- }
- else
- {
- ; /* An identifier...if we could not find a protocol. */
- }
+ if (fnd)
+ return fnd;
+ }
+ }
+ else
+ {
+ ; /* An identifier...if we could not find a protocol. */
+ }
- return 0;
+ return 0;
}
-/* Return 1 if LHS and RHS are compatible types for assignment
- or various other operations. Return 0 if they are incompatible,
- and return -1 if we choose to not decide. When the operation
- is REFLEXIVE, check for compatibility in either direction. */
+/* Return 1 if LHS and RHS are compatible types for assignment or
+ various other operations. Return 0 if they are incompatible, and
+ return -1 if we choose to not decide (because the types are really
+ just C types, not ObjC specific ones). When the operation is
+ REFLEXIVE (typically comparisons), check for compatibility in
+ either direction; when it's not (typically assignments), don't.
+
+ This function is called in two cases: when both lhs and rhs are
+ pointers to records (in which case we check protocols too), and
+ when both lhs and rhs are records (in which case we check class
+ inheritance only).
+
+ Warnings about classes/protocols not implementing a protocol are
+ emitted here (multiple of those warnings might be emitted for a
+ single line!); generic warnings about incompatible assignments and
+ lacks of casts in comparisons are/must be emitted by the caller if
+ we return 0.
+*/
int
objc_comptypes (lhs, rhs, reflexive)
{
/* New clause for protocols. */
+ /* Here we manage the case of a POINTER_TYPE = POINTER_TYPE. We only
+ manage the ObjC ones, and leave the rest to the C code. */
if (TREE_CODE (lhs) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (lhs)) == RECORD_TYPE
&& TREE_CODE (rhs) == POINTER_TYPE
tree rproto, rproto_list;
tree p;
+ /* <Protocol> = <Protocol> */
if (rhs_is_proto)
{
rproto_list = TYPE_PROTOCOL_LIST (rhs);
-
- /* Make sure the protocol is supported by the object
- on the rhs. */
- for (lproto = lproto_list; lproto; lproto = TREE_CHAIN (lproto))
+
+ if (!reflexive)
{
- p = TREE_VALUE (lproto);
- rproto = lookup_protocol_in_reflist (rproto_list, p);
+ /* An assignment between objects of type 'id
+ <Protocol>'; make sure the protocol on the lhs is
+ supported by the object on the rhs. */
+ for (lproto = lproto_list; lproto;
+ lproto = TREE_CHAIN (lproto))
+ {
+ p = TREE_VALUE (lproto);
+ rproto = lookup_protocol_in_reflist (rproto_list, p);
- if (!rproto)
- warning ("object does not conform to the `%s' protocol",
- IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
+ if (!rproto)
+ warning
+ ("object does not conform to the `%s' protocol",
+ IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
+ }
+ return 1;
+ }
+ else
+ {
+ /* Obscure case - a comparison between two objects
+ of type 'id <Protocol>'. Check that either the
+ protocol on the lhs is supported by the object on
+ the rhs, or viceversa. */
+
+ /* Check if the protocol on the lhs is supported by the
+ object on the rhs. */
+ for (lproto = lproto_list; lproto;
+ lproto = TREE_CHAIN (lproto))
+ {
+ p = TREE_VALUE (lproto);
+ rproto = lookup_protocol_in_reflist (rproto_list, p);
+
+ if (!rproto)
+ {
+ /* Check failed - check if the protocol on the rhs
+ is supported by the object on the lhs. */
+ for (rproto = rproto_list; rproto;
+ rproto = TREE_CHAIN (rproto))
+ {
+ p = TREE_VALUE (rproto);
+ lproto = lookup_protocol_in_reflist (lproto_list,
+ p);
+
+ if (!lproto)
+ {
+ /* This check failed too: incompatible */
+ return 0;
+ }
+ }
+ return 1;
+ }
+ }
+ return 1;
}
}
+ /* <Protocol> = <class> * */
else if (TYPED_OBJECT (TREE_TYPE (rhs)))
{
tree rname = TYPE_NAME (TREE_TYPE (rhs));
tree rinter;
- /* Make sure the protocol is supported by the object
- on the rhs. */
+ /* Make sure the protocol is supported by the object on
+ the rhs. */
for (lproto = lproto_list; lproto; lproto = TREE_CHAIN (lproto))
{
p = TREE_VALUE (lproto);
tree cat;
rproto_list = CLASS_PROTOCOL_LIST (rinter);
- /* If the underlying ObjC class does not have
- protocols attached to it, perhaps there are
- "one-off" protocols attached to the rhs?
- E.g., 'id<MyProt> foo;'. */
- if (!rproto_list)
- rproto_list = TYPE_PROTOCOL_LIST (TREE_TYPE (rhs));
rproto = lookup_protocol_in_reflist (rproto_list, p);
+ /* If the underlying ObjC class does not have
+ the protocol we're looking for, check for "one-off"
+ protocols (e.g., `NSObject<MyProt> *foo;') attached
+ to the rhs. */
+ if (!rproto)
+ {
+ rproto_list = TYPE_PROTOCOL_LIST (TREE_TYPE (rhs));
+ rproto = lookup_protocol_in_reflist (rproto_list, p);
+ }
/* Check for protocols adopted by categories. */
cat = CLASS_CATEGORY_LIST (rinter);
{
rproto_list = CLASS_PROTOCOL_LIST (cat);
rproto = lookup_protocol_in_reflist (rproto_list, p);
-
cat = CLASS_CATEGORY_LIST (cat);
}
if (!rproto)
warning ("class `%s' does not implement the `%s' protocol",
- IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (rhs))),
- IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
+ IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (rhs))),
+ IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
}
+ return 1;
}
-
- /* May change...based on whether there was any mismatch */
- return 1;
+ /* <Protocol> = id */
+ else if (TYPE_NAME (TREE_TYPE (rhs)) == objc_object_id)
+ {
+ return 1;
+ }
+ /* <Protocol> = Class */
+ else if (TYPE_NAME (TREE_TYPE (rhs)) == objc_class_id)
+ {
+ return 0;
+ }
+ /* <Protocol> = ?? : let comptypes decide. */
+ return -1;
}
else if (rhs_is_proto)
- /* Lhs is not a protocol...warn if it is statically typed */
- return (TYPED_OBJECT (TREE_TYPE (lhs)) != 0);
+ {
+ /* <class> * = <Protocol> */
+ if (TYPED_OBJECT (TREE_TYPE (lhs)))
+ {
+ if (reflexive)
+ {
+ tree rname = TYPE_NAME (TREE_TYPE (lhs));
+ tree rinter;
+ tree rproto, rproto_list = TYPE_PROTOCOL_LIST (rhs);
+
+ /* Make sure the protocol is supported by the object on
+ the lhs. */
+ for (rproto = rproto_list; rproto;
+ rproto = TREE_CHAIN (rproto))
+ {
+ tree p = TREE_VALUE (rproto);
+ tree lproto = 0;
+ rinter = lookup_interface (rname);
+ while (rinter && !lproto)
+ {
+ tree cat;
+
+ tree lproto_list = CLASS_PROTOCOL_LIST (rinter);
+ lproto = lookup_protocol_in_reflist (lproto_list, p);
+ /* If the underlying ObjC class does not
+ have the protocol we're looking for,
+ check for "one-off" protocols (e.g.,
+ `NSObject<MyProt> *foo;') attached to the
+ lhs. */
+ if (!lproto)
+ {
+ lproto_list = TYPE_PROTOCOL_LIST
+ (TREE_TYPE (lhs));
+ lproto = lookup_protocol_in_reflist
+ (lproto_list, p);
+ }
+
+ /* Check for protocols adopted by categories. */
+ cat = CLASS_CATEGORY_LIST (rinter);
+ while (cat && !lproto)
+ {
+ lproto_list = CLASS_PROTOCOL_LIST (cat);
+ lproto = lookup_protocol_in_reflist (lproto_list,
+ p);
+ cat = CLASS_CATEGORY_LIST (cat);
+ }
+
+ rinter = lookup_interface (CLASS_SUPER_NAME
+ (rinter));
+ }
+
+ if (!lproto)
+ warning ("class `%s' does not implement the `%s' protocol",
+ IDENTIFIER_POINTER (TYPE_NAME
+ (TREE_TYPE (lhs))),
+ IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
+ }
+ return 1;
+ }
+ else
+ return 0;
+ }
+ /* id = <Protocol> */
+ else if (TYPE_NAME (TREE_TYPE (lhs)) == objc_object_id)
+ {
+ return 1;
+ }
+ /* Class = <Protocol> */
+ else if (TYPE_NAME (TREE_TYPE (lhs)) == objc_class_id)
+ {
+ return 0;
+ }
+ /* ??? = <Protocol> : let comptypes decide */
+ else
+ {
+ return -1;
+ }
+ }
else
- /* Defer to comptypes. */
- return -1;
+ {
+ /* Attention: we shouldn't defer to comptypes here. One bad
+ side effect would be that we might loose the REFLEXIVE
+ information.
+ */
+ lhs = TREE_TYPE (lhs);
+ rhs = TREE_TYPE (rhs);
+ }
}
- else if (TREE_CODE (lhs) == RECORD_TYPE && TREE_CODE (rhs) == RECORD_TYPE)
- ; /* Fall thru. This is the case we have been handling all along */
- else
- /* Defer to comptypes. */
- return -1;
-
- /* `id' = `<class> *', `<class> *' = `id' */
+ if (TREE_CODE (lhs) != RECORD_TYPE || TREE_CODE (rhs) != RECORD_TYPE)
+ {
+ /* Nothing to do with ObjC - let immediately comptypes take
+ responsibility for checking. */
+ return -1;
+ }
+ /* `id' = `<class> *' `<class> *' = `id': always allow it.
+ Please note that
+ '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)))
return 1;
return 0;
}
else
- /* Defer to comptypes. */
+ /* Not an ObjC type - let comptypes do the check. */
return -1;
}
error_with_decl (decl, "`%s' cannot be statically allocated");
}
-void
-maybe_objc_check_decl (decl)
- tree decl;
-{
- objc_check_decl (decl);
-}
-
/* Implement static typing. At this point, we know we have an interface. */
tree
tree t, m = TYPE_MAIN_VARIANT (type);
t = copy_node (type);
- TYPE_BINFO (t) = make_tree_vec (2);
/* Add this type to the chain of variants of TYPE. */
TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m);
{
type = TREE_TYPE (type_decl);
if (TYPE_MAIN_VARIANT (type) != id_type)
- warning ("Unexpected type for `id' (%s)",
+ warning ("unexpected type for `id' (%s)",
gen_declaration (type, errbuf));
}
else
{
- error ("Undefined type `id', please import <objc/objc.h>");
+ error ("undefined type `id', please import <objc/objc.h>");
return error_mark_node;
}
tree t, m = TYPE_MAIN_VARIANT (type);
t = copy_node (type);
- TYPE_BINFO (t) = make_tree_vec (2);
/* Add this type to the chain of variants of TYPE. */
TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m);
if (!p)
{
- error ("Cannot find protocol declaration for `%s'",
+ error ("cannot find protocol declaration for `%s'",
IDENTIFIER_POINTER (ident));
if (prev)
TREE_CHAIN (prev) = TREE_CHAIN (proto);
DECL_INLINE (umsg_decl) = 1;
DECL_ARTIFICIAL (umsg_decl) = 1;
- if (flag_traditional && TAG_MSGSEND[0] != '_')
- DECL_BUILT_IN_NONANSI (umsg_decl) = 1;
-
make_decl_rtl (umsg_decl, NULL);
pushdecl (umsg_decl);
}
else
- umsg_decl = builtin_function (TAG_MSGSEND, temp_type, 0, NOT_BUILT_IN, 0);
+ umsg_decl = builtin_function (TAG_MSGSEND, temp_type, 0, NOT_BUILT_IN,
+ NULL, NULL_TREE);
/* id objc_msgSendSuper (struct objc_super *, SEL, ...); */
NULL_TREE)));
umsg_super_decl = builtin_function (TAG_MSGSENDSUPER,
- temp_type, 0, NOT_BUILT_IN, 0);
+ temp_type, 0, NOT_BUILT_IN,
+ NULL, NULL_TREE);
/* id objc_getClass (const char *); */
NULL_TREE)));
objc_get_class_decl
- = builtin_function (TAG_GETCLASS, temp_type, 0, NOT_BUILT_IN, 0);
+ = builtin_function (TAG_GETCLASS, temp_type, 0, NOT_BUILT_IN,
+ NULL, NULL_TREE);
/* id objc_getMetaClass (const char *); */
objc_get_meta_class_decl
- = builtin_function (TAG_GETMETACLASS, temp_type, 0, NOT_BUILT_IN, 0);
+ = builtin_function (TAG_GETMETACLASS, temp_type, 0, NOT_BUILT_IN,
+ NULL, NULL_TREE);
/* static SEL _OBJC_SELECTOR_TABLE[]; */
/* Suppress outputting debug symbols, because
dbxout_init hasn'r been called yet. */
enum debug_info_type save_write_symbols = write_symbols;
- struct gcc_debug_hooks *save_hooks = debug_hooks;
+ const struct gcc_debug_hooks *const save_hooks = debug_hooks;
write_symbols = NO_DEBUG;
debug_hooks = &do_nothing_debug_hooks;
/* Forward declare constant_string_id and constant_string_type. */
if (!constant_string_class_name)
- constant_string_class_name = STRING_OBJECT_CLASS_NAME;
-
+ constant_string_class_name = default_constant_string_class_name;
+
constant_string_id = get_identifier (constant_string_class_name);
constant_string_type = xref_tag (RECORD_TYPE, constant_string_id);
}
+/* Predefine the following data type:
+
+ struct STRING_OBJECT_CLASS_NAME
+ {
+ Object isa;
+ char *cString;
+ unsigned int length;
+ }; */
+
+static void
+build_string_class_template ()
+{
+ tree field_decl, field_decl_chain;
+
+ field_decl = create_builtin_decl (FIELD_DECL, id_type, "isa");
+ field_decl_chain = field_decl;
+
+ field_decl = create_builtin_decl (FIELD_DECL,
+ build_pointer_type (char_type_node),
+ "cString");
+ chainon (field_decl_chain, field_decl);
+
+ field_decl = create_builtin_decl (FIELD_DECL, unsigned_type_node, "length");
+ chainon (field_decl_chain, field_decl);
+
+ finish_struct (constant_string_type, field_decl_chain, NULL_TREE);
+}
+
/* Custom build_string which sets TREE_TYPE! */
static tree
int len;
const char *str;
{
- int wide_flag = 0;
- tree a_string = build_string (len, str);
-
- /* Some code from combine_strings, which is local to c-parse.y. */
- if (TREE_TYPE (a_string) == int_array_type_node)
- wide_flag = 1;
-
- TREE_TYPE (a_string)
- = build_array_type (wide_flag ? integer_type_node : char_type_node,
- build_index_type (build_int_2 (len - 1, 0)));
-
- TREE_CONSTANT (a_string) = 1; /* Puts string in the readonly segment */
- TREE_STATIC (a_string) = 1;
-
- return a_string;
+ return fix_string_type (build_string (len, str));
}
/* Given a chain of STRING_CST's, build a static instance of
if (lookup_interface (constant_string_id) == NULL_TREE)
{
- error ("Cannot find interface declaration for `%s'",
+ error ("cannot find interface declaration for `%s'",
IDENTIFIER_POINTER (constant_string_id));
return error_mark_node;
}
add_class_reference (constant_string_id);
- string = combine_strings (strings);
+ if (TREE_CHAIN (strings))
+ {
+ varray_type vstrings;
+ VARRAY_TREE_INIT (vstrings, 32, "strings");
+
+ for (; strings ; strings = TREE_CHAIN (strings))
+ VARRAY_PUSH_TREE (vstrings, strings);
+
+ string = combine_strings (vstrings);
+ }
+ else
+ string = strings;
+
+ string = fix_string_type (string);
+
TREE_SET_CODE (string, STRING_CST);
length = TREE_STRING_LENGTH (string) - 1;
- /* & ((NXConstantString) {0, string, length}) */
+ /* We could not properly create NXConstantString in synth_module_prologue,
+ because that's called before debugging is initialized. Do it now. */
+ if (TYPE_FIELDS (constant_string_type) == NULL_TREE)
+ build_string_class_template ();
+
+ /* & ((NXConstantString) { NULL, string, length }) */
if (flag_next_runtime)
{
setup_string_decl ();
if (string_class_decl == NULL_TREE)
{
- error ("Cannot find reference tag for class `%s'",
+ error ("cannot find reference tag for class `%s'",
IDENTIFIER_POINTER (constant_string_id));
return error_mark_node;
}
build_constructor (type, elts)
tree type, elts;
{
- tree constructor = build (CONSTRUCTOR, type, NULL_TREE, elts);
+ tree constructor, f, e;
+
+ /* ??? Most of the places that we build constructors, we don't fill in
+ the type of integers properly. Convert them all en masse. */
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ f = TREE_TYPE (type);
+ if (TREE_CODE (f) == POINTER_TYPE || TREE_CODE (f) == INTEGER_TYPE)
+ for (e = elts; e ; e = TREE_CHAIN (e))
+ TREE_VALUE (e) = convert (f, TREE_VALUE (e));
+ }
+ else
+ {
+ f = TYPE_FIELDS (type);
+ for (e = elts; e && f; e = TREE_CHAIN (e), f = TREE_CHAIN (f))
+ if (TREE_CODE (TREE_TYPE (f)) == POINTER_TYPE
+ || TREE_CODE (TREE_TYPE (f)) == INTEGER_TYPE)
+ TREE_VALUE (e) = convert (TREE_TYPE (f), TREE_VALUE (e));
+ }
+ constructor = build (CONSTRUCTOR, type, NULL_TREE, elts);
TREE_CONSTANT (constructor) = 1;
TREE_STATIC (constructor) = 1;
TREE_READONLY (constructor) = 1;
return build_constructor (type, nreverse (initlist));
}
-/* Push forward-declarations of all the categories
- so that init_def_list can use them in a CONSTRUCTOR. */
+/* Push forward-declarations of all the categories so that
+ init_def_list can use them in a CONSTRUCTOR. */
static void
forward_declare_categories ()
init_function_decl = current_function_decl;
TREE_PUBLIC (init_function_decl) = ! targetm.have_ctors_dtors;
TREE_USED (init_function_decl) = 1;
+ /* Don't let this one be deferred. */
+ DECL_INLINE (init_function_decl) = 0;
+ DECL_UNINLINABLE (init_function_decl) = 1;
current_function_cannot_inline
= "static constructors and destructors cannot be inlined";
c_expand_expr_stmt (decelerator);
- finish_function (0);
+ finish_function (0, 0);
return XEXP (DECL_RTL (init_function_decl), 0);
}
else
abort ();
- for (; chain != 0; chain = TREE_VALUE (chain))
+ for (; chain != 0; chain = TREE_CHAIN (chain))
if (TREE_VALUE (chain) == ident)
return (TREE_PURPOSE (chain));
{
tree expr;
+ if (warn_selector && objc_implementation_context)
+ {
+ tree method_chain;
+ bool found = false;
+ for (method_chain = meth_var_names_chain;
+ method_chain;
+ method_chain = TREE_CHAIN (method_chain))
+ {
+ if (TREE_VALUE (method_chain) == TREE_VALUE (chain))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ /* Adjust line number for warning message. */
+ int save_lineno = lineno;
+ if (flag_next_runtime && TREE_PURPOSE (chain))
+ lineno = DECL_SOURCE_LINE (TREE_PURPOSE (chain));
+ warning ("creating selector for non existant method %s",
+ IDENTIFIER_POINTER (TREE_VALUE (chain)));
+ lineno = save_lineno;
+ }
+ }
+
expr = build_selector (TREE_VALUE (chain));
if (flag_next_runtime)
identifier_node that represent the selector. */
static tree
-build_typed_selector_reference (ident, proto)
- tree ident, proto;
+build_typed_selector_reference (ident, prototype)
+ tree ident, prototype;
{
tree *chain = &sel_ref_chain;
tree expr;
while (*chain)
{
- if (TREE_PURPOSE (*chain) == ident && TREE_VALUE (*chain) == proto)
+ if (TREE_PURPOSE (*chain) == prototype && TREE_VALUE (*chain) == ident)
goto return_at_index;
index++;
chain = &TREE_CHAIN (*chain);
}
- *chain = tree_cons (proto, ident, NULL_TREE);
+ *chain = tree_cons (prototype, ident, NULL_TREE);
return_at_index:
expr = build_unary_op (ADDR_EXPR,
tree
get_class_reference (ident)
- tree ident;
+ tree ident;
{
if (flag_next_runtime)
{
tree class_ident;
{
if (is_class_name (class_ident) != class_ident)
- warning ("Cannot find class `%s'", IDENTIFIER_POINTER (class_ident));
+ warning ("cannot find class `%s'", IDENTIFIER_POINTER (class_ident));
else if (is_class_name (alias_ident))
- warning ("Class `%s' already exists", IDENTIFIER_POINTER (alias_ident));
+ warning ("class `%s' already exists", IDENTIFIER_POINTER (alias_ident));
else
alias_chain = tree_cons (class_ident, alias_ident, alias_chain);
}
}
tree
+objc_is_id (ident)
+ tree ident;
+{
+ /* NB: This function may be called before the ObjC front-end
+ has been initialized, in which case ID_TYPE will be NULL. */
+ return (id_type && ident && TYPE_P (ident) && IS_ID (ident))
+ ? id_type
+ : NULL_TREE;
+}
+
+tree
lookup_interface (ident)
tree ident;
{
return NULL_TREE;
}
-static tree
-objc_copy_list (list, head)
- tree list;
- tree *head;
-{
- tree newlist = NULL_TREE, tail = NULL_TREE;
+/* Used by: build_private_template, continue_class,
+ and for @defs constructs. */
- while (list)
- {
- tail = copy_node (list);
-
- /* The following statement fixes a bug when inheriting instance
- variables that are declared to be bitfields. finish_struct
- expects to find the width of the bitfield in DECL_INITIAL. */
- if (DECL_BIT_FIELD (tail) && DECL_INITIAL (tail) == 0)
- DECL_INITIAL (tail) = DECL_SIZE (tail);
-
- newlist = chainon (newlist, tail);
- list = TREE_CHAIN (list);
- }
-
- *head = newlist;
- return tail;
-}
-
-/* Used by: build_private_template, get_class_ivars, and
- continue_class. COPY is 1 when called from @defs. In this case
- copy all fields. Otherwise don't copy leaf ivars since we rely on
- them being side-effected exactly once by finish_struct. */
-
-static tree
-build_ivar_chain (interface, copy)
+tree
+get_class_ivars (interface)
tree interface;
- int copy;
{
tree my_name, super_name, ivar_chain;
my_name = CLASS_NAME (interface);
super_name = CLASS_SUPER_NAME (interface);
+ ivar_chain = CLASS_IVARS (interface);
- /* Possibly copy leaf ivars. */
- if (copy)
- objc_copy_list (CLASS_IVARS (interface), &ivar_chain);
- else
- ivar_chain = CLASS_IVARS (interface);
+ /* Save off a pristine copy of the leaf ivars (i.e, those not
+ inherited from a super class). */
+ if (!CLASS_OWN_IVARS (interface))
+ CLASS_OWN_IVARS (interface) = copy_list (ivar_chain);
while (super_name)
{
if (!super_interface)
{
/* fatal did not work with 2 args...should fix */
- error ("Cannot find interface declaration for `%s', superclass of `%s'",
+ error ("cannot find interface declaration for `%s', superclass of `%s'",
IDENTIFIER_POINTER (super_name),
IDENTIFIER_POINTER (my_name));
exit (FATAL_EXIT_CODE);
}
if (super_interface == interface)
- fatal_error ("Circular inheritance in interface declaration for `%s'",
+ fatal_error ("circular inheritance in interface declaration for `%s'",
IDENTIFIER_POINTER (super_name));
interface = super_interface;
my_name = CLASS_NAME (interface);
super_name = CLASS_SUPER_NAME (interface);
- op1 = CLASS_IVARS (interface);
+ op1 = CLASS_OWN_IVARS (interface);
if (op1)
{
- tree head, tail = objc_copy_list (op1, &head);
+ tree head = copy_list (op1);
/* Prepend super class ivars...make a copy of the list, we
do not want to alter the original. */
- TREE_CHAIN (tail) = ivar_chain;
+ chainon (head, ivar_chain);
ivar_chain = head;
}
}
{
uprivate_record = start_struct (RECORD_TYPE, CLASS_NAME (class));
- ivar_context = build_ivar_chain (class, 0);
+ ivar_context = get_class_ivars (class);
finish_struct (uprivate_record, ivar_context, NULL_TREE);
}
static void
-generate_method_descriptors (protocol) /* generate_dispatch_tables */
- tree protocol;
+generate_method_descriptors (protocol)
+ tree protocol;
{
tree initlist, chain, method_list_template;
tree cast, variable_length_type;
int size;
if (!objc_method_prototype_template)
- {
- objc_method_prototype_template = build_method_prototype_template ();
- }
+ objc_method_prototype_template = build_method_prototype_template ();
cast = build_tree_list (build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE,
get_identifier (UTAG_METHOD_PROTOTYPE_LIST))),
/* 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;
{
/* install return type */
TREE_TYPE (TREE_TYPE (tmp_decl)) = groktypename (TREE_TYPE (nst_methods));
+ current_function_decl = NULL;
}
static void
}
}
+/* For each protocol which was referenced either from a @protocol()
+ expression, or because a class/category implements it (then a
+ pointer to the protocol is stored in the struct describing the
+ class/category), we create a statically allocated instance of the
+ Protocol class. The code is written in such a way as to generate
+ as few Protocol objects as possible; we generate a unique Protocol
+ instance for each protocol, and we don't generate a Protocol
+ instance if the protocol is never referenced (either from a
+ @protocol() or from a class/category implementation). These
+ statically allocated objects can be referred to via the static
+ (that is, private to this module) symbols _OBJC_PROTOCOL_n.
+
+ The statically allocated Protocol objects that we generate here
+ need to be fixed up at runtime in order to be used: the 'isa'
+ pointer of the objects need to be set up to point to the 'Protocol'
+ class, as known at runtime.
+
+ The NeXT runtime fixes up all protocols at program startup time,
+ before main() is entered. It uses a low-level trick to look up all
+ those symbols, then loops on them and fixes them up.
+
+ The GNU runtime as well fixes up all protocols before user code
+ from the module is executed; it requires pointers to those symbols
+ to be put in the objc_symtab (which is then passed as argument to
+ the function __objc_exec_class() which the compiler sets up to be
+ executed automatically when the module is loaded); setup of those
+ Protocol objects happen in two ways in the GNU runtime: all
+ Protocol objects referred to by a class or category implementation
+ are fixed up when the class/category is loaded; all Protocol
+ objects referred to by a @protocol() expression are added by the
+ compiler to the list of statically allocated instances to fixup
+ (the same list holding the statically allocated constant string
+ objects). Because, as explained above, the compiler generates as
+ few Protocol objects as possible, some Protocol object might end up
+ being referenced multiple times when compiled with the GNU runtime,
+ and end up being fixed up multiple times at runtime inizialization.
+ But that doesn't hurt, it's just a little inefficient. */
static void
generate_protocols ()
{
tree decl;
tree rawdecl;
{
- count_error (0);
+ diagnostic_count_diagnostic (global_dc, DK_ERROR);
- report_error_function (DECL_SOURCE_FILE (decl));
+ diagnostic_report_current_function (global_dc);
error_with_file_and_line (DECL_SOURCE_FILE (decl),
DECL_SOURCE_LINE (decl),
}
-#define USERTYPE(t) \
- (TREE_CODE (t) == RECORD_TYPE || TREE_CODE (t) == UNION_TYPE \
- || TREE_CODE (t) == ENUMERAL_TYPE)
-
static void
check_ivars (inter, imp)
tree inter;
ivar);
obstack_free (&util_obstack, util_firstobj);
- /* Set offset. */
+ /* Set offset. */
ivar = tree_cons (NULL_TREE, byte_position (field_decl), ivar);
initlist = tree_cons (NULL_TREE,
build_constructor (type, nreverse (ivar)),
build_selector (METHOD_SEL_NAME (entries)),
NULL_TREE);
+ /* Generate the method encoding if we don't have one already. */
+ if (! METHOD_ENCODING (entries))
+ METHOD_ENCODING (entries) =
+ encode_method_def (METHOD_DEFINITION (entries));
+
elemlist = tree_cons (NULL_TREE,
add_objc_string (METHOD_ENCODING (entries),
meth_var_types),
chain;
chain = TREE_CHAIN (chain))
{
+ if (TYPED_OBJECT (TREE_VALUE (chain))
+ && !(TREE_VALUE (type)
+ && TREE_CODE (TREE_VALUE (type)) == INDIRECT_REF))
+ error ("can not use an object as parameter to a method\n");
if (!is_objc_type_qualifier (TREE_VALUE (chain)))
return type;
}
the identifier of the selector of the message. This is
used when printing warnings about argument mismatches. */
-static tree building_objc_message_expr = 0;
+static tree current_objc_message_selector = 0;
tree
-maybe_building_objc_message_expr ()
+objc_message_selector ()
{
- return building_objc_message_expr;
+ return current_objc_message_selector;
}
/* Construct an expression for sending a message.
tree selector, self_object, retval;
int statically_typed = 0, statically_allocated = 0;
- /* Determine receiver type. */
+ /* Determine receiver type. */
tree rtype = TREE_TYPE (receiver);
int super = IS_SUPER (rtype);
&& TREE_STATIC_TEMPLATE (TREE_TYPE (rtype)))
statically_typed = 1;
else if ((flag_next_runtime
- || (IS_ID (rtype)
- && (class_ident = receiver_is_class_object (receiver)))))
+ || (IS_ID (rtype)))
+ && (class_ident = receiver_is_class_object (receiver)))
;
else if (! IS_ID (rtype)
/* Allow any type that matches objc_class_type. */
if (statically_allocated)
receiver = build_unary_op (ADDR_EXPR, receiver, 0);
- /* Don't evaluate the receiver twice. */
+ /* Don't evaluate the receiver twice. */
receiver = save_expr (receiver);
self_object = receiver;
}
if (iface)
method_prototype = lookup_instance_method_static (iface, sel_name);
- if (! method_prototype && TYPE_PROTOCOL_LIST (ctype))
+ if (! method_prototype && ctype && TYPE_PROTOCOL_LIST (ctype))
method_prototype
= lookup_method_in_protocol_list (TYPE_PROTOCOL_LIST (ctype),
sel_name, 0);
if (!method_prototype)
{
- warning ("cannot find class (factory) method.");
+ warning ("cannot find class (factory) method");
warning ("return type for `%s' defaults to id",
IDENTIFIER_POINTER (sel_name));
}
{
hash hsh;
- warning ("method `%s' not implemented by protocol.",
+ warning ("method `%s' not implemented by protocol",
IDENTIFIER_POINTER (sel_name));
/* Try and find the method signature in the global pools. */
method_prototype = check_duplicates (hsh);
if (!method_prototype)
{
- warning ("cannot find method.");
+ warning ("cannot find method");
warning ("return type for `%s' defaults to id",
IDENTIFIER_POINTER (sel_name));
}
}
/* Save the selector name for printing error messages. */
- building_objc_message_expr = sel_name;
+ current_objc_message_selector = sel_name;
/* Build the parameters list for looking up the method.
These are the object itself and the selector. */
receiver, self_object,
selector, method_params);
- building_objc_message_expr = 0;
+ current_objc_message_selector = 0;
return retval;
}
PROTOCOL_FORWARD_DECL (p) = decl;
}
+/* This function is called by the parser when (and only when) a
+ @protocol() expression is found, in order to compile it. */
tree
build_protocol_expr (protoname)
tree protoname;
if (!p)
{
- error ("Cannot find protocol declaration for `%s'",
+ error ("cannot find protocol declaration for `%s'",
IDENTIFIER_POINTER (protoname));
return error_mark_node;
}
TREE_TYPE (expr) = protocol_type;
+ /* The @protocol() expression is being compiled into a pointer to a
+ statically allocated instance of the Protocol class. To become
+ usable at runtime, the 'isa' pointer of the instance need to be
+ fixed up at runtime by the runtime library, to point to the
+ actual 'Protocol' class. */
+
+ /* For the GNU runtime, put the static Protocol instance in the list
+ of statically allocated instances, so that we make sure that its
+ 'isa' pointer is fixed up at runtime by the GNU runtime library
+ to point to the Protocol class (at runtime, when loading the
+ module, the GNU runtime library loops on the statically allocated
+ instances (as found in the defs field in objc_symtab) and fixups
+ all the 'isa' pointers of those objects). */
+ if (! flag_next_runtime)
+ {
+ /* This type is a struct containing the fields of a Protocol
+ object. (Cfr. protocol_type instead is the type of a pointer
+ to such a struct). */
+ tree protocol_struct_type = xref_tag
+ (RECORD_TYPE, get_identifier (PROTOCOL_OBJECT_CLASS_NAME));
+ tree *chain;
+
+ /* Look for the list of Protocol statically allocated instances
+ to fixup at runtime. Create a new list to hold Protocol
+ statically allocated instances, if the list is not found. At
+ present there is only another list, holding NSConstantString
+ static instances to be fixed up at runtime. */
+ for (chain = &objc_static_instances;
+ *chain && TREE_VALUE (*chain) != protocol_struct_type;
+ chain = &TREE_CHAIN (*chain));
+ if (!*chain)
+ {
+ *chain = tree_cons (NULL_TREE, protocol_struct_type, NULL_TREE);
+ add_objc_string (TYPE_NAME (protocol_struct_type),
+ class_names);
+ }
+
+ /* Add this statically allocated instance to the Protocol list. */
+ TREE_PURPOSE (*chain) = tree_cons (NULL_TREE,
+ PROTOCOL_FORWARD_DECL (p),
+ TREE_PURPOSE (*chain));
+ }
+
+
return expr;
}
+/* This function is called by the parser when a @selector() expression
+ is found, in order to compile it. It is only called by the parser
+ and only to compile a @selector(). */
tree
build_selector_expr (selnamelist)
tree selnamelist;
else
abort ();
+ /* If we are required to check @selector() expressions as they
+ are found, check that the selector has been declared. */
+ if (warn_undeclared_selector)
+ {
+ /* Look the selector up in the list of all known class and
+ instance methods (up to this line) to check that the selector
+ exists. */
+ hash hsh;
+
+ /* First try with instance methods. */
+ hsh = hash_lookup (nst_method_hash_list, selname);
+
+ /* If not found, try with class methods. */
+ if (!hsh)
+ {
+ hsh = hash_lookup (cls_method_hash_list, selname);
+ }
+
+ /* If still not found, print out a warning. */
+ if (!hsh)
+ {
+ warning ("undeclared selector `%s'", IDENTIFIER_POINTER (selname));
+ }
+ }
+
+
if (flag_typed_selectors)
return build_typed_selector_reference (selname, 0);
else
return build_component_ref (build_indirect_ref (self_decl, "->"), id);
}
-\f/* Make the hash value positive. */
-#define HASHFUNCTION(key) ((size_t) key & 0x7fffffff)
+\f
+/* Compute a hash value for a given method SEL_NAME. */
+static size_t
+hash_func (sel_name)
+ tree sel_name;
+{
+ const unsigned char *s
+ = (const unsigned char *)IDENTIFIER_POINTER (sel_name);
+ size_t h = 0;
+
+ while (*s)
+ h = h * 67 + *s++ - 113;
+ return h;
+}
+
static void
hash_init ()
{
- nst_method_hash_list = (hash *) xcalloc (SIZEHASHTABLE, sizeof (hash));
- cls_method_hash_list = (hash *) xcalloc (SIZEHASHTABLE, sizeof (hash));
+ nst_method_hash_list = (hash *) ggc_calloc (SIZEHASHTABLE, sizeof (hash));
+ cls_method_hash_list = (hash *) ggc_calloc (SIZEHASHTABLE, sizeof (hash));
}
/* WARNING!!!! hash_enter is called with a method, and will peek
hash *hashlist;
tree method;
{
- static hash hash_alloc_list = 0;
- static int hash_alloc_index = 0;
hash obj;
- int slot = HASHFUNCTION (METHOD_SEL_NAME (method)) % SIZEHASHTABLE;
+ int slot = hash_func (METHOD_SEL_NAME (method)) % SIZEHASHTABLE;
- if (! hash_alloc_list || hash_alloc_index >= HASH_ALLOC_LIST_SIZE)
- {
- hash_alloc_index = 0;
- hash_alloc_list = (hash) xmalloc (sizeof (struct hashed_entry)
- * HASH_ALLOC_LIST_SIZE);
- }
- obj = &hash_alloc_list[hash_alloc_index++];
+ obj = (hash) ggc_alloc (sizeof (struct hashed_entry));
obj->list = 0;
obj->next = hashlist[slot];
obj->key = method;
{
hash target;
- target = hashlist[HASHFUNCTION (sel_name) % SIZEHASHTABLE];
+ target = hashlist[hash_func (sel_name) % SIZEHASHTABLE];
while (target)
{
hash entry;
tree value;
{
- static attr attr_alloc_list = 0;
- static int attr_alloc_index = 0;
attr obj;
- if (! attr_alloc_list || attr_alloc_index >= ATTR_ALLOC_LIST_SIZE)
- {
- attr_alloc_index = 0;
- attr_alloc_list = (attr) xmalloc (sizeof (struct hashed_attribute)
- * ATTR_ALLOC_LIST_SIZE);
- }
- obj = &attr_alloc_list[attr_alloc_index++];
+ obj = (attr) ggc_alloc (sizeof (struct hashed_attribute));
obj->next = entry->list;
obj->value = value;
{
if (METHOD_SEL_NAME (mchain) == key)
return mchain;
+
mchain = TREE_CHAIN (mchain);
}
return NULL_TREE;
else
{
if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE)
- error ("duplicate definition of class method `%s'.",
+ error ("duplicate definition of class method `%s'",
IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
else
{
/* Check types; if different, complain. */
if (!comp_proto_with_proto (method, mth))
- error ("duplicate declaration of class method `%s'.",
+ error ("duplicate declaration of class method `%s'",
IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
}
}
else
{
if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE)
- error ("duplicate definition of instance method `%s'.",
+ error ("duplicate definition of instance method `%s'",
IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
else
{
/* Check types; if different, complain. */
if (!comp_proto_with_proto (method, mth))
- error ("duplicate declaration of instance method `%s'.",
+ error ("duplicate declaration of instance method `%s'",
IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
}
}
{
if (!lookup_interface (TYPE_NAME (basetype)))
{
- error ("Cannot find interface declaration for `%s'",
+ error ("cannot find interface declaration for `%s'",
IDENTIFIER_POINTER (TYPE_NAME (basetype)));
return 0;
}
return 1;
}
-
-/* Implement @defs (<classname>) within struct bodies. */
-
-tree
-get_class_ivars (interface)
- tree interface;
-{
- /* Make sure we copy the leaf ivars in case @defs is used in a local
- context. Otherwise finish_struct will overwrite the layout info
- using temporary storage. */
- return build_ivar_chain (interface, 1);
-}
\f
/* Make sure all entries in CHAIN are also in LIST. */
chain = TREE_CHAIN (chain); /* next method... */
}
- return first;
+ return first;
}
/* Check whether the current interface (accessible via
int f1, f2;
/* Ensure that all protocols have bodies! */
- if (flag_warn_protocol)
+ if (warn_protocol)
{
f1 = check_methods (PROTOCOL_CLS_METHODS (p),
CLASS_CLS_METHODS (objc_implementation_context),
tree subs = PROTOCOL_LIST (p);
tree super_class =
lookup_interface (CLASS_SUPER_NAME (implementation_template));
+
while (subs)
{
tree sub = TREE_VALUE (subs);
}
class = make_node (code);
- TYPE_BINFO (class) = make_tree_vec (5);
+ TYPE_BINFO (class) = make_tree_vec (6);
CLASS_NAME (class) = class_name;
CLASS_SUPER_NAME (class) = super_name;
if (!(implementation_template = lookup_interface (class_name)))
{
- warning ("Cannot find interface declaration for `%s'",
+ warning ("cannot find interface declaration for `%s'",
IDENTIFIER_POINTER (class_name));
add_class (implementation_template = objc_implementation_context);
}
if (!(class_category_is_assoc_with = lookup_interface (class_name)))
{
- error ("Cannot find interface declaration for `%s'",
+ error ("cannot find interface declaration for `%s'",
IDENTIFIER_POINTER (class_name));
exit (FATAL_EXIT_CODE);
}
if (!(implementation_template = lookup_interface (class_name)))
{
- error ("Cannot find interface declaration for `%s'",
+ error ("cannot find interface declaration for `%s'",
IDENTIFIER_POINTER (class_name));
exit (FATAL_EXIT_CODE);
}
if (!objc_class_template)
build_class_template ();
- imp_entry = (struct imp_entry *) xmalloc (sizeof (struct imp_entry));
+ imp_entry = (struct imp_entry *) ggc_alloc (sizeof (struct imp_entry));
imp_entry->next = imp_list;
imp_entry->imp_context = class;
if (!TYPE_FIELDS (record))
{
- finish_struct (record, build_ivar_chain (class, 0), NULL_TREE);
+ finish_struct (record, get_class_ivars (class), NULL_TREE);
CLASS_STATIC_TEMPLATE (class) = record;
/* Mark this record as a class template for static typing. */
tree chain;
for (chain = protocol_chain; chain; chain = TREE_CHAIN (chain))
- {
- if (ident == PROTOCOL_NAME (chain))
- return chain;
- }
+ if (ident == PROTOCOL_NAME (chain))
+ return chain;
return NULL_TREE;
}
void
finish_protocol (protocol)
- tree protocol ATTRIBUTE_UNUSED;
+ tree protocol ATTRIBUTE_UNUSED;
{
}
{
tree name = TYPE_NAME (type);
- /* we have a reference; this is a NeXT extension. */
+ /* we have a reference; this is a NeXT extension. */
if (obstack_object_size (&util_obstack) - curtype == 1
&& format == OBJC_ENCODE_INLINE_DEFS)
{
- /* Output format of struct for first level only. */
+ /* Output format of struct for first level only. */
tree fields = TYPE_FIELDS (type);
if (name && TREE_CODE (name) == IDENTIFIER_NODE)
else
{
- /* We have an untagged structure or a typedef. */
+ /* We have an untagged structure or a typedef. */
obstack_1grow (&util_obstack, left);
obstack_1grow (&util_obstack, '?');
obstack_1grow (&util_obstack, right);
IDENTIFIER_POINTER (name),
strlen (IDENTIFIER_POINTER (name)));
else
- /* We have an untagged structure or a typedef. */
+ /* We have an untagged structure or a typedef. */
obstack_1grow (&util_obstack, '?');
obstack_1grow (&util_obstack, right);
}
static void
-encode_complete_bitfield (int position, tree type, int size)
+encode_complete_bitfield (position, type, size)
+ int position;
+ tree type;
+ int size;
{
enum tree_code code = TREE_CODE (type);
char buffer[40];
charType = 'q';
}
}
-
+ else if (code == ENUMERAL_TYPE)
+ charType = 'i';
else
abort ();
the bitfield typing information. */
if (flag_next_runtime)
{
- if (DECL_BIT_FIELD (field_decl))
+ if (DECL_BIT_FIELD_TYPE (field_decl))
encode_bitfield (tree_low_cst (DECL_SIZE (field_decl), 1));
else
encode_type (TREE_TYPE (field_decl), curtype, format);
}
else
{
- if (DECL_BIT_FIELD (field_decl))
+ if (DECL_BIT_FIELD_TYPE (field_decl))
encode_complete_bitfield (int_bit_position (field_decl),
DECL_BIT_FIELD_TYPE (field_decl),
tree_low_cst (DECL_SIZE (field_decl), 1));
int mtype;
tree method;
{
- if (count_error (1) == 0)
+ if (!diagnostic_count_diagnostic (global_dc, DK_WARNING))
return;
- report_error_function (DECL_SOURCE_FILE (method));
+ diagnostic_report_current_function (global_dc);
/* Add a readable method name to the warning. */
warning_with_file_and_line (DECL_SOURCE_FILE (method),
tree super_name = CLASS_SUPER_NAME (implementation_template);
tree super_class;
- /* Barf if super used in a category of Object. */
+ /* Barf if super used in a category of Object. */
if (!super_name)
{
error ("no super class declared in interface for `%s'",
{
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. */
super_class
- = build_component_ref (build_indirect_ref (super_class, "->"),
- get_identifier ("isa"));
+ = build_component_ref (build_indirect_ref
+ (build_c_cast (id_type, super_class), "->"),
+ get_identifier ("isa"));
}
else
{
finish_method_def ()
{
lang_expand_function_end = objc_expand_function_end;
- finish_function (0);
+ finish_function (0, 1);
lang_expand_function_end = NULL;
/* Required to implement _msgSuper. This must be done AFTER finish_function,
\f
/* Debug info. */
+
+/* Dump an @interface declaration of the supplied class CHAIN to the
+ supplied file FP. Used to implement the -gen-decls option (which
+ prints out an @interface declaration of all classes compiled in
+ this run); potentially useful for debugging the compiler too. */
static void
dump_interface (fp, chain)
FILE *fp;
tree chain;
{
- char *buf = (char *)xmalloc (256);
+ /* FIXME: A heap overflow here whenever a method (or ivar)
+ declaration is so long that it doesn't fit in the buffer. The
+ code and all the related functions should be rewritten to avoid
+ using fixed size buffers. */
+ char *buf = (char *) xmalloc (1024 * 10);
const char *my_name = IDENTIFIER_POINTER (CLASS_NAME (chain));
tree ivar_decls = CLASS_RAW_IVARS (chain);
tree nst_methods = CLASS_NST_METHODS (chain);
fprintf (fp, "\n@interface %s", my_name);
+ /* CLASS_SUPER_NAME is used to store the superclass name for
+ classes, and the category name for categories. */
if (CLASS_SUPER_NAME (chain))
{
- const char *super_name = IDENTIFIER_POINTER (CLASS_SUPER_NAME (chain));
- fprintf (fp, " : %s\n", super_name);
+ const char *name = IDENTIFIER_POINTER (CLASS_SUPER_NAME (chain));
+
+ if (TREE_CODE (chain) == CATEGORY_IMPLEMENTATION_TYPE
+ || TREE_CODE (chain) == CATEGORY_INTERFACE_TYPE)
+ {
+ fprintf (fp, " (%s)\n", name);
+ }
+ else
+ {
+ fprintf (fp, " : %s\n", name);
+ }
}
else
fprintf (fp, "\n");
+ /* FIXME - the following doesn't seem to work at the moment. */
if (ivar_decls)
{
fprintf (fp, "{\n");
fprintf (fp, "+ %s;\n", gen_method_decl (cls_methods, buf));
cls_methods = TREE_CHAIN (cls_methods);
}
- fprintf (fp, "\n@end");
+
+ fprintf (fp, "@end\n");
}
/* Demangle function for Objective-C */
return mangled; /* not an objc mangled name */
}
-static const char *
+const char *
objc_printable_name (decl, kind)
tree decl;
int kind ATTRIBUTE_UNUSED;
static void
init_objc ()
{
- /* Add the special tree codes of Objective C to the tables. */
-
gcc_obstack_init (&util_obstack);
util_firstobj = (char *) obstack_finish (&util_obstack);
- memcpy (tree_code_type + (int) LAST_BASE_TREE_CODE,
- objc_tree_code_type,
- (int) LAST_OBJC_TREE_CODE - (int) LAST_BASE_TREE_CODE);
- memcpy (tree_code_length + (int) LAST_BASE_TREE_CODE,
- objc_tree_code_length,
- (((int) LAST_OBJC_TREE_CODE - (int) LAST_BASE_TREE_CODE) * sizeof (int)));
- memcpy (tree_code_name + (int) LAST_BASE_TREE_CODE,
- objc_tree_code_name,
- (((int) LAST_OBJC_TREE_CODE - (int) LAST_BASE_TREE_CODE) * sizeof (char *)));
-
- errbuf = (char *)xmalloc (BUFSIZE);
+ errbuf = (char *) xmalloc (BUFSIZE);
hash_init ();
synth_module_prologue ();
}
#endif
/* Process the static instances here because initialization of objc_symtab
- depends on them. */
+ depends on them. */
if (objc_static_instances)
generate_static_references ();
UOBJC_CLASS_decl = impent->class_decl;
UOBJC_METACLASS_decl = impent->meta_decl;
-
+
+ /* Dump the @interface of each class as we compile it, if the
+ -gen-decls option is in use. TODO: Dump the classes in the
+ order they were found, rather than in reverse order as we
+ are doing now. */
+ if (flag_gen_declaration)
+ {
+ dump_interface (gen_declaration_file, objc_implementation_context);
+ }
+
if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE)
{
/* all of the following reference the string pool... */
if (objc_implementation_context || class_names_chain || objc_static_instances
|| meth_var_names_chain || meth_var_types_chain || sel_ref_chain)
{
- /* Arrange for Objc data structures to be initialized at run time. */
+ /* Arrange for ObjC data structures to be initialized at run time. */
rtx init_sym = build_module_descriptor ();
if (init_sym && targetm.have_ctors_dtors)
(* targetm.asm_out.constructor) (init_sym, DEFAULT_INIT_PRIORITY);
generate_strings ();
- if (flag_gen_declaration)
- {
- add_class (objc_implementation_context);
- dump_interface (gen_declaration_file, objc_implementation_context);
- }
-
if (warn_selector)
{
int slot;
static void
generate_classref_translation_entry (chain)
- tree chain;
+ tree chain;
{
tree expr, name, decl_specs, decl, sc_spec;
tree type;
decl = build_decl (VAR_DECL, get_identifier (string), string_type_node);
DECL_INITIAL (decl) = exp;
TREE_STATIC (decl) = 1;
+ TREE_USED (decl) = 1;
pushdecl (decl);
rest_of_decl_compilation (decl, 0, 0, 0);
string = (char *) alloca (strlen (class_name) + 30);
- sprintf (string, "*%sobjc_class_name_%s",
+ sprintf (string, "%sobjc_class_name_%s",
(flag_next_runtime ? "." : "__"), class_name);
}
else if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE)
/* Do the same for categories. Even though no references to
these symbols are generated automatically by the compiler, it
- gives you a handle to pull them into an archive by hand. */
+ gives you a handle to pull them into an archive by hand. */
sprintf (string, "*%sobjc_category_name_%s_%s",
(flag_next_runtime ? "." : "__"), class_name, class_super_name);
}
ASM_DECLARE_CLASS_REFERENCE (asm_out_file, string);
return;
}
+ else
#endif
-
- /* (Should this be a routine in varasm.c?) */
- readonly_data_section ();
- assemble_global (string);
- assemble_align (UNITS_PER_WORD);
- assemble_label (string);
- assemble_zeros (UNITS_PER_WORD);
-}
-\f
-static void
-ggc_mark_imp_list (arg)
- void *arg;
-{
- struct imp_entry *impent;
-
- for (impent = *(struct imp_entry **)arg; impent; impent = impent->next)
{
- ggc_mark_tree (impent->imp_context);
- ggc_mark_tree (impent->imp_template);
- ggc_mark_tree (impent->class_decl);
- ggc_mark_tree (impent->meta_decl);
- }
-}
-
-static void
-ggc_mark_hash_table (arg)
- void *arg;
-{
- hash *hash_table = *(hash **)arg;
- hash hst;
- attr list;
- int i;
-
- if (hash_table == NULL)
- return;
- for (i = 0; i < SIZEHASHTABLE; i++)
- for (hst = hash_table [i]; hst; hst = hst->next)
- {
- ggc_mark_tree (hst->key);
- for (list = hst->list; list; list = list->next)
- ggc_mark_tree (list->value);
- }
-}
+ tree decl, init;
-/* Add GC roots for variables local to this file. */
-static void
-objc_act_parse_init ()
-{
- ggc_add_tree_root (objc_global_trees, OCTI_MAX);
- ggc_add_root (&imp_list, 1, sizeof imp_list, ggc_mark_imp_list);
- ggc_add_root (&nst_method_hash_list, 1, sizeof nst_method_hash_list, ggc_mark_hash_table);
- ggc_add_root (&cls_method_hash_list, 1, sizeof cls_method_hash_list, ggc_mark_hash_table);
+ init = build_int_2 (0, 0);
+ TREE_TYPE (init) = c_common_type_for_size (BITS_PER_WORD, 1);
+ decl = build_decl (VAR_DECL, get_identifier (string), TREE_TYPE (init));
+ TREE_PUBLIC (decl) = 1;
+ TREE_READONLY (decl) = 1;
+ TREE_USED (decl) = 1;
+ TREE_CONSTANT (decl) = 1;
+ DECL_CONTEXT (decl) = 0;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_INITIAL (decl) = init;
+ assemble_variable (decl, 1, 0, 0);
+ }
}
-
+\f
/* Look up ID as an instance variable. */
tree
lookup_objc_ivar (id)
{
tree decl;
- if (objc_receiver_context && !strcmp (IDENTIFIER_POINTER (id), "super"))
- /* we have a message to super */
+ if (objc_method_context && !strcmp (IDENTIFIER_POINTER (id), "super"))
+ /* We have a message to super. */
return get_super_receiver ();
else if (objc_method_context && (decl = is_ivar (objc_ivar_chain, id)))
{
else
return 0;
}
+
+#include "gtype-objc.h"