Bug 80064 - [7 Regression] _Iter_cmp_iter instantiates bogus type
Summary: [7 Regression] _Iter_cmp_iter instantiates bogus type
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 7.0.1
: P3 normal
Target Milestone: 7.0
Assignee: Jonathan Wakely
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-03-16 10:06 UTC by Richard Biener
Modified: 2017-03-20 12:45 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work: 4.8.5, 5.4.1, 6.3.1
Known to fail:
Last reconfirmed: 2017-03-16 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Richard Biener 2017-03-16 10:06:53 UTC
The following testcase extracted from Cython is no longer accepted with G++7:

> g++-7 -c t.C
In file included from /usr/include/c++/7/bits/stl_algobase.h:71:0,
                 from /usr/include/c++/7/algorithm:61,
                 from t.C:1:
/usr/include/c++/7/bits/predefined_ops.h: In instantiation of ‘struct __gnu_cxx::__ops::_Iter_comp_iter<bool(int, int)>’:
/usr/include/c++/7/bits/stl_heap.h:394:51:   required from ‘void std::make_heap(_RAIter, _RAIter, _Compare) [with _RAIter = __gnu_cxx::__normal_iterator<int*, std::vector<int> >; _Compare = bool(int, int)]’
t.C:8:34:   required from here
/usr/include/c++/7/bits/predefined_ops.h:132:16: error: field ‘__gnu_cxx::__ops::_Iter_comp_iter<bool(int, int)>::_M_comp’ invalidly declared function type
       _Compare _M_comp;
                ^~~~~~~

while it is just fine with g++6:

> g++-6 -c t.C
>
Comment 1 Richard Biener 2017-03-16 10:10:21 UTC
clang++ errors the same way btw, so maybe G++6 (bogously) did not instantiate this type.
Comment 2 Richard Biener 2017-03-16 10:23:35 UTC
#include <algorithm>
#include <vector>
bool greater(int, int);
int main()
{
  std::vector<int> v;
  std::make_heap<std::vector<int>::iterator, bool (int, int)>
     (v.begin(), v.end(), greater);
}
Comment 3 Richard Biener 2017-03-16 10:40:36 UTC
https://github.com/cython/cython/issues/1632
Comment 4 Jonathan Wakely 2017-03-16 10:52:32 UTC
I think the testcase is invalid. std::make_heap is declared like so:

  template<class RandomAccessIterator>
  void make_heap(RandomAccessIterator first, RandomAccessIterator last);
  
  template<class RandomAccessIterator, class Compare>
  void make_heap(RandomAccessIterator first, RandomAccessIterator last,
                 Compare comp);

The explicit instantiation matches the second overload, then argument substitition creates the function:

  void make_heap(vector<int>::iterator first, vector<int>::iterator last,
                 bool(comp)(int, int));

You can't pass functions by value so the third argument decays to:

  void make_heap(vector<int>::iterator first, vector<int>::iterator last,
                 bool(*comp)(int, int));

However, this means the type of the function parameter comp is no longer of type Compare, and so if the implementation tries to use that type it will fail, 

e.g. GCC 7 does something like:

  struct wrapper {
    Compare cmp;
  } wrapped_comp = { comp };

And libc++ does something like:

  Compare& ref = comp;

Both fail, because Compare is a function type, but comp is a pointer to  function.

The test should use:

  std::make_heap<std::vector<int>::iterator, bool(*)(int, int)>

That is the actual type that is deduced for the greater argument.
Comment 5 Jonathan Wakely 2017-03-16 11:09:33 UTC
Re-opening because we can make it work fairly easily, by using the decayed type instead of the original Compare type, i.e.

  struct wrapper {
    __decltype(comp) cmp;
  } wrapped_comp = { comp };
Comment 6 Jonathan Wakely 2017-03-16 14:32:39 UTC
Author: redi
Date: Thu Mar 16 14:32:07 2017
New Revision: 246197

URL: https://gcc.gnu.org/viewcvs?rev=246197&root=gcc&view=rev
Log:
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.

Added:
    trunk/libstdc++-v3/testsuite/25_algorithms/make_heap/80064.cc
Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/include/bits/stl_heap.h
Comment 7 Jonathan Wakely 2017-03-16 15:25:12 UTC
Fixed. We might consider a static_assert for gcc8 to reject this code with a user-friendly diagnostic, but for now let's accept what used to work.