On Thu, Feb 5, 2026 at 7:17 AM François Dumont <[email protected]> wrote:

>
> On 1/27/26 11:31, Jonathan Wakely wrote:
> > On Tue, 27 Jan 2026 at 08:30, Tomasz Kaminski <[email protected]>
> wrote:
> >>
> >>
> >> On Mon, Jan 26, 2026 at 10:25 PM François Dumont <[email protected]>
> wrote:
> >>> Hi
> >>>
> >>>       libstdc++: [_GLIBCXX_DEBUG] Make constant evaluation compatible
> >>>
> >>>       In a constant evaluation context the _GLIBCXX_DEBUG is working
> in a
> >>>       degradated mode where only iterators are keeping a link to their
> >>> container,
> >>>       the container won't have a list of its iterators.
> >>>
> >>>       In std::__debug::vector and std::__debug::inplace_vector remove
> all
> >>> calls to
> >>>       std::is_constant_evaluated and code associated to it when
> returning
> >>> true. The
> >>>       same code is now used in both contexts.
> >> What are the exact benefits of this change? During constant evaluation
> we already
> >> detect all UB caused by access via invalid or past the end pointers, so
> most of the
> >> cases are detected.
> >>
> >> As this will have non-trivial impact on compile-times of programs
> operation on
> >> vector at compile time (including c++26) reflection, I would like to
> see a more concrete
> >> cost (how much longer a decently size example using reflection
> compilers) vs benefits
> >> (examples of situations where this new implementation will detect
> breach of library preconditions,
> >> that are not already detected).
>
> In this new version I've added an example of breach.
>
> _GLIBCXX_DEBUG mode is already known to be costly and is documented as
> having a performance impact. It seems normal to me that it also has some
> impact in consteval context.
>
But this patch is turning what would previously well-known performance
impact into impact on the compilation, both the time and the memory
consumption
at compile time. cosntexpr interpreters are currently an order of magnitude
slower than runtime
computation, and multiplying it may lead to simply being unable to produce
binary.

This may lead to _GLIBCXX_DEBUG being unusable for programs with heavy
use of vector at compile time (I am seeing reflection as driver for it, but
this could happen
already), to find a bug that occurs at runtime.


> I don't know much about the reflection subject but _GLIBCXX_DEBUG is
> optional so maybe it won't be usable along with reflection with this
> patch. It doesn't sound like a big deal to me but if it is then I'm
> ready to cut again all debug check when in consteval mode or when
> reflection is activated.

In the context of this patch, only relevant information about reflection,
is that
it will lead to heavy usage of std::vector of scalar types, at compile
time. Not
only creating such vectors, but also transforming them using standard
algorithms.

What would mitigate my concerns here, is measurements of compile time impact
of this case, on such examples.


>
> > Yes, I share the same concerns. This is a lot of extra code to run
> > during constant evaluation, for unclear benefit.
>
> It's a lot of extra code to compile in the consteval expressions but
> less code written, see the cleanup in <vector> and <inplace_vector>.
> Future move of containers like the unordered ones will be much more
> transparent for the _GLIBCXX_DEBUG mode.
>
> _GLIBCXX_DEBUG is already adding extra work to the compiler, I would
> prefer this extra work to serve a purpose like documented so do minimal
> checks just forgetting about tracking container's iterators.
>
> >
> > This would allow us to diagnose some uses of invalid iterators, like
> > the topic of https://cplusplus.github.io/LWG/issue2256
> > Currently that code Just Works, because there is a valid object at
> > that location, and the rule about invalidating iterators is only
> > enforced with debug mode, so not during constant evaluation:
> >
> > #include <vector>
> > #include <cassert>
> >
> > constexpr bool f()
> > {
> >    typedef std::vector<int> C;
> >    C c = {1, 2, 3, 4};
> >    C::iterator i = c.begin() + 1;
> >    C::iterator j = c.end() - 1;
> >    assert(*i == 2);
> >    assert(*j == 4);
> >    c.erase(c.begin());
> >    return *i == 3; // Why is this not perfectly fine?!
> > }
> This won't be detected in consteval, container's iterators are not tracked.
> >
> > static_assert(f());
> >
> > But I don't think I really care about this. There *is* a valid object,
> > and if there wasn't, it would fail to compile.
> >
>

Reply via email to