openSUSE/libzypp

libzypp (and anything using it) fails to build with clang due to std::mem_fn

Closed this issue · 5 comments

libzypp and anything using libzypp's <zypp/Arch.h> header fails to build with clang because clang is stricter about std::mem_fn than gcc, rejecting std::mem_fn use on a virtual member.

/home/bero/abf/libzypp/BUILD/libzypp-17.31.18/zypp/Arch.h:137:64: error: no matching function for call to 'mem_fn'
      return str::join( make_transform_iterator( cset.begin(), std::mem_fn(&Arch::asString) ),
                                                               ^~~~~~~~~~~
/usr/bin/../lib64/gcc/x86_64-openmandriva-linux-gnu/13.1.1/../../../../include/c++/13.1.1/functional:237:5: note: candidate template ignored: couldn't infer template argument '_Tp'
    mem_fn(_Tp _Class::* __pm) noexcept
    ^

The issue is not virtual functions but overload resolution does not work here. We have a static vs non static asString, which should be selectable via templates...
Because the type of the non static one should be const std::string & (Arch::*memfn)( ) const where the static one is std::string & (*memfn)( )

And the signature of mem_fn is:

  template<typename _Tp, typename _Class>
    _GLIBCXX20_CONSTEXPR
    inline _Mem_fn<_Tp _Class::*>
    mem_fn(_Tp _Class::* __pm) noexcept
    {
      return _Mem_fn<_Tp _Class::*>(__pm);
    }

So the static overload should not even be considered here... i guess we can work around it though

But note that compiling libzypp with clang is currently not supported

Does that solve your problem?

--- zypp/Arch.h
+++ zypp/Arch.h
@@ -134,8 +134,9 @@ namespace zypp
     /** */
     static std::string asString( const CompatSet & cset )
     {
-      return str::join( make_transform_iterator( cset.begin(), std::mem_fn(&Arch::asString) ),
-                        make_transform_iterator( cset.end(), std::mem_fn(&Arch::asString) ) );
+      const std::string & (Arch::*memfn)( ) const = &Arch::asString;
+      return str::join( make_transform_iterator( cset.begin(), std::mem_fn( memfn ) ),
+                        make_transform_iterator( cset.end(), std::mem_fn( memfn ) ) );
     }
 
   public:

Thanks, that does fix it. libzypp itself still doesn't build with clang (at least clang 16) because

/home/bero/abf/libzypp/BUILD/libzypp-17.31.18/zypp-tui/output/Out.h:450:36: error: integer value 255 is outside the valid range of values [0, 3] for this enumeration type [-Wenum-constexpr-conversion]
  static constexpr Type TYPE_ALL        = TypeBit(0xff);
                                          ^
1 warning and 1 error generated.

Clang realizes the enum only takes values of 0 to 3, so doesn't like the 0xff. Setting it to 3 (which for now should do the same thing) fixes it.

Clang realizes the enum only takes values of 0 to 3, so doesn't like the 0xff. Setting it to 3 (which for now should do the same thing) fixes it.

And Clang is correct there, i added a second commit to the PR that should fix the problem with Out.h