Another problem caused by my change to consider template conversion operators in calls to an object: in this case, the operator() is not a viable candidate, so we try to use the conversion operator. Which ends up trying to instantiate the operator() to determine its return type, which fails.
So, let's extend the 71117 fix and ignore the template conversion if there are any call operator candidates, not just any viable ones. Tested x86_64-pc-linux-gnu, applying to trunk.
commit 135b51494c6651a3c791941b6fabcbb1814a0942 Author: Jason Merrill <ja...@redhat.com> Date: Tue Apr 3 16:26:12 2018 -0400 PR c++/85118 - wrong error with generic lambda and std::bind. * call.c (add_template_conv_candidate): Disable if there are any call operators. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 901f18c43e6..f81773157b6 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -3274,10 +3274,10 @@ add_template_conv_candidate (struct z_candidate **candidates, tree tmpl, tree return_type, tree access_path, tree conversion_path, tsubst_flags_t complain) { - /* Making this work broke PR 71117, so until the committee resolves core - issue 2189, let's disable this candidate if there are any viable call + /* Making this work broke PR 71117 and 85118, so until the committee resolves + core issue 2189, let's disable this candidate if there are any call operators. */ - if (any_strictly_viable (*candidates)) + if (*candidates) return NULL; return diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic17.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic17.C new file mode 100644 index 00000000000..4a7392f93bc --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic17.C @@ -0,0 +1,125 @@ +// PR c++/85118 +// { dg-do compile { target c++14 } } + +namespace std +{ + template<typename _Tp> + struct remove_const + { typedef _Tp type; }; + + template<typename _Tp> + struct remove_const<_Tp const> + { typedef _Tp type; }; + + + template<typename _Tp> + struct remove_volatile + { typedef _Tp type; }; + + template<typename _Tp> + struct remove_volatile<_Tp volatile> + { typedef _Tp type; }; + + + template<typename _Tp> + struct remove_cv + { + typedef typename + remove_const<typename remove_volatile<_Tp>::type>::type type; + }; + + template<typename _Tp> + struct remove_reference + { typedef _Tp type; }; + + template<typename _Tp> + struct remove_reference<_Tp&> + { typedef _Tp type; }; + + template<typename _Tp> + struct remove_reference<_Tp&&> + { typedef _Tp type; }; + + template<typename _Tp> + struct decay + { + using type = typename remove_reference<typename remove_const<_Tp>::type>::type; + }; + + template<typename _Tp> + _Tp&& + declval() noexcept; + + template<typename _Tp> + constexpr _Tp&& + forward(typename std::remove_reference<_Tp>::type& __t) noexcept + { return static_cast<_Tp&&>(__t); } + + + template<typename _Arg> + struct _Mu + { + template<typename _CVArg, typename _Tuple> + _CVArg&& + operator()(_CVArg&& __arg, _Tuple&) const volatile + { return std::forward<_CVArg>(__arg); } + }; + + template<typename _Functor, typename _Bound_args> + struct _Bind + { + _Functor _M_f; + _Bound_args _M_bound_args; + + template<typename _Args, typename _Result + = decltype( std::declval<_Functor&>()( + _Mu<_Bound_args>()( std::declval<_Bound_args&>(), + std::declval<_Args&>() ) ) )> + _Result + operator()(_Args&& __args) { return {}; } + + template<typename _Args, typename _Result + = decltype( std::declval<volatile _Functor&>()( + _Mu<_Bound_args>()( std::declval<volatile _Bound_args&>(), + std::declval<_Args&>() ) ) )> + _Result + operator()(_Args&& __args) volatile; + + }; + + template<typename _Func, typename _BoundArgs> + _Bind<typename decay<_Func>::type, typename decay<_BoundArgs>::type> + bind(_Func&& __f, _BoundArgs&& __args) + { + return { + std::forward<_Func>(__f), + std::forward<_BoundArgs>(__args) + }; + } + +} // namespace std + + +template <typename T> +bool isOneOf(const 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, 'o'); + + isO('o'); +}