tree-object-size.c (addr_object_size): Add OSI argument.
authorJakub Jelinek <jakub@redhat.com>
Mon, 8 Jun 2009 16:28:38 +0000 (18:28 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Mon, 8 Jun 2009 16:28:38 +0000 (18:28 +0200)
* tree-object-size.c (addr_object_size): Add OSI argument.
Handle also INDIRECT_REF with SSA_NAME inside of it as base address.
(compute_builtin_object_size, expr_object_size): Adjust callers.
(plus_stmt_object_size): Call addr_object_size instead of
compute_builtin_object_size.

* gcc.dg/builtin-object-size-2.c (test1): Adjust expected results.
* gcc.dg/builtin-object-size-4.c (test1): Adjust expected results.
* gcc.dg/builtin-object-size-6.c: New test.

From-SVN: r148279

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/builtin-object-size-2.c
gcc/testsuite/gcc.dg/builtin-object-size-4.c
gcc/testsuite/gcc.dg/builtin-object-size-6.c [new file with mode: 0644]
gcc/tree-object-size.c

index 47126a1e649288b254fcabb10614f3e983b153f4..c31e618ea6a1d0c22173d0ef08548b1f85bcc9a3 100644 (file)
@@ -1,3 +1,11 @@
+2009-06-08  Jakub Jelinek  <jakub@redhat.com>
+
+       * tree-object-size.c (addr_object_size): Add OSI argument.
+       Handle also INDIRECT_REF with SSA_NAME inside of it as base address.
+       (compute_builtin_object_size, expr_object_size): Adjust callers.
+       (plus_stmt_object_size): Call addr_object_size instead of
+       compute_builtin_object_size.
+
 2009-06-08  Ghassan Shobaki  <ghassan.shobaki@amd.com>
             Dwarakanath Rajagopal  <dwarak.rajagopal@amd.com>
        
@@ -20,7 +28,6 @@
 2009-06-08  Michael Matz  <matz@suse.de>
 
        PR debug/40012
-
        * cfgexpand.c (set_rtl): Store place also in DECL_RTL, if all
        partitions use the same.
        (expand_one_var): Deal with DECL_RTL sometimes begin set also
index 9c7651db722fab07ff0b5868be9f39cb3b27c189..2a32d8fa4b23da1683b91795edff85de65d545c8 100644 (file)
@@ -1,5 +1,9 @@
 2009-06-08  Jakub Jelinek  <jakub@redhat.com>
 
+       * gcc.dg/builtin-object-size-2.c (test1): Adjust expected results.
+       * gcc.dg/builtin-object-size-4.c (test1): Adjust expected results.
+       * gcc.dg/builtin-object-size-6.c: New test.
+
        PR c++/40370
        PR c++/40372
        * g++.dg/template/error41.C: New test.
index 4071c2516eec3fd3284b043d2e4edd32b7809289..34f16759d680cec15eb290a400d2e66d36d19f00 100644 (file)
@@ -130,15 +130,15 @@ test1 (void *q, int x)
     abort ();    
   if (__builtin_object_size (&vara[5], 1) != (size_t) -1)
     abort ();
-  if (__builtin_object_size (&vara[0].a, 1) != (size_t) -1)
+  if (__builtin_object_size (&vara[0].a, 1) != sizeof (vara[0].a))
     abort ();
-  if (__builtin_object_size (&vara[10].a[0], 1) != (size_t) -1)
+  if (__builtin_object_size (&vara[10].a[0], 1) != sizeof (vara[0].a))
     abort ();
-  if (__builtin_object_size (&vara[5].a[4], 1) != (size_t) -1)
+  if (__builtin_object_size (&vara[5].a[4], 1) != sizeof (vara[0].a) - 4)
     abort ();
-  if (__builtin_object_size (&vara[5].b, 1) != (size_t) -1)
+  if (__builtin_object_size (&vara[5].b, 1) != sizeof (vara[0].b))
     abort ();
-  if (__builtin_object_size (&vara[7].c[7], 1) != (size_t) -1)
+  if (__builtin_object_size (&vara[7].c[7], 1) != sizeof (vara[0].c) - 7)
     abort ();
   if (__builtin_object_size (zerol, 1) != 0)
     abort ();
index 453c2d01921643691118c6dde18704e99ffe1a94..1eb30d1ba536b820c84ad9b85b4dd6dff9c50c53 100644 (file)
@@ -130,15 +130,15 @@ test1 (void *q, int x)
     abort ();    
   if (__builtin_object_size (&vara[5], 3) != 0)
     abort ();
-  if (__builtin_object_size (&vara[0].a, 3) != 0)
+  if (__builtin_object_size (&vara[0].a, 3) != sizeof (vara[0].a))
     abort ();
-  if (__builtin_object_size (&vara[10].a[0], 3) != 0)
+  if (__builtin_object_size (&vara[10].a[0], 3) != sizeof (vara[0].a))
     abort ();
-  if (__builtin_object_size (&vara[5].a[4], 3) != 0)
+  if (__builtin_object_size (&vara[5].a[4], 3) != sizeof (vara[0].a) - 4)
     abort ();
-  if (__builtin_object_size (&vara[5].b, 3) != 0)
+  if (__builtin_object_size (&vara[5].b, 3) != sizeof (vara[0].b))
     abort ();
-  if (__builtin_object_size (&vara[7].c[7], 3) != 0)
+  if (__builtin_object_size (&vara[7].c[7], 3) != sizeof (vara[0].c) - 7)
     abort ();
   if (__builtin_object_size (zerol, 3) != 0)
     abort ();
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-6.c b/gcc/testsuite/gcc.dg/builtin-object-size-6.c
new file mode 100644 (file)
index 0000000..9a285df
--- /dev/null
@@ -0,0 +1,435 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+typedef __SIZE_TYPE__ size_t;
+extern void abort (void);
+extern void exit (int);
+extern void *malloc (size_t);
+extern void free (void *);
+
+struct A
+{
+  char a[10];
+  int b;
+  char c[10];
+};
+
+void
+__attribute__ ((noinline))
+test1 (struct A *p)
+{
+  char *c;
+  if (__builtin_object_size (&p->a, 0) != (size_t) -1)
+    abort ();
+  if (__builtin_object_size (&p->a[0], 0) != (size_t) -1)
+    abort ();
+  if (__builtin_object_size (&p->a[3], 0) != (size_t) -1)
+    abort ();
+  if (__builtin_object_size (&p->b, 0) != (size_t) -1)
+    abort ();
+  if (__builtin_object_size (&p->c, 0) != (size_t) -1)
+    abort ();
+  c = p->a;
+  if (__builtin_object_size (c, 0) != (size_t) -1)
+    abort ();
+  c = &p->a[0];
+  if (__builtin_object_size (c, 0) != (size_t) -1)
+    abort ();
+  c = &p->a[3];
+  if (__builtin_object_size (c, 0) != (size_t) -1)
+    abort ();
+  c = (char *) &p->b;
+  if (__builtin_object_size (c, 0) != (size_t) -1)
+    abort ();
+  c = (char *) &p->c;
+  if (__builtin_object_size (c, 0) != (size_t) -1)
+    abort ();
+  if (__builtin_object_size (&p->a, 1) != sizeof (p->a))
+    abort ();
+  if (__builtin_object_size (&p->a[0], 1) != sizeof (p->a))
+    abort ();
+  if (__builtin_object_size (&p->a[3], 1) != sizeof (p->a) - 3)
+    abort ();
+  if (__builtin_object_size (&p->b, 1) != sizeof (p->b))
+    abort ();
+  if (__builtin_object_size (&p->c, 1) != (size_t) -1)
+    abort ();
+  c = p->a;
+  if (__builtin_object_size (c, 1) != sizeof (p->a))
+    abort ();
+  c = &p->a[0];
+  if (__builtin_object_size (c, 1) != sizeof (p->a))
+    abort ();
+  c = &p->a[3];
+  if (__builtin_object_size (c, 1) != sizeof (p->a) - 3)
+    abort ();
+  c = (char *) &p->b;
+  if (__builtin_object_size (c, 1) != sizeof (p->b))
+    abort ();
+  c = (char *) &p->c;
+  if (__builtin_object_size (c, 1) != (size_t) -1)
+    abort ();
+  if (__builtin_object_size (&p->a, 2) != 0)
+    abort ();
+  if (__builtin_object_size (&p->a[0], 2) != 0)
+    abort ();
+  if (__builtin_object_size (&p->a[3], 2) != 0)
+    abort ();
+  if (__builtin_object_size (&p->b, 2) != 0)
+    abort ();
+  if (__builtin_object_size (&p->c, 2) != 0)
+    abort ();
+  c = p->a;
+  if (__builtin_object_size (c, 2) != 0)
+    abort ();
+  c = &p->a[0];
+  if (__builtin_object_size (c, 2) != 0)
+    abort ();
+  c = &p->a[3];
+  if (__builtin_object_size (c, 2) != 0)
+    abort ();
+  c = (char *) &p->b;
+  if (__builtin_object_size (c, 2) != 0)
+    abort ();
+  c = (char *) &p->c;
+  if (__builtin_object_size (c, 2) != 0)
+    abort ();
+  if (__builtin_object_size (&p->a, 3) != sizeof (p->a))
+    abort ();
+  if (__builtin_object_size (&p->a[0], 3) != sizeof (p->a))
+    abort ();
+  if (__builtin_object_size (&p->a[3], 3) != sizeof (p->a) - 3)
+    abort ();
+  if (__builtin_object_size (&p->b, 3) != sizeof (p->b))
+    abort ();
+  if (__builtin_object_size (&p->c, 3) != 0)
+    abort ();
+  c = p->a;
+  if (__builtin_object_size (c, 3) != sizeof (p->a))
+    abort ();
+  c = &p->a[0];
+  if (__builtin_object_size (c, 3) != sizeof (p->a))
+    abort ();
+  c = &p->a[3];
+  if (__builtin_object_size (c, 3) != sizeof (p->a) - 3)
+    abort ();
+  c = (char *) &p->b;
+  if (__builtin_object_size (c, 3) != sizeof (p->b))
+    abort ();
+  c = (char *) &p->c;
+  if (__builtin_object_size (c, 3) != 0)
+    abort ();
+}
+
+void
+__attribute__ ((noinline))
+test2 (void)
+{
+  char *c;
+  size_t s = 2 * sizeof (struct A);
+  struct A *p = malloc (2 * sizeof (struct A));
+  if (__builtin_object_size (&p->a, 0) != s)
+    abort ();
+  if (__builtin_object_size (&p->a[0], 0) != s)
+    abort ();
+  if (__builtin_object_size (&p->a[3], 0) != s - 3)
+    abort ();
+  if (__builtin_object_size (&p->b, 0) != s - __builtin_offsetof (struct A, b))
+    abort ();
+  if (__builtin_object_size (&p->c, 0) != s - __builtin_offsetof (struct A, c))
+    abort ();
+  c = p->a;
+  if (__builtin_object_size (c, 0) != s)
+    abort ();
+  c = &p->a[0];
+  if (__builtin_object_size (c, 0) != s)
+    abort ();
+  c = &p->a[3];
+  if (__builtin_object_size (c, 0) != s - 3)
+    abort ();
+  c = (char *) &p->b;
+  if (__builtin_object_size (c, 0) != s - __builtin_offsetof (struct A, b))
+    abort ();
+  c = (char *) &p->c;
+  if (__builtin_object_size (c, 0) != s - __builtin_offsetof (struct A, c))
+    abort ();
+  if (__builtin_object_size (&p->a, 1) != sizeof (p->a))
+    abort ();
+  if (__builtin_object_size (&p->a[0], 1) != sizeof (p->a))
+    abort ();
+  if (__builtin_object_size (&p->a[3], 1) != sizeof (p->a) - 3)
+    abort ();
+  if (__builtin_object_size (&p->b, 1) != sizeof (p->b))
+    abort ();
+  if (__builtin_object_size (&p->c, 1) != s - __builtin_offsetof (struct A, c))
+    abort ();
+  c = p->a;
+  if (__builtin_object_size (c, 1) != sizeof (p->a))
+    abort ();
+  c = &p->a[0];
+  if (__builtin_object_size (c, 1) != sizeof (p->a))
+    abort ();
+  c = &p->a[3];
+  if (__builtin_object_size (c, 1) != sizeof (p->a) - 3)
+    abort ();
+  c = (char *) &p->b;
+  if (__builtin_object_size (c, 1) != sizeof (p->b))
+    abort ();
+  c = (char *) &p->c;
+  if (__builtin_object_size (c, 1) != s - __builtin_offsetof (struct A, c))
+    abort ();
+  if (__builtin_object_size (&p->a, 2) != s)
+    abort ();
+  if (__builtin_object_size (&p->a[0], 2) != s)
+    abort ();
+  if (__builtin_object_size (&p->a[3], 2) != s - 3)
+    abort ();
+  if (__builtin_object_size (&p->b, 2) != s - __builtin_offsetof (struct A, b))
+    abort ();
+  if (__builtin_object_size (&p->c, 2) != s - __builtin_offsetof (struct A, c))
+    abort ();
+  c = p->a;
+  if (__builtin_object_size (c, 2) != s)
+    abort ();
+  c = &p->a[0];
+  if (__builtin_object_size (c, 2) != s)
+    abort ();
+  c = &p->a[3];
+  if (__builtin_object_size (c, 2) != s - 3)
+    abort ();
+  c = (char *) &p->b;
+  if (__builtin_object_size (c, 2) != s - __builtin_offsetof (struct A, b))
+    abort ();
+  c = (char *) &p->c;
+  if (__builtin_object_size (c, 2) != s - __builtin_offsetof (struct A, c))
+    abort ();
+  if (__builtin_object_size (&p->a, 3) != sizeof (p->a))
+    abort ();
+  if (__builtin_object_size (&p->a[0], 3) != sizeof (p->a))
+    abort ();
+  if (__builtin_object_size (&p->a[3], 3) != sizeof (p->a) - 3)
+    abort ();
+  if (__builtin_object_size (&p->b, 3) != sizeof (p->b))
+    abort ();
+  if (__builtin_object_size (&p->c, 3) != s - __builtin_offsetof (struct A, c))
+    abort ();
+  c = p->a;
+  if (__builtin_object_size (c, 3) != sizeof (p->a))
+    abort ();
+  c = &p->a[0];
+  if (__builtin_object_size (c, 3) != sizeof (p->a))
+    abort ();
+  c = &p->a[3];
+  if (__builtin_object_size (c, 3) != sizeof (p->a) - 3)
+    abort ();
+  c = (char *) &p->b;
+  if (__builtin_object_size (c, 3) != sizeof (p->b))
+    abort ();
+  c = (char *) &p->c;
+  if (__builtin_object_size (c, 3) != s - __builtin_offsetof (struct A, c))
+    abort ();
+  free (p);
+}
+
+void
+__attribute__ ((noinline))
+test3 (void)
+{
+  char *c;
+  size_t s;
+  struct A *p = malloc (4);
+  if (__builtin_object_size (&p->a, 0) != 4)
+    abort ();
+  if (__builtin_object_size (&p->a[0], 0) != 4)
+    abort ();
+  if (__builtin_object_size (&p->a[3], 0) != 1)
+    abort ();
+  if (__builtin_object_size (&p->b, 0) != 0)
+    abort ();
+  if (__builtin_object_size (&p->c, 0) != 0)
+    abort ();
+  if (__builtin_object_size (&p->a, 1) != 4)
+    abort ();
+  if (__builtin_object_size (&p->a[0], 1) != 4)
+    abort ();
+  if (__builtin_object_size (&p->a[3], 1) != 1)
+    abort ();
+  if (__builtin_object_size (&p->b, 1) != 0)
+    abort ();
+  if (__builtin_object_size (&p->c, 1) != 0)
+    abort ();
+  free (p);
+  s = __builtin_offsetof (struct A, c) + 4;
+  p = malloc (s);
+  if (__builtin_object_size (&p->a, 0) != s)
+    abort ();
+  if (__builtin_object_size (&p->a[0], 0) != s)
+    abort ();
+  if (__builtin_object_size (&p->a[3], 0) != s - 3)
+    abort ();
+  if (__builtin_object_size (&p->b, 0) != s - __builtin_offsetof (struct A, b))
+    abort ();
+  if (__builtin_object_size (&p->c, 0) != 4)
+    abort ();
+  if (__builtin_object_size (&p->a, 1) != sizeof (p->a))
+    abort ();
+  if (__builtin_object_size (&p->a[0], 1) != sizeof (p->a))
+    abort ();
+  if (__builtin_object_size (&p->a[3], 1) != sizeof (p->a) - 3)
+    abort ();
+  if (__builtin_object_size (&p->b, 1) != sizeof (p->b))
+    abort ();
+  if (__builtin_object_size (&p->c, 1) != 4)
+    abort ();
+  free (p);
+}
+
+struct B
+{
+  struct A a[4];
+};
+
+void
+__attribute__ ((noinline))
+test4 (struct B *q, int i)
+{
+  if (__builtin_object_size (&q->a[2].a[2], 1) != sizeof (q->a[0].a) - 2)
+    abort ();
+  if (__builtin_object_size (&q->a[2].c[2], 1) != sizeof (q->a[0].c) - 2)
+    abort ();
+  if (__builtin_object_size (&q->a[3].a[2], 1) != sizeof (q->a[0].a) - 2)
+    abort ();
+  if (__builtin_object_size (&q->a[3].c[2], 1) != sizeof (q->a[0].c) - 2)
+    abort ();
+  if (__builtin_object_size (&q->a[i].a[2], 1) != sizeof (q->a[0].a) - 2)
+    abort ();
+  if (__builtin_object_size (&q->a[i].c[2], 1) != sizeof (q->a[0].c) - 2)
+    abort ();
+}
+
+struct C
+{
+  char a[10];
+  char b;
+};
+
+void
+__attribute__ ((noinline))
+test5 (struct C *c)
+{
+  if (__builtin_object_size (&c->b, 0) != (size_t) -1)
+    abort ();
+  if (__builtin_object_size (&c->b, 1) != 1)
+    abort ();
+  if (__builtin_object_size (&c->b, 2) != 0)
+    abort ();
+  if (__builtin_object_size (&c->b, 3) != 1)
+    abort ();
+}
+
+struct D
+{
+  int i;
+  struct D1
+  {
+    char b;
+    char a[10];
+  } j;
+};
+
+void
+__attribute__ ((noinline))
+test6 (struct D *d)
+{
+  if (__builtin_object_size (&d->j.a[3], 0) != (size_t) -1)
+    abort ();
+  if (__builtin_object_size (&d->j.a[3], 1) != sizeof (d->j.a) - 3)
+    abort ();
+  if (__builtin_object_size (&d->j.a[3], 2) != 0)
+    abort ();
+  if (__builtin_object_size (&d->j.a[3], 3) != sizeof (d->j.a) - 3)
+    abort ();
+}
+
+struct E
+{
+  int i;
+  struct E1
+  {
+    char b;
+    char a[10];
+  } j[1];
+};
+
+void
+__attribute__ ((noinline))
+test7 (struct E *e)
+{
+  if (__builtin_object_size (&e->j[0].a[3], 0) != (size_t) -1)
+    abort ();
+  if (__builtin_object_size (&e->j[0].a[3], 1) != sizeof (e->j[0].a) - 3)
+    abort ();
+  if (__builtin_object_size (&e->j[0].a[3], 2) != 0)
+    abort ();
+  if (__builtin_object_size (&e->j[0].a[3], 3) != sizeof (e->j[0].a) - 3)
+    abort ();
+  if (__builtin_object_size ((char *) &e->j[0], 0) != (size_t) -1)
+    abort ();
+  if (__builtin_object_size ((char *) &e->j[0], 1) != (size_t) -1)
+    abort ();
+  if (__builtin_object_size ((char *) &e->j[0], 2) != 0)
+    abort ();
+  if (__builtin_object_size ((char *) &e->j[0], 3) != 0)
+    abort ();
+}
+
+union F
+{
+  char a[1];
+  struct F1
+  {
+    char b;
+    char c[10];
+  } d;
+};
+
+void
+__attribute__ ((noinline))
+test8 (union F *f)
+{
+  if (__builtin_object_size (&f->d.c[3], 0) != (size_t) -1)
+    abort ();
+  if (__builtin_object_size (&f->d.c[3], 1) != sizeof (f->d.c) - 3)
+    abort ();
+  if (__builtin_object_size (&f->d.c[3], 2) != 0)
+    abort ();
+  if (__builtin_object_size (&f->d.c[3], 3) != sizeof (f->d.c) - 3)
+    abort ();
+}
+
+int
+main (void)
+{
+  struct A a, *p = &a;
+  int i = 1;
+  __asm ("" : "+r" (p));
+  test1 (p);
+  test2 ();
+  test3 ();
+  struct B b, *q = &b;
+  __asm ("" : "+r" (q), "+r" (i));
+  test4 (q, i);
+  struct C c, *cp = &c;
+  __asm ("" : "+r" (cp));
+  test5 (cp);
+  struct D d, *dp = &d;
+  __asm ("" : "+r" (dp));
+  test6 (dp);
+  struct E e, *ep = &e;
+  __asm ("" : "+r" (ep));
+  test7 (ep);
+  union F f, *fp = &f;
+  __asm ("" : "+r" (fp));
+  test8 (fp);
+  exit (0);
+}
index 18e62e860fdc164b566ead8d4c91bd103bbce6b2..dbd8af482da18aa25815cca26a214a19a7c0f6f2 100644 (file)
@@ -43,7 +43,8 @@ struct object_size_info
 static unsigned HOST_WIDE_INT unknown[4] = { -1, -1, 0, 0 };
 
 static tree compute_object_offset (const_tree, const_tree);
-static unsigned HOST_WIDE_INT addr_object_size (const_tree, int);
+static unsigned HOST_WIDE_INT addr_object_size (struct object_size_info *,
+                                               const_tree, int);
 static unsigned HOST_WIDE_INT alloc_object_size (const_gimple, int);
 static tree pass_through_call (const_gimple);
 static void collect_object_sizes_for (struct object_size_info *, tree);
@@ -152,9 +153,10 @@ compute_object_offset (const_tree expr, const_tree var)
    If unknown, return unknown[object_size_type].  */
 
 static unsigned HOST_WIDE_INT
-addr_object_size (const_tree ptr, int object_size_type)
+addr_object_size (struct object_size_info *osi, const_tree ptr,
+                 int object_size_type)
 {
-  tree pt_var;
+  tree pt_var, pt_var_size = NULL_TREE, var_size, bytes;
 
   gcc_assert (TREE_CODE (ptr) == ADDR_EXPR);
 
@@ -163,58 +165,170 @@ addr_object_size (const_tree ptr, int object_size_type)
     pt_var = get_base_address (pt_var);
 
   if (pt_var
-      && (SSA_VAR_P (pt_var) || TREE_CODE (pt_var) == STRING_CST)
-      && TYPE_SIZE_UNIT (TREE_TYPE (pt_var))
-      && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)), 1)
-      && (unsigned HOST_WIDE_INT)
-        tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)), 1) < offset_limit)
+      && TREE_CODE (pt_var) == INDIRECT_REF
+      && TREE_CODE (TREE_OPERAND (pt_var, 0)) == SSA_NAME
+      && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (pt_var, 0))))
     {
-      tree bytes;
+      unsigned HOST_WIDE_INT sz;
 
-      if (pt_var != TREE_OPERAND (ptr, 0))
+      if (!osi)
+       sz = compute_builtin_object_size (TREE_OPERAND (pt_var, 0),
+                                         object_size_type);
+      else
        {
-         tree var;
+         tree var = TREE_OPERAND (pt_var, 0);
+         if (osi->pass == 0)
+           collect_object_sizes_for (osi, var);
+         if (bitmap_bit_p (computed[object_size_type],
+                           SSA_NAME_VERSION (var)))
+           sz = object_sizes[object_size_type][SSA_NAME_VERSION (var)];
+         else
+           sz = unknown[object_size_type];
+       }
+
+      if (sz != unknown[object_size_type] && sz < offset_limit)
+       pt_var_size = size_int (sz);
+    }
+  else if (pt_var
+          && (SSA_VAR_P (pt_var) || TREE_CODE (pt_var) == STRING_CST)
+          && TYPE_SIZE_UNIT (TREE_TYPE (pt_var))
+          && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)), 1)
+          && (unsigned HOST_WIDE_INT)
+             tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)), 1)
+             < offset_limit)
+    pt_var_size = TYPE_SIZE_UNIT (TREE_TYPE (pt_var));
+  else
+    return unknown[object_size_type];
+
+  if (pt_var != TREE_OPERAND (ptr, 0))
+    {
+      tree var;
 
-         if (object_size_type & 1)
+      if (object_size_type & 1)
+       {
+         var = TREE_OPERAND (ptr, 0);
+
+         while (var != pt_var
+                && TREE_CODE (var) != BIT_FIELD_REF
+                && TREE_CODE (var) != COMPONENT_REF
+                && TREE_CODE (var) != ARRAY_REF
+                && TREE_CODE (var) != ARRAY_RANGE_REF
+                && TREE_CODE (var) != REALPART_EXPR
+                && TREE_CODE (var) != IMAGPART_EXPR)
+           var = TREE_OPERAND (var, 0);
+         if (var != pt_var && TREE_CODE (var) == ARRAY_REF)
+             var = TREE_OPERAND (var, 0);
+         if (! TYPE_SIZE_UNIT (TREE_TYPE (var))
+             || ! host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (var)), 1)
+             || (pt_var_size
+                 && tree_int_cst_lt (pt_var_size,
+                                     TYPE_SIZE_UNIT (TREE_TYPE (var)))))
+           var = pt_var;
+         else if (var != pt_var && TREE_CODE (pt_var) == INDIRECT_REF)
            {
-             var = TREE_OPERAND (ptr, 0);
-
-             while (var != pt_var
-                     && TREE_CODE (var) != BIT_FIELD_REF
-                     && TREE_CODE (var) != COMPONENT_REF
-                     && TREE_CODE (var) != ARRAY_REF
-                     && TREE_CODE (var) != ARRAY_RANGE_REF
-                     && TREE_CODE (var) != REALPART_EXPR
-                     && TREE_CODE (var) != IMAGPART_EXPR)
-               var = TREE_OPERAND (var, 0);
-             if (var != pt_var && TREE_CODE (var) == ARRAY_REF)
-               var = TREE_OPERAND (var, 0);
-             if (! TYPE_SIZE_UNIT (TREE_TYPE (var))
-                 || ! host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (var)), 1)
-                 || tree_int_cst_lt (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)),
-                                     TYPE_SIZE_UNIT (TREE_TYPE (var))))
+             tree v = var;
+             /* For &X->fld, compute object size only if fld isn't the last
+                field, as struct { int i; char c[1]; } is often used instead
+                of flexible array member.  */
+             while (v && v != pt_var)
+               switch (TREE_CODE (v))
+                 {
+                 case ARRAY_REF:
+                   if (TYPE_SIZE_UNIT (TREE_TYPE (TREE_OPERAND (v, 0)))
+                       && TREE_CODE (TREE_OPERAND (v, 1)) == INTEGER_CST)
+                     {
+                       tree domain
+                         = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (v, 0)));
+                       if (domain
+                           && TYPE_MAX_VALUE (domain)
+                           && TREE_CODE (TYPE_MAX_VALUE (domain))
+                              == INTEGER_CST
+                           && tree_int_cst_lt (TREE_OPERAND (v, 1),
+                                               TYPE_MAX_VALUE (domain)))
+                         {
+                           v = NULL_TREE;
+                           break;
+                         }
+                     }
+                   v = TREE_OPERAND (v, 0);
+                   break;
+                 case REALPART_EXPR:
+                 case IMAGPART_EXPR:
+                   v = NULL_TREE;
+                   break;
+                 case COMPONENT_REF:
+                   if ((TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
+                        == RECORD_TYPE
+                        && TREE_CHAIN (TREE_OPERAND (v, 1)))
+                       || TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
+                     v = NULL_TREE;
+                   else
+                     {
+                       if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
+                           == RECORD_TYPE)
+                         v = TREE_OPERAND (v, 0);
+                       while (v && v != pt_var && TREE_CODE (v) == COMPONENT_REF)
+                         if (TREE_CODE (TREE_TYPE (v)) != UNION_TYPE
+                             && TREE_CODE (TREE_TYPE (v)) != QUAL_UNION_TYPE)
+                           break;
+                         else
+                           v = TREE_OPERAND (v, 0);
+                       if (v && v != pt_var)
+                         v = NULL_TREE;
+                       else
+                         v = pt_var;
+                     }
+                   break;
+                 default:
+                   v = pt_var;
+                   break;
+                 }
+             if (v == pt_var)
                var = pt_var;
            }
