Skip to content

[libc++] Signature of complex pow does not allow some user overloads #109858

Closed
@SteveBronder

Description

@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. stan-dev/math#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, if a user has a custom type in complex this signature will be chosen by the compiler but then fail while calling __promote

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). 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.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    libc++libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions