summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/c-common.c
diff options
context:
space:
mode:
authorpfg <pfg@FreeBSD.org>2014-01-05 00:43:28 +0000
committerpfg <pfg@FreeBSD.org>2014-01-05 00:43:28 +0000
commit9c8bbe68490d277cf64459b3390cf48e2a09ddf6 (patch)
treefffd69b9133b091a53ee14b3de5fd5006d53f92a /contrib/gcc/c-common.c
parentc5e9a8143da358a2c480a64c9782d5eedda3b002 (diff)
downloadFreeBSD-src-9c8bbe68490d277cf64459b3390cf48e2a09ddf6.zip
FreeBSD-src-9c8bbe68490d277cf64459b3390cf48e2a09ddf6.tar.gz
gcc: Add support for Apple's Block extension
Block objects [1] are a C-level syntactic and runtime feature. They are similar to standard C functions, but in addition to executable code they may also contain variable bindings to automatic (stack) or managed (heap) memory. A block can therefore maintain a set of state (data) that it can use to impact behavior when executed. This port is based on Apple's GCC 5646 with some bugfixes from Apple GCC 5666.3. It has some small differences with the support in clang, which remains the recommended compiler. Perhaps the most notable difference is that in GCC that __block is not actually a keyword, but a macro. There will be workaround for this issue in a near future. Other issues can be consulted in the clang documentation [2] For better compatiblity with Apple's GCC and llvm-gcc some related fixes and features from Apple have been included. Support for the non-standard nested functions in GCC is now off by default. No effort was made to update the ObjC support since FreeBSD doesn't carry ObjC in the base system, but some of the code crept in and was more difficult to remove than to adjust. Reference: [1] https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Blocks/Articles/00_Introduction.html [2] http://clang.llvm.org/compatibility.html#block-variable-initialization Obtained from: Apple GCC 4.2 MFC after: 3 weeks
Diffstat (limited to 'contrib/gcc/c-common.c')
-rw-r--r--contrib/gcc/c-common.c359
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"
OpenPOWER on IntegriCloud