/* Implement classes and message passing for Objective C.
Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by Steve Naroff.
This file is part of GCC.
#endif
#include "c-common.h"
+#include "c-pragma.h"
#include "flags.h"
#include "langhooks.h"
#include "objc-act.h"
#include "tree-iterator.h"
#include "libfuncs.h"
#include "hashtab.h"
+#include "langhooks-def.h"
#define OBJC_VOID_AT_END void_list_node
+static unsigned int should_call_super_dealloc = 0;
+
/* When building Objective-C++, we are not linking against the C front-end
and so need to replicate the C tree-construction functions in some way. */
#ifdef OBJCPLUS
the module (file) was compiled for, and is recorded in the
module descriptor. */
-#define OBJC_VERSION (flag_next_runtime ? 5 : 8)
+#define OBJC_VERSION (flag_next_runtime ? 6 : 8)
#define PROTOCOL_VERSION 2
/* (Decide if these can ever be validly changed.) */
/* Code generation. */
-static void synth_module_prologue (void);
static tree objc_build_constructor (tree, tree);
-static void build_module_descriptor (void);
-static void build_module_initializer_routine (void);
-static tree init_module_descriptor (tree);
static tree build_objc_method_call (int, tree, tree, tree, tree);
-static void generate_strings (void);
static tree get_proto_encoding (tree);
-static void build_selector_translation_table (void);
static tree lookup_interface (tree);
static tree objc_add_static_instance (tree, tree);
static void objc_start_function (tree, tree, tree, struct c_arg_info *);
#endif
static tree start_protocol (enum tree_code, tree, tree);
-static tree build_method_decl (enum tree_code, tree, tree, tree);
+static tree build_method_decl (enum tree_code, tree, tree, tree, bool);
static tree objc_add_method (tree, tree, int);
static tree add_instance_variable (tree, int, tree);
static tree build_ivar_reference (tree);
static tree is_ivar (tree, tree);
-static int is_private (tree);
-static tree get_super_receiver (void);
static void build_objc_exception_stuff (void);
static void build_next_objc_exception_stuff (void);
-static tree build_ivar_template (void);
-static tree build_method_template (void);
-static tree build_private_template (tree);
static void build_class_template (void);
static void build_selector_template (void);
static void build_category_template (void);
-static tree lookup_method_in_hash_lists (tree, int);
static void build_super_template (void);
-static tree build_category_initializer (tree, tree, tree, tree, tree, tree);
static tree build_protocol_initializer (tree, tree, tree, tree, tree);
-static void synth_forward_declarations (void);
-static int ivar_list_length (tree);
static tree get_class_ivars (tree);
-static void generate_ivar_lists (void);
-static void generate_dispatch_tables (void);
-static void generate_shared_structures (void);
static tree generate_protocol_list (tree);
static void build_protocol_reference (tree);
-static tree build_keyword_selector (tree);
-static const char *synth_id_with_class_suffix (const char *, tree);
+#ifdef OBJCPLUS
+static void objc_generate_cxx_cdtors (void);
+#endif
-static void generate_static_references (void);
-static int check_methods_accessible (tree, tree, int);
-static void encode_aggregate_within (tree, int, int, int, int);
-static const char *objc_demangle (const char *);
+static const char *synth_id_with_class_suffix (const char *, tree);
/* 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 (tree);
-static void hash_init (void);
-static void hash_enter (hash *, tree);
static hash hash_lookup (hash *, tree);
-static void hash_add_attr (hash, tree);
static tree lookup_method (tree, tree);
static tree lookup_method_static (tree, tree, int);
-static void add_method_to_hash_list (hash *, tree);
-static tree add_class (tree);
-static void add_category (tree, tree);
-static inline tree lookup_category (tree, tree);
enum string_section
{
};
static tree add_objc_string (tree, enum string_section);
-static tree get_objc_string_decl (tree, enum string_section);
static tree build_objc_string_decl (enum string_section);
-static tree build_selector_reference_decl (void);
static void build_selector_table_decl (void);
/* Protocol additions. */
-static tree add_protocol (tree);
static tree lookup_protocol (tree);
-static void check_protocol_recursively (tree, tree);
static tree lookup_and_install_protocols (tree);
/* Type encoding. */
static void encode_type_qualifiers (tree);
-static void encode_pointer (tree, int, int);
-static void encode_array (tree, int, int);
-static void encode_aggregate (tree, int, int);
-static void encode_next_bitfield (int);
-static void encode_gnu_bitfield (int, tree, int);
static void encode_type (tree, int, int);
static void encode_field_decl (tree, int, int);
#else
static void really_start_method (tree, struct c_arg_info *);
#endif
-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 int comp_proto_with_proto (tree, tree, int);
static void objc_push_parm (tree);
#ifdef OBJCPLUS
static tree objc_get_parm_info (int);
#else
static struct c_arg_info *objc_get_parm_info (int);
#endif
-static void synth_self_and_ucmd_args (void);
/* Utilities for debugging and error diagnostics. */
static void warn_with_method (const char *, int, tree);
-static void error_with_ivar (const char *, tree);
static char *gen_type_name (tree);
static char *gen_type_name_0 (tree);
static char *gen_method_decl (tree);
static char *gen_declaration (tree);
-static void dump_interface (FILE *, tree);
/* Everything else. */
-static tree lookup_method_in_protocol_list (tree, tree, int);
-static tree lookup_protocol_in_reflist (tree, tree);
-static tree start_var_decl (tree, const char *);
-static void finish_var_decl (tree, tree);
static tree create_field_decl (tree, const char *);
-static tree setup_string_decl (void);
-static int check_string_class_template (void);
-static tree my_build_string (int, const char *);
-static void build_objc_symtab_template (void);
-static tree init_def_list (tree);
-static tree init_objc_symtab (tree);
-static tree build_metadata_decl (const char *, tree);
-static void forward_declare_categories (void);
-static void generate_objc_symtab_decl (void);
-static tree build_selector (tree);
-static tree build_typed_selector_reference (tree, tree);
-static tree build_selector_reference (tree);
-static tree build_class_reference_decl (void);
static void add_class_reference (tree);
static void build_protocol_template (void);
-static tree build_descriptor_table_initializer (tree, tree);
-static tree build_method_prototype_list_template (tree, int);
-static tree build_method_prototype_template (void);
-static tree objc_method_parm_type (tree);
-static int objc_encoded_type_size (tree);
static tree encode_method_prototype (tree);
-static tree generate_descriptor_table (tree, const char *, int, tree, tree);
-static void generate_method_descriptors (tree);
-static void generate_protocol_references (tree);
-static void generate_protocols (void);
-static void check_ivars (tree, tree);
-static tree build_ivar_list_template (tree, int);
-static tree build_method_list_template (tree, int);
-static tree build_ivar_list_initializer (tree, tree);
-static tree generate_ivars_list (tree, const char *, int, tree);
-static tree build_dispatch_table_initializer (tree, tree);
-static tree generate_dispatch_table (tree, const char *, int, tree);
-static tree build_shared_structure_initializer (tree, tree, tree, tree,
- tree, int, tree, tree, tree);
-static void generate_category (tree);
-static tree adjust_type_for_id_default (tree);
-static tree check_duplicates (hash, int, int);
-static tree receiver_is_class_object (tree, int, int);
-static int check_methods (tree, tree, int);
-static int conforms_to_protocol (tree, tree);
-static void check_protocol (tree, const char *, const char *);
-static void check_protocols (tree, const char *, const char *);
static void generate_classref_translation_entry (tree);
static void handle_class_ref (tree);
static void generate_struct_by_value_array (void)
/* Runtime metadata flags. */
#define CLS_FACTORY 0x0001L
#define CLS_META 0x0002L
+#define CLS_HAS_CXX_STRUCTORS 0x2000L
#define OBJC_MODIFIER_STATIC 0x00000001
#define OBJC_MODIFIER_FINAL 0x00000002
#define TAG_SETJMP "_setjmp"
#define UTAG_EXCDATA "_objc_exception_data"
+#define TAG_ASSIGNIVAR "objc_assign_ivar"
+#define TAG_ASSIGNGLOBAL "objc_assign_global"
+#define TAG_ASSIGNSTRONGCAST "objc_assign_strongCast"
+
+/* Branch entry points. All that matters here are the addresses;
+ functions with these names do not really exist in libobjc. */
+
+#define TAG_MSGSEND_FAST "objc_msgSend_Fast"
+#define TAG_ASSIGNIVAR_FAST "objc_assign_ivar_Fast"
+
+#define TAG_CXX_CONSTRUCT ".cxx_construct"
+#define TAG_CXX_DESTRUCT ".cxx_destruct"
+
/* GNU-specific tags. */
#define TAG_EXECCLASS "__objc_exec_class"
#define TAG_GNUINIT "__objc_gnu_init"
+/* Flags for lookup_method_static(). */
+#define OBJC_LOOKUP_CLASS 1 /* Look for class methods. */
+#define OBJC_LOOKUP_NO_SUPER 2 /* Do not examine superclasses. */
+
/* The OCTI_... enumeration itself is in objc/objc-act.h. */
tree objc_global_trees[OCTI_MAX];
static GTY((param_is (struct string_descriptor))) htab_t string_htab;
-static hashval_t string_hash (const void *);
-static int string_eq (const void *, const void *);
-
FILE *gen_declaration_file;
/* Tells "encode_pointer/encode_aggregate" whether we are generating
#endif
return false;
+#ifndef USE_MAPPED_LOCATION
/* Force the line number back to 0; check_newline will have
raised it to 1, which will make the builtin functions appear
not to be built in. */
input_line = 0;
+#endif
/* If gen_declaration desired, open the output file. */
if (flag_gen_declaration)
#ifdef OBJCPLUS
/* We need to instantiate templates _before_ we emit ObjC metadata;
if we do not, some metadata (such as selectors) may go missing. */
+ at_eof = 1;
instantiate_pending_templates (0);
#endif
/* Finalize Objective-C runtime data. No need to generate tables
- and code if only checking syntax. */
- if (!flag_syntax_only)
+ and code if only checking syntax, or if generating a PCH file. */
+ if (!flag_syntax_only && !pch_file)
finish_objc ();
if (gen_declaration_file)
void
objc_finish_implementation (void)
{
+#ifdef OBJCPLUS
+ if (flag_objc_call_cxx_cdtors)
+ objc_generate_cxx_cdtors ();
+#endif
+
if (objc_implementation_context)
{
finish_class (objc_implementation_context);
objc_implementation_context = NULL_TREE;
}
else
- warning ("`@end' must appear in an @implementation context");
+ warning (0, "%<@end%> must appear in an @implementation context");
}
void
}
tree
-objc_build_method_signature (tree rettype, tree selector, tree optparms)
+objc_build_method_signature (tree rettype, tree selector,
+ tree optparms, bool ellipsis)
{
- return build_method_decl (objc_inherit_code, rettype, selector, optparms);
+ return build_method_decl (objc_inherit_code, rettype, selector,
+ optparms, ellipsis);
}
void
return OBJC_TYPE_NAME (type) == objc_class_id;
}
+
+int
+objc_types_compatible_p (tree type1, tree type2)
+{
+
+ if (objc_is_object_ptr (type1) || objc_is_object_ptr (type2)
+ || objc_is_class_name (type1) || objc_is_class_name (type2))
+ {
+ return lhd_types_compatible_p (type1, type2);
+ }
+ else
+ {
+#ifdef OBJCPLUS
+ return cxx_types_compatible_p (type1, type2);
+#else
+ return c_types_compatible_p (type1, type2);
+#endif
+ }
+}
+
+
/* 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
&& TREE_CODE (rhs) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (rhs)) == RECORD_TYPE)
{
- int lhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (lhs);
- int rhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (rhs);
+ int lhs_is_proto = IS_PROTOCOL_QUALIFIED_UNTYPED (lhs);
+ int rhs_is_proto = IS_PROTOCOL_QUALIFIED_UNTYPED (rhs);
if (lhs_is_proto)
{
- tree lproto, lproto_list = TYPE_PROTOCOL_LIST (lhs);
+ tree lproto, lproto_list = TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (lhs));
tree rproto, rproto_list;
tree p;
/* <Protocol> = <Protocol> */
if (rhs_is_proto)
{
- rproto_list = TYPE_PROTOCOL_LIST (rhs);
+ /* Class <Protocol> != id <Protocol>;
+ id <Protocol> != Class <Protocol> */
+ if (IS_ID (lhs) != IS_ID (rhs))
+ return 0;
+
+ rproto_list = TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (rhs));
if (!reflexive)
{
if (!rproto)
warning
- ("object does not conform to the `%s' protocol",
+ (0, "object does not conform to the %qs protocol",
IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
}
return 1;
tree rname = OBJC_TYPE_NAME (TREE_TYPE (rhs));
tree rinter;
+ /* Class <Protocol> != <class> * */
+ if (IS_CLASS (lhs))
+ return 0;
+
/* Make sure the protocol is supported by the object on
the rhs. */
for (lproto = lproto_list; lproto; lproto = TREE_CHAIN (lproto))
the protocol we're looking for, check for "one-off"
protocols (e.g., `NSObject<MyProt> *foo;') attached
to the rhs. */
- if (!rproto)
+ if (!rproto && TYPE_HAS_OBJC_INFO (TREE_TYPE (rhs)))
{
- rproto_list = TYPE_PROTOCOL_LIST (TREE_TYPE (rhs));
+ rproto_list = TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (rhs));
rproto = lookup_protocol_in_reflist (rproto_list, p);
}
}
if (!rproto)
- warning ("class `%s' does not implement the `%s' protocol",
+ warning (0, "class %qs does not implement the %qs protocol",
IDENTIFIER_POINTER (OBJC_TYPE_NAME (TREE_TYPE (rhs))),
IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
}
return 1;
}
- /* <Protocol> = id */
+ /* id <Protocol> = id; Class <Protocol> = id */
else if (objc_is_object_id (TREE_TYPE (rhs)))
{
return 1;
}
- /* <Protocol> = Class */
+ /* id <Protocol> != Class; Class <Protocol> = Class */
else if (objc_is_class_id (TREE_TYPE (rhs)))
{
- return 0;
+ return IS_CLASS (lhs);
}
/* <Protocol> = ?? : let comptypes decide. */
return -1;
/* <class> * = <Protocol> */
if (TYPED_OBJECT (TREE_TYPE (lhs)))
{
+ /* <class> * != Class <Protocol> */
+ if (IS_CLASS (rhs))
+ return 0;
+
if (reflexive)
{
tree rname = OBJC_TYPE_NAME (TREE_TYPE (lhs));
tree rinter;
- tree rproto, rproto_list = TYPE_PROTOCOL_LIST (rhs);
+ tree rproto, rproto_list = TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (rhs));
/* Make sure the protocol is supported by the object on
the lhs. */
check for "one-off" protocols (e.g.,
`NSObject<MyProt> *foo;') attached to the
lhs. */
- if (!lproto)
+ if (!lproto && TYPE_HAS_OBJC_INFO (TREE_TYPE (lhs)))
{
- lproto_list = TYPE_PROTOCOL_LIST
+ lproto_list = TYPE_OBJC_PROTOCOL_LIST
(TREE_TYPE (lhs));
lproto = lookup_protocol_in_reflist
(lproto_list, p);
}
if (!lproto)
- warning ("class `%s' does not implement the `%s' protocol",
+ warning (0, "class %qs does not implement the %qs protocol",
IDENTIFIER_POINTER (OBJC_TYPE_NAME
(TREE_TYPE (lhs))),
IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
else
return 0;
}
- /* id = <Protocol> */
+ /* id = id <Protocol>; id = Class <Protocol> */
else if (objc_is_object_id (TREE_TYPE (lhs)))
{
return 1;
}
- /* Class = <Protocol> */
+ /* Class != id <Protocol>; Class = Class <Protocol> */
else if (objc_is_class_id (TREE_TYPE (lhs)))
{
- return 0;
+ return IS_CLASS (rhs);
}
/* ??? = <Protocol> : let comptypes decide */
else
if (TREE_CODE (type) != RECORD_TYPE)
return;
if (OBJC_TYPE_NAME (type) && (type = objc_is_class_name (OBJC_TYPE_NAME (type))))
- error ("statically allocated instance of Objective-C class `%s'",
+ error ("statically allocated instance of Objective-C class %qs",
IDENTIFIER_POINTER (type));
}
tree
objc_get_protocol_qualified_type (tree interface, tree protocols)
{
- tree type;
+ /* If INTERFACE is not provided, default to 'id'. */
+ tree type = (interface ? objc_is_id (interface) : objc_object_type);
+ bool is_ptr = (type != NULL_TREE);
- if (!interface)
- type = objc_object_type;
- else if (!(type = objc_is_id (interface)))
+ if (!is_ptr)
{
type = objc_is_class_name (interface);
if (protocols)
{
type = build_variant_type_copy (type);
- /* Look up protocols and install in lang specific list. Note
- that the protocol list can have a different lifetime than T! */
- SET_TYPE_PROTOCOL_LIST (type, lookup_and_install_protocols (protocols));
- /* Establish the ObjC-ness of this record. */
- if (TREE_CODE (type) == RECORD_TYPE)
- TREE_STATIC_TEMPLATE (type) = 1;
+ /* For pointers (i.e., 'id' or 'Class'), attach the protocol(s)
+ to the pointee. */
+ if (is_ptr)
+ {
+ TREE_TYPE (type) = build_variant_type_copy (TREE_TYPE (type));
+ TYPE_POINTER_TO (TREE_TYPE (type)) = type;
+ type = TREE_TYPE (type);
+ }
+
+ /* Look up protocols and install in lang specific list. */
+ DUP_TYPE_OBJC_INFO (type, TYPE_MAIN_VARIANT (type));
+ TYPE_OBJC_PROTOCOL_LIST (type) = lookup_and_install_protocols (protocols);
+
+ /* For RECORD_TYPEs, point to the @interface; for 'id' and 'Class',
+ return the pointer to the new pointee variant. */
+ if (is_ptr)
+ type = TYPE_POINTER_TO (type);
+ else
+ TYPE_OBJC_INTERFACE (type)
+ = TYPE_OBJC_INTERFACE (TYPE_MAIN_VARIANT (type));
}
return type;
pp = lookup_protocol (pp);
if (pp == proto)
- fatal_error ("protocol `%s' has circular dependency",
+ fatal_error ("protocol %qs has circular dependency",
IDENTIFIER_POINTER (PROTOCOL_NAME (pp)));
if (pp)
check_protocol_recursively (proto, PROTOCOL_LIST (pp));
tree p = lookup_protocol (ident);
if (!p)
- error ("cannot find protocol declaration for `%s'",
+ error ("cannot find protocol declaration for %qs",
IDENTIFIER_POINTER (ident));
else
return_value = chainon (return_value,
TREE_USED (var) = 1;
}
-/* Find the decl for the constant string class refernce. This is only
+/* Find the decl for the constant string class reference. This is only
used for the NeXT runtime. */
static tree
objc_super_type = build_pointer_type (xref_tag (RECORD_TYPE,
get_identifier (TAG_SUPER)));
+ /* Declare pointers to method and ivar lists. */
+ objc_method_list_ptr = build_pointer_type
+ (xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_METHOD_LIST)));
+ objc_method_proto_list_ptr
+ = build_pointer_type (xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_METHOD_PROTOTYPE_LIST)));
+ objc_ivar_list_ptr = build_pointer_type
+ (xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_IVAR_LIST)));
+
if (flag_next_runtime)
{
/* NB: In order to call one of the ..._stret (struct-returning)
type, 0, NOT_BUILT_IN,
NULL, NULL_TREE);
+ /* id objc_msgSend_Fast (id, SEL, ...)
+ __attribute__ ((hard_coded_address (OFFS_MSGSEND_FAST))); */
+#ifdef OFFS_MSGSEND_FAST
+ umsg_fast_decl = builtin_function (TAG_MSGSEND_FAST,
+ type, 0, NOT_BUILT_IN,
+ NULL, NULL_TREE);
+ DECL_ATTRIBUTES (umsg_fast_decl)
+ = tree_cons (get_identifier ("hard_coded_address"),
+ build_int_cst (NULL_TREE, OFFS_MSGSEND_FAST),
+ NULL_TREE);
+#else
+ /* No direct dispatch availible. */
+ umsg_fast_decl = umsg_decl;
+#endif
+
/* id objc_msgSendSuper (struct objc_super *, SEL, ...); */
/* id objc_msgSendSuper_stret (struct objc_super *, SEL, ...); */
type
if (!constant_string_class
|| !(constant_string_type
= CLASS_STATIC_TEMPLATE (constant_string_class)))
- error ("cannot find interface declaration for `%s'",
+ error ("cannot find interface declaration for %qs",
IDENTIFIER_POINTER (constant_string_id));
/* The NSConstantString/NXConstantString ivar layout is now known. */
else if (!check_string_class_template ())
- error ("interface `%s' does not have valid constant string layout",
+ error ("interface %qs does not have valid constant string layout",
IDENTIFIER_POINTER (constant_string_id));
/* For the NeXT runtime, we can generate a literal reference
to the string class, don't need to run a constructor. */
else if (flag_next_runtime && !setup_string_decl ())
- error ("cannot find reference tag for class `%s'",
+ error ("cannot find reference tag for class %qs",
IDENTIFIER_POINTER (constant_string_id));
else
{
if (!desc)
{
+ tree var;
*loc = desc = ggc_alloc (sizeof (*desc));
desc->literal = string;
if (!flag_next_runtime)
constructor
= objc_add_static_instance (constructor, constant_string_type);
-
+ else
+ {
+ var = build_decl (CONST_DECL, NULL, TREE_TYPE (constructor));
+ DECL_INITIAL (var) = constructor;
+ TREE_STATIC (var) = 1;
+ pushdecl_top_level (var);
+ constructor = var;
+ }
desc->constructor = constructor;
}
addr = build_unary_op (ADDR_EXPR, desc->constructor, 1);
- TREE_CONSTANT (addr) = true;
- TREE_INVARIANT (addr) = true;
- TREE_STATIC (addr) = true;
return addr;
}
/* sel_ref_cnt = { ..., 5, ... } */
- initlist = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, 0));
+ initlist = build_tree_list (NULL_TREE,
+ build_int_cst (long_integer_type_node, 0));
/* refs = { ..., _OBJC_SELECTOR_TABLE, ... } */
/* version = { 1, ... } */
- expr = build_int_cst (NULL_TREE, OBJC_VERSION);
+ expr = build_int_cst (long_integer_type_node, OBJC_VERSION);
initlist = build_tree_list (NULL_TREE, expr);
/* size = { ..., sizeof (struct _objc_module), ... } */
- expr = size_in_bytes (objc_module_template);
+ expr = convert (long_integer_type_node,
+ size_in_bytes (objc_module_template));
initlist = tree_cons (NULL_TREE, expr, initlist);
/* name = { ..., "foo.m", ... } */
}
}
if (!found)
- {
- /* Adjust line number for warning message. */
- int save_lineno = input_line;
- if (flag_next_runtime && TREE_PURPOSE (chain))
- input_line = DECL_SOURCE_LINE (TREE_PURPOSE (chain));
- warning ("creating selector for non existant method %s",
- IDENTIFIER_POINTER (TREE_VALUE (chain)));
- input_line = save_lineno;
- }
+ {
+ location_t *loc;
+ if (flag_next_runtime && TREE_PURPOSE (chain))
+ loc = &DECL_SOURCE_LOCATION (TREE_PURPOSE (chain));
+ else
+ loc = &input_location;
+ warning (0, "%Hcreating selector for nonexistent method %qE",
+ loc, TREE_VALUE (chain));
+ }
}
expr = build_selector (TREE_VALUE (chain));
objc_get_class_reference (tree ident)
{
tree orig_ident;
+ bool local_scope = false;
#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);
+ {
+ /* The type must exist in the global namespace. */
+ if (DECL_CONTEXT (ident) && DECL_CONTEXT (ident) != global_namespace)
+ local_scope = true;
+
+ ident = DECL_NAME (ident);
+ }
#endif
orig_ident = ident;
- if (!(ident = objc_is_class_name (ident)))
+ if (local_scope || !(ident = objc_is_class_name (ident)))
{
- error ("`%s' is not an Objective-C class name or alias",
+ error ("%qs is not an Objective-C class name or alias",
IDENTIFIER_POINTER (orig_ident));
return error_mark_node;
}
#endif /* OBJCPLUS */
if (!(underlying_class = objc_is_class_name (class_ident)))
- warning ("cannot find class `%s'", IDENTIFIER_POINTER (class_ident));
+ warning (0, "cannot find class %qs", IDENTIFIER_POINTER (class_ident));
else if (objc_is_class_name (alias_ident))
- warning ("class `%s' already exists", IDENTIFIER_POINTER (alias_ident));
+ warning (0, "class %qs already exists", IDENTIFIER_POINTER (alias_ident));
else
alias_chain = tree_cons (underlying_class, alias_ident, alias_chain);
}
if (! objc_is_class_name (ident))
{
- tree record = lookup_name (ident);
-
- if (record && ! TREE_STATIC_TEMPLATE (record))
+ tree record = lookup_name (ident), type = record;
+
+ if (record)
{
- error ("`%s' redeclared as different kind of symbol",
- IDENTIFIER_POINTER (ident));
- error ("%Jprevious declaration of '%D'",
- record, record);
+ if (TREE_CODE (record) == TYPE_DECL)
+ type = DECL_ORIGINAL_TYPE (record);
+
+ if (!TYPE_HAS_OBJC_INFO (type)
+ || !TYPE_OBJC_INTERFACE (type))
+ {
+ error ("%qs redeclared as different kind of symbol",
+ IDENTIFIER_POINTER (ident));
+ error ("%Jprevious declaration of '%D'",
+ record, record);
+ }
}
record = xref_tag (RECORD_TYPE, ident);
- TREE_STATIC_TEMPLATE (record) = 1;
+ INIT_TYPE_OBJC_INFO (record);
+ TYPE_OBJC_INTERFACE (record) = ident;
class_chain = tree_cons (NULL_TREE, ident, class_chain);
}
}
/* NB: This function may be called before the ObjC front-end has
been initialized, in which case OBJC_OBJECT_TYPE will (still) be NULL. */
- return (objc_object_type && type && (IS_ID (type) || IS_CLASS (type))
+ return (objc_object_type && type
+ && (IS_ID (type) || IS_CLASS (type) || IS_SUPER (type))
? type
: NULL_TREE);
}
return ret;
}
+static int
+objc_is_gcable_type (tree type, int or_strong_p)
+{
+ tree name;
+
+ if (!TYPE_P (type))
+ return 0;
+ if (objc_is_id (TYPE_MAIN_VARIANT (type)))
+ return 1;
+ if (or_strong_p && lookup_attribute ("objc_gc", TYPE_ATTRIBUTES (type)))
+ return 1;
+ if (TREE_CODE (type) != POINTER_TYPE && TREE_CODE (type) != INDIRECT_REF)
+ return 0;
+ type = TREE_TYPE (type);
+ if (TREE_CODE (type) != RECORD_TYPE)
+ return 0;
+ name = TYPE_NAME (type);
+ return (objc_is_class_name (name) != NULL_TREE);
+}
+
static tree
-lookup_interface (tree ident)
+objc_substitute_decl (tree expr, tree oldexpr, tree newexpr)
+{
+ if (expr == oldexpr)
+ return newexpr;
+
+ switch (TREE_CODE (expr))
+ {
+ case COMPONENT_REF:
+ return build_component_ref (objc_substitute_decl (TREE_OPERAND (expr, 0),
+ oldexpr,
+ newexpr),
+ DECL_NAME (TREE_OPERAND (expr, 1)));
+ case ARRAY_REF:
+ return build_array_ref (objc_substitute_decl (TREE_OPERAND (expr, 0),
+ oldexpr,
+ newexpr),
+ TREE_OPERAND (expr, 1));
+ case INDIRECT_REF:
+ return build_indirect_ref (objc_substitute_decl (TREE_OPERAND (expr, 0),
+ oldexpr,
+ newexpr), "->");
+ default:
+ return expr;
+ }
+}
+
+static tree
+objc_build_ivar_assignment (tree outervar, tree lhs, tree rhs)
{
- tree chain;
+ tree func_params;
+ /* The LHS parameter contains the expression 'outervar->memberspec';
+ we need to transform it into '&((typeof(outervar) *) 0)->memberspec',
+ where memberspec may be arbitrarily complex (e.g., 'g->f.d[2].g[3]').
+ */
+ tree offs
+ = objc_substitute_decl
+ (lhs, outervar, convert (TREE_TYPE (outervar), integer_zero_node));
+ tree func
+ = (flag_objc_direct_dispatch
+ ? objc_assign_ivar_fast_decl
+ : objc_assign_ivar_decl);
+
+ offs = convert (integer_type_node, build_unary_op (ADDR_EXPR, offs, 0));
+ offs = fold (offs);
+ func_params = tree_cons (NULL_TREE,
+ convert (objc_object_type, rhs),
+ tree_cons (NULL_TREE, convert (objc_object_type, outervar),
+ tree_cons (NULL_TREE, offs,
+ NULL_TREE)));
+
+ assemble_external (func);
+ return build_function_call (func, func_params);
+}
+
+static tree
+objc_build_global_assignment (tree lhs, tree rhs)
+{
+ tree func_params = tree_cons (NULL_TREE,
+ convert (objc_object_type, rhs),
+ tree_cons (NULL_TREE, convert (build_pointer_type (objc_object_type),
+ build_unary_op (ADDR_EXPR, lhs, 0)),
+ NULL_TREE));
+
+ assemble_external (objc_assign_global_decl);
+ return build_function_call (objc_assign_global_decl, func_params);
+}
+static tree
+objc_build_strong_cast_assignment (tree lhs, tree rhs)
+{
+ tree func_params = tree_cons (NULL_TREE,
+ convert (objc_object_type, rhs),
+ tree_cons (NULL_TREE, convert (build_pointer_type (objc_object_type),
+ build_unary_op (ADDR_EXPR, lhs, 0)),
+ NULL_TREE));
+
+ assemble_external (objc_assign_strong_cast_decl);
+ return build_function_call (objc_assign_strong_cast_decl, func_params);
+}
+
+static int
+objc_is_gcable_p (tree expr)
+{
+ return (TREE_CODE (expr) == COMPONENT_REF
+ ? objc_is_gcable_p (TREE_OPERAND (expr, 1))
+ : TREE_CODE (expr) == ARRAY_REF
+ ? (objc_is_gcable_p (TREE_TYPE (expr))
+ || objc_is_gcable_p (TREE_OPERAND (expr, 0)))
+ : TREE_CODE (expr) == ARRAY_TYPE
+ ? objc_is_gcable_p (TREE_TYPE (expr))
+ : TYPE_P (expr)
+ ? objc_is_gcable_type (expr, 1)
+ : (objc_is_gcable_p (TREE_TYPE (expr))
+ || (DECL_P (expr)
+ && lookup_attribute ("objc_gc", DECL_ATTRIBUTES (expr)))));
+}
+
+static int
+objc_is_ivar_reference_p (tree expr)
+{
+ return (TREE_CODE (expr) == ARRAY_REF
+ ? objc_is_ivar_reference_p (TREE_OPERAND (expr, 0))
+ : TREE_CODE (expr) == COMPONENT_REF
+ ? TREE_CODE (TREE_OPERAND (expr, 1)) == FIELD_DECL
+ : 0);
+}
+
+static int
+objc_is_global_reference_p (tree expr)
+{
+ return (TREE_CODE (expr) == INDIRECT_REF || TREE_CODE (expr) == PLUS_EXPR
+ ? objc_is_global_reference_p (TREE_OPERAND (expr, 0))
+ : DECL_P (expr)
+ ? (!DECL_CONTEXT (expr) || TREE_STATIC (expr))
+ : 0);
+}
+
+tree
+objc_generate_write_barrier (tree lhs, enum tree_code modifycode, tree rhs)
+{
+ tree result = NULL_TREE, outer;
+ int strong_cast_p = 0, outer_gc_p = 0, indirect_p = 0;
+
+ /* See if we have any lhs casts, and strip them out. NB: The lvalue casts
+ will have been transformed to the form '*(type *)&expr'. */
+ if (TREE_CODE (lhs) == INDIRECT_REF)
+ {
+ outer = TREE_OPERAND (lhs, 0);
+
+ while (!strong_cast_p
+ && (TREE_CODE (outer) == CONVERT_EXPR
+ || TREE_CODE (outer) == NOP_EXPR
+ || TREE_CODE (outer) == NON_LVALUE_EXPR))
+ {
+ tree lhstype = TREE_TYPE (outer);
+
+ /* Descend down the cast chain, and record the first objc_gc
+ attribute found. */
+ if (POINTER_TYPE_P (lhstype))
+ {
+ tree attr
+ = lookup_attribute ("objc_gc",
+ TYPE_ATTRIBUTES (TREE_TYPE (lhstype)));
+
+ if (attr)
+ strong_cast_p = 1;
+ }
+
+ outer = TREE_OPERAND (outer, 0);
+ }
+ }
+
+ /* If we have a __strong cast, it trumps all else. */
+ if (strong_cast_p)
+ {
+ if (modifycode != NOP_EXPR)
+ goto invalid_pointer_arithmetic;
+
+ if (warn_assign_intercept)
+ warning (0, "strong-cast assignment has been intercepted");
+
+ result = objc_build_strong_cast_assignment (lhs, rhs);
+
+ goto exit_point;
+ }
+
+ /* the lhs must be of a suitable type, regardless of its underlying
+ structure. */
+ if (!objc_is_gcable_p (lhs))
+ goto exit_point;
+
+ outer = lhs;
+
+ while (outer
+ && (TREE_CODE (outer) == COMPONENT_REF
+ || TREE_CODE (outer) == ARRAY_REF))
+ outer = TREE_OPERAND (outer, 0);
+
+ if (TREE_CODE (outer) == INDIRECT_REF)
+ {
+ outer = TREE_OPERAND (outer, 0);
+ indirect_p = 1;
+ }
+
+ outer_gc_p = objc_is_gcable_p (outer);
+
+ /* Handle ivar assignments. */
+ if (objc_is_ivar_reference_p (lhs))
+ {
+ /* if the struct to the left of the ivar is not an Objective-C object (__strong
+ doesn't cut it here), the best we can do here is suggest a cast. */
+ if (!objc_is_gcable_type (TREE_TYPE (outer), 0))
+ {
+ /* We may still be able to use the global write barrier... */
+ if (!indirect_p && objc_is_global_reference_p (outer))
+ goto global_reference;
+
+ suggest_cast:
+ if (modifycode == NOP_EXPR)
+ {
+ if (warn_assign_intercept)
+ warning (0, "strong-cast may possibly be needed");
+ }
+
+ goto exit_point;
+ }
+
+ if (modifycode != NOP_EXPR)
+ goto invalid_pointer_arithmetic;
+
+ if (warn_assign_intercept)
+ warning (0, "instance variable assignment has been intercepted");
+
+ result = objc_build_ivar_assignment (outer, lhs, rhs);
+
+ goto exit_point;
+ }
+
+ /* Likewise, intercept assignment to global/static variables if their type is
+ GC-marked. */
+ if (objc_is_global_reference_p (outer))
+ {
+ if (indirect_p)
+ goto suggest_cast;
+
+ global_reference:
+ if (modifycode != NOP_EXPR)
+ {
+ invalid_pointer_arithmetic:
+ if (outer_gc_p)
+ warning (0, "pointer arithmetic for garbage-collected objects not allowed");
+
+ goto exit_point;
+ }
+
+ if (warn_assign_intercept)
+ warning (0, "global/static variable assignment has been intercepted");
+
+ result = objc_build_global_assignment (lhs, rhs);
+ }
+
+ /* In all other cases, fall back to the normal mechanism. */
+ exit_point:
+ return result;
+}
+
+struct interface_tuple GTY(())
+{
+ tree id;
+ tree class_name;
+};
+
+static GTY ((param_is (struct interface_tuple))) htab_t interface_htab;
+
+static hashval_t
+hash_interface (const void *p)
+{
+ const struct interface_tuple *d = p;
+ return htab_hash_pointer (d->id);
+}
+
+static int
+eq_interface (const void *p1, const void *p2)
+{
+ const struct interface_tuple *d = p1;
+ return d->id == p2;
+}
+
+static tree
+lookup_interface (tree ident)
+{
#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 NULL_TREE;
+
+ if (ident == NULL_TREE || TREE_CODE (ident) != IDENTIFIER_NODE)
+ return NULL_TREE;
+
+ {
+ struct interface_tuple **slot;
+ tree i = NULL_TREE;
+
+ if (interface_htab)
+ {
+ slot = (struct interface_tuple **)
+ htab_find_slot_with_hash (interface_htab, ident,
+ htab_hash_pointer (ident),
+ NO_INSERT);
+ if (slot && *slot)
+ i = (*slot)->class_name;
+ }
+ return i;
+ }
}
/* Implement @defs (<classname>) within struct bodies. */
if (interface)
return get_class_ivars (interface);
- error ("cannot find interface declaration for `%s'",
+ error ("cannot find interface declaration for %qs",
IDENTIFIER_POINTER (class_name));
return error_mark_node;
/* On Darwin, ObjC exceptions require a sufficiently recent
version of the runtime, so the user must ask for them explicitly. */
if (!flag_objc_exceptions)
- warning ("use %<-fobjc-exceptions%> to enable Objective-C "
+ warning (0, "use %<-fobjc-exceptions%> to enable Objective-C "
"exception syntax");
}
#ifndef OBJCPLUS
t = build_component_ref (cur_try_context->stack_decl,
get_identifier ("buf"));
t = build_fold_addr_expr (t);
+#ifdef OBJCPLUS
+ /* Convert _setjmp argument to type that is expected. */
+ if (TYPE_ARG_TYPES (TREE_TYPE (objc_setjmp_decl)))
+ t = convert (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (objc_setjmp_decl))), t);
+ else
+ t = convert (ptr_type_node, t);
+#else
t = convert (ptr_type_node, t);
+#endif
t = tree_cons (NULL, t, NULL);
sj = build_function_call (objc_setjmp_decl, t);
cond = build (COMPOUND_EXPR, TREE_TYPE (sj), enter, sj);
- cond = lang_hooks.truthvalue_conversion (cond);
+ cond = c_common_truthvalue_conversion (cond);
return build (COND_EXPR, void_type_node, cond, NULL, NULL);
}
t = objc_get_class_reference (OBJC_TYPE_NAME (TREE_TYPE (type)));
args = tree_cons (NULL, t, args);
t = build_function_call (objc_exception_match_decl, args);
- cond = lang_hooks.truthvalue_conversion (t);
+ cond = c_common_truthvalue_conversion (t);
}
t = build (COND_EXPR, void_type_node, cond, body, NULL);
SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
{
t = build (MODIFY_EXPR, void_type_node, cur_try_context->rethrow_decl,
cur_try_context->caught_decl);
- annotate_with_locus (t, cur_try_context->end_catch_locus);
+ SET_EXPR_LOCATION (t, cur_try_context->end_catch_locus);
append_to_statement_list (t, last);
t = next_sjlj_build_try_exit ();
- annotate_with_locus (t, cur_try_context->end_catch_locus);
+ SET_EXPR_LOCATION (t, cur_try_context->end_catch_locus);
append_to_statement_list (t, last);
}
TREE_THIS_VOLATILE (rethrow_decl) = 1;
TREE_CHAIN (rethrow_decl) = stack_decl;
- /* Build the outermost varible binding level. */
+ /* Build the outermost variable binding level. */
bind = build (BIND_EXPR, void_type_node, rethrow_decl, NULL, NULL);
- annotate_with_locus (bind, cur_try_context->try_locus);
+ SET_EXPR_LOCATION (bind, cur_try_context->try_locus);
TREE_SIDE_EFFECTS (bind) = 1;
/* Initialize rethrow_decl. */
t = build (MODIFY_EXPR, void_type_node, rethrow_decl,
convert (objc_object_type, null_pointer_node));
- annotate_with_locus (t, cur_try_context->try_locus);
+ SET_EXPR_LOCATION (t, cur_try_context->try_locus);
append_to_statement_list (t, &BIND_EXPR_BODY (bind));
/* Build the outermost TRY_FINALLY_EXPR. */
try_fin = build (TRY_FINALLY_EXPR, void_type_node, NULL, NULL);
- annotate_with_locus (try_fin, cur_try_context->try_locus);
+ SET_EXPR_LOCATION (try_fin, cur_try_context->try_locus);
TREE_SIDE_EFFECTS (try_fin) = 1;
append_to_statement_list (try_fin, &BIND_EXPR_BODY (bind));
}
else
catch_seq = next_sjlj_build_exc_extract (rethrow_decl);
- annotate_with_locus (catch_seq, cur_try_context->end_try_locus);
+ SET_EXPR_LOCATION (catch_seq, cur_try_context->end_try_locus);
/* Build the main register-and-try if statement. */
t = next_sjlj_build_enter_and_setjmp ();
- annotate_with_locus (t, cur_try_context->try_locus);
+ SET_EXPR_LOCATION (t, cur_try_context->try_locus);
COND_EXPR_THEN (t) = catch_seq;
COND_EXPR_ELSE (t) = cur_try_context->try_body;
TREE_OPERAND (try_fin, 0) = t;
/* Build the complete FINALLY statement list. */
t = next_sjlj_build_try_exit ();
t = build_stmt (COND_EXPR,
- lang_hooks.truthvalue_conversion (rethrow_decl),
+ c_common_truthvalue_conversion (rethrow_decl),
NULL, t);
- annotate_with_locus (t, cur_try_context->finally_locus);
+ SET_EXPR_LOCATION (t, cur_try_context->finally_locus);
append_to_statement_list (t, &TREE_OPERAND (try_fin, 1));
append_to_statement_list (cur_try_context->finally_body,
t = tree_cons (NULL, rethrow_decl, NULL);
t = build_function_call (objc_exception_throw_decl, t);
t = build_stmt (COND_EXPR,
- lang_hooks.truthvalue_conversion (rethrow_decl),
+ c_common_truthvalue_conversion (rethrow_decl),
t, NULL);
- annotate_with_locus (t, cur_try_context->end_finally_locus);
+ SET_EXPR_LOCATION (t, cur_try_context->end_finally_locus);
append_to_statement_list (t, &TREE_OPERAND (try_fin, 1));
return bind;
cur_try_context = c;
objc_init_exceptions ();
+
+ if (flag_objc_sjlj_exceptions)
+ objc_mark_locals_volatile (NULL);
}
/* Called just after parsing "@catch (parm)". Open a binding level,
continue;
if (!t || objc_comptypes (TREE_TYPE (t), TREE_TYPE (type), 0) == 1)
{
- warning ("exception of type %<%T%> will be caught",
+ warning (0, "exception of type %<%T%> will be caught",
TREE_TYPE (type));
- warning ("%H by earlier handler for %<%T%>",
+ warning (0, "%H by earlier handler for %<%T%>",
EXPR_LOCUS (stmt), TREE_TYPE (t ? t : objc_object_type));
break;
}
/* Called to finalize a @try construct. */
-void
+tree
objc_finish_try_stmt (void)
{
struct objc_try_context *c = cur_try_context;
tree stmt;
if (c->catch_list == NULL && c->finally_body == NULL)
- error ("`@try' without `@catch' or `@finally'");
+ error ("%<@try%> without %<@catch%> or %<@finally%>");
/* If we're doing Darwin setjmp exceptions, build the big nasty. */
if (flag_objc_sjlj_exceptions)
if (c->catch_list)
{
stmt = build_stmt (TRY_CATCH_EXPR, stmt, c->catch_list);
- annotate_with_locus (stmt, cur_try_context->try_locus);
+ SET_EXPR_LOCATION (stmt, cur_try_context->try_locus);
}
if (c->finally_body)
{
stmt = build_stmt (TRY_FINALLY_EXPR, stmt, c->finally_body);
- annotate_with_locus (stmt, cur_try_context->try_locus);
+ SET_EXPR_LOCATION (stmt, cur_try_context->try_locus);
}
}
add_stmt (stmt);
cur_try_context = c->outer;
free (c);
+ return stmt;
}
tree
return add_stmt (build_function_call (objc_exception_throw_decl, args));
}
-void
+tree
objc_build_synchronized (location_t start_locus, tree mutex, tree body)
{
tree args, call;
mutex = save_expr (mutex);
args = tree_cons (NULL, mutex, NULL);
call = build_function_call (objc_sync_enter_decl, args);
- annotate_with_locus (call, start_locus);
+ SET_EXPR_LOCATION (call, start_locus);
add_stmt (call);
/* Build the mutex unlock. */
args = tree_cons (NULL, mutex, NULL);
call = build_function_call (objc_sync_exit_decl, args);
- annotate_with_locus (call, input_location);
+ SET_EXPR_LOCATION (call, input_location);
/* Put the that and the body in a TRY_FINALLY. */
objc_begin_try_stmt (start_locus, body);
objc_build_finally_clause (input_location, call);
- objc_finish_try_stmt ();
+ return objc_finish_try_stmt ();
}
\f
OBJC_VOID_AT_END)));
objc_exception_match_decl
= builtin_function (TAG_EXCEPTIONMATCH, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE);
+
+ /* id objc_assign_ivar (id, id, unsigned int); */
+ /* id objc_assign_ivar_Fast (id, id, unsigned int)
+ __attribute__ ((hard_coded_address (OFFS_ASSIGNIVAR_FAST))); */
+ temp_type
+ = build_function_type (objc_object_type,
+ tree_cons
+ (NULL_TREE, objc_object_type,
+ tree_cons (NULL_TREE, objc_object_type,
+ tree_cons (NULL_TREE,
+ unsigned_type_node,
+ OBJC_VOID_AT_END))));
+ objc_assign_ivar_decl
+ = builtin_function (TAG_ASSIGNIVAR, temp_type, 0, NOT_BUILT_IN,
+ NULL, NULL_TREE);
+#ifdef OFFS_ASSIGNIVAR_FAST
+ objc_assign_ivar_fast_decl
+ = builtin_function (TAG_ASSIGNIVAR_FAST, temp_type, 0,
+ NOT_BUILT_IN, NULL, NULL_TREE);
+ DECL_ATTRIBUTES (objc_assign_ivar_fast_decl)
+ = tree_cons (get_identifier ("hard_coded_address"),
+ build_int_cst (NULL_TREE, OFFS_ASSIGNIVAR_FAST),
+ NULL_TREE);
+#else
+ /* Default to slower ivar method. */
+ objc_assign_ivar_fast_decl = objc_assign_ivar_decl;
+#endif
+
+ /* id objc_assign_global (id, id *); */
+ /* id objc_assign_strongCast (id, id *); */
+ temp_type = build_function_type (objc_object_type,
+ tree_cons (NULL_TREE, objc_object_type,
+ tree_cons (NULL_TREE, build_pointer_type (objc_object_type),
+ OBJC_VOID_AT_END)));
+ objc_assign_global_decl
+ = builtin_function (TAG_ASSIGNGLOBAL, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE);
+ objc_assign_strong_cast_decl
+ = builtin_function (TAG_ASSIGNSTRONGCAST, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE);
}
static void
NULL, nothrow_list);
}
+/* Construct a C struct corresponding to ObjC class CLASS, with the same
+ name as the class:
-/* struct <classname> {
+ struct <classname> {
struct _objc_class *isa;
...
}; */
-static tree
+static void
build_private_template (tree class)
{
- tree ivar_context;
-
- if (CLASS_STATIC_TEMPLATE (class))
+ if (!CLASS_STATIC_TEMPLATE (class))
{
- uprivate_record = CLASS_STATIC_TEMPLATE (class);
- ivar_context = TYPE_FIELDS (CLASS_STATIC_TEMPLATE (class));
- }
- else
- {
- uprivate_record = start_struct (RECORD_TYPE, CLASS_NAME (class));
- ivar_context = get_class_ivars (class);
-
- finish_struct (uprivate_record, ivar_context, NULL_TREE);
-
- CLASS_STATIC_TEMPLATE (class) = uprivate_record;
+ tree record = start_struct (RECORD_TYPE, CLASS_NAME (class));
+ finish_struct (record, get_class_ivars (class), NULL_TREE);
/* mark this record as class template - for class type checking */
- TREE_STATIC_TEMPLATE (uprivate_record) = 1;
- }
-
- objc_instance_type = build_pointer_type (uprivate_record);
+ INIT_TYPE_OBJC_INFO (record);
+ TYPE_OBJC_INTERFACE (record) = class;
+ CLASS_STATIC_TEMPLATE (class) = record;
- return ivar_context;
+ /* Set the TREE_USED bit for this struct, so that stab generator
+ can emit stabs for this struct type. */
+ if (flag_debug_only_used_symbols && TYPE_STUB_DECL (record))
+ TREE_USED (TYPE_STUB_DECL (record)) = 1;
+ }
}
\f
/* Begin code generation for protocols... */
"protocol_list");
chainon (field_decl_chain, field_decl);
- /* struct objc_method_list *instance_methods; */
- field_decl = create_field_decl (build_pointer_type
- (xref_tag (RECORD_TYPE,
- get_identifier
- (UTAG_METHOD_PROTOTYPE_LIST))),
+ /* struct _objc__method_prototype_list *instance_methods; */
+ field_decl = create_field_decl (objc_method_proto_list_ptr,
"instance_methods");
chainon (field_decl_chain, field_decl);
- /* struct objc_method_list *class_methods; */
- field_decl = create_field_decl (build_pointer_type
- (xref_tag (RECORD_TYPE,
- get_identifier
- (UTAG_METHOD_PROTOTYPE_LIST))),
+ /* struct _objc__method_prototype_list *class_methods; */
+ field_decl = create_field_decl (objc_method_proto_list_ptr,
"class_methods");
chainon (field_decl_chain, field_decl);
type = TREE_VALUE (TREE_TYPE (type));
if (TREE_CODE (type) == TYPE_DECL)
type = TREE_TYPE (type);
- return TYPE_MAIN_VARIANT (type);
+ return type;
}
static int
generate_method_descriptors (tree protocol)
{
tree initlist, chain, method_list_template;
- tree variable_length_type
- = xref_tag (RECORD_TYPE,
- get_identifier (UTAG_METHOD_PROTOTYPE_LIST));
int size;
if (!objc_method_prototype_template)
= generate_descriptor_table (method_list_template,
"_OBJC_PROTOCOL_CLASS_METHODS",
size, initlist, protocol);
- TREE_TYPE (UOBJC_CLASS_METHODS_decl) = variable_length_type;
}
else
UOBJC_CLASS_METHODS_decl = 0;
= generate_descriptor_table (method_list_template,
"_OBJC_PROTOCOL_INSTANCE_METHODS",
size, initlist, protocol);
- TREE_TYPE (UOBJC_INSTANCE_METHODS_decl) = variable_length_type;
}
else
UOBJC_INSTANCE_METHODS_decl = 0;
}
}
+/* Generate either '- .cxx_construct' or '- .cxx_destruct' for the
+ current class. */
+#ifdef OBJCPLUS
+static void
+objc_generate_cxx_ctor_or_dtor (bool dtor)
+{
+ tree fn, body, compound_stmt, ivar;
+
+ /* - (id) .cxx_construct { ... return self; } */
+ /* - (void) .cxx_construct { ... } */
+
+ objc_set_method_type (MINUS_EXPR);
+ objc_start_method_definition
+ (objc_build_method_signature (build_tree_list (NULL_TREE,
+ dtor
+ ? void_type_node
+ : objc_object_type),
+ get_identifier (dtor
+ ? TAG_CXX_DESTRUCT
+ : TAG_CXX_CONSTRUCT),
+ make_node (TREE_LIST),
+ false));
+ body = begin_function_body ();
+ compound_stmt = begin_compound_stmt (0);
+
+ ivar = CLASS_IVARS (implementation_template);
+ /* Destroy ivars in reverse order. */
+ if (dtor)
+ ivar = nreverse (copy_list (ivar));
+
+ for (; ivar; ivar = TREE_CHAIN (ivar))
+ {
+ if (TREE_CODE (ivar) == FIELD_DECL)
+ {
+ tree type = TREE_TYPE (ivar);
+
+ /* Call the ivar's default constructor or destructor. Do not
+ call the destructor unless a corresponding constructor call
+ has also been made (or is not needed). */
+ if (IS_AGGR_TYPE (type)
+ && (dtor
+ ? (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
+ && (!TYPE_NEEDS_CONSTRUCTING (type)
+ || TYPE_HAS_DEFAULT_CONSTRUCTOR (type)))
+ : (TYPE_NEEDS_CONSTRUCTING (type)
+ && TYPE_HAS_DEFAULT_CONSTRUCTOR (type))))
+ finish_expr_stmt
+ (build_special_member_call
+ (build_ivar_reference (DECL_NAME (ivar)),
+ dtor ? complete_dtor_identifier : complete_ctor_identifier,
+ NULL_TREE, type, LOOKUP_NORMAL));
+ }
+ }
+
+ /* The constructor returns 'self'. */
+ if (!dtor)
+ finish_return_stmt (self_decl);
+
+ finish_compound_stmt (compound_stmt);
+ finish_function_body (body);
+ fn = current_function_decl;
+ finish_function ();
+ objc_finish_method_definition (fn);
+}
+
+/* The following routine will examine the current @interface for any
+ non-POD C++ ivars requiring non-trivial construction and/or
+ destruction, and then synthesize special '- .cxx_construct' and/or
+ '- .cxx_destruct' methods which will run the appropriate
+ construction or destruction code. Note that ivars inherited from
+ super-classes are _not_ considered. */
+static void
+objc_generate_cxx_cdtors (void)
+{
+ bool need_ctor = false, need_dtor = false;
+ tree ivar;
+
+ /* We do not want to do this for categories, since they do not have
+ their own ivars. */
+
+ if (TREE_CODE (objc_implementation_context) != CLASS_IMPLEMENTATION_TYPE)
+ return;
+
+ /* First, determine if we even need a constructor and/or destructor. */
+
+ for (ivar = CLASS_IVARS (implementation_template); ivar;
+ ivar = TREE_CHAIN (ivar))
+ {
+ if (TREE_CODE (ivar) == FIELD_DECL)
+ {
+ tree type = TREE_TYPE (ivar);
+
+ if (IS_AGGR_TYPE (type))
+ {
+ if (TYPE_NEEDS_CONSTRUCTING (type)
+ && TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
+ /* NB: If a default constructor is not available, we will not
+ be able to initialize this ivar; the add_instance_variable()
+ routine will already have warned about this. */
+ need_ctor = true;
+
+ if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
+ && (!TYPE_NEEDS_CONSTRUCTING (type)
+ || TYPE_HAS_DEFAULT_CONSTRUCTOR (type)))
+ /* NB: If a default constructor is not available, we will not
+ call the destructor either, for symmetry. */
+ need_dtor = true;
+ }
+ }
+ }
+
+ /* Generate '- .cxx_construct' if needed. */
+
+ if (need_ctor)
+ objc_generate_cxx_ctor_or_dtor (false);
+
+ /* Generate '- .cxx_destruct' if needed. */
+
+ if (need_dtor)
+ objc_generate_cxx_ctor_or_dtor (true);
+
+ /* The 'imp_list' variable points at an imp_entry record for the current
+ @implementation. Record the existence of '- .cxx_construct' and/or
+ '- .cxx_destruct' methods therein; it will be included in the
+ metadata for the class. */
+ if (flag_next_runtime)
+ imp_list->has_cxx_cdtors = (need_ctor || need_dtor);
+}
+#endif
+
/* 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
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.
+ and end up being fixed up multiple times at runtime initialization.
But that doesn't hurt, it's just a little inefficient. */
static void
initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
else
{
- expr = build_unary_op (ADDR_EXPR, instance_methods, 0);
+ expr = convert (objc_method_proto_list_ptr,
+ build_unary_op (ADDR_EXPR, instance_methods, 0));
initlist = tree_cons (NULL_TREE, expr, initlist);
}
initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
else
{
- expr = build_unary_op (ADDR_EXPR, class_methods, 0);
+ expr = convert (objc_method_proto_list_ptr,
+ build_unary_op (ADDR_EXPR, class_methods, 0));
initlist = tree_cons (NULL_TREE, expr, initlist);
}
chainon (field_decl_chain, field_decl);
/* struct _objc_method_list *instance_methods; */
- field_decl = create_field_decl (build_pointer_type
- (xref_tag (RECORD_TYPE,
- get_identifier
- (UTAG_METHOD_LIST))),
+ field_decl = create_field_decl (objc_method_list_ptr,
"instance_methods");
chainon (field_decl_chain, field_decl);
/* struct _objc_method_list *class_methods; */
- field_decl = create_field_decl (build_pointer_type
- (xref_tag (RECORD_TYPE,
- get_identifier
- (UTAG_METHOD_LIST))),
+ field_decl = create_field_decl (objc_method_list_ptr,
"class_methods");
chainon (field_decl_chain, field_decl);
chainon (field_decl_chain, field_decl);
/* struct _objc_ivar_list *ivars; */
- field_decl = create_field_decl (build_pointer_type
- (xref_tag (RECORD_TYPE,
- get_identifier
- (UTAG_IVAR_LIST))),
+ field_decl = create_field_decl (objc_ivar_list_ptr,
"ivars");
chainon (field_decl_chain, field_decl);
/* struct _objc_method_list *methods; */
- field_decl = create_field_decl (build_pointer_type
- (xref_tag (RECORD_TYPE,
- get_identifier
- (UTAG_METHOD_LIST))),
+ field_decl = create_field_decl (objc_method_list_ptr,
"methods");
chainon (field_decl_chain, field_decl);
static void
error_with_ivar (const char *message, tree decl)
{
- error ("%J%s `%s'", decl,
+ error ("%J%s %qs", decl,
message, gen_declaration (decl));
}
objc_ivar_list_record = start_struct (RECORD_TYPE, NULL_TREE);
/* struct _objc__method_prototype_list *method_next; */
- field_decl = create_field_decl (build_pointer_type
- (xref_tag (RECORD_TYPE,
- get_identifier
- (UTAG_METHOD_PROTOTYPE_LIST))),
+ field_decl = create_field_decl (objc_method_proto_list_ptr,
"method_next");
field_decl_chain = field_decl;
generate_ivar_lists (void)
{
tree initlist, ivar_list_template, chain;
- tree variable_length_type
- = xref_tag (RECORD_TYPE, get_identifier (UTAG_IVAR_LIST));
int size;
generating_instance_variables = 1;
UOBJC_CLASS_VARIABLES_decl
= generate_ivars_list (ivar_list_template, "_OBJC_CLASS_VARIABLES",
size, initlist);
- TREE_TYPE (UOBJC_CLASS_VARIABLES_decl) = variable_length_type;
}
else
UOBJC_CLASS_VARIABLES_decl = 0;
UOBJC_INSTANCE_VARIABLES_decl
= generate_ivars_list (ivar_list_template, "_OBJC_INSTANCE_VARIABLES",
size, initlist);
- TREE_TYPE (UOBJC_INSTANCE_VARIABLES_decl) = variable_length_type;
}
else
UOBJC_INSTANCE_VARIABLES_decl = 0;
generate_dispatch_tables (void)
{
tree initlist, chain, method_list_template;
- tree variable_length_type
- = xref_tag (RECORD_TYPE, get_identifier (UTAG_METHOD_LIST));
int size;
if (!objc_method_template)
? "_OBJC_CLASS_METHODS"
: "_OBJC_CATEGORY_CLASS_METHODS"),
size, initlist);
- TREE_TYPE (UOBJC_CLASS_METHODS_decl) = variable_length_type;
}
else
UOBJC_CLASS_METHODS_decl = 0;
= generate_dispatch_table (method_list_template,
"_OBJC_CATEGORY_INSTANCE_METHODS",
size, initlist);
- TREE_TYPE (UOBJC_INSTANCE_METHODS_decl) = variable_length_type;
}
else
UOBJC_INSTANCE_METHODS_decl = 0;
initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
else
{
- expr = build_unary_op (ADDR_EXPR, instance_methods, 0);
+ expr = convert (objc_method_list_ptr,
+ build_unary_op (ADDR_EXPR, instance_methods, 0));
initlist = tree_cons (NULL_TREE, expr, initlist);
}
if (!class_methods)
initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
else
{
- expr = build_unary_op (ADDR_EXPR, class_methods, 0);
+ expr = convert (objc_method_list_ptr,
+ build_unary_op (ADDR_EXPR, class_methods, 0));
initlist = tree_cons (NULL_TREE, expr, initlist);
}
initlist = tree_cons (NULL_TREE, default_conversion (name), initlist);
/* version = */
- initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (long_integer_type_node, 0),
+ initlist);
/* info = */
- initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, status), initlist);
+ initlist = tree_cons (NULL_TREE,
+ build_int_cst (long_integer_type_node, status),
+ initlist);
/* instance_size = */
- initlist = tree_cons (NULL_TREE, size, initlist);
+ initlist = tree_cons (NULL_TREE, convert (long_integer_type_node, size),
+ initlist);
/* objc_ivar_list = */
if (!ivar_list)
initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
else
{
- expr = build_unary_op (ADDR_EXPR, ivar_list, 0);
+ expr = convert (objc_ivar_list_ptr,
+ build_unary_op (ADDR_EXPR, ivar_list, 0));
initlist = tree_cons (NULL_TREE, expr, initlist);
}
initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist);
else
{
- expr = build_unary_op (ADDR_EXPR, dispatch_table, 0);
+ expr = convert (objc_method_list_ptr,
+ build_unary_op (ADDR_EXPR, dispatch_table, 0));
initlist = tree_cons (NULL_TREE, expr, initlist);
}
static struct objc_class _OBJC_CLASS_Foo={ ... }; */
static void
-generate_shared_structures (void)
+generate_shared_structures (int cls_flags)
{
tree sc_spec, decl_specs, decl;
tree name_expr, super_expr, root_expr;
convert (integer_type_node,
TYPE_SIZE_UNIT (CLASS_STATIC_TEMPLATE
(implementation_template))),
- 1 /*CLS_FACTORY*/,
+ 1 /*CLS_FACTORY*/ | cls_flags,
UOBJC_INSTANCE_METHODS_decl,
UOBJC_INSTANCE_VARIABLES_decl,
protocol_decl);
static tree
build_method_decl (enum tree_code code, tree ret_type, tree selector,
- tree add_args)
+ tree add_args, bool ellipsis)
{
tree method_decl;
METHOD_SEL_NAME (method_decl) = build_keyword_selector (selector);
METHOD_SEL_ARGS (method_decl) = selector;
METHOD_ADD_ARGS (method_decl) = add_args;
+ METHOD_ADD_ARGS_ELLIPSIS_P (method_decl) = ellipsis;
}
else
{
{
tree arg_type = TREE_VALUE (TREE_TYPE (akey));
+ /* Decay arrays and functions into pointers. */
+ if (TREE_CODE (arg_type) == ARRAY_TYPE)
+ arg_type = build_pointer_type (TREE_TYPE (arg_type));
+ else if (TREE_CODE (arg_type) == FUNCTION_TYPE)
+ arg_type = build_pointer_type (arg_type);
+
chainon (arglist, build_tree_list (NULL_TREE, arg_type));
}
chainon (arglist, build_tree_list (NULL_TREE, arg_type));
}
- if (!TREE_OVERFLOW (METHOD_ADD_ARGS (meth)))
+ if (!METHOD_ADD_ARGS_ELLIPSIS_P (meth))
goto lack_of_ellipsis;
}
else
different types. */
attr loop;
- warning ("multiple %s named `%c%s' found",
+ /* But just how different are those types? If
+ -Wno-strict-selector-match is specified, we shall not
+ complain if the differences are solely among types with
+ identical size and alignment. */
+ if (!warn_strict_selector_match)
+ {
+ for (loop = hsh->list; loop; loop = loop->next)
+ if (!comp_proto_with_proto (meth, loop->value, 0))
+ goto issue_warning;
+
+ return meth;
+ }
+
+ issue_warning:
+ warning (0, "multiple %s named %<%c%s%> found",
methods ? "methods" : "selectors",
(is_class ? '+' : '-'),
IDENTIFIER_POINTER (METHOD_SEL_NAME (meth)));
|| (TREE_CODE (receiver) == COMPOUND_EXPR
&& !IS_SUPER (rtype)));
+ /* If we are calling [super dealloc], reset our warning flag. */
+ if (super && !strcmp ("dealloc", IDENTIFIER_POINTER (sel_name)))
+ should_call_super_dealloc = 0;
+
/* If the receiver is a class object, retrieve the corresponding
@interface, if one exists. */
class_tree = receiver_is_class_object (receiver, self, super);
{
if (!CLASS_SUPER_NAME (implementation_template))
{
- error ("no super class declared in @interface for `%s'",
+ error ("no super class declared in @interface for %qs",
IDENTIFIER_POINTER (CLASS_NAME (implementation_template)));
return error_mark_node;
}
/* 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 || objc_is_id (rtype))
+ if (objc_is_id (rtype))
{
- if (!rtype)
- rtype = xref_tag (RECORD_TYPE, class_tree);
- else if (IS_ID (rtype))
- {
- rprotos = TYPE_PROTOCOL_LIST (rtype);
- rtype = NULL_TREE;
- }
- else
- {
- class_tree = objc_class_name;
- OBJC_SET_TYPE_NAME (rtype, class_tree);
- }
+ class_tree = (IS_CLASS (rtype) ? objc_class_name : NULL_TREE);
+ rprotos = (TYPE_HAS_OBJC_INFO (TREE_TYPE (rtype))
+ ? TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (rtype))
+ : NULL_TREE);
+ rtype = NULL_TREE;
if (rprotos)
- method_prototype
- = lookup_method_in_protocol_list (rprotos, sel_name,
- class_tree != NULL_TREE);
- if (!method_prototype && !rprotos)
- method_prototype
- = lookup_method_in_hash_lists (sel_name,
- class_tree != NULL_TREE);
+ {
+ /* If messaging 'id <Protos>' or 'Class <Proto>', first search
+ in protocols themselves for the method prototype. */
+ method_prototype
+ = lookup_method_in_protocol_list (rprotos, sel_name,
+ class_tree != NULL_TREE);
+
+ /* If messaging 'Class <Proto>' but did not find a class method
+ prototype, search for an instance method instead, and warn
+ about having done so. */
+ if (!method_prototype && !rtype && class_tree != NULL_TREE)
+ {
+ method_prototype
+ = lookup_method_in_protocol_list (rprotos, sel_name, 0);
+
+ if (method_prototype)
+ warning (0, "found %<-%s%> instead of %<+%s%> in protocol(s)",
+ IDENTIFIER_POINTER (sel_name),
+ IDENTIFIER_POINTER (sel_name));
+ }
+ }
}
- else
+ else if (rtype)
{
tree orig_rtype = rtype, saved_rtype;
saved_rtype = rtype;
if (TYPED_OBJECT (rtype))
{
- rprotos = TYPE_PROTOCOL_LIST (rtype);
- rtype = lookup_interface (OBJC_TYPE_NAME (rtype));
+ rprotos = TYPE_OBJC_PROTOCOL_LIST (rtype);
+ rtype = TYPE_OBJC_INTERFACE (rtype);
}
/* 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;
+ if (!rtype || TREE_CODE (rtype) == IDENTIFIER_NODE)
+ rtype = NULL_TREE;
else if (TREE_CODE (rtype) == CLASS_INTERFACE_TYPE
|| TREE_CODE (rtype) == CLASS_IMPLEMENTATION_TYPE)
{
}
else
{
- warning ("invalid receiver type `%s'",
+ warning (0, "invalid receiver type %qs",
gen_type_name (orig_rtype));
+ /* After issuing the "invalid receiver" warning, perform method
+ lookup as if we were messaging 'id'. */
rtype = rprotos = NULL_TREE;
}
}
+
+ /* For 'id' or 'Class' receivers, search in the global hash table
+ as a last resort. For all receivers, warn if protocol searches
+ have failed. */
+ if (!method_prototype)
+ {
+ if (rprotos)
+ warning (0, "%<%c%s%> not found in protocol(s)",
+ (class_tree ? '+' : '-'),
+ IDENTIFIER_POINTER (sel_name));
+
+ if (!rtype)
+ method_prototype
+ = lookup_method_in_hash_lists (sel_name, class_tree != NULL_TREE);
+ }
+
if (!method_prototype)
{
static bool warn_missing_methods = false;
if (rtype)
- warning ("`%s' may not respond to `%c%s'",
+ warning (0, "%qs may not respond to %<%c%s%>",
IDENTIFIER_POINTER (OBJC_TYPE_NAME (rtype)),
(class_tree ? '+' : '-'),
IDENTIFIER_POINTER (sel_name));
- if (rprotos)
- warning ("`%c%s' not implemented by protocol(s)",
+ /* If we are messaging an 'id' or 'Class' object and made it here,
+ then we have failed to find _any_ instance or class method,
+ respectively. */
+ else
+ warning (0, "no %<%c%s%> method found",
(class_tree ? '+' : '-'),
IDENTIFIER_POINTER (sel_name));
+
if (!warn_missing_methods)
{
- warning ("(Messages without a matching method signature");
- warning ("will be assumed to return `id' and accept");
- warning ("`...' as arguments.)");
+ warning (0, "(Messages without a matching method signature");
+ warning (0, "will be assumed to return %<id%> and accept");
+ warning (0, "%<...%> as arguments.)");
warn_missing_methods = true;
}
}
{
tree sender = (super_flag ? umsg_super_decl :
(!flag_next_runtime || flag_nil_receivers
- ? umsg_decl
+ ? (flag_objc_direct_dispatch
+ ? umsg_fast_decl
+ : umsg_decl)
: umsg_nonnil_decl));
tree rcv_p = (super_flag ? objc_super_type : objc_object_type);
if (!p)
{
- error ("cannot find protocol declaration for `%s'",
+ error ("cannot find protocol declaration for %qs",
IDENTIFIER_POINTER (protoname));
return error_mark_node;
}
/* If still not found, print out a warning. */
if (!hsh)
{
- warning ("undeclared selector `%s'", IDENTIFIER_POINTER (selname));
+ warning (0, "undeclared selector %qs", IDENTIFIER_POINTER (selname));
}
}
to an instance variable. It's better to catch the cases
where this is done unknowingly than to support the above
paradigm. */
- warning ("instance variable `%s' accessed in class method",
+ warning (0, "instance variable %qs accessed in class method",
IDENTIFIER_POINTER (id));
self_decl = convert (objc_instance_type, self_decl); /* cast */
}
return NULL_TREE;
}
+/* Look up a class (if OBJC_LOOKUP_CLASS is set in FLAGS) or instance method
+ in INTERFACE, along with any categories and protocols attached thereto.
+ If method is not found, and the OBJC_LOOKUP_NO_SUPER is _not_ set in FLAGS,
+ recursively examine the INTERFACE's superclass. If OBJC_LOOKUP_CLASS is
+ set, OBJC_LOOKUP_NO_SUPER is cleared, and no suitable class method could
+ be found in INTERFACE or any of its superclasses, look for an _instance_
+ method of the same name in the root class as a last resort.
+
+ If a suitable method cannot be found, return NULL_TREE. */
+
static tree
-lookup_method_static (tree interface, tree ident, int is_class)
+lookup_method_static (tree interface, tree ident, int flags)
{
tree meth = NULL_TREE, root_inter = NULL_TREE;
tree inter = interface;
+ int is_class = (flags & OBJC_LOOKUP_CLASS);
+ int no_superclasses = (flags & OBJC_LOOKUP_NO_SUPER);
while (inter)
{
return meth;
}
+ /* If we were instructed not to look in superclasses, don't. */
+ if (no_superclasses)
+ return NULL_TREE;
+
/* Failing that, climb up the inheritance hierarchy. */
root_inter = inter;
inter = lookup_interface (CLASS_SUPER_NAME (inter));
{
/* Check types against those; if different, add to a list. */
attr loop;
- int already_there = comp_proto_with_proto (method, hsh->key);
+ int already_there = comp_proto_with_proto (method, hsh->key, 1);
for (loop = hsh->list; !already_there && loop; loop = loop->next)
- already_there |= comp_proto_with_proto (method, loop->value);
+ already_there |= comp_proto_with_proto (method, loop->value, 1);
if (!already_there)
hash_add_attr (hsh, method);
}
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'",
+ && !comp_proto_with_proto (method, mth, 1))
+ error ("duplicate declaration of method %<%c%s%>",
is_class ? '+' : '-',
IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
}
add_method_to_hash_list (nst_method_hash_list, method);
/* Instance methods in root classes (and categories thereof)
- may acts as class methods as a last resort. */
+ may act as class methods as a last resort. We also add
+ instance methods listed in @protocol declarations to
+ the class hash table, on the assumption that @protocols
+ may be adopted by root classes or categories. */
if (TREE_CODE (class) == CATEGORY_INTERFACE_TYPE
|| TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE)
class = lookup_interface (CLASS_NAME (class));
- if (TREE_CODE (class) != PROTOCOL_INTERFACE_TYPE
- && !CLASS_SUPER_NAME (class))
+ if (TREE_CODE (class) == PROTOCOL_INTERFACE_TYPE
+ || !CLASS_SUPER_NAME (class))
add_method_to_hash_list (cls_method_hash_list, method);
}
}
static tree
-add_class (tree class)
+add_class (tree class_name, tree name)
{
+ struct interface_tuple **slot;
+
/* Put interfaces on list in reverse order. */
- TREE_CHAIN (class) = interface_chain;
- interface_chain = class;
+ TREE_CHAIN (class_name) = interface_chain;
+ interface_chain = class_name;
+
+ if (interface_htab == NULL)
+ interface_htab = htab_create_ggc (31, hash_interface, eq_interface, NULL);
+ slot = (struct interface_tuple **)
+ htab_find_slot_with_hash (interface_htab, name,
+ htab_hash_pointer (name),
+ INSERT);
+ if (!*slot)
+ {
+ *slot = (struct interface_tuple *) ggc_alloc_cleared (sizeof (struct interface_tuple));
+ (*slot)->id = name;
+ }
+ (*slot)->class_name = class_name;
+
return interface_chain;
}
if (cat)
{
- warning ("duplicate interface declaration for category `%s(%s)'",
+ warning (0, "duplicate interface declaration for category %<%s(%s)%>",
IDENTIFIER_POINTER (CLASS_NAME (class)),
IDENTIFIER_POINTER (CLASS_SUPER_NAME (category)));
}
#ifdef OBJCPLUS
if (TREE_CODE (field_type) == REFERENCE_TYPE)
{
- error ("illegal reference type specified for instance variable `%s'",
+ error ("illegal reference type specified for instance variable %qs",
ivar_name);
/* Return class as is without adding this ivar. */
return class;
|| TYPE_SIZE (field_type) == error_mark_node)
/* 'type[0]' is allowed, but 'type[]' is not! */
{
- error ("instance variable `%s' has unknown size", ivar_name);
+ error ("instance variable %qs 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)))
+ /* Check if the ivar being added has a non-POD C++ type. If so, we will
+ need to either (1) warn the user about it or (2) generate suitable
+ constructor/destructor call from '- .cxx_construct' or '- .cxx_destruct'
+ methods (if '-fobjc-call-cxx-cdtors' was specified). */
+ 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");
+
+ if (flag_objc_call_cxx_cdtors)
+ {
+ /* Since the ObjC runtime will be calling the constructors and
+ destructors for us, the only thing we can't handle is the lack
+ of a default constructor. */
+ if (TYPE_NEEDS_CONSTRUCTING (field_type)
+ && !TYPE_HAS_DEFAULT_CONSTRUCTOR (field_type))
+ {
+ warning (0, "type `%s' has no default constructor to call",
+ type_name);
+
+ /* If we cannot call a constructor, we should also avoid
+ calling the destructor, for symmetry. */
+ if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type))
+ warning (0, "destructor for `%s' shall not be run either",
+ type_name);
+ }
+ }
+ else
+ {
+ static bool warn_cxx_ivars = false;
+
+ 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 (0, "type `%s' has a user-defined constructor", type_name);
+ if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type))
+ warning (0, "type `%s' has a user-defined destructor", type_name);
+
+ if (!warn_cxx_ivars)
+ {
+ warning (0, "C++ constructors and destructors will not "
+ "be invoked for Objective-C fields");
+ warn_cxx_ivars = true;
+ }
+ }
}
#endif
objc_is_public (tree expr, tree identifier)
{
tree basetype = TREE_TYPE (expr);
- enum tree_code code = TREE_CODE (basetype);
tree decl;
- if (code == RECORD_TYPE)
+ if (basetype && TREE_CODE (basetype) == RECORD_TYPE)
{
- if (TREE_STATIC_TEMPLATE (basetype))
+ if (TYPE_HAS_OBJC_INFO (basetype) && TYPE_OBJC_INTERFACE (basetype))
{
- if (!lookup_interface (OBJC_TYPE_NAME (basetype)))
+ tree class = lookup_interface (OBJC_TYPE_NAME (basetype));
+
+ if (!class)
{
- error ("cannot find interface declaration for `%s'",
+ error ("cannot find interface declaration for %qs",
IDENTIFIER_POINTER (OBJC_TYPE_NAME (basetype)));
return 0;
}
- if ((decl = is_ivar (TYPE_FIELDS (basetype), identifier)))
+ if ((decl = is_ivar (get_class_ivars (class), identifier)))
{
if (TREE_PUBLIC (decl))
return 1;
int private = is_private (decl);
if (private)
- error ("instance variable `%s' is declared private",
+ error ("instance variable %qs is declared private",
IDENTIFIER_POINTER (DECL_NAME (decl)));
return !private;
}
non-@public ivars. We will let this slide for now... */
if (!objc_method_context)
{
- warning ("instance variable `%s' is %s; "
+ warning (0, "instance variable %qs 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",
+ error ("instance variable %qs is declared %s",
IDENTIFIER_POINTER (identifier),
TREE_PRIVATE (decl) ? "private" : "protected");
return 0;
}
}
-
- else if (objc_implementation_context && (basetype == objc_object_reference))
- {
- expr = convert (uprivate_record, expr);
- warning ("static access to object of type `id'");
- }
}
return 1;
{
if (TREE_CODE (objc_implementation_context)
== CLASS_IMPLEMENTATION_TYPE)
- warning ("incomplete implementation of class `%s'",
+ warning (0, "incomplete implementation of class %qs",
IDENTIFIER_POINTER (CLASS_NAME (objc_implementation_context)));
else if (TREE_CODE (objc_implementation_context)
== CATEGORY_IMPLEMENTATION_TYPE)
- warning ("incomplete implementation of category `%s'",
+ warning (0, "incomplete implementation of category %qs",
IDENTIFIER_POINTER (CLASS_SUPER_NAME (objc_implementation_context)));
first = 0;
}
- warning ("method definition for `%c%s' not found",
+ warning (0, "method definition for %<%c%s%> not found",
mtype, IDENTIFIER_POINTER (METHOD_SEL_NAME (chain)));
}
{
if (TREE_CODE (objc_implementation_context)
== CLASS_IMPLEMENTATION_TYPE)
- warning ("incomplete implementation of class `%s'",
+ warning (0, "incomplete implementation of class %qs",
IDENTIFIER_POINTER
(CLASS_NAME (objc_implementation_context)));
else if (TREE_CODE (objc_implementation_context)
== CATEGORY_IMPLEMENTATION_TYPE)
- warning ("incomplete implementation of category `%s'",
+ warning (0, "incomplete implementation of category %qs",
IDENTIFIER_POINTER
(CLASS_SUPER_NAME (objc_implementation_context)));
first = 0;
}
- warning ("method definition for `%c%s' not found",
+ warning (0, "method definition for %<%c%s%> not found",
mtype, IDENTIFIER_POINTER (METHOD_SEL_NAME (chain)));
}
}
if (!f1 || !f2)
- warning ("%s `%s' does not fully implement the `%s' protocol",
+ warning (0, "%s %qs does not fully implement the %qs protocol",
type, name, IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
}
if (objc_implementation_context)
{
- warning ("`@end' missing in implementation context");
+ warning (0, "%<@end%> missing in implementation context");
finish_class (objc_implementation_context);
objc_ivar_chain = NULL_TREE;
objc_implementation_context = NULL_TREE;
class = make_node (code);
TYPE_LANG_SLOT_1 (class) = make_tree_vec (CLASS_LANG_SLOT_ELTS);
- /* Check for existence of the super class, if one was specified. */
+ /* Check for existence of the super class, if one was specified. Note
+ that we must have seen an @interface, not just a @class. If we
+ are looking at a @compatibility_alias, traverse it first. */
if ((code == CLASS_INTERFACE_TYPE || code == CLASS_IMPLEMENTATION_TYPE)
- && super_name && !objc_is_class_name (super_name))
+ && super_name)
{
- error ("cannot find interface declaration for `%s', superclass of `%s'",
- IDENTIFIER_POINTER (super_name),
- IDENTIFIER_POINTER (class_name));
- super_name = NULL_TREE;
+ tree super = objc_is_class_name (super_name);
+
+ if (!super || !lookup_interface (super))
+ {
+ error ("cannot find interface declaration for %qs, superclass of %qs",
+ IDENTIFIER_POINTER (super ? super : super_name),
+ IDENTIFIER_POINTER (class_name));
+ super_name = NULL_TREE;
+ }
+ else
+ super_name = super;
}
CLASS_NAME (class) = class_name;
if (! objc_is_class_name (class_name)
&& (decl = lookup_name (class_name)))
{
- error ("`%s' redeclared as different kind of symbol",
+ error ("%qs redeclared as different kind of symbol",
IDENTIFIER_POINTER (class_name));
error ("%Jprevious declaration of '%D'",
decl, decl);
for (chain = implemented_classes; chain; chain = TREE_CHAIN (chain))
if (TREE_VALUE (chain) == class_name)
{
- error ("reimplementation of class `%s'",
+ error ("reimplementation of class %qs",
IDENTIFIER_POINTER (class_name));
return error_mark_node;
}
if (!(implementation_template = lookup_interface (class_name)))
{
- warning ("cannot find interface declaration for `%s'",
+ warning (0, "cannot find interface declaration for %qs",
IDENTIFIER_POINTER (class_name));
- add_class (implementation_template = objc_implementation_context);
+ add_class (implementation_template = objc_implementation_context,
+ class_name);
}
/* If a super class has been specified in the implementation,
tree previous_name = CLASS_SUPER_NAME (implementation_template);
const char *const name =
previous_name ? IDENTIFIER_POINTER (previous_name) : "";
- error ("conflicting super class name `%s'",
+ error ("conflicting super class name %qs",
IDENTIFIER_POINTER (super_name));
- error ("previous declaration of `%s'", name);
+ error ("previous declaration of %qs", name);
}
else if (! super_name)
{
if (lookup_interface (class_name))
#ifdef OBJCPLUS
- error ("duplicate interface declaration for class `%s'",
+ error ("duplicate interface declaration for class %qs",
#else
- warning ("duplicate interface declaration for class `%s'",
+ warning (0, "duplicate interface declaration for class %qs",
#endif
IDENTIFIER_POINTER (class_name));
else
- add_class (class);
+ add_class (class, class_name);
if (protocol_list)
CLASS_PROTOCOL_LIST (class)
if (!(class_category_is_assoc_with = lookup_interface (class_name)))
{
- error ("cannot find interface declaration for `%s'",
+ error ("cannot find interface declaration for %qs",
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 %qs",
IDENTIFIER_POINTER (class_name));
exit (FATAL_EXIT_CODE);
}
|| TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE)
{
struct imp_entry *imp_entry;
- tree ivar_context;
/* Check consistency of the instance variables. */
push_lang_context (lang_name_c);
#endif
- ivar_context = build_private_template (implementation_template);
+ build_private_template (implementation_template);
+ uprivate_record = CLASS_STATIC_TEMPLATE (implementation_template);
+ objc_instance_type = build_pointer_type (uprivate_record);
imp_entry = (struct imp_entry *) ggc_alloc (sizeof (struct imp_entry));
synth_forward_declarations ();
imp_entry->class_decl = UOBJC_CLASS_decl;
imp_entry->meta_decl = UOBJC_METACLASS_decl;
+ imp_entry->has_cxx_cdtors = 0;
/* Append to front and increment count. */
imp_list = imp_entry;
pop_lang_context ();
#endif /* OBJCPLUS */
- return ivar_context;
+ return get_class_ivars (implementation_template);
}
else if (TREE_CODE (class) == CLASS_INTERFACE_TYPE)
push_lang_context (lang_name_c);
#endif /* OBJCPLUS */
- if (!CLASS_STATIC_TEMPLATE (class))
- {
- tree record = start_struct (RECORD_TYPE, CLASS_NAME (class));
- 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_STATIC_TEMPLATE (record) = 1;
- }
+ build_private_template (class);
#ifdef OBJCPLUS
pop_lang_context ();
IDENTIFIER_POINTER (CLASS_SUPER_NAME (objc_implementation_context)));
}
}
-
- else if (TREE_CODE (class) == CLASS_INTERFACE_TYPE)
- {
- tree decl;
- const char *class_name = IDENTIFIER_POINTER (CLASS_NAME (class));
- char *string = (char *) alloca (strlen (class_name) + 3);
-
- /* extern struct objc_object *_<my_name>; */
-
- sprintf (string, "_%s", class_name);
-
- decl = build_decl (VAR_DECL, get_identifier (string),
- build_pointer_type (objc_object_reference));
- DECL_EXTERNAL (decl) = 1;
- lang_hooks.decls.pushdecl (decl);
- finish_decl (decl, NULL_TREE, NULL_TREE);
- }
}
static tree
}
else
{
- warning ("duplicate declaration for protocol `%s'",
+ warning (0, "duplicate declaration for protocol %qs",
IDENTIFIER_POINTER (name));
}
return protocol;
obstack_1grow (&util_obstack, '@');
return;
}
- else if (TREE_STATIC_TEMPLATE (pointer_to))
+ else if (TYPE_HAS_OBJC_INFO (pointer_to)
+ && TYPE_OBJC_INTERFACE (pointer_to))
{
if (generating_instance_variables)
{
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 ob_size = obstack_object_size (&util_obstack);
+ char c1 = ob_size > 1 ? *(obstack_next_free (&util_obstack) - 2) : 0;
+ char c0 = ob_size > 0 ? *(obstack_next_free (&util_obstack) - 1) : 0;
+ int pointed_to = (c0 == '^' || (c1 == '^' && c0 == 'r'));
int inline_contents
= ((format == OBJC_ENCODE_INLINE_DEFS || generating_instance_variables)
- && (!pointed_to || obstack_object_size (&util_obstack) - curtype == 1));
+ && (!pointed_to || ob_size - curtype == (c1 == 'r' ? 2 : 1)));
/* Traverse struct aliases; it is important to get the
original struct and its tag name (if any). */
{
case 32: c = 'f'; break;
case 64:
+ case 96:
case 128: c = 'd'; break;
default: abort ();
}
static void
objc_push_parm (tree parm)
{
- /* Convert array parameters of unknown size into pointers. */
- if (TREE_CODE (TREE_TYPE (parm)) == ARRAY_TYPE
- && !TYPE_SIZE (TREE_TYPE (parm)))
+ /* Decay arrays and functions into pointers. */
+ if (TREE_CODE (TREE_TYPE (parm)) == ARRAY_TYPE)
TREE_TYPE (parm) = build_pointer_type (TREE_TYPE (TREE_TYPE (parm)));
-
+ else if (TREE_CODE (TREE_TYPE (parm)) == FUNCTION_TYPE)
+ TREE_TYPE (parm) = build_pointer_type (TREE_TYPE (parm));
+
+ DECL_ARG_TYPE_AS_WRITTEN (parm) = TREE_TYPE (parm);
+ DECL_ARG_TYPE (parm)
+ = lang_hooks.types.type_promotes_to (TREE_TYPE (parm));
+
+ /* Record constancy and volatility. */
+ c_apply_type_quals_to_decl
+ ((TYPE_READONLY (TREE_TYPE (parm)) ? TYPE_QUAL_CONST : 0)
+ | (TYPE_RESTRICT (TREE_TYPE (parm)) ? TYPE_QUAL_RESTRICT : 0)
+ | (TYPE_VOLATILE (TREE_TYPE (parm)) ? TYPE_QUAL_VOLATILE : 0), parm);
+
objc_parmlist = chainon (objc_parmlist, parm);
}
-/* Retrieve the formal paramter list constructed via preceding calls to
+/* Retrieve the formal parameter list constructed via preceding calls to
objc_push_parm(). */
#ifdef OBJCPLUS
tree next = TREE_CHAIN (parm_info);
TREE_CHAIN (parm_info) = NULL_TREE;
- pushdecl (parm_info);
+ parm_info = pushdecl (parm_info);
+ finish_decl (parm_info, NULL_TREE, NULL_TREE);
parm_info = next;
}
arg_info = get_parm_info (have_ellipsis);
#endif
int have_ellipsis = 0;
+ /* If we are defining a "dealloc" method in a non-root class, we
+ will need to check if a [super dealloc] is missing, and warn if
+ it is. */
+ if(CLASS_SUPER_NAME (objc_implementation_context)
+ && !strcmp ("dealloc", IDENTIFIER_POINTER (METHOD_SEL_NAME (method))))
+ should_call_super_dealloc = 1;
+ else
+ should_call_super_dealloc = 0;
+
/* Required to implement _msgSuper. */
objc_method_context = method;
UOBJC_SUPER_decl = NULL_TREE;
parmlist = METHOD_SEL_ARGS (method);
while (parmlist)
{
- tree parm = build_decl (PARM_DECL, KEYWORD_ARG_NAME (parmlist),
- TREE_VALUE (TREE_TYPE (parmlist)));
+ tree type = TREE_VALUE (TREE_TYPE (parmlist)), parm;
+ parm = build_decl (PARM_DECL, KEYWORD_ARG_NAME (parmlist), type);
objc_push_parm (parm);
parmlist = TREE_CHAIN (parmlist);
}
objc_push_parm (TREE_VALUE (akey));
}
- if (TREE_OVERFLOW (METHOD_ADD_ARGS (method)))
+ if (METHOD_ADD_ARGS_ELLIPSIS_P (method))
have_ellipsis = 1;
}
warn_with_method (const char *message, int mtype, tree method)
{
/* Add a readable method name to the warning. */
- warning ("%J%s `%c%s'", method,
+ warning (0, "%J%s %<%c%s%>", method,
message, mtype, gen_method_decl (method));
}
if (TYPE_MAIN_VARIANT (type1) != TYPE_MAIN_VARIANT (type2))
return 0;
- type1 = TYPE_PROTOCOL_LIST (type1);
- type2 = TYPE_PROTOCOL_LIST (type2);
+ type1 = (TYPE_HAS_OBJC_INFO (type1)
+ ? TYPE_OBJC_PROTOCOL_LIST (type1)
+ : NULL_TREE);
+ type2 = (TYPE_HAS_OBJC_INFO (type2)
+ ? TYPE_OBJC_PROTOCOL_LIST (type2)
+ : NULL_TREE);
+
if (list_length (type1) == list_length (type2))
{
for (; type2; type2 = TREE_CHAIN (type2))
return 0;
}
+/* Return 1 if TYPE1 has the same size and alignment as TYPE2. */
+
+static int
+objc_types_share_size_and_alignment (tree type1, tree type2)
+{
+ return (simple_cst_equal (TYPE_SIZE (type1), TYPE_SIZE (type2))
+ && TYPE_ALIGN (type1) == TYPE_ALIGN (type2));
+}
+
/* Return 1 if PROTO1 is equivalent to PROTO2
- for purposes of method overloading. */
+ for purposes of method overloading. Ordinarily, the type signatures
+ should match up exactly, unless STRICT is zero, in which case we
+ shall allow differences in which the size and alignment of a type
+ is the same. */
static int
-comp_proto_with_proto (tree proto1, tree proto2)
+comp_proto_with_proto (tree proto1, tree proto2, int strict)
{
tree type1, type2;
type1 = TREE_VALUE (TREE_TYPE (proto1));
type2 = TREE_VALUE (TREE_TYPE (proto2));
- if (!objc_types_are_equivalent (type1, type2))
+ if (!objc_types_are_equivalent (type1, type2)
+ && (strict || !objc_types_share_size_and_alignment (type1, type2)))
return 0;
/* Compare argument types. */
type1 && type2;
type1 = TREE_CHAIN (type1), type2 = TREE_CHAIN (type2))
{
- if (!objc_types_are_equivalent (TREE_VALUE (type1), TREE_VALUE (type2)))
+ if (!objc_types_are_equivalent (TREE_VALUE (type1), TREE_VALUE (type2))
+ && (strict
+ || !objc_types_share_size_and_alignment (TREE_VALUE (type1),
+ TREE_VALUE (type2))))
return 0;
}
return (!type1 && !type2);
}
+/* Fold an OBJ_TYPE_REF expression for ObjC method dispatches, where
+ this occurs. ObjC method dispatches are _not_ like C++ virtual
+ member function dispatches, and we account for the difference here. */
+tree
+#ifdef OBJCPLUS
+objc_fold_obj_type_ref (tree ref, tree known_type)
+#else
+objc_fold_obj_type_ref (tree ref ATTRIBUTE_UNUSED,
+ tree known_type ATTRIBUTE_UNUSED)
+#endif
+{
+#ifdef OBJCPLUS
+ tree v = BINFO_VIRTUALS (TYPE_BINFO (known_type));
+
+ /* If the receiver does not have virtual member functions, there
+ is nothing we can (or need to) do here. */
+ if (!v)
+ return NULL_TREE;
+
+ /* Let C++ handle C++ virtual functions. */
+ return cp_fold_obj_type_ref (ref, known_type);
+#else
+ /* For plain ObjC, we currently do not need to do anything. */
+ return NULL_TREE;
+#endif
+}
+
static void
objc_start_function (tree name, tree type, tree attrs,
#ifdef OBJCPLUS
#ifdef OBJCPLUS
DECL_ARGUMENTS (fndecl) = params;
-#endif
DECL_INITIAL (fndecl) = error_mark_node;
DECL_EXTERNAL (fndecl) = 0;
TREE_STATIC (fndecl) = 1;
-
-#ifdef OBJCPLUS
retrofit_lang_decl (fndecl);
cplus_decl_attributes (&fndecl, attrs, 0);
start_preparsed_function (fndecl, attrs, /*flags=*/SF_DEFAULT);
#else
+ struct c_label_context_se *nstack_se;
+ struct c_label_context_vm *nstack_vm;
+ nstack_se = XOBNEW (&parser_obstack, struct c_label_context_se);
+ nstack_se->labels_def = NULL;
+ nstack_se->labels_used = NULL;
+ nstack_se->next = label_context_stack_se;
+ label_context_stack_se = nstack_se;
+ nstack_vm = XOBNEW (&parser_obstack, struct c_label_context_vm);
+ nstack_vm->labels_def = NULL;
+ nstack_vm->labels_used = NULL;
+ nstack_vm->scope = 0;
+ nstack_vm->next = label_context_stack_vm;
+ label_context_stack_vm = nstack_vm;
+ current_function_returns_value = 0; /* Assume, until we see it does. */
+ current_function_returns_null = 0;
+
decl_attributes (&fndecl, attrs, 0);
announce_function (fndecl);
+ DECL_INITIAL (fndecl) = error_mark_node;
+ DECL_EXTERNAL (fndecl) = 0;
+ TREE_STATIC (fndecl) = 1;
current_function_decl = pushdecl (fndecl);
push_scope ();
declare_parm_level ();
DECL_RESULT (current_function_decl)
= build_decl (RESULT_DECL, NULL_TREE,
TREE_TYPE (TREE_TYPE (current_function_decl)));
+ DECL_ARTIFICIAL (DECL_RESULT (current_function_decl)) = 1;
+ DECL_IGNORED_P (DECL_RESULT (current_function_decl)) = 1;
start_fname_decls ();
store_parm_decls_from (params);
#endif
tree proto
= lookup_method_static (implementation_template,
METHOD_SEL_NAME (method),
- TREE_CODE (method) == CLASS_METHOD_DECL);
+ ((TREE_CODE (method) == CLASS_METHOD_DECL)
+ | OBJC_LOOKUP_NO_SUPER));
if (proto)
{
- if (!comp_proto_with_proto (method, proto))
+ if (!comp_proto_with_proto (method, proto, 1))
{
char type = (TREE_CODE (method) == INSTANCE_METHOD_DECL ? '-' : '+');
/* Barf if super used in a category of Object. */
if (!super_name)
{
- error ("no super class declared in interface for `%s'",
+ error ("no super class declared in interface for %qs",
IDENTIFIER_POINTER (CLASS_NAME (implementation_template)));
return error_mark_node;
}
/* Required to implement _msgSuper. This must be done AFTER finish_function,
since the optimizer may find "may be used before set" errors. */
objc_method_context = NULL_TREE;
+
+ if (should_call_super_dealloc)
+ warning (0, "method possibly missing a [super dealloc] call");
}
#if 0
{
if (objc_method_context)
{
- fprintf (stderr, "In method `%s'\n",
+ fprintf (stderr, "In method %qs\n",
IDENTIFIER_POINTER (METHOD_SEL_NAME (objc_method_context)));
return 1;
}
if (TYPE_P (type) && TYPE_NAME (type))
type = TYPE_NAME (type);
- else if (POINTER_TYPE_P (type))
+ else if (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
{
- gen_type_name_0 (TREE_TYPE (type));
+ tree inner = TREE_TYPE (type);
+
+ while (TREE_CODE (inner) == ARRAY_TYPE)
+ inner = TREE_TYPE (inner);
+
+ gen_type_name_0 (inner);
- if (!POINTER_TYPE_P (TREE_TYPE (type)))
+ if (!POINTER_TYPE_P (inner))
strcat (errbuf, " ");
- strcat (errbuf, "*");
+ if (POINTER_TYPE_P (type))
+ strcat (errbuf, "*");
+ else
+ while (type != inner)
+ {
+ strcat (errbuf, "[");
+
+ if (TYPE_DOMAIN (type))
+ {
+ char sz[20];
+
+ sprintf (sz, HOST_WIDE_INT_PRINT_DEC,
+ (TREE_INT_CST_LOW
+ (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) + 1));
+ strcat (errbuf, sz);
+ }
+
+ strcat (errbuf, "]");
+ type = TREE_TYPE (type);
+ }
+
goto exit_function;
}
type = DECL_NAME (type);
strcat (errbuf, IDENTIFIER_POINTER (type));
- proto = TYPE_PROTOCOL_LIST (orig);
+
+ /* For 'id' and 'Class', adopted protocols are stored in the pointee. */
+ if (objc_is_id (orig))
+ orig = TREE_TYPE (orig);
+
+ proto = TYPE_HAS_OBJC_INFO (orig) ? TYPE_OBJC_PROTOCOL_LIST (orig) : NULL_TREE;
if (proto)
{
chain = TREE_CHAIN (chain);
}
- if (TREE_OVERFLOW (METHOD_ADD_ARGS (method)))
+ if (METHOD_ADD_ARGS_ELLIPSIS_P (method))
strcat (errbuf, ", ...");
}
}
/* A missing @end may not be detected by the parser. */
if (objc_implementation_context)
{
- warning ("`@end' missing in implementation context");
+ warning (0, "%<@end%> missing in implementation context");
finish_class (objc_implementation_context);
objc_ivar_chain = NULL_TREE;
objc_implementation_context = NULL_TREE;
/* all of the following reference the string pool... */
generate_ivar_lists ();
generate_dispatch_tables ();
- generate_shared_structures ();
+ generate_shared_structures (impent->has_cxx_cdtors
+ ? CLS_HAS_CXX_STRUCTORS
+ : 0);
}
else
{
if (protocol_chain)
generate_protocols ();
- if (flag_replace_objc_classes && imp_list)
+ if ((flag_replace_objc_classes && imp_list) || flag_objc_gc)
generate_objc_image_info ();
/* Arrange for ObjC data structures to be initialized at run time. */
generate_objc_image_info (void)
{
tree decl, initlist;
+ int flags
+ = ((flag_replace_objc_classes && imp_list ? 1 : 0)
+ | (flag_objc_gc ? 2 : 0));
decl = start_var_decl (build_array_type
(integer_type_node,
"_OBJC_IMAGE_INFO");
initlist = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, 0));
- initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 1), initlist);
+ initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, flags), initlist);
initlist = objc_build_constructor (TREE_TYPE (decl), nreverse (initlist));
finish_var_decl (decl, initlist);
}
-/* Look up ID as an instance variable. */
+/* Look up ID as an instance variable. OTHER contains the result of
+ the C or C++ lookup, which we may want to use instead. */
tree
-objc_lookup_ivar (tree id)
+objc_lookup_ivar (tree other, tree id)
{
- tree decl;
+ tree ivar;
+
+ /* If we are not inside of an ObjC method, ivar lookup makes no sense. */
+ if (!objc_method_context)
+ return other;
- if (objc_method_context && !strcmp (IDENTIFIER_POINTER (id), "super"))
+ if (!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)))
+
+ /* In a class method, look up an instance variable only as a last
+ resort. */
+ if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL
+ && other && other != error_mark_node)
+ return other;
+
+ /* Look up the ivar, but do not use it if it is not accessible. */
+ ivar = is_ivar (objc_ivar_chain, id);
+
+ if (!ivar || is_private (ivar))
+ return other;
+
+ /* In an instance method, a local variable (or parameter) may hide the
+ instance variable. */
+ if (TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL
+ && other && other != error_mark_node
+#ifdef OBJCPLUS
+ && CP_DECL_CONTEXT (other) != global_namespace)
+#else
+ && !DECL_FILE_SCOPE_P (other))
+#endif
{
- if (is_private (decl))
- return 0;
- else
- return build_ivar_reference (id);
+ warning (0, "local declaration of %qs hides instance variable",
+ IDENTIFIER_POINTER (id));
+
+ return other;
}
- else
+
+ /* At this point, we are either in an instance method with no obscuring
+ local definitions, or in a class method with no alternate definitions
+ at all. */
+ return build_ivar_reference (id);
+}
+
+/* Possibly rewrite a function CALL into an OBJ_TYPE_REF expression. This
+ needs to be done if we are calling a function through a cast. */
+
+tree
+objc_rewrite_function_call (tree function, tree params)
+{
+ if (TREE_CODE (function) == NOP_EXPR
+ && TREE_CODE (TREE_OPERAND (function, 0)) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (TREE_OPERAND (function, 0), 0))
+ == FUNCTION_DECL)
+ {
+ function = build (OBJ_TYPE_REF, TREE_TYPE (function),
+ TREE_OPERAND (function, 0),
+ TREE_VALUE (params), size_zero_node);
+ }
+
+ return function;
+}
+
+/* Look for the special case of OBJC_TYPE_REF with the address of
+ a function in OBJ_TYPE_REF_EXPR (presumably objc_msgSend or one
+ of its cousins). */
+
+enum gimplify_status objc_gimplify_expr (tree *expr_p, tree *pre_p,
+ tree *post_p)
+{
+ enum gimplify_status r0, r1;
+ if (TREE_CODE (*expr_p) == OBJ_TYPE_REF
+ && TREE_CODE (OBJ_TYPE_REF_EXPR (*expr_p)) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (OBJ_TYPE_REF_EXPR (*expr_p), 0))
+ == FUNCTION_DECL)
+ {
+ /* Postincrements in OBJ_TYPE_REF_OBJECT don't affect the
+ value of the OBJ_TYPE_REF, so force them to be emitted
+ during subexpression evaluation rather than after the
+ OBJ_TYPE_REF. This permits objc_msgSend calls in Objective
+ C to use direct rather than indirect calls when the
+ object expression has a postincrement. */
+ r0 = gimplify_expr (&OBJ_TYPE_REF_OBJECT (*expr_p), pre_p, NULL,
+ is_gimple_val, fb_rvalue);
+ r1 = gimplify_expr (&OBJ_TYPE_REF_EXPR (*expr_p), pre_p, post_p,
+ is_gimple_val, fb_rvalue);
+ return MIN (r0, r1);
+ }
+#ifdef OBJCPLUS
+ return cp_gimplify_expr (expr_p, pre_p, post_p);
+#else
+ return c_gimplify_expr (expr_p, pre_p, post_p);
+#endif
+}
+
+/* Given a CALL expression, find the function being called. The ObjC
+ version looks for the OBJ_TYPE_REF_EXPR which is used for objc_msgSend. */
+
+tree
+objc_get_callee_fndecl (tree call_expr)
+{
+ tree addr = TREE_OPERAND (call_expr, 0);
+ if (TREE_CODE (addr) != OBJ_TYPE_REF)
return 0;
+
+ addr = OBJ_TYPE_REF_EXPR (addr);
+
+ /* If the address is just `&f' for some function `f', then we know
+ that `f' is being called. */
+ if (TREE_CODE (addr) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (addr, 0)) == FUNCTION_DECL)
+ return TREE_OPERAND (addr, 0);
+
+ return 0;
}
#include "gt-objc-objc-act.h"