Martchus / cpp-utilities

Common C++ classes and routines used by my applications such as argument parser, IO and conversion utilities
GNU General Public License v2.0
52 stars 18 forks source link

Compile error with libc++ #6

Closed main-- closed 7 years ago

main-- commented 7 years ago

My C++ is unfortunately way too rusty to debug this but what I figured out is that this library fails to compile with libc++ (llvm's standard library). GNU libstdc++ works fine though.

Reduced test case here.

$ clang++ -std=c++14 -stdlib=libstdc++ fail.cpp   # works
$ clang++ -std=c++14 -stdlib=libc++ fail.cpp 
In file included from fail.cpp:2:
/usr/include/c++/v1/string:1938:44: error: 'basic_string<_CharT, _Traits, _Allocator>' is missing exception specification 'noexcept(is_nothrow_copy_constructible<allocator_type>::value)'
basic_string<_CharT, _Traits, _Allocator>::basic_string(const allocator_type& __a)
                                           ^
/usr/include/c++/v1/string:1326:40: note: previous declaration is here
    _LIBCPP_INLINE_VISIBILITY explicit basic_string(const allocator_type& __a)
                                       ^
In file included from fail.cpp:4:
In file included from /usr/include/c++/v1/sstream:174:
In file included from /usr/include/c++/v1/ostream:138:
/usr/include/c++/v1/ios:734:50: error: implicit instantiation of undefined template 'std::__1::ctype<char16_t>'
    return use_facet<ctype<char_type> >(getloc()).widen(__c);
                                                 ^
/usr/include/c++/v1/ios:743:19: note: in instantiation of member function 'std::__1::basic_ios<char16_t, std::__1::char_traits<char16_t> >::widen' requested here
        __fill_ = widen(' ');
                  ^
/usr/include/c++/v1/ostream:762:39: note: in instantiation of member function 'std::__1::basic_ios<char16_t, std::__1::char_traits<char16_t> >::fill' requested here
                                 __os.fill()).failed())
                                      ^
/usr/include/c++/v1/ostream:1080:19: note: in instantiation of function template specialization 'std::__1::__put_character_sequence<char16_t, std::__1::char_traits<char16_t> >' requested here
    return _VSTD::__put_character_sequence(__os, __str.data(), __str.size());
                  ^
fail.cpp:43:30: note: in instantiation of function template specialization 'std::__1::operator<<<char16_t, std::__1::char_traits<char16_t>, std::__1::allocator<char16_t> >' requested here
    ss << std::setbase(base) << string;
                             ^
fail.cpp:56:25: note: in instantiation of function template specialization 'stringToNumber<double, std::__1::basic_string<char16_t, std::__1::char_traits<char16_t>, std::__1::allocator<char16_t> >>' requested
      here
auto     milliseconds = stringToNumber<double>(
                        ^
/usr/include/c++/v1/__locale:427:53: note: template is declared here
template <class _CharT> class _LIBCPP_TYPE_VIS_ONLY ctype;
                                                    ^
/usr/include/c++/v1/__locale:186:54: error: implicit instantiation of undefined template 'std::__1::ctype<char16_t>'
    return static_cast<const _Facet&>(*__l.use_facet(_Facet::id));
                                                     ^
/usr/include/c++/v1/ios:734:12: note: in instantiation of function template specialization 'std::__1::use_facet<std::__1::ctype<char16_t> >' requested here
    return use_facet<ctype<char_type> >(getloc()).widen(__c);
           ^
/usr/include/c++/v1/ios:743:19: note: in instantiation of member function 'std::__1::basic_ios<char16_t, std::__1::char_traits<char16_t> >::widen' requested here
        __fill_ = widen(' ');
                  ^
/usr/include/c++/v1/ostream:762:39: note: in instantiation of member function 'std::__1::basic_ios<char16_t, std::__1::char_traits<char16_t> >::fill' requested here
                                 __os.fill()).failed())
                                      ^
/usr/include/c++/v1/ostream:1080:19: note: in instantiation of function template specialization 'std::__1::__put_character_sequence<char16_t, std::__1::char_traits<char16_t> >' requested here
    return _VSTD::__put_character_sequence(__os, __str.data(), __str.size());
                  ^
fail.cpp:43:30: note: in instantiation of function template specialization 'std::__1::operator<<<char16_t, std::__1::char_traits<char16_t>, std::__1::allocator<char16_t> >' requested here
    ss << std::setbase(base) << string;
                             ^
fail.cpp:56:25: note: in instantiation of function template specialization 'stringToNumber<double, std::__1::basic_string<char16_t, std::__1::char_traits<char16_t>, std::__1::allocator<char16_t> >>' requested
      here
