On Tue, Feb 3, 2026 at 8:57 PM Marek Polacek <[email protected]> wrote:

> On Tue, Feb 03, 2026 at 10:46:14AM +0000, Jonathan Wakely wrote:
> > On Mon, 2 Feb 2026 at 19:37, Marek Polacek <[email protected]> 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.

This does not impact the above change.
I wonder if else branch of if consteal should be discarded in immediate
functions, so if I have:
template<typename T>
constexpr  void foo()
{
   if consteval {
      return const_impl<T>();
   } else {
       return runtime_impl<T>();
   }
}
Then runtime_impl<T> does not need to be consteval, and thus have code
available inline.

>
> > > work around that in the Reflection code, but it would be better to
> > > clean this up.  (I see no allocation_result so I'm not changing that.)
> >
> > Right, that's not implemented yet.
>
> Ack.
>
> Marek
>
>

Reply via email to