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

Tomasz Kamiński <[email protected]>
Newsgroups gmane.comp.gcc.patches,gmane.comp.gcc.libstdc++.devel
Message-ID <[email protected]>
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
       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
     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.