[libcxx-commits] [libcxx] 7223bcf - [libc++] [C++20] [P0415] Constexpr for std::complex.

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Sun Jan 8 06:46:58 PST 2023


Author: Marek Kurdej
Date: 2023-01-08T15:46:51+01:00
New Revision: 7223bcf04c4ce3c1585df9408c6a6663cc8364ea

URL: https://github.com/llvm/llvm-project/commit/7223bcf04c4ce3c1585df9408c6a6663cc8364ea
DIFF: https://github.com/llvm/llvm-project/commit/7223bcf04c4ce3c1585df9408c6a6663cc8364ea.diff

LOG: [libc++] [C++20] [P0415] Constexpr for std::complex.

This patch adds constexpr to <complex> header: operators, member operators, and member functions (real, imag, norm, conj).

https://eel.is/c++draft/complex.numbers
https://wg21.link/p0415

Reviewed By: ldionne, #libc

Spies: philnik, danilaml, Quuxplusone, wmaxey, arichardson, libcxx-commits

Differential Revision: https://reviews.llvm.org/D79555

Added: 
    

Modified: 
    libcxx/docs/FeatureTestMacroTable.rst
    libcxx/docs/ReleaseNotes.rst
    libcxx/docs/Status/Cxx20Papers.csv
    libcxx/include/__config
    libcxx/include/cmath
    libcxx/include/complex
    libcxx/include/math.h
    libcxx/include/version
    libcxx/test/std/language.support/support.limits/support.limits.general/complex.version.compile.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
    libcxx/test/std/numerics/complex.number/cases.h
    libcxx/test/std/numerics/complex.number/cmplx.over/conj.pass.cpp
    libcxx/test/std/numerics/complex.number/cmplx.over/norm.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.member.ops/assignment_complex.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.member.ops/assignment_scalar.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.member.ops/divide_equal_complex.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.member.ops/divide_equal_scalar.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.member.ops/minus_equal_complex.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.member.ops/minus_equal_scalar.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.member.ops/plus_equal_complex.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.member.ops/plus_equal_scalar.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.member.ops/times_equal_complex.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.member.ops/times_equal_scalar.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.members/real_imag.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.ops/complex_divide_complex.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.ops/complex_divide_scalar.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.ops/complex_equals_complex.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.ops/complex_equals_scalar.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.ops/complex_minus_complex.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.ops/complex_minus_scalar.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.ops/complex_not_equals_complex.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.ops/complex_not_equals_scalar.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.ops/complex_plus_complex.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.ops/complex_plus_scalar.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.ops/complex_times_complex.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.ops/complex_times_scalar.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.ops/scalar_divide_complex.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.ops/scalar_equals_complex.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.ops/scalar_minus_complex.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.ops/scalar_not_equals_complex.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.ops/scalar_plus_complex.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.ops/scalar_times_complex.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.ops/unary_minus.pass.cpp
    libcxx/test/std/numerics/complex.number/complex.ops/unary_plus.pass.cpp
    libcxx/utils/generate_feature_test_macro_components.py

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index c4ecbd6279924..34e28a31d9e12 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -202,7 +202,7 @@ Status
     ------------------------------------------------- -----------------
     ``__cpp_lib_constexpr_algorithms``                ``201806L``
     ------------------------------------------------- -----------------
-    ``__cpp_lib_constexpr_complex``                   *unimplemented*
+    ``__cpp_lib_constexpr_complex``                   ``201711L``
     ------------------------------------------------- -----------------
     ``__cpp_lib_constexpr_dynamic_alloc``             ``201907L``
     ------------------------------------------------- -----------------

diff  --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst
index ba710c04e1af8..df0646e330157 100644
--- a/libcxx/docs/ReleaseNotes.rst
+++ b/libcxx/docs/ReleaseNotes.rst
@@ -50,6 +50,7 @@ Implemented Papers
 - P0600R1 - ``nodiscard`` in the library
 - P0339R6 - ``polymorphic_allocator<>`` as a vocabulary type
 - P1169R4 - ``static operator()``
+- P0415R1 - ``constexpr`` for ``std::complex``
 
 Improvements and New Features
 -----------------------------

diff  --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv
index 95e3c4cc51493..9ce8af1dea7aa 100644
--- a/libcxx/docs/Status/Cxx20Papers.csv
+++ b/libcxx/docs/Status/Cxx20Papers.csv
@@ -5,7 +5,7 @@
 "`P0020R6 <https://wg21.link/P0020R6>`__","LWG","Floating Point Atomic","Albuquerque","",""
 "`P0053R7 <https://wg21.link/P0053R7>`__","LWG","C++ Synchronized Buffered Ostream","Albuquerque","",""
 "`P0202R3 <https://wg21.link/P0202R3>`__","LWG","Add constexpr modifiers to functions in <algorithm> and <utility> Headers","Albuquerque","|Complete|","12.0"
-"`P0415R1 <https://wg21.link/P0415R1>`__","LWG","Constexpr for ``std::complex``\ ","Albuquerque","|In Progress|","7.0"
+"`P0415R1 <https://wg21.link/P0415R1>`__","LWG","Constexpr for ``std::complex``\ ","Albuquerque","|Complete|","16.0"
 "`P0439R0 <https://wg21.link/P0439R0>`__","LWG","Make ``std::memory_order``\  a scoped enumeration","Albuquerque","|Complete|",""
 "`P0457R2 <https://wg21.link/P0457R2>`__","LWG","String Prefix and Suffix Checking","Albuquerque","|Complete|","6.0"
 "`P0550R2 <https://wg21.link/P0550R2>`__","LWG","Transformation Trait ``remove_cvref``\ ","Albuquerque","|Complete|","6.0"

diff  --git a/libcxx/include/__config b/libcxx/include/__config
index 8f69db2270ba0..9f7aaddc3ad92 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -196,6 +196,10 @@
 #    define __has_cpp_attribute(__x) 0
 #  endif
 
+#  ifndef __has_constexpr_builtin
+#    define __has_constexpr_builtin(x) 0
+#  endif
+
 // '__is_identifier' returns '0' if '__x' is a reserved identifier provided by
 // the compiler and '1' otherwise.
 #  ifndef __is_identifier

diff  --git a/libcxx/include/cmath b/libcxx/include/cmath
index 29eb0fee57ee4..d106f63231729 100644
--- a/libcxx/include/cmath
+++ b/libcxx/include/cmath
@@ -308,6 +308,7 @@ constexpr long double lerp(long double a, long double b, long double t) noexcept
 #include <__config>
 #include <__type_traits/enable_if.h>
 #include <__type_traits/is_arithmetic.h>
+#include <__type_traits/is_constant_evaluated.h>
 #include <__type_traits/is_floating_point.h>
 #include <__type_traits/is_same.h>
 #include <__type_traits/remove_cv.h>
