Samstag, 16. Juni 2012

C++11: fixing a bug to use chrono with clang

Working with chrono in C++11 is working with gcc but fails with clang on my Debian system. Reports are in:
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=666539
http://llvm.org/bugs/show_bug.cgi?id=12893



The error looks like this:


In file included from ../main.cpp:3:
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:240:10: error: cannot cast from lvalue of type 'const long' to rvalue reference type 'rep' (aka 'long &&'); types
      are not compatible
          : __r(static_cast<rep>(__rep)) { }
                ^~~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:128:13: note: in instantiation of function template specialization 'std::chrono::duration<long &&, std::ratio<1,   
      1000000> >::duration<long, void>' requested here
            return _ToDur(static_cast<__to_rep>(__d.count()));
                   ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:182:9: note: in instantiation of function template specialization                                                  
      'std::chrono::__duration_cast_impl<std::chrono::duration<long &&, std::ratio<1, 1000000> >, std::ratio<1, 1>, long &&, true, true>::__cast<long, std::ratio<1, 1000000> >' requested here
        return __dc::__cast(__d);
               ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:247:10: note: in instantiation of function template specialization                                                 
      'std::chrono::duration_cast<std::chrono::duration<long &&, std::ratio<1, 1000000> >, long, std::ratio<1, 1000000> >' requested here
          : __r(duration_cast<duration>(__d).count()) { }
                ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:471:9: note: in instantiation of function template specialization 'std::chrono::duration<long &&, std::ratio<1,    
      1000000> >::duration<long, std::ratio<1, 1000000>, void>' requested here
        return __ct(__lhs).count() < __ct(__rhs).count();
               ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:682:7: note: in instantiation of function template specialization 'std::chrono::operator<<long, std::ratio<1,      
      1000000>, long, std::ratio<1, 1000000> >' requested here
                    < system_clock::duration::zero(),
                    ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:128:13: error: call to implicitly-deleted copy constructor of                                                      
      'std::chrono::duration<long &&, std::ratio<1, 1000000> >'
            return _ToDur(static_cast<__to_rep>(__d.count()));
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:182:9: note: in instantiation of function template specialization                                                  
      'std::chrono::__duration_cast_impl<std::chrono::duration<long &&, std::ratio<1, 1000000> >, std::ratio<1, 1>, long &&, true, true>::__cast<long, std::ratio<1, 1000000> >' requested here
        return __dc::__cast(__d);
               ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:247:10: note: in instantiation of function template specialization                                                 
      'std::chrono::duration_cast<std::chrono::duration<long &&, std::ratio<1, 1000000> >, long, std::ratio<1, 1000000> >' requested here
          : __r(duration_cast<duration>(__d).count()) { }
                ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:471:9: note: in instantiation of function template specialization 'std::chrono::duration<long &&, std::ratio<1,    
      1000000> >::duration<long, std::ratio<1, 1000000>, void>' requested here
        return __ct(__lhs).count() < __ct(__rhs).count();
               ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:682:7: note: in instantiation of function template specialization 'std::chrono::operator<<long, std::ratio<1,      
      1000000>, long, std::ratio<1, 1000000> >' requested here
                    < system_clock::duration::zero(),
                    ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:233:12: note: explicitly defaulted function was implicitly deleted here                                            
        constexpr duration(const duration&) = default;
                  ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:349:6: note: copy constructor of 'duration<long &&, std::ratio<1, 1000000> >' is implicitly deleted because field  
      '__r' is of rvalue reference type 'rep' (aka 'long &&')
        rep __r;
            ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:182:9: error: call to implicitly-deleted copy constructor of 'typename enable_if<__is_duration<duration<long &&,   
      ratio<1, 1000000> > >::value, duration<long &&, ratio<1, 1000000> > >::type' (aka 'std::chrono::duration<long &&, std::ratio<1, 1000000> >')
        return __dc::__cast(__d);
               ^~~~~~~~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:247:10: note: in instantiation of function template specialization                                                 
      'std::chrono::duration_cast<std::chrono::duration<long &&, std::ratio<1, 1000000> >, long, std::ratio<1, 1000000> >' requested here
          : __r(duration_cast<duration>(__d).count()) { }
                ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:471:9: note: in instantiation of function template specialization 'std::chrono::duration<long &&, std::ratio<1,    
      1000000> >::duration<long, std::ratio<1, 1000000>, void>' requested here
        return __ct(__lhs).count() < __ct(__rhs).count();
               ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:682:7: note: in instantiation of function template specialization 'std::chrono::operator<<long, std::ratio<1,      
      1000000>, long, std::ratio<1, 1000000> >' requested here
                    < system_clock::duration::zero(),
                    ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:233:12: note: explicitly defaulted function was implicitly deleted here                                            
        constexpr duration(const duration&) = default;
                  ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:349:6: note: copy constructor of 'duration<long &&, std::ratio<1, 1000000> >' is implicitly deleted because field  
      '__r' is of rvalue reference type 'rep' (aka 'long &&')
        rep __r;
            ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:255:11: error: rvalue reference to type 'long' cannot bind to lvalue of type 'long'                                
        { return __r; }
                 ^~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:247:39: note: in instantiation of member function 'std::chrono::duration<long &&, std::ratio<1, 1000000> >::count' 
      requested here
          : __r(duration_cast<duration>(__d).count()) { }
                                             ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:471:9: note: in instantiation of function template specialization 'std::chrono::duration<long &&, std::ratio<1,    
      1000000> >::duration<long, std::ratio<1, 1000000>, void>' requested here
        return __ct(__lhs).count() < __ct(__rhs).count();
               ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:682:7: note: in instantiation of function template specialization 'std::chrono::operator<<long, std::ratio<1,      
      1000000>, long, std::ratio<1, 1000000> >' requested here
                    < system_clock::duration::zero(),
                    ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:681:21: error: static_assert expression is not an integral constant expression                                     
      static_assert(system_clock::duration::min()
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:681:21: note: undefined function 'operator<<long, std::ratio<1, 1000000>, long, std::ratio<1, 1000000> >' cannot be
      used in a constant expression
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:465:7: note: declared here
      operator<(const duration<_Rep1, _Period1>& __lhs,
      ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:141:40: error: cannot cast from lvalue of type 'const intmax_t' (aka 'const long') to rvalue reference type        
      'long &&'; types are not compatible
              static_cast<_CR>(__d.count()) / static_cast<_CR>(_CF::den)));
                                              ^~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:182:9: note: in instantiation of function template specialization                                                  
      'std::chrono::__duration_cast_impl<std::chrono::duration<long, std::ratio<1, 1> >, std::ratio<1, 1000000>, long &&, true, false>::__cast<long, std::ratio<1, 1000000> >' requested here
        return __dc::__cast(__d);
               ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:694:21: note: in instantiation of function template specialization                                                 
      'std::chrono::duration_cast<std::chrono::duration<long, std::ratio<1, 1> >, long, std::ratio<1, 1000000> >' requested here
        return std::time_t(duration_cast<chrono::seconds>
                           ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:154:40: error: cannot cast from lvalue of type 'const intmax_t' (aka 'const long') to rvalue reference type        
      'long &&'; types are not compatible
              static_cast<_CR>(__d.count()) * static_cast<_CR>(_CF::num)));
                                              ^~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:182:9: note: in instantiation of function template specialization                                                  
      'std::chrono::__duration_cast_impl<std::chrono::duration<long, std::ratio<1, 1000000> >, std::ratio<1000000, 1>, long &&, false, true>::__cast<long, std::ratio<1, 1> >' requested here
        return __dc::__cast(__d);
               ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:582:22: note: in instantiation of function template specialization                                                 
      'std::chrono::duration_cast<std::chrono::duration<long, std::ratio<1, 1000000> >, long, std::ratio<1, 1> >' requested here
        return __time_point(duration_cast<_ToDur>(__t.time_since_epoch()));
                            ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/chrono:702:9: note: in instantiation of function template specialization                                                  
      'std::chrono::time_point_cast<std::chrono::duration<long, std::ratio<1, 1000000> >, std::chrono::system_clock, std::chrono::duration<long, std::ratio<1, 1> > >' requested here
        return time_point_cast<system_clock::duration>
               ^
7 errors generated.



Not awesome.

Funny thing: there is a fix to it:
http://clang.llvm.org/libstdc++4.7-clang11.patch

So I tried the following:
1) Opening the file: /usr/include/c++/4.7/type_traits
2) Going down to line 1749
3) Changing the line to what the patch said:
{ typedef typename decay<decltype(true ? declval<_Tp>() : declval<_Up>())>::type type; };

 Done.

Now I can use clang to compile my code even if it uses chrono.
Awesome.