diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -202,7 +202,7 @@ ------------------------------------------------- ----------------- ``__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 --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -50,6 +50,7 @@ - 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 --- a/libcxx/docs/Status/Cxx20Papers.csv +++ b/libcxx/docs/Status/Cxx20Papers.csv @@ -5,7 +5,7 @@ "`P0020R6 `__","LWG","Floating Point Atomic","Albuquerque","","" "`P0053R7 `__","LWG","C++ Synchronized Buffered Ostream","Albuquerque","","" "`P0202R3 `__","LWG","Add constexpr modifiers to functions in and Headers","Albuquerque","|Complete|","12.0" -"`P0415R1 `__","LWG","Constexpr for ``std::complex``\ ","Albuquerque","|In Progress|","7.0" +"`P0415R1 `__","LWG","Constexpr for ``std::complex``\ ","Albuquerque","|Complete|","16.0" "`P0439R0 `__","LWG","Make ``std::memory_order``\ a scoped enumeration","Albuquerque","|Complete|","" "`P0457R2 `__","LWG","String Prefix and Suffix Checking","Albuquerque","|Complete|","6.0" "`P0550R2 `__","LWG","Transformation Trait ``remove_cvref``\ ","Albuquerque","|Complete|","6.0" diff --git a/libcxx/include/__config b/libcxx/include/__config --- 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 --- a/libcxx/include/cmath +++ b/libcxx/include/cmath @@ -308,6 +308,7 @@ #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_CONSTEXPR typename enable_if::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 +_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI + typename std::__enable_if_t::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 ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR double __constexpr_fabs(_Tp __x) _NOEXCEPT { + return __builtin_fabs(static_cast(__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 ::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 +_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 +_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 --- a/libcxx/include/complex +++ b/libcxx/include/complex @@ -29,21 +29,21 @@ T real() const; // constexpr in C++14 T imag() const; // constexpr in C++14 - void real(T); - void imag(T); - - complex& operator= (const T&); - complex& operator+=(const T&); - complex& operator-=(const T&); - complex& operator*=(const T&); - complex& operator/=(const T&); - - complex& operator=(const complex&); - template complex& operator= (const complex&); - template complex& operator+=(const complex&); - template complex& operator-=(const complex&); - template complex& operator*=(const complex&); - template complex& operator/=(const complex&); + void real(T); // constexpr in C++20 + void imag(T); // constexpr in C++20 + + complex& operator= (const T&); // constexpr in C++20 + complex& operator+=(const T&); // constexpr in C++20 + complex& operator-=(const T&); // constexpr in C++20 + complex& operator*=(const T&); // constexpr in C++20 + complex& operator/=(const T&); // constexpr in C++20 + + complex& operator=(const complex&); // constexpr in C++20 + template complex& operator= (const complex&); // constexpr in C++20 + template complex& operator+=(const complex&); // constexpr in C++20 + template complex& operator-=(const complex&); // constexpr in C++20 + template complex& operator*=(const complex&); // constexpr in C++20 + template complex& operator/=(const complex&); // constexpr in C++20 }; template<> @@ -57,22 +57,22 @@ explicit constexpr complex(const complex&); constexpr float real() const; - void real(float); + void real(float); // constexpr in C++20 constexpr float imag() const; - void imag(float); - - complex& operator= (float); - complex& operator+=(float); - complex& operator-=(float); - complex& operator*=(float); - complex& operator/=(float); - - complex& operator=(const complex&); - template complex& operator= (const complex&); - template complex& operator+=(const complex&); - template complex& operator-=(const complex&); - template complex& operator*=(const complex&); - template complex& operator/=(const complex&); + void imag(float); // constexpr in C++20 + + complex& operator= (float); // constexpr in C++20 + complex& operator+=(float); // constexpr in C++20 + complex& operator-=(float); // constexpr in C++20 + complex& operator*=(float); // constexpr in C++20 + complex& operator/=(float); // constexpr in C++20 + + complex& operator=(const complex&); // constexpr in C++20 + template complex& operator= (const complex&); // constexpr in C++20 + template complex& operator+=(const complex&); // constexpr in C++20 + template complex& operator-=(const complex&); // constexpr in C++20 + template complex& operator*=(const complex&); // constexpr in C++20 + template complex& operator/=(const complex&); // constexpr in C++20 }; template<> @@ -86,22 +86,22 @@ explicit constexpr complex(const complex&); constexpr double real() const; - void real(double); + void real(double); // constexpr in C++20 constexpr double imag() const; - void imag(double); - - complex& operator= (double); - complex& operator+=(double); - complex& operator-=(double); - complex& operator*=(double); - complex& operator/=(double); - complex& operator=(const complex&); - - template complex& operator= (const complex&); - template complex& operator+=(const complex&); - template complex& operator-=(const complex&); - template complex& operator*=(const complex&); - template complex& operator/=(const complex&); + void imag(double); // constexpr in C++20 + + complex& operator= (double); // constexpr in C++20 + complex& operator+=(double); // constexpr in C++20 + complex& operator-=(double); // constexpr in C++20 + complex& operator*=(double); // constexpr in C++20 + complex& operator/=(double); // constexpr in C++20 + complex& operator=(const complex&); // constexpr in C++20 + + template complex& operator= (const complex&); // constexpr in C++20 + template complex& operator+=(const complex&); // constexpr in C++20 + template complex& operator-=(const complex&); // constexpr in C++20 + template complex& operator*=(const complex&); // constexpr in C++20 + template complex& operator/=(const complex&); // constexpr in C++20 }; template<> @@ -115,39 +115,39 @@ constexpr complex(const complex&); 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& operator=(const complex&); - complex& operator= (long double); - complex& operator+=(long double); - complex& operator-=(long double); - complex& operator*=(long double); - complex& operator/=(long double); - - template complex& operator= (const complex&); - template complex& operator+=(const complex&); - template complex& operator-=(const complex&); - template complex& operator*=(const complex&); - template complex& operator/=(const complex&); + void imag(long double); // constexpr in C++20 + + complex& operator=(const complex&); // constexpr in C++20 + complex& operator= (long double); // constexpr in C++20 + complex& operator+=(long double); // constexpr in C++20 + complex& operator-=(long double); // constexpr in C++20 + complex& operator*=(long double); // constexpr in C++20 + complex& operator/=(long double); // constexpr in C++20 + + template complex& operator= (const complex&); // constexpr in C++20 + template complex& operator+=(const complex&); // constexpr in C++20 + template complex& operator-=(const complex&); // constexpr in C++20 + template complex& operator*=(const complex&); // constexpr in C++20 + template complex& operator/=(const complex&); // constexpr in C++20 }; // 26.3.6 operators: -template complex operator+(const complex&, const complex&); -template complex operator+(const complex&, const T&); -template complex operator+(const T&, const complex&); -template complex operator-(const complex&, const complex&); -template complex operator-(const complex&, const T&); -template complex operator-(const T&, const complex&); -template complex operator*(const complex&, const complex&); -template complex operator*(const complex&, const T&); -template complex operator*(const T&, const complex&); -template complex operator/(const complex&, const complex&); -template complex operator/(const complex&, const T&); -template complex operator/(const T&, const complex&); -template complex operator+(const complex&); -template complex operator-(const complex&); +template complex operator+(const complex&, const complex&); // constexpr in C++20 +template complex operator+(const complex&, const T&); // constexpr in C++20 +template complex operator+(const T&, const complex&); // constexpr in C++20 +template complex operator-(const complex&, const complex&); // constexpr in C++20 +template complex operator-(const complex&, const T&); // constexpr in C++20 +template complex operator-(const T&, const complex&); // constexpr in C++20 +template complex operator*(const complex&, const complex&); // constexpr in C++20 +template complex operator*(const complex&, const T&); // constexpr in C++20 +template complex operator*(const T&, const complex&); // constexpr in C++20 +template complex operator/(const complex&, const complex&); // constexpr in C++20 +template complex operator/(const complex&, const T&); // constexpr in C++20 +template complex operator/(const T&, const complex&); // constexpr in C++20 +template complex operator+(const complex&); // constexpr in C++20 +template complex operator-(const complex&); // constexpr in C++20 template bool operator==(const complex&, const complex&); // constexpr in C++14 template bool operator==(const complex&, const T&); // constexpr in C++14 template bool operator==(const T&, const complex&); // constexpr in C++14 @@ -184,17 +184,17 @@ template double arg(T); float arg(float); -template T norm(const complex&); - long double norm(long double); - double norm(double); -template double norm(T); - float norm(float); +template T norm(const complex&); // constexpr in C++20 + long double norm(long double); // constexpr in C++20 + double norm(double); // constexpr in C++20 +template double norm(T); // constexpr in C++20 + float norm(float); // constexpr in C++20 -template complex conj(const complex&); - complex conj(long double); - complex conj(double); -template complex conj(T); - complex conj(float); +template complex conj(const complex&); // constexpr in C++20 + complex conj(long double); // constexpr in C++20 + complex conj(double); // constexpr in C++20 +template complex conj(T); // constexpr in C++20 + complex conj(float); // constexpr in C++20 template complex proj(const complex&); complex proj(long double); @@ -251,8 +251,8 @@ template class _LIBCPP_TEMPLATE_VIS complex; -template _LIBCPP_HIDE_FROM_ABI complex<_Tp> operator*(const complex<_Tp>& __z, const complex<_Tp>& __w); -template _LIBCPP_HIDE_FROM_ABI complex<_Tp> operator/(const complex<_Tp>& __x, const complex<_Tp>& __y); +template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator*(const complex<_Tp>& __z, const complex<_Tp>& __w); +template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator/(const complex<_Tp>& __x, const complex<_Tp>& __y); template class _LIBCPP_TEMPLATE_VIS complex @@ -273,40 +273,40 @@ _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 _LIBCPP_INLINE_VISIBILITY complex& operator= (const complex<_Xp>& __c) + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator= (const complex<_Xp>& __c) { __re_ = __c.real(); __im_ = __c.imag(); return *this; } - template _LIBCPP_INLINE_VISIBILITY complex& operator+=(const complex<_Xp>& __c) + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator+=(const complex<_Xp>& __c) { __re_ += __c.real(); __im_ += __c.imag(); return *this; } - template _LIBCPP_INLINE_VISIBILITY complex& operator-=(const complex<_Xp>& __c) + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator-=(const complex<_Xp>& __c) { __re_ -= __c.real(); __im_ -= __c.imag(); return *this; } - template _LIBCPP_INLINE_VISIBILITY complex& operator*=(const complex<_Xp>& __c) + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator*=(const complex<_Xp>& __c) { *this = *this * complex(__c.real(), __c.imag()); return *this; } - template _LIBCPP_INLINE_VISIBILITY complex& operator/=(const complex<_Xp>& __c) + template _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 @@ _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 _LIBCPP_INLINE_VISIBILITY complex& operator= (const complex<_Xp>& __c) + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator= (const complex<_Xp>& __c) { __re_ = __c.real(); __im_ = __c.imag(); return *this; } - template _LIBCPP_INLINE_VISIBILITY complex& operator+=(const complex<_Xp>& __c) + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator+=(const complex<_Xp>& __c) { __re_ += __c.real(); __im_ += __c.imag(); return *this; } - template _LIBCPP_INLINE_VISIBILITY complex& operator-=(const complex<_Xp>& __c) + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator-=(const complex<_Xp>& __c) { __re_ -= __c.real(); __im_ -= __c.imag(); return *this; } - template _LIBCPP_INLINE_VISIBILITY complex& operator*=(const complex<_Xp>& __c) + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator*=(const complex<_Xp>& __c) { *this = *this * complex(__c.real(), __c.imag()); return *this; } - template _LIBCPP_INLINE_VISIBILITY complex& operator/=(const complex<_Xp>& __c) + template _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 @@ _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 _LIBCPP_INLINE_VISIBILITY complex& operator= (const complex<_Xp>& __c) + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator= (const complex<_Xp>& __c) { __re_ = __c.real(); __im_ = __c.imag(); return *this; } - template _LIBCPP_INLINE_VISIBILITY complex& operator+=(const complex<_Xp>& __c) + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator+=(const complex<_Xp>& __c) { __re_ += __c.real(); __im_ += __c.imag(); return *this; } - template _LIBCPP_INLINE_VISIBILITY complex& operator-=(const complex<_Xp>& __c) + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator-=(const complex<_Xp>& __c) { __re_ -= __c.real(); __im_ -= __c.imag(); return *this; } - template _LIBCPP_INLINE_VISIBILITY complex& operator*=(const complex<_Xp>& __c) + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator*=(const complex<_Xp>& __c) { *this = *this * complex(__c.real(), __c.imag()); return *this; } - template _LIBCPP_INLINE_VISIBILITY complex& operator/=(const complex<_Xp>& __c) + template _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 @@ _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 _LIBCPP_INLINE_VISIBILITY complex& operator= (const complex<_Xp>& __c) + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator= (const complex<_Xp>& __c) { __re_ = __c.real(); __im_ = __c.imag(); return *this; } - template _LIBCPP_INLINE_VISIBILITY complex& operator+=(const complex<_Xp>& __c) + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator+=(const complex<_Xp>& __c) { __re_ += __c.real(); __im_ += __c.imag(); return *this; } - template _LIBCPP_INLINE_VISIBILITY complex& operator-=(const complex<_Xp>& __c) + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator-=(const complex<_Xp>& __c) { __re_ -= __c.real(); __im_ -= __c.imag(); return *this; } - template _LIBCPP_INLINE_VISIBILITY complex& operator*=(const complex<_Xp>& __c) + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex& operator*=(const complex<_Xp>& __c) { *this = *this * complex(__c.real(), __c.imag()); return *this; } - template _LIBCPP_INLINE_VISIBILITY complex& operator/=(const complex<_Xp>& __c) + template _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 @@ // 26.3.6 operators: template -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 @@ } template -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 @@ } template -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 @@ } template -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 @@ } template -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 @@ } template -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 @@ } template -_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 @@ 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 @@ } template -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 @@ } template -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 @@ } template -_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 @@ _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(__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 @@ } template -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 @@ } template -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 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator+(const complex<_Tp>& __x) { @@ -732,7 +805,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator-(const complex<_Tp>& __x) { @@ -903,7 +976,7 @@ // norm template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp norm(const complex<_Tp>& __c) { @@ -915,7 +988,7 @@ } template -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 @@ // conj template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> conj(const complex<_Tp>& __c) { @@ -934,7 +1007,7 @@ } template -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 --- a/libcxx/include/math.h +++ b/libcxx/include/math.h @@ -1043,43 +1043,12 @@ // 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 -_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 @@ -1091,7 +1060,7 @@ 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 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -317,7 +317,7 @@ # 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 --- 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 --- 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 --- 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 #include +#include +#include + +#include "test_macros.h" -const std::complex testcases[] = +TEST_CONSTEXPR_CXX20 const std::complex testcases[] = { std::complex( 1.e-6, 1.e-6), std::complex(-1.e-6, 1.e-6), @@ -56,32 +59,32 @@ std::complex( 1.e+6, 0), std::complex(-1.e+6, 0), - std::complex(NAN, NAN), - std::complex(-INFINITY, NAN), - std::complex(-2, NAN), - std::complex(-1, NAN), - std::complex(-0.5, NAN), - std::complex(-0., NAN), - std::complex(+0., NAN), - std::complex(0.5, NAN), - std::complex(1, NAN), - std::complex(2, NAN), - std::complex(INFINITY, NAN), - - std::complex(NAN, -INFINITY), - std::complex(-INFINITY, -INFINITY), - std::complex(-2, -INFINITY), - std::complex(-1, -INFINITY), - std::complex(-0.5, -INFINITY), - std::complex(-0., -INFINITY), - std::complex(+0., -INFINITY), - std::complex(0.5, -INFINITY), - std::complex(1, -INFINITY), - std::complex(2, -INFINITY), - std::complex(INFINITY, -INFINITY), - - std::complex(NAN, -2), - std::complex(-INFINITY, -2), + std::complex(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()), + std::complex(-std::numeric_limits::infinity(), std::numeric_limits::quiet_NaN()), + std::complex(-2, std::numeric_limits::quiet_NaN()), + std::complex(-1, std::numeric_limits::quiet_NaN()), + std::complex(-0.5, std::numeric_limits::quiet_NaN()), + std::complex(-0., std::numeric_limits::quiet_NaN()), + std::complex(+0., std::numeric_limits::quiet_NaN()), + std::complex(0.5, std::numeric_limits::quiet_NaN()), + std::complex(1, std::numeric_limits::quiet_NaN()), + std::complex(2, std::numeric_limits::quiet_NaN()), + std::complex(std::numeric_limits::infinity(), std::numeric_limits::quiet_NaN()), + + std::complex(std::numeric_limits::quiet_NaN(), -std::numeric_limits::infinity()), + std::complex(-std::numeric_limits::infinity(), -std::numeric_limits::infinity()), + std::complex(-2, -std::numeric_limits::infinity()), + std::complex(-1, -std::numeric_limits::infinity()), + std::complex(-0.5, -std::numeric_limits::infinity()), + std::complex(-0., -std::numeric_limits::infinity()), + std::complex(+0., -std::numeric_limits::infinity()), + std::complex(0.5, -std::numeric_limits::infinity()), + std::complex(1, -std::numeric_limits::infinity()), + std::complex(2, -std::numeric_limits::infinity()), + std::complex(std::numeric_limits::infinity(), -std::numeric_limits::infinity()), + + std::complex(std::numeric_limits::quiet_NaN(), -2), + std::complex(-std::numeric_limits::infinity(), -2), std::complex(-2, -2), std::complex(-1, -2), std::complex(-0.5, -2), @@ -90,10 +93,10 @@ std::complex(0.5, -2), std::complex(1, -2), std::complex(2, -2), - std::complex(INFINITY, -2), + std::complex(std::numeric_limits::infinity(), -2), - std::complex(NAN, -1), - std::complex(-INFINITY, -1), + std::complex(std::numeric_limits::quiet_NaN(), -1), + std::complex(-std::numeric_limits::infinity(), -1), std::complex(-2, -1), std::complex(-1, -1), std::complex(-0.5, -1), @@ -102,10 +105,10 @@ std::complex(0.5, -1), std::complex(1, -1), std::complex(2, -1), - std::complex(INFINITY, -1), + std::complex(std::numeric_limits::infinity(), -1), - std::complex(NAN, -0.5), - std::complex(-INFINITY, -0.5), + std::complex(std::numeric_limits::quiet_NaN(), -0.5), + std::complex(-std::numeric_limits::infinity(), -0.5), std::complex(-2, -0.5), std::complex(-1, -0.5), std::complex(-0.5, -0.5), @@ -114,10 +117,10 @@ std::complex(0.5, -0.5), std::complex(1, -0.5), std::complex(2, -0.5), - std::complex(INFINITY, -0.5), + std::complex(std::numeric_limits::infinity(), -0.5), - std::complex(NAN, -0.), - std::complex(-INFINITY, -0.), + std::complex(std::numeric_limits::quiet_NaN(), -0.), + std::complex(-std::numeric_limits::infinity(), -0.), std::complex(-2, -0.), std::complex(-1, -0.), std::complex(-0.5, -0.), @@ -126,10 +129,10 @@ std::complex(0.5, -0.), std::complex(1, -0.), std::complex(2, -0.), - std::complex(INFINITY, -0.), + std::complex(std::numeric_limits::infinity(), -0.), - std::complex(NAN, +0.), - std::complex(-INFINITY, +0.), + std::complex(std::numeric_limits::quiet_NaN(), +0.), + std::complex(-std::numeric_limits::infinity(), +0.), std::complex(-2, +0.), std::complex(-1, +0.), std::complex(-0.5, +0.), @@ -138,10 +141,10 @@ std::complex(0.5, +0.), std::complex(1, +0.), std::complex(2, +0.), - std::complex(INFINITY, +0.), + std::complex(std::numeric_limits::infinity(), +0.), - std::complex(NAN, 0.5), - std::complex(-INFINITY, 0.5), + std::complex(std::numeric_limits::quiet_NaN(), 0.5), + std::complex(-std::numeric_limits::infinity(), 0.5), std::complex(-2, 0.5), std::complex(-1, 0.5), std::complex(-0.5, 0.5), @@ -150,10 +153,10 @@ std::complex(0.5, 0.5), std::complex(1, 0.5), std::complex(2, 0.5), - std::complex(INFINITY, 0.5), + std::complex(std::numeric_limits::infinity(), 0.5), - std::complex(NAN, 1), - std::complex(-INFINITY, 1), + std::complex(std::numeric_limits::quiet_NaN(), 1), + std::complex(-std::numeric_limits::infinity(), 1), std::complex(-2, 1), std::complex(-1, 1), std::complex(-0.5, 1), @@ -162,10 +165,10 @@ std::complex(0.5, 1), std::complex(1, 1), std::complex(2, 1), - std::complex(INFINITY, 1), + std::complex(std::numeric_limits::infinity(), 1), - std::complex(NAN, 2), - std::complex(-INFINITY, 2), + std::complex(std::numeric_limits::quiet_NaN(), 2), + std::complex(-std::numeric_limits::infinity(), 2), std::complex(-2, 2), std::complex(-1, 2), std::complex(-0.5, 2), @@ -174,40 +177,51 @@ std::complex(0.5, 2), std::complex(1, 2), std::complex(2, 2), - std::complex(INFINITY, 2), - - std::complex(NAN, INFINITY), - std::complex(-INFINITY, INFINITY), - std::complex(-2, INFINITY), - std::complex(-1, INFINITY), - std::complex(-0.5, INFINITY), - std::complex(-0., INFINITY), - std::complex(+0., INFINITY), - std::complex(0.5, INFINITY), - std::complex(1, INFINITY), - std::complex(2, INFINITY), - std::complex(INFINITY, INFINITY) + std::complex(std::numeric_limits::infinity(), 2), + + std::complex(std::numeric_limits::quiet_NaN(), std::numeric_limits::infinity()), + std::complex(-std::numeric_limits::infinity(), std::numeric_limits::infinity()), + std::complex(-2, std::numeric_limits::infinity()), + std::complex(-1, std::numeric_limits::infinity()), + std::complex(-0.5, std::numeric_limits::infinity()), + std::complex(-0., std::numeric_limits::infinity()), + std::complex(+0., std::numeric_limits::infinity()), + std::complex(0.5, std::numeric_limits::infinity()), + std::complex(1, std::numeric_limits::infinity()), + std::complex(2, std::numeric_limits::infinity()), + std::complex(std::numeric_limits::infinity(), std::numeric_limits::infinity()) }; enum {zero, non_zero, inf, NaN, non_zero_nan}; +template ::value, int>::type = 0> +TEST_CONSTEXPR_CXX20 bool test_isinf(T v) { + return v == std::numeric_limits::infinity() || v == -std::numeric_limits::infinity(); +} + +template ::value, int>::type = 0> +TEST_CONSTEXPR_CXX20 bool test_isnan(T v) { + return v != v; +} + template +TEST_CONSTEXPR_CXX20 int classify(const std::complex& x) { if (x == std::complex()) 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 --- 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 @@ // -// template complex conj(const complex&); -// complex conj(long double); -// complex conj(double); -// template complex conj(T); -// complex conj(float); +// template complex conj(const complex&); // constexpr in C++20 +// complex conj(long double); // constexpr in C++20 +// complex conj(double); // constexpr in C++20 +// template complex conj(T); // constexpr in C++20 +// complex conj(float); // constexpr in C++20 #include #include @@ -22,6 +22,7 @@ #include "../cases.h" template +TEST_CONSTEXPR_CXX20 void test(T x, typename std::enable_if::value>::type* = 0) { @@ -30,6 +31,7 @@ } template +TEST_CONSTEXPR_CXX20 void test(T x, typename std::enable_if::value>::type* = 0) { @@ -38,6 +40,7 @@ } template +TEST_CONSTEXPR_CXX20 void test(T x, typename std::enable_if::value && !std::is_floating_point::value>::type* = 0) @@ -47,12 +50,14 @@ } template -void +TEST_CONSTEXPR_CXX20 +bool test() { test(0); test(1); test(10); + return true; } int main(int, char**) @@ -64,5 +69,14 @@ test(); test(); - return 0; +#if TEST_STD_VER >= 20 + static_assert(test()); + static_assert(test()); + static_assert(test()); + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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 // T -// norm(T x); +// norm(T x); // constexpr in C++20 #include #include @@ -20,6 +20,7 @@ #include "../cases.h" template +TEST_CONSTEXPR_CXX20 void test(T x, typename std::enable_if::value>::type* = 0) { @@ -28,6 +29,7 @@ } template +TEST_CONSTEXPR_CXX20 void test(T x, typename std::enable_if::value>::type* = 0) { @@ -36,12 +38,14 @@ } template -void +TEST_CONSTEXPR_CXX20 +bool test() { test(0); test(1); test(10); + return true; } int main(int, char**) @@ -53,5 +57,14 @@ test(); test(); - return 0; +#if TEST_STD_VER >= 20 + static_assert(test()); + static_assert(test()); + static_assert(test()); + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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& operator=(const complex&); -// template complex& operator= (const complex&); +// template complex& operator= (const complex&); // constexpr in C++20 #include #include @@ -17,7 +17,8 @@ #include "test_macros.h" template -void +TEST_CONSTEXPR_CXX20 +bool test() { std::complex c; @@ -31,6 +32,7 @@ c = c3; assert(c.real() == 3.5); assert(c.imag() == -4.5); + return true; } int main(int, char**) @@ -47,5 +49,19 @@ test(); test(); +#if TEST_STD_VER >= 20 + static_assert(test()); + static_assert(test()); + static_assert(test()); + + static_assert(test()); + static_assert(test()); + static_assert(test()); + + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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& operator= (const T&); +// complex& operator= (const T&); // constexpr in C++20 #include #include @@ -16,7 +16,8 @@ #include "test_macros.h" template -void +TEST_CONSTEXPR_CXX20 +bool test() { std::complex c; @@ -28,6 +29,7 @@ c = -1.5; assert(c.real() == -1.5); assert(c.imag() == 0); + return true; } int main(int, char**) @@ -36,5 +38,11 @@ test(); test(); +#if TEST_STD_VER >= 20 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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& operator/=(const complex& rhs); +// complex& operator/=(const complex& rhs); // constexpr in C++20 #include #include @@ -16,7 +16,8 @@ #include "test_macros.h" template -void +TEST_CONSTEXPR_CXX20 +bool test() { std::complex c(-4, 7.5); @@ -35,15 +36,15 @@ c3 = c; std::complex ic (1,1); c3 /= ic; - assert(c3.real() == 0.5); + assert(c3.real() == 0.5); assert(c3.imag() == -0.5); c3 = c; std::complex 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 @@ test(); test(); - return 0; +#if TEST_STD_VER >= 20 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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& operator/=(const T& rhs); +// complex& operator/=(const T& rhs); // constexpr in C++20 #include #include @@ -16,7 +16,8 @@ #include "test_macros.h" template -void +TEST_CONSTEXPR_CXX20 +bool test() { std::complex c(1); @@ -35,6 +36,7 @@ c /= 0.5; assert(c.real() == -16); assert(c.imag() == 4); + return true; } int main(int, char**) @@ -43,5 +45,11 @@ test(); test(); +#if TEST_STD_VER >= 20 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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& operator-=(const complex& rhs); +// complex& operator-=(const complex& rhs); // constexpr in C++20 #include #include @@ -16,7 +16,8 @@ #include "test_macros.h" template -void +TEST_CONSTEXPR_CXX20 +bool test() { std::complex c; @@ -43,6 +44,7 @@ c3 -= fc; assert(c3.real() == -4); assert(c3.imag() == -6); + return true; } int main(int, char**) @@ -51,5 +53,11 @@ test(); test(); - return 0; +#if TEST_STD_VER >= 20 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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& operator-=(const T& rhs); +// complex& operator-=(const T& rhs); // constexpr in C++20 #include #include @@ -16,7 +16,8 @@ #include "test_macros.h" template -void +TEST_CONSTEXPR_CXX20 +bool test() { std::complex c; @@ -31,6 +32,7 @@ c -= -1.5; assert(c.real() == -1.5); assert(c.imag() == 0); + return true; } int main(int, char**) @@ -39,5 +41,11 @@ test(); test(); +#if TEST_STD_VER >= 20 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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& operator+=(const complex& rhs); +// complex& operator+=(const complex& rhs); // constexpr in C++20 #include #include @@ -16,7 +16,8 @@ #include "test_macros.h" template -void +TEST_CONSTEXPR_CXX20 +bool test() { std::complex c; @@ -43,6 +44,7 @@ c3 += fc; assert(c3.real() == 4); assert(c3.imag() == 6); + return true; } int main(int, char**) @@ -51,5 +53,11 @@ test(); test(); - return 0; +#if TEST_STD_VER >= 20 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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& operator+=(const T& rhs); +// complex& operator+=(const T& rhs); // constexpr in C++20 #include #include @@ -16,7 +16,8 @@ #include "test_macros.h" template -void +TEST_CONSTEXPR_CXX20 +bool test() { std::complex c; @@ -31,6 +32,7 @@ c += -1.5; assert(c.real() == 1.5); assert(c.imag() == 0); + return true; } int main(int, char**) @@ -39,5 +41,11 @@ test(); test(); +#if TEST_STD_VER >= 20 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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& operator*=(const complex& rhs); +// complex& operator*=(const complex& rhs); // constexpr in C++20 #include #include @@ -16,7 +16,8 @@ #include "test_macros.h" template -void +TEST_CONSTEXPR_CXX20 +bool test() { std::complex c(1); @@ -36,13 +37,14 @@ std::complex ic (1,1); c3 *= ic; assert(c3.real() == -11.5); - assert(c3.imag() == 3.5); + assert(c3.imag() == 3.5); c3 = c; std::complex 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 @@ test(); test(); - return 0; +#if TEST_STD_VER >= 20 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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& operator*=(const T& rhs); +// complex& operator*=(const T& rhs); // constexpr in C++20 #include #include @@ -16,7 +16,8 @@ #include "test_macros.h" template -void +TEST_CONSTEXPR_CXX20 +bool test() { std::complex c(1); @@ -35,6 +36,7 @@ c *= 1.5; assert(c.real() == -5.0625); assert(c.imag() == 3); + return true; } int main(int, char**) @@ -43,5 +45,11 @@ test(); test(); +#if TEST_STD_VER >= 20 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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 @@ // -// 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 #include @@ -17,6 +17,7 @@ #include "test_macros.h" template +TEST_CONSTEXPR_CXX20 void test_constexpr() { @@ -34,7 +35,8 @@ } template -void +TEST_CONSTEXPR_CXX20 +bool test() { std::complex c; @@ -53,15 +55,21 @@ assert(c.real() == -4.5); assert(c.imag() == -5.5); - test_constexpr (); + test_constexpr(); + return true; } -int main(int, char**) -{ +int main(int, char**) { test(); test(); test(); - test_constexpr (); + test_constexpr(); + +#if TEST_STD_VER >= 20 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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 // complex -// operator/(const complex& lhs, const complex& rhs); +// operator/(const complex& lhs, const complex& rhs); // constexpr in C++20 + +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=5000000 #include #include @@ -19,135 +21,128 @@ #include "../cases.h" template -void -test(const std::complex& lhs, const std::complex& rhs, std::complex x) -{ - assert(lhs / rhs == x); -} - -template -void +TEST_CONSTEXPR_CXX20 +bool test() { - std::complex lhs(-4.0, 7.5); - std::complex rhs(1.5, 2.5); - std::complex x(1.5, 2.5); - test(lhs, rhs, x); + const std::complex lhs(-4.0, 7.5); + const std::complex rhs(1.5, 2.5); + assert(lhs / rhs == std::complex(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 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 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 @@ test(); test_edges(); - return 0; +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); + static_assert(test()); + 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 --- 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 // complex -// operator/(const complex& lhs, const T& rhs); +// operator/(const complex& lhs, const T& rhs); // constexpr in C++20 #include #include @@ -18,20 +18,14 @@ #include "test_macros.h" template -void -test(const std::complex& lhs, const T& rhs, std::complex x) -{ - assert(lhs / rhs == x); -} - -template -void +TEST_CONSTEXPR_CXX20 +bool test() { - std::complex lhs(-4.0, 7.5); - T rhs(2); - std::complex x(-2, 3.75); - test(lhs, rhs, x); + const std::complex lhs(-4.0, 7.5); + const T rhs(2); + assert(lhs / rhs == std::complex(-2, 3.75)); + return true; } int main(int, char**) @@ -40,5 +34,11 @@ test(); test(); - return 0; +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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 -void -test_constexpr() -{ -#if TEST_STD_VER > 11 - { - constexpr std::complex lhs(1.5, 2.5); - constexpr std::complex rhs(1.5, -2.5); - static_assert( !(lhs == rhs), ""); - } - { - constexpr std::complex lhs(1.5, 2.5); - constexpr std::complex rhs(1.5, 2.5); - static_assert(lhs == rhs, ""); - } -#endif -} - -template -void +TEST_CONSTEXPR_CXX20 +bool test() { { @@ -49,7 +32,7 @@ std::complex rhs(1.5, 2.5); assert(lhs == rhs); } - test_constexpr (); + return true; } int main(int, char**) @@ -57,7 +40,11 @@ test(); test(); test(); -// test_constexpr (); +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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 +TEST_CONSTEXPR_CXX20 void test_constexpr() { @@ -46,7 +47,8 @@ } template -void +TEST_CONSTEXPR_CXX20 +bool test() { { @@ -71,14 +73,20 @@ } test_constexpr (); - } + return true; +} int main(int, char**) { test(); test(); test(); -// test_constexpr (); + +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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 // complex -// operator-(const complex& lhs, const complex& rhs); +// operator-(const complex& lhs, const complex& rhs); // constexpr in C++20 #include #include @@ -18,28 +18,21 @@ #include "test_macros.h" template -void -test(const std::complex& lhs, const std::complex& rhs, std::complex x) -{ - assert(lhs - rhs == x); -} - -template -void +TEST_CONSTEXPR_CXX20 +bool test() { { - std::complex lhs(1.5, 2.5); - std::complex rhs(3.5, 4.5); - std::complex x(-2.0, -2.0); - test(lhs, rhs, x); + const std::complex lhs(1.5, 2.5); + const std::complex rhs(3.5, 4.5); + assert(lhs - rhs == std::complex(-2.0, -2.0)); } { - std::complex lhs(1.5, -2.5); - std::complex rhs(-3.5, 4.5); - std::complex x(5.0, -7.0); - test(lhs, rhs, x); + const std::complex lhs(1.5, -2.5); + const std::complex rhs(-3.5, 4.5); + assert(lhs - rhs == std::complex(5.0, -7.0)); } + return true; } int main(int, char**) @@ -48,5 +41,11 @@ test(); test(); +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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 // complex -// operator-(const complex& lhs, const T& rhs); +// operator-(const complex& lhs, const T& rhs); // constexpr in C++20 #include #include @@ -18,28 +18,21 @@ #include "test_macros.h" template -void -test(const std::complex& lhs, const T& rhs, std::complex x) -{ - assert(lhs - rhs == x); -} - -template -void +TEST_CONSTEXPR_CXX20 +bool test() { { - std::complex lhs(1.5, 2.5); - T rhs(3.5); - std::complex x(-2.0, 2.5); - test(lhs, rhs, x); + const std::complex lhs(1.5, 2.5); + const T rhs(3.5); + assert(lhs - rhs == std::complex(-2.0, 2.5)); } { - std::complex lhs(1.5, -2.5); - T rhs(-3.5); - std::complex x(5.0, -2.5); - test(lhs, rhs, x); + const std::complex lhs(1.5, -2.5); + const T rhs(-3.5); + assert(lhs - rhs == std::complex(5.0, -2.5)); } + return true; } int main(int, char**) @@ -48,5 +41,11 @@ test(); test(); +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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 +TEST_CONSTEXPR_CXX20 void test_constexpr() { @@ -35,31 +36,37 @@ #endif } - template -void +TEST_CONSTEXPR_CXX20 +bool test() { { - std::complex lhs(1.5, 2.5); - std::complex rhs(1.5, -2.5); + const std::complex lhs(1.5, 2.5); + const std::complex rhs(1.5, -2.5); assert(lhs != rhs); } { - std::complex lhs(1.5, 2.5); - std::complex rhs(1.5, 2.5); + const std::complex lhs(1.5, 2.5); + const std::complex rhs(1.5, 2.5); assert(!(lhs != rhs)); } test_constexpr (); - } + return true; +} int main(int, char**) { test(); test(); test(); -// test_constexpr (); + +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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 +TEST_CONSTEXPR_CXX20 void test_constexpr() { @@ -46,7 +47,8 @@ } template -void +TEST_CONSTEXPR_CXX20 +bool test() { { @@ -71,6 +73,7 @@ } test_constexpr (); + return true; } int main(int, char**) @@ -78,7 +81,12 @@ test(); test(); test(); -// test_constexpr (); + +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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 // complex -// operator+(const complex& lhs, const complex& rhs); +// operator+(const complex& lhs, const complex& rhs); // constexpr in C++20 #include #include @@ -18,28 +18,22 @@ #include "test_macros.h" template -void -test(const std::complex& lhs, const std::complex& rhs, std::complex x) -{ - assert(lhs + rhs == x); -} - -template -void +TEST_CONSTEXPR_CXX20 +bool test() { { - std::complex lhs(1.5, 2.5); - std::complex rhs(3.5, 4.5); - std::complex x(5.0, 7.0); - test(lhs, rhs, x); + const std::complex lhs(1.5, 2.5); + const std::complex rhs(3.5, 4.5); + assert(lhs + rhs == std::complex(5.0, 7.0)); } { - std::complex lhs(1.5, -2.5); - std::complex rhs(-3.5, 4.5); - std::complex x(-2.0, 2.0); - test(lhs, rhs, x); + const std::complex lhs(1.5, -2.5); + const std::complex rhs(-3.5, 4.5); + assert(lhs + rhs == std::complex(-2.0, 2.0)); } + + return true; } int main(int, char**) @@ -48,5 +42,11 @@ test(); test(); +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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 // complex -// operator+(const complex& lhs, const T& rhs); +// operator+(const complex& lhs, const T& rhs); // constexpr in C++20 #include #include @@ -18,28 +18,22 @@ #include "test_macros.h" template -void -test(const std::complex& lhs, const T& rhs, std::complex x) -{ - assert(lhs + rhs == x); -} - -template -void +TEST_CONSTEXPR_CXX20 +bool test() { { - std::complex lhs(1.5, 2.5); - T rhs(3.5); - std::complex x(5.0, 2.5); - test(lhs, rhs, x); + const std::complex lhs(1.5, 2.5); + const T rhs(3.5); + assert(lhs + rhs == std::complex(5.0, 2.5)); } { - std::complex lhs(1.5, -2.5); - T rhs(-3.5); - std::complex x(-2.0, -2.5); - test(lhs, rhs, x); + const std::complex lhs(1.5, -2.5); + const T rhs(-3.5); + assert(lhs + rhs == std::complex(-2.0, -2.5)); } + + return true; } int main(int, char**) @@ -48,5 +42,11 @@ test(); test(); +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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 // complex -// operator*(const complex& lhs, const complex& rhs); +// operator*(const complex& lhs, const complex& rhs); // constexpr in C++20 + +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=5000000 #include #include @@ -19,56 +21,48 @@ #include "../cases.h" template -void -test(const std::complex& lhs, const std::complex& rhs, std::complex x) -{ - assert(lhs * rhs == x); -} - -template -void +TEST_CONSTEXPR_CXX20 +bool test() { - std::complex lhs(1.5, 2.5); - std::complex rhs(1.5, 2.5); - std::complex x(-4.0, 7.5); - test(lhs, rhs, x); + const std::complex lhs(1.5, 2.5); + const std::complex rhs(1.5, 2.5); + assert(lhs * rhs == std::complex(-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 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 @@ 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 @@ } } } + return true; } int main(int, char**) @@ -159,5 +123,12 @@ test(); test_edges(); +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); + static_assert(test()); + 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 --- 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 // complex -// operator*(const complex& lhs, const T& rhs); +// operator*(const complex& lhs, const T& rhs); // constexpr in C++20 #include #include @@ -18,20 +18,14 @@ #include "test_macros.h" template -void -test(const std::complex& lhs, const T& rhs, std::complex x) -{ - assert(lhs * rhs == x); -} - -template -void +TEST_CONSTEXPR_CXX20 +bool test() { - std::complex lhs(1.5, 2.5); - T rhs(1.5); - std::complex x(2.25, 3.75); - test(lhs, rhs, x); + const std::complex lhs(1.5, 2.5); + const T rhs(1.5); + assert(lhs * rhs == std::complex(2.25, 3.75)); + return true; } int main(int, char**) @@ -40,5 +34,11 @@ test(); test(); +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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 // complex -// operator/(const T& lhs, const complex& rhs); +// operator/(const T& lhs, const complex& rhs); // constexpr in C++20 #include #include @@ -18,20 +18,14 @@ #include "test_macros.h" template -void -test(const T& lhs, const std::complex& rhs, std::complex x) -{ - assert(lhs / rhs == x); -} - -template -void +TEST_CONSTEXPR_CXX20 +bool test() { - T lhs(-8.5); - std::complex rhs(1.5, 2.5); - std::complex x(-1.5, 2.5); - test(lhs, rhs, x); + const T lhs(-8.5); + const std::complex rhs(1.5, 2.5); + assert(lhs / rhs == std::complex(-1.5, 2.5)); + return true; } int main(int, char**) @@ -40,5 +34,11 @@ test(); test(); +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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 +TEST_CONSTEXPR_CXX20 void test_constexpr() { @@ -46,7 +47,8 @@ } template -void +TEST_CONSTEXPR_CXX20 +bool test() { { @@ -71,6 +73,7 @@ } test_constexpr (); + return true; } int main(int, char**) @@ -78,7 +81,12 @@ test(); test(); test(); -// test_constexpr(); + +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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 // complex -// operator-(const T& lhs, const complex& rhs); +// operator-(const T& lhs, const complex& rhs); // constexpr in C++20 #include #include @@ -18,35 +18,33 @@ #include "test_macros.h" template -void -test(const T& lhs, const std::complex& rhs, std::complex x) -{ - assert(lhs - rhs == x); -} - -template -void +TEST_CONSTEXPR_CXX20 +bool test() { { - T lhs(1.5); - std::complex rhs(3.5, 4.5); - std::complex x(-2.0, -4.5); - test(lhs, rhs, x); + const T lhs(1.5); + const std::complex rhs(3.5, 4.5); + assert(lhs - rhs == std::complex(-2.0, -4.5)); } { - T lhs(1.5); - std::complex rhs(-3.5, 4.5); - std::complex x(5.0, -4.5); - test(lhs, rhs, x); + const T lhs(1.5); + const std::complex rhs(-3.5, 4.5); + assert(lhs - rhs == std::complex(5.0, -4.5)); } + return true; } -int main(int, char**) -{ +int main(int, char**) { test(); test(); test(); +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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 +TEST_CONSTEXPR_CXX20 void test_constexpr() { @@ -46,7 +47,8 @@ } template -void +TEST_CONSTEXPR_CXX20 +bool test() { { @@ -71,14 +73,20 @@ } test_constexpr (); - } + return true; +} int main(int, char**) { test(); test(); test(); -// test_constexpr(); + +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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 // complex -// operator+(const T& lhs, const complex& rhs); +// operator+(const T& lhs, const complex& rhs); // constexpr in C++20 #include #include @@ -18,28 +18,21 @@ #include "test_macros.h" template -void -test(const T& lhs, const std::complex& rhs, std::complex x) -{ - assert(lhs + rhs == x); -} - -template -void +TEST_CONSTEXPR_CXX20 +bool test() { { - T lhs(1.5); - std::complex rhs(3.5, 4.5); - std::complex x(5.0, 4.5); - test(lhs, rhs, x); + const T lhs(1.5); + const std::complex rhs(3.5, 4.5); + assert(lhs + rhs == std::complex(5.0, 4.5)); } { - T lhs(1.5); - std::complex rhs(-3.5, 4.5); - std::complex x(-2.0, 4.5); - test(lhs, rhs, x); + const T lhs(1.5); + const std::complex rhs(-3.5, 4.5); + assert(lhs + rhs == std::complex(-2.0, 4.5)); } + return true; } int main(int, char**) @@ -48,5 +41,11 @@ test(); test(); +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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 // complex -// operator*(const T& lhs, const complex& rhs); +// operator*(const T& lhs, const complex& rhs); // constexpr in C++20 #include #include @@ -18,20 +18,14 @@ #include "test_macros.h" template -void -test(const T& lhs, const std::complex& rhs, std::complex x) -{ - assert(lhs * rhs == x); -} - -template -void +TEST_CONSTEXPR_CXX20 +bool test() { - T lhs(1.5); - std::complex rhs(1.5, 2.5); - std::complex x(2.25, 3.75); - test(lhs, rhs, x); + const T lhs(1.5); + const std::complex rhs(1.5, 2.5); + assert(lhs * rhs == std::complex(2.25, 3.75)); + return true; } int main(int, char**) @@ -40,5 +34,11 @@ test(); test(); +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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 // complex -// operator-(const complex& lhs); +// operator-(const complex& lhs); // constexpr in C++20 #include #include @@ -18,15 +18,13 @@ #include "test_macros.h" template -void +TEST_CONSTEXPR_CXX20 +bool test() { - std::complex z(1.5, 2.5); - assert(z.real() == 1.5); - assert(z.imag() == 2.5); - std::complex c = -z; - assert(c.real() == -1.5); - assert(c.imag() == -2.5); + assert(-std::complex(1.5, -2.5) == std::complex(-1.5, 2.5)); + assert(-std::complex(-1.5, 2.5) == std::complex(1.5, -2.5)); + return true; } int main(int, char**) @@ -35,5 +33,11 @@ test(); test(); +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#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 --- 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 // complex -// operator+(const complex&); +// operator+(const complex&); // constexpr in C++20 #include #include @@ -18,22 +18,26 @@ #include "test_macros.h" template -void +TEST_CONSTEXPR_CXX20 +bool test() { - std::complex z(1.5, 2.5); - assert(z.real() == 1.5); - assert(z.imag() == 2.5); - std::complex c = +z; - assert(c.real() == 1.5); - assert(c.imag() == 2.5); + assert(+std::complex(1.5, -2.5) == std::complex(1.5, -2.5)); + assert(+std::complex(-1.5, 2.5) == std::complex(-1.5, 2.5)); + return true; } int main(int, char**) { - test(); - test(); - test(); + test(); + test(); + test(); + +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); + static_assert(test()); +#endif return 0; } diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -231,7 +231,6 @@ "name": "__cpp_lib_constexpr_complex", "values": { "c++20": 201711 }, "headers": ["complex"], - "unimplemented": True, }, { "name": "__cpp_lib_constexpr_dynamic_alloc", "values": { "c++20": 201907 },