
I have been recently discussing a problem regarding clang on Windows on the clang developers mailing list, but without any final resolution yet. This problem affects those using clang on Windows with Boost along with exported classes. This combination occurs when testing Boost.Test but I imagine also occurs with other Boost libraries and of course could affect Boost end-users using clang on Windows. The problem does not occur with clang on Linux for reasons which shall be understood in the explanation. The bug manifests itself in such code, compiled with clang, as: #include <boost/config.hpp> #include <boost/scoped_ptr.hpp> class BOOST_SYMBOL_EXPORT AClass { boost::scoped_ptr<int> sp_pointer; }; int main() { return 0; } On Windows for clang the BOOST_SYMBOL_EXPORT becomes __declspec(dllexport) whereas on Linux it becomes __attribute__((__visibility__("default"))). Clang decides with __declspec(dllexport) or its equivalent __attribute__((dllexport)), but not with __attribute__((__visibility__("default"))), that after generating a default copy constructor and assignment operator for a class which has not defined is own, even if an object of that class is never copied or assigned, if the default copy constructor or assignment operator is invalid the compilation is in error. Since the above class has a member which is non-copyable and non-assignable we get errors from clang along the lines of:
test_clang_bug.cpp:3:1: error: field of type 'boost::scoped_ptr<int>' has private copy constructor AClass { boost::scoped_ptr<int> sp_pointer; }; ^ ..\..\..\boost/smart_ptr/scoped_ptr.hpp:47:5: note: declared private here scoped_ptr(scoped_ptr const &); ^ test_clang_bug.cpp:3:1: note: implicit copy constructor for 'AClass' first required here AClass { boost::scoped_ptr<int> sp_pointer; }; ^ test_clang_bug.cpp:3:1: error: 'operator=' is a private member of 'boost::scoped_ptr<int>' AClass { boost::scoped_ptr<int> sp_pointer; }; ^ ..\..\..\boost/smart_ptr/scoped_ptr.hpp:48:18: note: declared private here scoped_ptr & operator=(scoped_ptr const &); ^ test_clang_bug.cpp:3:1: note: implicit copy assignment operator for 'AClass' first required here AClass { boost::scoped_ptr<int> sp_pointer; }; ^ 2 errors generated.
I have argued on the clang developers list that requiring C++ programmers to provide a default copy constructor for a class whose object is never meant to be copied or a default assignment operator for a class which is never meant to be assigned, even if that means private declarations in C++03 or deleted declarations in C++11, can never be a good idea and goes against the C++ standard. The clang answer has been that exporting classes is outside the C++ standard so the C++ standard rules do not apply in this case. Note again that having BOOST_SYMBOL_EXPORT become __attribute__((__visibility__("default"))) for clang on Windows targeting mingw/gcc fixes this problem for that compilation environment. In fact for gcc using mingw/gcc we do indeed use __attribute__((__visibility__("default"))) and that works fine with mingw/gcc in the exact same exporting situations. Similarly for VC++ compilation having BOOST_SYMBOL_EXPORT be __declspec(dllexport) works fine also. I have not yet been able to get from clang developer why exporting a class using __declspec(dllexport) or its equivalent __attribute__((dllexport)) works the way it does, but using __attribute__((__visibility__("default"))) gives no problems. The discussion still appears to be ongoing. Do we want to change BOOST_SYMBOL_EXPORT on clang with Windows targeting mingw/gcc to specify __attribute__((__visibility__("default"))) as we do with mingw/gcc ? It is a fairly simple change which I can make. I just wanted to bring this whole issue to the attention of Boost before I implement any change. I am of course still hoping tha clang changes the way it views the exporting situation and still think they are wrong.