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{});
+}

Reply via email to