https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126425

            Bug ID: 126425
           Summary: [C++26] GCC incorrectly treats deleting an object
                    outside its lifetime as a constant expression
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: painthingy at gmail dot com
  Target Milestone: ---

Version: trunk (17.0.0 20260726, experimental)

Reproducer: https://godbolt.org/z/s9s9T4af9

```cpp
#include <memory>

struct Base {
    constexpr ~Base() {}
};

struct Derived : Base {
    ~Derived() = default;
};

consteval {

    Derived* ptr = new Derived();
    std::destroy_at((Base*)ptr);
    // std::construct_at((Base*)ptr); // remove -> GCC still accepts

    delete ptr;
}

int main() {}
```
Compile options (GCC): -std=c++26 -freflection -O0 -Wall

Expected behavior:

After std::destroy_at((Base*)ptr) ends *ptr's lifetime, the subsequent delete
ptr; calls ~Derived() (and eventually deallocates) an object whose lifetime has
already ended. This is not a constant expression, since destroying or otherwise
using an object outside its lifetime during constant evaluation is one of the
operations explicitly disallowed by [expr.const]. Clang (clang-p2996, based on
clang 21) correctly rejects this program during evaluation of the consteval
block:
```
<source>:11:1: error: evaluating expression of a consteval block must be a
constant expression
<source>:17:5: note: destroying object '{*new Derived#0}' whose lifetime has
already ended
<source>:17:5: note: in call to '{*new Derived#0}.~Derived()'
```
Actual behavior:

GCC trunk accepts the program without diagnostic, silently allowing delete to
run the destructor and deallocation on an object whose lifetime has already
ended via the earlier std::destroy_at call. This holds whether or not the
commented-out std::construct_at((Base*)ptr) (which would legitimately restart
the object's lifetime) is present — GCC's acceptance doesn't change either way,
suggesting it isn't tracking lifetime-end at all in this context.

Additional info:

This looks related to bug 122336

GCC version details: 
g++
(Compiler-Explorer-Build-gcc-7149f5ebd52eee6ad29a06f6d46c4142d0eccf46-binutils-2.44)
17.0.0 20260726 (experimental)

Clang (for comparison) version details:
clang version 21.0.0git (https://github.com/Bloomberg/clang-p2996
7220baffd57ea5b0f8cf59bee494dd5b7cc2b748)
  Target: x86_64-unknown-linux-gnu

Clang compile options: -std=c++26 -freflection -fparameter-reflection
-freflection-latest -O0

Reply via email to