llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.64k stars 11.84k forks source link

clang can't successfully destroy an integer variable via a pseudo destructor #111639

Open tbaederr opened 2 weeks ago

tbaederr commented 2 weeks ago

This code:

  typedef int I;

  constexpr int foo() {
    int k = 0;
    k.~I();
    return 0;
  }

should probably work, GCC and MSVC accept it: https://godbolt.org/z/MavW6o7ox

And clang's diagnostic seem bogus:

./array.cpp:231:17: error: constexpr function never produces a constant expression [-Winvalid-constexpr]
  231 |   constexpr int foo() {
      |                 ^~~
./array.cpp:232:9: note: destroying object 'k' whose lifetime has already ended
  232 |     int k = 0;
      |         ^
llvmbot commented 2 weeks ago

@llvm/issue-subscribers-clang-frontend

Author: Timm Baeder (tbaederr)

This code: ```c++ typedef int I; constexpr int foo() { int k = 0; k.~I(); return 0; } ``` should probably work, GCC and MSVC accept it: https://godbolt.org/z/MavW6o7ox And clang's diagnostic seem bogus: ```console ./array.cpp:231:17: error: constexpr function never produces a constant expression [-Winvalid-constexpr] 231 | constexpr int foo() { | ^~~ ./array.cpp:232:9: note: destroying object 'k' whose lifetime has already ended 232 | int k = 0; | ^ ```
tbaederr commented 2 weeks ago

This might actually work just fine. The note is being emitted when k is being destroyed at the end of the scope, where its lifetime has already ended when it was destroyed by the pseudo dtor expr.

So is clang correct here or the other compilers?

Looks like MSVC simply ignores the pseudo destructor while GCC makes the most sense to me: https://godbolt.org/z/71E33dvxW

frederick-vs-ja commented 2 weeks ago

The title seems wrong. Clang accepts such use when one uses std::construct_at to resurrect k (demo). So, it turns out that Clang correctly destroys k but considers double destruction of a scalar object to be UB.

The current standard wording seemingly implies that double destruction of a scalar object is not UB and such repeated destruction has no effect. It's totally unclear to me whether this is intended, and I attempted to submit a CWG issue for this (cplusplus/CWG#361).

CC @zygoloid @jensmaurer

shafik commented 2 weeks ago

The title seems wrong. Clang accepts such use when one uses std::construct_at to resurrect k (demo). So, it turns out that Clang correctly destroys k but considers double destruction of a scalar object to be UB.

The current standard wording seemingly implies that double destruction of a scalar object is not UB and such repeated destruction has no effect. It's totally unclear to me whether this is intended, and I attempted to submit a CWG issue for this (cplusplus/CWG#361).

CC @zygoloid @jensmaurer

I am almost sure we had a recent issue related to this and IIRC the consensus was double destruction is UB.