Am I correct that BOOST_PROGRAM_OPTIONS_DECL is defined to BOOST_SYMBOL_IMPORT, which expands to nothing, and it breaks when Boost.ProgramOptions library throws an exception marked with it?
I'm asking because I have a similar setup in Boost.Filesystem, and it is tested with clang+libc++ on Linux, and the tests passed last time I checked.
I just checked that and yes, the setup is the same and yes tests pass. Surprised by that I checked the difference: The destructor is implemented in the cpp file (in fact the whole class is, which is why DECL is the right choice here). When I change the MWE in Boost.throw_exception (for example) so that the class is marked DECL then the test fails. Implementing the destructor in the cpp file makes it work.
One potential problem that I noticed is that if an exception is marked with BOOST_*_DECL and static linking is enabled, BOOST_*_DECL is empty and the exception RTTI is left hidden. This can be a problem if the user links with Boost statically (e.g. wraps it into a library of his own) and then the exception crosses the library boundary. True. So exceptions should be marked VISIBLE, not DECL or both if the DECL behavior on Windows is required (i.e. the class is implemented in a cpp file) Ned pointed out something on Slack: VISIBLE works similar to EXPORT and makes all inline members VISIBLE too, which might not be wanted.
So IMO conclusion is: Mark exception classes faced at users at least VISIBLE and test with libc++.