diff --git a/gcc/testsuite/g++.dg/ext/builtin-object-size1.C b/gcc/testsuite/g++.dg/ext/builtin-object-size1.C
index 165b415683b..5b863637123 100644
--- a/gcc/testsuite/g++.dg/ext/builtin-object-size1.C
+++ b/gcc/testsuite/g++.dg/ext/builtin-object-size1.C
@@ -103,7 +103,7 @@ test1 (A *p)
     FAIL ();
   if (__builtin_object_size (&p->b, 3) != sizeof (p->b))
     FAIL ();
-  if (__builtin_object_size (&p->c, 3) != 0)
+  if (__builtin_object_size (&p->c, 3) != 10)
     FAIL ();
   c = p->a;
   if (__builtin_object_size (c, 3) != sizeof (p->a))
@@ -118,7 +118,7 @@ test1 (A *p)
   if (__builtin_object_size (c, 3) != sizeof (p->b))
     FAIL ();
   c = (char *) &p->c;
-  if (__builtin_object_size (c, 3) != 0)
+  if (__builtin_object_size (c, 3) != 10)
     FAIL ();
 }
 
@@ -344,7 +344,7 @@ test6 (struct D *d)
 {
   if (__builtin_object_size (&d->j.a[3], 0) != (size_t) -1)
     FAIL ();
-  if (__builtin_object_size (&d->j.a[3], 1) != sizeof (d->j.a) - 3)
+  if (__builtin_object_size (&d->j.a[3], 1) != (size_t) -1)
     FAIL ();
   if (__builtin_object_size (&d->j.a[3], 2) != 0)
     FAIL ();
@@ -380,7 +380,7 @@ test7 (struct E *e)
     FAIL ();
   if (__builtin_object_size ((char *) &e->j[0], 2) != 0)
     FAIL ();
-  if (__builtin_object_size ((char *) &e->j[0], 3) != 0)
+  if (__builtin_object_size ((char *) &e->j[0], 3) != sizeof (e->j))
     FAIL ();
 }
 
@@ -404,7 +404,7 @@ test8 (union F *f)
     FAIL ();
   if (__builtin_object_size (&f->d.c[3], 2) != 0)
     FAIL ();
-  if (__builtin_object_size (&f->d.c[3], 3) != 0)
+  if (__builtin_object_size (&f->d.c[3], 3) != sizeof (f->d.c) - 3)
     FAIL ();
 }
 
diff --git a/gcc/testsuite/g++.dg/ext/builtin-object-size2.C b/gcc/testsuite/g++.dg/ext/builtin-object-size2.C
index c5dbd96193c..665dad886d4 100644
--- a/gcc/testsuite/g++.dg/ext/builtin-object-size2.C
+++ b/gcc/testsuite/g++.dg/ext/builtin-object-size2.C
@@ -106,7 +106,7 @@ test1 (A *p)
     FAIL ();
   if (__builtin_object_size (&p->b, 3) != sizeof (p->b))
     FAIL ();
-  if (__builtin_object_size (&p->c, 3) != 0)
+  if (__builtin_object_size (&p->c, 3) != 10)
     FAIL ();
   c = p->a;
   if (__builtin_object_size (c, 3) != sizeof (p->a))
@@ -121,7 +121,7 @@ test1 (A *p)
   if (__builtin_object_size (c, 3) != sizeof (p->b))
     FAIL ();
   c = (char *) &p->c;
-  if (__builtin_object_size (c, 3) != 0)
+  if (__builtin_object_size (c, 3) != 10)
     FAIL ();
 }
 
@@ -347,7 +347,7 @@ test6 (struct D *d)
 {
   if (__builtin_object_size (&d->j.a[3], 0) != (size_t) -1)
     FAIL ();
-  if (__builtin_object_size (&d->j.a[3], 1) != sizeof (d->j.a) - 3)
+  if (__builtin_object_size (&d->j.a[3], 1) != (size_t) -1)
     FAIL ();
   if (__builtin_object_size (&d->j.a[3], 2) != 0)
     FAIL ();
@@ -383,7 +383,7 @@ test7 (struct E *e)
     FAIL ();
   if (__builtin_object_size ((char *) &e->j[0], 2) != 0)
     FAIL ();
-  if (__builtin_object_size ((char *) &e->j[0], 3) != 0)
+  if (__builtin_object_size ((char *) &e->j[0], 3) != sizeof (e->j))
     FAIL ();
 }
 
@@ -407,7 +407,7 @@ test8 (union F *f)
     FAIL ();
   if (__builtin_object_size (&f->d.c[3], 2) != 0)
     FAIL ();
