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

    <tr>
        <th>Summary</th>
        <td>
            Thrown exception in `nothrow` function not detected
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            clang,
            c++
      </td>
    </tr>

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

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

<pre>
    If an exception is thrown in a function marked with `nothrow` clang usually reports a warning.

In the following example however an exception is thrown but clang fails to detect it and the 
warning is not reported at all.

```c++
void foo() noexcept {
  try {
    double *a[2][3];
    throw a;
  } catch (const double *const(*)[3]) {
 }
}
```

What makes this more interesting is that on [cppreference](https://en.cppreference.com/w/cpp/language/try_catch) the following can be seen:
```
When an exception is thrown by any statement in compound-statement, the exception object of type E is 
matched against the types of the formal parameters T of each catch-clause in handler-seq, in the order in 
which the catch clauses are listed. The exception is a match if any of the following is true:

...
- T is (possibly cv-qualified) U or const U& (since C++14), and U is a pointer or pointer to member type, and
  E is also a pointer or pointer to member type that is implicitly convertible to U by one or more of
  - a standard pointer conversion other than one to a private, protected, or ambiguous base class
  - **a qualification conversion**
  - a function pointer conversion (since C++17)
...
```
While the [qualification conversion section](https://en.cppreference.com/w/cpp/language/implicit_conversion#Qualification_conversions) lists a number of rules that describe when can 
the said conversion be performed, it gives the following example:
```c++
double *a[2][3];
double const * const (*ap)[3] = a; // OK
```
So technically the thrown type in `foo()` can be converted to the type in the handler, which
is the reason for clang not reporting a warning but the exception is thrown regardless. 

See the example on [godbolt](https://godbolt.org/z/sEz8eYeP1).
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJykVl2v2roS_TXmZQQK5iPwwMP-KFJ1H-696t6qzlM1iQfiU8dObQdKf_3R2AGy212dIx0JQT5sz5o1a9aAIeijJdqJ1aNYPU-wj43zOx36-ivGOkwqpy67jwdAC_S9pi5qZ0EHiI13ZwvaAsKht3V63qL_SgrOOjYg1oV1aZVYF1AbtEfoQ4_GXMBT53wMgHBGb7U9zkTxLIqH_P3RQmwIDs4Yd9b2CPQd284QNO5MJ_K_w1L1cYhzQG0CRAeKItURdAS0Kp2aQwxhebN1ccBDCjACGvMGjVgX-VML-cif9PTktIKDc0JuhNyCdRkQiHJYABD9ZXwLoFxfGQIhH1CsHqVYPYvV44J_FqNVKRnA0TNRPkONsW5AyE3tbIijo9J9QvEg5PZ6oNyOQovyeUjldnHNaZzo5wYjtPiVmFAdoHWeQNtInkIcyIq8xlkQq8e66zwdyJOtKYXcNDF2QSwehNwLuSc7Gy-Z1a4Vcn8Wcl93nZB7LlSPRxJyH_3lS0qQcb8tfY0WKoJAZPnk99B_bsj-VhIXQHuBEDFSSzayXmvXdq63anp7KuRTCns_wVV_sm7cAeKlI_jAR-ZoLeNkpRxRcyV4H68JaXHC7ls00KHHliL5AC_8irBuchWntcE-MLXQoFWG_DTQN8ags_CdV-T5ZtBqo-smvcgiyNsDoCcwOkRSM3h5g15zZyWgoA-JgBu2K69Mke_pzmn6ns0G6U_hJaUsN50LQVfmAvVp-q1How-aFNfpFZyHrMZXIde8NmhbEzzlPpkvWY_yKXXea8bUuaQn3nm9jA5aaiu-unQ0rL8qP_GOJrh_sjeLUwfQbWd0rSODdvZEPmpulujglQXhLFOc5e0O11BTQJaJVejVLUDeHpIiYsNxGrTpgJggeX3CmEB33rHTMDVPfDq2lT72rg9QYSCuWQj3UKlZHxAGQmtMZbtHy-_H0G4W-w60X5gvmfm3Bf2lZzQzwn64evwdCgiUYv7L7r6W48s4v8X_x0FHrwJri2XNerF9qq47gO8NDfajKNReVwRnbnw2iJwTZxNQq3EGFUFHnlsyV0ZHOOpTOumdAfOrw7zx_L_372FF7gohH25XbM_Y3Q0axOI5eTxkOuG__3m3Tp8cRKobq-s0N5PZZGdLimePWBe3MZQGbTbMQfikWKlXj7oazGA7TEgylxxLZ1Y8YXCWbWwYpvcByVTdRnYat_Fn3xnQeTqiV4ZCmMHYYD4RDXvyRM-j5OhU5Ux8T2fDq5nzRyH3P4Tchw8_NvQH_W8u5HY2UbuF2i62OKHdfF0utsVis1pPml1VLpdyruYb3FK5WS3nqlhKNcdyjijLpZzonSzkopjP13I-LxfrmaRyuVyqtdqWVK1XpVgW1KI2M2NOLcef6BB62q2LYrOeGKzIhPSvScrEk5BSyCe-GzQjWSETv-P906o_BrEskrDvJ0YdDe1eMmcjHu1P_55u3c-1yP9pSE16b3Y_saVj01dDM3KU4WfaeccDjbuRkwhC7lMefwUAAP__4184DQ">