On Mon, 8 Dec 2025, Yuao Ma wrote:

> On Mon, Dec 8, 2025 at 6:52 PM Jonathan Wakely <[email protected]> wrote:
> >
> > On Mon, 1 Dec 2025 at 19:52, Patrick Palka <[email protected]> wrote:
> > >
> > > On Wed, 26 Nov 2025, Yuao Ma wrote:
> > > > diff --git 
> > > > a/libstdc++-v3/testsuite/23_containers/flat_multiset/constexpr.cc 
> > > > b/libstdc++-v3/testsuite/23_containers/flat_multiset/constexpr.cc
> > > > new file mode 100644
> > > > index 00000000000..860b7660809
> > > > --- /dev/null
> > > > +++ b/libstdc++-v3/testsuite/23_containers/flat_multiset/constexpr.cc
> > > > @@ -0,0 +1,239 @@
> > > > +// { dg-do run { target c++26 } }
> > >
> > > I'd expect constexpr tests to be compile-only.
> >
> > The tests have a main() function which calls VERIFY(test()), which
> > only has an effect at runtime.
> >
> > Either they should be dg-do run, or the main() function can be removed
> > and just keep:
> >
> > static_assert( test() );
> >
> > Do these new tests add any checks which are not already covered by
> > existing runtime tests for flat_set and flat_multiset?
> >
> > If they don't add anything new, then remove the main() function and
> > just do static_assert(test());
> >
> 
> It turns out I misunderstood `target c++23`; I thought it would *only*
> test C++23, but it actually tests against both 23 and 26. I’ve merged
> the testcase and guarded it using __cplusplus > 202302L.
> Please take another look, thanks!

Works for me, it makes sense to just make the existing testcase constexpr.
Also instantiating flat_set/map is quite compile time/memory heavy so
reusing the existing test as much as possible is cheaper than having a
separate test.

