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 > > > >