-  if (__builtin_object_size (&f->d.c[3], 3) != 0)
+  if (__builtin_object_size (&f->d.c[3], 3) != sizeof (f->d.c) - 3)
     FAIL ();
 }
 
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-13.c b/gcc/testsuite/gcc.dg/builtin-object-size-13.c
index c7d58c941d4..6429dcaf426 100644
--- a/gcc/testsuite/gcc.dg/builtin-object-size-13.c
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-13.c
@@ -332,9 +332,9 @@ main (void)
   o2 = __builtin_offsetof (struct H, h2.e1.c2);
   h1 = malloc (s);
   h2 = malloc (o2 + 212);
-  TA (h1->h2.e1.c2.a2, s - o2, sizeof (h1->h2.e1.c2.a2));
+  TA (h1->h2.e1.c2.a2, s - o2, s - o2);
   s = o2 + 212;
-  TA (h2->h2.e1.c2.a2, s - o2, sizeof (h2->h2.e1.c2.a2));
+  TA (h2->h2.e1.c2.a2, s - o2, s - o2);
   free (h2);
   free (h1);
   s = sizeof (struct H);
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-6.c b/gcc/testsuite/gcc.dg/builtin-object-size-6.c
index 4ce05184143..1ae608d456b 100644
--- a/gcc/testsuite/gcc.dg/builtin-object-size-6.c
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-6.c
@@ -103,7 +103,7 @@ test1 (struct A *p)
     FAIL ();
   if (__builtin_object_size (&p->b, 3) != sizeof (p->b))
     FAIL ();
-  if (__builtin_object_size (&p->c, 3) != 0)
+  if (__builtin_object_size (&p->c, 3) != 10)
     FAIL ();
   c = p->a;
   if (__builtin_object_size (c, 3) != sizeof (p->a))
@@ -118,7 +118,7 @@ test1 (struct A *p)
   if (__builtin_object_size (c, 3) != sizeof (p->b))
     FAIL ();
   c = (char *) &p->c;
-  if (__builtin_object_size (c, 3) != 0)
+  if (__builtin_object_size (c, 3) != 10)
     FAIL ();
 }
 
@@ -344,7 +344,7 @@ test6 (struct D *d)
 {
   if (__builtin_object_size (&d->j.a[3], 0) != (size_t) -1)
     FAIL ();
-  if (__builtin_object_size (&d->j.a[3], 1) != sizeof (d->j.a) - 3)
+  if (__builtin_object_size (&d->j.a[3], 1) != -1)
     FAIL ();
   if (__builtin_object_size (&d->j.a[3], 2) != 0)
     FAIL ();
@@ -380,7 +380,7 @@ test7 (struct E *e)
     FAIL ();
   if (__builtin_object_size ((char *) &e->j[0], 2) != 0)
     FAIL ();
-  if (__builtin_object_size ((char *) &e->j[0], 3) != 0)
+  if (__builtin_object_size ((char *) &e->j[0], 3) != sizeof (e->j))
     FAIL ();
 }
 
@@ -404,7 +404,7 @@ test8 (union F *f)
     FAIL ();
   if (__builtin_object_size (&f->d.c[3], 2) != 0)
     FAIL ();
-  if (__builtin_object_size (&f->d.c[3], 3) != 0)
+  if (__builtin_object_size (&f->d.c[3], 3) != 7)
     FAIL ();
 }
 
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-8.c b/gcc/testsuite/gcc.dg/builtin-object-size-8.c
index f67902e29f0..184769f1bd8 100644
--- a/gcc/testsuite/gcc.dg/builtin-object-size-8.c
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-8.c
@@ -186,13 +186,13 @@ main (void)
   TS (h1->h1, s);
   TS (h1->h2.e1.c1, s - o);
   TS (h1->h2.e1.c2.a1, s - o2);
-  TA (h1->h2.e1.c2.a2, s - o2, sizeof (h1->h2.e1.c2.a2));
+  TA (h1->h2.e1.c2.a2, s - o2, s - o2);
   TF (h1->h2.e2, s - o);
   s = o2 + 212;
   TS (h2->h1, s);
   TS (h2->h2.e1.c1, s - o);
   TS (h2->h2.e1.c2.a1, s - o2);