> 
> From 821c14b7181940899b199ef21103efde59ebd1ae Mon Sep 17 00:00:00 2001
> From: Yuao Ma <[email protected]>
> Date: Mon, 8 Dec 2025 22:14:34 +0800
> Subject: [PATCH] libstdc++: constexpr flat_set and flat_multiset
> 
> This patch makes flat_set and flat_multiset constexpr as part of P3372R3.
> 
> libstdc++-v3/ChangeLog:
> 
>       * include/bits/version.def: Add FTM.
>       * include/bits/version.h: Regenerate.
>       * include/std/flat_set: Add constexpr.
>       * testsuite/23_containers/flat_multiset/1.cc: Add constexpr test.
>       * testsuite/23_containers/flat_set/1.cc: Add constexpr test.
> ---
>  libstdc++-v3/include/bits/version.def         |   8 ++
>  libstdc++-v3/include/bits/version.h           |  10 ++
>  libstdc++-v3/include/std/flat_set             | 103 +++++++++++++++++-
>  .../23_containers/flat_multiset/1.cc          |  78 ++++++++++---
>  .../testsuite/23_containers/flat_set/1.cc     |  79 +++++++++++---
>  5 files changed, 243 insertions(+), 35 deletions(-)
> 
> diff --git a/libstdc++-v3/include/bits/version.def 
> b/libstdc++-v3/include/bits/version.def
> index 412b9ce96f8..6ff88f3072a 100644
> --- a/libstdc++-v3/include/bits/version.def
> +++ b/libstdc++-v3/include/bits/version.def
> @@ -1347,6 +1347,14 @@ ftms = {
>    };
>  };
>  
> +ftms = {
> +  name = constexpr_flat_set;
> +  values = {
> +    v = 202502;
> +    cxxmin = 26;
> +  };
> +};
> +
>  ftms = {
>    name = constexpr_string;
>    values = {
> diff --git a/libstdc++-v3/include/bits/version.h 
> b/libstdc++-v3/include/bits/version.h
> index 2b96934ca09..ae0df182572 100644
> --- a/libstdc++-v3/include/bits/version.h
> +++ b/libstdc++-v3/include/bits/version.h
> @@ -1495,6 +1495,16 @@
>  #endif /* !defined(__cpp_lib_constexpr_dynamic_alloc) */
>  #undef __glibcxx_want_constexpr_dynamic_alloc
>  
> +#if !defined(__cpp_lib_constexpr_flat_set)
> +# if (__cplusplus >  202302L)
> +#  define __glibcxx_constexpr_flat_set 202502L
> +#  if defined(__glibcxx_want_all) || 
> defined(__glibcxx_want_constexpr_flat_set)
> +#   define __cpp_lib_constexpr_flat_set 202502L
> +#  endif
> +# endif
> +#endif /* !defined(__cpp_lib_constexpr_flat_set) */
> +#undef __glibcxx_want_constexpr_flat_set
> +
>  #if !defined(__cpp_lib_constexpr_string)
>  # if (__cplusplus >= 202002L) && _GLIBCXX_USE_CXX11_ABI && _GLIBCXX_HOSTED 
> && (defined(__glibcxx_is_constant_evaluated))
>  #  define __glibcxx_constexpr_string 201907L
> diff --git a/libstdc++-v3/include/std/flat_set 
> b/libstdc++-v3/include/std/flat_set
> index c48340d7980..3a1f5ba10da 100644
> --- a/libstdc++-v3/include/std/flat_set
> +++ b/libstdc++-v3/include/std/flat_set
> @@ -33,6 +33,7 @@
>  #pragma GCC system_header
>  #endif
>  
> +#define __glibcxx_want_constexpr_flat_set
>  #define __glibcxx_want_flat_set
>  #include <bits/version.h>
>  
> @@ -100,50 +101,60 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        {
>       container_type* _M_cont;
>  
> +     _GLIBCXX26_CONSTEXPR
>       _ClearGuard(container_type& __cont)
>       : _M_cont(std::__addressof(__cont))
>       { }
>  
> +     _GLIBCXX26_CONSTEXPR
>       ~_ClearGuard()
>       {
>         if (_M_cont)
>           _M_cont->clear();
>       }
>  
> +     _GLIBCXX26_CONSTEXPR
>       void
>       _M_disable()
>       { _M_cont = nullptr; }
>        };
>  
> +      _GLIBCXX26_CONSTEXPR
>        _ClearGuard
>        _M_make_clear_guard()
>        { return _ClearGuard{this->_M_cont}; }
>  
>      public:
>        // constructors
> +      _GLIBCXX26_CONSTEXPR
>        _Flat_set_impl() : _Flat_set_impl(key_compare()) { }
>  
> +      _GLIBCXX26_CONSTEXPR
>        explicit
>        _Flat_set_impl(const key_compare& __comp)
>        : _M_cont(), _M_comp(__comp)
>        { }
>  
> +      _GLIBCXX26_CONSTEXPR
>        _Flat_set_impl(container_type __cont, const key_compare& __comp = 
> key_compare())
>        : _M_cont(std::move(__cont)), _M_comp(__comp)
>        { _M_sort_uniq(); }
>  
> +      _GLIBCXX26_CONSTEXPR
>        _Flat_set_impl(__sorted_t,
>                    container_type __cont, const key_compare& __comp = 
> key_compare())
>        : _M_cont(std::move(__cont)), _M_comp(__comp)
>        { _GLIBCXX_DEBUG_ASSERT(ranges::is_sorted(_M_cont, _M_comp)); }
>  
>        template<__has_input_iter_cat _InputIterator>
> +     _GLIBCXX26_CONSTEXPR
>       _Flat_set_impl(_InputIterator __first, _InputIterator __last,
>                      const key_compare& __comp = key_compare())
>       : _M_cont(), _M_comp(__comp)
>       { insert(__first, __last); }
>  
>        template<__has_input_iter_cat _InputIterator>
> +     _GLIBCXX26_CONSTEXPR
>       _Flat_set_impl(__sorted_t __s,
>                      _InputIterator __first, _InputIterator __last,
>                      const key_compare& __comp = key_compare())
> @@ -151,20 +162,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       { insert(__s, __first, __last); }
>  
>        template<__detail::__container_compatible_range<value_type> _Rg>
> +     _GLIBCXX26_CONSTEXPR
>       _Flat_set_impl(from_range_t, _Rg&& __rg)
>       : _Flat_set_impl(from_range, std::forward<_Rg>(__rg), key_compare())
>       { }
>  
>        template<__detail::__container_compatible_range<value_type> _Rg>
> +     _GLIBCXX26_CONSTEXPR
>       _Flat_set_impl(from_range_t, _Rg&& __rg, const key_compare& __comp)
>       : _Flat_set_impl(__comp)
>       { insert_range(std::forward<_Rg>(__rg)); }
>  
> +      _GLIBCXX26_CONSTEXPR
>        _Flat_set_impl(initializer_list<value_type> __il,
>                    const key_compare& __comp = key_compare())
>        : _Flat_set_impl(__il.begin(), __il.end(), __comp)
>        { }
>  
> +      _GLIBCXX26_CONSTEXPR
>        _Flat_set_impl(__sorted_t __s,
>                    initializer_list<value_type> __il,
>                    const key_compare& __comp = key_compare())
> @@ -174,23 +189,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        // constructors with allocators
>  
>        template<__allocator_for<container_type> _Alloc>
> +     _GLIBCXX26_CONSTEXPR
>       explicit
>       _Flat_set_impl(const _Alloc& __a)
>       : _Flat_set_impl(key_compare(), __a)
>       { }
>  
>        template<__allocator_for<container_type> _Alloc>
> +     _GLIBCXX26_CONSTEXPR
>       _Flat_set_impl(const key_compare& __comp, const _Alloc& __a)
>       : _M_cont(std::make_obj_using_allocator<container_type>(__a)),
>         _M_comp(__comp)
>       { }
>  
>        template<__allocator_for<container_type> _Alloc>
> +     _GLIBCXX26_CONSTEXPR
>       _Flat_set_impl(const container_type& __cont, const _Alloc& __a)
>       : _Flat_set_impl(__cont, key_compare(), __a)
>       { }
>  
>        template<__allocator_for<container_type> _Alloc>
> +     _GLIBCXX26_CONSTEXPR
>       _Flat_set_impl(const container_type& __cont, const key_compare& __comp,
>                      const _Alloc& __a)
>       : _M_cont(std::make_obj_using_allocator<container_type>(__a, __cont)),
> @@ -198,11 +217,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       { _M_sort_uniq(); }
>  
>        template<__allocator_for<container_type> _Alloc>
> +     _GLIBCXX26_CONSTEXPR
>       _Flat_set_impl(__sorted_t __s, const container_type& __cont, const 
> _Alloc& __a)
>       : _Flat_set_impl(__s, __cont, key_compare(), __a)
>       { }
>  
>        template<__allocator_for<container_type> _Alloc>
> +     _GLIBCXX26_CONSTEXPR
>       _Flat_set_impl(__sorted_t, const container_type& __cont, const 
> key_compare& __comp,
>                      const _Alloc& __a)
>       : _M_cont(std::make_obj_using_allocator<container_type>(__a, __cont)),
> @@ -210,24 +231,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       { _GLIBCXX_DEBUG_ASSERT(ranges::is_sorted(_M_cont, _M_comp)); }
>  
>        template<__allocator_for<container_type> _Alloc>
> +     _GLIBCXX26_CONSTEXPR
>       _Flat_set_impl(const _Derived& __x, const _Alloc& __a)
>       : _M_cont(std::make_obj_using_allocator<container_type>(__a, 
> __x._M_cont)),
>         _M_comp(__x._M_comp)
>       { }
>  
>        template<__allocator_for<container_type> _Alloc>
> +     _GLIBCXX26_CONSTEXPR
>       _Flat_set_impl(_Derived&& __x, const _Alloc& __a)
>       : _M_cont(std::make_obj_using_allocator<container_type>(__a, 
> std::move(__x._M_cont))),
>         _M_comp(__x._M_comp)
>       { }
>  
>        template<__has_input_iter_cat _InputIterator, 
> __allocator_for<container_type> _Alloc>
> +     _GLIBCXX26_CONSTEXPR
>       _Flat_set_impl(_InputIterator __first, _InputIterator __last,
>                      const _Alloc& __a)
>       : _Flat_set_impl(std::move(__first), std::move(__last), key_compare(), 
> __a)
>       { }
>  
>        template<__has_input_iter_cat _InputIterator, 
> __allocator_for<container_type> _Alloc>
> +     _GLIBCXX26_CONSTEXPR
>       _Flat_set_impl(_InputIterator __first, _InputIterator __last,
>                      const key_compare& __comp,
>                      const _Alloc& __a)
> @@ -235,6 +260,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       { insert(__first, __last); }
>  
>        template<__has_input_iter_cat _InputIterator, 
> __allocator_for<container_type> _Alloc>
> +     _GLIBCXX26_CONSTEXPR
>       _Flat_set_impl(__sorted_t __s,
>                      _InputIterator __first, _InputIterator __last,
>                      const _Alloc& __a)
> @@ -242,6 +268,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       { }
>  
>        template<__has_input_iter_cat _InputIterator, 
> __allocator_for<container_type> _Alloc>
> +     _GLIBCXX26_CONSTEXPR
>       _Flat_set_impl(__sorted_t __s,
>                      _InputIterator __first, _InputIterator __last,
>                      const key_compare& __comp,
> @@ -251,6 +278,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  
>        template<__detail::__container_compatible_range<value_type> _Rg,
>              __allocator_for<container_type> _Alloc>
> +     _GLIBCXX26_CONSTEXPR
>       _Flat_set_impl(from_range_t, _Rg&& __rg,
>                      const _Alloc& __a)
>       : _Flat_set_impl(from_range, std::forward<_Rg>(__rg), key_compare(), 
> __a)
> @@ -258,6 +286,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  
>        template<__detail::__container_compatible_range<value_type> _Rg,
>              __allocator_for<container_type> _Alloc>
> +     _GLIBCXX26_CONSTEXPR
>       _Flat_set_impl(from_range_t, _Rg&& __rg,
>                      const key_compare& __comp,
>                      const _Alloc& __a)
> @@ -265,12 +294,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       { insert_range(std::forward<_Rg>(__rg)); }
>  
>        template<__allocator_for<container_type> _Alloc>
> +     _GLIBCXX26_CONSTEXPR
>       _Flat_set_impl(initializer_list<value_type> __il,
>                      const _Alloc& __a)
>       : _Flat_set_impl(__il, key_compare(), __a)
>       { }
>  
>        template<__allocator_for<container_type> _Alloc>
> +     _GLIBCXX26_CONSTEXPR
>       _Flat_set_impl(initializer_list<value_type> __il,
>                      const key_compare& __comp,
>                      const _Alloc& __a)
> @@ -278,6 +309,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       { }
>  
>        template<__allocator_for<container_type> _Alloc>
> +     _GLIBCXX26_CONSTEXPR
>       _Flat_set_impl(__sorted_t __s,
>                      initializer_list<value_type> __il,
>                      const _Alloc& __a)
> @@ -285,6 +317,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       { }
>  
>        template<__allocator_for<container_type> _Alloc>
> +     _GLIBCXX26_CONSTEXPR
>       _Flat_set_impl(__sorted_t __s,
>                      initializer_list<value_type> __il,
>                      const key_compare& __comp,
> @@ -292,6 +325,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       : _Flat_set_impl(__s, __il.begin(), __il.end(), __comp, __a)
>       { }
>  
> +      _GLIBCXX26_CONSTEXPR
>        _Derived&
>        operator=(initializer_list<value_type> __il)
>        {
> @@ -303,54 +337,66 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        }
>  
>        // iterators
> +      _GLIBCXX26_CONSTEXPR
>        const_iterator
>        begin() const noexcept
>        { return _M_cont.begin(); }
>  
> +      _GLIBCXX26_CONSTEXPR
>        const_iterator
>        end() const noexcept
>        { return _M_cont.end(); }
>  
> +      _GLIBCXX26_CONSTEXPR
>        const_reverse_iterator
>        rbegin() const noexcept
>        { return const_reverse_iterator(end()); }
>  
> +      _GLIBCXX26_CONSTEXPR
>        const_reverse_iterator
>        rend() const noexcept
>        { return const_reverse_iterator(begin()); }
>  
> +      _GLIBCXX26_CONSTEXPR
>        const_iterator
>        cbegin() const noexcept
>        { return begin(); }
>  
> +      _GLIBCXX26_CONSTEXPR
>        const_iterator
>        cend() const noexcept
>        { return end(); }
>  
> +      _GLIBCXX26_CONSTEXPR
>        const_reverse_iterator
>        crbegin() const noexcept
>        { return rbegin(); }
>  
> +      _GLIBCXX26_CONSTEXPR
>        const_reverse_iterator
>        crend() const noexcept
>        { return rend(); }
>  
>        // capacity
>        [[nodiscard]]
> +      _GLIBCXX26_CONSTEXPR
>        bool
>        empty() const noexcept
>        { return _M_cont.empty(); }
>  
> +      _GLIBCXX26_CONSTEXPR
>        size_type
>        size() const noexcept
>        { return _M_cont.size(); }
>  
> +      _GLIBCXX26_CONSTEXPR
>        size_type
>        max_size() const noexcept
>        { return _M_cont.max_size(); }
>  
>        // modifiers
>        template<typename _Arg, typename... _Args>
> +     _GLIBCXX26_CONSTEXPR
>       pair<iterator, bool>
>       _M_try_emplace(optional<const_iterator> __hint, _Arg&& __arg, 
> _Args&&... __args)
>       {
> @@ -410,12 +456,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       }
>  
>        template<typename... _Args>
> +     _GLIBCXX26_CONSTEXPR
>       pair<iterator, bool>
>       _M_try_emplace(optional<const_iterator> __hint)
>       { return _M_try_emplace(__hint, value_type()); }
>  
>        template<typename... _Args>
>       requires is_constructible_v<value_type, _Args...>
> +     _GLIBCXX26_CONSTEXPR
>       __emplace_result_t
>       emplace(_Args&&... __args)
>       {
> @@ -427,39 +475,47 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       }
>  
>        template<typename... _Args>
> +     _GLIBCXX26_CONSTEXPR
>       iterator
>       emplace_hint(const_iterator __position, _Args&&... __args)
>       { return _M_try_emplace(__position, 
> std::forward<_Args>(__args)...).first; }
>  
> +      _GLIBCXX26_CONSTEXPR
>        __emplace_result_t
>        insert(const value_type& __x)
>        { return emplace(__x); }
>  
> +      _GLIBCXX26_CONSTEXPR
>        __emplace_result_t
>        insert(value_type&& __x)
>        { return emplace(std::move(__x)); }
>  
> +      _GLIBCXX26_CONSTEXPR
>        iterator
>        insert(const_iterator __position, const value_type& __x)
>        { return emplace_hint(__position, __x); }
>  
> +      _GLIBCXX26_CONSTEXPR
>        iterator
>        insert(const_iterator __position, value_type&& __x)
>        { return emplace_hint(__position, std::move(__x)); }
>  
>        template<typename _Arg>
>       requires is_constructible_v<value_type, _Arg>
> +     _GLIBCXX26_CONSTEXPR
>       __emplace_result_t
>       insert(_Arg&& __x)
>       { return emplace(std::forward<_Arg>(__x)); }
>  
>        template<typename _Arg>
>       requires is_constructible_v<value_type, _Arg>
> +     _GLIBCXX26_CONSTEXPR
>       iterator
>       insert(const_iterator __position, _Arg&& __x)
>       { return emplace_hint(__position, std::forward<_Arg>(__x)); }
>  
>        template<__has_input_iter_cat _InputIterator>
> +     _GLIBCXX26_CONSTEXPR
>       void
>       insert(_InputIterator __first, _InputIterator __last)
>       {
> @@ -473,6 +529,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       }
>  
>        template<__has_input_iter_cat _InputIterator>
> +     _GLIBCXX26_CONSTEXPR
>       void
>       insert(__sorted_t, _InputIterator __first, _InputIterator __last)
>       {
> @@ -485,6 +542,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       }
>  
>        template<__detail::__container_compatible_range<value_type> _Rg>
> +     _GLIBCXX26_CONSTEXPR
>       void
>       insert_range(_Rg&& __rg)
>       {
> @@ -511,14 +569,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>         __guard._M_disable();
>       }
>  
> +      _GLIBCXX26_CONSTEXPR
>        void
>        insert(initializer_list<value_type> __il)
>        { insert(__il.begin(), __il.end()); }
>  
> +      _GLIBCXX26_CONSTEXPR
>        void
>        insert(__sorted_t __s, initializer_list<value_type> __il)
>        { insert(__s, __il.begin(), __il.end()); }
>  
> +      _GLIBCXX26_CONSTEXPR
>        container_type
>        extract() &&
>        {
> @@ -526,6 +587,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       return std::move(_M_cont);
>        }
>  
> +      _GLIBCXX26_CONSTEXPR
>        void
>        replace(container_type&& __cont)
>        {
> @@ -535,10 +597,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       __guard._M_disable();
>        }
>  
> +      _GLIBCXX26_CONSTEXPR
>        iterator
>        erase(const_iterator __position)
>        { return _M_cont.erase(__position); }
>  
> +      _GLIBCXX26_CONSTEXPR
>        size_type
>        erase(const key_type& __x)
>        { return erase<const key_type&>(__x); }
> @@ -548,6 +612,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>         || (__transparent_comparator<_Compare>
>             && !is_convertible_v<_Key2, iterator>
>             && !is_convertible_v<_Key2, const_iterator>)
> +     _GLIBCXX26_CONSTEXPR
>       size_type
>       erase(_Key2&& __x)
>       {
> @@ -557,10 +622,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>         return __n;
>       }
>  
> +      _GLIBCXX26_CONSTEXPR
>        iterator
>        erase(const_iterator __first, const_iterator __last)
>        { return _M_cont.erase(__first, __last); }
>  
> +      _GLIBCXX26_CONSTEXPR
>        void
>        swap(_Derived& __x) noexcept
>        {
> @@ -569,28 +636,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       swap(_M_comp, __x._M_comp);
>        }
>  
> +      _GLIBCXX26_CONSTEXPR
>        void
>        clear() noexcept
>        { _M_cont.clear(); }
>  
>        // observers
>        [[nodiscard]]
> +      _GLIBCXX26_CONSTEXPR
>        key_compare
>        key_comp() const
>        { return _M_comp; }
>  
>        [[nodiscard]]
> +      _GLIBCXX26_CONSTEXPR
>        value_compare
>        value_comp() const
>        { return _M_comp; }
>  
>        // set operations
>        [[nodiscard]]
> +      _GLIBCXX26_CONSTEXPR
>        iterator
>        find(const key_type& __x)
>        { return find<key_type>(__x); }
>  
>        [[nodiscard]]
> +      _GLIBCXX26_CONSTEXPR
>        const_iterator
>        find(const key_type& __x) const
>        { return find<key_type>(__x); }
> @@ -598,6 +670,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        template<typename _Key2>
>       requires same_as<_Key2, _Key> || __transparent_comparator<_Compare>
>       [[nodiscard]]
> +     _GLIBCXX26_CONSTEXPR
>       iterator
>       find(const _Key2& __x)
>       {
> @@ -611,6 +684,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        template<typename _Key2>
>       requires same_as<_Key2, _Key> || __transparent_comparator<_Compare>
>       [[nodiscard]]
> +     _GLIBCXX26_CONSTEXPR
>       const_iterator
>       find(const _Key2& __x) const
>       {
> @@ -622,6 +696,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       }
>  
>        [[nodiscard]]
> +      _GLIBCXX26_CONSTEXPR
>        size_type
>        count(const key_type& __x) const
>        { return count<key_type>(__x); }
> @@ -629,6 +704,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        template<typename _Key2>
>       requires same_as<_Key2, _Key> || __transparent_comparator<_Compare>
>       [[nodiscard]]
> +     _GLIBCXX26_CONSTEXPR
>       size_type
>       count(const _Key2& __x) const
>       {
> @@ -642,6 +718,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       }
>  
>        [[nodiscard]]
> +      _GLIBCXX26_CONSTEXPR
>        bool
>        contains(const key_type& __x) const
>        { return contains<key_type>(__x); }
> @@ -649,16 +726,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        template<typename _Key2>
>       requires same_as<_Key2, _Key> || __transparent_comparator<_Compare>
>       [[nodiscard]]
> +     _GLIBCXX26_CONSTEXPR
>       bool
>       contains(const _Key2& __x) const
>       { return find(__x) != cend(); }
>  
>        [[nodiscard]]
> +      _GLIBCXX26_CONSTEXPR
>        iterator
>        lower_bound(const key_type& __x)
>        { return lower_bound<key_type>(__x); }
>  
>        [[nodiscard]]
> +      _GLIBCXX26_CONSTEXPR
>        const_iterator
>        lower_bound(const key_type& __x) const
>        { return lower_bound<key_type>(__x); }
> @@ -666,6 +746,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        template<typename _Key2>
>       requires same_as<_Key2, _Key> || __transparent_comparator<_Compare>
>       [[nodiscard]]
> +     _GLIBCXX26_CONSTEXPR
>       iterator
>       lower_bound(const _Key2& __x)
>       { return std::lower_bound(begin(), end(), __x, _M_comp); }
> @@ -673,16 +754,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        template<typename _Key2>
>       requires same_as<_Key2, _Key> || __transparent_comparator<_Compare>
>       [[nodiscard]]
> +     _GLIBCXX26_CONSTEXPR
>       const_iterator
>       lower_bound(const _Key2& __x) const
>       { return std::lower_bound(begin(), end(), __x, _M_comp); }
>  
>        [[nodiscard]]
> +      _GLIBCXX26_CONSTEXPR
>        iterator
>        upper_bound(const key_type& __x)
>        { return upper_bound<key_type>(__x); }
>  
>        [[nodiscard]]
> +      _GLIBCXX26_CONSTEXPR
>        const_iterator
>        upper_bound(const key_type& __x) const
>        { return upper_bound<key_type>(__x); }
> @@ -690,6 +774,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        template<typename _Key2>
>       requires same_as<_Key2, _Key> || __transparent_comparator<_Compare>
>       [[nodiscard]]
> +     _GLIBCXX26_CONSTEXPR
>       iterator
>       upper_bound(const _Key2& __x)
>       { return std::upper_bound(begin(), end(), __x, _M_comp); }
> @@ -697,16 +782,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        template<typename _Key2>
>       requires same_as<_Key2, _Key> || __transparent_comparator<_Compare>
>       [[nodiscard]]
> +     _GLIBCXX26_CONSTEXPR
>       const_iterator
>       upper_bound(const _Key2& __x) const
>       { return std::upper_bound(begin(), end(), __x, _M_comp); }
>  
>        [[nodiscard]]
> +      _GLIBCXX26_CONSTEXPR
>        pair<iterator, iterator>
>        equal_range(const key_type& __x)
>        { return equal_range<key_type>(__x); }
>  
>        [[nodiscard]]
> +      _GLIBCXX26_CONSTEXPR
>        pair<const_iterator, const_iterator>
>        equal_range(const key_type& __x) const
>        { return equal_range<key_type>(__x); }
> @@ -714,6 +802,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        template<typename _Key2>
>       requires same_as<_Key2, _Key> || __transparent_comparator<_Compare>
>       [[nodiscard]]
> +     _GLIBCXX26_CONSTEXPR
>       pair<iterator, iterator>
>       equal_range(const _Key2& __x)
>       { return std::equal_range(begin(), end(), __x, _M_comp); }
> @@ -721,18 +810,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        template<typename _Key2>
>       requires same_as<_Key2, _Key> || __transparent_comparator<_Compare>
>       [[nodiscard]]
> +     _GLIBCXX26_CONSTEXPR
>       pair<const_iterator, const_iterator>
>       equal_range(const _Key2& __x) const
>       { return std::equal_range(begin(), end(), __x, _M_comp); }
>  
>        [[nodiscard]]
> -      friend bool
> +      friend _GLIBCXX26_CONSTEXPR bool
>        operator==(const _Derived& __x, const _Derived& __y)
>        { return std::equal(__x.begin(), __x.end(), __y.begin(), __y.end()); }
>  
>        template<typename _Up = value_type>
>       [[nodiscard]]
> -     friend __detail::__synth3way_t<_Up>
> +     friend _GLIBCXX26_CONSTEXPR __detail::__synth3way_t<_Up>
>       operator<=>(const _Derived& __x, const _Derived& __y)
>       {
>         return std::lexicographical_compare_three_way(__x.begin(), __x.end(),
> @@ -740,11 +830,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>                                                       __detail::__synth3way);
>       }
>  
> -      friend void
> +      friend _GLIBCXX26_CONSTEXPR void
>        swap(_Derived& __x, _Derived& __y) noexcept
>        { return __x.swap(__y); }
>  
>        template<typename _Predicate>
> +     _GLIBCXX26_CONSTEXPR
>       size_type
>       _M_erase_if(_Predicate __pred)
>       {
> @@ -762,6 +853,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        container_type _M_cont;
>        [[no_unique_address]] _Compare _M_comp;
>  
> +      _GLIBCXX26_CONSTEXPR
>        void
>        _M_sort_uniq()
>        {
> @@ -770,13 +862,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>         _M_unique();
>        }
>  
> +      _GLIBCXX26_CONSTEXPR
>        void
>        _M_unique() requires (!_Multi)
>        {
>       struct __key_equiv
>       {
> +       _GLIBCXX26_CONSTEXPR
>         __key_equiv(key_compare __c) : _M_comp(__c) { }
>  
> +       _GLIBCXX26_CONSTEXPR
>         bool
>         operator()(const_reference __x, const_reference __y) const
>         { return !_M_comp(__x, __y) && !_M_comp(__y, __x); }
> @@ -934,6 +1029,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  
>    template<typename _Key, typename _Compare, typename _KeyContainer,
>          typename _Predicate>
> +    _GLIBCXX26_CONSTEXPR
>      typename flat_set<_Key, _Compare, _KeyContainer>::size_type
>      erase_if(flat_set<_Key, _Compare, _KeyContainer>& __c, _Predicate __pred)
>      { return __c._M_erase_if(std::move(__pred)); }
> @@ -1081,6 +1177,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  
>    template<typename _Key, typename _Compare, typename _KeyContainer,
>          typename _Predicate>
> +    _GLIBCXX26_CONSTEXPR
>      typename flat_multiset<_Key, _Compare, _KeyContainer>::size_type
>      erase_if(flat_multiset<_Key, _Compare, _KeyContainer>& __c, _Predicate 
> __pred)
>      { return __c._M_erase_if(std::move(__pred)); }
> diff --git a/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc 
> b/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc
> index 63855e07065..d1a81c65762 100644
> --- a/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc
> +++ b/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc
> @@ -8,6 +8,7 @@
>  #include <testsuite_hooks.h>
>  
>  template<template<class> class Sequence>
> +constexpr
>  void
>  test01()
>  {
> @@ -42,6 +43,7 @@ test01()
>    VERIFY( m.size() == 5 );
>  }
>  
> +constexpr
>  void
>  test02()
>  {
> @@ -67,6 +69,7 @@ test02()
>    VERIFY( m.count(3) == 2 );
>  }
>  
> +constexpr
>  void
>  test03()
>  {
> @@ -95,6 +98,7 @@ test03()
>    VERIFY( std::ranges::equal(m, (int[]){5}) );
>  }
>  
> +constexpr
>  void
>  test04()
>  {
> @@ -121,6 +125,7 @@ test04()
>    VERIFY( std::move(m5).extract().get_allocator().get_personality() == 44 );
>  }
>  
> +constexpr
>  void
>  test05()
>  {
> @@ -129,6 +134,7 @@ test05()
>    VERIFY( std::ranges::equal(m, (int[]){1, 2, 3, 3, 4, 5}) );
>  }
>  
> +constexpr
>  void
>  test06()
>  {
> @@ -156,25 +162,25 @@ struct NoCatIterator {
>    using difference_type = int;
>    using value_type = int;
>  
> -  NoCatIterator() : v(0) {}
> -  NoCatIterator(int x) : v(x) {}
> +  constexpr NoCatIterator() : v(0) {}
> +  constexpr NoCatIterator(int x) : v(x) {}
>  
> -  int operator*() const
> +  constexpr int operator*() const
>    { return v; }
>  
> -  NoCatIterator& operator++()
> +  constexpr NoCatIterator& operator++()
>    {
>      ++v;
>      return *this;
>    }
>  
> -  NoCatIterator operator++(int)
> +  constexpr NoCatIterator operator++(int)
>    {
>      ++v;
>      return NoCatIterator(v-1);
>    }
>  
> -  bool operator==(const NoCatIterator& rhs) const
> +  constexpr bool operator==(const NoCatIterator& rhs) const
>    { return v == rhs.v; }
>  
>  private:
> @@ -189,7 +195,9 @@ struct std::iterator_traits<NoCatIterator> {
>    // no iterator_category, happens also for common_iterator
>  };
>  
> -void test07()
> +constexpr
> +void
> +test07()
>  {
>    std::flat_multiset<int> s;
>    std::flat_multiset<int, std::less<int>, NoInsertRange<int>> s2;
> @@ -214,27 +222,39 @@ void test07()
>  #endif
>  }
>  
> +constexpr
>  void
>  test08()
>  {
>    // PR libstdc++/119620 -- flat_set::emplace always constructs element on 
> the stack
> -  static int copy_counter;
> +  int copy_counter = 0;
> +
>    struct A {
> -    A() { }
> -    A(const A&) { ++copy_counter; }
> -    A& operator=(const A&) { ++copy_counter; return *this; }
> -    auto operator<=>(const A&) const = default;
> +    int *counter;
> +    constexpr A(int &c) : counter(&c) {}
> +
> +    constexpr A(const A &other) : counter(other.counter) { ++(*counter); }
> +
> +    constexpr A &operator=(const A &other) {
> +      counter = other.counter;
> +      ++(*counter);
> +      return *this;
> +    }
> +
> +    constexpr auto operator<=>(const A &) const = default;
>    };
> +
>    std::vector<A> v;
>    v.reserve(2);
>    std::flat_multiset<A> s(std::move(v));
> -  A a;
> +  A a(copy_counter);
>    s.emplace(a);
> -  VERIFY( copy_counter == 1 );
> +  VERIFY(copy_counter == 1);
>    s.emplace(a);
> -  VERIFY( copy_counter == 2 );
> +  VERIFY(copy_counter == 2);
>  }
>  
> +constexpr
>  void
>  test09()
>  {
> @@ -245,8 +265,8 @@ test09()
>    VERIFY( std::ranges::equal(s, (int[]){2,2,4}) );
>  }
>  
> -int
> -main()
> +void
> +test()
>  {
>    test01<std::vector>();
>    test01<std::deque>();
> @@ -259,3 +279,27 @@ main()
>    test08();
>    test09();
>  }
> +
> +constexpr
> +bool
> +test_constexpr()
> +{
> +  test01<std::vector>();
> +  test02();
> +  test03();
> +  test04();
> +  test06();
> +  test07();
> +  test08();
> +  test09();
> +  return true;
> +}
> +
> +int
> +main()
> +{
> +  test();
> +#if __cplusplus > 202302L
> +  static_assert(test_constexpr());
> +#endif
> +}
> diff --git a/libstdc++-v3/testsuite/23_containers/flat_set/1.cc 
> b/libstdc++-v3/testsuite/23_containers/flat_set/1.cc
> index b1d9002caba..65848271c07 100644
> --- a/libstdc++-v3/testsuite/23_containers/flat_set/1.cc
> +++ b/libstdc++-v3/testsuite/23_containers/flat_set/1.cc
> @@ -6,6 +6,12 @@
>  # error "Feature-test macro __cpp_lib_flat_set has wrong value in <flat_set>"
>  #endif
>  
> +#if __cplusplus > 202302L
> +#if __cpp_lib_constexpr_flat_set != 202502L
> +#error "Feature-test macro __cpp_lib_constexpr_flat_set has wrong value in 
> <flat_set>"
> +#endif
> +#endif
> +
>  #include <deque>
>  #include <ranges>
>  #include <vector>
> @@ -13,6 +19,7 @@
>  #include <testsuite_hooks.h>
>  
>  template<template<typename> class KeyContainer>
> +constexpr
>  void
>  test01()
>  {
> @@ -56,6 +63,7 @@ test01()
>    VERIFY( m_copy == m );
>  }
>  
> +constexpr
>  void
>  test02()
>  {
> @@ -82,6 +90,7 @@ test02()
>    VERIFY( m.count(3) == 1 );
>  }
>  
> +constexpr
>  void
>  test03()
>  {
> @@ -110,6 +119,7 @@ test03()
>    VERIFY( std::ranges::equal(m, (int[]){5}) );
>  }
>  
> +constexpr
>  void
>  test04()
>  {
> @@ -136,6 +146,7 @@ test04()
>    VERIFY( std::move(m5).extract().get_allocator().get_personality() == 44 );
>  }
>  
> +constexpr
>  void
>  test05()
>  {
> @@ -144,6 +155,7 @@ test05()
>    VERIFY( std::ranges::equal(m, (int[]){1, 2, 3, 4, 5}) );
>  }
>  
> +constexpr
>  void
>  test06()
>  {
> @@ -171,25 +183,25 @@ struct NoCatIterator {
>    using difference_type = int;
>    using value_type = int;
>  
> -  NoCatIterator() : v(0) {}
> -  NoCatIterator(int x) : v(x) {}
> +  constexpr NoCatIterator() : v(0) {}
> +  constexpr NoCatIterator(int x) : v(x) {}
>  
> -  int operator*() const
> +  constexpr int operator*() const
>    { return v; }
>  
> -  NoCatIterator& operator++()
> +  constexpr NoCatIterator& operator++()
>    {
>      ++v;
>      return *this;
>    }
>  
> -  NoCatIterator operator++(int)
> +  constexpr NoCatIterator operator++(int)
>    {
>      ++v;
>      return NoCatIterator(v-1);
>    }
>  
> -  bool operator==(const NoCatIterator& rhs) const
> +  constexpr bool operator==(const NoCatIterator& rhs) const
>    { return v == rhs.v; }
>  
>  private:
> @@ -204,7 +216,9 @@ struct std::iterator_traits<NoCatIterator> {
>    // no iterator_category, happens also for common_iterator
>  };
>  
> -void test07()
> +constexpr
> +void
> +test07()
>  {
>    std::flat_set<int> s;
>    std::flat_set<int, std::less<int>, NoInsertRange<int>> s2;
> @@ -229,25 +243,36 @@ void test07()
>  #endif
>  }
>  
> +constexpr
>  void
>  test08()
>  {
>    // PR libstdc++/119620 -- flat_set::emplace always constructs element on 
> the stack
> -  static int copy_counter;
> +  int copy_counter = 0;
> +
>    struct A {
> -    A() { }
> -    A(const A&) { ++copy_counter; }
> -    A& operator=(const A&) { ++copy_counter; return *this; }
> -    auto operator<=>(const A&) const = default;
> +    int *counter;
> +    constexpr A(int &c) : counter(&c) {}
> +
> +    constexpr A(const A &other) : counter(other.counter) { ++(*counter); }
> +
> +    constexpr A &operator=(const A &other) {
> +      counter = other.counter;
> +      ++(*counter);
> +      return *this;
> +    }
> +
> +    constexpr auto operator<=>(const A &) const = default;
>    };
>    std::flat_set<A> s;
> -  A a;
> +  A a(copy_counter);
>    s.emplace(a);
>    VERIFY( copy_counter == 1 );
>    s.emplace(a);
>    VERIFY( copy_counter == 1 );
>  }
>  
> +constexpr
>  void
>  test09()
>  {
> @@ -258,8 +283,8 @@ test09()
>    VERIFY( std::ranges::equal(s, (int[]){2,4}) );
>  }
>  
> -int
> -main()
> +void
> +test()
>  {
>    test01<std::vector>();
>    test01<std::deque>();
> @@ -272,3 +297,27 @@ main()
>    test08();
>    test09();
>  }
> +
> +constexpr
> +bool
> +test_constexpr()
> +{
> +  test01<std::vector>();
> +  test02();
> +  test03();
> +  test04();
> +  test06();
> +  test07();
> +  test08();
> +  test09();
> +  return true;
> +}
> +
> +int
> +main()
> +{
> +  test();
> +#if __cplusplus > 202302L
> +  static_assert(test_constexpr());
> +#endif
> +}
> -- 
> 2.52.0
> 

Reply via email to