<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/56980>56980</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            Feature request: allow teaching llvm that coroutines can only be destroyed when done
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          jacobsa
      </td>
    </tr>
</table>

<pre>
    The following code contains two things:

* A basic coroutine task type that can be awaited from other coroutines returning that task type. It is not possible to do anything with the task except await it. In particular it's not possible to destroy the task's coroutine early: **coroutines are always destroyed only when they are done**.

* A coroutine called `Foo` returning that task type that has several different suspend points, each with a different instance of `GlobalSetter` alive. When `GlobalSetter` is destroyed, it sets `some_global` in a way that can be seen in assembly code.

```c++
#include <coroutine>

class MyTask{
 public:
  struct promise_type {
    MyTask get_return_object() { return MyTask(std::coroutine_handle<promise_type>::from_promise(*this)); }
    std::suspend_always initial_suspend() { return {}; }

    void unhandled_exception();

    void return_void() {} 

    auto await_transform(MyTask task) {
      struct Awaiter {
        bool await_ready() { return false; }
        std::coroutine_handle<promise_type> await_suspend(std::coroutine_handle<promise_type> h) {
          caller.resume_when_done = h;
          return std::coroutine_handle<promise_type>::from_promise(callee);
        }

        void await_resume() {
          std::coroutine_handle<promise_type>::from_promise(callee).destroy();
        }

        promise_type& caller;
        promise_type& callee;
      };

      return Awaiter{*this, task.handle_.promise()};
    }
    
    auto final_suspend() noexcept {
      struct Awaiter {
        bool await_ready() noexcept { return false; }
        std::coroutine_handle<promise_type> await_suspend(std::coroutine_handle<promise_type> h) noexcept {
          return to_resume;
        }

        void await_resume() noexcept;

        std::coroutine_handle<promise_type> to_resume;
      };

      return Awaiter{resume_when_done};
    }

    // The coroutine to resume when we're done.
    std::coroutine_handle<promise_type> resume_when_done;
  };


 private:
  explicit MyTask(const std::coroutine_handle<promise_type> handle)
      : handle_(handle) {}

  // A handle for the coroutine that returned this task. This is not
  // revealed to the user: it can only be used to await the task.
  const std::coroutine_handle<promise_type> handle_;
};

int some_global;

// A type whose destructor takes an action that's easy to see in the output
// assembly code.
struct GlobalSetter {
  int value;

  GlobalSetter(int value) : value(value) {}
  ~GlobalSetter() { some_global = value; }
};

MyTask __attribute__((noinline)) Qux() { co_return; }

MyTask Foo() {
  {
    GlobalSetter gs(0);
    co_await Qux();
  }

  {
    GlobalSetter gs(1);
    co_await Qux();
  }

  {
    GlobalSetter gs(2);
    co_await Qux();
  }

  {
    GlobalSetter gs(3);
    co_await Qux();
  }

  {
    GlobalSetter gs(4);
    co_await Qux();
  }

  {
    GlobalSetter gs(5);
    co_await Qux();
  }

  {
    GlobalSetter gs(6);
    co_await Qux();
  }
}
```

Because it's not possible to destroy the frame for `Foo` until it is completely finished, the cleanup code in theory can be trivial: there is no need to worry about running `~GlobalSetter`, because that will always have already run in the coroutine body itself. But when compiled with `-std=c++20 -O2 -fno-exceptions`, clang is unable to see this and generates a bunch of dead code within `Foo.destroy` ([compiler explorer](https://godbolt.org/z/9K8eKE9Kh)):

