Prevent ill-formed instantiation of __invoke_of<...> during the evaluation of a bind expression. Fixes PR22003.

The SFINAE on the function __mu(Fn, Args...) that evaluates nested bind
expressions always tries to deduce the return type for Fn(Args...) even when Fn
is not a nested bind expression. This can cause hard compile errors when the
instantation of Fn(Args...) is ill-formed. This patch prevents the instantation
of __invoke_of<Fn, Args...> unless Fn is actually a bind expression.

Bug reportand patch from Michel Morin.

http://llvm.org/bugs/show_bug.cgi?id=22003

llvm-svn: 224753
This commit is contained in:
Eric Fiselier 2014-12-23 05:54:34 +00:00
parent 2c55974da5
commit 279663c1b4
2 changed files with 51 additions and 2 deletions

View File

@ -1863,10 +1863,10 @@ __mu_expand(_Ti& __ti, tuple<_Uj...>& __uj, __tuple_indices<_Indx...>)
template <class _Ti, class ..._Uj>
inline _LIBCPP_INLINE_VISIBILITY
typename enable_if
typename __lazy_enable_if
<
is_bind_expression<_Ti>::value,
typename __invoke_of<_Ti&, _Uj...>::type
__invoke_of<_Ti&, _Uj...>
>::type
__mu(_Ti& __ti, tuple<_Uj...>& __uj)
{

View File

@ -0,0 +1,49 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// <functional>
// template<CopyConstructible Fn, CopyConstructible... Types>
// unspecified bind(Fn, Types...);
// template<Returnable R, CopyConstructible Fn, CopyConstructible... Types>
// unspecified bind(Fn, Types...);
// http://llvm.org/bugs/show_bug.cgi?id=22003
#include <functional>
struct DummyUnaryFunction
{
template <typename S>
int operator()(S const & s) const { return 0; }
};
struct BadUnaryFunction
{
template <typename S>
constexpr int operator()(S const & s) const
{
// Trigger a compile error if this function is instantiated.
// The constexpr is needed so that it is instantiated while checking
// __invoke_of<BadUnaryFunction &, ...>.
static_assert(!std::is_same<S, S>::value, "Shit");
return 0;
}
};
int main(int argc, char* argv[])
{
// Check that BadUnaryFunction::operator()(S const &) is not
// instantiated when checking if BadUnaryFunction is a nested bind
// expression during b(0). See PR22003.
auto b = std::bind(DummyUnaryFunction(), BadUnaryFunction());
b(0);
auto b2 = std::bind<long>(DummyUnaryFunction(), BadUnaryFunction());
b2(0);
}