Is the following code legal?
struct S
{};
int main()
{
S* p = new S;
p->~S();
delete p;
}
The standard rules at [basic.life#6]:
Before the lifetime of an object has started but after the storage which the object will occupy has been allocated24 or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that represents the address of the storage location where the object will be or was located may be used but only in limited ways. For an object under construction or destruction, see [class.cdtor]. Otherwise, such a pointer refers to allocated storage ([basic.stc.dynamic.allocation]), and using the pointer as if the pointer were of type void* is well-defined. Indirection through such a pointer is permitted but the resulting lvalue may only be used in limited ways, as described below. The program has undefined behavior if:
(6.1) — the object will be or was of a class type with a non-trivial destructor and the pointer is used as the operand of a delete-expression,
(6.2) — the pointer is used to access a non-static data member or call a non-static member function of the object
[basic.life#6.1] doesn't apply, so this code seems to be legal because S has a trivial destructor.
However, according to [basic.life#6.2], this code is illegal because the delete-expression calls the destructor of the S object, which is a non-static member function of it.
EDIT: According to [class.dtor#19], it's also illegal.
Which should I listen to? Maybe [basic.life#6.2], because [basic.life#6.1] doesn't stipulate that it must be legal to do so for classes with trivial destructor.
The conclusion is that it's illegal.
However, after replacing S with a scalar type, things seem to be different:
#include <memory>
int main()
{
char* p = new char;
std::destroy_at(p);
delete p;
}
This will make a pseudo-destructor call to the char object pointed to by p, which will end its lifetime, according to [expr.call#5]:
If the postfix-expression names a pseudo-destructor (in which case the postfix-expression is a possibly-parenthesized class member access), the function call destroys the object of scalar type denoted by the object expression of the class member access ([expr.ref], [basic.life]).
[basic.life#6.1] still doesn't apply.
But the difference is that [basic.life#6.2] doesn't apply either, because there is no non-static member function called for the char object (char isn't a class after all).
The conclusion is that it's legal.
Why?