<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Sat, Feb 14, 2015 at 4:08 PM, Edward Diener <span dir="ltr"><<a href="mailto:eldlistmailingz@tropicsoft.com" target="_blank">eldlistmailingz@tropicsoft.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On 2/14/2015 5:48 PM, Reid Kleckner wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
There might be a Clang bug here, depending on whether the copy ctor is<br>
supposed to be implicitly deleted or not. I forget if having a base<br>
class with a private copy ctor implicitly deletes derived class copy<br>
ctors or not.<br>
</blockquote>
<br></span>
The second sentence above is not the case in my example, since there is no base class involved. I also did not compile in C++11 mode in my example AFAICS. Don't I need a command-line switch of -std=c++11 for that ?</blockquote><div><br></div><div>In C++11, the copy constructor would be deleted because the base class dtor is inaccessible. In C++98, it will not be, because there is no notion of deleted functions.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Clang's class dllexport semantics are modeled on MSVC's because they<br>
make more sense than GCC's for PE/COFF. As Nico said, the idea is that<br>
we emit all these special members (and inline functions!) so that<br>
clients can dllimport them and not have to emit definitions. This is an<br>
intentional semantic difference from ELF's visibility model, which has a<br>
different mechanism for ensuring that the addresses of inline functions<br>
are the same across DSO boundaries.<br>
<br>
If you can find a way to delete, explicitly or implicitly, the unwanted<br>
copy ctor, then Clang should skip it while exporting the rest. If not,<br>
that's a bug.<br>
</blockquote>
<br></span>
Let me start by saying that both mingw/mingw64/gcc on Windows and VC++ compiles the example I gave without error using their respective Windows export keywords. Clang as I have shown does not.<br></blockquote><div><br></div><div>Presumably MSVC accepts because they build in C++11 mode (sort of -- they don't *have* a separate C++98 mode). I would expect Clang to also accept the code that MSVC accepts when run in C++11 mode.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Whether or not clang generates an implicit copy constructor / copy-assignment operator when the user does not have one seems to me to be an irrelevant issue. If objects of the class are never copied/assigned why should clang generate an error ?</blockquote><div><br></div><div>Because, as has already been stated, marking a class as dllexport causes some of its implicitly-generated methods to be exported, which triggers their definition. We may be getting the "some" wrong here, or the rules for mingw and for MSVC might be different, but it *is* correct that we trigger the definition of some implicit members in some cases when the class is marked dllexport -- this is necessary for link compatibility with MSVC.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">This is regardless of whether the class is exported or not. I have a class that cannot be copied/assigned so naturally I see no need to create a user-defined copy constructor or copy-assignment operator. How can I be wrong not doing so ? Even when I export the class I am still telling users of the class that import it that it cannot be copied or assigned. That seems pretty clearcut to me. Clang now wants to tell me that if I export the class I must change how I code the class as to provide a user-defined copy constructor/assignment operator ( or a private declaration/deleted function depending on C++03/C++11 ) to satisfy clang ? That is not logically right from this end-user's point of view. I am also pretty sure that in C++03 if a class is not copyable I am not required to provide a user-defined copy constructor or private copy constructor declaration when defining the class.<br>
<br>
Even in a C++11 compilation is it actually a C++ standard error if the programmer does not provide deleted versions of the copy constructor / assignment operator when objects of that class cannot be copied / assigned using the default generated copy constructor / assignment operator ? I do not think so. According to my reading of the C++11 standard as interpreted by Lippman in C++ Fifth Edition,<br>
<br>
"The synthesized copy constructor is defined as deleted if the class has a member whose own copy constructor is deleted or inaccesible..."<br>
<br>
"The synthesized copy-assignment operator is defined as deleted if a member has a deleted or inaccessible copy-assignment operator..."<br>
<br>
I realized I am not quoting from the C++11 standard but unless Lippman is in error here I cannot see other than that clang is in error in the case I have presented.<br></blockquote><div><br></div><div>You're using a language extension, so the guarantees of the C++ standard are not relevant.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
I don't mind filing a bug report on this but I want to get some agreement here that clang is not doing the right thing even in the face of an "export" of the class. The job of defining an implicit copy constructor and copy-assignment operator is that of the compiler and if clang wants to claim that in the face of the "export" keyword it is not required to follow the standard C++ rules of how thiws should be done, I do not want to follow up with such a bug report.<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
<br>
On Fri, Feb 13, 2015 at 11:26 PM, Edward Diener<br>
<<a href="mailto:eldlistmailingz@tropicsoft.com" target="_blank">eldlistmailingz@tropicsoft.<u></u>com</a><br></span><span class="">
<mailto:<a href="mailto:eldlistmailingz@tropicsoft.com" target="_blank">eldlistmailingz@<u></u>tropicsoft.com</a>>> wrote:<br>
<br>
    On 2/14/2015 1:22 AM, Nico Weber wrote:<br>
<br>
        On Fri, Feb 13, 2015 at 8:43 PM, Edward Diener<br></span><span class="">
        <eldlistmailingz@tropicsoft.__<u></u>com<br>
        <mailto:<a href="mailto:eldlistmailingz@tropicsoft.com" target="_blank">eldlistmailingz@<u></u>tropicsoft.com</a>><br>
        <mailto:<a href="mailto:eldlistmailingz@" target="_blank">eldlistmailingz@</a>__<a href="http://tropicsoft.com" target="_blank">trop<u></u>icsoft.com</a><br>
        <mailto:<a href="mailto:eldlistmailingz@tropicsoft.com" target="_blank">eldlistmailingz@<u></u>tropicsoft.com</a>>>><br>
        wrote:<br>
<br></span><div><div class="h5">
             On 2/13/2015 11:17 PM, Nico Weber wrote:<br>
<br>
                 Hans would know for sure, but I think this is<br>
        intentional: Since<br>
                 AClass<br>
                 is dllexported, all its implicit functions get<br>
        generated (so<br>
                 that they<br>
                 can be exported from the dll), which means they need to be<br>
                 semantically<br>
                 checked. If you give the class a deleted copy<br>
        constructor and<br>
                 assignment<br>
                 operator, it might work.<br>
<br>
<br>
             Where in the C++ standard is such behavior justified ?<br>
<br>
<br>
        The C++ standard doesn't talk about dllexport, so it won't say<br>
        either way.<br>
<br>
        This isn't a question of standards, it's a question of<br>
        practicality. The<br>
        way dllexport / dllimport are used is usually like so (think of<br>
        a class<br>
        that has a valid copy constructor for a bit):<br>
<br>
        #ifdef IMPL<br>
        #define EXPORT __attribute__((dllexport))<br>
        #else<br>
        #define EXPORT __attribute((dllimport))<br>
        #endif<br>
<br>
        class EXPORT MyClass { ... };<br>
<br>
        Then, while building your dll, you define IMPL, and while building<br>
        users, you don't.<br>
<br>
<br>
    I know this of course.<br>
<br>
        When the dll is being built, the compiler doesn't know<br>
        if clients are going to use MyClass's implicit copy constructor,<br>
        so its<br>
        choices are:<br>
<br>
        1.) Generate it when it's dllexported and put it into the dll.<br>
        Then, if<br>
        clients use it, they'll get it from the dll.<br>
        2.) Don't generate it when it's dllexported.<br>
        2a) Don't even generate the implementation when clients use it.<br>
        Now the<br>
        copy constructor isn't defined anywhere and you'll get linker<br>
        errors.<br>
        2b) Emit a weak definition into every TU that uses it. I think this<br>
        would work, but you end up with several copy constructors – if you<br>
        wanted this, you probably wouldn't have EXPORTed the class.<br>