auto     milliseconds = stringToNumber<double>(
                        ^
/usr/include/c++/v1/__locale:427:53: note: template is declared here
template <class _CharT> class _LIBCPP_TYPE_VIS_ONLY ctype;
                                                    ^
In file included from fail.cpp:4:
In file included from /usr/include/c++/v1/sstream:175:
/usr/include/c++/v1/istream:291:41: error: no matching function for call to 'use_facet'
            const ctype<_CharT>& __ct = use_facet<ctype<_CharT> >(__is.getloc());
                                        ^~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/v1/istream:547:16: note: in instantiation of member function 'std::__1::basic_istream<char16_t, std::__1::char_traits<char16_t> >::sentry::sentry' requested here
        sentry __s(*this);
               ^
fail.cpp:45:12: note: in instantiation of member function 'std::__1::basic_istream<char16_t, std::__1::char_traits<char16_t> >::operator>>' requested here
    if((ss >> result) && ss.eof()) {
           ^
fail.cpp:56:25: note: in instantiation of function template specialization 'stringToNumber<double, std::__1::basic_string<char16_t, std::__1::char_traits<char16_t>, std::__1::allocator<char16_t> >>' requested
      here
auto     milliseconds = stringToNumber<double>(
                        ^
/usr/include/c++/v1/__locale:184:1: note: candidate template ignored: substitution failure [with _Facet = std::__1::ctype<char16_t>]
use_facet(const locale& __l)
^
In file included from fail.cpp:4:
In file included from /usr/include/c++/v1/sstream:174:
In file included from /usr/include/c++/v1/ostream:140:
/usr/include/c++/v1/locale:589:5: error: no matching function for call to 'use_facet'
    use_facet<ctype<_CharT> >(__loc).widen(__src, __src + 32, __atoms);
    ^~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/v1/locale:1112:31: note: in instantiation of member function 'std::__1::__num_get<char16_t>::__stage2_float_prep' requested here
    string __grouping = this->__stage2_float_prep(__iob, __atoms,
                              ^
/usr/include/c++/v1/locale:850:20: note: in instantiation of function template specialization 'std::__1::num_get<char16_t, std::__1::istreambuf_iterator<char16_t, std::__1::char_traits<char16_t> >
      >::__do_get_floating_point<double>' requested here
    { return this->__do_get_floating_point ( __b, __e, __iob, __err, __v ); }
                   ^
/usr/include/c++/v1/locale:778:16: note: in instantiation of member function 'std::__1::num_get<char16_t, std::__1::istreambuf_iterator<char16_t, std::__1::char_traits<char16_t> > >::do_get' requested here
        return do_get(__b, __e, __iob, __err, __v);
               ^
/usr/include/c++/v1/istream:553:44: note: in instantiation of member function 'std::__1::num_get<char16_t, std::__1::istreambuf_iterator<char16_t, std::__1::char_traits<char16_t> > >::get' requested here
            use_facet<_Fp>(this->getloc()).get(_Ip(*this), _Ip(), *this, __err, __n);
                                           ^
fail.cpp:45:12: note: in instantiation of member function 'std::__1::basic_istream<char16_t, std::__1::char_traits<char16_t> >::operator>>' requested here
    if((ss >> result) && ss.eof()) {
           ^
fail.cpp:56:25: note: in instantiation of function template specialization 'stringToNumber<double, std::__1::basic_string<char16_t, std::__1::char_traits<char16_t>, std::__1::allocator<char16_t> >>' requested
      here
auto     milliseconds = stringToNumber<double>(
                        ^
/usr/include/c++/v1/__locale:184:1: note: candidate template ignored: substitution failure [with _Facet = std::__1::ctype<char16_t>]
use_facet(const locale& __l)
^
In file included from fail.cpp:4:
In file included from /usr/include/c++/v1/sstream:174:
In file included from /usr/include/c++/v1/ostream:140:
/usr/include/c++/v1/locale:591:27: error: implicit instantiation of undefined template 'std::__1::numpunct<char16_t>'
    __decimal_point = __np.decimal_point();
                          ^
/usr/include/c++/v1/__locale:1369:53: note: template is declared here
template <class _CharT> class _LIBCPP_TYPE_VIS_ONLY numpunct;
                                                    ^
In file included from fail.cpp:4:
In file included from /usr/include/c++/v1/sstream:174:
In file included from /usr/include/c++/v1/ostream:140:
/usr/include/c++/v1/locale:592:27: error: implicit instantiation of undefined template 'std::__1::numpunct<char16_t>'
    __thousands_sep = __np.thousands_sep();
                          ^
/usr/include/c++/v1/__locale:1369:53: note: template is declared here
template <class _CharT> class _LIBCPP_TYPE_VIS_ONLY numpunct;
                                                    ^
In file included from fail.cpp:4:
In file included from /usr/include/c++/v1/sstream:174:
In file included from /usr/include/c++/v1/ostream:140:
/usr/include/c++/v1/locale:593:16: error: implicit instantiation of undefined template 'std::__1::numpunct<char16_t>'
    return __np.grouping();
               ^
/usr/include/c++/v1/__locale:1369:53: note: template is declared here
template <class _CharT> class _LIBCPP_TYPE_VIS_ONLY numpunct;
                                                    ^
/usr/include/c++/v1/__locale:186:54: error: implicit instantiation of undefined template 'std::__1::numpunct<char16_t>'
    return static_cast<const _Facet&>(*__l.use_facet(_Facet::id));
                                                     ^
/usr/include/c++/v1/locale:590:36: note: in instantiation of function template specialization 'std::__1::use_facet<std::__1::numpunct<char16_t> >' requested here
    const numpunct<_CharT>& __np = use_facet<numpunct<_CharT> >(__loc);
                                   ^
/usr/include/c++/v1/locale:1112:31: note: in instantiation of member function 'std::__1::__num_get<char16_t>::__stage2_float_prep' requested here
    string __grouping = this->__stage2_float_prep(__iob, __atoms,
                              ^
/usr/include/c++/v1/locale:850:20: note: in instantiation of function template specialization 'std::__1::num_get<char16_t, std::__1::istreambuf_iterator<char16_t, std::__1::char_traits<char16_t> >
      >::__do_get_floating_point<double>' requested here
    { return this->__do_get_floating_point ( __b, __e, __iob, __err, __v ); }
                   ^
/usr/include/c++/v1/locale:778:16: note: in instantiation of member function 'std::__1::num_get<char16_t, std::__1::istreambuf_iterator<char16_t, std::__1::char_traits<char16_t> > >::do_get' requested here
        return do_get(__b, __e, __iob, __err, __v);
               ^
/usr/include/c++/v1/istream:553:44: note: in instantiation of member function 'std::__1::num_get<char16_t, std::__1::istreambuf_iterator<char16_t, std::__1::char_traits<char16_t> > >::get' requested here
            use_facet<_Fp>(this->getloc()).get(_Ip(*this), _Ip(), *this, __err, __n);
                                           ^
fail.cpp:45:12: note: in instantiation of member function 'std::__1::basic_istream<char16_t, std::__1::char_traits<char16_t> >::operator>>' requested here
    if((ss >> result) && ss.eof()) {
           ^
fail.cpp:56:25: note: in instantiation of function template specialization 'stringToNumber<double, std::__1::basic_string<char16_t, std::__1::char_traits<char16_t>, std::__1::allocator<char16_t> >>' requested
      here
auto     milliseconds = stringToNumber<double>(
                        ^
/usr/include/c++/v1/__locale:1369:53: note: template is declared here
template <class _CharT> class _LIBCPP_TYPE_VIS_ONLY numpunct;
                                                    ^
9 errors generated.
$
Martchus commented 7 years ago

I can reproduce the issue under Arch with latest libc++. I never tested building c++utilities with it because it also depends on iconv which is provided as part of libstdc++ under Arch and hence only available when using libc++. I'll try to find out what's going on.

And thanks for all the feedback so far.

Martchus commented 7 years ago

Ok, it was actually very easy to find out the reason. You're using u16string which does not seem to be supported at all. Using libstd++ you just get a runtime error instead:

terminate called after throwing an instance of 'std::bad_cast'
  what():  std::bad_cast

The reason u16string is not supported by std::basic_stringstream is actually the reason I implemented the stringToNumber and numberToString functions for integral types on my own. However, I currently don't need such conversion for floating point types so I didn't provide an own implementation here.

So you don't just build the library to get Tag Editor, Syncthing Tray or any of my applications (because otherwise you wouldn't have run into this issue)?

Note that the code would work if you used wstring. Also note that using u16string is not a good idea and use of UTF-8 should be preferred whenever possible - especially in Unix environment. Of course that's only my opinion and sometimes not possible (hence I implemented the conversion for integral types and u16string).

main-- commented 7 years ago

So you don't just build the library to get Tag Editor, Syncthing Tray or any of my applications (because otherwise you wouldn't have run into this issue)?

Actually, that's exactly what I'm trying to do. To be precise, I'm just trying to create Rust bindings for tagparser.

The error originates here:

milliseconds = ConversionUtilities::stringToNumber<double>(parseWideString(buffer.get() + 1, m_dataSize - 1, dataEncoding), 10);

Where parseWideString returns u16string (unless I'm missing something obvious).

Martchus commented 7 years ago

Ok, then that's the actual bug. Since it is only a runtime error with libstd++ I didn't noticed it. The line seems to be never tested (not in the test suite nor manually).

Martchus commented 7 years ago

Should be fixed now in tagparser: https://github.com/Martchus/tagparser/commit/add833f87f25aef7821333d7f9349ce870d688ee

I'll definitely install standalone iconv to compile here everything with libc++, too.

To be precise, I'm just trying to create Rust bindings for tagparser.

Ah, now I get the "My C++ is unfortunately way too rusty" :-)

But of course thanks for trying to create Rust bindings. I checked how to create Python bindings some time ago and it looked like a huge effort. But maybe integration with Rust is a little bit easier.

I would recommend to only bind the high level API, though (MediaFileInfo, Tag, AbstractTrack, AbstractChapter and AbstractAttachment classes). Let me know if you make any process.

Martchus commented 7 years ago

Is the error fixed with the mentioned commit so I can close the issue? I also compiled everything with libc++ and standalone iconv now and found no further problems so far.

By the way, if you have any questions about the library when creating those bindings, just ask.

main-- commented 7 years ago

It works now, thanks.