Index: gcc/alias.c =================================================================== --- gcc/alias.c (revision 246678) +++ gcc/alias.c (working copy) @@ -879,6 +879,10 @@ get_alias_set (tree t) t = TREE_TYPE (t); } + /* Honor the typeless_storage type attribute. */ + if (TYPE_TYPELESS_STORAGE (t)) + return 0; + /* Variant qualifiers don't affect the alias set, so get the main variant. */ t = TYPE_MAIN_VARIANT (t); @@ -1234,7 +1238,8 @@ record_component_aliases (tree type) /* VECTOR_TYPE and ARRAY_TYPE share the alias set with their element type and that type has to be normalized to void *, too, in the case it is a pointer. */ - while (!canonical_type_used_p (t) && !POINTER_TYPE_P (t)) + while (!canonical_type_used_p (t) && !POINTER_TYPE_P (t) + && !TYPE_TYPELESS_STORAGE (t)) { gcc_checking_assert (TYPE_STRUCTURAL_EQUALITY_P (t)); t = TREE_TYPE (t); Index: gcc/c-family/c-attribs.c =================================================================== --- gcc/c-family/c-attribs.c (revision 246678) +++ gcc/c-family/c-attribs.c (working copy) @@ -113,6 +113,7 @@ static tree handle_vector_size_attribute (tree *, bool *); static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *); static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *); +static tree handle_typeless_storage_attribute (tree *, tree, tree, int, bool *); static tree handle_cleanup_attribute (tree *, tree, tree, int, bool *); static tree handle_warn_unused_result_attribute (tree *, tree, tree, int, bool *); @@ -265,6 +266,8 @@ const struct attribute_spec c_common_attribute_tab { "nothrow", 0, 0, true, false, false, handle_nothrow_attribute, false }, { "may_alias", 0, 0, false, true, false, NULL, false }, + { "typeless_storage", 0, 0, false, true, false, + handle_typeless_storage_attribute, false }, { "cleanup", 1, 1, true, false, false, handle_cleanup_attribute, false }, { "warn_unused_result", 0, 0, false, true, true, @@ -2879,6 +2882,24 @@ handle_nothrow_attribute (tree *node, tree name, t return NULL_TREE; } +/* Handle a "typeless_storage" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_typeless_storage_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TYPE_P (*node)) + TYPE_TYPELESS_STORAGE (*node) = 1; + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + /* Handle a "cleanup" attribute; arguments as in struct attribute_spec.handler. */ Index: gcc/cp/class.c =================================================================== --- gcc/cp/class.c (revision 246678) +++ gcc/cp/class.c (working copy) @@ -2083,7 +2083,8 @@ fixup_attribute_variants (tree t) tree attrs = TYPE_ATTRIBUTES (t); unsigned align = TYPE_ALIGN (t); bool user_align = TYPE_USER_ALIGN (t); - bool may_alias = lookup_attribute ("may_alias", attrs); + bool may_alias = TYPE_TYPELESS_STORAGE (t) + || lookup_attribute ("may_alias", attrs); if (may_alias) fixup_may_alias (t); @@ -7345,6 +7348,12 @@ finish_struct_1 (tree t) the class or perform any other required target modifications. */ targetm.cxx.adjust_class_at_definition (t); + if (cxx_dialect >= cxx1z && cxx_type_contains_byte_buffer (t)) + { + TYPE_TYPELESS_STORAGE (t) = 1; + fixup_attribute_variants (t); + } + maybe_suppress_debug_info (t); if (flag_vtable_verify) Index: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h (revision 246678) +++ gcc/cp/cp-tree.h (working copy) @@ -6858,6 +6858,7 @@ extern tree finish_binary_fold_expr (tree extern void require_complete_eh_spec_types (tree, tree); extern void cxx_incomplete_type_diagnostic (location_t, const_tree, const_tree, diagnostic_t); +extern bool cxx_type_contains_byte_buffer (tree); inline void cxx_incomplete_type_diagnostic (const_tree value, const_tree type, diagnostic_t diag_kind) Index: gcc/cp/decl.c =================================================================== --- gcc/cp/decl.c (revision 246678) +++ gcc/cp/decl.c (working copy) @@ -14081,10 +14081,11 @@ start_enum (tree name, tree enumtype, tree underly enumtype = pushtag (name, enumtype, /*tag_scope=*/ts_current); /* std::byte aliases anything. */ - if (enumtype != error_mark_node + if (cxx_dialect >= cxx1z + && enumtype != error_mark_node && TYPE_CONTEXT (enumtype) == std_node && !strcmp ("byte", TYPE_NAME_STRING (enumtype))) - TYPE_ALIAS_SET (enumtype) = 0; + TYPE_TYPELESS_STORAGE (enumtype) = 1; } else enumtype = xref_tag (enum_type, name, /*tag_scope=*/ts_current, Index: gcc/cp/pt.c =================================================================== --- gcc/cp/pt.c (revision 246678) +++ gcc/cp/pt.c (working copy) @@ -8853,7 +8853,8 @@ lookup_template_class_1 (tree d1, tree arglist, tr { static const char *tags[] = {"abi_tag", "may_alias"}; - for (unsigned ix = 0; ix != 2; ix++) + TYPE_TYPELESS_STORAGE (t) |= TYPE_TYPELESS_STORAGE (template_type); + for (unsigned ix = 0; ix < sizeof (tags) / sizeof (tags[0]); ix++) { tree attributes = lookup_attribute (tags[ix], TYPE_ATTRIBUTES (template_type)); Index: gcc/cp/typeck2.c =================================================================== --- gcc/cp/typeck2.c (revision 246678) +++ gcc/cp/typeck2.c (working copy) @@ -2234,5 +2234,29 @@ require_complete_eh_spec_types (tree fntype, tree } } +/* True iff type either is or contains a byte buffer (which can be used for + storing any trivially copyable type). */ + +bool +cxx_type_contains_byte_buffer (tree type) +{ + if (TREE_CODE (type) == ARRAY_TYPE + && (cxx_type_contains_byte_buffer (TREE_TYPE (type)) + || TREE_TYPE (type) == unsigned_char_type_node + || (TREE_CODE (TREE_TYPE (type)) == ENUMERAL_TYPE + && TYPE_CONTEXT (TREE_TYPE (type)) == std_node + && !strcmp ("byte", TYPE_NAME_STRING (TREE_TYPE (type)))))) + return true; + + if (CLASS_TYPE_P (type)) + for (tree field = next_initializable_field (TYPE_FIELDS (type)); + field; + field = next_initializable_field (DECL_CHAIN (field))) + if (cxx_type_contains_byte_buffer (TREE_TYPE (field))) + return true; + + return false; +} + #include "gt-cp-typeck2.h" Index: gcc/doc/extend.texi =================================================================== --- gcc/doc/extend.texi (revision 246678) +++ gcc/doc/extend.texi (working copy) @@ -6656,6 +6656,11 @@ declaration, the above program would abort when co @option{-fstrict-aliasing}, which is on by default at @option{-O2} or above. +@item typeless_storage +@cindex @code{typeless_storage} type attribute +An object declared with a type with this attribute behaves like a +character type with respect to aliasing semantics. + @item packed @cindex @code{packed} type attribute This attribute, attached to @code{struct} or @code{union} type Index: gcc/lto/lto.c =================================================================== --- gcc/lto/lto.c (revision 246678) +++ gcc/lto/lto.c (working copy) @@ -1164,6 +1164,7 @@ compare_tree_sccs_1 (tree t1, tree t2, tree **map) compare_values (TYPE_NONALIASED_COMPONENT); compare_values (TYPE_PACKED); compare_values (TYPE_RESTRICT); + compare_values (TYPE_TYPELESS_STORAGE); compare_values (TYPE_USER_ALIGN); compare_values (TYPE_READONLY); compare_values (TYPE_PRECISION); Index: gcc/lto-streamer-out.c =================================================================== --- gcc/lto-streamer-out.c (revision 246678) +++ gcc/lto-streamer-out.c (working copy) @@ -1134,6 +1134,7 @@ hash_tree (struct streamer_tree_cache_d *cache, ha hstate.add_flag (TYPE_NEEDS_CONSTRUCTING (t)); hstate.add_flag (TYPE_PACKED (t)); hstate.add_flag (TYPE_RESTRICT (t)); + hstate.add_flag (TYPE_TYPELESS_STORAGE (t)); hstate.add_flag (TYPE_USER_ALIGN (t)); hstate.add_flag (TYPE_READONLY (t)); if (RECORD_OR_UNION_TYPE_P (t)) Index: gcc/print-tree.c =================================================================== --- gcc/print-tree.c (revision 246678) +++ gcc/print-tree.c (working copy) @@ -574,6 +574,9 @@ print_node (FILE *file, const char *prefix, tree n if (TYPE_RESTRICT (node)) fputs (" restrict", file); + if (TYPE_TYPELESS_STORAGE (node)) + fputs (" typeless-storage", file); + if (TYPE_LANG_FLAG_0 (node)) fputs (" type_0", file); if (TYPE_LANG_FLAG_1 (node)) Index: gcc/testsuite/c-c++-common/attr-typeless-storage-1.c =================================================================== --- gcc/testsuite/c-c++-common/attr-typeless-storage-1.c (revision 0) +++ gcc/testsuite/c-c++-common/attr-typeless-storage-1.c (working copy) @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -Wall" } */ + +typedef int T __attribute__((typeless_storage)); + +extern T t, v; +extern T *p; +extern int *p; + +extern int *p2; +extern T *p2; + +void fn1 (T); +void fn1 (int); + +void fn2 (int); +void fn2 (T); + +/* Ensure that the composite types have typeless_storage. */ +void +f (long *i) +{ + *i = *(__typeof (*p) *) &p; + asm ("" : : "r" (*p)); + *i = *(__typeof (*p2) *) &p2; + asm ("" : : "r" (*p2)); + t = v; + asm ("" : : "r" (t)); +} Index: gcc/testsuite/c-c++-common/attr-typeless-storage-2.c =================================================================== --- gcc/testsuite/c-c++-common/attr-typeless-storage-2.c (revision 0) +++ gcc/testsuite/c-c++-common/attr-typeless-storage-2.c (working copy) @@ -0,0 +1,17 @@ +/* We used to reject this because types differentiating only in + TYPE_REF_CAN_ALIAS_ALL were deemed incompatible. */ +/* { dg-do compile } */ + +struct sockaddr; +struct sockaddr *f (void); + +struct __attribute__((typeless_storage)) sockaddr { int j; }; +struct sockaddr * +f (void) +{ + return +#ifndef __cplusplus + (void *) +#endif + 0; +} Index: gcc/testsuite/gcc.c-torture/execute/typeless-storage-1.c =================================================================== --- gcc/testsuite/gcc.c-torture/execute/typeless-storage-1.c (revision 0) +++ gcc/testsuite/gcc.c-torture/execute/typeless-storage-1.c (working copy) @@ -0,0 +1,20 @@ +/* Tests that the typeless_storage attribute works as expected. */ + +extern void abort(void); +extern void exit(int); + +typedef int __attribute__((__typeless_storage__)) int_a; + +int +main (void) +{ + int_a a = 0x12345678; + short *b = (short*) &a; + + b[1] = 0; + + if (a == 0x12345678) + abort(); + + exit(0); +} Index: gcc/tree-core.h =================================================================== --- gcc/tree-core.h (revision 246678) +++ gcc/tree-core.h (working copy) @@ -1491,6 +1491,7 @@ struct GTY(()) tree_type_common { unsigned needs_constructing_flag : 1; unsigned transparent_aggr_flag : 1; unsigned restrict_flag : 1; + unsigned typeless_storage_flag : 1; unsigned contains_placeholder_bits : 2; ENUM_BITFIELD(machine_mode) mode : 8; @@ -1511,7 +1512,7 @@ struct GTY(()) tree_type_common { so we need to store the value 32 (not 31, as we need the zero as well), hence six bits. */ unsigned align : 6; - unsigned spare : 25; + unsigned spare : 24; alias_set_type alias_set; tree pointer_to; tree reference_to; Index: gcc/tree-streamer-in.c =================================================================== --- gcc/tree-streamer-in.c (revision 246678) +++ gcc/tree-streamer-in.c (working copy) @@ -367,6 +367,7 @@ unpack_ts_type_common_value_fields (struct bitpack TYPE_NEEDS_CONSTRUCTING (expr) = (unsigned) bp_unpack_value (bp, 1); TYPE_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1); TYPE_RESTRICT (expr) = (unsigned) bp_unpack_value (bp, 1); + TYPE_TYPELESS_STORAGE (expr) = (unsigned) bp_unpack_value (bp, 1); TYPE_USER_ALIGN (expr) = (unsigned) bp_unpack_value (bp, 1); TYPE_READONLY (expr) = (unsigned) bp_unpack_value (bp, 1); if (RECORD_OR_UNION_TYPE_P (expr)) Index: gcc/tree-streamer-out.c =================================================================== --- gcc/tree-streamer-out.c (revision 246678) +++ gcc/tree-streamer-out.c (working copy) @@ -316,6 +316,7 @@ pack_ts_type_common_value_fields (struct bitpack_d bp_pack_value (bp, TYPE_NEEDS_CONSTRUCTING (expr), 1); bp_pack_value (bp, TYPE_PACKED (expr), 1); bp_pack_value (bp, TYPE_RESTRICT (expr), 1); + bp_pack_value (bp, TYPE_TYPELESS_STORAGE (expr), 1); bp_pack_value (bp, TYPE_USER_ALIGN (expr), 1); bp_pack_value (bp, TYPE_READONLY (expr), 1); /* We used to stream TYPE_ALIAS_SET == 0 information to let frontends mark Index: gcc/tree.c =================================================================== --- gcc/tree.c (revision 246678) +++ gcc/tree.c (working copy) @@ -8041,7 +8041,8 @@ build_pointer_type_for_mode (tree to_type, machine /* If the pointed-to type has the may_alias attribute set, force a TYPE_REF_CAN_ALIAS_ALL pointer to be generated. */ - if (lookup_attribute ("may_alias", TYPE_ATTRIBUTES (to_type))) + if (TYPE_TYPELESS_STORAGE (to_type) + || lookup_attribute ("may_alias", TYPE_ATTRIBUTES (to_type))) can_alias_all = true; /* In some cases, languages will have things that aren't a POINTER_TYPE @@ -8110,7 +8111,8 @@ build_reference_type_for_mode (tree to_type, machi /* If the pointed-to type has the may_alias attribute set, force a TYPE_REF_CAN_ALIAS_ALL pointer to be generated. */ - if (lookup_attribute ("may_alias", TYPE_ATTRIBUTES (to_type))) + if (TYPE_TYPELESS_STORAGE (to_type) + || lookup_attribute ("may_alias", TYPE_ATTRIBUTES (to_type))) can_alias_all = true; /* In some cases, languages will have things that aren't a REFERENCE_TYPE Index: gcc/tree.h =================================================================== --- gcc/tree.h (revision 246678) +++ gcc/tree.h (working copy) @@ -1944,6 +1944,11 @@ extern machine_mode element_mode (const_tree t); the term. */ #define TYPE_RESTRICT(NODE) (TYPE_CHECK (NODE)->type_common.restrict_flag) +/* Nonzero if the type should behave like a character type + with respect to aliasing sementics. */ +#define TYPE_TYPELESS_STORAGE(NODE) \ + (TYPE_CHECK (NODE)->type_common.typeless_storage_flag) + /* If nonzero, type's name shouldn't be emitted into debug info. */ #define TYPE_NAMELESS(NODE) (TYPE_CHECK (NODE)->base.u.bits.nameless_flag)