diff --git a/stl/inc/complex b/stl/inc/complex index dc9ced16f3b..97c3ddd4c67 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -1758,8 +1758,11 @@ template using _Upgrade_to_double = conditional_t, double, _Ty>; template , int> = 0> -_NODISCARD _Upgrade_to_double<_Ty> arg(_Ty) { - return 0; +_NODISCARD _Upgrade_to_double<_Ty> arg(_Ty _Left) { + using _Upgraded = _Upgrade_to_double<_Ty>; + const auto _Val = static_cast<_Upgraded>(_Left); + + return _Ctraits<_Upgraded>::atan2(0, _Val); } template , int> = 0> @@ -1769,22 +1772,40 @@ _NODISCARD _CONSTEXPR20 _Upgrade_to_double<_Ty> imag(_Ty) { template , int> = 0> _NODISCARD _CONSTEXPR20 _Upgrade_to_double<_Ty> real(_Ty _Left) { - return static_cast<_Upgrade_to_double<_Ty>>(_Left); + using _Upgraded = _Upgrade_to_double<_Ty>; + const auto _Val = static_cast<_Upgraded>(_Left); + + return _Val; } template , int> = 0> _NODISCARD _CONSTEXPR20 _Upgrade_to_double<_Ty> norm(_Ty _Left) { - return static_cast<_Upgrade_to_double<_Ty>>(_Left * _Left); + using _Upgraded = _Upgrade_to_double<_Ty>; + const auto _Val = static_cast<_Upgraded>(_Left); + + return _Val * _Val; } template , int> = 0> -_NODISCARD _CONSTEXPR20 _Upgrade_to_double<_Ty> conj(_Ty _Left) { - return static_cast<_Upgrade_to_double<_Ty>>(_Left); +_NODISCARD _CONSTEXPR20 complex<_Upgrade_to_double<_Ty>> conj(_Ty _Left) { + using _Upgraded = _Upgrade_to_double<_Ty>; + const auto _Val = static_cast<_Upgraded>(_Left); + + return complex<_Upgraded>(_Val, -_Upgraded{0}); } template , int> = 0> -_NODISCARD _Upgrade_to_double<_Ty> proj(_Ty _Left) { - return static_cast<_Upgrade_to_double<_Ty>>(_Left); +_NODISCARD complex<_Upgrade_to_double<_Ty>> proj(_Ty _Left) { + using _Upgraded = _Upgrade_to_double<_Ty>; + const auto _Val = static_cast<_Upgraded>(_Left); + + if (_Ctraits<_Upgraded>::_Isinf(_Val)) { + // C11 7.3.9.5/2: "z projects to z except that all complex infinities [...] + // project to positive infinity on the real axis." + return complex<_Upgraded>(_Ctraits<_Upgraded>::_Infv(), 0); + } + + return complex<_Upgraded>(_Val, 0); } // FUNCTION TEMPLATE pow diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index b91c3caf449..5cb45fccb9a 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -597,9 +597,7 @@ std/numerics/complex.number/complex.special/float_long_double_implicit.compile.f std/re/re.traits/transform.pass.cpp FAIL # STL bug: Incorrect return types. -std/numerics/complex.number/cmplx.over/conj.pass.cpp FAIL std/numerics/complex.number/cmplx.over/pow.pass.cpp FAIL -std/numerics/complex.number/cmplx.over/proj.pass.cpp FAIL # STL bug: Missing assignment operators. std/numerics/numarray/template.mask.array/mask.array.assign/mask_array.pass.cpp FAIL @@ -846,6 +844,10 @@ std/iterators/predef.iterators/insert.iterators/back.insert.iterator/types.pass. std/iterators/predef.iterators/insert.iterators/front.insert.iterator/types.pass.cpp SKIPPED std/iterators/predef.iterators/insert.iterators/insert.iterator/types.pass.cpp SKIPPED +# Tests emit warning C4244: 'argument': conversion from 'T' to 'const std::complex::_Ty', possible loss of data +std/numerics/complex.number/cmplx.over/conj.pass.cpp:0 FAIL +std/numerics/complex.number/cmplx.over/proj.pass.cpp:0 FAIL + # *** LIKELY STL BUGS *** # Not yet analyzed, likely STL bugs. Assertions and other runtime failures. diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index 9f53e131880..dcba77ec788 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -597,9 +597,7 @@ numerics\complex.number\complex.special\float_long_double_implicit.compile.fail. re\re.traits\transform.pass.cpp # STL bug: Incorrect return types. -numerics\complex.number\cmplx.over\conj.pass.cpp numerics\complex.number\cmplx.over\pow.pass.cpp -numerics\complex.number\cmplx.over\proj.pass.cpp # STL bug: Missing assignment operators. numerics\numarray\template.mask.array\mask.array.assign\mask_array.pass.cpp @@ -846,6 +844,10 @@ iterators\predef.iterators\insert.iterators\back.insert.iterator\types.pass.cpp iterators\predef.iterators\insert.iterators\front.insert.iterator\types.pass.cpp iterators\predef.iterators\insert.iterators\insert.iterator\types.pass.cpp +# Tests emit warning C4244: 'argument': conversion from 'T' to 'const std::complex::_Ty', possible loss of data +numerics\complex.number\cmplx.over\conj.pass.cpp +numerics\complex.number\cmplx.over\proj.pass.cpp + # *** LIKELY STL BUGS *** # Not yet analyzed, likely STL bugs. Assertions and other runtime failures. diff --git a/tests/std/tests/Dev10_555491_complex_linker_errors/test.cpp b/tests/std/tests/Dev10_555491_complex_linker_errors/test.cpp index 781374770d4..77e1fdbd773 100644 --- a/tests/std/tests/Dev10_555491_complex_linker_errors/test.cpp +++ b/tests/std/tests/Dev10_555491_complex_linker_errors/test.cpp @@ -2,12 +2,17 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include +#include #include +#include #include #include +#include using namespace std; +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + template T pseudo_bit_cast(const U& source) { static_assert(sizeof(T) == sizeof(U), ""); @@ -90,4 +95,57 @@ int main() { assert(nearly_equal_partwise(asinh(-1e+307 + 2e+307i), -708.3914896859491 + 1.1071487177940904i)); assert(nearly_equal_partwise(asinh(-2e+37f + 4e+37if), -87.386663f + 1.1071488if)); assert(nearly_equal_partwise(asinh(-1e+307L + 2e+307il), -708.3914896859491L + 1.1071487177940904il)); + + // Also test GH-785 ": std::arg does not work for negative real values" + + STATIC_ASSERT(is_same_v); + STATIC_ASSERT(is_same_v); + STATIC_ASSERT(is_same_v); + STATIC_ASSERT(is_same_v); + STATIC_ASSERT(is_same_v>); + STATIC_ASSERT(is_same_v>); + + STATIC_ASSERT(is_same_v); + STATIC_ASSERT(is_same_v); + STATIC_ASSERT(is_same_v); + STATIC_ASSERT(is_same_v); + STATIC_ASSERT(is_same_v>); + STATIC_ASSERT(is_same_v>); + + STATIC_ASSERT(is_same_v); + STATIC_ASSERT(is_same_v); + STATIC_ASSERT(is_same_v); + STATIC_ASSERT(is_same_v); + STATIC_ASSERT(is_same_v>); + STATIC_ASSERT(is_same_v>); + + STATIC_ASSERT(is_same_v); + STATIC_ASSERT(is_same_v); + STATIC_ASSERT(is_same_v); + STATIC_ASSERT(is_same_v); + STATIC_ASSERT(is_same_v>); + STATIC_ASSERT(is_same_v>); + + assert((arg(-1.0) == arg(complex{-1.0, 0.0}))); + assert((arg(-1) == arg(complex{-1.0, 0.0}))); + + assert(imag(1729.0) == 0.0); + assert(imag(1729) == 0.0); + + assert(real(1729.0) == 1729.0); + assert(real(1729) == 1729.0); + + assert(norm(0x1p63) == 0x1p126); + assert(norm(0x8000'0000'0000'0000ULL) == 0x1p126); + + assert((conj(1729.0) == complex{1729.0, -0.0})); + assert((conj(1729) == complex{1729.0, -0.0})); + assert(signbit(conj(1729.0).imag())); + assert(signbit(conj(1729).imag())); + + assert((proj(1729.0) == complex{1729.0, 0.0})); + assert((proj(1729) == complex{1729.0, 0.0})); + constexpr double inf = numeric_limits::infinity(); + assert((proj(inf) == complex{inf, 0.0})); + assert((proj(-inf) == complex{inf, 0.0})); }