In the case of default_delete it must be diagnosed. See

On Sat, Nov 2, 2019 at 10:40 AM Myria via Std-Discussion <> wrote:
delete for an incomplete type is legal, though it probably should not be.  If the completed type ends up having a nontrivial destructor, the behavior is undefined.

On Sat, Nov 2, 2019 at 07:15 Mark Stegeman via Std-Discussion <> wrote:
Hi list,

I'm having some trouble determining the validity of the following C++17 code:

#include <memory>

struct Base {
    virtual ~Base() = default;

struct Bar;
struct Foo : Base {
    std::unique_ptr<Bar> bar_{};

The following standard quotes lead me to believe that this is ill-formed:

If a class has no user-declared destructor, a destructor is implicitly declared as defaulted. [...]

[...] If a class has a base class with a virtual destructor, its destructor (whether user- or implicitly-declared) is virtual.

A destructor that is defaulted and not defined as deleted is implicitly defined when it is odr-used or when it is explicitly defaulted after its first declaration.

A defaulted destructor for a class X is defined as deleted if:
 - X is a union-like class that has a variant member with a non-trivial destructor,
 - any potentially constructed subobject has class type M (or array thereof) and M has a deleted destructor or a destructor that is inaccessible from the defaulted destructor,
 - or, for a virtual destructor, lookup of the non-array deallocation function results in an ambiguity or in a function that is deleted or inaccessible from the defaulted destructor.

[...] A virtual member function is odr-used if it is not pure. [...]

I would interpret these quotes as: ~Foo() must be implicitly defined, because it is virtual, defaulted, and not defined as deleted. This ~Foo() must invoke ~std::unique_ptr<Bar>(), which invokes std::default_delete<Bar>, which makes the program ill-formed, because Bar is incomplete.

However, practically speaking, since no Foo's are created, there should be no reason to define ~Foo() here. The description of CWG2068 indeed suggests that the intended interpretation is that implementations are not required to define ~Foo() in this example. And the implementations I checked (MSVC, gcc, clang) all accept it as well. So it looks like my interpretation is wrong, but I haven't been able to find why.

Could you tell me where my interpretation goes wrong? What have I missed?


See for a previous discussion

Std-Discussion mailing list
Std-Discussion mailing list

Brian Bi