[libcxx-commits] [libcxx] [libc+][stack] P3372R3: `constexpr <stack>` (PR #163510)

Hristo Hristov via libcxx-commits libcxx-commits at lists.llvm.org
Wed Oct 15 10:07:23 PDT 2025


https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/163510

>From bb9e48dca3197cd75edff4577604b2ead3c1cb0a Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 15 Oct 2025 08:32:39 +0300
Subject: [PATCH] [libc+][stack] P3372R3: `constexpr <stack>`

Implements `<stack>` as per P3372R3: `constexpr` containers and adaptors
- https://wg21.link/P3372R3

Closes #128672

This should be a fairly straightforward implementation, as `std::stack` is a
container adaptor, and most of the work is done in the underlying container.

Depends on #128656
Part of #127876

- https://wg21.link/P3372R3
- https://eel.is/c++draft/#containers
  - https://eel.is/c++draft/container.adaptors#stack.syn
    - https://eel.is/c++draft/stack.syn
    - https://eel.is/c++draft/stack
---
 libcxx/.clang-format                          |   1 +
 libcxx/include/stack                          | 165 ++++++++++--------
 .../stack/compare.three_way.pass.cpp          |  13 +-
 .../stack/stack.cons/ctor_default.pass.cpp    |  11 +-
 .../stack/stack.defn/emplace.pass.cpp         |  11 +-
 .../stack/stack.defn/empty.pass.cpp           |  11 +-
 .../stack/stack.defn/pop.pass.cpp             |  11 +-
 .../stack/stack.defn/push.pass.cpp            |  11 +-
 .../stack/stack.defn/push_range.pass.cpp      |  11 +-
 .../stack/stack.defn/push_rv.pass.cpp         |  11 +-
 .../stack/stack.defn/size.pass.cpp            |  11 +-
 .../stack/stack.defn/swap.pass.cpp            |  13 +-
 .../stack/stack.defn/top.pass.cpp             |  11 +-
 .../stack/stack.defn/top_const.pass.cpp       |  11 +-
 .../stack/stack.ops/eq.pass.cpp               |  13 +-
 .../stack/stack.ops/lt.pass.cpp               |  13 +-
 .../stack/stack.special/swap.pass.cpp         |  13 +-
 17 files changed, 248 insertions(+), 93 deletions(-)

diff --git a/libcxx/.clang-format b/libcxx/.clang-format
index 9557b955cd72c..269597a223ed0 100644
--- a/libcxx/.clang-format
+++ b/libcxx/.clang-format
@@ -25,6 +25,7 @@ AttributeMacros: [
                   '_LIBCPP_CONSTEXPR_SINCE_CXX17',
                   '_LIBCPP_CONSTEXPR_SINCE_CXX20',
                   '_LIBCPP_CONSTEXPR_SINCE_CXX23',
+                  '_LIBCPP_CONSTEXPR_SINCE_CXX26',
                   '_LIBCPP_CONSTEXPR',
                   '_LIBCPP_CONSTINIT',
                   '_LIBCPP_DEPRECATED_IN_CXX11',
diff --git a/libcxx/include/stack b/libcxx/include/stack
index a2f285c1994b9..f98fabbc99cfb 100644
--- a/libcxx/include/stack
+++ b/libcxx/include/stack
@@ -10,6 +10,8 @@
 #ifndef _LIBCPP_STACK
 #define _LIBCPP_STACK
 
+// clang-format off
+
 /*
     stack synopsis
 
@@ -30,7 +32,7 @@ protected:
     container_type c;
 
 public:
-    stack() = default;
+    constexpr stack() = default;                                                      // constexpr since C++26
     ~stack() = default;
 
     stack(const stack& q) = default;
@@ -39,33 +41,33 @@ public:
     stack& operator=(const stack& q) = default;
     stack& operator=(stack&& q) = default;
 
-    explicit stack(const container_type& c);
-    explicit stack(container_type&& c);
-    template <class InputIterator> stack(InputIterator first, InputIterator last); // since C++23
-    template<container-compatible-range<T> R> stack(from_range_t, R&& rg); // since C++23
-    template <class Alloc> explicit stack(const Alloc& a);
-    template <class Alloc> stack(const container_type& c, const Alloc& a);
-    template <class Alloc> stack(container_type&& c, const Alloc& a);
-    template <class Alloc> stack(const stack& c, const Alloc& a);
-    template <class Alloc> stack(stack&& c, const Alloc& a);
+    constexpr explicit stack(const container_type& c);                                // constexpr since C++26
+    constexpr explicit stack(container_type&& c);                                     // constexpr since C++26
+    template <class InputIterator> constexpr  stack(InputIterator first, InputIterator last); // since C++23, constexpr since C++26
+    template<container-compatible-range<T> R> constexpr  stack(from_range_t, R&& rg); // since C++23, constexpr since C++26
+    template <class Alloc> constexpr explicit stack(const Alloc& a);                  // constexpr since C++26
+    template <class Alloc> constexpr stack(const container_type& c, const Alloc& a);  // constexpr since C++26
+    template <class Alloc> constexpr stack(container_type&& c, const Alloc& a);       // constexpr since C++26
+    template <class Alloc> constexpr stack(const stack& c, const Alloc& a);           // constexpr since C++26
+    template <class Alloc> constexpr stack(stack&& c, const Alloc& a);                // constexpr since C++26
     template<class InputIterator, class Alloc>
-    stack(InputIterator first, InputIterator last, const Alloc&); // since C++23
+    constexpr stack(InputIterator first, InputIterator last, const Alloc&);           // since C++23, constexpr since C++26
     template<container-compatible-range<T> R, class Alloc>
-      stack(from_range_t, R&& rg, const Alloc&); // since C++23
+      constexpr stack(from_range_t, R&& rg, const Alloc&);                            // since C++23, constexpr since C++26
 
-    bool empty() const;
-    size_type size() const;
-    reference top();
-    const_reference top() const;
+    constexpr bool empty() const;             // constexpr since C++26
+    constexpr size_type size() const;         // constexpr since C++26
+    constexpr reference top();                // constexpr since C++26
+    constexpr const_reference top() const;    // constexpr since C++26
 
-    void push(const value_type& x);
-    void push(value_type&& x);
+    constexpr void push(const value_type& x); // constexpr since C++26
+    constexpr void push(value_type&& x);      // constexpr since C++26
     template<container-compatible-range<T> R>
-      void push_range(R&& rg); // C++23
-    template <class... Args> reference emplace(Args&&... args); // reference in C++17
-    void pop();
+      constexpr void push_range(R&& rg);      // C++23, constexpr since C++26
+    template <class... Args> constexpr reference emplace(Args&&... args); // reference in C++17, constexpr since C++26
+    constexpr void pop();                     // constexpr since C++26
 
-    void swap(stack& c) noexcept(is_nothrow_swappable_v<Container>)
+    constexpr void swap(stack& c) noexcept(is_nothrow_swappable_v<Container>)        // constexpr since C++26
 };
 
 template<class Container>
@@ -90,29 +92,31 @@ template<ranges::input_range R, class Allocator>
     -> stack<ranges::range_value_t<R>, deque<ranges::range_value_t<R>, Allocator>>; // since C++23
 
 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); // constexpr since C++26
 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); // constexpr since C++26
 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); // constexpr since C++26
 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); // constexpr since C++26
 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); // constexpr since C++26
 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); // constexpr since C++26
 template<class T, three_way_comparable Container>
-  compare_three_way_result_t<Container>
-    operator<=>(const stack<T, Container>& x, const stack<T, Container>& y); // since C++20
+  constexpr compare_three_way_result_t<Container>
+    operator<=>(const stack<T, Container>& x, const stack<T, Container>& y);             // since C++20, constexpr since C++26
 
 template <class T, class Container>
-  void swap(stack<T, Container>& x, stack<T, Container>& y)
-  noexcept(noexcept(x.swap(y)));
+  constexpr void swap(stack<T, Container>& x, stack<T, Container>& y)
+  noexcept(noexcept(x.swap(y)));                                                         // constexpr since C++26
 
 }  // std
 
 */
 
+// clang-format on
+
 #if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
 #  include <__cxx03/stack>
 #else
@@ -147,10 +151,12 @@ _LIBCPP_PUSH_MACROS
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _Tp, class _Container>
-_LIBCPP_HIDE_FROM_ABI bool operator==(const stack<_Tp, _Container>& __x, const stack<_Tp, _Container>& __y);
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool
+operator==(const stack<_Tp, _Container>& __x, const stack<_Tp, _Container>& __y);
 
 template <class _Tp, class _Container>
-_LIBCPP_HIDE_FROM_ABI bool operator<(const stack<_Tp, _Container>& __x, const stack<_Tp, _Container>& __y);
+_LIBCPP_HIDE_FROM_ABI bool _LIBCPP_CONSTEXPR_SINCE_CXX26
+operator<(const stack<_Tp, _Container>& __x, const stack<_Tp, _Container>& __y);
 
 template <class _Tp, class _Container /*= deque<_Tp>*/>
 class stack {
@@ -166,86 +172,93 @@ protected:
   container_type c;
 
 public:
-  _LIBCPP_HIDE_FROM_ABI stack() _NOEXCEPT_(is_nothrow_default_constructible<container_type>::value) : c() {}
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 stack()
+      _NOEXCEPT_(is_nothrow_default_constructible<container_type>::value)
+      : c() {}
 
-  _LIBCPP_HIDE_FROM_ABI stack(const stack& __q) : c(__q.c) {}
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 stack(const stack& __q) : c(__q.c) {}
 
-  _LIBCPP_HIDE_FROM_ABI stack& operator=(const stack& __q) {
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 stack& operator=(const stack& __q) {
     c = __q.c;
     return *this;
   }
 
 #  ifndef _LIBCPP_CXX03_LANG
-  _LIBCPP_HIDE_FROM_ABI stack(stack&& __q) noexcept(is_nothrow_move_constructible<container_type>::value)
+  _LIBCPP_HIDE_FROM_ABI
+  _LIBCPP_CONSTEXPR_SINCE_CXX26 stack(stack&& __q) noexcept(is_nothrow_move_constructible<container_type>::value)
       : c(std::move(__q.c)) {}
 
-  _LIBCPP_HIDE_FROM_ABI stack& operator=(stack&& __q) noexcept(is_nothrow_move_assignable<container_type>::value) {
+  _LIBCPP_HIDE_FROM_ABI
+  _LIBCPP_CONSTEXPR_SINCE_CXX26 stack& operator=(stack&& __q) noexcept(is_nothrow_move_assignable<container_type>::value) {
     c = std::move(__q.c);
     return *this;
   }
 
-  _LIBCPP_HIDE_FROM_ABI explicit stack(container_type&& __c) : c(std::move(__c)) {}
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 explicit stack(container_type&& __c) : c(std::move(__c)) {}
 #  endif // _LIBCPP_CXX03_LANG
 
-  _LIBCPP_HIDE_FROM_ABI explicit stack(const container_type& __c) : c(__c) {}
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 explicit stack(const container_type& __c) : c(__c) {}
 
   template <class _Alloc>
-  _LIBCPP_HIDE_FROM_ABI explicit stack(const _Alloc& __a,
-                                       __enable_if_t<uses_allocator<container_type, _Alloc>::value>* = 0)
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 explicit stack(
+      const _Alloc& __a, __enable_if_t<uses_allocator<container_type, _Alloc>::value>* = 0)
       : c(__a) {}
   template <class _Alloc>
-  _LIBCPP_HIDE_FROM_ABI
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
   stack(const container_type& __c, const _Alloc& __a, __enable_if_t<uses_allocator<container_type, _Alloc>::value>* = 0)
       : c(__c, __a) {}
   template <class _Alloc>
-  _LIBCPP_HIDE_FROM_ABI
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
   stack(const stack& __s, const _Alloc& __a, __enable_if_t<uses_allocator<container_type, _Alloc>::value>* = 0)
       : c(__s.c, __a) {}
 #  ifndef _LIBCPP_CXX03_LANG
   template <class _Alloc>
-  _LIBCPP_HIDE_FROM_ABI
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
   stack(container_type&& __c, const _Alloc& __a, __enable_if_t<uses_allocator<container_type, _Alloc>::value>* = 0)
       : c(std::move(__c), __a) {}
   template <class _Alloc>
-  _LIBCPP_HIDE_FROM_ABI
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
   stack(stack&& __s, const _Alloc& __a, __enable_if_t<uses_allocator<container_type, _Alloc>::value>* = 0)
       : c(std::move(__s.c), __a) {}
 #  endif // _LIBCPP_CXX03_LANG
 
 #  if _LIBCPP_STD_VER >= 23
   template <class _InputIterator, __enable_if_t<__has_input_iterator_category<_InputIterator>::value, int> = 0>
-  _LIBCPP_HIDE_FROM_ABI stack(_InputIterator __first, _InputIterator __last) : c(__first, __last) {}
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 stack(_InputIterator __first, _InputIterator __last)
+      : c(__first, __last) {}
 
   template <_ContainerCompatibleRange<_Tp> _Range>
-  _LIBCPP_HIDE_FROM_ABI stack(from_range_t, _Range&& __range) : c(from_range, std::forward<_Range>(__range)) {}
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 stack(from_range_t, _Range&& __range)
+      : c(from_range, std::forward<_Range>(__range)) {}
 
   template <class _InputIterator,
             class _Alloc,
             __enable_if_t<__has_input_iterator_category<_InputIterator>::value, int> = 0,
             __enable_if_t<uses_allocator<container_type, _Alloc>::value, int>        = 0>
-  _LIBCPP_HIDE_FROM_ABI stack(_InputIterator __first, _InputIterator __last, const _Alloc& __alloc)
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
+  stack(_InputIterator __first, _InputIterator __last, const _Alloc& __alloc)
       : c(__first, __last, __alloc) {}
 
   template <_ContainerCompatibleRange<_Tp> _Range,
             class _Alloc,
             __enable_if_t<uses_allocator<container_type, _Alloc>::value, int> = 0>
-  _LIBCPP_HIDE_FROM_ABI stack(from_range_t, _Range&& __range, const _Alloc& __alloc)
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 stack(from_range_t, _Range&& __range, const _Alloc& __alloc)
       : c(from_range, std::forward<_Range>(__range), __alloc) {}
 
 #  endif
 
-  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool empty() const { return c.empty(); }
-  _LIBCPP_HIDE_FROM_ABI size_type size() const { return c.size(); }
-  _LIBCPP_HIDE_FROM_ABI reference top() { return c.back(); }
-  _LIBCPP_HIDE_FROM_ABI const_reference top() const { return c.back(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool empty() const { return c.empty(); }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type size() const { return c.size(); }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 reference top() { return c.back(); }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_reference top() const { return c.back(); }
 
-  _LIBCPP_HIDE_FROM_ABI void push(const value_type& __v) { c.push_back(__v); }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void push(const value_type& __v) { c.push_back(__v); }
 #  ifndef _LIBCPP_CXX03_LANG
-  _LIBCPP_HIDE_FROM_ABI void push(value_type&& __v) { c.push_back(std::move(__v)); }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void push(value_type&& __v) { c.push_back(std::move(__v)); }
 
 #    if _LIBCPP_STD_VER >= 23
   template <_ContainerCompatibleRange<_Tp> _Range>
-  _LIBCPP_HIDE_FROM_ABI void push_range(_Range&& __range) {
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void push_range(_Range&& __range) {
     if constexpr (requires(container_type& __c) { __c.append_range(std::forward<_Range>(__range)); }) {
       c.append_range(std::forward<_Range>(__range));
     } else {
@@ -269,26 +282,26 @@ public:
 #    endif
 #  endif // _LIBCPP_CXX03_LANG
 
-  _LIBCPP_HIDE_FROM_ABI void pop() { c.pop_back(); }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void pop() { c.pop_back(); }
 
-  _LIBCPP_HIDE_FROM_ABI void swap(stack& __s) _NOEXCEPT_(__is_nothrow_swappable_v<container_type>) {
-    using std::swap;
-    swap(c, __s.c);
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(stack& __s)
+      _NOEXCEPT_(__is_nothrow_swappable_v<container_type>) {
+    std::swap(c, __s.c);
   }
 
-  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const _Container& __get_container() const { return c; }
+  // [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const _Container& __get_container() const { return c; }
 
   template <class _T1, class _OtherContainer>
-  friend _LIBCPP_HIDE_FROM_ABI bool
+  friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool
   operator==(const stack<_T1, _OtherContainer>& __x, const stack<_T1, _OtherContainer>& __y);
 
   template <class _T1, class _OtherContainer>
-  friend _LIBCPP_HIDE_FROM_ABI bool
+  friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool
   operator<(const stack<_T1, _OtherContainer>& __x, const stack<_T1, _OtherContainer>& __y);
 
 #  if _LIBCPP_STD_VER >= 20
   template <class _T1, three_way_comparable _OtherContainer>
-  friend _LIBCPP_HIDE_FROM_ABI compare_three_way_result_t<_OtherContainer>
+  friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 compare_three_way_result_t<_OtherContainer>
   operator<=>(const stack<_T1, _OtherContainer>& __x, const stack<_T1, _OtherContainer>& __y);
 #  endif
 };
@@ -325,39 +338,45 @@ stack(from_range_t, _Range&&, _Alloc)
 #  endif
 
 template <class _Tp, class _Container>
-inline _LIBCPP_HIDE_FROM_ABI bool operator==(const stack<_Tp, _Container>& __x, const stack<_Tp, _Container>& __y) {
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool
+operator==(const stack<_Tp, _Container>& __x, const stack<_Tp, _Container>& __y) {
   return __x.c == __y.c;
 }
 
 template <class _Tp, class _Container>
-inline _LIBCPP_HIDE_FROM_ABI bool operator<(const stack<_Tp, _Container>& __x, const stack<_Tp, _Container>& __y) {
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool
+operator<(const stack<_Tp, _Container>& __x, const stack<_Tp, _Container>& __y) {
   return __x.c < __y.c;
 }
 
 template <class _Tp, class _Container>
-inline _LIBCPP_HIDE_FROM_ABI bool operator!=(const stack<_Tp, _Container>& __x, const stack<_Tp, _Container>& __y) {
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool
+operator!=(const stack<_Tp, _Container>& __x, const stack<_Tp, _Container>& __y) {
   return !(__x == __y);
 }
 
 template <class _Tp, class _Container>
-inline _LIBCPP_HIDE_FROM_ABI bool operator>(const stack<_Tp, _Container>& __x, const stack<_Tp, _Container>& __y) {
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool
+operator>(const stack<_Tp, _Container>& __x, const stack<_Tp, _Container>& __y) {
   return __y < __x;
 }
 
 template <class _Tp, class _Container>
-inline _LIBCPP_HIDE_FROM_ABI bool operator>=(const stack<_Tp, _Container>& __x, const stack<_Tp, _Container>& __y) {
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool
+operator>=(const stack<_Tp, _Container>& __x, const stack<_Tp, _Container>& __y) {
   return !(__x < __y);
 }
 
 template <class _Tp, class _Container>
-inline _LIBCPP_HIDE_FROM_ABI bool operator<=(const stack<_Tp, _Container>& __x, const stack<_Tp, _Container>& __y) {
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool
+operator<=(const stack<_Tp, _Container>& __x, const stack<_Tp, _Container>& __y) {
   return !(__y < __x);
 }
 
 #  if _LIBCPP_STD_VER >= 20
 
 template <class _Tp, three_way_comparable _Container>
-_LIBCPP_HIDE_FROM_ABI compare_three_way_result_t<_Container>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 compare_three_way_result_t<_Container>
 operator<=>(const stack<_Tp, _Container>& __x, const stack<_Tp, _Container>& __y) {
   return __x.c <=> __y.c;
 }
diff --git a/libcxx/test/std/containers/container.adaptors/stack/compare.three_way.pass.cpp b/libcxx/test/std/containers/container.adaptors/stack/compare.three_way.pass.cpp
index c2da41a5f728a..a7596f0865fd0 100644
--- a/libcxx/test/std/containers/container.adaptors/stack/compare.three_way.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/stack/compare.three_way.pass.cpp
@@ -24,12 +24,21 @@
 #include "nasty_containers.h"
 #include "test_container_comparisons.h"
 
-int main(int, char**) {
+TEST_CONSTEXPR_CXX26 bool test() {
   assert((test_sequence_container_adaptor_spaceship<std::stack, std::deque>()));
   assert((test_sequence_container_adaptor_spaceship<std::stack, std::list>()));
   assert((test_sequence_container_adaptor_spaceship<std::stack, std::vector>()));
   assert((test_sequence_container_adaptor_spaceship<std::stack, nasty_list>()));
   assert((test_sequence_container_adaptor_spaceship<std::stack, nasty_vector>()));
-  // `std::stack` is not constexpr, so no `static_assert` test here.
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 26
+  static_assert(test());
+#endif
+
   return 0;
 }
diff --git a/libcxx/test/std/containers/container.adaptors/stack/stack.cons/ctor_default.pass.cpp b/libcxx/test/std/containers/container.adaptors/stack/stack.cons/ctor_default.pass.cpp
index 98fa904adb7ed..1cba696a4957e 100644
--- a/libcxx/test/std/containers/container.adaptors/stack/stack.cons/ctor_default.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/stack/stack.cons/ctor_default.pass.cpp
@@ -22,7 +22,7 @@
 #  include "test_convertible.h"
 #endif
 
-int main(int, char**) {
+TEST_CONSTEXPR_CXX26 bool test() {
   typedef std::vector<int, limited_allocator<int, 10> > Container;
   typedef std::stack<int, Container> Q;
   Q q;
@@ -37,5 +37,14 @@ int main(int, char**) {
   static_assert(test_convertible<Q>(), "");
 #endif
 
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 26
+  static_assert(test());
+#endif
+
   return 0;
 }
diff --git a/libcxx/test/std/containers/container.adaptors/stack/stack.defn/emplace.pass.cpp b/libcxx/test/std/containers/container.adaptors/stack/stack.defn/emplace.pass.cpp
index 2a4d9d47e1fba..4e85b0dadeb14 100644
--- a/libcxx/test/std/containers/container.adaptors/stack/stack.defn/emplace.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/stack/stack.defn/emplace.pass.cpp
@@ -36,7 +36,7 @@ void test_return_type() {
 #endif
 }
 
-int main(int, char**) {
+TEST_CONSTEXPR_CXX26 bool test() {
   test_return_type<std::stack<int> >();
   test_return_type<std::stack<int, std::vector<int> > >();
 
@@ -57,5 +57,14 @@ int main(int, char**) {
   assert(q.size() == 3);
   assert(q.top() == Emplaceable(3, 4.5));
 
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 26
+  static_assert(test());
+#endif
+
   return 0;
 }
diff --git a/libcxx/test/std/containers/container.adaptors/stack/stack.defn/empty.pass.cpp b/libcxx/test/std/containers/container.adaptors/stack/stack.defn/empty.pass.cpp
index d66c16a56fd0c..fabaec7246c2c 100644
--- a/libcxx/test/std/containers/container.adaptors/stack/stack.defn/empty.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/stack/stack.defn/empty.pass.cpp
@@ -15,7 +15,7 @@
 
 #include "test_macros.h"
 
-int main(int, char**) {
+TEST_CONSTEXPR_CXX26 bool test() {
   std::stack<int> q;
   assert(q.empty());
   q.push(1);
@@ -23,5 +23,14 @@ int main(int, char**) {
   q.pop();
   assert(q.empty());
 
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 26
+  static_assert(test());
+#endif
+
   return 0;
 }
diff --git a/libcxx/test/std/containers/container.adaptors/stack/stack.defn/pop.pass.cpp b/libcxx/test/std/containers/container.adaptors/stack/stack.defn/pop.pass.cpp
index 4af23fa911a0c..24f5943393081 100644
--- a/libcxx/test/std/containers/container.adaptors/stack/stack.defn/pop.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/stack/stack.defn/pop.pass.cpp
@@ -15,7 +15,7 @@
 
 #include "test_macros.h"
 
-int main(int, char**) {
+TEST_CONSTEXPR_CXX26 bool test() {
   std::stack<int> q;
   assert(q.size() == 0);
   q.push(1);
@@ -32,5 +32,14 @@ int main(int, char**) {
   q.pop();
   assert(q.size() == 0);
 
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 26
+  static_assert(test());
+#endif
+
   return 0;
 }
diff --git a/libcxx/test/std/containers/container.adaptors/stack/stack.defn/push.pass.cpp b/libcxx/test/std/containers/container.adaptors/stack/stack.defn/push.pass.cpp
index b514033b65242..95e9305a04431 100644
--- a/libcxx/test/std/containers/container.adaptors/stack/stack.defn/push.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/stack/stack.defn/push.pass.cpp
@@ -15,7 +15,7 @@
 
 #include "test_macros.h"
 
-int main(int, char**) {
+TEST_CONSTEXPR_CXX26 bool test() {
   std::stack<int> q;
   q.push(1);
   assert(q.size() == 1);
@@ -29,3 +29,12 @@ int main(int, char**) {
 
   return 0;
 }
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 26
+  static_assert(test());
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/containers/container.adaptors/stack/stack.defn/push_range.pass.cpp b/libcxx/test/std/containers/container.adaptors/stack/stack.defn/push_range.pass.cpp
index 0466fc7867859..aac3e7e3c5350 100644
--- a/libcxx/test/std/containers/container.adaptors/stack/stack.defn/push_range.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/stack/stack.defn/push_range.pass.cpp
@@ -17,7 +17,7 @@
 #include "../../push_range_container_adaptors.h"
 #include "test_macros.h"
 
-int main(int, char**) {
+TEST_CONSTEXPR_CXX26 bool test() {
   for_all_iterators_and_allocators<int, const int*>([]<class Iter, class Sent, class Alloc>() {
     test_push_range<std::stack<int, std::deque<int, Alloc>>, Iter, Sent>();
   });
@@ -29,5 +29,14 @@ int main(int, char**) {
   test_push_range_exception_safety_throwing_copy<std::stack>();
   test_push_range_exception_safety_throwing_allocator<std::stack, std::deque, int>();
 
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 26
+  static_assert(test());
+#endif
+
   return 0;
 }
diff --git a/libcxx/test/std/containers/container.adaptors/stack/stack.defn/push_rv.pass.cpp b/libcxx/test/std/containers/container.adaptors/stack/stack.defn/push_rv.pass.cpp
index 12771feccd162..f29a847a408ef 100644
--- a/libcxx/test/std/containers/container.adaptors/stack/stack.defn/push_rv.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/stack/stack.defn/push_rv.pass.cpp
@@ -18,7 +18,7 @@
 #include "test_macros.h"
 #include "MoveOnly.h"
 
-int main(int, char**) {
+TEST_CONSTEXPR_CXX26 bool test() {
   std::stack<MoveOnly> q;
   q.push(MoveOnly(1));
   assert(q.size() == 1);
@@ -30,5 +30,14 @@ int main(int, char**) {
   assert(q.size() == 3);
   assert(q.top() == MoveOnly(3));
 
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 26
+  static_assert(test());
+#endif
+
   return 0;
 }
diff --git a/libcxx/test/std/containers/container.adaptors/stack/stack.defn/size.pass.cpp b/libcxx/test/std/containers/container.adaptors/stack/stack.defn/size.pass.cpp
index 8a25d059d26f7..954696dcb8004 100644
--- a/libcxx/test/std/containers/container.adaptors/stack/stack.defn/size.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/stack/stack.defn/size.pass.cpp
@@ -15,7 +15,7 @@
 
 #include "test_macros.h"
 
-int main(int, char**) {
+TEST_CONSTEXPR_CXX26 bool test() {
   std::stack<int> q;
   assert(q.size() == 0);
   q.push(1);
@@ -23,3 +23,12 @@ int main(int, char**) {
 
   return 0;
 }
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 26
+  static_assert(test());
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/containers/container.adaptors/stack/stack.defn/swap.pass.cpp b/libcxx/test/std/containers/container.adaptors/stack/stack.defn/swap.pass.cpp
index 736a02ef98d38..efff823792d14 100644
--- a/libcxx/test/std/containers/container.adaptors/stack/stack.defn/swap.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/stack/stack.defn/swap.pass.cpp
@@ -16,14 +16,14 @@
 #include "test_macros.h"
 
 template <class C>
-C make(int n) {
+TEST_CONSTEXPR_CXX26 C make(int n) {
   C c;
   for (int i = 0; i < n; ++i)
     c.push(i);
   return c;
 }
 
-int main(int, char**) {
+TEST_CONSTEXPR_CXX26 bool test() {
   std::stack<int> q1      = make<std::stack<int> >(5);
   std::stack<int> q2      = make<std::stack<int> >(10);
   std::stack<int> q1_save = q1;
@@ -32,5 +32,14 @@ int main(int, char**) {
   assert(q1 == q2_save);
   assert(q2 == q1_save);
 
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 26
+  static_assert(test());
+#endif
+
   return 0;
 }
diff --git a/libcxx/test/std/containers/container.adaptors/stack/stack.defn/top.pass.cpp b/libcxx/test/std/containers/container.adaptors/stack/stack.defn/top.pass.cpp
index 2226bc557ab5a..992dcdbef09e6 100644
--- a/libcxx/test/std/containers/container.adaptors/stack/stack.defn/top.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/stack/stack.defn/top.pass.cpp
@@ -15,7 +15,7 @@
 
 #include "test_macros.h"
 
-int main(int, char**) {
+TEST_CONSTEXPR_CXX26 bool test() {
   std::stack<int> q;
   assert(q.size() == 0);
   q.push(1);
@@ -26,3 +26,12 @@ int main(int, char**) {
 
   return 0;
 }
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 26
+  static_assert(test());
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/containers/container.adaptors/stack/stack.defn/top_const.pass.cpp b/libcxx/test/std/containers/container.adaptors/stack/stack.defn/top_const.pass.cpp
index 59f2a4b7495f2..09d950b0de104 100644
--- a/libcxx/test/std/containers/container.adaptors/stack/stack.defn/top_const.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/stack/stack.defn/top_const.pass.cpp
@@ -15,7 +15,7 @@
 
 #include "test_macros.h"
 
-int main(int, char**) {
+TEST_CONSTEXPR_CXX26 bool test() {
   std::stack<int> q;
   assert(q.size() == 0);
   q.push(1);
@@ -25,5 +25,14 @@ int main(int, char**) {
   const int& cir             = cqr.top();
   assert(cir == 3);
 
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 26
+  static_assert(test());
+#endif
+
   return 0;
 }
diff --git a/libcxx/test/std/containers/container.adaptors/stack/stack.ops/eq.pass.cpp b/libcxx/test/std/containers/container.adaptors/stack/stack.ops/eq.pass.cpp
index 31c15af27faaf..8701198073eef 100644
--- a/libcxx/test/std/containers/container.adaptors/stack/stack.ops/eq.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/stack/stack.ops/eq.pass.cpp
@@ -20,14 +20,14 @@
 #include "test_macros.h"
 
 template <class C>
-C make(int n) {
+TEST_CONSTEXPR_CXX26 C make(int n) {
   C c;
   for (int i = 0; i < n; ++i)
     c.push(i);
   return c;
 }
 
-int main(int, char**) {
+TEST_CONSTEXPR_CXX26 bool test() {
   std::stack<int> q1      = make<std::stack<int> >(5);
   std::stack<int> q2      = make<std::stack<int> >(10);
   std::stack<int> q1_save = q1;
@@ -36,5 +36,14 @@ int main(int, char**) {
   assert(q1 != q2);
   assert(q2 == q2_save);
 
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 26
+  static_assert(test());
+#endif
+
   return 0;
 }
diff --git a/libcxx/test/std/containers/container.adaptors/stack/stack.ops/lt.pass.cpp b/libcxx/test/std/containers/container.adaptors/stack/stack.ops/lt.pass.cpp
index 51259aa59e4c1..73463efaab90b 100644
--- a/libcxx/test/std/containers/container.adaptors/stack/stack.ops/lt.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/stack/stack.ops/lt.pass.cpp
@@ -26,14 +26,14 @@
 #include "test_macros.h"
 
 template <class C>
-C make(int n) {
+TEST_CONSTEXPR_CXX26 C make(int n) {
   C c;
   for (int i = 0; i < n; ++i)
     c.push(i);
   return c;
 }
 
-int main(int, char**) {
+TEST_CONSTEXPR_CXX26 bool test() {
   std::stack<int> q1 = make<std::stack<int> >(5);
   std::stack<int> q2 = make<std::stack<int> >(10);
   assert(q1 < q2);
@@ -41,5 +41,14 @@ int main(int, char**) {
   assert(q1 <= q2);
   assert(q2 >= q1);
 
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 26
+  static_assert(test());
+#endif
+
   return 0;
 }
diff --git a/libcxx/test/std/containers/container.adaptors/stack/stack.special/swap.pass.cpp b/libcxx/test/std/containers/container.adaptors/stack/stack.special/swap.pass.cpp
index 16e91d1e1ef06..00972a614e79f 100644
--- a/libcxx/test/std/containers/container.adaptors/stack/stack.special/swap.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/stack/stack.special/swap.pass.cpp
@@ -17,14 +17,14 @@
 #include "test_macros.h"
 
 template <class C>
-C make(int n) {
+TEST_CONSTEXPR_CXX26 C make(int n) {
   C c;
   for (int i = 0; i < n; ++i)
     c.push(i);
   return c;
 }
 
-int main(int, char**) {
+TEST_CONSTEXPR_CXX26 bool test() {
   std::stack<int> q1      = make<std::stack<int> >(5);
   std::stack<int> q2      = make<std::stack<int> >(10);
   std::stack<int> q1_save = q1;
@@ -33,5 +33,14 @@ int main(int, char**) {
   assert(q1 == q2_save);
   assert(q2 == q1_save);
 
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 26
+  static_assert(test());
+#endif
+
   return 0;
 }



More information about the libcxx-commits mailing list