@@ -623,7 +624,162 @@ _LIBCPP_INLINE_VISIBILITY
 _LIBCPP_CONSTEXPR typename enable_if<!is_floating_point<_A1>::value, bool>::type
 __constexpr_isfinite(_A1 __lcpp_x) _NOEXCEPT
 {
-    return std::isfinite(__lcpp_x);
+    return __builtin_isfinite(__lcpp_x);
+}
+
+_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI float __constexpr_copysign(float __x, float __y) _NOEXCEPT {
+    return __builtin_copysignf(__x, __y);
+}
+
+_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI double __constexpr_copysign(double __x, double __y) _NOEXCEPT {
+    return __builtin_copysign(__x, __y);
+}
+
+_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI long double
+__constexpr_copysign(long double __x, long double __y) _NOEXCEPT {
+    return __builtin_copysignl(__x, __y);
+}
+
+template <class _A1, class _A2>
+_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI
+    typename std::__enable_if_t<std::is_arithmetic<_A1>::value && std::is_arithmetic<_A2>::value,
+                                std::__promote<_A1, _A2> >::type
+    __constexpr_copysign(_A1 __x, _A2 __y) _NOEXCEPT {
+    typedef typename std::__promote<_A1, _A2>::type __result_type;
+    static_assert((!(std::_IsSame<_A1, __result_type>::value && std::_IsSame<_A2, __result_type>::value)), "");
+    return __builtin_copysign((__result_type)__x, (__result_type)__y);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR float __constexpr_fabs(float __x) _NOEXCEPT {
+    return __builtin_fabsf(__x);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR double __constexpr_fabs(double __x) _NOEXCEPT {
+    return __builtin_fabs(__x);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR long double __constexpr_fabs(long double __x) _NOEXCEPT {
+    return __builtin_fabsl(__x);
+}
+
+template <class _Tp, __enable_if_t<is_integral<_Tp>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR double __constexpr_fabs(_Tp __x) _NOEXCEPT {
+    return __builtin_fabs(static_cast<double>(__x));
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 float __constexpr_fmax(float __x, float __y) _NOEXCEPT {
+#if !__has_constexpr_builtin(__builtin_fmaxf)
+  if (__libcpp_is_constant_evaluated()) {
+    if (std::__constexpr_isnan(__x))
+      return __y;
+    if (std::__constexpr_isnan(__y))
+      return __x;
+    return __x < __y ? __y : __x;
+  }
+#endif
+  return __builtin_fmaxf(__x, __y);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 double __constexpr_fmax(double __x, double __y) _NOEXCEPT {
+#if !__has_constexpr_builtin(__builtin_fmax)
+  if (__libcpp_is_constant_evaluated()) {
+    if (std::__constexpr_isnan(__x))
+      return __y;
+    if (std::__constexpr_isnan(__y))
+      return __x;
+    return __x < __y ? __y : __x;
+  }
+#endif
+  return __builtin_fmax(__x, __y);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 long double
+__constexpr_fmax(long double __x, long double __y) _NOEXCEPT {
+#if !__has_constexpr_builtin(__builtin_fmaxl)
+  if (__libcpp_is_constant_evaluated()) {
+    if (std::__constexpr_isnan(__x))
+      return __y;
+    if (std::__constexpr_isnan(__y))
+      return __x;
+    return __x < __y ? __y : __x;
+  }
+#endif
+  return __builtin_fmaxl(__x, __y);
+}
+
+template <class _Tp, class _Up, __enable_if_t<is_arithmetic<_Tp>::value && is_arithmetic<_Up>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename __promote<_Tp, _Up>::type
+__constexpr_fmax(_Tp __x, _Up __y) _NOEXCEPT {
+  using __result_type = typename __promote<_Tp, _Up>::type;
+  return std::__constexpr_fmax(static_cast<__result_type>(__x), static_cast<__result_type>(__y));
+}
+
+template <class _Tp>
+_LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __constexpr_logb(_Tp __x) {
+#if !__has_constexpr_builtin(__builtin_logb)
+  if (__libcpp_is_constant_evaluated()) {
+    if (__x == _Tp(0)) {
+      // raise FE_DIVBYZERO
+      return -numeric_limits<_Tp>::infinity();
+    }
+
+    if (std::__constexpr_isinf(__x))
+      return numeric_limits<_Tp>::infinity();
+
+    if (std::__constexpr_isnan(__x))
+      return numeric_limits<_Tp>::quiet_NaN();
+
+    __x = std::__constexpr_fabs(__x);
+    unsigned long long __exp = 0;
+    while (__x >= numeric_limits<_Tp>::radix) {
+      __x /= numeric_limits<_Tp>::radix;
+      __exp += 1;
+    }
+    return _Tp(__exp);
+  }
+#endif // _LIBCPP_STD_VER > 17
+  return __builtin_logb(__x);
+}
+
+template <class _Tp>
+_LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp __constexpr_scalbn(_Tp __x, int __exp) {
+#if !__has_constexpr_builtin(__builtin_scalbln)
+  if (__libcpp_is_constant_evaluated()) {
+    if (__x == _Tp(0))
+      return __x;
+
+    if (std::__constexpr_isinf(__x))
+      return __x;
+
+    if (__exp == _Tp(0))
+      return __x;
+
+    if (std::__constexpr_isnan(__x))
+      return numeric_limits<_Tp>::quiet_NaN();
+
+    _Tp __mult(1);
+    if (__exp > 0) {
+      __mult = numeric_limits<_Tp>::radix;
+      --__exp;
+    } else {
+      ++__exp;
+      __exp = -__exp;
+      __mult /= numeric_limits<_Tp>::radix;
+    }
+
+    while (__exp > 0) {
+      if (!(__exp & 1)) {
+        __mult *= __mult;
+        __exp >>= 1;
+      } else {
+        __x *= __mult;
+        --__exp;
+      }
+    }
+    return __x;
+  }
+#endif // _LIBCPP_STD_VER > 17
+  return __builtin_scalbn(__x, __exp);
 }
 
 #if _LIBCPP_STD_VER > 17

diff  --git a/libcxx/include/complex b/libcxx/include/complex
index 1117dda257a34..760fbaa81128e 100644
--- a/libcxx/include/complex
+++ b/libcxx/include/complex
@@ -29,21 +29,21 @@ public:
     T real() const; // constexpr in C++14
     T imag() const; // constexpr in C++14
 
-    void real(T);
-    void imag(T);
-
-    complex<T>& operator= (const T&);
-    complex<T>& operator+=(const T&);
-    complex<T>& operator-=(const T&);
-    complex<T>& operator*=(const T&);
-    complex<T>& operator/=(const T&);
-
-    complex& operator=(const complex&);
-    template<class X> complex<T>& operator= (const complex<X>&);
-    template<class X> complex<T>& operator+=(const complex<X>&);
-    template<class X> complex<T>& operator-=(const complex<X>&);
-    template<class X> complex<T>& operator*=(const complex<X>&);
-    template<class X> complex<T>& operator/=(const complex<X>&);
+    void real(T); // constexpr in C++20
+    void imag(T); // constexpr in C++20
+
+    complex<T>& operator= (const T&); // constexpr in C++20
+    complex<T>& operator+=(const T&); // constexpr in C++20
+    complex<T>& operator-=(const T&); // constexpr in C++20
+    complex<T>& operator*=(const T&); // constexpr in C++20
+    complex<T>& operator/=(const T&); // constexpr in C++20
+
+    complex& operator=(const complex&); // constexpr in C++20
+    template<class X> complex<T>& operator= (const complex<X>&); // constexpr in C++20
+    template<class X> complex<T>& operator+=(const complex<X>&); // constexpr in C++20
+    template<class X> complex<T>& operator-=(const complex<X>&); // constexpr in C++20
+    template<class X> complex<T>& operator*=(const complex<X>&); // constexpr in C++20
+    template<class X> complex<T>& operator/=(const complex<X>&); // constexpr in C++20
 };
 
 template<>
@@ -57,22 +57,22 @@ public:
     explicit constexpr complex(const complex<long double>&);
 
     constexpr float real() const;
-    void real(float);
+    void real(float); // constexpr in C++20
     constexpr float imag() const;
-    void imag(float);
-
-    complex<float>& operator= (float);
-    complex<float>& operator+=(float);
-    complex<float>& operator-=(float);
-    complex<float>& operator*=(float);
-    complex<float>& operator/=(float);
-
-    complex<float>& operator=(const complex<float>&);
-    template<class X> complex<float>& operator= (const complex<X>&);
-    template<class X> complex<float>& operator+=(const complex<X>&);
-    template<class X> complex<float>& operator-=(const complex<X>&);
-    template<class X> complex<float>& operator*=(const complex<X>&);
-    template<class X> complex<float>& operator/=(const complex<X>&);
+    void imag(float); // constexpr in C++20
+
+    complex<float>& operator= (float); // constexpr in C++20
+    complex<float>& operator+=(float); // constexpr in C++20
+    complex<float>& operator-=(float); // constexpr in C++20
+    complex<float>& operator*=(float); // constexpr in C++20
+    complex<float>& operator/=(float); // constexpr in C++20
+
+    complex<float>& operator=(const complex<float>&); // constexpr in C++20
+    template<class X> complex<float>& operator= (const complex<X>&); // constexpr in C++20
+    template<class X> complex<float>& operator+=(const complex<X>&); // constexpr in C++20
+    template<class X> complex<float>& operator-=(const complex<X>&); // constexpr in C++20
+    template<class X> complex<float>& operator*=(const complex<X>&); // constexpr in C++20
+    template<class X> complex<float>& operator/=(const complex<X>&); // constexpr in C++20
 };
 
 template<>
@@ -86,22 +86,22 @@ public:
     explicit constexpr complex(const complex<long double>&);
 
     constexpr double real() const;
-    void real(double);
+    void real(double); // constexpr in C++20
     constexpr double imag() const;
-    void imag(double);
-
-    complex<double>& operator= (double);
-    complex<double>& operator+=(double);
-    complex<double>& operator-=(double);
-    complex<double>& operator*=(double);
-    complex<double>& operator/=(double);
-    complex<double>& operator=(const complex<double>&);
-
-    template<class X> complex<double>& operator= (const complex<X>&);
-    template<class X> complex<double>& operator+=(const complex<X>&);
-    template<class X> complex<double>& operator-=(const complex<X>&);
-    template<class X> complex<double>& operator*=(const complex<X>&);
-    template<class X> complex<double>& operator/=(const complex<X>&);
+    void imag(double); // constexpr in C++20
+
+    complex<double>& operator= (double); // constexpr in C++20
+    complex<double>& operator+=(double); // constexpr in C++20
+    complex<double>& operator-=(double); // constexpr in C++20
+    complex<double>& operator*=(double); // constexpr in C++20
+    complex<double>& operator/=(double); // constexpr in C++20
+    complex<double>& operator=(const complex<double>&); // constexpr in C++20
+
+    template<class X> complex<double>& operator= (const complex<X>&); // constexpr in C++20
+    template<class X> complex<double>& operator+=(const complex<X>&); // constexpr in C++20
+    template<class X> complex<double>& operator-=(const complex<X>&); // constexpr in C++20
+    template<class X> complex<double>& operator*=(const complex<X>&); // constexpr in C++20
+    template<class X> complex<double>& operator/=(const complex<X>&); // constexpr in C++20
 };
 
 template<>
@@ -115,39 +115,39 @@ public:
     constexpr complex(const complex<double>&);
 
     constexpr long double real() const;
-    void real(long double);
+    void real(long double); // constexpr in C++20
     constexpr long double imag() const;
-    void imag(long double);
-
-    complex<long double>& operator=(const complex<long double>&);
-    complex<long double>& operator= (long double);
-    complex<long double>& operator+=(long double);
-    complex<long double>& operator-=(long double);
-    complex<long double>& operator*=(long double);
-    complex<long double>& operator/=(long double);
-
-    template<class X> complex<long double>& operator= (const complex<X>&);
-    template<class X> complex<long double>& operator+=(const complex<X>&);
-    template<class X> complex<long double>& operator-=(const complex<X>&);
-    template<class X> complex<long double>& operator*=(const complex<X>&);
-    template<class X> complex<long double>& operator/=(const complex<X>&);
+    void imag(long double); // constexpr in C++20
+
+    complex<long double>& operator=(const complex<long double>&); // constexpr in C++20
+    complex<long double>& operator= (long double); // constexpr in C++20
+    complex<long double>& operator+=(long double); // constexpr in C++20
+    complex<long double>& operator-=(long double); // constexpr in C++20
+    complex<long double>& operator*=(long double); // constexpr in C++20
+    complex<long double>& operator/=(long double); // constexpr in C++20
+
+    template<class X> complex<long double>& operator= (const complex<X>&); // constexpr in C++20
+    template<class X> complex<long double>& operator+=(const complex<X>&); // constexpr in C++20
+    template<class X> complex<long double>& operator-=(const complex<X>&); // constexpr in C++20
+    template<class X> complex<long double>& operator*=(const complex<X>&); // constexpr in C++20
+    template<class X> complex<long double>& operator/=(const complex<X>&); // constexpr in C++20
 };
 
 // 26.3.6 operators:
-template<class T> complex<T> operator+(const complex<T>&, const complex<T>&);
-template<class T> complex<T> operator+(const complex<T>&, const T&);
-template<class T> complex<T> operator+(const T&, const complex<T>&);
-template<class T> complex<T> operator-(const complex<T>&, const complex<T>&);
-template<class T> complex<T> operator-(const complex<T>&, const T&);
-template<class T> complex<T> operator-(const T&, const complex<T>&);
-template<class T> complex<T> operator*(const complex<T>&, const complex<T>&);
-template<class T> complex<T> operator*(const complex<T>&, const T&);
-template<class T> complex<T> operator*(const T&, const complex<T>&);
-template<class T> complex<T> operator/(const complex<T>&, const complex<T>&);
-template<class T> complex<T> operator/(const complex<T>&, const T&);
-template<class T> complex<T> operator/(const T&, const complex<T>&);
-template<class T> complex<T> operator+(const complex<T>&);
-template<class T> complex<T> operator-(const complex<T>&);
+template<class T> complex<T> operator+(const complex<T>&, const complex<T>&); // constexpr in C++20
+template<class T> complex<T> operator+(const complex<T>&, const T&);          // constexpr in C++20
+template<class T> complex<T> operator+(const T&, const complex<T>&);          // constexpr in C++20
+template<class T> complex<T> operator-(const complex<T>&, const complex<T>&); // constexpr in C++20
+template<class T> complex<T> operator-(const complex<T>&, const T&);          // constexpr in C++20
+template<class T> complex<T> operator-(const T&, const complex<T>&);          // constexpr in C++20
+template<class T> complex<T> operator*(const complex<T>&, const complex<T>&); // constexpr in C++20
+template<class T> complex<T> operator*(const complex<T>&, const T&);          // constexpr in C++20
+template<class T> complex<T> operator*(const T&, const complex<T>&);          // constexpr in C++20
+template<class T> complex<T> operator/(const complex<T>&, const complex<T>&); // constexpr in C++20
+template<class T> complex<T> operator/(const complex<T>&, const T&);          // constexpr in C++20
+template<class T> complex<T> operator/(const T&, const complex<T>&);          // constexpr in C++20
+template<class T> complex<T> operator+(const complex<T>&);                    // constexpr in C++20
+template<class T> complex<T> operator-(const complex<T>&);                    // constexpr in C++20
 template<class T> bool operator==(const complex<T>&, const complex<T>&); // constexpr in C++14
 template<class T> bool operator==(const complex<T>&, const T&); // constexpr in C++14
 template<class T> bool operator==(const T&, const complex<T>&); // constexpr in C++14
@@ -184,17 +184,17 @@ template<class T>              T arg(const complex<T>&);
 template<Integral T>      double arg(T);
                           float  arg(float);
 
-template<class T>              T norm(const complex<T>&);
-                     long double norm(long double);
-                          double norm(double);
-template<Integral T>      double norm(T);
-                          float  norm(float);
+template<class T>              T norm(const complex<T>&); // constexpr in C++20
+                     long double norm(long double);       // constexpr in C++20
+                          double norm(double);            // constexpr in C++20
+template<Integral T>      double norm(T);                 // constexpr in C++20
+                          float  norm(float);             // constexpr in C++20
 
-template<class T>      complex<T>           conj(const complex<T>&);
-                       complex<long double> conj(long double);
-                       complex<double>      conj(double);
-template<Integral T>   complex<double>      conj(T);
-                       complex<float>       conj(float);
+template<class T>      complex<T>           conj(const complex<T>&); // constexpr in C++20
+                       complex<long double> conj(long double);       // constexpr in C++20
+                       complex<double>      conj(double);            // constexpr in C++20
+template<Integral T>   complex<double>      conj(T);                 // constexpr in C++20
+                       complex<float>       conj(float);             // constexpr in C++20
 
 template<class T>    complex<T>           proj(const complex<T>&);
                      complex<long double> proj(long double);
@@ -251,8 +251,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 template<class _Tp> class _LIBCPP_TEMPLATE_VIS complex;
 
-template<class _Tp> _LIBCPP_HIDE_FROM_ABI complex<_Tp> operator*(const complex<_Tp>& __z, const complex<_Tp>& __w);
-template<class _Tp> _LIBCPP_HIDE_FROM_ABI complex<_Tp> operator/(const complex<_Tp>& __x, const complex<_Tp>& __y);
+template<class _Tp> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator*(const complex<_Tp>& __z, const complex<_Tp>& __w);
+template<class _Tp> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator/(const complex<_Tp>& __x, const complex<_Tp>& __y);
 
 template<class _Tp>
 class _LIBCPP_TEMPLATE_VIS complex
@@ -273,40 +273,40 @@ public:
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14 value_type real() const {return __re_;}
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14 value_type imag() const {return __im_;}
 
-    _LIBCPP_INLINE_VISIBILITY void real(value_type __re) {__re_ = __re;}
-    _LIBCPP_INLINE_VISIBILITY void imag(value_type __im) {__im_ = __im;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 void real(value_type __re) {__re_ = __re;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 void imag(value_type __im) {__im_ = __im;}
 
-    _LIBCPP_INLINE_VISIBILITY complex& operator= (const value_type& __re)
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator= (const value_type& __re)
         {__re_ = __re; __im_ = value_type(); return *this;}
-    _LIBCPP_INLINE_VISIBILITY complex& operator+=(const value_type& __re) {__re_ += __re; return *this;}
-    _LIBCPP_INLINE_VISIBILITY complex& operator-=(const value_type& __re) {__re_ -= __re; return *this;}
-    _LIBCPP_INLINE_VISIBILITY complex& operator*=(const value_type& __re) {__re_ *= __re; __im_ *= __re; return *this;}
-    _LIBCPP_INLINE_VISIBILITY complex& operator/=(const value_type& __re) {__re_ /= __re; __im_ /= __re; return *this;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator+=(const value_type& __re) {__re_ += __re; return *this;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator-=(const value_type& __re) {__re_ -= __re; return *this;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator*=(const value_type& __re) {__re_ *= __re; __im_ *= __re; return *this;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator/=(const value_type& __re) {__re_ /= __re; __im_ /= __re; return *this;}
 
-    template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator= (const complex<_Xp>& __c)
+    template<class _Xp> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator= (const complex<_Xp>& __c)
         {
             __re_ = __c.real();
             __im_ = __c.imag();
             return *this;
         }
-    template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator+=(const complex<_Xp>& __c)
+    template<class _Xp> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator+=(const complex<_Xp>& __c)
         {
             __re_ += __c.real();
             __im_ += __c.imag();
             return *this;
         }
-    template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator-=(const complex<_Xp>& __c)
+    template<class _Xp> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator-=(const complex<_Xp>& __c)
         {
             __re_ -= __c.real();
             __im_ -= __c.imag();
             return *this;
         }
-    template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator*=(const complex<_Xp>& __c)
+    template<class _Xp> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator*=(const complex<_Xp>& __c)
         {
             *this = *this * complex(__c.real(), __c.imag());
             return *this;
         }
-    template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator/=(const complex<_Xp>& __c)
+    template<class _Xp> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator/=(const complex<_Xp>& __c)
         {
             *this = *this / complex(__c.real(), __c.imag());
             return *this;
@@ -334,40 +334,40 @@ public:
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR float real() const {return __re_;}
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR float imag() const {return __im_;}
 
-    _LIBCPP_INLINE_VISIBILITY void real(value_type __re) {__re_ = __re;}
-    _LIBCPP_INLINE_VISIBILITY void imag(value_type __im) {__im_ = __im;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 void real(value_type __re) {__re_ = __re;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 void imag(value_type __im) {__im_ = __im;}
 
-    _LIBCPP_INLINE_VISIBILITY complex& operator= (float __re)
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator= (float __re)
         {__re_ = __re; __im_ = value_type(); return *this;}
-    _LIBCPP_INLINE_VISIBILITY complex& operator+=(float __re) {__re_ += __re; return *this;}
-    _LIBCPP_INLINE_VISIBILITY complex& operator-=(float __re) {__re_ -= __re; return *this;}
-    _LIBCPP_INLINE_VISIBILITY complex& operator*=(float __re) {__re_ *= __re; __im_ *= __re; return *this;}
-    _LIBCPP_INLINE_VISIBILITY complex& operator/=(float __re) {__re_ /= __re; __im_ /= __re; return *this;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator+=(float __re) {__re_ += __re; return *this;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator-=(float __re) {__re_ -= __re; return *this;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator*=(float __re) {__re_ *= __re; __im_ *= __re; return *this;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator/=(float __re) {__re_ /= __re; __im_ /= __re; return *this;}
 
-    template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator= (const complex<_Xp>& __c)
+    template<class _Xp> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator= (const complex<_Xp>& __c)
         {
             __re_ = __c.real();
             __im_ = __c.imag();
             return *this;
         }
-    template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator+=(const complex<_Xp>& __c)
+    template<class _Xp> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator+=(const complex<_Xp>& __c)
         {
             __re_ += __c.real();
             __im_ += __c.imag();
             return *this;
         }
-    template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator-=(const complex<_Xp>& __c)
+    template<class _Xp> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator-=(const complex<_Xp>& __c)
         {
             __re_ -= __c.real();
             __im_ -= __c.imag();
             return *this;
         }
-    template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator*=(const complex<_Xp>& __c)
+    template<class _Xp> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator*=(const complex<_Xp>& __c)
         {
             *this = *this * complex(__c.real(), __c.imag());
             return *this;
         }
-    template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator/=(const complex<_Xp>& __c)
+    template<class _Xp> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator/=(const complex<_Xp>& __c)
         {
             *this = *this / complex(__c.real(), __c.imag());
             return *this;
@@ -392,40 +392,40 @@ public:
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR double real() const {return __re_;}
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR double imag() const {return __im_;}
 
-    _LIBCPP_INLINE_VISIBILITY void real(value_type __re) {__re_ = __re;}
-    _LIBCPP_INLINE_VISIBILITY void imag(value_type __im) {__im_ = __im;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 void real(value_type __re) {__re_ = __re;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 void imag(value_type __im) {__im_ = __im;}
 
-    _LIBCPP_INLINE_VISIBILITY complex& operator= (double __re)
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator= (double __re)
         {__re_ = __re; __im_ = value_type(); return *this;}
-    _LIBCPP_INLINE_VISIBILITY complex& operator+=(double __re) {__re_ += __re; return *this;}
-    _LIBCPP_INLINE_VISIBILITY complex& operator-=(double __re) {__re_ -= __re; return *this;}
-    _LIBCPP_INLINE_VISIBILITY complex& operator*=(double __re) {__re_ *= __re; __im_ *= __re; return *this;}
-    _LIBCPP_INLINE_VISIBILITY complex& operator/=(double __re) {__re_ /= __re; __im_ /= __re; return *this;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator+=(double __re) {__re_ += __re; return *this;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator-=(double __re) {__re_ -= __re; return *this;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator*=(double __re) {__re_ *= __re; __im_ *= __re; return *this;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator/=(double __re) {__re_ /= __re; __im_ /= __re; return *this;}
 
-    template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator= (const complex<_Xp>& __c)
+    template<class _Xp> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator= (const complex<_Xp>& __c)
         {
             __re_ = __c.real();
             __im_ = __c.imag();
             return *this;
         }
-    template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator+=(const complex<_Xp>& __c)
+    template<class _Xp> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator+=(const complex<_Xp>& __c)
         {
             __re_ += __c.real();
             __im_ += __c.imag();
             return *this;
         }
-    template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator-=(const complex<_Xp>& __c)
+    template<class _Xp> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator-=(const complex<_Xp>& __c)
         {
             __re_ -= __c.real();
             __im_ -= __c.imag();
             return *this;
         }
-    template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator*=(const complex<_Xp>& __c)
+    template<class _Xp> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator*=(const complex<_Xp>& __c)
         {
             *this = *this * complex(__c.real(), __c.imag());
             return *this;
         }
-    template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator/=(const complex<_Xp>& __c)
+    template<class _Xp> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator/=(const complex<_Xp>& __c)
         {
             *this = *this / complex(__c.real(), __c.imag());
             return *this;
@@ -450,40 +450,40 @@ public:
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR long double real() const {return __re_;}
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR long double imag() const {return __im_;}
 
-    _LIBCPP_INLINE_VISIBILITY void real(value_type __re) {__re_ = __re;}
-    _LIBCPP_INLINE_VISIBILITY void imag(value_type __im) {__im_ = __im;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 void real(value_type __re) {__re_ = __re;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 void imag(value_type __im) {__im_ = __im;}
 
-    _LIBCPP_INLINE_VISIBILITY complex& operator= (long double __re)
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator= (long double __re)
         {__re_ = __re; __im_ = value_type(); return *this;}
-    _LIBCPP_INLINE_VISIBILITY complex& operator+=(long double __re) {__re_ += __re; return *this;}
-    _LIBCPP_INLINE_VISIBILITY complex& operator-=(long double __re) {__re_ -= __re; return *this;}
-    _LIBCPP_INLINE_VISIBILITY complex& operator*=(long double __re) {__re_ *= __re; __im_ *= __re; return *this;}
-    _LIBCPP_INLINE_VISIBILITY complex& operator/=(long double __re) {__re_ /= __re; __im_ /= __re; return *this;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator+=(long double __re) {__re_ += __re; return *this;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator-=(long double __re) {__re_ -= __re; return *this;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator*=(long double __re) {__re_ *= __re; __im_ *= __re; return *this;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator/=(long double __re) {__re_ /= __re; __im_ /= __re; return *this;}
 
-    template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator= (const complex<_Xp>& __c)
+    template<class _Xp> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator= (const complex<_Xp>& __c)
         {
             __re_ = __c.real();
             __im_ = __c.imag();
             return *this;
         }
-    template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator+=(const complex<_Xp>& __c)
+    template<class _Xp> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator+=(const complex<_Xp>& __c)
         {
             __re_ += __c.real();
             __im_ += __c.imag();
             return *this;
         }
-    template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator-=(const complex<_Xp>& __c)
+    template<class _Xp> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator-=(const complex<_Xp>& __c)
         {
             __re_ -= __c.real();
             __im_ -= __c.imag();
             return *this;
         }
-    template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator*=(const complex<_Xp>& __c)
+    template<class _Xp> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator*=(const complex<_Xp>& __c)
         {
             *this = *this * complex(__c.real(), __c.imag());
             return *this;
         }
-    template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator/=(const complex<_Xp>& __c)
+    template<class _Xp> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator/=(const complex<_Xp>& __c)
         {
             *this = *this / complex(__c.real(), __c.imag());
             return *this;
@@ -523,7 +523,7 @@ complex<long double>::complex(const complex<double>& __c)
 // 26.3.6 operators:
 
 template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
 complex<_Tp>
 operator+(const complex<_Tp>& __x, const complex<_Tp>& __y)
 {
@@ -533,7 +533,7 @@ operator+(const complex<_Tp>& __x, const complex<_Tp>& __y)
 }
 
 template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
 complex<_Tp>
 operator+(const complex<_Tp>& __x, const _Tp& __y)
 {
@@ -543,7 +543,7 @@ operator+(const complex<_Tp>& __x, const _Tp& __y)
 }
 
 template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
 complex<_Tp>
 operator+(const _Tp& __x, const complex<_Tp>& __y)
 {
@@ -553,7 +553,7 @@ operator+(const _Tp& __x, const complex<_Tp>& __y)
 }
 
 template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
 complex<_Tp>
 operator-(const complex<_Tp>& __x, const complex<_Tp>& __y)
 {
@@ -563,7 +563,7 @@ operator-(const complex<_Tp>& __x, const complex<_Tp>& __y)
 }
 
 template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
 complex<_Tp>
 operator-(const complex<_Tp>& __x, const _Tp& __y)
 {
@@ -573,7 +573,7 @@ operator-(const complex<_Tp>& __x, const _Tp& __y)
 }
 
 template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
 complex<_Tp>
 operator-(const _Tp& __x, const complex<_Tp>& __y)
 {
@@ -583,13 +583,46 @@ operator-(const _Tp& __x, const complex<_Tp>& __y)
 }
 
 template<class _Tp>
-_LIBCPP_HIDE_FROM_ABI complex<_Tp>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp>
 operator*(const complex<_Tp>& __z, const complex<_Tp>& __w)
 {
     _Tp __a = __z.real();
     _Tp __b = __z.imag();
     _Tp __c = __w.real();
     _Tp __d = __w.imag();
+
+    // Avoid floating point operations that are invalid during constant evaluation
+    if (__libcpp_is_constant_evaluated()) {
+        bool __z_zero = __a == _Tp(0) && __b == _Tp(0);
+        bool __w_zero = __c == _Tp(0) && __d == _Tp(0);
+        bool __z_inf = std::__constexpr_isinf(__a) || std::__constexpr_isinf(__b);
+        bool __w_inf = std::__constexpr_isinf(__c) || std::__constexpr_isinf(__d);
+        bool __z_nan = !__z_inf && (
+            (std::__constexpr_isnan(__a) && std::__constexpr_isnan(__b))
+            || (std::__constexpr_isnan(__a) && __b == _Tp(0))
+            || (__a == _Tp(0) && std::__constexpr_isnan(__b))
+        );
+        bool __w_nan = !__w_inf && (
+            (std::__constexpr_isnan(__c) && std::__constexpr_isnan(__d))
+            || (std::__constexpr_isnan(__c) && __d == _Tp(0))
+            || (__c == _Tp(0) && std::__constexpr_isnan(__d))
+        );
+        if (__z_nan || __w_nan) {
+            return complex<_Tp>(_Tp(numeric_limits<_Tp>::quiet_NaN()), _Tp(0));
+        }
+        if (__z_inf || __w_inf) {
+            if (__z_zero || __w_zero) {
+                return complex<_Tp>(_Tp(numeric_limits<_Tp>::quiet_NaN()), _Tp(0));
+            }
+            return complex<_Tp>(_Tp(numeric_limits<_Tp>::infinity()), _Tp(numeric_limits<_Tp>::infinity()));
+        }
+        bool __z_nonzero_nan = !__z_inf && !__z_nan && (std::__constexpr_isnan(__a) || std::__constexpr_isnan(__b));
+        bool __w_nonzero_nan = !__w_inf && !__w_nan && (std::__constexpr_isnan(__c) || std::__constexpr_isnan(__d));
+        if (__z_nonzero_nan || __w_nonzero_nan) {
+            return complex<_Tp>(_Tp(numeric_limits<_Tp>::quiet_NaN()), _Tp(0));
+        }
+    }
+
     _Tp __ac = __a * __c;
     _Tp __bd = __b * __d;
     _Tp __ad = __a * __d;
@@ -601,35 +634,35 @@ operator*(const complex<_Tp>& __z, const complex<_Tp>& __w)
         bool __recalc = false;
         if (std::__constexpr_isinf(__a) || std::__constexpr_isinf(__b))
         {
-            __a = std::copysign(std::__constexpr_isinf(__a) ? _Tp(1) : _Tp(0), __a);
-            __b = std::copysign(std::__constexpr_isinf(__b) ? _Tp(1) : _Tp(0), __b);
+            __a = std::__constexpr_copysign(std::__constexpr_isinf(__a) ? _Tp(1) : _Tp(0), __a);
+            __b = std::__constexpr_copysign(std::__constexpr_isinf(__b) ? _Tp(1) : _Tp(0), __b);
             if (std::__constexpr_isnan(__c))
-                __c = std::copysign(_Tp(0), __c);
+                __c = std::__constexpr_copysign(_Tp(0), __c);
             if (std::__constexpr_isnan(__d))
-                __d = std::copysign(_Tp(0), __d);
+                __d = std::__constexpr_copysign(_Tp(0), __d);
             __recalc = true;
         }
         if (std::__constexpr_isinf(__c) || std::__constexpr_isinf(__d))
         {
-            __c = std::copysign(std::__constexpr_isinf(__c) ? _Tp(1) : _Tp(0), __c);
-            __d = std::copysign(std::__constexpr_isinf(__d) ? _Tp(1) : _Tp(0), __d);
+            __c = std::__constexpr_copysign(std::__constexpr_isinf(__c) ? _Tp(1) : _Tp(0), __c);
+            __d = std::__constexpr_copysign(std::__constexpr_isinf(__d) ? _Tp(1) : _Tp(0), __d);
             if (std::__constexpr_isnan(__a))
-                __a = std::copysign(_Tp(0), __a);
+                __a = std::__constexpr_copysign(_Tp(0), __a);
             if (std::__constexpr_isnan(__b))
-                __b = std::copysign(_Tp(0), __b);
+                __b = std::__constexpr_copysign(_Tp(0), __b);
             __recalc = true;
         }
         if (!__recalc && (std::__constexpr_isinf(__ac) || std::__constexpr_isinf(__bd) ||
                           std::__constexpr_isinf(__ad) || std::__constexpr_isinf(__bc)))
         {
             if (std::__constexpr_isnan(__a))
-                __a = std::copysign(_Tp(0), __a);
+                __a = std::__constexpr_copysign(_Tp(0), __a);
             if (std::__constexpr_isnan(__b))
-                __b = std::copysign(_Tp(0), __b);
+                __b = std::__constexpr_copysign(_Tp(0), __b);
             if (std::__constexpr_isnan(__c))
-                __c = std::copysign(_Tp(0), __c);
+                __c = std::__constexpr_copysign(_Tp(0), __c);
             if (std::__constexpr_isnan(__d))
-                __d = std::copysign(_Tp(0), __d);
+                __d = std::__constexpr_copysign(_Tp(0), __d);
             __recalc = true;
         }
         if (__recalc)
@@ -642,7 +675,7 @@ operator*(const complex<_Tp>& __z, const complex<_Tp>& __w)
 }
 
 template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
 complex<_Tp>
 operator*(const complex<_Tp>& __x, const _Tp& __y)
 {
@@ -652,7 +685,7 @@ operator*(const complex<_Tp>& __x, const _Tp& __y)
 }
 
 template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
 complex<_Tp>
 operator*(const _Tp& __x, const complex<_Tp>& __y)
 {
@@ -662,7 +695,7 @@ operator*(const _Tp& __x, const complex<_Tp>& __y)
 }
 
 template<class _Tp>
-_LIBCPP_HIDE_FROM_ABI complex<_Tp>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp>
 operator/(const complex<_Tp>& __z, const complex<_Tp>& __w)
 {
     int __ilogbw = 0;
@@ -670,34 +703,74 @@ operator/(const complex<_Tp>& __z, const complex<_Tp>& __w)
     _Tp __b = __z.imag();
     _Tp __c = __w.real();
     _Tp __d = __w.imag();
-    _Tp __logbw = std::logb(std::fmax(std::fabs(__c), std::fabs(__d)));
+    _Tp __logbw = std::__constexpr_logb(std::__constexpr_fmax(std::__constexpr_fabs(__c), std::__constexpr_fabs(__d)));
     if (std::__constexpr_isfinite(__logbw))
     {
         __ilogbw = static_cast<int>(__logbw);
-        __c = std::scalbn(__c, -__ilogbw);
-        __d = std::scalbn(__d, -__ilogbw);
+        __c = std::__constexpr_scalbn(__c, -__ilogbw);
+        __d = std::__constexpr_scalbn(__d, -__ilogbw);
     }
+
+    // Avoid floating point operations that are invalid during constant evaluation
+    if (__libcpp_is_constant_evaluated()) {
+        bool __z_zero = __a == _Tp(0) && __b == _Tp(0);
+        bool __w_zero = __c == _Tp(0) && __d == _Tp(0);
+        bool __z_inf = std::__constexpr_isinf(__a) || std::__constexpr_isinf(__b);
+        bool __w_inf = std::__constexpr_isinf(__c) || std::__constexpr_isinf(__d);
+        bool __z_nan = !__z_inf && (
+            (std::__constexpr_isnan(__a) && std::__constexpr_isnan(__b))
+            || (std::__constexpr_isnan(__a) && __b == _Tp(0))
+            || (__a == _Tp(0) && std::__constexpr_isnan(__b))
+        );
+        bool __w_nan = !__w_inf && (
+            (std::__constexpr_isnan(__c) && std::__constexpr_isnan(__d))
+            || (std::__constexpr_isnan(__c) && __d == _Tp(0))
+            || (__c == _Tp(0) && std::__constexpr_isnan(__d))
+        );
+        if ((__z_nan || __w_nan) || (__z_inf && __w_inf)) {
+            return complex<_Tp>(_Tp(numeric_limits<_Tp>::quiet_NaN()), _Tp(0));
+        }
+        bool __z_nonzero_nan = !__z_inf && !__z_nan && (std::__constexpr_isnan(__a) || std::__constexpr_isnan(__b));
+        bool __w_nonzero_nan = !__w_inf && !__w_nan && (std::__constexpr_isnan(__c) || std::__constexpr_isnan(__d));
+        if (__z_nonzero_nan || __w_nonzero_nan) {
+            if (__w_zero) {
+                return complex<_Tp>(_Tp(numeric_limits<_Tp>::infinity()), _Tp(numeric_limits<_Tp>::infinity()));
+            }
+            return complex<_Tp>(_Tp(numeric_limits<_Tp>::quiet_NaN()), _Tp(0));
+        }
+        if (__w_inf) {
+            return complex<_Tp>(_Tp(0), _Tp(0));
+        }
+        if (__z_inf) {
+            return complex<_Tp>(_Tp(numeric_limits<_Tp>::infinity()), _Tp(numeric_limits<_Tp>::infinity()));
+        }
+        if (__w_zero) {
+            if (__z_zero) {
+                return complex<_Tp>(_Tp(numeric_limits<_Tp>::quiet_NaN()), _Tp(0));
+            }
+            return complex<_Tp>(_Tp(numeric_limits<_Tp>::infinity()), _Tp(numeric_limits<_Tp>::infinity()));
+        }
+    }
+
     _Tp __denom = __c * __c + __d * __d;
-    _Tp __x = std::scalbn((__a * __c + __b * __d) / __denom, -__ilogbw);
-    _Tp __y = std::scalbn((__b * __c - __a * __d) / __denom, -__ilogbw);
+    _Tp __x = std::__constexpr_scalbn((__a * __c + __b * __d) / __denom, -__ilogbw);
+    _Tp __y = std::__constexpr_scalbn((__b * __c - __a * __d) / __denom, -__ilogbw);
     if (std::__constexpr_isnan(__x) && std::__constexpr_isnan(__y))
     {
         if ((__denom == _Tp(0)) && (!std::__constexpr_isnan(__a) || !std::__constexpr_isnan(__b)))
         {
-            __x = std::copysign(_Tp(INFINITY), __c) * __a;
-            __y = std::copysign(_Tp(INFINITY), __c) * __b;
-        }
-        else if ((std::__constexpr_isinf(__a) || std::__constexpr_isinf(__b)) && std::__constexpr_isfinite(__c) && std::__constexpr_isfinite(__d))
-        {
-            __a = std::copysign(std::__constexpr_isinf(__a) ? _Tp(1) : _Tp(0), __a);
-            __b = std::copysign(std::__constexpr_isinf(__b) ? _Tp(1) : _Tp(0), __b);
+            __x = std::__constexpr_copysign(_Tp(INFINITY), __c) * __a;
+            __y = std::__constexpr_copysign(_Tp(INFINITY), __c) * __b;
+        } else if ((std::__constexpr_isinf(__a) || std::__constexpr_isinf(__b)) && std::__constexpr_isfinite(__c) &&
+                   std::__constexpr_isfinite(__d)) {
+            __a = std::__constexpr_copysign(std::__constexpr_isinf(__a) ? _Tp(1) : _Tp(0), __a);
+            __b = std::__constexpr_copysign(std::__constexpr_isinf(__b) ? _Tp(1) : _Tp(0), __b);
             __x = _Tp(INFINITY) * (__a * __c + __b * __d);
             __y = _Tp(INFINITY) * (__b * __c - __a * __d);
-        }
-        else if (std::__constexpr_isinf(__logbw) && __logbw > _Tp(0) && std::__constexpr_isfinite(__a) && std::__constexpr_isfinite(__b))
-        {
-            __c = std::copysign(std::__constexpr_isinf(__c) ? _Tp(1) : _Tp(0), __c);
-            __d = std::copysign(std::__constexpr_isinf(__d) ? _Tp(1) : _Tp(0), __d);
+        } else if (std::__constexpr_isinf(__logbw) && __logbw > _Tp(0) && std::__constexpr_isfinite(__a) &&
+                   std::__constexpr_isfinite(__b)) {
+            __c = std::__constexpr_copysign(std::__constexpr_isinf(__c) ? _Tp(1) : _Tp(0), __c);
+            __d = std::__constexpr_copysign(std::__constexpr_isinf(__d) ? _Tp(1) : _Tp(0), __d);
             __x = _Tp(0) * (__a * __c + __b * __d);
             __y = _Tp(0) * (__b * __c - __a * __d);
         }
@@ -706,7 +779,7 @@ operator/(const complex<_Tp>& __z, const complex<_Tp>& __w)
 }
 
 template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
 complex<_Tp>
 operator/(const complex<_Tp>& __x, const _Tp& __y)
 {
@@ -714,7 +787,7 @@ operator/(const complex<_Tp>& __x, const _Tp& __y)
 }
 
 template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
 complex<_Tp>
 operator/(const _Tp& __x, const complex<_Tp>& __y)
 {
@@ -724,7 +797,7 @@ operator/(const _Tp& __x, const complex<_Tp>& __y)
 }
 
 template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
 complex<_Tp>
 operator+(const complex<_Tp>& __x)
 {
@@ -732,7 +805,7 @@ operator+(const complex<_Tp>& __x)
 }
 
 template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
 complex<_Tp>
 operator-(const complex<_Tp>& __x)
 {
@@ -903,7 +976,7 @@ arg(_Tp __re)
 // norm
 
 template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
 _Tp
 norm(const complex<_Tp>& __c)
 {
@@ -915,7 +988,7 @@ norm(const complex<_Tp>& __c)
 }
 
 template <class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
 typename __libcpp_complex_overload_traits<_Tp>::_ValueType
 norm(_Tp __re)
 {
@@ -926,7 +999,7 @@ norm(_Tp __re)
 // conj
 
 template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
 complex<_Tp>
 conj(const complex<_Tp>& __c)
 {
@@ -934,7 +1007,7 @@ conj(const complex<_Tp>& __c)
 }
 
 template <class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
 typename __libcpp_complex_overload_traits<_Tp>::_ComplexType
 conj(_Tp __re)
 {

diff  --git a/libcxx/include/math.h b/libcxx/include/math.h
index 14fa9e286ea30..1636ec4b7050e 100644
--- a/libcxx/include/math.h
+++ b/libcxx/include/math.h
@@ -1043,43 +1043,12 @@ cbrt(_A1 __x) _NOEXCEPT {return __builtin_cbrt((double)__x);}
 
 // copysign
 
-_LIBCPP_CONSTEXPR
-inline _LIBCPP_HIDE_FROM_ABI float __libcpp_copysign(float __x, float __y) _NOEXCEPT {
-  return __builtin_copysignf(__x, __y);
-}
-
-_LIBCPP_CONSTEXPR
-inline _LIBCPP_HIDE_FROM_ABI double __libcpp_copysign(double __x, double __y) _NOEXCEPT {
-  return __builtin_copysign(__x, __y);
-}
-
-_LIBCPP_CONSTEXPR
-inline _LIBCPP_HIDE_FROM_ABI long double __libcpp_copysign(long double __x, long double __y) _NOEXCEPT {
-  return __builtin_copysignl(__x, __y);
-}
-
-template <class _A1, class _A2>
-_LIBCPP_CONSTEXPR
-inline _LIBCPP_HIDE_FROM_ABI
-typename std::__enable_if_t
-<
-    std::is_arithmetic<_A1>::value &&
-    std::is_arithmetic<_A2>::value,
-    std::__promote<_A1, _A2>
->::type
-__libcpp_copysign(_A1 __x, _A2 __y) _NOEXCEPT {
-    typedef typename std::__promote<_A1, _A2>::type __result_type;
-    static_assert((!(std::_IsSame<_A1, __result_type>::value &&
-                     std::_IsSame<_A2, __result_type>::value)), "");
-    return __builtin_copysign((__result_type)__x, (__result_type)__y);
-}
-
 inline _LIBCPP_HIDE_FROM_ABI float copysign(float __x, float __y) _NOEXCEPT {
-  return ::__libcpp_copysign(__x, __y);
+  return ::__builtin_copysignf(__x, __y);
 }
 
 inline _LIBCPP_HIDE_FROM_ABI long double copysign(long double __x, long double __y) _NOEXCEPT {
-  return ::__libcpp_copysign(__x, __y);
+  return ::__builtin_copysignl(__x, __y);
 }
 
 template <class _A1, class _A2>
@@ -1091,7 +1060,7 @@ typename std::__enable_if_t
     std::__promote<_A1, _A2>
 >::type
     copysign(_A1 __x, _A2 __y) _NOEXCEPT {
-  return ::__libcpp_copysign(__x, __y);
+  return ::__builtin_copysign(__x, __y);
 }
 
 // erf

diff  --git a/libcxx/include/version b/libcxx/include/version
index ae4e14f337284..d348325d1bf50 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -317,7 +317,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 # endif
 # define __cpp_lib_concepts                             202002L
 # define __cpp_lib_constexpr_algorithms                 201806L
-// # define __cpp_lib_constexpr_complex                    201711L
+# define __cpp_lib_constexpr_complex                    201711L
 # define __cpp_lib_constexpr_dynamic_alloc              201907L
 # define __cpp_lib_constexpr_functional                 201907L
 # define __cpp_lib_constexpr_iterator                   201811L

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/complex.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/complex.version.compile.pass.cpp
index 527805f7c36b7..1ee022b94cc56 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/complex.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/complex.version.compile.pass.cpp
@@ -68,17 +68,11 @@
 #   error "__cpp_lib_complex_udls should have the value 201309L in c++20"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_constexpr_complex
-#     error "__cpp_lib_constexpr_complex should be defined in c++20"
-#   endif
-#   if __cpp_lib_constexpr_complex != 201711L
-#     error "__cpp_lib_constexpr_complex should have the value 201711L in c++20"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_constexpr_complex
-#     error "__cpp_lib_constexpr_complex should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_constexpr_complex
+#   error "__cpp_lib_constexpr_complex should be defined in c++20"
+# endif
+# if __cpp_lib_constexpr_complex != 201711L
+#   error "__cpp_lib_constexpr_complex should have the value 201711L in c++20"
 # endif
 
 #elif TEST_STD_VER > 20
@@ -90,17 +84,11 @@
 #   error "__cpp_lib_complex_udls should have the value 201309L in c++2b"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_constexpr_complex
-#     error "__cpp_lib_constexpr_complex should be defined in c++2b"
-#   endif
-#   if __cpp_lib_constexpr_complex != 201711L
-#     error "__cpp_lib_constexpr_complex should have the value 201711L in c++2b"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_constexpr_complex
-#     error "__cpp_lib_constexpr_complex should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_constexpr_complex
+#   error "__cpp_lib_constexpr_complex should be defined in c++2b"
+# endif
+# if __cpp_lib_constexpr_complex != 201711L
+#   error "__cpp_lib_constexpr_complex should have the value 201711L in c++2b"
 # endif
 
 #endif // TEST_STD_VER > 20

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 9026cd120bbd3..9af0226b0e5e4 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -2705,17 +2705,11 @@
 #   error "__cpp_lib_constexpr_cmath should not be defined before c++2b"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_constexpr_complex
-#     error "__cpp_lib_constexpr_complex should be defined in c++20"
-#   endif
-#   if __cpp_lib_constexpr_complex != 201711L
-#     error "__cpp_lib_constexpr_complex should have the value 201711L in c++20"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_constexpr_complex
-#     error "__cpp_lib_constexpr_complex should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_constexpr_complex
+#   error "__cpp_lib_constexpr_complex should be defined in c++20"
+# endif
+# if __cpp_lib_constexpr_complex != 201711L
+#   error "__cpp_lib_constexpr_complex should have the value 201711L in c++20"
 # endif
 
 # ifndef __cpp_lib_constexpr_dynamic_alloc
@@ -3931,17 +3925,11 @@
 #   endif
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_constexpr_complex
-#     error "__cpp_lib_constexpr_complex should be defined in c++2b"
-#   endif
-#   if __cpp_lib_constexpr_complex != 201711L
-#     error "__cpp_lib_constexpr_complex should have the value 201711L in c++2b"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_constexpr_complex
-#     error "__cpp_lib_constexpr_complex should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_constexpr_complex
+#   error "__cpp_lib_constexpr_complex should be defined in c++2b"
+# endif
+# if __cpp_lib_constexpr_complex != 201711L
+#   error "__cpp_lib_constexpr_complex should have the value 201711L in c++2b"
 # endif
 
 # ifndef __cpp_lib_constexpr_dynamic_alloc

diff  --git a/libcxx/test/std/numerics/complex.number/cases.h b/libcxx/test/std/numerics/complex.number/cases.h
index ccab643879cd2..b360e1423ff57 100644
--- a/libcxx/test/std/numerics/complex.number/cases.h
+++ b/libcxx/test/std/numerics/complex.number/cases.h
@@ -13,10 +13,13 @@
 #ifndef CASES_H
 #define CASES_H
 
-#include <complex>
 #include <cassert>
+#include <complex>
+#include <type_traits>
+
+#include "test_macros.h"
 
-const std::complex<double> testcases[] =
+TEST_CONSTEXPR_CXX20 const std::complex<double> testcases[] =
 {
     std::complex<double>( 1.e-6,  1.e-6),
     std::complex<double>(-1.e-6,  1.e-6),
@@ -56,32 +59,32 @@ const std::complex<double> testcases[] =
     std::complex<double>( 1.e+6,  0),
     std::complex<double>(-1.e+6,  0),
 
-    std::complex<double>(NAN, NAN),
-    std::complex<double>(-INFINITY, NAN),
-    std::complex<double>(-2, NAN),
-    std::complex<double>(-1, NAN),
-    std::complex<double>(-0.5, NAN),
-    std::complex<double>(-0., NAN),
-    std::complex<double>(+0., NAN),
-    std::complex<double>(0.5, NAN),
-    std::complex<double>(1, NAN),
-    std::complex<double>(2, NAN),
-    std::complex<double>(INFINITY, NAN),
-
-    std::complex<double>(NAN, -INFINITY),
-    std::complex<double>(-INFINITY, -INFINITY),
-    std::complex<double>(-2, -INFINITY),
-    std::complex<double>(-1, -INFINITY),
-    std::complex<double>(-0.5, -INFINITY),
-    std::complex<double>(-0., -INFINITY),
-    std::complex<double>(+0., -INFINITY),
-    std::complex<double>(0.5, -INFINITY),
-    std::complex<double>(1, -INFINITY),
-    std::complex<double>(2, -INFINITY),
-    std::complex<double>(INFINITY, -INFINITY),
-
-    std::complex<double>(NAN, -2),
-    std::complex<double>(-INFINITY, -2),
+    std::complex<double>(std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()),
+    std::complex<double>(-std::numeric_limits<double>::infinity(), std::numeric_limits<double>::quiet_NaN()),
+    std::complex<double>(-2, std::numeric_limits<double>::quiet_NaN()),
+    std::complex<double>(-1, std::numeric_limits<double>::quiet_NaN()),
+    std::complex<double>(-0.5, std::numeric_limits<double>::quiet_NaN()),
+    std::complex<double>(-0., std::numeric_limits<double>::quiet_NaN()),
+    std::complex<double>(+0., std::numeric_limits<double>::quiet_NaN()),
+    std::complex<double>(0.5, std::numeric_limits<double>::quiet_NaN()),
+    std::complex<double>(1, std::numeric_limits<double>::quiet_NaN()),
+    std::complex<double>(2, std::numeric_limits<double>::quiet_NaN()),
+    std::complex<double>(std::numeric_limits<double>::infinity(), std::numeric_limits<double>::quiet_NaN()),
+
+    std::complex<double>(std::numeric_limits<double>::quiet_NaN(), -std::numeric_limits<double>::infinity()),
+    std::complex<double>(-std::numeric_limits<double>::infinity(), -std::numeric_limits<double>::infinity()),
+    std::complex<double>(-2, -std::numeric_limits<double>::infinity()),
+    std::complex<double>(-1, -std::numeric_limits<double>::infinity()),
+    std::complex<double>(-0.5, -std::numeric_limits<double>::infinity()),
+    std::complex<double>(-0., -std::numeric_limits<double>::infinity()),
+    std::complex<double>(+0., -std::numeric_limits<double>::infinity()),
+    std::complex<double>(0.5, -std::numeric_limits<double>::infinity()),
+    std::complex<double>(1, -std::numeric_limits<double>::infinity()),
+    std::complex<double>(2, -std::numeric_limits<double>::infinity()),
+    std::complex<double>(std::numeric_limits<double>::infinity(), -std::numeric_limits<double>::infinity()),
+
+    std::complex<double>(std::numeric_limits<double>::quiet_NaN(), -2),
+    std::complex<double>(-std::numeric_limits<double>::infinity(), -2),
     std::complex<double>(-2, -2),
     std::complex<double>(-1, -2),
     std::complex<double>(-0.5, -2),
@@ -90,10 +93,10 @@ const std::complex<double> testcases[] =
     std::complex<double>(0.5, -2),
     std::complex<double>(1, -2),
     std::complex<double>(2, -2),
-    std::complex<double>(INFINITY, -2),
+    std::complex<double>(std::numeric_limits<double>::infinity(), -2),
 
-    std::complex<double>(NAN, -1),
-    std::complex<double>(-INFINITY, -1),
+    std::complex<double>(std::numeric_limits<double>::quiet_NaN(), -1),
+    std::complex<double>(-std::numeric_limits<double>::infinity(), -1),
     std::complex<double>(-2, -1),
     std::complex<double>(-1, -1),
     std::complex<double>(-0.5, -1),
@@ -102,10 +105,10 @@ const std::complex<double> testcases[] =
     std::complex<double>(0.5, -1),
     std::complex<double>(1, -1),
     std::complex<double>(2, -1),
-    std::complex<double>(INFINITY, -1),
+    std::complex<double>(std::numeric_limits<double>::infinity(), -1),
 
-    std::complex<double>(NAN, -0.5),
-    std::complex<double>(-INFINITY, -0.5),
+    std::complex<double>(std::numeric_limits<double>::quiet_NaN(), -0.5),
+    std::complex<double>(-std::numeric_limits<double>::infinity(), -0.5),
     std::complex<double>(-2, -0.5),
     std::complex<double>(-1, -0.5),
     std::complex<double>(-0.5, -0.5),
@@ -114,10 +117,10 @@ const std::complex<double> testcases[] =
     std::complex<double>(0.5, -0.5),
     std::complex<double>(1, -0.5),
     std::complex<double>(2, -0.5),
-    std::complex<double>(INFINITY, -0.5),
+    std::complex<double>(std::numeric_limits<double>::infinity(), -0.5),
 
-    std::complex<double>(NAN, -0.),
-    std::complex<double>(-INFINITY, -0.),
+    std::complex<double>(std::numeric_limits<double>::quiet_NaN(), -0.),
+    std::complex<double>(-std::numeric_limits<double>::infinity(), -0.),
     std::complex<double>(-2, -0.),
     std::complex<double>(-1, -0.),
     std::complex<double>(-0.5, -0.),
@@ -126,10 +129,10 @@ const std::complex<double> testcases[] =
     std::complex<double>(0.5, -0.),
     std::complex<double>(1, -0.),
     std::complex<double>(2, -0.),
-    std::complex<double>(INFINITY, -0.),
+    std::complex<double>(std::numeric_limits<double>::infinity(), -0.),
 
-    std::complex<double>(NAN, +0.),
-    std::complex<double>(-INFINITY, +0.),
+    std::complex<double>(std::numeric_limits<double>::quiet_NaN(), +0.),
+    std::complex<double>(-std::numeric_limits<double>::infinity(), +0.),
     std::complex<double>(-2, +0.),
     std::complex<double>(-1, +0.),
     std::complex<double>(-0.5, +0.),
@@ -138,10 +141,10 @@ const std::complex<double> testcases[] =
     std::complex<double>(0.5, +0.),
     std::complex<double>(1, +0.),
     std::complex<double>(2, +0.),
-    std::complex<double>(INFINITY, +0.),
+    std::complex<double>(std::numeric_limits<double>::infinity(), +0.),
 
-    std::complex<double>(NAN, 0.5),
-    std::complex<double>(-INFINITY, 0.5),
+    std::complex<double>(std::numeric_limits<double>::quiet_NaN(), 0.5),
+    std::complex<double>(-std::numeric_limits<double>::infinity(), 0.5),
     std::complex<double>(-2, 0.5),
     std::complex<double>(-1, 0.5),
     std::complex<double>(-0.5, 0.5),
@@ -150,10 +153,10 @@ const std::complex<double> testcases[] =
     std::complex<double>(0.5, 0.5),
     std::complex<double>(1, 0.5),
     std::complex<double>(2, 0.5),
-    std::complex<double>(INFINITY, 0.5),
+    std::complex<double>(std::numeric_limits<double>::infinity(), 0.5),
 
-    std::complex<double>(NAN, 1),
-    std::complex<double>(-INFINITY, 1),
+    std::complex<double>(std::numeric_limits<double>::quiet_NaN(), 1),
+    std::complex<double>(-std::numeric_limits<double>::infinity(), 1),
     std::complex<double>(-2, 1),
     std::complex<double>(-1, 1),
     std::complex<double>(-0.5, 1),
@@ -162,10 +165,10 @@ const std::complex<double> testcases[] =
     std::complex<double>(0.5, 1),
     std::complex<double>(1, 1),
     std::complex<double>(2, 1),
-    std::complex<double>(INFINITY, 1),
+    std::complex<double>(std::numeric_limits<double>::infinity(), 1),
 
-    std::complex<double>(NAN, 2),
-    std::complex<double>(-INFINITY, 2),
+    std::complex<double>(std::numeric_limits<double>::quiet_NaN(), 2),
+    std::complex<double>(-std::numeric_limits<double>::infinity(), 2),
     std::complex<double>(-2, 2),
     std::complex<double>(-1, 2),
     std::complex<double>(-0.5, 2),
@@ -174,40 +177,51 @@ const std::complex<double> testcases[] =
     std::complex<double>(0.5, 2),
     std::complex<double>(1, 2),
     std::complex<double>(2, 2),
-    std::complex<double>(INFINITY, 2),
-
-    std::complex<double>(NAN, INFINITY),
-    std::complex<double>(-INFINITY, INFINITY),
-    std::complex<double>(-2, INFINITY),
-    std::complex<double>(-1, INFINITY),
-    std::complex<double>(-0.5, INFINITY),
-    std::complex<double>(-0., INFINITY),
-    std::complex<double>(+0., INFINITY),
-    std::complex<double>(0.5, INFINITY),
-    std::complex<double>(1, INFINITY),
-    std::complex<double>(2, INFINITY),
-    std::complex<double>(INFINITY, INFINITY)
+    std::complex<double>(std::numeric_limits<double>::infinity(), 2),
+
+    std::complex<double>(std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::infinity()),
+    std::complex<double>(-std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity()),
+    std::complex<double>(-2, std::numeric_limits<double>::infinity()),
+    std::complex<double>(-1, std::numeric_limits<double>::infinity()),
+    std::complex<double>(-0.5, std::numeric_limits<double>::infinity()),
+    std::complex<double>(-0., std::numeric_limits<double>::infinity()),
+    std::complex<double>(+0., std::numeric_limits<double>::infinity()),
+    std::complex<double>(0.5, std::numeric_limits<double>::infinity()),
+    std::complex<double>(1, std::numeric_limits<double>::infinity()),
+    std::complex<double>(2, std::numeric_limits<double>::infinity()),
+    std::complex<double>(std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity())
 };
 
 enum {zero, non_zero, inf, NaN, non_zero_nan};
 
+template <class T, typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
+TEST_CONSTEXPR_CXX20 bool test_isinf(T v) {
+    return v == std::numeric_limits<T>::infinity() || v == -std::numeric_limits<T>::infinity();
+}
+
+template <class T, typename std::enable_if<std::is_arithmetic<T>::value, int>::type = 0>
+TEST_CONSTEXPR_CXX20 bool test_isnan(T v) {
+    return v != v;
+}
+
 template <class T>
+TEST_CONSTEXPR_CXX20
 int
 classify(const std::complex<T>& x)
 {
     if (x == std::complex<T>())
         return zero;
-    if (std::isinf(x.real()) || std::isinf(x.imag()))
+    if (test_isinf(x.real()) || test_isinf(x.imag()))
         return inf;
-    if (std::isnan(x.real()) && std::isnan(x.imag()))
+    if (test_isnan(x.real()) && test_isnan(x.imag()))
         return NaN;
-    if (std::isnan(x.real()))
+    if (test_isnan(x.real()))
     {
         if (x.imag() == T(0))
             return NaN;
         return non_zero_nan;
     }
-    if (std::isnan(x.imag()))
+    if (test_isnan(x.imag()))
     {
         if (x.real() == T(0))
             return NaN;

diff  --git a/libcxx/test/std/numerics/complex.number/cmplx.over/conj.pass.cpp b/libcxx/test/std/numerics/complex.number/cmplx.over/conj.pass.cpp
index 3367620aaf3be..553ead653bbf5 100644
--- a/libcxx/test/std/numerics/complex.number/cmplx.over/conj.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/cmplx.over/conj.pass.cpp
@@ -8,11 +8,11 @@
 
 // <complex>
 
-// template<class T>      complex<T>           conj(const complex<T>&);
-//                        complex<long double> conj(long double);
-//                        complex<double>      conj(double);
-// template<Integral T>   complex<double>      conj(T);
-//                        complex<float>       conj(float);
+// template<class T>      complex<T>           conj(const complex<T>&); // constexpr in C++20
+//                        complex<long double> conj(long double);       // constexpr in C++20
+//                        complex<double>      conj(double);            // constexpr in C++20
+// template<Integral T>   complex<double>      conj(T);                 // constexpr in C++20
+//                        complex<float>       conj(float);             // constexpr in C++20
 
 #include <complex>
 #include <type_traits>
@@ -22,6 +22,7 @@
 #include "../cases.h"
 
 template <class T>
+TEST_CONSTEXPR_CXX20
 void
 test(T x, typename std::enable_if<std::is_integral<T>::value>::type* = 0)
 {
@@ -30,6 +31,7 @@ test(T x, typename std::enable_if<std::is_integral<T>::value>::type* = 0)
 }
 
 template <class T>
+TEST_CONSTEXPR_CXX20
 void
 test(T x, typename std::enable_if<std::is_floating_point<T>::value>::type* = 0)
 {
@@ -38,6 +40,7 @@ test(T x, typename std::enable_if<std::is_floating_point<T>::value>::type* = 0)
 }
 
 template <class T>
+TEST_CONSTEXPR_CXX20
 void
 test(T x, typename std::enable_if<!std::is_integral<T>::value &&
                                   !std::is_floating_point<T>::value>::type* = 0)
@@ -47,12 +50,14 @@ test(T x, typename std::enable_if<!std::is_integral<T>::value &&
 }
 
 template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     test<T>(0);
     test<T>(1);
     test<T>(10);
+    return true;
 }
 
 int main(int, char**)
@@ -64,5 +69,14 @@ int main(int, char**)
     test<unsigned>();
     test<long long>();
 
-  return 0;
+#if TEST_STD_VER >= 20
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+    static_assert(test<int>());
+    static_assert(test<unsigned>());
+    static_assert(test<long long>());
+#endif
+
+    return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/cmplx.over/norm.pass.cpp b/libcxx/test/std/numerics/complex.number/cmplx.over/norm.pass.cpp
index 8dc6daa93fc5f..c56123a78e27f 100644
--- a/libcxx/test/std/numerics/complex.number/cmplx.over/norm.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/cmplx.over/norm.pass.cpp
@@ -10,7 +10,7 @@
 
 // template<Arithmetic T>
 //   T
-//   norm(T x);
+//   norm(T x); // constexpr in C++20
 
 #include <complex>
 #include <type_traits>
@@ -20,6 +20,7 @@
 #include "../cases.h"
 
 template <class T>
+TEST_CONSTEXPR_CXX20
 void
 test(T x, typename std::enable_if<std::is_integral<T>::value>::type* = 0)
 {
@@ -28,6 +29,7 @@ test(T x, typename std::enable_if<std::is_integral<T>::value>::type* = 0)
 }
 
 template <class T>
+TEST_CONSTEXPR_CXX20
 void
 test(T x, typename std::enable_if<!std::is_integral<T>::value>::type* = 0)
 {
@@ -36,12 +38,14 @@ test(T x, typename std::enable_if<!std::is_integral<T>::value>::type* = 0)
 }
 
 template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     test<T>(0);
     test<T>(1);
     test<T>(10);
+    return true;
 }
 
 int main(int, char**)
@@ -53,5 +57,14 @@ int main(int, char**)
     test<unsigned>();
     test<long long>();
 
-  return 0;
+#if TEST_STD_VER >= 20
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+    static_assert(test<int>());
+    static_assert(test<unsigned>());
+    static_assert(test<long long>());
+#endif
+
+    return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.member.ops/assignment_complex.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.member.ops/assignment_complex.pass.cpp
index e6522c0628cbf..1d0e868e789a8 100644
--- a/libcxx/test/std/numerics/complex.number/complex.member.ops/assignment_complex.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.member.ops/assignment_complex.pass.cpp
@@ -9,7 +9,7 @@
 // <complex>
 
 // complex& operator=(const complex&);
-// template<class X> complex& operator= (const complex<X>&);
+// template<class X> complex& operator= (const complex<X>&); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -17,7 +17,8 @@
 #include "test_macros.h"
 
 template <class T, class X>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     std::complex<T> c;
@@ -31,6 +32,7 @@ test()
     c = c3;
     assert(c.real() == 3.5);
     assert(c.imag() == -4.5);
+    return true;
 }
 
 int main(int, char**)
@@ -47,5 +49,19 @@ int main(int, char**)
     test<long double, double>();
     test<long double, long double>();
 
+#if TEST_STD_VER >= 20
+    static_assert(test<float, float>());
+    static_assert(test<float, double>());
+    static_assert(test<float, long double>());
+
+    static_assert(test<double, float>());
+    static_assert(test<double, double>());
+    static_assert(test<double, long double>());
+
+    static_assert(test<long double, float>());
+    static_assert(test<long double, double>());
+    static_assert(test<long double, long double>());
+#endif
+
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.member.ops/assignment_scalar.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.member.ops/assignment_scalar.pass.cpp
index 176c3c7591c3d..6a8c73948e33c 100644
--- a/libcxx/test/std/numerics/complex.number/complex.member.ops/assignment_scalar.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.member.ops/assignment_scalar.pass.cpp
@@ -8,7 +8,7 @@
 
 // <complex>
 
-// complex& operator= (const T&);
+// complex& operator= (const T&); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -16,7 +16,8 @@
 #include "test_macros.h"
 
 template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     std::complex<T> c;
@@ -28,6 +29,7 @@ test()
     c = -1.5;
     assert(c.real() == -1.5);
     assert(c.imag() == 0);
+    return true;
 }
 
 int main(int, char**)
@@ -36,5 +38,11 @@ int main(int, char**)
     test<double>();
     test<long double>();
 
+#if TEST_STD_VER >= 20
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
+
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.member.ops/divide_equal_complex.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.member.ops/divide_equal_complex.pass.cpp
index 989177b25bff9..af2561e4cb9e9 100644
--- a/libcxx/test/std/numerics/complex.number/complex.member.ops/divide_equal_complex.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.member.ops/divide_equal_complex.pass.cpp
@@ -8,7 +8,7 @@
 
 // <complex>
 
-// complex& operator/=(const complex& rhs);
+// complex& operator/=(const complex& rhs); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -16,7 +16,8 @@
 #include "test_macros.h"
 
 template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     std::complex<T> c(-4, 7.5);
@@ -35,15 +36,15 @@ test()
     c3 = c;
     std::complex<int> ic (1,1);
     c3 /= ic;
-    assert(c3.real() ==  0.5);
+    assert(c3.real() == 0.5);
     assert(c3.imag() == -0.5);
 
     c3 = c;
     std::complex<float> fc (1,1);
     c3 /= fc;
-    assert(c3.real() ==  0.5);
+    assert(c3.real() == 0.5);
     assert(c3.imag() == -0.5);
-
+    return true;
 }
 
 int main(int, char**)
@@ -52,5 +53,11 @@ int main(int, char**)
     test<double>();
     test<long double>();
 
-  return 0;
+#if TEST_STD_VER >= 20
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
+
+    return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.member.ops/divide_equal_scalar.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.member.ops/divide_equal_scalar.pass.cpp
index 100cd34f1064c..9251fb4f1bfeb 100644
--- a/libcxx/test/std/numerics/complex.number/complex.member.ops/divide_equal_scalar.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.member.ops/divide_equal_scalar.pass.cpp
@@ -8,7 +8,7 @@
 
 // <complex>
 
-// complex& operator/=(const T& rhs);
+// complex& operator/=(const T& rhs); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -16,7 +16,8 @@
 #include "test_macros.h"
 
 template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     std::complex<T> c(1);
@@ -35,6 +36,7 @@ test()
     c /= 0.5;
     assert(c.real() == -16);
     assert(c.imag() == 4);
+    return true;
 }
 
 int main(int, char**)
@@ -43,5 +45,11 @@ int main(int, char**)
     test<double>();
     test<long double>();
 
+#if TEST_STD_VER >= 20
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
+
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.member.ops/minus_equal_complex.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.member.ops/minus_equal_complex.pass.cpp
index b47793d09f0a5..c801a700e05ae 100644
--- a/libcxx/test/std/numerics/complex.number/complex.member.ops/minus_equal_complex.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.member.ops/minus_equal_complex.pass.cpp
@@ -8,7 +8,7 @@
 
 // <complex>
 
-// complex& operator-=(const complex& rhs);
+// complex& operator-=(const complex& rhs); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -16,7 +16,8 @@
 #include "test_macros.h"
 
 template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     std::complex<T> c;
@@ -43,6 +44,7 @@ test()
     c3 -= fc;
     assert(c3.real() == -4);
     assert(c3.imag() == -6);
+    return true;
 }
 
 int main(int, char**)
@@ -51,5 +53,11 @@ int main(int, char**)
     test<double>();
     test<long double>();
 
-  return 0;
+#if TEST_STD_VER >= 20
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
+
+    return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.member.ops/minus_equal_scalar.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.member.ops/minus_equal_scalar.pass.cpp
index 6fccd8bcb9fe5..b9b240cefea74 100644
--- a/libcxx/test/std/numerics/complex.number/complex.member.ops/minus_equal_scalar.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.member.ops/minus_equal_scalar.pass.cpp
@@ -8,7 +8,7 @@
 
 // <complex>
 
-// complex& operator-=(const T& rhs);
+// complex& operator-=(const T& rhs); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -16,7 +16,8 @@
 #include "test_macros.h"
 
 template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     std::complex<T> c;
@@ -31,6 +32,7 @@ test()
     c -= -1.5;
     assert(c.real() == -1.5);
     assert(c.imag() == 0);
+    return true;
 }
 
 int main(int, char**)
@@ -39,5 +41,11 @@ int main(int, char**)
     test<double>();
     test<long double>();
 
+#if TEST_STD_VER >= 20
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
+
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.member.ops/plus_equal_complex.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.member.ops/plus_equal_complex.pass.cpp
index 43357a80d6234..6ceb56b66ea2c 100644
--- a/libcxx/test/std/numerics/complex.number/complex.member.ops/plus_equal_complex.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.member.ops/plus_equal_complex.pass.cpp
@@ -8,7 +8,7 @@
 
 // <complex>
 
-// complex& operator+=(const complex& rhs);
+// complex& operator+=(const complex& rhs); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -16,7 +16,8 @@
 #include "test_macros.h"
 
 template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     std::complex<T> c;
@@ -43,6 +44,7 @@ test()
     c3 += fc;
     assert(c3.real() == 4);
     assert(c3.imag() == 6);
+    return true;
 }
 
 int main(int, char**)
@@ -51,5 +53,11 @@ int main(int, char**)
     test<double>();
     test<long double>();
 
-  return 0;
+#if TEST_STD_VER >= 20
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
+
+    return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.member.ops/plus_equal_scalar.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.member.ops/plus_equal_scalar.pass.cpp
index 78bf371eeb28d..fab151d0946da 100644
--- a/libcxx/test/std/numerics/complex.number/complex.member.ops/plus_equal_scalar.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.member.ops/plus_equal_scalar.pass.cpp
@@ -8,7 +8,7 @@
 
 // <complex>
 
-// complex& operator+=(const T& rhs);
+// complex& operator+=(const T& rhs); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -16,7 +16,8 @@
 #include "test_macros.h"
 
 template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     std::complex<T> c;
@@ -31,6 +32,7 @@ test()
     c += -1.5;
     assert(c.real() == 1.5);
     assert(c.imag() == 0);
+    return true;
 }
 
 int main(int, char**)
@@ -39,5 +41,11 @@ int main(int, char**)
     test<double>();
     test<long double>();
 
+#if TEST_STD_VER >= 20
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
+
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.member.ops/times_equal_complex.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.member.ops/times_equal_complex.pass.cpp
index aabe9229cb52a..65492857db55e 100644
--- a/libcxx/test/std/numerics/complex.number/complex.member.ops/times_equal_complex.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.member.ops/times_equal_complex.pass.cpp
@@ -8,7 +8,7 @@
 
 // <complex>
 
-// complex& operator*=(const complex& rhs);
+// complex& operator*=(const complex& rhs); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -16,7 +16,8 @@
 #include "test_macros.h"
 
 template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     std::complex<T> c(1);
@@ -36,13 +37,14 @@ test()
     std::complex<int> ic (1,1);
     c3 *= ic;
     assert(c3.real() == -11.5);
-    assert(c3.imag() ==   3.5);
+    assert(c3.imag() == 3.5);
 
     c3 = c;
     std::complex<float> fc (1,1);
     c3 *= fc;
     assert(c3.real() == -11.5);
-    assert(c3.imag() ==   3.5);
+    assert(c3.imag() == 3.5);
+    return true;
 }
 
 int main(int, char**)
@@ -51,5 +53,11 @@ int main(int, char**)
     test<double>();
     test<long double>();
 
-  return 0;
+#if TEST_STD_VER >= 20
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
+
+    return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.member.ops/times_equal_scalar.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.member.ops/times_equal_scalar.pass.cpp
index 600c79f8d2100..56606248a07d6 100644
--- a/libcxx/test/std/numerics/complex.number/complex.member.ops/times_equal_scalar.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.member.ops/times_equal_scalar.pass.cpp
@@ -8,7 +8,7 @@
 
 // <complex>
 
-// complex& operator*=(const T& rhs);
+// complex& operator*=(const T& rhs); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -16,7 +16,8 @@
 #include "test_macros.h"
 
 template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     std::complex<T> c(1);
@@ -35,6 +36,7 @@ test()
     c *= 1.5;
     assert(c.real() == -5.0625);
     assert(c.imag() == 3);
+    return true;
 }
 
 int main(int, char**)
@@ -43,5 +45,11 @@ int main(int, char**)
     test<double>();
     test<long double>();
 
+#if TEST_STD_VER >= 20
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
+
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.members/real_imag.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.members/real_imag.pass.cpp
index c4a1ef9353982..26db8ddf3b4ca 100644
--- a/libcxx/test/std/numerics/complex.number/complex.members/real_imag.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.members/real_imag.pass.cpp
@@ -8,8 +8,8 @@
 
 // <complex>
 
-// void real(T val);
-// void imag(T val);
+// void real(T val); // constexpr in C++20
+// void imag(T val); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -17,6 +17,7 @@
 #include "test_macros.h"
 
 template <class T>
+TEST_CONSTEXPR_CXX20
 void
 test_constexpr()
 {
@@ -34,7 +35,8 @@ test_constexpr()
 }
 
 template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     std::complex<T> c;
@@ -53,15 +55,21 @@ test()
     assert(c.real() == -4.5);
     assert(c.imag() == -5.5);
 
-    test_constexpr<T> ();
+    test_constexpr<T>();
+    return true;
 }
 
-int main(int, char**)
-{
+int main(int, char**) {
     test<float>();
     test<double>();
     test<long double>();
-    test_constexpr<int> ();
+    test_constexpr<int>();
+
+#if TEST_STD_VER >= 20
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
 
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.ops/complex_divide_complex.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.ops/complex_divide_complex.pass.cpp
index 363b0189ed1cd..7119710a95557 100644
--- a/libcxx/test/std/numerics/complex.number/complex.ops/complex_divide_complex.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.ops/complex_divide_complex.pass.cpp
@@ -10,7 +10,9 @@
 
 // template<class T>
 //   complex<T>
-//   operator/(const complex<T>& lhs, const complex<T>& rhs);
+//   operator/(const complex<T>& lhs, const complex<T>& rhs); // constexpr in C++20
+
+// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=5000000
 
 #include <complex>
 #include <cassert>
@@ -19,135 +21,128 @@
 #include "../cases.h"
 
 template <class T>
-void
-test(const std::complex<T>& lhs, const std::complex<T>& rhs, std::complex<T> x)
-{
-    assert(lhs / rhs == x);
-}
-
-template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
-    std::complex<T> lhs(-4.0, 7.5);
-    std::complex<T> rhs(1.5, 2.5);
-    std::complex<T>   x(1.5, 2.5);
-    test(lhs, rhs, x);
+    const std::complex<T> lhs(-4.0, 7.5);
+    const std::complex<T> rhs(1.5, 2.5);
+    assert(lhs / rhs == std::complex<T>(1.5, 2.5));
+    return true;
 }
 
-void test_edges()
+TEST_CONSTEXPR_CXX20
+bool
+test_edges()
 {
-    const unsigned N = sizeof(testcases) / sizeof(testcases[0]);
-    for (unsigned i = 0; i < N; ++i)
-    {
-        for (unsigned j = 0; j < N; ++j)
-        {
-            std::complex<double> r = testcases[i] / testcases[j];
-            switch (classify(testcases[i]))
-            {
-            case zero:
-                switch (classify(testcases[j]))
-                {
-                case zero:
-                    assert(classify(r) == NaN);
-                    break;
-                case non_zero:
-                    assert(classify(r) == zero);
-                    break;
-                case inf:
-                    assert(classify(r) == zero);
-                    break;
-                case NaN:
-                    assert(classify(r) == NaN);
-                    break;
-                case non_zero_nan:
-                    assert(classify(r) == NaN);
-                    break;
-                }
-                break;
-            case non_zero:
-                switch (classify(testcases[j]))
-                {
-                case zero:
-                    assert(classify(r) == inf);
-                    break;
-                case non_zero:
-                    assert(classify(r) == non_zero);
-                    break;
-                case inf:
-                    assert(classify(r) == zero);
-                    break;
-                case NaN:
-                    assert(classify(r) == NaN);
-                    break;
-                case non_zero_nan:
-                    assert(classify(r) == NaN);
-                    break;
-                }
-                break;
-            case inf:
-                switch (classify(testcases[j]))
-                {
-                case zero:
-                    assert(classify(r) == inf);
-                    break;
-                case non_zero:
-                    assert(classify(r) == inf);
-                    break;
-                case inf:
-                    assert(classify(r) == NaN);
-                    break;
-                case NaN:
-                    assert(classify(r) == NaN);
-                    break;
-                case non_zero_nan:
-                    assert(classify(r) == NaN);
-                    break;
-                }
-                break;
-            case NaN:
-                switch (classify(testcases[j]))
-                {
-                case zero:
-                    assert(classify(r) == NaN);
-                    break;
-                case non_zero:
-                    assert(classify(r) == NaN);
-                    break;
-                case inf:
-                    assert(classify(r) == NaN);
-                    break;
-                case NaN:
-                    assert(classify(r) == NaN);
-                    break;
-                case non_zero_nan:
-                    assert(classify(r) == NaN);
-                    break;
-                }
-                break;
-            case non_zero_nan:
-                switch (classify(testcases[j]))
-                {
-                case zero:
-                    assert(classify(r) == inf);
-                    break;
-                case non_zero:
-                    assert(classify(r) == NaN);
-                    break;
-                case inf:
-                    assert(classify(r) == NaN);
-                    break;
-                case NaN:
-                    assert(classify(r) == NaN);
-                    break;
-                case non_zero_nan:
-                    assert(classify(r) == NaN);
-                    break;
-                }
-                break;
-            }
+  const unsigned N = sizeof(testcases) / sizeof(testcases[0]);
+  int classification[N];
+  for (unsigned i=0; i < N; ++i)
+    classification[i] = classify(testcases[i]);
+
+  for (unsigned i = 0; i < N; ++i) {
+    for (unsigned j = 0; j < N; ++j) {
+      std::complex<double> r = testcases[i] / testcases[j];
+      switch (classification[i]) {
+      case zero:
+        switch (classification[j]) {
+        case zero:
+          assert(classify(r) == NaN);
+          break;
+        case non_zero:
+          assert(classify(r) == zero);
+          break;
+        case inf:
+          assert(classify(r) == zero);
+          break;
+        case NaN:
+          assert(classify(r) == NaN);
+          break;
+        case non_zero_nan:
+          assert(classify(r) == NaN);
+          break;
         }
+        break;
+      case non_zero:
+        switch (classification[j]) {
+        case zero:
+          assert(classify(r) == inf);
+          break;
+        case non_zero:
+          assert(classify(r) == non_zero);
+          break;
+        case inf:
+          assert(classify(r) == zero);
+          break;
+        case NaN:
+          assert(classify(r) == NaN);
+          break;
+        case non_zero_nan:
+          assert(classify(r) == NaN);
+          break;
+        }
+        break;
+      case inf:
+        switch (classification[j]) {
+        case zero:
+          assert(classify(r) == inf);
+          break;
+        case non_zero:
+          assert(classify(r) == inf);
+          break;
+        case inf:
+          assert(classify(r) == NaN);
+          break;
+        case NaN:
+          assert(classify(r) == NaN);
+          break;
+        case non_zero_nan:
+          assert(classify(r) == NaN);
+          break;
+        }
+        break;
+      case NaN:
+        switch (classification[j]) {
+        case zero:
+          assert(classify(r) == NaN);
+          break;
+        case non_zero:
+          assert(classify(r) == NaN);
+          break;
+        case inf:
+          assert(classify(r) == NaN);
+          break;
+        case NaN:
+          assert(classify(r) == NaN);
+          break;
+        case non_zero_nan:
+          assert(classify(r) == NaN);
+          break;
+        }
+        break;
+      case non_zero_nan:
+        switch (classification[j]) {
+        case zero:
+          assert(classify(r) == inf);
+          break;
+        case non_zero:
+          assert(classify(r) == NaN);
+          break;
+        case inf:
+          assert(classify(r) == NaN);
+          break;
+        case NaN:
+          assert(classify(r) == NaN);
+          break;
+        case non_zero_nan:
+          assert(classify(r) == NaN);
+          break;
+        }
+        break;
+      }
     }
+  }
+  return true;
 }
 
 int main(int, char**)
@@ -157,5 +152,12 @@ int main(int, char**)
     test<long double>();
     test_edges();
 
-  return 0;
+#if TEST_STD_VER > 17
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+    static_assert(test_edges());
+#endif
+
+    return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.ops/complex_divide_scalar.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.ops/complex_divide_scalar.pass.cpp
index 24a0e8cb61a38..b7fc9a9a0f10a 100644
--- a/libcxx/test/std/numerics/complex.number/complex.ops/complex_divide_scalar.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.ops/complex_divide_scalar.pass.cpp
@@ -10,7 +10,7 @@
 
 // template<class T>
 //   complex<T>
-//   operator/(const complex<T>& lhs, const T& rhs);
+//   operator/(const complex<T>& lhs, const T& rhs); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -18,20 +18,14 @@
 #include "test_macros.h"
 
 template <class T>
-void
-test(const std::complex<T>& lhs, const T& rhs, std::complex<T> x)
-{
-    assert(lhs / rhs == x);
-}
-
-template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
-    std::complex<T> lhs(-4.0, 7.5);
-    T rhs(2);
-    std::complex<T>   x(-2, 3.75);
-    test(lhs, rhs, x);
+    const std::complex<T> lhs(-4.0, 7.5);
+    const T rhs(2);
+    assert(lhs / rhs == std::complex<T>(-2, 3.75));
+    return true;
 }
 
 int main(int, char**)
@@ -40,5 +34,11 @@ int main(int, char**)
     test<double>();
     test<long double>();
 
-  return 0;
+#if TEST_STD_VER > 17
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
+
+    return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.ops/complex_equals_complex.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.ops/complex_equals_complex.pass.cpp
index 27621f165cf8a..bf18a8422d1a8 100644
--- a/libcxx/test/std/numerics/complex.number/complex.ops/complex_equals_complex.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.ops/complex_equals_complex.pass.cpp
@@ -18,25 +18,8 @@
 #include "test_macros.h"
 
 template <class T>
-void
-test_constexpr()
-{
-#if TEST_STD_VER > 11
-    {
-    constexpr std::complex<T> lhs(1.5,  2.5);
-    constexpr std::complex<T> rhs(1.5, -2.5);
-    static_assert( !(lhs == rhs), "");
-    }
-    {
-    constexpr std::complex<T> lhs(1.5, 2.5);
-    constexpr std::complex<T> rhs(1.5, 2.5);
-    static_assert(lhs == rhs, "");
-    }
-#endif
-}
-
-template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     {
@@ -49,7 +32,7 @@ test()
     std::complex<T> rhs(1.5, 2.5);
     assert(lhs == rhs);
     }
-    test_constexpr<T> ();
+    return true;
 }
 
 int main(int, char**)
@@ -57,7 +40,11 @@ int main(int, char**)
     test<float>();
     test<double>();
     test<long double>();
-//    test_constexpr<int> ();
+#if TEST_STD_VER > 17
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
 
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.ops/complex_equals_scalar.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.ops/complex_equals_scalar.pass.cpp
index 1ec74e703f117..151a356d7930a 100644
--- a/libcxx/test/std/numerics/complex.number/complex.ops/complex_equals_scalar.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.ops/complex_equals_scalar.pass.cpp
@@ -18,6 +18,7 @@
 #include "test_macros.h"
 
 template <class T>
+TEST_CONSTEXPR_CXX20
 void
 test_constexpr()
 {
@@ -46,7 +47,8 @@ test_constexpr()
 }
 
 template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     {
@@ -71,14 +73,20 @@ test()
     }
 
     test_constexpr<T> ();
-    }
+    return true;
+}
 
 int main(int, char**)
 {
     test<float>();
     test<double>();
     test<long double>();
-//     test_constexpr<int> ();
+
+#if TEST_STD_VER > 17
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
 
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.ops/complex_minus_complex.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.ops/complex_minus_complex.pass.cpp
index f96cc47a470fb..d61f6e8f1fee3 100644
--- a/libcxx/test/std/numerics/complex.number/complex.ops/complex_minus_complex.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.ops/complex_minus_complex.pass.cpp
@@ -10,7 +10,7 @@
 
 // template<class T>
 //   complex<T>
-//   operator-(const complex<T>& lhs, const complex<T>& rhs);
+//   operator-(const complex<T>& lhs, const complex<T>& rhs); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -18,28 +18,21 @@
 #include "test_macros.h"
 
 template <class T>
-void
-test(const std::complex<T>& lhs, const std::complex<T>& rhs, std::complex<T> x)
-{
-    assert(lhs - rhs == x);
-}
-
-template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     {
-    std::complex<T> lhs(1.5, 2.5);
-    std::complex<T> rhs(3.5, 4.5);
-    std::complex<T>   x(-2.0, -2.0);
-    test(lhs, rhs, x);
+    const std::complex<T> lhs(1.5, 2.5);
+    const std::complex<T> rhs(3.5, 4.5);
+    assert(lhs - rhs == std::complex<T>(-2.0, -2.0));
     }
     {
-    std::complex<T> lhs(1.5, -2.5);
-    std::complex<T> rhs(-3.5, 4.5);
-    std::complex<T>   x(5.0, -7.0);
-    test(lhs, rhs, x);
+    const std::complex<T> lhs(1.5, -2.5);
+    const std::complex<T> rhs(-3.5, 4.5);
+    assert(lhs - rhs == std::complex<T>(5.0, -7.0));
     }
+    return true;
 }
 
 int main(int, char**)
@@ -48,5 +41,11 @@ int main(int, char**)
     test<double>();
     test<long double>();
 
+#if TEST_STD_VER > 17
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
+
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.ops/complex_minus_scalar.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.ops/complex_minus_scalar.pass.cpp
index 3002085968517..8d4ecffa41baf 100644
--- a/libcxx/test/std/numerics/complex.number/complex.ops/complex_minus_scalar.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.ops/complex_minus_scalar.pass.cpp
@@ -10,7 +10,7 @@
 
 // template<class T>
 //   complex<T>
-//   operator-(const complex<T>& lhs, const T& rhs);
+//   operator-(const complex<T>& lhs, const T& rhs); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -18,28 +18,21 @@
 #include "test_macros.h"
 
 template <class T>
-void
-test(const std::complex<T>& lhs, const T& rhs, std::complex<T> x)
-{
-    assert(lhs - rhs == x);
-}
-
-template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     {
-    std::complex<T> lhs(1.5, 2.5);
-    T rhs(3.5);
-    std::complex<T>   x(-2.0, 2.5);
-    test(lhs, rhs, x);
+    const std::complex<T> lhs(1.5, 2.5);
+    const T rhs(3.5);
+    assert(lhs - rhs == std::complex<T>(-2.0, 2.5));
     }
     {
-    std::complex<T> lhs(1.5, -2.5);
-    T rhs(-3.5);
-    std::complex<T>   x(5.0, -2.5);
-    test(lhs, rhs, x);
+    const std::complex<T> lhs(1.5, -2.5);
+    const T rhs(-3.5);
+    assert(lhs - rhs == std::complex<T>(5.0, -2.5));
     }
+    return true;
 }
 
 int main(int, char**)
@@ -48,5 +41,11 @@ int main(int, char**)
     test<double>();
     test<long double>();
 
+#if TEST_STD_VER > 17
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
+
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.ops/complex_not_equals_complex.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.ops/complex_not_equals_complex.pass.cpp
index 319e453a900a4..81adc690dc26e 100644
--- a/libcxx/test/std/numerics/complex.number/complex.ops/complex_not_equals_complex.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.ops/complex_not_equals_complex.pass.cpp
@@ -18,6 +18,7 @@
 #include "test_macros.h"
 
 template <class T>
+TEST_CONSTEXPR_CXX20
 void
 test_constexpr()
 {
@@ -35,31 +36,37 @@ test_constexpr()
 #endif
 }
 
-
 template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     {
-    std::complex<T> lhs(1.5,  2.5);
-    std::complex<T> rhs(1.5, -2.5);
+    const std::complex<T> lhs(1.5,  2.5);
+    const std::complex<T> rhs(1.5, -2.5);
     assert(lhs != rhs);
     }
     {
-    std::complex<T> lhs(1.5, 2.5);
-    std::complex<T> rhs(1.5, 2.5);
+    const std::complex<T> lhs(1.5, 2.5);
+    const std::complex<T> rhs(1.5, 2.5);
     assert(!(lhs != rhs));
     }
 
     test_constexpr<T> ();
-    }
+    return true;
+}
 
 int main(int, char**)
 {
     test<float>();
     test<double>();
     test<long double>();
-//   test_constexpr<int> ();
+
+#if TEST_STD_VER > 17
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
 
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.ops/complex_not_equals_scalar.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.ops/complex_not_equals_scalar.pass.cpp
index 35074e5772dcb..702900b381433 100644
--- a/libcxx/test/std/numerics/complex.number/complex.ops/complex_not_equals_scalar.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.ops/complex_not_equals_scalar.pass.cpp
@@ -18,6 +18,7 @@
 #include "test_macros.h"
 
 template <class T>
+TEST_CONSTEXPR_CXX20
 void
 test_constexpr()
 {
@@ -46,7 +47,8 @@ test_constexpr()
 }
 
 template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     {
@@ -71,6 +73,7 @@ test()
     }
 
     test_constexpr<T> ();
+    return true;
 }
 
 int main(int, char**)
@@ -78,7 +81,12 @@ int main(int, char**)
     test<float>();
     test<double>();
     test<long double>();
-//     test_constexpr<int> ();
+
+#if TEST_STD_VER > 17
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
 
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.ops/complex_plus_complex.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.ops/complex_plus_complex.pass.cpp
index 963b026f26990..f9a22f6effbc4 100644
--- a/libcxx/test/std/numerics/complex.number/complex.ops/complex_plus_complex.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.ops/complex_plus_complex.pass.cpp
@@ -10,7 +10,7 @@
 
 // template<class T>
 //   complex<T>
-//   operator+(const complex<T>& lhs, const complex<T>& rhs);
+//   operator+(const complex<T>& lhs, const complex<T>& rhs); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -18,28 +18,22 @@
 #include "test_macros.h"
 
 template <class T>
-void
-test(const std::complex<T>& lhs, const std::complex<T>& rhs, std::complex<T> x)
-{
-    assert(lhs + rhs == x);
-}
-
-template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     {
-    std::complex<T> lhs(1.5, 2.5);
-    std::complex<T> rhs(3.5, 4.5);
-    std::complex<T>   x(5.0, 7.0);
-    test(lhs, rhs, x);
+    const std::complex<T> lhs(1.5, 2.5);
+    const std::complex<T> rhs(3.5, 4.5);
+    assert(lhs + rhs == std::complex<T>(5.0, 7.0));
     }
     {
-    std::complex<T> lhs(1.5, -2.5);
-    std::complex<T> rhs(-3.5, 4.5);
-    std::complex<T>   x(-2.0, 2.0);
-    test(lhs, rhs, x);
+    const std::complex<T> lhs(1.5, -2.5);
+    const std::complex<T> rhs(-3.5, 4.5);
+    assert(lhs + rhs == std::complex<T>(-2.0, 2.0));
     }
+
+    return true;
 }
 
 int main(int, char**)
@@ -48,5 +42,11 @@ int main(int, char**)
     test<double>();
     test<long double>();
 
+#if TEST_STD_VER > 17
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
+
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.ops/complex_plus_scalar.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.ops/complex_plus_scalar.pass.cpp
index f4d6b6b9ac569..e86ded70e4797 100644
--- a/libcxx/test/std/numerics/complex.number/complex.ops/complex_plus_scalar.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.ops/complex_plus_scalar.pass.cpp
@@ -10,7 +10,7 @@
 
 // template<class T>
 //   complex<T>
-//   operator+(const complex<T>& lhs, const T& rhs);
+//   operator+(const complex<T>& lhs, const T& rhs); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -18,28 +18,22 @@
 #include "test_macros.h"
 
 template <class T>
-void
-test(const std::complex<T>& lhs, const T& rhs, std::complex<T> x)
-{
-    assert(lhs + rhs == x);
-}
-
-template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     {
-    std::complex<T> lhs(1.5, 2.5);
-    T rhs(3.5);
-    std::complex<T>   x(5.0, 2.5);
-    test(lhs, rhs, x);
+    const std::complex<T> lhs(1.5, 2.5);
+    const T rhs(3.5);
+    assert(lhs + rhs == std::complex<T>(5.0, 2.5));
     }
     {
-    std::complex<T> lhs(1.5, -2.5);
-    T rhs(-3.5);
-    std::complex<T>   x(-2.0, -2.5);
-    test(lhs, rhs, x);
+    const std::complex<T> lhs(1.5, -2.5);
+    const T rhs(-3.5);
+    assert(lhs + rhs == std::complex<T>(-2.0, -2.5));
     }
+
+    return true;
 }
 
 int main(int, char**)
@@ -48,5 +42,11 @@ int main(int, char**)
     test<double>();
     test<long double>();
 
+#if TEST_STD_VER > 17
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
+
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.ops/complex_times_complex.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.ops/complex_times_complex.pass.cpp
index bcf85a9aabb83..38ec71e3a00a5 100644
--- a/libcxx/test/std/numerics/complex.number/complex.ops/complex_times_complex.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.ops/complex_times_complex.pass.cpp
@@ -10,7 +10,9 @@
 
 // template<class T>
 //   complex<T>
-//   operator*(const complex<T>& lhs, const complex<T>& rhs);
+//   operator*(const complex<T>& lhs, const complex<T>& rhs); // constexpr in C++20
+
+// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=5000000
 
 #include <complex>
 #include <cassert>
@@ -19,56 +21,48 @@
 #include "../cases.h"
 
 template <class T>
-void
-test(const std::complex<T>& lhs, const std::complex<T>& rhs, std::complex<T> x)
-{
-    assert(lhs * rhs == x);
-}
-
-template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
-    std::complex<T> lhs(1.5, 2.5);
-    std::complex<T> rhs(1.5, 2.5);
-    std::complex<T>   x(-4.0, 7.5);
-    test(lhs, rhs, x);
+    const std::complex<T> lhs(1.5, 2.5);
+    const std::complex<T> rhs(1.5, 2.5);
+    assert(lhs * rhs == std::complex<T>(-4.0, 7.5));
+    return true;
 }
 
 // test edges
 
-void test_edges()
+TEST_CONSTEXPR_CXX20 bool test_edges()
 {
     const unsigned N = sizeof(testcases) / sizeof(testcases[0]);
+    int classification[N];
+    for (unsigned i=0; i < N; ++i)
+        classification[i] = classify(testcases[i]);
+
     for (unsigned i = 0; i < N; ++i)
     {
         for (unsigned j = 0; j < N; ++j)
         {
             std::complex<double> r = testcases[i] * testcases[j];
-            switch (classify(testcases[i]))
+            switch (classification[i])
             {
             case zero:
-                switch (classify(testcases[j]))
+                switch (classification[j])
                 {
                 case zero:
-                    assert(classify(r) == zero);
-                    break;
                 case non_zero:
                     assert(classify(r) == zero);
                     break;
                 case inf:
-                    assert(classify(r) == NaN);
-                    break;
                 case NaN:
-                    assert(classify(r) == NaN);
-                    break;
                 case non_zero_nan:
                     assert(classify(r) == NaN);
                     break;
                 }
                 break;
             case non_zero:
-                switch (classify(testcases[j]))
+                switch (classification[j])
                 {
                 case zero:
                     assert(classify(r) == zero);
@@ -80,68 +74,37 @@ void test_edges()
                     assert(classify(r) == inf);
                     break;
                 case NaN:
-                    assert(classify(r) == NaN);
-                    break;
                 case non_zero_nan:
                     assert(classify(r) == NaN);
                     break;
                 }
                 break;
             case inf:
-                switch (classify(testcases[j]))
+                switch (classification[j])
                 {
                 case zero:
+                case NaN:
                     assert(classify(r) == NaN);
                     break;
                 case non_zero:
-                    assert(classify(r) == inf);
-                    break;
                 case inf:
-                    assert(classify(r) == inf);
-                    break;
-                case NaN:
-                    assert(classify(r) == NaN);
-                    break;
                 case non_zero_nan:
                     assert(classify(r) == inf);
                     break;
                 }
                 break;
             case NaN:
-                switch (classify(testcases[j]))
-                {
-                case zero:
-                    assert(classify(r) == NaN);
-                    break;
-                case non_zero:
-                    assert(classify(r) == NaN);
-                    break;
-                case inf:
-                    assert(classify(r) == NaN);
-                    break;
-                case NaN:
-                    assert(classify(r) == NaN);
-                    break;
-                case non_zero_nan:
-                    assert(classify(r) == NaN);
-                    break;
-                }
+                assert(classify(r) == NaN);
                 break;
             case non_zero_nan:
-                switch (classify(testcases[j]))
+                switch (classification[j])
                 {
-                case zero:
-                    assert(classify(r) == NaN);
-                    break;
-                case non_zero:
-                    assert(classify(r) == NaN);
-                    break;
                 case inf:
                     assert(classify(r) == inf);
                     break;
+                case zero:
+                case non_zero:
                 case NaN:
-                    assert(classify(r) == NaN);
-                    break;
                 case non_zero_nan:
                     assert(classify(r) == NaN);
                     break;
@@ -150,6 +113,7 @@ void test_edges()
             }
         }
     }
+    return true;
 }
 
 int main(int, char**)
@@ -159,5 +123,12 @@ int main(int, char**)
     test<long double>();
     test_edges();
 
+#if TEST_STD_VER > 17
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+    static_assert(test_edges());
+#endif
+
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.ops/complex_times_scalar.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.ops/complex_times_scalar.pass.cpp
index 897d2c290f2d7..19c0f22b63d0b 100644
--- a/libcxx/test/std/numerics/complex.number/complex.ops/complex_times_scalar.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.ops/complex_times_scalar.pass.cpp
@@ -10,7 +10,7 @@
 
 // template<class T>
 //   complex<T>
-//   operator*(const complex<T>& lhs, const T& rhs);
+//   operator*(const complex<T>& lhs, const T& rhs); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -18,20 +18,14 @@
 #include "test_macros.h"
 
 template <class T>
-void
-test(const std::complex<T>& lhs, const T& rhs, std::complex<T> x)
-{
-    assert(lhs * rhs == x);
-}
-
-template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
-    std::complex<T> lhs(1.5, 2.5);
-    T rhs(1.5);
-    std::complex<T>   x(2.25, 3.75);
-    test(lhs, rhs, x);
+    const std::complex<T> lhs(1.5, 2.5);
+    const T rhs(1.5);
+    assert(lhs * rhs == std::complex<T>(2.25, 3.75));
+    return true;
 }
 
 int main(int, char**)
@@ -40,5 +34,11 @@ int main(int, char**)
     test<double>();
     test<long double>();
 
+#if TEST_STD_VER > 17
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
+
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.ops/scalar_divide_complex.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.ops/scalar_divide_complex.pass.cpp
index 2b72a1a78d07e..50981216cc5f0 100644
--- a/libcxx/test/std/numerics/complex.number/complex.ops/scalar_divide_complex.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.ops/scalar_divide_complex.pass.cpp
@@ -10,7 +10,7 @@
 
 // template<class T>
 //   complex<T>
-//   operator/(const T& lhs, const complex<T>& rhs);
+//   operator/(const T& lhs, const complex<T>& rhs); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -18,20 +18,14 @@
 #include "test_macros.h"
 
 template <class T>
-void
-test(const T& lhs, const std::complex<T>& rhs, std::complex<T> x)
-{
-    assert(lhs / rhs == x);
-}
-
-template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
-    T lhs(-8.5);
-    std::complex<T> rhs(1.5, 2.5);
-    std::complex<T>   x(-1.5, 2.5);
-    test(lhs, rhs, x);
+    const T lhs(-8.5);
+    const std::complex<T> rhs(1.5, 2.5);
+    assert(lhs / rhs == std::complex<T>(-1.5, 2.5));
+    return true;
 }
 
 int main(int, char**)
@@ -40,5 +34,11 @@ int main(int, char**)
     test<double>();
     test<long double>();
 
+#if TEST_STD_VER > 17
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
+
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.ops/scalar_equals_complex.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.ops/scalar_equals_complex.pass.cpp
index d5dcc29182de0..4fe46bb370041 100644
--- a/libcxx/test/std/numerics/complex.number/complex.ops/scalar_equals_complex.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.ops/scalar_equals_complex.pass.cpp
@@ -18,6 +18,7 @@
 #include "test_macros.h"
 
 template <class T>
+TEST_CONSTEXPR_CXX20
 void
 test_constexpr()
 {
@@ -46,7 +47,8 @@ test_constexpr()
 }
 
 template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     {
@@ -71,6 +73,7 @@ test()
     }
 
     test_constexpr<T> ();
+    return true;
 }
 
 int main(int, char**)
@@ -78,7 +81,12 @@ int main(int, char**)
     test<float>();
     test<double>();
     test<long double>();
-//     test_constexpr<int>();
+
+#if TEST_STD_VER > 17
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
 
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.ops/scalar_minus_complex.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.ops/scalar_minus_complex.pass.cpp
index 9cd9207c0323e..126782ccc18bd 100644
--- a/libcxx/test/std/numerics/complex.number/complex.ops/scalar_minus_complex.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.ops/scalar_minus_complex.pass.cpp
@@ -10,7 +10,7 @@
 
 // template<class T>
 //   complex<T>
-//   operator-(const T& lhs, const complex<T>& rhs);
+//   operator-(const T& lhs, const complex<T>& rhs); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -18,35 +18,33 @@
 #include "test_macros.h"
 
 template <class T>
-void
-test(const T& lhs, const std::complex<T>& rhs, std::complex<T> x)
-{
-    assert(lhs - rhs == x);
-}
-
-template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     {
-    T lhs(1.5);
-    std::complex<T> rhs(3.5, 4.5);
-    std::complex<T>   x(-2.0, -4.5);
-    test(lhs, rhs, x);
+    const T lhs(1.5);
+    const std::complex<T> rhs(3.5, 4.5);
+    assert(lhs - rhs == std::complex<T>(-2.0, -4.5));
     }
     {
-    T lhs(1.5);
-    std::complex<T> rhs(-3.5, 4.5);
-    std::complex<T>   x(5.0, -4.5);
-    test(lhs, rhs, x);
+    const T lhs(1.5);
+    const std::complex<T> rhs(-3.5, 4.5);
+    assert(lhs - rhs == std::complex<T>(5.0, -4.5));
     }
+    return true;
 }
 
-int main(int, char**)
-{
+int main(int, char**) {
     test<float>();
     test<double>();
     test<long double>();
 
+#if TEST_STD_VER > 17
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
+
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.ops/scalar_not_equals_complex.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.ops/scalar_not_equals_complex.pass.cpp
index edff47a016069..f5be41fa4074c 100644
--- a/libcxx/test/std/numerics/complex.number/complex.ops/scalar_not_equals_complex.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.ops/scalar_not_equals_complex.pass.cpp
@@ -18,6 +18,7 @@
 #include "test_macros.h"
 
 template <class T>
+TEST_CONSTEXPR_CXX20
 void
 test_constexpr()
 {
@@ -46,7 +47,8 @@ test_constexpr()
 }
 
 template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     {
@@ -71,14 +73,20 @@ test()
     }
 
     test_constexpr<T> ();
-    }
+    return true;
+}
 
 int main(int, char**)
 {
     test<float>();
     test<double>();
     test<long double>();
-//     test_constexpr<int>();
+
+#if TEST_STD_VER > 17
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
 
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.ops/scalar_plus_complex.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.ops/scalar_plus_complex.pass.cpp
index 6f8e0495b475c..a2fe82e42ff19 100644
--- a/libcxx/test/std/numerics/complex.number/complex.ops/scalar_plus_complex.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.ops/scalar_plus_complex.pass.cpp
@@ -10,7 +10,7 @@
 
 // template<class T>
 //   complex<T>
-//   operator+(const T& lhs, const complex<T>& rhs);
+//   operator+(const T& lhs, const complex<T>& rhs); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -18,28 +18,21 @@
 #include "test_macros.h"
 
 template <class T>
-void
-test(const T& lhs, const std::complex<T>& rhs, std::complex<T> x)
-{
-    assert(lhs + rhs == x);
-}
-
-template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
     {
-    T lhs(1.5);
-    std::complex<T> rhs(3.5, 4.5);
-    std::complex<T>   x(5.0, 4.5);
-    test(lhs, rhs, x);
+    const T lhs(1.5);
+    const std::complex<T> rhs(3.5, 4.5);
+    assert(lhs + rhs == std::complex<T>(5.0, 4.5));
     }
     {
-    T lhs(1.5);
-    std::complex<T> rhs(-3.5, 4.5);
-    std::complex<T>   x(-2.0, 4.5);
-    test(lhs, rhs, x);
+    const T lhs(1.5);
+    const std::complex<T> rhs(-3.5, 4.5);
+    assert(lhs + rhs == std::complex<T>(-2.0, 4.5));
     }
+    return true;
 }
 
 int main(int, char**)
@@ -48,5 +41,11 @@ int main(int, char**)
     test<double>();
     test<long double>();
 
+#if TEST_STD_VER > 17
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
+
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.ops/scalar_times_complex.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.ops/scalar_times_complex.pass.cpp
index 3ab8be29f88e6..4c523da67f50c 100644
--- a/libcxx/test/std/numerics/complex.number/complex.ops/scalar_times_complex.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.ops/scalar_times_complex.pass.cpp
@@ -10,7 +10,7 @@
 
 // template<class T>
 //   complex<T>
-//   operator*(const T& lhs, const complex<T>& rhs);
+//   operator*(const T& lhs, const complex<T>& rhs); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -18,20 +18,14 @@
 #include "test_macros.h"
 
 template <class T>
-void
-test(const T& lhs, const std::complex<T>& rhs, std::complex<T> x)
-{
-    assert(lhs * rhs == x);
-}
-
-template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
-    T lhs(1.5);
-    std::complex<T> rhs(1.5, 2.5);
-    std::complex<T>   x(2.25, 3.75);
-    test(lhs, rhs, x);
+    const T lhs(1.5);
+    const std::complex<T> rhs(1.5, 2.5);
+    assert(lhs * rhs == std::complex<T>(2.25, 3.75));
+    return true;
 }
 
 int main(int, char**)
@@ -40,5 +34,11 @@ int main(int, char**)
     test<double>();
     test<long double>();
 
+#if TEST_STD_VER > 17
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
+
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.ops/unary_minus.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.ops/unary_minus.pass.cpp
index a61218323a616..9310ac8f223bd 100644
--- a/libcxx/test/std/numerics/complex.number/complex.ops/unary_minus.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.ops/unary_minus.pass.cpp
@@ -10,7 +10,7 @@
 
 // template<class T>
 //   complex<T>
-//   operator-(const complex<T>& lhs);
+//   operator-(const complex<T>& lhs); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -18,15 +18,13 @@
 #include "test_macros.h"
 
 template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
-    std::complex<T> z(1.5, 2.5);
-    assert(z.real() == 1.5);
-    assert(z.imag() == 2.5);
-    std::complex<T> c = -z;
-    assert(c.real() == -1.5);
-    assert(c.imag() == -2.5);
+    assert(-std::complex<T>(1.5, -2.5) == std::complex<T>(-1.5, 2.5));
+    assert(-std::complex<T>(-1.5, 2.5) == std::complex<T>(1.5, -2.5));
+    return true;
 }
 
 int main(int, char**)
@@ -35,5 +33,11 @@ int main(int, char**)
     test<double>();
     test<long double>();
 
+#if TEST_STD_VER > 17
+    static_assert(test<float>());
+    static_assert(test<double>());
+    static_assert(test<long double>());
+#endif
+
   return 0;
 }

diff  --git a/libcxx/test/std/numerics/complex.number/complex.ops/unary_plus.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.ops/unary_plus.pass.cpp
index 4c693a581a492..cfd494b3c7dff 100644
--- a/libcxx/test/std/numerics/complex.number/complex.ops/unary_plus.pass.cpp
+++ b/libcxx/test/std/numerics/complex.number/complex.ops/unary_plus.pass.cpp
@@ -10,7 +10,7 @@
 
 // template<class T>
 //   complex<T>
-//   operator+(const complex<T>&);
+//   operator+(const complex<T>&); // constexpr in C++20
 
 #include <complex>
 #include <cassert>
@@ -18,22 +18,26 @@
 #include "test_macros.h"
 
 template <class T>
-void
+TEST_CONSTEXPR_CXX20
+bool
 test()
 {
-    std::complex<T> z(1.5, 2.5);
-    assert(z.real() == 1.5);
-    assert(z.imag() == 2.5);
-    std::complex<T> c = +z;
-    assert(c.real() == 1.5);
-    assert(c.imag() == 2.5);
+  assert(+std::complex<T>(1.5, -2.5) == std::complex<T>(1.5, -2.5));
+  assert(+std::complex<T>(-1.5, 2.5) == std::complex<T>(-1.5, 2.5));
+  return true;
 }
 
 int main(int, char**)
 {
-    test<float>();
-    test<double>();
-    test<long double>();
+  test<float>();
+  test<double>();
+  test<long double>();
+
+#if TEST_STD_VER > 17
+  static_assert(test<float>());
+  static_assert(test<double>());
+  static_assert(test<long double>());
+#endif
 
   return 0;
 }

diff  --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index ed502184a3413..c09ea3e980b89 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -231,7 +231,6 @@ def add_version_header(tc):
     "name": "__cpp_lib_constexpr_complex",
     "values": { "c++20": 201711 },
     "headers": ["complex"],
-    "unimplemented": True,
   }, {
     "name": "__cpp_lib_constexpr_dynamic_alloc",
     "values": { "c++20": 201907 },


        


More information about the libcxx-commits mailing list