```asm
Foo() [clone .destroy]:                        # @Foo() [clone .destroy]
        cmp     qword ptr [rdi], 0
        je      .LBB5_9
        movzx   ecx, byte ptr [rdi + 96]
        xor     eax, eax
        lea     rdx, [rip + .LJTI5_0]
        movsxd  rcx, dword ptr [rdx + 4*rcx]
        add     rcx, rdx
        jmp     rcx
.LBB5_2:
        mov     eax, 1
        jmp     .LBB5_8
.LBB5_3:
        mov     eax, 2
        jmp     .LBB5_8
.LBB5_4:
        mov     eax, 3
        jmp     .LBB5_8
.LBB5_5:
        mov     eax, 4
        jmp     .LBB5_8
.LBB5_6:
        mov     eax, 5
        jmp     .LBB5_8
.LBB5_7:
        mov     eax, 6
.LBB5_8:
        mov     dword ptr [rip + some_global], eax
.LBB5_9:
        jmp     operator delete(void*)@PLT                      # TAILCALL
.LJTI5_0:
        .long   .LBB5_9-.LJTI5_0
        .long   .LBB5_8-.LJTI5_0
        .long   .LBB5_2-.LJTI5_0
        .long   .LBB5_3-.LJTI5_0
        .long   .LBB5_4-.LJTI5_0
        .long   .LBB5_5-.LJTI5_0
        .long   .LBB5_6-.LJTI5_0
        .long   .LBB5_7-.LJTI5_0
```

In theory **this should just be a single instruction**: a tail call to `operator delete`. Instead we get generated code that duplicates all of the logic for destroying the `GlobalSetter` objects that is also in `Foo.resume`.

