Bug 85118 - [6 Regression] Error when using std::bind with a generic lambda - "cannot bind 'const volatile char&' to an rvalue of type 'const volatile char'"
Summary: [6 Regression] Error when using std::bind with a generic lambda - "cannot bin...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 7.3.0
: P2 normal
Target Milestone: 6.5
Assignee: Jason Merrill
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2018-03-29 10:46 UTC by Mykhailo Kremniov
Modified: 2018-10-12 12:39 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work: 4.9.4, 5.5.0
Known to fail: 6.4.0, 7.3.0, 8.0.1
Last reconfirmed: 2018-03-29 00:00:00


Attachments
Preprocessed test code (74.81 KB, text/plain)
2018-03-29 10:46 UTC, Mykhailo Kremniov
Details
reduced testcase (713 bytes, text/plain)
2018-04-03 17:51 UTC, Jonathan Wakely
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Mykhailo Kremniov 2018-03-29 10:46:24 UTC
Created attachment 43794 [details]
Preprocessed test code

Seemingly innocent code gives a strange error "cannot bind 'const volatile char&' to an rvalue of type 'const volatile char'".

The code:
===
#include <functional>

template <typename T>
bool isOneOf(const T& /*t*/)
{
    return false;
}

template <typename T, typename FirstType, typename... Tail>
bool isOneOf(const T& t, const FirstType& firstValue, const Tail&... tail)
{
    return t == firstValue || isOneOf(t, tail...);
}

int main()
{
    const auto isOneOfHelper = [](auto&&... params)
    {
        return isOneOf(std::forward<decltype(params)>(params)...);
    };
    
    auto isO = std::bind(isOneOfHelper, std::placeholders::_1, 'o');
    
    isO('o');
}
===

GCC version:
===
$ g++-7.3.0 -v
Using built-in specs.
COLLECT_GCC=g++-7.3.0
COLLECT_LTO_WRAPPER=/home/brd/soft/gcc-7.3.0/libexec/gcc/x86_64-pc-linux-gnu/7.3.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ./configure --prefix=/home/brd/soft/gcc-7.3.0
Thread model: posix
gcc version 7.3.0 (GCC)
===

