[libcxx-commits] [libcxx] [libc++] Implement LWG3133: Modernizing numeric type requirements (PR #208145)

Yordan Vásquez via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jul 9 14:47:00 PDT 2026


https://github.com/vyordan updated https://github.com/llvm/llvm-project/pull/208145

>From e8ec4e380ceab7757af7bcec7e8bb10efe9512ee Mon Sep 17 00:00:00 2001
From: vyordan <vyordangiovani at gmail.com>
Date: Tue, 7 Jul 2026 23:55:36 -0600
Subject: [PATCH] [libc++] Implement LWG3133: Modernizing numeric type
 requirements

Add a static_assert to both std::complex<T> and std::valarray<T>
requiring that T be a cv-unqualified object type that satisfies the
Cpp17DefaultConstructible, Cpp17CopyConstructible, Cpp17CopyAssignable,
and Cpp17Destructible named requirements, per the revised wording in
[numeric.requirements]. This mirrors the existing pattern already used
by std::optional<T>.

Test coverage:
- A .verify.cpp for complex<T> and one for valarray<T>, each covering
  six failure modes: cv-qualified types, and one type violating each
  of the four named requirements individually.
- operator_hijacker-based tests added to valarray's access.pass.cpp
  and const_access.pass.cpp, confirming operator[] does not rely on a
  user-overloadable operator&.

Verified locally: 894/896 tests passing in libcxx/test/std/numerics/
(2 unsupported, 0 failures).

Fixes #100254
---
 libcxx/docs/Status/Cxx20Issues.csv            |  2 +-
 libcxx/include/complex                        | 11 ++++
 libcxx/include/valarray                       | 11 ++++
 ..._requires_cv_unqualified_object.verify.cpp | 63 +++++++++++++++++++
 .../valarray.access/access.pass.cpp           |  6 ++
 .../valarray.access/const_access.pass.cpp     |  6 ++
 ..._requires_cv_unqualified_object.verify.cpp | 62 ++++++++++++++++++
 7 files changed, 160 insertions(+), 1 deletion(-)
 create mode 100644 libcxx/test/std/numerics/complex.number/complex/complex_requires_cv_unqualified_object.verify.cpp
 create mode 100644 libcxx/test/std/numerics/numarray/template.valarray/valarray_requires_cv_unqualified_object.verify.cpp

diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv
index f43a56f99f025..e3845d3e946d3 100644
--- a/libcxx/docs/Status/Cxx20Issues.csv
+++ b/libcxx/docs/Status/Cxx20Issues.csv
@@ -136,7 +136,7 @@
 "`LWG3101 <https://wg21.link/LWG3101>`__","``span``\ 's ``Container``\  constructors need another constraint","2019-02 (Kona)","|Complete|","","`#103837 <https://github.com/llvm/llvm-project/issues/103837>`__",""
 "`LWG3112 <https://wg21.link/LWG3112>`__","``system_error``\  and ``filesystem_error``\  constructors taking a ``string``\  may not be able to meet their postconditions","2019-02 (Kona)","|Nothing To Do|","","`#100253 <https://github.com/llvm/llvm-project/issues/100253>`__",""
 "`LWG3119 <https://wg21.link/LWG3119>`__","Program-definedness of closure types","2019-02 (Kona)","|Nothing To Do|","","`#103838 <https://github.com/llvm/llvm-project/issues/103838>`__",""
-"`LWG3133 <https://wg21.link/LWG3133>`__","Modernizing numeric type requirements","2019-02 (Kona)","","","`#100254 <https://github.com/llvm/llvm-project/issues/100254>`__",""
+"`LWG3133 <https://wg21.link/LWG3133>`__","Modernizing numeric type requirements","2019-02 (Kona)","|Complete|","23","`#100254 <https://github.com/llvm/llvm-project/issues/100254>`__",""
 "`LWG3144 <https://wg21.link/LWG3144>`__","``span``\  does not have a ``const_pointer``\  typedef","2019-02 (Kona)","|Complete|","","`#103839 <https://github.com/llvm/llvm-project/issues/103839>`__",""
 "`LWG3173 <https://wg21.link/LWG3173>`__","Enable CTAD for ``ref-view``\ ","2019-02 (Kona)","|Complete|","15","`#103840 <https://github.com/llvm/llvm-project/issues/103840>`__",""
 "`LWG3179 <https://wg21.link/LWG3179>`__","``subrange``\  should always model ``Range``\ ","2019-02 (Kona)","|Nothing To Do|","","`#103842 <https://github.com/llvm/llvm-project/issues/103842>`__",""
diff --git a/libcxx/include/complex b/libcxx/include/complex
index f1ba85eb9624e..1a2b1bc01ab20 100644
--- a/libcxx/include/complex
+++ b/libcxx/include/complex
@@ -266,6 +266,11 @@ template<class T> complex<T> tanh (const complex<T>&);
 #  include <__tuple/tuple_element.h>
 #  include <__tuple/tuple_size.h>
 #  include <__type_traits/conditional.h>
+#  include <__type_traits/is_assignable.h>
+#  include <__type_traits/is_constructible.h>
+#  include <__type_traits/is_destructible.h>
+#  include <__type_traits/is_object.h>
+#  include <__type_traits/is_unqualified.h>
 #  include <__utility/move.h>
 #  include <cmath>
 #  include <version>
@@ -307,6 +312,12 @@ class complex {
 public:
   typedef _Tp value_type;
 
+  static_assert(is_object<_Tp>::value && __is_unqualified_v<_Tp> && is_default_constructible_v<_Tp> &&
+                    is_copy_constructible_v<_Tp> && is_copy_assignable_v<_Tp> && is_destructible_v<_Tp>,
+                "std::complex<T> requires T to be a cv-unqualified object type that satisfies the "
+                "Cpp17DefaultConstructible, Cpp17CopyConstructible, Cpp17CopyAssignable, and "
+                "Cpp17Destructible requirements");
+
 private:
   value_type __re_;
   value_type __im_;
diff --git a/libcxx/include/valarray b/libcxx/include/valarray
index 37ab9864ac452..22e48da06fc0e 100644
--- a/libcxx/include/valarray
+++ b/libcxx/include/valarray
@@ -361,6 +361,11 @@ template <class T> unspecified2 end(const valarray<T>& v);
 #  include <__memory/allocator.h>
 #  include <__memory/uninitialized_algorithms.h>
 #  include <__type_traits/decay.h>
+#  include <__type_traits/is_assignable.h>
+#  include <__type_traits/is_constructible.h>
+#  include <__type_traits/is_destructible.h>
+#  include <__type_traits/is_object.h>
+#  include <__type_traits/is_unqualified.h>
 #  include <__type_traits/remove_reference.h>
 #  include <__utility/exception_guard.h>
 #  include <__utility/move.h>
@@ -785,6 +790,12 @@ template <class _Tp>
 class valarray {
 public:
   typedef _Tp value_type;
+
+  static_assert(is_object<_Tp>::value && __is_unqualified_v<_Tp> && is_default_constructible_v<_Tp> &&
+                    is_copy_constructible_v<_Tp> && is_copy_assignable_v<_Tp> && is_destructible_v<_Tp>,
+                "std::valarray<T> requires T to be a cv-unqualified object type that satisfies the "
+                "Cpp17DefaultConstructible, Cpp17CopyConstructible, Cpp17CopyAssignable, and "
+                "Cpp17Destructible requirements");
   typedef _Tp __result_type;
 
 private:
diff --git a/libcxx/test/std/numerics/complex.number/complex/complex_requires_cv_unqualified_object.verify.cpp b/libcxx/test/std/numerics/complex.number/complex/complex_requires_cv_unqualified_object.verify.cpp
new file mode 100644
index 0000000000000..81139c99c974f
--- /dev/null
+++ b/libcxx/test/std/numerics/complex.number/complex/complex_requires_cv_unqualified_object.verify.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: FROZEN-CXX03-HEADERS-FIXME
+
+// <complex>
+
+// template<class T>
+// class complex
+//
+// T shall be a cv-unqualified object type (LWG3133)
+
+#include <complex>
+
+struct NotDefaultConstructible {
+  NotDefaultConstructible() = delete;
+};
+
+struct NotCopyConstructible {
+  NotCopyConstructible()                            = default;
+  NotCopyConstructible(const NotCopyConstructible&) = delete;
+};
+
+struct NotCopyAssignable {
+  NotCopyAssignable()                                    = default;
+  NotCopyAssignable(const NotCopyAssignable&)            = default;
+  NotCopyAssignable& operator=(const NotCopyAssignable&) = delete;
+};
+
+struct NotDestructible {
+  NotDestructible()                                  = default;
+  NotDestructible(const NotDestructible&)            = default;
+  NotDestructible& operator=(const NotDestructible&) = default;
+
+private:
+  ~NotDestructible() = default;
+};
+
+void test() {
+  // expected-error-re at complex:* {{static assertion failed{{.*}}std::complex<T> requires T to be a cv-unqualified object type}}
+  (void)sizeof(std::complex<const double>);
+  // expected-error-re at complex:* {{static assertion failed{{.*}}std::complex<T> requires T to be a cv-unqualified object type}}
+  (void)sizeof(std::complex<volatile int>);
+  // expected-error-re at complex:* {{static assertion failed{{.*}}std::complex<T> requires T to be a cv-unqualified object type}}
+  (void)sizeof(std::complex<const volatile float>);
+
+  // expected-error-re at complex:* {{static assertion failed{{.*}}std::complex<T> requires T to be a cv-unqualified object type}}
+  (void)sizeof(std::complex<NotDefaultConstructible>);
+
+  // expected-error-re at complex:* {{static assertion failed{{.*}}std::complex<T> requires T to be a cv-unqualified object type}}
+  (void)sizeof(std::complex<NotCopyConstructible>);
+
+  // expected-error-re at complex:* {{static assertion failed{{.*}}std::complex<T> requires T to be a cv-unqualified object type}}
+  (void)sizeof(std::complex<NotCopyAssignable>);
+
+  // expected-error-re at complex:* {{static assertion failed{{.*}}std::complex<T> requires T to be a cv-unqualified object type}}
+  (void)sizeof(std::complex<NotDestructible>);
+}
diff --git a/libcxx/test/std/numerics/numarray/template.valarray/valarray.access/access.pass.cpp b/libcxx/test/std/numerics/numarray/template.valarray/valarray.access/access.pass.cpp
index 4a72cc73c12fc..c500e86220607 100644
--- a/libcxx/test/std/numerics/numarray/template.valarray/valarray.access/access.pass.cpp
+++ b/libcxx/test/std/numerics/numarray/template.valarray/valarray.access/access.pass.cpp
@@ -15,6 +15,7 @@
 #include <valarray>
 #include <cassert>
 
+#include "operator_hijacker.h"
 #include "test_macros.h"
 
 int main(int, char**)
@@ -31,6 +32,11 @@ int main(int, char**)
             assert(v[i] == static_cast<int>(i));
         }
     }
+    {
+      std::valarray<operator_hijacker> v(1);
+      operator_hijacker& r = v[0];
+      (void)r;
+    }
 
   return 0;
 }
