[cfe-dev] problem with std::function and virtual destructor

Richard Smith richard at metafoo.co.uk
Sun Jul 15 01:07:37 PDT 2012


On Sun, Jul 15, 2012 at 12:59 AM, Richard Smith <richard at metafoo.co.uk>wrote:

> On Sat, Jul 14, 2012 at 11:40 PM, Rich E <reakinator at gmail.com> wrote:
>
>> Hi all,
>>
>> Can anyone explain why the following doesn't compile?
>>
>> #include <functional>
>>
>> struct X{
>> typedef std::function<void(X&)> callback_type;
>>  virtual ~X() {}
>> private:
>> callback_type _cb;
>> };
>>
>> int main(){}
>>
>>
>> If you comment out the virtual destructor, the code compiles fine.  Full
>> error report:
>>
>>
>> ################################################
>>
>> CompileC
>> build/test_function_callback.build/Debug/test_function_callback.build/Objects-normal/x86_64/main.o
>> test_function_callback/main.cpp normal x86_64 c++
>> com.apple.compilers.llvm.clang.1_0.compiler
>>
>>     cd /Volumes/ssd/code/sandbox/test_function_callback
>>
>>     setenv LANG en_US.US-ASCII
>>
>>
>> /Applications/Xcode45-DP2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang
>> -x c++ -arch x86_64 -fmessage-length=0 -std=gnu++11 -stdlib=libc++
>> -Wno-trigraphs -fpascal-strings -O0 -Wno-missing-field-initializers
>> -Wno-missing-prototypes -Wreturn-type -Wno-non-virtual-dtor
>> -Wno-overloaded-virtual -Wno-exit-time-destructors -Wformat
>> -Wno-missing-braces -Wparentheses -Wswitch -Wno-unused-function
>> -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value
>> -Wuninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants
>> -Wno-conversion -Wno-sign-compare -Wshorten-64-to-32 -Wno-newline-eof
>> -Wc++11-extensions -DDEBUG=1 -isysroot
>> /Applications/Xcode45-DP2.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk
>> -fasm-blocks -Wdeprecated-declarations -Winvalid-offsetof
>> -mmacosx-version-min=10.7 -g -fvisibility-inlines-hidden
>> -Wno-sign-conversion -iquote
>> /Volumes/ssd/code/sandbox/test_function_callback/build/test_function_callback.build/Debug/test_function_callback.build/test_function_callback-generated-files.hmap
>> -I/Volumes/ssd/code/sandbox/test_function_callback/build/test_function_callback.build/Debug/test_function_callback.build/test_function_callback-own-target-headers.hmap
>> -I/Volumes/ssd/code/sandbox/test_function_callback/build/test_function_callback.build/Debug/test_function_callback.build/test_function_callback-all-target-headers.hmap
>> -iquote
>> /Volumes/ssd/code/sandbox/test_function_callback/build/test_function_callback.build/Debug/test_function_callback.build/test_function_callback-project-headers.hmap
>> -I/Volumes/ssd/code/sandbox/test_function_callback/build/Debug/include
>> -I/Applications/Xcode45-DP2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include
>> -I/Volumes/ssd/code/sandbox/test_function_callback/build/test_function_callback.build/Debug/test_function_callback.build/DerivedSources/x86_64
>> -I/Volumes/ssd/code/sandbox/test_function_callback/build/test_function_callback.build/Debug/test_function_callback.build/DerivedSources
>> -F/Volumes/ssd/code/sandbox/test_function_callback/build/Debug -MMD -MT
>> dependencies -MF
>> /Volumes/ssd/code/sandbox/test_function_callback/build/test_function_callback.build/Debug/test_function_callback.build/Objects-normal/x86_64/main.d
>> --serialize-diagnostics
>> /Volumes/ssd/code/sandbox/test_function_callback/build/test_function_callback.build/Debug/test_function_callback.build/Objects-normal/x86_64/main.dia
>> -c
>> /Volumes/ssd/code/sandbox/test_function_callback/test_function_callback/main.cpp
>> -o
>> /Volumes/ssd/code/sandbox/test_function_callback/build/test_function_callback.build/Debug/test_function_callback.build/Objects-normal/x86_64/main.o
>>
>>
>> In file included from
>> /Volumes/ssd/code/sandbox/test_function_callback/test_function_callback/main.cpp:1:
>>
>> In file included from
>> /Applications/Xcode45-DP2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/functional:462:
>>
>> /Applications/Xcode45-DP2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/type_traits:2825:19:
>> error: invalid application of 'sizeof' to an incomplete type 'X'
>>
>>     static_assert(sizeof(_Tp) > 0, "Type must be complete.");
>>
>>                   ^~~~~~~~~~~
>>
>> /Applications/Xcode45-DP2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/type_traits:2830:15:
>> note: in instantiation of template class 'std::__1::__check_complete<X>'
>> requested here
>>
>>     : private __check_complete<_Tp>
>>
>>               ^
>>
>> /Applications/Xcode45-DP2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/type_traits:2812:15:
>> note: in instantiation of template class 'std::__1::__check_complete<X &>'
>> requested here
>>
>>       private __check_complete<_T0, _Tp...>
>>
>>               ^
>>
>> /Applications/Xcode45-DP2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/type_traits:2978:15:
>> note: in instantiation of template class
>> 'std::__1::__check_complete<std::__1::function<void (X &)> &, X &>'
>> requested here
>>
>>     : private __check_complete<_Fp, _Args...>
>>
>>               ^
>>
>> /Applications/Xcode45-DP2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/type_traits:2989:11:
>> note: in instantiation of template class
>> 'std::__1::__invokable_imp<std::__1::function<void (X &)> &, X &>'
>> requested here
>>
>>           __invokable_imp<_Fp, _Args...>::value>
>>
>>           ^
>>
>> /Applications/Xcode45-DP2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/functional:1115:33:
>> note: in instantiation of template class
>> 'std::__1::__invokable<std::__1::function<void (X &)> &, X &>' requested
>> here
>>
>>     template <class _Fp, bool = __invokable<_Fp&, _ArgTypes...>::value>
>>
>>                                 ^
>>
>> /Applications/Xcode45-DP2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/functional:1163:9:
>> note: in instantiation of default argument for
>> '__callable<std::__1::function<void (X &)> >' required here
>>
>>         __callable<typename decay<_Fp>::type>::value,
>>
>>         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>
>> /Applications/Xcode45-DP2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/functional:1166:7:
>> note: while substituting deduced template arguments into function template
>> 'operator=' [with _Fp = const std::__1::function<void (X &)> &]
>>
>>       operator=(_Fp&&);
>>
>>       ^
>>
>> /Volumes/ssd/code/sandbox/test_function_callback/test_function_callback/main.cpp:3:8:
>> note: definition of 'X' is not complete until the closing '}'
>>
>> struct X{
>>
>>        ^
>>
>> 1 error generated.
>> ################################################
>>
>>
>>
>> Please let me know if I should report this as a bug.
>>
>
> What's happening is:
> * We need to implicitly declare a copy assignment operator for X.
> * To do that, we need to compute whether the implicitly-declared copy
> assignment operator takes a const or non-const argument.
> * To do that, we need to check whether any member of the class takes a
> non-const argument.
> * To do that, we perform overload resolution in callback_type looking for
> the operator= which is used to copy _cb. And that leads to the diagnostic
> you're seeing.
>
> The C++ standard doesn't say that we should use overload resolution here,
> and that we should instead just look for any operator= in the member's
> class type M with a parameter type of exactly const M&, const volatile M&,
> or M. So that seems like a Clang bug (please do file a bug for this).
>
> As it happens, we'd currently have to perform overload resolution to look
> up the member's operator= anyway, since it's needed to determine X's
> operator='s exception specification, but the standard is being changed so
> that the exception specification is computed on demand (this is core issue
> 1330, and we do not yet implement this part of it).
>

We also need to perform the lookup to determine whether operator= should be
deleted or constexpr, so this extra leeway actually doesn't help, and your
code would still be rejected when we fix those issues.


> As an optimization, we defer adding the implicit members to a class if it
> has no virtual functions (if there are virtual functions, the
> implicitly-declared member might override a virtual function in a base
> class, so we don't perform this optimization in that case). This process
> isn't supposed to be able to fail, so that's safe. And that's why removing
> the virtual destructor makes the bug disappear.
>
>
> I'm not sure why instantiating std::function<void(X&)>::operator= would
> require X to be complete -- libstdc++ does not behave that way. It's
> possible this is a bug in libc++, but it's also possible that the standard
> allows this behavior and libstdc++ is just more permissive. Hopefully
> Howard can help with that part.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20120715/18bd6008/attachment.html>


More information about the cfe-dev mailing list