This is a feature request to **add some facility to teach llvm that generating code for destroying local variables is unnecessary in the coroutine destroy function**. I thought perhaps adding a `__builtin_unreachable` section in the promise's destructor that you hit when the promise's handle is not done might work, but [no such luck](https://godbolt.org/z/jf5K78hn8).
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzNWVlv4zgS_jX2CxFDkS_5wQ9O0j3o7Sx2FxtgHwVKoiOmadJDUj7m128VSZ12Ju6ZCTCGE9tSsS7W8RWVqeK8fikZ2Soh1JHLV5KrgsE_aSmXhtijIraE62Y03Yyip1FU_483ZEMyangO1FpVlktGLDU_iD3v4VtJLcmpJBkj9Ei5ZQXZarUjypZMt0sM0cxWWqJot6ZhMSHfLOGGSGXJXhnDMwFsFSkUofLslCJHbktYFgSzU8721osj3AIDSfZUW55Xgmq4MoqXV_gxY7U6N2wcUWsSo1qcwXgCFsO7ozjVYJo40rOpeYCNSoozOZZMIr-zoymUZH7x5NKDraCcCgEMRovoq1Lw_13H-J8lNcSwA9NUkIJvt0wzaYmpzJ7JAgzk0ppR_Aj656X3E-3Qwd5aKnNG1BYl_iJURsV_mbVMo2gq-AE24H9ox5XbvGMxygB3G2YNkhq1Y-mro3eUEsSCi3rxYBiwxTvGsF0G_sKY6_tmEfl3Poof8B08NuUyFxUE6Gj62HhuNP3SXZsL4Ev-eX7BvVyGpWRfZYLnTRATAupXOUQCxCQ3LHWObcnh5TmQV2ZTvxOpyt5YDkGUjOIV0oYdqmXFibEFSpi2UZKWVBYCVHzsCkKNHR1mRBruOL4biGvYthW-pw8g5KlVqOEeNjkNwcclt5yKNFy-1A_NAkZdfi3Xg-IFqaTXs0h9DnElPRtYdHVB8Ah-b-UBdzKkphWkmMvI1GoqzVbpHawIzvX5tuo7vtmbjasbeniXkEwpEZhqRovzpclbKsCjQw_2vPjxHgURrV9_Zm15xS58uTTXE81MBZmClSLFAgER_QRrphf0waA_G1pOLOvuaC3gSkw021z7GHXt7PNAxb9Mt0moKoPY-0DTnoh4ETx8sfoqGRuQ-Ty5lBJ2IUQk-qBO1UcXxBNvcDrpJvOqy61ngPvRz5Etlxc5LFVoaX9NfnTZ_c0S5T1LO763qg7EPxnBtayrG_1zdr-n081hNCwD70ZM51L8Fd4EUVsHeCniWXnscQRblwF6TK50kBtMu9CsVevSurrJan6glnW6LDvtoe0CPmh6JEBLY39Kk3AD0qnrYUBkIeeAaUNS97qez4LH6gUAdrVDex33ITrxmwMQDBPbZzV4Gb56EDrgpgF7UQRsVjlmlcGas0EshDDH4cDMXXYkHpTWGLPZkz_qjbTdgIvN4IgDOzBssFW1MxziOZbKMA_moKKgX-gPhLYAznJEAc4zDhEzas5oCIA3xG5oCai6r2yP7TVIF6pVF0R20xzVPVBRsYuM6cHOOGkJcZ_B1eFH0l7sbD6G6ZcBhxokdLzj-m4tvpNuF14NiCVNqbWaZ5VlaepYJhKwtkAc6mAb-U916ojKVUCPV-BXYIlw_6K39upgz3UwisVJNOyPIMeHWCN-kLD9jPh97vefyj3-VO7TT-U--1Tu80_lvviD3Jsv9VDWlfrAcgo17pbheqvpzhffdsatpOUCaybHmXu3F8wyqB4Ahrgp_XDpKrVgVFZ7fzjhq4_S53qehHw8cCx0G7wBbc8VbCKZL71HpYGWZlCuiK6km6jRikF5gCsgLQv2uI5w5ELUI35JDzjuOzyFbOoi2DaRTMEdbg0T2wl5AGGuFaNVHPuEm8FByp2r9k9hso0jcvevmNxtpbprZi8TlIFRFnQFaypJg0Ox_Lr-BG0AZlMJ87_Fgk2ySsKgD-N8ARp6R6FELoO3G2wNXsfNnj8EzbRr0kqDC-ZP2Eut3bvTHlfRX1WRKWEnSr_Cr9_gb_U9Yd-_rL6X9ZjaPxeqg4Sanb_SKW8gU-Cs0-gCAqcdpNd_wbhPRrPog_U97Jbv9u7zV9jzguytxjW64M6yRxL1qd-Y_5w8PzzM01X_5k4dfjvBJ8tPLi7OlnUYgnIPZLW4UOAE0Y0vRk_-8OXUvw9x7IFg4e4jM753zCbP_3j5Nk-jC5agiDkVsMQrUvRNO7nFUJY2eH-4lhaFF-fXotS-B4K_8L674V0RdxBco0TXrvvrbPzqpMtq-hGr-GZWs49YTW9mNf-I1exmVouPWM1vZrX8iNWiS528S90PkRBfXUTos6EJzjr-h_xqVdUeqwxEdsGwPiPicuc-G0z_WfTv5xdy9YUJ_LL59vy4eX6uJYUgH4qaQF6_Nl5Z3TWEv0OV3EQV30Q1vYlqdhPV_CaqxU1UywHV1R78rWmI_pjZ9QdTqkoU5K2C-QLP4ImBvieYO_lFPO6O-JAaKzAF3A99GI9EsMkA_-GeLyI8TjcWm8uR4alo031Ct3Eds6hw3vMtCXhBO8IeKdQrz13nD4XbH2qza2fL_pDVeHbY54RRpO1iYdwGdboeqMc0SraMAtpmMJ79WoEsZ40zE0sh5gDZ0pwLbt0wY93puBCHnZcXTGqegwxUFgo8BNOC5tiOje_MkuXMGArev0AENfrZQm9uHQ6OBDpVvZaAlZgu6d5goUYBFM1M06ziAhikldSoIApD1xjmZ7IgpzlqWpreBIeGnFVFSm6bJxE94jAGh2cr7vRxx1EbqBs_XLMD8AKlAzCUqdA_Vf7jNmzwtp1_XyalxHY9GbP1_WK-SqbJIlmNi_W0WE1XdGy5FWz9tb9PLgjxEZTfEufsZlc6z1y6o3X70MVZiXaMKy3WAyUBBFXZBMAO_ECe4eMOPOKP879yY0AH-DJfrJJoXK6jYjlL4vw-TvLpcpFsk0URTRf3cb4EgiyZjwXNmDBr8BH4ZczXcRTHURIto_g-iZJJXszu6f2MLudJns1h4JlFbAcJNkHB6K6xXjsdsgqQ-SwS3FjT3oQhmr8Ceq350wrCRa_faK4yQ8dO3bXT9f_UPTfD">