On Wed, Mar 17, 2021 at 4:06 AM v.S. F. via Std-Discussion <std-discussion@lists.isocpp.org> wrote:

  Since C++17 (via P0012R1), except specifications have became part of the type system, and a noexcept function is implicitly convertible to a pointer to a non-noexcept function. However, it seems that calling a noexcept function through a pointer to a non-noexcept function is UB, as [expr.call]/6 remains unchanged (known compilers accept such call in constant evaluation in C++17 and later modes).

  In the other hand, the definition “int main() noexcept {}” was guaranteed to be supported in C++11/14 (as noexcept was not part of the function type), but the guarantee is removed by P0012R1, because [basic.start.main]/2 says about the type of main and remains unchanged.

  These cases should be addressed as CWG issue(s) IMO.


I don't consider the second case here to be a defect; it's more of a feature that you're not allowed to declare `main` to be `noexcept`. To declare a function to be `noexcept` means that it does not emit an exception to its caller (and if you try, the program will terminate). Well, `main` has no "caller" as far as the C++ standard is concerned, so who would it be emitting exceptions to? And if someone tries to emit an exception from `main`, the program terminates.

Which brings us to the next question: what exactly would `noexcept` `main` mean?

If an appropriate `catch` clause is not found (either before reaching past `main` or a thread function), `std::terminate` is called. However, whether the stack is unwound is implementation defined. And this is basically the same as what happens if you try to throw past a `noexcept` function; whether the stack is unwound is still implementation-defined.

So what's the point?