-  TA (h2->h2.e1.c2.a2, s - o2, sizeof (h2->h2.e1.c2.a2));
+  TA (h2->h2.e1.c2.a2, s - o2, s - o2);
   TF (h2->h2.e2, s - o);
   free (h2);
   free (h1);
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-flex-common.h b/gcc/testsuite/gcc.dg/builtin-object-size-flex-common.h
new file mode 100644
index 00000000000..b8b68da762d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-flex-common.h
@@ -0,0 +1,90 @@
+#include "builtin-object-size-common.h"
+
+typedef __SIZE_TYPE__ size_t;
+
+void
+__attribute__ ((noinline))
+test_flexarray_allocate (const char *name)
+{
+  size_t n = sizeof (flex_t);
+
+  if (name != (void *) 0)
+    n += __builtin_strlen (name) + 1;
+
+  flex_t *p = __builtin_malloc (n);
+
+  if (__builtin_dynamic_object_size (FLEX_ARRAY (p), 0)
+      != n - sizeof (*p) + SIZEOF_FLEX_ARRAY)
+    FAIL ();
+
+  if (__builtin_dynamic_object_size (FLEX_ARRAY (p), 1)
+      != n - sizeof (*p) + SIZEOF_FLEX_ARRAY)
+    FAIL ();
+
+  if (__builtin_dynamic_object_size (FLEX_ARRAY (p), 2)
+      != n - sizeof (*p) + SIZEOF_FLEX_ARRAY)
+    FAIL ();
+
+  if (__builtin_dynamic_object_size (FLEX_ARRAY (p), 3)
+      != n - sizeof (*p) + SIZEOF_FLEX_ARRAY)
+    FAIL ();
+
+  __builtin_free (p);
+}
+
+void
+__attribute__ ((noinline))
+__attribute__ ((access (read_only, 1, 2)))
+test_flexarray_access (flex_t *p, size_t sz)
+{
+  if (__builtin_dynamic_object_size (FLEX_ARRAY (p), 0)
+      != (sz - 1) * sizeof (*p) + SIZEOF_FLEX_ARRAY)
+    FAIL ();
+
+  if (__builtin_dynamic_object_size (FLEX_ARRAY (p), 1)
+      != (sz - 1) * sizeof (*p) + SIZEOF_FLEX_ARRAY)
+    FAIL ();
+
+  if (__builtin_dynamic_object_size (FLEX_ARRAY (p), 2)
+      != (sz - 1) * sizeof (*p) + SIZEOF_FLEX_ARRAY)
+    FAIL ();
+
+  if (__builtin_dynamic_object_size (FLEX_ARRAY (p), 3)
+      != (sz - 1) * sizeof (*p) + SIZEOF_FLEX_ARRAY)
+    FAIL ();
+}
+
+void
+__attribute__ ((noinline))
+test_flexarray_none (flex_t *p)
+{
+  if (__builtin_dynamic_object_size (FLEX_ARRAY (p), 0) != -1)
+    FAIL ();
+
+  if (__builtin_dynamic_object_size (FLEX_ARRAY (p), 1) != -1)
+    FAIL ();
+
+  if (__builtin_dynamic_object_size (FLEX_ARRAY (p), 2) != 0)
+    FAIL ();
+
+  if (__builtin_dynamic_object_size (FLEX_ARRAY (p), 3) != SIZEOF_FLEX_ARRAY)
+    FAIL ();
+}
+
+int
+main (int argc, char **argv)
+{
+  const char *str = "qwertyuiopasdfgghjklzxcvbnm";
+
+  test_flexarray_allocate (str);
+
+  const size_t sz = 1024;
+  flex_t *p = __builtin_malloc (sz * sizeof (*p));
+
+  test_flexarray_access (p, sz);
+
+  test_flexarray_none (p);
+  __builtin_free (p);
+
+  DONE ();
+}
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct-nonzero.c b/gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct-nonzero.c
new file mode 100644
index 00000000000..c50cd89a817
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct-nonzero.c
@@ -0,0 +1,6 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#define SIZEOF_FLEX_ARRAY 4
+
+#include "builtin-object-size-flex-nested-struct.c"
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct-zero.c b/gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct-zero.c
new file mode 100644
index 00000000000..554aece0b46
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct-zero.c
@@ -0,0 +1,6 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#define SIZEOF_FLEX_ARRAY 0
+
+#include "builtin-object-size-flex-nested-struct.c"
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct.c b/gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct.c
new file mode 100644
index 00000000000..1adeac16ac4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#ifndef SIZEOF_FLEX_ARRAY
+# define SIZEOF_FLEX_ARRAY_DECL
+# define SIZEOF_FLEX_ARRAY 0
+#else
+# define SIZEOF_FLEX_ARRAY_DECL SIZEOF_FLEX_ARRAY
+#endif
+
+typedef struct {
+  unsigned pad;
+  struct {
+    unsigned pad;
+    char data[SIZEOF_FLEX_ARRAY_DECL];
+  } s;
+} flex_t;
+
+#define FLEX_ARRAY(p) p->s.data
+#define SIZE_OF_FLEX sizeof (unsigned) + sizeof (unsigned)
+
+#include "builtin-object-size-flex-common.h"
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union-nonzero.c b/gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union-nonzero.c
new file mode 100644
index 00000000000..58e387c8db6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union-nonzero.c
@@ -0,0 +1,6 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#define SIZEOF_FLEX_ARRAY 4
+
+#include "builtin-object-size-flex-nested-union.c"
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union-zero.c b/gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union-zero.c
new file mode 100644
index 00000000000..ec6429a5a9b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union-zero.c
@@ -0,0 +1,6 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#define SIZEOF_FLEX_ARRAY 0
+
+#include "builtin-object-size-flex-nested-union.c"
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union.c b/gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union.c
new file mode 100644
index 00000000000..8326131c890
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#ifndef SIZEOF_FLEX_ARRAY
+# define SIZEOF_FLEX_ARRAY_DECL
+# define SIZEOF_FLEX_ARRAY 0
+#else
+# define SIZEOF_FLEX_ARRAY_DECL SIZEOF_FLEX_ARRAY
+#endif
+
+typedef struct {
+  unsigned pad;
+  union {
+      struct {
+	unsigned pad;
+	char data[SIZEOF_FLEX_ARRAY_DECL];
+      } s1;
+      struct {
+	unsigned pad;
+	char data[SIZEOF_FLEX_ARRAY_DECL];
+      } s2;
+  } u;
+} flex_t;
+
+#define FLEX_ARRAY(p) p->u.s1.data
+#define SIZE_OF_FLEX sizeof (unsigned) + sizeof (unsigned)
+
+#include "builtin-object-size-flex-common.h"
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-flex-nonzero.c b/gcc/testsuite/gcc.dg/builtin-object-size-flex-nonzero.c
new file mode 100644
index 00000000000..693d2e98758
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-flex-nonzero.c
@@ -0,0 +1,6 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#define SIZEOF_FLEX_ARRAY 4
+
+#include "builtin-object-size-flex.c"
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-flex-zero.c b/gcc/testsuite/gcc.dg/builtin-object-size-flex-zero.c
new file mode 100644
index 00000000000..f38d0e01d4b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-flex-zero.c
@@ -0,0 +1,6 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#define SIZEOF_FLEX_ARRAY 0
+
+#include "builtin-object-size-flex.c"
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-flex.c b/gcc/testsuite/gcc.dg/builtin-object-size-flex.c
new file mode 100644
index 00000000000..34aba8942d6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-flex.c
@@ -0,0 +1,18 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#ifndef SIZEOF_FLEX_ARRAY
+# define SIZEOF_FLEX_ARRAY_DECL
+# define SIZEOF_FLEX_ARRAY 0
+#else
+# define SIZEOF_FLEX_ARRAY_DECL SIZEOF_FLEX_ARRAY
+#endif
+
+typedef struct {
+  unsigned pad;
+  char data[SIZEOF_FLEX_ARRAY_DECL];
+} flex_t;
+
+#define FLEX_ARRAY(p) p->data
+
+#include "builtin-object-size-flex-common.h"
diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
index d9f25397c71..98ee3c2b527 100644
--- a/gcc/tree-object-size.cc
+++ b/gcc/tree-object-size.cc
@@ -499,6 +499,19 @@ decl_init_size (tree decl, bool min)
   return size;
 }
 