<br>
        Because of this reasoning (I would guess), clang chooses 1 and<br>
        defines<br>
        all implicit methods for dllexported classes. Now, in your case the<br>
        definition of some of these implicit methods causes an error. I<br>
        suppose<br>
        clang's logic could instead be "only define all implicit methods<br>
        that<br>
        are valid", but I think this can be different in different TUs.<br>
        Consider:<br>
<br>
            class A;<br>
            class EXPORT B { unique_ptr<A> a_; };<br>
<br>
        I think the implicit destructor of B will be valid in TUs that<br>
        happen to<br>
        include the header that defines A but not in others. So that doesn't<br>
        seem like a good rule.<br>
<br>
<br>
    A TU that does not include the header that defines A is just being<br>
    stupid so I think the compiler can choose to assume that an implicit<br>
    destructor can be generated. And if there really is no definition<br>
    for A then the design of B is just an error. The compiler should<br>
    make reasonable choices. For B since C++11 is necesary for<br>
    unique_ptr, deleted copy constructors and assignment operators<br>
    should be generated if the compiler does not encounter any since<br>
    unique_ptr is not copyable or assignable.<br>
<br>
    The problem is that you are forcing class designers, when a class is<br>
    exportable, to generate copy constructors and assignment operators<br>
    even when objects of that class are never meant to be copied or<br>
    assigned. Of course the practical solution for this is to generate<br>
    private declarations in C++03 and deleted declarations in C++11, but<br>
    still it seems silly to enforce this. Instead the compiler should<br>
    automatically generate these solutions when it sees that a class is<br>
    not copyable or when it sees that a class is not assignable, and the<br>
    designer has not provided his own declarations.<br>
