Have you thought about how std::allocator<>::allocate_at_least
might usefully discover whether the ::op new (it is obliged by the Standard to use) is the one in libstdc++, and will supply extra
details about memory allocated, not one the user has supplied and
the linker has substituted in its place? Ideally it would all be
decided at link time, and not conditionally in every call, but
linker magic is fragile even without LTO. And users can call ::op
new directly, with no #include to declare it.

Maybe pass an extra argument to ::op new that the user's version
won't notice, and that ours may discover is present by looking at
the stack frame? The extra argument might be a pointer to a place
to scribble extra details. (A hint argument might be placed there,
besides.) But stack frame conventions vary too.

-N

On 3/8/26 7:01 AM, Jonathan Wakely wrote:
On Sat, 7 Mar 2026, 12:38 Nathan Myers, <[email protected] +       *  @return Memory of suitable size and alignment for @a n or
    more
    +       *  contiguous objects of type @c value_type .


Please use markdown for new doxygen comments instead of doxygen's @c  or html like <tt>. In general only back ticks are needed, and they're more readable then the alternatives.
Good.

    +       *
    +       *  Returns <tt> a.allocate_at_least(n) </tt> if that expression
    +       *  is well-formed, else <tt> { a.allocate(n), n } </tt>. When an
    +       *  allocator is obliged to reserve more space than required for
    +       *  the cited @c n objects, it may deliver the extra space to the
    +       *  caller.
    +      */
    +      [[nodiscard]] static constexpr auto
    +      allocate_at_least(_Alloc& __a, size_type __n)
    +       -> allocation_result<pointer, size_type>
    +      {
    +       static_assert(requires { sizeof(value_type); },
    +         "allocated object type must be complete");


Does using a requires-expression make a difference here, rather than just sizeof directly?

Just that it writes out the error message attached.

    +       if constexpr (requires { __a.allocate_at_least(__n); })
    +         return __a.allocate_at_least(__n);
    +       else
    +         return { __a.allocate(__n), __n };
    +      }
    +#endif
    +
            /**
             *  @brief  Deallocate memory.
             *  @param  __a  An allocator.
    @@ -635,6 +662,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
      #endif
            }

    +#ifdef __glibcxx_allocate_at_least  // C++23
    +      /**
    +       *  @brief  Allocate memory, generously.
    +       *  @param  __a  An allocator.
    +       *  @param  __n  The minimum number of objects to allocate
    space for.
    +       *  @return Memory of suitable size and alignment for @a n or
    more
    +       *  contiguous objects of type @c value_type .
    +       *
    +       *  Returns <tt> a.allocate_at_least(n) </tt>.
    +      */
    +      [[nodiscard]] static constexpr auto
    +      allocate_at_least(allocator_type __a, size_type __n)
    +       -> allocation_result<pointer, size_type>
    +      {
    +       static_assert(requires { sizeof(value_type); },
    +         "allocated object type must be complete");


I think this static_assert is redundant, because std::allocator::allocate_at_least calls std::allocator::allocate which checks the same condition.

But, does it? Maybe it should. I have it here only because the Standard
says "Mandates:", which I have (mistakenly?) interpreted as requiring
a call-site diagnostic.

    --- a/libstdc++-v3/include/bits/allocator.h
    +++ b/libstdc++-v3/include/bits/allocator.h
    @@ -61,6 +61,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
         *  @{
         */

    +#ifdef __glibcxx_allocate_at_least  // C++23
    +  template <typename _Pointer, typename _Size = size_t>
    +    struct allocation_result


Defining this type here means it won't be declared in bits/ alloc_traits.h for freestanding, because of:

# if _GLIBCXX_HOSTED
#  include <bits/allocator.h>
# endif

I think it would be better in bits/memoryfwd.h

Good catch.

    +    {
    +      _Pointer ptr;
    +      _Size count;
    +    };
    +#endif
    +

... >     +#ifdef __glibcxx_allocate_at_least  // C++23
    +      [[nodiscard]] constexpr allocation_result<_Tp*, size_t>
    +      allocate_at_least(size_t __n)
    +      { return { this->allocate(__n), __n }; }
    +#endif

See, no static_assert here.

Reply via email to