diff options
Diffstat (limited to 'gcc/c-common.c')
-rw-r--r-- | gcc/c-common.c | 50 |
1 files changed, 27 insertions, 23 deletions
diff --git a/gcc/c-common.c b/gcc/c-common.c index 4114fbf2b19..c5b409e77c0 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -4309,39 +4309,43 @@ handle_transparent_union_attribute (tree *node, tree name, tree ARG_UNUSED (args), int flags, bool *no_add_attrs) { - tree decl = NULL_TREE; - tree *type = NULL; - int is_type = 0; + tree type = NULL; + + *no_add_attrs = true; if (DECL_P (*node)) { - decl = *node; - type = &TREE_TYPE (decl); - is_type = TREE_CODE (*node) == TYPE_DECL; + if (TREE_CODE (*node) != TYPE_DECL) + goto ignored; + node = &TREE_TYPE (*node); + type = *node; } else if (TYPE_P (*node)) - type = node, is_type = 1; + type = *node; + else + goto ignored; - if (is_type - && TREE_CODE (*type) == UNION_TYPE - && (decl == 0 - || (TYPE_FIELDS (*type) != 0 - && TYPE_MODE (*type) == DECL_MODE (TYPE_FIELDS (*type))))) + if (TREE_CODE (type) == UNION_TYPE) { + /* When IN_PLACE is set, leave the check for FIELDS and MODE to + the code in finish_struct. */ if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) - *type = build_variant_type_copy (*type); - TYPE_TRANSPARENT_UNION (*type) = 1; - } - else if (decl != 0 && TREE_CODE (decl) == PARM_DECL - && TREE_CODE (*type) == UNION_TYPE - && TYPE_MODE (*type) == DECL_MODE (TYPE_FIELDS (*type))) - DECL_TRANSPARENT_UNION (decl) = 1; - else - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; + { + if (TYPE_FIELDS (type) == NULL_TREE + || TYPE_MODE (type) != DECL_MODE (TYPE_FIELDS (type))) + goto ignored; + + /* A type variant isn't good enough, since we don't a cast + to such a type removed as a no-op. */ + *node = type = build_duplicate_type (type); + } + + TYPE_TRANSPARENT_UNION (type) = 1; + return NULL_TREE; } + ignored: + warning (OPT_Wattributes, "%qE attribute ignored", name); return NULL_TREE; } |