+/* Return the size of SUBOBJ that is within VAR where the latter has VAR_SIZE
+   size.  */
+
+static tree
+size_from_objects (const_tree subobj, const_tree var, tree var_size,
+		   int object_size_type)
+{
+  tree bytes = compute_object_offset (subobj, var);
+
+  return (bytes != error_mark_node ? size_for_offset (var_size, bytes)
+	  : size_unknown (object_size_type));
+}
+
 /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR.
    OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
    If unknown, return size_unknown (object_size_type).  */
@@ -589,105 +602,52 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
 	{
 	  var = TREE_OPERAND (ptr, 0);
 
+	  /* Get the immediate containing subobject.  Skip over conversions
+	     because we don't need them.  */
 	  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)
+		 && (!handled_component_p (var)
+		     || TREE_CODE (var) == VIEW_CONVERT_EXPR))
 	    var = TREE_OPERAND (var, 0);
 	  if (var != pt_var && TREE_CODE (var) == ARRAY_REF)
 	    var = TREE_OPERAND (var, 0);
+
+	  /* If the subobject size cannot be easily inferred or is smaller than
+	     the whole size, just use the whole size.  */
 	  if (! TYPE_SIZE_UNIT (TREE_TYPE (var))
 	      || ! tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (var)))
 	      || (pt_var_size && TREE_CODE (pt_var_size) == INTEGER_CST
 		  && 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) == MEM_REF)