-         else
-           var = pt_var;
+       }
+      else
+       var = pt_var;
 
-         bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var);
-         if (bytes != error_mark_node)
+      if (var != pt_var)
+       var_size = TYPE_SIZE_UNIT (TREE_TYPE (var));
+      else if (!pt_var_size)
+       return unknown[object_size_type];
+      else
+       var_size = pt_var_size;
+      bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var);
+      if (bytes != error_mark_node)
+       {
+         if (TREE_CODE (bytes) == INTEGER_CST
+             && tree_int_cst_lt (var_size, bytes))
+           bytes = size_zero_node;
+         else
+           bytes = size_binop (MINUS_EXPR, var_size, bytes);
+       }
+      if (var != pt_var
+         && pt_var_size
+         && TREE_CODE (pt_var) == INDIRECT_REF
+         && bytes != error_mark_node)
+       {
+         tree bytes2 = compute_object_offset (TREE_OPERAND (ptr, 0), pt_var);
+         if (bytes2 != error_mark_node)
            {
-             if (TREE_CODE (bytes) == INTEGER_CST
-                 && tree_int_cst_lt (TYPE_SIZE_UNIT (TREE_TYPE (var)), bytes))
-               bytes = size_zero_node;
+             if (TREE_CODE (bytes2) == INTEGER_CST
+                 && tree_int_cst_lt (pt_var_size, bytes2))
+               bytes2 = size_zero_node;
              else
-               bytes = size_binop (MINUS_EXPR,
-                                   TYPE_SIZE_UNIT (TREE_TYPE (var)), bytes);
+               bytes2 = size_binop (MINUS_EXPR, var_size, bytes2);
+             bytes = size_binop (MIN_EXPR, bytes, bytes2);
            }
        }
