Message ID | 20210914090206.GV304296@tucnak |
---|---|
State | New |
Headers | show |
Series | c++: Update DECL_*SIZE for objects with flexible array members with initializers [PR102295] | expand |
On 9/14/21 5:02 AM, Jakub Jelinek wrote: > Hi! > > The C FE updates DECL_*SIZE for vars which have initializers for flexible > array members for many years, but C++ FE kept DECL_*SIZE the same as the > type size (i.e. as if there were zero elements in the flexible array > member). This results e.g. in ELF symbol sizes being too small. > > The following patch fixes that, bootstrapped/regtested on x86_64-linux and > i686-linux, ok for trunk? OK. > Note, if the flexible array member is initialized only with non-constant > initializers, we have a worse bug that this patch doesn't solve, the > splitting of initializers into constant and dynamic initialization removes > the initializer and we don't have just wrong DECL_*SIZE, but nothing is > emitted when emitting those vars into assembly either and so the dynamic > initialization clobbers other vars that may overlap the variable. > I think we need keep an empty CONSTRUCTOR elt in DECL_INITIAL for the > flexible array member in that case. Makes sense. > 2021-09-14 Jakub Jelinek <jakub@redhat.com> > > PR c++/102295 > * decl.c (layout_var_decl): For aggregates ending with a flexible > array member, add the size of the initializer for that member to > DECL_SIZE and DECL_SIZE_UNIT. > > * g++.target/i386/pr102295.C: New test. > > --- gcc/cp/decl.c.jj 2021-09-09 10:40:26.063176136 +0200 > +++ gcc/cp/decl.c 2021-09-13 18:23:01.131587057 +0200 > @@ -6091,6 +6091,38 @@ layout_var_decl (tree decl) > error_at (DECL_SOURCE_LOCATION (decl), > "storage size of %qD isn%'t constant", decl); > TREE_TYPE (decl) = error_mark_node; > + type = error_mark_node; > + } > + } > + > + /* If the final element initializes a flexible array field, add the size of > + that initializer to DECL's size. */ > + if (type != error_mark_node > + && DECL_INITIAL (decl) > + && TREE_CODE (DECL_INITIAL (decl)) == CONSTRUCTOR > + && !vec_safe_is_empty (CONSTRUCTOR_ELTS (DECL_INITIAL (decl))) > + && DECL_SIZE (decl) != NULL_TREE > + && TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST > + && TYPE_SIZE (type) != NULL_TREE > + && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST > + && tree_int_cst_equal (DECL_SIZE (decl), TYPE_SIZE (type))) > + { > + constructor_elt &elt = CONSTRUCTOR_ELTS (DECL_INITIAL (decl))->last (); > + if (elt.index) > + { > + tree itype = TREE_TYPE (elt.index); > + tree vtype = TREE_TYPE (elt.value); > + if (TREE_CODE (itype) == ARRAY_TYPE > + && TYPE_DOMAIN (itype) == NULL > + && 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)); > + } > } > } > } > --- gcc/testsuite/g++.target/i386/pr102295.C.jj 2021-09-13 18:28:08.406370163 +0200 > +++ gcc/testsuite/g++.target/i386/pr102295.C 2021-09-13 18:28:26.846117106 +0200 > @@ -0,0 +1,12 @@ > +// PR c++/102295 > +// { dg-do compile { target *-*-linux* } } > +// { dg-options "-Wno-pedantic" } > + > +struct S { > + int a; > + int b[]; > +} S; > + > +struct S s = { 1, { 2, 3 } }; > + > +/* { dg-final { scan-assembler ".size\[\t \]*s, 12" } } */ > > Jakub >
--- gcc/cp/decl.c.jj 2021-09-09 10:40:26.063176136 +0200 +++ gcc/cp/decl.c 2021-09-13 18:23:01.131587057 +0200 @@ -6091,6 +6091,38 @@ layout_var_decl (tree decl) error_at (DECL_SOURCE_LOCATION (decl), "storage size of %qD isn%'t constant", decl); TREE_TYPE (decl) = error_mark_node; + type = error_mark_node; + } + } + + /* If the final element initializes a flexible array field, add the size of + that initializer to DECL's size. */ + if (type != error_mark_node + && DECL_INITIAL (decl) + && TREE_CODE (DECL_INITIAL (decl)) == CONSTRUCTOR + && !vec_safe_is_empty (CONSTRUCTOR_ELTS (DECL_INITIAL (decl))) + && DECL_SIZE (decl) != NULL_TREE + && TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST + && TYPE_SIZE (type) != NULL_TREE + && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST + && tree_int_cst_equal (DECL_SIZE (decl), TYPE_SIZE (type))) + { + constructor_elt &elt = CONSTRUCTOR_ELTS (DECL_INITIAL (decl))->last (); + if (elt.index) + { + tree itype = TREE_TYPE (elt.index); + tree vtype = TREE_TYPE (elt.value); + if (TREE_CODE (itype) == ARRAY_TYPE + && TYPE_DOMAIN (itype) == NULL + && 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)); + } } } } --- gcc/testsuite/g++.target/i386/pr102295.C.jj 2021-09-13 18:28:08.406370163 +0200 +++ gcc/testsuite/g++.target/i386/pr102295.C 2021-09-13 18:28:26.846117106 +0200 @@ -0,0 +1,12 @@ +// PR c++/102295 +// { dg-do compile { target *-*-linux* } } +// { dg-options "-Wno-pedantic" } + +struct S { + int a; + int b[]; +} S; + +struct S s = { 1, { 2, 3 } }; + +/* { dg-final { scan-assembler ".size\[\t \]*s, 12" } } */