Bug 1541688

Summary: Compiling stl::set compare on GCC 8.0 causes error
Product: [Fedora] Fedora Reporter: R4SAS <r4sas>
Component: gccAssignee: Jakub Jelinek <jakub>
Status: CLOSED UPSTREAM QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: rawhideCC: aoliva, davejohansen, fweimer, jakub, jwakely, law, mpolacek
Target Milestone: ---   
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2018-02-05 02:15:41 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description R4SAS 2018-02-04 01:30:05 UTC
Compiling code with compare using gcc-c++ 8.0.1-0.8 causes error

/usr/include/c++/8/bits/stl_tree.h: In instantiation of 'class std::_Rb_tree<std::shared_ptr<i2p::tunnel::InboundTunnel>, std::shared_ptr<i2p::tunnel::InboundTunnel>, std::_Identity<std::shared_ptr<i2p::tunnel::InboundTunnel> >, i2p::tunnel::TunnelCreationTimeCmp, std::allocator<std::shared_ptr<i2p::tunnel::InboundTunnel> > >':
/usr/include/c++/8/bits/stl_set.h:133:17:   required from 'class std::set<std::shared_ptr<i2p::tunnel::InboundTunnel>, i2p::tunnel::TunnelCreationTimeCmp>'
/builddir/build/BUILD/i2pd-git-2.18.0/libi2pd/TunnelPool.h:117:68:   required from here
/usr/include/c++/8/bits/stl_tree.h:452:21: error: static assertion failed: comparison object must be invocable with two arguments of key type
       static_assert(__is_invocable<_Compare&, const _Key&, const _Key&>{},
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Full log on COPR: https://copr-be.cloud.fedoraproject.org/results/supervillain/i2pd/fedora-rawhide-x86_64/00709308-i2pd-git/builder-live.log

Code:
> https://github.com/PurpleI2P/i2pd/blob/openssl/libi2pd/TunnelPool.h#L117
std::set<std::shared_ptr<InboundTunnel>, TunnelCreationTimeCmp> m_InboundTunnels;

> https://github.com/PurpleI2P/i2pd/blob/openssl/libi2pd/TunnelBase.h#L60
struct TunnelCreationTimeCmp
{
	bool operator() (const std::shared_ptr<const TunnelBase> & t1, const std::shared_ptr<const TunnelBase> & t2) const
	{
		if (t1->GetCreationTime () != t2->GetCreationTime ())
			return t1->GetCreationTime () > t2->GetCreationTime ();
		else
			return t1 < t2;
	};
};

Changes regarding on GCC bug #83102 doesn't solved problem.

Comment 1 Jonathan Wakely 2018-02-04 23:39:13 UTC
The problem is that the InboundTunnel and OutboundTunnel types are incomplete, so it's not possible to verify that the comparison function is valid.

That code is very inefficient, as it will create new temporary shared_ptr objects for every comparison in the sets, requiring four atomic reference count updates for every comparison.

Making the comparison function accept the derived types would avoid that, and fix the compilation error too:

struct TunnelCreationTimeCmp
{
  template<typename T>
    bool operator() (const std::shared_ptr<T>& t1, const std::shared_ptr<T>& t2) const
    {
      if (t1->GetCreationTime () != t2->GetCreationTime ())
        return t1->GetCreationTime () > t2->GetCreationTime ();
      else
        return t1 < t2;
    }
};

Comment 2 R4SAS 2018-02-05 02:15:41 UTC
--- a/libi2pd/TunnelBase.h
+++ b/libi2pd/TunnelBase.h
@@ -59,7 +59,8 @@ namespace tunnel

        struct TunnelCreationTimeCmp
        {
-               bool operator() (const std::shared_ptr<const TunnelBase> & t1, const std::shared_ptr<const TunnelBase> & t2) const
+               template<typename T>
+               bool operator() (const std::shared_ptr<T> & t1, const std::shared_ptr<T> & t2) const
                {
                        if (t1->GetCreationTime () != t2->GetCreationTime ())
                                return t1->GetCreationTime () > t2->GetCreationTime ();

https://github.com/PurpleI2P/i2pd/commit/4af0caa50639c9c080034b2ea8239eb7e06f0ba3
Thank you, issue resolved.