The error:
===
$ g++-7.3.0 ~/tmp/test.cpp -std=c++14 -o test -save-temps
/home/brd/tmp/test.cpp: In instantiation of ‘main()::<lambda(auto:1&& ...)> [with auto:1 = {char, const volatile char}]’:
/home/brd/tmp/test.cpp:17:51:   required by substitution of ‘template<class ... auto:1> main()::<lambda(auto:1&& ...)>::operator decltype (((const main()::<lambda(auto:1&& ...)>*)((const main()::<lambda(auto:1&& ...)>* const)0))->operator()(static_cast<auto:1&>(main::__lambda0::_FUN::<unnamed>) ...)) (*)(auto:1&& ...)() const [with auto:1 = {char, const volatile char}]’
/home/brd/soft/gcc-7.3.0/include/c++/7.3.0/type_traits:2428: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 = const volatile main()::<lambda(auto:1&& ...)>&; _Args = {char&&, const volatile char&}]’
/home/brd/soft/gcc-7.3.0/include/c++/7.3.0/type_traits:2439:55:   required from ‘struct std::__result_of_impl<false, false, const volatile main()::<lambda(auto:1&& ...)>&, char&&, const volatile char&>’
/home/brd/soft/gcc-7.3.0/include/c++/7.3.0/type_traits:2444:12:   required from ‘struct std::__invoke_result<const volatile main()::<lambda(auto:1&& ...)>&, char&&, const volatile char&>’
/home/brd/soft/gcc-7.3.0/include/c++/7.3.0/type_traits:2457:12:   required from ‘class std::result_of<const volatile main()::<lambda(auto:1&& ...)>&(char&&, const volatile char&)>’
/home/brd/soft/gcc-7.3.0/include/c++/7.3.0/functional:511:72:   required by substitution of ‘template<class _Functor, class ... _Bound_args> template<class _Fn, class _CallArgs, class ... _BArgs> using _Res_type_impl = typename std::result_of<_Fn&(std::_Bind<_Functor(_Bound_args ...)>::_Mu_type<_BArgs, _CallArgs>&& ...)>::type [with _Fn = std::add_cv<main()::<lambda(auto:1&& ...)> >::type; _CallArgs = std::tuple<char>; _BArgs = {std::add_cv<std::_Placeholder<1> >::type, std::add_cv<char>::type}; _Functor = main()::<lambda(auto:1&& ...)>; _Bound_args = {std::_Placeholder<1>, char}]’
/home/brd/soft/gcc-7.3.0/include/c++/7.3.0/functional:524:46:   required by substitution of ‘template<class _Functor, class ... _Bound_args> template<class _CallArgs, template<class _CallArgs, template<class> class __cv_quals> template<class _Functor, class ... _Bound_args> template<class> class __cv_quals> using _Res_type_cv = std::_Bind<_Functor(_Bound_args ...)>::_Res_type_impl<typename __cv_quals<typename std::enable_if<(bool)((std::tuple_size<_Tuple>::value + 1)), _Functor>::type>::type, _CallArgs, typename __cv_quals<_Bound_args>::type ...> [with _CallArgs = std::tuple<char>; __cv_quals = std::add_cv; _Functor = main()::<lambda(auto:1&& ...)>; _Bound_args = {std::_Placeholder<1>, char}]’
/home/brd/soft/gcc-7.3.0/include/c++/7.3.0/functional:585:9:   required by substitution of ‘template<class ... _Args, class _Result> _Result std::_Bind<main()::<lambda(auto:1&& ...)>(std::_Placeholder<1>, char)>::operator()<_Args ..., _Result>(_Args&& ...) const volatile [with _Args = {char}; _Result = <missing>]’
/home/brd/tmp/test.cpp:24:12:   required from here
/home/brd/tmp/test.cpp:19:23: error: no matching function for call to ‘isOneOf(char, const volatile char)’
         return isOneOf(std::forward<decltype(params)>(params)...);
                ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/brd/tmp/test.cpp:4:6: note: candidate: template<class T> bool isOneOf(const T&)
 bool isOneOf(const T& /*t*/)
      ^~~~~~~
/home/brd/tmp/test.cpp:4:6: note:   template argument deduction/substitution failed:
/home/brd/tmp/test.cpp:19:23: note:   candidate expects 1 argument, 2 provided
         return isOneOf(std::forward<decltype(params)>(params)...);
                ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/brd/tmp/test.cpp:10:6: note: candidate: bool isOneOf(const T&, const FirstType&, const Tail& ...) [with T = char; FirstType = volatile char; Tail = {}] <near match>
 bool isOneOf(const T& t, const FirstType& firstValue, const Tail&... tail)
      ^~~~~~~
/home/brd/tmp/test.cpp:10:6: note:   conversion of argument 2 would be ill-formed:
/home/brd/tmp/test.cpp:19:23: error: cannot bind non-const lvalue reference of type ‘const volatile char&’ to an rvalue of type ‘const volatile char’
         return isOneOf(std::forward<decltype(params)>(params)...);
                ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/brd/tmp/test.cpp: In instantiation of ‘main()::<lambda(auto:1&& ...)> [with auto:1 = {char, volatile char}]’:
