Skip to content

Conversation

H-G-Hristov
Copy link
Contributor

Implements <stack> as per P3372R3: constexpr containers and adaptors

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

Copy link

github-actions bot commented Oct 15, 2025

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff origin/main HEAD --extensions ,cpp -- libcxx/include/stack libcxx/test/std/containers/container.adaptors/stack/compare.three_way.pass.cpp libcxx/test/std/containers/container.adaptors/stack/stack.cons/ctor_default.pass.cpp libcxx/test/std/containers/container.adaptors/stack/stack.defn/emplace.pass.cpp libcxx/test/std/containers/container.adaptors/stack/stack.defn/empty.pass.cpp libcxx/test/std/containers/container.adaptors/stack/stack.defn/pop.pass.cpp libcxx/test/std/containers/container.adaptors/stack/stack.defn/push.pass.cpp libcxx/test/std/containers/container.adaptors/stack/stack.defn/push_range.pass.cpp libcxx/test/std/containers/container.adaptors/stack/stack.defn/push_rv.pass.cpp libcxx/test/std/containers/container.adaptors/stack/stack.defn/size.pass.cpp libcxx/test/std/containers/container.adaptors/stack/stack.defn/swap.pass.cpp libcxx/test/std/containers/container.adaptors/stack/stack.defn/top.pass.cpp libcxx/test/std/containers/container.adaptors/stack/stack.defn/top_const.pass.cpp libcxx/test/std/containers/container.adaptors/stack/stack.ops/eq.pass.cpp libcxx/test/std/containers/container.adaptors/stack/stack.ops/lt.pass.cpp libcxx/test/std/containers/container.adaptors/stack/stack.special/swap.pass.cpp --diff_from_common_commit

⚠️
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing origin/main to the base branch/commit you want to compare against.
⚠️

View the diff from clang-format here.
diff --git a/libcxx/include/stack b/libcxx/include/stack
index 52910e645..e6ea58c04 100644
--- a/libcxx/include/stack
+++ b/libcxx/include/stack
@@ -184,8 +184,8 @@ public:
   }
 
 #  ifndef _LIBCPP_CXX03_LANG
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
-  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 _LIBCPP_CONSTEXPR_SINCE_CXX26 stack&
@@ -338,8 +338,8 @@ stack(from_range_t, _Range&&, _Alloc)
 #  endif
 
 template <class _Tp, class _Container>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 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;
 }
 

@Zingam Zingam added libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. c++26 labels Oct 15, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 15, 2025

@llvm/pr-subscribers-libcxx

Author: Hristo Hristov (H-G-Hristov)

Changes

Implements &lt;stack&gt; as per P3372R3: constexpr containers and adaptors

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


Patch is 30.79 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/163510.diff

17 Files Affected:

  • (modified) libcxx/.clang-format (+1)
  • (modified) libcxx/include/stack (+92-73)
  • (modified) libcxx/test/std/containers/container.adaptors/stack/compare.three_way.pass.cpp (+11-2)
  • (modified) libcxx/test/std/containers/container.adaptors/stack/stack.cons/ctor_default.pass.cpp (+10-1)
  • (modified) libcxx/test/std/containers/container.adaptors/stack/stack.defn/emplace.pass.cpp (+11-1)
  • (modified) libcxx/test/std/containers/container.adaptors/stack/stack.defn/empty.pass.cpp (+11-1)
  • (modified) libcxx/test/std/containers/container.adaptors/stack/stack.defn/pop.pass.cpp (+10-1)
  • (modified) libcxx/test/std/containers/container.adaptors/stack/stack.defn/push.pass.cpp (+10-1)
  • (modified) libcxx/test/std/containers/container.adaptors/stack/stack.defn/push_range.pass.cpp (+11-1)
  • (modified) libcxx/test/std/containers/container.adaptors/stack/stack.defn/push_rv.pass.cpp (+11-1)
  • (modified) libcxx/test/std/containers/container.adaptors/stack/stack.defn/size.pass.cpp (+11-1)
  • (modified) libcxx/test/std/containers/container.adaptors/stack/stack.defn/swap.pass.cpp (+12-2)
  • (modified) libcxx/test/std/containers/container.adaptors/stack/stack.defn/top.pass.cpp (+11-1)
  • (modified) libcxx/test/std/containers/container.adaptors/stack/stack.defn/top_const.pass.cpp (+11-1)
  • (modified) libcxx/test/std/containers/container.adaptors/stack/stack.ops/eq.pass.cpp (+11-2)
  • (modified) libcxx/test/std/containers/container.adaptors/stack/stack.ops/lt.pass.cpp (+11-2)
  • (modified) libcxx/test/std/containers/container.adaptors/stack/stack.special/swap.pass.cpp (+11-2)
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..52910e6458518 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..5c72bea46ea0...
[truncated]

@H-G-Hristov H-G-Hristov force-pushed the hgh/libcxx/P3372R3-constexpr-std_stack branch from 7621483 to bb9e48d Compare October 15, 2025 17:07
Implements `<stack>` as per P3372R3: `constexpr` containers and adaptors
- https://wg21.link/P3372R3

Closes llvm#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 llvm#128656
Part of llvm#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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++26 libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[libc++] P3372R3: constexpr stack

3 participants