https://gcc.gnu.org/g:b6a513909793a87b62ca52da85ff3baa44f6b4b6
commit r15-5792-gb6a513909793a87b62ca52da85ff3baa44f6b4b6 Author: Martin Uecker <uec...@tugraz.at> Date: Thu Nov 28 20:06:16 2024 +0100 c: Correct type compatibility for bit-fields [PR117828] Add missing test for consistency of bit-fields when comparing tagged types for compatibility. PR c/117828 gcc/c/ChangeLog: * c-typeck.cc (tagged_types_tu_compatible_p): Add check. gcc/testsuite/ChangeLog: * gcc.dg/c23-tag-bitfields-1.c: New test. * gcc.dg/pr117828.c: New test. Diff: --- gcc/c/c-typeck.cc | 17 +++++++++- gcc/testsuite/gcc.dg/c23-tag-bitfields-1.c | 51 ++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/pr117828.c | 14 ++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 0189a800c11f..611daccb926d 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -1909,18 +1909,33 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, gcc_assert (TREE_CODE (s1) == FIELD_DECL); gcc_assert (TREE_CODE (s2) == FIELD_DECL); + tree ft1 = TREE_TYPE (s1); + tree ft2 = TREE_TYPE (s2); + if (DECL_NAME (s1) != DECL_NAME (s2)) return false; if (DECL_ALIGN (s1) != DECL_ALIGN (s2)) return false; + if (DECL_C_BIT_FIELD (s1) != DECL_C_BIT_FIELD (s2)) + return false; + + if (DECL_C_BIT_FIELD (s1)) + { + if (!tree_int_cst_equal (DECL_SIZE (s1), DECL_SIZE (s2))) + return false; + + ft1 = DECL_BIT_FIELD_TYPE (s1); + ft2 = DECL_BIT_FIELD_TYPE (s2); + } + data->anon_field = !DECL_NAME (s1); data->pointedto = false; const struct tagged_tu_seen_cache *cache = data->cache; data->cache = &entry; - bool ret = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), data); + bool ret = comptypes_internal (ft1, ft2, data); data->cache = cache; if (!ret) return false; diff --git a/gcc/testsuite/gcc.dg/c23-tag-bitfields-1.c b/gcc/testsuite/gcc.dg/c23-tag-bitfields-1.c new file mode 100644 index 000000000000..d775d9f67a13 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-bitfields-1.c @@ -0,0 +1,51 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c23" } */ + +struct bar0 { int r : 16; }; +struct bar0 { int r : 16; }; + +struct bar1 { int r : 16; }; +struct bar1 { int r : 17; }; /* { dg-error "redefinition" } */ + +extern struct { int r : 14; } a; +extern struct { int r : 14; } b; + +extern struct { int r : 14; } x; +extern struct { int r : 13; } x; /* { dg-error "conflicting" } */ + +struct bar2 { int s; int: 0; }; +struct bar2 { int s; int: 15; }; /* { dg-error "redefinition" } */ + +struct bar3 { int s; int : 0; }; +struct bar3 { int s; }; /* { dg-error "redefinition" } */ + +struct bar4 { int r : 3; }; +struct bar4 { const int r : 3; }; /* { dg-error "redefinition" } */ + +struct bar5 { int r : 16; }; +struct bar5 { int r; }; /* { dg-error "redefinition" } */ + +union ubar { int r : 16; }; +union ubar { int r : 16; }; + +union ubar1 { int r : 16; }; +union ubar1 { int r : 17; }; /* { dg-error "redefinition" } */ + +extern union { int r : 14; } c; +extern union { int r : 14; } d; + +extern union { int r : 14; } y; +extern union { int r : 13; } y; /* { dg-error "conflicting" } */ + +union ubar2 { int s; int : 0; }; +union ubar2 { int s; int : 15; }; /* { dg-error "redefinition" } */ + +union ubar3 { int s: 3; int: 0; }; +union ubar3 { int s: 3; }; /* { dg-error "redefinition" } */ + +union ubar4 { int r : 3; }; +union ubar4 { const int r : 3; }; /* { dg-error "redefinition" } */ + +union ubar5 { int r : 16; }; +union ubar5 { int r; }; /* { dg-error "redefinition" } */ + diff --git a/gcc/testsuite/gcc.dg/pr117828.c b/gcc/testsuite/gcc.dg/pr117828.c new file mode 100644 index 000000000000..d6750310d97d --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr117828.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-g" } */ + +struct { + struct { + int Reserved : 32; + } u; +} v; +struct { + struct { + int Reserved; + } u; +} w; +