-
Notifications
You must be signed in to change notification settings - Fork 772
Update the example of temporary pseudo-destruction to undefined behavior #4944
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
Comments
Clang seems to agree, but not the others: https://godbolt.org/z/41q4vszP8. [basic.life] says
From [expr.prim.id.dtor], it seems that only explicitly evaluating |
That seems to be [class.temporary] p7. So it would seem that GCC and MSVC are non-conforming here. |
I think that example cannot prove that
[basic.life#7] has no strong evidence/never that says |
Let’s ask @zygoloid since he is the author of the proposal P0593R6. |
A few remarks here. First, the comment is certainly wrong, because "no effect" is wrong. We definitely explicitly destroy the 0 temporary here, causing its lifetime to end before the end of the full-expression. The pseudo-destructor is not a member function, so the question whether it is constexpr doesn't arise (it's handled the way it is by direct core language semantics without involving member functions, even though the syntax looks similar). It seems [basic.life] p7 doesn't speak to the question whether you can end the lifetime of a scalar twice. |
For the first point, [expr.call] p5 says
Hence, constexpr void f() {
using T = int;
(void)0 .T::~T();
}
int main() {
[]() consteval {
f();
}(); // #1 shall be a constant expression as per [expr.const] p13
}
It is not clear whether the pseudo-destructor is a constexpr function or not, hence it's not clear whether For the second point, it is not clear how to destroy an object of scalar type, whether it behaves as if the corresponding pseudo-constructor is called for that object or behaves something else. At least, [basic.lifetime] didn't say such a case is UB. Incidentally, in [class.dtor] p14, should we consider the destructor of a scalar type as the pseudo-destructor since it didn't restrict type |
@xmh0511 |
@languagelawyer Since it is a function call expression, why is there no function invocation? What's the difference here? |
Because there is no function to invoke.
Function call is an expression of the form «postfix-expression |
@languagelawyer An function call expression can directly cause a function invocation, an function invocation can be implicitly caused. For the following concept
I didn't see an explicit definition in the current standard. Assume it is, however, it's unclear whether a pseudo-destructor has a function body or not. Specifically, [basic.def.odr] p7 designates that it's an odr-use of that function; [basic.def.odr] p10 requires that function shall have a definition. |
I think it should be just |
@languagelawyer However,
According to [basic.lval] p1
Hence, we could arguably say |
Could be solved by introducing the concept of an «empty lvalue» from CWG232. There are other lvalues, in addition to |
Actually, I think [expr.ref]/3 should just be prvalue, like in non-scalar type case. |
@languagelawyer Agree. I would wonder why is this example not accepted by the implementations int main() {
using T = int;
T a = 0;
auto ptr = &(a.~T);
}
The example should be fine. It seems that empty value cannot solve the vague of pseudo-destructor since |
@xmh0511 the example violates https://timsong-cpp.github.io/cppwp/n4868/expr.prim.id.dtor#2.sentence-1 |
@languagelawyer Ah, right! I forgot that rule. It seems empty value can work here. |
Since Richard Smith’s proposal P0593R6, a pseudo-destructor call ends the lifetime of a scalar object:
So doesn’t the statement
0 .T::~T();
given in [expr.prim.id.dtor]/3 produce undefined behavior now that it destroys the temporary object 0 twice?The text was updated successfully, but these errors were encountered: