Index: gcc/doc/extend.texi =================================================================== --- gcc/doc/extend.texi (revision 246678) +++ gcc/doc/extend.texi (working copy) @@ -6656,6 +6656,36 @@ @option{-fstrict-aliasing}, which is on by default at @option{-O2} or above. +@item typeless_storage +@cindex @code{typeless_storage} type attribute +In the context of section 6.5 paragraph 6 of the C11 standard, +an object of this type behaves as if it has no declared type. +In the context of section 6.5 paragraph 7 of the C11 standard, +an object or a pointer if this type behaves as if it were a +character type. +This attribute is similar to the @code{may_alias} attribute, +except that it is not restricted to pointers. + +Example of use: + +@smallexample +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); +@} +@end smallexample + @item packed @cindex @code{packed} type attribute This attribute, attached to @code{struct} or @code{union} type 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) @@ -2097,6 +2097,7 @@ fixup_attribute_variants (tree t) /* These are the two fields that check_qualified_type looks at and are affected by attributes. */ TYPE_ATTRIBUTES (variants) = attrs; + TYPE_TYPELESS_STORAGE (variants) = TYPE_TYPELESS_STORAGE (t); unsigned valign = align; if (TYPE_USER_ALIGN (variants)) valign = MAX (valign, TYPE_ALIGN (variants)); @@ -7345,6 +7346,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/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/tree-core.h =================================================================== --- gcc/tree-core.h (revision 246678) +++ gcc/tree-core.h (working copy) @@ -1216,6 +1216,9 @@ struct GTY(()) tree_base { DECL_NONALIASED in VAR_DECL + TYPE_TYPELESS_STORAGE in + all types + deprecated_flag: TREE_DEPRECATED in 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.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)->base.nothrow_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) 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); +}