diff options
Diffstat (limited to 'gcc/c-family/c-common.c')
-rw-r--r-- | gcc/c-family/c-common.c | 65 |
1 files changed, 62 insertions, 3 deletions
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index bdcb5b25401..53c1d81c0c8 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -339,6 +339,8 @@ static tree handle_no_reorder_attribute (tree *, tree, tree, int, static tree handle_const_attribute (tree *, tree, tree, int, bool *); static tree handle_transparent_union_attribute (tree *, tree, tree, int, bool *); +static tree handle_scalar_storage_order_attribute (tree *, tree, tree, + int, bool *); static tree handle_constructor_attribute (tree *, tree, tree, int, bool *); static tree handle_destructor_attribute (tree *, tree, tree, int, bool *); static tree handle_mode_attribute (tree *, tree, tree, int, bool *); @@ -693,6 +695,8 @@ const struct attribute_spec c_common_attribute_table[] = /* The same comments as for noreturn attributes apply to const ones. */ { "const", 0, 0, true, false, false, handle_const_attribute, false }, + { "scalar_storage_order", 1, 1, false, false, false, + handle_scalar_storage_order_attribute, false }, { "transparent_union", 0, 0, false, false, false, handle_transparent_union_attribute, false }, { "constructor", 0, 1, true, false, false, @@ -7668,6 +7672,62 @@ handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args), return NULL_TREE; } +/* Handle a "scalar_storage_order" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_scalar_storage_order_attribute (tree *node, tree name, tree args, + int flags, bool *no_add_attrs) +{ + tree id = TREE_VALUE (args); + tree type; + + if (TREE_CODE (*node) == TYPE_DECL + && ! (flags & ATTR_FLAG_CXX11)) + node = &TREE_TYPE (*node); + type = *node; + + if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN) + { + error ("scalar_storage_order is not supported because endianness " + "is not uniform"); + return NULL_TREE; + } + + if (RECORD_OR_UNION_TYPE_P (type) && !c_dialect_cxx ()) + { + bool reverse = false; + + if (TREE_CODE (id) == STRING_CST + && strcmp (TREE_STRING_POINTER (id), "big-endian") == 0) + reverse = !BYTES_BIG_ENDIAN; + else if (TREE_CODE (id) == STRING_CST + && strcmp (TREE_STRING_POINTER (id), "little-endian") == 0) + reverse = BYTES_BIG_ENDIAN; + else + { + error ("scalar_storage_order argument must be one of \"big-endian\"" + " or \"little-endian\""); + return NULL_TREE; + } + + if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) + { + if (reverse) + /* A type variant isn't good enough, since we don't want a cast + to such a type to be removed as a no-op. */ + *node = type = build_duplicate_type (type); + } + + TYPE_REVERSE_STORAGE_ORDER (type) = reverse; + return NULL_TREE; + } + + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + return NULL_TREE; +} + /* Handle a "transparent_union" attribute; arguments as in struct attribute_spec.handler. */ @@ -7680,7 +7740,6 @@ handle_transparent_union_attribute (tree *node, tree name, *no_add_attrs = true; - if (TREE_CODE (*node) == TYPE_DECL && ! (flags & ATTR_FLAG_CXX11)) node = &TREE_TYPE (*node); @@ -7711,8 +7770,8 @@ handle_transparent_union_attribute (tree *node, tree name, if (c_dialect_cxx ()) goto ignored; - /* A type variant isn't good enough, since we don't a cast - to such a type removed as a no-op. */ + /* A type variant isn't good enough, since we don't want a cast + to such a type to be removed as a no-op. */ *node = type = build_duplicate_type (type); } |