Richi reported a GCC 7 regression for a testcase from Cython that
boils down to:

void
test01(int* first, int* last)
{
 extern bool cmp(int, int);
 // PR libstdc++/80064
 // This is undefined, because [alg.sorting] requires the template argument
 // Compare to be a function object type, and bool(int, int) is not an
 // object type. We previously accepted it by accident, so keep doing so.
 std::make_heap<int*, bool(int, int)>(first, last, cmp);
}

I can restore support for this with the attached patch (changing the
heap algos to use the decayed type of the cmp parameter instead of the
original _Compare template argument type), but should we support it?

Is this worth fixing, or should we just say it worked by accident
before and the user code needs to be fixed?

FWIW MSVC accepts the example, libc++ rejects it for similar reasons
to GCC 7.

        PR libstdc++/80064
        * include/bits/stl_heap.h (__is_heap, push_heap, __adjust_heap)
        (pop_heap, make_heap, sort_heap, is_heap_until, is_heap): Cope with
        invalid instantiations using function types for _Compare argument.
        * testsuite/25_algorithms/make_heap/80064.cc: New test.

commit 873ca61fbfbd5b3a84d1f9c36cd09e8a5c54fbf5
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Thu Mar 16 12:24:42 2017 +0000

    PR libstdc++/80064 make heap algorithms work with function types
    
        PR libstdc++/80064
        * include/bits/stl_heap.h (__is_heap, push_heap, __adjust_heap)
        (pop_heap, make_heap, sort_heap, is_heap_until, is_heap): Cope with
        invalid instantiations using function types for _Compare argument.
        * testsuite/25_algorithms/make_heap/80064.cc: New test.

diff --git a/libstdc++-v3/include/bits/stl_heap.h 
b/libstdc++-v3/include/bits/stl_heap.h
index 3c102f1..f8cd0c0 100644
--- a/libstdc++-v3/include/bits/stl_heap.h
+++ b/libstdc++-v3/include/bits/stl_heap.h
@@ -100,7 +100,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline bool
     __is_heap(_RandomAccessIterator __first, _Compare __comp, _Distance __n)
     {
-      __gnu_cxx::__ops::_Iter_comp_iter<_Compare> __cmp(_GLIBCXX_MOVE(__comp));
+      typedef __decltype(__comp) _Cmp;
+      __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
       return std::__is_heap_until(__first, __n, __cmp) == __n;
     }
 
@@ -313,8 +314,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       if (__last - __first > 1)
        {
-         using __gnu_cxx::__ops::_Iter_comp_iter;
-         _Iter_comp_iter<_Compare> __cmp(_GLIBCXX_MOVE(__comp));
+         typedef __decltype(__comp) _Cmp;
+         __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
          --__last;
          std::__pop_heap(__first, __last, __last, __cmp);
        }
@@ -391,7 +392,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __glibcxx_requires_valid_range(__first, __last);
       __glibcxx_requires_irreflexive_pred(__first, __last, __comp);
 
-      __gnu_cxx::__ops::_Iter_comp_iter<_Compare> __cmp(_GLIBCXX_MOVE(__comp));
+      typedef __decltype(__comp) _Cmp;
+      __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
       std::__make_heap(__first, __last, __cmp);
     }
 
@@ -454,7 +456,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __glibcxx_requires_irreflexive_pred(__first, __last, __comp);
       __glibcxx_requires_heap_pred(__first, __last, __comp);
 
-      __gnu_cxx::__ops::_Iter_comp_iter<_Compare> __cmp(_GLIBCXX_MOVE(__comp));
+      typedef __decltype(__comp) _Cmp;
+      __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
       std::__sort_heap(__first, __last, __cmp);
     }
 
@@ -508,7 +511,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __glibcxx_requires_valid_range(__first, __last);
       __glibcxx_requires_irreflexive_pred(__first, __last, __comp);
 
-      __gnu_cxx::__ops::_Iter_comp_iter<_Compare> __cmp(_GLIBCXX_MOVE(__comp));
+      typedef __decltype(__comp) _Cmp;
+      __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
       return __first
        + std::__is_heap_until(__first, std::distance(__first, __last), __cmp);
     }
@@ -545,7 +549,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __glibcxx_requires_irreflexive_pred(__first, __last, __comp);
 
       const auto __dist = std::distance(__first, __last);
-      __gnu_cxx::__ops::_Iter_comp_iter<_Compare> __cmp(_GLIBCXX_MOVE(__comp));
+      typedef __decltype(__comp) _Cmp;
+      __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
       return std::__is_heap_until(__first, __dist, __cmp) == __dist;
     }
 #endif
diff --git a/libstdc++-v3/testsuite/25_algorithms/make_heap/80064.cc 
b/libstdc++-v3/testsuite/25_algorithms/make_heap/80064.cc
new file mode 100644
index 0000000..eedcc32
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/make_heap/80064.cc
@@ -0,0 +1,31 @@
+// 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 }
+
+#include <algorithm>
+
+void
+test01(int* first, int* last)
+{
+  extern bool cmp(int, int);
+  // PR libstdc++/80064
+  // This is undefined, because [alg.sorting] requires the template argument
+  // Compare to be a function object type, and bool(int, int) is not an
+  // object type. We previously accepted it by accident, so keep doing so.
+  std::make_heap<int*, bool(int, int)>(first, last, cmp);
+}

Reply via email to