Issue 109858
Summary [libc++] Signature of complex `pow` does not allow some user overloads
Labels libc++
Assignees
Reporter SteveBronder
    Testing the Stan math library against clang 19.0.1 we found that one of libc++'s complex pow signatures  is overriding one of our signatures. https://github.com/stan-dev/math/issues/3106

We can fix this by making the exponent's type `const&`, or by users calling `stan::math::pow` fully instead of bringing `pow` into the local scope. But I wanted to suggest a fix here that I think will stop this issue from coming up for other users.

In the `pow` signatures for a complex base and arithmetic exponent, such as the one below from [complex](https://github.com/llvm/llvm-project/blob/a4bf6cd7cfb1a1421ba92bca9d017b49936c55e4/libcxx/include/complex#L1109C1-L1113C2), if a user has a custom type in `complex` this signature will be chosen by the compiler but then fail while calling `__promote`

```c++
template <class _Tp, class _Up, __enable_if_t<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));
}
```

This signature only checks that `Up_` is arithmetic while the compiler is looking for candidates, but then after that signature has been chosen it also requires that `_Tp` is arithmetic since `__promote<_Tp, _Up>` will throw a compiler error from it's static assert if both types are not arithmetic ([code](https://github.com/llvm/llvm-project/pull/81379/files#diff-d62c3ba6f0744bc0a5f7f2996847a72ba90af330f88e1251cc61d95974538c1eR32)). It looks like the signature should be checking that `__promote<_Tp, _Up>` is arithmetic so that users with custom types can add their own `pow` functions with custom complex types.

This could be fixed by adding another NTTP to these functions that checks if the result of `__promote` is valid.

```c++
template <class _Tp, class _Up, 
 __enable_if_t<is_arithmetic<_Up>::value, int> = 0,
 __enable_if_t<is_arithmetic_promotable<_Tp, _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));
}
```

The example of the fix and issue can be found in the godbolt below. You can toggle the `SHOW_ERROR` macro on and off to see the current error and suggested fix

https://godbolt.org/z/1vE665xqT
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to