[cfe-dev] Interesting clang behavior/bug? on Windows

Nico Weber thakis at chromium.org
Fri Feb 13 22:22:16 PST 2015


On Fri, Feb 13, 2015 at 8:43 PM, Edward Diener <
eldlistmailingz at tropicsoft.com> wrote:

> On 2/13/2015 11:17 PM, Nico Weber wrote:
>
>> Hans would know for sure, but I think this is intentional: Since AClass
>> is dllexported, all its implicit functions get generated (so that they
>> can be exported from the dll), which means they need to be semantically
>> checked. If you give the class a deleted copy constructor and assignment
>> operator, it might work.
>>
>
> Where in the C++ standard is such behavior justified ?
>

The C++ standard doesn't talk about dllexport, so it won't say either way.

This isn't a question of standards, it's a question of practicality. The
way dllexport / dllimport are used is usually like so (think of a class
that has a valid copy constructor for a bit):

#ifdef IMPL
#define EXPORT __attribute__((dllexport))
#else
#define EXPORT __attribute((dllimport))
#endif

class EXPORT MyClass { ... };

Then, while building your dll, you define IMPL, and while building users,
you don't. When the dll is being built, the compiler doesn't know if
clients are going to use MyClass's implicit copy constructor, so its
choices are:

1.) Generate it when it's dllexported and put it into the dll. Then, if
clients use it, they'll get it from the dll.
2.) Don't generate it when it's dllexported.
2a) Don't even generate the implementation when clients use it. Now the
copy constructor isn't defined anywhere and you'll get linker errors.
2b) Emit a weak definition into every TU that uses it. I think this would
work, but you end up with several copy constructors – if you wanted this,
you probably wouldn't have EXPORTed the class.

Because of this reasoning (I would guess), clang chooses 1 and defines all
implicit methods for dllexported classes. Now, in your case the definition
of some of these implicit methods causes an error. I suppose clang's logic
could instead be "only define all implicit methods that are valid", but I
think this can be different in different TUs. Consider:

  class A;
  class EXPORT B { unique_ptr<A> a_; };

I think the implicit destructor of B will be valid in TUs that happen to
include the header that defines A but not in others. So that doesn't seem
like a good rule.

Nico


>
> The C++ standard does tell us I believe that if an object of a class is
> not copied there is never a need to specify a copy constructor and if a
> class is not assigned there is never a need to specify an assignment
> operator, whether or not one has a non-copyable or non-assignable member or
> not. Changing that basic rule to support something in clang related to
> "exported' classes cannot be correct IMO.
>
> Why does '__attribute__((__visibility__("default")))' work but
> '__attribute__((dllexport))' does not ? Aren't they both the equivalent of
> "exporting" a class in clang ?
>
> I realize that for clang on Windows targeting mingw/gcc and not VC++ that
> the correct "export" attribute is probably '__attribute__((__visibility__("default")))'
> and not '__attribute__((dllexport))'. But I heavily object to the idea that
> because I might be exporting a class the rules of copyability or
> assignability for that class must change contrary to the C++ standard. This
> also puts an extra conceptual burden on the design of a class.
>
>
>> On Fri, Feb 13, 2015 at 8:07 PM, Edward Diener
>> <eldlistmailingz at tropicsoft.com
>> <mailto:eldlistmailingz at tropicsoft.com>> wrote:
>>
>>     I am compiling code with "-c -x c++ -O0 -g -fno-inline -Wall -g"
>>     using clang targeting mingw/gcc on Windows.
>>
>>     This code compiles with no errors ( boost::scoped_ptr<T> is
>>     non-copyable, non-assignable ):
>>
>>     #include <boost/scoped_ptr.hpp>
>>     class
>>     AClass { boost::scoped_ptr<int> sp_pointer; };
>>     int main()  {  return 0;  }
>>
>>     This code compiles with no errors:
>>
>>     #include <boost/scoped_ptr.hpp>
>>     class __attribute__((__visibility__(__"default")))
>>     AClass { boost::scoped_ptr<int> sp_pointer; };
>>     int main()  {  return 0;  }
>>
>>     but this code compiles with errors:
>>
>>     #include <boost/scoped_ptr.hpp>
>>     class __attribute__((dllexport))
>>     AClass { boost::scoped_ptr<int> sp_pointer; };
>>     int main()  {  return 0;  }
>>
>>         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.
>>
>>
>>     Comments ?
>>
>>     Should I file a bug report ?
>>
>>     I do not see why, even "exporting" a class, clang should give an
>>     error. If I am not copying/assigning an instance of a class I should
>>     never get a compiler error telling me that some member is not
>>     copyable or assignable.
>>
>>     _________________________________________________
>>     cfe-dev mailing list
>>     cfe-dev at cs.uiuc.edu
>>     <mailto:cfe-dev at cs.uiuc.edu>
>>     http://lists.cs.uiuc.edu/__mailman/listinfo/cfe-dev
>>     <http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev>
>>
>>
>>
>>
>> _______________________________________________
>> cfe-dev mailing list
>> cfe-dev at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>>
>>
>
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20150213/bab819cf/attachment.html>


More information about the cfe-dev mailing list