[PATCH 1/2] libstdc++: Implement P3725R3 Filter View Extensions for Safer Use

Tomasz Kaminski tkaminsk@redhat.com
Wed Apr 1 19:45:50 GMT 2026


On Wed, Apr 1, 2026 at 9:02 PM Jonathan Wakely <jwakely@redhat.com> wrote:

> On Wed, 1 Apr 2026 at 19:18, Jonathan Wakely <jwakely@redhat.com> wrote:
> >
> > On Wed, 1 Apr 2026 at 18:35, Patrick Palka <ppalka@redhat.com> wrote:
> > >
> > > On Wed, 1 Apr 2026, Jonathan Wakely wrote:
> > >
> > > > On Wed, 1 Apr 2026 at 15:50, Patrick Palka <ppalka@redhat.com>
> wrote:
> > > > >
> > > > > On Tue, 31 Mar 2026, Jonathan Wakely wrote:
> > > > >
> > > > > > On Tue, 31 Mar 2026 at 19:43, Patrick Palka <ppalka@redhat.com>
> wrote:
> > > > > > >
> > > > > > > Tested on x86_64-pc-linux-gnu, does this look OK for trunk and
> > > > > > > eventually backports?
> > > > > >
> > > > > > OK for trunk, yes. Thanks for doing this so quickly!
> > > > >
> > > > > Thanks for the review.
> > > > >
> > > > > >
> > > > > > For the backports we should either not do it, or add separate
> > > > > > _CIterator and _CSentinel instead of changing the iterator and
> > > > > > sentinel into templates, so that we don't change the ABI of the
> > > > > > existing non-const filter_view::begin() and filter_view::end()
> > > > > > members.
> > > > > > Otherwise we'd change the return types of those functions in a
> dot
> > > > > > release (15.3 and 14.4) which is not what people expect/want when
> > > > > > updating within a stable release.
> > > > >
> > > > > Ah, makes sense.  Agreed in principle, but I was struggling to
> think of
> > > > > a concrete scenario that'd actually cause user breakage with this
> change,
> > > > > (i.e. changing the mangling of a user-visible
> implementation-detail type
> > > > > that is nonetheless layout-compatible with the original type).  I
> thought
> > > > > layout-compatibility would be enough to avoid breakage, but that's
> not
> > > > > true.
> > > > >
> > > > > If a user-defined function depends on the type of the filter_view
> > > > > iterator, e.g.:
> > > > >
> > > > >   inline void f(auto& it) { }
> > > > >   ...
> > > > >   auto v = r | views::filter(p);
> > > > >   f(v.begin());
> > > > >
> > > > > and one TU with such an f call was compiled before the change, and
> > > > > another such TU was compiled after the change, then the two TUs now
> > > > > refer to logically distinct functions, with different manglings and
> > > > > addresses.  This could be problematic if user code stores their
> address
> > > > > across TUs and later compares it.  Also any static local variables
> > > > > within f won't be merged by the linker and we'll end up with two
> copies
> > > > > thereof.  Unlikely, but theoretically possible breakage, so still
> > > > > must be avoided on a release branch.
> > > > >
> > > > > I think we could avoid changing the mangling of the original
> _Iterator
> > > > > in a relatively concise way with:
> > > > >
> > > > >     struct _Iterator : _GIterator<_Iterator, false>
> > > > >     { using _GIterator<false>::_GIterator; };
> > > > >
> > > > > where _GIterator is a CRTP version of the new generic iterator
> class
> > > > > template.  The mangling of _Iterator's member functions would still
> > > > > change but I believe that's fine because user code can't take the
> > > > > address of such standard member functions (and so the mangling of
> > > > > user-defined functions can't depend on _Iterator's member
> functions).
> > > >
> > > > I think you'd need to override operator++ and operator-- because the
> > > > ones in the base class will return the base class, not the derived
> > > > class :-(
> > >
> > > That's where CRTP comes in handy, the following restores the original
> > > _Iterator mangling with minimal code duplication and passes testing:
> >
> > Ah yes, of course. For some reason I glossed over the "CRTP" in your
> last mail.
> >
> > This looks like a good solution for the branches, which avoids any
> > change in mangled name for the _Iterator and _Sentinel cases.
>
>
> It occurs to me that the new spec for filter_view implies that
> sentinel_t<filter_view<R, F>> and sentinel_t<const filter_view<R, F>>
> are always distinct types, even if sentinel_t<R> and sentinel_t<const
> R> are the same type, e.g. if ranges::end(R) always returns
> std::default_sentinel_t.
>
Same is true for transform view (
https://eel.is/c++draft/range.transform.view),
which is more likely to happen. The
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1994r1.html
is also revelant here.
I think in general we do not apply simple-view optimization for views
that uses functor.

>
>  I don't think it matters, I expect most code
> to only use a given specialization of filter_view as either const or
> as non-const, but not both in the same program. So the fact you get
> two different sentinel types isn't likely to result in extra types.
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20260401/9cc27209/attachment.htm>


More information about the Libstdc++ mailing list