Extended Description
Consider the following code:
template <class T> T &&declval() noexcept;
template <class _Functor> struct invoke_result {
template <class _Fn> static decltype(declval<_Fn>()(0)) s_test();
typedef decltype(s_test<_Functor>()) type;
};
template <class T> struct Core {
Core() {}
virtual ~Core() {}
};
template <class FF> auto run(FF &&ff) {
auto lambda = [ff](auto) { return ff(0); };
using T = typename invoke_result<decltype(lambda)>::type;
return lambda(0);
}
class Trivial {};
Core<Trivial> *f() {
return run([](auto) -> Core<Trivial> * { return new Core<Trivial>(); });
}
If I build this with clang, it emits a vtable for Core<Trivial> that references the complete object and deleting destructors for Core<Trivial>, but it doesn't actually emit those destructors, which later leads to a link error. As best as I can tell, it should be emitting the destructors; all the relevant types are complete, and there's no key functions. https://godbolt.org/z/czGEzT shows that GCC does emit the destructors (-O2 and -fno-rtti are just to clean up the assembly, and if you remove the filtering for directives you'll see that GCC is aliasing the complete object destructor to the base object destructor).
The reduction is very sensitive. Removing the explicit return type from the lambda in f, removing the parameters from the lambdas (so as to make them non-generic lambdas), using FF instead of decltype(lambda) in run, and making s_test in invoke_result use _Functor instead of having its own _Fn template type all make the destructors be emitted. (invoke_result and declval are reduced from libstdc++; I'm not fully confident about the validity of my reduction, but GCC is still able to emit the destructors.)
Extended Description
Consider the following code:
If I build this with clang, it emits a vtable for
Core<Trivial>that references the complete object and deleting destructors forCore<Trivial>, but it doesn't actually emit those destructors, which later leads to a link error. As best as I can tell, it should be emitting the destructors; all the relevant types are complete, and there's no key functions. https://godbolt.org/z/czGEzT shows that GCC does emit the destructors (-O2and-fno-rttiare just to clean up the assembly, and if you remove the filtering for directives you'll see that GCC is aliasing the complete object destructor to the base object destructor).The reduction is very sensitive. Removing the explicit return type from the lambda in
f, removing the parameters from the lambdas (so as to make them non-generic lambdas), usingFFinstead ofdecltype(lambda)in run, and makings_testininvoke_resultuse_Functorinstead of having its own_Fntemplate type all make the destructors be emitted. (invoke_resultanddeclvalare reduced from libstdc++; I'm not fully confident about the validity of my reduction, but GCC is still able to emit the destructors.)