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

            Bug ID: 100553
           Summary: [constexpr] new/delete matching fails when ref-counted
                    pointers are stored in arrays
           Product: gcc
           Version: 12.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: ldalessandro at gmail dot com
  Target Milestone: ---

Sorry about the complexity of this test case. Consider the following code.

```
#include <memory>

struct Node {
    int count = 0;
    constexpr virtual void destroy() const = 0; // workaround
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100495
};

struct node_ptr
{
    Node *ptr_;

    constexpr ~node_ptr()
    {
      dec();
    }

    constexpr node_ptr(node_ptr const& b)
        : ptr_(b.ptr_)
    {
      inc();
    }

    constexpr node_ptr(node_ptr&& b)
        : ptr_(std::exchange(b.ptr_, nullptr))
    {
    }

    constexpr node_ptr(Node *ptr)
        : ptr_(ptr)
    {
      inc();
    }

    constexpr node_ptr& operator=(Node* b)
    {
      if (b) {
        ++b->count;
      }
      dec();
      ptr_ = b;
      return *this;
    }

    constexpr void inc() const
    {
      if (ptr_) {
        ++ptr_->count;
      }
    }

    constexpr void dec()
    {
      if (ptr_) {
        if (--ptr_->count == 0) {
          std::exchange(ptr_, nullptr)->destroy();
        }
      }
    }
};

struct Unary : Node
{
    node_ptr children[1] = { nullptr };
    node_ptr a = nullptr;

    constexpr void destroy() const override
    {
        delete this;
    }
};

#ifdef ARRAY // fails
#define a(node) node->children[0]
#else
#define a(node) node->a
#endif

struct Tree 
{
    Unary c;
    constexpr Tree(node_ptr const& tree) {
        std::construct_at(&c, static_cast<Unary const&>(*tree.ptr_));
        a((&c)) = nullptr;
    }
};

constexpr node_ptr foo() {
    Unary *node = new Unary;
    a(node) = new Unary;
    return node;
}

constexpr Tree tree = foo(); // error: use of allocated storage after
deallocation in a constant expression
```

This is a fragment of some tree code that I'm using and includes a base Node*
type with a count for an intrusive node_ptr reference counted pointer. There is
one derived type, Unary, that stores a single node_ptr, either as an ARRAY or
as a scalar member. The tree stores a single Unary node.

There's a macro for the sake of the test case, -DARRAY uses the array member.
When I use the array member gcc-trunk fails to match the new/deletes, while its
fine with the scalar member. Clang compiles both without error.

https://godbolt.org/z/oGc1qTvvo

Reply via email to