diff options
author | A. Jiang <de34@live.cn> | 2024-10-30 07:16:40 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-30 07:16:40 +0800 |
commit | 0f8dbb2fac532e37a9859d52982f0e8994305a11 (patch) | |
tree | 71d2c8d3e215f59b7284b3e199146307124ded89 | |
parent | f71ea0e72e2419691e3c67bdbbe338d314ee77c0 (diff) | |
download | llvm-0f8dbb2fac532e37a9859d52982f0e8994305a11.zip llvm-0f8dbb2fac532e37a9859d52982f0e8994305a11.tar.gz llvm-0f8dbb2fac532e37a9859d52982f0e8994305a11.tar.bz2 |
[libc++] Constrain additional overloads of `pow` for `complex` harder (#110235)
Fixes #109858.
The changes in #81379 broke some 3rd party library code that expected
usability of `std::complex<NonFloatingPoint>`. Although such code isn't
portable per [complex.numbers.general]/2, it might be better to make
these additional overloads not to interfere overload resolution too
much.
---------
Co-authored-by: Louis Dionne <ldionne.2@gmail.com>
-rw-r--r-- | libcxx/include/complex | 6 | ||||
-rw-r--r-- | libcxx/test/libcxx/numerics/complex.number/cmplx.over.pow.pass.cpp | 84 |
2 files changed, 87 insertions, 3 deletions
diff --git a/libcxx/include/complex b/libcxx/include/complex index 4030d96..15e4280 100644 --- a/libcxx/include/complex +++ b/libcxx/include/complex @@ -1097,20 +1097,20 @@ inline _LIBCPP_HIDE_FROM_ABI complex<_Tp> pow(const complex<_Tp>& __x, const com return std::exp(__y * std::log(__x)); } -template <class _Tp, class _Up> +template <class _Tp, class _Up, __enable_if_t<is_floating_point<_Tp>::value && is_floating_point<_Up>::value, int> = 0> inline _LIBCPP_HIDE_FROM_ABI complex<typename __promote<_Tp, _Up>::type> pow(const complex<_Tp>& __x, const complex<_Up>& __y) { typedef complex<typename __promote<_Tp, _Up>::type> result_type; return std::pow(result_type(__x), result_type(__y)); } -template <class _Tp, class _Up, __enable_if_t<is_arithmetic<_Up>::value, int> = 0> +template <class _Tp, class _Up, __enable_if_t<is_floating_point<_Tp>::value && is_arithmetic<_Up>::value, int> = 0> inline _LIBCPP_HIDE_FROM_ABI complex<typename __promote<_Tp, _Up>::type> pow(const complex<_Tp>& __x, const _Up& __y) { typedef complex<typename __promote<_Tp, _Up>::type> result_type; return std::pow(result_type(__x), result_type(__y)); } -template <class _Tp, class _Up, __enable_if_t<is_arithmetic<_Tp>::value, int> = 0> +template <class _Tp, class _Up, __enable_if_t<is_arithmetic<_Tp>::value && is_floating_point<_Up>::value, int> = 0> inline _LIBCPP_HIDE_FROM_ABI complex<typename __promote<_Tp, _Up>::type> pow(const _Tp& __x, const complex<_Up>& __y) { typedef complex<typename __promote<_Tp, _Up>::type> result_type; return std::pow(result_type(__x), result_type(__y)); diff --git a/libcxx/test/libcxx/numerics/complex.number/cmplx.over.pow.pass.cpp b/libcxx/test/libcxx/numerics/complex.number/cmplx.over.pow.pass.cpp new file mode 100644 index 0000000..1c790c2 --- /dev/null +++ b/libcxx/test/libcxx/numerics/complex.number/cmplx.over.pow.pass.cpp @@ -0,0 +1,84 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// <complex> + +// template<class T, class U> complex<__promote<T, U>::type> pow(const complex<T>&, const U&); +// template<class T, class U> complex<__promote<T, U>::type> pow(const complex<T>&, const complex<U>&); +// template<class T, class U> complex<__promote<T, U>::type> pow(const T&, const complex<U>&); + +// Test that these additional overloads are free from catching std::complex<non-floating-point>, +// which is expected by several 3rd party libraries, see https://github.com/llvm/llvm-project/issues/109858. +// +// Note that we reserve the right to break this in the future if we have a reason to, but for the time being, +// make sure we don't break this property unintentionally. +#include <cassert> +#include <cmath> +#include <complex> +#include <type_traits> + +#include "test_macros.h" + +namespace usr { +struct usr_tag {}; + +template <class T, class U> +typename std::enable_if<(std::is_same<T, usr_tag>::value && std::is_floating_point<U>::value) || + (std::is_floating_point<T>::value && std::is_same<U, usr_tag>::value), + int>::type +pow(const T&, const std::complex<U>&) { + return std::is_same<T, usr_tag>::value ? 0 : 1; +} + +template <class T, class U> +typename std::enable_if<(std::is_same<T, usr_tag>::value && std::is_floating_point<U>::value) || + (std::is_floating_point<T>::value && std::is_same<U, usr_tag>::value), + int>::type +pow(const std::complex<T>&, const U&) { + return std::is_same<U, usr_tag>::value ? 2 : 3; +} + +template <class T, class U> +typename std::enable_if<(std::is_same<T, usr_tag>::value && std::is_floating_point<U>::value) || + (std::is_floating_point<T>::value && std::is_same<U, usr_tag>::value), + int>::type +pow(const std::complex<T>&, const std::complex<U>&) { + return std::is_same<T, usr_tag>::value ? 4 : 5; +} +} // namespace usr + +int main(int, char**) { + using std::pow; + using usr::pow; + + usr::usr_tag tag; + const std::complex<usr::usr_tag> ctag; + + assert(pow(tag, std::complex<float>(1.0f)) == 0); + assert(pow(std::complex<float>(1.0f), tag) == 2); + assert(pow(tag, std::complex<double>(1.0)) == 0); + assert(pow(std::complex<double>(1.0), tag) == 2); + assert(pow(tag, std::complex<long double>(1.0l)) == 0); + assert(pow(std::complex<long double>(1.0l), tag) == 2); + + assert(pow(1.0f, ctag) == 1); + assert(pow(ctag, 1.0f) == 3); + assert(pow(1.0, ctag) == 1); + assert(pow(ctag, 1.0) == 3); + assert(pow(1.0l, ctag) == 1); + assert(pow(ctag, 1.0l) == 3); + + assert(pow(ctag, std::complex<float>(1.0f)) == 4); + assert(pow(std::complex<float>(1.0f), ctag) == 5); + assert(pow(ctag, std::complex<double>(1.0)) == 4); + assert(pow(std::complex<double>(1.0), ctag) == 5); + assert(pow(ctag, std::complex<long double>(1.0l)) == 4); + assert(pow(std::complex<long double>(1.0l), ctag) == 5); + + return 0; +} |