diff options
author | Martin Uecker <uecker@tugraz.at> | 2023-08-15 22:38:14 +0200 |
---|---|---|
committer | Martin Uecker <uecker@tugraz.at> | 2023-12-21 08:43:16 +0100 |
commit | 140aa2cdf93c7729e362b09534535395357183f0 (patch) | |
tree | d64e26001033f9e6079a5720a8da4746090e4a5e /gcc/c/c-decl.cc | |
parent | ced651b7757e6ef7e7e309f022cd71b4b6ead295 (diff) | |
download | gcc-140aa2cdf93c7729e362b09534535395357183f0.zip gcc-140aa2cdf93c7729e362b09534535395357183f0.tar.gz gcc-140aa2cdf93c7729e362b09534535395357183f0.tar.bz2 |
c23: aliasing of compatible tagged types
Tell the backend which types are equivalent by setting
TYPE_CANONICAL to one struct in the set of equivalent
structs. Structs are considered equivalent by ignoring
all sizes of arrays nested in types below field level.
The following two structs are incompatible and lvalues
with these types can be assumed not to alias:
struct foo { int a[3]; };
struct foo { int a[4]; };
The following two structs are also incompatible, but
will get the same TYPE_CANONICAL and it is then not
exploited that lvalues with those types can not alias:
struct bar { int (*p)[3]; };
struct bar { int (*p)[4]; };
The reason is that both are compatible to
struct bar { int (*p)[]; };
and therefore are in the same equivalence class. For
the same reason all enums with the same underyling type
are in the same equivalence class. Tests are added
for the expected aliasing behavior with optimization.
gcc/c:
* c-decl.cc (c_struct_hasher): Hash stable for struct
types.
(c_struct_hasher::hash, c_struct_hasher::equal): New
functions.
(finish_struct): Set TYPE_CANONICAL to first struct in
equivalence class.
* c-objc-common.cc (c_get_alias_set): Let structs or
unions with variable size alias anything.
* c-tree.h (comptypes_equiv): New prototype.
* c-typeck.cc (comptypes_equiv): New function.
(comptypes_internal): Implement equivalence mode.
(tagged_types_tu_compatible): Implement equivalence mode.
gcc/testsuite:
* gcc.dg/c23-tag-2.c: Activate.
* gcc.dg/c23-tag-5.c: Activate.
* gcc.dg/c23-tag-alias-1.c: New test.
* gcc.dg/c23-tag-alias-2.c: New test.
* gcc.dg/c23-tag-alias-3.c: New test.
* gcc.dg/c23-tag-alias-4.c: New test.
* gcc.dg/c23-tag-alias-5.c: New test.
* gcc.dg/gnu23-tag-alias-1.c: New test.
* gcc.dg/gnu23-tag-alias-2.c: New test.
* gcc.dg/gnu23-tag-alias-3.c: New test.
* gcc.dg/gnu23-tag-alias-4.c: New test.
* gcc.dg/gnu23-tag-alias-5.c: New test.
* gcc.dg/gnu23-tag-alias-6.c: New test.
* gcc.dg/gnu23-tag-alias-7.c: New test.
Diffstat (limited to 'gcc/c/c-decl.cc')
-rw-r--r-- | gcc/c/c-decl.cc | 51 |
1 files changed, 50 insertions, 1 deletions
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 26188aa..6639ec3 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -634,6 +634,36 @@ public: auto_vec<tree> typedefs_seen; }; + +/* Hash table for structs and unions. */ +struct c_struct_hasher : ggc_ptr_hash<tree_node> +{ + static hashval_t hash (tree t); + static bool equal (tree, tree); +}; + +/* Hash an RECORD OR UNION. */ +hashval_t +c_struct_hasher::hash (tree type) +{ + inchash::hash hstate; + + hstate.add_int (TREE_CODE (type)); + hstate.add_object (TYPE_NAME (type)); + + return hstate.end (); +} + +/* Compare two RECORD or UNION types. */ +bool +c_struct_hasher::equal (tree t1, tree t2) +{ + return comptypes_equiv_p (t1, t2); +} + +/* All tagged typed so that TYPE_CANONICAL can be set correctly. */ +static GTY (()) hash_table<c_struct_hasher> *c_struct_htab; + /* Information for the struct or union currently being parsed, or NULL if not parsing a struct or union. */ static class c_struct_parse_info *struct_parse_info; @@ -8713,7 +8743,8 @@ parser_xref_tag (location_t loc, enum tree_code code, tree name, ref = lookup_tag (code, name, has_enum_type_specifier, &refloc); /* If the visble type is still being defined, see if there is - an earlier definition (which may be complete). */ + an earlier definition (which may be complete). We do not + have to loop because nested redefinitions are not allowed. */ if (flag_isoc23 && ref && C_TYPE_BEING_DEFINED (ref)) { tree vis = previous_tag (ref); @@ -9661,6 +9692,24 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, C_TYPE_BEING_DEFINED (t) = 0; + /* Set type canonical based on equivalence class. */ + if (flag_isoc23) + { + if (NULL == c_struct_htab) + c_struct_htab = hash_table<c_struct_hasher>::create_ggc (61); + + hashval_t hash = c_struct_hasher::hash (t); + + tree *e = c_struct_htab->find_slot_with_hash (t, hash, INSERT); + if (*e) + TYPE_CANONICAL (t) = *e; + else + { + TYPE_CANONICAL (t) = t; + *e = t; + } + } + tree incomplete_vars = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t)); for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x)) { |