On 9/11/26 8:55 AM, Jakub Jelinek wrote:
On Wed, Sep 09, 2026 at 10:11:38AM -0400, Jason Merrill wrote:
On 9/9/26 3:41 AM, Jakub Jelinek wrote:
On Thu, Aug 06, 2026 at 05:31:50PM +0200, Jakub Jelinek wrote:
Turns out it doesn't prevent that, because match.pd has also
/* Associate (p +p off1) +p off2 as (p +p (off1 + off2)). */
(simplify
(pointer_plus (pointer_plus:s @0 @1) @3)
(pointer_plus @0 (plus @1 @3)))
#if GENERIC
(simplify
(pointer_plus (convert:s (pointer_plus:s @0 @1)) @3)
(pointer_plus (convert:type @0) (plus @1 @3)))
#endif
Guess I'll try the cxx_fold_pointer_plus_expression change you're proposing.
Actually cxx_fold_pointer_plus_expression can't help that much, the main
optimization is folding of (convert (pointer_plus @0 @1)) into
(pointer_plus (convert @0) @1) and similar optimizations, so upon
fold_convert, which isn't called just from cp_fold_convert, but many other
spots.
Yes? I was thinking that when cxx_fold_pointer_plus_expression sees
(pointer_plus (convert @0) @1) it can evaluate (pointer_plus @0 @1) instead
and then convert the result.
Ah, I forgot the details.
I still think it is unsafe compared to the patch with the langhook I've
posted, e.g. it makes us reject
struct A { int a; };
struct B : A {};
struct C { B a; A b; A c; };
constexpr int
foo ()
{
C d {};
A *p = static_cast <A *> (&d.a);
B *q = static_cast <B *> (p) + 2;
A *r = static_cast <A *> (q);
return r->a;
}
static_assert (foo () == 0);
which we accepted before (though clang++ rejects it, but for a different
reason - that the pointer addition is not valid because d.a is not an array
element).
Yes, under https://eel.is/c++draft/expr#add-4.3 , which we don't
currently check.
So, now it is rejected for a wrong reason with this patch.
I don't know if it is possible to construct a valid testcase where this
problem occurs.
As in my CWG mail, let's consider
struct A { int a; };
struct B : A {};
struct C { B a[3]; };
constexpr int
foo ()
{
C d {};
A *p = d.a;
B *q = static_cast <B *> (p) /* +2 */;
A *r = q + 2;
return r->a;
}
static_assert (foo () == 0);
I think it's uncontroversial that p does not "point to an array
element", so p+2 is UB. The question is whether q does, after the round
trip, and so whether q+2 is OK. Currently MSVC thinks it's OK, EDG
thinks it's UB, Clang curiously treats it differently if the addition is
done before or after initializing q.
Which sounds like exactly this POINTER_PLUS_EXPR situation: if we do the
addition in A* and then convert to B*, the addition is UB because the A
base subobject is not an array element.
For now I think this patch is OK, we can refine this case later when
implementing this check.
Or if you'd rather pursue the langhook now let's try to make it more
generic, something to do with type-safe folding rather than specifically
about pointer_plus_expr?
Jason