diff options
Diffstat (limited to 'contrib/gcc/c-common.c')
-rw-r--r-- | contrib/gcc/c-common.c | 359 |
1 files changed, 352 insertions, 7 deletions
diff --git a/contrib/gcc/c-common.c b/contrib/gcc/c-common.c index f9b06f4..2fc1d1e 100644 --- a/contrib/gcc/c-common.c +++ b/contrib/gcc/c-common.c @@ -552,6 +552,8 @@ static tree handle_cleanup_attribute (tree *, tree, tree, int, bool *); static tree handle_warn_unused_result_attribute (tree *, tree, tree, int, bool *); static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *); +/* APPLE LOCAL radar 5932809 - copyable byref blocks */ +static tree handle_blocks_attribute (tree *, tree, tree, int, bool *); static void check_function_nonnull (tree, tree); static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT); @@ -607,7 +609,8 @@ const struct attribute_spec c_common_attribute_table[] = handle_section_attribute }, { "aligned", 0, 1, false, false, false, handle_aligned_attribute }, - { "weak", 0, 0, true, false, false, + /* APPLE LOCAL weak types 5954418 */ + { "weak", 0, 0, false, false, false, handle_weak_attribute }, { "alias", 1, 1, true, false, false, handle_alias_attribute }, @@ -650,6 +653,8 @@ const struct attribute_spec c_common_attribute_table[] = handle_warn_unused_result_attribute }, { "sentinel", 0, 1, false, true, true, handle_sentinel_attribute }, + /* APPLE LOCAL radar 5932809 - copyable byref blocks */ + { "blocks", 1, 1, true, false, false, handle_blocks_attribute }, { NULL, 0, 0, false, false, false, NULL } }; @@ -4259,7 +4264,10 @@ handle_noreturn_attribute (tree *node, tree name, tree ARG_UNUSED (args), tree type = TREE_TYPE (*node); /* See FIXME comment in c_common_attribute_table. */ - if (TREE_CODE (*node) == FUNCTION_DECL) + /* APPLE LOCAL begin radar 4727659 */ + if (TREE_CODE (*node) == FUNCTION_DECL + || objc_method_decl (TREE_CODE (*node))) + /* APPLE LOCAL end radar 4727659 */ TREE_THIS_VOLATILE (*node) = 1; else if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) @@ -4267,6 +4275,14 @@ handle_noreturn_attribute (tree *node, tree name, tree ARG_UNUSED (args), = build_pointer_type (build_type_variant (TREE_TYPE (type), TYPE_READONLY (TREE_TYPE (type)), 1)); + /* APPLE LOCAL begin radar 6237713 */ + else if (TREE_CODE (type) == BLOCK_POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) + TREE_TYPE (*node) + = build_block_pointer_type + (build_type_variant (TREE_TYPE (type), + TYPE_READONLY (TREE_TYPE (type)), 1)); + /* APPLE LOCAL end radar 6237713 */ else { warning (OPT_Wattributes, "%qE attribute ignored", name); @@ -4893,6 +4909,23 @@ handle_weak_attribute (tree *node, tree name, if (TREE_CODE (*node) == FUNCTION_DECL || TREE_CODE (*node) == VAR_DECL) declare_weak (*node); + /* APPLE LOCAL begin weak types 5954418 */ + else if (!DECL_P (*node) + /* If the weak flag can be associated with something else, + prefer that. */ + && (flags & (ATTR_FLAG_FUNCTION_NEXT + |ATTR_FLAG_DECL_NEXT + |ATTR_FLAG_ARRAY_NEXT))) + { + *no_add_attrs = true; + return tree_cons (name, args, NULL_TREE); + } + else if (! targetm.cxx.class_data_always_comdat () + && TREE_CODE (*node) == RECORD_TYPE) + { + /* Leave on the type for the C++ front end */ + } + /* APPLE LOCAL end weak types 5954418 */ else warning (OPT_Wattributes, "%qE attribute ignored", name); @@ -5381,8 +5414,10 @@ handle_unavailable_attribute (tree *node, tree name, || TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL - || TREE_CODE (decl) == FIELD_DECL) - /* Removed radar 3803157 - objc attribute */ + /* APPLE LOCAL begin radar 3803157 - objc attribute */ + || TREE_CODE (decl) == FIELD_DECL + || objc_method_decl (TREE_CODE (decl))) + /* APPLE LOCAL end radar 3803157 - objc attribute */ { TREE_UNAVAILABLE (decl) = 1; } @@ -5558,7 +5593,10 @@ handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name), return NULL_TREE; } - if (TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE) + /* APPLE LOCAL begin blocks 5925781 */ + if (TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE && + TREE_CODE (TREE_VALUE (argument)) != BLOCK_POINTER_TYPE) + /* APPLE LOCAL end blocks 5925781 */ { error ("nonnull argument references non-pointer operand (argument %lu, operand %lu)", (unsigned long) attr_arg_num, (unsigned long) arg_num); @@ -5705,8 +5743,11 @@ check_nonnull_arg (void * ARG_UNUSED (ctx), tree param, happen if the "nonnull" attribute was given without an operand list (which means to check every pointer argument). */ - if (TREE_CODE (TREE_TYPE (param)) != POINTER_TYPE) - return; + /* APPLE LOCAL begin blocks 5925781 */ + if (TREE_CODE (TREE_TYPE (param)) != POINTER_TYPE && + TREE_CODE (TREE_TYPE (param)) != BLOCK_POINTER_TYPE) + /* APPLE LOCAL end blocks 5925781 */ + return; if (integer_zerop (param)) warning (OPT_Wnonnull, "null argument where non-null required " @@ -5809,6 +5850,168 @@ handle_warn_unused_result_attribute (tree *node, tree name, return NULL_TREE; } +/* APPLE LOCAL begin radar 5932809 - copyable byref blocks */ +/* Handle "blocks" attribute. */ +static tree +handle_blocks_attribute (tree *node, tree name, + tree args, + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + tree arg_ident; + /* APPLE LOCAL radar 6217257 */ + tree type; + *no_add_attrs = true; + if (!(*node) || TREE_CODE (*node) != VAR_DECL) + { + error ("__block attribute can be specified on variables only"); + return NULL_TREE; + } + arg_ident = TREE_VALUE (args); + gcc_assert (TREE_CODE (arg_ident) == IDENTIFIER_NODE); + /* APPLE LOCAL radar 6096219 */ + if (strcmp (IDENTIFIER_POINTER (arg_ident), "byref")) + { + /* APPLE LOCAL radar 6096219 */ + warning (OPT_Wattributes, "Only \"byref\" is allowed - %qE attribute ignored", + name); + return NULL_TREE; + } + /* APPLE LOCAL begin radar 6217257 */ + type = TREE_TYPE (*node); + if (TREE_CODE (type) == ERROR_MARK) + return NULL_TREE; + if (TREE_CODE (type) == ARRAY_TYPE) + { + if (!TYPE_SIZE (type) || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) + { + error ("__block not allowed on a variable length array declaration"); + return NULL_TREE; + } + } + /* APPLE LOCAL end radar 6217257 */ + COPYABLE_BYREF_LOCAL_VAR (*node) = 1; + COPYABLE_BYREF_LOCAL_NONPOD (*node) = block_requires_copying (*node); + return NULL_TREE; +} +/* APPLE LOCAL end radar 5932809 - copyable byref blocks */ + +/* APPLE LOCAL begin blocks 6040305 */ + +/* This routine builds: + *(void **)(EXP+20) expression which references the object pointer. +*/ +tree +build_indirect_object_id_exp (tree exp) +{ + tree dst_obj; + int int_size = int_cst_value (TYPE_SIZE_UNIT (unsigned_type_node)); + int offset; + /* dst->object In thid case 'object' is the field + of the object passed offset by: void * + void* + int + int + void* + void * + This must match definition of Block_byref structs. */ + /* APPLE LOCAL radar 6244520 */ + offset = GET_MODE_SIZE (Pmode) + GET_MODE_SIZE (Pmode) + + int_size + int_size + GET_MODE_SIZE (Pmode) + + GET_MODE_SIZE (Pmode); + dst_obj = build2 (PLUS_EXPR, ptr_type_node, exp, + build_int_cst (NULL_TREE, offset)); + /* APPLE LOCAL begin radar 6180456 */ + /* Type case to: 'void **' */ + dst_obj = build_c_cast (build_pointer_type (ptr_type_node), dst_obj); + dst_obj = build_indirect_ref (dst_obj, "unary *"); + /* APPLE LOCAL end radar 6180456 */ + return dst_obj; +} + +/* This routine builds call to: + _Block_object_dispose(VAR_DECL.__forwarding, BLOCK_FIELD_IS_BYREF); + and adds it to the statement list. + */ +tree +build_block_byref_release_exp (tree var_decl) +{ + tree exp = var_decl, call_exp; + tree type = TREE_TYPE (var_decl); + /* __block variables imported into Blocks are not _Block_object_dispose() + from within the Block statement itself; otherwise, each envokation of + the block causes a release. Make sure to release __block variables declared + and used locally in the block though. */ + if (cur_block + && (BLOCK_DECL_COPIED (var_decl) || BLOCK_DECL_BYREF (var_decl))) + return NULL_TREE; + if (BLOCK_DECL_BYREF (var_decl)) { + /* This is a "struct Block_byref_X *" type. Get its pointee. */ + gcc_assert (POINTER_TYPE_P (type)); + type = TREE_TYPE (type); + exp = build_indirect_ref (exp, "unary *"); + } + TREE_USED (var_decl) = 1; + + /* Declare: _Block_object_dispose(void*, BLOCK_FIELD_IS_BYREF) if not done already. */ + exp = build_component_ref (exp, get_identifier ("__forwarding")); + call_exp = build_block_object_dispose_call_exp (exp, BLOCK_FIELD_IS_BYREF); + return call_exp; +} +/* APPLE LOCAL end blocks 6040305 */ +/* APPLE LOCAL begin radar 5803600 */ +/** add_block_global_byref_list - Adds global variable decl to the list of + byref global declarations in the current block. +*/ +void add_block_global_byref_list (tree decl) +{ + cur_block->block_byref_global_decl_list = + tree_cons (NULL_TREE, decl, cur_block->block_byref_global_decl_list); +} + +/** in_block_global_byref_list - returns TRUE if global variable is + in the list of 'byref' declarations. +*/ +bool in_block_global_byref_list (tree decl) +{ + tree chain; + if (TREE_STATIC (decl)) { + for (chain = cur_block->block_byref_global_decl_list; chain; + chain = TREE_CHAIN (chain)) + if (TREE_VALUE (chain) == decl) + return true; + } + return false; +} +/* APPLE LOCAL end radar 5803600 */ + +/* APPLE LOCAL begin radar 6160536 */ +tree +build_block_helper_name (int unique_count) +{ + char *buf; + if (!current_function_decl) + { + /* APPLE LOCAL begin radar 6411649 */ + static int global_count; + buf = (char *)alloca (32); + sprintf (buf, "__block_global_%d", ++global_count); + /* APPLE LOCAL end radar 6411649 */ + } + else + { + tree outer_decl = current_function_decl; + /* APPLE LOCAL begin radar 6169580 */ + while (outer_decl && + DECL_CONTEXT (outer_decl) && TREE_CODE (DECL_CONTEXT (outer_decl)) == FUNCTION_DECL) + /* APPLE LOCAL end radar 6169580 */ + outer_decl = DECL_CONTEXT (outer_decl); + /* APPLE LOCAL begin radar 6411649 */ + if (!unique_count) + unique_count = ++DECL_STRUCT_FUNCTION(outer_decl)->unqiue_block_number; + /* APPLE LOCAL end radar 6411649 */ + buf = (char *)alloca (IDENTIFIER_LENGTH (DECL_NAME (outer_decl)) + 32); + sprintf (buf, "__%s_block_invoke_%d", + IDENTIFIER_POINTER (DECL_NAME (outer_decl)), unique_count); + } + return get_identifier (buf); +} +/* APPLE LOCAL end radar 6160536 */ + /* Handle a "sentinel" attribute. */ static tree @@ -6725,5 +6928,147 @@ warn_about_parentheses (enum tree_code code, enum tree_code code_left, "have their mathematical meaning"); } +/* APPLE LOCAL begin radar 6246527 */ +/* This routine is called for a "format" attribute. It adds the number of + hidden argument ('1') to the format's 2nd and 3rd argument to compensate + for these two arguments. This is to make rest of the "format" attribute + processing done in the middle-end to work seemlessly. */ + +static void +block_delta_format_args (tree format) +{ + tree format_num_expr, first_arg_num_expr; + int val; + tree args = TREE_VALUE (format); + gcc_assert (TREE_CHAIN (args) && TREE_CHAIN (TREE_CHAIN (args))); + format_num_expr = TREE_VALUE (TREE_CHAIN (args)); + first_arg_num_expr = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))); + if (format_num_expr && TREE_CODE (format_num_expr) == INTEGER_CST) + { + val = TREE_INT_CST_LOW (format_num_expr); + TREE_VALUE (TREE_CHAIN (args)) = build_int_cst (NULL_TREE, val+1); + } + if (first_arg_num_expr && TREE_CODE (first_arg_num_expr) == INTEGER_CST) + { + val = TREE_INT_CST_LOW (first_arg_num_expr); + if (val != 0) + TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))) = + build_int_cst (NULL_TREE, val+1); + } +} + +/* This routine recognizes legal block attributes. In case of block's "format" + attribute, it calls block_delta_format_args to compensate for hidden + argument _self getting passed to block's helper function. */ +bool +any_recognized_block_attribute (tree attributes) +{ + tree chain; + bool res = false; + for (chain = attributes; chain; chain = TREE_CHAIN (chain)) + { + if (is_attribute_p ("format", TREE_PURPOSE (chain))) + { + block_delta_format_args (chain); + res = true; + } + else if (is_attribute_p ("sentinel", TREE_PURPOSE (chain))) + res = true; + } + return res; +} +/* APPLE LOCAL end radar 6246527 */ +/* APPLE LOCAL begin radar 5847976 */ +static GTY(()) tree block_object_assign_decl; +static GTY(()) tree block_object_dispose_func_decl; +/* This routine declares: + void _Block_object_assign (void *, void *, int) or uses an + existing one. +*/ +static tree +build_block_object_assign_decl (void) +{ + tree func_type; + if (block_object_assign_decl) + return block_object_assign_decl; + block_object_assign_decl = lookup_name (get_identifier ("_Block_object_assign")); + if (block_object_assign_decl) + return block_object_assign_decl; + func_type = + build_function_type (void_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, void_list_node)))); + + block_object_assign_decl = builtin_function ("_Block_object_assign", func_type, + 0, NOT_BUILT_IN, 0, NULL_TREE); + TREE_NOTHROW (block_object_assign_decl) = 0; + return block_object_assign_decl; +} + +/* This routine builds: + _Block_object_assign(dest, src, flag) +*/ +tree build_block_object_assign_call_exp (tree dst, tree src, int flag) +{ + tree func_params = tree_cons (NULL_TREE, dst, + tree_cons (NULL_TREE, src, + tree_cons (NULL_TREE, + build_int_cst (integer_type_node, flag), + NULL_TREE))); + return build_function_call (build_block_object_assign_decl (), func_params); +} +/* This routine declares: + void _Block_object_dispose (void *, int) or uses an + existing one. +*/ +static tree +build_block_object_dispose_decl (void) +{ + tree func_type; + if (block_object_dispose_func_decl) + return block_object_dispose_func_decl; + block_object_dispose_func_decl = lookup_name (get_identifier ("_Block_object_dispose")); + if (block_object_dispose_func_decl) + return block_object_dispose_func_decl; + func_type = + build_function_type (void_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, void_list_node))); + + block_object_dispose_func_decl = builtin_function ("_Block_object_dispose", func_type, + 0, NOT_BUILT_IN, 0, NULL_TREE); + TREE_NOTHROW (block_object_dispose_func_decl) = 0; + return block_object_dispose_func_decl; +} + +/* This routine builds the call tree: + _Block_object_dispose(src, flag) +*/ +tree build_block_object_dispose_call_exp (tree src, int flag) +{ + tree func_params = tree_cons (NULL_TREE, src, + tree_cons (NULL_TREE, + build_int_cst (integer_type_node, flag), + NULL_TREE)); + return build_function_call (build_block_object_dispose_decl (), func_params); +} +/* APPLE LOCAL end radar 5847976 */ +/* APPLE LOCAL begin radar 7760213 */ +int HasByrefArray(tree byrefType) +{ + tree s1; + /* Check for possibility of an error condition. */ + if (TREE_CODE(byrefType) != RECORD_TYPE) + return 0; + + for (s1 = TYPE_FIELDS (byrefType); s1; s1 = TREE_CHAIN (s1)) + { + if (TREE_CODE(TREE_TYPE(s1)) == ARRAY_TYPE) + return 1; + } + return 0; +} +/* APPLE LOCAL end radar 7760213 */ #include "gt-c-common.h" |