/home/brd/tmp/test.cpp:17:51:   required by substitution of ‘template<class ... auto:1> main()::<lambda(auto:1&& ...)>::operator decltype (((const main()::<lambda(auto:1&& ...)>*)((const main()::<lambda(auto:1&& ...)>* const)0))->operator()(static_cast<auto:1&>(main::__lambda0::_FUN::<unnamed>) ...)) (*)(auto:1&& ...)() const [with auto:1 = {char, volatile char}]’
/home/brd/soft/gcc-7.3.0/include/c++/7.3.0/type_traits:2428: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 = volatile main()::<lambda(auto:1&& ...)>&; _Args = {char&&, volatile char&}]’
/home/brd/soft/gcc-7.3.0/include/c++/7.3.0/type_traits:2439:55:   required from ‘struct std::__result_of_impl<false, false, volatile main()::<lambda(auto:1&& ...)>&, char&&, volatile char&>’
/home/brd/soft/gcc-7.3.0/include/c++/7.3.0/type_traits:2444:12:   required from ‘struct std::__invoke_result<volatile main()::<lambda(auto:1&& ...)>&, char&&, volatile char&>’
/home/brd/soft/gcc-7.3.0/include/c++/7.3.0/type_traits:2457:12:   required from ‘class std::result_of<volatile main()::<lambda(auto:1&& ...)>&(char&&, volatile char&)>’
/home/brd/soft/gcc-7.3.0/include/c++/7.3.0/functional:511:72:   required by substitution of ‘template<class _Functor, class ... _Bound_args> template<class _Fn, class _CallArgs, class ... _BArgs> using _Res_type_impl = typename std::result_of<_Fn&(std::_Bind<_Functor(_Bound_args ...)>::_Mu_type<_BArgs, _CallArgs>&& ...)>::type [with _Fn = std::add_volatile<main()::<lambda(auto:1&& ...)> >::type; _CallArgs = std::tuple<char>; _BArgs = {std::add_volatile<std::_Placeholder<1> >::type, std::add_volatile<char>::type}; _Functor = main()::<lambda(auto:1&& ...)>; _Bound_args = {std::_Placeholder<1>, char}]’
/home/brd/soft/gcc-7.3.0/include/c++/7.3.0/functional:524:46:   required by substitution of ‘template<class _Functor, class ... _Bound_args> template<class _CallArgs, template<class _CallArgs, template<class> class __cv_quals> template<class _Functor, class ... _Bound_args> template<class> class __cv_quals> using _Res_type_cv = std::_Bind<_Functor(_Bound_args ...)>::_Res_type_impl<typename __cv_quals<typename std::enable_if<(bool)((std::tuple_size<_Tuple>::value + 1)), _Functor>::type>::type, _CallArgs, typename __cv_quals<_Bound_args>::type ...> [with _CallArgs = std::tuple<char>; __cv_quals = std::add_volatile; _Functor = main()::<lambda(auto:1&& ...)>; _Bound_args = {std::_Placeholder<1>, char}]’
/home/brd/soft/gcc-7.3.0/include/c++/7.3.0/functional:573:9:   required by substitution of ‘template<class ... _Args, class _Result> _Result std::_Bind<main()::<lambda(auto:1&& ...)>(std::_Placeholder<1>, char)>::operator()<_Args ..., _Result>(_Args&& ...) volatile [with _Args = {char}; _Result = <missing>]’
/home/brd/tmp/test.cpp:24:12:   required from here
/home/brd/tmp/test.cpp:19:23: error: no matching function for call to ‘isOneOf(char, volatile char)’
/home/brd/tmp/test.cpp:4:6: note: candidate: template<class T> bool isOneOf(const T&)
 bool isOneOf(const T& /*t*/)
      ^~~~~~~
/home/brd/tmp/test.cpp:4:6: note:   template argument deduction/substitution failed:
/home/brd/tmp/test.cpp:19:23: note:   candidate expects 1 argument, 2 provided
         return isOneOf(std::forward<decltype(params)>(params)...);
                ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/brd/tmp/test.cpp:10:6: note: candidate: bool isOneOf(const T&, const FirstType&, const Tail& ...) [with T = char; FirstType = volatile char; Tail = {}] <near match>
 bool isOneOf(const T& t, const FirstType& firstValue, const Tail&... tail)
      ^~~~~~~
/home/brd/tmp/test.cpp:10:6: note:   conversion of argument 2 would be ill-formed:
/home/brd/tmp/test.cpp:19:23: error: cannot bind non-const lvalue reference of type ‘const volatile char&’ to an rvalue of type ‘volatile char’
         return isOneOf(std::forward<decltype(params)>(params)...);
                ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
===

P.S. I also tried GCC 6.3.0 (got similar error) and 5.2.0 (no errors).
Comment 1 Richard Biener 2018-03-29 12:15:25 UTC
clang accepts it as well.
Comment 2 Jonathan Wakely 2018-04-03 11:53:14 UTC
Ugh, this again. I've battled with this when working on the implementation of std::bind. I'll try to reduce it to something independent of the library headers.
Comment 3 Jonathan Wakely 2018-04-03 15:50:16 UTC
Started to be rejected with r233719

            PR c++/69842
            * method.c (forward_parm): Handle parameter packs.
            * lambda.c (maybe_add_lambda_conv_op): Use it for them.

