[PATCH] libstdc++, c++/reflection: mark {,de}allocate constexpr
Marek Polacek
polacek@redhat.com
Tue Feb 3 20:13:03 GMT 2026
On Tue, Feb 03, 2026 at 08:00:53PM +0000, Jonathan Wakely wrote:
> On Tue, 3 Feb 2026 at 19:57, Marek Polacek <polacek@redhat.com> wrote:
> >
> > On Tue, Feb 03, 2026 at 10:46:14AM +0000, Jonathan Wakely wrote:
> > > On Mon, 2 Feb 2026 at 19:37, Marek Polacek <polacek@redhat.com> wrote:
> > > >
> > > > Bootstrapped/regtested on ppc64le-pc-linux-gnu, ok for trunk?
> > > >
> > > > -- >8 --
> > > > [allocator.members] says that allocator::{,de}allocate should be
> > > > constexpr but currently we don't mark them as such. I had to
> > >
> > > We do mark std::allocator::allocate and deallocate, the ones you're
> > > changing below are std::__new_allocator::allocate and
> > > std::__new_allocator::deallocate, which should never be used during
> > > constant eval:
> >
> > Aha.
> >
> > > include/bits/allocator.h has:
> > >
> > > #if __cplusplus > 201703L
> > > [[nodiscard,__gnu__::__always_inline__]]
> > > constexpr _Tp*
> > > allocate(size_t __n)
> > > {
> > > if (std::__is_constant_evaluated())
> > > {
> > > if (__builtin_mul_overflow(__n, sizeof(_Tp), &__n))
> > > std::__throw_bad_array_new_length();
> > > return static_cast<_Tp*>(::operator new(__n));
> > > }
> > >
> > > return __allocator_base<_Tp>::allocate(__n, 0);
> > > }
> > >
> > > [[__gnu__::__always_inline__]]
> > > constexpr void
> > > deallocate(_Tp* __p, size_t __n)
> > > {
> > > if (std::__is_constant_evaluated())
> > > {
> > > ::operator delete(__p);
> > > return;
> > > }
> > > __allocator_base<_Tp>::deallocate(__p, __n);
> > > }
> > > #endif // C++20
> > >
> > >
> > > and __allocator_base is __new_allocator (for the default configure
> > > flags anyway).
> > >
> > > So I'm surprised that the __new_allocator members need fixing. Why
> > > does the reflection code ever end up looking at the __new_allocator
> > > members?
> >
> > bases_of uses std::vector<info> so we instantiate
> >
> > constexpr _Tp* std::allocator<<...>::allocate(std::size_t) [with _Tp = std::meta::info; std::size_t = long unsigned int]
> >
> > which due to the "return __allocator_base<_Tp>::allocate(__n, 0)" instantiates
> >
> > _Tp* std::__new_allocator<_Tp>::allocate(size_type, const void*) [with _Tp = std::meta::info; size_type = long unsigned int]
> >
> > which has
> >
> > return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp)));
> >
> > in its body. _Tp is std::meta::info so we think this is a consteval-only
> > expression, but std::__new_allocator::allocate isn't an "instantiation of
> > a templated entity defined with the constexpr specifier" so we can't
> > promote it to consteval so we error. With the added constexpr we can
> > promote it to consteval and we don't error.
> >
> > Sorry that the original mail didn't explain this.
>
> Ah gotcha, so it's about instantiating it, not actually using it.
Yeah, the same problem happens even if I change
if (std::__is_constant_evaluated())
to if (true) in std::allocator::allocate.
> The library parts of the patch are fine then, thanks.
Thanks!
Marek
More information about the Libstdc++
mailing list