[Bug c++/126425] New: [C++26] GCC incorrectly treats deleting an object outside its lifetime as a constant expression

painthingy at gmail dot com via Gcc-bugs <[email protected]>
Newsgroups gmane.comp.gcc.bugs
Message-ID <[email protected]/bugzilla/>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.