https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105078
--- Comment #3 from Jakub Jelinek <jakub at gcc dot gnu.org> --- This changed with r12-2270-gdddb6ffdc5c25264dd75ad82dad8e48a0718d2d9 Before that commit it has been the forwprop2 pass that changed _6 = &MEM[(struct QTypedArrayData *)header_8].D.2415; _7 = _6 + 16; to _7 = &MEM <struct QArrayData> [(void *)header_8 + 16B]; and that was done before objsz2 pass, but now objsz is done before fwprop2 (intentionally). The D.2415 there is the artificial base object. I'd say the C++ derived class case is similar to: struct S { int size; __PTRDIFF_TYPE__ offset; }; struct T { struct S base; }; __SIZE_TYPE__ foo (struct T *p) { return __builtin_object_size ((char *) &p->base + sizeof (struct S), 1); } __SIZE_TYPE__ bar (struct T *p) { return __builtin_object_size ((char *) p + sizeof (struct S), 1); } We've been since forever returning 0 from foo and all ones from bar, because in the first case we are crossing subobject boundary. I guess what would work is add char payload[]; to QArrayData and base the pointer on address of that (+ offset - offsetof(QArrayData, payload)).