diff options
Diffstat (limited to 'contrib/gcc/c-decl.c')
-rw-r--r-- | contrib/gcc/c-decl.c | 1014 |
1 files changed, 1012 insertions, 2 deletions
diff --git a/contrib/gcc/c-decl.c b/contrib/gcc/c-decl.c index 7b3833c..0f23ee3 100644 --- a/contrib/gcc/c-decl.c +++ b/contrib/gcc/c-decl.c @@ -71,6 +71,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA enum decl_context { NORMAL, /* Ordinary declaration */ FUNCDEF, /* Function definition */ + /* APPLE LOCAL blocks 6339747 */ + BLOCKDEF, /* Block literal declaration */ PARM, /* Declaration of parm before function body */ FIELD, /* Declaration inside struct or union */ TYPENAME}; /* Typename (inside cast or sizeof) */ @@ -3191,7 +3193,28 @@ add_flexible_array_elts_to_size (tree decl, tree init) = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl), TYPE_SIZE_UNIT (type)); } } - + +/* APPLE LOCAL begin blocks 6339747 */ +/* Decode a block literal type, such as "int **", returning a ...FUNCTION_DECL node. */ + +tree +grokblockdecl (struct c_declspecs *specs, struct c_declarator *declarator) +{ + tree decl; + tree attrs = specs->attrs; + + specs->attrs = NULL_TREE; + + decl = grokdeclarator (declarator, specs, BLOCKDEF, + false, NULL); + + /* Apply attributes. */ + decl_attributes (&decl, attrs, 0); + + return decl; +} +/* APPLE LOCAL end blocks 6339747 */ + /* Decode a "typename", such as "int **", returning a ..._TYPE node. */ tree @@ -3453,6 +3476,322 @@ c_maybe_initialize_eh (void) using_eh_for_cleanups (); } +/* APPLE LOCAL begin radar 5932809 - copyable byref blocks (C++ cr) */ +#define BLOCK_ALIGN_MAX 18 +static tree block_byref_id_object_copy[BLOCK_BYREF_CURRENT_MAX*(BLOCK_ALIGN_MAX+1)]; +static tree block_byref_id_object_dispose[BLOCK_BYREF_CURRENT_MAX*(BLOCK_ALIGN_MAX+1)]; + +/** + This routine builds: + + void __Block_byref_id_object_copy(struct Block_byref_id_object *dst, + struct Block_byref_id_object *src) { + _Block_object_assign (&_dest->object, _src->object, BLOCK_FIELD_IS_OBJECT[|BLOCK_FIELD_IS_WEAK]) // objects + _Block_object_assign(&_dest->object, _src->object, BLOCK_FIELD_IS_BLOCK[|BLOCK_FIELD_IS_WEAK]) // blocks + } */ +static void +synth_block_byref_id_object_copy_func (int flag, int kind) +{ + tree stmt, fnbody; + tree dst_arg, src_arg; + tree dst_obj, src_obj; + struct c_arg_info * arg_info; + tree call_exp; + gcc_assert (block_byref_id_object_copy[kind]); + /* Set up: (void* _dest, void*_src) parameters. */ + dst_arg = build_decl (PARM_DECL, get_identifier ("_dst"), + ptr_type_node); + TREE_USED (dst_arg) = 1; + DECL_ARG_TYPE (dst_arg) = ptr_type_node; + src_arg = build_decl (PARM_DECL, get_identifier ("_src"), + ptr_type_node); + TREE_USED (src_arg) = 1; + DECL_ARG_TYPE (src_arg) = ptr_type_node; + arg_info = xcalloc (1, sizeof (struct c_arg_info)); + TREE_CHAIN (dst_arg) = src_arg; + arg_info->parms = dst_arg; + arg_info->types = tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, + ptr_type_node, + NULL_TREE)); + /* function header synthesis. */ + push_function_context (); + start_block_helper_function (block_byref_id_object_copy[kind]); + store_parm_decls_from (arg_info); + + /* Body of the function. */ + stmt = c_begin_compound_stmt (true); + /* Build dst->object */ + dst_obj = build_indirect_object_id_exp (dst_arg); + + + /* src_obj is: _src->object. */ + src_obj = build_indirect_object_id_exp (src_arg); + + /* APPLE LOCAL begin radar 6180456 */ + /* _Block_object_assign (&_dest->object, _src->object, BLOCK_FIELD_IS_OBJECT) or : + _Block_object_assign (&_dest->object, _src->object, BLOCK_FIELD_IS_BLOCK) */ + /* APPLE LOCAL begin radar 6573923 */ + /* Also add the new flag when calling _Block_object_dispose + from byref dispose helper. */ + flag |= BLOCK_BYREF_CALLER; + /* APPLE LOCAL end radar 6573923 */ + call_exp = build_block_object_assign_call_exp (build_fold_addr_expr (dst_obj), src_obj, flag); + add_stmt (call_exp); + /* APPLE LOCAL end radar 6180456 */ + + fnbody = c_end_compound_stmt (stmt, true); + add_stmt (fnbody); + finish_function (); + pop_function_context (); + free (arg_info); +} + +/** + This routine builds: + + void __Block_byref_id_object_dispose(struct Block_byref_id_object *_src) { + _Block_object_dispose(_src->object, BLOCK_FIELD_IS_OBJECT[|BLOCK_FIELD_IS_WEAK]) // object + _Block_object_dispose(_src->object, BLOCK_FIELD_IS_BLOCK[|BLOCK_FIELD_IS_WEAK]) // block + } */ +static void +synth_block_byref_id_object_dispose_func (int flag, int kind) +{ + tree stmt, fnbody; + tree src_arg, src_obj, rel_exp; + struct c_arg_info * arg_info; + gcc_assert (block_byref_id_object_dispose[kind]); + /* Set up: (void *_src) parameter. */ + src_arg = build_decl (PARM_DECL, get_identifier ("_src"), + ptr_type_node); + TREE_USED (src_arg) = 1; + DECL_ARG_TYPE (src_arg) = ptr_type_node; + arg_info = xcalloc (1, sizeof (struct c_arg_info)); + arg_info->parms = src_arg; + arg_info->types = tree_cons (NULL_TREE, ptr_type_node, + NULL_TREE); + /* function header synthesis. */ + push_function_context (); + start_block_helper_function (block_byref_id_object_dispose[kind]); + store_parm_decls_from (arg_info); + + /* Body of the function. */ + stmt = c_begin_compound_stmt (true); + src_obj = build_indirect_object_id_exp (src_arg); + + /* APPLE LOCAL begin radar 6180456 */ + /* _Block_object_dispose(_src->object, BLOCK_FIELD_IS_OBJECT) : or + _Block_object_dispose(_src->object, BLOCK_FIELD_IS_BLOCK) */ + /* APPLE LOCAL begin radar 6573923 */ + /* Also add the new flag when calling _Block_object_dispose + from byref dispose helper. */ + flag |= BLOCK_BYREF_CALLER; + /* APPLE LOCAL end radar 6573923 */ + rel_exp = build_block_object_dispose_call_exp (src_obj, flag); + /* APPLE LOCAL end radar 6180456 */ + add_stmt (rel_exp); + + fnbody = c_end_compound_stmt (stmt, true); + add_stmt (fnbody); + finish_function (); + pop_function_context (); + free (arg_info); +} + +/* new_block_byref_decl - This routine changes a 'typex x' declared variable into: + + struct __Block_byref_x { + // APPLE LOCAL radar 6244520 + void *__isa; // NULL for everything except __weak pointers + struct Block_byref_x *__forwarding; + int32_t __flags; + int32_t __size; + void *__ByrefKeepFuncPtr; // Only if variable is __block ObjC object + void *__ByrefDestroyFuncPtr; // Only if variable is __block ObjC object + typex x; + } x; +*/ + +static tree +new_block_byref_decl (tree decl) +{ + static int unique_count; + /* APPLE LOCAL radar 5847976 */ + int save_flag_objc_gc; + tree Block_byref_type; + tree field_decl_chain, field_decl; + const char *prefix = "__Block_byref_"; + char *string = alloca (strlen (IDENTIFIER_POINTER (DECL_NAME (decl))) + + strlen (prefix) + 8 /* to hold the count */); + + sprintf (string, "%s%d_%s", prefix, ++unique_count, + IDENTIFIER_POINTER (DECL_NAME (decl))); + + push_to_top_level (); + Block_byref_type = start_struct (RECORD_TYPE, get_identifier (string)); + + /* APPLE LOCAL begin radar 6244520 */ + /* void *__isa; */ + field_decl = build_decl (FIELD_DECL, get_identifier ("__isa"), ptr_type_node); + field_decl_chain = field_decl; + /* APPLE LOCAL end radar 6244520 */ + + /* struct Block_byref_x *__forwarding; */ + field_decl = build_decl (FIELD_DECL, get_identifier ("__forwarding"), + build_pointer_type (Block_byref_type)); + /* APPLE LOCAL radar 6244520 */ + chainon (field_decl_chain, field_decl); + + /* int32_t __flags; */ + field_decl = build_decl (FIELD_DECL, get_identifier ("__flags"), + unsigned_type_node); + chainon (field_decl_chain, field_decl); + + /* int32_t __size; */ + field_decl = build_decl (FIELD_DECL, get_identifier ("__size"), + unsigned_type_node); + chainon (field_decl_chain, field_decl); + + if (COPYABLE_BYREF_LOCAL_NONPOD (decl)) + { + /* void *__ByrefKeepFuncPtr; */ + field_decl = build_decl (FIELD_DECL, get_identifier ("__ByrefKeepFuncPtr"), + ptr_type_node); + chainon (field_decl_chain, field_decl); + + /* void *__ByrefDestroyFuncPtr; */ + field_decl = build_decl (FIELD_DECL, get_identifier ("__ByrefDestroyFuncPtr"), + ptr_type_node); + chainon (field_decl_chain, field_decl); + } + + /* typex x; */ + field_decl = build_decl (FIELD_DECL, DECL_NAME (decl), TREE_TYPE (decl)); + chainon (field_decl_chain, field_decl); + + pop_from_top_level (); + /* APPLE LOCAL begin radar 5847976 */ + /* Hack so we don't issue warning on a field_decl having __weak attribute */ + save_flag_objc_gc = flag_objc_gc; + flag_objc_gc = 0; + finish_struct (Block_byref_type, field_decl_chain, NULL_TREE); + flag_objc_gc = save_flag_objc_gc; + /* APPLE LOCAL end radar 5847976 */ + + TREE_TYPE (decl) = Block_byref_type; + /* Force layout_decl to recompute these fields. */ + DECL_SIZE (decl) = DECL_SIZE_UNIT (decl) = 0; + layout_decl (decl, 0); + return decl; +} + +/* init_byref_decl - This routine builds the initializer for the __Block_byref_x + type in the form of: + { NULL, &x, 0, sizeof(struct __Block_byref_x), initializer-expr}; + + or: + { NULL, &x, 0, sizeof(struct __Block_byref_x)}; + when INIT is NULL_TREE + + For __block ObjC objects, it also adds "byref_keep" and "byref_destroy" + Funtion pointers. So the most general initializers would be: + + { NULL, &x, 0, sizeof(struct __Block_byref_x), &byref_keep, &byref_destroy, + &initializer-expr}; +*/ +static tree +/* APPLE LOCAL radar 5847976 */ +init_byref_decl (tree decl, tree init, int flag) +{ + tree initlist; + tree block_byref_type = TREE_TYPE (decl); + int size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (block_byref_type)); + unsigned flags = 0; + tree fields; + + if (COPYABLE_BYREF_LOCAL_NONPOD (decl)) + flags = BLOCK_HAS_COPY_DISPOSE; + + fields = TYPE_FIELDS (block_byref_type); + /* APPLE LOCAL begin radar 6244520 */ + /* APPLE LOCAL begin radar 5847976 */ + initlist = tree_cons (fields, fold_convert (ptr_type_node, ((flag & BLOCK_FIELD_IS_WEAK) != 0) ? integer_one_node + : integer_zero_node), 0); + /* APPLE LOCAL end radar 5847976 */ + fields = TREE_CHAIN (fields); + + initlist = tree_cons (fields, + build_unary_op (ADDR_EXPR, decl, 0), initlist); + /* APPLE LOCAL end radar 6244520 */ + fields = TREE_CHAIN (fields); + + initlist = tree_cons (fields, build_int_cst (TREE_TYPE (fields), flags), + initlist); + fields = TREE_CHAIN (fields); + initlist = tree_cons (fields, build_int_cst (TREE_TYPE (fields), size), + initlist); + fields = TREE_CHAIN (fields); + + if (COPYABLE_BYREF_LOCAL_NONPOD (decl)) + { + char name[64]; + int align = exact_log2 ((DECL_ALIGN (decl)+TYPE_ALIGN (ptr_type_node)-1) / TYPE_ALIGN (ptr_type_node)); + int kind; + if (align == -1 || align > BLOCK_ALIGN_MAX) { + error ("invalid alignment for __block variable"); + kind = 0; + } else + kind = align*BLOCK_BYREF_CURRENT_MAX + flag; + /* Add &__Block_byref_id_object_copy, &__Block_byref_id_object_dispose + initializers. */ + if (!block_byref_id_object_copy[kind]) + { + /* Build a void __Block_byref_id_object_copy(void*, void*) type. */ + tree func_type = + build_function_type (void_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + void_list_node))); + sprintf (name, "__Block_byref_id_object_copy%d", kind); + block_byref_id_object_copy[kind] = build_helper_func_decl (get_identifier (name), + func_type); + /* Synthesize function definition. */ + synth_block_byref_id_object_copy_func (flag, kind); + } + initlist = tree_cons (fields, + build_fold_addr_expr (block_byref_id_object_copy[kind]), + initlist); + fields = TREE_CHAIN (fields); + + if (!block_byref_id_object_dispose[kind]) + { + /* Synthesize void __Block_byref_id_object_dispose (void*) and + build &__Block_byref_id_object_dispose. */ + tree func_type = + build_function_type (void_type_node, + tree_cons (NULL_TREE, ptr_type_node, void_list_node)); + sprintf (name, "__Block_byref_id_object_dispose%d", kind); + block_byref_id_object_dispose[kind] = build_helper_func_decl (get_identifier (name), + func_type); + /* Synthesize function definition. */ + synth_block_byref_id_object_dispose_func (flag, kind); + } + initlist = tree_cons (fields, + build_fold_addr_expr (block_byref_id_object_dispose[kind]), + initlist); + fields = TREE_CHAIN (fields); + } + + if (init) + { + init = do_digest_init (TREE_TYPE (fields), init); + initlist = tree_cons (fields, init, initlist); + } + init = build_constructor_from_list (block_byref_type, nreverse (initlist)); + return init; +} +/* APPLE LOCAL end radar 5932809 - copyable byref blocks (C++ cr) */ + /* Finish processing of a declaration; install its initial value. If the length of an array type is not known before, @@ -3479,6 +3818,45 @@ finish_decl (tree decl, tree init, tree asmspec_tree) /* Don't crash if parm is initialized. */ if (TREE_CODE (decl) == PARM_DECL) init = 0; + /* APPLE LOCAL begin radar 5932809 - copyable byref blocks (C++ cq) */ + /* We build a new type for each local variable declared as __block + and initialize it to a list of initializers. */ + else if (TREE_CODE (decl) == VAR_DECL && COPYABLE_BYREF_LOCAL_VAR (decl)) + { + if (DECL_EXTERNAL (decl) || TREE_STATIC (decl)) + { + error ("__block attribute on %q+D not allowed, only allowed on local variables", decl); + COPYABLE_BYREF_LOCAL_VAR (decl) = 0; + COPYABLE_BYREF_LOCAL_NONPOD (decl) = 0; + } + else + { + int flag = 0; + if (objc_is_gcable_type (TREE_TYPE (decl)) == -1) + flag = BLOCK_FIELD_IS_WEAK; + if (block_requires_copying (decl)) + { + if (TREE_CODE (TREE_TYPE (decl)) == BLOCK_POINTER_TYPE) + flag |= BLOCK_FIELD_IS_BLOCK; + else + flag |= BLOCK_FIELD_IS_OBJECT; + } + decl = new_block_byref_decl (decl); + /* APPLE LOCAL begin radar 6289031 */ +#if 0 + if (! flag_objc_gc_only) +#endif + { + push_cleanup (decl, build_block_byref_release_exp (decl), false); + } + /* APPLE LOCAL end radar 6289031 */ + /* APPLE LOCAL begin radar 5847976 */ + COPYABLE_WEAK_BLOCK (decl) = ((flag & BLOCK_FIELD_IS_WEAK) != 0); + init = init_byref_decl (decl, init, flag); + /* APPLE LOCAL end radar 5847976 */ + } + } + /* APPLE LOCAL end radar 5932809 - copyable byref blocks (C++ cq) */ if (init) store_init_value (decl, init); @@ -4097,6 +4475,8 @@ grokdeclarator (const struct c_declarator *declarator, case cdk_function: case cdk_array: case cdk_pointer: + /* APPLE LOCAL radar 5732232 - blocks */ + case cdk_block_pointer: funcdef_syntax = (decl->kind == cdk_function); decl = decl->declarator; break; @@ -4705,6 +5085,30 @@ grokdeclarator (const struct c_declarator *declarator, declarator = declarator->declarator; break; } + + + /* APPLE LOCAL begin radar 5732232 - blocks (C++ cj) */ + case cdk_block_pointer: + { + if (TREE_CODE (type) != FUNCTION_TYPE) + { + error ("block pointer to non-function type is invalid"); + type = error_mark_node; + } + else + { + type = build_block_pointer_type (type); + /* APPLE LOCAL begin radar 5814025 (C++ cj) */ + /* Process type qualifiers (such as const or volatile) + that were given inside the `^'. */ + type_quals = declarator->u.pointer_quals; + /* APPLE LOCAL end radar 5814025 (C++ cj) */ + declarator = declarator->declarator; + } + break; + } + /* APPLE LOCAL end radar 5732232 - blocks (C++ cj) */ + default: gcc_unreachable (); } @@ -4730,6 +5134,41 @@ grokdeclarator (const struct c_declarator *declarator, type = error_mark_node; } + /* APPLE LOCAL begin blocks 6339747 */ + if (decl_context == BLOCKDEF) + { + tree decl; + + if (type == error_mark_node) + return error_mark_node; + + if (TREE_CODE (type) != FUNCTION_TYPE) + { + tree arg_types; + + if (TREE_CODE (type) == ARRAY_TYPE) + { + error ("block declared as returning an array"); + return error_mark_node; + } + + arg_info = XOBNEW (&parser_obstack, struct c_arg_info); + arg_info->parms = 0; + arg_info->tags = 0; + arg_info->types = 0; + arg_info->others = 0; + arg_info->pending_sizes = 0; + arg_info->had_vla_unspec = 0; + arg_types = grokparms (arg_info, false); + type_quals = TYPE_UNQUALIFIED; + type = build_function_type (type, arg_types); + } + decl = build_decl (FUNCTION_DECL, NULL_TREE, type); + DECL_ARGUMENTS (decl) = arg_info ? arg_info->parms : NULL_TREE; + return decl; + } + /* APPLE LOCAL end blocks 6339747 */ + /* If this is declaring a typedef name, return a TYPE_DECL. */ if (storage_class == csc_typedef) @@ -7071,6 +7510,13 @@ check_for_loop_decls (void) error ("%<enum %E%> declared in %<for%> loop initial declaration", id); break; + /* APPLE LOCAL begin radar 6268817 */ + case FUNCTION_DECL: + /* Block helper function can be declared in the statement block + for the for-loop declarations. */ + if (BLOCK_SYNTHESIZED_FUNC (decl)) + break; + /* APPLE LOCAL end radar 6268817 */ default: error ("declaration of non-variable %q+D in %<for%> loop " "initial declaration", decl); @@ -7111,7 +7557,10 @@ c_pop_function_context (struct function *f) { struct language_function *p = f->language; - if (DECL_STRUCT_FUNCTION (current_function_decl) == 0 + /* APPLE LOCAL begin blocks 6040305 */ + if (current_function_decl + && DECL_STRUCT_FUNCTION (current_function_decl) == 0 + /* APPLE LOCAL end blocks 6040305 */ && DECL_SAVED_TREE (current_function_decl) == NULL_TREE) { /* Stop pointing to the local nodes about to be freed. */ @@ -7294,6 +7743,536 @@ make_pointer_declarator (struct c_declspecs *type_quals_attrs, return ret; } +/* APPLE LOCAL begin radar 5932809 - copyable byref blocks (C++ ch) */ +/* build_byref_local_var_access - converts EXPR to: + EXPR.__forwarding-><decl-name>. +*/ +tree +build_byref_local_var_access (tree expr, tree decl_name) +{ + tree exp = build_component_ref (expr, get_identifier ("__forwarding")); + exp = build_indirect_ref (exp, "unary *"); + exp = build_component_ref (exp, decl_name); + return exp; +} +/* APPLE LOCAL end radar 5932809 - copyable byref blocks (C++ ch) */ +/* APPLE LOCAL begin radar 5732232 - blocks (C++ ch) */ +/** + build_block_byref_decl - This routine inserts a variable declared as a + 'byref' variable using the |...| syntax in helper function's outer-most scope. +*/ +tree +build_block_byref_decl (tree name, tree decl, tree exp) +{ + struct c_scope *scope = current_scope; + tree ptr_type, byref_decl; + /* APPLE LOCAL begin radar 6225809 */ + if (cur_block->prev_block_info) { + /* Traverse enclosing blocks. Insert a __block variable in + each enclosing block which has no declaration of this + variable. This is to ensure that the current (inner) block + gets the __block version of the variable; */ + struct block_sema_info *cb = cur_block->prev_block_info; + while (cb) { + struct c_binding *b = I_SYMBOL_BINDING (name); + /* Find the first declaration not in current block. */ + while (b && b->decl + && (TREE_CODE (b->decl) == VAR_DECL + || TREE_CODE (b->decl) == PARM_DECL) + && b->depth >= cur_block->the_scope->depth) + b = b->shadowed; + + /* Is the next declaration not in enclosing block? */ + if (b && b->decl + && (TREE_CODE (b->decl) == VAR_DECL + || TREE_CODE (b->decl) == PARM_DECL) + && b->depth < cb->the_scope->depth) { + /* No declaration of variable seen in the block. Must insert one. */ + struct c_scope *save_scope = current_scope; + struct block_sema_info *save_current_block = cur_block; + current_scope = cb->the_scope; + cur_block = cb; + decl = build_block_byref_decl (name, decl, exp); + cur_block = save_current_block; + current_scope = save_scope; + } + cb = cb->prev_block_info; + } + } + /* APPLE LOCAL end radar 6225809 */ + + /* If it is already a byref declaration, do not add the pointer type + because such declarations already have the pointer type + added. This happens when we have two nested byref declarations in + nested blocks. */ + ptr_type = (TREE_CODE (decl) == VAR_DECL && BLOCK_DECL_BYREF (decl)) + ? TREE_TYPE (decl) : build_pointer_type (TREE_TYPE (decl)); + byref_decl = build_decl (VAR_DECL, name, ptr_type); + /* APPLE LOCAL begin radars 6144664 & 6145471 */ + DECL_SOURCE_LOCATION (byref_decl) = DECL_SOURCE_LOCATION + (cur_block->helper_func_decl); + /* APPLE LOCAL end radars 6144664 & 6145471 */ + BLOCK_DECL_BYREF (byref_decl) = 1; + + /* APPLE LOCAL begin radar 5932809 - copyable byref blocks (C++ ch) */ + if (TREE_CODE (decl) == VAR_DECL && COPYABLE_BYREF_LOCAL_VAR (decl)) + { + COPYABLE_BYREF_LOCAL_VAR (byref_decl) = 1; + COPYABLE_BYREF_LOCAL_NONPOD (byref_decl) = COPYABLE_BYREF_LOCAL_NONPOD (decl); + /* APPLE LOCAL radar 5847976 */ + COPYABLE_WEAK_BLOCK (byref_decl) = COPYABLE_WEAK_BLOCK (decl); + } + /* APPLE LOCAL end radar 5932809 - copyable byref blocks (C++ ch) */ + + /* In the presence of nested "{" + move up the scope chain until reaching the main function body's scope. + */ + while (scope && !scope->function_body) + scope = scope->outer; + /* Current scope must be that of the main function body. */ + gcc_assert (scope && scope->function_body); + bind (name, byref_decl, + scope, /*invisible=*/false, /*nested=*/false); + cur_block->block_byref_decl_list = + tree_cons (NULL_TREE, byref_decl, cur_block->block_byref_decl_list); + /* APPLE LOCAL radar 5847213 - building block_original_byref_decl_list list removed. */ + /* APPLE LOCAL begin radar 6289031 */ +#if 0 + if (! flag_objc_gc_only) +#endif + push_cleanup (byref_decl, build_block_byref_release_exp (byref_decl), false); + /* APPLE LOCAL end radar 6289031 */ + + return byref_decl; +} + +/** + build_block_ref_decl - This routine inserts a copied-in variable (a variable + referenced in the block but whose scope is outside the block) in helper + function's outer-most scope. It also sets its type to 'const' as such + variables are read-only. +*/ +tree +build_block_ref_decl (tree name, tree decl) +{ + struct c_scope *scope = current_scope; + tree ref_decl; + /* APPLE LOCAL radar 6212722 */ + tree type, exp; + /* APPLE LOCAL begin radar 5932809 - copyable byref blocks (C++ ch) */ + /* 'decl' was previously declared as __block. Simply, copy the value + embedded in the above variable. */ + if (TREE_CODE (decl) == VAR_DECL && COPYABLE_BYREF_LOCAL_VAR (decl)) + decl = build_byref_local_var_access (decl, DECL_NAME (decl)); + else { + /* APPLE LOCAL begin radar 5988451 (C++ ch) */ + if (cur_block->prev_block_info) { + /* Traverse enclosing blocks. Insert a copied-in variable in + each enclosing block which has no declaration of this + variable. This is to ensure that the current (inner) block + has the 'frozen' value of the copied-in variable; which means + the value of the copied in variable is at the point of the + block declaration and *not* when the inner block is + invoked. */ + struct block_sema_info *cb = cur_block->prev_block_info; + while (cb) { + struct c_binding *b = I_SYMBOL_BINDING (name); + /* Find the first declaration not in current block. */ + while (b && b->decl + && (TREE_CODE (b->decl) == VAR_DECL + || TREE_CODE (b->decl) == PARM_DECL) + && b->depth >= cur_block->the_scope->depth) + b = b->shadowed; + + /* Is the next declaration not in enclosing block? */ + if (b && b->decl + && (TREE_CODE (b->decl) == VAR_DECL + || TREE_CODE (b->decl) == PARM_DECL) + && b->depth < cb->the_scope->depth) { + /* No declaration of variable seen in the block. Must insert one, + so it 'freezes' the variable in this block. */ + struct c_scope *save_scope = current_scope; + struct block_sema_info *save_current_block = cur_block; + current_scope = cb->the_scope; + cur_block = cb; + decl = build_block_ref_decl (name, decl); + cur_block = save_current_block; + current_scope = save_scope; + } + cb = cb->prev_block_info; + } + } + /* APPLE LOCAL end radar 5988451 (C++ ch) */ + } + /* APPLE LOCAL end radar 5932809 - copyable byref blocks (C++ ch) */ + /* APPLE LOCAL begin radar 6212722 */ + exp = decl; + type = TREE_TYPE (exp); + if (TREE_CODE (type) == ARRAY_TYPE) { + exp = array_to_pointer_conversion (decl); + type = TREE_TYPE (exp); + } + else if (TREE_CODE (type) == FUNCTION_TYPE) { + exp = function_to_pointer_conversion (exp); + type = TREE_TYPE (exp); + } + ref_decl = build_decl (VAR_DECL, name, + build_qualified_type (type, TYPE_QUAL_CONST)); + /* APPLE LOCAL end radar 6212722 */ + /* APPLE LOCAL begin radars 6144664 & 6145471 */ + DECL_SOURCE_LOCATION (ref_decl) = DECL_SOURCE_LOCATION + (cur_block->helper_func_decl); + /* APPLE LOCAL end radars 6144664 & 6145471 */ + DECL_INITIAL (ref_decl) = error_mark_node; + /* APPLE LOCAL radar 5805175 - blocks (C++ ch) */ + c_apply_type_quals_to_decl (TYPE_QUAL_CONST, ref_decl); + BLOCK_DECL_COPIED (ref_decl) = 1; + + /* Find the scope for function body (outer-most scope) and insert + this variable in that scope. This is to avoid duplicate + declaration of the save variable. */ + while (scope && !scope->function_body) + scope = scope->outer; + /* We are enterring the copied-in variable in helper function's + outer scope; that of its main body. */ + gcc_assert (scope); + bind (name, ref_decl, + scope, /*invisible=*/false, /*nested=*/false); + cur_block->block_ref_decl_list = + tree_cons (NULL_TREE, ref_decl, cur_block->block_ref_decl_list); + cur_block->block_original_ref_decl_list = + /* APPLE LOCAL radar 6212722 */ + tree_cons (NULL_TREE, exp, cur_block->block_original_ref_decl_list); + return ref_decl; +} + +/* APPLE LOCAL begin radar 5847213 - radar 6329245 */ +static GTY (()) tree descriptor_ptr_type; +static GTY (()) tree descriptor_ptr_type_with_copydispose; +/** build_block_descriptor_type - This routine builds following internal type: + struct __block_descriptor { + unsigned long int reserved; // NULL + unsigned long int Size; // sizeof(struct Block_literal_1) + + // optional helper functions + void *CopyFuncPtr; // When BLOCK_HAS_COPY_DISPOSE is set (withCopyDispose true) + void *DestroyFuncPtr; // When BLOCK_HAS_COPY_DISPOSE is set (withCopyDispose true) +} *descriptor_ptr_type; + +Objects of this type will always be static. This is one main component of abi change. +*/ +tree +build_block_descriptor_type (bool withCopyDispose) +{ + tree field_decl_chain, field_decl; + tree main_type; + + if (withCopyDispose && descriptor_ptr_type_with_copydispose) + return descriptor_ptr_type_with_copydispose; + if (!withCopyDispose && descriptor_ptr_type) + return descriptor_ptr_type; + + main_type = + withCopyDispose ? + start_struct (RECORD_TYPE, get_identifier ("__block_descriptor_withcopydispose")) + : start_struct (RECORD_TYPE, get_identifier ("__block_descriptor")); + + /* unsigned long int reserved; */ + field_decl = build_decl (FIELD_DECL, get_identifier ("reserved"), long_unsigned_type_node); + field_decl_chain = field_decl; + + /* unsigned long int Size; */ + field_decl = build_decl (FIELD_DECL, get_identifier ("Size"), long_unsigned_type_node); + chainon (field_decl_chain, field_decl); + + if (withCopyDispose) + { + /* void *CopyFuncPtr; */ + field_decl = build_decl (FIELD_DECL, get_identifier ("CopyFuncPtr"), ptr_type_node); + chainon (field_decl_chain, field_decl); + /* void *DestroyFuncPtr; */ + field_decl = build_decl (FIELD_DECL, get_identifier ("DestroyFuncPtr"), ptr_type_node); + chainon (field_decl_chain, field_decl); + } + + /* Mark this struct as being a block struct rather than a 'normal' + struct. */ + TYPE_BLOCK_IMPL_STRUCT (main_type) = 1; + finish_struct (main_type, field_decl_chain, NULL_TREE); + + main_type = build_pointer_type (main_type); + if (withCopyDispose) + descriptor_ptr_type_with_copydispose = main_type; + else + descriptor_ptr_type = main_type; + return main_type; +} +/* APPLE LOCAL end radar 5847213 - radar 6329245 */ + +/* APPLE LOCAL begin radar 5814025 (C++ ch) */ +struct c_declarator * +make_block_pointer_declarator (struct c_declspecs *type_quals_attrs, + struct c_declarator *target) +{ + int quals = 0; + struct c_declarator *itarget = target; + struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator); + + if (type_quals_attrs) + { + tree attrs = type_quals_attrs->attrs; + quals = quals_from_declspecs (type_quals_attrs); + if (attrs != NULL_TREE) + itarget = build_attrs_declarator (attrs, target); + } + ret->kind = cdk_block_pointer; + /* APPLE LOCAL radar 5882266 (C++ ch) */ + ret->declarator = itarget; + ret->u.pointer_quals = quals; + return ret; +} +/* APPLE LOCAL end radar 5814025 (C++ ch) */ + +tree +begin_block (void) +{ + struct block_sema_info *csi; +#if 0 + push_scope (); +#endif + csi = (struct block_sema_info*)xcalloc (1, sizeof (struct block_sema_info)); + csi->prev_block_info = cur_block; + cur_block = csi; + return NULL_TREE; +} + +struct block_sema_info * +finish_block (tree block __attribute__ ((__unused__))) +{ + struct block_sema_info *csi = cur_block; + cur_block = cur_block->prev_block_info; +#if 0 + pop_scope (); +#endif + return csi; +} + +bool +in_imm_block (void) +{ + /* APPLE LOCAL radar 5988451 (C++ ch) */ + return (cur_block && cur_block->the_scope == current_scope); +} + +/* This routine returns 'true' if 'name' has a declaration inside the + current block, 'false' otherwise. If 'name' has no declaration in + the current block, it returns in DECL the user declaration for + 'name' found in the enclosing scope. Note that if it is declared + in current declaration, it can be either a user declaration or a + byref/copied-in declaration added in current block's scope by the + compiler. */ +bool +lookup_name_in_block (tree name, tree *decl) +{ + if (cur_block) + { + struct c_binding *b = I_SYMBOL_BINDING (name); + if (b->depth >= cur_block->the_scope->depth) + return true; + + /* Check for common case of block nested inside a non-block. */ + if (!cur_block->prev_block_info) + return false; + /* Check for less common case of nested blocks. */ + /* Declaration not in current block. Find the first user + declaration of 'name' in outer scope. */ + /* APPLE LOCAL begin radar 5988451 (C++ ch) */ + /* Check for variables only, as we may have parameters, such as + 'self' */ + /* Note that if a copied-in variable (BLOCK_DECL_COPIED) in the + enclosing block is found, it must be returned as this is + where the variable in current (nested block) will have to get + its value. */ + while (b && b->decl + && (TREE_CODE (b->decl) == VAR_DECL) + && BLOCK_DECL_BYREF (b->decl)) + b = b->shadowed; + /* APPLE LOCAL end radar 5988451 (C++ ch) */ + if (b && b->decl) + *decl = b->decl; + } + return false; +} + +static struct c_scope *save_current_scope; +static tree save_current_function_decl; +void +push_to_top_level (void) +{ + save_current_scope = current_scope; + save_current_function_decl = current_function_decl; + current_scope = file_scope; + current_function_decl = NULL_TREE; +} + +void +pop_from_top_level (void) +{ + current_scope = save_current_scope; + current_function_decl = save_current_function_decl; +} + +/** + build_helper_func_decl - This routine builds a FUNCTION_DECL for + a block helper function. +*/ +tree +build_helper_func_decl (tree ident, tree type) +{ + tree func_decl = build_decl (FUNCTION_DECL, ident, type); + DECL_EXTERNAL (func_decl) = 0; + TREE_PUBLIC (func_decl) = 0; + TREE_USED (func_decl) = 1; + TREE_NOTHROW (func_decl) = 0; + /* APPLE LOCAL radar 6172148 */ + BLOCK_SYNTHESIZED_FUNC (func_decl) = 1; + return func_decl; +} + +/** + start_block_helper_function - This is a light-weight version of start_function(). + It has removed all the fuss in the start_function(). + */ +void +start_block_helper_function (tree decl1) +{ + struct c_label_context_se *nstack_se; + struct c_label_context_vm *nstack_vm; + tree restype, resdecl; + + current_function_returns_value = 0; /* Assume, until we see it does. */ + current_function_returns_null = 0; + current_function_returns_abnormally = 0; + warn_about_return_type = 0; + c_switch_stack = NULL; + + nstack_se = XOBNEW (&parser_obstack, struct c_label_context_se); + nstack_se->labels_def = NULL; + nstack_se->labels_used = NULL; + nstack_se->next = label_context_stack_se; + label_context_stack_se = nstack_se; + + nstack_vm = XOBNEW (&parser_obstack, struct c_label_context_vm); + nstack_vm->labels_def = NULL; + nstack_vm->labels_used = NULL; + nstack_vm->scope = 0; + nstack_vm->next = label_context_stack_vm; + label_context_stack_vm = nstack_vm; + + /* Indicate no valid break/continue context by setting these variables + to some non-null, non-label value. We'll notice and emit the proper + error message in c_finish_bc_stmt. */ + c_break_label = c_cont_label = size_zero_node; + + announce_function (decl1); + + /* Make the init_value nonzero so pushdecl knows this is not tentative. + error_mark_node is replaced below (in pop_scope) with the BLOCK. */ + DECL_INITIAL (decl1) = error_mark_node; + + current_function_prototype_locus = UNKNOWN_LOCATION; + current_function_prototype_built_in = false; + current_function_prototype_arg_types = NULL_TREE; + + /* This function exists in static storage. + (This does not mean `static' in the C sense!) */ + TREE_STATIC (decl1) = 1; + /* A helper function is not global */ + TREE_PUBLIC (decl1) = 0; + + /* This is the earliest point at which we might know the assembler + name of the function. Thus, if it's set before this, die horribly. */ + gcc_assert (!DECL_ASSEMBLER_NAME_SET_P (decl1)); + current_function_decl = pushdecl (decl1); + + push_scope (); + declare_parm_level (); + + restype = TREE_TYPE (TREE_TYPE (current_function_decl)); + resdecl = build_decl (RESULT_DECL, NULL_TREE, restype); + DECL_ARTIFICIAL (resdecl) = 1; + DECL_IGNORED_P (resdecl) = 1; + DECL_RESULT (current_function_decl) = resdecl; + + start_fname_decls (); +} + +/** + declare_block_prologue_local_vars - utility routine to do the actual + declaration and initialization for each referecned block variable. +*/ +static void +declare_block_prologue_local_vars (tree self_parm, tree component, + tree stmt) +{ + tree decl, block_component; + tree_stmt_iterator i; + tree decl_stmt; + + decl = component; + block_component = build_component_ref (build_indirect_ref (self_parm, "->"), + DECL_NAME (component)); + gcc_assert (block_component); + DECL_EXTERNAL (decl) = 0; + TREE_STATIC (decl) = 0; + TREE_USED (decl) = 1; + DECL_CONTEXT (decl) = current_function_decl; + DECL_ARTIFICIAL (decl) = 1; + DECL_INITIAL (decl) = block_component; + /* Prepend a DECL_EXPR statement to the statement list. */ + i = tsi_start (stmt); + decl_stmt = build_stmt (DECL_EXPR, decl); + /* APPLE LOCAL Radar 5811961, Fix location of block prologue vars (C++ ch) */ + SET_EXPR_LOCATION (decl_stmt, DECL_SOURCE_LOCATION (decl)); + /* APPLE LOCAL begin radar 6163705, Blocks prologues */ + /* Give the prologue statements a line number of one before the beginning of + the function, to make them easily identifiable later. */ + EXPR_LINENO (decl_stmt) = DECL_SOURCE_LINE (decl) - 1; + /* APPLE LOCAL end radar 6163705, Blocks prologues */ + tsi_link_before (&i, decl_stmt, TSI_SAME_STMT); +} + +/** + block_build_prologue + - This routine builds the declarations for the + variables referenced in the block; as in: + int *y = .block_descriptor->y; + int x = .block_descriptor->x; + + The decl_expr declaration for each initialization is enterred at the + beginning of the helper function's statement-list which is passed + in block_impl->block_body. +*/ +void +block_build_prologue (struct block_sema_info *block_impl) +{ + tree chain; + /* APPLE LOCAL radar 6404979 */ + tree self_parm = lookup_name (get_identifier (".block_descriptor")); + gcc_assert (self_parm); + + for (chain = block_impl->block_ref_decl_list; chain; + chain = TREE_CHAIN (chain)) + declare_block_prologue_local_vars (self_parm, TREE_VALUE (chain), + block_impl->block_body); + + for (chain = block_impl->block_byref_decl_list; chain; + chain = TREE_CHAIN (chain)) + declare_block_prologue_local_vars (self_parm, TREE_VALUE (chain), + block_impl->block_body); +} +/* APPLE LOCAL end radar 5732232 - blocks (C++ ch) */ + /* Return a pointer to a structure for an empty list of declaration specifiers. */ @@ -8131,4 +9110,35 @@ c_write_global_declarations (void) ext_block = NULL; } +/* APPLE LOCAL begin radar 5741070 */ + +/* Given an IDENTIFIER tree for a class interface, find (if possible) and + return the record type for the class interface. */ + +tree +c_return_interface_record_type (tree typename) +{ + enum tree_code_class class; + enum tree_code code; + tree retval = NULL; + + if (typename == NULL) + return retval; + + code = TREE_CODE (typename); + class = TREE_CODE_CLASS (code); + + if (code != IDENTIFIER_NODE + || class != tcc_exceptional) + return retval; + + retval = I_TAG_DECL (typename); + + if (TREE_CODE (retval) != RECORD_TYPE) + retval = NULL; + + return retval; +} +/* APPLE LOCAL end radar 5741070 */ + #include "gt-c-decl.h" |