/* Implement classes and message passing for Objective C.
- Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
- 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
- Free Software Foundation, Inc.
+ Copyright (C) 1992-2015 Free Software Foundation, Inc.
Contributed by Steve Naroff.
This file is part of GCC.
#include "system.h"
#include "coretypes.h"
#include "tm.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "options.h"
+#include "wide-int.h"
+#include "inchash.h"
#include "tree.h"
+#include "fold-const.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "attribs.h"
#ifdef OBJCPLUS
-#include "cp-tree.h"
+#include "cp/cp-tree.h"
#else
-#include "c-tree.h"
-#include "c-lang.h"
+#include "c/c-tree.h"
+#include "c/c-lang.h"
#endif
#include "c-family/c-common.h"
#include "flags.h"
#include "langhooks.h"
#include "objc-act.h"
+#include "objc-map.h"
#include "input.h"
+#include "hard-reg-set.h"
#include "function.h"
-#include "output.h"
#include "toplev.h"
-#include "ggc.h"
#include "debug.h"
#include "c-family/c-target.h"
#include "diagnostic-core.h"
#include "intl.h"
+#include "hash-map.h"
+#include "is-a.h"
+#include "plugin-api.h"
+#include "ipa-ref.h"
#include "cgraph.h"
#include "tree-iterator.h"
-#include "hashtab.h"
+#include "hash-table.h"
+#include "wide-int.h"
#include "langhooks-def.h"
/* Different initialization, code gen and meta data generation for each
runtime. */
#include "tree-pretty-print.h"
/* For enum gimplify_status */
-#include "gimple.h"
+#include "gimple-expr.h"
+#include "gimplify.h"
+
+/* For encode_method_prototype(). */
+#include "objc-encoding.h"
static unsigned int should_call_super_dealloc = 0;
#define OBJC_FORWARDING_MIN_OFFSET 0
#endif
-/* Set up for use of obstacks. */
-
-#include "obstack.h"
-
-/* This obstack is used to accumulate the encoding of a data type. */
-struct obstack util_obstack;
-
-/* This points to the beginning of obstack contents, so we can free
- the whole contents. */
-char *util_firstobj;
-
/*** Private Interface (procedures) ***/
/* Init stuff. */
static void objc_gen_property_data (tree, tree);
static void objc_synthesize_getter (tree, tree, tree);
static void objc_synthesize_setter (tree, tree, tree);
-static char *objc_build_property_setter_name (tree);
static tree lookup_property (tree, tree);
static tree lookup_property_in_list (tree, tree);
static tree lookup_property_in_protocol_list (tree, tree);
static void objc_decl_method_attributes (tree*, tree, int);
static tree build_keyword_selector (tree);
-/* Hash tables to manage the global pool of method prototypes. */
static void hash_init (void);
-hash *nst_method_hash_list = 0;
-hash *cls_method_hash_list = 0;
+/* Hash tables to manage the global pool of method prototypes. Each
+ of these maps map a method name (selector) identifier to either a
+ single tree (for methods with a single method prototype) or a
+ TREE_VEC (for methods with multiple method prototypes). */
+static GTY(()) objc_map_t instance_method_map = 0;
+static GTY(()) objc_map_t class_method_map = 0;
/* Hash tables to manage the global pool of class names. */
-hash *cls_name_hash_list = 0;
-hash *als_name_hash_list = 0;
-
-hash *ivar_offset_hash_list = 0;
-
-static void hash_class_name_enter (hash *, tree, tree);
-static hash hash_class_name_lookup (hash *, tree);
+static GTY(()) objc_map_t class_name_map = 0;
+static GTY(()) objc_map_t alias_name_map = 0;
-static hash hash_lookup (hash *, tree);
static tree lookup_method (tree, tree);
static tree lookup_method_static (tree, tree, int);
-static tree add_class (tree, tree);
+static void interface_hash_init (void);
+static tree add_interface (tree, tree);
static void add_category (tree, tree);
static inline tree lookup_category (tree, tree);
static tree lookup_protocol (tree, bool, bool);
static tree lookup_and_install_protocols (tree, bool);
-/* Type encoding. */
-
-static void encode_type_qualifiers (tree);
-static void encode_type (tree, int, int);
-
#ifdef OBJCPLUS
static void really_start_method (tree, tree);
#else
static void mark_referenced_methods (void);
static bool objc_type_valid_for_messaging (tree type, bool allow_classes);
-static tree check_duplicates (hash, int, int);
+static tree check_duplicates (tree, int, int);
/*** Private Interface (data) ***/
/* Flags for lookup_method_static(). */
int imp_count = 0; /* `@implementation' */
int cat_count = 0; /* `@category' */
-objc_ivar_visibility_kind objc_ivar_visibility;
+objc_ivar_visibility_kind objc_ivar_visibility, objc_default_ivar_visibility;
/* Use to generate method labels. */
static int method_slot = 0;
/* An array of all the local variables in the current function that
need to be marked as volatile. */
-VEC(tree,gc) *local_variables_to_volatilize = NULL;
+vec<tree, va_gc> *local_variables_to_volatilize = NULL;
/* Store all constructed constant strings in a hash table so that
they get uniqued properly. */
-struct GTY(()) string_descriptor {
+struct GTY((for_user)) string_descriptor {
/* The literal argument . */
tree literal;
tree constructor;
};
-static GTY((param_is (struct string_descriptor))) htab_t string_htab;
-
-FILE *gen_declaration_file;
+struct objc_string_hasher : ggc_hasher<string_descriptor *>
+{
+ static hashval_t hash (string_descriptor *);
+ static bool equal (string_descriptor *, string_descriptor *);
+};
-/* Tells "encode_pointer/encode_aggregate" whether we are generating
- type descriptors for instance variables (as opposed to methods).
- Type descriptors for instance variables contain more information
- than methods (for static typing and embedded structures). */
+static GTY(()) hash_table<objc_string_hasher> *string_htab;
-int generating_instance_variables = 0;
+FILE *gen_declaration_file;
/* Hooks for stuff that differs between runtimes. */
objc_runtime_hooks runtime;
/* Set up stuff used by FE parser and all runtimes. */
errbuf = XNEWVEC (char, 1024 * 10);
+ interface_hash_init ();
hash_init ();
- gcc_obstack_init (&util_obstack);
- util_firstobj = (char *) obstack_finish (&util_obstack);
-
+ objc_encoding_init ();
/* ... and then check flags and set-up for the selected runtime ... */
if (flag_next_runtime && flag_objc_abi >= 2)
ok = objc_next_runtime_abi_02_init (&runtime);
if (!ok)
return false;
+ /* Determine the default visibility for instance variables. */
+ switch (default_ivar_visibility)
+ {
+ case IVAR_VISIBILITY_PRIVATE:
+ objc_default_ivar_visibility = OBJC_IVAR_VIS_PRIVATE;
+ break;
+ case IVAR_VISIBILITY_PUBLIC:
+ objc_default_ivar_visibility = OBJC_IVAR_VIS_PUBLIC;
+ break;
+ case IVAR_VISIBILITY_PACKAGE:
+ objc_default_ivar_visibility = OBJC_IVAR_VIS_PACKAGE;
+ break;
+ default:
+ objc_default_ivar_visibility = OBJC_IVAR_VIS_PROTECTED;
+ }
+
/* Generate general types and push runtime-specific decls to file scope. */
synth_module_prologue ();
if (warn_selector)
{
- int slot;
- hash hsh;
+ objc_map_iterator_t i;
- /* Run through the selector hash tables and print a warning for any
- selector which has multiple methods. */
+ objc_map_iterator_initialize (class_method_map, &i);
+ while (objc_map_iterator_move_to_next (class_method_map, &i))
+ check_duplicates (objc_map_iterator_current_value (class_method_map, i), 0, 1);
- for (slot = 0; slot < SIZEHASHTABLE; slot++)
- {
- for (hsh = cls_method_hash_list[slot]; hsh; hsh = hsh->next)
- check_duplicates (hsh, 0, 1);
- for (hsh = nst_method_hash_list[slot]; hsh; hsh = hsh->next)
- check_duplicates (hsh, 0, 0);
- }
+ objc_map_iterator_initialize (instance_method_map, &i);
+ while (objc_map_iterator_move_to_next (instance_method_map, &i))
+ check_duplicates (objc_map_iterator_current_value (instance_method_map, i), 0, 0);
}
/* TODO: consider an early exit here if either errorcount or sorrycount
objc_interface_context
= objc_ivar_context
= start_class (CLASS_INTERFACE_TYPE, klass, super_class, protos, attributes);
- objc_ivar_visibility = OBJC_IVAR_VIS_PROTECTED;
+ objc_ivar_visibility = objc_default_ivar_visibility;
}
void
= objc_ivar_context
= start_class (CLASS_IMPLEMENTATION_TYPE, klass, super_class, NULL_TREE,
NULL_TREE);
- objc_ivar_visibility = OBJC_IVAR_VIS_PROTECTED;
+ objc_ivar_visibility = objc_default_ivar_visibility;
}
void
object.component dot-syntax without a declared
property (this is valid for classes too). Look
for getter/setter methods and internally declare
- an artifical property based on them if found. */
+ an artificial property based on them if found. */
x = maybe_make_artificial_property_decl (NULL_TREE,
NULL_TREE,
rprotos,
tree s = objc_start_struct (name);
tree super = (super_name ? xref_tag (RECORD_TYPE, super_name) : NULL_TREE);
tree t;
- VEC(tree,heap) *objc_info = NULL;
+ vec<tree> objc_info = vNULL;
int i;
if (super)
for (t = TYPE_MAIN_VARIANT (s); t; t = TYPE_NEXT_VARIANT (t))
{
INIT_TYPE_OBJC_INFO (t);
- VEC_safe_push (tree, heap, objc_info, TYPE_OBJC_INFO (t));
+ objc_info.safe_push (TYPE_OBJC_INFO (t));
}
s = objc_finish_struct (s, fields);
/* Replace TYPE_OBJC_INFO with the saved one. This restores any
protocol information that may have been associated with the
type. */
- TYPE_OBJC_INFO (t) = VEC_index (tree, objc_info, i);
+ TYPE_OBJC_INFO (t) = objc_info[i];
/* Replace the IDENTIFIER_NODE with an actual @interface now
that we have it. */
TYPE_OBJC_INTERFACE (t) = klass;
}
- VEC_free (tree, heap, objc_info);
+ objc_info.release ();
/* Use TYPE_BINFO structures to point at the super class, if any. */
objc_xref_basetypes (s, super);
|| TREE_CODE (decl) == PARM_DECL))
{
if (local_variables_to_volatilize == NULL)
- local_variables_to_volatilize = VEC_alloc (tree, gc, 8);
+ vec_alloc (local_variables_to_volatilize, 8);
- VEC_safe_push (tree, gc, local_variables_to_volatilize, decl);
+ vec_safe_push (local_variables_to_volatilize, decl);
}
}
{
int i;
tree decl;
- FOR_EACH_VEC_ELT (tree, local_variables_to_volatilize, i, decl)
+ FOR_EACH_VEC_ELT (*local_variables_to_volatilize, i, decl)
{
tree t = TREE_TYPE (decl);
}
/* Now we delete the vector. This sets it to NULL as well. */
- VEC_free (tree, gc, local_variables_to_volatilize);
+ vec_free (local_variables_to_volatilize);
}
}
static void
objc_xref_basetypes (tree ref, tree basetype)
{
+ tree variant;
tree binfo = make_tree_binfo (basetype ? 1 : 0);
-
TYPE_BINFO (ref) = binfo;
BINFO_OFFSET (binfo) = size_zero_node;
BINFO_TYPE (binfo) = ref;
+ gcc_assert (TYPE_MAIN_VARIANT (ref) == ref);
+ for (variant = ref; variant; variant = TYPE_NEXT_VARIANT (variant))
+ TYPE_BINFO (variant) = binfo;
+
if (basetype)
{
tree base_binfo = objc_copy_binfo (TYPE_BINFO (basetype));
BINFO_INHERITANCE_CHAIN (base_binfo) = binfo;
- BINFO_BASE_ACCESSES (binfo) = VEC_alloc (tree, gc, 1);
+ vec_alloc (BINFO_BASE_ACCESSES (binfo), 1);
BINFO_BASE_APPEND (binfo, base_binfo);
BINFO_BASE_ACCESS_APPEND (binfo, access_public_node);
}
return build1 (ADDR_EXPR, ptrtype, string);
}
-static hashval_t
-string_hash (const void *ptr)
+hashval_t
+objc_string_hasher::hash (string_descriptor *ptr)
{
- const_tree const str = ((const struct string_descriptor *)ptr)->literal;
+ const_tree const str = ptr->literal;
const unsigned char *p = (const unsigned char *) TREE_STRING_POINTER (str);
int i, len = TREE_STRING_LENGTH (str);
hashval_t h = len;
return h;
}
-static int
-string_eq (const void *ptr1, const void *ptr2)
+bool
+objc_string_hasher::equal (string_descriptor *ptr1, string_descriptor *ptr2)
{
- const_tree const str1 = ((const struct string_descriptor *)ptr1)->literal;
- const_tree const str2 = ((const struct string_descriptor *)ptr2)->literal;
+ const_tree const str1 = ptr1->literal;
+ const_tree const str2 = ptr2->literal;
int len1 = TREE_STRING_LENGTH (str1);
return (len1 == TREE_STRING_LENGTH (str2)
int length;
tree addr;
struct string_descriptor *desc, key;
- void **loc;
- /* Prep the string argument. */
- string = fix_string_type (string);
- TREE_SET_CODE (string, STRING_CST);
+ /* We should be passed a STRING_CST. */
+ gcc_checking_assert (TREE_CODE (string) == STRING_CST);
length = TREE_STRING_LENGTH (string) - 1;
/* The target may have different ideas on how to construct an ObjC string
/* Perhaps we already constructed a constant string just like this one? */
key.literal = string;
- loc = htab_find_slot (string_htab, &key, INSERT);
- desc = (struct string_descriptor *) *loc;
+ string_descriptor **loc = string_htab->find_slot (&key, INSERT);
+ desc = *loc;
if (!desc)
{
- *loc = desc = ggc_alloc_string_descriptor ();
+ *loc = desc = ggc_alloc<string_descriptor> ();
desc->literal = string;
desc->constructor =
(*runtime.build_const_string_constructor) (input_location, string, length);
with type TYPE and elements ELTS. */
tree
-objc_build_constructor (tree type, VEC(constructor_elt,gc) *elts)
+objc_build_constructor (tree type, vec<constructor_elt, va_gc> *elts)
{
tree constructor = build_constructor (type, elts);
#ifdef OBJCPLUS
/* Adjust for impedance mismatch. We should figure out how to build
CONSTRUCTORs that consistently please both the C and C++ gods. */
- if (!VEC_index (constructor_elt, elts, 0)->index)
+ if (!(*elts)[0].index)
TREE_TYPE (constructor) = init_list_type_node;
#endif
#ifdef OBJCPLUS
if (processing_template_decl)
/* Must wait until template instantiation time. */
- return build_min_nt (CLASS_REFERENCE_EXPR, ident);
+ return build_min_nt_loc (UNKNOWN_LOCATION, CLASS_REFERENCE_EXPR, ident);
#endif
if (TREE_CODE (ident) == TYPE_DECL)
#ifdef OBJCPLUS
pop_lang_context ();
#endif
- hash_class_name_enter (als_name_hash_list, alias_ident,
- underlying_class);
+ objc_map_put (alias_name_map, alias_ident, underlying_class);
}
}
the TYPE_OBJC_INTERFACE. If later an @interface is found,
we'll replace the ident with the interface. */
TYPE_OBJC_INTERFACE (record) = identifier;
- hash_class_name_enter (cls_name_hash_list, identifier, NULL_TREE);
+ objc_map_put (class_name_map, identifier, NULL_TREE);
}
}
tree
objc_is_class_name (tree ident)
{
- hash target;
-
if (ident && TREE_CODE (ident) == IDENTIFIER_NODE)
{
tree t = identifier_global_value (ident);
if (lookup_interface (ident))
return ident;
- target = hash_class_name_lookup (cls_name_hash_list, ident);
- if (target)
- return target->key;
+ {
+ tree target;
- target = hash_class_name_lookup (als_name_hash_list, ident);
- if (target)
- {
- gcc_assert (target->list && target->list->value);
- return target->list->value;
- }
+ target = objc_map_get (class_name_map, ident);
+ if (target != OBJC_MAP_NOT_FOUND)
+ return ident;
+
+ target = objc_map_get (alias_name_map, ident);
+ if (target != OBJC_MAP_NOT_FOUND)
+ return target;
+ }
return 0;
}
tree_cons (NULL_TREE, offs,
NULL_TREE)));
- assemble_external (func);
return build_function_call (input_location, func, func_params);
}
build_unary_op (input_location, ADDR_EXPR, lhs, 0)),
NULL_TREE));
- assemble_external (objc_assign_global_decl);
return build_function_call (input_location,
objc_assign_global_decl, func_params);
}
build_unary_op (input_location, ADDR_EXPR, lhs, 0)),
NULL_TREE));
- assemble_external (objc_assign_strong_cast_decl);
return build_function_call (input_location,
objc_assign_strong_cast_decl, func_params);
}
return result;
}
-struct GTY(()) interface_tuple {
- tree id;
- tree class_name;
-};
+/* Implementation of the table mapping a class name (as an identifier)
+ to a class node. The two public functions for it are
+ lookup_interface() and add_interface(). add_interface() is only
+ used in this file, so we can make it static. */
-static GTY ((param_is (struct interface_tuple))) htab_t interface_htab;
+static GTY(()) objc_map_t interface_map;
-static hashval_t
-hash_interface (const void *p)
+static void
+interface_hash_init (void)
{
- const struct interface_tuple *d = (const struct interface_tuple *) p;
- return IDENTIFIER_HASH_VALUE (d->id);
+ interface_map = objc_map_alloc_ggc (200);
}
-static int
-eq_interface (const void *p1, const void *p2)
+static tree
+add_interface (tree class_name, tree name)
{
- const struct interface_tuple *d = (const struct interface_tuple *) p1;
- return d->id == p2;
+ /* Put interfaces on list in reverse order. */
+ TREE_CHAIN (class_name) = interface_chain;
+ interface_chain = class_name;
+
+ /* Add it to the map. */
+ objc_map_put (interface_map, name, class_name);
+
+ return interface_chain;
}
tree
return NULL_TREE;
{
- struct interface_tuple **slot;
- tree i = NULL_TREE;
+ tree interface = objc_map_get (interface_map, ident);
- if (interface_htab)
- {
- slot = (struct interface_tuple **)
- htab_find_slot_with_hash (interface_htab, ident,
- IDENTIFIER_HASH_VALUE (ident),
- NO_INSERT);
- if (slot && *slot)
- i = (*slot)->class_name;
- }
- return i;
+ if (interface == OBJC_MAP_NOT_FOUND)
+ return NULL_TREE;
+ else
+ return interface;
}
}
allows us to store keys in the hashtable, without values (it looks
more like a set). So, we store the DECLs, but define equality as
DECLs having the same name, and hash as the hash of the name. */
-static hashval_t
-hash_instance_variable (const PTR p)
+
+struct decl_name_hash : typed_noop_remove <tree_node>
+{
+ typedef tree_node value_type;
+ typedef tree_node compare_type;
+ static inline hashval_t hash (const value_type *);
+ static inline bool equal (const value_type *, const compare_type *);
+};
+
+inline hashval_t
+decl_name_hash::hash (const value_type *q)
{
- const_tree q = (const_tree)p;
return (hashval_t) ((intptr_t)(DECL_NAME (q)) >> 3);
}
-static int
-eq_instance_variable (const PTR p1, const PTR p2)
+inline bool
+decl_name_hash::equal (const value_type *a, const compare_type *b)
{
- const_tree a = (const_tree)p1;
- const_tree b = (const_tree)p2;
return DECL_NAME (a) == DECL_NAME (b);
}
{
/* First, build the hashtable by putting all the instance
variables of superclasses in it. */
- htab_t htab = htab_create (37, hash_instance_variable,
- eq_instance_variable, NULL);
+ hash_table<decl_name_hash> htab (37);
tree interface;
for (interface = lookup_interface (CLASS_SUPER_NAME
(objc_interface_context));
{
if (DECL_NAME (ivar) != NULL_TREE)
{
- void **slot = htab_find_slot (htab, ivar, INSERT);
+ tree_node **slot = htab.find_slot (ivar, INSERT);
/* Do not check for duplicate instance
variables in superclasses. Errors have
already been generated. */
{
if (DECL_NAME (ivar) != NULL_TREE)
{
- tree duplicate_ivar = (tree)(htab_find (htab, ivar));
+ tree duplicate_ivar = htab.find (ivar);
if (duplicate_ivar != HTAB_EMPTY_ENTRY)
{
error_at (DECL_SOURCE_LOCATION (ivar),
{
if (DECL_NAME (ivar) != NULL_TREE)
{
- void **slot = htab_find_slot (htab, ivar, INSERT);
+ tree_node **slot = htab.find_slot (ivar, INSERT);
if (*slot)
{
tree duplicate_ivar = (tree)(*slot);
}
}
}
- htab_delete (htab);
return true;
}
}
}
}
-/* Begin code generation for protocols... */
-
-static tree
-objc_method_parm_type (tree type)
-{
- type = TREE_VALUE (TREE_TYPE (type));
- if (TREE_CODE (type) == TYPE_DECL)
- type = TREE_TYPE (type);
- return type;
-}
-
-static int
-objc_encoded_type_size (tree type)
-{
- int sz = int_size_in_bytes (type);
-
- /* Make all integer and enum types at least as large
- as an int. */
- if (sz > 0 && INTEGRAL_TYPE_P (type))
- sz = MAX (sz, int_size_in_bytes (integer_type_node));
- /* Treat arrays as pointers, since that's how they're
- passed in. */
- else if (TREE_CODE (type) == ARRAY_TYPE)
- sz = int_size_in_bytes (ptr_type_node);
- return sz;
-}
-
-/* Encode a method prototype.
-
- The format is described in gcc/doc/objc.texi, section 'Method
- signatures'.
- */
-
-tree
-encode_method_prototype (tree method_decl)
-{
- tree parms;
- int parm_offset, i;
- char buf[40];
- tree result;
-
- /* ONEWAY and BYCOPY, for remote object are the only method qualifiers. */
- encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (method_decl)));
-
- /* Encode return type. */
- encode_type (objc_method_parm_type (method_decl),
- obstack_object_size (&util_obstack),
- OBJC_ENCODE_INLINE_DEFS);
-
- /* Stack size. */
- /* The first two arguments (self and _cmd) are pointers; account for
- their size. */
- i = int_size_in_bytes (ptr_type_node);
- parm_offset = 2 * i;
- for (parms = METHOD_SEL_ARGS (method_decl); parms;
- parms = DECL_CHAIN (parms))
- {
- tree type = objc_method_parm_type (parms);
- int sz = objc_encoded_type_size (type);
-
- /* If a type size is not known, bail out. */
- if (sz < 0)
- {
- error_at (DECL_SOURCE_LOCATION (method_decl),
- "type %qT does not have a known size",
- type);
- /* Pretend that the encoding succeeded; the compilation will
- fail nevertheless. */
- goto finish_encoding;
- }
- parm_offset += sz;
- }
-
- sprintf (buf, "%d@0:%d", parm_offset, i);
- obstack_grow (&util_obstack, buf, strlen (buf));
-
- /* Argument types. */
- parm_offset = 2 * i;
- for (parms = METHOD_SEL_ARGS (method_decl); parms;
- parms = DECL_CHAIN (parms))
- {
- tree type = objc_method_parm_type (parms);
-
- /* Process argument qualifiers for user supplied arguments. */
- encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (parms)));
-
- /* Type. */
- encode_type (type, obstack_object_size (&util_obstack),
- OBJC_ENCODE_INLINE_DEFS);
-
- /* Compute offset. */
- sprintf (buf, "%d", parm_offset);
- parm_offset += objc_encoded_type_size (type);
-
- obstack_grow (&util_obstack, buf, strlen (buf));
- }
-
- finish_encoding:
- obstack_1grow (&util_obstack, '\0');
- result = get_identifier (XOBFINISH (&util_obstack, char *));
- obstack_free (&util_obstack, util_firstobj);
- return result;
-}
-
/* Generate either '- .cxx_construct' or '- .cxx_destruct' for the
current class. */
#ifdef OBJCPLUS
chain = CLASS_CLS_METHODS (impent->imp_context);
while (chain)
{
- cgraph_mark_needed_node (
- cgraph_get_create_node (METHOD_DEFINITION (chain)));
+ cgraph_node::get_create (METHOD_DEFINITION (chain))->mark_force_output ();
chain = DECL_CHAIN (chain);
}
chain = CLASS_NST_METHODS (impent->imp_context);
while (chain)
{
- cgraph_mark_needed_node (
- cgraph_get_create_node (METHOD_DEFINITION (chain)));
+ cgraph_node::get_create (METHOD_DEFINITION (chain))->mark_force_output ();
chain = DECL_CHAIN (chain);
}
}
number = TREE_VALUE (second_argument);
if (number
&& TREE_CODE (number) == INTEGER_CST
- && TREE_INT_CST_HIGH (number) == 0)
- {
- TREE_VALUE (second_argument)
- = build_int_cst (integer_type_node,
- TREE_INT_CST_LOW (number) + 2);
- }
+ && !wi::eq_p (number, 0))
+ TREE_VALUE (second_argument)
+ = wide_int_to_tree (TREE_TYPE (number),
+ wi::add (number, 2));
/* This is the third argument, the "first-to-check",
which specifies the index of the first argument to
number = TREE_VALUE (third_argument);
if (number
&& TREE_CODE (number) == INTEGER_CST
- && TREE_INT_CST_HIGH (number) == 0
- && TREE_INT_CST_LOW (number) != 0)
- {
- TREE_VALUE (third_argument)
- = build_int_cst (integer_type_node,
- TREE_INT_CST_LOW (number) + 2);
- }
+ && !wi::eq_p (number, 0))
+ TREE_VALUE (third_argument)
+ = wide_int_to_tree (TREE_TYPE (number),
+ wi::add (number, 2));
}
filtered_attributes = chainon (filtered_attributes,
new_attribute);
{
/* Get the value of the argument and add 2. */
tree number = TREE_VALUE (argument);
- if (number
- && TREE_CODE (number) == INTEGER_CST
- && TREE_INT_CST_HIGH (number) == 0
- && TREE_INT_CST_LOW (number) != 0)
- {
- TREE_VALUE (argument)
- = build_int_cst (integer_type_node,
- TREE_INT_CST_LOW (number) + 2);
- }
+ if (number && TREE_CODE (number) == INTEGER_CST
+ && !wi::eq_p (number, 0))
+ TREE_VALUE (argument)
+ = wide_int_to_tree (TREE_TYPE (number),
+ wi::add (number, 2));
argument = TREE_CHAIN (argument);
}
build_function_type_for_method (tree return_type, tree method,
int context, bool super_flag)
{
- VEC(tree,gc) *argtypes = make_tree_vector ();
+ vec<tree, va_gc> *argtypes = make_tree_vector ();
tree t, ftype;
bool is_varargs = false;
appropriate. */
arg_type = objc_decay_parm_type (arg_type);
- VEC_safe_push (tree, gc, argtypes, arg_type);
+ vec_safe_push (argtypes, arg_type);
}
if (METHOD_ADD_ARGS (method))
arg_type = objc_decay_parm_type (arg_type);
- VEC_safe_push (tree, gc, argtypes, arg_type);
+ vec_safe_push (argtypes, arg_type);
}
if (METHOD_ADD_ARGS_ELLIPSIS_P (method))
return ftype;
}
+/* The 'method' argument is a tree; this tree could either be a single
+ method, which is returned, or could be a TREE_VEC containing a list
+ of methods. In that case, the first one is returned, and warnings
+ are issued as appropriate. */
static tree
-check_duplicates (hash hsh, int methods, int is_class)
+check_duplicates (tree method, int methods, int is_class)
{
- tree meth = NULL_TREE;
-
- if (hsh)
- {
- meth = hsh->key;
-
- if (hsh->list)
- {
- /* We have two or more methods with the same name but
- different types. */
- attr loop;
-
- /* 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;
- }
+ tree first_method;
+ size_t i;
- issue_warning:
- if (methods)
- {
- bool type = TREE_CODE (meth) == INSTANCE_METHOD_DECL;
-
- warning_at (input_location, 0,
- "multiple methods named %<%c%E%> found",
- (is_class ? '+' : '-'),
- METHOD_SEL_NAME (meth));
- inform (DECL_SOURCE_LOCATION (meth), "using %<%c%s%>",
- (type ? '-' : '+'),
- identifier_to_locale (gen_method_decl (meth)));
- }
- else
- {
- bool type = TREE_CODE (meth) == INSTANCE_METHOD_DECL;
-
- warning_at (input_location, 0,
- "multiple selectors named %<%c%E%> found",
- (is_class ? '+' : '-'),
- METHOD_SEL_NAME (meth));
- inform (DECL_SOURCE_LOCATION (meth), "found %<%c%s%>",
- (type ? '-' : '+'),
- identifier_to_locale (gen_method_decl (meth)));
- }
-
- for (loop = hsh->list; loop; loop = loop->next)
- {
- bool type = TREE_CODE (loop->value) == INSTANCE_METHOD_DECL;
+ if (method == NULL_TREE)
+ return NULL_TREE;
- inform (DECL_SOURCE_LOCATION (loop->value), "also found %<%c%s%>",
- (type ? '-' : '+'),
- identifier_to_locale (gen_method_decl (loop->value)));
- }
- }
+ if (TREE_CODE (method) != TREE_VEC)
+ return method;
+
+ /* We have two or more methods with the same name but different
+ types. */
+ first_method = TREE_VEC_ELT (method, 0);
+
+ /* 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 (i = 0; i < (size_t) TREE_VEC_LENGTH (method); i++)
+ if (!comp_proto_with_proto (first_method, TREE_VEC_ELT (method, i), 0))
+ goto issue_warning;
+
+ return first_method;
+ }
+
+ issue_warning:
+ if (methods)
+ {
+ bool type = TREE_CODE (first_method) == INSTANCE_METHOD_DECL;
+
+ warning_at (input_location, 0,
+ "multiple methods named %<%c%E%> found",
+ (is_class ? '+' : '-'),
+ METHOD_SEL_NAME (first_method));
+ inform (DECL_SOURCE_LOCATION (first_method), "using %<%c%s%>",
+ (type ? '-' : '+'),
+ identifier_to_locale (gen_method_decl (first_method)));
}
- return meth;
+ else
+ {
+ bool type = TREE_CODE (first_method) == INSTANCE_METHOD_DECL;
+
+ warning_at (input_location, 0,
+ "multiple selectors named %<%c%E%> found",
+ (is_class ? '+' : '-'),
+ METHOD_SEL_NAME (first_method));
+ inform (DECL_SOURCE_LOCATION (first_method), "found %<%c%s%>",
+ (type ? '-' : '+'),
+ identifier_to_locale (gen_method_decl (first_method)));
+ }
+
+ for (i = 0; i < (size_t) TREE_VEC_LENGTH (method); i++)
+ {
+ bool type = TREE_CODE (TREE_VEC_ELT (method, i)) == INSTANCE_METHOD_DECL;
+
+ inform (DECL_SOURCE_LOCATION (TREE_VEC_ELT (method, i)), "also found %<%c%s%>",
+ (type ? '-' : '+'),
+ identifier_to_locale (gen_method_decl (TREE_VEC_ELT (method, i))));
+ }
+
+ return first_method;
}
/* If RECEIVER is a class reference, return the identifier node for
#ifdef OBJCPLUS
if (processing_template_decl)
/* Must wait until template instantiation time. */
- return build_min_nt (MESSAGE_SEND_EXPR, receiver, sel_name,
- method_params);
+ return build_min_nt_loc (UNKNOWN_LOCATION, MESSAGE_SEND_EXPR, receiver,
+ sel_name, method_params);
#endif
return objc_finish_message_expr (receiver, sel_name, method_params, NULL);
static tree
lookup_method_in_hash_lists (tree sel_name, int is_class)
{
- hash method_prototype = NULL;
+ tree method_prototype = OBJC_MAP_NOT_FOUND;
if (!is_class)
- method_prototype = hash_lookup (nst_method_hash_list,
- sel_name);
-
- if (!method_prototype)
+ method_prototype = objc_map_get (instance_method_map, sel_name);
+
+ if (method_prototype == OBJC_MAP_NOT_FOUND)
{
- method_prototype = hash_lookup (cls_method_hash_list,
- sel_name);
+ method_prototype = objc_map_get (class_method_map, sel_name);
is_class = 1;
+
+ if (method_prototype == OBJC_MAP_NOT_FOUND)
+ return NULL_TREE;
}
return check_duplicates (method_prototype, 1, is_class);
/* Look the selector up in the list of all known class and
instance methods (up to this line) to check that the selector
exists. */
- hash hsh;
+ tree method;
/* First try with instance methods. */
- hsh = hash_lookup (nst_method_hash_list, selname);
+ method = objc_map_get (instance_method_map, selname);
/* If not found, try with class methods. */
- if (!hsh)
+ if (method == OBJC_MAP_NOT_FOUND)
{
- hsh = hash_lookup (cls_method_hash_list, selname);
- }
+ method = objc_map_get (class_method_map, selname);
- /* If still not found, print out a warning. */
- if (!hsh)
- {
- warning (0, "undeclared selector %qE", selname);
+ /* If still not found, print out a warning. */
+ if (method == OBJC_MAP_NOT_FOUND)
+ warning (0, "undeclared selector %qE", selname);
}
}
return (*runtime.build_selector_reference) (loc, selname, NULL_TREE);
}
-/* This is used to implement @encode(). See gcc/doc/objc.texi,
- section '@encode'. */
-tree
-objc_build_encode_expr (tree type)
-{
- tree result;
- const char *string;
-
- encode_type (type, obstack_object_size (&util_obstack),
- OBJC_ENCODE_INLINE_DEFS);
- obstack_1grow (&util_obstack, 0); /* null terminate string */
- string = XOBFINISH (&util_obstack, const char *);
-
- /* Synthesize a string that represents the encoded struct/union. */
- result = my_build_string (strlen (string) + 1, string);
- obstack_free (&util_obstack, util_firstobj);
- return result;
-}
-
static tree
build_ivar_reference (tree id)
{
return (*runtime.build_ivar_reference) (input_location, base, id);
}
-/* Compute a hash value for a given method SEL_NAME. */
-
-static size_t
-hash_func (tree sel_name)
-{
- const unsigned char *s
- = (const unsigned char *)IDENTIFIER_POINTER (sel_name);
- size_t h = 0;
-
- while (*s)
- h = h * 67 + *s++ - 113;
- return h;
-}
-
static void
hash_init (void)
{
- nst_method_hash_list = ggc_alloc_cleared_vec_hash (SIZEHASHTABLE);
- cls_method_hash_list = ggc_alloc_cleared_vec_hash (SIZEHASHTABLE);
+ instance_method_map = objc_map_alloc_ggc (1000);
+ class_method_map = objc_map_alloc_ggc (1000);
- cls_name_hash_list = ggc_alloc_cleared_vec_hash (SIZEHASHTABLE);
- als_name_hash_list = ggc_alloc_cleared_vec_hash (SIZEHASHTABLE);
-
- ivar_offset_hash_list = ggc_alloc_cleared_vec_hash (SIZEHASHTABLE);
+ class_name_map = objc_map_alloc_ggc (200);
+ alias_name_map = objc_map_alloc_ggc (200);
/* Initialize the hash table used to hold the constant string objects. */
- string_htab = htab_create_ggc (31, string_hash,
- string_eq, NULL);
+ string_htab = hash_table<objc_string_hasher>::create_ggc (31);
}
-/* This routine adds sel_name to the hash list. sel_name is a class or alias
- name for the class. If alias name, then value is its underlying class.
- If class, the value is NULL_TREE. */
-
+/* Use the following to add a method to class_method_map or
+ instance_method_map. It will add the method, keyed by the
+ METHOD_SEL_NAME. If the method already exists, but with one or
+ more different prototypes, it will store a TREE_VEC in the map,
+ with the method prototypes in the vector. */
static void
-hash_class_name_enter (hash *hashlist, tree sel_name, tree value)
+insert_method_into_method_map (bool class_method, tree method)
{
- hash obj;
- int slot = hash_func (sel_name) % SIZEHASHTABLE;
+ tree method_name = METHOD_SEL_NAME (method);
+ tree existing_entry;
+ objc_map_t map;
- obj = ggc_alloc_hashed_entry ();
- if (value != NULL_TREE)
- {
- /* Save the underlying class for the 'alias' in the hash table */
- attr obj_attr = ggc_alloc_hashed_attribute ();
- obj_attr->value = value;
- obj->list = obj_attr;
- }
+ if (class_method)
+ map = class_method_map;
else
- obj->list = 0;
- obj->next = hashlist[slot];
- obj->key = sel_name;
-
- hashlist[slot] = obj; /* append to front */
-
-}
-
-/*
- Searches in the hash table looking for a match for class or alias name.
-*/
+ map = instance_method_map;
-static hash
-hash_class_name_lookup (hash *hashlist, tree sel_name)
-{
- hash target;
-
- target = hashlist[hash_func (sel_name) % SIZEHASHTABLE];
+ /* Check if the method already exists in the map. */
+ existing_entry = objc_map_get (map, method_name);
- while (target)
+ /* If not, we simply add it to the map. */
+ if (existing_entry == OBJC_MAP_NOT_FOUND)
+ objc_map_put (map, method_name, method);
+ else
{
- if (sel_name == target->key)
- return target;
-
- target = target->next;
- }
- return 0;
-}
-
-/* WARNING!!!! hash_enter is called with a method, and will peek
- inside to find its selector! But hash_lookup is given a selector
- directly, and looks for the selector that's inside the found
- entry's key (method) for comparison. */
-
-static void
-hash_enter (hash *hashlist, tree method)
-{
- hash obj;
- int slot = hash_func (METHOD_SEL_NAME (method)) % SIZEHASHTABLE;
-
- obj = ggc_alloc_hashed_entry ();
- obj->list = 0;
- obj->next = hashlist[slot];
- obj->key = method;
-
- hashlist[slot] = obj; /* append to front */
-}
-
-static hash
-hash_lookup (hash *hashlist, tree sel_name)
-{
- hash target;
+ tree new_entry;
+
+ /* If an entry already exists, it's more complicated. We'll
+ have to check whether the method prototype is the same or
+ not. */
+ if (TREE_CODE (existing_entry) != TREE_VEC)
+ {
+ /* If the method prototypes are the same, there is nothing
+ to do. */
+ if (comp_proto_with_proto (method, existing_entry, 1))
+ return;
- target = hashlist[hash_func (sel_name) % SIZEHASHTABLE];
+ /* If not, create a vector to store both the method already
+ in the map, and the new one that we are adding. */
+ new_entry = make_tree_vec (2);
+
+ TREE_VEC_ELT (new_entry, 0) = existing_entry;
+ TREE_VEC_ELT (new_entry, 1) = method;
+ }
+ else
+ {
+ /* An entry already exists, and it's already a vector. This
+ means that at least 2 different method prototypes were
+ already found, and we're considering registering yet
+ another one. */
+ size_t i;
+
+ /* Check all the existing prototypes. If any matches the
+ one we need to add, there is nothing to do because it's
+ already there. */
+ for (i = 0; i < (size_t) TREE_VEC_LENGTH (existing_entry); i++)
+ if (comp_proto_with_proto (method, TREE_VEC_ELT (existing_entry, i), 1))
+ return;
- while (target)
- {
- if (sel_name == METHOD_SEL_NAME (target->key))
- return target;
+ /* Else, create a new, bigger vector and add the new method
+ at the end of it. This is inefficient but extremely
+ rare; in any sane program most methods have a single
+ prototype, and very few, if any, will have more than
+ 2! */
+ new_entry = make_tree_vec (TREE_VEC_LENGTH (existing_entry) + 1);
+
+ /* Copy the methods from the existing vector. */
+ for (i = 0; i < (size_t) TREE_VEC_LENGTH (existing_entry); i++)
+ TREE_VEC_ELT (new_entry, i) = TREE_VEC_ELT (existing_entry, i);
+
+ /* Add the new method at the end. */
+ TREE_VEC_ELT (new_entry, i) = method;
+ }
- target = target->next;
+ /* Store the new vector in the map. */
+ objc_map_put (map, method_name, new_entry);
}
- return 0;
}
-static void
-hash_add_attr (hash entry, tree value)
-{
- attr obj;
-
- obj = ggc_alloc_hashed_attribute ();
- obj->next = entry->list;
- obj->value = value;
-
- entry->list = obj; /* append to front */
-}
\f
static tree
lookup_method (tree mchain, tree method)
}
}
-/* Add the method to the hash list if it doesn't contain an identical
- method already. */
-
-static void
-add_method_to_hash_list (hash *hash_list, tree method)
-{
- hash hsh;
-
- if (!(hsh = hash_lookup (hash_list, METHOD_SEL_NAME (method))))
- {
- /* Install on a global chain. */
- hash_enter (hash_list, method);
- }
- else
- {
- /* Check types against those; if different, add to a list. */
- attr loop;
- 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, 1);
- if (!already_there)
- hash_add_attr (hsh, method);
- }
-}
-
static tree
objc_add_method (tree klass, tree method, int is_class, bool is_optional)
{
}
if (is_class)
- add_method_to_hash_list (cls_method_hash_list, method);
+ insert_method_into_method_map (true, method);
else
{
- add_method_to_hash_list (nst_method_hash_list, method);
+ insert_method_into_method_map (false, method);
/* Instance methods in root classes (and categories thereof)
may act as class methods as a last resort. We also add
if (TREE_CODE (klass) == PROTOCOL_INTERFACE_TYPE
|| !CLASS_SUPER_NAME (klass))
- add_method_to_hash_list (cls_method_hash_list, method);
+ insert_method_into_method_map (true, method);
}
return method;
}
-static tree
-add_class (tree class_name, tree name)
-{
- struct interface_tuple **slot;
-
- /* Put interfaces on list in reverse order. */
- 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,
- IDENTIFIER_HASH_VALUE (name),
- INSERT);
- if (!*slot)
- {
- *slot = ggc_alloc_cleared_interface_tuple ();
- (*slot)->id = name;
- }
- (*slot)->class_name = class_name;
-
- return interface_chain;
-}
-
static void
add_category (tree klass, tree category)
{
{
warning (0, "cannot find interface declaration for %qE",
class_name);
- add_class (implementation_template = objc_implementation_context,
- class_name);
+ add_interface (implementation_template = objc_implementation_context,
+ class_name);
}
/* If a super class has been specified in the implementation,
warning (0, "duplicate interface declaration for class %qE", class_name);
#endif
else
- add_class (klass, class_name);
+ add_interface (klass, class_name);
if (protocol_list)
CLASS_PROTOCOL_LIST (klass)
uprivate_record = CLASS_STATIC_TEMPLATE (implementation_template);
objc_instance_type = build_pointer_type (uprivate_record);
- imp_entry = ggc_alloc_imp_entry ();
+ imp_entry = ggc_alloc<struct imp_entry> ();
imp_entry->next = imp_list;
imp_entry->imp_context = klass;
}
/* This routine builds name of the setter synthesized function. */
-static char *
+char *
objc_build_property_setter_name (tree ident)
{
/* TODO: Use alloca to allocate buffer of appropriate size. */
the same type, there is no need to lookup the ivar. */
size_of = c_sizeof_or_alignof_type (location, TREE_TYPE (property),
true /* is_sizeof */,
+ false /* min_alignof */,
false /* complain */);
if (PROPERTY_NONATOMIC (property))
the same type, there is no need to lookup the ivar. */
size_of = c_sizeof_or_alignof_type (location, TREE_TYPE (property),
true /* is_sizeof */,
+ false /* min_alignof */,
false /* complain */);
if (PROPERTY_NONATOMIC (property))
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_ATOMIC (TREE_TYPE (parm)) ? TYPE_QUAL_ATOMIC : 0)
| (TYPE_VOLATILE (TREE_TYPE (parm)) ? TYPE_QUAL_VOLATILE : 0), parm);
objc_parmlist = chainon (objc_parmlist, parm);
&& other && other != error_mark_node)
return other;
+ /* Don't look up the ivar if the user has explicitly advised against
+ it with -fno-local-ivars. */
+
+ if (!flag_local_ivars)
+ return other;
+
/* Look up the ivar, but do not use it if it is not accessible. */
ivar = is_ivar (objc_ivar_chain, id);
&& !DECL_FILE_SCOPE_P (other))
#endif
{
- warning (0, "local declaration of %qE hides instance variable", id);
-
+ if (warn_shadow_ivar == 1 || (warn_shadow && warn_shadow_ivar != 0)) {
+ warning (warn_shadow_ivar ? OPT_Wshadow_ivar : OPT_Wshadow,
+ "local declaration of %qE hides instance variable", id);
+ }
+
return other;
}
{
}
-/* --- Encode --- */
-/* "Encode" a data type into a string, which grows in util_obstack.
-
- The format is described in gcc/doc/objc.texi, section 'Type
- encoding'.
-
- Most of the encode_xxx functions have a 'type' argument, which is
- the type to encode, and an integer 'curtype' argument, which is the
- index in the encoding string of the beginning of the encoding of
- the current type, and allows you to find what characters have
- already been written for the current type (they are the ones in the
- current encoding string starting from 'curtype').
-
- For example, if we are encoding a method which returns 'int' and
- takes a 'char **' argument, then when we get to the point of
- encoding the 'char **' argument, the encoded string already
- contains 'i12@0:4' (assuming a pointer size of 4 bytes). So,
- 'curtype' will be set to 7 when starting to encode 'char **'.
- During the whole of the encoding of 'char **', 'curtype' will be
- fixed at 7, so the routine encoding the second pointer can find out
- that it's actually encoding a pointer to a pointer by looking
- backwards at what has already been encoded for the current type,
- and seeing there is a "^" (meaning a pointer) in there.
-*/
-
-
-/* Encode type qualifiers encodes one of the "PQ" Objective-C
- keywords, ie 'in', 'out', 'inout', 'bycopy', 'byref', 'oneway'.
- 'const', instead, is encoded directly as part of the type.
- */
-
-static void
-encode_type_qualifiers (tree declspecs)
-{
- tree spec;
-
- for (spec = declspecs; spec; spec = TREE_CHAIN (spec))
- {
- /* FIXME: Shouldn't we use token->keyword here ? */
- if (ridpointers[(int) RID_IN] == TREE_VALUE (spec))
- obstack_1grow (&util_obstack, 'n');
- else if (ridpointers[(int) RID_INOUT] == TREE_VALUE (spec))
- obstack_1grow (&util_obstack, 'N');
- else if (ridpointers[(int) RID_OUT] == TREE_VALUE (spec))
- obstack_1grow (&util_obstack, 'o');
- else if (ridpointers[(int) RID_BYCOPY] == TREE_VALUE (spec))
- obstack_1grow (&util_obstack, 'O');
- else if (ridpointers[(int) RID_BYREF] == TREE_VALUE (spec))
- obstack_1grow (&util_obstack, 'R');
- else if (ridpointers[(int) RID_ONEWAY] == TREE_VALUE (spec))
- obstack_1grow (&util_obstack, 'V');
- else
- gcc_unreachable ();
- }
-}
-
-/* Determine if a pointee is marked read-only. Only used by the NeXT
- runtime to be compatible with gcc-3.3. */
-
-static bool
-pointee_is_readonly (tree pointee)
-{
- while (POINTER_TYPE_P (pointee))
- pointee = TREE_TYPE (pointee);
-
- return TYPE_READONLY (pointee);
-}
-
-/* Encode a pointer type. */
-
-static void
-encode_pointer (tree type, int curtype, int format)
-{
- tree pointer_to = TREE_TYPE (type);
-
- if (flag_next_runtime)
- {
- /* This code is used to be compatible with gcc-3.3. */
- /* For historical/compatibility reasons, the read-only qualifier
- of the pointee gets emitted _before_ the '^'. The read-only
- qualifier of the pointer itself gets ignored, _unless_ we are
- looking at a typedef! Also, do not emit the 'r' for anything
- but the outermost type! */
- if (!generating_instance_variables
- && (obstack_object_size (&util_obstack) - curtype <= 1)
- && (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
- ? TYPE_READONLY (type)
- : pointee_is_readonly (pointer_to)))
- obstack_1grow (&util_obstack, 'r');
- }
-
- if (TREE_CODE (pointer_to) == RECORD_TYPE)
- {
- if (OBJC_TYPE_NAME (pointer_to)
- && TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE)
- {
- const char *name = IDENTIFIER_POINTER (OBJC_TYPE_NAME (pointer_to));
-
- if (strcmp (name, TAG_OBJECT) == 0) /* '@' */
- {
- obstack_1grow (&util_obstack, '@');
- return;
- }
- else if (TYPE_HAS_OBJC_INFO (pointer_to)
- && TYPE_OBJC_INTERFACE (pointer_to))
- {
- if (generating_instance_variables)
- {
- obstack_1grow (&util_obstack, '@');
- obstack_1grow (&util_obstack, '"');
- obstack_grow (&util_obstack, name, strlen (name));
- obstack_1grow (&util_obstack, '"');
- return;
- }
- else
- {
- obstack_1grow (&util_obstack, '@');
- return;
- }
- }
- else if (strcmp (name, TAG_CLASS) == 0) /* '#' */
- {
- obstack_1grow (&util_obstack, '#');
- return;
- }
- else if (strcmp (name, TAG_SELECTOR) == 0) /* ':' */
- {
- obstack_1grow (&util_obstack, ':');
- return;
- }
- }
- }
- else if (TREE_CODE (pointer_to) == INTEGER_TYPE
- && TYPE_MODE (pointer_to) == QImode)
- {
- tree pname = TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE
- ? OBJC_TYPE_NAME (pointer_to)
- : DECL_NAME (OBJC_TYPE_NAME (pointer_to));
-
- /* (BOOL *) are an exception and are encoded as ^c, while all
- other pointers to char are encoded as *. */
- if (strcmp (IDENTIFIER_POINTER (pname), "BOOL"))
- {
- if (!flag_next_runtime)
- {
- /* The NeXT runtime adds the 'r' before getting here. */
-
- /* It appears that "r*" means "const char *" rather than
- "char *const". "char *const" is encoded as "*",
- which is identical to "char *", so the "const" is
- unfortunately lost. */
- if (TYPE_READONLY (pointer_to))
- obstack_1grow (&util_obstack, 'r');
- }
-
- obstack_1grow (&util_obstack, '*');
- return;
- }
- }
-
- /* We have a normal pointer type that does not get special treatment. */
- obstack_1grow (&util_obstack, '^');
- encode_type (pointer_to, curtype, format);
-}
-
-static void
-encode_array (tree type, int curtype, int format)
-{
- tree an_int_cst = TYPE_SIZE (type);
- tree array_of = TREE_TYPE (type);
- char buffer[40];
-
- if (an_int_cst == NULL)
- {
- /* We are trying to encode an incomplete array. An incomplete
- array is forbidden as part of an instance variable; but it
- may occur if the instance variable is a pointer to such an
- array. */
-
- /* So the only case in which an incomplete array could occur
- (without being pointed to) is if we are encoding the
- arguments or return value of a method. In that case, an
- incomplete array argument or return value (eg,
- -(void)display: (char[])string) is treated like a pointer
- because that is how the compiler does the function call. A
- special, more complicated case, is when the incomplete array
- is the last member of a struct (eg, if we are encoding
- "struct { unsigned long int a;double b[];}"), which is again
- part of a method argument/return value. In that case, we
- really need to communicate to the runtime that there is an
- incomplete array (not a pointer!) there. So, we detect that
- special case and encode it as a zero-length array.
-
- Try to detect that we are part of a struct. We do this by
- searching for '=' in the type encoding for the current type.
- NB: This hack assumes that you can't use '=' as part of a C
- identifier.
- */
- {
- char *enc = obstack_base (&util_obstack) + curtype;
- if (memchr (enc, '=',
- obstack_object_size (&util_obstack) - curtype) == NULL)
- {
- /* We are not inside a struct. Encode the array as a
- pointer. */
- encode_pointer (type, curtype, format);
- return;
- }
- }
-
- /* Else, we are in a struct, and we encode it as a zero-length
- array. */
- sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT)0);
- }
- else if (TREE_INT_CST_LOW (TYPE_SIZE (array_of)) == 0)
- sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT)0);
- else
- sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC,
- TREE_INT_CST_LOW (an_int_cst)
- / TREE_INT_CST_LOW (TYPE_SIZE (array_of)));
-
- obstack_grow (&util_obstack, buffer, strlen (buffer));
- encode_type (array_of, curtype, format);
- obstack_1grow (&util_obstack, ']');
- return;
-}
-
-/* Encode a vector. The vector type is a GCC extension to C. */
-static void
-encode_vector (tree type, int curtype, int format)
-{
- tree vector_of = TREE_TYPE (type);
- char buffer[40];
-
- /* Vectors are like simple fixed-size arrays. */
-
- /* Output ![xx,yy,<code>] where xx is the vector_size, yy is the
- alignment of the vector, and <code> is the base type. Eg, int
- __attribute__ ((vector_size (16))) gets encoded as ![16,32,i]
- assuming that the alignment is 32 bytes. We include size and
- alignment in bytes so that the runtime does not have to have any
- knowledge of the actual types.
- */
- sprintf (buffer, "![" HOST_WIDE_INT_PRINT_DEC ",%d",
- /* We want to compute the equivalent of sizeof (<vector>).
- Code inspired by c_sizeof_or_alignof_type. */
- ((TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type))
- / (TYPE_PRECISION (char_type_node) / BITS_PER_UNIT))),
- /* We want to compute the equivalent of __alignof__
- (<vector>). Code inspired by
- c_sizeof_or_alignof_type. */
- TYPE_ALIGN_UNIT (type));
- obstack_grow (&util_obstack, buffer, strlen (buffer));
- encode_type (vector_of, curtype, format);
- obstack_1grow (&util_obstack, ']');
- return;
-}
-\f
-static void
-encode_aggregate_fields (tree type, bool pointed_to, int curtype, int format)
-{
- tree field = TYPE_FIELDS (type);
-
- for (; field; field = DECL_CHAIN (field))
- {
-#ifdef OBJCPLUS
- /* C++ static members, and things that are not field at all,
- should not appear in the encoding. */
- if (TREE_CODE (field) != FIELD_DECL || TREE_STATIC (field))
- continue;
-#endif
-
- /* Recursively encode fields of embedded base classes. */
- if (DECL_ARTIFICIAL (field) && !DECL_NAME (field)
- && TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
- {
- encode_aggregate_fields (TREE_TYPE (field),
- pointed_to, curtype, format);
- continue;
- }
-
- if (generating_instance_variables && !pointed_to)
- {
- tree fname = DECL_NAME (field);
-
- obstack_1grow (&util_obstack, '"');
-
- if (fname && TREE_CODE (fname) == IDENTIFIER_NODE)
- obstack_grow (&util_obstack,
- IDENTIFIER_POINTER (fname),
- strlen (IDENTIFIER_POINTER (fname)));
-
- obstack_1grow (&util_obstack, '"');
- }
-
- encode_field_decl (field, curtype, format);
- }
-}
-
-static void
-encode_aggregate_within (tree type, int curtype, int format, int left,
- int right)
-{
- tree name;
- /* NB: aggregates that are pointed to have slightly different encoding
- rules in that you never encode the names of instance variables. */
- int ob_size = obstack_object_size (&util_obstack);
- bool inline_contents = false;
- bool pointed_to = false;
-
- if (flag_next_runtime)
- {
- if (ob_size > 0 && *(obstack_next_free (&util_obstack) - 1) == '^')
- pointed_to = true;
-
- if ((format == OBJC_ENCODE_INLINE_DEFS || generating_instance_variables)
- && (!pointed_to || ob_size - curtype == 1
- || (ob_size - curtype == 2
- && *(obstack_next_free (&util_obstack) - 2) == 'r')))
- inline_contents = true;
- }
- else
- {
- /* c0 and c1 are the last two characters in the encoding of the
- current type; if the last two characters were '^' or '^r',
- then we are encoding an aggregate that is "pointed to". The
- comment above applies: in that case we should avoid encoding
- the names of instance variables.
- */
- char c1 = ob_size > 1 ? *(obstack_next_free (&util_obstack) - 2) : 0;
- char c0 = ob_size > 0 ? *(obstack_next_free (&util_obstack) - 1) : 0;
-
- if (c0 == '^' || (c1 == '^' && c0 == 'r'))
- pointed_to = true;
-
- if (format == OBJC_ENCODE_INLINE_DEFS || generating_instance_variables)
- {
- if (!pointed_to)
- inline_contents = true;
- else
- {
- /* Note that the check (ob_size - curtype < 2) prevents
- infinite recursion when encoding a structure which is
- a linked list (eg, struct node { struct node *next;
- }). Each time we follow a pointer, we add one
- character to ob_size, and curtype is fixed, so after
- at most two pointers we stop inlining contents and
- break the loop.
-
- The other case where we don't inline is "^r", which
- is a pointer to a constant struct.
- */
- if ((ob_size - curtype <= 2) && !(c0 == 'r'))
- inline_contents = true;
- }
- }
- }
-
- /* Traverse struct aliases; it is important to get the
- original struct and its tag name (if any). */
- type = TYPE_MAIN_VARIANT (type);
- name = OBJC_TYPE_NAME (type);
- /* Open parenth/bracket. */
- obstack_1grow (&util_obstack, left);
-
- /* Encode the struct/union tag name, or '?' if a tag was
- not provided. Typedef aliases do not qualify. */
-#ifdef OBJCPLUS
- /* For compatibility with the NeXT runtime, ObjC++ encodes template
- args as a composite struct tag name. */
- if (name && TREE_CODE (name) == IDENTIFIER_NODE
- /* Did this struct have a tag? */
- && !TYPE_WAS_ANONYMOUS (type))
- obstack_grow (&util_obstack,
- decl_as_string (type, TFF_DECL_SPECIFIERS | TFF_UNQUALIFIED_NAME),
- strlen (decl_as_string (type, TFF_DECL_SPECIFIERS | TFF_UNQUALIFIED_NAME)));
-#else
- if (name && TREE_CODE (name) == IDENTIFIER_NODE)
- obstack_grow (&util_obstack,
- IDENTIFIER_POINTER (name),
- strlen (IDENTIFIER_POINTER (name)));
-#endif
- else
- obstack_1grow (&util_obstack, '?');
-
- /* Encode the types (and possibly names) of the inner fields,
- if required. */
- if (inline_contents)
- {
- obstack_1grow (&util_obstack, '=');
- encode_aggregate_fields (type, pointed_to, curtype, format);
- }
- /* Close parenth/bracket. */
- obstack_1grow (&util_obstack, right);
-}
-
-/* Encode a bitfield NeXT-style (i.e., without a bit offset or the underlying
- field type. */
-
-static void
-encode_next_bitfield (int width)
-{
- char buffer[40];
- sprintf (buffer, "b%d", width);
- obstack_grow (&util_obstack, buffer, strlen (buffer));
-}
-
-/* Encodes 'type', ignoring type qualifiers (which you should encode
- beforehand if needed) with the exception of 'const', which is
- encoded by encode_type. See above for the explanation of
- 'curtype'. 'format' can be OBJC_ENCODE_INLINE_DEFS or
- OBJC_ENCODE_DONT_INLINE_DEFS.
-*/
-static void
-encode_type (tree type, int curtype, int format)
-{
- enum tree_code code = TREE_CODE (type);
-
- /* Ignore type qualifiers other than 'const' when encoding a
- type. */
-
- if (type == error_mark_node)
- return;
-
- if (!flag_next_runtime)
- {
- if (TYPE_READONLY (type))
- obstack_1grow (&util_obstack, 'r');
- }
-
- switch (code)
- {
- case ENUMERAL_TYPE:
- if (flag_next_runtime)
- {
- /* Kludge for backwards-compatibility with gcc-3.3: enums
- are always encoded as 'i' no matter what type they
- actually are (!). */
- obstack_1grow (&util_obstack, 'i');
- break;
- }
- /* Else, they are encoded exactly like the integer type that is
- used by the compiler to store them. */
- case INTEGER_TYPE:
- {
- char c;
- switch (GET_MODE_BITSIZE (TYPE_MODE (type)))
- {
- case 8: c = TYPE_UNSIGNED (type) ? 'C' : 'c'; break;
- case 16: c = TYPE_UNSIGNED (type) ? 'S' : 's'; break;
- case 32:
- {
- tree int_type = type;
- if (flag_next_runtime)
- {
- /* Another legacy kludge for compatiblity with
- gcc-3.3: 32-bit longs are encoded as 'l' or 'L',
- but not always. For typedefs, we need to use 'i'
- or 'I' instead if encoding a struct field, or a
- pointer! */
- int_type = ((!generating_instance_variables
- && (obstack_object_size (&util_obstack)
- == (unsigned) curtype))
- ? TYPE_MAIN_VARIANT (type)
- : type);
- }
- if (int_type == long_unsigned_type_node
- || int_type == long_integer_type_node)
- c = TYPE_UNSIGNED (type) ? 'L' : 'l';
- else
- c = TYPE_UNSIGNED (type) ? 'I' : 'i';
- }
- break;
- case 64: c = TYPE_UNSIGNED (type) ? 'Q' : 'q'; break;
- case 128: c = TYPE_UNSIGNED (type) ? 'T' : 't'; break;
- default: gcc_unreachable ();
- }
- obstack_1grow (&util_obstack, c);
- break;
- }
- case REAL_TYPE:
- {
- char c;
- /* Floating point types. */
- switch (GET_MODE_BITSIZE (TYPE_MODE (type)))
- {
- case 32: c = 'f'; break;
- case 64: c = 'd'; break;
- case 96:
- case 128: c = 'D'; break;
- default: gcc_unreachable ();
- }
- obstack_1grow (&util_obstack, c);
- break;
- }
- case VOID_TYPE:
- obstack_1grow (&util_obstack, 'v');
- break;
-
- case BOOLEAN_TYPE:
- obstack_1grow (&util_obstack, 'B');
- break;
-
- case ARRAY_TYPE:
- encode_array (type, curtype, format);
- break;
-
- case POINTER_TYPE:
-#ifdef OBJCPLUS
- case REFERENCE_TYPE:
-#endif
- encode_pointer (type, curtype, format);
- break;
-
- case RECORD_TYPE:
- encode_aggregate_within (type, curtype, format, '{', '}');
- break;
-
- case UNION_TYPE:
- encode_aggregate_within (type, curtype, format, '(', ')');
- break;
-
- case FUNCTION_TYPE: /* '?' means an unknown type. */
- obstack_1grow (&util_obstack, '?');
- break;
-
- case COMPLEX_TYPE:
- /* A complex is encoded as 'j' followed by the inner type (eg,
- "_Complex int" is encoded as 'ji'). */
- obstack_1grow (&util_obstack, 'j');
- encode_type (TREE_TYPE (type), curtype, format);
- break;
-
- case VECTOR_TYPE:
- encode_vector (type, curtype, format);
- break;
-
- default:
- warning (0, "unknown type %s found during Objective-C encoding",
- gen_type_name (type));
- obstack_1grow (&util_obstack, '?');
- break;
- }
-
- if (flag_next_runtime)
- {
- /* Super-kludge. Some ObjC qualifier and type combinations need
- to be rearranged for compatibility with gcc-3.3. */
- if (code == POINTER_TYPE && obstack_object_size (&util_obstack) >= 3)
- {
- char *enc = obstack_base (&util_obstack) + curtype;
-
- /* Rewrite "in const" from "nr" to "rn". */
- if (curtype >= 1 && !strncmp (enc - 1, "nr", 2))
- strncpy (enc - 1, "rn", 2);
- }
- }
-}
-
-static void
-encode_gnu_bitfield (int position, tree type, int size)
-{
- enum tree_code code = TREE_CODE (type);
- char buffer[40];
- char charType = '?';
-
- /* This code is only executed for the GNU runtime, so we can ignore
- the NeXT runtime kludge of always encoding enums as 'i' no matter
- what integers they actually are. */
- if (code == INTEGER_TYPE || code == ENUMERAL_TYPE)
- {
- if (integer_zerop (TYPE_MIN_VALUE (type)))
- /* Unsigned integer types. */
- {
- switch (TYPE_MODE (type))
- {
- case QImode:
- charType = 'C'; break;
- case HImode:
- charType = 'S'; break;
- case SImode:
- {
- if (type == long_unsigned_type_node)
- charType = 'L';
- else
- charType = 'I';
- break;
- }
- case DImode:
- charType = 'Q'; break;
- default:
- gcc_unreachable ();
- }
- }
- else
- /* Signed integer types. */
- {
- switch (TYPE_MODE (type))
- {
- case QImode:
- charType = 'c'; break;
- case HImode:
- charType = 's'; break;
- case SImode:
- {
- if (type == long_integer_type_node)
- charType = 'l';
- else
- charType = 'i';
- break;
- }
- case DImode:
- charType = 'q'; break;
- default:
- gcc_unreachable ();
- }
- }
- }
- else
- {
- /* Do not do any encoding, produce an error and keep going. */
- error ("trying to encode non-integer type as a bitfield");
- return;
- }
-
- sprintf (buffer, "b%d%c%d", position, charType, size);
- obstack_grow (&util_obstack, buffer, strlen (buffer));
-}
-
-void
-encode_field_decl (tree field_decl, int curtype, int format)
-{
-#ifdef OBJCPLUS
- /* C++ static members, and things that are not fields at all,
- should not appear in the encoding. */
- if (TREE_CODE (field_decl) != FIELD_DECL || TREE_STATIC (field_decl))
- return;
-#endif
-
- /* Generate the bitfield typing information, if needed. Note the difference
- between GNU and NeXT runtimes. */
- if (DECL_BIT_FIELD_TYPE (field_decl))
- {
- int size = tree_low_cst (DECL_SIZE (field_decl), 1);
-
- if (flag_next_runtime)
- encode_next_bitfield (size);
- else
- encode_gnu_bitfield (int_bit_position (field_decl),
- DECL_BIT_FIELD_TYPE (field_decl), size);
- }
- else
- encode_type (TREE_TYPE (field_decl), curtype, format);
-}
-
-/* This routine encodes the attribute of the input PROPERTY according
- to following formula:
-
- Property attributes are stored as a comma-delimited C string.
- Simple attributes such as readonly are encoded as single
- character. The parametrized attributes, getter=name and
- setter=name, are encoded as a single character followed by an
- identifier. Property types are also encoded as a parametrized
- attribute. The characters used to encode these attributes are
- defined by the following enumeration:
-
- enum PropertyAttributes {
- kPropertyReadOnly = 'R',
- kPropertyBycopy = 'C',
- kPropertyByref = '&',
- kPropertyDynamic = 'D',
- kPropertyGetter = 'G',
- kPropertySetter = 'S',
- kPropertyInstanceVariable = 'V',
- kPropertyType = 'T',
- kPropertyWeak = 'W',
- kPropertyStrong = 'P',
- kPropertyNonAtomic = 'N'
- }; */
-tree
-objc_v2_encode_prop_attr (tree property)
-{
- const char *string;
- tree type = TREE_TYPE (property);
-
- obstack_1grow (&util_obstack, 'T');
- encode_type (type, obstack_object_size (&util_obstack),
- OBJC_ENCODE_INLINE_DEFS);
-
- if (PROPERTY_READONLY (property))
- obstack_grow (&util_obstack, ",R", 2);
-
- switch (PROPERTY_ASSIGN_SEMANTICS (property))
- {
- case OBJC_PROPERTY_COPY:
- obstack_grow (&util_obstack, ",C", 2);
- break;
- case OBJC_PROPERTY_RETAIN:
- obstack_grow (&util_obstack, ",&", 2);
- break;
- case OBJC_PROPERTY_ASSIGN:
- default:
- break;
- }
-
- if (PROPERTY_DYNAMIC (property))
- obstack_grow (&util_obstack, ",D", 2);
-
- if (PROPERTY_NONATOMIC (property))
- obstack_grow (&util_obstack, ",N", 2);
-
- /* Here we want to encode the getter name, but only if it's not the
- standard one. */
- if (PROPERTY_GETTER_NAME (property) != PROPERTY_NAME (property))
- {
- obstack_grow (&util_obstack, ",G", 2);
- string = IDENTIFIER_POINTER (PROPERTY_GETTER_NAME (property));
- obstack_grow (&util_obstack, string, strlen (string));
- }
-
- if (!PROPERTY_READONLY (property))
- {
- /* Here we want to encode the setter name, but only if it's not
- the standard one. */
- tree standard_setter = get_identifier (objc_build_property_setter_name (PROPERTY_NAME (property)));
- if (PROPERTY_SETTER_NAME (property) != standard_setter)
- {
- obstack_grow (&util_obstack, ",S", 2);
- string = IDENTIFIER_POINTER (PROPERTY_SETTER_NAME (property));
- obstack_grow (&util_obstack, string, strlen (string));
- }
- }
-
- /* TODO: Encode strong ('P'), weak ('W') for garbage collection. */
-
- if (!PROPERTY_DYNAMIC (property))
- {
- obstack_grow (&util_obstack, ",V", 2);
- if (PROPERTY_IVAR_NAME (property))
- string = IDENTIFIER_POINTER (PROPERTY_IVAR_NAME (property));
- else
- string = IDENTIFIER_POINTER (PROPERTY_NAME (property));
- obstack_grow (&util_obstack, string, strlen (string));
- }
-
- /* NULL-terminate string. */
- obstack_1grow (&util_obstack, 0);
- string = XOBFINISH (&util_obstack, char *);
- obstack_free (&util_obstack, util_firstobj);
- return get_identifier (string);
-}
-
void
objc_common_init_ts (void)
{
MARK_TS_TYPED (PROPERTY_REF);
}
+size_t
+objc_common_tree_size (enum tree_code code)
+{
+ switch (code)
+ {
+ case CLASS_METHOD_DECL:
+ case INSTANCE_METHOD_DECL:
+ case KEYWORD_DECL:
+ case PROPERTY_DECL:
+ return sizeof (struct tree_decl_non_common);
+ default:
+ gcc_unreachable ();
+
+ }
+}
+
+
#include "gt-objc-objc-act.h"