16

Consider the following program:

#include <type_traits>

struct Thrower
{
    ~Thrower() noexcept(false) { throw 1; }
};

struct Implicit
{
    Thrower t;
};
static_assert(!std::is_nothrow_destructible<Implicit>::value, "Implicit");

struct Explicit
{
    ~Explicit() {}

    Thrower t;
};
static_assert(!std::is_nothrow_destructible<Explicit>::value, "Explicit");

With g++-4.8.1, there is a static assertion failure on Explicit -- it seems to think that ~Explicit() is noexcept. This does not match my expectations. According to §12.4.3:

A declaration of a destructor that does not have an exception-specification is implicitly considered to have the same exception-specification as an implicit declaration

The funny thing here is the check of Implicit seems to be behaving according to my interpretation of §15.4.14 (through §12.4.7).

...If f is an...destructor...it's implicit exception-specification specifies...f has the exception-specification noexcept(true) if every function it directly invokes allows no exceptions.

g++-4.7 lacks is_nothrow_destructable, I wrote my own to check the behavior in 4.7. The program seems to compile perfectly fine. I reserve the right for this to be completely wrong and the source of my confusion:

template <typename T>
struct is_nothrow_destructible
{
    static constexpr bool value = noexcept(std::declval<T>().~T());
};

TL;DR: Why does g++-4.8.1 think that an explicitly-declared destructor with no exception specification is always noexcept(true)?


Update: I opened a bug on this: 57645. If you really need to work around this issue, you can add an exception specification to the destructor (like Thrower has in the example).

Travis Gockel
  • 26,877
  • 14
  • 89
  • 116

1 Answers1

7

TL;DR: Why does g++-4.8.1 think that an explicitly-declared destructor with no exception specification is always noexcept(true)?

Because it has a bug?

Your interpretation of the standard is correct, and Clang implements it correctly (the assert doesn't fire).

f has the exception-specification noexcept(true) if every function it directly invokes allows no exceptions.

A destructor directly invokes the destructor of all subobjects:

§12.4 [class.dtor] p8:

After executing the body of the destructor and destroying any automatic objects allocated within the body, a destructor for class X calls the destructors for X’s direct non-variant non-static data members, [...].

Xeo
  • 129,499
  • 52
  • 291
  • 397
  • 2
    Oh yeah, please file a bugreport [over at GCC's bugtracker](http://gcc.gnu.org/bugzilla/). – Xeo Jun 18 '13 at 20:54
  • I was hoping I was wrong instead of the compiler...it is a much more comfortable thing. I opened a bug on it. – Travis Gockel Jun 19 '13 at 05:09