Re: [PATCH] libstdc++: Make std::stack conxtexpr.

Tomasz Kaminski <[email protected]>
Newsgroups gmane.comp.gcc.patches,gmane.comp.gcc.libstdc++.devel
Message-ID <CAKvuMXBxtskeAV1QskBg0b6-xn=J_S802xer+9aHNFY+bCSRDg@mail.gmail.com>
On Wed, Aug 19, 2026 at 12:37 PM Jonathan Wakely <[email protected]> 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
> >
>
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.