Use TYPE_INCLUDES_FLEXARRAY in __builtin_object_size [PR tree-optimization/101832]
__builtin_object_size should treat struct with TYPE_INCLUDES_FLEXARRAY as flexible size. gcc/ChangeLog: PR tree-optimization/101832 * tree-object-size.cc (addr_object_size): Handle structure/union type when it has flexible size. gcc/testsuite/ChangeLog: PR tree-optimization/101832 * gcc.dg/builtin-object-size-pr101832.c: New test.
This commit is contained in:
parent
db5d70632a
commit
e050ce7c3a
2 changed files with 156 additions and 1 deletions
134
gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
Normal file
134
gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
Normal file
|
@ -0,0 +1,134 @@
|
|||
/* PR 101832:
|
||||
GCC extension accepts the case when a struct with a C99 flexible array
|
||||
member is embedded into another struct (possibly recursively).
|
||||
__builtin_object_size will treat such struct as flexible size.
|
||||
However, when a structure with non-C99 flexible array member, i.e, trailing
|
||||
[0], [1], or [4], is embedded into anther struct, the stucture will not
|
||||
be treated as flexible size. */
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2" } */
|
||||
|
||||
#include "builtin-object-size-common.h"
|
||||
|
||||
#define expect(p, _v) do { \
|
||||
size_t v = _v; \
|
||||
if (p == v) \
|
||||
__builtin_printf ("ok: %s == %zd\n", #p, p); \
|
||||
else {\
|
||||
__builtin_printf ("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
|
||||
FAIL (); \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
|
||||
struct A {
|
||||
int n;
|
||||
char data[];
|
||||
};
|
||||
|
||||
struct B {
|
||||
int m;
|
||||
struct A a;
|
||||
};
|
||||
|
||||
struct C {
|
||||
int q;
|
||||
struct B b;
|
||||
};
|
||||
|
||||
struct A0 {
|
||||
int n;
|
||||
char data[0];
|
||||
};
|
||||
|
||||
struct B0 {
|
||||
int m;
|
||||
struct A0 a;
|
||||
};
|
||||
|
||||
struct C0 {
|
||||
int q;
|
||||
struct B0 b;
|
||||
};
|
||||
|
||||
struct A1 {
|
||||
int n;
|
||||
char data[1];
|
||||
};
|
||||
|
||||
struct B1 {
|
||||
int m;
|
||||
struct A1 a;
|
||||
};
|
||||
|
||||
struct C1 {
|
||||
int q;
|
||||
struct B1 b;
|
||||
};
|
||||
|
||||
struct An {
|
||||
int n;
|
||||
char data[8];
|
||||
};
|
||||
|
||||
struct Bn {
|
||||
int m;
|
||||
struct An a;
|
||||
};
|
||||
|
||||
struct Cn {
|
||||
int q;
|
||||
struct Bn b;
|
||||
};
|
||||
|
||||
volatile void *magic1, *magic2;
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
struct B *outer;
|
||||
struct C *outest;
|
||||
|
||||
/* Make sure optimization can't find some other object size. */
|
||||
outer = (void *)magic1;
|
||||
outest = (void *)magic2;
|
||||
|
||||
expect (__builtin_object_size (&outer->a, 1), -1);
|
||||
expect (__builtin_object_size (&outest->b, 1), -1);
|
||||
expect (__builtin_object_size (&outest->b.a, 1), -1);
|
||||
|
||||
struct B0 *outer0;
|
||||
struct C0 *outest0;
|
||||
|
||||
/* Make sure optimization can't find some other object size. */
|
||||
outer0 = (void *)magic1;
|
||||
outest0 = (void *)magic2;
|
||||
|
||||
expect (__builtin_object_size (&outer0->a, 1), sizeof (outer0->a));
|
||||
expect (__builtin_object_size (&outest0->b, 1), sizeof (outest0->b));
|
||||
expect (__builtin_object_size (&outest0->b.a, 1), sizeof (outest0->b.a));
|
||||
|
||||
struct B1 *outer1;
|
||||
struct C1 *outest1;
|
||||
|
||||
/* Make sure optimization can't find some other object size. */
|
||||
outer1 = (void *)magic1;
|
||||
outest1 = (void *)magic2;
|
||||
|
||||
expect (__builtin_object_size (&outer1->a, 1), sizeof (outer1->a));
|
||||
expect (__builtin_object_size (&outest1->b, 1), sizeof (outest1->b));
|
||||
expect (__builtin_object_size (&outest1->b.a, 1), sizeof (outest1->b.a));
|
||||
|
||||
struct Bn *outern;
|
||||
struct Cn *outestn;
|
||||
|
||||
/* Make sure optimization can't find some other object size. */
|
||||
outern = (void *)magic1;
|
||||
outestn = (void *)magic2;
|
||||
|
||||
expect (__builtin_object_size (&outern->a, 1), sizeof (outern->a));
|
||||
expect (__builtin_object_size (&outestn->b, 1), sizeof (outestn->b));
|
||||
expect (__builtin_object_size (&outestn->b.a, 1), sizeof (outestn->b.a));
|
||||
|
||||
DONE ();
|
||||
return 0;
|
||||
}
|
|
@ -633,11 +633,32 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
|
|||
v = NULL_TREE;
|
||||
break;
|
||||
case COMPONENT_REF:
|
||||
if (TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
|
||||
/* When the ref is not to an aggregate type, i.e, an array,
|
||||
a record or a union, it will not have flexible size,
|
||||
compute the object size directly. */
|
||||
if (!AGGREGATE_TYPE_P (TREE_TYPE (v)))
|
||||
{
|
||||
v = NULL_TREE;
|
||||
break;
|
||||
}
|
||||
/* if the ref is to a record or union type, but the type
|
||||
does not include a flexible array recursively, compute
|
||||
the object size directly. */
|
||||
if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (v)))
|
||||
{
|
||||
if (!TYPE_INCLUDES_FLEXARRAY (TREE_TYPE (v)))
|
||||
{
|
||||
v = NULL_TREE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
v = TREE_OPERAND (v, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Now the ref is to an array type. */
|
||||
gcc_assert (TREE_CODE (TREE_TYPE (v)) == ARRAY_TYPE);
|
||||
is_flexible_array_mem_ref = array_ref_flexible_size_p (v);
|
||||
while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
|
||||
if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
|
||||
|
|
Loading…
Add table
Reference in a new issue