diff --git a/libcxx/test/std/numerics/numarray/template.valarray/valarray.access/const_access.pass.cpp b/libcxx/test/std/numerics/numarray/template.valarray/valarray.access/const_access.pass.cpp
index ef9ac713af474..5970a514975ab 100644
--- a/libcxx/test/std/numerics/numarray/template.valarray/valarray.access/const_access.pass.cpp
+++ b/libcxx/test/std/numerics/numarray/template.valarray/valarray.access/const_access.pass.cpp
@@ -15,6 +15,7 @@
 #include <valarray>
 #include <cassert>
 
+#include "operator_hijacker.h"
 #include "test_macros.h"
 
 int main(int, char**)
@@ -29,6 +30,11 @@ int main(int, char**)
             assert(v[i] == a[i]);
         }
     }
+    {
+      const std::valarray<operator_hijacker> v(1);
+      const operator_hijacker& r = v[0];
+      (void)r;
+    }
 
   return 0;
 }
diff --git a/libcxx/test/std/numerics/numarray/template.valarray/valarray_requires_cv_unqualified_object.verify.cpp b/libcxx/test/std/numerics/numarray/template.valarray/valarray_requires_cv_unqualified_object.verify.cpp
new file mode 100644
index 0000000000000..44c1adc224736
--- /dev/null
+++ b/libcxx/test/std/numerics/numarray/template.valarray/valarray_requires_cv_unqualified_object.verify.cpp
@@ -0,0 +1,62 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: FROZEN-CXX03-HEADERS-FIXME
+
+// <valarray>
+
+// template<class T>
+// class valarray
+//
+// T shall be a cv-unqualified object type that satisfies the Cpp17DefaultConstructible,
+// Cpp17CopyConstructible, Cpp17CopyAssignable, and Cpp17Destructible requirements (LWG3133)
+
+#include <valarray>
+
+struct NotDefaultConstructible {
+  NotDefaultConstructible() = delete;
+};
+
+struct NotCopyConstructible {
+  NotCopyConstructible()                            = default;
+  NotCopyConstructible(const NotCopyConstructible&) = delete;
+};
+
+struct NotCopyAssignable {
+  NotCopyAssignable()                                    = default;
+  NotCopyAssignable(const NotCopyAssignable&)            = default;
+  NotCopyAssignable& operator=(const NotCopyAssignable&) = delete;
+};
+
+struct NotDestructible {
+  NotDestructible()                                  = default;
+  NotDestructible(const NotDestructible&)            = default;
+  NotDestructible& operator=(const NotDestructible&) = default;
+
+private:
+  ~NotDestructible() = default;
+};
+
+void test() {
+  // expected-error-re at valarray:* {{static assertion failed{{.*}}std::valarray<T> requires T to be a cv-unqualified object type}}
+  (void)sizeof(std::valarray<const int>);
+  // expected-error-re at valarray:* {{static assertion failed{{.*}}std::valarray<T> requires T to be a cv-unqualified object type}}
+  (void)sizeof(std::valarray<volatile int>);
+
+  // expected-error-re at valarray:* {{static assertion failed{{.*}}std::valarray<T> requires T to be a cv-unqualified object type}}
+  (void)sizeof(std::valarray<NotDefaultConstructible>);
+
+  // expected-error-re at valarray:* {{static assertion failed{{.*}}std::valarray<T> requires T to be a cv-unqualified object type}}
+  (void)sizeof(std::valarray<NotCopyConstructible>);
+
+  // expected-error-re at valarray:* {{static assertion failed{{.*}}std::valarray<T> requires T to be a cv-unqualified object type}}
+  (void)sizeof(std::valarray<NotCopyAssignable>);
+
+  // expected-error-re at valarray:* {{static assertion failed{{.*}}std::valarray<T> requires T to be a cv-unqualified object type}}
+  (void)sizeof(std::valarray<NotDestructible>);
+}



More information about the libcxx-commits mailing list