new file mode 100644
@@ -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)))