https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119284
Bug ID: 119284
Summary: Overload resolution selects wrong overload with
`std::invocable` concept and `auto &` in lambda
parameter
Product: gcc
Version: 14.2.1
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: [email protected]
Target Milestone: ---
In the following code the wrong overload is selected if both the
`std::invocable` (1) are required and the parameter of the lambda is `auto &`
(2). Specifically, the compiler selects the `const` overload, which causes a
compiler error.
This happens in GCC-{12,13,14}.
```c++
#include <concepts>
struct S {
void member_func() {
}
};
template<typename F> requires (std::invocable<F, S const &>) // (1) removing
this requires clause makes this compile
void func(S const &x, F f) {
f(x);
}
template<typename F> requires (std::invocable<F, S &>)
void func(S &x, F f) {
f(x);
}
int main() {
S s;
func(s, [](auto &x) { // (2) changing `auto &` to `S &` makes this compile
x.member_func();
});
}
```
## Error Message (from gcc-14)
```
<source>: In instantiation of 'main()::<lambda(auto:1&)> [with auto:1 = const
S]':
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/type_traits:2640:26:
required by substitution of 'template<class _Fn, class ... _Args> static
std::__result_of_success<decltype (declval<_Fn>()((declval<_Args>)()...)),
std::__invoke_other> std::__result_of_other_impl::_S_test(int) [with _Fn =
main()::<lambda(auto:1&)>; _Args = {const S&}]'
2640 | std::declval<_Fn>()(std::declval<_Args>()...)
| ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/type_traits:2651:60:
required from 'struct std::__result_of_impl<false, false,
main()::<lambda(auto:1&)>, const S&>'
2651 | using type = decltype(_S_test<_Functor, _ArgTypes...>(0));
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/type_traits:3159:12:
recursively required by substitution of 'template<class _Result, class _Ret>
struct std::__is_invocable_impl<_Result, _Ret, true, std::__void_t<typename
_CTp::type> > [with _Result = std::__invoke_result<main()::<lambda(auto:1&)>,
const S&>; _Ret = void]'
3159 | struct is_invocable
| ^~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/type_traits:3159:12:
required from 'struct std::is_invocable<main()::<lambda(auto:1&)>, const S&>'
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/type_traits:3523:71:
required from 'constexpr const bool
std::is_invocable_v<main()::<lambda(auto:1&)>, const S&>'
3523 | inline constexpr bool is_invocable_v = is_invocable<_Fn,
_Args...>::value;
|
^~~~~
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/concepts:360:25:
required by substitution of 'template<class F> requires invocable<F, const
S&> void func(const S&, F) [with F = main()::<lambda(auto:1&)>]'
360 | concept invocable = is_invocable_v<_Fn, _Args...>;
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:21:9: required from here
21 | func(s, [](auto &x) {
| ~~~~^~~~~~~~~~~~~~~~~
22 | x.member_func();
| ~~~~~~~~~~~~~~~~
23 | });
| ~~
<source>:22:22: error: passing 'const S' as 'this' argument discards qualifiers
[-fpermissive]
22 | x.member_func();
| ~~~~~~~~~~~~~^~
<source>:4:10: note: in call to 'void S::member_func()'
4 | void member_func() {
| ^~~~~~~~~~~
Compiler returned: 1
```
## Expected Behaviour
Since func is called with non-const `S`, the non-const overload should be
selected.
In the lambda `auto &` should deduce to `S &` and the requires-clause should be
satisfied.