https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122772

Jakub Jelinek <jakub at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
   Last reconfirmed|                            |2025-11-20
             Status|UNCONFIRMED                 |NEW
           Priority|P3                          |P2
     Ever confirmed|0                           |1
                 CC|                            |jason at gcc dot gnu.org,
                   |                            |mpolacek at gcc dot gnu.org,
                   |                            |ppalka at gcc dot gnu.org

--- Comment #4 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
So, guess cp_stabilize_expr for this needs to have another case for this.
Currently it uses
      cp_lvalue_kind kind = lvalue_kind (ref);
      if ((kind & ~clk_class) != clk_none)
        {
          tree type = unlowered_expr_type (ref);
          bool rval = !!(kind & clk_rvalueref);
          type = cp_build_reference_type (type, rval);
          /* This inhibits warnings in, eg, cxx_mark_addressable
             (c++/60955).  */
          warning_sentinel s (extra_warnings);
          ref = build_static_cast (input_location, type, ref,
                                   tf_error);
        }
but for kind & (clk_bitfield|clk_packed) that isn't an option.
And then it uses
  return stabilize_reference (ref);
for selected other trees.  But for bit-fields and DECL_PACKED fields, we can't
bind a reference to those, so we really need some other function which will
return a reference to the containing aggregate but handle all the possible
trees that stand in a way, COMPOUND_EXPR, MODIFY_EXPR, the various
tcc_reference trees etc.

E.g. for
int foo () { return 0; }
int bar () { return 1; }
struct S { int y; };
S &baz () { static S s; return s; }
int
main ()
{
  (baz ().y = foo ()) += bar ();
}
the current build_static_cast to reference way turns that (baz ().y = foo ())
expression into
(*(int &) (SAVE_EXPR <SAVE_EXPR <baz ()>->y = foo (), &SAVE_EXPR <baz ()>->y>)
i.e. we first call baz (), remember its result, then evaluate the whole former
expression and then bind a reference to the y member in there.
Now, for clk_bitfield and clk_packed, it would need to instead do
((S &) (SAVE_EXPR <SAVE_EXPR <baz ()>->y = foo (), SAVE_EXPR <baz ()> >).y

Reply via email to