This solves a problem when using libstdc++ with Clang, due to Clang more eagerly instantiating constexpr function templates during argument deduction. G++ has some shortcuts to avoid this problem, but Clang doesn't, and it's not clear that it's strictly speaking a bug in Clang or if it's following the standard. By making these constructors explicit we stop them being considered by overload resolution for copying these functors, which stops us ending up back in the std::function SFINAE checks.
I'm also using _GLIBCXX_MOVE to turn some internal copies into moves, because otherwise using something like std::function with <algorithm> results in a number of potentially expensive copies. PR libstdc++/78991 * include/bits/predefined_ops.h (_Iter_comp_iter, _Iter_comp_val) (_Val_comp_iter, _Iter_equals_val, _Iter_pred, _Iter_comp_to_val) (_Iter_comp_to_iter, _Iter_negate): Make constructors explicit and move function objects. (__iter_comp_iter, __iter_comp_val, __val_comp_iter, __pred_iter) (__iter_comp_val, __iter_comp_iter, __negate): Move function objects. * testsuite/25_algorithms/sort/78991.cc: New test. Tested powerpc64le-linux, committed to trunk. I'll backport the 'explicit' constructors (but not the _GLIBCXX_MOVE changes) to the branches too.
commit 882c06f293550aa080f07cfcb8de1411e4b86121 Author: Jonathan Wakely <jwak...@redhat.com> Date: Fri Jan 6 11:22:21 2017 +0000 PR78991 make __gnu_cxx::__ops constructors explicit PR libstdc++/78991 * include/bits/predefined_ops.h (_Iter_comp_iter, _Iter_comp_val) (_Val_comp_iter, _Iter_equals_val, _Iter_pred, _Iter_comp_to_val) (_Iter_comp_to_iter, _Iter_negate): Make constructors explicit and move function objects. (__iter_comp_iter, __iter_comp_val, __val_comp_iter, __pred_iter) (__iter_comp_val, __iter_comp_iter, __negate): Move function objects. * testsuite/25_algorithms/sort/78991.cc: New test. diff --git a/libstdc++-v3/include/bits/predefined_ops.h b/libstdc++-v3/include/bits/predefined_ops.h index 92feef3..2742984 100644 --- a/libstdc++-v3/include/bits/predefined_ops.h +++ b/libstdc++-v3/include/bits/predefined_ops.h @@ -42,6 +42,7 @@ namespace __ops operator()(_Iterator1 __it1, _Iterator2 __it2) const { return *__it1 < *__it2; } }; + _GLIBCXX14_CONSTEXPR inline _Iter_less_iter __iter_less_iter() @@ -53,7 +54,7 @@ namespace __ops bool operator()(_Iterator __it, _Value& __val) const { return *__it < __val; } - }; + }; inline _Iter_less_val __iter_less_val() @@ -69,7 +70,7 @@ namespace __ops bool operator()(_Value& __val, _Iterator __it) const { return __val < *__it; } - }; + }; inline _Val_less_iter __val_less_iter() @@ -85,7 +86,7 @@ namespace __ops bool operator()(_Iterator1 __it1, _Iterator2 __it2) const { return *__it1 == *__it2; } - }; + }; inline _Iter_equal_to_iter __iter_equal_to_iter() @@ -97,7 +98,7 @@ namespace __ops bool operator()(_Iterator __it, _Value& __val) const { return *__it == __val; } - }; + }; inline _Iter_equal_to_val __iter_equal_to_val() @@ -111,9 +112,10 @@ namespace __ops struct _Iter_comp_iter { _Compare _M_comp; - _GLIBCXX14_CONSTEXPR + + explicit _GLIBCXX14_CONSTEXPR _Iter_comp_iter(_Compare __comp) - : _M_comp(__comp) + : _M_comp(_GLIBCXX_MOVE(__comp)) { } template<typename _Iterator1, typename _Iterator2> @@ -127,15 +129,16 @@ namespace __ops _GLIBCXX14_CONSTEXPR inline _Iter_comp_iter<_Compare> __iter_comp_iter(_Compare __comp) - { return _Iter_comp_iter<_Compare>(__comp); } + { return _Iter_comp_iter<_Compare>(_GLIBCXX_MOVE(__comp)); } template<typename _Compare> struct _Iter_comp_val { _Compare _M_comp; + explicit _Iter_comp_val(_Compare __comp) - : _M_comp(__comp) + : _M_comp(_GLIBCXX_MOVE(__comp)) { } template<typename _Iterator, typename _Value> @@ -147,20 +150,21 @@ namespace __ops template<typename _Compare> inline _Iter_comp_val<_Compare> __iter_comp_val(_Compare __comp) - { return _Iter_comp_val<_Compare>(__comp); } + { return _Iter_comp_val<_Compare>(_GLIBCXX_MOVE(__comp)); } template<typename _Compare> inline _Iter_comp_val<_Compare> __iter_comp_val(_Iter_comp_iter<_Compare> __comp) - { return _Iter_comp_val<_Compare>(__comp._M_comp); } + { return _Iter_comp_val<_Compare>(_GLIBCXX_MOVE(__comp._M_comp)); } template<typename _Compare> struct _Val_comp_iter { _Compare _M_comp; + explicit _Val_comp_iter(_Compare __comp) - : _M_comp(__comp) + : _M_comp(_GLIBCXX_MOVE(__comp)) { } template<typename _Value, typename _Iterator> @@ -172,18 +176,19 @@ namespace __ops template<typename _Compare> inline _Val_comp_iter<_Compare> __val_comp_iter(_Compare __comp) - { return _Val_comp_iter<_Compare>(__comp); } + { return _Val_comp_iter<_Compare>(_GLIBCXX_MOVE(__comp)); } template<typename _Compare> inline _Val_comp_iter<_Compare> __val_comp_iter(_Iter_comp_iter<_Compare> __comp) - { return _Val_comp_iter<_Compare>(__comp._M_comp); } + { return _Val_comp_iter<_Compare>(_GLIBCXX_MOVE(__comp._M_comp)); } template<typename _Value> struct _Iter_equals_val { _Value& _M_value; + explicit _Iter_equals_val(_Value& __value) : _M_value(__value) { } @@ -204,6 +209,7 @@ namespace __ops { typename std::iterator_traits<_Iterator1>::reference _M_ref; + explicit _Iter_equals_iter(_Iterator1 __it1) : _M_ref(*__it1) { } @@ -224,8 +230,9 @@ namespace __ops { _Predicate _M_pred; + explicit _Iter_pred(_Predicate __pred) - : _M_pred(__pred) + : _M_pred(_GLIBCXX_MOVE(__pred)) { } template<typename _Iterator> @@ -237,7 +244,7 @@ namespace __ops template<typename _Predicate> inline _Iter_pred<_Predicate> __pred_iter(_Predicate __pred) - { return _Iter_pred<_Predicate>(__pred); } + { return _Iter_pred<_Predicate>(_GLIBCXX_MOVE(__pred)); } template<typename _Compare, typename _Value> struct _Iter_comp_to_val @@ -246,7 +253,7 @@ namespace __ops _Value& _M_value; _Iter_comp_to_val(_Compare __comp, _Value& __value) - : _M_comp(__comp), _M_value(__value) + : _M_comp(_GLIBCXX_MOVE(__comp)), _M_value(__value) { } template<typename _Iterator> @@ -258,7 +265,9 @@ namespace __ops template<typename _Compare, typename _Value> _Iter_comp_to_val<_Compare, _Value> __iter_comp_val(_Compare __comp, _Value &__val) - { return _Iter_comp_to_val<_Compare, _Value>(__comp, __val); } + { + return _Iter_comp_to_val<_Compare, _Value>(_GLIBCXX_MOVE(__comp), __val); + } template<typename _Compare, typename _Iterator1> struct _Iter_comp_to_iter @@ -267,7 +276,7 @@ namespace __ops typename std::iterator_traits<_Iterator1>::reference _M_ref; _Iter_comp_to_iter(_Compare __comp, _Iterator1 __it1) - : _M_comp(__comp), _M_ref(*__it1) + : _M_comp(_GLIBCXX_MOVE(__comp)), _M_ref(*__it1) { } template<typename _Iterator2> @@ -279,15 +288,19 @@ namespace __ops template<typename _Compare, typename _Iterator> inline _Iter_comp_to_iter<_Compare, _Iterator> __iter_comp_iter(_Iter_comp_iter<_Compare> __comp, _Iterator __it) - { return _Iter_comp_to_iter<_Compare, _Iterator>(__comp._M_comp, __it); } + { + return _Iter_comp_to_iter<_Compare, _Iterator>( + _GLIBCXX_MOVE(__comp._M_comp), __it); + } template<typename _Predicate> struct _Iter_negate { _Predicate _M_pred; + explicit _Iter_negate(_Predicate __pred) - : _M_pred(__pred) + : _M_pred(_GLIBCXX_MOVE(__pred)) { } template<typename _Iterator> @@ -299,7 +312,7 @@ namespace __ops template<typename _Predicate> inline _Iter_negate<_Predicate> __negate(_Iter_pred<_Predicate> __pred) - { return _Iter_negate<_Predicate>(__pred._M_pred); } + { return _Iter_negate<_Predicate>(_GLIBCXX_MOVE(__pred._M_pred)); } } // namespace __ops } // namespace __gnu_cxx diff --git a/libstdc++-v3/testsuite/25_algorithms/sort/78991.cc b/libstdc++-v3/testsuite/25_algorithms/sort/78991.cc new file mode 100644 index 0000000..472763d --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/sort/78991.cc @@ -0,0 +1,40 @@ +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-do compile { target c++14 } } + +// PR 78991 +// This failed to compile with Clang because the result_of expression causes +// instantiation of _Iter_comp_iter::operator() outside the immediate context. + +#include <algorithm> + +struct function +{ + function() = default; + + template<typename F, typename = std::result_of_t<F&(int, int)>> + function(F) { } + + bool operator()(int x, int y) const { return x < y; } +}; + +int main() +{ + int a[2]{ 2, 1 }; + std::sort(a, a+2, function{}); +}