<br>
    I really think it is wrong for clang to force class designers, even<br>
    when exporting a class, to do something he would ordinarily never<br>
    have to do in C++.<br>
<br>
    BTW gcc works correctly in the same situation in not generating any<br>
    error when '__attribute__((dllexport))' is being used for mingw/gcc,<br>
    if that means anything to clang.<br>
<br>
    Also VC++ works correctly in the same situation when<br>
    __declspec(dllexport) is being used, if that means anything to clang.<br>
<br>
    Also as I noticed, when<br></div></div>
    '__attribute__((__visibility__<u></u>____("default")))' is being used,<span class=""><br>
    which I assume is the Linux equivalent of 'exporting' a class, clang<br>
    evidently does the right thing and generates no error. Why does it<br>
    therefore operate differently with '__attribute__((dllexport))' ?<br>
<br>
    Is it a valid Boost solution to use<br></span>
    '__attribute__((__visibility__<u></u>____("default")))' for clang on<span class=""><br>
    Windows targeting mingw/gcc as a workaround for this problem instead<br>
    of having to change the exported class itself ? This of course would<br>
    not solve the problem of using clang on Windows targeting VC++,<br>
    where I assume '__attribute__((dllexport))' is correct and<br></span>
    '__attribute__((__visibility__<u></u>____("default")))' would not be<span class=""><br>
    recognized, but I am less interested in that compiler for Boost.<br>
<br>
<br>
        Nico<br>
<br>
<br>
             The C++ standard does tell us I believe that if an object<br>
        of a class<br>
             is not copied there is never a need to specify a copy<br>
        constructor<br>
             and if a class is not assigned there is never a need to<br>
        specify an<br>
             assignment operator, whether or not one has a non-copyable or<br>
             non-assignable member or not. Changing that basic rule to<br>
        support<br>
             something in clang related to "exported' classes cannot be<br>
        correct IMO.<br>
<br></span>
             Why does '__attribute__((__visibility__<u></u>____("default")))'<span class=""><br>
        work but<br>
             '__attribute__((dllexport))' does not ? Aren't they both the<br>
             equivalent of "exporting" a class in clang ?<br>
<br>
             I realize that for clang on Windows targeting mingw/gcc and<br>
        not VC++<br>
             that the correct "export" attribute is probably<br></span>
             '__attribute__((__visibility__<u></u>____("default")))' and not<span class=""><br>
             '__attribute__((dllexport))'. But I heavily object to the<br>
        idea that<br>
             because I might be exporting a class the rules of<br>
        copyability or<br>
             assignability for that class must change contrary to the C++<br>
             standard. This also puts an extra conceptual burden on the<br>
        design of<br>
             a class.<br>
<br>
<br>
                 On Fri, Feb 13, 2015 at 8:07 PM, Edward Diener<br></span>
                 <eldlistmailingz@tropicsoft.__<u></u>__com<br>
                 <mailto:<a href="mailto:eldlistmailingz@" target="_blank">eldlistmailingz@</a>__<a href="http://tropicsoft.com" target="_blank">trop<u></u>icsoft.com</a><br>
        <mailto:<a href="mailto:eldlistmailingz@tropicsoft.com" target="_blank">eldlistmailingz@<u></u>tropicsoft.com</a>>><br>
                 <mailto:<a href="mailto:eldlistmailingz@" target="_blank">eldlistmailingz@</a><br>
        <mailto:<a href="mailto:eldlistmailingz@" target="_blank">eldlistmailingz@</a>>__<a href="http://trop__icsoft.com" target="_blank">tro<u></u>p__icsoft.com</a> <<a href="http://tropicsoft.com" target="_blank">http://tropicsoft.com</a>><span class=""><br>
                 <mailto:<a href="mailto:eldlistmailingz@" target="_blank">eldlistmailingz@</a>__<a href="http://tropicsoft.com" target="_blank">trop<u></u>icsoft.com</a><br>
        <mailto:<a href="mailto:eldlistmailingz@tropicsoft.com" target="_blank">eldlistmailingz@<u></u>tropicsoft.com</a>>>>><br>
                 wrote:<br>
