I'm trying to get this is-class-defined-check to work, which relies on the fact that decltype(std::declval<Foo>().~Foo())
is void
if Foo
has a destructor (which it has if it is defined…) and is ill-formed otherwise, invoking SFINAE in this case.
However, I can't get the code to work with GCC 9.1, and that is because GCC 9.1 seems to consider that type to be void &
if the destructor is defaulted, consider this example:
#include <type_traits>
class Foo {
public:
// With this, the DestructorReturnType below becomes "void"
// ~Foo () {}
};
// … unless I specify the user-defined destructor above, in which case it is "void"
using DestructorReturnType = decltype(std::declval<Foo>().~Foo());
template<class T>
class TD;
// Says: aggregate 'TD<void&> t' has incomplete type and cannot be defined
TD<DestructorReturnType> t;
(available at https://gcc.godbolt.org/z/K1TjOP )
If I user-define an empty destructor, the type jumps back to void
. Also if I switch back to GCC 8.x.
The C++17 standard states in [expr.call]:
If the postfix-expression designates a destructor, the type of the function call expression is void; […]
Because of all this, I suspect that GCC 8.x (and clang, …) are correct, and GCC 9.1 is just wrong. Or am I missing something?
Long story short: Yes, this is a regression in GCC 9.1. void&
is not even a valid type, so something is very wrong. Apparrently, the problem can be worked around by setting the -fno-lifetime-dse
compiler option, at the (possible, slight) expense of performance. Also, GCC versions before 9.1 are not affected.
If you find this answer because you are also trying to implement the is-class-defined-check above, I think that the much simpler form using sizeof should be well-defined, work and is not hit by this bug.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With