[PATCH] libstdc++: Make std::stack conxtexpr.
Tomasz Kaminski
tkaminsk@redhat.com
Wed Aug 19 10:56:11 GMT 2026
On Wed, Aug 19, 2026 at 12:37 PM Jonathan Wakely <jwakely@redhat.com> wrote:
> Typo of "constexpr" in the subject line
>
>
> On Mon, 10 Aug 2026 at 10:00, Tomasz Kamiński wrote:
> >
> > This patch make stack and it's formatter constexpr, implementing
> > corresponding part of P3372, "constexpr containers and adaptors",
> > and final parts of P3391R2, "constexpr format".
> >
> > libstdc++-v3/ChangeLog:
> >
> > * include/bits/stl_stack.h (std::stack): Declare members as
> > _GLIBCXX26_CONSTEXPR.
> > (std::operator==, std::operator!=, std::operator<,
> std::operator>)
> > (std::operator<=, std::operator>=, std::operator<=>, std::swap):
> > Declare as _GLIBCXX26_CONSTEXPR.
> > * include/bits/version.def (constexpr_stack): Define.
> > * include/bits/version.h: Regenerate.
> > * include/std/stack (__cpp_lib_constexpr_stack): Define.
> > * (formatter<stack<....>, _CharT>::format)
> > [__glibcxx_constexpr_format]: Declare as constexpr.
> > * testsuite/23_containers/headers/stack/synopsis.cc:
> > Update declarations.
> > * testsuite/std/format/ranges/adaptors.cc: Expand test to stack.
> > * testsuite/23_containers/stack/constexpr.cc: New test derived
> > from 23_containers/queue/constexpr.cc.
> > ---
> > Updated also stack, so I will not forgget about updating the formatter
> > later (and I could reuse the test).
> >
> > Tested on x86_64-linux. *format/ranges/adaptors.cc* and *stack* also
> > tested in all standard modes, debug and -m32. OK for trunk?
> >
> > libstdc++-v3/include/bits/stl_stack.h | 58 +++--
> > libstdc++-v3/include/bits/version.def | 9 +
> > libstdc++-v3/include/bits/version.h | 10 +
> > libstdc++-v3/include/std/stack | 4 +
> > .../23_containers/headers/stack/synopsis.cc | 30 ++-
> > .../23_containers/stack/constexpr.cc | 241 ++++++++++++++++++
> > .../testsuite/std/format/ranges/adaptors.cc | 1 +
> > 7 files changed, 317 insertions(+), 36 deletions(-)
> > create mode 100644
> libstdc++-v3/testsuite/23_containers/stack/constexpr.cc
> >
> > diff --git a/libstdc++-v3/include/bits/stl_stack.h
> b/libstdc++-v3/include/bits/stl_stack.h
> > index 94b05776049..fd29579e21a 100644
> > --- a/libstdc++-v3/include/bits/stl_stack.h
> > +++ b/libstdc++-v3/include/bits/stl_stack.h
> > @@ -117,16 +117,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > #endif
> >
> > template<typename _Tp1, typename _Seq1>
> > - friend bool
> > + friend _GLIBCXX26_CONSTEXPR bool
> > operator==(const stack<_Tp1, _Seq1>&, const stack<_Tp1, _Seq1>&);
> >
> > template<typename _Tp1, typename _Seq1>
> > - friend bool
> > + friend _GLIBCXX26_CONSTEXPR bool
> > operator<(const stack<_Tp1, _Seq1>&, const stack<_Tp1, _Seq1>&);
> >
> > #if __cpp_lib_three_way_comparison
> > template<typename _Tp1, three_way_comparable _Seq1>
> > - friend compare_three_way_result_t<_Seq1>
> > + friend _GLIBCXX26_CONSTEXPR compare_three_way_result_t<_Seq1>
> > operator<=>(const stack<_Tp1, _Seq1>&, const stack<_Tp1,
> _Seq1>&);
> > #endif
> >
> > @@ -167,20 +167,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > #else
> > template<typename _Seq = _Sequence, typename _Requires = typename
> > enable_if<is_default_constructible<_Seq>::value>::type>
> > + _GLIBCXX26_CONSTEXPR
> > stack()
> > : c() { }
> >
> > - explicit
> > + explicit _GLIBCXX26_CONSTEXPR
> > stack(const _Sequence& __c)
> > : c(__c) { }
> >
> > - explicit
> > + explicit _GLIBCXX26_CONSTEXPR
> > stack(_Sequence&& __c)
> > : c(std::move(__c)) { }
> >
> > #ifdef __glibcxx_adaptor_iterator_pair_constructor // C++ >= 23 &&
> HOSTED
> > template<typename _InputIterator,
> > typename = _RequireInputIter<_InputIterator>>
> > + _GLIBCXX26_CONSTEXPR
> > stack(_InputIterator __first, _InputIterator __last)
> > : c(__first, __last) { }
> > #endif
> > @@ -191,6 +193,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > * @since C++23
> > */
> > template<__detail::__container_compatible_range<_Tp> _Rg>
> > + _GLIBCXX26_CONSTEXPR
> > stack(from_range_t, _Rg&& __rg)
> > : c(ranges::to<_Sequence>(std::forward<_Rg>(__rg)))
> > { }
> > @@ -201,29 +204,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > */
> > template<__detail::__container_compatible_range<_Tp> _Rg,
> > typename _Alloc>
> > + _GLIBCXX26_CONSTEXPR
> > stack(from_range_t, _Rg&& __rg, const _Alloc& __a)
> > : c(ranges::to<_Sequence>(std::forward<_Rg>(__rg), __a))
> > { }
> > #endif
> >
> > template<typename _Alloc, typename _Requires = _Uses<_Alloc>>
> > - explicit
> > + explicit _GLIBCXX26_CONSTEXPR
> > stack(const _Alloc& __a)
> > : c(__a) { }
> >
> > template<typename _Alloc, typename _Requires = _Uses<_Alloc>>
> > + _GLIBCXX26_CONSTEXPR
> > stack(const _Sequence& __c, const _Alloc& __a)
> > : c(__c, __a) { }
> >
> > template<typename _Alloc, typename _Requires = _Uses<_Alloc>>
> > + _GLIBCXX26_CONSTEXPR
> > stack(_Sequence&& __c, const _Alloc& __a)
> > : c(std::move(__c), __a) { }
> >
> > template<typename _Alloc, typename _Requires = _Uses<_Alloc>>
> > + _GLIBCXX26_CONSTEXPR
> > stack(const stack& __q, const _Alloc& __a)
> > : c(__q.c, __a) { }
> >
> > template<typename _Alloc, typename _Requires = _Uses<_Alloc>>
> > + _GLIBCXX26_CONSTEXPR
> > stack(stack&& __q, const _Alloc& __a)
> > : c(std::move(__q.c), __a) { }
> >
> > @@ -231,6 +239,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > template<typename _InputIterator, typename _Alloc,
> > typename = _RequireInputIter<_InputIterator>,
> > typename = _Uses<_Alloc>>
> > + _GLIBCXX26_CONSTEXPR
> > stack(_InputIterator __first, _InputIterator __last, const
> _Alloc& __a)
> > : c(__first, __last, __a) { }
> > #endif
> > @@ -239,13 +248,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > /**
> > * Returns true if the %stack is empty.
> > */
> > - _GLIBCXX_NODISCARD bool
> > + _GLIBCXX_NODISCARD
> > + _GLIBCXX26_CONSTEXPR bool
>
> Elsewhere we have the ugly NODISCARD and CONSTEXPR macros on the same
> line, and the return type on a separate line. See for example
> std::string and std::vector. I think it's more readable that way.
>
But on the other side, we usually have constexpr (the non-macro version),
at the same line, and I am looking for them there. Also, I see a NODISCARD
as fluff, but constexpr is sometimes meaningful, so prefer having
constexpr and constexpr-from-cxx26 on the same line.
That's what I also did for deque.
>
> OK for trunk with the typo fixed and those whitepace changes.
>
Let me know, if I should still change the CONSTEXPR placement, to keep
consistency with the rest of the containers. That's actually convincing
argument,
>
> > empty() const
> > { return c.empty(); }
> >
> > /** Returns the number of elements in the %stack. */
> > _GLIBCXX_NODISCARD
> > - size_type
> > + _GLIBCXX26_CONSTEXPR size_type
> > size() const
> > { return c.size(); }
> >
> > @@ -254,7 +264,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > * element of the %stack.
> > */
> > _GLIBCXX_NODISCARD
> > - reference
> > + _GLIBCXX26_CONSTEXPR reference
> > top()
> > {
> > __glibcxx_requires_nonempty();
> > @@ -266,7 +276,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > * element of the %stack.
> > */
> > _GLIBCXX_NODISCARD
> > - const_reference
> > + _GLIBCXX26_CONSTEXPR const_reference
> > top() const
> > {
> > __glibcxx_requires_nonempty();
> > @@ -282,18 +292,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > * to it. The time complexity of the operation depends on the
> > * underlying sequence.
> > */
> > - void
> > + _GLIBCXX26_CONSTEXPR void
> > push(const value_type& __x)
> > { c.push_back(__x); }
> >
> > #if __cplusplus >= 201103L
> > - void
> > + _GLIBCXX26_CONSTEXPR void
> > push(value_type&& __x)
> > { c.push_back(std::move(__x)); }
> >
> > #if __cplusplus > 201402L
> > template<typename... _Args>
> > - decltype(auto)
> > + _GLIBCXX26_CONSTEXPR decltype(auto)
> > emplace(_Args&&... __args)
> > { return c.emplace_back(std::forward<_Args>(__args)...); }
> > #else
> > @@ -306,7 +316,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >
> > #if __glibcxx_containers_ranges // C++ >= 23
> > template<__detail::__container_compatible_range<_Tp> _Rg>
> > - void
> > + _GLIBCXX26_CONSTEXPR void
> > push_range(_Rg&& __rg)
> > {
> > if constexpr (requires {
> c.append_range(std::forward<_Rg>(__rg)); })
> > @@ -327,7 +337,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > * data is needed, it should be retrieved before pop() is
> > * called.
> > */
> > - void
> > + _GLIBCXX26_CONSTEXPR void
> > pop()
> > {
> > __glibcxx_requires_nonempty();
> > @@ -335,7 +345,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > }
> >
> > #if __cplusplus >= 201103L
> > - void
> > + _GLIBCXX26_CONSTEXPR void
> > swap(stack& __s)
> > #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or
> gnu++11
> > noexcept(__is_nothrow_swappable<_Sequence>::value)
> > @@ -405,7 +415,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > */
> > template<typename _Tp, typename _Seq>
> > _GLIBCXX_NODISCARD
> > - inline bool
> > + inline _GLIBCXX26_CONSTEXPR bool
>
For example this makes a lot of sense for me.
> > operator==(const stack<_Tp, _Seq>& __x, const stack<_Tp, _Seq>& __y)
> > { return __x.c == __y.c; }
> >
> > @@ -424,49 +434,49 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > */
> > template<typename _Tp, typename _Seq>
> > _GLIBCXX_NODISCARD
> > - inline bool
> > + inline _GLIBCXX26_CONSTEXPR bool
> > operator<(const stack<_Tp, _Seq>& __x, const stack<_Tp, _Seq>& __y)
> > { return __x.c < __y.c; }
> >
> > /// Based on operator==
> > template<typename _Tp, typename _Seq>
> > _GLIBCXX_NODISCARD
> > - inline bool
> > + inline _GLIBCXX26_CONSTEXPR bool
> > operator!=(const stack<_Tp, _Seq>& __x, const stack<_Tp, _Seq>& __y)
> > { return !(__x == __y); }
> >
> > /// Based on operator<
> > template<typename _Tp, typename _Seq>
> > _GLIBCXX_NODISCARD
> > - inline bool
> > + inline _GLIBCXX26_CONSTEXPR bool
> > operator>(const stack<_Tp, _Seq>& __x, const stack<_Tp, _Seq>& __y)
> > { return __y < __x; }
> >
> > /// Based on operator<
> > template<typename _Tp, typename _Seq>
> > _GLIBCXX_NODISCARD
> > - inline bool
> > + inline _GLIBCXX26_CONSTEXPR bool
> > operator<=(const stack<_Tp, _Seq>& __x, const stack<_Tp, _Seq>& __y)
> > { return !(__y < __x); }
> >
> > /// Based on operator<
> > template<typename _Tp, typename _Seq>
> > _GLIBCXX_NODISCARD
> > - inline bool
> > + inline _GLIBCXX26_CONSTEXPR bool
> > operator>=(const stack<_Tp, _Seq>& __x, const stack<_Tp, _Seq>& __y)
> > { return !(__x < __y); }
> >
> > #if __cpp_lib_three_way_comparison
> > template<typename _Tp, three_way_comparable _Seq>
> > [[nodiscard]]
> > - inline compare_three_way_result_t<_Seq>
> > + inline _GLIBCXX26_CONSTEXPR compare_three_way_result_t<_Seq>
> > operator<=>(const stack<_Tp, _Seq>& __x, const stack<_Tp, _Seq>&
> __y)
> > { return __x.c <=> __y.c; }
> > #endif
> >
> > #if __cplusplus >= 201103L
> > template<typename _Tp, typename _Seq>
> > - inline
> > + inline _GLIBCXX26_CONSTEXPR
> > #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or
> gnu++11
> > // Constrained free swap overload, see p0185r1
> > typename enable_if<__is_swappable<_Seq>::value>::type
> > diff --git a/libstdc++-v3/include/bits/version.def
> b/libstdc++-v3/include/bits/version.def
> > index b7349fdef63..81bbf0ea63a 100644
> > --- a/libstdc++-v3/include/bits/version.def
> > +++ b/libstdc++-v3/include/bits/version.def
> > @@ -1481,6 +1481,15 @@ ftms = {
> > };
> > };
> >
> > +ftms = {
> > + name = constexpr_stack;
> > + values = {
> > + v = 202502;
> > + cxxmin = 26;
> > + hosted = yes;
> > + };
> > +};
> > +
> > ftms = {
> > name = constrained_equality;
> > values = {
> > diff --git a/libstdc++-v3/include/bits/version.h
> b/libstdc++-v3/include/bits/version.h
> > index 142d550279f..786db34d6be 100644
> > --- a/libstdc++-v3/include/bits/version.h
> > +++ b/libstdc++-v3/include/bits/version.h
> > @@ -1616,6 +1616,16 @@
> > #endif /* !defined(__cpp_lib_constexpr_queue) */
> > #undef __glibcxx_want_constexpr_queue
> >
> > +#if !defined(__cpp_lib_constexpr_stack)
> > +# if (__cplusplus > 202302L) && _GLIBCXX_HOSTED
> > +# define __glibcxx_constexpr_stack 202502L
> > +# if defined(__glibcxx_want_all) ||
> defined(__glibcxx_want_constexpr_stack)
> > +# define __cpp_lib_constexpr_stack 202502L
> > +# endif
> > +# endif
> > +#endif /* !defined(__cpp_lib_constexpr_stack) */
> > +#undef __glibcxx_want_constexpr_stack
> > +
> > #if !defined(__cpp_lib_constrained_equality)
> > # if (__cplusplus > 202002L) && (__glibcxx_three_way_comparison)
> > # define __glibcxx_constrained_equality 202411L
> > diff --git a/libstdc++-v3/include/std/stack
> b/libstdc++-v3/include/std/stack
> > index b7f9d589b37..2ace5a732fd 100644
> > --- a/libstdc++-v3/include/std/stack
> > +++ b/libstdc++-v3/include/std/stack
> > @@ -63,6 +63,7 @@
> >
> > #define __glibcxx_want_adaptor_iterator_pair_constructor
> > #define __glibcxx_want_containers_ranges
> > +#define __glibcxx_want_constexpr_stack
> > #include <bits/version.h>
> >
> > #include <deque>
> > @@ -96,6 +97,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > // Standard declares this as template accepting unconstrained
> > // FormatContext type.
> > template<typename _Out>
> > +#ifdef __glibcxx_constexpr_format // C++ >= 26 && HOSTED && CXX11 string
> > + constexpr
> > +#endif
> > typename basic_format_context<_Out, _CharT>::iterator
> > format(__maybe_const_adaptor& __a,
> > basic_format_context<_Out, _CharT>& __fc) const
> > diff --git
> a/libstdc++-v3/testsuite/23_containers/headers/stack/synopsis.cc
> b/libstdc++-v3/testsuite/23_containers/headers/stack/synopsis.cc
> > index 39be405d4bd..25e6229034c 100644
> > --- a/libstdc++-v3/testsuite/23_containers/headers/stack/synopsis.cc
> > +++ b/libstdc++-v3/testsuite/23_containers/headers/stack/synopsis.cc
> > @@ -20,30 +20,36 @@
> >
> > #include <stack>
> >
> > +#if __cplusplus > 202302L
> > +# define CONSTEXPR constexpr
> > +#else
> > +# define CONSTEXPR
> > +#endif
> > +
> > namespace std {
> > template <class T, class Container> class stack;
> >
> > template <class T, class Container>
> > - bool operator==(const stack<T, Container>& x,
> > - const stack<T, Container>& y);
> > + CONSTEXPR bool
> > + operator==(const stack<T, Container>& x, const stack<T, Container>&
> y);
> >
> > template <class T, class Container>
> > - bool operator< (const stack<T, Container>& x,
> > - const stack<T, Container>& y);
> > + CONSTEXPR bool
> > + operator<(const stack<T, Container>& x, const stack<T, Container>&
> y);
> >
> > template <class T, class Container>
> > - bool operator!=(const stack<T, Container>& x,
> > - const stack<T, Container>& y);
> > + CONSTEXPR bool
> > + operator!=(const stack<T, Container>& x, stack<T, Container>& y);
> >
> > template <class T, class Container>
> > - bool operator> (const stack<T, Container>& x,
> > - const stack<T, Container>& y);
> > + CONSTEXPR bool
> > + operator>(const stack<T, Container>& x, const stack<T, Container>&
> y);
> >
> > template <class T, class Container>
> > - bool operator>=(const stack<T, Container>& x,
> > - const stack<T, Container>& y);
> > + CONSTEXPR bool
> > + operator>=(const stack<T, Container>& x, const stack<T, Container>&
> y);
> >
> > template <class T, class Container>
> > - bool operator<=(const stack<T, Container>& x,
> > - const stack<T, Container>& y);
> > + CONSTEXPR bool
> > + operator<=(const stack<T, Container>& x, const stack<T, Container>&
> y);
> > }
> > diff --git a/libstdc++-v3/testsuite/23_containers/stack/constexpr.cc
> b/libstdc++-v3/testsuite/23_containers/stack/constexpr.cc
> > new file mode 100644
> > index 00000000000..c4c96e7b537
> > --- /dev/null
> > +++ b/libstdc++-v3/testsuite/23_containers/stack/constexpr.cc
> > @@ -0,0 +1,241 @@
> > +// { dg-do compile { target c++26 } }
> > +
> > +#include <stack>
> > +
> > +#ifndef __cpp_lib_constexpr_stack
> > +# error "Feature test macro for __cpp_lib_constexpr_stack is missing in
> <stack>"
> > +#elif __cpp_lib_constexpr_stack != 202502L
> > +# error "Feature test macro for __cpp_lib_constexpr_stack has wrong
> value in <stack>"
> > +#endif
> > +
> > +#include <ranges>
> > +#include <functional>
> > +#include <vector>
> > +#include <numeric>
> > +#include <testsuite_hooks.h>
> > +#include <testsuite_iterators.h>
> > +#include <testsuite_allocator.h>
> > +
> > +using namespace __gnu_test;
> > +
> > +template<typename Cont>
> > +constexpr bool
> > +ctor_tests()
> > +{
> > + using Tp = typename Cont::value_type;
> > + using Alloc = typename Cont::allocator_type;
> > +
> > + auto es = [] (std::stack<Tp, Cont> l, std::span<Tp> r) {
> > + if (l.size() != r.size())
> > + return false;
> > +
> > + std::vector<Tp> s(r.begin(), r.end());
> > + for (size_t i = s.size(); i > 0; --i) {
> > + if (s[i-1] != l.top())
> > + return false;
> > + l.pop();
> > + }
> > + return true;
> > + };
> > +
> > + Cont c0;
> > + Alloc alloc0;
> > +
> > + std::stack<Tp, Cont> s1(c0);
> > + VERIFY( s1.size() == 0 && s1.empty() );
> > + s1.push(1);
> > + s1.push(2);
> > + VERIFY( s1.size() == 2 );
> > +
> > + Cont c1{1, 2};
> > + std::stack<Tp, Cont> s2(c1);
> > + VERIFY ( s2 == s1 );
> > + std::stack<Tp, Cont> s3(std::move(c1));
> > + VERIFY ( s3 == s1 );
> > +
> > + std::stack<Tp, Cont> s4(s1);
> > + std::stack<Tp, Cont> s5(std::move(s1));
> > + VERIFY ( s4 == s5 );
> > +
> > + Tp rg[4] = {2, 3, 5, 7};
> > + std::stack<Tp, Cont> s6(std::begin(rg), std::end(rg));
> > + VERIFY ( es(s6, rg) );
> > +
> > + VERIFY( s6.size() == std::size(rg));
> > + VERIFY( s6.top() == 7 );
> > + s6.pop();
> > + VERIFY( s6.top() == 5 );
> > + s6.pop();
> > + VERIFY( s6.top() == 3 );
> > + s6.pop();
> > + VERIFY( s6.top() == 2 );
> > + s6.pop();
> > +
> > + std::stack<Tp, Cont> s7(alloc0);
> > + s7.push(1);
> > + s7.push(2);
> > + VERIFY( s7.size() == 2 );
> > +
> > + Cont c2{1, 2};
> > + std::stack<Tp, Cont> s8(c2, alloc0);
> > + VERIFY( s8 == s7 );
> > + std::stack<Tp, Cont> s9(std::move(c2), alloc0);
> > + VERIFY( s9 == s7 );
> > + VERIFY( c2.empty() );
> > +
> > + std::stack<Tp, Cont> s10(s7, alloc0);
> > + VERIFY( s10 == s7 );
> > + VERIFY( s10.size() == s7.size() );
> > + VERIFY( s10.top() == s7.top() );
> > +
> > + std::stack<Tp, Cont> s11(std::move(s7), alloc0);
> > + VERIFY( s11 == s10 );
> > + VERIFY( s11.size() == s10.size() );
> > + VERIFY( s7.empty() );
> > +
> > + std::stack<Tp, Cont> s12(std::begin(rg), std::end(rg), alloc0);
> > + VERIFY ( es(s12, rg) );
> > + VERIFY( s12.size() == std::size(rg));
> > + VERIFY( s12.top() == 7 );
> > + s12.pop();
> > + VERIFY( s12.top() == 5 );
> > + s12.pop();
> > + VERIFY( s12.top() == 3 );
> > + s12.pop();
> > + VERIFY( s12.top() == 2 );
> > + s12.pop();
> > +
> > + std::stack<Tp, Cont> s13(std::from_range, rg);
> > + VERIFY( es(s13, rg) );
> > + std::stack<Tp, Cont> s14(std::from_range, rg, alloc0);
> > + VERIFY( es(s14, rg) );
> > +
> > + return true;
> > +}
> > +static_assert( ctor_tests<std::vector<int>>() );
> > +static_assert( ctor_tests<std::vector<int, SimpleAllocator<int>>>() );
> > +static_assert( ctor_tests<std::deque<int>>() );
> > +static_assert( ctor_tests<std::deque<int, SimpleAllocator<int>>>() );
> > +
> > +template<typename Range, typename Cont>
> > +constexpr void
> > +do_ranges_tests_a()
> > +{
> > + using Tp = typename Cont::value_type;
> > + typename Cont::allocator_type alloc;
> > + Tp a[] {2, 3, 5, 7};
> > +
> > + auto es = [&] (auto l, auto r) {
> > + if (l.size() != r.size())
> > + return false;
> > +
> > + while (!l.empty()) {
> > + if (l.top() != r.top())
> > + return false;
> > + l.pop();
> > + r.pop();
> > + }
> > + return true;
> > + };
> > +
> > + std::stack<Tp, Cont> s1(std::from_range, Range(a, a+4));
> > + std::stack<Tp> s2;
> > + s2.push_range(Range(a, a+4));
> > + VERIFY( es(s1, s2) );
> > +
> > + std::stack<Tp, Cont> s3(std::from_range, Range(a, a+4), alloc);
> > + std::stack<Tp, Cont> s4(std::from_range, Range(a, a+4));
> > + VERIFY( es(s3, s4) );
> > +}
> > +
> > +template<typename Cont>
> > +constexpr bool
> > +ranges_tests()
> > +{
> > + using Tp = typename Cont::value_type;
> > +
> > + do_ranges_tests_a<test_forward_range<Tp>, Cont>();
> > + do_ranges_tests_a<test_forward_sized_range<Tp>, Cont>();
> > + do_ranges_tests_a<
> > + test_sized_range_sized_sent<Tp, forward_iterator_wrapper>, Cont>();
> > +
> > + do_ranges_tests_a<test_input_range<Tp>, Cont>();
> > + do_ranges_tests_a<test_input_sized_range<Tp>, Cont>();
> > + do_ranges_tests_a<
> > + test_sized_range_sized_sent<Tp, forward_iterator_wrapper>, Cont>();
> > +
> > + do_ranges_tests_a<
> > + test_range<Tp, input_iterator_wrapper_nocopy>, Cont>();
> > + do_ranges_tests_a<
> > + test_sized_range<Tp, input_iterator_wrapper_nocopy>, Cont>();
> > + do_ranges_tests_a<
> > + test_sized_range_sized_sent<Tp, input_iterator_wrapper_nocopy>,
> Cont>();
> > + return true;
> > +}
> > +static_assert( ranges_tests<std::vector<int>>() );
> > +static_assert( ranges_tests<std::vector<int, SimpleAllocator<int>>>() );
> > +
> > +constexpr bool
> > +push_and_pop_test()
> > +{
> > + std::stack<int> a;
> > + a.push(2);
> > + a.push(4);
> > + VERIFY( a.top() == 4 );
> > + a.pop();
> > + VERIFY( a.top() == 2 );
> > + a.pop();
> > + VERIFY( a.empty() );
> > + return true;
> > +}
> > +static_assert( push_and_pop_test() );
> > +
> > +constexpr bool
> > +swap_test()
> > +{
> > + std::stack<int> a,b;
> > + a.push(1);
> > + b.push(2);
> > + std::swap(a, b);
> > + VERIFY( a.top() == 2 );
> > + VERIFY( b.top() == 1 );
> > + return true;
> > +}
> > +static_assert( swap_test() );
> > +
> > +constexpr bool
> > +emplace_test()
> > +{
> > + struct S
> > + {
> > + int foo;
> > + constexpr S(int i, int j) : foo{i + j} {}
> > + };
> > +
> > + std::stack<S> a;
> > + const S& s = a.emplace(196883, 1);
> > + VERIFY( a.size() == 1 );
> > + VERIFY( a.top().foo == 196884 );
> > + return true;
> > +}
> > +static_assert( emplace_test() );
> > +
> > +constexpr bool
> > +operator_test()
> > +{
> > + std::stack<int> a, b;
> > + a.push(1);
> > + b.push(1);
> > + VERIFY( a == b );
> > + VERIFY( a <= b );
> > + VERIFY( a >= b );
> > + b.pop();
> > + b.push(2);
> > + VERIFY( a < b );
> > + VERIFY( !(a > b) );
> > + VERIFY( a <= b );
> > + VERIFY( !(a >= b) );
> > + VERIFY( a != b );
> > + return true;
> > +}
> > +static_assert( operator_test() );
> > diff --git a/libstdc++-v3/testsuite/std/format/ranges/adaptors.cc
> b/libstdc++-v3/testsuite/std/format/ranges/adaptors.cc
> > index 968ac00b63e..188a6092ac7 100644
> > --- a/libstdc++-v3/testsuite/std/format/ranges/adaptors.cc
> > +++ b/libstdc++-v3/testsuite/std/format/ranges/adaptors.cc
> > @@ -167,6 +167,7 @@ test_compare()
> > CONSTEXPR bool
> > test_all()
> > {
> > + test_adaptor<std::stack>();
> > test_adaptor<std::queue>();
> > test_adaptor<std::priority_queue>();
> > test_compare<char>();
> > --
> > 2.55.0
> >
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20260819/82c838d0/attachment-0001.htm>
More information about the Libstdc++
mailing list