Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 29 additions & 8 deletions stl/inc/complex
Original file line number Diff line number Diff line change
Expand Up @@ -1758,8 +1758,11 @@ template <class _Ty>
using _Upgrade_to_double = conditional_t<is_integral_v<_Ty>, double, _Ty>;

template <class _Ty, enable_if_t<is_arithmetic_v<_Ty>, int> = 0>
_NODISCARD _Upgrade_to_double<_Ty> arg(_Ty) {
return 0;
_NODISCARD _Upgrade_to_double<_Ty> arg(_Ty _Left) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_Left could be const for all of these.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep - but as these are very small functions and test runs are at a premium right now, I'll refrain from further cleanups in this PR.

using _Upgraded = _Upgrade_to_double<_Ty>;
const auto _Val = static_cast<_Upgraded>(_Left);

return _Ctraits<_Upgraded>::atan2(0, _Val);
}

template <class _Ty, enable_if_t<is_arithmetic_v<_Ty>, int> = 0>
Expand All @@ -1769,22 +1772,40 @@ _NODISCARD _CONSTEXPR20 _Upgrade_to_double<_Ty> imag(_Ty) {

template <class _Ty, enable_if_t<is_arithmetic_v<_Ty>, 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 <class _Ty, enable_if_t<is_arithmetic_v<_Ty>, 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 <class _Ty, enable_if_t<is_arithmetic_v<_Ty>, 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 <class _Ty, enable_if_t<is_arithmetic_v<_Ty>, 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
Expand Down
6 changes: 4 additions & 2 deletions tests/libcxx/expected_results.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 <valarray> assignment operators.
std/numerics/numarray/template.mask.array/mask.array.assign/mask_array.pass.cpp FAIL
Expand Down Expand Up @@ -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<double>::_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.
Expand Down
6 changes: 4 additions & 2 deletions tests/libcxx/skipped_tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 <valarray> assignment operators.
numerics\numarray\template.mask.array\mask.array.assign\mask_array.pass.cpp
Expand Down Expand Up @@ -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<double>::_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.
Expand Down
58 changes: 58 additions & 0 deletions tests/std/tests/Dev10_555491_complex_linker_errors/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <assert.h>
#include <cmath>
#include <complex>
#include <limits>
#include <stdint.h>
#include <string.h>
#include <type_traits>

using namespace std;

#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)

template <class T, class U>
T pseudo_bit_cast(const U& source) {
static_assert(sizeof(T) == sizeof(U), "");
Expand Down Expand Up @@ -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 "<complex>: std::arg does not work for negative real values"

STATIC_ASSERT(is_same_v<decltype(arg(1729)), double>);
Comment thread
StephanTLavavej marked this conversation as resolved.
STATIC_ASSERT(is_same_v<decltype(imag(1729)), double>);
STATIC_ASSERT(is_same_v<decltype(real(1729)), double>);
STATIC_ASSERT(is_same_v<decltype(norm(1729)), double>);
STATIC_ASSERT(is_same_v<decltype(conj(1729)), complex<double>>);
STATIC_ASSERT(is_same_v<decltype(proj(1729)), complex<double>>);

STATIC_ASSERT(is_same_v<decltype(arg(1729.0f)), float>);
STATIC_ASSERT(is_same_v<decltype(imag(1729.0f)), float>);
STATIC_ASSERT(is_same_v<decltype(real(1729.0f)), float>);
STATIC_ASSERT(is_same_v<decltype(norm(1729.0f)), float>);
STATIC_ASSERT(is_same_v<decltype(conj(1729.0f)), complex<float>>);
STATIC_ASSERT(is_same_v<decltype(proj(1729.0f)), complex<float>>);

STATIC_ASSERT(is_same_v<decltype(arg(1729.0)), double>);
STATIC_ASSERT(is_same_v<decltype(imag(1729.0)), double>);
STATIC_ASSERT(is_same_v<decltype(real(1729.0)), double>);
STATIC_ASSERT(is_same_v<decltype(norm(1729.0)), double>);
STATIC_ASSERT(is_same_v<decltype(conj(1729.0)), complex<double>>);
STATIC_ASSERT(is_same_v<decltype(proj(1729.0)), complex<double>>);

STATIC_ASSERT(is_same_v<decltype(arg(1729.0L)), long double>);
STATIC_ASSERT(is_same_v<decltype(imag(1729.0L)), long double>);
STATIC_ASSERT(is_same_v<decltype(real(1729.0L)), long double>);
STATIC_ASSERT(is_same_v<decltype(norm(1729.0L)), long double>);
STATIC_ASSERT(is_same_v<decltype(conj(1729.0L)), complex<long double>>);
STATIC_ASSERT(is_same_v<decltype(proj(1729.0L)), complex<long double>>);

assert((arg(-1.0) == arg(complex<double>{-1.0, 0.0})));
assert((arg(-1) == arg(complex<double>{-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<double>{1729.0, -0.0}));
assert((conj(1729) == complex<double>{1729.0, -0.0}));
assert(signbit(conj(1729.0).imag()));
assert(signbit(conj(1729).imag()));

assert((proj(1729.0) == complex<double>{1729.0, 0.0}));
assert((proj(1729) == complex<double>{1729.0, 0.0}));
constexpr double inf = numeric_limits<double>::infinity();
assert((proj(inf) == complex<double>{inf, 0.0}));
assert((proj(-inf) == complex<double>{inf, 0.0}));
}