On Thu, 12 Feb 2026, Jason Merrill wrote:

> On 2/12/26 5:43 AM, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > OK for trunk/15?
> > 
> > -- >8 --
> > 
> > The object argument of an xobj memfn call needs to be evaluated before
> > its formal arguments, like with an iobj memfn call.  This patch
> > generalizes the existing METHOD_TYPE callee evaluation order handling
> > in cp_gimplify_expr to also handle xobj memfn callees.  (The handling
> > needs to look at both fntype and decl because the callee can be e.g. an
> > OBJ_TYPE_REF for which decl would be NULL.)
> 
> It seems to me that this sequencing is a property of the syntax "a.f ("
> ([expr.call]/7) rather than of the function; it is not required for e.g.
> "(*&A::f) (a, ++a.m)".  Though it is still allowed under "indeterminately
> sequenced", so this is OK with an added comment.

AFAICT the METHOD_TYPE check is needed more for virtual function calls,
e.g. m_fallback->seek(newPos) in g++.dg/pr121757.C, where the callee is
expressed as OBJ_TYPE_REF:

  OBJ_TYPE_REF(*NON_LVALUE_EXPR <NON_LVALUE_EXPR <((struct 
QQmlPreviewFileEngine *) this)->m_fallback>->_vptr.QAbstractFileEngine>;(struct 
QAbstractFileEngine)NON_LVALUE_EXPR <((struct QQmlPreviewFileEngine *) 
this)->m_fallback>->0B)
    (NON_LVALUE_EXPR <((struct QQmlPreviewFileEngine *) this)->m_fallback>, 
newPos);

So I suppose we want to continue evaluating the callee first there,
given the syntactic form.

For (&A::f)(a, ++a.m) we express it the same as a.f(++a.m):

  A::f (TARGET_EXPR <D.3029, a>,  ++a.m);

and so checking 'decl' will cover both forms.

We also express (a.*&A::g)(...) the same as a.g(...), so checking
'decl' will also cover both forms (checking METHOD_TYPE will too).

> 
> >     PR c++/123989
> > 
> > gcc/cp/ChangeLog:
> > 
> >     * cp-gimplify.cc (cp_gimplify_expr) <case CALL_EXPR>: Evaluate
> >     the object argument of an xobj memfn call first too.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> >     * g++.dg/cpp23/explicit-obj-eval-order.C: New test.
> > ---
> >   gcc/cp/cp-gimplify.cc                            |  5 ++++-
> >   .../g++.dg/cpp23/explicit-obj-eval-order.C       | 16 ++++++++++++++++
> >   2 files changed, 20 insertions(+), 1 deletion(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-eval-order.C
> > 
> > diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
> > index 5ccfeefa6982..ba6a65961200 100644
> > --- a/gcc/cp/cp-gimplify.cc
> > +++ b/gcc/cp/cp-gimplify.cc
> > @@ -921,7 +921,10 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p,
> > gimple_seq *post_p)
> >       tree fntype = TREE_TYPE (CALL_EXPR_FN (*expr_p));
> >       if (INDIRECT_TYPE_P (fntype))
> >         fntype = TREE_TYPE (fntype);
> > -     if (TREE_CODE (fntype) == METHOD_TYPE)
> > +     tree decl = cp_get_callee_fndecl_nofold (*expr_p);
> > +     if (TREE_CODE (fntype) == METHOD_TYPE
> > +         || (decl && DECL_LANG_SPECIFIC (decl)
> > +             && DECL_XOBJ_MEMBER_FUNCTION_P (decl)))
> >         {
> >           int nargs = call_expr_nargs (*expr_p);
> >           bool side_effects = false;
> > diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-eval-order.C
> > b/gcc/testsuite/g++.dg/cpp23/explicit-obj-eval-order.C
> > new file mode 100644
> > index 000000000000..7ce81f32cc4b
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-eval-order.C
> > @@ -0,0 +1,16 @@
> > +// PR c++/123989
> > +// { dg-do run { target c++23 } }
> > +
> > +struct A {
> > +  int m = 42;
> > +
> > +  void f(this A self, int n) {
> > +    if (self.m != 42 || n != 43)
> > +      __builtin_abort();
> > +  }
> > +};
> > +
> > +int main() {
> > +  A a;
> > +  a.f(++a.m);
> > +}
> 
> 

Reply via email to