-      else
-       bytes = TYPE_SIZE_UNIT (TREE_TYPE (pt_var));
-
-      if (host_integerp (bytes, 1))
-       return tree_low_cst (bytes, 1);
     }
+  else if (!pt_var_size)
+    return unknown[object_size_type];
+  else
+    bytes = pt_var_size;
+
+  if (host_integerp (bytes, 1))
+    return tree_low_cst (bytes, 1);
 
   return unknown[object_size_type];
 }
@@ -332,11 +446,11 @@ compute_builtin_object_size (tree ptr, int object_size_type)
     init_offset_limit ();
 
   if (TREE_CODE (ptr) == ADDR_EXPR)
-    return addr_object_size (ptr, object_size_type);
+    return addr_object_size (NULL, ptr, object_size_type);
 
   if (TREE_CODE (ptr) == SSA_NAME
-          && POINTER_TYPE_P (TREE_TYPE (ptr))
-          && object_sizes[object_size_type] != NULL)
+      && POINTER_TYPE_P (TREE_TYPE (ptr))
+      && object_sizes[object_size_type] != NULL)
     {
       if (!bitmap_bit_p (computed[object_size_type], SSA_NAME_VERSION (ptr)))
        {
@@ -477,7 +591,7 @@ expr_object_size (struct object_size_info *osi, tree ptr, tree value)
              || !POINTER_TYPE_P (TREE_TYPE (value)));
 
   if (TREE_CODE (value) == ADDR_EXPR)
-    bytes = addr_object_size (value, object_size_type);
+    bytes = addr_object_size (osi, value, object_size_type);
   else
     bytes = unknown[object_size_type];
 
@@ -633,7 +747,7 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple stmt)
          unsigned HOST_WIDE_INT off = tree_low_cst (op1, 1);
 
           /* op0 will be ADDR_EXPR here.  */
-         bytes = compute_builtin_object_size (op0, object_size_type);
+         bytes = addr_object_size (osi, op0, object_size_type);
          if (bytes == unknown[object_size_type])
            ;
          else if (off > offset_limit)