"add_flexible_array_elts_to_size" C++ FE routine "layout_var_decl" to handle the cases when the DECL is union.
Add testing cases to test the _bos for flexible array members in unions or alone in structures. gcc/c/ChangeLog: * c-decl.cc (add_flexible_array_elts_to_size): Handle the cases when the DECL is union. gcc/cp/ChangeLog: * decl.cc (layout_var_decl): Handle the cases when the DECL is union with a flexible array member initializer. gcc/testsuite/ChangeLog: * c-c++-common/fam-in-union-alone-in-struct-bos-1.c: New test. * c-c++-common/fam-in-union-alone-in-struct-bos.c: New test. --- gcc/c/c-decl.cc | 29 ++++++-- gcc/cp/decl.cc | 32 +++++++-- .../fam-in-union-alone-in-struct-bos-1.c | 66 +++++++++++++++++++ .../fam-in-union-alone-in-struct-bos.c | 45 +++++++++++++ 4 files changed, 159 insertions(+), 13 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/fam-in-union-alone-in-struct-bos-1.c create mode 100644 gcc/testsuite/c-c++-common/fam-in-union-alone-in-struct-bos.c diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 947f3cd589eb..5d571621d915 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -5337,8 +5337,9 @@ zero_length_array_type_p (const_tree type) } /* INIT is a constructor that forms DECL's initializer. If the final - element initializes a flexible array field, add the size of that - initializer to DECL's size. */ + element initializes a flexible array field, adjust the size of the + DECL with the initializer based on whether the DECL is a union or + a structure. */ static void add_flexible_array_elts_to_size (tree decl, tree init) @@ -5353,10 +5354,26 @@ add_flexible_array_elts_to_size (tree decl, tree init) if (flexible_array_member_type_p (type)) { complete_array_type (&type, elt, false); - DECL_SIZE (decl) - = size_binop (PLUS_EXPR, DECL_SIZE (decl), TYPE_SIZE (type)); - DECL_SIZE_UNIT (decl) - = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl), TYPE_SIZE_UNIT (type)); + /* For a structure, add the size of the initializer to the DECL's + size. */ + if (TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE) + { + DECL_SIZE (decl) + = size_binop (PLUS_EXPR, DECL_SIZE (decl), TYPE_SIZE (type)); + DECL_SIZE_UNIT (decl) + = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl), + TYPE_SIZE_UNIT (type)); + } + /* For a union, the DECL's size is the maximum of the current size + and the size of the initializer. */ + else + { + DECL_SIZE (decl) + = size_binop (MAX_EXPR, DECL_SIZE (decl), TYPE_SIZE (type)); + DECL_SIZE_UNIT (decl) + = size_binop (MAX_EXPR, DECL_SIZE_UNIT (decl), + TYPE_SIZE_UNIT (type)); + } } } diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 9a91c6f80da1..78e21b05296c 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -6555,8 +6555,9 @@ layout_var_decl (tree decl) } } - /* If the final element initializes a flexible array field, add the size of - that initializer to DECL's size. */ + /* If the final element initializes a flexible array field, adjust + the size of the DECL with the initializer based on whether the + DECL is a union or a structure. */ if (type != error_mark_node && DECL_INITIAL (decl) && TREE_CODE (DECL_INITIAL (decl)) == CONSTRUCTOR @@ -6577,11 +6578,28 @@ layout_var_decl (tree decl) && TREE_CODE (vtype) == ARRAY_TYPE && COMPLETE_TYPE_P (vtype)) { - DECL_SIZE (decl) - = size_binop (PLUS_EXPR, DECL_SIZE (decl), TYPE_SIZE (vtype)); - DECL_SIZE_UNIT (decl) - = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl), - TYPE_SIZE_UNIT (vtype)); + /* For a structure, add the size of the initializer to the DECL's + size. */ + if (TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE) + { + DECL_SIZE (decl) + = size_binop (PLUS_EXPR, DECL_SIZE (decl), + TYPE_SIZE (vtype)); + DECL_SIZE_UNIT (decl) + = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl), + TYPE_SIZE_UNIT (vtype)); + } + /* For a union, the DECL's size is the maximum of the current size + and the size of the initializer. */ + else + { + DECL_SIZE (decl) + = size_binop (MAX_EXPR, DECL_SIZE (decl), + TYPE_SIZE (vtype)); + DECL_SIZE_UNIT (decl) + = size_binop (MAX_EXPR, DECL_SIZE_UNIT (decl), + TYPE_SIZE_UNIT (vtype)); + } } } } diff --git a/gcc/testsuite/c-c++-common/fam-in-union-alone-in-struct-bos-1.c b/gcc/testsuite/c-c++-common/fam-in-union-alone-in-struct-bos-1.c new file mode 100644 index 000000000000..aae9cf39c8c7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/fam-in-union-alone-in-struct-bos-1.c @@ -0,0 +1,66 @@ +/* testing flexible array members in unions and alone in structures: + __bos/__bdos */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +union with_fam_1 { + char a; + int b[]; +} *with_fam_1_v; + +union with_fam_2 { + int a; + char b[]; +} *with_fam_2_v; + +union with_fam_3 { + char a[]; + int b[]; +} *with_fam_3_v; + +struct only_fam { + int b[]; +} *only_fam_v; + +struct only_fam_2 { + unsigned int : 2; + unsigned int : 3; + int b[]; +} *only_fam_2_v; + +void __attribute__((__noinline__)) +setup (int n1, int n2, int n3, int n4, int n5) +{ + with_fam_1_v = (union with_fam_1 *) __builtin_malloc (n1 * sizeof (int)); + with_fam_2_v = (union with_fam_2 *) __builtin_malloc (n2 * sizeof (char)); + with_fam_3_v = (union with_fam_3 *) __builtin_malloc (n3 * sizeof (int)); + only_fam_v = (struct only_fam *) __builtin_malloc (n4 * sizeof (int)); + only_fam_2_v = (struct only_fam_2 *) __builtin_malloc (n5 * sizeof (int)); + return; +} + +void __attribute__((__noinline__)) stuff( + union with_fam_1 *with_fam_1_v, + union with_fam_2 *with_fam_2_v, + union with_fam_3 *with_fam_3_v, + struct only_fam *only_fam_v, + struct only_fam_2 *only_fam_2_v) +{ + if (__builtin_object_size(with_fam_1_v->b, 1) != -1) + __builtin_abort (); + if (__builtin_object_size(with_fam_2_v->b, 1) != -1) + __builtin_abort (); + if (__builtin_object_size(with_fam_3_v->b, 1) != -1) + __builtin_abort (); + if (__builtin_object_size(only_fam_v->b, 1) != -1) + __builtin_abort (); + if (__builtin_object_size(only_fam_2_v->b, 1) != -1) + __builtin_abort (); +} + +int main (int argc, char *argv[]) +{ + setup (2, 3, 4, 5, 6); + stuff (with_fam_1_v, with_fam_2_v, with_fam_3_v, only_fam_v, only_fam_2_v); + return 0; +} diff --git a/gcc/testsuite/c-c++-common/fam-in-union-alone-in-struct-bos.c b/gcc/testsuite/c-c++-common/fam-in-union-alone-in-struct-bos.c new file mode 100644 index 000000000000..21badc57982b --- /dev/null +++ b/gcc/testsuite/c-c++-common/fam-in-union-alone-in-struct-bos.c @@ -0,0 +1,45 @@ +/* testing flexible array members in unions and alone in structures: + __bos/__bdos */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +union with_fam_1 { + char a; + int b[]; +} with_fam_1_v = {.b = {1, 2, 3, 4, 5}}; + +union with_fam_2 { + int a; + char b[]; +} with_fam_2_v = {.a = 0x1f2f3f4f}; + +union with_fam_3 { + char a[]; + int b[]; +} with_fam_3_v = {.b = {0x1f2f3f4f, 0x5f6f7f7f}}; + +struct only_fam { + int b[]; +} only_fam_v = {{7, 11}}; + +struct only_fam_2 { + unsigned int : 2; + unsigned int : 3; + int b[]; +} only_fam_2_v = {{7, 11}}; + +int main () +{ + if (__builtin_object_size(with_fam_1_v.b, 1) != 20) + __builtin_abort (); + if (__builtin_object_size(with_fam_2_v.b, 1) != 4) + __builtin_abort (); + if (__builtin_object_size(with_fam_3_v.b, 1) != 8) + __builtin_abort (); + if (__builtin_object_size(only_fam_v.b, 1) != 8) + __builtin_abort (); + if (__builtin_object_size(only_fam_2_v.b, 1) != 8) + __builtin_abort (); + + return 0; +} -- 2.31.1