Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CWG2839 [class.dtor] A destructor call might need to know whether the object to destroy is a most derived object if there is a virtual base class #478

Open
frederick-vs-ja opened this issue Dec 7, 2023 · 3 comments

Comments

@frederick-vs-ja
Copy link

frederick-vs-ja commented Dec 7, 2023

Full name of submitter (unless configured in github; will be published with the issue): Jiang An

Reference (section label): [class.dtor]

Link to reflector thread (if any):

Issue description:

[class.dtor] p13 reads:

[...] and, if X is the most derived class ([class.base.init]), its destructor calls the destructors for X's virtual base classes. [...]

When the destructor is implicitly invoked, the structure of objects to be destroy are statically known, and thus it's clear whether every X is the most derived class.

However, if the destructor is explicitly invoked, there can be situations where the structure of the explicitly destroyed object is not statically known. As a result, it may be unclear to the implementation whether destructors need to or not to be called for virtual base class subobjects.

E.g. in the following example, does the explicit destructor invocation call B::~B?

struct B {
    B() = default;
    ~B() { /* some operations */ }
};

struct DX : virtual B {};

struct DY : virtual B {};

struct DZ : DX, DY {};

template<class T>
union NoDestroy {
    T val;
    NoDestroy() : val() {}
    NoDestroy(const NoDestroy&) = delete;
    NoDestroy &operator=(const NoDestroy&) = delete;
    ~NoDestroy() {}
};

int main()
{
    NoDestroy<DZ> d{};
    static_cast<DY&>(d.val).~DY();
}

It doesn't seem intended to require the implementation to record whether such an object is a most derived object. Current implementations call destructors for virtual base class subobjects whenever the destructor of the derived class is explicitly called. However, on some implementations (GCC and Clang), such an explicit destructor call can be only valid for most derived objects (llvm/llvm-project#74282).

Suggested resolution:

@t3nsor
Copy link

t3nsor commented Dec 12, 2023

I think this question is closely related to the question of what should happen if you have a most derived object of type Z, it has a base class X, and X has a virtual base class V, and you attempt to transparently replace the X subobject, i.e., by placement newing an X over it. It seems like we can't support transparent replacement in that case because it's unspecified whether the V subobject gets constructed in the right place for the most derived object. That being the case, it means that in your scenario if the X subobject's destructor were to be invoked explicitly, it cannot ever be safe to invoke Z's destructor subsequently unless you replace the entire Z object first.

@frederick-vs-ja
Copy link
Author

That being the case, it means that in your scenario if the X subobject's destructor were to be invoked explicitly, it cannot ever be safe to invoke Z's destructor subsequently unless you replace the entire Z object first.

Ah, what I attempted to do was not separately invoking two destructors. I've added a simplified version of the example in llvm/llvm-project#74282.

IIRC currently it's clear that a base class subobject, which is always potentially-overlapping, is never transparent replacable. Perhaps we need to specify that the lifetime of the Z most derived object to be ended by the explicit invocation of X::~X() for the X subobject (perhaps when a virtual function or a virtual base class is involved, see also #477).

@jensmaurer jensmaurer changed the title [class.dtor] A destructor call might need to know whether the object to destroy is a most derived object if there is a virtual base class CWG2839 [class.dtor] A destructor call might need to know whether the object to destroy is a most derived object if there is a virtual base class Dec 13, 2023
@jensmaurer
Copy link
Member

CWG2839

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants