<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - Clang either crashes or choose wrong destructor when using multiple destructors using C++20 constraints"
   href="https://bugs.llvm.org/show_bug.cgi?id=50570">50570</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>Clang either crashes or choose wrong destructor when using multiple destructors using C++20 constraints
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>clang
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>All
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>All
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>release blocker
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>C++2a
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedclangbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>kashishnagpal0007@gmail.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>blitzrakete@gmail.com, erik.pilkington@gmail.com, llvm-bugs@lists.llvm.org, richard-llvm@metafoo.co.uk
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Created <span class=""><a href="attachment.cgi?id=24905" name="attach_24905" title="1 of the program which i described above (also have links to godbolt)">attachment 24905</a> <a href="attachment.cgi?id=24905&action=edit" title="1 of the program which i described above (also have links to godbolt)">[details]</a></span>
1 of the program which i described above (also have links to godbolt)

Overview: When we use multiple destructor (1 default and 1 constraint 1) ,
using just a simple constraint, then 1 of 2 things happen:




A.) If we define the constraint destructor first, and then define default
destructor:

<a href="https://godbolt.org/z/PWbfzscs4">https://godbolt.org/z/PWbfzscs4</a>


#include <iostream>
#include <concepts>

template <typename T>
concept hasReleaseMethod = requires(T t)
{
        t.release();
};

template <typename T>
class ComWrapper
{
        T t;

  public:
        ~ComWrapper() requires requires(T t) { t.release(); }
        {
                std::cout << "destructor";
                t.release();
        }

        ~ComWrapper() = default;
};

struct hasRelease
{
        int a = 23;
        void release()
        {
                std::cout << "in release method:\n"
                                  << a;
        }
        void method()
        {
        }
};

struct notHadRelease
{
};

int main()
{
        ComWrapper<hasRelease> Ob;
        ComWrapper<notHadRelease> ob2;
};

Actual result: the compiler crashed (you can see the error through the cooler l
compiler explorer (godbolt)).

Expected result: the clang should choose the constraint destructor on ob1
(hasRelease) and default destructor on ob2. The GCC produce the expected output



The program works on GCC and didn't work on clang, where we declared the
constraint destructor first and then default destructor (GCC compiler &
executor on the upper window and Clang on the lower)
<a href="https://godbolt.org/z/PWbfzscs4">https://godbolt.org/z/PWbfzscs4</a>

You can check on godbolt through the above link





B.) When we declared the default destructor first, & then the constraint
destructor

//The program is same as above except the default destructor is declared first


#include <iostream>
#include <concepts>

template <typename T>
concept hasReleaseMethod = requires(T t)
{
        t.release();
};

template <typename T>
class ComWrapper
{
        T t;

  public:
        ~ComWrapper() = default;

        ~ComWrapper() requires requires(T t) { t.release(); }
        {
                std::cout << "destructor";
                t.release();
        }
};

struct hasRelease
{
        int a = 23;
        void release()
        {
                std::cout << "in release method:\n"
                                  << a;
        }
        void method()
        {
        }
};

struct notHadRelease
{
};

int main()
{
        ComWrapper<hasRelease> Ob;
        ComWrapper<notHadRelease> ob2;
};

<a href="https://godbolt.org/z/ss11d5cdd">https://godbolt.org/z/ss11d5cdd</a>

When we declared the default destructor first, & then the constraint destructor
, the Clang compiles, but the default destructor is called & the constraint
destructor is discarded every time(see the executor and assembly in clang). 
Whereas, GCC executes correctly.</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>