[Bug c++/119284] Overload resolution selects wrong overload with `std::invocable` concept and `auto &` in lambda parameter

2025-03-17 Thread liss.heidrich--- via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119284

--- Comment #5 from Liss Heidrich  ---
Thank you for your detailed explanation. I was not aware that this is how it
works.

[Bug c++/119284] New: Overload resolution selects wrong overload with `std::invocable` concept and `auto &` in lambda parameter

2025-03-14 Thread liss.heidrich--- via Gcc-bugs
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: liss.heidr...@uni-paderborn.de
  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 

struct S {
void member_func() {
}
};

template requires (std::invocable) // (1) removing
this requires clause makes this compile
void func(S const &x, F f) {
f(x);
}

template requires (std::invocable) 
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)
```
: In instantiation of 'main():: [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 static
std::__result_of_success()((declval<_Args>)()...)),
std::__invoke_other> std::__result_of_other_impl::_S_test(int) [with _Fn =
main()::; _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, 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
struct std::__is_invocable_impl<_Result, _Ret, true, std::__void_t > [with _Result = std::__invoke_result,
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, 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, 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  requires  invocable void func(const S&, F) [with F = main()::]'
  360 | concept invocable = is_invocable_v<_Fn, _Args...>;
  | ^
:21:9:   required from here
   21 | func(s, [](auto &x) {
  | ^
   22 | x.member_func();
  | 
   23 | });
  | ~~   
:22:22: error: passing 'const S' as 'this' argument discards qualifiers
[-fpermissive]
   22 | x.member_func();
  | ~^~
: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.