Opened 6 years ago

Last modified 5 years ago

#12243 new Bugs

Boost.Serialization compilation error in Visual Studio with Zc:wchar_t-

Reported by: anonymous Owned by: Robert Ramey
Milestone: To Be Determined Component: serialization
Version: Boost 1.61.0 Severity: Showstopper
Keywords: Cc:

Description

The error is following:

C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\limits(85) : error C2090: function returns array
        H:\Third_party_src\boost\boost_1_61_0-compiled\boost/archive/basic_text_oprimitive.hpp(147) : see reference to class template instantiation 'std::numeric_limits<_Ty>' being compiled
        with
        [
            _Ty=const unsigned short [24]
        ]
        H:\Third_party_src\boost\boost_1_61_0-compiled\boost/archive/basic_text_oprimitive.hpp(180) : see reference to class template instantiation 'boost::archive::basic_text_oprimitive<OStream>::is_float<T>' being compiled
        with
        [
            OStream=std::wostream,
            T=const unsigned short [24]
        ]
        H:\Third_party_src\boost\boost_1_61_0-compiled\boost/archive/xml_woarchive.hpp(73) : see reference to function template instantiation 'void boost::archive::basic_text_oprimitive<OStream>::save<const unsigned short[24]>(T (&))' being compiled
        with
        [
            OStream=std::wostream,
            T=const unsigned short [24]
        ]
        H:\Third_party_src\boost\boost_1_61_0-compiled\boost/archive/xml_woarchive.hpp(73) : see reference to function template instantiation 'void boost::archive::basic_text_oprimitive<OStream>::save<const unsigned short[24]>(T (&))' being compiled
        with
        [
            OStream=std::wostream,
            T=const unsigned short [24]
        ]
        H:\Third_party_src\boost\boost_1_61_0-compiled\boost/archive/impl/xml_woarchive_impl.ipp(144) : see reference to function template instantiation 'void boost::archive::xml_woarchive_impl<Archive>::save<const unsigned short[24]>(T (&))' being compiled
        with
        [
            Archive=boost::archive::xml_woarchive,
            T=const unsigned short [24]
        ]
...............................

The problem is with boost/archive/impl/xml_woarchive_impl.ipp(144) line:

        save(L"</boost_serialization>\n");

It's fixed by replacing line with

        save((const wchar_t*)L"</boost_serialization>\n");

Interesting error, as it treats the literal L"</boost_serialization>\n" as 'const unsigned short [24]' and picks

template<class T>
    void
    save(const T & t){
        basic_text_oprimitive<std::wostream>::save(t);
    }

from boost/archive/xml_woarchive.hpp , instead of correct

    #ifndef BOOST_NO_INTRINSIC_WCHAR_T
    BOOST_WARCHIVE_DECL void 
    save(const wchar_t * t);
    #endif

And... If we remove the

    #ifndef BOOST_NO_INTRINSIC_WCHAR_T

everything (including /Zc:wchar_t and /Zc:wchar_t- configurations) compiles fine.

So the actual bug is this 'ifndef'.

Why it was placed here? Most likely by mistake.

Please remove this 'ifndef'.

Change History (6)

comment:1 by anonymous, 6 years ago

I searched the boost code a bit and came to conclusion that you should use

    #ifndef BOOST_NO_CWCHAR

for functions that accept wchar_t literals.

Otherwise the function xml_woarchive_impl::save (and similar functions) won't work with wchar_t literals in Visual Studio with /Zc:wchar_t- .

The Boost.Serialization compilation error is a side effect of this oversight.

comment:2 by anonymous, 6 years ago

Component: Noneserialization
Owner: set to Robert Ramey

comment:3 by Robert Ramey, 6 years ago

could you expand a little on this? Where should the define go? I'm getting that there is no fix called for in the serialization library itself.

comment:4 by Robert Ramey, 5 years ago

So the actual bug is this 'ifndef'.

Why it was placed here? Most likely by mistake.

nope - removing it will result in compile errors on platforms which don't define wchar_t

according to documentation on boost.config, BOOST_NO_CWCHAR is meant to indicate that the platform doesn't have headers for <wchar.h> and <cwchar> so that's not a great choice either

And... If we remove the

remove #ifndef BOOST_NO_INTRINSIC_WCHAR_T

everything (including /Zc:wchar_t and /Zc:wchar_t- configurations) compiles fine.

I can't see how this would actually work

comment:5 by anonymous, 5 years ago

I couldn't modify the bug description, so I placed additional info in the follow-up comment, so please read it.

In short, you should replace the uses of

#ifndef BOOST_NO_INTRINSIC_WCHAR_T

with

#ifndef BOOST_NO_CWCHAR

in several headers. (Othervise some functions for wchar_t will not be declared in /Zc:wchar_t- configuration.)

Such replacement would be consistent with other function declarations across boost, where type wchar_t is required (whether intrinsic of typedef'd). The macro BOOST_NO_INTRINSIC_WCHAR_T in these headers was used incorrectly, because the BOOST_NO_CWCHAR was actually meant.

The configuration /Zc:wchar_t- seems not to be properly tested in boost, as can be concluded from existence of this bug.

comment:6 by John Maddock, 5 years ago

Sorry to confuse things but there are actually 3 distinct and completely orthogonal configuration macros here, and it appears serialization may need all 3:

BOOST_NO_INTRINSIC_WCHAR_T: Use when you are specializing a template or overloading a function on wchar_t as well as the other integer types. BOOST_NO_CWCHAR: Use before inclusion of <cwchar> or use of it's functions. BOOST_NO_STD_WSTRING: Use before use of std::wstring. Perversely, presence of this macro does not mean that you cannot at least forward declare basic_string<wchar_t>, but you may not be able to instantiate it (or it's members) without linker errors unless the user has specified some command-line magic. Or to put it another way, you can still use basic_string<wchar_t> in templates that will only be instantiated when actually used: in which situation the user gets what they deserve ;)

Note that the presence of one of these does not imply much if anything about the others - for example we have msvc with <cwchar> but wchar_t not a native type, while on gcc wchar_t is always a native type, even though the platform it's building for (early cygwin, some embedded platforms) has no wide character functions.

There is one final conundrum that only Robert can decide on - if wchar_t is not a distinct type, and integer and character types are to be handled differently, what is the library supposed to do exactly when presented with an unsigned short? We have no way of knowing whether it's a character or an integer. Special treatment for wchar_t* seems sensible though since there is no special overload for unsigned short*.

I'm not going to go through the whole codebase and suggest which should be used where (but let me know if you need help testing this specific configuration), but my suggestion would be:

load/save overloaded on wchar_t* : use BOOST_NO_CWCHAR, ditto in the implementation. load/save overloaded on wchar_t : maybe check for both BOOST_NO_INTRINSIC_WCHAR_T and BOOST_NO_CWCHAR.

HTH.

Note: See TracTickets for help on using tickets.