https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116533
Bug ID: 116533 Summary: Possibly missing SAVE_EXPR in get_member_function_from_ptrfunc() Product: gcc Version: 15.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: sirl at gcc dot gnu.org Target Milestone: --- This came up during the discussion of PR 116449. get_member_function_from_ptrfunc() generates a statement with repeated expressions, but the repeated expressions are not wrapped into SAVE_EXPRs. This code class C { public: void P(int); void IP(); int parr[16]; }; typedef void (C::*fp)(); typedef struct arr_t { fp func; } arr_t; static arr_t farr[1] = { { &C::IP }, }; void C::P(int c) { ((*this).*farr[parr[c]].func)(); } results in this statement for C::P() in .original: <<cleanup_point <<< Unknown tree: expr_stmt (((long int) farr[((struct C *) this)->parr[c]].func.__pfn & 1) != 0) ? (void C::<T3fd> (struct C *) *) *(*((int (*) () * *) this + (sizetype) farr[((struct C *) this)->parr[c]].func.__delta) + (sizetype) ((long int) farr[((struct C *) this)->parr[c]].func.__pfn + -1)) : farr[((struct C *) this)->parr[c]].func.__pfn ((struct C *) this + (sizetype) farr[((struct C *) this)->parr[c]].func.__delta) >>>>>; As you can see the terms "farr[((struct C *) this)->parr[c]].func" and "farr[((struct C *) this)->parr[c]].func.__pfn" are used everywhere (condition and both arms of the ternary). Compiling results in the following .gimple: void C::P (struct C * const this, int c) { void C::<T3fd> (struct C *) * iftmp.0; # DEBUG BEGIN_STMT _1 = this->parr[c]; _2 = farr[_1].func.__pfn; _3 = (long int) _2; _4 = _3 & 1; if (_4 != 0) goto <D.2821>; else goto <D.2822>; <D.2821>: _5 = this->parr[c]; _6 = farr[_5].func.__delta; _7 = (sizetype) _6; _8 = this + _7; _9 = *_8; _10 = this->parr[c]; _11 = farr[_10].func.__pfn; _12 = (long int) _11; _13 = _12 + -1; _14 = (sizetype) _13; _15 = _9 + _14; iftmp.0 = *_15; goto <D.2823>; <D.2822>: _16 = this->parr[c]; iftmp.0 = farr[_16].func.__pfn; <D.2823>: iftmp.1_17 = iftmp.0; _18 = this->parr[c]; _19 = farr[_18].func.__delta; _20 = (sizetype) _19; _21 = this + _20; iftmp.1_17 (_21); } Now with this tentative patch: @@ -4191,11 +4191,10 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function, if (TREE_SIDE_EFFECTS (instance_ptr)) instance_ptr = instance_save_expr = save_expr (instance_ptr); - if (TREE_SIDE_EFFECTS (function)) - function = save_expr (function); + function = save_expr(function); /* Start by extracting all the information from the PMF itself. */ - e3 = pfn_from_ptrmemfunc (function); + e3 = save_expr(pfn_from_ptrmemfunc (function)); delta = delta_from_ptrmemfunc (function); idx = build1 (NOP_EXPR, vtable_index_type, e3); switch (TARGET_PTRMEMFUNC_VBIT_LOCATION) results in this statement: <<cleanup_point <<< Unknown tree: expr_stmt (((long int) SAVE_EXPR <SAVE_EXPR <farr[((struct C *) this)->parr[c]].func>.__pfn> & 1) != 0) ? (void C::<T40a> (struct C *) *) *(*((int (*) () * *) this + (sizetype) SAVE_EXPR <farr[((struct C *) this)->parr[c]].func>.__delta) + (sizetype) ((long int) SAVE_EXPR <SAVE_EXPR <farr[((struct C *) this)->parr[c]].func>.__pfn> + -1)) : SAVE_EXPR <SAVE_EXPR <farr[((struct C *) this)->parr[c]].func>.__pfn> ((struct C *) this + (sizetype) SAVE_EXPR <farr[((struct C *) this)->parr[c]].func>.__delta) >>>>>; and gimple like this: void C::P (struct C * const this, int c) { void C::<T40a> (struct C *) * iftmp.0; struct { void C::<T40a> (struct C *) * __pfn; long int __delta; } D.2853; void C::<T40a> (struct C *) * D.2854; # DEBUG BEGIN_STMT _1 = this->parr[c]; D.2853 = farr[_1].func; D.2854 = D.2853.__pfn; _2 = (long int) D.2854; _3 = _2 & 1; if (_3 != 0) goto <D.2855>; else goto <D.2856>; <D.2855>: _4 = D.2853.__delta; _5 = (sizetype) _4; _6 = this + _5; _7 = *_6; _8 = (long int) D.2854; _9 = _8 + -1; _10 = (sizetype) _9; _11 = _7 + _10; iftmp.0 = *_11; goto <D.2857>; <D.2856>: iftmp.0 = D.2854; <D.2857>: iftmp.1_12 = iftmp.0; _13 = D.2853.__delta; _14 = (sizetype) _13; _15 = this + _14; iftmp.1_12 (_15); } In my eyes this gimple looks much better, but there maybe valid reasons why the SAVE_EXPRs were not added before. But a lot of the code in get_member_function_from_ptrfunc() is decades old ("75th Cygnus merge" for example), so it's hard to find anything related in the ChangeLogs. The tentative patch maybe incomplete and/or too broad, but it nicely shows what's going on. So, what do you think? Should more SAVE_EXPR be added in get_member_function_from_ptrfunc()?