--- /dev/null
+/* { dg-do run } */
+/* { dg-additional-options "-std=gnu++20" { target c++ } } */
+
+struct B {};
+struct A { int a;
+#ifdef __cplusplus
+ [[no_unique_address]]
+#endif
+ struct B b;
+ char c[]; };
+volatile void *p;
+
+void __attribute__((noipa))
+bar (void *q)
+{
+ p = q;
+}
+
+__SIZE_TYPE__ __attribute__((noipa))
+foo (struct A *p)
+{
+ bar (&p->b);
+ bar (&p->c);
+ return __builtin_object_size (&p->c, 1);
+}
+
+__SIZE_TYPE__ __attribute__((noipa))
+baz (void)
+{
+ struct A *p = (struct A *) __builtin_malloc (__builtin_offsetof (struct A, c) + 64);
+ bar (&p->b);
+ bar (&p->c);
+ return __builtin_object_size (&p->c, 1);
+}
+
+__SIZE_TYPE__ __attribute__((noipa))
+qux (struct A *p)
+{
+ bar (&p->b);
+ bar (&p->c);
+ return __builtin_object_size (&p->c, 3);
+}
+
+__SIZE_TYPE__ __attribute__((noipa))
+boo (void)
+{
+ struct A *p = (struct A *) __builtin_malloc (__builtin_offsetof (struct A, c) + 64);
+ bar (&p->b);
+ bar (&p->c);
+ return __builtin_object_size (&p->c, 3);
+}
+
+int
+main ()
+{
+ static struct A a = { .a = 1, .b = {}, .c = { 1, 2, 3, 4, 0 } };
+ if (foo (&a) < 5)
+ __builtin_abort ();
+ if (baz () < 64)
+ __builtin_abort ();
+}
poly_offset_int off
= (wi::to_poly_offset (this_offset)
+ (wi::to_offset (bit_offset) >> LOG2_BITS_PER_UNIT));
- /* Probibit value-numbering zero offset components
+ /* Prohibit value-numbering zero offset components
of addresses the same before the pass folding
- __builtin_object_size had a chance to run. */
+ __builtin_object_size had a chance to run. Likewise
+ for components of zero size at arbitrary offset. */
if (TREE_CODE (orig) != ADDR_EXPR
- || maybe_ne (off, 0)
+ || (TYPE_SIZE (temp.type)
+ && integer_nonzerop (TYPE_SIZE (temp.type))
+ && maybe_ne (off, 0))
|| (cfun->curr_properties & PROP_objsz))
off.to_shwi (&temp.off);
}
if (! temp.op2)
temp.op2 = size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (eltype),
size_int (TYPE_ALIGN_UNIT (eltype)));
+ /* Prohibit value-numbering addresses of one-after-the-last
+ element ARRAY_REFs the same as addresses of other components
+ before the pass folding __builtin_object_size had a chance
+ to run. */
+ bool avoid_oob = true;
+ if (TREE_CODE (orig) != ADDR_EXPR
+ || cfun->curr_properties & PROP_objsz)
+ avoid_oob = false;
+ else if (poly_int_tree_p (temp.op0))
+ {
+ tree ub = array_ref_up_bound (ref);
+ if (ub
+ && poly_int_tree_p (ub)
+ /* ??? The C frontend for T[0] uses [0:] and the
+ C++ frontend [0:-1U]. See layout_type for how
+ awkward this is. */
+ && !integer_minus_onep (ub)
+ && known_le (wi::to_poly_offset (temp.op0),
+ wi::to_poly_offset (ub)))
+ avoid_oob = false;
+ }
if (poly_int_tree_p (temp.op0)
&& poly_int_tree_p (temp.op1)
- && TREE_CODE (temp.op2) == INTEGER_CST)
+ && TREE_CODE (temp.op2) == INTEGER_CST
+ && !avoid_oob)
{
poly_offset_int off = ((wi::to_poly_offset (temp.op0)
- wi::to_poly_offset (temp.op1))
&& poly_int_tree_p (vro->op1)
&& TREE_CODE (vro->op2) == INTEGER_CST)
{
+ /* Prohibit value-numbering addresses of one-after-the-last
+ element ARRAY_REFs the same as addresses of other components
+ before the pass folding __builtin_object_size had a chance
+ to run. */
+ if (!(cfun->curr_properties & PROP_objsz)
+ && (*orig)[0].opcode == ADDR_EXPR)
+ {
+ tree dom = TYPE_DOMAIN ((*orig)[i + 1].type);
+ if (!dom
+ || !TYPE_MAX_VALUE (dom)
+ || !poly_int_tree_p (TYPE_MAX_VALUE (dom))
+ || integer_minus_onep (TYPE_MAX_VALUE (dom)))
+ continue;
+ if (!known_le (wi::to_poly_offset (vro->op0),
+ wi::to_poly_offset (TYPE_MAX_VALUE (dom))))
+ continue;
+ }
+
poly_offset_int off = ((wi::to_poly_offset (vro->op0)
- wi::to_poly_offset (vro->op1))
* wi::to_offset (vro->op2)