Still reducing it.
Comment 4 Jonathan Wakely 2018-04-03 17:51:31 UTC
Created attachment 43831 [details]
reduced testcase
Comment 5 Jonathan Wakely 2018-04-03 17:55:09 UTC
GCC 5, Clang and EDG all compile it.

GCC 6 onwards fail with:

85118.C: In instantiation of 'main()::<lambda(auto:1&& ...)> [with auto:1 = {volatile char}]':
85118.C:114:51:   required by substitution of 'template<class ... auto:1> main()::<lambda(auto:1&& ...)>::operator decltype (((const main()::<lambda(auto:1&& ...)>*)((const main()::<lambda(auto:1&& ...)>* const)0u))->operator()(static_cast<auto:1&>(main::__lambda0::_FUN::<unnamed>) ...)) (*)(auto:1&& ...)() const [with auto:1 = {volatile char}]'
85118.C:79:56:   required by substitution of 'template<class _Args, class _Result> _Result std::_Bind<_Functor, _Bound_args>::operator()(_Args&&) volatile [with _Args = char; _Result = <missing>]'
85118.C:121:12:   required from here
85118.C:116:23: error: no matching function for call to 'isOneOf(volatile char)'
         return isOneOf(std::forward<decltype(params)>(params)...);
                ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
85118.C:101:6: note: candidate: bool isOneOf(const T&) [with T = volatile char] <near match>
 bool isOneOf(const T& )
      ^~~~~~~
85118.C:101:6: note:   conversion of argument 1 would be ill-formed:
85118.C:116:23: error: invalid initialization of non-const reference of type 'const volatile char&' from an rvalue of type 'volatile char'
         return isOneOf(std::forward<decltype(params)>(params)...);
                ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
85118.C:107:6: note: candidate: template<class T, class FirstType, class ... Tail> bool isOneOf(const T&, const FirstType&, const Tail& ...)
 bool isOneOf(const T& t, const FirstType& firstValue, const Tail&... tail)
      ^~~~~~~
85118.C:107:6: note:   template argument deduction/substitution failed:
85118.C:116:23: note:   candidate expects at least 2 arguments, 1 provided
         return isOneOf(std::forward<decltype(params)>(params)...);
                ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
85118.C:76:10: warning: '_Result std::_Bind<_Functor, _Bound_args>::operator()(_Args&&) [with _Args = char; _Result = bool; _Functor = const main()::<lambda(auto:1&& ...)>; _Bound_args = char]' used but never defined
          operator()(_Args&& __args);
          ^~~~~~~~


The error says "invalid initialization of non-const reference of type 'const volatile char&' from an rvalue of type 'volatile char'" which is bogus, because const volatile char& is not a non-const reference.
Comment 6 Jonathan Wakely 2018-04-03 18:28:30 UTC
... and it's only a substitution failure anyway, not an error.
Comment 7 Jason Merrill 2018-04-04 16:43:16 UTC
Author: jason
Date: Wed Apr  4 16:42:44 2018
New Revision: 259090

URL: https://gcc.gnu.org/viewcvs?rev=259090&root=gcc&view=rev
Log:
	PR c++/85118 - wrong error with generic lambda and std::bind.

	* call.c (add_template_conv_candidate): Disable if there are any
	call operators.

Added:
    trunk/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic17.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/call.c
Comment 8 Jason Merrill 2018-04-04 16:46:32 UTC
Author: jason
Date: Wed Apr  4 16:46:00 2018
New Revision: 259094

URL: https://gcc.gnu.org/viewcvs?rev=259094&root=gcc&view=rev
Log:
	PR c++/85118 - wrong error with generic lambda and std::bind.

	* call.c (add_template_conv_candidate): Disable if there are any
	call operators.

Added:
    branches/gcc-7-branch/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic17.C
Modified:
    branches/gcc-7-branch/gcc/cp/ChangeLog
    branches/gcc-7-branch/gcc/cp/call.c
Comment 9 Jason Merrill 2018-10-12 12:39:20 UTC
This doesn't seem worth applying to the 6 branch.