-	    {
-	      tree v = var;
-	      /* For &X->fld, compute object size if fld isn't a flexible array
-		 member.  */
-	      bool is_flexible_array_mem_ref = false;
-	      while (v && v != pt_var)
-		switch (TREE_CODE (v))
-		  {
-		  case ARRAY_REF:
-		    if (TYPE_SIZE_UNIT (TREE_TYPE (TREE_OPERAND (v, 0))))
-		      {
-			tree domain
-			  = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (v, 0)));
-			if (domain && 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 (v)) != ARRAY_TYPE)
-		      {
-			v = NULL_TREE;
-			break;
-		      }
-		    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)))
-			  != UNION_TYPE
-			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
-			  != QUAL_UNION_TYPE)
-			break;
-		      else
-			v = TREE_OPERAND (v, 0);
-		    if (TREE_CODE (v) == COMPONENT_REF
-			&& TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
-			   == RECORD_TYPE)
-		      {
-			/* compute object size only if v is not a
-			   flexible array member.  */
-			if (!is_flexible_array_mem_ref)
-			  {
-			    v = NULL_TREE;
-			    break;
-			  }
-			v = TREE_OPERAND (v, 0);
-		      }
-		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
-		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
-			  != UNION_TYPE
-			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
-			  != QUAL_UNION_TYPE)
-			break;
-		      else
-			v = TREE_OPERAND (v, 0);
-		    if (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;
 
+      bool is_flexible_array_mem_ref = false;
+      /* Find out if this is a flexible array.  This will change
+	 according to -fstrict-flex-arrays.  */
+      if (var != pt_var && TREE_CODE (pt_var) == MEM_REF)
+	is_flexible_array_mem_ref = array_ref_flexible_size_p (var);
+
+      /* We cannot get a maximum estimate for a flex array without the
+	 whole object size.  */
+      if (is_flexible_array_mem_ref && !pt_var_size
+	  && !(object_size_type & OST_MINIMUM))
+	return false;
+
       if (var != pt_var)
 	{
-	  var_size = TYPE_SIZE_UNIT (TREE_TYPE (var));
-	  if (!TREE_CONSTANT (var_size))
-	    var_size = get_or_create_ssa_default_def (cfun, var_size);
+	  /* For flexible arrays, we prefer the size based on the whole object
+	     if it is available.  */
+	  if (is_flexible_array_mem_ref && pt_var_size)
+	    var_size = size_from_objects (var, pt_var, pt_var_size,
+					  object_size_type);
+	  else
+	    {
+	      var_size = TYPE_SIZE_UNIT (TREE_TYPE (var));
+	      if (!TREE_CONSTANT (var_size))
+		var_size = get_or_create_ssa_default_def (cfun, var_size);
+	    }
 	  if (!var_size)
 	    return false;
 	}
@@ -695,23 +655,17 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
 	return false;
       else
 	var_size = pt_var_size;
-      bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var);
-      if (bytes != error_mark_node)
+
+      bytes = size_from_objects (TREE_OPERAND (ptr, 0), var, var_size,
+				 object_size_type);
+
+      if (var != pt_var && pt_var_size && TREE_CODE (pt_var) == MEM_REF
+	  && !is_flexible_array_mem_ref)
 	{
-	  bytes = size_for_offset (var_size, bytes);
-	  if (var != pt_var && pt_var_size && TREE_CODE (pt_var) == MEM_REF)
-	    {
-	      tree bytes2 = compute_object_offset (TREE_OPERAND (ptr, 0),
-						   pt_var);
-	      if (bytes2 != error_mark_node)
-		{
-		  bytes2 = size_for_offset (pt_var_size, bytes2);
-		  bytes = size_binop (MIN_EXPR, bytes, bytes2);
-		}
-	    }
+	  tree bytes2 = size_from_objects (TREE_OPERAND (ptr, 0), pt_var,
+					   pt_var_size, object_size_type);
+	  bytes = size_binop (MIN_EXPR, bytes, bytes2);
 	}
-      else
-	bytes = size_unknown (object_size_type);
 
       wholebytes
 	= object_size_type & OST_SUBOBJECT ? var_size : pt_var_wholesize;
