| /* Implement classes and message passing for Objective C. |
| Copyright (C) 1992-2022 Free Software Foundation, Inc. |
| Contributed by Steve Naroff. |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| GCC is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "tm.h" |
| #include "tree.h" |
| #include "stringpool.h" |
| #include "stor-layout.h" |
| #include "attribs.h" |
| |
| #ifdef OBJCPLUS |
| #include "cp/cp-tree.h" |
| #else |
| #include "c/c-tree.h" |
| #include "c/c-lang.h" |
| #endif |
| |
| #include "c-family/c-objc.h" |
| #include "langhooks.h" |
| #include "objc-act.h" |
| #include "objc-map.h" |
| #include "function.h" |
| #include "toplev.h" |
| #include "debug.h" |
| #include "c-family/c-target.h" |
| #include "intl.h" |
| #include "cgraph.h" |
| #include "tree-iterator.h" |
| /* Different initialization, code gen and meta data generation for each |
| runtime. */ |
| #include "objc-runtime-hooks.h" |
| /* Routines used mainly by the runtimes. */ |
| #include "objc-runtime-shared-support.h" |
| /* For default_tree_printer (). */ |
| |
| /* For enum gimplify_status */ |
| #include "gimple-expr.h" |
| #include "gimplify.h" |
| |
| /* For encode_method_prototype(). */ |
| #include "objc-encoding.h" |
| |
| 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 |
| #define OBJCP_REMAP_FUNCTIONS |
| #include "objcp-decl.h" |
| #endif /* OBJCPLUS */ |
| |
| /* This is the default way of generating a method name. */ |
| /* This has the problem that "test_method:argument:" and |
| "test:method_argument:" will generate the same name |
| ("_i_Test__test_method_argument_" for an instance method of the |
| class "Test"), so you can't have them both in the same class! |
| Moreover, the demangling (going from |
| "_i_Test__test_method_argument" back to the original name) is |
| undefined because there are two correct ways of demangling the |
| name. */ |
| #ifndef OBJC_GEN_METHOD_LABEL |
| #define OBJC_GEN_METHOD_LABEL(BUF, IS_INST, CLASS_NAME, CAT_NAME, SEL_NAME, NUM) \ |
| do { \ |
| char *temp; \ |
| sprintf ((BUF), "_%s_%s_%s_%s", \ |
| ((IS_INST) ? "i" : "c"), \ |
| (CLASS_NAME), \ |
| ((CAT_NAME)? (CAT_NAME) : ""), \ |
| (SEL_NAME)); \ |
| for (temp = (BUF); *temp; temp++) \ |
| if (*temp == ':') *temp = '_'; \ |
| } while (0) |
| #endif |
| |
| /* These need specifying. */ |
| #ifndef OBJC_FORWARDING_STACK_OFFSET |
| #define OBJC_FORWARDING_STACK_OFFSET 0 |
| #endif |
| |
| #ifndef OBJC_FORWARDING_MIN_OFFSET |
| #define OBJC_FORWARDING_MIN_OFFSET 0 |
| #endif |
| |
| /*** Private Interface (procedures) ***/ |
| |
| /* Init stuff. */ |
| static void synth_module_prologue (void); |
| |
| /* Code generation. */ |
| |
| static tree start_class (enum tree_code, tree, tree, tree, tree); |
| static tree continue_class (tree); |
| static void finish_class (tree); |
| static void start_method_def (tree, tree); |
| |
| static tree start_protocol (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, bool); |
| static tree add_instance_variable (tree, objc_ivar_visibility_kind, tree); |
| static tree build_ivar_reference (tree); |
| static tree is_ivar (tree, tree); |
| |
| /* We only need the following for ObjC; ObjC++ will use C++'s definition |
| of DERIVED_FROM_P. */ |
| #ifndef OBJCPLUS |
| static bool objc_derived_from_p (tree, tree); |
| #define DERIVED_FROM_P(PARENT, CHILD) objc_derived_from_p (PARENT, CHILD) |
| #endif |
| |
| /* Property. */ |
| 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 tree lookup_property (tree, tree); |
| static tree lookup_property_in_list (tree, tree); |
| static tree lookup_property_in_protocol_list (tree, tree); |
| static void build_common_objc_property_accessor_helpers (void); |
| |
| static void objc_xref_basetypes (tree, tree); |
| |
| static tree get_class_ivars (tree, bool); |
| |
| static void build_fast_enumeration_state_template (void); |
| |
| #ifdef OBJCPLUS |
| static void objc_generate_cxx_cdtors (void); |
| #endif |
| |
| /* objc attribute */ |
| static void objc_decl_method_attributes (tree*, tree, int); |
| static tree build_keyword_selector (tree); |
| |
| static void hash_init (void); |
| |
| /* 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. */ |
| |
| static GTY(()) objc_map_t class_name_map = 0; |
| static GTY(()) objc_map_t alias_name_map = 0; |
| |
| static tree lookup_method (tree, tree); |
| static tree lookup_method_static (tree, tree, int); |
| |
| 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); |
| |
| /* Protocols. */ |
| |
| static tree lookup_protocol (tree, bool, bool); |
| static tree lookup_and_install_protocols (tree, bool); |
| |
| #ifdef OBJCPLUS |
| static void really_start_method (tree, tree); |
| #else |
| static void really_start_method (tree, struct c_arg_info *); |
| #endif |
| static int comp_proto_with_proto (tree, tree, int); |
| static tree objc_decay_parm_type (tree); |
| |
| /* Utilities for debugging and error diagnostics. */ |
| |
| static char *gen_type_name (tree); |
| static char *gen_type_name_0 (tree); |
| static char *gen_method_decl (tree); |
| static char *gen_declaration (tree); |
| |
| /* Everything else. */ |
| |
| static void generate_struct_by_value_array (void) ATTRIBUTE_NORETURN; |
| |
| static void mark_referenced_methods (void); |
| static bool objc_type_valid_for_messaging (tree type, bool allow_classes); |
| static tree check_duplicates (tree, int, int); |
| |
| /*** Private Interface (data) ***/ |
| /* Flags for lookup_method_static(). */ |
| |
| /* Look for class methods. */ |
| #define OBJC_LOOKUP_CLASS 1 |
| /* Do not examine superclasses. */ |
| #define OBJC_LOOKUP_NO_SUPER 2 |
| /* Disable returning an instance method of a root class when a class |
| method can't be found. */ |
| #define OBJC_LOOKUP_NO_INSTANCE_METHODS_OF_ROOT_CLASS 4 |
| |
| /* The OCTI_... enumeration itself is in objc/objc-act.h. */ |
| tree objc_global_trees[OCTI_MAX]; |
| |
| struct imp_entry *imp_list = 0; |
| int imp_count = 0; /* `@implementation' */ |
| int cat_count = 0; /* `@category' */ |
| |
| objc_ivar_visibility_kind objc_ivar_visibility, objc_default_ivar_visibility; |
| |
| /* Use to generate method labels. */ |
| static int method_slot = 0; |
| |
| /* Flag to say whether methods in a protocol are optional or |
| required. */ |
| static bool objc_method_optional_flag = false; |
| |
| static int objc_collecting_ivars = 0; |
| |
| /* Flag that is set to 'true' while we are processing a class |
| extension. Since a class extension just "reopens" the main |
| @interface, this can be used to determine if we are in the main |
| @interface, or in a class extension. */ |
| static bool objc_in_class_extension = false; |
| |
| static char *errbuf; /* Buffer for error diagnostics */ |
| |
| /* An array of all the local variables in the current function that |
| need to be marked as volatile. */ |
| 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((for_user)) string_descriptor { |
| /* The literal argument . */ |
| tree literal; |
| |
| /* The resulting constant string. */ |
| tree constructor; |
| }; |
| |
| struct objc_string_hasher : ggc_ptr_hash<string_descriptor> |
| { |
| static hashval_t hash (string_descriptor *); |
| static bool equal (string_descriptor *, string_descriptor *); |
| }; |
| |
| static GTY(()) hash_table<objc_string_hasher> *string_htab; |
| |
| FILE *gen_declaration_file; |
| |
| /* Hooks for stuff that differs between runtimes. */ |
| objc_runtime_hooks runtime; |
| |
| /* Create a temporary variable of type 'type'. If 'name' is set, uses |
| the specified name, else use no name. Returns the declaration of |
| the type. The 'name' is mostly useful for debugging. |
| */ |
| tree |
| objc_create_temporary_var (tree type, const char *name) |
| { |
| tree decl; |
| |
| if (name != NULL) |
| { |
| decl = build_decl (input_location, |
| VAR_DECL, get_identifier (name), type); |
| } |
| else |
| { |
| decl = build_decl (input_location, |
| VAR_DECL, NULL_TREE, type); |
| } |
| TREE_USED (decl) = 1; |
| DECL_ARTIFICIAL (decl) = 1; |
| DECL_IGNORED_P (decl) = 1; |
| DECL_CONTEXT (decl) = current_function_decl; |
| |
| return decl; |
| } |
| |
| /* Some platforms pass small structures through registers versus |
| through an invisible pointer. Determine at what size structure is |
| the transition point between the two possibilities. */ |
| |
| static void |
| generate_struct_by_value_array (void) |
| { |
| tree type; |
| tree decls; |
| int i, j; |
| int aggregate_in_mem[32]; |
| int found = 0; |
| |
| /* Presumably no platform passes 32 byte structures in a register. */ |
| /* ??? As an example, m64/ppc/Darwin can pass up to 8*long+13*double |
| in registers. */ |
| for (i = 1; i < 32; i++) |
| { |
| char buffer[5]; |
| tree *chain = NULL; |
| |
| /* Create an unnamed struct that has `i' character components */ |
| type = objc_start_struct (NULL_TREE); |
| |
| strcpy (buffer, "c1"); |
| decls = add_field_decl (char_type_node, buffer, &chain); |
| |
| for (j = 1; j < i; j++) |
| { |
| sprintf (buffer, "c%d", j + 1); |
| add_field_decl (char_type_node, buffer, &chain); |
| } |
| objc_finish_struct (type, decls); |
| |
| aggregate_in_mem[i] = aggregate_value_p (type, 0); |
| if (!aggregate_in_mem[i]) |
| found = 1; |
| } |
| |
| /* We found some structures that are returned in registers instead of memory |
| so output the necessary data. */ |
| if (found) |
| { |
| for (i = 31; i >= 0; i--) |
| if (!aggregate_in_mem[i]) |
| break; |
| printf ("#define OBJC_MAX_STRUCT_BY_VALUE %d\n", i); |
| } |
| |
| exit (0); |
| } |
| |
| bool |
| objc_init (void) |
| { |
| bool ok; |
| #ifdef OBJCPLUS |
| if (cxx_init () == false) |
| #else |
| if (c_objc_common_init () == false) |
| #endif |
| return false; |
| |
| /* print_struct_values is triggered by -print-runtime-info (used |
| when building libobjc, with an empty file as input). It does not |
| require any ObjC setup, and it never returns. |
| |
| -fcompare-debug is used to check the compiler output; we are |
| executed twice, once with flag_compare_debug set, and once with |
| it not set. If the flag is used together with |
| -print-runtime-info, we want to print the runtime info only once, |
| else it would be output in duplicate. So we check |
| flag_compare_debug to output it in only one of the invocations. |
| |
| As a side effect, this also that means -fcompare-debug |
| -print-runtime-info will run the compiler twice, and compare the |
| generated assembler file; the first time the compiler exits |
| immediately (producing no file), and the second time it compiles |
| an empty file. This checks, as a side effect, that compiling an |
| empty file produces no assembler output. */ |
| if (print_struct_values && !flag_compare_debug) |
| generate_struct_by_value_array (); |
| |
| /* Set up stuff used by FE parser and all runtimes. */ |
| errbuf = XNEWVEC (char, 1024 * 10); |
| interface_hash_init (); |
| hash_init (); |
| 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); |
| else if (flag_next_runtime) |
| ok = objc_next_runtime_abi_01_init (&runtime); |
| else |
| ok = objc_gnu_runtime_abi_01_init (&runtime); |
| |
| /* If that part of the setup failed - bail out immediately. */ |
| 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 (); |
| |
| return true; |
| } |
| |
| /* This is called at the end of parsing by the C/C++ parsers. */ |
| void |
| objc_write_global_declarations (void) |
| { |
| mark_referenced_methods (); |
| |
| /* A missing @end might not be detected by the parser. */ |
| if (objc_implementation_context) |
| { |
| warning (0, "%<@end%> missing in implementation context"); |
| finish_class (objc_implementation_context); |
| objc_ivar_chain = NULL_TREE; |
| objc_implementation_context = NULL_TREE; |
| } |
| |
| if (warn_selector) |
| { |
| objc_map_iterator_t i; |
| |
| 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); |
| |
| 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 |
| is non-zero. Not only is it wasting time to generate the metadata, |
| it needlessly imposes need to re-check for things that are already |
| determined to be errors. */ |
| |
| /* Finalize Objective-C runtime data. No need to generate tables |
| and code if only checking syntax, or if generating a PCH file. */ |
| if (!flag_syntax_only && !pch_file) |
| { |
| location_t saved_location; |
| |
| /* If gen_declaration desired, open the output file. */ |
| if (flag_gen_declaration) |
| { |
| char * const dumpname = concat (dump_base_name, ".decl", NULL); |
| gen_declaration_file = fopen (dumpname, "w"); |
| if (gen_declaration_file == 0) |
| fatal_error (input_location, "cannot open %s: %m", dumpname); |
| free (dumpname); |
| } |
| |
| /* Set the input location to BUILTINS_LOCATION. This is good |
| for error messages, in case any is generated while producing |
| the metadata, but it also silences warnings that would be |
| produced when compiling with -Wpadded in case when padding is |
| automatically added to the built-in runtime data structure |
| declarations. We know about this padding, and it is fine; we |
| don't want users to see any warnings about it if they use |
| -Wpadded. */ |
| saved_location = input_location; |
| input_location = BUILTINS_LOCATION; |
| |
| /* Compute and emit the meta-data tables for this runtime. */ |
| (*runtime.generate_metadata) (); |
| |
| /* Restore the original location, just in case it mattered. */ |
| input_location = saved_location; |
| |
| /* ... and then close any declaration file we opened. */ |
| if (gen_declaration_file) |
| fclose (gen_declaration_file); |
| } |
| } |
| |
| /* Return the first occurrence of a method declaration corresponding |
| to sel_name in rproto_list. Search rproto_list recursively. |
| If is_class is 0, search for instance methods, otherwise for class |
| methods. */ |
| static tree |
| lookup_method_in_protocol_list (tree rproto_list, tree sel_name, |
| int is_class) |
| { |
| tree rproto, p, m; |
| |
| for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto)) |
| { |
| p = TREE_VALUE (rproto); |
| m = NULL_TREE; |
| |
| if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) |
| { |
| /* First, search the @required protocol methods. */ |
| if (is_class) |
| m = lookup_method (PROTOCOL_CLS_METHODS (p), sel_name); |
| else |
| m = lookup_method (PROTOCOL_NST_METHODS (p), sel_name); |
| |
| if (m) |
| return m; |
| |
| /* If still not found, search the @optional protocol methods. */ |
| if (is_class) |
| m = lookup_method (PROTOCOL_OPTIONAL_CLS_METHODS (p), sel_name); |
| else |
| m = lookup_method (PROTOCOL_OPTIONAL_NST_METHODS (p), sel_name); |
| |
| if (m) |
| return m; |
| |
| /* If still not found, search the attached protocols. */ |
| if (PROTOCOL_LIST (p)) |
| m = lookup_method_in_protocol_list (PROTOCOL_LIST (p), |
| sel_name, is_class); |
| if (m) |
| return m; |
| } |
| else |
| { |
| ; /* An identifier...if we could not find a protocol. */ |
| } |
| } |
| |
| return 0; |
| } |
| |
| static tree |
| lookup_protocol_in_reflist (tree rproto_list, tree lproto) |
| { |
| tree rproto, p; |
| |
| /* Make sure the protocol is supported by the object on the rhs. */ |
| if (TREE_CODE (lproto) == PROTOCOL_INTERFACE_TYPE) |
| { |
| tree fnd = 0; |
| for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto)) |
| { |
| p = TREE_VALUE (rproto); |
| |
| if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) |
| { |
| if (lproto == p) |
| fnd = lproto; |
| |
| else if (PROTOCOL_LIST (p)) |
| fnd = lookup_protocol_in_reflist (PROTOCOL_LIST (p), lproto); |
| } |
| |
| if (fnd) |
| return fnd; |
| } |
| } |
| else |
| { |
| ; /* An identifier...if we could not find a protocol. */ |
| } |
| |
| return 0; |
| } |
| |
| void |
| objc_start_class_interface (tree klass, location_t name_loc, tree super_class, |
| tree protos, tree attributes) |
| { |
| if (flag_objc1_only && attributes) |
| error_at (name_loc, "class attributes are not available in Objective-C 1.0"); |
| |
| objc_interface_context |
| = objc_ivar_context |
| = start_class (CLASS_INTERFACE_TYPE, klass, super_class, protos, attributes); |
| objc_ivar_visibility = objc_default_ivar_visibility; |
| } |
| |
| void |
| objc_start_category_interface (tree klass, tree categ, |
| tree protos, tree attributes) |
| { |
| if (attributes) |
| { |
| if (flag_objc1_only) |
| error_at (input_location, "category attributes are not available in Objective-C 1.0"); |
| else |
| warning_at (input_location, OPT_Wattributes, |
| "category attributes are not available in this version" |
| " of the compiler, (ignored)"); |
| } |
| if (categ == NULL_TREE) |
| { |
| if (flag_objc1_only) |
| error_at (input_location, "class extensions are not available in Objective-C 1.0"); |
| else |
| { |
| /* Iterate over all the classes and categories implemented |
| up to now in this compilation unit. */ |
| struct imp_entry *t; |
| |
| for (t = imp_list; t; t = t->next) |
| { |
| /* If we find a class @implementation with the same name |
| as the one we are extending, produce an error. */ |
| if (TREE_CODE (t->imp_context) == CLASS_IMPLEMENTATION_TYPE |
| && IDENTIFIER_POINTER (CLASS_NAME (t->imp_context)) == IDENTIFIER_POINTER (klass)) |
| error_at (input_location, |
| "class extension for class %qE declared after its %<@implementation%>", |
| klass); |
| } |
| } |
| } |
| objc_interface_context |
| = start_class (CATEGORY_INTERFACE_TYPE, klass, categ, protos, NULL_TREE); |
| objc_ivar_chain |
| = continue_class (objc_interface_context); |
| } |
| |
| void |
| objc_start_protocol (tree name, tree protos, tree attributes) |
| { |
| if (flag_objc1_only && attributes) |
| error_at (input_location, "protocol attributes are not available in Objective-C 1.0"); |
| |
| objc_interface_context |
| = start_protocol (PROTOCOL_INTERFACE_TYPE, name, protos, attributes); |
| objc_method_optional_flag = false; |
| } |
| |
| void |
| objc_continue_interface (void) |
| { |
| objc_ivar_chain |
| = continue_class (objc_interface_context); |
| } |
| |
| void |
| objc_finish_interface (void) |
| { |
| finish_class (objc_interface_context); |
| objc_interface_context = NULL_TREE; |
| objc_method_optional_flag = false; |
| objc_in_class_extension = false; |
| } |
| |
| void |
| objc_start_class_implementation (tree klass, tree super_class) |
| { |
| objc_implementation_context |
| = objc_ivar_context |
| = start_class (CLASS_IMPLEMENTATION_TYPE, klass, super_class, NULL_TREE, |
| NULL_TREE); |
| objc_ivar_visibility = objc_default_ivar_visibility; |
| } |
| |
| void |
| objc_start_category_implementation (tree klass, tree categ) |
| { |
| objc_implementation_context |
| = start_class (CATEGORY_IMPLEMENTATION_TYPE, klass, categ, NULL_TREE, |
| NULL_TREE); |
| objc_ivar_chain |
| = continue_class (objc_implementation_context); |
| } |
| |
| void |
| objc_continue_implementation (void) |
| { |
| objc_ivar_chain |
| = continue_class (objc_implementation_context); |
| } |
| |
| 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_ivar_chain = NULL_TREE; |
| objc_implementation_context = NULL_TREE; |
| } |
| else |
| warning (0, "%<@end%> must appear in an @implementation context"); |
| } |
| |
| void |
| objc_set_visibility (objc_ivar_visibility_kind visibility) |
| { |
| if (visibility == OBJC_IVAR_VIS_PACKAGE) |
| { |
| if (flag_objc1_only) |
| error ("%<@package%> is not available in Objective-C 1.0"); |
| else |
| warning (0, "%<@package%> presently has the same effect as %<@public%>"); |
| } |
| objc_ivar_visibility = visibility; |
| } |
| |
| void |
| objc_set_method_opt (bool optional) |
| { |
| if (flag_objc1_only) |
| { |
| if (optional) |
| error_at (input_location, "%<@optional%> is not available in Objective-C 1.0"); |
| else |
| error_at (input_location, "%<@required%> is not available in Objective-C 1.0"); |
| } |
| |
| objc_method_optional_flag = optional; |
| if (!objc_interface_context |
| || TREE_CODE (objc_interface_context) != PROTOCOL_INTERFACE_TYPE) |
| { |
| if (optional) |
| error ("%<@optional%> is allowed in @protocol context only"); |
| else |
| error ("%<@required%> is allowed in @protocol context only"); |
| objc_method_optional_flag = false; |
| } |
| } |
| |
| /* This routine looks for a given PROPERTY in a list of CLASS, CATEGORY, or |
| PROTOCOL. */ |
| static tree |
| lookup_property_in_list (tree chain, tree property) |
| { |
| tree x; |
| for (x = CLASS_PROPERTY_DECL (chain); x; x = TREE_CHAIN (x)) |
| if (PROPERTY_NAME (x) == property) |
| return x; |
| return NULL_TREE; |
| } |
| |
| /* This routine looks for a given PROPERTY in the tree chain of RPROTO_LIST. */ |
| static tree lookup_property_in_protocol_list (tree rproto_list, tree property) |
| { |
| tree rproto, x; |
| for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto)) |
| { |
| tree p = TREE_VALUE (rproto); |
| if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) |
| { |
| if ((x = lookup_property_in_list (p, property))) |
| return x; |
| if (PROTOCOL_LIST (p)) |
| return lookup_property_in_protocol_list (PROTOCOL_LIST (p), property); |
| } |
| else |
| { |
| ; /* An identifier...if we could not find a protocol. */ |
| } |
| } |
| return NULL_TREE; |
| } |
| |
| /* This routine looks up the PROPERTY in current INTERFACE, its categories and up the |
| chain of interface hierarchy. */ |
| static tree |
| lookup_property (tree interface_type, tree property) |
| { |
| tree inter = interface_type; |
| while (inter) |
| { |
| tree x, category; |
| if ((x = lookup_property_in_list (inter, property))) |
| return x; |
| /* Failing that, look for the property in each category of the class. */ |
| category = inter; |
| while ((category = CLASS_CATEGORY_LIST (category))) |
| { |
| if ((x = lookup_property_in_list (category, property))) |
| return x; |
| |
| /* When checking a category, also check the protocols |
| attached with the category itself. */ |
| if (CLASS_PROTOCOL_LIST (category) |
| && (x = lookup_property_in_protocol_list |
| (CLASS_PROTOCOL_LIST (category), property))) |
| return x; |
| } |
| |
| /* Failing to find in categories, look for property in protocol list. */ |
| if (CLASS_PROTOCOL_LIST (inter) |
| && (x = lookup_property_in_protocol_list |
| (CLASS_PROTOCOL_LIST (inter), property))) |
| return x; |
| |
| /* Failing that, climb up the inheritance hierarchy. */ |
| inter = lookup_interface (CLASS_SUPER_NAME (inter)); |
| } |
| return inter; |
| } |
| |
| /* This routine returns a PROPERTY_KIND for the front end RID code supplied. */ |
| |
| enum objc_property_attribute_kind |
| objc_prop_attr_kind_for_rid (enum rid prop_rid) |
| { |
| switch (prop_rid) |
| { |
| default: return OBJC_PROPERTY_ATTR_UNKNOWN; |
| case RID_GETTER: return OBJC_PROPERTY_ATTR_GETTER; |
| case RID_SETTER: return OBJC_PROPERTY_ATTR_SETTER; |
| |
| case RID_READONLY: return OBJC_PROPERTY_ATTR_READONLY; |
| case RID_READWRITE: return OBJC_PROPERTY_ATTR_READWRITE; |
| |
| case RID_ASSIGN: return OBJC_PROPERTY_ATTR_ASSIGN; |
| case RID_RETAIN: return OBJC_PROPERTY_ATTR_RETAIN; |
| case RID_COPY: return OBJC_PROPERTY_ATTR_COPY; |
| |
| case RID_PROPATOMIC: return OBJC_PROPERTY_ATTR_ATOMIC; |
| case RID_NONATOMIC: return OBJC_PROPERTY_ATTR_NONATOMIC; |
| |
| case RID_NULL_UNSPECIFIED:return OBJC_PROPERTY_ATTR_NULL_UNSPECIFIED; |
| case RID_NULLABLE: return OBJC_PROPERTY_ATTR_NULLABLE; |
| case RID_NONNULL: return OBJC_PROPERTY_ATTR_NONNULL; |
| case RID_NULL_RESETTABLE: return OBJC_PROPERTY_ATTR_NULL_RESETTABLE; |
| |
| case RID_CLASS: return OBJC_PROPERTY_ATTR_CLASS; |
| } |
| } |
| |
| /* This routine is called by the parser when a |
| @property... declaration is found. 'decl' is the declaration of |
| the property (type/identifier), and the other arguments represent |
| property attributes that may have been specified in the Objective-C |
| declaration. 'parsed_property_readonly' is 'true' if the attribute |
| 'readonly' was specified, and 'false' if not; similarly for the |
| other bool parameters. 'property_getter_ident' is NULL_TREE |
| if the attribute 'getter' was not specified, and is the identifier |
| corresponding to the specified getter if it was; similarly for |
| 'property_setter_ident'. */ |
| void |
| objc_add_property_declaration (location_t location, tree decl, |
| vec<property_attribute_info *>& prop_attr_list) |
| { |
| if (flag_objc1_only) |
| /* FIXME: we probably ought to bail out at this point. */ |
| error_at (location, "%<@property%> is not available in Objective-C 1.0"); |
| |
| /* We must be in an interface, category, or protocol. */ |
| if (!objc_interface_context) |
| { |
| error_at (location, "property declaration not in %<@interface%>," |
| " %<@protocol%> or %<category%> context"); |
| return; |
| } |
| |
| /* Do some spot-checks for the most obvious invalid cases. */ |
| |
| gcc_checking_assert (decl && TREE_CODE (decl) == FIELD_DECL); |
| |
| if (decl && !DECL_NAME (decl)) |
| { |
| error_at (location, "properties must be named"); |
| return; |
| } |
| |
| location_t decl_loc = DECL_SOURCE_LOCATION (decl); |
| decl_loc = make_location (decl_loc, location, decl_loc); |
| if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) |
| { |
| error_at (decl_loc, "property cannot be an array"); |
| return; |
| } |
| |
| if (DECL_C_BIT_FIELD (decl)) |
| { |
| /* A @property is not an actual variable, but it is a way to |
| describe a pair of accessor methods, so its type (which is |
| the type of the return value of the getter and the first |
| argument of the setter) can't be a bitfield (as return values |
| and arguments of functions cannot be bitfields). The |
| underlying instance variable could be a bitfield, but that is |
| a different matter. */ |
| error_at (decl_loc, "property cannot be a bit-field"); |
| return; |
| } |
| |
| /* The final results of parsing the (growing number) of property |
| attributes. */ |
| property_attribute_info *attrs[OBJC_PROPATTR_GROUP_MAX] = { nullptr }; |
| |
| tree property_getter_ident = NULL_TREE; |
| tree property_setter_ident = NULL_TREE; |
| for (unsigned pn = 0; pn < prop_attr_list.length (); ++pn) |
| { |
| if (prop_attr_list[pn]->parse_error) |
| continue; /* Ignore attributes known to be wrongly parsed. */ |
| |
| switch (int g = (int) prop_attr_list[pn]->group()) |
| { |
| case OBJC_PROPATTR_GROUP_UNKNOWN: |
| continue; |
| case OBJC_PROPATTR_GROUP_SETTER: |
| case OBJC_PROPATTR_GROUP_GETTER: |
| if (attrs[g]) |
| { |
| warning_at (prop_attr_list[pn]->prop_loc, OPT_Wattributes, |
| "multiple property %qE methods specified, the latest" |
| " one will be used", attrs[g]->name); |
| inform (attrs[g]->prop_loc, "previous specification"); |
| } |
| attrs[g] = prop_attr_list[pn]; |
| if (g == OBJC_PROPATTR_GROUP_SETTER) |
| property_setter_ident = attrs[g]->ident; |
| else |
| property_getter_ident = attrs[g]->ident; |
| continue; |
| default: |
| { |
| if (!attrs[g]) |
| ; |
| else if (attrs[g]->prop_kind != prop_attr_list[pn]->prop_kind) |
| { |
| error_at (prop_attr_list[pn]->prop_loc, |
| "%qE attribute conflicts with %qE attribute", |
| prop_attr_list[pn]->name, attrs[g]->name); |
| inform (attrs[g]->prop_loc, "%qE specified here", |
| attrs[g]->name ); |
| } |
| else |
| { |
| warning_at (prop_attr_list[pn]->prop_loc, OPT_Wattributes, |
| "duplicate %qE attribute", attrs[g]->name); |
| inform (attrs[g]->prop_loc, "first specified here"); |
| } |
| attrs[g] = prop_attr_list[pn]; |
| } |
| continue; |
| } |
| } |
| |
| /* The defaults for atomicity (atomic) and write-ability (readwrite) apply |
| even if the user provides no specified attributes. */ |
| bool property_nonatomic = false; |
| bool property_readonly = false; |
| |
| /* Set the values from any specified by the user; these are easy, only two |
| states. */ |
| if (attrs[OBJC_PROPATTR_GROUP_ATOMIC]) |
| property_nonatomic = attrs[OBJC_PROPATTR_GROUP_ATOMIC]->prop_kind |
| == OBJC_PROPERTY_ATTR_NONATOMIC; |
| |
| if (attrs[OBJC_PROPATTR_GROUP_READWRITE]) |
| property_readonly = attrs[OBJC_PROPATTR_GROUP_READWRITE]->prop_kind |
| == OBJC_PROPERTY_ATTR_READONLY; |
| |
| /* One can't set a readonly value; we issue an error, but force the property |
| to readwrite as well. */ |
| if (property_readonly && property_setter_ident) |
| { |
| error_at (attrs[OBJC_PROPATTR_GROUP_READWRITE]->prop_loc, "%<readonly%>" |
| " attribute conflicts with %<setter%> attribute"); |
| gcc_checking_assert (attrs[OBJC_PROPATTR_GROUP_SETTER]); |
| inform (attrs[OBJC_PROPATTR_GROUP_SETTER]->prop_loc, "%<setter%>" |
| " specified here"); |
| property_readonly = false; |
| } |
| |
| /* Assign semantics is a tri-state property, and also needs some further |
| checking against the object type. */ |
| objc_property_assign_semantics property_assign_semantics |
| = OBJC_PROPERTY_ASSIGN; |
| |
| if (attrs[OBJC_PROPATTR_GROUP_ASSIGN]) |
| { |
| if (attrs[OBJC_PROPATTR_GROUP_ASSIGN]->prop_kind |
| == OBJC_PROPERTY_ATTR_ASSIGN) |
| property_assign_semantics = OBJC_PROPERTY_ASSIGN; |
| else if (attrs[OBJC_PROPATTR_GROUP_ASSIGN]->prop_kind |
| == OBJC_PROPERTY_ATTR_RETAIN) |
| property_assign_semantics = OBJC_PROPERTY_RETAIN; |
| else if (attrs[OBJC_PROPATTR_GROUP_ASSIGN]->prop_kind |
| == OBJC_PROPERTY_ATTR_COPY) |
| property_assign_semantics = OBJC_PROPERTY_COPY; |
| else |
| gcc_unreachable (); |
| } |
| |
| /* An attribute that indicates this property manipulates a class variable. |
| In this case, both the variable and the getter/setter must be provided |
| by the user. */ |
| bool property_class = false; |
| if (attrs[OBJC_PROPATTR_GROUP_CLASS]) |
| property_nonatomic = attrs[OBJC_PROPATTR_GROUP_CLASS]->prop_kind |
| == OBJC_PROPERTY_ATTR_CLASS; |
| |
| /* Nullability specifications for the property. */ |
| enum objc_property_nullability property_nullability |
| = OBJC_PROPERTY_NULL_UNSET; |
| if (attrs[OBJC_PROPATTR_GROUP_NULLABLE]) |
| { |
| if (attrs[OBJC_PROPATTR_GROUP_NULLABLE]->prop_kind |
| == OBJC_PROPERTY_ATTR_NULL_UNSPECIFIED) |
| property_nullability = OBJC_PROPERTY_NULL_UNSPECIFIED; |
| else if (attrs[OBJC_PROPATTR_GROUP_NULLABLE]->prop_kind |
| == OBJC_PROPERTY_ATTR_NULLABLE) |
| property_nullability = OBJC_PROPERTY_NULLABLE; |
| else if (attrs[OBJC_PROPATTR_GROUP_NULLABLE]->prop_kind |
| == OBJC_PROPERTY_ATTR_NONNULL) |
| property_nullability = OBJC_PROPERTY_NONNULL; |
| else if (attrs[OBJC_PROPATTR_GROUP_NULLABLE]->prop_kind |
| == OBJC_PROPERTY_ATTR_NULL_RESETTABLE) |
| property_nullability = OBJC_PROPERTY_NULL_RESETTABLE; |
| else |
| gcc_unreachable (); |
| } |
| |
| /* TODO: Check that the property type is an Objective-C object or a |
| "POD". */ |
| |
| /* Implement -Wproperty-assign-default (which is enabled by default). */ |
| if (warn_property_assign_default |
| /* If garbage collection is not being used, then 'assign' is |
| valid for objects (and typically used for delegates) but it |
| is wrong in most cases (since most objects need to be |
| retained or copied in setters). Warn users when 'assign' is |
| used implicitly. */ |
| && property_assign_semantics == OBJC_PROPERTY_ASSIGN |
| /* Read-only properties are never assigned, so the assignment |
| semantics do not matter in that case. */ |
| && !property_readonly |
| && !flag_objc_gc) |
| { |
| /* Please note that it would make sense to default to 'assign' |
| for non-{Objective-C objects}, and to 'retain' for |
| Objective-C objects. But that would break compatibility with |
| other compilers. */ |
| if (!attrs[OBJC_PROPATTR_GROUP_ASSIGN]) |
| { |
| /* Use 'false' so we do not warn for Class objects. */ |
| if (objc_type_valid_for_messaging (TREE_TYPE (decl), false)) |
| { |
| warning_at (decl_loc, 0, "object property %qD has no %<assign%>," |
| " %<retain%> or %<copy%> attribute; assuming" |
| " %<assign%>", decl); |
| inform (decl_loc, "%<assign%> can be unsafe for Objective-C" |
| " objects; please state explicitly if you need it"); |
| } |
| } |
| } |
| |
| /* Some attributes make no sense unless applied to an Objective-C object. */ |
| bool prop_objc_object_p |
| = objc_type_valid_for_messaging (TREE_TYPE (decl), true); |
| if (!prop_objc_object_p) |
| { |
| tree p_name = NULL_TREE; |
| if (property_assign_semantics == OBJC_PROPERTY_RETAIN |
| || property_assign_semantics == OBJC_PROPERTY_COPY) |
| p_name = attrs[OBJC_PROPATTR_GROUP_ASSIGN]->name; |
| |
| if (p_name) |
| error_at (decl_loc, "%qE attribute is only valid for Objective-C" |
| " objects", p_name); |
| } |
| |
| /* Now determine the final property getter and setter names. They |
| will be stored in the PROPERTY_DECL, from which they'll always be |
| extracted and used. */ |
| |
| /* Adjust, or fill in, setter and getter names. We overwrite the |
| property_setter_ident and property_getter_ident |
| with the final setter and getter identifiers that will be |
| used. */ |
| if (property_setter_ident) |
| { |
| /* The setter should be terminated by ':', but the parser only |
| gives us an identifier without ':'. So, we need to add ':' |
| at the end. */ |
| const char *parsed_setter = IDENTIFIER_POINTER (property_setter_ident); |
| size_t length = strlen (parsed_setter); |
| char *final_setter = (char *)alloca (length + 2); |
| |
| sprintf (final_setter, "%s:", parsed_setter); |
| property_setter_ident = get_identifier (final_setter); |
| } |
| else |
| { |
| if (!property_readonly) |
| property_setter_ident = get_identifier (objc_build_property_setter_name |
| (DECL_NAME (decl))); |
| } |
| |
| if (!property_getter_ident) |
| property_getter_ident = DECL_NAME (decl); |
| |
| /* Check for duplicate property declarations. We first check the |
| immediate context for a property with the same name. Any such |
| declarations are an error, unless this is a class extension and |
| we are extending a property from readonly to readwrite. */ |
| bool property_extension_in_class_extension = false; |
| tree x = NULL_TREE; |
| for (x = CLASS_PROPERTY_DECL (objc_interface_context); x; x = TREE_CHAIN (x)) |
| { |
| if (PROPERTY_NAME (x) == DECL_NAME (decl)) |
| { |
| if (objc_in_class_extension |
| && !property_readonly |
| && PROPERTY_READONLY (x) == 1) |
| { |
| /* This is a class extension, and we are extending an |
| existing readonly property to a readwrite one. |
| That's fine. :-) */ |
| property_extension_in_class_extension = true; |
| break; |
| } |
| else |
| { |
| location_t original_location = DECL_SOURCE_LOCATION (x); |
| |
| error_at (location, "redeclaration of property %qD", decl); |
| |
| if (original_location != UNKNOWN_LOCATION) |
| inform (original_location, "originally specified here"); |
| return; |
| } |
| } |
| } |
| |
| /* If x is not NULL_TREE, we must be in a class extension and we're |
| extending a readonly property. In that case, no point in |
| searching for another declaration. */ |
| if (x == NULL_TREE) |
| { |
| /* We now need to check for existing property declarations (in |
| the superclass, other categories or protocols) and check that |
| the new declaration is not in conflict with existing |
| ones. */ |
| |
| /* Search for a previous, existing declaration of a property |
| with the same name in superclasses, protocols etc. If one is |
| found, it will be in the 'x' variable. */ |
| |
| /* Note that, for simplicity, the following may search again the |
| local context. That's Ok as nothing will be found (else we'd |
| have thrown an error above); it's only a little inefficient, |
| but the code is simpler. */ |
| switch (TREE_CODE (objc_interface_context)) |
| { |
| case CLASS_INTERFACE_TYPE: |
| /* Look up the property in the current @interface (which |
| will find nothing), then its protocols and categories and |
| superclasses. */ |
| x = lookup_property (objc_interface_context, DECL_NAME (decl)); |
| break; |
| case CATEGORY_INTERFACE_TYPE: |
| /* Look up the property in the main @interface, then |
| protocols and categories (one of them is ours, and will |
| find nothing) and superclasses. */ |
| x = lookup_property (lookup_interface (CLASS_NAME (objc_interface_context)), |
| DECL_NAME (decl)); |
| break; |
| case PROTOCOL_INTERFACE_TYPE: |
| /* Looks up the property in any protocols attached to the |
| current protocol. */ |
| if (PROTOCOL_LIST (objc_interface_context)) |
| { |
| x = lookup_property_in_protocol_list (PROTOCOL_LIST (objc_interface_context), |
| DECL_NAME (decl)); |
| } |
| break; |
| default: |
| gcc_unreachable (); |
| } |
| } |
| |
| if (x != NULL_TREE) |
| { |
| /* An existing property was found; check that it has the same |
| types, or it is compatible. */ |
| location_t original_location = DECL_SOURCE_LOCATION (x); |
| |
| if (PROPERTY_NONATOMIC (x) != property_nonatomic) |
| { |
| warning_at (location, 0, |
| "%<nonatomic%> attribute of property %qD conflicts with " |
| "previous declaration", decl); |
| |
| if (original_location != UNKNOWN_LOCATION) |
| inform (original_location, "originally specified here"); |
| return; |
| } |
| |
| if (PROPERTY_GETTER_NAME (x) != property_getter_ident) |
| { |
| warning_at (location, 0, |
| "%<getter%> attribute of property %qD conflicts with " |
| "previous declaration", decl); |
| |
| if (original_location != UNKNOWN_LOCATION) |
| inform (original_location, "originally specified here"); |
| return; |
| } |
| |
| /* We can only compare the setter names if both the old and new property have a setter. */ |
| if (!property_readonly && !PROPERTY_READONLY(x)) |
| { |
| if (PROPERTY_SETTER_NAME (x) != property_setter_ident) |
| { |
| warning_at (location, 0, |
| "%<setter%> attribute of property %qD conflicts with " |
| "previous declaration", decl); |
| |
| if (original_location != UNKNOWN_LOCATION) |
| inform (original_location, "originally specified here"); |
| return; |
| } |
| } |
| |
| if (PROPERTY_ASSIGN_SEMANTICS (x) != property_assign_semantics) |
| { |
| warning_at (location, 0, |
| "assign semantics attributes of property %qD conflict with previous declaration", decl); |
| |
| if (original_location != UNKNOWN_LOCATION) |
| inform (original_location, "originally specified here"); |
| return; |
| } |
| |
| /* It's ok to have a readonly property that becomes a readwrite, but not vice versa. */ |
| if (PROPERTY_READONLY (x) == 0 && property_readonly == 1) |
| { |
| warning_at (location, 0, |
| "%<readonly%> attribute of property %qD conflicts with " |
| "previous declaration", decl); |
| |
| if (original_location != UNKNOWN_LOCATION) |
| inform (original_location, "originally specified here"); |
| return; |
| } |
| |
| /* We now check that the new and old property declarations have |
| the same types (or compatible one). In the Objective-C |
| tradition of loose type checking, we do type-checking but |
| only generate warnings (not errors) if they do not match. |
| For non-readonly properties, the types must match exactly; |
| for readonly properties, it is allowed to use a "more |
| specialized" type in the new property declaration. Eg, the |
| superclass has a getter returning (NSArray *) and the |
| subclass a getter returning (NSMutableArray *). The object's |
| getter returns an (NSMutableArray *); but if you cast the |
| object to the superclass, which is allowed, you'd still |
| expect the getter to return an (NSArray *), which works since |
| an (NSMutableArray *) is an (NSArray *) too. So, the set of |
| objects belonging to the type of the new @property should be |
| a subset of the set of objects belonging to the type of the |
| old @property. This is what "specialization" means. And the |
| reason it only applies to readonly properties is that for a |
| readwrite property the setter would have the opposite |
| requirement - ie that the superclass type is more specialized |
| then the subclass one; hence the only way to satisfy both |
| constraints is that the types match. */ |
| |
| /* If the types are not the same in the C sense, we warn ... */ |
| if (!comptypes (TREE_TYPE (x), TREE_TYPE (decl)) |
| /* ... unless the property is readonly, in which case we |
| allow a new, more specialized, declaration. */ |
| && (!property_readonly |
| || !objc_compare_types (TREE_TYPE (x), |
| TREE_TYPE (decl), -5, NULL_TREE))) |
| { |
| warning_at (location, 0, |
| "type of property %qD conflicts with previous declaration", decl); |
| if (original_location != UNKNOWN_LOCATION) |
| inform (original_location, "originally specified here"); |
| return; |
| } |
| |
| /* If we are in a class extension and we're extending a readonly |
| property in the main @interface, we'll just update the |
| existing property with the readwrite flag and potentially the |
| new setter name. */ |
| if (property_extension_in_class_extension) |
| { |
| PROPERTY_READONLY (x) = 0; |
| PROPERTY_SETTER_NAME (x) = property_setter_ident; |
| return; |
| } |
| } |
| |
| /* Create a PROPERTY_DECL node. */ |
| tree property_decl = make_node (PROPERTY_DECL); |
| |
| /* Copy the basic information from the original decl. */ |
| tree p_type = TREE_TYPE (decl); |
| TREE_TYPE (property_decl) = p_type; |
| DECL_SOURCE_LOCATION (property_decl) = DECL_SOURCE_LOCATION (decl); |
| TREE_DEPRECATED (property_decl) = TREE_DEPRECATED (decl); |
| TREE_UNAVAILABLE (property_decl) = TREE_UNAVAILABLE (decl); |
| |
| /* Add property-specific information. */ |
| PROPERTY_NAME (property_decl) = DECL_NAME (decl); |
| PROPERTY_GETTER_NAME (property_decl) = property_getter_ident; |
| PROPERTY_SETTER_NAME (property_decl) = property_setter_ident; |
| PROPERTY_READONLY (property_decl) = property_readonly; |
| PROPERTY_NONATOMIC (property_decl) = property_nonatomic; |
| PROPERTY_CLASS (property_decl) = property_class; |
| PROPERTY_ASSIGN_SEMANTICS (property_decl) = property_assign_semantics; |
| PROPERTY_IVAR_NAME (property_decl) = NULL_TREE; |
| PROPERTY_DYNAMIC (property_decl) = 0; |
| |
| /* FIXME: We seem to drop any existing DECL_ATTRIBUTES on the floor. */ |
| if (property_nullability != OBJC_PROPERTY_NULL_UNSET) |
| { |
| if (p_type && !POINTER_TYPE_P (p_type)) |
| error_at (decl_loc, "nullability specifier %qE cannot be applied to" |
| " non-pointer type %qT", |
| attrs[OBJC_PROPATTR_GROUP_NULLABLE]->name, p_type); |
| else if (p_type && POINTER_TYPE_P (p_type) && TREE_TYPE (p_type) |
| && POINTER_TYPE_P (TREE_TYPE (p_type))) |
| error_at (decl_loc, "nullability specifier %qE cannot be applied to" |
| " multi-level pointer type %qT", |
| attrs[OBJC_PROPATTR_GROUP_NULLABLE]->name, p_type); |
| else |
| { |
| tree attr_name = get_identifier ("objc_nullability"); |
| tree attr_value = build_int_cst (unsigned_type_node, |
| (unsigned)property_nullability); |
| tree nulla = build_tree_list (attr_name, attr_value); |
| DECL_ATTRIBUTES (property_decl) = nulla; |
| } |
| } |
| |
| /* Remember the fact that the property was found in the @optional |
| section in a @protocol, or not. */ |
| if (objc_method_optional_flag) |
| PROPERTY_OPTIONAL (property_decl) = 1; |
| else |
| PROPERTY_OPTIONAL (property_decl) = 0; |
| |
| /* Note that PROPERTY_GETTER_NAME is always set for all |
| PROPERTY_DECLs, and PROPERTY_SETTER_NAME is always set for all |
| PROPERTY_DECLs where PROPERTY_READONLY == 0. Any time we deal |
| with a getter or setter, we should get the PROPERTY_DECL and use |
| PROPERTY_GETTER_NAME and PROPERTY_SETTER_NAME to know the correct |
| names. */ |
| |
| /* Add the PROPERTY_DECL to the list of properties for the class. */ |
| TREE_CHAIN (property_decl) = CLASS_PROPERTY_DECL (objc_interface_context); |
| CLASS_PROPERTY_DECL (objc_interface_context) = property_decl; |
| } |
| |
| /* This is a subroutine of objc_maybe_build_component_ref. Search the |
| list of methods in the interface (and, failing that, the local list |
| in the implementation, and failing that, the protocol list) |
| provided for a 'setter' or 'getter' for 'component' with default |
| names (ie, if 'component' is "name", then search for "name" and |
| "setName:"). It is also possible to specify a different |
| 'getter_name' (this is used for @optional readonly properties). If |
| any is found, then create an artificial property that uses them. |
| Return NULL_TREE if 'getter' or 'setter' could not be found. */ |
| static tree |
| maybe_make_artificial_property_decl (tree interface, tree implementation, |
| tree protocol_list, tree component, bool is_class, |
| tree getter_name) |
| { |
| tree setter_name = get_identifier (objc_build_property_setter_name (component)); |
| tree getter = NULL_TREE; |
| tree setter = NULL_TREE; |
| |
| if (getter_name == NULL_TREE) |
| getter_name = component; |
| |
| /* First, check the @interface and all superclasses. */ |
| if (interface) |
| { |
| int flags = 0; |
| |
| /* Using instance methods of the root class as accessors is most |
| likely unwanted and can be extremely confusing (and, most |
| importantly, other Objective-C 2.0 compilers do not do it). |
| Turn it off. */ |
| if (is_class) |
| flags = OBJC_LOOKUP_CLASS | OBJC_LOOKUP_NO_INSTANCE_METHODS_OF_ROOT_CLASS; |
| |
| getter = lookup_method_static (interface, getter_name, flags); |
| setter = lookup_method_static (interface, setter_name, flags); |
| } |
| |
| /* Second, check the local @implementation context. */ |
| if (!getter && !setter) |
| { |
| if (implementation) |
| { |
| if (is_class) |
| { |
| getter = lookup_method (CLASS_CLS_METHODS (implementation), getter_name); |
| setter = lookup_method (CLASS_CLS_METHODS (implementation), setter_name); |
| } |
| else |
| { |
| getter = lookup_method (CLASS_NST_METHODS (implementation), getter_name); |
| setter = lookup_method (CLASS_NST_METHODS (implementation), setter_name); |
| } |
| } |
| } |
| |
| /* Try the protocol_list if we didn't find anything in the |
| @interface and in the @implementation. */ |
| if (!getter && !setter) |
| { |
| getter = lookup_method_in_protocol_list (protocol_list, getter_name, is_class); |
| setter = lookup_method_in_protocol_list (protocol_list, setter_name, is_class); |
| } |
| |
| /* There needs to be at least a getter or setter for this to be a |
| valid 'object.component' syntax. */ |
| if (getter || setter) |
| { |
| /* Yes ... determine the type of the expression. */ |
| tree property_decl; |
| tree type; |
| |
| if (getter) |
| type = TREE_VALUE (TREE_TYPE (getter)); |
| else |
| type = TREE_VALUE (TREE_TYPE (METHOD_SEL_ARGS (setter))); |
| |
| /* Create an artificial property declaration with the |
| information we collected on the type and getter/setter |
| names. */ |
| property_decl = make_node (PROPERTY_DECL); |
| |
| TREE_TYPE (property_decl) = type; |
| DECL_SOURCE_LOCATION (property_decl) = input_location; |
| TREE_DEPRECATED (property_decl) = 0; |
| TREE_UNAVAILABLE (property_decl) = 0; |
| DECL_ARTIFICIAL (property_decl) = 1; |
| |
| /* Add property-specific information. Note that one of |
| PROPERTY_GETTER_NAME or PROPERTY_SETTER_NAME may refer to a |
| non-existing method; this will generate an error when the |
| expression is later compiled. At this stage we don't know if |
| the getter or setter will be used, so we can't generate an |
| error. */ |
| PROPERTY_NAME (property_decl) = component; |
| PROPERTY_GETTER_NAME (property_decl) = getter_name; |
| PROPERTY_SETTER_NAME (property_decl) = setter_name; |
| PROPERTY_READONLY (property_decl) = 0; |
| PROPERTY_NONATOMIC (property_decl) = 0; |
| PROPERTY_ASSIGN_SEMANTICS (property_decl) = 0; |
| PROPERTY_IVAR_NAME (property_decl) = NULL_TREE; |
| PROPERTY_DYNAMIC (property_decl) = 0; |
| PROPERTY_OPTIONAL (property_decl) = 0; |
| |
| if (!getter) |
| PROPERTY_HAS_NO_GETTER (property_decl) = 1; |
| |
| /* The following is currently unused, but it's nice to have |
| there. We may use it if we need in the future. */ |
| if (!setter) |
| PROPERTY_HAS_NO_SETTER (property_decl) = 1; |
| |
| return property_decl; |
| } |
| |
| return NULL_TREE; |
| } |
| |
| /* This hook routine is invoked by the parser when an expression such |
| as 'xxx.yyy' is parsed. We get a chance to process these |
| expressions in a way that is specified to Objective-C (to implement |
| the Objective-C 2.0 dot-syntax, properties, or non-fragile ivars). |
| If the expression is not an Objective-C specified expression, we |
| should return NULL_TREE; else we return the expression. |
| |
| At the moment this only implements dot-syntax and properties (not |
| non-fragile ivars yet), ie 'object.property' or 'object.component' |
| where 'component' is not a declared property, but a valid getter or |
| setter for it could be found. */ |
| tree |
| objc_maybe_build_component_ref (tree object, tree property_ident) |
| { |
| tree x = NULL_TREE; |
| tree rtype; |
| |
| /* If we are in Objective-C 1.0 mode, dot-syntax and properties are |
| not available. */ |
| if (flag_objc1_only) |
| return NULL_TREE; |
| |
| /* Try to determine if 'object' is an Objective-C object or not. If |
| not, return. */ |
| if (object == NULL_TREE || object == error_mark_node |
| || (rtype = TREE_TYPE (object)) == NULL_TREE) |
| return NULL_TREE; |
| |
| if (property_ident == NULL_TREE || property_ident == error_mark_node |
| || TREE_CODE (property_ident) != IDENTIFIER_NODE) |
| return NULL_TREE; |
| |
| /* The following analysis of 'object' is similar to the one used for |
| the 'receiver' of a method invocation. We need to determine what |
| 'object' is and find the appropriate property (either declared, |
| or artificial) for it (in the same way as we need to find the |
| appropriate method prototype for a method invocation). There are |
| some simplifications here though: "object.property" is invalid if |
| "object" has a type of "id" or "Class"; it must at least have a |
| protocol attached to it, and "object" is never a class name as |
| that is done by objc_build_class_component_ref. Finally, we |
| don't know if this really is a dot-syntax expression, so we want |
| to make a quick exit if it is not; for this reason, we try to |
| postpone checks after determining that 'object' looks like an |
| Objective-C object. */ |
| |
| if (objc_is_id (rtype)) |
| { |
| /* This is the case that the 'object' is of type 'id' or |
| 'Class'. */ |
| |
| /* Check if at least it is of type 'id <Protocol>' or 'Class |
| <Protocol>'; if so, look the property up in the |
| protocols. */ |
| if (TYPE_HAS_OBJC_INFO (TREE_TYPE (rtype))) |
| { |
| tree rprotos = TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (rtype)); |
| |
| if (rprotos) |
| { |
| /* No point looking up declared @properties if we are |
| dealing with a class. Classes have no declared |
| properties. */ |
| if (!IS_CLASS (rtype)) |
| x = lookup_property_in_protocol_list (rprotos, property_ident); |
| |
| if (x == NULL_TREE) |
| { |
| /* Ok, no property. Maybe it was an |
| object.component dot-syntax without a declared |
| property (this is valid for classes too). Look |
| for getter/setter methods and internally declare |
| an artificial property based on them if found. */ |
| x = maybe_make_artificial_property_decl (NULL_TREE, |
| NULL_TREE, |
| rprotos, |
| property_ident, |
| IS_CLASS (rtype), |
| NULL_TREE); |
| } |
| else if (PROPERTY_OPTIONAL (x) && PROPERTY_READONLY (x)) |
| { |
| /* This is a special, complicated case. If the |
| property is optional, and is read-only, then the |
| property is always used for reading, but an |
| eventual existing non-property setter can be used |
| for writing. We create an artificial property |
| decl copying the getter from the optional |
| property, and looking up the setter in the |
| interface. */ |
| x = maybe_make_artificial_property_decl (NULL_TREE, |
| NULL_TREE, |
| rprotos, |
| property_ident, |
| false, |
| PROPERTY_GETTER_NAME (x)); |
| } |
| } |
| } |
| else if (objc_method_context) |
| { |
| /* Else, if we are inside a method it could be the case of |
| 'super' or 'self'. */ |
| tree interface_type = NULL_TREE; |
| tree t = object; |
| while (TREE_CODE (t) == COMPOUND_EXPR |
| || TREE_CODE (t) == MODIFY_EXPR |
| || CONVERT_EXPR_P (t) |
| || TREE_CODE (t) == COMPONENT_REF) |
| t = TREE_OPERAND (t, 0); |
| |
| STRIP_ANY_LOCATION_WRAPPER (t); |
| |
| if (t == UOBJC_SUPER_decl) |
| interface_type = lookup_interface (CLASS_SUPER_NAME (implementation_template)); |
| else if (t == self_decl) |
| interface_type = lookup_interface (CLASS_NAME (implementation_template)); |
| |
| if (interface_type) |
| { |
| if (TREE_CODE (objc_method_context) != CLASS_METHOD_DECL) |
| x = lookup_property (interface_type, property_ident); |
| |
| if (x == NULL_TREE) |
| { |
| /* Try the dot-syntax without a declared property. |
| If this is an access to 'self', it is possible |
| that they may refer to a setter/getter that is |
| not declared in the interface, but exists locally |
| in the implementation. In that case, get the |
| implementation context and use it. */ |
| tree implementation = NULL_TREE; |
| |
| if (t == self_decl) |
| implementation = objc_implementation_context; |
| |
| x = maybe_make_artificial_property_decl |
| (interface_type, implementation, NULL_TREE, |
| property_ident, |
| (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL), |
| NULL_TREE); |
| } |
| else if (PROPERTY_OPTIONAL (x) && PROPERTY_READONLY (x)) |
| { |
| tree implementation = NULL_TREE; |
| |
| if (t == self_decl) |
| implementation = objc_implementation_context; |
| |
| x = maybe_make_artificial_property_decl (interface_type, |
| implementation, |
| NULL_TREE, |
| property_ident, |
| false, |
| PROPERTY_GETTER_NAME (x)); |
| } |
| } |
| } |
| } |
| else |
| { |
| /* This is the case where we have more information on 'rtype'. */ |
| tree basetype = TYPE_MAIN_VARIANT (rtype); |
| |
| /* Skip the pointer - if none, it's not an Objective-C object or |
| class. */ |
| if (basetype != NULL_TREE && TREE_CODE (basetype) == POINTER_TYPE) |
| basetype = TREE_TYPE (basetype); |
| else |
| return NULL_TREE; |
| |
| /* Traverse typedefs. */ |
| while (basetype != NULL_TREE |
| && TREE_CODE (basetype) == RECORD_TYPE |
| && OBJC_TYPE_NAME (basetype) |
| && TREE_CODE (OBJC_TYPE_NAME (basetype)) == TYPE_DECL |
| && DECL_ORIGINAL_TYPE (OBJC_TYPE_NAME (basetype))) |
| basetype = DECL_ORIGINAL_TYPE (OBJC_TYPE_NAME (basetype)); |
| |
| if (basetype != NULL_TREE && TYPED_OBJECT (basetype)) |
| { |
| tree interface_type = TYPE_OBJC_INTERFACE (basetype); |
| tree protocol_list = TYPE_OBJC_PROTOCOL_LIST (basetype); |
| |
| if (interface_type |
| && (TREE_CODE (interface_type) == CLASS_INTERFACE_TYPE |
| || TREE_CODE (interface_type) == CATEGORY_INTERFACE_TYPE |
| || TREE_CODE (interface_type) == PROTOCOL_INTERFACE_TYPE)) |
| { |
| /* Not sure 'rtype' could ever be a class here! Just |
| for safety we keep the checks. */ |
| if (!IS_CLASS (rtype)) |
| { |
| x = lookup_property (interface_type, property_ident); |
| |
| if (x == NULL_TREE) |
| x = lookup_property_in_protocol_list (protocol_list, |
| property_ident); |
| } |
| |
| if (x == NULL_TREE) |
| { |
| /* Try the dot-syntax without a declared property. |
| If we are inside a method implementation, it is |
| possible that they may refer to a setter/getter |
| that is not declared in the interface, but exists |
| locally in the implementation. In that case, get |
| the implementation context and use it. */ |
| tree implementation = NULL_TREE; |
| |
| if (objc_implementation_context |
| && CLASS_NAME (objc_implementation_context) |
| == OBJC_TYPE_NAME (interface_type)) |
| implementation = objc_implementation_context; |
| |
| x = maybe_make_artificial_property_decl (interface_type, |
| implementation, |
| protocol_list, |
| property_ident, |
| IS_CLASS (rtype), |
| NULL_TREE); |
| } |
| else if (PROPERTY_OPTIONAL (x) && PROPERTY_READONLY (x)) |
| { |
| tree implementation = NULL_TREE; |
| |
| if (objc_implementation_context |
| && CLASS_NAME (objc_implementation_context) |
| == OBJC_TYPE_NAME (interface_type)) |
| implementation = objc_implementation_context; |
| |
| x = maybe_make_artificial_property_decl (interface_type, |
| implementation, |
| protocol_list, |
| property_ident, |
| false, |
| PROPERTY_GETTER_NAME (x)); |
| } |
| } |
| } |
| } |
| |
| if (x) |
| { |
| tree expression; |
| tree getter_call; |
| tree method_prototype_avail = NULL_TREE; |
| |
| /* We have an additional nasty problem here; if this |
| PROPERTY_REF needs to become a 'getter', then the conversion |
| from PROPERTY_REF into a getter call happens in gimplify, |
| after the selector table has already been generated and when |
| it is too late to add another selector to it. To work around |
| the problem, we always create the getter call at this stage, |
| which puts the selector in the table. Note that if the |
| PROPERTY_REF becomes a 'setter' instead of a 'getter', then |
| we have added a selector too many to the selector table. |
| This is a little inefficient. |
| |
| Also note that method calls to 'self' and 'super' require the |
| context (self_decl, UOBJS_SUPER_decl, |
| objc_implementation_context etc) to be built correctly; this |
| is yet another reason why building the call at the gimplify |
| stage (when this context has been lost) is not very |
| practical. If we build it at this stage, we know it will |
| always be built correctly. |
| |
| If the PROPERTY_HAS_NO_GETTER() (ie, it is an artificial |
| property decl created to deal with a dotsyntax not really |
| referring to an existing property) then do not try to build a |
| call to the getter as there is no getter. */ |
| if (PROPERTY_HAS_NO_GETTER (x)) |
| getter_call = NULL_TREE; |
| else |
| getter_call = objc_finish_message_expr |
| (object, PROPERTY_GETTER_NAME (x), NULL_TREE, |
| /* Disable the immediate deprecation warning if the getter |
| is deprecated, but record the fact that the getter is |
| deprecated by setting PROPERTY_REF_DEPRECATED_GETTER to |
| the method prototype. */ |
| &method_prototype_avail); |
| |
| expression = build4 (PROPERTY_REF, TREE_TYPE(x), object, x, getter_call, |
| method_prototype_avail); |
| SET_EXPR_LOCATION (expression, input_location); |
| TREE_SIDE_EFFECTS (expression) = 1; |
| |
| return expression; |
| } |
| |
| return NULL_TREE; |
| } |
| |
| /* This hook routine is invoked by the parser when an expression such |
| as 'xxx.yyy' is parsed, and 'xxx' is a class name. This is the |
| Objective-C 2.0 dot-syntax applied to classes, so we need to |
| convert it into a setter/getter call on the class. */ |
| tree |
| objc_build_class_component_ref (tree class_name, tree property_ident) |
| { |
| tree x = NULL_TREE; |
| tree object, rtype; |
| |
| if (flag_objc1_only) |
| error_at (input_location, "the dot syntax is not available in Objective-C 1.0"); |
| |
| if (class_name == NULL_TREE || class_name == error_mark_node |
| || TREE_CODE (class_name) != IDENTIFIER_NODE) |
| return error_mark_node; |
| |
| if (property_ident == NULL_TREE || property_ident == error_mark_node |
| || TREE_CODE (property_ident) != IDENTIFIER_NODE) |
| return NULL_TREE; |
| |
| object = objc_get_class_reference (class_name); |
| if (!object) |
| { |
| /* We know that 'class_name' is an Objective-C class name as the |
| parser won't call this function if it is not. This is only a |
| double-check for safety. */ |
| error_at (input_location, "could not find class %qE", class_name); |
| return error_mark_node; |
| } |
| |
| rtype = lookup_interface (class_name); |
| if (!rtype) |
| { |
| /* Again, this should never happen, but we do check. */ |
| error_at (input_location, "could not find interface for class %qE", class_name); |
| return error_mark_node; |
| } |
| else |
| { |
| if (TREE_UNAVAILABLE (rtype)) |
| error ("class %qE is unavailable", class_name); |
| else if (TREE_DEPRECATED (rtype)) |
| warning (OPT_Wdeprecated_declarations, "class %qE is deprecated", class_name); |
| } |
| |
| x = maybe_make_artificial_property_decl (rtype, NULL_TREE, NULL_TREE, |
| property_ident, |
| true, NULL_TREE); |
| |
| if (x) |
| { |
| tree expression; |
| tree getter_call; |
| tree method_prototype_avail = NULL_TREE; |
| |
| if (PROPERTY_HAS_NO_GETTER (x)) |
| getter_call = NULL_TREE; |
| else |
| getter_call = objc_finish_message_expr |
| (object, PROPERTY_GETTER_NAME (x), NULL_TREE, |
| &method_prototype_avail); |
| |
| expression = build4 (PROPERTY_REF, TREE_TYPE(x), object, x, getter_call, |
| method_prototype_avail); |
| SET_EXPR_LOCATION (expression, input_location); |
| TREE_SIDE_EFFECTS (expression) = 1; |
| |
| return expression; |
| } |
| else |
| { |
| error_at (input_location, "could not find setter/getter for %qE in class %qE", |
| property_ident, class_name); |
| return error_mark_node; |
| } |
| |
| return NULL_TREE; |
| } |
| |
| |
| /* This is used because we don't want to expose PROPERTY_REF to the |
| C/C++ frontends. Maybe we should! */ |
| bool |
| objc_is_property_ref (tree node) |
| { |
| if (node && TREE_CODE (node) == PROPERTY_REF) |
| return true; |
| else |
| return false; |
| } |
| |
| /* We use this to report tree codes that are known to be invalid in const- |
| expression contexts. */ |
| bool |
| objc_non_constant_expr_p (tree node) |
| { |
| switch (TREE_CODE (node)) |
| { |
| default: |
| return false; |
| case MESSAGE_SEND_EXPR: |
| case PROPERTY_REF: |
| return true; |
| } |
| } |
| |
| /* This function builds a setter call for a PROPERTY_REF (real, for a |
| declared property, or artificial, for a dot-syntax accessor which |
| is not corresponding to a property). 'lhs' must be a PROPERTY_REF |
| (the caller must check this beforehand). 'rhs' is the value to |
| assign to the property. A plain setter call is returned, or |
| error_mark_node if the property is readonly. */ |
| |
| static tree |
| objc_build_setter_call (tree lhs, tree rhs) |
| { |
| tree object_expr = PROPERTY_REF_OBJECT (lhs); |
| tree property_decl = PROPERTY_REF_PROPERTY_DECL (lhs); |
| |
| if (PROPERTY_READONLY (property_decl)) |
| { |
| error ("%qs property cannot be set", "readonly"); |
| return error_mark_node; |
| } |
| else |
| { |
| tree setter_argument = build_tree_list (NULL_TREE, rhs); |
| tree setter; |
| |
| /* TODO: Check that the setter return type is 'void'. */ |
| |
| /* TODO: Decay arguments in C. */ |
| setter = objc_finish_message_expr (object_expr, |
| PROPERTY_SETTER_NAME (property_decl), |
| setter_argument, NULL); |
| return setter; |
| } |
| } |
| |
| /* This hook routine is called when a MODIFY_EXPR is being built. We |
| check what is being modified; if it is a PROPERTY_REF, we need to |
| generate a 'setter' function call for the property. If this is not |
| a PROPERTY_REF, we return NULL_TREE and the C/C++ frontend will go |
| on creating their MODIFY_EXPR. |
| |
| This is used for example if you write |
| |
| object.count = 1; |
| |
| where 'count' is a property. The left-hand side creates a |
| PROPERTY_REF, and then the compiler tries to generate a MODIFY_EXPR |
| to assign something to it. We intercept that here, and generate a |
| call to the 'setter' method instead. */ |
| tree |
| objc_maybe_build_modify_expr (tree lhs, tree rhs) |
| { |
| if (lhs && TREE_CODE (lhs) == PROPERTY_REF) |
| { |
| /* Building a simple call to the setter method would work for cases such as |
| |
| object.count = 1; |
| |
| but wouldn't work for cases such as |
| |
| count = object2.count = 1; |
| |
| to get these to work with very little effort, we build a |
| compound statement which does the setter call (to set the |
| property to 'rhs'), but which can also be evaluated returning |
| the 'rhs'. If the 'rhs' has no side effects, we can simply |
| evaluate it twice, building |
| |
| ([object setProperty: rhs]; rhs) |
| |
| If it has side effects, we put it in a temporary variable first, |
| so we create the following: |
| |
| (temp = rhs; [object setProperty: temp]; temp) |
| |
| setter_argument is rhs in the first case, and temp in the second |
| case. |
| */ |
| tree setter_argument; |
| |
| /* s1, s2 and s3 are the tree statements that we need in the |
| compound expression. */ |
| tree s1, s2, s3, compound_expr; |
| |
| if (TREE_SIDE_EFFECTS (rhs)) |
| { |
| tree bind; |
| |
| /* Declare __objc_property_temp in a local bind. */ |
| setter_argument = objc_create_temporary_var (TREE_TYPE (rhs), "__objc_property_temp"); |
| DECL_SOURCE_LOCATION (setter_argument) = input_location; |
| bind = build3 (BIND_EXPR, void_type_node, setter_argument, NULL, NULL); |
| SET_EXPR_LOCATION (bind, input_location); |
| TREE_SIDE_EFFECTS (bind) = 1; |
| add_stmt (bind); |
| |
| /* s1: x = rhs */ |
| s1 = build_modify_expr (input_location, setter_argument, NULL_TREE, |
| NOP_EXPR, |
| input_location, rhs, NULL_TREE); |
| SET_EXPR_LOCATION (s1, input_location); |
| } |
| else |
| { |
| /* No s1. */ |
| setter_argument = rhs; |
| s1 = NULL_TREE; |
| } |
| |
| /* Now build the compound statement. */ |
| |
| /* s2: [object setProperty: x] */ |
| s2 = objc_build_setter_call (lhs, setter_argument); |
| |
| /* This happens if building the setter failed because the |
| property is readonly. */ |
| if (s2 == error_mark_node) |
| return error_mark_node; |
| |
| SET_EXPR_LOCATION (s2, input_location); |
| |
| /* s3: x */ |
| s3 = convert (TREE_TYPE (lhs), setter_argument); |
| |
| /* Now build the compound statement (s1, s2, s3) or (s2, s3) as |
| appropriate. */ |
| if (s1) |
| compound_expr = build_compound_expr (input_location, build_compound_expr (input_location, s1, s2), s3); |
| else |
| compound_expr = build_compound_expr (input_location, s2, s3); |
| |
| /* Without this, with -Wall you get a 'valued computed is not |
| used' every time there is a "object.property = x" where the |
| value of the resulting MODIFY_EXPR is not used. That is |
| correct (maybe a more sophisticated implementation could |
| avoid generating the compound expression if not needed), but |
| we need to turn it off. */ |
| suppress_warning (compound_expr, OPT_Wunused); |
| return compound_expr; |
| } |
| else |
| return NULL_TREE; |
| } |
| |
| /* This hook is called by the frontend when one of the four unary |
| expressions PREINCREMENT_EXPR, POSTINCREMENT_EXPR, |
| PREDECREMENT_EXPR and POSTDECREMENT_EXPR is being built with an |
| argument which is a PROPERTY_REF. For example, this happens if you have |
| |
| object.count++; |
| |
| where 'count' is a property. We need to use the 'getter' and |
| 'setter' for the property in an appropriate way to build the |
| appropriate expression. 'code' is the code for the expression (one |
| of the four mentioned above); 'argument' is the PROPERTY_REF, and |
| 'increment' is how much we need to add or subtract. */ |
| tree |
| objc_build_incr_expr_for_property_ref (location_t location, |
| enum tree_code code, |
| tree argument, tree increment) |
| { |
| /* Here are the expressions that we want to build: |
| |
| For PREINCREMENT_EXPR / PREDECREMENT_EXPR: |
| (temp = [object property] +/- increment, [object setProperty: temp], temp) |
| |
| For POSTINCREMENT_EXPR / POSTECREMENT_EXPR: |
| (temp = [object property], [object setProperty: temp +/- increment], temp) */ |
| |
| tree temp_variable_decl, bind; |
| /* s1, s2 and s3 are the tree statements that we need in the |
| compound expression. */ |
| tree s1, s2, s3, compound_expr; |
| |
| /* Safety check. */ |
| if (!argument || TREE_CODE (argument) != PROPERTY_REF) |
| return error_mark_node; |
| |
| /* Declare __objc_property_temp in a local bind. */ |
| temp_variable_decl = objc_create_temporary_var (TREE_TYPE (argument), "__objc_property_temp"); |
| DECL_SOURCE_LOCATION (temp_variable_decl) = location; |
| bind = build3 (BIND_EXPR, void_type_node, temp_variable_decl, NULL, NULL); |
| SET_EXPR_LOCATION (bind, location); |
| TREE_SIDE_EFFECTS (bind) = 1; |
| add_stmt (bind); |
| |
| /* Now build the compound statement. */ |
| |
| /* Note that the 'getter' is generated at gimplify time; at this |
| time, we can simply put the property_ref (ie, argument) wherever |
| we want the getter ultimately to be. */ |
| |
| /* s1: __objc_property_temp = [object property] <+/- increment> */ |
| switch (code) |
| { |
| case PREINCREMENT_EXPR: |
| /* __objc_property_temp = [object property] + increment */ |
| s1 = build_modify_expr (location, temp_variable_decl, NULL_TREE, |
| NOP_EXPR, |
| location, build2 (PLUS_EXPR, TREE_TYPE (argument), |
| argument, increment), NULL_TREE); |
| break; |
| case PREDECREMENT_EXPR: |
| /* __objc_property_temp = [object property] - increment */ |
| s1 = build_modify_expr (location, temp_variable_decl, NULL_TREE, |
| NOP_EXPR, |
| location, build2 (MINUS_EXPR, TREE_TYPE (argument), |
| argument, increment), NULL_TREE); |
| break; |
| case POSTINCREMENT_EXPR: |
| case POSTDECREMENT_EXPR: |
| /* __objc_property_temp = [object property] */ |
| s1 = build_modify_expr (location, temp_variable_decl, NULL_TREE, |
| NOP_EXPR, |
| location, argument, NULL_TREE); |
| break; |
| default: |
| gcc_unreachable (); |
| } |
| |
| /* s2: [object setProperty: __objc_property_temp <+/- increment>] */ |
| switch (code) |
| { |
| case PREINCREMENT_EXPR: |
| case PREDECREMENT_EXPR: |
| /* [object setProperty: __objc_property_temp] */ |
| s2 = objc_build_setter_call (argument, temp_variable_decl); |
| break; |
| case POSTINCREMENT_EXPR: |
| /* [object setProperty: __objc_property_temp + increment] */ |
| s2 = objc_build_setter_call (argument, |
| build2 (PLUS_EXPR, TREE_TYPE (argument), |
| temp_variable_decl, increment)); |
| break; |
| case POSTDECREMENT_EXPR: |
| /* [object setProperty: __objc_property_temp - increment] */ |
| s2 = objc_build_setter_call (argument, |
| build2 (MINUS_EXPR, TREE_TYPE (argument), |
| temp_variable_decl, increment)); |
| break; |
| default: |
| gcc_unreachable (); |
| } |
| |
| /* This happens if building the setter failed because the property |
| is readonly. */ |
| if (s2 == error_mark_node) |
| return error_mark_node; |
| |
| SET_EXPR_LOCATION (s2, location); |
| |
| /* s3: __objc_property_temp */ |
| s3 = convert (TREE_TYPE (argument), temp_variable_decl); |
| |
| /* Now build the compound statement (s1, s2, s3) */ |
| compound_expr = build_compound_expr (location, build_compound_expr (location, s1, s2), s3); |
| |
| /* Prevent C++ from warning with -Wall that "right operand of comma |
| operator has no effect". */ |
| suppress_warning (compound_expr, OPT_Wunused); |
| return compound_expr; |
| } |
| |
| tree |
| objc_build_method_signature (bool is_class_method, tree rettype, tree selector, |
| tree optparms, bool ellipsis) |
| { |
| if (is_class_method) |
| return build_method_decl (CLASS_METHOD_DECL, rettype, selector, |
| optparms, ellipsis); |
| else |
| return build_method_decl (INSTANCE_METHOD_DECL, rettype, selector, |
| optparms, ellipsis); |
| } |
| |
| void |
| objc_add_method_declaration (bool is_class_method, tree decl, tree attributes) |
| { |
| if (!objc_interface_context) |
| { |
| /* PS: At the moment, due to how the parser works, it should be |
| impossible to get here. But it's good to have the check in |
| case the parser changes. |
| */ |
| fatal_error (input_location, |
| "method declaration not in @interface context"); |
| } |
| |
| if (flag_objc1_only && attributes) |
| error_at (input_location, "method attributes are not available in Objective-C 1.0"); |
| |
| objc_decl_method_attributes (&decl, attributes, 0); |
| objc_add_method (objc_interface_context, |
| decl, |
| is_class_method, |
| objc_method_optional_flag); |
| } |
| |
| /* Return 'true' if the method definition could be started, and |
| 'false' if not (because we are outside an @implementation context). |
| EXPR is NULL or an expression that needs to be evaluated for the |
| side effects of array size expressions in the parameters. |
| */ |
| bool |
| objc_start_method_definition (bool is_class_method, tree decl, tree attributes, |
| tree expr) |
| { |
| if (!objc_implementation_context) |
| { |
| error ("method definition not in @implementation context"); |
| return false; |
| } |
| |
| if (decl != NULL_TREE && METHOD_SEL_NAME (decl) == error_mark_node) |
| return false; |
| |
| #ifndef OBJCPLUS |
| /* Indicate no valid break/continue context. */ |
| in_statement = 0; |
| #endif |
| |
| if (attributes) |
| warning_at (input_location, 0, "method attributes cannot be specified in @implementation context"); |
| else |
| objc_decl_method_attributes (&decl, attributes, 0); |
| |
| objc_add_method (objc_implementation_context, |
| decl, |
| is_class_method, |
| /* is optional */ false); |
| start_method_def (decl, expr); |
| return true; |
| } |
| |
| void |
| objc_add_instance_variable (tree decl) |
| { |
| (void) add_instance_variable (objc_ivar_context, |
| objc_ivar_visibility, |
| decl); |
| } |
| |
| /* Construct a C struct with same name as KLASS, a base struct with tag |
| SUPER_NAME (if any), and FIELDS indicated. */ |
| |
| static tree |
| objc_build_struct (tree klass, tree fields, tree super_name) |
| { |
| tree name = CLASS_NAME (klass); |
| tree s = objc_start_struct (name); |
| tree super = (super_name ? xref_tag (RECORD_TYPE, super_name) : NULL_TREE); |
| tree t; |
| vec<tree> objc_info = vNULL; |
| int i; |
| |
| if (super) |
| { |
| /* Prepend a packed variant of the base class into the layout. This |
| is necessary to preserve ObjC ABI compatibility. */ |
| tree base = build_decl (input_location, |
| FIELD_DECL, NULL_TREE, super); |
| tree field = TYPE_FIELDS (super); |
| |
| while (field && DECL_CHAIN (field) |
| && TREE_CODE (DECL_CHAIN (field)) == FIELD_DECL) |
| field = DECL_CHAIN (field); |
| |
| /* For ObjC ABI purposes, the "packed" size of a base class is |
| the sum of the offset and the size (in bits) of the last field |
| in the class. */ |
| DECL_SIZE (base) |
| = (field && TREE_CODE (field) == FIELD_DECL |
| ? size_binop (PLUS_EXPR, |
| size_binop (PLUS_EXPR, |
| size_binop |
| (MULT_EXPR, |
| convert (bitsizetype, |
| DECL_FIELD_OFFSET (field)), |
| bitsize_int (BITS_PER_UNIT)), |
| DECL_FIELD_BIT_OFFSET (field)), |
| DECL_SIZE (field)) |
| : bitsize_zero_node); |
| DECL_SIZE_UNIT (base) |
| = size_binop (FLOOR_DIV_EXPR, convert (sizetype, DECL_SIZE (base)), |
| size_int (BITS_PER_UNIT)); |
| DECL_ARTIFICIAL (base) = 1; |
| SET_DECL_ALIGN (base, 1); |
| DECL_FIELD_CONTEXT (base) = s; |
| #ifdef OBJCPLUS |
| DECL_FIELD_IS_BASE (base) = 1; |
| |
| if (fields) |
| /* Suppress C++ ABI warnings: we are following the ObjC ABI here. */ |
| suppress_warning (fields, OPT_Wabi); |
| #endif |
| DECL_CHAIN (base) = fields; |
| fields = base; |
| } |
| |
| /* NB: Calling finish_struct() may cause type TYPE_OBJC_INFO |
| information in all variants of this RECORD_TYPE to be destroyed |
| (this is because the C frontend manipulates TYPE_LANG_SPECIFIC |
| for something else and then will change all variants to use the |
| same resulting TYPE_LANG_SPECIFIC, ignoring the fact that we use |
| it for ObjC protocols and that such propagation will make all |
| variants use the same objc_info), but it is therein that we store |
| protocol conformance info (e.g., 'NSObject <MyProtocol>'). |
| Hence, we must save the ObjC-specific information before calling |
| finish_struct(), and then reinstate it afterwards. */ |
| |
| for (t = TYPE_MAIN_VARIANT (s); t; t = TYPE_NEXT_VARIANT (t)) |
| { |
| INIT_TYPE_OBJC_INFO (t); |
| objc_info.safe_push (TYPE_OBJC_INFO (t)); |
| } |
| |
| s = objc_finish_struct (s, fields); |
| |
| for (i = 0, t = TYPE_MAIN_VARIANT (s); t; t = TYPE_NEXT_VARIANT (t), i++) |
| { |
| /* We now want to restore the different TYPE_OBJC_INFO, but we |
| have the additional problem that the C frontend doesn't just |
| copy TYPE_LANG_SPECIFIC from one variant to the other; it |
| actually makes all of them the *same* TYPE_LANG_SPECIFIC. As |
| we need a different TYPE_OBJC_INFO for each (and |
| TYPE_OBJC_INFO is a field in TYPE_LANG_SPECIFIC), we need to |
| make a copy of each TYPE_LANG_SPECIFIC before we modify |
| TYPE_OBJC_INFO. */ |
| if (TYPE_LANG_SPECIFIC (t)) |
| { |
| /* Create a copy of TYPE_LANG_SPECIFIC. */ |
| struct lang_type *old_lang_type = TYPE_LANG_SPECIFIC (t); |
| ALLOC_OBJC_TYPE_LANG_SPECIFIC (t); |
| memcpy (TYPE_LANG_SPECIFIC (t), old_lang_type, |
| SIZEOF_OBJC_TYPE_LANG_SPECIFIC); |
| } |
| else |
| { |
| /* Just create a new one. */ |
| ALLOC_OBJC_TYPE_LANG_SPECIFIC (t); |
| } |
| /* 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) = objc_info[i]; |
| /* Replace the IDENTIFIER_NODE with an actual @interface now |
| that we have it. */ |
| TYPE_OBJC_INTERFACE (t) = klass; |
| } |
| objc_info.release (); |
| |
| /* Use TYPE_BINFO structures to point at the super class, if any. */ |
| objc_xref_basetypes (s, super); |
| |
| /* Mark this struct as a class template. */ |
| CLASS_STATIC_TEMPLATE (klass) = s; |
| |
| return s; |
| } |
| |
| /* Mark DECL as being 'volatile' for purposes of Darwin |
| _setjmp()/_longjmp() exception handling. Called from |
| objc_mark_locals_volatile(). */ |
| void |
| objc_volatilize_decl (tree decl) |
| { |
| /* Do not mess with variables that are 'static' or (already) |
| 'volatile'. */ |
| if (!TREE_THIS_VOLATILE (decl) && !TREE_STATIC (decl) |
| && (TREE_CODE (decl) == VAR_DECL |
| || TREE_CODE (decl) == PARM_DECL)) |
| { |
| if (local_variables_to_volatilize == NULL) |
| vec_alloc (local_variables_to_volatilize, 8); |
| |
| vec_safe_push (local_variables_to_volatilize, decl); |
| } |
| } |
| |
| /* Called when parsing of a function completes; if any local variables |
| in the function were marked as variables to volatilize, change them |
| to volatile. We do this at the end of the function when the |
| warnings about discarding 'volatile' have already been produced. |
| We are making the variables as volatile just to force the compiler |
| to preserve them between setjmp/longjmp, but we don't want warnings |
| for them as they aren't really volatile. */ |
| void |
| objc_finish_function (void) |
| { |
| /* If there are any local variables to volatilize, volatilize them. */ |
| if (local_variables_to_volatilize) |
| { |
| int i; |
| tree decl; |
| FOR_EACH_VEC_ELT (*local_variables_to_volatilize, i, decl) |
| { |
| tree t = TREE_TYPE (decl); |
| |
| t = build_qualified_type (t, TYPE_QUALS (t) | TYPE_QUAL_VOLATILE); |
| TREE_TYPE (decl) = t; |
| TREE_THIS_VOLATILE (decl) = 1; |
| TREE_SIDE_EFFECTS (decl) = 1; |
| DECL_REGISTER (decl) = 0; |
| #ifndef OBJCPLUS |
| C_DECL_REGISTER (decl) = 0; |
| #endif |
| } |
| |
| /* Now we delete the vector. This sets it to NULL as well. */ |
| vec_free (local_variables_to_volatilize); |
| } |
| } |
| |
| /* Check if protocol PROTO is adopted (directly or indirectly) by class CLS |
| (including its categories and superclasses) or by object type TYP. |
| Issue a warning if PROTO is not adopted anywhere and WARN is set. */ |
| |
| static bool |
| objc_lookup_protocol (tree proto, tree cls, tree typ, bool warn) |
| { |
| bool class_type = (cls != NULL_TREE); |
| |
| while (cls) |
| { |
| tree c; |
| |
| /* Check protocols adopted by the class and its categories. */ |
| for (c = cls; c; c = CLASS_CATEGORY_LIST (c)) |
| { |
| if (lookup_protocol_in_reflist (CLASS_PROTOCOL_LIST (c), proto)) |
| return true; |
| } |
| |
| /* Repeat for superclasses. */ |
| cls = lookup_interface (CLASS_SUPER_NAME (cls)); |
| } |
| |
| /* Check for any protocols attached directly to the object type. */ |
| if (TYPE_HAS_OBJC_INFO (typ)) |
| { |
| if (lookup_protocol_in_reflist (TYPE_OBJC_PROTOCOL_LIST (typ), proto)) |
| return true; |
| } |
| |
| if (warn) |
| { |
| *errbuf = 0; |
| gen_type_name_0 (class_type ? typ : TYPE_POINTER_TO (typ)); |
| /* NB: Types 'id' and 'Class' cannot reasonably be described as |
| "implementing" a given protocol, since they do not have an |
| implementation. */ |
| if (class_type) |
| warning (0, "class %qs does not implement the %qE protocol", |
| identifier_to_locale (errbuf), PROTOCOL_NAME (proto)); |
| else |
| warning (0, "type %qs does not conform to the %qE protocol", |
| identifier_to_locale (errbuf), PROTOCOL_NAME (proto)); |
| } |
| |
| return false; |
| } |
| |
| /* Check if class RCLS and instance struct type RTYP conform to at least the |
| same protocols that LCLS and LTYP conform to. */ |
| |
| static bool |
| objc_compare_protocols (tree lcls, tree ltyp, tree rcls, tree rtyp, bool warn) |
| { |
| tree p; |
| bool have_lproto = false; |
| |
| while (lcls) |
| { |
| /* NB: We do _not_ look at categories defined for LCLS; these may or |
| may not get loaded in, and therefore it is unreasonable to require |
| that RCLS/RTYP must implement any of their protocols. */ |
| for (p = CLASS_PROTOCOL_LIST (lcls); p; p = TREE_CHAIN (p)) |
| { |
| have_lproto = true; |
| |
| if (!objc_lookup_protocol (TREE_VALUE (p), rcls, rtyp, warn)) |
| return warn; |
| } |
| |
| /* Repeat for superclasses. */ |
| lcls = lookup_interface (CLASS_SUPER_NAME (lcls)); |
| } |
| |
| /* Check for any protocols attached directly to the object type. */ |
| if (TYPE_HAS_OBJC_INFO (ltyp)) |
| { |
| for (p = TYPE_OBJC_PROTOCOL_LIST (ltyp); p; p = TREE_CHAIN (p)) |
| { |
| have_lproto = true; |
| |
| if (!objc_lookup_protocol (TREE_VALUE (p), rcls, rtyp, warn)) |
| return warn; |
| } |
| } |
| |
| /* NB: If LTYP and LCLS have no protocols to search for, return 'true' |
| vacuously, _unless_ RTYP is a protocol-qualified 'id'. We can get |
| away with simply checking for 'id' or 'Class' (!RCLS), since this |
| routine will not get called in other cases. */ |
| return have_lproto || (rcls != NULL_TREE); |
| } |
| |
| /* Given two types TYPE1 and TYPE2, return their least common ancestor. |
| Both TYPE1 and TYPE2 must be pointers, and already determined to be |
| compatible by objc_compare_types() below. */ |
| |
| tree |
| objc_common_type (tree type1, tree type2) |
| { |
| tree inner1 = TREE_TYPE (type1), inner2 = TREE_TYPE (type2); |
| |
| while (POINTER_TYPE_P (inner1)) |
| { |
| inner1 = TREE_TYPE (inner1); |
| inner2 = TREE_TYPE (inner2); |
| } |
| |
| /* If one type is derived from another, return the base type. */ |
| if (DERIVED_FROM_P (inner1, inner2)) |
| return type1; |
| else if (DERIVED_FROM_P (inner2, inner1)) |
| return type2; |
| |
| /* If both types are 'Class', return 'Class'. */ |
| if (objc_is_class_id (inner1) && objc_is_class_id (inner2)) |
| return objc_class_type; |
| |
| /* Otherwise, return 'id'. */ |
| return objc_object_type; |
| } |
| |
| /* Determine if it is permissible to assign (if ARGNO is greater than -3) |
| an instance of RTYP to an instance of LTYP or to compare the two |
| (if ARGNO is equal to -3), per ObjC type system rules. Before |
| returning 'true', this routine may issue warnings related to, e.g., |
| protocol conformance. When returning 'false', the routine must |
| produce absolutely no warnings; the C or C++ front-end will do so |
| instead, if needed. If either LTYP or RTYP is not an Objective-C |
| type, the routine must return 'false'. |
| |
| The ARGNO parameter is encoded as follows: |
| >= 1 Parameter number (CALLEE contains function being called); |
| 0 Return value; |
| -1 Assignment; |
| -2 Initialization; |
| -3 Comparison (LTYP and RTYP may match in either direction); |
| -4 Silent comparison (for C++ overload resolution); |
| -5 Silent "specialization" comparison for RTYP to be a "specialization" |
| of LTYP (a specialization means that RTYP is LTYP plus some constraints, |
| so that each object of type RTYP is also of type LTYP). This is used |
| when comparing property types. */ |
| |
| bool |
| objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee) |
| { |
| tree lcls, rcls, lproto, rproto; |
| bool pointers_compatible; |
| |
| /* We must be dealing with pointer types */ |
| if (!POINTER_TYPE_P (ltyp) || !POINTER_TYPE_P (rtyp)) |
| return false; |
| |
| tree ltyp_attr, rtyp_attr; |
| do |
| { |
| /* Remove indirections, but keep the type attributes from the innermost |
| pointer type, to check for NSObject. */ |
| ltyp_attr = TYPE_ATTRIBUTES (ltyp); |
| ltyp = TREE_TYPE (ltyp); |
| rtyp_attr = TYPE_ATTRIBUTES (rtyp); |
| rtyp = TREE_TYPE (rtyp); |
| } |
| while (POINTER_TYPE_P (ltyp) && POINTER_TYPE_P (rtyp)); |
| |
| /* We must also handle function pointers, since ObjC is a bit more |
| lenient than C or C++ on this. */ |
| if (TREE_CODE (ltyp) == FUNCTION_TYPE && TREE_CODE (rtyp) == FUNCTION_TYPE) |
| { |
| function_args_iterator liter, riter; |
| |
| /* Return types must be covariant. */ |
| if (!comptypes (TREE_TYPE (ltyp), TREE_TYPE (rtyp)) |
| && !objc_compare_types (TREE_TYPE (ltyp), TREE_TYPE (rtyp), |
| argno, callee)) |
| return false; |
| |
| /* Argument types must be contravariant. */ |
| function_args_iter_init (&liter, ltyp); |
| function_args_iter_init (&riter, rtyp); |
| |
| while (1) |
| { |
| ltyp = function_args_iter_cond (&liter); |
| rtyp = function_args_iter_cond (&riter); |
| |
| /* If we've exhaused both lists simulateously, we're done. */ |
| if (ltyp == NULL_TREE && rtyp == NULL_TREE) |
| break; |
| |
| /* If one list is shorter than the other, they fail to match. */ |
| if (ltyp == NULL_TREE || rtyp == NULL_TREE) |
| return false; |
| |
| if (!comptypes (rtyp, ltyp) |
| && !objc_compare_types (rtyp, ltyp, argno, callee)) |
| return false; |
| |
| function_args_iter_next (&liter); |
| function_args_iter_next (&riter); |
| } |
| |
| return true; |
| } |
| |
| /* We might have void * with NSObject type attr. */ |
| bool l_NSObject_p = ltyp_attr && lookup_attribute ("NSObject", ltyp_attr); |
| bool r_NSObject_p = rtyp_attr && lookup_attribute ("NSObject", rtyp_attr); |
| |
| /* Past this point, we are only interested in ObjC class instances, |
| or 'id' or 'Class' (except if the user applied the NSObject type |
| attribute). */ |
| if ((TREE_CODE (ltyp) != RECORD_TYPE && !l_NSObject_p) |
| || (TREE_CODE (rtyp) != RECORD_TYPE && !r_NSObject_p)) |
| return false; |
| |
| if (!objc_is_object_id (ltyp) && !objc_is_class_id (ltyp) |
| && !TYPE_HAS_OBJC_INFO (ltyp) && !l_NSObject_p) |
| return false; |
| |
| if (!objc_is_object_id (rtyp) && !objc_is_class_id (rtyp) |
| && !TYPE_HAS_OBJC_INFO (rtyp) && !r_NSObject_p) |
| return false; |
| |
| /* Past this point, we are committed to returning 'true' to the caller |
| (unless performing a silent comparison; see below). However, we can |
| still warn about type and/or protocol mismatches. */ |
| |
| if (TYPE_HAS_OBJC_INFO (ltyp)) |
| { |
| lcls = TYPE_OBJC_INTERFACE (ltyp); |
| lproto = TYPE_OBJC_PROTOCOL_LIST (ltyp); |
| } |
| else |
| lcls = lproto = NULL_TREE; |
| |
| if (TYPE_HAS_OBJC_INFO (rtyp)) |
| { |
| rcls = TYPE_OBJC_INTERFACE (rtyp); |
| rproto = TYPE_OBJC_PROTOCOL_LIST (rtyp); |
| } |
| else |
| rcls = rproto = NULL_TREE; |
| |
| /* If we could not find an @interface declaration, we must have |
| only seen a @class declaration; for purposes of type comparison, |
| treat it as a stand-alone (root) class. */ |
| |
| if (lcls && TREE_CODE (lcls) == IDENTIFIER_NODE) |
| lcls = NULL_TREE; |
| |
| if (rcls && TREE_CODE (rcls) == IDENTIFIER_NODE) |
| rcls = NULL_TREE; |
| |
| /* If either type is an unqualified 'id', we're done. This is because |
| an 'id' can be assigned to or from any type with no warnings. When |
| the pointer has NSObject attribute, consider that to be equivalent. */ |
| if (argno != -5) |
| { |
| if ((!lproto && objc_is_object_id (ltyp)) |
| || (!rproto && objc_is_object_id (rtyp))) |
| return true; |
| if (l_NSObject_p || r_NSObject_p) |
| return true; |
| } |
| else |
| { |
| /* For property checks, though, an 'id' is considered the most |
| general type of object, hence if you try to specialize an |
| 'NSArray *' (ltyp) property with an 'id' (rtyp) one, we need |
| to warn. */ |
| if (!lproto && (objc_is_object_id (ltyp) || l_NSObject_p)) |
| return true; |
| } |
| |
| pointers_compatible = (TYPE_MAIN_VARIANT (ltyp) == TYPE_MAIN_VARIANT (rtyp)); |
| |
| /* If the underlying types are the same, and at most one of them has |
| a protocol list, we do not need to issue any diagnostics. */ |
| if (pointers_compatible && (!lproto || !rproto)) |
| return true; |
| |
| /* If exactly one of the types is 'Class', issue a diagnostic; any |
| exceptions of this rule have already been handled. */ |
| if (objc_is_class_id (ltyp) ^ objc_is_class_id (rtyp)) |
| pointers_compatible = false; |
| /* Otherwise, check for inheritance relations. */ |
| else |
| { |
| if (!pointers_compatible) |
| { |
| /* Again, if any of the two is an 'id', we're satisfied, |
| unless we're comparing properties, in which case only an |
| 'id' on the left-hand side (old property) is good |
| enough. */ |
| if (argno != -5) |
| pointers_compatible |
| = (objc_is_object_id (ltyp) || objc_is_object_id (rtyp)); |
| else |
| pointers_compatible = objc_is_object_id (ltyp); |
| } |
| |
| if (!pointers_compatible) |
| pointers_compatible = DERIVED_FROM_P (ltyp, rtyp); |
| |
| if (!pointers_compatible && (argno == -3 || argno == -4)) |
| pointers_compatible = DERIVED_FROM_P (rtyp, ltyp); |
| } |
| |
| /* If the pointers match modulo protocols, check for protocol conformance |
| mismatches. */ |
| if (pointers_compatible) |
| { |
| pointers_compatible = objc_compare_protocols (lcls, ltyp, rcls, rtyp, |
| argno != -3); |
| |
| if (!pointers_compatible && argno == -3) |
| pointers_compatible = objc_compare_protocols (rcls, rtyp, lcls, ltyp, |
| argno != -3); |
| } |
| |
| if (!pointers_compatible) |
| { |
| /* The two pointers are not exactly compatible. Issue a warning, unless |
| we are performing a silent comparison, in which case return 'false' |
| instead. */ |
| /* NB: For the time being, we shall make our warnings look like their |
| C counterparts. In the future, we may wish to make them more |
| ObjC-specific. */ |
| switch (argno) |
| { |
| case -5: |
| case -4: |
| return false; |
| |
| case -3: |
| warning (0, "comparison of distinct Objective-C types lacks a cast"); |
| break; |
| |
| case -2: |
| warning (0, "initialization from distinct Objective-C type"); |
| break; |
| |
| case -1: |
| warning (0, "assignment from distinct Objective-C type"); |
| break; |
| |
| case 0: |
| warning (0, "distinct Objective-C type in return"); |
| break; |
| |
| default: |
| warning (0, "passing argument %d of %qE from distinct " |
| "Objective-C type", argno, callee); |
| break; |
| } |
| } |
| |
| return true; |
| } |
| |
| /* This routine is similar to objc_compare_types except that function-pointers are |
| excluded. This is because, caller assumes that common types are of (id, Object*) |
| variety and calls objc_common_type to obtain a common type. There is no commonolty |
| between two function-pointers in this regard. */ |
| |
| bool |
| objc_have_common_type (tree ltyp, tree rtyp, int argno, tree callee) |
| { |
| if (objc_compare_types (ltyp, rtyp, argno, callee)) |
| { |
| /* exclude function-pointer types. */ |
| do |
| { |
| ltyp = TREE_TYPE (ltyp); /* Remove indirections. */ |
| rtyp = TREE_TYPE (rtyp); |
| } |
| while (POINTER_TYPE_P (ltyp) && POINTER_TYPE_P (rtyp)); |
| return !(TREE_CODE (ltyp) == FUNCTION_TYPE && TREE_CODE (rtyp) == FUNCTION_TYPE); |
| } |
| return false; |
| } |
| |
| #ifndef OBJCPLUS |
| /* Determine if CHILD is derived from PARENT. The routine assumes that |
| both parameters are RECORD_TYPEs, and is non-reflexive. */ |
| |
| static bool |
| objc_derived_from_p (tree parent, tree child) |
| { |
| parent = TYPE_MAIN_VARIANT (parent); |
| |
| for (child = TYPE_MAIN_VARIANT (child); |
| TYPE_BINFO (child) && BINFO_N_BASE_BINFOS (TYPE_BINFO (child));) |
| { |
| child = TYPE_MAIN_VARIANT (BINFO_TYPE (BINFO_BASE_BINFO |
| (TYPE_BINFO (child), |
| 0))); |
| |
| if (child == parent) |
| return true; |
| } |
| |
| return false; |
| } |
| #endif |
| |
| tree |
| objc_build_component_ref (tree datum, tree component) |
| { |
| /* If COMPONENT is NULL, the caller is referring to the anonymous |
| base class field. */ |
| if (!component) |
| { |
| tree base = TYPE_FIELDS (TREE_TYPE (datum)); |
| |
| return build3 (COMPONENT_REF, TREE_TYPE (base), datum, base, NULL_TREE); |
| } |
| |
| /* The 'build_component_ref' routine has been removed from the C++ |
| front-end, but 'finish_class_member_access_expr' seems to be |
| a worthy substitute. */ |
| #ifdef OBJCPLUS |
| return finish_class_member_access_expr (datum, component, false, |
| tf_warning_or_error); |
| #else |
| return build_component_ref (input_location, datum, component, |
| UNKNOWN_LOCATION); |
| #endif |
| } |
| |
| /* Recursively copy inheritance information rooted at BINFO. To do this, |
| we emulate the song and dance performed by cp/tree.cc:copy_binfo(). */ |
| |
| static tree |
| objc_copy_binfo (tree binfo) |
| { |
| tree btype = BINFO_TYPE (binfo); |
| tree binfo2 = make_tree_binfo (BINFO_N_BASE_BINFOS (binfo)); |
| tree base_binfo; |
| int ix; |
| |
| BINFO_TYPE (binfo2) = btype; |
| BINFO_OFFSET (binfo2) = BINFO_OFFSET (binfo); |
| BINFO_BASE_ACCESSES (binfo2) = BINFO_BASE_ACCESSES (binfo); |
| |
| /* Recursively copy base binfos of BINFO. */ |
| for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++) |
| { |
| tree base_binfo2 = objc_copy_binfo (base_binfo); |
| |
| BINFO_INHERITANCE_CHAIN (base_binfo2) = binfo2; |
| BINFO_BASE_APPEND (binfo2, base_binfo2); |
| } |
| |
| return binfo2; |
| } |
| |
| /* Record superclass information provided in BASETYPE for ObjC class REF. |
| This is loosely based on cp/decl.cc:xref_basetypes(). */ |
| |
| 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; |
| vec_alloc (BINFO_BASE_ACCESSES (binfo), 1); |
| BINFO_BASE_APPEND (binfo, base_binfo); |
| BINFO_BASE_ACCESS_APPEND (binfo, access_public_node); |
| } |
| } |
| |
| /* Called from finish_decl. */ |
| |
| void |
| objc_check_decl (tree decl) |
| { |
| tree type = TREE_TYPE (decl); |
| |
| 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 %qE", |
| type); |
| } |
| |
| void |
| objc_check_global_decl (tree decl) |
| { |
| tree id = DECL_NAME (decl); |
| if (objc_is_class_name (id) && global_bindings_p()) |
| error ("redeclaration of Objective-C class %qs", IDENTIFIER_POINTER (id)); |
| } |
| |
| /* Construct a PROTOCOLS-qualified variant of INTERFACE, where |
| INTERFACE may either name an Objective-C class, or refer to the |
| special 'id' or 'Class' types. If INTERFACE is not a valid ObjC |
| type, just return it unchanged. This function is often called when |
| PROTOCOLS is NULL_TREE, in which case we simply look up the |
| appropriate INTERFACE. */ |
| |
| tree |
| objc_get_protocol_qualified_type (tree interface, tree protocols) |
| { |
| /* 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 (!is_ptr) |
| { |
| type = objc_is_class_name (interface); |
| |
| if (type) |
| { |
| /* If looking at a typedef, retrieve the precise type it |
| describes. */ |
| if (TREE_CODE (interface) == IDENTIFIER_NODE) |
| interface = identifier_global_value (interface); |
| |
| type = ((interface && TREE_CODE (interface) == TYPE_DECL |
| && DECL_ORIGINAL_TYPE (interface)) |
| ? DECL_ORIGINAL_TYPE (interface) |
| : xref_tag (RECORD_TYPE, type)); |
| } |
| else |
| { |
| /* This case happens when we are given an 'interface' which |
| is not a valid class name. For example if a typedef was |
| used, and 'interface' really is the identifier of the |
| typedef, but when you resolve it you don't get an |
| Objective-C class, but something else, such as 'int'. |
| This is an error; protocols make no sense unless you use |
| them with Objective-C objects. */ |
| error_at (input_location, "only Objective-C object types can be qualified with a protocol"); |
| |
| /* Try to recover. Ignore the invalid class name, and treat |
| the object as an 'id' to silence further warnings about |
| the class. */ |
| type = objc_object_type; |
| is_ptr = true; |
| } |
| } |
| |
| if (protocols) |
| { |
| type = build_variant_type_copy (type); |
| |
| /* For pointers (i.e., 'id' or 'Class'), attach the protocol(s) |
| to the pointee. */ |
| if (is_ptr) |
| { |
| tree orig_pointee_type = TREE_TYPE (type); |
| TREE_TYPE (type) = build_variant_type_copy (orig_pointee_type); |
| |
| /* Set up the canonical type information. */ |
| TYPE_CANONICAL (type) |
| = TYPE_CANONICAL (TYPE_POINTER_TO (orig_pointee_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, /* definition_required */ false); |
| |
| /* 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; |
| } |
| |
| /* Check for circular dependencies in protocols. The arguments are |
| PROTO, the protocol to check, and LIST, a list of protocol it |
| conforms to. */ |
| |
| static void |
| check_protocol_recursively (tree proto, tree list) |
| { |
| tree p; |
| |
| for (p = list; p; p = TREE_CHAIN (p)) |
| { |
| tree pp = TREE_VALUE (p); |
| |
| if (TREE_CODE (pp) == IDENTIFIER_NODE) |
| pp = lookup_protocol (pp, /* warn if deprecated */ false, |
| /* definition_required */ false); |
| |
| if (pp == proto) |
| fatal_error (input_location, "protocol %qE has circular dependency", |
| PROTOCOL_NAME (pp)); |
| if (pp) |
| check_protocol_recursively (proto, PROTOCOL_LIST (pp)); |
| } |
| } |
| |
| /* Look up PROTOCOLS, and return a list of those that are found. If |
| none are found, return NULL. Note that this function will emit a |
| warning if a protocol is found and is deprecated. If |
| 'definition_required', then warn if the protocol is found but is |
| not defined (ie, if we only saw a forward-declaration of the |
| protocol (as in "@protocol NSObject;") not a real definition with |
| the list of methods). */ |
| static tree |
| lookup_and_install_protocols (tree protocols, bool definition_required) |
| { |
| tree proto; |
| tree return_value = NULL_TREE; |
| |
| if (protocols == error_mark_node) |
| return NULL; |
| |
| for (proto = protocols; proto; proto = TREE_CHAIN (proto)) |
| { |
| tree ident = TREE_VALUE (proto); |
| tree p = lookup_protocol (ident, /* warn_if_deprecated */ true, |
| definition_required); |
| |
| if (p) |
| return_value = chainon (return_value, |
| build_tree_list (NULL_TREE, p)); |
| else if (ident != error_mark_node) |
| error ("cannot find protocol declaration for %qE", |
| ident); |
| } |
| |
| return return_value; |
| } |
| |
| static void |
| build_common_objc_exception_stuff (void) |
| { |
| tree noreturn_list, nothrow_list, temp_type; |
| |
| noreturn_list = tree_cons (get_identifier ("noreturn"), NULL, NULL); |
| nothrow_list = tree_cons (get_identifier ("nothrow"), NULL, NULL); |
| |
| /* void objc_exception_throw(id) __attribute__((noreturn)); */ |
| /* void objc_sync_enter(id); */ |
| /* void objc_sync_exit(id); */ |
| temp_type = build_function_type_list (void_type_node, |
| objc_object_type, |
| NULL_TREE); |
| objc_exception_throw_decl |
| = add_builtin_function (TAG_EXCEPTIONTHROW, temp_type, 0, NOT_BUILT_IN, NULL, |
| noreturn_list); |
| /* Make sure that objc_exception_throw (id) claims that it may throw an |
| exception. */ |
| TREE_NOTHROW (objc_exception_throw_decl) = 0; |
| |
| objc_sync_enter_decl |
| = add_builtin_function (TAG_SYNCENTER, temp_type, 0, NOT_BUILT_IN, |
| NULL, nothrow_list); |
| |
| objc_sync_exit_decl |
| = add_builtin_function (TAG_SYNCEXIT, temp_type, 0, NOT_BUILT_IN, |
| NULL, nothrow_list); |
| } |
| |
| /* Purpose: "play" parser, creating/installing representations |
| of the declarations that are required by Objective-C. |
| |
| Model: |
| |
| type_spec--------->sc_spec |
| (tree_list) (tree_list) |
| | | |
| | | |
| identifier_node identifier_node */ |
| |
| static void |
| synth_module_prologue (void) |
| { |
| tree type; |
| uint32_t save_write_symbols = write_symbols; |
| const struct gcc_debug_hooks *const save_hooks = debug_hooks; |
| |
| /* Suppress outputting debug symbols, because |
| dbxout_init hasn't been called yet. */ |
| write_symbols = NO_DEBUG; |
| debug_hooks = &do_nothing_debug_hooks; |
| |
| #ifdef OBJCPLUS |
| push_lang_context (lang_name_c); /* extern "C" */ |
| #endif |
| |
| /* The following are also defined in <objc/objc.h> and friends. */ |
| |
| objc_object_id = get_identifier (TAG_OBJECT); |
| objc_class_id = get_identifier (TAG_CLASS); |
| |
| objc_object_reference = xref_tag (RECORD_TYPE, objc_object_id); |
| objc_class_reference = xref_tag (RECORD_TYPE, objc_class_id); |
| |
| objc_object_type = build_pointer_type (objc_object_reference); |
| objc_instancetype_type = build_pointer_type (objc_object_reference); |
| objc_class_type = build_pointer_type (objc_class_reference); |
| |
| objc_object_name = get_identifier (OBJECT_TYPEDEF_NAME); |
| objc_instancetype_name = get_identifier (INSTANCE_TYPEDEF_NAME); |
| objc_class_name = get_identifier (CLASS_TYPEDEF_NAME); |
| objc_selector_name = get_identifier (SEL_TYPEDEF_NAME); |
| |
| /* Declare the 'id', 'instancetype' and 'Class' typedefs. */ |
| type = lang_hooks.decls.pushdecl (build_decl (input_location, |
| TYPE_DECL, |
| objc_object_name, |
| objc_object_type)); |
| suppress_warning (type); |
| |
| type = lang_hooks.decls.pushdecl (build_decl (input_location, |
| TYPE_DECL, |
| objc_instancetype_name, |
| objc_instancetype_type)); |
| suppress_warning (type); |
| |
| type = lang_hooks.decls.pushdecl (build_decl (input_location, |
| TYPE_DECL, |
| objc_class_name, |
| objc_class_type)); |
| suppress_warning (type); |
| |
| /* Forward-declare '@interface Protocol'. */ |
| type = get_identifier (PROTOCOL_OBJECT_CLASS_NAME); |
| objc_declare_class (type); |
| objc_protocol_type = build_pointer_type (xref_tag (RECORD_TYPE, type)); |
| |
| /* Declare receiver type used for dispatching messages to 'super'. */ |
| /* `struct objc_super *' */ |
| 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))); |
| |
| build_common_objc_exception_stuff (); |
| |
| /* Set-up runtime-specific templates, message and exception stuff. */ |
| (*runtime.initialize) (); |
| |
| /* Declare objc_getProperty, object_setProperty and other property |
| accessor helpers. */ |
| build_common_objc_property_accessor_helpers (); |
| |
| /* Forward declare constant_string_id and constant_string_type. */ |
| if (!constant_string_class_name) |
| constant_string_class_name = runtime.default_constant_string_class_name; |
| constant_string_id = get_identifier (constant_string_class_name); |
| objc_declare_class (constant_string_id); |
| |
| /* Pre-build the following entities - for speed/convenience. */ |
| self_id = get_identifier ("self"); |
| ucmd_id = get_identifier ("_cmd"); |
| |
| /* Declare struct _objc_fast_enumeration_state { ... }; */ |
| build_fast_enumeration_state_template (); |
| |
| /* void objc_enumeration_mutation (id) */ |
| type = build_function_type_list (void_type_node, |
| objc_object_type, NULL_TREE); |
| objc_enumeration_mutation_decl |
| = add_builtin_function (TAG_ENUMERATION_MUTATION, type, 0, NOT_BUILT_IN, |
| NULL, NULL_TREE); |
| TREE_NOTHROW (objc_enumeration_mutation_decl) = 0; |
| |
| #ifdef OBJCPLUS |
| pop_lang_context (); |
| #endif |
| |
| write_symbols = save_write_symbols; |
| debug_hooks = save_hooks; |
| } |
| |
| /* --- const strings --- */ |
| |
| /* Ensure that the ivar list for NSConstantString/NXConstantString |
| (or whatever was specified via `-fconstant-string-class') |
| contains fields at least as large as the following three, so that |
| the runtime can stomp on them with confidence: |
| |
| struct STRING_OBJECT_CLASS_NAME |
| { |
| Object isa; |
| char *cString; |
| unsigned int length; |
| }; */ |
| |
| static int |
| check_string_class_template (void) |
| { |
| tree field_decl = objc_get_class_ivars (constant_string_id); |
| |
| #define AT_LEAST_AS_LARGE_AS(F, T) \ |
| (F && TREE_CODE (F) == FIELD_DECL \ |
| && (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (F))) \ |
| >= TREE_INT_CST_LOW (TYPE_SIZE (T)))) |
| |
| if (!AT_LEAST_AS_LARGE_AS (field_decl, ptr_type_node)) |
| return 0; |
| |
| field_decl = DECL_CHAIN (field_decl); |
| if (!AT_LEAST_AS_LARGE_AS (field_decl, ptr_type_node)) |
| return 0; |
| |
| field_decl = DECL_CHAIN (field_decl); |
| return AT_LEAST_AS_LARGE_AS (field_decl, unsigned_type_node); |
| |
| #undef AT_LEAST_AS_LARGE_AS |
| } |
| |
| /* Avoid calling `check_string_class_template ()' more than once. */ |
| static GTY(()) int string_layout_checked; |
| |
| /* Construct an internal string layout to be used as a template for |
| creating NSConstantString/NXConstantString instances. */ |
| |
| static tree |
| objc_build_internal_const_str_type (void) |
| { |
| tree type = (*lang_hooks.types.make_type) (RECORD_TYPE); |
| tree fields = build_decl (input_location, |
| FIELD_DECL, NULL_TREE, ptr_type_node); |
| tree field = build_decl (input_location, |
| FIELD_DECL, NULL_TREE, ptr_type_node); |
| |
| DECL_CHAIN (field) = fields; fields = field; |
| field = build_decl (input_location, |
| FIELD_DECL, NULL_TREE, unsigned_type_node); |
| DECL_CHAIN (field) = fields; fields = field; |
| /* NB: The finish_builtin_struct() routine expects FIELD_DECLs in |
| reverse order! */ |
| finish_builtin_struct (type, "__builtin_ObjCString", |
| fields, NULL_TREE); |
| |
| return type; |
| } |
| |
| /* Custom build_string which sets TREE_TYPE! */ |
| |
| tree |
| my_build_string (int len, const char *str) |
| { |
| return fix_string_type (build_string (len, str)); |
| } |
| |
| /* Build a string with contents STR and length LEN and convert it to a |
| pointer. */ |
| |
| tree |
| my_build_string_pointer (int len, const char *str) |
| { |
| tree string = my_build_string (len, str); |
| tree ptrtype = build_pointer_type (TREE_TYPE (TREE_TYPE (string))); |
| return build1 (ADDR_EXPR, ptrtype, string); |
| } |
| |
| hashval_t |
| objc_string_hasher::hash (string_descriptor *ptr) |
| { |
| 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; |
| |
| for (i = 0; i < len; i++) |
| h = ((h * 613) + p[i]); |
| |
| return h; |
| } |
| |
| bool |
| objc_string_hasher::equal (string_descriptor *ptr1, string_descriptor *ptr2) |
| { |
| const_tree const str1 = ptr1->literal; |
| const_tree const str2 = ptr2->literal; |
| int len1 = TREE_STRING_LENGTH (str1); |
| |
| return (len1 == TREE_STRING_LENGTH (str2) |
| && !memcmp (TREE_STRING_POINTER (str1), TREE_STRING_POINTER (str2), |
| len1)); |
| } |
| |
| /* Given a chain of STRING_CST's, build a static instance of |
| NXConstantString which points at the concatenation of those |
| strings. We place the string object in the __string_objects |
| section of the __OBJC segment. The Objective-C runtime will |
| initialize the isa pointers of the string objects to point at the |
| NXConstantString class object. */ |
| |
| tree |
| objc_build_string_object (tree string) |
| { |
| tree constant_string_class; |
| int length; |
| tree addr; |
| struct string_descriptor *desc, key; |
| |
| /* 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 |
| literal. On Darwin (Mac OS X), for example, we may wish to obtain a |
| constant CFString reference instead. |
| At present, this is only supported for the NeXT runtime. */ |
| if (flag_next_runtime |
| && targetcm.objc_construct_string_object) |
| { |
| tree constructor = (*targetcm.objc_construct_string_object) (string); |
| if (constructor) |
| return build1 (NOP_EXPR, objc_object_type, constructor); |
| } |
| |
| /* Check whether the string class being used actually exists and has the |
| correct ivar layout. */ |
| if (!string_layout_checked) |
| { |
| string_layout_checked = -1; |
| constant_string_class = lookup_interface (constant_string_id); |
| internal_const_str_type = objc_build_internal_const_str_type (); |
| |
| if (!constant_string_class |
| || !(constant_string_type |
| = CLASS_STATIC_TEMPLATE (constant_string_class))) |
| error ("cannot find interface declaration for %qE", |