<br>
                      I am compiling code with "-c -x c++ -O0 -g -fno-inline<br>
                 -Wall -g"<br>
                      using clang targeting mingw/gcc on Windows.<br>
<br>
                      This code compiles with no errors (<br>
        boost::scoped_ptr<T> is<br>
                      non-copyable, non-assignable ):<br>
<br>
                      #include <boost/scoped_ptr.hpp><br>
                      class<br>
                      AClass { boost::scoped_ptr<int> sp_pointer; };<br>
                      int main()  {  return 0;  }<br>
<br>
                      This code compiles with no errors:<br>
<br>
                      #include <boost/scoped_ptr.hpp><br></span>
                      class __attribute__((__visibility__(<u></u>______"default")))<span class=""><br>
                      AClass { boost::scoped_ptr<int> sp_pointer; };<br>
                      int main()  {  return 0;  }<br>
<br>
                      but this code compiles with errors:<br>
<br>
                      #include <boost/scoped_ptr.hpp><br>
                      class __attribute__((dllexport))<br>
                      AClass { boost::scoped_ptr<int> sp_pointer; };<br>
                      int main()  {  return 0;  }<br>
<br>
                          test_clang_bug.cpp:3:1: error: field of type<br>
                          'boost::scoped_ptr<int>' has private copy<br>
        constructor<br>
                          AClass { boost::scoped_ptr<int> sp_pointer; };<br>
                          ^<br>
<br></span>
          ..\..\..\boost/smart_ptr/_____<u></u>_scoped_ptr.hpp:47:5: note:<span class=""><br>
                 declared<br>
                          private here<br>
                               scoped_ptr(scoped_ptr const &);<br>
                               ^<br>
                          test_clang_bug.cpp:3:1: note: implicit copy<br>
        constructor for<br>
                          'AClass' first required here<br>
                          AClass { boost::scoped_ptr<int> sp_pointer; };<br>
                          ^<br>
                          test_clang_bug.cpp:3:1: error: 'operator=' is<br>
        a private<br>
                 member<br>
                          of 'boost::scoped_ptr<int>'<br>
                          AClass { boost::scoped_ptr<int> sp_pointer; };<br>
                          ^<br>
<br></span>
          ..\..\..\boost/smart_ptr/_____<u></u>_scoped_ptr.hpp:48:18:<div><div class="h5"><br>
                 note: declared<br>
                          private here<br>
                               scoped_ptr & operator=(scoped_ptr const &);<br>
                                            ^<br>
                          test_clang_bug.cpp:3:1: note: implicit copy<br>
        assignment<br>
                 operator<br>
                          for 'AClass' first required here<br>
                          AClass { boost::scoped_ptr<int> sp_pointer; };<br>
                          ^<br>
                          2 errors generated.<br>
<br>
<br>
                      Comments ?<br>
<br>
                      Should I file a bug report ?<br>
<br>
                      I do not see why, even "exporting" a class, clang<br>
        should<br>
                 give an<br>
                      error. If I am not copying/assigning an instance<br>
        of a class<br>
                 I should<br>
                      never get a compiler error telling me that some<br>
        member is not<br>
                      copyable or assignable.<br>
</div></div></blockquote><div class="HOEnZb"><div class="h5">
<br>
<br>
<br>
______________________________<u></u>_________________<br>
cfe-dev mailing list<br>
<a href="mailto:cfe-dev@cs.uiuc.edu" target="_blank">cfe-dev@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev" target="_blank">http://lists.cs.uiuc.edu/<u></u>mailman/listinfo/cfe-dev</a><br>
</div></div></blockquote></div><br></div></div>