On Mon, Oct 19, 2026 at 03:56:57PM -0400, Jason Merrill wrote:
> > @@ -1112,12 +1112,42 @@ ctor_ref_range::accumulate_range_from_co
> > {
> > unsigned ix;
> > tree index, val;
> > - FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), ix, index, val)
> > + if (TYPE_MAIN_VARIANT (TREE_TYPE (init)) == DECL_CONTEXT (fld))
> > + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), ix, index, val)
> > + {
> > + if (index != fld)
> > + continue;
> > + return accumulate_range (val, i);
> > + }
> > + else if (TYPE_CANONICAL (TYPE_MAIN_VARIANT (TREE_TYPE (init)))
> > + == TYPE_CANONICAL (DECL_CONTEXT (fld)))
> > {
> > - if (index != fld)
> > - continue;
> > - return accumulate_range (val, i);
> > + // If fld is from a different record/union than the CONSTRUCTOR,
> > + // fallback to bit offset/size comparison. This happens e.g.
> > + // with C++ pointer-to-members, where we can get different
> > + // __ptrmemfunc_type RECORD_TYPEs with __pfn and __delta
> > + // FIELD_DECLs at the same offsets.
>
> Up to you, but comparing names might be simpler?
It would need to be offset/size based when DECL_NAME is NULL, because there
can be several FIELD_DECLs with no name, and I'm not
sure if other FEs don't allow compatible structure types with different
names. Even say between different TUs and with LTO, not necessarily inside
the same TU. Just checked C23 and it has a rule that if one field has a name,
the other has to have the same name, but both can also have no name.
With C/C++ covered, there are 9 other FEs. Unsure where else in the
middle-end we make such assumptions (as I wrote, gimple-fold makes all the
decisions based on offsets/sizes and nothing else).
> > + else
> > + return false;
>
> How about gcc_unreachable() to avoid silent breakage on any future similar
> cases?
return false; just means we don't try to optimize it, perfectly safe choice,
no silent breakage, just perhaps missed optimization.
Jakub