[libc++] std::invoke() substitution failure when using function object with default argument
tcbrindle opened this issue · 4 comments
The following test program compiles with libc++17 and libstdc++, but fails with libc++18:
#include <concepts>
#include <functional>
#include <ranges>
#include <source_location>
#define FWD(x) static_cast<decltype(x)&&>(x)
struct add_fn {
template <std::integral T>
constexpr auto operator()(T lhs, T rhs,
std::source_location loc = std::source_location::current())
const -> T
{
return lhs + rhs;
}
};
inline constexpr auto add = add_fn{};
struct fold_op {
template <typename Rng, typename Func, typename Init>
constexpr auto operator()(Rng&& rng, Func func, Init init) const
{
auto init_ = std::ranges::range_value_t<Rng>(std::move(init));
for (auto&& elem : rng) {
init_ = std::invoke(func, std::move(init_), FWD(elem));
}
return init_;
}
};
inline constexpr auto fold = fold_op{};
auto sum(std::span<int const> arr) -> int
{
return fold(arr, add, 0);
}
https://godbolt.org/z/h47dnM3eP
The error is:
<source>:27:21: error: no matching function for call to 'invoke'
27 | init_ = std::invoke(func, std::move(init_), FWD(elem));
| ^~~~~~~~~~~
<source>:38:16: note: in instantiation of function template specialization 'fold_op::operator()<std::span<const int> &, add_fn, int>' requested here
38 | return fold(arr, add, 0);
| ^
/opt/compiler-explorer/clang-18.1.0/bin/../include/c++/v1/__functional/invoke.h:27:1: note: candidate template ignored: substitution failure [with _Fn = add_fn &, _Args = <__libcpp_remove_reference_t<int &>, const int &>]
27 | invoke(_Fn&& __f, _Args&&... __args) noexcept(is_nothrow_invocable_v<_Fn, _Args...>) {
| ^
1 error generated.
Compiler returned: 1
Removing the source_location
default argument from add_fn::operator()
allows the code to compile as expected.
This appears to be a Clang regression in Clang 18, not in libc++.
Reduced: https://godbolt.org/z/TMc3Wqjb8
template <class _Fp, class... _Args>
decltype(_Fp{}(0, 0))
__invoke(_Fp&& __f);
template<typename T>
struct type_identity { using type = T; };
template<class Fn>
struct invoke_result : type_identity<decltype(__invoke(Fn{}))> {};
namespace std {
struct source_location {
struct __impl {
const char *_M_file_name;
const char *_M_function_name;
unsigned _M_line;
unsigned _M_column;
};
};
}
struct add_fn {
template <typename T>
constexpr auto operator()(T lhs, T rhs,
const std::source_location::__impl* = __builtin_source_location())
const -> T
{
return lhs + rhs;
}
};
using i = invoke_result<add_fn>::type;
static_assert(__is_same(i, int));
<source>:39:25: error: unknown type name 'i'
34 | static_assert(__is_same(i, int));
| ^
@llvm/issue-subscribers-clang-frontend
Author: Tristan Brindle (tcbrindle)
#include <concepts>
#include <functional>
#include <ranges>
#include <source_location>
#define FWD(x) static_cast<decltype(x)&&>(x)
struct add_fn {
template <std::integral T>
constexpr auto operator()(T lhs, T rhs,
std::source_location loc = std::source_location::current())
const -> T
{
return lhs + rhs;
}
};
inline constexpr auto add = add_fn{};
struct fold_op {
template <typename Rng, typename Func, typename Init>
constexpr auto operator()(Rng&& rng, Func func, Init init) const
{
auto init_ = std::ranges::range_value_t<Rng>(std::move(init));
for (auto&& elem : rng) {
init_ = std::invoke(func, std::move(init_), FWD(elem));
}
return init_;
}
};
inline constexpr auto fold = fold_op{};
auto sum(std::span<int const> arr) -> int
{
return fold(arr, add, 0);
}
https://godbolt.org/z/h47dnM3eP
The error is:
<source>:27:21: error: no matching function for call to 'invoke'
27 | init_ = std::invoke(func, std::move(init_), FWD(elem));
| ^~~~~~~~~~~
<source>:38:16: note: in instantiation of function template specialization 'fold_op::operator()<std::span<const int> &, add_fn, int>' requested here
38 | return fold(arr, add, 0);
| ^
/opt/compiler-explorer/clang-18.1.0/bin/../include/c++/v1/__functional/invoke.h:27:1: note: candidate template ignored: substitution failure [with _Fn = add_fn &, _Args = <__libcpp_remove_reference_t<int &>, const int &>]
27 | invoke(_Fn&& __f, _Args&&... __args) noexcept(is_nothrow_invocable_v<_Fn, _Args...>) {
| ^
1 error generated.
Compiler returned: 1
Removing the source_location
default argument from add_fn::operator()
allows the code to compile as expected.
Will there ever be a patch for clang-18? Or will this be broken for ever for this whole major version?
@DNKpp We're in the LLVM 20 release cycle now, so fixes will only be back-ported to LLVM 19.