<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<!-- 2024-03-17 Sun 00:22 -->
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>P3166R0: Static Exception Specifications</title>
<meta name="author" content="Lewis Baker" />
<meta name="generator" content="Org Mode" />
<style>
  #content { max-width: 60em; margin: auto; }
  .title  { text-align: center;
             margin-bottom: .2em; }
  .subtitle { text-align: center;
              font-size: medium;
              font-weight: bold;
              margin-top:0; }
  .todo   { font-family: monospace; color: red; }
  .done   { font-family: monospace; color: green; }
  .priority { font-family: monospace; color: orange; }
  .tag    { background-color: #eee; font-family: monospace;
            padding: 2px; font-size: 80%; font-weight: normal; }
  .timestamp { color: #bebebe; }
  .timestamp-kwd { color: #5f9ea0; }
  .org-right  { margin-left: auto; margin-right: 0px;  text-align: right; }
  .org-left   { margin-left: 0px;  margin-right: auto; text-align: left; }
  .org-center { margin-left: auto; margin-right: auto; text-align: center; }
  .underline { text-decoration: underline; }
  #postamble p, #preamble p { font-size: 90%; margin: .2em; }
  p.verse { margin-left: 3%; }
  pre {
    border: 1px solid #e6e6e6;
    border-radius: 3px;
    background-color: #f2f2f2;
    padding: 8pt;
    font-family: monospace;
    overflow: auto;
    margin: 1.2em;
  }
  pre.src {
    position: relative;
    overflow: auto;
  }
  pre.src:before {
    display: none;
    position: absolute;
    top: -8px;
    right: 12px;
    padding: 3px;
    color: #555;
    background-color: #f2f2f299;
  }
  pre.src:hover:before { display: inline; margin-top: 14px;}
  /* Languages per Org manual */
  pre.src-asymptote:before { content: 'Asymptote'; }
  pre.src-awk:before { content: 'Awk'; }
  pre.src-authinfo::before { content: 'Authinfo'; }
  pre.src-C:before { content: 'C'; }
  /* pre.src-C++ doesn't work in CSS */
  pre.src-clojure:before { content: 'Clojure'; }
  pre.src-css:before { content: 'CSS'; }
  pre.src-D:before { content: 'D'; }
  pre.src-ditaa:before { content: 'ditaa'; }
  pre.src-dot:before { content: 'Graphviz'; }
  pre.src-calc:before { content: 'Emacs Calc'; }
  pre.src-emacs-lisp:before { content: 'Emacs Lisp'; }
  pre.src-fortran:before { content: 'Fortran'; }
  pre.src-gnuplot:before { content: 'gnuplot'; }
  pre.src-haskell:before { content: 'Haskell'; }
  pre.src-hledger:before { content: 'hledger'; }
  pre.src-java:before { content: 'Java'; }
  pre.src-js:before { content: 'Javascript'; }
  pre.src-latex:before { content: 'LaTeX'; }
  pre.src-ledger:before { content: 'Ledger'; }
  pre.src-lisp:before { content: 'Lisp'; }
  pre.src-lilypond:before { content: 'Lilypond'; }
  pre.src-lua:before { content: 'Lua'; }
  pre.src-matlab:before { content: 'MATLAB'; }
  pre.src-mscgen:before { content: 'Mscgen'; }
  pre.src-ocaml:before { content: 'Objective Caml'; }
  pre.src-octave:before { content: 'Octave'; }
  pre.src-org:before { content: 'Org mode'; }
  pre.src-oz:before { content: 'OZ'; }
  pre.src-plantuml:before { content: 'Plantuml'; }
  pre.src-processing:before { content: 'Processing.js'; }
  pre.src-python:before { content: 'Python'; }
  pre.src-R:before { content: 'R'; }
  pre.src-ruby:before { content: 'Ruby'; }
  pre.src-sass:before { content: 'Sass'; }
  pre.src-scheme:before { content: 'Scheme'; }
  pre.src-screen:before { content: 'Gnu Screen'; }
  pre.src-sed:before { content: 'Sed'; }
  pre.src-sh:before { content: 'shell'; }
  pre.src-sql:before { content: 'SQL'; }
  pre.src-sqlite:before { content: 'SQLite'; }
  /* additional languages in org.el's org-babel-load-languages alist */
  pre.src-forth:before { content: 'Forth'; }
  pre.src-io:before { content: 'IO'; }
  pre.src-J:before { content: 'J'; }
  pre.src-makefile:before { content: 'Makefile'; }
  pre.src-maxima:before { content: 'Maxima'; }
  pre.src-perl:before { content: 'Perl'; }
  pre.src-picolisp:before { content: 'Pico Lisp'; }
  pre.src-scala:before { content: 'Scala'; }
  pre.src-shell:before { content: 'Shell Script'; }
  pre.src-ebnf2ps:before { content: 'ebfn2ps'; }
  /* additional language identifiers per "defun org-babel-execute"
       in ob-*.el */
  pre.src-cpp:before  { content: 'C++'; }
  pre.src-abc:before  { content: 'ABC'; }
  pre.src-coq:before  { content: 'Coq'; }
  pre.src-groovy:before  { content: 'Groovy'; }
  /* additional language identifiers from org-babel-shell-names in
     ob-shell.el: ob-shell is the only babel language using a lambda to put
     the execution function name together. */
  pre.src-bash:before  { content: 'bash'; }
  pre.src-csh:before  { content: 'csh'; }
  pre.src-ash:before  { content: 'ash'; }
  pre.src-dash:before  { content: 'dash'; }
  pre.src-ksh:before  { content: 'ksh'; }
  pre.src-mksh:before  { content: 'mksh'; }
  pre.src-posh:before  { content: 'posh'; }
  /* Additional Emacs modes also supported by the LaTeX listings package */
  pre.src-ada:before { content: 'Ada'; }
  pre.src-asm:before { content: 'Assembler'; }
  pre.src-caml:before { content: 'Caml'; }
  pre.src-delphi:before { content: 'Delphi'; }
  pre.src-html:before { content: 'HTML'; }
  pre.src-idl:before { content: 'IDL'; }
  pre.src-mercury:before { content: 'Mercury'; }
  pre.src-metapost:before { content: 'MetaPost'; }
  pre.src-modula-2:before { content: 'Modula-2'; }
  pre.src-pascal:before { content: 'Pascal'; }
  pre.src-ps:before { content: 'PostScript'; }
  pre.src-prolog:before { content: 'Prolog'; }
  pre.src-simula:before { content: 'Simula'; }
  pre.src-tcl:before { content: 'tcl'; }
  pre.src-tex:before { content: 'TeX'; }
  pre.src-plain-tex:before { content: 'Plain TeX'; }
  pre.src-verilog:before { content: 'Verilog'; }
  pre.src-vhdl:before { content: 'VHDL'; }
  pre.src-xml:before { content: 'XML'; }
  pre.src-nxml:before { content: 'XML'; }
  /* add a generic configuration mode; LaTeX export needs an additional
     (add-to-list 'org-latex-listings-langs '(conf " ")) in .emacs */
  pre.src-conf:before { content: 'Configuration File'; }

  table { border-collapse:collapse; }
  caption.t-above { caption-side: top; }
  caption.t-bottom { caption-side: bottom; }
  td, th { vertical-align:top;  }
  th.org-right  { text-align: center;  }
  th.org-left   { text-align: center;   }
  th.org-center { text-align: center; }
  td.org-right  { text-align: right;  }
  td.org-left   { text-align: left;   }
  td.org-center { text-align: center; }
  dt { font-weight: bold; }
  .footpara { display: inline; }
  .footdef  { margin-bottom: 1em; }
  .figure { padding: 1em; }
  .figure p { text-align: center; }
  .equation-container {
    display: table;
    text-align: center;
    width: 100%;
  }
  .equation {
    vertical-align: middle;
  }
  .equation-label {
    display: table-cell;
    text-align: right;
    vertical-align: middle;
  }
  .inlinetask {
    padding: 10px;
    border: 2px solid gray;
    margin: 10px;
    background: #ffffcc;
  }
  #org-div-home-and-up
   { text-align: right; font-size: 70%; white-space: nowrap; }
  textarea { overflow-x: auto; }
  .linenr { font-size: smaller }
  .code-highlighted { background-color: #ffff00; }
  .org-info-js_info-navigation { border-style: none; }
  #org-info-js_console-label
    { font-size: 10px; font-weight: bold; white-space: nowrap; }
  .org-info-js_search-highlight
    { background-color: #ffff00; color: #000000; font-weight: bold; }
  .org-svg { }
</style>
</head>
<body>
<div id="content" class="content">
<h1 class="title">P3166R0: Static Exception Specifications</h1>
<div id="table-of-contents" role="doc-toc">
<h2>Table of Contents</h2>
<div id="text-table-of-contents" role="doc-toc">
<ul>
<li><a href="#org39e3e7a">1. Abstract</a></li>
<li><a href="#org65638c7">2. Synopsis</a></li>
<li><a href="#orgb6fffd8">3. Overview</a></li>
<li><a href="#org3d65ca7">4. Motivation</a>
<ul>
<li><a href="#orgbbba720">4.1. Alternative error-signalling mechansisms have problems too</a>
<ul>
<li><a href="#orgcec19d3">4.1.1. Composition of facilities that use different error-signaling mechanisms</a></li>
<li><a href="#orgcc13320">4.1.2. Runtime overhead due to additional branching, packing/unpacking</a></li>
<li><a href="#org316521c">4.1.3. May require an additional "invalid" state, additional preconditions</a></li>
</ul>
</li>
<li><a href="#orgf5d6ae8">4.2. Making exceptions fast by-design</a></li>
<li><a href="#org4a64a64">4.3. Supporting exceptions in freestanding and real-time environments</a></li>
<li><a href="#orgaf83d0c">4.4. Reducing bugs caused by failure to handle error-conditions</a></li>
<li><a href="#orgfde7b81">4.5. Describing the contract in code instead of in documentation</a>
<ul>
<li><a href="#org99023a6">4.5.1. Uses in generic code</a></li>
</ul>
</li>
<li><a href="#orgea98202">4.6. Reducing boiler-plate when writing functions that are transparent to exceptions</a></li>
</ul>
</li>
<li><a href="#org85e3be4">5. Proposal</a>
<ul>
<li><a href="#orgcada955">5.1. Overview</a></li>
<li><a href="#org4585572">5.2. (Re)Adding throw specifiers</a></li>
<li><a href="#orgbc4a37f">5.3. Static and dynamic exception specifications</a>
<ul>
<li><a href="#org7ea3527">5.3.1. Types in a throw-specification form an unordered set</a></li>
<li><a href="#org8cced06">5.3.2. Handling of <code>std::any_exception</code> in the throw-specifier</a></li>
<li><a href="#orgd2d1532">5.3.3. The types in the throw specification describe all concrete types that may be thrown</a></li>
<li><a href="#org7308b93">5.3.4. Exception types may not be references, cv-qualified, or void</a></li>
<li><a href="#orgd5fc979">5.3.5. Static exception specifications are part of the function type</a></li>
<li><a href="#orga3b6ff7">5.3.6. Deducing the throw-specifier from a function signature</a></li>
<li><a href="#org8639d71">5.3.7. <code>throw(auto)</code> - Deducing exception-specifications from the body of a function</a></li>
<li><a href="#org9f78458">5.3.8. Forward declarations of <code>throw(auto)</code> functions</a></li>
<li><a href="#orgf0d5aee">5.3.9. Deduced exception-specifications and recursive functions</a></li>
<li><a href="#org32484e6">5.3.10. Delayed computation of deduced throw specifications</a></li>
<li><a href="#orge1e9733">5.3.11. Do we also need <code>noexcept(auto)</code>?</a></li>
</ul>
</li>
<li><a href="#orgbbe1dbe">5.4. Querying the throw-specification</a>
<ul>
<li><a href="#org672f304">5.4.1. <code>declthrow</code> of a call to a <code>throw(...)</code> function</a></li>
<li><a href="#org34605cc">5.4.2. Mixed dynamic and static exception specifications</a></li>
<li><a href="#org914aaec">5.4.3. Order of the exception types</a></li>
<li><a href="#org5cdb143">5.4.4. Exception specifications of defaulted special member functions</a></li>
<li><a href="#orgd0abf53">5.4.5. Introducing a pack outside of a template</a></li>
<li><a href="#orgb1e1874">5.4.6. Packs of <code>declthrow</code> packs</a></li>
<li><a href="#org1a7ad02">5.4.7. Availability of the <code>declthrow</code> keyword</a></li>
<li><a href="#orgc815b1b">5.4.8. Alternative Syntaxes Considered</a></li>
<li><a href="#orgf80ea67">5.4.9. Filtering the set of exceptions</a></li>
</ul>
</li>
<li><a href="#orge0276a5">5.5. Checking the throw-specification of a function</a></li>
<li><a href="#org8907dc8">5.6. Computing the set of potentially-thrown exception types</a>
<ul>
<li><a href="#org65cc23d">5.6.1. Statement Reachability</a></li>
<li><a href="#org2c90250">5.6.2. <i>function-body</i></a></li>
<li><a href="#org212b10e">5.6.3. <i>statement</i></a></li>
<li><a href="#orgd5fd1f4">5.6.4. <i>expression-statement</i></a></li>
<li><a href="#org2c818c8">5.6.5. <i>compound-statement</i></a></li>
<li><a href="#org62ddfd3">5.6.6. <i>selection-statement</i></a></li>
<li><a href="#org70777a6">5.6.7. <i>iteration-statement</i></a></li>
<li><a href="#org0d9407a">5.6.8. <i>jump-statement</i></a></li>
<li><a href="#org7f689ea">5.6.9. <i>declaration-statement</i></a></li>
<li><a href="#org7b11c92">5.6.10. <i>try-block</i></a></li>
<li><a href="#orgf331168">5.6.11. <i>init-statement</i></a></li>
<li><a href="#orgd9e064d">5.6.12. <i>expression</i></a></li>
</ul>
</li>
<li><a href="#org283635a">5.7. Template handlers</a>
<ul>
<li><a href="#orgf8e04ae">5.7.1. Template argument deduction</a></li>
<li><a href="#orgca7c6e5">5.7.2. Matching dynamic exception objects</a></li>
<li><a href="#org70b1a5e">5.7.3. Ordering of instantiated handlers</a></li>
</ul>
</li>
<li><a href="#org888225e">5.8. Virtual Functions</a>
<ul>
<li><a href="#org9682a36">5.8.1. ABI of virtual functions with differing exception specifications</a></li>
</ul>
</li>
<li><a href="#org7fda6d1">5.9. Concepts</a></li>
<li><a href="#org837c881">5.10. Coroutines</a>
<ul>
<li><a href="#org8ad42de">5.10.1. Coroutine promise object handling for static exception objects</a></li>
<li><a href="#org74b05f8">5.10.2. Computing the exception specification of a coroutine with a deduced throw specification</a></li>
</ul>
</li>
<li><a href="#org56dc8b3">5.11. Type traits</a>
<ul>
<li><a href="#org579cce7">5.11.1. Nothrow queries</a></li>
<li><a href="#org38b17f8">5.11.2. <code>std::is_function</code> and <code>std::is_member_function_pointer</code></a></li>
<li><a href="#org849b714">5.11.3. Additional traits</a></li>
</ul>
</li>
<li><a href="#org1d6476a">5.12. Freestanding</a></li>
</ul>
</li>
<li><a href="#orge66ceec">6. Prior Work</a>
<ul>
<li><a href="#org8758d0b">6.1. Throw specifications and noexcept</a></li>
<li><a href="#org95611f6">6.2. Java Checked Exceptions</a>
<ul>
<li><a href="#org63cd782">6.2.1. Background On How Exceptions work in Java</a></li>
<li><a href="#orgd361bb3">6.2.2. Criticisms of Java Checked exceptions</a></li>
</ul>
</li>
<li><a href="#orgce4f3aa">6.3. Midori</a></li>
<li><a href="#org5673755">6.4. Deducing exception specifications</a></li>
<li><a href="#org3cff64e">6.5. Faster Exceptions</a></li>
</ul>
</li>
<li><a href="#org3e2ce6f">7. Design Discussion</a>
<ul>
<li><a href="#orge4603da">7.1. Code Evolution</a></li>
<li><a href="#orge480e84">7.2. A new calling convention / function-type</a></li>
<li><a href="#org0bcbd48">7.3. Changing the implementation changes the calling convention</a></li>
<li><a href="#org4c9465d">7.4. How accurate does the potentially-thrown exception type calculation need to be?</a></li>
<li><a href="#org9716515">7.5. Permission to throw types derived from <code>std::bad_alloc</code> / <code>std::bad_cast</code></a></li>
<li><a href="#org4b80ae0">7.6. Avoiding dependencies on thread-locals</a>
<ul>
<li><a href="#org9823fe5">7.6.1. Avoiding overhead implied by <code>std::current_exception()</code> and <code>throw;</code></a></li>
<li><a href="#orgf16672e">7.6.2. Avoiding overhead implied by <code>std::unhandled_exceptions()</code></a></li>
</ul>
</li>
<li><a href="#org0df00cd">7.7. Calling C functions</a></li>
<li><a href="#org3dece97">7.8. Interaction with Contracts</a></li>
<li><a href="#orgd4a8d2e">7.9. Standard Library Impacts</a>
<ul>
<li><a href="#org02c12ee">7.9.1. Whether implementations add <code>noexcept</code> to "Throws: Nothing" functions can now affect well-formedness of a program</a></li>
<li><a href="#org9c171c2">7.9.2. Should implementations be allowed to strengthen "Throws: something" exception specification to a static exception specification?</a></li>
<li><a href="#org4bd02d0">7.9.3. Usage of the standard library in functions with static throw-specifications will be painful without more noexcept</a></li>
<li><a href="#org375278b">7.9.4. Function-wrapper types</a></li>
<li><a href="#org2d7f84d">7.9.5. Algorithms</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#org65f744e">8. Implementation Strategies</a>
<ul>
<li><a href="#orgc7a921f">8.1. Multiple return-paths/return-addresses</a>
<ul>
<li><a href="#orgd83e104">8.1.1. Inline Jump Tables</a></li>
<li><a href="#org8a1806c">8.1.2. "NOP Stuffing" Jump Tables</a></li>
</ul>
</li>
<li><a href="#orgd40790f">8.2. Multiple return-value-slots</a></li>
<li><a href="#org289c68a">8.3. Passing an exception-value-slot parameter</a></li>
<li><a href="#orgeca46de">8.4. Walking stack to find storage</a></li>
<li><a href="#org4c177e9">8.5. Unwinding through scopes with destructors</a></li>
<li><a href="#org80c9807">8.6. Interop between static-exception functions and dynamic-exception functions</a></li>
<li><a href="#orgb9a86e9">8.7. Virtual function calls</a></li>
<li><a href="#org3ff4e32">8.8. Interaction with <code>std::uncaught_exceptions()</code></a></li>
<li><a href="#orgc177aee">8.9. Static exceptions and the Itanium C++ ABI</a></li>
</ul>
</li>
<li><a href="#orgf4a1577">9. Acknowledgements</a></li>
<li><a href="#org55b463f">10. References</a></li>
</ul>
</div>
</div>
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">


<colgroup>
<col  class="org-left" />

<col  class="org-left" />
</colgroup>
<tbody>
<tr>
<td class="org-left">Document</td>
<td class="org-left"><b>P3166R0</b></td>
</tr>

<tr>
<td class="org-left">Date</td>
<td class="org-left"><b>2024-03-16</b></td>
</tr>

<tr>
<td class="org-left">Reply To</td>
<td class="org-left"><b>Lewis Baker &lt;lewissbaker@gmail.com&gt;</b></td>
</tr>

<tr>
<td class="org-left">Audience</td>
<td class="org-left"><b>EWGI</b>, <b>LEWGI</b></td>
</tr>
</tbody>
</table>

<div id="outline-container-org39e3e7a" class="outline-2">
<h2 id="org39e3e7a"><span class="section-number-2">1.</span> Abstract</h2>
<div class="outline-text-2" id="text-1">
<p>
Exceptions are the C++ language's primary tool for communicating errors to callers.
However, the dynamic exceptions we have today come with runtime overheads that
cause many people to avoid using, or even completely disable exceptions in domains
that are performance-sensitive.
</p>

<p>
This paper proposes adding new language features for annotating functions with
additional type information, in the form of static exception specifications,
that should allow exception objects to be returned on the stack with performance
similar to that of normal return-paths.
</p>

<p>
These features include:
</p>
<ul class="org-ul">
<li>Adding the ability to add <code>throw</code>-specifiers to function declarations as a way of
declaring the complete set of exception types that the function may exit with.</li>
<li>Allow declaring a function as <code>throw(auto)</code> to deduce the set of exception types
that may be thrown based on the body of the function.</li>
<li>Add a new <code>declthrow()</code> syntax for querying the set of exceptions that an expression
may exit with.</li>
<li>Add a <code>template catch</code> syntax to allow writing exception handlers that are templates
which are instantiated based on the set of exception types that may be thrown from the
associated try-block.</li>
<li>Enable static checking of exception specifications for function definitions with
a static <code>throw</code>-specifier to ensure that they can not exit with exceptions not listed
in their throw specifier. Functions definitions with a <code>throw(auto)</code>, <code>throw(...)</code>
or <code>noexcept</code> specifier are not checked, even if they call functions with static
exception specifications.</li>
</ul>

<p>
This paper has the following main goals:
</p>
<ol class="org-ol">
<li>Eliminate the performance-related reasons for not using exceptions
in embedded and other performance critical code.</li>
<li>Enable the use of exception-based error handling in freestanding environments
by enabling exceptions to be thrown/caught without a need for heavy-weight
runtime components or dynamic allocation.</li>
<li>Eliminate classes of bugs relating to unhandled exceptions and error code-paths
by making it possible to identify at compile-time code that is failing to
handle some exception-types that might be thrown and make it ill-formed.</li>
</ol>

<p>
This proposal is still in the early stages and is being published to solicit feedback
on direction and also on potential interaction with other in-flight papers, such
as contracts and discussions around <code>noexcept</code> policy in the standard library.
</p>
</div>
</div>

<div id="outline-container-org65638c7" class="outline-2">
<h2 id="org65638c7"><span class="section-number-2">2.</span> Synopsis</h2>
<div class="outline-text-2" id="text-2">
<p>
<b>Example 1: Explicit throw specifications on declarations</b>
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">throws_nothing</span>() <span class="org-keyword">throw</span>(); <span class="org-comment-delimiter">// </span><span class="org-comment">empty static exception specification - equivalent to noexcept(true)</span>
<span class="org-type">void</span> <span class="org-function-name">throws_a_b</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>, <span class="org-type">B</span>); <span class="org-comment-delimiter">// </span><span class="org-comment">static exception specification</span>
<span class="org-type">void</span> <span class="org-function-name">throws_any</span>() <span class="org-keyword">throw</span>(...);  <span class="org-comment-delimiter">// </span><span class="org-comment">dynamic exception specification - equivalent to noexcept(false)</span>
<span class="org-type">void</span> <span class="org-function-name">throws_any2</span>() <span class="org-keyword">throw</span>(<span class="org-constant">std</span>::<span class="org-type">any_exception</span>); <span class="org-comment-delimiter">// </span><span class="org-comment">same as throw(...)</span>
</pre>
</div>

<p>
<b>Example 2: Deduced throw specifications</b>
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-type">range</span> <span class="org-variable-name">R</span>, <span class="org-keyword">typename</span> <span class="org-type">F</span>&gt;
<span class="org-type">requires</span> <span class="org-constant">std</span>::<span class="org-type">invocable</span>&lt;<span class="org-type">F</span>&amp;, <span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-type">range_reference_t</span>&lt;R&gt;&gt;
<span class="org-type">void</span> for_each(<span class="org-type">R</span> <span class="org-variable-name">rng</span>, <span class="org-type">F</span> <span class="org-variable-name">func</span>) <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) {
  <span class="org-keyword">for</span> (<span class="org-keyword">auto</span>&amp;&amp; <span class="org-variable-name">x</span> : rng) {
    func(<span class="org-keyword">static_cast</span>&lt;<span class="org-keyword">decltype</span>(x)&gt;(x));
  }
}
</pre>
</div>

<p>
<b>Example 3: Querying the potentially-thrown exception types + use of template handlers</b>
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-constant">std</span>::<span class="org-type">variant</span>&lt;<span class="org-constant">std</span>::monostate, declthrow(<span class="org-type">throws_a_b</span>())...&gt; <span class="org-variable-name">err</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">variant&lt;monostate, A, B&gt;</span>
<span class="org-keyword">try</span> {
  <span class="org-variable-name">throws_a_b</span>();
} <span class="org-keyword">template</span> <span class="org-keyword">catch</span> (<span class="org-keyword">auto</span>&amp; <span class="org-variable-name">e</span>) { <span class="org-comment-delimiter">// </span><span class="org-comment">instantiated for each static exception type in set { A , B }</span>
  err.<span class="org-keyword">template</span> emplace&lt;<span class="org-keyword">decltype</span>(<span class="org-keyword">auto</span>(<span class="org-variable-name">e</span>))&gt;(<span class="org-constant">std</span>::move(e));
}
</pre>
</div>

<p>
<b>Example 4: Checked exception specifications - Calling <code>throw(A,B)</code> function from <code>throw()</code> function</b>
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">nothrow_caller</span>() <span class="org-keyword">throw</span>() {
  throws_a_b(); <span class="org-comment-delimiter">// </span><span class="org-comment">Ill-formed: A and B not handled locally and not listed in throw specification</span>

  <span class="org-keyword">try</span> {
    throws_a_b(); <span class="org-comment-delimiter">// </span><span class="org-comment">Ill-formed: A not handled locally and not listed in throw specification</span>
  }
  <span class="org-keyword">catch</span> (B) {}

  <span class="org-keyword">try</span> {
    throws_a_b(); <span class="org-comment-delimiter">// </span><span class="org-comment">OK: all potentially-thrown exceptions are handled locally</span>
  }
  <span class="org-keyword">catch</span> (A) {}
  <span class="org-keyword">catch</span> (B) {}
}
</pre>
</div>

<p>
<b>Example 5: Checked exception specifications - Calling <code>throw(...)</code> function from <code>throw()</code> function</b>
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">nothrow_caller</span>() <span class="org-keyword">throw</span>() {
  throws_any(); <span class="org-comment-delimiter">// </span><span class="org-comment">Ill-formed: dynamic exception not handled locally</span>

  <span class="org-keyword">try</span> {
    throws_any(); <span class="org-comment-delimiter">// </span><span class="org-comment">OK</span>
  }
  <span class="org-keyword">catch</span>(...) {}
}
</pre>
</div>

<p>
<b>Example 6: Checked exception specifications - Calling <code>throw(A,B)</code> function from <code>throw(A)</code> function</b>
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">caller</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>) {
  throws_a_b(); <span class="org-comment-delimiter">// </span><span class="org-comment">Ill-formed: B not handled locally and not listed in throw specification</span>

  <span class="org-keyword">try</span> { throws_a_b(); <span class="org-comment-delimiter">/* </span><span class="org-comment">OK</span><span class="org-comment-delimiter"> */</span> }
  <span class="org-keyword">catch</span> (B) {}

  <span class="org-keyword">try</span> { throws_a_b(); <span class="org-comment-delimiter">/* </span><span class="org-comment">OK</span><span class="org-comment-delimiter"> */</span> }
  <span class="org-keyword">catch</span> (<span class="org-type">A</span> <span class="org-variable-name">a</span>) {
    <span class="org-keyword">if</span> (<span class="org-negation-char">!</span>can_handle(a)) <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">OK: rethrows A, which is allowed</span>
  }
  <span class="org-keyword">catch</span> (B) {}
}
</pre>
</div>

<p>
<b>Example 7: Checked exception specifications - Calling <code>throw(...)</code> function from <code>throw(A)</code> function</b>
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">caller</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>) {
  throws_any(); <span class="org-comment-delimiter">// </span><span class="org-comment">Ill-formed: dynamic exception not handled locally</span>

  <span class="org-keyword">try</span> { throws_any(); <span class="org-comment-delimiter">/* </span><span class="org-comment">OK - all exceptions handled</span><span class="org-comment-delimiter"> */</span> }
  <span class="org-keyword">catch</span> (<span class="org-keyword">const</span> <span class="org-type">A</span>&amp;) {
    <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">Ill-formed: Might rethrow type derived from A (unless A is final)</span>
  }
  <span class="org-keyword">catch</span>(...) {}

  <span class="org-keyword">try</span> { throws_any(); <span class="org-comment-delimiter">/* </span><span class="org-comment">OK - exceptions handled</span><span class="org-comment-delimiter"> */</span> }
  <span class="org-keyword">catch</span>(<span class="org-keyword">const</span> <span class="org-type">A</span>&amp; <span class="org-variable-name">a</span>) {
    <span class="org-keyword">throw</span> a; <span class="org-comment-delimiter">// </span><span class="org-comment">OK - only throws A - slices types derived from A</span>
  }
  <span class="org-keyword">catch</span>(...) {}
}
</pre>
</div>

<p>
<b>Example 8: Simpler alternative to <code>std::expected</code> / <code>std::variant</code> code</b>
</p>

<p>
An API that can fail but avoids using exceptions might look like:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-constant">std</span>::<span class="org-type">expected</span>&lt;X, E1&gt; <span class="org-function-name">get_x</span>() <span class="org-keyword">noexcept</span>;
<span class="org-constant">std</span>::<span class="org-type">expected</span>&lt;Y, E2&gt; <span class="org-function-name">get_y</span>() <span class="org-keyword">noexcept</span>;

<span class="org-constant">std</span>::<span class="org-type">expected</span>&lt;Z, <span class="org-constant">std</span>::<span class="org-type">variant</span>&lt;E1, E2&gt;&gt; <span class="org-function-name">make_z</span>() <span class="org-keyword">noexcept</span> {
  <span class="org-keyword">auto</span> <span class="org-variable-name">x</span> = get_x();
  <span class="org-keyword">if</span> (<span class="org-negation-char">!</span>x) <span class="org-keyword">return</span> {<span class="org-constant">std</span>::unexpect, <span class="org-constant">std</span>::move(x).error()};

  <span class="org-keyword">auto</span> <span class="org-variable-name">y</span> = get_y();
  <span class="org-keyword">if</span> (<span class="org-negation-char">!</span>x) <span class="org-keyword">return</span> {<span class="org-constant">std</span>::unexpect, <span class="org-constant">std</span>::move(y).error()};

  <span class="org-keyword">return</span> {<span class="org-constant">std</span>::in_place, <span class="org-constant">std</span>::move(x).value(), <span class="org-constant">std</span>::move(y).value()};
}

<span class="org-constant">std</span>::<span class="org-type">expected</span>&lt;Z, <span class="org-constant">std</span>::<span class="org-type">variant</span>&lt;E1, E2&gt;&gt; <span class="org-function-name">make_z_p2561</span>() {
  <span class="org-keyword">return</span> {<span class="org-constant">std</span>::in_place, get_x()??, get_y()??}; <span class="org-comment-delimiter">// </span><span class="org-comment">?? error-propagation operator from P2561</span>
}

<span class="org-type">void</span> <span class="org-function-name">consumer</span>() <span class="org-keyword">noexcept</span> {
  <span class="org-keyword">auto</span> <span class="org-variable-name">result</span> = make_z();
  <span class="org-keyword">if</span> (<span class="org-negation-char">!</span>result) {
    <span class="org-constant">std</span>::visit(overload(
      [&amp;](<span class="org-keyword">const</span> <span class="org-type">E1</span>&amp; <span class="org-variable-name">e</span>) <span class="org-keyword">noexcept</span> { <span class="org-comment-delimiter">/* </span><span class="org-comment">handle E1</span><span class="org-comment-delimiter"> */</span> },
      [&amp;](<span class="org-keyword">const</span> <span class="org-type">E2</span>&amp; <span class="org-variable-name">e</span>) <span class="org-keyword">noexcept</span> { <span class="org-comment-delimiter">/* </span><span class="org-comment">handle E2</span><span class="org-comment-delimiter"> */</span> }),
      result.error());
    <span class="org-keyword">return</span>;
  }

  <span class="org-type">Z</span>&amp; <span class="org-variable-name">z</span> = result.value();
  <span class="org-comment-delimiter">// </span><span class="org-comment">use z</span>
}
</pre>
</div>
<p>
which can instead be written using static exceptions, with equivalent (or better) performance:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">X</span> <span class="org-function-name">get_x</span>() <span class="org-keyword">throw</span>(<span class="org-type">E1</span>);
<span class="org-type">Y</span> <span class="org-function-name">get_y</span>() <span class="org-keyword">throw</span>(<span class="org-type">E2</span>);

<span class="org-type">Z</span> <span class="org-function-name">make_z</span>() <span class="org-keyword">throw</span>(<span class="org-type">E1</span>, <span class="org-type">E2</span>) {
  <span class="org-keyword">return</span> Z{get_x(), get_y()}; <span class="org-comment-delimiter">// </span><span class="org-comment">allows aggregate initialization</span>
}

<span class="org-type">void</span> <span class="org-function-name">consumer</span>() <span class="org-keyword">throw</span>() {
  <span class="org-keyword">try</span> {
    <span class="org-type">Z</span> <span class="org-variable-name">z</span> = make_z();
    <span class="org-comment-delimiter">// </span><span class="org-comment">use z</span>
  }
  <span class="org-keyword">catch</span> (<span class="org-keyword">const</span> <span class="org-type">E1</span>&amp; <span class="org-variable-name">e</span>) { <span class="org-comment-delimiter">/* </span><span class="org-comment">handle E1</span><span class="org-comment-delimiter"> */</span> }
  <span class="org-keyword">catch</span> (<span class="org-keyword">const</span> <span class="org-type">E2</span>&amp; <span class="org-variable-name">e</span>) { <span class="org-comment-delimiter">/* </span><span class="org-comment">handle E2</span><span class="org-comment-delimiter"> */</span> }
}
</pre>
</div>

<p>
<b>Example 9: Guaranteed deterministic local throw/catch, even in <code>throw(...)</code> functions</b>
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">example</span>(<span class="org-constant">std</span>::<span class="org-type">vector</span>&lt;<span class="org-constant">std</span>::<span class="org-type">vector</span>&lt;<span class="org-constant">std</span>::string&gt;&gt; <span class="org-variable-name">vec</span>) {
  <span class="org-keyword">struct</span> <span class="org-type">InvalidString</span> {};
  <span class="org-keyword">try</span> {
    <span class="org-keyword">for</span> (<span class="org-keyword">auto</span>&amp; <span class="org-variable-name">strings</span> : vec) {
      <span class="org-keyword">for</span> (<span class="org-keyword">auto</span>&amp; <span class="org-variable-name">string</span> : strings) {
        <span class="org-keyword">if</span> (<span class="org-negation-char">!</span>is_valid(string))
          <span class="org-keyword">throw</span> InvalidString{}; <span class="org-comment-delimiter">// </span><span class="org-comment">cost equivalent to local goto</span>
        <span class="org-comment-delimiter">// </span><span class="org-comment">process string...</span>
      }
    }
  }
  <span class="org-keyword">catch</span> (InvalidString) {
    <span class="org-comment-delimiter">// </span><span class="org-comment">handle invalid input</span>
  }
}
</pre>
</div>
</div>
</div>

<div id="outline-container-orgb6fffd8" class="outline-2">
<h2 id="orgb6fffd8"><span class="section-number-2">3.</span> Overview</h2>
<div class="outline-text-2" id="text-3">
<p>
This paper proposes introducing <i>static exception specifications</i>, repurposing the
throw-specification syntax which was removed in C++17, to provide additional
type-information about the closed-set of possible exception types that might be
thrown from a function. The proposed design tries to avoid the shortcomings of the
previous design of throw-specifications by requiring that checks are performed
at compile-time instead of at runtime.
</p>

<p>
Function definitions with a throw specification are checked by the
compiler at compile-time to ensure that there are no code-paths that might allow
an exception to exit the function that would violate the declared throw-specification,
rather than dynamically check this at runtime and terminate.
Functions that fail this static exception specification check are ill-formed.
</p>

<p>
While we are yet to gain implementation experience for this proposal, the design
for static exception specifications should permit implementation strategies that
can achieve efficiency of throwing exceptions close to that of normal return values,
with exception objects able to be returned on the stack or in registers using
similar conventions to normal return-values. Some potential implementation strategies
for this are described in the <a href="#org65f744e">Implementation Strategies</a> section.
</p>

<p>
The proposed design is also similar in many ways to the design proposed in
<a href="https://wg21.link/P0709R4">P0709R4 - Zero-overhead deterministic exceptions: Throwing values</a>.
However, it differs in a number of key areas:
</p>
<ul class="org-ul">
<li>It allows users to specify a list of multiple exception types they might throw
in the throw specifier rather than limiting them to throwing only <code>std::error</code> or,
in the extension proposed at the end of P0709, a single error type.</li>
<li>It does not require the introduction of a special <code>std::error</code> type
that must be used to wrap all exceptions-as-values. Such a type could
potentially be used in conjunction with this proposal via <code>throw(std::error)</code>,
but would require explicit conversion between exception types at function boundaries.</li>
<li>It does not require falling back to dynamic-allocation when propagating
exception types that do not fit in the small-object optimisation built into P0709's proposed
<code>std::error</code> type. All static exception objects are passed in automatic storage duration
storage so can be as large or as small as you like. Throwing an empty exception object
does not need to consume a register, throwing a large object does not require dynamic
allocation.</li>
<li>It provides the <code>template catch</code> facility to allow generically handling multiple
static exception types - something P0709 does not provide as it expects you to
just be propagating a single static exception type, <code>std::error</code>.</li>
</ul>

<p>
This design does not change the semantics of existing C++23 code. It can be
incrementally adopted throughout a code-base by annotating functions with
static exception specifications using the <code>throw(/type-list/)</code> syntax where appropriate
in much the same way that code-bases could incrementally adopt <code>noexcept</code>
specifiers in their code-base when they were introduced. Changing
a function from <code>noexcept(false)</code> to <code>throw(A, B, C)</code> will likely be an ABI
break, however, and so will require recompilation of any calling code.
</p>

<p>
This proposal aims to enable use of static exception specifications in freestanding
environments which were traditionally unable to use exceptions. Static exception-specifications
provide enough type-information to the compiler to allow exceptions to be thrown, propagated,
caught and rethrown with minimal runtime machinery - without need for dynamic-allocation,
runtime type information, or <code>dynamic_cast</code>.
</p>

<p>
If a program can avoid using facilities that require dynamic exceptions, such as
<code>std::current_exception()</code> and <code>throw;</code> expressions that appear outside of the lexical
scope of handlers, then the only dependency on thread-local storage is <code>std::uncaught_exceptions()</code>,
which is not required in a lot of projects and could potentially be omitted from freestanding environments.
See the section on <a href="#org4b80ae0">Avoiding dependencies on thread-locals</a> for more details.
</p>

<p>
The ability to opt-in to compile-time checking that all exceptions are handled helps to
ensure that all error-conditions have been handled, potentially helping to improve the
correctness, reliability and safety of code. Callers of a function cannot forget to
handle errors like they can with other mechanisms for communicating errors.
</p>

<p>
It also allows a program to ensure that there are no hidden calls to <code>std::terminate()</code>
inserted by the compiler due to unhandled exceptions, which can potentially remove some
barriers to use of C++ exceptions in environments where termination should only be performed
in the presence of unrecoverable errors.
</p>

<p>
Authors of functions that have checked exception specifications can still explicitly catch
exceptions that represent fatal error conditions and insert an explicit call to <code>std::terminate()</code>
to get the same behaviour as the dynamically-checked <code>noexcept</code> behaviour - only now these calls
to <code>std::terminate()</code> appear in source code and so can be more easily audited than the implicit
ones the compiler was inserting.
</p>

<p>
Adopting this paper would have some implications for the P2900 contracts proposal and general <code>noexcept</code>
policy in the standard library. It forces us to confront the question of whether a function with
a deduced exception specification that evaluates a <code>contract_assert</code> should be considered
potentially-throwing.
This paper discusses these question briefly and poses some potential directions, but does not
seek to answer them at this stage.
</p>

<p>
This paper is structured into the following sections:
</p>
<ul class="org-ul">
<li><b><a href="#org3d65ca7">Motivation</a></b> - motivation for addition of this feature</li>
<li><b><a href="#org85e3be4">Proposal</a></b> - describes the design of the features this paper is proposing</li>
<li><b><a href="#orge66ceec">Prior Work</a></b> - a comparison of this work to prior-art in this area. e.g. to Java, Midori, C++98</li>
<li><b><a href="#org3e2ce6f">Design Discussion</a></b> - further discussion of important design points, alternatives, future work, etc.</li>
<li><b><a href="#org65f744e">Implementation Strategies</a></b> - discusses potential strategies implementations could use to implement this design efficiently</li>
</ul>
</div>
</div>

<div id="outline-container-org3d65ca7" class="outline-2">
<h2 id="org3d65ca7"><span class="section-number-2">4.</span> Motivation</h2>
<div class="outline-text-2" id="text-4">
<p>
The paper [P0709R4] "Deterministic exceptions: throwing values" by Herb Sutter
contains detailed motivation for improving exceptions, and covers the background
and history of exceptions in C++ better than I could do here.
</p>

<p>
I agree with much of the philosophy and motivations expressed in P0709 and have
used them as inspiration for the design for this paper. However, this paper takes
a different approach to solving the issues raised.
</p>

<p>
The paper [P1947R0] "C++ exceptions and alternatives" by Bjarne Stroustrup argues that
adding yet-another-error-handling mechanism is likely to further fracture the community
because existing mechanisms and styles won't disappear and efficiency improvements
will be patchy and limited.
</p>

<p>
P1947 advocates instead for improving the existing C++ exceptions that we have and
highlights some problems with some of the alternative error-code based handling mechanisms.
</p>

<p>
Improvements in this space should try to be consistent with, as much as possible, the
existing C++ exception design. For example, by ensuring that a thrown exception object
of type, <code>T</code>, remains an exception object of type <code>T</code> as it propagates up the stack,
regardless of whether callers have dynamic or static exception specifications.
</p>
</div>

<div id="outline-container-orgbbba720" class="outline-3">
<h3 id="orgbbba720"><span class="section-number-3">4.1.</span> Alternative error-signalling mechansisms have problems too</h3>
<div class="outline-text-3" id="text-4-1">
<p>
Code-bases that avoid using exceptions, for whatever reason, need to choose an alternative
error-signalling mechanism to signal to the caller that an operation failed.
</p>

<p>
Popular choices include using <code>std::error_code</code> (either as a return-value or out-parameter),
<code>boost::outcome</code>, <code>std::expected</code>, <code>std::optional</code>, etc.
</p>

<p>
Many of these error-handling mechanisms force the user to make other trade-offs
in return for avoiding exceptions. If we can reduce the reasons for people to
avoid using exceptions, we can potentially reduce the need to make some of these
trade-offs.
</p>
</div>

<div id="outline-container-orgcec19d3" class="outline-4">
<h4 id="orgcec19d3"><span class="section-number-4">4.1.1.</span> Composition of facilities that use different error-signaling mechanisms</h4>
<div class="outline-text-4" id="text-4-1-1">
<p>
As pointed out in P1947, these alternative error mechanisms aren't universally
usable in all places. For example, calls to constructors are unable to change the return-type
to return a value-or-error object, and overload operators are unable to take additional
out-parameters that can receive error-codes.
</p>

<p>
Many of these error-signalling mechanisms don't force users to handle the errors,
meaning users can mask problems by accidentally ignoring errors, making their use "error"-prone.
</p>

<p>
The growing number of error-handling mechanisms in use means it is harder to
compose components that use different error-handling techniques - often requiring
explicit conversion/adaptation between components that use different error-signalling
mechanisms.
</p>

<p>
Many generic algorithms assume that if an operation doesn't throw an exception then it
must have succeeded. Adapting these algorithms to other error-signalling mechanisms
often requires reimplementing them.
</p>
</div>
</div>

<div id="outline-container-orgcc13320" class="outline-4">
<h4 id="orgcc13320"><span class="section-number-4">4.1.2.</span> Runtime overhead due to additional branching, packing/unpacking</h4>
<div class="outline-text-4" id="text-4-1-2">
<p>
The alternative error-handling mechanisms can also incur runtime overhead on the
success-path compared to exception-based code.
</p>

<p>
They often require returning a value that can either represent a success or an error.
The calling code then needs to inspect the value to see which kind of result it is
and then branch on the answer rather than just continuing on the success path.
</p>

<p>
Alternatives can inhibit copy-elision of returned values. Results typically need to
be packed into some container, such as <code>std::expected</code>, and then unpacked by the caller
before being passed by-value to another function, or used to initialize a data-member
with aggregate initialization.
</p>

<p>
When propagating error values through many layers of a call-stack each caller needs
to inspect the result, unpack the error, repack into a new wrapper object of a
different return-type.
</p>

<p>
Both cases require additional calls to move-constructors compared to returning the
success value on its own, or compared to throwing an exception.
</p>
</div>
</div>

<div id="outline-container-org316521c" class="outline-4">
<h4 id="org316521c"><span class="section-number-4">4.1.3.</span> May require an additional "invalid" state, additional preconditions</h4>
<div class="outline-text-4" id="text-4-1-3">
<p>
Alternative error-handling mechanisms also typically require objects to have an invalid state.
</p>

<p>
A constructor that can fail but that does not throw an exception will generally require
a subsequent query after calling the constructor to check whether construction succeeded
before attempting to use that object.
</p>

<p>
This can potentially require that object to hold additional state to represent that
invalid state.
</p>

<p>
It also requires adding additional pre-conditions on each operation performed on the object
that check that the object is valid.
</p>
</div>
</div>
</div>

<div id="outline-container-orgf5d6ae8" class="outline-3">
<h3 id="orgf5d6ae8"><span class="section-number-3">4.2.</span> Making exceptions fast by-design</h3>
<div class="outline-text-3" id="text-4-2">
<p>
Exceptions are expensive on many platforms for error-handling that is not rare.
In some cases, taking the exceptional path can be 100-1000x slower than the normal
return-path.
</p>

<p>
This can be especially problematic for services that use exceptions for signalling errors
which trigger in service-overload situations. If a system is overloaded and starts
raising errors but this results in taking code-paths that are significantly more
expensive then this can result in a snow-balling effect where a few small
errors quickly leads to much larger system failures.
</p>

<p>
The dynamic nature of exceptions as they are today, which relies on dynamic allocation,
run-time type information and dynamic type-matching of handlers during unwind, makes
it very difficult to reason about the performance of code in exceptional situations.
</p>

<p>
Dynamic allocation can potentially make system-calls to acquire memory from the operating
system, or can block acquring locks on shared data-structures, leading to unpredictable,
non-deterministic execution times.
</p>

<p>
The cost of dynamic type-matching when searching for a handler can depend on what DLLs
happen to be loaded into the process - something that is very difficult to reason about
locally.
</p>

<p>
While there have been efforts to reduce the cost of the dynamic exceptions, such as
[FastCasting] and [Renwick], they do not solve the whole problem. For example,
even with the stack-allocation techniques described in [Renwick], dynamic allocation
is still required to transport exceptions across threads - something that will be
increasingly common with the upcoming <code>std::excecution</code> facilities proposed in [P2300].
</p>

<p>
The cost of exceptions in production implementations have remained roughly the same
over the past few decades as improvements, to the extent they would be possible, would
result in extremely disruptive ABI breaks.
</p>

<p>
All of these performance issues with exceptions are well-known and are one of the
primary reasons why people avoid using exceptions, or restrict their use to genuinely
rare error-conditions.
</p>

<p>
However, exceptions as a model for error handling generally have a lot of benefits
and are well integrated into the language.
</p>

<p>
If we can find a way to make exceptions fast by-design, of the order of normal return-values
and as efficient or better than the alternative error-signalling mechanisms, then it
would opens up a number of possibilities.
</p>

<p>
Exceptions then become possible to use in environments that were traditionally unable
to use them (or even enable them) for performance reasons.
e.g. freestanding/embedded systems, or real-time systems such as games.
</p>

<p>
It also opens up opportunities for APIs to use exceptions to report errors that are not rare.
This can help make the ergonomics of using these APIs nicer by keeping the success-path
of using the APIs clean and free-of error-handling logic.
</p>
</div>
</div>

<div id="outline-container-org4a64a64" class="outline-3">
<h3 id="org4a64a64"><span class="section-number-3">4.3.</span> Supporting exceptions in freestanding and real-time environments</h3>
<div class="outline-text-3" id="text-4-3">
<p>
The current lack of support for exceptions in freestanding environments
significantly limits the how much of the standard library can be used in those environments,
and also forces those environments to use other error-handling techniques which are
potentially more error-prone.
This is unfortunate as many safety-critical systems target freestanding environments.
</p>

<p>
To be able to be used in freestanding environments, the code-size and run-time overhead
of using exceptions needs to be small enough that it can be used on small micro-controllers
that may only have 10's of KB of memory available.
</p>

<p>
Dependencies on dynamic allocation, run-time type-information and thread-locals can easily
eat up a significant portion of memory available for program text.
</p>

<p>
For real-time environments, such as games, where high-performance and binary size is a
key reqirement, the current dynamic nature of exceptions and the common implementations
of that design lead to overhead that is undesirable, even if exception paths are not evaluated.
</p>
</div>
</div>

<div id="outline-container-orgaf83d0c" class="outline-3">
<h3 id="orgaf83d0c"><span class="section-number-3">4.4.</span> Reducing bugs caused by failure to handle error-conditions</h3>
<div class="outline-text-3" id="text-4-4">
<p>
Use of exceptions in a program can introduce hidden control-flow that makes it hard to
know if you have handled all possible error-cases in your function.
</p>

<p>
The existing proposals for exceptions have not yet sought to address the problem
of programs unintentionally failing to handle exceptions as a potential source of bugs
in a program. Although it is worth noting that [P0709R4]'s proposed `try` expression
syntax at least sought to make the hidden control flow more visible.
</p>

<p>
If function authors are able to opt-in to having their function's exception specification
checked at compile time to make sure they are not violating it by failing to handle some
exception types then we can potentially
reduce or eliminate two classes of bugs relating to unhandled exceptions.
</p>

<p>
The first case is where the programmer fails to handle a given exception due to an
oversight when initially writing the function.
</p>

<p>
The second case is where a function was correct when initially written, but as code
evolves, a function it calls is later modified to report new error-conditions for
which the initial function was not aware it needed to handle.
</p>

<p>
Currently, the language offers little help to users wanting to catch this class of errors.
</p>
</div>
</div>

<div id="outline-container-orgfde7b81" class="outline-3">
<h3 id="orgfde7b81"><span class="section-number-3">4.5.</span> Describing the contract in code instead of in documentation</h3>
<div class="outline-text-3" id="text-4-5">
<p>
A function declaration defines the contract between callers of that function and the
implementations of that function.
</p>

<p>
The status quo is that the function declaration currently only describes the types
that a caller must provide as arguments, the type that the function will return on
success, and whether or not the function might indicate failure by throwing an
exception (via the <code>noexcept</code> specifier).
</p>

<p>
We have also added attributes such as <code>[[noreturn]]</code> and <code>[[nodiscard]]</code> that provide
the user more information about whether the function can return normally, or whether
the return-value is safe to discard.
</p>

<p>
With the contracts facility proposed in [P2900R6], we would gain the ability to describe
runtime properties of the values that must be passed to a function and returned from
it.
</p>

<p>
The set of exception-types that may be thrown forms an important part of a function's
contract - it tells the caller "here are the ways in which I might fail", not just <span class="underline">that</span>
it might fail.
</p>

<p>
However, currently, the ability to describe a set of exception-types that a function
may throw in the function declaration is noticeably absent.
</p>

<p>
Prior to C++17, there was the ability to declare constraints on the set of exception
types a function could throw, by declaring a function with a throw-specifier.
The types listed, however, were not necessarily the complete set of types - the function was
permitted to throw types derived from the types listed.
</p>

<p>
While this information was of some help to users who could know what handlers to
write to match all of the exceptions, it was not useful for compilers in determining
the potential size of exception ojbects in order to be able to return them on the stack.
Some form of type-erasure and run-time type-information was still required.
See <a href="#org4585572">(Re)Adding <code>throw()</code> specifiers</a> for more
details.
</p>

<p>
This facility was deprecated in C++11 with the introduction of <code>noexcept</code> and removed
in C++17.
</p>

<p>
Both users and compilers would benefit from having more information about the
set of exceptions that can be thrown - allowing local reasoning about the potential
exception code-paths without requiring global knowledge of the program.
</p>
</div>

<div id="outline-container-org99023a6" class="outline-4">
<h4 id="org99023a6"><span class="section-number-4">4.5.1.</span> Uses in generic code</h4>
<div class="outline-text-4" id="text-4-5-1">
<p>
When writing generic code that ends up calling into APIs on types provided by the user,
we don't necessarily know what exception types they may throw. If that generic code
wants to be able to capture an exception, store it and rethrow it later, the best it
can do is store the exception in a <code>std::exception_ptr</code> - meaning we need type-erasure
and dynamic allocation.
</p>

<p>
If a program had a way to query the set of concrete exception types that may be thrown
from an expression at compile time then the generic code could find more efficient ways
to store an exception object, such as in a <code>std::variant</code>.
</p>
</div>
</div>
</div>

<div id="outline-container-orgea98202" class="outline-3">
<h3 id="orgea98202"><span class="section-number-3">4.6.</span> Reducing boiler-plate when writing functions that are transparent to exceptions</h3>
<div class="outline-text-3" id="text-4-6">
<p>
Authors of generic code often desire to write facilities that are transparent to exceptions.
e.g. they call onto methods on types provided by the user and want to throw any exceptions
that those methods can throw.
</p>

<p>
This is often expressed in standardese as "is expression equivalent to", or "Throws: exceptions
thrown by <code>func(x)</code>".
</p>

<p>
Currently, if generic functions want their <code>noexcept</code> specifier to correctly report whether
or not the function might throw an exception, the author must write an expression as a
parameter to the <code>noexcept</code> specifier that computes this result.
</p>

<p>
To do this correctly, the author must identify and duplicate every expression in the
function body (including any implicit conversions) and then query whether or not that
expression can potentially throw by passing it as the argument to a <code>noexcept</code> expression.
</p>

<p>
This is highly tedious code to write and often difficult to get right, especially in the
presence of constructs like <code>if constexpr</code> within the function body.
</p>

<p>
If you get it wrong by being conservative, resulting in a <code>noexcept(false)</code> when a
<code>noexcept(true)</code> would have been appropriate then you might end up with slower code-generation,
or dispatching to a less efficient algorithm (e.g. via <code>std::move_if_noexcept</code>).
</p>

<p>
However, it is much more likely that an author misses an expression and accidentally
declares a function as <code>noexcept(true)</code> when it should have been <code>noexcept(false)</code>.
If this is the case and the function throws then your program ends up terminating.
</p>

<p>
The compiler is much better placed to be able to reliably deduce whether or not
a function can potentially throw an exception from the body than the programmer is.
</p>

<p>
Futher, the extra syntactic noise in the signature of the function often obscures the more
important parts of the function definition, like the parameters, const-qualifiers, etc,
reducing readability of the code.
</p>

<p>
We already have the ability to deduce the return-type of a function from the function body
by declaring a return-type of <code>auto</code> or <code>decltype(auto)</code>. It would simplify a lot of
generic code that wants to be transparent to exceptions if we could also let the compiler
deduce the exception specification.
</p>
</div>
</div>
</div>

<div id="outline-container-org85e3be4" class="outline-2">
<h2 id="org85e3be4"><span class="section-number-2">5.</span> Proposal</h2>
<div class="outline-text-2" id="text-5">
</div>

<div id="outline-container-orgcada955" class="outline-3">
<h3 id="orgcada955"><span class="section-number-3">5.1.</span> Overview</h3>
<div class="outline-text-3" id="text-5-1">
<p>
The key components of this proposal are as follows:
</p>

<p>
It proposes (re)adding throw specifiers which can be used to declare a function
as having either a static exception specification, <code>throw(T1, T2...)</code>,
or dynamic exception specification, <code>throw(...)</code> or <code>throw(std::any_exception)</code>.
</p>

<p>
It proposes adding the <code>throw(auto)</code> syntax for deducing the throw-specification of a
function from its definition, which must be visible before use of the function.
</p>

<p>
It proposes rules for statically checking at compile-time that the bodies of function
definitions with throw specifiers do not violate their exception specification.
Failure to either handle all such cases or declare that you forward on unhandled
exceptions are ill-formed.
</p>

<p>
It proposes adding the <code>declthrow(expr)</code> syntax for querying what set of exception
types might be thrown from a particular expression.
</p>

<p>
It proposes adding the <code>template catch</code> syntax to allow catching static exceptions
thrown from the associated try-block, allowing a way to use the same handler template
to handle different types, without the need for type-erasing the exception.
</p>
</div>
</div>

<div id="outline-container-org4585572" class="outline-3">
<h3 id="org4585572"><span class="section-number-3">5.2.</span> (Re)Adding throw specifiers</h3>
<div class="outline-text-3" id="text-5-2">
<p>
The original design of exceptions in C++ included a throw-specification that allowed
the programmer to declare a list of exception types that a function might exit with, by
specifying the <code>throw(E1, E2, E3)</code> specifier after the function parameter list.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">Example</span>(<span class="org-keyword">const</span> <span class="org-constant">std</span>::<span class="org-type">string_view</span>&amp; <span class="org-variable-name">path</span>)
     <span class="org-keyword">throw</span>(<span class="org-constant">std</span>::<span class="org-type">bad_alloc</span>, <span class="org-constant">std</span>::<span class="org-type">system_error</span>);
</pre>
</div>

<p>
The throw-specification, as originally designed, had a number of issues that limited
its usability and utility, and in time most people came to avoid the feature as its
pitfalls outweighed the benefits of using it.
</p>

<p>
The following is a summarized list of the issues:
</p>
<ul class="org-ul">
<li>The runtime/code-size overhead cost due to need to dynamically-check for unhandled
exception types.</li>
<li>The <code>std::unexpected()</code> notification mechanism did not lend itself to recovery from
unhandled exceptions.</li>
<li>MSVC (at the time) did not enforce the contract - a function with a <code>throw()</code>
specification could still throw exceptions of types other than those mentioned in the
throw-specification, but the compiler would optimise based assumptions that it did not.
This made the feature dangerous to use as it would result in undefined behaviour if
the programmer failed to adhere to the throw-specification.</li>
</ul>

<p>
In C++11, we introduced <code>noexcept</code>, initially as a tool needed to restore the strong
exception-safety guarantee to types like <code>std::vector</code> after the introduction of
move-constructors.
</p>

<p>
The original throw-specifications were deprecated along with the introduction of
<code>noexcept</code> and, in C++17, were removed from the C++ language. This frees up the syntax
for being reused for a similar purpose, albeit with an improved design that tries to
avoid the pitfalls of the original design.
</p>
</div>
</div>

<div id="outline-container-orgbc4a37f" class="outline-3">
<h3 id="orgbc4a37f"><span class="section-number-3">5.3.</span> Static and dynamic exception specifications</h3>
<div class="outline-text-3" id="text-5-3">
<p>
A <i>static exception specification</i> is an exception specification that lists a finite
set of possible exception types that a function may exit with.
</p>

<p>
A <i>non-empty static exception specification</i> is a static exception specification that
contains one or more exception types listed in the throw specification.
</p>

<p>
A <i>dynamic exception specification</i> is an exception specification that allows the function
to exit with any exception type.
</p>

<p>
A <i>throw-specifier</i> can be used to declare a function with either a static or dynamic
exception specification.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>();    <span class="org-comment-delimiter">// </span><span class="org-comment">static-exception-specification with empty exception type list</span>
                     <span class="org-comment-delimiter">// </span><span class="org-comment">equivalent to noexcept(true)</span>

<span class="org-type">void</span> <span class="org-function-name">g</span>() <span class="org-keyword">throw</span>(...); <span class="org-comment-delimiter">// </span><span class="org-comment">dynamic-exception-specification</span>
                     <span class="org-comment-delimiter">// </span><span class="org-comment">equivalent to noexcept(false)</span>

<span class="org-type">void</span> <span class="org-function-name">g</span>() <span class="org-keyword">throw</span>(<span class="org-constant">std</span>::<span class="org-type">any_exception</span>); <span class="org-comment-delimiter">// </span><span class="org-comment">equivalent to throw(...)</span>
                                    <span class="org-comment-delimiter">// </span><span class="org-comment">see section on declthrow for rationale</span>

<span class="org-type">void</span> <span class="org-function-name">h</span>() <span class="org-keyword">throw</span>(<span class="org-type">E1</span>);     <span class="org-comment-delimiter">// </span><span class="org-comment">throws only E1  (static-exception-specification)</span>
<span class="org-type">void</span> <span class="org-function-name">i</span>() <span class="org-keyword">throw</span>(<span class="org-type">E1</span>, <span class="org-type">E2</span>); <span class="org-comment-delimiter">// </span><span class="org-comment">throws either E1 or E2</span>
<span class="org-type">void</span> <span class="org-function-name">j</span>() <span class="org-keyword">throw</span>(<span class="org-type">Es</span>...);  <span class="org-comment-delimiter">// </span><span class="org-comment">throws one of the types in pack Es...</span>

<span class="org-type">void</span> <span class="org-function-name">k</span>() <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>);   <span class="org-comment-delimiter">// </span><span class="org-comment">set of exceptions it could throw is deduced from body of function,</span>
                        <span class="org-comment-delimiter">// </span><span class="org-comment">much like using decltype(auto) to deduce the return-type.</span>
</pre>
</div>

<p>
A declaration signature of <code>void foo() throw();</code> is equivalent to <code>void foo() noexcept;</code>.
However, a function definition with a <code>throw()</code> specifier differs from one with <code>noexcept</code>
specifier in that the definition is ill-formed if an exception can possibly escape the function,
whereas <code>void foo() noexcept</code> detects such a failure to fulfil its contract at runtime and terminates.
i.e. throw-specifications are statically checked/enforced rather than dynamically checked/enforced.
</p>

<p>
Similarly, <code>void bar() throw(E1, E2)</code> is ill-formed if any exception types other than <code>E1</code> or <code>E2</code>
can possibly escape the body of the function. The aim is to avoid hidden calls to <code>std::terminate</code>
in response to unhandled exceptions.
</p>

<p>
It is permitted to declare a function with the specifier <code>noexcept(true)</code> and define it with
the specifier <code>throw()</code>, and vice versa. Doing so allows you to have the compiler statically
check that there are no unhandled exceptions exiting the function body that might implicitly
result in a call to <code>std::terminate</code>.
</p>

<p>
Similarly, it is permitted to declare a function with the specifier <code>noexcept(false)</code> and define
it with the specifier <code>throw(...)</code>, and vice versa. However, there are no differences in semantics
of the definition between these two syntaxes - they are pure aliases for each other.
</p>

<p>
A forward declaration of a function with a non-empty static exception specification on its
definition must have an equivalent static exception specification on the declaration.
</p>
</div>

<div id="outline-container-org7ea3527" class="outline-4">
<h4 id="org7ea3527"><span class="section-number-4">5.3.1.</span> Types in a throw-specification form an unordered set</h4>
<div class="outline-text-4" id="text-5-3-1">
<p>
The order of the types in the throw-specification is not significant. The throw-specification
declares an unordered set of types that may be thrown, rather than an ordered list of types.
</p>

<p>
Two throw-specifications are equivalent if they contain the same set of types, regardless
of the order in which those types are listed in the source code.
</p>

<p>
It is valid to list a type multiple times in a throw-specification.
Any duplicates are ignored/eliminated by the compiler.
</p>

<p>
Eliminating duplicates is helpful when composing lists of exception types
from multiple <code>declthrow</code> expressions that have overlap in the set of exceptions
they may throw - see the section "Querying the throw-specification".
</p>

<p>
For example, the following functions all have the same exception specification:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>(<span class="org-type">E1</span>, <span class="org-type">E2</span>);
<span class="org-type">void</span> <span class="org-function-name">g</span>() <span class="org-keyword">throw</span>(<span class="org-type">E2</span>, <span class="org-type">E1</span>);
<span class="org-type">void</span> <span class="org-function-name">h</span>() <span class="org-keyword">throw</span>(<span class="org-type">E1</span>, <span class="org-type">E1</span>, <span class="org-type">E2</span>);
</pre>
</div>

<p>
The rationale for making the set of exceptions an unordered set rather than an ordered list is
to reduce the chance of annoying incompatibilities when casting a function to a function-pointer.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-comment-delimiter">// </span><span class="org-comment">declared in lib1</span>
<span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>(<span class="org-type">E1</span>, <span class="org-type">E2</span>);

<span class="org-comment-delimiter">// </span><span class="org-comment">declared in lib2</span>
<span class="org-type">void</span> <span class="org-function-name">g</span>() <span class="org-keyword">throw</span>(<span class="org-type">E2</span>, <span class="org-type">E1</span>);


<span class="org-type">void</span> (*<span class="org-function-name">func</span>)() <span class="org-keyword">throw</span>(<span class="org-type">E1</span>, <span class="org-type">E2</span>) = &amp;f;
<span class="org-keyword">if</span> (cond) {
  func = &amp;g; <span class="org-comment-delimiter">// </span><span class="org-comment">It would be annoying if this was ill-formed because the throw-specification had a different order.</span>
}
</pre>
</div>
</div>
</div>

<div id="outline-container-org8cced06" class="outline-4">
<h4 id="org8cced06"><span class="section-number-4">5.3.2.</span> Handling of <code>std::any_exception</code> in the throw-specifier</h4>
<div class="outline-text-4" id="text-5-3-2">
<p>
The <code>std::any_exception</code> type is a type that is handled specially by throw specifications.
See the section "<code>declthrow</code> of a <code>throw(...)</code> expression" below for a definition of this type.
</p>

<p>
If the list of types passed as arguments to the <code>throw</code> specifier contains the type
<code>std::any_exception</code> then the overall exception-specification is evaluated to be
<code>throw(...)</code>. i.e. that it can throw any exception type.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">a</span>() <span class="org-keyword">throw</span>(<span class="org-constant">std</span>::<span class="org-type">any_exception</span>);       <span class="org-comment-delimiter">// </span><span class="org-comment">-&gt; throw(...)</span>
<span class="org-type">void</span> <span class="org-function-name">b</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>, <span class="org-type">B</span>, <span class="org-constant">std</span>::<span class="org-type">any_exception</span>); <span class="org-comment-delimiter">// </span><span class="org-comment">-&gt; throw(...)</span>
</pre>
</div>

<p>
The use of a type <code>std::any_exception</code> allows template metaprogramming libraries to be
able to conditionally compute a throw-specification that can evaluate as either a static exception specification
or a dynamic exception specification.
</p>

<p>
For example: Computing a throw-specification to either be <code>throw(...)</code> or
a static exception specification, depending on a template parameter.
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span>... <span class="org-type">Ts</span>&gt;
<span class="org-keyword">using</span> ...pack = Ts; <span class="org-comment-delimiter">// </span><span class="org-comment">P1858R2 pack alias syntax</span>

<span class="org-comment-delimiter">// </span><span class="org-comment">Generic case</span>
<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">T</span>&gt;
<span class="org-keyword">struct</span> <span class="org-type">_compute_foo_throw_types</span> {
  <span class="org-keyword">using</span> ...types = <span class="org-type">pack</span>&lt;<span class="org-constant">std</span>::any_exception&gt;; <span class="org-comment-delimiter">// </span><span class="org-comment">P1858R2 pack alias syntax</span>
};

<span class="org-comment-delimiter">// </span><span class="org-comment">When T satisfies the Foo concept, we know it will only</span>
<span class="org-comment-delimiter">// </span><span class="org-comment">fail with two possible exceptions.</span>
<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">T</span>&gt;
  <span class="org-type">requires</span> <span class="org-type">Foo</span>&lt;<span class="org-type">T</span>&gt;
<span class="org-keyword">struct</span> <span class="org-type">_compute_foo_throw_types</span>&lt;<span class="org-type">T</span>&gt; {
  <span class="org-keyword">using</span> ...types = <span class="org-type">pack</span>&lt;FooError, <span class="org-constant">std</span>::bad_alloc&gt;;
};

<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">T</span>&gt;
<span class="org-type">void</span> <span class="org-function-name">foo</span>(<span class="org-keyword">const</span> <span class="org-type">T</span>&amp; <span class="org-variable-name">x</span>) <span class="org-keyword">throw</span>(<span class="org-constant">_compute_foo_throw_types</span>&lt;<span class="org-type">T</span>&gt;::...<span class="org-type">types</span>...); <span class="org-comment-delimiter">// </span><span class="org-comment">P1858R2 pack expansion syntax</span>
</pre>
</div>

<p>
Here, the function <code>foo&lt;T&gt;</code> has an exception specification that is either <code>throw(FooError, std::bad_alloc)</code> or <code>throw(...)</code>,
depending on the type, <code>T</code>.
</p>
</div>
</div>

<div id="outline-container-orgd2d1532" class="outline-4">
<h4 id="orgd2d1532"><span class="section-number-4">5.3.3.</span> The types in the throw specification describe all concrete types that may be thrown</h4>
<div class="outline-text-4" id="text-5-3-3">
<p>
One of the prime motivations behind re-adding throw-specifiers is to provide the compiler
with enough static type information for it to be able to allocate storage for exceptions that
may be thrown on the stack of the caller, rather than the runtime having to dynamically-allocate
storage for them on the heap. It also allows the compiler to statically dispatch to the appropriate
handler for each possible exception that might be thrown, without requiring dynamic type-matching
or run-time type information.
</p>

<p>
For this to be possible, the compiler needs to know the size/alignment of all exception types so
that it can reserve storage in the stack-frame for any exception-types which cannot be passed
back to the caller in registers. Similarly, it needs to know which exception types may be passed
back in registers.
</p>

<p>
This means that we cannot just list an exception base-class in the throw-specifier and then
leave the set of possible exception types open to include any type derived from that base-class,
as this would not allow callers to reserve space for any such exception on the stack-frame caller.
</p>

<p>
For example, a declaration with a throw-specifier of <code>throw(std::exception)</code> does not declare
that the function may throw an exception derived from <code>std::exception</code>, it instead states that
the function may throw an instance of <code>std::exception</code> (e.g. as if via <code>throw std::exception{};</code>)
and does not exit with any other type of exception.
</p>

<p>
The implication of this restriction, however, is that any changes to the set of exception-types
that may be thrown by a function is a potential ABI break for that function, requiring, at a minimum,
recompilation of all callers of that function.
</p>

<p>
This is no different to changing the return-type of a function.
e.g. when adding a new entry to a <code>std::variant</code>-returning function.
</p>

<p>
This places some interesting constraints on the evolution of such functions, which are discussed
in detail in a later section.
</p>
</div>
</div>

<div id="outline-container-org7308b93" class="outline-4">
<h4 id="org7308b93"><span class="section-number-4">5.3.4.</span> Exception types may not be references, cv-qualified, or void</h4>
<div class="outline-text-4" id="text-5-3-4">
<p>
Types listed in the throw-specifier may not be references, cv-qualified, or <code>void</code>.
</p>

<p>
Static-exception types are returned by-value to callers, so it does not make sense to
support throw-specifiers that include types that are references or cv-qualified.
</p>
</div>
</div>

<div id="outline-container-orgd5fc979" class="outline-4">
<h4 id="orgd5fc979"><span class="section-number-4">5.3.5.</span> Static exception specifications are part of the function type</h4>
<div class="outline-text-4" id="text-5-3-5">
<p>
A static exception specification is part of the function type, much like <code>noexcept</code> specifier is
part of the function type.
</p>

<p>
In general, a function-pointer with a non-empty static-exception-specification cannot be cast to a
function-pointer type with a different exception-specification. This is because the calling-convention
between such functions may be different, as the list of exceptions that may be thrown forms part of the
ABI of such a function.
</p>

<p>
Note that it is possible to cast a function directly to a function-pointer type with a wider exception
specification than the function was declared with as the compiler is able to then generate
a thunk that can implement the ABI for the wider specification in terms of the function's native ABI.
</p>

<p>
Once the identity of the function has been erased as a function-pointer, it is no longer possible for
the compiler to know how to generate such a thunk.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>();
<span class="org-type">void</span> <span class="org-function-name">g</span>() <span class="org-keyword">throw</span>(<span class="org-type">E1</span>);
<span class="org-type">void</span> <span class="org-function-name">h</span>() <span class="org-keyword">throw</span>(<span class="org-type">E1</span>, <span class="org-type">E2</span>);
<span class="org-type">void</span> <span class="org-function-name">i</span>() <span class="org-keyword">throw</span>(...);

<span class="org-type">void</span>(*<span class="org-function-name">pf</span>)() <span class="org-keyword">throw</span>() = f; <span class="org-comment-delimiter">// </span><span class="org-comment">OK</span>
pf = g; <span class="org-comment-delimiter">// </span><span class="org-comment">ERROR - can't cast g() to a function-ptr with narrower throw-specification</span>
pf = h; <span class="org-comment-delimiter">// </span><span class="org-comment">ERROR - can't cast h() to a function-ptr with narrower throw-specification</span>
pf = i; <span class="org-comment-delimiter">// </span><span class="org-comment">ERROR - can't cast i() to a function-ptr with narrower throw-specification</span>

<span class="org-type">void</span>(*<span class="org-function-name">pg</span>)() <span class="org-keyword">throw</span>(<span class="org-type">E1</span>) = g; <span class="org-comment-delimiter">// </span><span class="org-comment">OK</span>
pg = f; <span class="org-comment-delimiter">// </span><span class="org-comment">OK - points either to f or to thunk that calls f</span>
pg = h; <span class="org-comment-delimiter">// </span><span class="org-comment">ERROR - can't cast h() to a function-ptr with narrower throw-specification</span>
pg = i; <span class="org-comment-delimiter">// </span><span class="org-comment">ERROR - can't cast i() to a function-ptr with narrower throw-specification</span>

<span class="org-type">void</span>(*<span class="org-function-name">ph</span>)() <span class="org-keyword">throw</span>(<span class="org-type">E1</span>, <span class="org-type">E2</span>) = h; <span class="org-comment-delimiter">// </span><span class="org-comment">OK</span>
ph = f;  <span class="org-comment-delimiter">// </span><span class="org-comment">OK - ph points to f or to a thunk that calls f</span>
ph = g;  <span class="org-comment-delimiter">// </span><span class="org-comment">OK - ph points to a thunk that calls g</span>
ph = i;  <span class="org-comment-delimiter">// </span><span class="org-comment">ERROR - can't cast i() to function-ptr with narrower throw-specification</span>

<span class="org-type">void</span>(*<span class="org-function-name">pi</span>)() <span class="org-keyword">throw</span>(...) = i; <span class="org-comment-delimiter">// </span><span class="org-comment">OK</span>
pi = f; <span class="org-comment-delimiter">// </span><span class="org-comment">OK - ph points to f (same as casting noexcept(true) function-ptr to a noexcept(false) one)</span>
pi = g; <span class="org-comment-delimiter">// </span><span class="org-comment">OK - ph points to a thunk that calls g and translates static-exceptions into dynamic-exceptions</span>
pi = h; <span class="org-comment-delimiter">// </span><span class="org-comment">OK - ph points to a thunk that calls g and translates static-exceptions into dynamic-exceptions</span>

<span class="org-comment-delimiter">// </span><span class="org-comment">The same casts are not all valid when casting function-pointers to other function-pointer</span>
<span class="org-comment-delimiter">// </span><span class="org-comment">types instead of functions to function-pointer types.</span>
pf = pg; <span class="org-comment-delimiter">// </span><span class="org-comment">ERROR: Can't cast function-ptr with static throw specification to another function-ptr type</span>
pf = ph; <span class="org-comment-delimiter">// </span><span class="org-comment">ERROR: (same)</span>
pf = pi; <span class="org-comment-delimiter">// </span><span class="org-comment">ERROR: Can't cast throw(...) function-ptr to throw() function-ptr</span>

pg = pf; <span class="org-comment-delimiter">// </span><span class="org-comment">MAYBE?: In some ABIs the calling convention may be compatible.</span>
         <span class="org-comment-delimiter">// </span><span class="org-comment">Do we want to restrict the options here?</span>
pg = ph; <span class="org-comment-delimiter">// </span><span class="org-comment">ERROR: Can't cast to function-ptr with narrower throw-specification</span>
pg = pi; <span class="org-comment-delimiter">// </span><span class="org-comment">ERROR: Can't cast to function-ptr with narrower throw-specification</span>

ph = pf; <span class="org-comment-delimiter">// </span><span class="org-comment">MAYBE?: In some ABIs the calling convention may be compatible.</span>
ph = pg; <span class="org-comment-delimiter">// </span><span class="org-comment">ERROR: Can't cast function-ptr with static exception specification to function-ptr with a</span>
         <span class="org-comment-delimiter">// </span><span class="org-comment">different exception specification. Compiler is unable to generate the necessary thunk here.</span>
ph = pi; <span class="org-comment-delimiter">// </span><span class="org-comment">ERROR: Can't cast to function-ptr with narrower throw-specification.</span>

pi = pf; <span class="org-comment-delimiter">// </span><span class="org-comment">OK: this is same as casting function-ptr with noexcept(true) to function-ptr with noexcept(false)</span>
pi = pg; <span class="org-comment-delimiter">// </span><span class="org-comment">ERROR: Can't cast function-ptr with static exception specification to function-ptr with</span>
         <span class="org-comment-delimiter">// </span><span class="org-comment">different exception specification. Compiler is unable to generate the necessary thunk here.</span>
pi = ph; <span class="org-comment-delimiter">// </span><span class="org-comment">ERROR: Can't cast function-ptr with static exception specification to function-ptr with</span>
         <span class="org-comment-delimiter">// </span><span class="org-comment">different exception specification.</span>
</pre>
</div>

<p>
The existing type-conversions from pointers to a function with a <code>noexcept(true)</code> exception specification
to a pointer to a function with a <code>noexcept(false)</code> exception specification are unchanged.
</p>
</div>
</div>

<div id="outline-container-orga3b6ff7" class="outline-4">
<h4 id="orga3b6ff7"><span class="section-number-4">5.3.6.</span> Deducing the throw-specifier from a function signature</h4>
<div class="outline-text-4" id="text-5-3-6">
<p>
It is permitted to allow template arguments to be deduced from the throw-specification
in a function-signature.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">Ret</span>, <span class="org-keyword">typename</span>... <span class="org-type">Args</span>, <span class="org-keyword">typename</span>... <span class="org-type">Errors</span>&gt;
<span class="org-type">void</span> <span class="org-function-name">Call</span>(<span class="org-type">Ret</span>(*<span class="org-function-name">func_ptr</span>)(<span class="org-type">Args</span>...) <span class="org-keyword">throw</span>(<span class="org-type">Errors</span>...));

<span class="org-type">void</span> <span class="org-function-name">a</span>() <span class="org-keyword">throw</span>();
<span class="org-type">void</span> <span class="org-function-name">b</span>() <span class="org-keyword">throw</span>(<span class="org-type">int</span>);
<span class="org-type">void</span> <span class="org-function-name">c</span>() <span class="org-keyword">throw</span>(<span class="org-constant">std</span>::<span class="org-type">bad_alloc</span>, <span class="org-constant">std</span>::<span class="org-type">system_error</span>);
<span class="org-type">void</span> <span class="org-function-name">d</span>() <span class="org-keyword">throw</span>(...);

Call(&amp;a); <span class="org-comment-delimiter">// </span><span class="org-comment">deduces Errors to be the empty pack.</span>
Call(&amp;b); <span class="org-comment-delimiter">// </span><span class="org-comment">deduces Errors to be the pack: int</span>
Call(&amp;c); <span class="org-comment-delimiter">// </span><span class="org-comment">deduces Errors to be the pack: std::bad_alloc, std::system_error   (in some unspecified order)</span>
Call(&amp;d); <span class="org-comment-delimiter">// </span><span class="org-comment">deduces Errors to be the pack: std::any_exception</span>
</pre>
</div>

<p>
This is similar to the ability to deduce whether a function signature is <code>noexcept</code> or not.
</p>
</div>
</div>

<div id="outline-container-org8639d71" class="outline-4">
<h4 id="org8639d71"><span class="section-number-4">5.3.7.</span> <code>throw(auto)</code> - Deducing exception-specifications from the body of a function</h4>
<div class="outline-text-4" id="text-5-3-7">
<p>
Often, when writing forwarding functions, or function templates, you just want the function to be
transparent to exceptions. i.e. any unhandled exceptions should be propagated to the caller.
</p>

<p>
In these cases, ideally the function's exception-specification should mirror the set of
exceptions that the body of the function may throw.
</p>

<p>
With the current facilities available with <code>noexcept</code>, this typically means that you need to
repeat every expression in the body of the function in the <code>noexcept</code> specifier for that function.
</p>

<p>
For simple functions this is manageable, although tedious. However, for more complicated function bodies,
or for function-bodies that include conditionally-executed logic guarded by an <code>if constexpr</code> branch,
the expression needed to compute the <code>noexcept</code> specifier argument quickly becomes unwieldy.
</p>
</div>

<ol class="org-ol">
<li><a id="org3be5e99"></a>Prior work on deducing exception specifications<br />
<div class="outline-text-5" id="text-5-3-7-1">
<p>
This usability issue was identified as a problem back when <code>noexcept</code> was originally proposed for C++11:
</p>
<ul class="org-ul">
<li><a href="https://wg21.link/N3227">N3227</a> - Please reconsider <code>noexcept</code> (Ottosen, 2010)</li>
</ul>

<p>
There have since been multiple papers exploring the idea of deducing the exception-specification:
</p>
<ul class="org-ul">
<li><a href="https://wg21.link/N3202">N3202</a> - To which extent can <code>noexcept</code> be deduced? (Stroustrup, 2010)</li>
<li><a href="https://wg21.link/N3207">N3207</a> - <code>noexcept(auto)</code> (Merrill, 2010)</li>
<li><a href="https://wg21.link/N4473">N4473</a> - <code>noexcept(auto)</code>, again (Voutilainen, 2015)</li>
<li><a href="https://wg21.link/P0133R0">P0133R0</a> - Putting <code>noexcept(auto)</code> on hold, again (Voutilainen, 2015)</li>
</ul>

<p>
It is worth noting that the rationale given in P0133R0 for putting on hold the pursuit of
<code>noexcept(auto)</code> was mainly because it did not solve the whole problem of having to duplicate
the function-body in the declaration - the expressions of the body still needed to be duplicated
in the return-type for SFINAE purposes - and therefore it was not good use of committee time
to pursue a partial solution.
</p>

<p>
Since this paper was written, we have gained support for concepts in C++20, which goes some way
to simplifying the code needed to write function-templates that eliminates overloads with SFINAE.
However, this only applies when there are existing concepts defined that can be used to constrain
the function. For many cases you still need to duplicate the expressions of the function body
in a <code>requires</code> clause.
</p>

<p>
Despite this limitation, I feel there is still benefit to enabling deduced exception specifications
as there are often case that are either covered by concepts or that do not require SFINAE, but that
do need to compute accurate exception specifications.
</p>
</div>
</li>

<li><a id="org1b142f5"></a><code>throw(auto)</code><br />
<div class="outline-text-5" id="text-5-3-7-2">
<p>
With the (re)introduction of throw-specifiers, the task of computing a correct throw-specification
from a set of sub-expressions becomes even more onerous than for <code>noexcept</code>, as you need to compute
lists of types, not just a boolean expression.
</p>

<p>
This paper therefore proposes the addition of the <code>throw(auto)</code> specifier on a function declaration,
as a way of declaring that the compiler should compute the set of exception types that may exit the
function from the definition of the body of the function and use that as the exception-specification
for the function.
</p>

<p>
For example, consider a hypothetical <code>for_each</code> function that invokes a function for each
element of a range. If we wanted this function to have the same exception-specification as its
body, it would need to be written with <code>noexcept</code> specifiers, something similar to the following:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;
  <span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-type">range</span> <span class="org-variable-name">Range</span>,
  <span class="org-keyword">typename</span> <span class="org-type">Func</span>&gt;
<span class="org-type">requires</span> <span class="org-constant">std</span>::<span class="org-type">invocable</span>&lt;<span class="org-type">Func</span>&amp;, <span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-type">range_reference_t</span>&lt;Range&gt;&gt;
<span class="org-type">void</span> for_each(<span class="org-type">Range</span>&amp;&amp; <span class="org-variable-name">range</span>, <span class="org-type">Func</span>&amp;&amp; <span class="org-variable-name">func</span>)
  <span class="org-keyword">noexcept</span>(<span class="org-keyword">noexcept</span>(<span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-type">begin</span>(<span class="org-variable-name">range</span>)) &amp;&amp;
           <span class="org-keyword">noexcept</span>(<span class="org-constant">std</span>::<span class="org-constant">ranges</span>::end(range)) &amp;&amp;
           <span class="org-keyword">noexcept</span>(++<span class="org-constant">std</span>::declval&lt;<span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-type">iterator_t</span>&lt;<span class="org-type">Range</span>&gt;&amp;&gt;()) &amp;&amp;
           <span class="org-keyword">noexcept</span>(<span class="org-constant">std</span>::declval&lt;<span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-type">iterator_t</span>&lt;<span class="org-type">Range</span>&gt;&amp;&gt;() != <span class="org-constant">std</span>::declval&lt;<span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-type">sentinel_t</span>&lt;<span class="org-type">Range</span>&gt;&amp;&gt;()) &amp;&amp;
           <span class="org-keyword">noexcept</span>(func(*<span class="org-constant">std</span>::declval&lt;<span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-type">iterator_t</span>&lt;<span class="org-type">Range</span>&gt;&amp;&gt;()))) {
  <span class="org-keyword">auto</span> <span class="org-variable-name">iterEnd</span> = <span class="org-constant">std</span>::<span class="org-constant">ranges</span>::end(range);
  <span class="org-keyword">auto</span> <span class="org-variable-name">iter</span> = <span class="org-constant">std</span>::<span class="org-constant">ranges</span>::begin(range);
  <span class="org-keyword">while</span> (iter != iterEnd) {
    func(*iter);
    ++iter;
  }
}
</pre>
</div>

<p>
And with the <code>throw()</code> specifier proposed by this paper, in conjunction with the <code>declthrow()</code> expression
(described in detail in the following section), we would need to write:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-type">range</span> <span class="org-variable-name">Range</span>, <span class="org-keyword">typename</span> <span class="org-type">Func</span>&gt;
<span class="org-type">requires</span> <span class="org-constant">std</span>::<span class="org-type">invocable</span>&lt;<span class="org-type">Func</span>&amp;, <span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-type">range_reference_t</span>&lt;Range&gt;&gt;
<span class="org-type">void</span> for_each(<span class="org-type">Range</span>&amp;&amp; <span class="org-variable-name">range</span>, <span class="org-type">Func</span>&amp;&amp; <span class="org-variable-name">func</span>)
  <span class="org-keyword">throw</span>(<span class="org-type">declthrow</span>(<span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-type">begin</span>(<span class="org-type">range</span>))...,
        <span class="org-type">declthrow</span>(<span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-type">end</span>(<span class="org-type">range</span>))...,
        <span class="org-type">declthrow</span>(++<span class="org-constant">std</span>::declval&lt;<span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-type">iterator_t</span>&lt;<span class="org-type">Range</span>&gt;&amp;&gt;())...,
        <span class="org-type">declthrow</span>(<span class="org-constant">std</span>::declval&lt;<span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-type">iterator_t</span>&lt;<span class="org-type">Range</span>&gt;&amp;&gt;() != <span class="org-constant">std</span>::declval&lt;<span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-type">sentinel_t</span>&lt;<span class="org-type">Range</span>&gt;&amp;&gt;())...
        <span class="org-type">declthrow</span>(<span class="org-type">func</span>(*<span class="org-constant">std</span>::declval&lt;<span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-type">iterator_t</span>&lt;<span class="org-type">Range</span>&gt;&amp;&gt;()))...)  {
  <span class="org-keyword">auto</span> <span class="org-variable-name">iterEnd</span> = <span class="org-constant">std</span>::<span class="org-constant">ranges</span>::end(range);
  <span class="org-keyword">auto</span> <span class="org-variable-name">iter</span> = <span class="org-constant">std</span>::<span class="org-constant">ranges</span>::begin(range);
  <span class="org-keyword">while</span> (iter != iterEnd) {
    func(*iter);
    ++iter;
  }
}
</pre>
</div>

<p>
Having to repeat the body in a different way in the <code>noexcept</code> or <code>throw</code> specification like
this is tedious and error-prone. It can be easy to miss an expression, or to later modify the
body of the function and forget to update the throw-specification.
</p>

<p>
Instead, if we use the proposed <code>throw(auto)</code> syntax, then the function definition simply becomes:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-type">range</span> <span class="org-variable-name">Range</span>, <span class="org-keyword">typename</span> <span class="org-type">Func</span>&gt;
<span class="org-type">requires</span> <span class="org-constant">std</span>::<span class="org-type">invocable</span>&lt;<span class="org-type">Func</span>&amp;, <span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-type">range_reference_t</span>&lt;Range&gt;&gt;
<span class="org-type">void</span> for_each(<span class="org-type">Range</span>&amp;&amp; <span class="org-variable-name">range</span>, <span class="org-type">Func</span>&amp;&amp; <span class="org-variable-name">func</span>) <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) {
  <span class="org-keyword">auto</span> <span class="org-variable-name">iterEnd</span> = <span class="org-constant">std</span>::<span class="org-constant">ranges</span>::end(range);
  <span class="org-keyword">auto</span> <span class="org-variable-name">iter</span> = <span class="org-constant">std</span>::<span class="org-constant">ranges</span>::begin(range);
  <span class="org-keyword">while</span> (iter != iterEnd) {
    func(*iter);
    ++iter;
  }
}
</pre>
</div>

<p>
This is much more concise, and is now impossible for the throw-specification to be
inconsistent with the function body.
</p>

<p>
This facility will greatly simplify the definition of function-templates, in particular the
function-templates that are defined as "expression-equivalent to" some expression or statement
sequence.
</p>
</div>
</li>

<li><a id="orgf02869c"></a>Further motivation for <code>throw(auto)</code> from P2300 <code>std::execution</code><br />
<div class="outline-text-5" id="text-5-3-7-3">
<p>
One place where having accurate exception specifications (whether <code>noexcept</code> or <code>throw()</code> specifications)
is when using the <code>std::execution</code> facility proposed in P2300.
</p>

<p>
There are generic async algorithms that can potentially have more efficient implementations if
they know that a given operation cannot fail with an error.
</p>

<p>
For example <code>when_all()</code> when passed a collection of senders that cannot complete with an error
the implementation can avoid introducing expensive stop-token synchronization required
for cancelling other child operations if one of them fails. It can also avoid having to reserve
storage for a <code>std::exception_ptr</code> (or other error type) in the operation-state in order to be
able to stash the error while waiting for the other operations to stop.
</p>

<p>
So throughout the design of P2300, the specification tries to ensure that, as much as possible, the
noexcept-ness of expressions are passed-through. An unnecessarily conservative <code>noexcept(false)</code>
can result in additional overhead that the compiler cannot inline away like it can for normal
functions.
</p>

<p>
The <code>noexcept</code>-ness of operations on arguments passed to <code>std::execution</code> algorithms can influence
the return-type of functions, whether particular overloads of template <code>set_error()</code> functions
are instantiated, etc. and so can influence the ABI and whether a program is well-formed.
</p>

<p>
For users using the <code>std::execution</code> algorithms, using the <code>throw(auto)</code> syntax would be beneficial
for cases where they are passing lambdas as parameters to these algorithms and they either:
</p>
<ol class="org-ol">
<li>Don't care whether or not the expressions could throw, but if they can then just do the right
thing by having those expressions transparently propagate exceptions, and if they don't then
do the fast thing.</li>
<li>The do care, but they are writing generic code which may or may not be noexcept depending on
the types it is instantiated with.</li>
</ol>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-constant">std</span>::<span class="org-constant">execution</span>::<span class="org-type">sender</span> <span class="org-variable-name">S</span>&gt;
<span class="org-keyword">auto</span> <span class="org-function-name">sender_example</span>(<span class="org-type">S</span> <span class="org-variable-name">source</span>) <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) {
  <span class="org-keyword">return</span> <span class="org-constant">std</span>::move(source)
    | <span class="org-constant">std</span>::<span class="org-constant">execution</span>::then([](<span class="org-keyword">const</span> <span class="org-keyword">auto</span>&amp; <span class="org-variable-name">data</span>) <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) {
        <span class="org-comment-delimiter">// </span><span class="org-comment">do something with data that might throw or might not throw depending on 'data'</span>
        <span class="org-keyword">return</span> some_computed_value;
      })
    | <span class="org-constant">std</span>::<span class="org-constant">execution</span>::let_value([](<span class="org-keyword">auto</span>&amp; <span class="org-variable-name">computed_value</span>) <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) {
        <span class="org-keyword">return</span> <span class="org-constant">std</span>::<span class="org-constant">execution</span>::when_all(
          sub_operation_1(computed_value),
          sub_operation_2(computed_value))
        | <span class="org-constant">std</span>::<span class="org-constant">execution</span>::then([&amp;](<span class="org-keyword">auto</span> <span class="org-variable-name">op_1_result</span>, <span class="org-keyword">auto</span> <span class="org-variable-name">op_2_result</span>) <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) {
            <span class="org-comment-delimiter">// </span><span class="org-comment">... combine results</span>
            <span class="org-keyword">return</span> some_expr;
          });
      });
}
</pre>
</div>

<p>
If we want this expression to produce a sender that is no-fail when the lambdas within it
are guaranteed not to throw exceptions then currently you'd have to duplicate the body of
each of the lambdas in the noexcept/throw-specifier. This greatly affects the readability of
this sort of code. Most people are probably not going to bother and so the sender algorithm
will have to pessimistically choose a less-efficient implementation to handle the possibility
that some of those expressions might throw. If the author of the lambdas had access to
<code>throw(auto)</code> then users would probably annotate their lambdas as a matter of course so that
their sender/receiver code runs faster when appropriate.
</p>
</div>
</li>
</ol>
</div>

<div id="outline-container-org9f78458" class="outline-4">
<h4 id="org9f78458"><span class="section-number-4">5.3.8.</span> Forward declarations of <code>throw(auto)</code> functions</h4>
<div class="outline-text-4" id="text-5-3-8">
<p>
The use of <code>throw(auto)</code> on a forward-declaration of the function requires that the definition
of the function is visible before the use of the function, in the same way that a function
declared with a deduced-return-type requires that the function definition is available before
it's ODR-used. This is consistent with the behaviour of functions with deduced return-types.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">example</span>() <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>);

<span class="org-type">void</span> <span class="org-function-name">caller1</span>() {
  example();  <span class="org-comment-delimiter">// </span><span class="org-comment">ill-formed. cannot be ODR-used before the definition is seen</span>
}

<span class="org-keyword">auto</span>* <span class="org-variable-name">example_ptr</span> = &amp;example; <span class="org-comment-delimiter">// </span><span class="org-comment">ill-formed. Type of example() is not known until definition is seen.</span>

<span class="org-type">void</span> <span class="org-function-name">caller2</span>() <span class="org-keyword">throw</span>(<span class="org-type">declthrow</span>(<span class="org-type">example</span>())...); <span class="org-comment-delimiter">// </span><span class="org-comment">ill-formed. Cannot query the exception specification</span>
                                               <span class="org-comment-delimiter">// </span><span class="org-comment">of example() before it's definition is seen.</span>
<span class="org-type">void</span> <span class="org-function-name">caller3</span>() <span class="org-keyword">noexcept</span>(<span class="org-keyword">noexcept</span>(<span class="org-variable-name">example</span>())); <span class="org-comment-delimiter">// </span><span class="org-comment">ill-formed. For same reason.</span>

<span class="org-type">void</span> <span class="org-function-name">example</span>() <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) {
  <span class="org-keyword">if</span> (foo()) {
    do_thing1();
  } <span class="org-keyword">else</span> {
    <span class="org-keyword">try</span> {
      do_thing2();
    } <span class="org-keyword">catch</span> (Thing2Failure) {
      do_backup_thing2();
    }
  }
}

<span class="org-comment-delimiter">// </span><span class="org-comment">Now that the definition is visible and the exception-specification</span>
<span class="org-comment-delimiter">// </span><span class="org-comment">can be deduced, the following usages are well-formed.</span>

<span class="org-type">void</span> <span class="org-function-name">caller4</span>() <span class="org-keyword">throw</span>(<span class="org-type">declthrow</span>(<span class="org-type">example</span>())...) { <span class="org-comment-delimiter">// </span><span class="org-comment">OK</span>
  example(); <span class="org-comment-delimiter">// </span><span class="org-comment">OK</span>
}

<span class="org-keyword">auto</span>* <span class="org-variable-name">example_ptr2</span> = &amp;example; <span class="org-comment-delimiter">// </span><span class="org-comment">OK</span>
</pre>
</div>

<p>
The restriction that the function definition with a deduced exception specification needs to be visible before
it can be used has implications for recursive functions, however.
</p>
</div>
</div>

<div id="outline-container-orgf0d5aee" class="outline-4">
<h4 id="orgf0d5aee"><span class="section-number-4">5.3.9.</span> Deduced exception-specifications and recursive functions</h4>
<div class="outline-text-4" id="text-5-3-9">
<p>
Supporting deduced exception-specifications for recursive functions is a challenge.
</p>

<p>
In theory we could define some language rules that would allow some kinds of recursive
functions to be able to deduce their exception-specification.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">struct</span> <span class="org-type">Tree</span> {
  <span class="org-type">Tree</span>* <span class="org-variable-name">left</span>;
  <span class="org-type">Tree</span>* <span class="org-variable-name">right</span>;
  <span class="org-type">int</span> <span class="org-variable-name">value</span>;
};

<span class="org-type">void</span> <span class="org-function-name">process_value</span>(<span class="org-type">int</span> <span class="org-variable-name">value</span>) <span class="org-keyword">throw</span>(<span class="org-type">InvalidValue</span>);

<span class="org-type">void</span> <span class="org-function-name">process_tree</span>(<span class="org-type">Tree</span>&amp; <span class="org-variable-name">tree</span>) <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) {
  <span class="org-keyword">if</span> (tree.left != <span class="org-constant">nullptr</span>)
    process_tree(*tree.left);

  process_value(tree.value); <span class="org-comment-delimiter">// </span><span class="org-comment">recursive-call</span>

  <span class="org-keyword">if</span> (tree.right != <span class="org-constant">nullptr</span>)
    process_tree(*tree.right);
}
</pre>
</div>

<p>
In this case, the only call that is made that is not recursive is the call to <code>process_value()</code>
which can throw <code>InvalidValue</code>. Therefore, we could in theory deduce that the overall throw
specification is <code>throw(InvalidValue)</code>.
</p>

<p>
However, it is relatively easy to construct examples where such rules would not work.
</p>

<p>
Consider:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">contradiction</span>(<span class="org-type">int</span> <span class="org-variable-name">arg</span>) <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) {
  <span class="org-keyword">if</span> <span class="org-keyword">constexpr</span> (<span class="org-keyword">noexcept</span>(<span class="org-variable-name">contradiction</span>(arg)) {
    <span class="org-keyword">throw</span> X{};
  } <span class="org-keyword">else</span> {
    <span class="org-keyword">if</span> (arg &gt; 0)
      <span class="org-keyword">return</span> contradiction(arg - 1);
  }
}
</pre>
</div>

<p>
If the throw-specification is deduced to be <code>throw()</code> then it throws an exception,
otherwise if it is potentially throwing, it calls itself but no longer contains
any statements that might throw an exception except the call to itself, leading
to a contradiction.
</p>

<p>
The key feature of this example that makes it problematic is that it is attempting
to query the exception specification before the exception specification has been deduced.
</p>

<p>
There are also other cases that can directly or indirectly require the exception specification to be known.
Including:
</p>
<ul class="org-ul">
<li>Calling the function within a <code>try { ... } template catch (auto e) { ... }</code> block.
The template catch block needs to know the types that might be thrown in order to
instantiate the catch-block with the correct types.</li>
<li>Passing a pointer to the function to an algorithm.
Constructing the function-pointer type to pass requires knowing the exception specification.</li>
<li>Forming a call to the function as a sub-expression passed to <code>declthrow()</code>.</li>
</ul>

<p>
There are also further challenges with defining mutually-recursive functions that both
have deduced exception specifications.
</p>

<p>
While we may be able to eventually define rules that may allow a subset of recursive
function use-cases to have deduced exception specifications, this seems like a relatively
niche case and so this paper proposes that it be left ill-formed for now.
</p>
</div>
</div>

<div id="outline-container-org32484e6" class="outline-4">
<h4 id="org32484e6"><span class="section-number-4">5.3.10.</span> Delayed computation of deduced throw specifications</h4>
<div class="outline-text-4" id="text-5-3-10">
<p>
The exception specification of a function or function-template with a <code>throw(auto)</code> specifier
need only be computed when the function is selected by overload resolution, or is otherwise ODR-used.
</p>

<p>
This allows the compiler to avoid instantiating function-templates that are part of an overload
set but that are never selected for overload resolution in order to compute the throw specification.
</p>

<p>
Taking the address of a function with a deduced throw-specification will also force the compiler
to compute the throw-specification so that the function-pointer type is known.
</p>

<p>
This behaviour is consistent with functions with computed/deduced <code>noexcept</code> specifiers today.
</p>
</div>
</div>

<div id="outline-container-orge1e9733" class="outline-4">
<h4 id="orge1e9733"><span class="section-number-4">5.3.11.</span> Do we also need <code>noexcept(auto)</code>?</h4>
<div class="outline-text-4" id="text-5-3-11">
<p>
We could also consider adding support for the <code>noexcept(auto)</code> syntax, in addition to <code>throw(auto)</code>.
</p>

<p>
The primary semantic difference between these two would be that <code>noexcept(auto)</code> would only deduce
to either <code>noexcept(true)</code> or <code>noexcept(false)</code>, (equivalent to <code>throw()</code> or <code>throw(...)</code>, respectively),
whereas <code>throw(auto)</code> could also deduce to a non-empty static-exception-specification.
</p>

<p>
While, in most cases, it would be preferable to use <code>throw(auto)</code>, as that allows the exception-specification
to deduce to the more-efficient static-exception-specification, where possible, there may be some scenarios
where deducing to either <code>noexcept(true)</code> or <code>noexcept(false)</code> could be preferable.
</p>

<p>
The one use-case I can think of is where you want to have the exception-specification deduce to a function
whose signature allows a pointer to that function to be assigned to a function-pointer variable that has a
<code>noexcept(false)</code> exception-specification.
</p>

<p>
However, this use-case is somewhat tenuous as it would still be possible to directly cast any function
to a signature-compatible function-pointer with a <code>noexcept(false)</code> exception-specification, it's just
not possible to cast first to a function-pointer with a non-empty static exception specification and
then cast that function-pointer to a function-pointer with a <code>noexcept(false)</code> exception-specification.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">a</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>);
<span class="org-type">void</span> <span class="org-function-name">b</span>() <span class="org-keyword">throw</span>(<span class="org-type">B</span>);

<span class="org-type">void</span> <span class="org-function-name">c</span>() <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) { <span class="org-comment-delimiter">// </span><span class="org-comment">deduces to throw(A, B)</span>
  a();
  b();
}

<span class="org-type">void</span> <span class="org-function-name">d</span>() <span class="org-keyword">noexcept</span>(<span class="org-keyword">auto</span>) { <span class="org-comment-delimiter">// </span><span class="org-comment">deduces to noexcept(false)</span>
  a();
  b();
}

<span class="org-type">void</span> <span class="org-function-name">execute</span>(<span class="org-type">void</span>(*<span class="org-function-name">func</span>)());

<span class="org-type">void</span> <span class="org-function-name">example</span>() {
  <span class="org-keyword">auto</span>* <span class="org-variable-name">c_ptr</span> = &amp;c;
  execute(c_ptr); <span class="org-comment-delimiter">// </span><span class="org-comment">ill-formed: no conversion from 'void(*)() throw(A,B)' to 'void(*)()'</span>

  <span class="org-keyword">auto</span>* <span class="org-variable-name">d_ptr</span> = &amp;d;
  execute(d_ptr); <span class="org-comment-delimiter">// </span><span class="org-comment">OK: 'void(*)() noexcept' implicitly convertible to 'void(*)()'.</span>
}

<span class="org-type">void</span> <span class="org-function-name">workaround</span>() {
  execute(<span class="org-keyword">static_cast</span>&lt;<span class="org-type">void</span>(*)()&gt;(c)); <span class="org-comment-delimiter">// </span><span class="org-comment">OK: explicit cast to noexcept(false) function-pointer from function</span>
  execute(&amp;d); <span class="org-comment-delimiter">// </span><span class="org-comment">OK: Explicit cast not needed</span>
}
</pre>
</div>

<p>
It is an open question whether adding support for <code>noexcept(auto)</code> in addition to <code>throw(auto)</code> is
worth the extra complexity/specification effort.
</p>

<p>
However, in the author's opinion, it is probably not necessary to add in the initial version.
It can be added later if usage experience shows that it would have sufficient value.
</p>
</div>
</div>
</div>

<div id="outline-container-orgbbe1dbe" class="outline-3">
<h3 id="orgbbe1dbe"><span class="section-number-3">5.4.</span> Querying the throw-specification</h3>
<div class="outline-text-3" id="text-5-4">
<p>
Once we have the ability to specify static-exception-specifications on functions, there
will inevitably be cases where we want to be able to know what that set of exception
types is in library code.
</p>

<p>
This paper proposes adding <code>declthrow(expr)</code> syntax as a way of querying what the list of exceptions
that <code>expr</code> may exit with.
</p>

<p>
As the <code>declthrow(expr)</code> needs to be able to produce a list of types, it is proposed that this
form names a pack of types, which can be expanded as needed using <code>declthrow(expr)...</code>.
</p>

<p>
Note that the pack of types produced by <code>declthrow()</code> does not contain any duplicate types.
</p>

<p>
One of the common expected use-cases is in computing a derived throw-specification
for a function composing other functions such that if their exception specifications change
then so does the exception specification of the function composing them.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-comment-delimiter">// </span><span class="org-comment">Header file</span>
<span class="org-type">void</span> <span class="org-function-name">PartA</span>() <span class="org-keyword">throw</span>(<span class="org-type">OutOfWidgets</span>);
<span class="org-type">void</span> <span class="org-function-name">PartB</span>() <span class="org-keyword">throw</span>(<span class="org-type">ProtocolError</span>, <span class="org-type">Timeout</span>);

<span class="org-type">void</span> <span class="org-function-name">ComposedOperation</span>() <span class="org-keyword">throw</span>(<span class="org-type">declthrow</span>(<span class="org-type">PartA</span>())...,
                               <span class="org-type">declthrow</span>(<span class="org-type">PartB</span>())...);

<span class="org-comment-delimiter">// </span><span class="org-comment">... out-of-line definition in .cpp file</span>

<span class="org-type">void</span> <span class="org-function-name">ComposedOperation</span>() <span class="org-keyword">throw</span>(<span class="org-type">declthrow</span>(<span class="org-type">PartA</span>())...,
                               <span class="org-type">declthrow</span>(<span class="org-type">PartB</span>())...) {
  PartA();
  PartB();
  <span class="org-keyword">try</span> {
    PartC();
  } <span class="org-keyword">catch</span> (...) {
    NothrowFallbackPart();
  }
}
</pre>
</div>
</div>

<div id="outline-container-org672f304" class="outline-4">
<h4 id="org672f304"><span class="section-number-4">5.4.1.</span> <code>declthrow</code> of a call to a <code>throw(...)</code> function</h4>
<div class="outline-text-4" id="text-5-4-1">
<p>
If the expression may exit with a dynamic-exception (i.e. one of the sub-expressions has an
exception specification of <code>noexcept(false)</code> or <code>throw(...)</code>)
then the result of this is a compiler-generated type, much like <code>decltype(nullptr)</code>.
</p>

<p>
An alias for this type is made available as <code>std::any_exception</code> in the header <code>&lt;exception&gt;</code>.
</p>

<div class="org-src-container">
<pre class="src src-c++" id="orge3d75e9"><span class="org-keyword">namespace</span> <span class="org-constant">std</span> {
  <span class="org-comment-delimiter">// </span><span class="org-comment">NOTE: using pack indexing syntax proposed in P2662R2</span>
  <span class="org-keyword">using</span> <span class="org-type">any_exception</span> = declthrow(<span class="org-keyword">static_cast</span>&lt;<span class="org-type">void</span>(*)()<span class="org-keyword">throw</span>(...)&gt;(<span class="org-constant">nullptr</span>)())...[0];
}
</pre>
</div>

<p>
The <code>std::any_exception</code> type is not constructible or usable as a value.
It is only intended for use as a placeholder/marker for throw-specifications to indicate
a dynamic exception specification.
</p>

<p>
An alternative design worth considering is having the special type that indicates a
dynamic exception specification to instead be the type <code>std::exception_ptr</code>.
</p>

<p>
This would be useful in cases where you want to store the exception results in a
<code>std::variant</code>. However, it would mean that you could not have an exception specification
that allowed throwing a <code>std::exception_ptr</code> object itself (instead of rethrowing the
exception object contained within the <code>std::exception_ptr</code>).
</p>

<p>
This is explored in more detail in the design discussion section.
</p>
</div>
</div>

<div id="outline-container-org34605cc" class="outline-4">
<h4 id="org34605cc"><span class="section-number-4">5.4.2.</span> Mixed dynamic and static exception specifications</h4>
<div class="outline-text-4" id="text-5-4-2">
<p>
When the operand to <code>declthrow()</code> contains multiple sub-expressions, some of which have
non-empty static exception specifications and some of which have dynamic exception specifications,
there is the question of what the result of the <code>declthrow()</code> query should be.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-comment-delimiter">// </span><span class="org-comment">Given the following</span>
<span class="org-keyword">struct</span> <span class="org-type">X</span>;
<span class="org-keyword">struct</span> <span class="org-type">Y</span>;
<span class="org-type">int</span> <span class="org-function-name">foo</span>() <span class="org-keyword">throw</span>(<span class="org-type">X</span>, <span class="org-type">Y</span>);
<span class="org-type">void</span> <span class="org-function-name">bar</span>(<span class="org-type">int</span> <span class="org-variable-name">x</span>) <span class="org-keyword">throw</span>(...);

<span class="org-comment-delimiter">// </span><span class="org-comment">What types are in the following type-list?</span>
<span class="org-keyword">using</span> <span class="org-type">types</span> = <span class="org-type">type_list</span>&lt;declthrow(bar(foo()))...&gt;;
</pre>
</div>

<p>
There are two viable options to consider here:
</p>
<ul class="org-ul">
<li>We say that the overall expression could emit any exception, so the deduced exception
specification of a function containing this expression would be <code>throw(...)</code>, and so
the resulting type list should contain only <code>std::any_exception</code>; or</li>
<li>We list the union of all of the types listed in static exception specifications and
also list <code>std::any_exception</code> in the result.</li>
</ul>

<p>
This paper proposes to have the result include both <code>std::any_exception</code> and the types
from any static exception specifications, for the following reasons:
</p>
<ul class="org-ul">
<li>It can be used to determine what types might be used to instantiate a <code>template catch</code>
block (see section on this below) associated with a try-block that contains this expression.</li>
<li>It is not necessary to reduce the result to <code>std::any_exception</code> in the <code>declthrow()</code>
expression if it is being used as the argument to a <code>throw</code> specifier - the <code>throw</code>
specifier will do the reduction for you. Reducing the result early is just throwing away
type information.</li>
</ul>

<p>
For example: With this behaviour we can write the following code
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">T</span>, <span class="org-keyword">typename</span>... <span class="org-type">Ts</span>&gt;
<span class="org-type">concept</span> <span class="org-variable-name">one_of</span> = (<span class="org-constant">std</span>::<span class="org-type">same_as</span>&lt;<span class="org-type">T</span>, <span class="org-type">Ts</span>&gt; || ...);

<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span>... <span class="org-type">Es</span>&gt;
<span class="org-keyword">using</span> <span class="org-type">err_variant</span> = <span class="org-constant">std</span>::<span class="org-type">variant</span>&lt;<span class="org-constant">std</span>::monostate,
                                 <span class="org-constant">std</span>::<span class="org-type">conditional_t</span>&lt;<span class="org-constant">std</span>::<span class="org-type">same_as</span>&lt;<span class="org-constant">std</span>::any_exception, <span class="org-type">Es</span>&gt;,
                                                    <span class="org-constant">std</span>::exception_ptr, <span class="org-type">Es</span>&gt;...&gt;;

<span class="org-type">err_variant</span>&lt;declthrow(<span class="org-type">do_foo</span>())...&gt; <span class="org-variable-name">error</span>;
<span class="org-keyword">try</span> {
  <span class="org-variable-name">do_foo</span>();
} <span class="org-keyword">template</span> <span class="org-keyword">catch</span> (<span class="org-keyword">auto</span> <span class="org-variable-name">e</span>) {
  error.emplace&lt;<span class="org-keyword">decltype</span>(e)&gt;(<span class="org-constant">std</span>::move(e));
} <span class="org-keyword">catch</span> (...) {
  <span class="org-keyword">if</span> <span class="org-keyword">constexpr</span> (one_of&lt;<span class="org-constant">std</span>::any_exception, declthrow(do_foo())...&gt;) {
    error.emplace&lt;<span class="org-constant">std</span>::exception_ptr&gt;(<span class="org-constant">std</span>::current_exception());
  }
}
</pre>
</div>
</div>
</div>

<div id="outline-container-org914aaec" class="outline-4">
<h4 id="org914aaec"><span class="section-number-4">5.4.3.</span> Order of the exception types</h4>
<div class="outline-text-4" id="text-5-4-3">
<p>
In the section on throw-specifications above it noted that the order of types listed in the throw
specification was not significant, and that the types in the throw-specification formed an
unordered set for the purposes of function-type-equivalence.
</p>

<p>
However, when querying the types in the throw-specification, we need to return the types in <i>some</i>
order, and so we need to specify what the constraints of that order are.
</p>

<p>
At the very least, the order of the types returned needs to be deterministic and consistent across
different queries of the same expression, across all translation-units. This is because code may
compute types that have different layouts or ABIs based on the order of the types produced by the
<code>declthrow</code> expression, and having the same computation produce the results in different orders
is a sure-fire way to introduce ODR-violations.
</p>

<p>
Any unique set of exception types queried via a <code>declthrow</code> expression or by deducing the types
listed in a static exception specification of a function signature needs to consistently yield
a list of types in that set in a canonical order.
</p>

<p>
There are a few other questions around the ordering of the exception types:
</p>
<ul class="org-ul">
<li>Should the order be a total ordering of all types?
i.e. if <code>E1</code> appears before <code>E2</code> in some <code>declthrow()</code> query, then <code>E1</code> appears before <code>E2</code> in <i>all</i> <code>declthrow()</code> queries
that return those two types.
<ul class="org-ul">
<li>This would effectively provide a built-in facility for sorting types in type-lists.</li>
<li>Note that [P2830R1] "Standardized Type Ordering" is also exploring the design space for sorting of types.
Should the order that types are returned in be consistent with the order produced by that facility?</li>
</ul></li>
<li>Should the order be specified by the standard? or should it be unspecified/implementation-defined?
<ul class="org-ul">
<li>It might be difficult to specify an ordering of all types in a portable way.</li>
<li>Doing so may improve portability/compatibility of code across compilers, however.</li>
<li>Standard library implementations do not necessarily define all types with portable canonical names.
e.g. some implementations place some <code>std::</code> library types inside inline ABI-version namespaces, which would give those
types different names to the same types defined in other standard library implementations, which would
negate some of the portability benefit.</li>
</ul></li>
<li><p>
Should the order of the exceptions from a <code>declthrow()</code> query be consistent with the order of exception
types deduced from the throw-specification of a function type?
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-comment-delimiter">// </span><span class="org-comment">Given the following.</span>
<span class="org-type">void</span> <span class="org-function-name">foo</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>, <span class="org-type">B</span>);

<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">T</span>&gt;
<span class="org-keyword">struct</span> <span class="org-type">throw_specifier</span>;

<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">Ret</span>, <span class="org-keyword">typename</span>... <span class="org-type">Args</span>, <span class="org-keyword">typename</span>... <span class="org-type">Es</span>&gt;
<span class="org-keyword">struct</span> <span class="org-type">throw_specifier</span>&lt;Ret(<span class="org-type">Args</span>...) <span class="org-keyword">throw</span>(<span class="org-type">Es</span>...)&gt; {
  <span class="org-keyword">using</span> ...types = Es;
};

<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span>... <span class="org-type">Ts</span>&gt;
<span class="org-keyword">struct</span> <span class="org-type">type_list</span> {};

<span class="org-comment-delimiter">// </span><span class="org-comment">Should the following static_assert be guaranteed to hold on all conforming implementations?</span>
static_assert(<span class="org-constant">std</span>::<span class="org-type">same_as</span>&lt;<span class="org-type">type_list</span>&lt;declthrow(<span class="org-type">foo</span>())...&gt;,
                           <span class="org-type">type_list</span>&lt;<span class="org-constant">throw_specifier</span>&lt;<span class="org-keyword">decltype</span>(foo)&gt;::<span class="org-type">types</span>...&gt;&gt;);
</pre>
</div></li>
<li>Should the <code>std::any_exception</code> type appear in a specific location within the types returned
by <code>declthrow()</code> if it is present? e.g. as the first or last type in the pack.
<ul class="org-ul">
<li><p>
This might make it easier/more compile-time efficient to write metafunctions that want to
detect whether there is a dynamic exception that may be thrown.
e.g.
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-comment-delimiter">// </span><span class="org-comment">If std::any_exception is always first type</span>
<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span>... <span class="org-type">Es</span>&gt;
<span class="org-type">concept</span> <span class="org-variable-name">DynamicException</span> = <span class="org-keyword">sizeof</span>...(Es) &gt; 0 &amp;&amp; <span class="org-constant">std</span>::<span class="org-type">same_as</span>&lt;<span class="org-constant">std</span>::any_exception, Es...[0]&gt;; <span class="org-comment-delimiter">// </span><span class="org-comment">P2662R2 pack indexing</span>

<span class="org-comment-delimiter">// </span><span class="org-comment">vs</span>

<span class="org-comment-delimiter">// </span><span class="org-comment">If std::any_exception could appear anywhere</span>
<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span>... <span class="org-type">Es</span>&gt;
<span class="org-type">concept</span> <span class="org-variable-name">DynamicException</span> = (<span class="org-constant">std</span>::<span class="org-type">same_as</span>&lt;<span class="org-constant">std</span>::any_exception, <span class="org-type">Es</span>&gt; || ...);
</pre>
</div></li>
<li>Doing so might be inconsistent with rules for sorting types, however, if we decide that
the type list produced by a <code>declthrow()</code> query must produce types in a sorted order
consistent with the sorting order described in P2830.</li>
</ul></li>
<li>Do exception types need to be complete when used in throw specifications and
subsequently queried via <code>declthrow()</code>?
<ul class="org-ul">
<li>This may be somewhat limiting - preventing use of</li>
<li>It would open the possibility of sorting types based on their ABI properties like size/trivial-copyability, etc.
e.g. so that all error-types that might be returned by register appear earlier in the list</li>
<li>The exception types need to be complete anyway when a function that might throw them is invoked, just like
the return-type needs to be complete.</li>
<li>The syntax proposed below for filtering exception types would need the exception types
to be complete so that it can determine whether they would match a given <code>catch</code> handler.</li>
</ul></li>
</ul>
</div>
</div>

<div id="outline-container-org5cdb143" class="outline-4">
<h4 id="org5cdb143"><span class="section-number-4">5.4.4.</span> Exception specifications of defaulted special member functions</h4>
<div class="outline-text-4" id="text-5-4-4">
<p>
See [dcl.fct.def.default].
</p>

<p>
The following functions may have defaulted definitions
</p>
<ul class="org-ul">
<li>special member functions
<ul class="org-ul">
<li>default ctor</li>
<li>move ctor</li>
<li>copy ctor</li>
<li>move assignment</li>
<li>copy assignment</li>
<li>destructor</li>
</ul></li>
<li>comparison operators
<ul class="org-ul">
<li>equality</li>
<li>three-way-comparison</li>
</ul></li>
</ul>

<p>
For defaulted functions:
</p>
<ul class="org-ul">
<li>implicitly defaulted functions have an implicit exception specification</li>
<li>explicitly defaulted functions which are defaulted on first declaration have an implicit exception specification
if they don't explicitly specify an exception specification.</li>
<li>explicitly defaulted functions which are defaulted on first declaration that have an explicit exception specification
use that explicit exception specification.</li>
</ul>

<p>
This paper proposes changing the implicit exception specifications of defaulted functions
to be equivalent to a throw-specification of <code>throw(auto)</code>.
</p>

<p>
This should have no semantic effect on existing types / existing programs as
all existing types will have either a <code>noexcept(true)</code> or <code>noexcept(false)</code>
member function and thus the deduced exception specification will either
deduce to <code>noexcept(false)</code> or <code>noexcept(true)</code>. The rules for deduction of
the exception specification via <code>throw(auto)</code> are consistent with the pre-existing
rules of deduction for defaulted member functions.
</p>

<p>
However, it would ideally have an effect on types that compose new types that
are defined with static exception specifications for these special
member functions.
</p>

<p>
For example: Defining a struct that composes two types with static exception
specifications on their special member functions.
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">struct</span> <span class="org-type">A</span> {
  <span class="org-function-name">A</span>() <span class="org-keyword">throw</span>(<span class="org-constant">std</span>::<span class="org-type">bad_alloc</span>);
  <span class="org-function-name">A</span>(<span class="org-keyword">const</span> <span class="org-type">A</span>&amp;) <span class="org-keyword">throw</span>(<span class="org-constant">std</span>::<span class="org-type">bad_alloc</span>);
  <span class="org-function-name">A</span>(<span class="org-type">A</span>&amp;&amp;) <span class="org-keyword">throw</span>();
  ~<span class="org-function-name">A</span>();
};

<span class="org-keyword">struct</span> <span class="org-type">B</span> {
  <span class="org-function-name">B</span>() <span class="org-keyword">throw</span>(<span class="org-constant">std</span>::<span class="org-type">system_error</span>);
  <span class="org-function-name">B</span>(<span class="org-keyword">const</span> <span class="org-type">B</span>&amp;) <span class="org-keyword">throw</span>(<span class="org-constant">std</span>::<span class="org-type">system_error</span>);
  <span class="org-function-name">B</span>(<span class="org-type">B</span>&amp;&amp;) <span class="org-keyword">throw</span>();
  ~<span class="org-function-name">B</span>();
};

<span class="org-keyword">struct</span> <span class="org-type">C</span> {
  <span class="org-type">A</span> <span class="org-variable-name">a</span>;
  <span class="org-type">B</span> <span class="org-variable-name">b</span>;

  <span class="org-comment-delimiter">// </span><span class="org-comment">C has implicitly defaulted special member functions.</span>
};

<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span>... <span class="org-type">Ts</span>&gt;
<span class="org-keyword">struct</span> <span class="org-type">type_list</span>;

<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">Func</span>&gt;
<span class="org-keyword">struct</span> <span class="org-type">throw_specification</span>;

<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">Ret</span>, <span class="org-keyword">typename</span>... <span class="org-type">Args</span>, <span class="org-keyword">typename</span>... <span class="org-type">Es</span>&gt;
<span class="org-keyword">struct</span> <span class="org-type">throw_specification</span>&lt;Ret(<span class="org-type">Args</span>...) <span class="org-keyword">throw</span>(<span class="org-type">Es</span>...)&gt; {
  <span class="org-keyword">using</span> <span class="org-type">types</span> = <span class="org-type">type_list</span>&lt;<span class="org-type">Es</span>...&gt;;
};

<span class="org-comment-delimiter">// </span><span class="org-comment">Sorts the list of types in the canonical order for a throw-specification</span>
<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span>... <span class="org-type">Ts</span>&gt;
<span class="org-keyword">using</span> <span class="org-type">throw_specification_t</span> = <span class="org-keyword">typename</span> <span class="org-constant">throw_specification</span>&lt;<span class="org-type">void</span>() <span class="org-keyword">throw</span>(<span class="org-type">Ts</span>...)&gt;::types;

<span class="org-comment-delimiter">// </span><span class="org-comment">The following static_asserts will always pass for conforming implementations.</span>

static_assert(<span class="org-constant">std</span>::<span class="org-type">same_as</span>&lt;<span class="org-type">throw_specification_t</span>&lt;declthrow(C{})...&gt;,
                           <span class="org-type">throw_specification_t</span>&lt;<span class="org-constant">std</span>::bad_alloc, <span class="org-constant">std</span>::system_error&gt;&gt;);
static_assert(<span class="org-constant">std</span>::<span class="org-type">same_as</span>&lt;<span class="org-type">throw_specification_t</span>&lt;declthrow(C{<span class="org-constant">std</span>::declval&lt;<span class="org-keyword">const</span> <span class="org-type">C</span>&amp;&gt;()})...&gt;,
                           <span class="org-type">throw_specification_t</span>&lt;<span class="org-constant">std</span>::bad_alloc, <span class="org-constant">std</span>::system_error&gt;&gt;);
static_assert(<span class="org-constant">std</span>::<span class="org-type">is_nothrow_move_constructible_v</span>&lt;<span class="org-type">C</span>&gt;);
</pre>
</div>

<p>
It would also be ideal if the same approach could be applied to special member
functions of certain standard library types.
</p>

<p>
For example: Constructing a <code>std::tuple</code> of types with default-constructors with
static exception specifications would ideally result in the <code>std::tuple</code> type
having a static exception specification.
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-comment-delimiter">// </span><span class="org-comment">Ideally the following would hold true for all implementations.</span>
<span class="org-comment-delimiter">// </span><span class="org-comment">i.e. the throw-specification of the default constructor of std::tuple is the union</span>
<span class="org-comment-delimiter">// </span><span class="org-comment">of the throw-specifications for all of the tuple member default constructors.</span>
static_assert(<span class="org-constant">std</span>::<span class="org-type">same_as</span>&lt;<span class="org-type">throw_specification_t</span>&lt;declthrow(<span class="org-constant">std</span>::<span class="org-type">tuple</span>&lt;A, B&gt;{})...&gt;,
                           <span class="org-type">throw_specification_t</span>&lt;<span class="org-constant">std</span>::bad_alloc, <span class="org-constant">std</span>::system_error&gt;&gt;);
</pre>
</div>

<p>
It's worth noting that, as currently specified, the default constructor of <code>std::pair</code> or
<code>std::tuple</code> is not required to be declared <code>noexcept</code> if all of its member default constructors are
declared <code>noexcept</code>, so making this work would require a change to the exception-specification of
the default constructors.
</p>

<p>
The copy/move constructors are, however, declared as either implicitly or explicitly defaulted,
which therefore implies that the exception specification for these functions is deduced from the
exception specifications of the members.
</p>

<p>
A more in-depth analysis of standard library types is required to determine where this kind
of defaulted exception specifications can be applied.
</p>
</div>
</div>

<div id="outline-container-orgd0abf53" class="outline-4">
<h4 id="orgd0abf53"><span class="section-number-4">5.4.5.</span> Introducing a pack outside of a template</h4>
<div class="outline-text-4" id="text-5-4-5">
<p>
The introduction of a <code>declthrow(expr)</code> syntax that can introduce a pack of types at an arbitrary
point within the program.
</p>

<p>
It may be problematic for some compilers to support arbitrary use of anonymous packs outside
of templates.
</p>

<p>
If this is a restriction we want to maintain in the language, then it's possible we can
restrict, for now, the <code>declthrow(expr)</code> syntax to having to be immediately expanded in-place
to the list of types. i.e. <code>declthrow(expr)</code> must be immediately followed by a <code>...</code> to
expand the pack.
</p>

<p>
While this would be somewhat restrictive, it would still allow some basic common usage
within <code>throw()</code> specifiers, and can be used to expand into the template arguments of
variadic class templates, or concepts.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span>... <span class="org-type">Ts</span>&gt; <span class="org-keyword">class</span> <span class="org-type">type_list</span> {};

<span class="org-comment-delimiter">// </span><span class="org-comment">Can pass the result as template arguments to a class-template.</span>
<span class="org-keyword">using</span> <span class="org-type">error_types</span> = <span class="org-type">type_list</span>&lt;declthrow(foo(a,b,c))...&gt;;

<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">T</span>, <span class="org-keyword">typename</span>... <span class="org-type">Ts</span>&gt;
<span class="org-type">concept</span> <span class="org-variable-name">one_of</span> = (<span class="org-constant">std</span>::<span class="org-type">same_as</span>&lt;<span class="org-type">T</span>, <span class="org-type">Ts</span>&gt; || ...);

<span class="org-comment-delimiter">// </span><span class="org-comment">Can pass the result as template-arguments to a concept.</span>
<span class="org-keyword">constexpr</span> <span class="org-type">bool</span> <span class="org-variable-name">throws_bad_alloc</span> =
   <span class="org-type">one_of</span>&lt;<span class="org-constant">std</span>::bad_alloc, declthrow(foo(a,b,c))...&gt;;

<span class="org-comment-delimiter">// </span><span class="org-comment">Can use it to compute the type of a variant that can hold all</span>
<span class="org-comment-delimiter">// </span><span class="org-comment">possible exception types that might be thrown.</span>
<span class="org-constant">std</span>::<span class="org-type">variant</span>&lt;<span class="org-constant">std</span>::monostate, declthrow(foo(a,b,c))...&gt; <span class="org-variable-name">error</span>;
<span class="org-keyword">try</span> {
    foo(a,b,c);
} <span class="org-keyword">template</span> <span class="org-keyword">catch</span> (<span class="org-keyword">auto</span> <span class="org-variable-name">e</span>) {
  error.<span class="org-keyword">template</span> emplace&lt;<span class="org-keyword">decltype</span>(e)&gt;(<span class="org-constant">std</span>::move(e));
}

<span class="org-comment-delimiter">// </span><span class="org-comment">Can use it in the throw-specification of a function that wants to transparently</span>
<span class="org-comment-delimiter">// </span><span class="org-comment">throw whatever exceptions foo() throws, plus errors that it throws itself.</span>
<span class="org-type">void</span> <span class="org-function-name">example</span>(<span class="org-type">int</span> <span class="org-variable-name">a</span>, <span class="org-type">int</span> <span class="org-variable-name">b</span>, <span class="org-type">int</span> <span class="org-variable-name">c</span>) <span class="org-keyword">throw</span>(<span class="org-constant">std</span>::<span class="org-type">system_error</span>, <span class="org-type">declthrow</span>(<span class="org-type">foo</span>(<span class="org-type">a</span>,<span class="org-type">b</span>,<span class="org-type">c</span>))...);
</pre>
</div>

<p>
However, it wouldn't be able to support things like the following:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">foo</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>, <span class="org-type">B</span>);

<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">Nested</span>&gt;
<span class="org-keyword">struct</span> <span class="org-type">BarError</span> {
  <span class="org-type">Nested</span> <span class="org-variable-name">nested</span>;
};

<span class="org-type">void</span> <span class="org-function-name">bar</span>(<span class="org-type">int</span> <span class="org-variable-name">count</span>) <span class="org-keyword">throw</span>(<span class="org-type">BarError</span>&lt;declthrow(<span class="org-type">foo</span>())&gt;...) {
  <span class="org-keyword">try</span> {
    <span class="org-keyword">for</span> (<span class="org-type">int</span> <span class="org-variable-name">i</span> = 0; i &lt; count; ++i) {
      <span class="org-variable-name">foo</span>();
    }
  } <span class="org-keyword">template</span> <span class="org-keyword">catch</span>(<span class="org-keyword">auto</span> <span class="org-variable-name">e</span>) {
    <span class="org-keyword">throw</span> <span class="org-type">BarError</span>&lt;<span class="org-keyword">decltype</span>(e)&gt;{<span class="org-constant">std</span>::move(e)};
  }
}

</pre>
</div>

<p>
As that requires using the pack in way that is not immediately expanding the pack.
</p>

<p>
Further, if we do not have the ability to generate a pack in a non-template then we
will not be able to take a type-list computed by some meta-programming and then expand
that type-list into elements of the <code>throw()</code> specification.
</p>

<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span>... <span class="org-type">Ts</span>&gt;
<span class="org-keyword">struct</span> <span class="org-type">compute_new_exception_types</span> {
  <span class="org-keyword">using</span> <span class="org-type">type</span> = <span class="org-type">type_list</span>&lt; <span class="org-comment-delimiter">/* </span><span class="org-comment">template magic goes here</span><span class="org-comment-delimiter"> */</span>&gt;;
};

<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">T</span>&gt;
<span class="org-type">void</span> <span class="org-function-name">algorithm</span>(<span class="org-keyword">const</span> <span class="org-type">T</span>&amp; <span class="org-variable-name">obj</span>)
   <span class="org-keyword">throw</span>(<span class="org-keyword">typename</span> <span class="org-constant">compute_new_exception_types</span>&lt;
           declthrow((obj.foo(), obj.bar()))...&gt;::<span class="org-type">type</span> <span class="org-comment-delimiter">/* </span><span class="org-comment">how to expand this to a pack here?</span><span class="org-comment-delimiter"> */</span>);

</pre>
</div>

<p>
While additional workarounds could be added to the <code>throw()</code> specification to make this
work, I think doing this would needlessly complicate the design. I am hopeful that we
can instead make progress on improving general pack-manipulation facilites to make
some of these cases possible. See P1858R2, P2632R0.
</p>
</div>
</div>

<div id="outline-container-orgb1e1874" class="outline-4">
<h4 id="orgb1e1874"><span class="section-number-4">5.4.6.</span> Packs of <code>declthrow</code> packs</h4>
<div class="outline-text-4" id="text-5-4-6">
<p>
One common use-case of <code>declthrow</code> is to compute throw-specifications for other functions.
</p>

<p>
For example, say we have a user pass an invocable that we will call with elements of a span,
the <code>throw()</code> specification might be defined as follows:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">T</span>, <span class="org-keyword">typename</span> <span class="org-type">Func</span>&gt;
    <span class="org-type">requires</span> <span class="org-constant">std</span>::<span class="org-type">invocable</span>&lt;<span class="org-type">Func</span>&amp;, <span class="org-type">T</span>&amp;&gt;
<span class="org-type">void</span> for_each(<span class="org-constant">std</span>::<span class="org-type">span</span>&lt;<span class="org-type">T</span>&gt; <span class="org-variable-name">values</span>, <span class="org-type">Func</span>&amp;&amp; <span class="org-variable-name">func</span>) <span class="org-keyword">throw</span>(<span class="org-type">declthrow</span>(<span class="org-type">func</span>(<span class="org-constant">std</span>::declval&lt;<span class="org-type">T</span>&amp;&gt;()))...);
</pre>
</div>

<p>
However, if we were to, say, try to do something similar with a <code>std::tuple</code>, where the function
may be evaluated with multiple different argument types, each argument type represented by a
pack element, then the throw-specification effectively needs to become a concatenation of the
<code>declthrow</code> packs, one pack for each element of the tuple.
</p>

<p>
Ideally we'd be able to write something like the following:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span>... <span class="org-type">Ts</span>, <span class="org-keyword">typename</span> <span class="org-type">Func</span>&gt;
    <span class="org-function-name">requires</span> (<span class="org-constant">std</span>::<span class="org-type">invocable</span>&lt;<span class="org-type">Func</span>&amp;, <span class="org-type">Ts</span>&amp;&gt; &amp;&amp; ...)
<span class="org-type">void</span> <span class="org-function-name">for_each</span>(<span class="org-constant">std</span>::<span class="org-type">tuple</span>&lt;<span class="org-type">Ts</span>...&gt;&amp; <span class="org-variable-name">values</span>, <span class="org-type">Func</span>&amp;&amp; <span class="org-variable-name">func</span>) <span class="org-keyword">throw</span>(<span class="org-type">declthrow</span>(<span class="org-type">func</span>(<span class="org-constant">std</span>::declval&lt;<span class="org-type">Ts</span>&amp;&gt;()))... ...);
</pre>
</div>

<p>
However, there are known issues with expanding a pack of packs (see P2632R0 - section "Single level of packness").
</p>

<p>
As a workaround, we could instead write this with a single <code>declthrow</code> expression that
contains a compound expression using <code>operator,</code>.
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span>... <span class="org-type">Ts</span>, <span class="org-keyword">typename</span> <span class="org-type">Func</span>&gt;
    <span class="org-function-name">requires</span> (<span class="org-constant">std</span>::<span class="org-type">invocable</span>&lt;<span class="org-type">Func</span>&amp;, <span class="org-type">Ts</span>&amp;&gt; &amp;&amp; ...)
<span class="org-type">void</span> <span class="org-function-name">for_each</span>(<span class="org-constant">std</span>::<span class="org-type">tuple</span>&lt;<span class="org-type">Ts</span>...&gt;&amp; <span class="org-variable-name">values</span>, <span class="org-type">Func</span>&amp;&amp; <span class="org-variable-name">func</span>) <span class="org-keyword">throw</span>(<span class="org-type">declthrow</span>((<span class="org-type">func</span>(<span class="org-constant">std</span>::<span class="org-variable-name">declval</span>&lt;<span class="org-type">Ts</span>&amp;&gt;()), ...))...);
</pre>
</div>

<p>
This way the <code>Ts</code> pack is expanded inside the argument to <code>declthrow</code> and it is no longer problematic
expanding the <code>declthrow</code> expression.
</p>

<p>
The other alternative for function templates / inline functions that wish to be transparent in the set
of exceptions they may throw is to just use <code>throw(auto)</code> to deduce the throw-specification
from the body, rather than having to duplicate the relevant parts of the body in the <code>throw()</code>-specification.
</p>
</div>
</div>

<div id="outline-container-org1a7ad02" class="outline-4">
<h4 id="org1a7ad02"><span class="section-number-4">5.4.7.</span> Availability of the <code>declthrow</code> keyword</h4>
<div class="outline-text-4" id="text-5-4-7">
<p>
A search of GitHub public repositories yielded no direct matches for the identifier <code>declthrow</code>,
although it is worth noting that it did yield instances of a macro named <code>DECLTHROW(X)</code> which
was used to conditionally define throw-specifications if available in the target C++ language/compiler.
</p>

<p>
A search of <a href="https://codesearch.isocpp.org/">https://codesearch.isocpp.org/</a> yielded no matches for <code>declthrow</code>.
</p>
</div>
</div>

<div id="outline-container-orgc815b1b" class="outline-4">
<h4 id="orgc815b1b"><span class="section-number-4">5.4.8.</span> Alternative Syntaxes Considered</h4>
<div class="outline-text-4" id="text-5-4-8">
<p>
Another alternative syntax considered was the reuse of the <code>throw</code> keyword in a
<code>throw...(expr)</code> that would expand to the pack of types that could potentially be
thrown by that expression.
</p>

<p>
However, this syntax would have a potential inconsistency with <code>sizeof...(pack)</code>
which takes an unexpanded pack and returns a single value. Whereas <code>throw...(expr)</code>
needs to take a single expression and produce a pack.
</p>

<p>
The <code>throw...(expr)</code> syntax may also be more easily confused with <code>throw (expr)</code> which
throws an exception instead of querying what exception types it might throw.
</p>

<p>
The <code>declthrow</code> keyword also has the benefit of association/similarity with <code>decltype</code> which is
used to query the value-type of an expression.
</p>
</div>
</div>

<div id="outline-container-orgf80ea67" class="outline-4">
<h4 id="orgf80ea67"><span class="section-number-4">5.4.9.</span> Filtering the set of exceptions</h4>
<div class="outline-text-4" id="text-5-4-9">
<p>
Sometimes we want to build a throw-specification that indicates that we throw any exception
that some other expression throws, but that we handle some number of errors within the function
and so we want to exclude those from the list. This way if the exception-specification of the
other expression changes, then the expression-specification of our function changes to
include the new set of exceptions.
</p>

<p>
While this could, in theory, be done with some template metaprogramming on packs, which would
become possible with the introduction of more pack-manipulation facilites described in P2632R0,
the resulting code is still onerous, and compile-time expensive compared to not filtering
the exceptions.
</p>

<p>
For example: Using <code>throw(auto)</code> and P3115R0 generalized pack facilities, we can define a helper <code>filter_exceptions</code>
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">ErrorType</span>&gt;
[[noreturn]] <span class="org-function-name">_throws</span>() <span class="org-keyword">throw</span>(<span class="org-type">ErrorType</span>);

<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">HandledType</span>, <span class="org-keyword">typename</span> <span class="org-type">ErrorType</span>&gt;
<span class="org-type">void</span> <span class="org-function-name">_handle</span>() <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) {
  <span class="org-keyword">if</span> <span class="org-keyword">constexpr</span> (<span class="org-keyword">not</span> <span class="org-constant">std</span>::<span class="org-type">same_as</span>&lt;<span class="org-type">HandledType</span>, <span class="org-constant">std</span>::any_exception&gt;) {
    <span class="org-keyword">try</span> { _throws&lt;<span class="org-type">ErrorType</span>&gt;(); } <span class="org-keyword">catch</span>(HandledType) {}
  }
}

<span class="org-comment-delimiter">// </span><span class="org-comment">P3115R0 pack alias syntax</span>
<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">HandledType</span>, <span class="org-keyword">typename</span>... <span class="org-type">Errors</span>&gt;
<span class="org-keyword">using</span> ...filter_exceptions = declthrow((_handle&lt;HandledType, Errors&gt;(), ...));
</pre>
</div>

<p>
Which could then be used as follows:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">example</span>() <span class="org-keyword">throw</span>(<span class="org-type">filter_exceptions</span>&lt;CaughtException, declthrow(some_expression)...&gt;...);
</pre>
</div>

<p>
One alternative would be to add a syntax that allowed the programmer to describe the intent
to filter the exception list directly in the language.
</p>

<p>
A strawman syntax for this could be to allow additional arguments to <code>declthrow()</code> to list types
to exclude from the list of types. i.e. <code>declthrow(expr, filter-clauses...)</code>
</p>

<p>
For example: We could add additional <code>catch(type)</code> arguments after the first argument to <code>declthrow()</code>
to list exception types from the expression that are caught and thus should be removed from the list.
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-comment-delimiter">// </span><span class="org-comment">Given.</span>
<span class="org-keyword">struct</span> <span class="org-type">A</span> : <span class="org-constant">std</span>::<span class="org-type">exception</span> {};
<span class="org-keyword">struct</span> <span class="org-type">FooError</span> : <span class="org-constant">std</span>::<span class="org-type">exception</span> {};
<span class="org-keyword">struct</span> <span class="org-type">B</span> : <span class="org-type">FooError</span> {};
<span class="org-keyword">struct</span> <span class="org-type">C</span> : <span class="org-type">FooError</span> {};

<span class="org-type">void</span> <span class="org-function-name">foo</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>, <span class="org-type">B</span>, <span class="org-type">C</span>);

<span class="org-type">void</span> <span class="org-function-name">example1</span>() <span class="org-keyword">throw</span>(<span class="org-type">declthrow</span>(<span class="org-type">foo</span>())...);                        <span class="org-comment-delimiter">// </span><span class="org-comment">-&gt; throw(A, B, C)</span>
<span class="org-type">void</span> <span class="org-function-name">example2</span>() <span class="org-keyword">throw</span>(<span class="org-type">declthrow</span>(<span class="org-type">foo</span>(), <span class="org-keyword">catch</span>(<span class="org-type">A</span>))...);              <span class="org-comment-delimiter">// </span><span class="org-comment">-&gt; throw(B, C)</span>
<span class="org-type">void</span> <span class="org-function-name">example3</span>() <span class="org-keyword">throw</span>(<span class="org-type">declthrow</span>(<span class="org-type">foo</span>(), <span class="org-keyword">catch</span>(<span class="org-type">A</span>), <span class="org-keyword">catch</span>(<span class="org-type">B</span>))...);    <span class="org-comment-delimiter">// </span><span class="org-comment">-&gt; throw(C)</span>
<span class="org-type">void</span> <span class="org-function-name">example4</span>() <span class="org-keyword">throw</span>(<span class="org-type">declthrow</span>(<span class="org-type">foo</span>(), <span class="org-keyword">catch</span>(<span class="org-type">FooError</span>))...);       <span class="org-comment-delimiter">// </span><span class="org-comment">-&gt; throw(A)</span>
<span class="org-type">void</span> <span class="org-function-name">example5</span>() <span class="org-keyword">throw</span>(<span class="org-type">declthrow</span>(<span class="org-type">foo</span>(), <span class="org-keyword">catch</span>(<span class="org-constant">std</span>::<span class="org-type">exception</span>))...); <span class="org-comment-delimiter">// </span><span class="org-comment">-&gt; throw()</span>
</pre>
</div>

<p>
Note that listing the <code>catch(FooError)</code> base class removes both derived types from the list.
</p>

<p>
Despite the potential syntactic and compile-time benefits that might arise from adding such a syntax,
it's not clear whether the added complexity is worthwhile at this point. Usage experience is needed
to better understand how often such a feature would be needed.
</p>

<p>
For a lot of these cases, it is expected that the <code>throw(auto)</code> syntax will serve most of the
needs in this direction, and assuming that more generalised pack facilities become available,
users that really need to do such filtering would still be able to do this in library.
</p>

<p>
If we can specify the syntax of <code>declthrow</code> such that it reserves the ability to be extended
in some way such that this capability could be added later, then we can take a wait-and-see
approach.
</p>
</div>
</div>
</div>

<div id="outline-container-orge0276a5" class="outline-3">
<h3 id="orge0276a5"><span class="section-number-3">5.5.</span> Checking the throw-specification of a function</h3>
<div class="outline-text-3" id="text-5-5">
<p>
A function declaration that includes a <i>static-exception-specification</i> must have a definition that
ensures that only exceptions of those types may exit the function.
</p>

<p>
To assist with this, the compiler looks at the body of the function to compute the set
of potentially-thrown exception types that may exit the body of the function.
</p>

<p>
If this set of possible exception types is not a subset of the set of exception types listed
in the exception-specification then the program is ill-formed.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">int</span> <span class="org-function-name">other</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>);

<span class="org-comment-delimiter">// </span><span class="org-comment">OK: set of potentially-thrown exceptions is {A, B}, all of which are</span>
<span class="org-comment-delimiter">// </span><span class="org-comment">listed in the function's throw-specification.</span>
<span class="org-type">void</span> <span class="org-function-name">example1</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>, <span class="org-type">B</span>) {
  <span class="org-type">int</span> <span class="org-variable-name">x</span> = other();
  <span class="org-keyword">if</span> (x &lt; 0) <span class="org-keyword">throw</span> B{};
}

<span class="org-comment-delimiter">// </span><span class="org-comment">Ill-formed: call to other() can potentially throw exception A</span>
<span class="org-comment-delimiter">// </span><span class="org-comment">which is not listed in example2()'s throw-specification.</span>
<span class="org-type">void</span> <span class="org-function-name">example2</span>() <span class="org-keyword">throw</span>(<span class="org-type">B</span>) {
  <span class="org-type">int</span> <span class="org-variable-name">x</span> = other();
  <span class="org-keyword">if</span> (x &lt; 0) <span class="org-keyword">throw</span> B{};
}
</pre>
</div>

<p>
Note that for functions with a throw-specifier of <code>throw(auto)</code> the check
always passes as the compiler computes the exception-specification to be exactly the
set of potentially-thrown exception types and thus every exception type is, by-definition,
listed in the exception-specification.
</p>

<p>
For functions with a throw-specifier of <code>throw(...)</code> or <code>noexcept(false)</code>, the
function is permitted to throw an exception of any type and so this check is not
required to be performed.
</p>
</div>
</div>

<div id="outline-container-org8907dc8" class="outline-3">
<h3 id="org8907dc8"><span class="section-number-3">5.6.</span> Computing the set of potentially-thrown exception types</h3>
<div class="outline-text-3" id="text-5-6">
<p>
The ability to check the throw-specifier of a function, compute the results of a <code>declthrow</code>
query, instantiate a template-handler with the appropriate types, or deduce the set of exception
types that may be thrown from a function with a <code>throw(auto)</code> throw-specification all depend on
the ability to compute the set of potentially-thrown exception types for expressions and statements.
</p>

<p>
When computing the set of exception types that might exit an expression, statement or function,
we ideally want a set of rules that can be reliably evaluated in a consistent way across all
conforming implementations, and that is not dependent on inlining, or compiler optimisations.
This is because the computation can be important for correctness and well-formedness of a program,
and can also affect the ABI of functions with deduced throw specifications.
</p>

<p>
Computing the set of potentially thrown exception types, therefore, needs to be computable locally
for each function, from looking only at the function body and the signatures of any functions
called from that function, since we cannot assume that the definitions of called functions will
be available.
</p>

<p>
The following sections describe such a set of rules for computing the
<i>set of potentially-thrown exception types</i> for each grammar term that
may appear within a <i>function-body</i>.
</p>

<p>
The descriptions here are not as precise as they would need to be for wording, but are hopefully
descriptive enough to understand the proposed semantics.
</p>
</div>

<div id="outline-container-org65cc23d" class="outline-4">
<h4 id="org65cc23d"><span class="section-number-4">5.6.1.</span> Statement Reachability</h4>
<div class="outline-text-4" id="text-5-6-1">
<p>
When computing the set of exceptions that may the thrown from some constructs, there are cases
where we need to determine whether execution can potentially flow off the end of a <i>compound-statement</i>
as these can affect the set of exceptions that can potentially be thrown.
</p>

<p>
For example:
</p>
<ul class="org-ul">
<li>If execution flows off the end of a coroutine, it implicitly evaluates <code>co_return;</code>.
This calls <code>promise.return_void()</code> which may be potentially-throwing.</li>
<li>If execution flows off the end of a handler of a <i>function-try-block</i> for a constructor
or destructor then the exception is implicitly rethrown as if there was a <code>throw;</code>
statement inserted at the end of the handler's <i>compound-statement</i>.</li>
</ul>

<p>
Therefore, we need to first define some rules around defining the reachability of certain
statements. These rules will need to be somewhat conservative as computing an accurate
sense of reachability is equivalent to solving the halting problem, and thus intractable.
</p>

<p>
The rules below use the terminology <i>potentially reachable statement</i> to
indicate that the computation is conservative.
</p>

<p>
A <i>compound-statement</i> evaluates a sequence of <i>statements</i>. There are some statements/expressions
for which it is never possible to execute the next statement, however, as they unconditionally
divert control-flow elsewhere.
</p>
</div>

<ol class="org-ol">
<li><a id="org3808b07"></a>Interrupted-flow statements<br />
<div class="outline-text-5" id="text-5-6-1-1">
<p>
An <i>interrupted-flow statement</i> is a statement for which execution cannot flow to the next statement
from this statement.
</p>

<p>
The following statements are <i>interrupted-flow statements</i>:
</p>
<ul class="org-ul">
<li>A <i>jump-statement</i> - i.e. <code>break;</code>, <code>continue;</code>,  <code>goto;</code>,  <code>return expr-or-braced-init-list[opt];</code> or <i>coroutine-return-statement</i>.</li>
<li>A <i>compound-statement</i> where execution cannot flow off the end of the block (see below)</li>
<li>An if or if-else <i>selection-statement</i> where either;
<ul class="org-ul">
<li>the <i>init-statement</i>, if any, is an <i>interrupted-flow statement</i>; or</li>
<li>the <i>condition</i> is an <i>interrupted-flow expression</i>.</li>
</ul></li>
<li>An if-else <i>selection-statement</i> where the first and second sub-statements are both <i>interrupted-flow statements</i>.
Note: this includes <code>if consteval</code> selection-statements.</li>
<li>A constexpr if or if-else <i>selection-statement</i> where the condition evaluated to true and the first sub-statement is an <i>interrupted-flow statement</i>.</li>
<li>A constexpr if-else <i>selection-statement</i> where the condition evaluated to false and the second sub-statement is an <i>interupted-flow statement</i>.</li>
<li>A <i>try-block</i> where the <i>compound-statement</i> is an <i>interrupted-flow statement</i> and the <i>compound-statement</i> of every
reachable handler (see section on <i>try-block</i> below) of the <i>try-block</i>'s <i>handler-seq</i> is an <i>interrupted-flow statement</i>.</li>
<li>A switch <i>selection-statement</i> where either;
<ul class="org-ul">
<li>the <i>init-statement</i>, if any, is an <i>interrupted-flow statement</i>; or</li>
<li>the <i>condition</i> is an <i>interrupted-flow expression</i>; or</li>
<li>all of the following are true;
<ul class="org-ul">
<li>the body <i>statement</i> is an <i>interrupted-flow statement</i>; and</li>
<li>the body <i>statement</i> has a <code>default:</code> label associated with the switch; and</li>
<li>there is no potentially-reachable <code>break;</code> statement associated with the switch.</li>
</ul></li>
</ul></li>
<li>A do-while <i>iteration-statement</i> where both the following are true;
<ul class="org-ul">
<li>the loop body <i>statement</i> does not enclose any potentially-reachable <code>break;</code> statements associated with the loop; and</li>
<li>either;
<ul class="org-ul">
<li>both of the following are true;
<ul class="org-ul">
<li>the loop body statement does not enclose any potentially-reachable <code>continue;</code> statements associated with the loop; and</li>
<li>the loop body <i>statement</i> is an <i>interrupted-flow statement</i>; or</li>
</ul></li>
<li>the loop <i>expression</i> is an <i>interrupted-flow expression</i></li>
</ul></li>
</ul></li>
<li>A for or while <i>iteration-statement</i> where either;
<ul class="org-ul">
<li>the <i>init-statement</i>, if present, is an <i>interrupted-flow-statement</i>; or</li>
<li>the <i>condition</i> expression is an <i>interrupted-flow expression</i>;</li>
</ul></li>
<li>A range-based for <i>iteration-statement</i> where either;
<ul class="org-ul">
<li>the <i>init-statement</i> is an <i>interrupted-flow statement</i>; or</li>
<li>the <i>for-range-initializer</i> expression is an <i>interrupted-flow expression</i>; or</li>
<li>the <i>begin-expr</i> is an <i>interrupted-flow expression</i>; or</li>
<li>the <i>end-expr</i> is an <i>interrupted-flow expression</i>.</li>
</ul></li>
<li>An expression-statement where the expression is an <i>interrupted-flow expression</i>.</li>
<li>A declaration-statement that is an object declaration where the initializer expression is an <i>interrupted-flow expression</i>.</li>
</ul>
</div>
</li>

<li><a id="orgcc6ea41"></a>Interrupted-flow expressions<br />
<div class="outline-text-5" id="text-5-6-1-2">
<p>
An <i>interrupted-flow-expression</i> is a potentially evaluated expression that is one of the following:
</p>
<ul class="org-ul">
<li>A <i>throw-expression</i></li>
<li>A <i>postfix-expression</i> that evaluates a call to a function marked <code>[[noreturn]]</code>.</li>
<li>A <i>conditional-expression</i> (ternary <code>?:</code> operator) where either;
<ul class="org-ul">
<li>the first sub-expression is an <i>interrupted-flow-expression</i>; or</li>
<li>the second and third sub-expressions are both <i>interrupted-flow-expressions</i>.</li>
</ul></li>
<li>A built-in logical AND or logical OR expression where the first sub-expression is an <i>interrupted-flow expression</i>.</li>
<li>A prvalue expression of class type whose destructor is marked <code>[[noreturn]]</code>.</li>
<li>Any other compound expression that has an immediate sub-expression that is an <i>interrupted-flow-expression</i>.</li>
</ul>
</div>
</li>

<li><a id="org38990f7"></a>Potentially-reachable statements<br />
<div class="outline-text-5" id="text-5-6-1-3">
<p>
A <i>potentially-reachable statement</i> is a statement of a function that the compiler determines
can potentially be executed based on a local analysis of the control-flow of the function.
It does not consider the values of any expressions which are semantically computed at runtime.
</p>
</div>

<ol class="org-ol">
<li><a id="orge58e0a2"></a>Reachability of compound-statements<br />
<div class="outline-text-6" id="text-5-6-1-3-1">
<p>
A sub-statement of a <i>compound-statement</i> is a <i>potentially-reachable statement</i> if:
</p>
<ul class="org-ul">
<li>it is the first sub-statement of the <i>compound-statement</i> and the <i>compound-statement</i> is reachable; or</li>
<li>the immediately preceding statement is a <i>potentially-reachable statement</i> and was not an <i>interrupted-flow-statement</i>; or</li>
<li>the statement was immediately preceded by a label
(Note: this does not include the implicit labels mentioned in the definition of a <code>while</code> statement)</li>
</ul>
<p>
Otherwise a sub-statement of a <i>compound-statement</i> is considered an <i>unreachable-statement</i>.
</p>

<p>
A <i>compound-statement</i> that is the top-level <i>compound-statement</i> of a function body or lambda body is a <i>potentially reachable statement</i>.
</p>
</div>
</li>

<li><a id="orgbf8d91b"></a>Reachability of components of an if-statement<br />
<div class="outline-text-6" id="text-5-6-1-3-2">
<p>
In an if-statement of the form <code>if ( /condition/ ) /statement/</code> or <code>if ( /init-statement/ /condition/ ) /statement/</code> with or without the <code>else /statement/</code> then;
</p>
<ul class="org-ul">
<li>The <i>init-statement</i>, if present, is a potentially-reachable statement if the if-statement is a potentially-reachable statement.</li>
<li>The <i>condition</i> expression is a potentially reachable statement if;
<ul class="org-ul">
<li>The if-statement is potentially reachable; and</li>
<li>The <i>init-statement</i> is either not present, or if present, is not an <i>interrupted-flow statement</i>.</li>
</ul></li>
<li>The first and second (if present) <i>statement</i> is a potentially reachable statement if the <i>condition</i> expression
is a potentially-reachable expression and the <i>condition</i> expression is not an <i>interrupted-flow expression</i>.</li>
</ul>

<p>
In a constexpr if statement;
</p>
<ul class="org-ul">
<li>the first substatement is potentially reachable if and only if the if-statement is potentially reachable and the <i>condition</i> evaluates to <code>true</code>;</li>
<li>the second substatement, if present, is potentially reachable if and only if the if-statement is potentially reachable and the <i>condition</i>
evaluates to <code>false</code>.</li>
</ul>
</div>
</li>

<li><a id="org701f4b2"></a>Reachability of components of a switch statement<br />
<div class="outline-text-6" id="text-5-6-1-3-3">
<p>
In a switch-statement of the form <code>switch ( /condition/ ) /statement/</code>:
</p>
<ul class="org-ul">
<li>the <i>condition</i> expression is potentially reachable if the switch-statement is potentially reachable</li>
</ul>

<p>
And, in a switch-statement of the form <code>switch ( /init-statement/ /condition/ ) /statement/</code>:
</p>
<ul class="org-ul">
<li>the <i>init-statement</i> is potentially reachable if the switch-statement is potentially reachable</li>
<li>the <i>condition</i> expression is potentially reachable if the switch-statement is potentially reachable;
and the <i>init-statement</i> was not an interrupted-flow statement.</li>
</ul>

<p>
In both cases, the <i>statement</i> is not potentially-reachable.
Execution can only enter <i>statement</i> via a jump to a label enclosed by <i>statement</i>.
</p>

<p>
Any <code>case</code> and <code>default</code> labels associated with the switch statement are potentially
reachable if and only if the <i>condition</i> expression is potentially reachable and is
not an <i>interrupted-flow expression</i>.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">f</span>(<span class="org-type">int</span> <span class="org-variable-name">x</span>) {
  <span class="org-keyword">switch</span> (x) {
    a; <span class="org-comment-delimiter">// </span><span class="org-comment">not-reachable</span>
  <span class="org-keyword">case</span> 0:
    b; <span class="org-comment-delimiter">// </span><span class="org-comment">reachable - appears after a label</span>
    <span class="org-keyword">break</span>;
    c; <span class="org-comment-delimiter">// </span><span class="org-comment">not reachable - appears after a jump-statement</span>
  <span class="org-keyword">default</span>:
    d; <span class="org-comment-delimiter">// </span><span class="org-comment">reachable - appears after a label</span>
  }
}
</pre>
</div>
</div>
</li>

<li><a id="org310d296"></a>Reachability of components of an iteration-statement<br />
<div class="outline-text-6" id="text-5-6-1-3-4">
<p>
In an iteration-statement of the form <code>while ( /condition/ ) /statement/</code>
</p>
<ul class="org-ul">
<li>The <i>condition</i> is a potentially reachable expression if the while-statement is a potentially reachable statement</li>
<li>The <i>statement</i> is a potentially reachable statement if the <i>condition</i> expression is potentially
reachable and the <i>condition</i> expression is not a <i>flow-interrupted expression</i>.</li>
</ul>

<p>
In an iteration-statement of the form <code>do /statement/ while ( /expression/ ) ;</code>
</p>
<ul class="org-ul">
<li>The <i>statement</i> is potentially reachable statement if the do-statement is potentially reachable</li>
<li>The <i>expression</i> is a potentially reachable expression if do-statement is potentially reachable
and either;
<ul class="org-ul">
<li>the <i>statement</i> is not a <i>flow-interrupted statement</i>; or</li>
<li>the <i>statement</i> encloses a potentially reachable <code>continue;</code> statement associated with the do-statement</li>
</ul></li>
</ul>

<p>
In an iteration-statement of the form <code>for ( /init-statement/ /condition/ ; /expression/ ) /statement/</code>
</p>
<ul class="org-ul">
<li>The <i>init-statement</i> is potentially-reachable if the for-statement is potentially-reachable</li>
<li>The <i>condition</i> expression (if present) is potentially-reachable if the for-statement is potentially-reachable
and the <i>init-statement</i> is not an <i>interrupted-flow statement</i></li>
<li>The <i>statement</i> is a potentially-reachable statement if the <i>init-statement</i> is a potentially-reachable statement
and is not an <i>interrupted-flow statement</i> and either the <i>condition</i> expression is not present or the
<i>condition</i> expression is not an <i>interrupted-flow expression</i>.</li>
<li>The <i>expression</i> is a potentially-reachable expression if either;
<ul class="org-ul">
<li>The <i>statement</i> is a potentially-reachable statement and is not an <i>interrupted-flow statement</i>; or</li>
<li>There is a potentially-reachable <code>continue;</code> statement enclosed by <i>statement</i> that is associated with the for-loop.</li>
</ul></li>
</ul>
</div>
</li>

<li><a id="org9fd4339"></a>Reachability of identifier labels<br />
<div class="outline-text-6" id="text-5-6-1-3-5">
<p>
These rules treat all identifier labels as potentially-reachable and does not do any analysis to
determine whether there is any jump-statement that could potentially jump to that label.
</p>

<p>
For example, the rules could potentially require looking elsewhere in the function to determine whether there
are any <code>goto</code> statements that target a particular label.
</p>

<p>
However, requiring this prevents doing analysis of reachability in a single pass as you may need
to look later in the function in order find a <code>goto</code> statement that targets a label earlier in
the function.
</p>

<p>
For example: When the compiler reaches the <code>retry:</code> label it has not yet seen the <code>goto retry;</code>
statement and so does not yet know whether <code>retry:</code> label is reachable.
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">int</span> <span class="org-function-name">foo</span>(<span class="org-type">int</span> <span class="org-variable-name">x</span>) {
  {
    <span class="org-keyword">auto</span> <span class="org-variable-name">result</span> = try_fast(x);
    <span class="org-keyword">if</span> (<span class="org-negation-char">!</span>result) {
      <span class="org-keyword">goto</span> <span class="org-constant">slow</span>;
    }

    <span class="org-keyword">return</span> result.value();
  }

 <span class="org-constant">retry</span>:
  reset_slow();

 <span class="org-constant">slow</span>:
  <span class="org-keyword">auto</span> <span class="org-variable-name">result</span> = try_slow(x);
  <span class="org-keyword">if</span> (<span class="org-negation-char">!</span>result) {
    <span class="org-keyword">goto</span> <span class="org-constant">retry</span>;   <span class="org-comment-delimiter">// </span><span class="org-comment">only know that 'retry:' label is reachable after processing this statement</span>
  }

  <span class="org-keyword">return</span> result.value();
}
</pre>
</div>

<p>
An even more sophisticated approach could consider the potential
reachability of the <code>goto</code> statement targeting a label itself.
</p>

<p>
There may be cycles of reachability of <code>goto</code> statements which are not themselves reachable
from the function entry-point.
</p>

<p>
For example: In the following function there is a <code>goto</code> statement targeting each of the
labels in this function, but none of those <code>goto</code> statements are themselves reachable
from the function entry-point.
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">foo</span>(<span class="org-type">int</span> <span class="org-variable-name">x</span>) {
  <span class="org-keyword">if</span> <span class="org-keyword">constexpr</span> (<span class="org-constant">false</span>) {
    <span class="org-keyword">goto</span> <span class="org-constant">foo</span>;
  }

  <span class="org-keyword">return</span> x;

 <span class="org-constant">foo</span>:
  <span class="org-keyword">if</span> (x &lt; 0)
    <span class="org-keyword">throw</span> negative_error{};
  <span class="org-keyword">goto</span> <span class="org-constant">baz</span>;

 <span class="org-constant">bar</span>:
  --x;
  <span class="org-keyword">goto</span> <span class="org-constant">foo</span>;

 <span class="org-constant">baz</span>:
  <span class="org-keyword">goto</span> <span class="org-constant">bar</span>;
}
</pre>
</div>

<p>
It is not difficult to imagine such code occuring in practice in function templates where
there are <code>goto</code> statements in <code>if constexpr</code> branches that are either discarded or not
discarded, depending on the types the function template was instantiated with.
</p>

<p>
The rules could potentially be extended to consider a label as potentially reachable
only if there is a potentially reachable <code>goto</code> statement that targets the label.
</p>

<p>
Computing the reachability in this case would basically require the compiler to hold
the control-flow graph of the entire function in memory and then walk that graph,
marking statements as reachable or not.
This may be incompatible with the architecture of some compiler implementations.
</p>

<p>
The proposed design chooses a more conservative algorithm that treats all labels as reachable
in order to permit implementations that can compute a more conservative concept of
reachability in a single pass.
</p>

<p>
It is not clear whether or not handling such cases in a more accurate way would be
worth the additional complexity it would place on implementations.
</p>
</div>
</li>
</ol>
</li>

<li><a id="orgab75760"></a>Flowing off the end of a compound-statement<br />
<div class="outline-text-5" id="text-5-6-1-4">
<p>
Execution may flow off the end of a <i>compound-statement</i> if either;
</p>
<ul class="org-ul">
<li>the <i>compound-statement</i> is a <i>potentially-reachable statement</i> and has an empty sequence of sub-statements; or</li>
<li>both;
<ul class="org-ul">
<li>the last sub-statement of the <i>compound-statement</i> is potentially-reachable and is not an <i>interrupted-flow-statement</i>
(Note: This includes any null sub-statement implicitly inserted after a trailing label immediately before the closing brace);
and</li>
<li>There are no object declarations declared in the scope of the <i>compound-statement</i> that
have destructors that have the attribute <code>[[noreturn]]</code>.</li>
</ul></li>
</ul>
</div>
</li>

<li><a id="org9a71b34"></a>Flowing off the end of a switch statement<br />
<div class="outline-text-5" id="text-5-6-1-5">
<p>
The rules for determining that a switch statement is an <i>interrupted-flow statement</i> require
that the body of the switch statement has a <code>default:</code> label associated with the switch.
</p>

<p>
This approach is somewhat conservative, as it may be possible that all of the potential
cases are already covered by <code>case</code> labels and that, therefore, it is not possible for
the switch statement to jump over the statement body and flow onto the next statement.
</p>

<p>
For example: The rules above result in the following
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">example</span>(<span class="org-type">bool</span> <span class="org-variable-name">x</span>) {
  <span class="org-comment-delimiter">// </span><span class="org-comment">Not an interrupted-flow statement - no default: case</span>
  <span class="org-keyword">switch</span> (x) {
  <span class="org-keyword">case</span> <span class="org-constant">true</span>: <span class="org-keyword">throw</span> X{};
  <span class="org-keyword">case</span> <span class="org-constant">false</span>: <span class="org-keyword">throw</span> Y{};
  }
  <span class="org-comment-delimiter">// </span><span class="org-comment">The following statement is considered potentially-reachable.</span>

  <span class="org-comment-delimiter">// </span><span class="org-comment">An interrupted-flow statement - has a default: case</span>
  <span class="org-keyword">switch</span> (x) {
  <span class="org-keyword">case</span> <span class="org-constant">true</span>: <span class="org-keyword">throw</span> X{};
  <span class="org-keyword">default</span>: <span class="org-keyword">throw</span> Y{};
  }

  <span class="org-comment-delimiter">// </span><span class="org-comment">Not potentially-reachable.</span>
  <span class="org-comment-delimiter">// </span><span class="org-comment">Prior statement is an interrupted-flow statement.</span>
  <span class="org-comment-delimiter">// </span><span class="org-comment">Control cannot flow off the end of the function's compound-statement.</span>
}
</pre>
</div>

<p>
The rationale here is that trying to determine whether every possible value for the
switch expression is covered by a case label is non-trivial and/or probably doesn't
do what you want.
</p>

<p>
For example: Consider switching on an enum where all enum members have case labels.
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">enum</span> <span class="org-keyword">class</span> <span class="org-type">state_t</span> { <span class="org-variable-name">stopped</span> = 0, <span class="org-variable-name">starting</span> = 1, <span class="org-variable-name">running</span> = 2 };

<span class="org-type">int</span> <span class="org-function-name">example</span>(<span class="org-type">state_t</span> <span class="org-variable-name">state</span>) {
  <span class="org-keyword">switch</span> (state) {
  <span class="org-keyword">case</span> <span class="org-constant">state_t</span>::stopped: <span class="org-keyword">return</span> 0;
  <span class="org-keyword">case</span> <span class="org-constant">state_t</span>::starting: <span class="org-keyword">return</span> 1;
  <span class="org-keyword">case</span> <span class="org-constant">state_t</span>::running: <span class="org-keyword">return</span> 2;
  }

  foo(); <span class="org-comment-delimiter">// </span><span class="org-comment">should this statement be considered "potentially-reachable"?</span>
}

<span class="org-comment-delimiter">// </span><span class="org-comment">Consider the following call.</span>
example(<span class="org-keyword">static_cast</span>&lt;<span class="org-type">state_t</span>&gt;(3));
</pre>
</div>

<p>
If, instead, we just look for a <code>default:</code> label then we know that every
possible case is handled.
</p>

<p>
If we are willing to define rules for determining whether all possible cases are
listed as <code>case</code> labels then we could potentially relax the rule requiring the use
of a <code>default:</code> label here.
</p>
</div>
</li>

<li><a id="org2b745b7"></a>Use of <code>[[noreturn]]</code> for normative semantics<br />
<div class="outline-text-5" id="text-5-6-1-6">
<p>
The rules above treat calls to functions marked as <code>[[noreturn]]</code> as being interrupted-flow expressions
and the interpretation as such can potentially affect the computation of the set of potentially-thrown
exceptions, which in turn can affect the semantics and well-formedness of a program.
</p>

<p>
The use of an attribute in this way is novel and would no longer have optional semantics,
which would go against the intent of the following note in [dcl.attr.grammar] p6
</p>

<blockquote>
<p>
[Note : The attributes specified in \[dcl.attr] have optional semantics: given a well-formed program,
        removing all instances of any one of those attributes results in a program whose set of
        possible executions (\[intro.abstract]) for a given input is a subset of those of the original
        program for the same input, absent implementation-defined guarantees with respect to that attribute.
— end note]
</p>
</blockquote>

<p>
The statement reachability computation depends on the ability to determine whether a function can
return normally and flow to the next statement or not. For example, programs may insert calls to
<code>std::terminate()</code> or <code>std::unreachable()</code> before the end of a compound-statement to indicate that
control should not flow off the end (e.g. after a loop that is never expected to exit except by
<code>return</code>).
</p>

<p>
If we do not wish to give the <code>[[noreturn]]</code> attribute normative semantics, then perhaps we
should explore defining an alternative normative mechanism for annotating functions as never
returning normally.
</p>
</div>
</li>
</ol>
</div>

<div id="outline-container-org2c90250" class="outline-4">
<h4 id="org2c90250"><span class="section-number-4">5.6.2.</span> <i>function-body</i></h4>
<div class="outline-text-4" id="text-5-6-2">
<p>
The computation of the set of exception types of a <i>function-body</i> is used for two main purposes:
</p>
<ul class="org-ul">
<li>checking that exception types that can potentially exit the function are listed in a function's <i>throw-specifier</i>.</li>
<li>deducing the throw-specification for a function with a <code>throw(auto)</code> specifier.</li>
</ul>

<p>
The following steps are used to compute the set of potentially-thrown exception types for a function body.
</p>

<p>
Let <i>A</i> be the set of potentially-thrown exception types for the function body's
<i>compound-statement</i>.
</p>

<p>
If the function is a coroutine and <code>return_void</code> is found in the scope of
the coroutine's <code>promise_type</code> then flowing off the end of the coroutine is
equivalent to evaluating <code>co_return;</code>. If this implicit <code>co_return;</code> statement
is potentially reachable (see above definition), then the computation of <i>A</i>
takes into account any potentially-thrown exceptions that may result from the
evaluation of the <code>co_return;</code> statement.
</p>

<p>
If the function is a constructor, then
</p>
<ul class="org-ul">
<li>Let <i>B</i> be the set of potentially-thrown exception types of the function
call expressions of the constructors of the base-classes and non-static data-members.</li>
</ul>
<p>
Otherwise, if the function is a destructor, then
</p>
<ul class="org-ul">
<li>Let <i>B</i> be the set of potentially-thrown exception types of the function
call expressions of the destructors of the base-classes and non-static data-members.</li>
</ul>
<p>
Otherwise,
</p>
<ul class="org-ul">
<li>Let <i>B</i> be the empty set.</li>
</ul>

<p>
Let <i>C</i> be the union of the sets <i>A</i> and <i>B</i>.
</p>

<p>
If the <i>function-body</i> has a <i>function-try-block</i>, then;
</p>
<ul class="org-ul">
<li>let <i>D</i> be the subset of types in <i>C</i> that would be caught by the handlers of the <i>function-try-block</i>.
(see the <i>try-block</i> description for more details about this); and</li>
<li>for each potentially reachable handler, <i>Hi</i>, of the try-block, let <i>Ei</i> be the set of potentially-thrown
exception types corresponding to the <i>compound-statement</i> of that handler.
For the purposes of computing the set of potentially-thrown exception types, if the function-body is
of a constructor or destructor then the <i>compound-statement</i> of <i>Hi</i> should be considered to have an
implicit <code>throw;</code> statement inserted immediately prior to the closing brace.
Note: This implicit <code>throw;</code> statement may or may not be potentially-reachable and therefore may or
may not contribute to the set of potentially-thrown exception types computed for <i>Ei</i>.</li>
<li>Let <i>E</i> be the union of the sets <i>Ei</i>.</li>
</ul>
<p>
Otherwise, let <i>D</i> and <i>E</i> both be the empty set.
</p>

<p>
Then the set of potentially-thrown exception types of the <i>function-body</i> is the set
of types described by (<i>C</i> - <i>D</i>) ∪ <i>E</i>.
</p>
</div>
</div>

<div id="outline-container-org212b10e" class="outline-4">
<h4 id="org212b10e"><span class="section-number-4">5.6.3.</span> <i>statement</i></h4>
<div class="outline-text-4" id="text-5-6-3">
<p>
A statement is one of the following cases:
</p>
<ul class="org-ul">
<li><i>expression-statement</i></li>
<li><i>compound-statement</i></li>
<li><i>selection-statement</i></li>
<li><i>iteration-statement</i></li>
<li><i>jump-statement</i></li>
<li><i>declaration-statement</i></li>
<li><i>try-block</i></li>
</ul>

<p>
See the relevant section for a description of each.
</p>
</div>
</div>

<div id="outline-container-orgd5fd1f4" class="outline-4">
<h4 id="orgd5fd1f4"><span class="section-number-4">5.6.4.</span> <i>expression-statement</i></h4>
<div class="outline-text-4" id="text-5-6-4">
<p>
An <i>expression-statement</i> has a set of potentially-thrown exception types equal to
the set of potentially-thrown exception types of the <i>expression</i>.
</p>

<p>
See section on <i>expression</i> handling below.
</p>
</div>
</div>

<div id="outline-container-org2c818c8" class="outline-4">
<h4 id="org2c818c8"><span class="section-number-4">5.6.5.</span> <i>compound-statement</i></h4>
<div class="outline-text-4" id="text-5-6-5">
<p>
The set of potentially thrown exception types for a <i>compound-statement</i> is the union of
the set of potentially-thrown exception types for each of the <i>potentially-reachable statements</i> in the
<i>statement-seq</i> of the <i>compound-statement</i>.
</p>

<p>
Note that this takes into account some basic control-flow analysis to eliminate potentially-thrown
exceptions from statements in the <i>statement-seq</i> that are determined to be unreachable.
e.g. ignoring a statement because a preceding statement branched unconditionally to some other
code-path via <code>return</code>, <code>break</code>, <code>continue</code>, <code>goto</code>, <code>throw</code> or calling a <code>[﻿[noreturn]]</code> function.
</p>

<p>
For example: Assuming the following declarations:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">foo</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>);
<span class="org-type">void</span> <span class="org-function-name">bar</span>() <span class="org-keyword">throw</span>(<span class="org-type">B</span>, <span class="org-type">C</span>);
<span class="org-type">void</span> <span class="org-function-name">baz</span>() <span class="org-keyword">throw</span>(<span class="org-type">D</span>);
</pre>
</div>

<p>
The set of potentially-thrown-exceptions from the following compound-statement is { <code>A</code>, <code>D</code> }
</p>
<div class="org-src-container">
<pre class="src src-c++">{
  foo(); <span class="org-comment-delimiter">// </span><span class="org-comment">might throw A</span>
  <span class="org-keyword">goto</span> <span class="org-constant">label</span>;
  bar(); <span class="org-comment-delimiter">// </span><span class="org-comment">might throw B or C (note this is an unreachable-statement)</span>
<span class="org-constant">label</span>:
  baz(); <span class="org-comment-delimiter">// </span><span class="org-comment">might throw D</span>
}
</pre>
</div>
</div>
</div>

<div id="outline-container-org62ddfd3" class="outline-4">
<h4 id="org62ddfd3"><span class="section-number-4">5.6.6.</span> <i>selection-statement</i></h4>
<div class="outline-text-4" id="text-5-6-6">
<p>
Selection statements include <code>if</code>, <code>if constexpr</code>, <code>if consteval</code> and <code>switch</code> statements.
</p>
</div>

<ol class="org-ol">
<li><a id="org19d8bdb"></a><code>if</code> statements<br />
<div class="outline-text-5" id="text-5-6-6-1">
<p>
The set of potentially-thrown exception types of an <code>if</code> statement is the
union of the potentially-thrown exception types of the:
</p>
<ul class="org-ul">
<li><i>init-statement</i> - if present</li>
<li><i>condition</i> expression</li>
<li><i>statement</i> - the first substatement</li>
<li><i>statement</i> - the second substatement (if the <code>else</code> part is present)</li>
</ul>

<p>
Note that the computation of potentially-thrown exception types does not consider
whether or not the <i>condition</i> is a constant expression or not - both branches of
sub-statements are always considered when computing the set of potentially-thrown
exception-types.
</p>

<p>
For example: The following if-statement has a set of potentially-thrown exception types equal to { <code>X</code> },
despite the condition being a constant
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">if</span> (<span class="org-constant">false</span>) {
  <span class="org-keyword">throw</span> X{};
}
</pre>
</div>

<p>
If you want to force the branching decision to be performed at compile-time then
use the <code>if constexpr</code> form of selection-statement (see below).
</p>
</div>

<ol class="org-ol">
<li><a id="org3197326"></a>Reachability of if-statement components<br />
<div class="outline-text-6" id="text-5-6-6-1-1">
<p>
With if-statements there is the question of whether we should consider the set of potentially-thrown
exceptions of the first or second sub-statements if either the <i>init-statement</i> is a
<i>interrupted-flow statement</i>, or if the <i>condition</i> is an <i>interrupted-flow expression</i>.
</p>

<p>
For example: Should the following function, <code>f()</code> deduce to a throw-specification of <code>throw(X)</code> or
to <code>throw(X, Y, Z)</code>?
</p>
<div class="org-src-container">
<pre class="src src-c++">[[noreturn]] <span class="org-type">bool</span> <span class="org-function-name">throws_something</span>() <span class="org-keyword">throw</span>(<span class="org-type">X</span>);

<span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) {
  <span class="org-keyword">if</span> (throws_something()) {
    <span class="org-keyword">throw</span> Y{};
  } <span class="org-keyword">else</span> {
    <span class="org-keyword">throw</span> Z{};
  }
}
</pre>
</div>

<p>
The rules above do not try to compute the individual reachability of the substatements and
applying the rules as written would result in a deduced exception specification for <code>f()</code>
of <code>throw(X, Y, Z)</code>.
</p>

<p>
While it would be relatively straight-forward to extend the rules to, instead, compute
a deduced exception specification of <code>throw(X)</code>, it is not clear that this would bring
significant value, as this kind of code is expected to be relatively rare, and could
be straight-forwardly rewritten in a form that separates the <i>interrupted-flow expression</i>
into a separate statement.
</p>

<p>
For example: The following code is equivalent but deduces the throw-specification to <code>throw(X)</code>
according to the above rules since the if-statement is not a reachable statement.
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>)  {
  <span class="org-type">bool</span> <span class="org-variable-name">cond</span> = throws_something();
  <span class="org-comment-delimiter">// </span><span class="org-comment">The if-statement is unreachable as prior statement was an interrupted-flow statement.</span>
  <span class="org-keyword">if</span> (cond) {
    <span class="org-keyword">throw</span> Y{};
  }  <span class="org-keyword">else</span> {
    <span class="org-keyword">throw</span> Z{};
  }
}
</pre>
</div>
</div>
</li>
</ol>
</li>

<li><a id="org4c2bf47"></a><code>if constexpr</code> statements<br />
<div class="outline-text-5" id="text-5-6-6-2">
<p>
As the condition of a constexpr if statement is evaluated as part of constant evaluation
and a constant evaluation is not permitted to result in a thrown exception, the <i>condition</i>
part does not contribute to the set of potentially-thrown exception types.
</p>

<p>
If the <i>selection-statement</i> contains an <i>init-statement</i> part, then let <i>I</i> be
the set of potentially-thrown exception types of the <i>init-statement</i>,
otherwise let <i>I</i> be the empty set.
</p>

<p>
If the value of the converted <i>condition</i> expression is <code>true</code> then then set of
potentially-thrown exception types of the <i>selection-statement</i> is the union of
<i>I</i> and the set of potentially-thrown exception types of the the first substatement.
i.e. the body of the <code>if</code> <i>statement</i>.
</p>

<p>
Otherwise, if the <code>else</code> part of the selection statement is present, then the
set of potentially-thrown exception types of the <i>selection-statement</i> is the union of
<i>I</i> and the set of potentially-thrown exception types of the second substatement.
i.e. the body of the <code>else</code> <i>statement</i>.
</p>

<p>
Otherwise, the set of potentially-thrown exception types of the <i>selection-statement</i>
is <i>I</i>.
</p>

<p>
For example: The following statement has a set of potentially-thrown exceptions
equal to { <code>X</code> }.
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">if</span> <span class="org-keyword">constexpr</span> (<span class="org-constant">true</span>) {
  <span class="org-keyword">throw</span> X{};
} <span class="org-keyword">else</span> {
  <span class="org-keyword">throw</span> Y{};
}
</pre>
</div>
</div>
</li>

<li><a id="org1f82816"></a><code>if consteval</code><br />
<div class="outline-text-5" id="text-5-6-6-3">
<p>
An if-statement of the form <code>if consteval /compound-statement/</code> has a set of
potentially-thrown exception types that is the set of potentially-thrown
exception types of the <i>compound-statement</i>.
</p>

<p>
An if-statement of the form <code>if consteval /compound-statement/ else /statement/</code> has
a set of potentially-thrown exception types that is equal to the union of the
sets of potentially thrown exception types of <i>compound-statement</i> and <i>statement</i>,
respectively.
</p>

<p>
Note that the <i>compound-statement</i> is manifestly constant-evaluated and so is
not currently permitted to throw exceptions and so could potentially be considered
as not contributing to the set of potentially-thrown exception types.
</p>

<p>
However, it is possible that we may want to support the ability to throw exceptions
during constant-evaluation in future.
See <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3068r0.pdf">P3068R0</a> "Allowing exception throwing in constant-evaluation" for such a proposal.
</p>

<p>
If we were to initially treat code within the manifestly-constant-evaluated
branch as non-throwing then later changing it to be potentially-throwing would be a
breaking change.
</p>
</div>
</li>

<li><a id="orga4f55f6"></a><code>switch</code><br />
<div class="outline-text-5" id="text-5-6-6-4">
<p>
A switch statement of the form <code>switch ( /init-statement/ /condition/ ) /statement/</code>
or <code>switch ( /condition/ ) /statement/</code>
has a set of potentially thrown exception-types equal to union of the sets of potentially
thrown exception types of the following parts:
</p>
<ul class="org-ul">
<li><i>init-statement</i> (if present)</li>
<li><i>condition</i> expression</li>
<li><i>statement</i></li>
</ul>

<p>
Note that similarly to the if-statement we could modify this to consider the <i>condition</i> only if it
is a potentially-reachable expression (i.e. the <i>init-statement</i> is absent or is not
a flow-interrupted statement).
</p>

<p>
Further, if the <i>condition</i> is either not reachable or is a flow-interrupted excpression then
we could also consider any <code>case</code> or <code>default</code> labels associated with the switch-statement as
unreachabel labels.
</p>

<p>
The <i>statement</i> of a <code>switch</code> is not itself a potentially-reachable statement, although it may
contain potentially-reachable sub-statements if there are labelled sub-statements.
The set of potentially-thrown exception types of the <i>statement</i> only considers the
potentially-reachable sub-statements.
</p>
</div>
</li>
</ol>
</div>

<div id="outline-container-org70777a6" class="outline-4">
<h4 id="org70777a6"><span class="section-number-4">5.6.7.</span> <i>iteration-statement</i></h4>
<div class="outline-text-4" id="text-5-6-7">
<p>
The following kinds of iteration-statement are possible:
</p>
<ul class="org-ul">
<li><code>while ( /condition/ ) /statement/</code></li>
<li><code>do /statement/ while ( /expression/ ) ;</code></li>
<li><code>for ( /init-statement/ /condition/ ; /expression/ ) /statement/</code></li>
<li><code>for ( /init-statement/ /for-range-declaration/ : /for-range-initializer/ ) /statement/</code></li>
</ul>

<p>
For all of these forms of iteration statement, the set of potentially-thrown exception types
of the iteration statement is the union of the sets of potentially-thrown exception types
from each of the relevant subexpressions or substatements:
</p>
<ul class="org-ul">
<li><i>condition</i></li>
<li><i>statement</i></li>
<li><i>expression</i></li>
<li><i>init-statement</i></li>
<li><i>for-range-declaration</i></li>
<li><i>for-range-initiailizer</i></li>
</ul>

<p>
Note that this includes exceptions that may be thrown from the body of the iteration statement,
even if the statement's <i>condition</i> is such that the body will never be executed.
</p>

<p>
Note that if [P2809R2] "Trivial infinite loops are not Undefined Behavior" is adopted, then
trivial infinite loops could potentially be required to be implemented as a call to the
proposed function <code>std::this_thread::yield_forever()</code>, which is marked <code>[[noreturn]]</code>.
This means that such a trivial infinite loop would be considered a flow-interrupted statement.
If P2809 is adopted after this paper then this could potentially be a breaking change as
it could change the deduced set of potentially-thrown exception types of a function with
a <code>throw(auto)</code> specifier.
</p>

<p>
For example: Without P2809 the following function would deduce its exception specification to <code>throw(X)</code> 
but with P2809 it would deduce to <code>throw()</code>.\
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">example</span>() <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) {
  <span class="org-keyword">while</span> (<span class="org-constant">true</span>) ;
  <span class="org-keyword">throw</span> X{};
}
</pre>
</div>
</div>
</div>

<div id="outline-container-org0d9407a" class="outline-4">
<h4 id="org0d9407a"><span class="section-number-4">5.6.8.</span> <i>jump-statement</i></h4>
<div class="outline-text-4" id="text-5-6-8">
<p>
Jump statements include:
</p>
<ul class="org-ul">
<li><code>break;</code></li>
<li><code>continue;</code></li>
<li><code>return</code> <i>expr-or-braced-init-list</i> <code>;</code></li>
<li><i>coroutine-return-statement</i></li>
<li><code>goto</code> <i>identifier</i> <code>;</code></li>
</ul>

<p>
Only the <code>return</code> and <code>co_return</code> statements can potentially affect the set of potentially-thrown
exception types here. The others are pure control flow, and while they can potentially trigger
exceptions to be thrown when exiting scopes via that control-flow (if destructors are potentially-throwing),
those exceptions should be covered by the declaration statement for that variable.
</p>
</div>

<ol class="org-ol">
<li><a id="org3066b0a"></a><code>return</code> statements<br />
<div class="outline-text-5" id="text-5-6-8-1">
<p>
A <code>return</code> statement has a set of potentially-thrown exception types equal to the
union of the set of potentially-thrown exception types of the operand expression,
and the set of potentially-thrown exception types from any implicit conversion
or constructor call required to initialize the return-value.
</p>

<p>
Note that there is an edge-case here that needs to be considered, where the operand
to the return statement is a prvalue which is returned with guaranteed copy-elision
and where the object has a potentially-throwing destructor. Normally, an expression
that creates a pr-value includes the potentially-throwing types of both the call to
the constructor, and the call to the destructor, as a statement containing that
expression will also call the destructor at the end of the full-expression.
However, for a return-value that is initialized with guaranteed copy-elision, the
destructor will be invoked by the caller of the function, rather than the local
function, and so the exception-specification of the return-value type should not
be included in the calculation of the set of potentially-thrown exception types for
the return statement.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">struct</span> <span class="org-type">Foo</span> {
  <span class="org-function-name">Foo</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>);
  <span class="org-function-name">Foo</span>(<span class="org-type">Foo</span>&amp;&amp;) <span class="org-keyword">throw</span>(<span class="org-type">B</span>);
  ~<span class="org-function-name">Foo</span>() <span class="org-keyword">throw</span>(<span class="org-type">C</span>);
};

<span class="org-type">Foo</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) { <span class="org-comment-delimiter">// </span><span class="org-comment">deduces to throw(A)</span>
  <span class="org-keyword">return</span> Foo{}; <span class="org-comment-delimiter">// </span><span class="org-comment">constructor called here but not destructor</span>
}

<span class="org-type">Foo</span> <span class="org-function-name">g</span>() <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) { <span class="org-comment-delimiter">// </span><span class="org-comment">deduces to throw(A, B, C)</span>
  <span class="org-type">Foo</span> <span class="org-variable-name">f</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declaration statement potentially throws A (from constructor) and C (from destructor)</span>
  <span class="org-keyword">return</span> f; <span class="org-comment-delimiter">// </span><span class="org-comment">move-constructor potentially called here, even if copy is elided due to NRVO</span>
}
</pre>
</div>

<p>
We also need to consider the case where the returned object is initialized using aggregate
initialization, where there may be a whole tree of sub-expressions that potentially initialize
sub-objects of the returned object.
</p>

<p>
Any expression in such a return-statement that directly initializes an object or sub-object of
the return-value that will be destroyed by the caller should not consider the exception-specification
of that sub-object's type's destructor when computing the set of potentially-thrown exceptions of
the <code>return</code> statement.
</p>

<p>
Note that, while it may be possible that the return-statement may execute the destructor of some
of these sub-objects in the case that initialization of a subsequent sub-object exits with an
exception, we do not need to consider this case for the purposes of computing the potentially-thrown
exceptions as these destructors will only be called in case there is an unwind due to another
exception - if these destructors then throw their own exceptions during unwind then this results
in an immediate call to <code>std::terminate</code>.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">struct</span> <span class="org-type">X</span> {
  <span class="org-function-name">X</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>);
  ~<span class="org-function-name">X</span>() <span class="org-keyword">throw</span>(<span class="org-type">B</span>);
};
<span class="org-keyword">struct</span> <span class="org-type">Y</span> {
  <span class="org-function-name">Y</span>() <span class="org-keyword">throw</span>(<span class="org-type">C</span>);
  ~<span class="org-function-name">Y</span>() <span class="org-keyword">throw</span>(<span class="org-type">D</span>);
};

<span class="org-keyword">struct</span> <span class="org-type">Z</span> {
  <span class="org-type">X</span> <span class="org-variable-name">x</span>;
  <span class="org-type">Y</span> <span class="org-variable-name">y</span>;
};

<span class="org-type">Z</span> <span class="org-function-name">h</span>() <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) { <span class="org-comment-delimiter">// </span><span class="org-comment">deduces to throw(A, C)</span>
  <span class="org-keyword">return</span> Z{X{}, Y{}};
}
</pre>
</div>

<p>
In this example, if <code>Z::x</code> is initialized and then the call to <code>Z::y</code>'s constructor throws
then the <code>Z::x</code> destructor will be called, which could theoretically exit with an exception
of type, <code>B</code>. However, since this can only happen while unwinding with an exception of type
<code>C</code>, if <code>Z::x.~X()</code> exits with an exception during unwind then <code>std::terminate()</code> is called.
So it is not possible for the function <code>h()</code> to exit with an exception of type <code>B</code>.
</p>

<p>
As an aside, it would be useful to be able to make ill-formed any cases that could result in
potential calls to <code>std::terminate()</code> due to an exception being thrown during unwind - at
least in pursuit of the goal of embedded systems having no hidden calls to <code>std::terminate()</code>.
How, and whether, to do this is an open-question.
</p>
</div>
</li>

<li><a id="orgc41c8fd"></a><code>co_return</code> statements<br />
<div class="outline-text-5" id="text-5-6-8-2">
<p>
A <code>co_return</code> statement of the form <code>co_return;</code> has a set of potentially-thrown exception types
equal to the set of potentially-thown exception types of the statement <code>promise.return_void();</code>,
where <i>promise</i> is the current coroutine's promise object.
</p>

<p>
A <code>co_return</code> statement of the form <code>co_return /expr/ ;</code>, where <i>expr</i> has type <code>void</code> has
a set of potentially-thrown exception types equal to the union of the set of potentially-thrown
exception types of <i>expr</i> and the set of potentially-thrown exception types of the statement
<code>promise.return_void()</code>, where <i>promise</i> is the current coroutine's promise object.
</p>

<p>
A <code>co_return</code> statement of the form <code>co_return /expr-or-braced-init-list/ ;</code>, where the operand
is either an <i>expression</i> of non-<code>void</code> type or is a <i>braced-init-list</i>, has a set of potentially-thrown
exception types equal to the set of potentially thrown exception types of the statement
<code>promise.return_value( /expr-or-braced-init-list/ );</code>.
</p>
</div>
</li>
</ol>
</div>

<div id="outline-container-org7f689ea" class="outline-4">
<h4 id="org7f689ea"><span class="section-number-4">5.6.9.</span> <i>declaration-statement</i></h4>
<div class="outline-text-4" id="text-5-6-9">
<p>
A declaration statement consists of a <i>block-declaration</i>, which in turn consists of one of the following:
</p>
<ul class="org-ul">
<li><i>simple-declaration</i></li>
<li><i>asm-declaration</i></li>
<li><i>namespace-alias-definition</i></li>
<li><i>using-declaration</i></li>
<li><i>using-enum-declaration</i></li>
<li><i>using-directive</i></li>
<li><i>static<sub>assert</sub>-declaration</i></li>
<li><i>alias-declaration</i></li>
<li><i>opaque-enum-declaration</i></li>
</ul>

<p>
Other than the first two cases, the rest of the declarations do not introduce any executable code that
might throw exceptions.
</p>

<p>
Note that, while the <i>static<sub>assert</sub>-declaration</i> has a child expression, this expression is evaluated
as a manifestly constant expression, and therefore the program is ill-formed if that expression exits
with an exception.
</p>
</div>

<ol class="org-ol">
<li><a id="org4430563"></a><i>simple-declaration</i><br />
<div class="outline-text-5" id="text-5-6-9-1">
<p>
A declaration statement that declares one or more block variables with automatic storage duration
has a set of potentially-thrown exception types equal to the union of the sets of potentially
thrown exception types of any <i>initializer</i> expressions and any calls to constructors or
conversion operators required to initialize the local variables, and any potentially thrown
exception types of calls to the destructors of the declared variables.
</p>

<p>
A declaration statement that declares one or more block variables with either static storage duration
or thread storage duration has a set of potentially-thrown exception types equal to the union
of the sets of potentially-thrown exception types of any <i>initializer</i> expressions and any calls
to constructors of conversion operators required to initialize the local variables, but does <span class="underline">not</span>
include exception types of calls to the destructors of the declared variables.
</p>

<p>
We do not include the exceptions thrown by destructors of static/thread<sub>local</sub> variables because
these destructors are not called from within the scope of a function that initializes these
variables.
</p>

<p>
Q. Initialization of variables with static storage duration needs to perform synchronization
in multi-threaded environments in order to guard against data-races initializing the
variable. Is it possible that operations on the synchronization primitives might fail with an
implementation-defined or unspecified exception (in which case we would need to include this
in the set of exception types) or can we assume that the synchronization will always succeed?
</p>

<p>
A declaration statement that declares a constant expression (i.e. is declared with the <code>constexpr</code>
specifier) has an empty set of potentially-thrown exception types, assuming that the program is ill-formed
if a constant-evaluation exits with an exception.
</p>
</div>
</li>

<li><a id="org298829f"></a><i>asm-declaration</i><br />
<div class="outline-text-5" id="text-5-6-9-2">
<p>
The <i>asm-declaration</i> has implementation defined behaviour and, while in theory, on some implementations,
an assembly declaration might be able to throw an exception, we cannot, in general, deduce anything about
the set of exception types that might be thrown in a portable way.
</p>

<p>
There are three possible options we take here:
</p>
<ul class="org-ul">
<li>the <i>asm-declaration</i> has implementation-defined behaviour, so the set of potentially-thrown exceptions
from such a declaration should be implementation-defined.</li>
<li>the <i>asm-declaration</i> could potentially do anything (invoke a potentially-throwing function,
implement some exception-throwing mechanics, etc.) so we should treat this as potentially throwing
any type of exception.</li>
<li>the vast majority of <i>asm-declaration</i> usage is for implementing optimized, inline code, which
won't throw any exceptions, so we could define it to be non-throwing.</li>
<li>we could make it ill-formed to use an <i>asm-declaration</i> in any context in which the
exception-specification needs to be deduced.</li>
</ul>

<p>
This paper suggests treating an <i>asm-declaration</i> statement as having an implementation-defined
set of potentially-thrown exceptions as this at least allows the possibility of the implementation
being able to analyse a declaration and deduce what exceptions might be thrown in an implementation-specific
way.
</p>

<p>
However, it would be worth a more detailed discussion within the Evolution sub-group about
what the desired semantics are here.
</p>
</div>
</li>
</ol>
</div>

<div id="outline-container-org7b11c92" class="outline-4">
<h4 id="org7b11c92"><span class="section-number-4">5.6.10.</span> <i>try-block</i></h4>
<div class="outline-text-4" id="text-5-6-10">
<p>
A <i>try-block</i> statement has the form <code>try /compound-statement/</code> followed by one or more
handlers of the form <code>catch ( /exception-declaration/ ) /compound-statement/</code>.
</p>

<p>
In addition, a <i>function-try-block</i> statement for a constructor can also have the form
<code>try /ctor-initializer/ /compound-statement/</code> followed by one or more handlers of the
form <code>catch ( /exception-declaration/ ) /compound-statement/</code>.
</p>

<p>
Let <i>A</i> be the set of potentially-thrown exception types of the try block's <i>compound-statement</i>.
</p>

<p>
If this is a function try block for a constructor then let <i>B</i> be the union of <i>A</i> and
the sets of potentially-thrown exceptions of initializer expressions and calls to
constructors of any base classes and non-static data-members.
</p>

<p>
Otherwise, let <i>B</i> be the set <i>A</i>.
</p>

<p>
Let <i>E</i> initially be the empty set.
</p>

<p>
For each type, <i>x</i>, in the set <i>B</i>
</p>
<ul class="org-ul">
<li>if <i>x</i> is <code>std::any_exception</code> then
<ul class="org-ul">
<li>add the set of potentially-thrown exception types of the <i>compound-statement</i> of every reachable
handler to <i>E</i>.
<ul class="org-ul">
<li>NOTE: a handler is not reachable if the <i>exception-declaration</i> for that handler names a type
unambiguously derived from a base class type that is listed in an earlier handler's <i>exception-declaration</i>.</li>
<li>NOTE: this does not include template handlers as those are only invoked from exceptions thrown
from expressions that have a static exception specification.</li>
</ul></li>
<li>if the list of handlers associated with this try-block does not include a handler with an <i>exception-declaration</i> of <code>...</code>
then add <code>std::any_exception</code> to <i>E</i>.</li>
</ul></li>
<li>otherwise, if any handler is a match for an exception object of type <i>x</i> then
<ul class="org-ul">
<li>The selected handler for this exception type is the first handler, <i>h</i>, that matches
an exception object of type <i>x</i>. <i>h</i> is a potentially-reachable handler.</li>
<li>Add the set of potentially-thrown exception-types of <i>h</i>'s <i>compound-statement</i> to <i>E</i>.</li>
<li>Add the set of potentially-thrown exception-types of a function call expression
that invokes the destructor of an object of type, <i>x</i>.
<ul class="org-ul">
<li>NOTE: This is because exiting the handler's <i>compound-statement</i> will potentiallly
call the destructor of the exception object of type <i>x</i>.</li>
<li>NOTE: There is a potential edge-case here, where the <i>compound-statement</i> unconditionally
rethrows the exception (e.g. with a <code>throw;</code> statement). In this case, the destructor
of the exception object is never called upon exiting the <i>compound-statement</i> and so
we could avoid adding the destructor's set of potentially-thrown exception types to
the set of potentially-thrown exception types for this handler.
This is unlikely to make much difference in practice, as most exception types used in
practice have a non-throwing destructor, but still needs to be defined.</li>
</ul></li>
</ul></li>
<li>otherwise,
<ul class="org-ul">
<li>add <i>x</i> to <i>E</i></li>
</ul></li>
</ul>

<p>
If the <i>try-block</i> is part of a <i>function-try-block</i> of a constructor or destructor
then a handler associated with that <i>try-block</i> should be treated as if the statement
<code>throw;</code> was inserted immediately prior to the closing brace of its <i>compound-statement</i>
for the purposes of computing its set of potentially-thrown exception types.
</p>

<p>
The set of potentially-thrown exception types of the <i>try-block</i> is the resulting set, <i>E</i>.
</p>
</div>
</div>

<div id="outline-container-orgf331168" class="outline-4">
<h4 id="orgf331168"><span class="section-number-4">5.6.11.</span> <i>init-statement</i></h4>
<div class="outline-text-4" id="text-5-6-11">
<p>
An init-statement is either a:
</p>
<ul class="org-ul">
<li><i>simple-declaration</i></li>
<li><i>expression-statement</i> - Expression statements are already described above.</li>
<li><i>alias-declaration</i> - These do not contain any executable code and thus do not contribute to the set of potentially-thrown exception types.</li>
</ul>


<p>
If the statement is a <i>simple-declaration</i> that is an object declaration,
the set of potentially-thrown exception types of that statement is the union
of the sets of potentially-thrown exception types of the <i>initializer</i> expression,
the function call expression of the objects selected constructor and the
function call expression of the object's destructor.
</p>
</div>
</div>

<div id="outline-container-orgd9e064d" class="outline-4">
<h4 id="orgd9e064d"><span class="section-number-4">5.6.12.</span> <i>expression</i></h4>
<div class="outline-text-4" id="text-5-6-12">
<p>
There are many different types of expressions that need to be considered.
</p>

<p>
This paper does not attempt to list all of them here, but instead gives some general rules that
apply to most expressions and then describe separately the rules for any expressions
that do not follow the general rules.
</p>
</div>

<ol class="org-ol">
<li><a id="orgdcb84ae"></a>General rules for expressions<br />
<div class="outline-text-5" id="text-5-6-12-1">
<p>
Expressions that have sub-expressions in general have a set of potentially-thrown exception
types that includes the union of the sets of potentially-thrown exception types of the
immediate-sub-expressions of that expression.
</p>

<p>
Operator expressions or conversions that resolve to calls to user-defined operator
functions have a set of potentially-thrown exception types of a function call expression to
that user-defined operator function. Built-in implicit conversions and operators
generally have an empty set of potentially-thrown exceptions.
</p>
</div>
</li>

<li><a id="org295b3e8"></a>Function call expressions<br />
<div class="outline-text-5" id="text-5-6-12-2">
<p>
Function call expressions have a set of potentially-thrown exception types equal to the
union of the sets of potentially-thrown exception types of the following expressions:
</p>
<ul class="org-ul">
<li>the expressions provided as arguments to the function, including any default argument expressions.</li>
<li>any implicit conversion expression required to convert the argument to the corresponding parameter type, and</li>
<li>the <i>postfix-expression</i> immediately preceding the parenthesised argument-list</li>
</ul>
<p>
unioned with the set of exception types listed in the <i>postfix-expression</i>'s function type's or function-pointer type's
exception-specification.
</p>

<p>
If the <i>postfix-expression</i> has function type then the set of potentially-thrown exception types
is taken from the exception-specification of the function declaration.
</p>

<p>
If the <i>postfix-expression</i> has function-pointer or member-function-pointer type then the set of
potentially-thrown exception types is taken from the exception-specification of the pointed-to
function type.
Note that this may be a superset of the set of exception types listed in the pointed-to
function's exception specification.
</p>

<p>
If the function or function-pointer has an dynamic exception-specification then the
set of potentially-thrown exception types is the set { <code>std::any_exception</code> },
otherwise, if it has a static exception-specification then the set of potentially
thrown exception types is the set of types listed in the exception specification.
</p>

<p>
Note that if any parameter types of the function or function-pointer being called have
a value category of prvalue then the set of potentially-thrown exception types will also
include the exception types listed in the type's destructor's exception-specification,
as per the next section.
</p>
</div>
</li>

<li><a id="org8218a65"></a>prvalue expressions<br />
<div class="outline-text-5" id="text-5-6-12-3">
<p>
If an expression has a prvalue value category then the set of potentially thrown exception
types of that expression includes the set of potentially thrown exception types of a
function call expression to that object's destructor, unless that expression is the operand
of a <code>return</code> statement of a function returning a prvalue of the same type as the operand
and the operand is used to initialize the result object via copy-initialization.
</p>

<p>
See the section on <code>return</code> statements for more details (in particular regarding aggregate
initialization of return values).
</p>
</div>
</li>

<li><a id="orgbd39727"></a>Standard conversions<br />
<div class="outline-text-5" id="text-5-6-12-4">
<p>
The set of potentially-thrown exceptions from all standard conversions listed under
[conv.general] is the empty set.
</p>
</div>
</li>

<li><a id="org767818f"></a>Constant expressions<br />
<div class="outline-text-5" id="text-5-6-12-5">
<p>
In C++23 it is not permitted for an exception to be thrown within the evaluation of a constant
expression. If this is to remain the case, then we could assume that any manifestly constant expression
has an empty set of potentially-thrown exceptions.
</p>

<p>
However, it's possible that in the future we may decide to allow exceptions to be thrown during
the evaluation of a constant expression. Although this may be limited to the cases where any thrown
exception is caught within the same constant evaluation - similar to how dynamic memory allocation
is allowed, as long as the memory is freed within the same constant evaluation.
The paper <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3068r0.pdf">P3068</a> "Allowing exception throwing in constant-evaluation" proposes such a change to the language.
</p>

<p>
In order to allow for this possibility, and to avoid having adding this capability later be a
breaking change, manifestly constant expressions should be treated the same as runtime-evaluated
expressions for the purposes of computing the set of potentially-thrown exception types of that
expression.
</p>

<p>
However, the top-level expression that begins a new constant evaluation, such as initialization of
a <code>constexpr</code> variable or the <i>condition</i> of an <code>if constexpr</code> statement, should be assumed to be
non-throwing. An exception propagating out of such an expression would make the program ill-formed.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">constexpr</span> <span class="org-type">int</span> <span class="org-function-name">parse_integer</span>(<span class="org-keyword">const</span> <span class="org-type">char</span>* <span class="org-variable-name">s</span>) <span class="org-keyword">throw</span>(<span class="org-type">parse_error</span>) {
  <span class="org-type">int</span> <span class="org-variable-name">result</span> = 0;
  <span class="org-keyword">do</span> {
    <span class="org-keyword">if</span> (<span class="org-negation-char">!</span><span class="org-constant">std</span>::isdigit(*s)) <span class="org-keyword">throw</span> parse_error{};
    result = 10 * result  + (*s - <span class="org-string">'0'</span>);
    ++s;
  } <span class="org-keyword">while</span> (*s != <span class="org-string">'\0'</span>);
  <span class="org-keyword">return</span> result;
}

<span class="org-type">int</span> <span class="org-function-name">example_1</span>() <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) { <span class="org-comment-delimiter">// </span><span class="org-comment">deduces to throw()</span>
  <span class="org-keyword">constexpr</span> <span class="org-type">int</span> <span class="org-variable-name">i</span> = parse_integer(<span class="org-string">"1234"</span>);
  <span class="org-keyword">return</span> i;
}

<span class="org-type">int</span> <span class="org-function-name">example_2</span>() <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) { <span class="org-comment-delimiter">// </span><span class="org-comment">deduces to throw(parse_error)</span>
  <span class="org-keyword">const</span> <span class="org-type">int</span> <span class="org-variable-name">i</span> = parse_integer(<span class="org-string">"1234"</span>);
  <span class="org-keyword">return</span> i;
}

<span class="org-type">int</span> <span class="org-function-name">example_3</span>() <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) { <span class="org-comment-delimiter">// </span><span class="org-comment">deduces to throw()</span>
  <span class="org-keyword">if</span> <span class="org-keyword">constexpr</span> (parse_integer(<span class="org-string">"1234"</span>) &gt;= 10) {
    <span class="org-keyword">return</span> 10;
  }
  <span class="org-keyword">return</span> 0;
}

<span class="org-keyword">constexpr</span> <span class="org-type">int</span> <span class="org-function-name">example_4</span>() <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) { <span class="org-comment-delimiter">// </span><span class="org-comment">deduces to throw(parse_error)</span>
  <span class="org-keyword">if</span> <span class="org-keyword">consteval</span> {
    <span class="org-keyword">return</span> parse_integer(<span class="org-string">"1234"</span>);
  } <span class="org-keyword">else</span> {
    <span class="org-keyword">return</span> 0;
  }
}
</pre>
</div>

<p>
In <code>example_2()</code>, even though a compiler could potentially evaluate the call to <code>parse_integer()</code>
as a constant-expression, it is not required to do so and so could potentially have a runtime
call to a function that is potentially-throwing.
</p>

<p>
Also, if the function does happen to throw during a speculative constant execution of the function
then the compiler falls back to inserting a runtime call to the function instead, rather than
making the program ill-formed, like it would be if the invocation in <code>example_1()</code> or <code>example_3()</code>
were to throw.
</p>

<p>
For example, consider what the semantics should be if <code>example_2()</code> replaced the argument to
<code>parse_integer</code> with <code>"not-a-number"</code> . In this case, we would expect that calling <code>example_2</code>
would throw <code>parse_error</code> at runtime. Simply changing the value of the string literal passed
to <code>parse_integer</code> should not change the deduced exception-specification of the function.
</p>

<p>
In <code>example_4()</code>, despite the call to the <code>parse_integer()</code> function being evaluated as a
manifestly constant expression (inside the first-substatement of <code>if consteval</code>) this context
is not being evaluated as a top-level constant evaluation and so might (one day) propagate
the exception up to some caller that then handles the exception.
</p>
</div>
</li>

<li><a id="orgb1c8d1f"></a>Throw expressions<br />
<div class="outline-text-5" id="text-5-6-12-6">
<p>
We need to consider both:
</p>
<ul class="org-ul">
<li><code>throw &lt;expr&gt;</code> expressions that throw new exception objects, and</li>
<li><code>throw</code> expressions that rethrow an existing exception.</li>
</ul>
</div>

<ol class="org-ol">
<li><a id="org3695886"></a><code>throw &lt;expr&gt;</code><br />
<div class="outline-text-6" id="text-5-6-12-6-1">
<p>
A throw-expression constructs and throws a new exception object of type equal to the decayed type of the operand expression.
</p>

<p>
Some throw-expressions may require dynamic allocation of storage for the exception object,
which might fail due to resource exhaustion. In this case, the throw expression may instead
result in throwing an exception of type <code>std::bad_alloc</code>.
</p>

<p>
Note that currently, the behaviour of a program that fails to allocate storage for a newly
thrown exception is unspecified. However, the behaviour for failure to allocate/rethrow
an <code>exception_ptr</code> is well-defined and so I would expect most implementations to do something
similar - i.e. throw <code>std::bad_alloc</code>.
</p>

<p>
This was discussed in the mailing list thread: <a href="https://lists.isocpp.org/core/2023/10/15012.php">https://lists.isocpp.org/core/2023/10/15012.php</a>
</p>

<p>
This paper proposes defining some forms of throw expressions as not requiring dynamic memory
allocation, but instead requiring that implementations allocate the exception objects as
automatic storage duration objects. This is necessary to be able to provide the guarantee
to programs that particular throw expressions actually throw an exception of that type
and do not throw an expression of some other type (like <code>std::bad_alloc</code>) and therefore
that the set of potentially-thrown exception types is limited to the types of the actual
thrown exceptions.
</p>
</div>

<ol class="org-ol">
<li><a id="org8ae2e4f"></a>Dynamic and Static throw expressions<br />
<div class="outline-text-7" id="text-5-6-12-6-1-1">
<p>
The function that contained the throw expression that created the exception object is
called the "originating function".
</p>

<p>
If the exception thrown by a throw-expression is either handled within the originating
function or if the exception escapes the originating function (possibly after a number
of catch/rethrow steps) and the function definition has a throw-specifier with a static
exception specification (note this implies the exception type is listed in the
throw-specification as otherwise the program would be ill-formed), then the throw
expression is considered a <i>static throw expression</i>. All other throw-expressions
are <i>dynamic throw expressions</i>.
</p>

<p>
In general, this means that all throw expressions in functions with a throw-specifier
on the definition that have a static exception specifications will be <i>static throw expressions</i>
and throw-expressions in a function with a dynamic exception specification will be
dynamic throw expressions unless they are caught locally within the originating
function.
</p>

<p>
For example: Both of the throw-expressions and the rethrow-expressions are all
<i>static throw expressions</i>.
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">example1</span>(<span class="org-type">int</span> <span class="org-variable-name">i</span>) <span class="org-keyword">throw</span>(<span class="org-type">Y</span>, <span class="org-type">Z</span>) {
  <span class="org-keyword">try</span> {
    <span class="org-keyword">switch</span> (i) {
    <span class="org-keyword">case</span> 0:
      <span class="org-keyword">throw</span> X{}; <span class="org-comment-delimiter">// </span><span class="org-comment">static throw-expression: doesn't escape the function - locally handled</span>
    <span class="org-keyword">case</span> 1:
      <span class="org-keyword">throw</span> Y{}; <span class="org-comment-delimiter">// </span><span class="org-comment">static throw-expression: can escape the function (with rethrow)</span>
    <span class="org-keyword">case</span> 2:
      <span class="org-keyword">throw</span> Z{}; <span class="org-comment-delimiter">// </span><span class="org-comment">static throw-expression: escapes the function (not handled locally)</span>
    }
  } <span class="org-keyword">catch</span> (X) {
    <span class="org-comment-delimiter">// </span><span class="org-comment">handled, not rethrown</span>
  } <span class="org-keyword">catch</span> (Y) {
    <span class="org-comment-delimiter">// </span><span class="org-comment">handled, rethrown</span>
    <span class="org-keyword">throw</span>;
  }
}

</pre>
</div>

<p>
Another example: this time with some dynamic exception specifications
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">example2</span>(<span class="org-type">int</span> <span class="org-variable-name">i</span>) <span class="org-keyword">throw</span>(...) {
  <span class="org-keyword">try</span> {
    <span class="org-keyword">switch</span> (i) {
    <span class="org-keyword">case</span> 0:
      <span class="org-keyword">throw</span> X{}; <span class="org-comment-delimiter">// </span><span class="org-comment">static throw-expression: doesn't escape the function - locally handled</span>
    <span class="org-keyword">case</span> 1:
      <span class="org-keyword">throw</span> Y{}; <span class="org-comment-delimiter">// </span><span class="org-comment">dynamic throw-expression: can escape the function (with rethrow)</span>
    <span class="org-keyword">case</span> 2:
      <span class="org-keyword">throw</span> Z{}; <span class="org-comment-delimiter">// </span><span class="org-comment">dynamic throw-expression: escapes the function (not handled locally)</span>
    }
  } <span class="org-keyword">catch</span> (X) {
    <span class="org-comment-delimiter">// </span><span class="org-comment">handled, not rethrown</span>
  } <span class="org-keyword">catch</span> (Y) {
    <span class="org-comment-delimiter">// </span><span class="org-comment">handled, rethrown</span>
    <span class="org-keyword">throw</span>;
  }
}
</pre>
</div>

<p>
A <i>dynamic throw expression</i> allocates the storage in an unspecified way
controlled by the implementation in the same way that storage for thrown exception
objects are currently allocated. The exception object created by a <i>dynamic throw expression</i>
is called a <i>dynamic exception object</i>.
</p>

<p>
A <i>static throw expression</i> allocates the storage for the exception object
with automatic storage duration. The exception object created by a <i>static throw expression</i>
is called a <i>static exception object</i>. The scope of the storage ends after the end
of the lifetime of the static exception object.
</p>
</div>
</li>

<li><a id="org50cc3a9"></a>Lifetime of exception objects created by static throw expressions<br />
<div class="outline-text-7" id="text-5-6-12-6-1-2">
<p>
According to [except.throw] p4
</p>
<blockquote>
<p>
The points of potential destruction for the exception object are:
</p>
<ul class="org-ul">
<li>when an active handler for the exception exits by any means other than rethrowing, immediately after
the destruction of the object (if any) declared in the exception-declaration in the handler.</li>
<li>when an object of type <code>std::exception_ptr</code> that refers to the exception object is destroyed, before
the destructor of <code>std::exception_ptr</code> returns.</li>
</ul>

<p>
Among all points of potential destruction for the exception object, there is an unspecified last one
where the exception object is destroyed. All other points <i>happen before</i> the last one.
</p>
</blockquote>

<p>
For exception objects created by <i>static throw expressions</i>, we need to be able to deterministically
compute their latest-possible point of destruction so that we know where to allocate the automatic
storage-duration storage for that exception object.
</p>

<p>
To allow the compiler to compute this point, we need to eliminate the possibility of the exception object's
lifetime being dynamically extended by calling <code>std::current_exception()</code> and holding on to the <code>std::exception_ptr</code>.
However, we still want to permit users to call <code>std::current_exception()</code> if desired.
</p>

<p>
If the exception object being handled by the most-recently entered handler is a <i>static exception object</i>
then a call to <code>std::current_exception()</code> returns an <code>exception_ptr</code> that references a <i>dynamic exception object</i>
that is copied from the <i>static exception object</i>.
</p>

<p>
Note that the current semantics of capturing the exception in a <code>std::exception_ptr</code> by calling
<code>std::current_exception()</code> and throwing the captured exception by <code>std::rethrow_exception()</code> does
not guarantee to throw the same exception object. An implementation is allowed to copy the current
exception object into storage referenced by the returned <code>std::exception_ptr</code>, so this behaviour
is consistent with existing semantics.
</p>

<p>
Similarly, if a <i>static exception object</i> is rethrown by a <code>throw;</code> expression that is not
a <i>lexically associated rethrow</i> of the active handler then the compiler may not be able to
deduce that the current exception object escapes the current handler and should not be destroyed
when the current handler exits.
</p>

<p>
A <i>lexically associated rethrow</i> is a <code>throw;</code> expression that is a sub-statement of a
handler's <i>compound-statement</i> and that is;
</p>
<ul class="org-ul">
<li>not inside the handler of a try-block nested within this handler; and</li>
<li>not inside the body of a lambda expression nested within this handler; and</li>
<li>not inside the body of a member function of a local class</li>
</ul>

<p>
A <code>throw;</code> expression that is not a <i>lexically associated rethrow</i> throws a
<i>dynamic exception object</i>.
If the current exception is a <i>static exception object</i> then this will allocate a new
<i>dynamic exception object</i> copied from the current <i>static exception object</i>.
</p>

<p>
With those cases handled, we can now define that the lifetime of a <i>static exception object</i>
ends deterministically upon exiting a handler for that exception through any means other
that a <i>lexically associated rethrow</i>.
</p>

<p>
Storage for a <i>static exception object</i> has automatic storage-duration.
</p>

<p>
Generally, the storage for a <i>static exception object</i> will be allocated in the scope of
the function that has the outer-most dynamic scope for a handler that can match the
exception object's type, taking into account possible chains of catch/rethrow of the
exception object.
</p>

<p>
However, there are some cases where rethrowing an exception object may result in copying a
<i>static exception object</i> from automatic storage duration storage allocated in an
inner dynamic-scope to automatic storage duration allocated by an outer dynamic-scope.
</p>

<p>
A caller of a function with a static exception specification will generally provide storage
to the called function so that the called function can allocate the exception object in
storage owned by the caller before it exits. If the caller is not the final handler of
an exception (i.e. the lifetime of the exception object may escape the calling function),
the caller may choose to reuse the storage provided to it by its caller as the storage
it provides to the function it calls.
</p>
</div>

<ol class="org-ol">
<li><a id="orgb02ef6b"></a>Examples of static exception object lifetime and storage duration<br />
<div class="outline-text-8" id="text-5-6-12-6-1-2-1">
<p>
The following examples walk through some simple cases and describe how the
exception object lifetime of static exception objects is intended to work.
</p>

<p>
Given the following exception type, <code>X</code>, and function <code>f()</code>, which throws an instance of <code>X</code>:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">struct</span> <span class="org-type">X</span> {
  <span class="org-keyword">explicit</span> <span class="org-function-name">X</span>(<span class="org-type">int</span>) <span class="org-keyword">noexcept</span>;
  <span class="org-function-name">X</span>(<span class="org-keyword">const</span> <span class="org-type">X</span>&amp;) <span class="org-keyword">noexcept</span>;
  ~<span class="org-function-name">X</span>();
  <span class="org-type">int</span> <span class="org-variable-name">value</span>;
};

<span class="org-keyword">extern</span> <span class="org-type">int</span> <span class="org-variable-name">some_int</span>;

<span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>(<span class="org-type">X</span>) { <span class="org-keyword">throw</span> X{some_int}; }
</pre>
</div>

<p>
Example 0: Consider the following case:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">g0</span>() <span class="org-keyword">throw</span>(<span class="org-type">X</span>) {
  f();
}

<span class="org-type">void</span> <span class="org-function-name">h0</span>() <span class="org-keyword">throw</span>() {
  <span class="org-keyword">try</span> { g0(); } <span class="org-keyword">catch</span> (<span class="org-keyword">const</span> <span class="org-type">X</span>&amp;) {}
}
</pre>
</div>

<p>
In this case:
</p>
<ul class="org-ul">
<li><code>h0()</code> allocates automatic-storage duration storage for an exception object of
type <code>X</code> and provides the address of this storage to <code>g0()</code>.</li>
<li>then <code>g0()</code> calls <code>f()</code> and provides the address provided by <code>h0()</code> to <code>f()</code></li>
<li>if <code>f()</code> throws an exception, then it constructs the object directly into the
storage provided by <code>h0()</code>.</li>
<li>the exception unwinds through <code>g0()</code> and the handler in <code>h0()</code> is activated</li>
<li>the exception object is destroyed and the lifetime of the storage for the
exception ends when the handler in <code>h0()</code> exits.</li>
</ul>

<p>
Example 1: Consider the following case:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">g1</span>() <span class="org-keyword">throw</span>(<span class="org-type">X</span>) {
  <span class="org-keyword">try</span> { f(); }
  <span class="org-keyword">catch</span> (<span class="org-keyword">const</span> <span class="org-type">X</span>&amp;) { <span class="org-keyword">throw</span>; }
}

<span class="org-type">void</span> <span class="org-function-name">h1</span>() <span class="org-keyword">throw</span>() {
  <span class="org-keyword">try</span> { g1(); } <span class="org-keyword">catch</span> (<span class="org-keyword">const</span> <span class="org-type">X</span>&amp;) {}
}
</pre>
</div>

<p>
In this case:
</p>
<ul class="org-ul">
<li><code>h1()</code> allocates automatic-storage duration storage for an exception object of
type <code>X</code> and provides the address of this storage to <code>g1()</code>.</li>
<li>when <code>g1()</code> calls <code>f()</code> it forwards the address provided by <code>h1()</code> to <code>f()</code> and
<code>f()</code> constructs the exception object directly into the storage provided by <code>h1()</code>.</li>
<li>execution returns from <code>f()</code> and the handler in <code>g1()</code> is activated.</li>
<li>this handler then rethrows the exception - as the exception object is already
constructed in the final location there is no need to copy the object.</li>
<li>execution then returns to <code>h1()</code> and its handler is activated</li>
<li>the exception object is destroyed when the handler in <code>h1()</code> exits</li>
</ul>

<p>
Note that <code>g1()</code> in this case was able to pass the address of the storage for the exception
object provided by <code>h1()</code> to <code>f()</code> because there was no other exception object being
thrown by <code>g1()</code> whose lifetime overlaps with the lifetime of the exception object thrown
by <code>f()</code>.
</p>

<p>
Example 2: Consider the following case:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">g2</span>() <span class="org-keyword">throw</span>(<span class="org-type">X</span>) {
  <span class="org-keyword">try</span> { f(); }
  <span class="org-keyword">catch</span> (<span class="org-keyword">const</span> <span class="org-type">X</span>&amp; <span class="org-variable-name">x</span>) { <span class="org-keyword">throw</span> x; }
}

<span class="org-type">void</span> <span class="org-function-name">h2</span>() <span class="org-keyword">throw</span>() {
  <span class="org-keyword">try</span> { g2(); } <span class="org-keyword">catch</span> (<span class="org-keyword">const</span> <span class="org-type">X</span>&amp;) {}
}
</pre>
</div>

<p>
In this case:
</p>
<ul class="org-ul">
<li>The handler in <code>g2()</code> throws a new exception object insead of rethrowing the existing one</li>
<li>This means that the lifetime of the new exception object thrown by <code>g2()</code> overlaps the lifetime
of the exception object thrown by <code>f()</code>, which is alive until the handler is exited.</li>
<li>This means that <code>g2()</code> cannot reuse the storage for the exception object provided by <code>h2()</code>
to pass to <code>f()</code> and it needs to allocate its own automatic storage duration storage to
provide to <code>f()</code> for any exception object</li>
<li>When <code>f()</code> throws an exception it constructs into the storage in <code>g2()</code> and then unwinds
and activates the handler in <code>g2()</code>.</li>
<li>The <code>throw x;</code> statement in <code>g2()</code>'s handler then constructs a new exception object in
the storage provided by <code>h2()</code>.</li>
<li>When the handler in <code>g2()</code> exits, the exception object thrown by <code>f()</code> is destroyed
and its storage lifetime ends.</li>
<li>Control then unwinds to <code>h2()</code> and activates its handler.</li>
<li>When the handler in <code>h2()</code> exits, the exception object thrown by <code>g2()</code> is destroyed
and its storage lifetime ends.</li>
</ul>

<p>
Example 3: Consider the following case:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">g3</span>() <span class="org-keyword">throw</span>(<span class="org-type">X</span>) {
  <span class="org-keyword">try</span> { f(); }
  <span class="org-keyword">catch</span> (<span class="org-keyword">const</span> <span class="org-type">X</span>&amp; <span class="org-variable-name">x</span>) {
    <span class="org-keyword">if</span> (x.value &lt; 0) {
      <span class="org-keyword">throw</span> X{0}; <span class="org-comment-delimiter">// </span><span class="org-comment">throw a new object</span>
    }
    <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">rethrow</span>
  }

  <span class="org-type">void</span> <span class="org-variable-name">h3</span>() <span class="org-keyword">throw</span>() {
    <span class="org-keyword">try</span> { g3(); } <span class="org-keyword">catch</span> (<span class="org-keyword">const</span> <span class="org-type">X</span>&amp;) {}
  }
</pre>
</div>

<p>
In this case:
</p>
<ul class="org-ul">
<li>The handler in <code>g3()</code> conditionally either rethrows the current exception object
or throws a new exception object.</li>
<li>In the case that the handler throws a new object, we have a similar case to <code>g2()</code> where
there is overlap in lifetime between the exception object thrown by <code>f()</code> (whose lifetime
ends at the end of the current handler) and the new exception object created by the
<code>throw X{0};</code> statement.</li>
<li>This means that we cannot reuse the storage that <code>h3()</code> provided to <code>g3()</code> for returning
the exception as the storage that <code>g3()</code> provides to <code>f()</code> for returning its exception,
even though there is another code-path in <code>g3()</code>'s handler that rethrows the current
exception to <code>h3()</code>.</li>
<li>Instead, <code>g3()</code> will need to allocate its own local storage to provide to <code>f()</code>, and then
in both of the throw and rethrow-expressions, construct a new exception object in the storage
provided by <code>h3()</code> to <code>g3()</code>.</li>
<li>Note that in the rethrow-expression case, since the original exception object is about to
be destroyed, we may be able to move-construct the new exception object from the original
object instead of copy it as the <code>throw;</code> statement will exit the handler.
Note: This may not be the case for all rethrow expressions.</li>
</ul>

<p>
Example 4: Consider the following case:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">g4</span>() <span class="org-keyword">throw</span>(<span class="org-type">X</span>) {
  <span class="org-keyword">try</span> { f(); }
  <span class="org-keyword">catch</span> (<span class="org-keyword">const</span> <span class="org-type">X</span>&amp; <span class="org-variable-name">x</span>) { <span class="org-keyword">if</span> (x.value &gt;= 0) <span class="org-keyword">throw</span>; }
  <span class="org-keyword">throw</span> X{0};
}

<span class="org-type">void</span> <span class="org-function-name">h4</span>() {
  <span class="org-keyword">try</span> { g4(); } <span class="org-keyword">catch</span> (<span class="org-keyword">const</span> <span class="org-type">X</span>&amp;) {}
}
</pre>
</div>

<p>
In this case:
</p>
<ul class="org-ul">
<li>It is similar to the above <code>g3()</code> example, except that this time, the new exception object
is thrown from outside of the handler.</li>
<li>This means that the new exception object's lifetime no longer overlaps the lifetime of the
exception object thrown by <code>f()</code>.
If the exception object is rethrown by <code>g4()</code>'s handler then the exception object is already
constructed in the right location. Otherwise, the handler exits and the exception object
thrown by <code>f()</code> is destroyed before the new exception object is created by <code>throw X{0}</code>.</li>
<li>It is therefore safe for <code>g4()</code> to pass through the storage provided to it for the exception
object to the call to <code>f()</code>.</li>
</ul>
</div>
</li>
</ol>
</li>

<li><a id="org77a5fb9"></a>Rules for throw expressions<br />
<div class="outline-text-7" id="text-5-6-12-6-1-3">
<p>
The set of potentially-thrown exception types of a throw expression is the union of
</p>
<ul class="org-ul">
<li>the set of potentially-thrown exception types of the operand expression</li>
<li>the type of exception thrown. i.e. <code>std::decay_t&lt;decltype(&lt;expr&gt;)&gt;</code></li>
<li>the set of potentially-thrown exception type of copy-initialization of the exception-object</li>
</ul>

<p>
Additionally, if the throw-expression is a dynamic-throw-expression then the set of
potentially-thrown exception types also includes <code>std::bad_alloc</code>, which may be thrown
if the implementation fails to allocate storage for the exception object.
</p>
</div>
</li>
</ol>
</li>

<li><a id="org27a7f77"></a><code>throw</code> (rethrowing the currently handled exception)<br />
<div class="outline-text-6" id="text-5-6-12-6-2">
<p>
If the rethrow expression occurs lexically within the body of a handler and is not nested within
a locally defined function body or a lambda expression body defined in the scope of that handler,
then we say that the rethrow expression is associated with the inner-most enclosing handler.
</p>

<p>
Otherwise, we say that the rethrow expression is unassociated with a handler.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++">
<span class="org-type">void</span> <span class="org-function-name">example</span>() {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">unassociated - not inside handler</span>

  <span class="org-keyword">try</span> {
    <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">unassociated - not inside handler</span>
  } <span class="org-keyword">catch</span> (<span class="org-type">A</span> <span class="org-variable-name">a</span>) { <span class="org-comment-delimiter">// </span><span class="org-comment">#1</span>
    <span class="org-keyword">if</span> (<span class="org-negation-char">!</span>can_handle(a)) {
      <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">associated with #1</span>
    }

    <span class="org-keyword">auto</span> <span class="org-variable-name">rethrow</span> = [] {
      <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">unassociated - inside lambda</span>
    };

    <span class="org-keyword">struct</span> <span class="org-type">LocalClass</span> {
      <span class="org-keyword">static</span> <span class="org-type">void</span> <span class="org-function-name">Rethrow</span>() {
        <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">unassociated - inside nested function</span>
      }
    };
  } <span class="org-keyword">catch</span> (...) { <span class="org-comment-delimiter">// </span><span class="org-comment">#2</span>
    <span class="org-keyword">try</span> {
      <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">associated with #2</span>
    } <span class="org-keyword">catch</span> (<span class="org-type">B</span> <span class="org-variable-name">b</span>) { <span class="org-comment-delimiter">// </span><span class="org-comment">#3</span>
      <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">associated with #3</span>
    }
  }
}
</pre>
</div>

<p>
If a rethrow expression is associated with a handler then we potentially have more static information about
the set of possible exception types that might be thrown by that expression than a rethrow expression that
is unassociated with a handler.
</p>

<p>
We can compute the set of exception types that might be thrown by such a rethrow exception
based on the set of exception-types that may propagate out of the try-block and based on the exception
types that may be handled by handlers earlier in the sequence of handlers for that try-block.
</p>
</div>

<ol class="org-ol">
<li><a id="org677f4aa"></a>Unreachable handlers<br />
<div class="outline-text-7" id="text-5-6-12-6-2-1">
<p>
One of the interesting cases to handle is when we can statically determine whether the handler is
unreachable. This can happen in one of two cases:
</p>
<ul class="org-ul">
<li>When an earlier handler matches an unambiguous base-class of the later handler's exception-declaration type and
will therefore preferentially match any exception types that would be handled by the later later handler.</li>
<li>When the set of potentially thrown exception types of the try-block's <i>compound-statement</i> is a finite set
(i.e. does not contain contain <code>std::any_exception</code>) and there are no types in that finite set that match
this handler and that do not match any earlier handler.</li>
</ul>

<p>
In this case, there is the question of what the set of potentially-thrown exception types should be for
a rethrow expression that is associated with such an unreachable handler.
</p>

<p>
As the handler itself is statically determined to be unreachable, the body of the handler's compound-statement does
not contribute to the overall set of potentially-thrown exception types of the try-block, so we might say
"it doesn't matter".
</p>

<p>
However, if we consider the ability to query the set of potentially-thrown exception types
using <code>declthrow()</code> then a program might want to query within the context of the handler, what types might
be thrown by a rethrow expression. i.e. <code>declthrow(throw)...</code>.
</p>

<p>
The ability to query whether or not a given handler is reachable can be useful in eliminating code that would
otherwise be ill-formed, or that we want to avoid instantiating to reduce compile-times.
</p>

<p>
For example: Code for implementing the P2300 <code>std::execution::then()</code> algorithm needs to determine whether invoking
the transformation function might throw and only if it does then invoke the receiver with <code>set_error()</code>, otherwise
it should not form a call to <code>set_error()</code>.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span>... <span class="org-type">Args</span>&gt;
<span class="org-type">void</span> <span class="org-constant">then_receiver</span>::<span class="org-function-name">set_value</span>(<span class="org-type">Args</span>&amp;&amp;... <span class="org-variable-name">args</span>) <span class="org-keyword">noexcept</span> {
  <span class="org-keyword">try</span> {
    <span class="org-keyword">if</span> <span class="org-keyword">constexpr</span> (<span class="org-constant">std</span>::is_void_v&lt;<span class="org-keyword">decltype</span>(<span class="org-keyword">this</span>-&gt;func(<span class="org-constant">std</span>::forward&lt;<span class="org-type">Args</span>&gt;(args)...)&gt;) {
      <span class="org-keyword">this</span>-&gt;func(<span class="org-constant">std</span>::forward&lt;<span class="org-type">Args</span>&gt;(args)...);
      <span class="org-constant">std</span>::<span class="org-constant">execution</span>::set_value(<span class="org-keyword">this</span>-&gt;receiver);
    } <span class="org-keyword">else</span> {
      <span class="org-constant">std</span>::<span class="org-constant">execution</span>::set_value(<span class="org-keyword">this</span>-&gt;receiver, <span class="org-keyword">this</span>-&gt;func(<span class="org-constant">std</span>::forward&lt;<span class="org-type">Args</span>&gt;(args)...));
    }
  } <span class="org-keyword">catch</span> (...) {
    <span class="org-comment-delimiter">// </span><span class="org-comment">Only want to instantiate the call to set_error() if there are actually</span>
    <span class="org-comment-delimiter">// </span><span class="org-comment">any errors possible.</span>
    <span class="org-keyword">if</span> <span class="org-keyword">constexpr</span> (<span class="org-keyword">noexcept</span>(<span class="org-keyword">this</span>-&gt;func(<span class="org-constant">std</span>::forward&lt;<span class="org-type">Args</span>&gt;(args)...)) {
      <span class="org-constant">std</span>::<span class="org-constant">execution</span>::set_error(<span class="org-keyword">this</span>-&gt;receiver, <span class="org-constant">std</span>::current_exception());
    }
  }
}
</pre>
</div>

<p>
Note that here we need to repeat the essential parts of the body of the try-block in a
constexpr if condition noexcept expression to determine whether or not the <code>catch(...)</code> block
was reachable. And while, for this example, the body only has one such expression, it
is relatively easy to conceive of try-block logic that could be much more involved.
</p>

<p>
If, instead, we were able to query whether or not the handler was reachable by querying
the set of exception types that might be thrown by <code>throw;</code> within that handler, then
we could avoid having to duplicate the body expressions in the constexpr if condition.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span>... <span class="org-type">Args</span>&gt;
<span class="org-type">void</span> <span class="org-constant">then_receiver</span>::<span class="org-function-name">set_value</span>(<span class="org-type">Args</span>&amp;&amp;... <span class="org-variable-name">args</span>) <span class="org-keyword">noexcept</span> {
  <span class="org-keyword">try</span> {
    <span class="org-keyword">if</span> <span class="org-keyword">constexpr</span> (<span class="org-constant">std</span>::is_void_v&lt;<span class="org-keyword">decltype</span>(<span class="org-keyword">this</span>-&gt;func(<span class="org-constant">std</span>::forward&lt;<span class="org-type">Args</span>&gt;(args)...)&gt;) {
      <span class="org-keyword">this</span>-&gt;func(<span class="org-constant">std</span>::forward&lt;<span class="org-type">Args</span>&gt;(args)...);
      <span class="org-constant">std</span>::<span class="org-constant">execution</span>::set_value(<span class="org-keyword">this</span>-&gt;get_receiver());
    } <span class="org-keyword">else</span> {
      <span class="org-constant">std</span>::<span class="org-constant">execution</span>::set_value(<span class="org-keyword">this</span>-&gt;get_receiver(), <span class="org-keyword">this</span>-&gt;func(<span class="org-constant">std</span>::forward&lt;<span class="org-type">Args</span>&gt;(args)...));
    }
  } <span class="org-keyword">catch</span> (...) {
    <span class="org-comment-delimiter">// </span><span class="org-comment">Only want to instantiate the call to set_error() if there are actually</span>
    <span class="org-comment-delimiter">// </span><span class="org-comment">any errors possible.</span>
    <span class="org-comment-delimiter">//</span>
    <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow(throw)... will produce the empty pack if the try-block body</span>
    <span class="org-comment-delimiter">// </span><span class="org-comment">is not potentially-throwing.</span>
    <span class="org-keyword">if</span> <span class="org-keyword">constexpr</span> (<span class="org-keyword">sizeof</span>...(<span class="org-type">declthrow</span>(<span class="org-keyword">throw</span>)) != 0) {
      <span class="org-constant">std</span>::<span class="org-constant">execution</span>::set_error(<span class="org-keyword">this</span>-&gt;get_receiver(), <span class="org-constant">std</span>::current_exception());
    }
  }
}
</pre>
</div>

<p>
Another design direction that could be taken here is to allow writing the catch-all handler
as a template catch that is instantiated with an exception declaration of <code>std::exception_ptr</code>.
This could build upon the alternative suggested earlier for using <code>std::exception_ptr</code> in place
of <code>std::any_exception</code> for indicating the set of potenially-thrown exception types for a
call to a function with a dynamic exception specification.
</p>

<p>
If the body of the try-block had a set of potentially-thrown exception types that was empty
then the <code>template catch</code> handler would not be instantiated.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span>... <span class="org-type">Args</span>&gt;
<span class="org-type">void</span> <span class="org-constant">then_receiver</span>::<span class="org-function-name">set_value</span>(<span class="org-type">Args</span>&amp;&amp;... <span class="org-variable-name">args</span>) <span class="org-keyword">noexcept</span> {
  <span class="org-keyword">try</span> {
    <span class="org-keyword">if</span> <span class="org-keyword">constexpr</span> (<span class="org-constant">std</span>::is_void_v&lt;<span class="org-keyword">decltype</span>(<span class="org-keyword">this</span>-&gt;func(<span class="org-constant">std</span>::forward&lt;<span class="org-type">Args</span>&gt;(args)...)&gt;) {
      <span class="org-keyword">this</span>-&gt;func(<span class="org-constant">std</span>::forward&lt;<span class="org-type">Args</span>&gt;(args)...);
      <span class="org-constant">std</span>::<span class="org-constant">execution</span>::set_value(<span class="org-keyword">this</span>-&gt;get_receiver());
    } <span class="org-keyword">else</span> {
      <span class="org-constant">std</span>::<span class="org-constant">execution</span>::set_value(<span class="org-keyword">this</span>-&gt;get_receiver(), <span class="org-keyword">this</span>-&gt;func(<span class="org-constant">std</span>::forward&lt;<span class="org-type">Args</span>&gt;(args)...));
    }
  } <span class="org-keyword">template</span> <span class="org-keyword">catch</span> (<span class="org-keyword">auto</span>&amp; <span class="org-variable-name">error</span>) {
    <span class="org-comment-delimiter">// </span><span class="org-comment">Catch-block is only instantiated if there are any exceptions that might be thrown from code in the try-block.</span>
    <span class="org-comment-delimiter">// </span><span class="org-comment">If an exception is thrown by a 'throw(...)' function then 'error' will have type 'std::exception_ptr&amp;'.</span>
    <span class="org-constant">std</span>::<span class="org-constant">execution</span>::set_error(<span class="org-keyword">this</span>-&gt;get_receiver(), <span class="org-constant">std</span>::move(error));
  }
}
</pre>
</div>
</div>
</li>

<li><a id="org0490751"></a>Rethrow expression rules<br />
<div class="outline-text-7" id="text-5-6-12-6-2-2">
<p>
If the rethrow expression is unassociated with a handler then the set of potentially-thrown exception types
for that rethrow expression is equal to the set { <code>std::any_exception</code> }.
This is because the expression could potentially be executed within the dynamic scope of any handler and
thus could rethrow any caught exception type.
</p>

<p>
Otherwise, if the rethrow expression is associated with a handler, <i>H</i>, then;
</p>

<p>
Let <i>E</i> be the set of potentially-thrown exception types of the <i>compound-statement</i> of the try-block associated with <i>H</i>.
</p>

<p>
Let <i>H-pre</i> be the set of handlers associated with the same try-block as <i>H</i> that precede <i>H</i> in the try-block's <i>handler-seq</i>.
</p>

<p>
Let <i>X</i> be initially the empty set.
</p>

<p>
For each type, <code>e</code>, in the set <i>E</i>
</p>
<ul class="org-ul">
<li>if <code>e</code> is <code>std::any_exception</code> then
<ul class="org-ul">
<li>if the <i>exception-declaration</i> of <i>H</i> is <code>...</code> then add <code>std::any_exception</code> to the set <i>X</i></li>
<li>otherwise, let <code>h</code> be the type named in <i>H</i>'s <i>exception-declaration</i>
<ul class="org-ul">
<li>if any handler in <i>H-pre</i> matches exceptions of type <code>h</code> then, do nothing (this handler is unreachable)</li>
<li>otherwise, if <code>h</code> is of non-class type or is a final class then add <code>h</code> to <i>X</i></li>
<li>otherwise add <code>std::any_exception</code> to <i>X</i> (it might handle an unbounded set of potential exceptions derived from <code>h</code>)</li>
</ul></li>
</ul></li>
<li>otherwise,
<ul class="org-ul">
<li>if any handler in <i>H-pre</i> matches exceptions of type <code>e</code>, then do-nothing</li>
<li>otherwise, if <i>H</i> matches exceptions of type <code>e</code>, then add <code>e</code> to <i>X</i></li>
<li>otherwise, do nothing</li>
</ul></li>
</ul>

<p>
The set of potentially-thrown exception types for a rethrow expression associated with <i>H</i> is <i>X</i>.
</p>

<p>
Note that this algorithm can produce a set of potentially-thrown exception types that includes
a list of concrete exception types as well as <code>std::any_exception</code>.
</p>

<p>
Note that these rules make the result of a <code>declthrow(throw)</code> expression context dependent.
</p>

<p>
Note that each instantiation of a template handler has a separate set, <i>X</i>, of potentially-thrown
exception types that it handles. Thus a lexically-associated rethrow expression within a template
handler will have different sets of potentially-rethrown exception types for different instantiations.
The sets of potentially-rethrown exception types for each instantiation of a template handler will
be disjoint.
</p>
</div>
</li>

<li><a id="org0e1c0a7"></a>Examples<br />
<div class="outline-text-7" id="text-5-6-12-6-2-3">
<p>
Given the following declarations:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">struct</span> <span class="org-type">A</span> {};
<span class="org-keyword">struct</span> <span class="org-type">B</span> : <span class="org-type">A</span> {};
<span class="org-keyword">struct</span> <span class="org-type">C</span> : <span class="org-type">A</span> {};
<span class="org-keyword">struct</span> <span class="org-type">D</span> : <span class="org-type">B</span>, <span class="org-type">C</span> {};
<span class="org-keyword">struct</span> <span class="org-type">E</span> <span class="org-keyword">final</span> {};

<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span>... <span class="org-type">Ts</span>&gt;
<span class="org-type">void</span> <span class="org-function-name">throws</span>() <span class="org-keyword">throw</span>(<span class="org-type">Ts</span>...);
</pre>
</div>

<p>
Example 1: static exception list, catch(&#x2026;)
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">try</span> {
  throws&lt;A&gt;();
} <span class="org-keyword">catch</span> (...) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { A }</span>
}
</pre>
</div>

<p>
Example 2: static exception list, typed handler, unreachable catch (&#x2026;)
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">try</span> {
  throws&lt;A&gt;();
} <span class="org-keyword">catch</span> (A) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { A }</span>
} <span class="org-keyword">catch</span> (...) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { }</span>
}
</pre>
</div>

<p>
Example 3: multiple exceptions caught by single handler
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">try</span> {
  throws&lt;A, B&gt;();
} <span class="org-keyword">catch</span> (A) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { A, B }</span>
} <span class="org-keyword">catch</span> (...) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { }</span>
}
</pre>
</div>

<p>
Example 4: multiple exceptions caught by multiple handlers
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">try</span> {
  throws&lt;A, B&gt;();
} <span class="org-keyword">catch</span> (B) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { B }</span>
} <span class="org-keyword">catch</span> (A) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { A }</span>
} <span class="org-keyword">catch</span>  (...) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow - &gt; { }</span>
}
</pre>
</div>

<p>
Example 5: ambiguous bases
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">try</span> {
  throws&lt;D&gt;();
} <span class="org-keyword">catch</span> (A) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { } - empty because A is ambiguous base of D and so doesn't match</span>
} <span class="org-keyword">catch</span> (B) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { D } - catch (B) unambiguously handles exceptions of type D</span>
} <span class="org-keyword">catch</span> (C) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { } - already handled by catch (B)</span>
} <span class="org-keyword">catch</span> (D) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { } - already handled by catch (B)</span>
}
</pre>
</div>

<p>
Example 6: mixed static/dynamic
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">try</span> {
  throws&lt;A&gt;();
  throws&lt;<span class="org-constant">std</span>::any_exception&gt;();
} <span class="org-keyword">catch</span> (A) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { std::any_exception, A }</span>
} <span class="org-keyword">catch</span> (...) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { std::any_exception }</span>
}
</pre>
</div>

<p>
Example 7: dynamic throw with final class
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">try</span> {
  throws&lt;<span class="org-constant">std</span>::any_exception&gt;();
} <span class="org-keyword">catch</span> (E) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { E }</span>
} <span class="org-keyword">catch</span> (...) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { std::any_exception }</span>
}
</pre>
</div>

<p>
Example 8: mixed static/dynamic with final class
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">try</span> {
  throws&lt;E&gt;();
  throws&lt;<span class="org-constant">std</span>::any_exception&gt;();
} <span class="org-keyword">catch</span> (E) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { E }</span>
} <span class="org-keyword">catch</span> (...) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { std::any_exception }</span>
}
</pre>
</div>

<p>
Example 9: template handler, single type
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">try</span> {
  throws&lt;A&gt;();
} <span class="org-keyword">template</span> <span class="org-keyword">catch</span> (<span class="org-keyword">auto</span> <span class="org-variable-name">e</span>) { <span class="org-comment-delimiter">// </span><span class="org-comment">Instantiated for types { A }</span>
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { decltype(e) }</span>
}
</pre>
</div>

<p>
Example 10: template handler, multiple types
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">try</span> {
  throws&lt;A, B, C, D&gt;();
} <span class="org-keyword">template</span> <span class="org-keyword">catch</span> (<span class="org-keyword">auto</span> <span class="org-variable-name">e</span>) { <span class="org-comment-delimiter">// </span><span class="org-comment">Instantiated for following types { D, B, C, A }</span>
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { decltype(e) }</span>
}
</pre>
</div>

<p>
Example 11: template handler + non-template handler
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">try</span> {
  throws&lt;A, B, C, D&gt;();
} <span class="org-keyword">catch</span> (B) {
  <span class="org-keyword">throw</span>;  <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { B, D }</span>
} <span class="org-keyword">template</span> <span class="org-keyword">catch</span> (<span class="org-keyword">auto</span> <span class="org-variable-name">e</span>) { <span class="org-comment-delimiter">// </span><span class="org-comment">Instantiated for { C, A }</span>
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { decltype(e) } - either { A } or { C }</span>
}
</pre>
</div>

<p>
Example 12: template handler + non-template handler + dynamic throw
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">try</span> {
  throws&lt;A, B, C, D&gt;();
  throws&lt;<span class="org-constant">std</span>::any_exception&gt;();
} <span class="org-keyword">catch</span> (B) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { B, D, std::any_exception }</span>
} <span class="org-keyword">template</span> <span class="org-keyword">catch</span> (<span class="org-keyword">auto</span> <span class="org-variable-name">e</span>) { <span class="org-comment-delimiter">// </span><span class="org-comment">Instantiated for { C, A }</span>
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { decltype(e) }</span>
} <span class="org-keyword">catch</span> (...) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { std::any_exception }</span>
}
</pre>
</div>

<p>
Note that for example 12 the template handler is instantiated for
types A and C and rethrowing within the template handler only
rethrows those concrete types, despite the possibility of the
<code>throws&lt;std::any_exception&gt;()</code> potentially being able to throw
exceptions of type derived from either <code>C</code> or <code>A</code>.
</p>

<p>
Example 13: constrained template handler + non-template handler + dynamic throw
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">try</span> {
  throws&lt;A, B, C, D&gt;();
  throws&lt;<span class="org-constant">std</span>::any_exception&gt;();
} <span class="org-keyword">template</span> <span class="org-keyword">catch</span> (<span class="org-constant">std</span>::<span class="org-type">one_of</span>&lt;B, C&gt; <span class="org-keyword">auto</span> <span class="org-variable-name">e</span>) { <span class="org-comment-delimiter">// </span><span class="org-comment">instantiated for { B, C }</span>
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { decltype(e) }</span>
} <span class="org-keyword">catch</span> (A) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { A, D, std::any_exception }</span>
} <span class="org-keyword">catch</span> (...) {
  <span class="org-keyword">throw</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">declthrow -&gt; { std::any_exception }</span>
}
</pre>
</div>

<p>
Note that with this example, the compiler tries to instantiate the template
handler for each of the static exception types, but substitution fails for
types A and D, succeeding only for types B and C.
</p>

<p>
The handler for A matches A and D and potentially also an unbounded set of other types derived from A.
</p>

<p>
The final handler matches an unbounded set of types not derived from A.
</p>
</div>
</li>
</ol>
</li>
</ol>
</li>

<li><a id="org9a696ef"></a><i>await-expression</i><br />
<div class="outline-text-5" id="text-5-6-12-7">
<p>
An expression of the form <code>co_await /expression/</code> has a set of potentially-thrown exception
types equal to union of the sets of potentially-thrown exception types of each of the
sub-expressions that the <i>await-expression</i> de-composes into.
</p>

<p>
Including:
</p>
<ul class="org-ul">
<li>The operand <i>expression</i></li>
<li>The call to <code>p.await_transform(expr)</code>, if applicable.</li>
<li>The call to member or non-member <code>operator co_await</code>, if applicable.</li>
<li>The calls to <code>await_ready()</code>, <code>await_suspend()</code> and <code>await_resume()</code>.</li>
<li>A call to the destructors of any temporary objects created as a result of one of the above sub-expressions</li>
</ul>

<p>
Note that if one of the sub-expressions is an <i>interrupted-flow expression</i> then we still consider the
set of potentially-thrown exception types of subsequently evaluated sub-expressions even though they
may be unreachable. If we want to consider ignoring unreachable sub-expressions then this should be
applied more generally across all expression evaluation.
</p>
</div>
</li>

<li><a id="org4691a99"></a><i>yield-expression</i><br />
<div class="outline-text-5" id="text-5-6-12-8">
<p>
A <code>co_yield /assignment-expression/</code> or <code>co_yield /braced-init-list/</code> expression has a
set of potentially-thrown exception types equal to the union of the sets of the potentially
thrown exception types of the expression <code>co_await promise.yield_value(expr)</code>, where
<code>promise</code> is an lvalue reference that refers to the current coroutine's promise object.
</p>

<p>
Note that the call to <code>promise.await_transform()</code> is not applied as part of a
<code>co_yield</code> expression, so does not contribute to the set of exception types.
</p>
</div>
</li>

<li><a id="org3de8e01"></a><code>dynamic_cast</code><br />
<div class="outline-text-5" id="text-5-6-12-9">
<p>
Basically, any <code>dynamic_cast</code> expression to reference-type that could fail the runtime
check has a set of potentially-thrown exception types equal to the set { <code>std::bad_cast</code> }.
</p>

<p>
A <code>dynamic_cast</code> expression that is a cast to pointer-type or that was a cast to a reference
type that would not fail (e.g. because it was a cast to an unambiguous base-class of the operand's class type)
has an empty set of potentially-throw exception types.
</p>

<p>
Note that the wording of <code>dynamic_cast</code> currently permits implementations to throw some type
that would match a handler of type <code>std::bad_cast</code>, which currently permits throwing types
derived from <code>std::bad_cast</code>.
This change would require that the exception thrown was exactly the type <code>std::bad_cast</code>.
</p>
</div>
</li>

<li><a id="orgf429de9"></a><code>typeid</code><br />
<div class="outline-text-5" id="text-5-6-12-10">
<p>
A <code>typeid(/type-id/)</code> expression has an empty set of potentially-thrown exception types.
</p>

<p>
A <code>typeid(/expression/)</code> expression has a set of potentially-thrown exception types equal
to { <code>std::bad_typeid</code> }. This exception may be thrown if the operand of the <code>typeid</code>
expression is the result of dereferencing a null pointer of non-cv type.
</p>


<p>
While this behaviour matches the current specification of <code>typeid</code> expressions, supporting
the ability to ask for the type of a dereferenced null pointer seems to be of questionable
value. The wording for the builtin unary <code>*</code> operator in [expr.unary.op] says that the behaviour
of performing an indirection on a pointer that does not point to a function or object is
undefined <i>except as specified in [expr.typeid]</i>.
</p>

<p>
So, literally the only thing you can do with an lvalue produced by dereferencing a null pointer
is pass it to a <code>typeid</code> expression.
</p>

<p>
It may be worth exploring whether we can either deprecate/remove this behaviour from <code>typeid</code>
(which would be a breaking change) or whether we can add a new form of <code>typeid(/expression/)</code>
that has a precondition that the <i>expression</i> does result in an glvalue that refers to an
object or function. i.e. such that passing a dereferenced null pointer is undefined-behaviour.
</p>

<p>
This would allow the set of potentially-thrown exception types for a <code>typeid</code> expression
to be empty.
</p>
</div>
</li>

<li><a id="org59da980"></a>Name expressions<br />
<div class="outline-text-5" id="text-5-6-12-11">
<p>
Expressions that simply name an object
</p>

<p>
These expressions include:
</p>
<ul class="org-ul">
<li><i>id-expression</i></li>
<li><code>this</code></li>
</ul>

<p>
These expressions have an empty set of potentially thrown exception types.
</p>
</div>
</li>

<li><a id="org355a506"></a>Lambda expressions<br />
<div class="outline-text-5" id="text-5-6-12-12">
<p>
The set of potentially-thrown exception types of a lambda expression are
the union of the set of potentially thrown exception types of the initializers
of the lambda captures.
</p>
</div>
</li>
</ol>
</div>
</div>

<div id="outline-container-org283635a" class="outline-3">
<h3 id="org283635a"><span class="section-number-3">5.7.</span> Template handlers</h3>
<div class="outline-text-3" id="text-5-7">
<p>
Template handlers are the static-exception equivalent of a <code>catch(...)</code>.
</p>

<p>
They allow a generic handler to be written that can be instantiated to handle any
number of exception types statically. The compiler instantiates the handler based
on the set of potentially-thrown exception types computed for the body of the
corresponding <code>try</code> block which were not caught by any preceding handlers.
</p>

<p>
The short-hand syntax allows the user to prefix the <code>catch</code> keyword with the
<code>template</code> keyword and then use a <i>placeholder-type-specifier</i> as the <i>exception-declaration</i>.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">do_something</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>, <span class="org-type">B</span>, <span class="org-type">C</span>);

<span class="org-keyword">try</span> {
  do_something();
} <span class="org-keyword">template</span> <span class="org-keyword">catch</span> (<span class="org-keyword">auto</span> <span class="org-variable-name">e</span>) {
  <span class="org-comment-delimiter">// </span><span class="org-comment">catch-block instantiated for each unique type in the static-exception specification</span>
  <span class="org-comment-delimiter">// </span><span class="org-comment">In this case where 'e' has type A, B or C.</span>
}
</pre>
</div>

<p>
The <code>template</code> keyword is technically redundant in this case as we could deduce that the handler
is a template from the use of a <i>placeholder-type-specifier</i>. However, the use of the keyword
<code>template</code> here can also serve as an indication in code that something a bit different is going
on.
</p>

<p>
The requirement for the <code>template</code> keyword could potentially be dropped in this case if desired
to match consistency with the syntax for function declarations.
</p>

<p>
The short-hand syntax also allows a trailing <i>requires-clause</i> to be added after the <i>exception-declaration</i>
to allow introducing type-constraints on the instantiation of the template handler.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">do_something</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>, <span class="org-type">B</span>, <span class="org-type">C</span>);

<span class="org-keyword">try</span> {
  do_something();
} <span class="org-keyword">template</span> <span class="org-keyword">catch</span> (<span class="org-keyword">auto</span> <span class="org-variable-name">e</span>) <span class="org-type">requires</span> <span class="org-constant">std</span>::<span class="org-type">derived_from</span>&lt;<span class="org-keyword">decltype</span>(e), <span class="org-constant">std</span>::exception&gt; {
  <span class="org-comment-delimiter">// </span><span class="org-comment">catch block only instantiated for types that inherit from ~std::exception~.</span>
  LOG(<span class="org-string">"error: %s"</span>, ex.what());
} <span class="org-keyword">template</span> <span class="org-keyword">catch</span> (<span class="org-keyword">auto</span> <span class="org-variable-name">e</span>) {
  <span class="org-comment-delimiter">// </span><span class="org-comment">handle types not inherited from std::exception</span>
}
</pre>
</div>

<p>
The more general syntax for a template catch-block allows the use of a <i>template-head</i> before the
<code>catch</code> keyword and then refer to to a dependent type that allows any template parameters declared
in the <i>template-head</i> to be deduced from the type of the exception.
</p>

<p>
For example: Alternative to <code>template catch (auto e)</code> using the <i>template-head</i> syntax
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">try</span> {
  do_something();
 }
 <span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">T</span>&gt;
 <span class="org-keyword">catch</span> (<span class="org-type">T</span> <span class="org-variable-name">e</span>) {
   <span class="org-comment-delimiter">//</span><span class="org-comment">... do something with 'e'</span>
}
</pre>
</div>

<p>
For example: Using constraints and deduced template arguments for a class template
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">Inner</span>&gt;
<span class="org-keyword">struct</span> <span class="org-type">MyException</span> : <span class="org-constant">std</span>::<span class="org-type">exception</span> {
  <span class="org-keyword">const</span> <span class="org-type">char</span>* <span class="org-function-name">what</span>() <span class="org-keyword">noexcept</span> <span class="org-keyword">override</span> { <span class="org-keyword">return</span> <span class="org-string">"MyException"</span>; }
  <span class="org-type">Inner</span> <span class="org-variable-name">inner</span>;
};

<span class="org-keyword">try</span> {
  do_something();
}
<span class="org-keyword">template</span>&lt;<span class="org-constant">std</span>::<span class="org-type">derived_from</span>&lt;<span class="org-constant">std</span>::exception&gt; <span class="org-variable-name">Inner</span>&gt;
<span class="org-type">requires</span> (<span class="org-negation-char">!</span><span class="org-constant">std</span>::<span class="org-type">derived_from</span>&lt;<span class="org-type">Inner</span>, <span class="org-constant">std</span>::runtime_exception&gt;)
<span class="org-keyword">catch</span> (<span class="org-keyword">const</span> <span class="org-type">MyException</span>&lt;<span class="org-type">Inner</span>&gt;&amp; <span class="org-variable-name">err</span>) {
  LOG(<span class="org-string">"Failed with MyException because: {}"</span>, err.inner.what());
}
</pre>
</div>

<p>
Template handlers can also then be used with <code>if constexpr</code> to handle
a given exception based on static properties of the exception type.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">T</span>, <span class="org-keyword">typename</span> <span class="org-type">Inner</span>&gt;
<span class="org-keyword">struct</span> <span class="org-type">NestedException</span> : <span class="org-keyword">public</span> <span class="org-type">T</span> {
  <span class="org-type">Inner</span> <span class="org-variable-name">inner</span>;
};

<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">T</span>&gt;
<span class="org-keyword">constexpr</span> <span class="org-type">bool</span> <span class="org-variable-name">is_nested_v</span> = <span class="org-constant">false</span>;
<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">T</span>, <span class="org-keyword">typename</span> <span class="org-type">Inner</span>&gt;
<span class="org-keyword">constexpr</span> <span class="org-type">bool</span> <span class="org-type">is_nested_v</span>&lt;<span class="org-type">NestedException</span>&lt;<span class="org-type">T</span>, <span class="org-type">Inner</span>&gt;&gt; = <span class="org-constant">true</span>;

<span class="org-type">void</span> <span class="org-function-name">foo</span>() <span class="org-keyword">throw</span>(<span class="org-type">FooError</span>,
                 <span class="org-type">NestedException</span>&lt;FooError, <span class="org-constant">std</span>::bad_alloc&gt;,
                 <span class="org-type">NestedException</span>&lt;FooError, <span class="org-constant">std</span>::system_error&gt;);

<span class="org-keyword">try</span> {
  foo();
} <span class="org-keyword">template</span> <span class="org-keyword">catch</span> (<span class="org-constant">std</span>::<span class="org-type">derived_from</span>&lt;FooError&gt; <span class="org-keyword">auto</span> <span class="org-variable-name">err</span>) {
  <span class="org-comment-delimiter">// </span><span class="org-comment">generic FooError handling</span>
  <span class="org-keyword">if</span> <span class="org-keyword">constexpr</span> (<span class="org-type">is_nested_v</span>&lt;<span class="org-keyword">decltype</span>(err)&gt;) {
    <span class="org-constant">std</span>::print(<span class="org-string">"error: Failed with FooError because {}"</span>, err.inner);
  } <span class="org-keyword">else</span> {
    <span class="org-constant">std</span>::print(<span class="org-string">"error: Failed with FooError"</span>);
  }
}
</pre>
</div>
</div>

<div id="outline-container-orgf8e04ae" class="outline-4">
<h4 id="orgf8e04ae"><span class="section-number-4">5.7.1.</span> Template argument deduction</h4>
<div class="outline-text-4" id="text-5-7-1">
<p>
When the compiler is trying to determine which handler, if any, will match
a static exception object thrown from the body of a <i>try-block</i>, it proceeds
to try each handler in order. If a handler matches the exception type then
the compiler stops searching and does not look at any subsequent handlers.
</p>

<p>
If, during the search for a matching handler, the compiler encounters a template
handler, then the compiler performs the following to determine whether the
handler is a match:
</p>
<ul class="org-ul">
<li>Attempts to deduce template arguments of the template handler by treating
the handler as if it were a function template with a single argument and
then forming a call to that function-template, passing a single argument
which is a non-const lvalue reference to the static exception object.
However, this is done with the restriction that the only conversions allowed
are implicit conversion to an unambiguous base-class.</li>
<li>If template argument deduction fails then the handler is not a match.</li>
<li>Otherwise, if template argument deduction succeeds, then any constraints
are evaluated using those deduced template arguments.</li>
<li>If those constraints are not satisfied then the handler is not a match.</li>
<li>Otherwise, the handler is a match and the body of the handler is instantiated
with the deduced template arguments, substituting those template arguments
into the body of the handler. The resulting handler instantiation becomes
the handler for static exception objects of that type.</li>
</ul>

<p>
If a handler template is never instantiated (i.e. because it did not match
any thrown static exception object types) then the <i>compound-statement</i> of
that handler does not contribute any statements to the body of the enclosing
function.
</p>

<p>
This can potentially affect the return-type of a function with a deduced return-type.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">auto</span> <span class="org-function-name">example</span>(<span class="org-keyword">auto</span> <span class="org-variable-name">f</span>) <span class="org-keyword">throw</span>(<span class="org-type">X</span>) {
  <span class="org-keyword">try</span> {
    f();
  }
  <span class="org-keyword">template</span> <span class="org-keyword">catch</span> (<span class="org-keyword">auto</span> <span class="org-variable-name">err</span>) {
    <span class="org-keyword">return</span> err;
  }

  <span class="org-keyword">throw</span> X{};
}

example([] <span class="org-keyword">throw</span>() {}); <span class="org-comment-delimiter">// </span><span class="org-comment">deduces return type to be 'void' as return statement never instantiated</span>
example([] <span class="org-keyword">throw</span>(<span class="org-type">int</span>) {}); <span class="org-comment-delimiter">// </span><span class="org-comment">deduces return type to be 'int' - single return statement</span>
example([] <span class="org-keyword">throw</span>(<span class="org-type">int</span>, <span class="org-type">long</span>) {}); <span class="org-comment-delimiter">// </span><span class="org-comment">ill-formed: multiple return statements with different deduced return types</span>
</pre>
</div>
</div>
</div>

<div id="outline-container-orgca7c6e5" class="outline-4">
<h4 id="orgca7c6e5"><span class="section-number-4">5.7.2.</span> Matching dynamic exception objects</h4>
<div class="outline-text-4" id="text-5-7-2">
<p>
The proposed design is such that a template handler does not match a thrown
dynamic exception object, so if the body contains any <code>throw(...)</code> expressions
then the handler sequence will still require a <code>catch(...)</code> handler as the
last handler to handle those.
</p>

<p>
However, one design direction being explored is to allow a dynamic-exception-object
to match template and non-template handlers as if the exception object had type
<code>std::exception_ptr</code>. In this case, a <code>template catch (auto e)</code> would be
instantiated with <code>decltype(e)</code> deduced to <code>std::exception_ptr</code>.
</p>
</div>
</div>

<div id="outline-container-org70b1a5e" class="outline-4">
<h4 id="org70b1a5e"><span class="section-number-4">5.7.3.</span> Ordering of instantiated handlers</h4>
<div class="outline-text-4" id="text-5-7-3">
<p>
For the purposes of determining which handler is a match, instantiations of a given
handler template are unordered. If multiple instantiations would potentially match a
given handler when written out then which one is chosen is determined by deducing
template arguments and choosing that instantiation rather than looking at which one
appears earlier in a list of instantiations.
</p>
</div>
</div>
</div>

<div id="outline-container-org888225e" class="outline-3">
<h3 id="org888225e"><span class="section-number-3">5.8.</span> Virtual Functions</h3>
<div class="outline-text-3" id="text-5-8">
<p>
Virtual functions declared on a base-class can potentially have a different (wider) exception
specification than an override of that virtual function declared in a derived class.
</p>

<p>
For example: A base class might declare a virtual function as <code>noexcept(false)</code> whereas a
derived class might declare its override as <code>noexcept(true)</code>.
</p>

<p>
However, a derived class cannot have an exception-specification that is wider than the base
class method. Callers of a base-class virtual method marked <code>noexcept</code> can rightly expect that
derived classes cannot override this method to start throwing exceptions from the call.
</p>

<p>
If we want to extend this idea to throw-specifications, then we need to require that
an override of a virtual function does not widen the set of potentially-thrown exception
types.
</p>

<p>
If a base class has a virtual function with an exception specification that is
<code>noexcept(false)</code> or <code>throw(...)</code> then an override of this function in a derived
class can have any exception-specifier.
</p>

<p>
Example 1
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">struct</span> <span class="org-type">base</span> {
  <span class="org-keyword">virtual</span> <span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>(...);
};

<span class="org-keyword">struct</span> <span class="org-type">derived1</span> : <span class="org-type">base</span> {
  <span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>() <span class="org-keyword">override</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">OK</span>
};
<span class="org-keyword">struct</span> <span class="org-type">derived2</span> : <span class="org-type">base</span> {
  <span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>, <span class="org-type">B</span>, <span class="org-type">C</span>) <span class="org-keyword">override</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">OK</span>
};
<span class="org-keyword">struct</span> <span class="org-type">derived3</span> : <span class="org-type">base</span> {
  <span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>(...) <span class="org-keyword">override</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">OK</span>
};
</pre>
</div>

<p>
If a base-class has a virtual function with an exception specification that is
<code>noexcept(true)</code> or <code>throw()</code> then an override of this function must also have
an exception specification that is either <code>noexcept(true)</code> or <code>throw()</code>.
</p>

<p>
Example 2
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">struct</span> <span class="org-type">base</span> {
  <span class="org-keyword">virtual</span> <span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>();
};

<span class="org-keyword">struct</span> <span class="org-type">derived1</span> : <span class="org-type">base</span> {
  <span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>() <span class="org-keyword">override</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">OK</span>
};
<span class="org-keyword">struct</span> <span class="org-type">derived2</span> : <span class="org-type">base</span> {
  <span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>, <span class="org-type">B</span>, <span class="org-type">C</span>) <span class="org-keyword">override</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">ERROR: f() has wider exception specification than base::f()</span>
};
<span class="org-keyword">struct</span> <span class="org-type">derived3</span> : <span class="org-type">base</span> {
  <span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>(...) <span class="org-keyword">override</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">ERROR: f() has wider exception specification than base::f()</span>
};
</pre>
</div>

<p>
If a base-class has a virtual function with a non-empty static exception specification
then an override of this function must have a static exception specification that
is a subset of the set of exception types listed in the base class exception specification.
</p>

<p>
Example 3
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">struct</span> <span class="org-type">base</span> {
  <span class="org-keyword">virtual</span> <span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>, <span class="org-type">B</span>);
};

<span class="org-keyword">struct</span> <span class="org-type">derived1</span> : <span class="org-type">base</span> {
  <span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>, <span class="org-type">B</span>) <span class="org-keyword">override</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">OK</span>
};
<span class="org-keyword">struct</span> <span class="org-type">derived2</span> : <span class="org-type">base</span> {
  <span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>) <span class="org-keyword">override</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">OK</span>
};
<span class="org-keyword">struct</span> <span class="org-type">derived3</span> : <span class="org-type">base</span> {
  <span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>(<span class="org-type">B</span>) <span class="org-keyword">override</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">OK</span>
};
<span class="org-keyword">struct</span> <span class="org-type">derived4</span> : <span class="org-type">base</span> {
  <span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>() <span class="org-keyword">override</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">OK</span>
};
<span class="org-keyword">struct</span> <span class="org-type">derived5</span> : <span class="org-type">base</span> {
  <span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>, <span class="org-type">C</span>) <span class="org-keyword">override</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">ERROR: Throws C which is not allowed by base::f() throw specification</span>
};
<span class="org-keyword">struct</span> <span class="org-type">derived6</span> : <span class="org-type">base</span> {
  <span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>(...) <span class="org-keyword">override</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">ERROR: f() has wider exception specification than base::f().</span>
};
</pre>
</div>

<p>
It is worth noting here that virtual function overrides are only permitted to throw
a subset of the set of types listed in the throw-specification of the base class declaration.
They are not permitted to throw types not listed in the throw-specification that are derived
from the types listed in the base class declaration.
</p>

<p>
Virtual functions that want to allow overrides to throw types not listed in the
base class function's throw-specification should declare the base-class virtual
function with the <code>noexcept(false)</code> or <code>throw(...)</code> specifier to indicate that
a dynamic exception type may be thrown.
</p>

<p>
Alternatively, the base class function declaration can list an exception type
that can allow derived types to extend with different values it can hold.
e.g. <code>std::error_code</code>
</p>
</div>

<div id="outline-container-org9682a36" class="outline-4">
<h4 id="org9682a36"><span class="section-number-4">5.8.1.</span> ABI of virtual functions with differing exception specifications</h4>
<div class="outline-text-4" id="text-5-8-1">
<p>
While the language semantics described above are a natural extension of the current rules around
noexcept, they do have some impacts on what implementations need to do to provide these
semantics.
</p>

<p>
A virtual function with a non-empty static exception-specification can have a different
calling-convention to a function with a different exception-specification.
</p>

<p>
This means that in cases where an override chooses to narrow the exception specification
that we may not be able to directly use a pointer to the overridden function in the
vtable slot used for a call that dispatches statically via the base class interface
as the calling conventions may not match.
</p>

<p>
This is a similar case to how the compiler needs to handle overrides that can have
covariant return-types that return a pointer/reference to some type that is derived
from the return-type of the base class function.
</p>

<p>
In many cases the ABI of the override that returns a derived type is the same as the
ABI of the base class function.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">struct</span> <span class="org-type">base</span> {
  <span class="org-keyword">virtual</span> <span class="org-type">base</span>* <span class="org-function-name">clone</span>();
};
<span class="org-keyword">struct</span> <span class="org-type">derived</span> : <span class="org-type">base</span> {
  <span class="org-type">derived</span>* <span class="org-function-name">clone</span>() <span class="org-keyword">override</span>;
};
</pre>
</div>

<p>
In this case, the <code>derived</code> class has the <code>base</code> class as its first sub-object
and so the address of the <code>derived</code> object returned by <code>derived::clone()</code> can be
reused as the address of the <code>base</code> object and so the vtable entries for calling
<code>base::clone()</code> and <code>derived::clone()</code> can be the same.
</p>

<p>
However, if you consider:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">struct</span> <span class="org-type">base</span> {
  <span class="org-keyword">virtual</span> <span class="org-type">base</span>* <span class="org-function-name">clone</span>();
};
<span class="org-keyword">struct</span> <span class="org-type">other_base</span> {
  <span class="org-keyword">virtual</span> <span class="org-constant">std</span>::<span class="org-type">string</span> <span class="org-function-name">to_string</span>();
};
<span class="org-keyword">struct</span> <span class="org-type">derived</span> : <span class="org-type">other_base</span>, <span class="org-type">base</span> {
  derived* clone() <span class="org-keyword">override</span>;
};
</pre>
</div>

<p>
Now, the <code>base</code> object is not necessarily the first sub-object of a <code>derived</code> and
so the pointer returned by <code>derived::clone()</code> may need to be adjusted by an offset
when called via the <code>base::clone()</code> interface so that the returned pointer refers
to the <code>base</code> sub-object.
</p>

<p>
This means that the vtable entry for <code>base::clone()</code> cannot just contain the address
of the <code>derived::clone()</code> function as it would return an address that was not a
pointer to the <code>base</code> sub-object.
</p>

<p>
Instead, the table entry for <code>base::clone()</code> in the <code>derived</code> type's vtable contains
the address of a "thunk" - a function stub that forwards the call onto the real
implementation and then adjusts the returned address by applying the necessary offset.
</p>

<p>
When a call is made via the <code>derived::clone()</code> interface, it instead dispatches to
a separate vtable entry that directly calls the <code>derived::clone()</code> function.
</p>

<p>
The same approach would be required whenever a base-class virtual function is overridden
by a derived class that has an exception-specification that differs such that it has a
different calling convention and is thus ABI incompatible with the ABI of the base
class function's ABI.
</p>

<p>
These thunks would be the kind of thunk that is generated when you cast a function
to a function-pointer with a different exception-specification, described in
<a href="#orgd5fc979">Static exception specifications are part of the function type</a>.
</p>
</div>
</div>
</div>

<div id="outline-container-org7fda6d1" class="outline-3">
<h3 id="org7fda6d1"><span class="section-number-3">5.9.</span> Concepts</h3>
<div class="outline-text-3" id="text-5-9">
<p>
A <code>requires</code> expression allows checking that certain expressions are <code>noexcept</code>.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">T</span>, <span class="org-keyword">typename</span> <span class="org-type">U</span>&gt;
<span class="org-type">concept</span> <span class="org-variable-name">nothrow_assignable_from</span> =
  requires(<span class="org-type">T</span> <span class="org-variable-name">t</span>, <span class="org-type">U</span> <span class="org-variable-name">u</span>) {
    { <span class="org-keyword">static_cast</span>&lt;<span class="org-type">T</span>&amp;&amp;&gt;(t) = <span class="org-keyword">static_cast</span>&lt;<span class="org-type">U</span>&amp;&amp;&gt;(u) } <span class="org-keyword">noexcept</span>;
  };
</pre>
</div>

<p>
This concept checking that the assignment expression is valid and that the set
of potentially thrown exceptions for the expression is the empty set.
</p>

<p>
It is equivalent to the following, only without the repetition of expressions:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">T</span>, <span class="org-keyword">typename</span> <span class="org-type">U</span>&gt;
<span class="org-type">concept</span> <span class="org-variable-name">nothrow_assignable_from</span> =
  requires(<span class="org-type">T</span> <span class="org-variable-name">t</span>, <span class="org-type">U</span> <span class="org-variable-name">u</span>) {
    <span class="org-keyword">static_cast</span>&lt;<span class="org-type">T</span>&amp;&amp;&gt;(t) = <span class="org-keyword">static_cast</span>&lt;<span class="org-type">U</span>&amp;&amp;&gt;(u);
  } &amp;&amp;
  <span class="org-keyword">noexcept</span>(<span class="org-constant">std</span>::declval&lt;<span class="org-type">T</span>&amp;&amp;&gt;() = <span class="org-keyword">static_cast</span>&lt;<span class="org-type">U</span>&amp;&amp;&gt;(u));
</pre>
</div>

<p>
If we are to introduce static exception specifications then it seems reasonable to
also want to extend the requires-expression syntax with the ability to check that
the set of potentially-thrown exceptions from an expression satisfies some requirement.
</p>

<p>
For example, say we wanted to check that a given member-function-call could only throw <code>std::bad_alloc</code>,
we we could allow the user to write something like:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">T</span>&gt;
<span class="org-type">concept</span> <span class="org-variable-name">foo_factory</span> =
  requires(<span class="org-type">T</span>&amp; <span class="org-variable-name">obj</span>) {
    { obj.make_foo() } <span class="org-keyword">throw</span>(<span class="org-constant">std</span>::<span class="org-type">bad_alloc</span>) -&gt; foo_concept;
  };
</pre>
</div>

<p>
However, from this syntax it's not clear exactly what the semantics of such a check should be.
It could be:
</p>
<ul class="org-ul">
<li>Check that the set of potentially-thrown exceptions is a subset of the listed types.
e.g. because it needs to be callable from a function with a <code>throw(std::bad_alloc)</code> specifier.</li>
<li>Check that the set of potentially-thrown exceptions would be caught by a handler whose
exception-declaration is <code>std::bad_alloc</code>.
e.g. because the expression needs to be callable from within a <code>noexcept</code> function but is
surrounded by a try/catch that catches and handles <code>std::bad_alloc</code>.</li>
</ul>

<p>
This confusion/ambiguity is similar to the one that was raised during the design of concepts
for C++20 - is a <code>{ expr } -&gt; T;</code> clause in a requires-expression checking that the expression
results in exactly type <code>T</code>, or is it checking that the expression is convertible to type <code>T</code>?
</p>

<p>
The approach taken to resolve this was to require that you specify a concept that the result of
the expresion needs to match. This forces the user to be explicit about intent.
i.e. either write <code>std::same_as&lt;T&gt;</code> or <code>std::convertible_to&lt;T&gt;</code>.
</p>

<p>
Thus this paper proposes taking a similar approach.
i.e. to extend the <i>compound-requirement</i> as follows:
</p>

<div class="org-src-container">
<pre class="src src-text">/compound-requirement/:
   { /expression/ } /exception-requirement[opt]/ /return-type-requirement[opt]/ ;

/exception-requirement/:
   noexcept
   /throw-requirement/

/throw-requirement/:
   throw ( /type-constraint/ )
</pre>
</div>

<p>
The propsed semantics of providing a <i>throw-requirement</i> as part of a <i>compound-requirement</i> are as follows.
</p>

<p>
The set of potentially-thrown exceptions is computed by applying <code>declthrow()</code> query to the expression.
</p>

<p>
The requirement is satisfied if, for each type produced in the expanded pack produced by the <code>declthrow()</code>
query, the type satisfies the specified <i>type-constraint</i>.
</p>

<p>
i.e. If the <i>throw-requirement</i> was <code>throw(C)</code>, then the requirement is satisfied if <code>(C&lt;declthrow(expr)&gt; &amp;&amp; ...)</code> is <code>true</code>.
</p>

<p>
If we wanted the above example to mean "Any exceptions caught by a handler for type <code>std::bad_alloc</code>"
then we could write the concept as follows:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">T</span>&gt;
<span class="org-type">concept</span> <span class="org-variable-name">foo_factory</span> =
  requires(<span class="org-type">T</span>&amp; <span class="org-variable-name">obj</span>) {
    { obj.make_foo() } <span class="org-keyword">throw</span>(<span class="org-constant">std</span>::<span class="org-type">derived_from</span>&lt;<span class="org-constant">std</span>::bad_alloc&gt;) -&gt; foo_concept;
</pre>
</div>

<p>
Or, if you want to check that the only exception thrown (if any) is exactly <code>std::bad_alloc</code> then
replace the use of <code>std::derived_from</code> with <code>std::same_as</code>.
</p>

<p>
To handle the case where you want the expression to be one of a set of types,
e.g. because the expression is called from a function that is only allowed to
emit those exception types, you can use the <code>one_of</code> concept helper.
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">T</span>, <span class="org-keyword">typename</span>... <span class="org-type">Ts</span>&gt;
<span class="org-type">concept</span> <span class="org-variable-name">one_of</span> = (<span class="org-constant">std</span>::<span class="org-type">same_as</span>&lt;<span class="org-type">T</span>, <span class="org-type">Ts</span>&gt; || ...);

<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">T</span>&gt;
<span class="org-type">concept</span> <span class="org-variable-name">foo_factory</span> =
  requires(<span class="org-type">T</span>&amp; <span class="org-variable-name">obj</span>) {
    { obj.make_foo() } <span class="org-keyword">throw</span>(<span class="org-constant">std</span>::<span class="org-type">one_of</span>&lt;A, B, C&gt;) -&gt; foo_concept;
  };

<span class="org-type">void</span> <span class="org-function-name">usage</span>(<span class="org-type">foo_factory</span> <span class="org-keyword">auto</span>&amp; <span class="org-variable-name">factory</span>) <span class="org-keyword">throw</span>(<span class="org-type">A</span>, <span class="org-type">B</span>, <span class="org-type">C</span>) {
  <span class="org-keyword">auto</span> <span class="org-variable-name">foo</span> = factory.make_foo();
  <span class="org-comment-delimiter">// </span><span class="org-comment">...</span>
}
</pre>
</div>

<p>
It is expected this should cover most scenarios that users will want to write.
</p>

<p>
For other scenarios, expressions involving direct use of <code>declthrow()</code> queries can be used
to for more complicated type-constraints.
</p>
</div>
</div>

<div id="outline-container-org837c881" class="outline-3">
<h3 id="org837c881"><span class="section-number-3">5.10.</span> Coroutines</h3>
<div class="outline-text-3" id="text-5-10">
<p>
Coroutines have several areas that require updates to support static exception specifications:
</p>
<ul class="org-ul">
<li>Extensions to <code>unhandled_exception()</code> function of a coroutine's promise-type to allow handling
static exception objects.</li>
<li>Rules for computing the exception specification of a coroutine with a deduced throw specificiation</li>
</ul>

<p>
The rules for computing the set of potentially thrown exceptions for <code>co_return</code> statements and
<code>co_await</code> and <code>co_yield</code> expressions are already described above.
</p>
</div>

<div id="outline-container-org8ad42de" class="outline-4">
<h4 id="org8ad42de"><span class="section-number-4">5.10.1.</span> Coroutine promise object handling for static exception objects</h4>
<div class="outline-text-4" id="text-5-10-1">
<p>
The current behaviour of a coroutine with a given <i>function-body</i> is specified to be as if the <i>function-body</i> were replaced by:
</p>
<div class="org-src-container">
<pre class="src src-c++">{
  /promise-type/ promise /promise-constructor-arguments/ ;
  <span class="org-keyword">try</span> {
    <span class="org-keyword">co_await</span> promise.initial_suspend();
    /function-body/
  } <span class="org-keyword">catch</span> (...) {
    <span class="org-keyword">if</span> (<span class="org-negation-char">!</span>initial-await-resume-called)
      <span class="org-keyword">throw</span>;
    promise.unhandled_exception();
  }
<span class="org-constant">final_suspend</span>:
  <span class="org-keyword">co_await</span> promise.final_suspend();
}
</pre>
</div>

<p>
The only way that the <code>promise.unhandled_exception()</code> object can observe the current exception object
is by either performing a dynamic rethrow expression, <code>throw;</code>, or by calling <code>std::current_exception()</code>.
This would force any static exception object to be copied to a dynamic exception object, which negates
the benefit of static exceptions.
</p>

<p>
Also, we may want to define a coroutine promise type such that the coroutine body itself cannot throw
types other than a specified set of potentially-thrown exception types.
</p>

<p>
To support these use-cases, we can modify the above translation as follows:
</p>
<div class="org-src-container">
<pre class="src src-c++">{
  /promise-type/ promise /promise-constructor-arguments/ ;
  <span class="org-keyword">try</span> {
    <span class="org-keyword">co_await</span> promise.initial_suspend();
    /function-body/
  } <span class="org-keyword">template</span> <span class="org-keyword">catch</span> (<span class="org-keyword">auto</span>&amp; <span class="org-variable-name">ex</span>) {
    <span class="org-comment-delimiter">// </span><span class="org-comment">Static exception objects caught here</span>
    <span class="org-keyword">if</span> (<span class="org-negation-char">!</span>initial-await-resume-called)
      <span class="org-keyword">throw</span>;

    <span class="org-keyword">if</span> <span class="org-keyword">constexpr</span> (can_handle_exception&lt;/promise-type/, <span class="org-keyword">decltype</span>(ex)&gt;) {
      promise.unhandled_exception(ex);
    } <span class="org-keyword">else</span> <span class="org-keyword">if</span> (can_handle_exception&lt;/promise-type/, <span class="org-constant">std</span>::exception_ptr&gt;) {
      promise.unhandled_exception(<span class="org-constant">std</span>::make_exception_ptr(<span class="org-constant">std</span>::move(ex)));
    } <span class="org-keyword">else</span> {
      promise.unhandled_exception();
    }
  } <span class="org-keyword">catch</span> (...) {
    <span class="org-comment-delimiter">// </span><span class="org-comment">Dynamic exception objects caught here</span>
    <span class="org-keyword">if</span> (<span class="org-negation-char">!</span>initial-await-resume-called)
      <span class="org-keyword">throw</span>;

    <span class="org-keyword">constexpr</span> <span class="org-type">bool</span> <span class="org-variable-name">is_handler_reachable</span> = <span class="org-keyword">sizeof</span>...(<span class="org-type">declthrow</span>(<span class="org-keyword">throw</span>)) &gt; 0;
    <span class="org-keyword">if</span> <span class="org-keyword">constexpr</span> (is_handler_reachable) {
      <span class="org-keyword">if</span> <span class="org-keyword">constexpr</span> (can_handle_exception&lt;/promise-type/, <span class="org-constant">std</span>::exception_ptr&gt;) {
        promise.unhandled_exception(<span class="org-constant">std</span>::current_exception());
      } <span class="org-keyword">else</span> {
        promise.unhandled_exception();
      }
    }
  }
<span class="org-constant">final_suspend</span>:
  <span class="org-keyword">co_await</span> promise.final_suspend();
}
</pre>
</div>

<p>
Where the following exposition-only concept is defined:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">P</span>, <span class="org-keyword">typename</span> <span class="org-type">E</span>&gt;
<span class="org-type">concept</span> <span class="org-variable-name">can_handle_exception</span> =
  requires(<span class="org-type">P</span>&amp; <span class="org-variable-name">promise</span>, <span class="org-type">E</span>&amp; <span class="org-variable-name">ex</span>) {
    p.unhandled_exception(ex);
  };
</pre>
</div>


<p>
If a thrown static exception object, <code>ex</code>, escapes the body of the coroutine then the exception is caught
and one of the following expressions is evaluated, tried in-order;
</p>
<ul class="org-ul">
<li>Call <code>promise.unhandled_exception(ex)</code>, if that expression is valid; otherwise</li>
<li>Call <code>promise.unhandled_exception(std::current_exception())</code>, if that expression is valid; otherwise</li>
<li>Call <code>promise.unhandled_exception()</code> if that expression is valid; otherwise</li>
<li>The program is ill-formed</li>
</ul>
<p>
If a thrown dynamic exception object escapes the body of the coroutine then the exception is caught
and one of the following expressions is evaluated, tried in-order;
</p>
<ul class="org-ul">
<li>Call <code>promise.unhandled_exception(std::current_exception())</code>, if that expression is valid; otherwise</li>
<li>Call <code>promise.unhandled_exception()</code>, if that expression is valid; otherwise</li>
<li>The program is ill-formed</li>
</ul>

<p>
Some key points to note here:
</p>
<ul class="org-ul">
<li>The <code>unhandled_exception()</code> method can now optionally take a parameter that accepts an
lvalue-reference to the static exception object
<ul class="org-ul">
<li>It is a non-const reference to allow the implementation to move/mutate the exception object
if desired.</li>
</ul></li>
<li>The <code>unhandled_exception()</code> method can also optionally take a parameter of type <code>std::exception_ptr</code>
to refer to the current exception.
<ul class="org-ul">
<li>This can be potentially more efficient on some platforms than having the <code>unhandled_exception()</code>
method call <code>std::current_exception()</code> since, in the case of a static exception object being thrown,
it has a reference to the exception object already and so doesn't necessarily have to access the
thread-local values inside <code>std::current_exception()</code>.</li>
<li>It also allows some freestanding implementations that do not support thread-locals and thus do not
support <code>std::current_exception()</code> to still allow type-erasing exception objects in a <code>std::exception_ptr</code>.</li>
</ul></li>
<li>We only try to form a call to <code>promise.unhandled_exception()</code> if the handler is potentially-reachable.
i.e. if either the <code>await_resume()</code> method on the initial-suspend awaiter object is potentially-throwing
or if the <i>function-body</i> of the coroutine is potentially-throwing.
<ul class="org-ul">
<li>This differs from C++20 which always requires that a promise type has an <code>unhandled_exception()</code> object.</li>
<li>This also means that a coroutine promise-type that does not define any <code>unhandled_exception()</code>
member function can still be used as long as the set of potentially-thrown exceptions from the function-body
is the empty set.</li>
</ul></li>
</ul>

<p>
Together, these changes will allow a coroutine promise type to store and/or inspect an exception object without
having to first dynamically rethrow the exception, or if <a href="https://wg21.link/P2927">P2927</a> is adopted,
have to allocate a dynamic exception object and call <code>eptr.try_cast&lt;T&gt;()</code> to check if it has a particular
type.
</p>

<p>
For example, say we wanted to write a coroutine type that only permitted exceptions of type <code>A</code> and <code>B</code>
to exit the coroutine body, we could define it to have a promise-type that had the following
<code>unhandled_exception()</code> member-function.
</p>

<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">struct</span> <span class="org-type">my_promise_type</span> {

  <span class="org-comment-delimiter">// </span><span class="org-comment">... rest of promise type omitted for brevity</span>

  <span class="org-type">void</span> <span class="org-function-name">unhandled_exception</span>(<span class="org-type">one_of</span>&lt;A, B&gt; <span class="org-keyword">auto</span>&amp; <span class="org-variable-name">ex</span>) <span class="org-keyword">throw</span>() {
    <span class="org-keyword">constexpr</span> <span class="org-constant">std</span>::<span class="org-type">size_t</span> <span class="org-variable-name">index</span> = <span class="org-constant">std</span>::<span class="org-type">same_as</span>&lt;<span class="org-keyword">decltype</span>(ex), <span class="org-type">A</span>&amp;&gt; ? 2 : 3;
    result.emplace&lt;index&gt;(<span class="org-constant">std</span>::<span class="org-type">move</span>(<span class="org-variable-name">ex</span>));
  }

  <span class="org-constant">std</span>::<span class="org-type">variant</span>&lt;<span class="org-constant">std</span>::monostate, value_type, <span class="org-type">A</span>, B&gt; <span class="org-variable-name">result</span>;
};
</pre>
</div>

<p>
If any other exception than <code>A</code> or <code>B</code> escapes the function body then the compiler will fail to
find a suitable overload for a call to <code>promise.unhandled_exception()</code> and will be considered ill-formed.
This allows the author of a coroutine type to mimic the equivalent throw-specification checking that
normal functions with a <code>throw(A, B)</code> specfication does.
</p>

<p>
This will allow async coroutines to efficiently propagate static-exception objects through chains of
coroutines without needing to invoke any of the dynamic exception machinery of the C++ runtime.
</p>
</div>
</div>

<div id="outline-container-org74b05f8" class="outline-4">
<h4 id="org74b05f8"><span class="section-number-4">5.10.2.</span> Computing the exception specification of a coroutine with a deduced throw specification</h4>
<div class="outline-text-4" id="text-5-10-2">
<p>
When a coroutine is invoked, the call to the coroutine does not necessarily invoke the entire body
of the coroutine before returning. The coroutine may suspend at the initial-suspend point and then
return immediately.
</p>

<p>
Also, once the execution of the coroutine reaches a certain point during the execution of the initial-suspend
expression, any exceptions that exit the coroutine body from that point are caught and directed to the
promise object's <code>unhandled_exception()</code> member-function, as described in the previous section.
</p>

<p>
This means that the set of potentially-thrown exceptions of the initial call to the coroutine is
different from the set of potentially-thrown exceptions of the coroutine function-body that the
user writes.
</p>

<p>
This section defines the steps for computing the deduced throw specification of a coroutine
that accurately matches the set of potentially-thrown exception types of the initial invocation
of a coroutine.
</p>

<p>
The steps involved in the initial call to a coroutine are:
</p>
<ul class="org-ul">
<li>allocating the coroutine frame, calling <code>promise_type::operator new()</code> if present and viable, otherwise
calls global <code>operator new</code>.</li>
<li>copying/moving parameters of the function to the coroutine-frame</li>
<li>constructing the promise object, optionally passing lvalues of the parameter copies to the promise constructor</li>
<li>calling <code>promise.get_return_object()</code></li>
<li>calling <code>promise.initial_suspend()</code></li>
<li>calling <code>operator co_await()</code> on the returned object, if one is defined</li>
<li>calling <code>await_ready()</code> on the awaiter</li>
<li>calling <code>await_suspend()</code> on the awaiter</li>
<li>any implicit conversions required to convert the result of <code>promise.get_return_object()</code> to the
return-type of the coroutine.</li>
</ul>

<p>
If any of these expressions throw an exception then this exception will propagate out of the
initial call to the coroutine and so the deduced exception specification should include the
union of the sets of potentially-thrown exception types of these expressions.
</p>

<p>
Any subsequent expressions evaluated as part of the coroutine body, from the initial-suspend-point's
<code>await_resume()</code> call onwards, will be evaluated inside the try/catch around the coroutine body and
thus will be filtered through the <code>promise.unhandled_exception()</code> logic described above.
</p>

<p>
As it's possible that the coroutine may not suspend at the initial suspend-point and may
execute the body of the coroutine, and thus can potentially execute any of the reachable
handlers that call <code>promise.unhandled_exception()</code>. If any of these calls to <code>promise.unhandled_exception()</code>
exit with an exception then this exception would also propagate from the initial call to the coroutine.
</p>

<p>
Futher, if the coroutine first suspends at a suspend-point that symmetrically transfers execution to another
coroutine by returning a <code>coroutine_handle</code> from <code>await_suspend()</code> then if that other
coroutine has a promise-type with a potentially-throwing <code>unhandled_exception()</code> method then
this could still exit with any exception thrown by that other coroutine's <code>unhandled_exception()</code>.
</p>

<p>
Or that other coroutine could suspend and symmetrically transfer execution to some other coroutine
which has a throwing <code>promise.unhandled_exception()</code>. This could continue transitively for an arbitrary
chain of coroutines.
</p>

<p>
This possibility for the initial call to a coroutine potentially throwing any exception that could
be thrown by a coroutine that is symmetrically transferred to transitively from the initial call
makes it difficult in general to deduce an accurate exception specification that is anything other
than a dynamic exception specification.
</p>

<p>
It is currently impossible to tell whether a call to <code>coroutine_handle::resume()</code>
might throw or not, which makes it difficult to compute an accurate deduced exception specification for
any coroutine that suspends and symmetrically transfers to another coroutine.
</p>

<p>
This in turn means that we need to conservatively assume that every coroutine with a symmetric-transfer
has a dynamic exception specification, which also means that we cannot permit such a coroutine to have
a static exception specification.
</p>

<p>
It's possible that we can later relax this by allowing defining coroutines that have a non-throwing resume
which in turn only allow symmetric transfer to other coroutines that have a non-throwing resume and which
require the coroutine promise-type's unhandled<sub>exception</sub>() functions to also be non-throwing.
</p>

<p>
This direction requires more investigation before a design proposal can be made to address this issue, however.
</p>
</div>
</div>
</div>

<div id="outline-container-org56dc8b3" class="outline-3">
<h3 id="org56dc8b3"><span class="section-number-3">5.11.</span> Type traits</h3>
<div class="outline-text-3" id="text-5-11">
<p>
The standard library has a number of traits queries that let you query properties about
certain operations and whether or not they are "nothrow".
</p>
</div>

<div id="outline-container-org579cce7" class="outline-4">
<h4 id="org579cce7"><span class="section-number-4">5.11.1.</span> Nothrow queries</h4>
<div class="outline-text-4" id="text-5-11-1">
<p>
The existing <code>std::is_nothrow_*</code> traits are specified in terms of <code>noexcept</code> expressions.
</p>

<p>
As the <code>noexcept</code> operator will still "do the right thing" for expressions that have static
exception specifications (i.e. will return <code>false</code> if there is a non-empty static exception
specification) these existing type-traits should not require any changes in specification.
</p>

<p>
It is not expected that implementations will require any changes to these traits.
</p>
</div>
</div>

<div id="outline-container-org38b17f8" class="outline-4">
<h4 id="org38b17f8"><span class="section-number-4">5.11.2.</span> <code>std::is_function</code> and <code>std::is_member_function_pointer</code></h4>
<div class="outline-text-4" id="text-5-11-2">
<p>
While the specification of these traits need not change, as they are just defined in terms
of whether or not a given type is a function type, there may be some changes to standard
library implementations which use partial specialization of all of the different forms
of functions.
</p>

<p>
It is noted that libc++, libstdc++ and MSSTL all either are defined in terms of compiler
intrinsics, which would need to be updated as part of implementing this feature, or are
defined in terms of other properties of the type. For example, by computing <code>is_function_v&lt;T&gt;</code>
by checking whether the result of evaluating <code>!is_const_v&lt;const  T&gt; &amp;&amp; !is_reference_v&lt;T&gt;</code> is <code>true</code>.
</p>
</div>
</div>

<div id="outline-container-org849b714" class="outline-4">
<h4 id="org849b714"><span class="section-number-4">5.11.3.</span> Additional traits</h4>
<div class="outline-text-4" id="text-5-11-3">
<p>
It's possible we may want to add some additional traits for querying information about
static exception specifications of certain expressions, however this has not yet been
explored.
</p>

<p>
It is expected that any such traits could be added in future as and when a need for
them has been established.
</p>
</div>
</div>
</div>

<div id="outline-container-org1d6476a" class="outline-3">
<h3 id="org1d6476a"><span class="section-number-3">5.12.</span> Freestanding</h3>
<div class="outline-text-3" id="text-5-12">
<p>
This paper proposes that the following facilites be available in conforming freestanding implementations:
</p>
<ul class="org-ul">
<li>static throw expressions</li>
<li>static rethrow expressions</li>
<li>try/catch</li>
<li><code>template catch</code> handlers</li>
<li>functions with throw specifications</li>
</ul>

<p>
The following facilities would not be required in a freestanding implementation:
</p>
<ul class="org-ul">
<li>dynamic throw expression</li>
<li>dynamic rethrow expression</li>
<li><code>std::exception_ptr</code></li>
<li><code>std::uncaught_exceptions()</code></li>
<li><code>std::current_exception()</code></li>
</ul>
</div>
</div>
</div>

<div id="outline-container-orge66ceec" class="outline-2">
<h2 id="orge66ceec"><span class="section-number-2">6.</span> Prior Work</h2>
<div class="outline-text-2" id="text-6">
<p>
There have been a number of prior proposals and prior work that have looked at
this area of exception specifications and various improvements to exceptions.
</p>

<p>
This section tries to summarise some of the history of the prior art.
</p>
</div>

<div id="outline-container-org8758d0b" class="outline-3">
<h3 id="org8758d0b"><span class="section-number-3">6.1.</span> Throw specifications and noexcept</h3>
<div class="outline-text-3" id="text-6-1">
<ul class="org-ul">
<li><a href="https://wg21.link/N2855">N2855</a> - Rvalue References and Exception Safety (2009)
<ul class="org-ul">
<li>Discusses the problem with move-constructors and providing strong exception-safe guarantee,
which motivates some way for the library to check whether an expression/move-ctor can throw.</li>
<li>Proposes introducing the <code>noexcept</code> specifier</li>
<li>Originally proposed to have <code>noexcept</code> functions be ill-formed if any exception could
potentially escape the function.</li>
<li>Proposed to use syntax <code>throw(...)</code> to mean "this function can throw any exception."
This eventually became <code>noexcept(false)</code>.</li>
<li>Proposes making destructors <code>noexcept</code> by default.</li>
<li><p>
Proposes adding a <code>noexcept</code> block that allows telling the compiler to assume that no
exceptions will propagate out of this block. e.g. where exceptions are a dynamic property
that is guarded against by other means.
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">double</span> <span class="org-function-name">sqrt</span>(<span class="org-type">double</span>);

<span class="org-keyword">noexcept</span> <span class="org-type">void</span> <span class="org-function-name">f</span>(<span class="org-type">double</span>&amp; <span class="org-variable-name">x</span>) {
  <span class="org-keyword">if</span> (x &gt; 0) {
    <span class="org-keyword">noexcept</span> { x = sqrt(x); } <span class="org-comment-delimiter">// </span><span class="org-comment">okay: if sqrt(x) throws, invokes undefined behaviour</span>
  }
}
</pre>
</div></li>

<li>Proposes that exception specifications are deprecated
<ul class="org-ul">
<li>Lack of static checking has limited usability and confused users</li>
<li>Provide few benefits for compilers</li>
<li>Not useful in generic code, where functions need to know whether an exception can be
thrown or not, but don't know (or care) what kind of exceptions can be thrown.</li>
<li>In fact, the <code>noexcept</code> specifier, along with the ability to detect whether an
operation is <code>noexcept</code> via concepts, provides precisely the statically-checked
exception specifications that are required in C++ code.</li>
</ul></li>
</ul></li>

<li>N2983 Allowing Move Constructors to Throw (2009)
<ul class="org-ul">
<li>Proposes use of <code>std::move_if_noexcept()</code> in move-constructors that require strong exception-safety guarantee.</li>
<li>Proposes new <code>noexcept(&lt;expr&gt;)</code> expression.</li>
<li>Proposes a parameterised <code>noexcept(&lt;bool-expr&gt;)</code> function specifier.</li>
<li>Suggests making destructors <code>noexcept</code> by default.</li>
</ul></li>

<li><a href="https://wg21.link/N3051">N3051</a> - Deprecating exception specifications
<ul class="org-ul">
<li>Talks about shortcoming of original throw-specifications
<ul class="org-ul">
<li>Run-time checking
<ul class="org-ul">
<li>Offers programmer no guarantees all exceptions have been handled.</li>
<li><code>std::unexpected()</code> does not lend itself to recovery.</li>
</ul></li>
<li>Run-time overhead
<ul class="org-ul">
<li>Run-time checking requires compiler to generate extra code, which hampers optimisations.</li>
</ul></li>
<li>Unusable in generic code
<ul class="org-ul">
<li>Not generally possible to know what types of exceptions may be thrown from operations on
template arguments, so precise exception specification cannot be written.</li>
</ul></li>
</ul></li>
<li>Claims that there are only two useful exception-specifications: throws-something and throws-nothing.</li>
<li>Proposes deprecation of <code>throw()</code> specifications as <code>noexcept</code> covers the two useful cases.</li>
<li>Also proposed that <code>noexcept</code> was equivalent to <code>throw()</code> on a declaration, but differed
in semantics when it was placed on the definition.</li>
</ul></li>

<li><a href="https://wg21.link/N3103">N3103</a> - Security impact of noexcept
<ul class="org-ul">
<li>Says that a program that continues after noexcept function exits with an exception can
lead to undefined/unexpected-behaviour that can be exploited by a malicious user to bypass
security restrictions and/or cause denial-of-service attacks.</li>
<li>Proposes mandating that the program should terminate if there is ever an unhandled exception
that is about to exit a <code>noexcept</code> function.</li>
</ul></li>

<li><a href="https://wg21.link/N3248">N3248</a> - noexcept prevents library validation (2011)
<ul class="org-ul">
<li>The "Lakos Rule" paper
<ul class="org-ul">
<li>don't put noexcept on functions with narrow contracts</li>
<li>so we can test assertions/preconditions</li>
</ul></li>
<li>The risk from overly aggressive use of noexcept specifications is that programs with hidden terminate calls are produced</li>
<li>The risk of under-specifying noexcept specifications is that they become difficult to add in a later
revision of the standard, as the noexcept operator becomes an observable part of the ABI.</li>
<li>Long list of library changes to roll back use of noexcept in standard library.</li>
</ul></li>

<li><a href="https://wg21.link/N3279">N3279</a> - Conservative use of noexcept in the Library (2011)
<ul class="org-ul">
<li>Summary of N3248 that just describes the guidelines for use of noexcept</li>
</ul></li>

<li>N4133 - Cleanup for exception-specification and throw-expression
<ul class="org-ul">
<li>Revised by N4285</li>
<li>Editorial wording cleanup</li>
<li>Introduces "exception specification" semantic concept separate from the grammar term exception-specification.</li>
<li>Wording changes from "throws an exception" to "exits via an exception"</li>
</ul></li>

<li>N4320 - Make exception specifications be part of the type system (2014)
<ul class="org-ul">
<li>Revised by N4518, N4533, P0012R0, P0012R1</li>
<li>Proposes to make <code>noexcept</code> specifier part of the type of a function and function-pointer</li>
</ul></li>

<li>P0003R0 - "Removing Deprecated Dynamic Exception Specifications (2015)
<ul class="org-ul">
<li>Revised by P0003R2, P0003R5 (2016)</li>
<li>Proposes to remove the <code>throw</code> specifiers deprecated in C++11.</li>
<li>This was adopted and throw specifiers were removed in C++17.</li>
</ul></li>
</ul>
</div>
</div>

<div id="outline-container-org95611f6" class="outline-3">
<h3 id="org95611f6"><span class="section-number-3">6.2.</span> Java Checked Exceptions</h3>
<div class="outline-text-3" id="text-6-2">
</div>
<div id="outline-container-org63cd782" class="outline-4">
<h4 id="org63cd782"><span class="section-number-4">6.2.1.</span> Background On How Exceptions work in Java</h4>
<div class="outline-text-4" id="text-6-2-1">
<p>
In the Java exception model all exception types inherit from the <code>Throwable</code> base class.
A <code>throw</code> expression can only throw objects that inhert frim <code>Throwable</code>.
</p>

<p>
There are a number of important base-classes for exceptions defined in
</p>

<ul class="org-ul">
<li><code>Throwable</code> - Base-class for all types that can be thrown
<ul class="org-ul">
<li><code>Error</code> - Base-class for bugs (assertion failures) or more serious problems with the runtime (e.g. <code>StackOverflowException</code>, <code>OutOfMemory</code>).
Applications are not expected to handle these errors.</li>
<li><code>Exception</code> - Base-class for conditions that an application may need to handle.
<ul class="org-ul">
<li><code>RuntimeException</code> - Base-class of conditions that might be raised at any time by the runtime.
e.g. <code>NullPointerException</code>, <code>IndexOutOfBoundsException</code>, etc.</li>
</ul></li>
</ul></li>
</ul>

<p>
Types inheriting from <code>Throwable</code>, directly or indirectly, are classified as
either "checked" exceptions, or "unchecked" exceptions.
</p>

<p>
Types inheriting from either <code>Error</code> or <code>RuntimeException</code> are "unchecked" exceptions.
These could potentially be raised by the runtime at any time and may not require an
explicit <code>throw</code> expression in user-code.
</p>

<p>
Types inheriting from <code>Throwable</code> that are not "unchecked" exceptions are classified
as "checked" exceptions.
</p>

<p>
This property of being "checked" or "unchecked" is a property of the type.
A checked exception type is always a checked exception type, regardless of context.
</p>

<p>
Functions in Java have an optional <code>throws</code> clause that is placed after the argument list.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-java"><span class="org-keyword">public</span> <span class="org-type">void</span> <span class="org-function-name">foo</span>() <span class="org-keyword">throws</span> <span class="org-type">IOException</span> {
    <span class="org-comment-delimiter">// </span><span class="org-comment">...</span>
}
</pre>
</div>

<p>
If a function can potentially throw a checked exception then it must list that checked
exception type, or one of its base-classes, in the throws clause, otherwise the program
is ill-formed.
</p>

<p>
A function is allowed to list unchecked exception types in its throws clause, but is
not required to.
</p>
</div>
</div>

<div id="outline-container-orgd361bb3" class="outline-4">
<h4 id="orgd361bb3"><span class="section-number-4">6.2.2.</span> Criticisms of Java Checked exceptions</h4>
<div class="outline-text-4" id="text-6-2-2">
<p>
In the interview "The trouble with checked exceptions" [Trouble] between Bruce Eckel and Anders Hejlsberg
they talks about checked exceptions in Java and some of the problems they had found in
practice with this design.
</p>

<p>
The interview discussed two main problems:
</p>
<ul class="org-ul">
<li>versioning and evolvability of interfaces</li>
<li>scalability of the design at high levels</li>
</ul>
</div>

<ol class="org-ol">
<li><a id="orgc0dab60"></a>Versioning and evolvability of interfaces<br />
<div class="outline-text-5" id="text-6-2-2-1">
<p>
The problem with versioning and evolvability of interfaces with Java checked exceptions
arises when an API that is initially released and is in use by users later wants to
evolve to add additional error-conditions for a given operation.
</p>

<p>
Consider a function that initially specifies that it throws <code>A</code>, <code>B</code> or <code>C</code> but then later wants to
add some features that means it can fail in new ways and wants to now add <code>D</code> to the list.
Adding <code>D</code> to the list of potentially thrown exceptions is now a breaking change, potentially
requiring updating each caller to either handle that exception, or if it does not handle that
error, then adding that exception to its throw specification.
</p>

<p>
This in turn can require recursively updating many calling functions with new error-conditions.
</p>

<p>
To avoid having to go and update callers to add additional exceptions to their throw specifiers
programmers often just listed <code>throws Exception</code> which allows it to transparently throw any type
of exception - which basically defeats the purpose of checked exceptions.
</p>

<p>
This is arguably already the status quo in C++, where a dynamic exception specification
already just says "I can throw anything".
</p>

<p>
This allows C++ functions to later be modified to throw new exceptions without that introducing
a compilation error. However, in many cases this can still be a breaking change if existing
callers were not expecting this new exception to be thrown - potentially leading to bugs relating
to unhandled exceptions.
</p>

<p>
One of the arguments against checked exceptions in Java was that for a lot of use-cases people
don't want to handle the exceptions. If something fails then they just want to let these errors
propagate up to some top-level handler and just let it log/report the error. Forcing the programmer
to write a lot of boiler-plate to accurately list exception types in cases where callers do not
handle specific errors does not add a lot of benefit and so writing <code>throws Exception</code> may make
sense in that situation.
</p>

<p>
This paper holds the position that adding a new exception to the list of potentially thrown
exceptions is indeed a potentially breaking change to a function, regardless of whether this
is represented in the signature of the function or not.
</p>

<p>
The set of ways in which a function can potentially fail is a key aspect of its interface and
should be considered as part of its design.
</p>

<p>
The design proposed in this paper provides a few additional tools compared to Java to help
manage evolution of a function's exception specifications.
</p>

<p>
It provides the ability to introspect the set of potentially-thrown exceptions for some expression
via <code>declthrow</code>, allowing computation of derived exception specifications in terms of the exception
specifications of other functions. This can help with allowing the signatures of calling functions
to automatically adapt when callees are modified to throw additional exception types.
</p>

<p>
It also provides the ability to deduce the exception specification from the body by using <code>throw(auto)</code>.
This is largely just a convenience to manually writing out complex <code>declthrow</code> expressions to compute
the exception specification, but requires that the body of the function is visible to the caller.
</p>

<p>
Functions that want to have an extensible set of error-conditions that can be emitted can also
take the approach of using types that have extensible values, such as <code>std::error_code</code>, which
can allow new error-categories and error-conditions to be represented in a single value in an
extensible way.
</p>

<p>
This requires calling code to manually check for each error-condition, however, and have a fallback
for error-conditions it doesn't yet support. If a new error-condition should require callers to handle
it then it may be better to represent this as a new exception type which callers need to handle.
</p>
</div>
</li>

<li><a id="org8873dca"></a>Scalability of checked exceptions<br />
<div class="outline-text-5" id="text-6-2-2-2">
<p>
The second issue discussed in the [Trouble] interview was the use of checked exceptions in large
systems.
</p>

<p>
The point was made that checked exceptions look good in the small when you are looking at leaf functions
with a few exception-types and their callers, but when it comes to composing multiple high-level
systems it is easy for those high-level calls to end up with 50+ exception-types being listed in
each function, affecting readability of the code.
</p>

<p>
To avoid such large lists of exceptions, Java code ends up either just listing base-class exceptions
like <code>throws Exception</code>, or ends up catching and ignoring the exception via a <code>catch</code> with an empty
handler.
</p>

<p>
Note that the status quo in C++ is that any function not marked <code>noexcept</code> has an exception specification
that is the equivalent of Java's <code>throws Exception</code>, so if dynamic exceptions are suitable for your
use-cases then you can continue to use them.
</p>

<p>
With this paper, if you want to use throw-specifiers and static exceptions all the way up into
the high-level systems then it's possible there would indeed be a need to list a large number
of exceptions in such high-level functions.
</p>

<p>
There are additional tools in C++ that could help make this more manageable compared to Java, however.
</p>

<ul class="org-ul">
<li>Pack aliases, proposed by [P3115R0], could be used to define shorter names for reusable
sets of exceptions thrown by each subsystem. Then high-level functions could list the
pack-alias names, <code>throw(foo_errors..., bar_errors..., baz_errors...)</code> instead of listing
every exception that might be thrown by each subsystem.</li>
<li>Use of <code>throw(auto)</code> could be used on functions that compose multiple systems to allow
the compiler to compute the exception-specification - with the tradeoff that these functions
must have their definitions visible to users. Alternatively, use of <code>throw</code> specfications
using <code>declthrow()</code> queries could be used in the declaration if separate compilation is
required.</li>
<li>Multiple subsystems could throw types like <code>std::error_code</code> to represent error conditions
so that there is overlap between sets of potentially-thrown exceptions from different
subsystems and the errors.</li>
</ul>
</div>
</li>
</ol>
</div>
</div>

<div id="outline-container-orgce4f3aa" class="outline-3">
<h3 id="orgce4f3aa"><span class="section-number-3">6.3.</span> Midori</h3>
<div class="outline-text-3" id="text-6-3">
<p>
Midori was an internal research/incubation project at Microsoft that explored ways of
innovating the software stack, including programming languages, compilers, operating-systems,
services, applications and overall programming models.
</p>

<p>
Joe Duffy has written an excellent <a href="https://joeduffyblog.com/2015/11/03/blogging-about-midori/">blog series</a>
about the Midori project, which is generally a good read which I highly recommend.
However, there is one article in particular on the
<a href="https://joeduffyblog.com/2016/02/07/the-error-model/">Midori Error Model</a>
that is worth discussing here as it contains a lot of good ideas and
also critique of error models of other languages, including Java's checked exceptions
and C++ exceptions.
</p>

<p>
The critique of what he calls the "unchecked exceptions" model:
</p>
<blockquote>
<p>
In this model, any function call – and sometimes any statement – can throw an exception,
transferring control non-locally somewhere else. Where? Who knows.
There are no annotations or type system artifacts to guide your analysis.
As a result, it’s difficult for anyone to reason about a program’s state at the time of the throw,
the state changes that occur while that exception is propagated up the call stack – and possibly
across threads in a concurrent program – and the resulting state by the time it gets caught or goes unhandled.
</p>
</blockquote>

<p>
TODO: Finish writing this.
</p>
</div>
</div>

<div id="outline-container-org5673755" class="outline-3">
<h3 id="org5673755"><span class="section-number-3">6.4.</span> Deducing exception specifications</h3>
<div class="outline-text-3" id="text-6-4">
<p>
There have been several papers that have explored the idea of deducing exception
specifications of a function. This section tries to summarise them.
</p>

<ul class="org-ul">
<li><a href="https://wg21.link/N3202">N3202</a> - To which extent can noexcept be deduced (Stroustrop) (2010)
<ul class="org-ul">
<li>Summarises <a href="https://wg21.link/N3227">N3227</a> "Please reconsider <code>noexcept</code>" (2010)
<ul class="org-ul">
<li>"almost every statement in function templates leak into the noexcept declaration"</li>
<li>"a user-maintained noexcept increases the likelihood that the specification is not
correct. In turn this implies (a) an increased chance that client code terminates
unexpectedly, or (b) that optimization opportunities are lost. (Note tha providing
correct warnings is also undecidable.)</li>
<li>client code can still change (fail to compile, different runtime behaviour) if
noexcept is added or removed from a library.</li>
<li><p>
Questions of consistency of deducing noexcept declarations:
</p>
<blockquote>
<p>
The idea of noexcept is to allow code to be written to take
advantage of knowing that code will not throw. The key observation is that if we fail to deem a
function noexcept even though it doesn’t throw the worst that can happen is that sub-optimal,
but still correct, code will be executed. In other words, as long as we don’t mistakenly deem a
throwing function noexcept, not serious harm is done.
</p>
</blockquote></li>
<li>Walks through some cases where there might be inconsistencies in deducing the noexceptness
in different contexts.
<ul class="org-ul">
<li>This seems to be based on the assumption that it needs to be an implicit deduction rather
than explicit opt-in for each function.</li>
</ul></li>
</ul></li>
</ul></li>

<li><a href="https://wg21.link/N3207">N3207</a> - noexcept(auto) (2010)
<ul class="org-ul">
<li>Highlights issues with implicit deduction in N3202
<ul class="org-ul">
<li>Easy to accidentally introduce ODR violations</li>
<li>Issues with eager function template instantiation to determine function signature/noexceptness
(not SFINAE friendly).</li>
</ul></li>
<li>Proposes <code>noexcept(auto)</code> as in-between compromise between having to duplicate body in noexcept declaration,
and fully implicit, which has issues.</li>
<li><p>
Doesn't let mutually recursive functions all have their noexcept-specification deduced
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">struct</span> <span class="org-type">A</span> {
  <span class="org-type">void</span> <span class="org-function-name">f</span>(<span class="org-type">int</span> <span class="org-variable-name">i</span>) <span class="org-keyword">noexcept</span>(<span class="org-keyword">auto</span>)
  { <span class="org-keyword">if</span> (i &gt; 1) g(i-1); } <span class="org-comment-delimiter">// </span><span class="org-comment">call to g() is ill-formed as it's noexcept specifier is incomplete.</span>
  <span class="org-type">void</span> <span class="org-function-name">g</span>(<span class="org-type">int</span> <span class="org-variable-name">i</span>) <span class="org-keyword">noexcept</span>(<span class="org-keyword">auto</span>)
  { <span class="org-keyword">if</span> (i &gt; 1) f(i-1); }
};
</pre>
</div></li>
<li><p>
Also mentions this example as being ill-formed:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-type">bool</span>&gt; <span class="org-keyword">struct</span> <span class="org-type">M</span>;
<span class="org-keyword">template</span>&lt;&gt; <span class="org-keyword">struct</span> <span class="org-type">M</span>&lt;<span class="org-constant">true</span>&gt; { <span class="org-type">int</span> <span class="org-variable-name">large</span>[100]; };
<span class="org-keyword">template</span>&lt;&gt; <span class="org-keyword">struct</span> <span class="org-type">M</span>&lt;<span class="org-constant">false</span>&gt; { <span class="org-type">char</span> <span class="org-variable-name">small</span>; };
<span class="org-keyword">struct</span> <span class="org-type">B</span> {
  <span class="org-keyword">template</span>&lt;<span class="org-type">bool</span>&gt; <span class="org-type">void</span> <span class="org-function-name">maybe_throw</span>();
  <span class="org-keyword">template</span>&lt;&gt; <span class="org-type">void</span> <span class="org-function-name">maybe_throw</span>&lt;<span class="org-constant">true</span>&gt;() <span class="org-keyword">noexcept</span>(<span class="org-keyword">auto</span>) { <span class="org-keyword">throw</span> 0; } <span class="org-comment-delimiter">// </span><span class="org-comment">deduced noexcept(false)</span>
  <span class="org-keyword">template</span>&lt;&gt; <span class="org-type">void</span> <span class="org-function-name">maybe_throw</span>&lt;<span class="org-constant">false</span>&gt;() <span class="org-keyword">noexcept</span>(<span class="org-keyword">auto</span>) { } <span class="org-comment-delimiter">// </span><span class="org-comment">deduced noexcept</span>
  <span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">noexcept</span>(<span class="org-keyword">auto</span>) { maybe_throw&lt;(<span class="org-keyword">sizeof</span>(<span class="org-type">B</span>) &gt; 10)&gt;(); };
  <span class="org-type">M</span>&lt;<span class="org-keyword">noexcept</span>(<span class="org-variable-name">f</span>())&gt; <span class="org-variable-name">data</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">ill-formed because the noexcept-specification for f() is not yet deduced</span>
                         <span class="org-comment-delimiter">// </span><span class="org-comment">because definition of f() is not available until end of class definition.</span>
};
<span class="org-comment-delimiter">// </span><span class="org-comment">Definition of f() isn't available until the end of the class-definition, here.</span>
</pre>
</div></li>
<li><p>
Recursion is also interesting:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">int</span> <span class="org-function-name">f</span>(<span class="org-type">int</span> <span class="org-variable-name">i</span>) <span class="org-keyword">noexcept</span>(<span class="org-keyword">auto</span>)
{
  <span class="org-keyword">if</span> (i == 0)
    <span class="org-keyword">return</span> i;
  <span class="org-keyword">else</span>
    <span class="org-keyword">return</span> f(i-1) + i;
}
</pre>
</div>
<p>
Should in theory be deducible, but ill-formed similar to mutually recursive functions
</p>
<ul class="org-ul">
<li>Minutes:
<ul class="org-ul">
<li>dislike of <code>noexcept(auto)</code> with SFINAE on exception-specifications; having only the latter without the former is ok</li>
<li>you can't overload on exception-specifications, why do you want to SFINAE on it?</li>
<li>can delay determining exception-specification until the function was selected in overload resolution</li>
<li><p>
Issue with non-template deduced member inside class template
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">class</span> <span class="org-type">T1</span>, <span class="org-keyword">class</span> <span class="org-type">T2</span>&gt;
<span class="org-keyword">struct</span> <span class="org-type">C</span> {
  <span class="org-function-name">C</span>(<span class="org-type">C</span>&amp;&amp; <span class="org-variable-name">other</span>) <span class="org-keyword">noexcept</span>(<span class="org-keyword">auto</span>)
  : first(<span class="org-constant">std</span>::move(other)), <span class="org-function-name">second</span>(<span class="org-constant">std</span>::move(other))
  { }
  <span class="org-type">T1</span> <span class="org-variable-name">first</span>;
  <span class="org-type">T2</span> <span class="org-variable-name">second</span>;
};

<span class="org-type">C</span>&lt;<span class="org-type">int</span>, <span class="org-type">int</span>&gt; <span class="org-variable-name">x</span>;  <span class="org-comment-delimiter">// </span><span class="org-comment">will instantiate the body of C::C(&amp;&amp;) right here</span>
</pre>
</div>
<p>
The implicit instantiation of the body of the move constructor should only be performed if ODR-used.
This would make <code>noexcept(auto)</code> more like explicitly enumerating the expressions.
Ideally, the noexcept specification shoud only be deduced if overload selected.
May need to be deduced even if used in unevaluated operand - e.g. <code>noexcept(f())</code>
</p></li>
<li>Issue with debug builds w/ assertions that throw in move-ctor with deduced noexcept meaning that <code>std::vector</code> copies instead of throwing and never calls move ctor.</li>
</ul></li>
<li>Paper was struck from core motions in 2010-11 Batvia meeting
<ul class="org-ul">
<li>I was unable to locate minutes indicating why this was.</li>
</ul></li>

<li>Presentation Notes
<a href="https://wiki.edg.com/pub/Wg21batavia/Documents/noexcept_auto.pdf">https://wiki.edg.com/pub/Wg21batavia/Documents/noexcept_auto.pdf</a>
Lists two perils
<ul class="org-ul">
<li>Adding print statements changes the deduced exception-specification (e.g. using cout)
<ul class="org-ul">
<li>Can workaround by adding try/catch.</li>
</ul></li>
<li>Adding assertions can change deduced exception-specification.
<ul class="org-ul">
<li>An issue if assertion macro throws.</li>
<li>Not an issue if it terminates.</li>
</ul></li>
</ul></li>
</ul></li>
</ul></li>

<li><a href="https://wg21.link/N3227">N3227</a> - Please reconsider noexcept (2010)
<ul class="org-ul">
<li>Draft: <a href="https://wiki.edg.com/pub/Wg21batavia/EvolutionWorkingGroup/reconsider_noexcept.html">https://wiki.edg.com/pub/Wg21batavia/EvolutionWorkingGroup/reconsider_noexcept.html</a></li>
<li><a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3227.html">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3227.html</a></li>
<li>Suggests that we should support deducing <code>noexcept</code>-ness of a function</li>
<li>Talked about avoiding use of flow-analysis to determine noexceptness of a function (undecidable/hard problem - Rice's theorem).</li>
<li>Concerns about inconsistencies across compiler with flow-analysis leading to some programs being well-formed on some compilers but ill-formed on others based on whether they deduced the noexcept the same way.</li>
<li>Not a problem if you ignore flow-analysis and just look at whether there are any potentially-throwing expressions that do not catch exceptions.</li>
<li>Has some expected objections and some counter-arguments</li>
</ul></li>

<li><a href="https://wg21.link/N3204">N3204</a> -  Deducing "noexcept" for destructors (2010)
<ul class="org-ul">
<li>Short paper</li>
<li>Wording for default exception-specification user-defined destructors to be the same as for an implicit destructor.
i.e. deduced from the exception-specifications of the data-members/base-classes.</li>
</ul></li>

<li>N3386 - return type deduction for normal functions (2012)
<ul class="org-ul">
<li>N3638 - Return-type deduction for normal functions (2013)</li>
<li>maybe relevant to <code>noexcept(auto)</code> deduction?</li>
<li>talks about deduced return types for recursive functions
<ul class="org-ul">
<li>works if there is a prior recursion-breaking return-statement by the
time we get to the use of the recursive call.</li>
</ul></li>
<li>Talks about instantiation of function templates even if they are not odr-used
e.g. if you use it in a non-evaluated context such as <code>decltype(f(1))</code>.</li>
<li>Proposes adding <code>decltype(auto)</code> as well.</li>
</ul></li>

<li><a href="https://wg21.link/N4473">N4473</a> - <code>noexcept(auto)</code>, again (2015) (Voutilainen)
<ul class="org-ul">
<li>Tries to open up the discussion about adding <code>noexcept(auto)</code> again.</li>
<li>Not a lot of detail here, other than this is something that is oft-requested, and is a big pain point for some people.</li>
<li><a href="https://wiki.edg.com/bin/view/Wg21lenexa/N4473">Minutes</a>
<ul class="org-ul">
<li>Jason M had some proposed wording (not found/attached)</li>
<li>Had consensus in EWG in Lenexa</li>
</ul></li>
</ul></li>

<li><a href="https://wg21.link/P0133R0">P0133R0</a> -  Putting <code>noexcept(auto)</code> on hold, again (2015) (Voutilainen)
<ul class="org-ul">
<li>Abandoned <code>noexcept(auto)</code> upon realising that you still need to duplicate the expressions
for SFINAE cases.
<ul class="org-ul">
<li>Concern should be reduced now that we have concepts as a nicer syntax for SFINAE</li>
</ul></li>
</ul></li>
</ul>
</div>
</div>

<div id="outline-container-org3cff64e" class="outline-3">
<h3 id="org3cff64e"><span class="section-number-3">6.5.</span> Faster Exceptions</h3>
<div class="outline-text-3" id="text-6-5">
<p>
A number of papers have explored the concept of improving the performance of exceptions.
</p>

<ul class="org-ul">
<li>N4049 - 0-overhead-principle violations in exception handling (2014)</li>
<li>N4234 - 0-overhead-principle violations in exception handling - part 2 (2014)</li>

<li>low-latency SG
<ul class="org-ul">
<li>N4456 - Towards improved support for games, graphics, real-time, low latency, embedded systems
<ul class="org-ul">
<li>Mentions wanting guaranteed support for -fno-exceptions, -fno-rtti
No detail on why/motivation/issues.</li>
</ul></li>
</ul></li>

<li>P0709 Zero-overhead deterministic exceptions (Herb Sutter)
<ul class="org-ul">
<li>Intro sections have a lot of good motivation for fixing exceptions.</li>
<li>Makes the claim that the overheads of dynamic exceptions cannot be avoided by a better
implementation strategy.</li>
<li>Section 4.1 contains EWG polls indicating that exception-handling is something that they want to improve</li>
<li>Marking function with <code>throws</code> turns return type into a union of R + E with a bool flag to indicate whether it's a result/error.
<ul class="org-ul">
<li>Basically baking std::expected into the language</li>
<li>Requires a new function-call ABI.</li>
</ul></li>
<li><code>throws(cond)</code> can be a bool value, or an <code>except_t</code> value (no<sub>except</sub>, static<sub>except</sub>, dynamic<sub>except</sub>)</li>
<li>Proposes a new <code>std::error</code> type
<ul class="org-ul">
<li>Tries to map error values to exception type when propagating out of a function.
e.g. std::errc::ENOMEM &lt;-&gt; std::bad<sub>alloc</sub></li>
<li>For types where there is no obvious standard mapping, it would just wrap an <code>exception_ptr</code></li>
<li>This mapping seems like it would be complicated, and difficult to specify/extend.</li>
</ul></li>
<li>At call sites (that propagate or handle an error), a potential downside of the if-error-goto-handler
implementation model is that it injects branches that can interfere with optimizations.
<ul class="org-ul">
<li>Claims that you can still use table-based handling.
But not sure what this would look like.</li>
</ul></li>
<li>Catching <code>std::error</code> then requires you to do further conditional branches
to determine which of the many possible error-conditions it might be.
<ul class="org-ul">
<li>The callee knew which error they returned with, yet this information has
been type-erased in the <code>std::error</code> object, and the type information
now needs to be extracted again.</li>
</ul></li>

<li>try expression / statement
<ul class="org-ul">
<li>Require every potentially throwing expressions/statement inside a <code>throws</code> function
to be covered by a <code>try</code> expression.</li>
<li>Also proposes a <code>catch(E) { ... }</code> without an opening <code>try { ... }</code> block.
Instead, could have <code>try</code> expressions scattered throughout code between
enclosing open-brace and <code>catch</code> clause.
<ul class="org-ul">
<li>This would have issues with the programmer determining what variables are in-scope inside
the <code>catch</code> block. Every variable whose scope beings after the first <code>try</code> expression
would potentially not exist and not be available in the <code>catch</code> block.</li>
</ul></li>
</ul></li>

<li>Suggests adding a <code>throws{E}</code> syntax for specifying a single error type that would be thrown
instead of <code>std::error</code>.</li>
</ul></li>
</ul>
</div>
</div>
</div>

<div id="outline-container-org3e2ce6f" class="outline-2">
<h2 id="org3e2ce6f"><span class="section-number-2">7.</span> Design Discussion</h2>
<div class="outline-text-2" id="text-7">
</div>
<div id="outline-container-orge4603da" class="outline-3">
<h3 id="orge4603da"><span class="section-number-3">7.1.</span> Code Evolution</h3>
<div class="outline-text-3" id="text-7-1">
<p>
TODO:
</p>
<ul class="org-ul">
<li>How do we evolve a function to add new exception types?</li>
<li>How do we evolve a function to remove exception types from throw-specification?</li>
<li>What about changing from dynamic to static?</li>
<li>Or from static to dynamic?</li>
</ul>
</div>
</div>

<div id="outline-container-orge480e84" class="outline-3">
<h3 id="orge480e84"><span class="section-number-3">7.2.</span> A new calling convention / function-type</h3>
<div class="outline-text-3" id="text-7-2">
<p>
TODO: Describe impacts of adding another category of function-types.
</p>
<ul class="org-ul">
<li>specialization of function-traits</li>
<li>function-object wrappers</li>
<li>type-erasing facilities</li>
</ul>

<p>
TODO: Discuss trade-offs of allowing cast from <code>throw(T1, T2)</code> function-pointers to
<code>throw(...)</code> / <code>noexcept(false)</code> function-pointers
</p>
<ul class="org-ul">
<li>ABI / calling-convention impacts</li>
<li>thunks</li>
</ul>
</div>
</div>

<div id="outline-container-org0bcbd48" class="outline-3">
<h3 id="org0bcbd48"><span class="section-number-3">7.3.</span> Changing the implementation changes the calling convention</h3>
<div class="outline-text-3" id="text-7-3">
<p>
TODO: Expand on these points in more detail
</p>

<ul class="org-ul">
<li>this was a problem with the paper [P1235R0] "implicit <code>constexpr</code>"</li>
</ul>

<p>
counter points
</p>
<ul class="org-ul">
<li>this is already a problem for things with deduced return-type
<ul class="org-ul">
<li>mangled names don't include the return type</li>
<li><code>std::execution</code> / other expression template libraries can change
the return-type of a function if they change the implementation
(i.e. the type of the expression-object being returned)</li>
</ul></li>
<li>lots of template code that wants to be <code>noexcept</code> transparent already has to
maintain this by hand - duplicating the body in the noexcept clause
<ul class="org-ul">
<li>if the implementation changes then so does the noexcept clause</li>
<li>this is not eliminating something</li>
</ul></li>
<li>lots of code is currently specified as "expression equivalent to", which
implies having the equivalent noexceptness.
<ul class="org-ul">
<li>using <code>throw(auto)</code> is a more direct way of expressing that the exception
specification is "expression equivalent to" the function body</li>
</ul></li>
</ul>
</div>
</div>

<div id="outline-container-org4c9465d" class="outline-3">
<h3 id="org4c9465d"><span class="section-number-3">7.4.</span> How accurate does the potentially-thrown exception type calculation need to be?</h3>
<div class="outline-text-3" id="text-7-4">
<p>
This paper currently proposes rules for computing the set of potentially-thrown exception types in a
somewhat conservative way and might include exceptions that a deeper analysis would deduce are
unreachable.
</p>

<p>
It considers only control-flow structure of the function-body and function-signatures of called functions.
It does not involve or require any reasoning about whether or not conditions are always true or false except for
those conditions required to be constant evaluated. i.e. <code>if constexpr</code>.
</p>

<p>
There are a couple of decisions that were made in the design described in this paper which should
be considered further:
</p>
<ul class="org-ul">
<li>whether to consider all identifier labels as reachable or whether to only consider an identifier
label reachable if there is a corresponding <code>goto</code> statement that targets the label that is also
reachable.</li>
<li><p>
whether to consider sub-expressions that are sequenced after other interrupted-flow expressions
within the same statement as unreachable and thus not contributing to the set of potentially
thrown exceptions.
For example: What should the deduced exception specification of <code>f()</code> and <code>g()</code> be?
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">f</span>() <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) { <span class="org-comment-delimiter">// </span><span class="org-comment">deduces to throw(A) or throw(A, B)</span>
  (<span class="org-keyword">throw</span> A{}, <span class="org-keyword">throw</span> B{}); <span class="org-comment-delimiter">// </span><span class="org-comment">throw B{} is unreachable</span>
}

[[noreturn]] <span class="org-type">int</span> <span class="org-function-name">always_throws</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>);
<span class="org-type">void</span> <span class="org-function-name">takes_an_int</span>(<span class="org-type">int</span> <span class="org-variable-name">x</span>) <span class="org-keyword">throw</span>(<span class="org-type">B</span>);

<span class="org-type">void</span> <span class="org-function-name">g</span>() <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) { <span class="org-comment-delimiter">// </span><span class="org-comment">deduces to throw(A) or throw(A, B)</span>
  takes_an_int(never_returns()); <span class="org-comment-delimiter">// </span><span class="org-comment">takes_an_int() is never invoked</span>
}
</pre>
</div></li>
</ul>
</div>
</div>

<div id="outline-container-org9716515" class="outline-3">
<h3 id="org9716515"><span class="section-number-3">7.5.</span> Permission to throw types derived from <code>std::bad_alloc</code> / <code>std::bad_cast</code></h3>
<div class="outline-text-3" id="text-7-5">
<p>
The definition of global <code>operator new</code> and <code>dynamic_cast</code> facilities permit implementations to
throw exceptions that will be caught by a handler for <code>std::bad_alloc</code> or <code>std::bad_cast</code>.
</p>

<p>
This allows implementations to throw types that are derived from these types.
</p>

<p>
If we want to allow these expressions to have static exception specifications then we would
need to constrain these implementations to throw types that were exactly <code>std::bad_alloc</code>
or <code>std::bad_cast</code>. However, doing so is a potential breaking change for any implementations
that are throwing some type derived from these types.
</p>

<p>
And whilst portable C++ code should not be relying on catching a particular exception-type
derived from these classes, implementations could potentially define the semantics for their
implementations of these facilities to throw <code>vendor::bad_alloc</code> or <code>vendor::bad_cast</code>.
</p>

<p>
Having these expressions actually have a static throw-specification would also introduce
a dependency of those expressions on the corresponding library-defined types, which
could be problematic for some implementations. There is presumably already this dependency,
however, since the compiler needs to generate code to throw <code>std::bad_cast</code> for <code>dynamic_cast</code>
expressions.
</p>
</div>
</div>

<div id="outline-container-org4b80ae0" class="outline-3">
<h3 id="org4b80ae0"><span class="section-number-3">7.6.</span> Avoiding dependencies on thread-locals</h3>
<div class="outline-text-3" id="text-7-6">
<p>
The design proposed by this paper allows eliminating some of the overhead of dynamic exceptions;
in particular the dynamic allocation, reference-counting and run-time type-information needed to
perform dynamic matching of handlers.
</p>

<p>
However, there is still some overhead that remains and that is the dependency on thread-local
variables needed to support <code>std::uncaught_exceptions()</code>, <code>std::current_exception()</code> and
dynamic-rethrow expressions.
</p>

<p>
As mentioned in the "Error Handling" section of Ben Craig's paper, <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2268r0.html#error_handling">P2268R0</a> "Freestanding Roadmap",
there are some freestanding environments that do not support thread-locals. P2268 suggests
some potential directions we could take to try to eliminate the dependency on
thread-locals for freestanding environments and this paper discusses them further here.
</p>
</div>

<div id="outline-container-org9823fe5" class="outline-4">
<h4 id="org9823fe5"><span class="section-number-4">7.6.1.</span> Avoiding overhead implied by <code>std::current_exception()</code> and <code>throw;</code></h4>
<div class="outline-text-4" id="text-7-6-1">
<p>
The <code>std::current_exception()</code> function and <code>throw;</code> expression can be called from any
function dynamically within the scope of a handler - they don't need to be called from
code lexically within the handler.
</p>

<p>
However, this means that, because they could be called from an arbitrary number of different
contexts, they don't know anything about the type of the exception objects that might be
returned or rethrown - so they necessarily need to deal with dynamic exception objects.
</p>

<p>
These facilities also rely on accessing thread-local state to be able to find the
current exception object.
</p>

<p>
When a thrown static exception object is caught by a handler, the exception object will be living
on the stack. However, if we want a call to <code>std::current_exception()</code> to be able to return
an <code>exception_ptr</code> that references a dynamic exception object that is a copy of the stack-allocated
object on the stack, then the handler needs to register the address of the static exception object
along with some basic type-information and information about how to copy that object to a new location.
</p>

<p>
This then allows a subsequent call to <code>std::current_exception()</code> within the scope of the handler
to find the object, allocate new storage for a dynamic-exception-object of the right size, copy
the static-exception-object to the dynamic-exception-object and then return an <code>exception_ptr</code>
referencing that dynamic-exception-object.
</p>

<p>
Then on exit from the handler, the handler needs to deregister this information from the
thread-local.
</p>

<p>
All of this generated code for registering/unregistering the static-exception-object
adds to the cost of handling an exception, both in terms of execution and in terms
of binary size.
</p>

<p>
If the compiler can prove that there will be no calls to <code>std::current_exception()</code> or
dynamic rethrow it could theoretically optimize out the registration/deregistration logic.
But this is difficult to prove as soon as the handler contains any calls to functions
that weren't inlined.
</p>

<p>
However, if we were to annotate the handler with some kind of marker that told the
compiler that within the dynamic scope of this handler there will be no calls to
<code>std::current_exception()</code> or any dynamic-rethrow expressions, then the compiler
could avoid needing to register the information about the exception object.
</p>
</div>

<ol class="org-ol">
<li><a id="orge0ac0ac"></a>Using <code>catch static</code> to reduce overhead of dynamic exception facilities<br />
<div class="outline-text-5" id="text-7-6-1-1">
<p>
We could consider adding some kind of annotation/specifier to a handler that allows
the author to indicate that they will not be making use of the dynamic exception
facilities within the handler and that the compiler can optimise on this basis.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">try</span> { something(); }
<span class="org-keyword">catch</span> <span class="org-keyword">static</span> (<span class="org-keyword">const</span> <span class="org-type">X</span>&amp; <span class="org-variable-name">ex</span>) {
  <span class="org-comment-delimiter">// </span><span class="org-comment">user promises not to call std::current_exception() or dynamic-rethrow in here</span>
}
</pre>
</div>

<p>
Annotating a handler thusly signals to the compiler that, while this handler is the active
handler, that:
</p>
<ul class="org-ul">
<li>evaluating a call to <code>std::current_exception()</code> will return an unspecified
<code>std::exception_ptr</code>. It is unspecified since if the handler has caught a
dynamic exception object then there may not be any overhead in registering
the exception object if the act of throwing the exception already registered it.</li>
<li>evaluating a dynamic-rethrow expression either calls <code>std::terminate()</code> or
is undefined-behaviour (which one is TBD).</li>
</ul>

<p>
Note that the handler can still rethrow the exception by evaluating a <code>throw;</code>
expression that is lexically associated with the handler - the compiler knows
where to go to get the exception object in this case.
</p>
</div>
</li>

<li><a id="org211b3f3"></a>Catching <code>std::exception_ptr</code> as an alternative to calling <code>std::current_exception()</code><br />
<div class="outline-text-5" id="text-7-6-1-2">
<p>
Another avenue to explore that might reduce the need for thread-local access
is to allow the user to write:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">try</span> { something(); }
<span class="org-keyword">catch</span> <span class="org-comment-delimiter">/* </span><span class="org-comment">static</span><span class="org-comment-delimiter"> */</span> (<span class="org-constant">std</span>::<span class="org-type">exception_ptr</span> <span class="org-variable-name">e</span>) {
  <span class="org-comment-delimiter">// </span><span class="org-comment">stash 'e' somewhere</span>
}
</pre>
</div>
<p>
as an alternative to writing:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">try</span> { something(); }
<span class="org-keyword">catch</span> (...) {
  <span class="org-keyword">auto</span> <span class="org-variable-name">e</span> = <span class="org-constant">std</span>::current_exception();
  <span class="org-comment-delimiter">// </span><span class="org-comment">stash 'e' somewhere</span>
}
</pre>
</div>

<p>
The alternative formulation potentially allows the compiler to directly
construct the <code>exception_ptr</code> and pass it to the handler without needing
to access the thread-local state.
</p>

<p>
If the thrown exception object was a dynamic-exception-object then it
might not be any more efficient and so might lower to calling <code>std::current_exception()</code>
and just passing the result.
</p>

<p>
If the thrown exception object was a static-exception-object, however, then
the compiler could directly construct a new dynamic-exception-object from the
static-exception-object and pass the pointer withouth having to access the
thread-locals. e.g. as if by <code>std::make_exception_ptr(obj)</code>.
</p>

<p>
On the throwing side, we could consider making a <code>throw expr</code> expression where
argument is a possibly-cv-qualified <code>std::exception_ptr</code> as equivalent to calling
<code>std::rethrow_exception()</code>.
</p>

<p>
This would have great benefits for generic programming if we could treat <code>std::exception_ptr</code>
as if it were just another exception object that could be thrown/caught.
</p>

<p>
The major challenge to a syntax like this, however, is that it would be a breaking change.
There may be code-bases out there that are intentionally throwing an exception of type
<code>std::exception_ptr</code> and catching <code>std::exception_ptr</code> rather than using <code>std::rethrow_exception()</code>
to rethrow the contained dynamic-exception-object.
</p>

<p>
Adoping the semantics described above would mean their <code>catch(std::exception_ptr)</code> handler
would now start matching all exceptions, not just a thrown <code>std::exception_ptr</code>.
</p>

<p>
Also, if we decided that, like <code>catch(...)</code>, that a <code>catch(std::exception_ptr)</code> must
appear as the last handler in the sequence of handlers for a try-block, then it may
cause existing code to become ill-formed if <code>catch(std::exception_ptr)</code> does not
appear as the last handler.
</p>

<p>
A quick search in <a href="https://codesearch.isocpp.org/">https://codesearch.isocpp.org/</a> showed 2 matches for handlers that
were catching a <code>std::exception_ptr</code>.
</p>

<p>
One was a unit-test<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup> in cpprestsdk that was making sure that when an <code>exception_ptr</code>
was being rethrown by an async task library that it was using <code>std::rethrow_exception(eptr)</code>
instead of <code>throw eptr</code> and was checking that the <code>catch(std::exception_ptr)</code> handler was not
being entered when the exception was rethrown.
</p>

<p>
The other was similarly for an async framework in the Ice project which was intentionally
catching an <code>exception_ptr</code> and then immediately calling <code>std::rethrow_exception()</code> to
propagate the exception. Upon further investigation, I found an issue<sup><a id="fnr.2" class="footref" href="#fn.2" role="doc-backlink">2</a></sup> that indicated
a desire to move away from this and a search of the latest version of the codebase
yielded no usage.
</p>

<p>
A search of github yielded one other hit:
</p>
<ul class="org-ul">
<li><a href="https://github.com/quantanotes/heisenberg-go/blob/3a5404c1cba7ae1fe16262219e5535223cf32adf/core/hnsw/hnsw_wrapper.cc#L72">heisenberg-go hnsw<sub>wrapper.cc</sub></a>
This looks like it might be a bug and may have intended to write <code>catch(const std::exception&amp;)</code> as I could
not find any <code>throw</code> expressions that were throwing an <code>exception_ptr</code> in the project.</li>
</ul>

<p>
Usage of this pattern in open-source projects does not seem to be wide-spread.
While not representative of code-bases at large, it may be worth considering a syntax
like this to both allow freestanding platforms that don't have access to thread-locals
an alternative API for obtaining the current exception an an <code>exception_ptr</code> and also
to simplify generic code that needs to deal both dynamic and generic exceptions by
giving them similar forms.
</p>
</div>
</li>
</ol>
</div>

<div id="outline-container-orgf16672e" class="outline-4">
<h4 id="orgf16672e"><span class="section-number-4">7.6.2.</span> Avoiding overhead implied by <code>std::unhandled_exceptions()</code></h4>
<div class="outline-text-4" id="text-7-6-2">
<p>
The <code>std::unhandled_exceptions()</code> function reports a count of the number of in-flight
exceptions on the current thread - ones for which a <code>throw</code> expression has been evaluated
but for which the corresponding handler has not yet been activated.
</p>

<p>
Multiple exceptions can be in-flight at once in the case that a destructor calls some
function that throws an exception which is then caught within the scope of the destructor.
</p>

<p>
This is used by facilities such as <code>scope_success</code> or <code>scope_failure</code> scope-guard objects
that conditionally execute some logic if the destructor is called during the normal scope
exit path or during exception unwind. These classes capture the number of uncaught exceptions
in their constructor and then compare that number to the number of uncaught exceptions in
their destructor decide whether to execute the logic based on the result of that comparison.
</p>

<p>
For example: A scope<sub>failure</sub> can be used to roll back a transaction if something fails
</p>
<div class="org-src-container">
<pre class="src src-c++">{
  <span class="org-type">scope_failure</span> <span class="org-variable-name">cancel_on_fail</span>{[&amp;] { transaction.RollBack(); }};

  <span class="org-keyword">for</span> (<span class="org-keyword">auto</span>&amp; <span class="org-variable-name">x</span> : items) {
    transaction.execute(generate_sql(x)); <span class="org-comment-delimiter">// </span><span class="org-comment">might throw</span>
  }
}
</pre>
</div>

<p>
To make this work, however, the C++ runtime needs to store a thread-local count of the
number of in-flight exceptions and then increment it whenever executing a <code>throw</code> expression
and decrement it whenever a handler is activated.
</p>

<p>
For example, on the Itanium ABI, there is the following interface relevant to <code>std::uncaught_exceptions()</code>
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">struct</span> <span class="org-type">__cxa_eh_globals</span> {
  <span class="org-type">__cxa_exception</span>* <span class="org-variable-name">caughtExceptions</span>;
  <span class="org-type">unsigned</span> <span class="org-type">int</span> <span class="org-variable-name">uncaughtExceptions</span>;
};

<span class="org-comment-delimiter">// </span><span class="org-comment">Gets a pointer to the current thread's exception state</span>
<span class="org-type">__cxa_eh_globals</span>* <span class="org-function-name">__cxa_get_globals</span>(<span class="org-type">void</span>);
</pre>
</div>

<p>
When an exception is thrown, the compiler needs to ensure that something equivalent to
the following:
</p>
<div class="org-src-container">
<pre class="src src-c++">++__cxa_get_globals()-&gt;uncaughtExceptions;
</pre>
</div>
<p>
and then in the handler (immediately after initializing any exception-object parameter)
</p>
<div class="org-src-container">
<pre class="src src-c++">--__cxa_get_globals()-&gt;uncaughtExceptions;
</pre>
</div>

<p>
Usually the increment/decrement is wrapped up inside the <code>__cxa_throw()</code> and <code>__cxa_begin_catch()</code>
functions.
</p>

<p>
The use of a thread-local here is a somewhat indirect mechanism to detect which context
the compiler is calling the destructor and has known deficiencies when used in
conjunction with coroutines or fibers which can suspend and then resume in a different
context, potentially with a different number of in-flight exceptions.
</p>

<p>
One direction to explore, which has been previously hinted at in both P0709 and P2268
(and possibly others) is to allow either having two destructors, one to execute during
exception unwind and another to execute during normal scope exits, or to pass a flag
that indicates the disposition in which the destructor is being called.
</p>

<p>
For example, the strawman syntax of a destructor that takes a parameter of type <code>std::unepxect_t</code>:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-constant">std</span>::<span class="org-type">invocable</span> <span class="org-variable-name">F</span>&gt;
<span class="org-keyword">struct</span> <span class="org-type">scope_failure</span> {
  <span class="org-type">F</span> <span class="org-variable-name">func</span>;

  <span class="org-comment-delimiter">// </span><span class="org-comment">Normal destruction</span>
  ~<span class="org-function-name">scope_failure</span>() {}

  <span class="org-comment-delimiter">// </span><span class="org-comment">Unwind destruction</span>
  ~<span class="org-function-name">scope_failure</span>(<span class="org-constant">std</span>::unexpect_t) {
    func();
  }
};

<span class="org-keyword">template</span>&lt;<span class="org-constant">std</span>::<span class="org-type">invocable</span> <span class="org-variable-name">F</span>&gt;
<span class="org-function-name">scope_failure</span>(<span class="org-type">F</span>) -&gt; <span class="org-type">scope_failure</span>&lt;<span class="org-type">F</span>&gt;;
</pre>
</div>

<p>
The compiler already knows in what contexts it is calling the destructors - the calls
to destructors during unwind is typically separate from the code that calls destructors
during normal scope exit, and so it would be straight-forward for compilers to call
a different overload in exceptional contexts.
</p>

<p>
While this would allow classes like <code>scope_success</code> and <code>scope_failure</code> to be implmented
without a dependency on thread-locals, it would be a fairly large design change and
potentially require a lot of viral changes to standard library types to support.
</p>

<p>
More exploration is needed to determine the viability of this option.
</p>

<p>
In the meantime, it's possible that freestanding platforms that do not support thread-locals
could provide basic exception support but without providing <code>std::uncaught_exceptions()</code>.
</p>
</div>
</div>
</div>

<div id="outline-container-org0df00cd" class="outline-3">
<h3 id="org0df00cd"><span class="section-number-3">7.7.</span> Calling C functions</h3>
<div class="outline-text-3" id="text-7-7">
<p>
When importing APIs from C libraries which were not written with consumption by C++ in-mind,
C function declarations will generally not have any exception-specification listed on them,
thus defaulting the exception-specification to <code>noexcept(false)</code>.
</p>

<p>
When a C++ program calls such functions, the compiler must assume that they could potentially
throw an exception and so may end up generating additional code to handle the case that these
functions throw an exception, even if the vast majority of these functions will never emit
an exception.
</p>

<p>
When you call these C functions from a <code>noexcept</code> function then the worst you get is some
suboptimal code-gen that bloats your binary and maybe misses out on some optimizations.
</p>

<p>
However, within a function that has a static-exception-specification, calling such functions
would require surrounding the call in a <code>try { } catch (...) {  }</code> to ensure that all exceptions
are handled.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">extern</span> <span class="org-string">"C"</span> <span class="org-type">int</span> <span class="org-function-name">some_c_api</span>(<span class="org-type">void</span>*);

<span class="org-type">void</span> <span class="org-function-name">some_caller</span>() <span class="org-keyword">throw</span>(<span class="org-constant">std</span>::<span class="org-type">error_code</span>) {
  <span class="org-comment-delimiter">// </span><span class="org-comment">...</span>

  <span class="org-type">void</span>* <span class="org-variable-name">handle</span> = <span class="org-comment-delimiter">/* </span><span class="org-comment">...</span><span class="org-comment-delimiter"> */</span>;

  <span class="org-type">int</span> <span class="org-variable-name">result</span> = some_c_api(handle); <span class="org-comment-delimiter">// </span><span class="org-comment">ERROR: some_c_api() may throw a dynamic exception which is not handled locally</span>
  <span class="org-keyword">if</span> (result &lt; 0) {
    <span class="org-keyword">throw</span> <span class="org-constant">std</span>::error_code{errno, <span class="org-constant">std</span>::system_category()}
  }

  <span class="org-comment-delimiter">// </span><span class="org-comment">...</span>
}
</pre>
</div>

<p>
This is helpful that the compiler can identify places where control flow may cause
an unhandled exception to be emitted, however in this case may be an example of
a false-positive.
</p>

<p>
The code can be amended either by adding a <code>try/catch(...)</code> around the call,
with either a <code>std::unreachable()</code> or <code>std::terminate()</code> call, although this
still ends up generating sub-optimal code.
</p>

<p>
Alternatively, if the developer knows that the function will not throw, the function-pointer
can be <code>reinterpret_cast</code> to an equivalent function-pointer annotated with <code>noexcept</code> and then
call through that function-pointer. While non-portable, this will work on most platforms and
gives better codegen (without code for handlers).
</p>

<p>
For example: Given the following helpers
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">T</span>&gt; <span class="org-keyword">struct</span> <span class="org-type">noexcept_cast_helper</span>;
<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">R</span>, <span class="org-keyword">typename</span>... <span class="org-type">As</span>&gt;
<span class="org-keyword">struct</span> <span class="org-type">noexcept_cast_helper</span>&lt;<span class="org-type">R</span>(*)(<span class="org-type">As</span>...)&gt; {
  <span class="org-keyword">using</span> <span class="org-type">type</span> = R(*)(<span class="org-type">As</span>...) <span class="org-keyword">noexcept</span>;
};
<span class="org-keyword">template</span>&lt;<span class="org-keyword">typename</span> <span class="org-type">F</span>&gt;
[[<span class="org-constant">clang</span>::always_inline]] <span class="org-keyword">auto</span> <span class="org-function-name">noexcept_cast</span>(<span class="org-type">F</span> <span class="org-variable-name">func</span>) <span class="org-keyword">noexcept</span> {
  <span class="org-keyword">return</span> <span class="org-keyword">reinterpret_cast</span>&lt;<span class="org-keyword">typename</span> <span class="org-constant">noexcept_cast_helper</span>&lt;<span class="org-type">F</span>&gt;::<span class="org-type">type</span>&gt;(func);
}
</pre>
</div>
<p>
you can write the following (which is now well-formed):
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">some_caller</span>() <span class="org-keyword">throw</span>(<span class="org-constant">std</span>::<span class="org-type">error_code</span>) {
  <span class="org-comment-delimiter">// </span><span class="org-comment">...</span>

  <span class="org-type">void</span>* <span class="org-variable-name">handle</span> = <span class="org-comment-delimiter">/* </span><span class="org-comment">...</span><span class="org-comment-delimiter"> */</span>;

  <span class="org-type">int</span> <span class="org-variable-name">result</span> = noexcept_cast(some_c_api)(handle); <span class="org-comment-delimiter">// </span><span class="org-comment">OK: This is now a call to a noexcept function.</span>
  <span class="org-keyword">if</span> (result &lt; 0) {
    <span class="org-keyword">throw</span> <span class="org-constant">std</span>::error_code{errno, <span class="org-constant">std</span>::system_category()}
  }

  <span class="org-comment-delimiter">// </span><span class="org-comment">...</span>
}
</pre>
</div>

<p>
Another direction suggested by Ben Craig was to add something similar to the <code>extern "C"</code> block to allow
declaring that all functions in a given block are <code>noexcept</code>.
</p>

<p>
For example: The following would
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">extern</span> <span class="org-string">"C"</span> { <span class="org-keyword">noexcept</span> {
<span class="org-preprocessor">#include</span> <span class="org-string">"the_c_api.h"</span>
} }
</pre>
</div>

<p>
One concern with this approach would be that it could transitively apply
the <code>noexcept</code> qualifier to all headers included by "the<sub>c</sub><sub>api.h</sub>", not necessarily
just the APIs directly declared by that header.
</p>

<p>
Another potential direction we could explore is the use of <code>try</code> expressions.
For example: A <code>try/else</code> expression that evaluates a first sub-expression and if that exits with an exception then evaluates a second sub-expression as a fallback value.
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">int</span> <span class="org-variable-name">result</span> = <span class="org-keyword">try</span> some_c_api(handle) <span class="org-keyword">else</span> <span class="org-constant">std</span>::terminate();
<span class="org-type">int</span> <span class="org-variable-name">result</span> = <span class="org-keyword">try</span> some_c_api(handle) <span class="org-keyword">else</span> nothrow_unreachable(); <span class="org-comment-delimiter">// </span><span class="org-comment">compiler optimizes this to be as if the function was noexcept.</span>
<span class="org-type">int</span> <span class="org-variable-name">result</span> = <span class="org-keyword">try</span> some_c_api(handle) <span class="org-keyword">else</span> -1;
</pre>
</div>

<p>
This could help simplify calling C APIs that have not been marked non-throwing but for which
the programmer knows it cannot throw.
</p>

<p>
Note that this paper does not propose either of these directions at this time, only
list them as potential directions for further investigation.
</p>
</div>
</div>

<div id="outline-container-org3dece97" class="outline-3">
<h3 id="org3dece97"><span class="section-number-3">7.8.</span> Interaction with Contracts</h3>
<div class="outline-text-3" id="text-7-8">
<p>
The contracts proposal [P2900R6] adds the ability to add pre-conditions and post-conditions to function declarations
and also allows adding <code>contract_assert()</code> expressions.
</p>

<p>
When a contract that is checked is violated, a violation handler is invoked.
As currently specified, implementations can permit the volation handler to throw an exception.
This means that <code>contract_assert()</code> statements can potentially throw exceptions.
</p>

<p>
Whether the violation handler is a throwing handler or not is not necessarily known
by the compiler at the time that a <code>contract_assert()</code> statement is compiled, and the
current contracts facility provides no way of detecting whether or not a contract-assertion
is potentially throwing.
</p>

<p>
Further, throwing violation handlers are not restricted to throwing an exception of a particular type,
so if treating a <code>contract_assert()</code> statement as potentially-throwing then we would need to consider
it as potentially-throwing <span class="underline">any</span> exception type - i.e. as if it had a dynamic exception specification.
</p>

<p>
However, one stated design principle of the contracts facility, listed in [P2900R6]:
</p>
<blockquote>
<p>
<b>Concepts do not see Contracts</b> - if the mere presence of a contract assertion, independent
of the predicate within that assertion, on a function or in a block of code would change
when the satisfiability of a concept then a contained program could be substantially changed
by simply using contracts in such a way. Therefore, we remove the ability to do this.
As a corollary, the addition or removal of a contract assertion must not change the result
of SFINAE, the result of overload resolution, the result of <code>noexcept</code> operator, or which
branch is selected by an <code>if constexpr</code>.
</p>
</blockquote>

<p>
However, this principle, in combination with potentially-throwing contract violation handlers,
seems to be incompatible with several of the features proposed in this paper.
</p>

<p>
The design in P2900R6 makes <code>contract_assert</code> a statement so that you cannot ask the question
whether it is <code>noexcept</code> or not as a <code>noexcept</code> expression requires its operand to also be
an expression. This defers needing to answer the question of whether or not <code>contract_assert</code>
is potentially throwing.
</p>

<p>
However, this question needs to be answered if we wanted to be able to use contracts in
combination with the features proposed in this paper - something I think we should support
</p>

<p>
For example: What is the deduced exception specification of these functions?
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">int</span> <span class="org-function-name">example1</span>(<span class="org-type">int</span> <span class="org-variable-name">x</span>) <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) {
  contract_assert(x != 0);
  <span class="org-keyword">return</span> 42 / x;
}
<span class="org-type">int</span> <span class="org-function-name">example2</span>(<span class="org-type">int</span> <span class="org-variable-name">x</span>) <span class="org-keyword">throw</span>(<span class="org-keyword">auto</span>) <span class="org-function-name">pre</span>(x != 0) {
  <span class="org-keyword">return</span> 42 / x;
}
</pre>
</div>

<p>
For example: Are the following functions well-formed?
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">example3</span>(<span class="org-type">int</span> <span class="org-variable-name">x</span>) <span class="org-keyword">throw</span>() {
  contract_assert(x != 0); <span class="org-comment-delimiter">// </span><span class="org-comment">ill-formed if potentially-throwing</span>
}
<span class="org-type">void</span> <span class="org-function-name">example4</span>(<span class="org-type">int</span> <span class="org-variable-name">x</span>) <span class="org-keyword">throw</span>() <span class="org-function-name">pre</span>(x != 0) {
  <span class="org-comment-delimiter">// </span><span class="org-comment">does a function with a precondition have a potentially-throwing function-body?</span>
}
</pre>
</div>

<p>
For example: Is the call to <code>set_error()</code> below a discarded statement or not?
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">example5</span>(<span class="org-type">int</span> <span class="org-variable-name">x</span>) <span class="org-keyword">throw</span>() {
  <span class="org-keyword">try</span> {
    contract_assert(x != 0);
  } <span class="org-keyword">catch</span> (...) {
    <span class="org-keyword">constexpr</span> <span class="org-type">bool</span> <span class="org-variable-name">is_reachable</span> = <span class="org-keyword">sizeof</span>...(<span class="org-type">declthrow</span>(<span class="org-keyword">throw</span>)) &gt; 0;
    <span class="org-keyword">if</span> <span class="org-keyword">constexpr</span> (is_reachable) {
      set_error(<span class="org-constant">std</span>::current_exception());
    }
  }
}
</pre>
</div>

<p>
If we follow the principle that introducing contracts should not change the satisfiability
of a concept then, for the purposes of computing the set of potentially-thrown exception types
of a <code>contract_assert</code> statement, we would need to treat it as if it were non-throwing.
Otherwise, adding a <code>contract_assert</code> might change the signature of a function with a deduced
exception specification, or might make a function with a static exception specification ill-formed.
</p>

<p>
However, this then seems at odds with the desire for people to make use of throwing
violation handlers to recover from program bugs, as code surrounding contract-assertions
is going to assume that they do not throw - which they don't, for a correct program
which does not violate any of its contracts.
</p>

<p>
I think this conflict helps us get to the core question of what does an exception-specification
mean <i>in the presence of contract checks that might fail</i>.
</p>

<p>
If I mark a function as <code>noexcept</code>, does that mean that it guarantees that calling it will not
ever throw an exception?
Or does it mean it will not throw <i>for an evaluation that does not violate any contract checks</i>?
</p>

<p>
I don't have any solutions to propose here at this stage, but I would like to try to find a
solution that allows both static exceptions and contracts to work well together.
</p>
</div>
</div>

<div id="outline-container-orgd4a8d2e" class="outline-3">
<h3 id="orgd4a8d2e"><span class="section-number-3">7.9.</span> Standard Library Impacts</h3>
<div class="outline-text-3" id="text-7-9">
</div>
<div id="outline-container-org02c12ee" class="outline-4">
<h4 id="org02c12ee"><span class="section-number-4">7.9.1.</span> Whether implementations add <code>noexcept</code> to "Throws: Nothing" functions can now affect well-formedness of a program</h4>
<div class="outline-text-4" id="text-7-9-1">
<p>
A function in the standard library specified as "Throws: Nothing" but for which there is a pre-condition
are often specified as being <code>noexcept(false)</code> functions. The main rationale here is to allow for the
possibility that an implementation might want to throw an exception if the pre-condition is violated,
since violating a pre-condition is undefined-behaviour the implementation is technically free to do
anything, including throw an exception.
</p>

<p>
However, implementations that do not throw exceptions on pre-condition violations and instead
choose to terminate/abort are currently free to add <code>noexcept</code> to function declarations wherever they
feel is appropriate.
</p>

<p>
This permission is granted to them by [<a href="https://eel.is/c++draft/res.on.exception.handling#5">res.on.exception.handling</a>] p5 which says
</p>
<blockquote>
<p>
An implementation may strengthen the exception specification for a non-virtual function
by adding a non-throwing exception specification.
</p>
</blockquote>

<p>
For example MS-STL, libc++ and libstdc++ all declare <code>std::vector::operator[]</code> as <code>noexcept</code> despite it
having a pre-condition that the index is less-than <code>size()</code>. It is worth noting, however, the same
standard library implementations do not mark <code>std::vector&lt;bool&gt;::operator[]</code> with <code>noexcept</code>.
</p>

<p>
With this paper and the ability to either declare a function as having a deduced throw-specification
or to call these functions from a context where the the exception-specification is checked, the
implementation differences on <code>noexcept</code> qualification of these member functions can potentially
affect the well-formedness of the program.
</p>

<p>
For example: The following function would be well-formed on current major standard library implementations
which mark <code>std::vector::operator[]</code> as <code>noexcept</code>, but might be ill-formed on other conforming implementations
that do not mark <code>std::vector::operator[]</code> as <code>noexcept</code>, and thus would not be portable C++ code.
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">example</span>(<span class="org-keyword">const</span> <span class="org-constant">std</span>::<span class="org-type">vector</span>&lt;<span class="org-type">int</span>&gt;&amp; <span class="org-variable-name">v</span>) <span class="org-keyword">throw</span>() {
  <span class="org-type">int</span> <span class="org-variable-name">sum</span> = 0;
  <span class="org-keyword">for</span> (<span class="org-type">size_t</span> <span class="org-variable-name">i</span> = 0; i &lt; v.size(); ++i) {
    sum += v[i];
  }
  <span class="org-keyword">return</span> sum;
}
</pre>
</div>

<p>
A portable implementation would either need to declare this function as <code>noexcept</code> and allow
the possibility of a runtime <code>std::terminate()</code> call if the implementation of <code>example()</code>
happens to contain a bug that violates a pre-condition and the implementation of <code>vector::operator[]</code>
handles this by throwing an exception.
</p>

<p>
Or you would need to surround the body in a <i>function-try-block</i> that calls either <code>std::terminate()</code>
or, if you are confident in the correctness of the code, calls <code>std::unreachable()</code> in the handler.
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">example2</span>(<span class="org-keyword">const</span> <span class="org-constant">std</span>::<span class="org-type">vector</span>&lt;<span class="org-type">int</span>&gt;&amp; <span class="org-variable-name">v</span>) <span class="org-keyword">throw</span>() <span class="org-keyword">try</span> {
  <span class="org-type">int</span> <span class="org-variable-name">sum</span> = 0;
  <span class="org-keyword">for</span> (<span class="org-type">size_t</span> <span class="org-variable-name">i</span> = 0; i &lt; v.size(); ++i) {
    sum += v[i];
  }
  <span class="org-keyword">return</span> sum;
} <span class="org-keyword">catch</span> (...) { <span class="org-constant">std</span>::terminate(); }
</pre>
</div>

<p>
Of course, this is then just semantically equivalent to declaring the function <code>noexcept</code>.
</p>

<p>
Ideally we'd be able to declare that this handler was unreachable by calling <code>std::unreachable()</code>
instead, however <code>std::unreachable()</code> is not specified as <code>noexcept</code> and so might again throw
an exception which would violate the <code>throw()</code> specifier checking.
</p>

<p>
The <code>std::terminate()</code> function, on the other hand, is specified to be <code>noexcept</code>,
and so can be called in this case to portably indicate that the function does not exit
with an exception.
</p>

<p>
Alternatively, the user can define a new <code>nothrow_unreachable()</code> function as follows and call
that instead of <code>std::terminate()</code>:
</p>
<div class="org-src-container">
<pre class="src src-c++">[[noreturn]] <span class="org-type">void</span> <span class="org-function-name">nothrow_unreachable</span>() <span class="org-keyword">noexcept</span> {
  <span class="org-constant">std</span>::unreachable();
}
</pre>
</div>

<p>
This would allow the compiler to assume that the handler is unreachable in modes where
calling <code>std::unreachable()</code> does not throw an exception, and be equivalent to
<code>std::terminate()</code> in modes where it does throw an exception.
</p>
</div>
</div>

<div id="outline-container-org9c171c2" class="outline-4">
<h4 id="org9c171c2"><span class="section-number-4">7.9.2.</span> Should implementations be allowed to strengthen "Throws: something" exception specification to a static exception specification?</h4>
<div class="outline-text-4" id="text-7-9-2">
<p>
Similar to the case where a function that is specified as "Throws: Nothing", there are also functions that are
specified as "Throws: &lt;some-concrete-list-of-types&gt;".
</p>

<p>
For example:
</p>
<ul class="org-ul">
<li><code>std::vector::at(size_t n)</code> is specified to throw <code>std::out_of_range</code> if <code>n &gt;= size()</code>.</li>
<li><code>std::optional::value()</code> is specified to throw <code>std::bad_optional_access</code> if the optional does not contain a value.</li>
<li><code>std::function::operator()</code> is specified to throw either <code>std::bad_function_call</code> or any exception thrown by the target object.</li>
</ul>

<p>
There are also many other cases where a function is specified to throw whatever some other expression throws.
</p>

<p>
In the same vein as the "Throws: Nothing" rule, should we also grant standard library implementations
permission to declare functions that can throw exceptions to have a narrower exception specification
than <code>noexcept(false)</code>. i.e. to have a static-exception-specification.
</p>

<p>
For example, should we allow conforming implementations to declare <code>std::vector::at()</code> with a
<code>throw(std::out_of_range)</code> exception specifier?
</p>

<p>
This would greatly assist with calling such functions from a function with a checked exception specification,
which would otherwise require surrounding such calls in <code>try/catch(...)</code>, and would also allow those functions
to have deterministic performance for the exceptional code-paths.
</p>

<p>
For example: A portable implementation would need to write an extra <code>catch(...)</code> to handle any exceptions that are not specified
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-constant">std</span>::<span class="org-type">uint32_t</span> <span class="org-function-name">walk_graph</span>(<span class="org-keyword">const</span> <span class="org-constant">std</span>::<span class="org-type">vector</span>&lt;<span class="org-constant">std</span>::<span class="org-type">optional</span>&lt;<span class="org-constant">std</span>::<span class="org-type">uint32_t</span>&gt;&gt;&amp; <span class="org-variable-name">v</span>, <span class="org-constant">std</span>::<span class="org-type">uint32_t</span> <span class="org-variable-name">start_at</span>) <span class="org-keyword">throw</span>() {
  <span class="org-constant">std</span>::<span class="org-type">uint32_t</span> <span class="org-variable-name">current</span> = start_at;
  <span class="org-keyword">try</span> {
    <span class="org-keyword">while</span> (<span class="org-constant">true</span>) {
      current = v.at(current).value();
    }
  }
  <span class="org-keyword">catch</span> (<span class="org-constant">std</span>::out_of_range) {}
  <span class="org-keyword">catch</span> (<span class="org-constant">std</span>::bad_optional_access) [}
  <span class="org-keyword">catch</span> (...) { [] <span class="org-keyword">noexcept</span> { <span class="org-constant">std</span>::unreachable(); }(); } <span class="org-comment-delimiter">// </span><span class="org-comment">This line would be unnecessary with static exception specifications</span>
  <span class="org-keyword">return</span> current;
}
</pre>
</div>

<p>
Having a static exception specification for functions like <code>std::vector::at()</code> and <code>std::optional::value()</code>
would actually make them more useful as their performance could now be guaranteed to be on the order of
normal control flow you could write yourself with extra if-checks, rather than the many thousands of cycles
that the current dynamic exception meachnisms would take.
</p>

<p>
However, user code written assuming such narrow exception declarations were placed on the standard library functions
would, again, be non-portable, because other implementations might not put the tighter exception declarations
on their implementations.
</p>

<p>
Note that specifying that these functions must have have a static exception specification
would likely be an ABI break for many implemenations, so we are unlikely to be able to require
implementations to do that.
</p>
</div>
</div>

<div id="outline-container-org4bd02d0" class="outline-4">
<h4 id="org4bd02d0"><span class="section-number-4">7.9.3.</span> Usage of the standard library in functions with static throw-specifications will be painful without more noexcept</h4>
<div class="outline-text-4" id="text-7-9-3">
<p>
Trying to use standard library functions with pre-conditions, and thus a <code>noexcept(false)</code>
exception specification, or even library functions with a <i>Throws: some-type</i> exception
specification from within a function with a static exception specification is going to
require callers to surround the calls in a try/catch(&#x2026;) to ensure that the exception-specification
is not violated.
</p>

<p>
Thus, if this paper is adopted then there will be some pressure on vendors and on the
standard library to provide APIs with narrower exception specifications for these
kinds of functions to allow them to be used in contexts with static exception
specifications without having to write <code>catch(...)</code> in any handlers.
</p>
</div>
</div>

<div id="outline-container-org375278b" class="outline-4">
<h4 id="org375278b"><span class="section-number-4">7.9.4.</span> Function-wrapper types</h4>
<div class="outline-text-4" id="text-7-9-4">
</div>
<ol class="org-ol">
<li><a id="orgd31b2ae"></a><code>std::function</code><br />
<div class="outline-text-5" id="text-7-9-4-1">
<p>
This type is parameterised by a function signature of form <code>R(Args...)</code>.
</p>

<p>
This class is undefined for function signatures of the form <code>R(Args...) noexcept</code>,
largely because doing so would have no effecton the resulting class.
</p>

<p>
The <code>std::function::operator()</code> call can throw the <code>std::bad_function_call</code> exception
if invoked on a <code>std::function</code> instance that is empty and so the <code>operator()</code> could
not be marked <code>noexcept</code> anyway.
</p>

<p>
The existing <code>std::function</code> class could be used as-is to wrap functions and function-objects
whose call-operator as a non-empty static-exception specification. Although we would need to
extend the function-pointer casting rules to allow casting from <code>void(*)() throw(X)</code> to
<code>void(*)() throw(...)</code>.
</p>

<p>
We could also consider defining an additional partial-specialization of <code>std::function</code> that
allowed specifying a function-signature with a static-exception specification and then computed
a static-exception specification for <code>operator()</code> that added <code>std::bad_function_call</code> to that
exception-list.
</p>
</div>
</li>

<li><a id="org18454f1"></a><code>std::copyable_function</code> and <code>std::move_only_function</code><br />
<div class="outline-text-5" id="text-7-9-4-2">
<p>
These types are parameterised on a function-type that inclues the exception-specification.
</p>

<p>
We would need to add additional partial specializations for cases where the function
type passed as the first template argument has a non-empty static exception specification
to have this apply that exception specification to its <code>operator()</code>, and also to require
that the wrapped callable has a compatible exception specification.
</p>
</div>
</li>

<li><a id="org25744e2"></a><code>std::reference_wrapper</code><br />
<div class="outline-text-5" id="text-7-9-4-3">
<p>
This type could have its <code>operator()</code> modified to have a deduced exception specification
so that if the referenced object has an <code>operator()</code> with a static exception specification
then the <code>reference_wrapper::operator()</code> also has an equivalent exception specification.
</p>
</div>
</li>

<li><a id="org4394637"></a>Function objects<br />
<div class="outline-text-5" id="text-7-9-4-4">
<p>
The following types could be extended to have call operators annotated with <code>throw(auto)</code>
to have them deduce the exception specification based on the exception specification of
the underlying operator implementation.
</p>

<p>
Arithmetic function objects
</p>
<ul class="org-ul">
<li><code>std::plus</code></li>
<li><code>std::minus</code></li>
<li><code>std::multiplies</code></li>
<li><code>std::divides</code></li>
<li><code>std::modulus</code></li>
<li><code>std::negate</code></li>
</ul>
<p>
Comparison function object
</p>
<ul class="org-ul">
<li><code>std::less</code></li>
<li><code>std::greater</code></li>
<li><code>std::less_equal</code></li>
<li><code>std::greater_equal</code></li>
<li><code>std::equal_to</code></li>
<li><code>std::not_equal_to</code></li>
<li><code>std::compare_three_way</code></li>
</ul>
<p>
Logical Operations
</p>
<ul class="org-ul">
<li><code>std::logical_and</code></li>
<li><code>std::logical_or</code></li>
<li><code>std::logical_not</code></li>
</ul>
<p>
Bitwise Operations
</p>
<ul class="org-ul">
<li><code>std::bit_and</code></li>
<li><code>std::bit_or</code></li>
<li><code>std::bit_xor</code></li>
<li><code>std::bit_not</code></li>
</ul>
</div>
</li>
</ol>
</div>

<div id="outline-container-org2d7f84d" class="outline-4">
<h4 id="org2d7f84d"><span class="section-number-4">7.9.5.</span> Algorithms</h4>
<div class="outline-text-4" id="text-7-9-5">
<p>
We could also consider adapting algorithms that take lambdas/function-objects as parameters
that the user provides as being transparen to exceptions such that if the user-provided
iterators/ranges and function-objects have static exception specifications then the algorithm
itself has a static exception specification.
</p>

<p>
At the moment, algorithms tend to have <code>noexcept(false)</code> exception specifications and so would
require a <code>try/catch(...)</code> around calls to them if used inside a function with a static exception
specification.
</p>
</div>
</div>
</div>
</div>

<div id="outline-container-org65f744e" class="outline-2">
<h2 id="org65f744e"><span class="section-number-2">8.</span> Implementation Strategies</h2>
<div class="outline-text-2" id="text-8">
<p>
This section describes some potential implementation strategies that could be taken
for implementing the semantics described above.
</p>

<p>
Note that this is just a sketch that talks through some of the potential challenges and
techniques that could be used. It has not yet been implemented in a compiler, so treat
this section as speculative until implementation experience has been gained.
</p>
</div>

<div id="outline-container-orgc7a921f" class="outline-3">
<h3 id="orgc7a921f"><span class="section-number-3">8.1.</span> Multiple return-paths/return-addresses</h3>
<div class="outline-text-3" id="text-8-1">
<p>
One of the intents of the semantics described above for functions with static-exception specifications
is to model them effectively as a function that can either return a value object for the success
return-path or can return an error object for each of a set of possible exception-types listed in the
exception specification.
</p>

<p>
With a normal function call there is usually a single return-address that the callee must transfer
control to when the callee completes.
</p>

<p>
The return-address is usually passed from the caller to the callee on the stack. Many hardware
architectures have dedicated hardware instructions for pushing the address of the next
instruction onto the stack before then jumping to the entry-point of the callee. When returning
there is also often hardware support for popping this return address from the stack and then
jumping to the return address.
</p>

<p>
If the callee is potentially throwing then there is, logically, a second potential return-address
that the callee might transfer execution to when it exits - the exception unwind path. The unwind
path is the path that, logically, exits scopes, destroying automatic-storage duration variables,
until it reaches a matching handler and then transfers execution to that handler.
</p>

<p>
To avoid overhead in having to pass multiple return-addresses to a function and to take advantage of
the dedicated hardware instructions for passing a single return-address and returning to that
return-address upon completion, implementations often use auxiliary data-structures stored within
the binary that allow looking up the exceptional return-address for the current function based
on the return-address for the normal path.
</p>

<p>
With functions with static exception specifications we have a function that has 1 normal return
path and zero or more possible exceptional return-paths.
</p>

<p>
If the caller knows what all of the possible exception types that might be thrown are, it can
statically compute what the unwind path should be for each potential exception type thrown.
e.g. whether it is handled locally within the function or is propagated through to its caller.
</p>

<p>
If the caller could pass, somehow, a list of return-addresses to the callee, one for each
possible return-path, then the callee can then return directly to the return-address corresponding
to either the normal return-path or a particular exception-type return-path.
</p>

<p>
However, we want to do so without increasing substantially the cost of making a normal call.
For example, if we were to have to generate assembly code to push 5 separate return-addresses
onto the stack for a function call to a function that could thrown 4 different exception types
then this would increase the cost of making the function call and the stack-space used by
the calling convention.
</p>

<p>
Also, many CPUs optimise their branch predictor for call/ret instructions to maintain a
stack of recent return-addresses pushed onto the stack so that it can predict the target
that a ret instruction will jump to, assuming that for every call instruction there is
eventually a corresponding ret instruction. Any scheme that doesn't maintain balanced
call/ret instructions can result in a misaligned return-address branch predictor cache
which can significantly increase the number of subsequent branch mispredictions.
</p>

<p>
One approach to implementing this with a lower cost for a function call would be to provide
a jump-table of possible return-addresses and to instead push a pointer to the jump-table
as part of the call instruction.
</p>

<p>
On x86/x86-64 architectures this can be done relatively cheaply in one of two ways
without increasing the amount of stack-space and would only require one additional
instruction to be executed on the normal return path compared to a normal function-call.
</p>
</div>

<div id="outline-container-orgd83e104" class="outline-4">
<h4 id="orgd83e104"><span class="section-number-4">8.1.1.</span> Inline Jump Tables</h4>
<div class="outline-text-4" id="text-8-1-1">
<p>
The first option would be to immediately follow a <code>call</code> instruction with a series of
5-byte <code>jmp</code> instructions that jump to the relevant block for handling the corresponding
return-path. The first jmp instruction would jump to the code for the normal-return path,
and subsequent jmp instructions for each exception path.
</p>

<p>
This calling convention is backwards compatible with existing calling conventions.
The caller issues a <code>call</code> instruction as per normal and the callee when it returns a value
just issues a <code>ret</code> instruction to return, which transfers to the first <code>jmp</code> instruction
which then unconditionally jumps to the code that handles this path.
</p>

<p>
The additional direct <code>jmp</code> instruction should be reasonably able to be predicted/pipelined
by a CPU so shouldn't add much in the way of additional latency (NOTE: to be confirmed with data).
</p>

<p>
For example, given the following code:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">int</span> <span class="org-function-name">divide</span>(<span class="org-type">int</span> <span class="org-variable-name">num</span>, <span class="org-type">int</span> <span class="org-variable-name">den</span>) <span class="org-keyword">throw</span>(<span class="org-type">divide_by_zero</span>, <span class="org-type">overflow</span>) {
  <span class="org-keyword">if</span> (den == 0) <span class="org-keyword">throw</span> divide_by_zero{};
  <span class="org-keyword">if</span> (den == -1 &amp;&amp; num == INT_MIN) <span class="org-keyword">throw</span> overflow{};
  <span class="org-keyword">return</span> num/den;
}

<span class="org-type">int</span> <span class="org-variable-name">x</span>, <span class="org-variable-name">y</span>;

<span class="org-type">int</span> <span class="org-function-name">example</span>() {
  <span class="org-keyword">try</span> {
    <span class="org-type">int</span> <span class="org-variable-name">result</span> = divide(x, y);
    <span class="org-keyword">return</span> 2 * result;
  } <span class="org-keyword">catch</span> (<span class="org-type">divide_by_zero</span> <span class="org-variable-name">e</span>) {
    <span class="org-keyword">return</span> -1;
  } <span class="org-keyword">catch</span> (overflow) {
    <span class="org-keyword">return</span> -2;
  }
}
</pre>
</div>

<p>
The caller could be translated into assembly similar to the following:
</p>
<div class="org-src-container">
<pre class="src src-asm"><span class="org-function-name">x</span>:
  <span class="org-keyword">.data</span> 4

<span class="org-function-name">y</span>:
  <span class="org-keyword">.data</span> 4

<span class="org-function-name">example</span>:
  <span class="org-keyword">mov</span> edi, dword ptr [x]   <span class="org-comment-delimiter">; </span><span class="org-comment">Load 'x' into register for param 1</span>
  <span class="org-keyword">mov</span> esi, dword ptr [y]   <span class="org-comment-delimiter">; </span><span class="org-comment">Load 'y' into register for param 2</span>
  <span class="org-keyword">call</span> divide    <span class="org-comment-delimiter">; </span><span class="org-comment">Jump to 'divide' and push address of .JUMP_TABLE onto stack</span>
<span class="org-function-name">.JUMP_TABLE</span>:     <span class="org-comment-delimiter">; </span><span class="org-comment">Each entry is a 'JMP rel32' encoded instruction which is 5 bytes</span>
  <span class="org-keyword">jmp</span> .SUCCESS   <span class="org-comment-delimiter">; </span><span class="org-comment">entry[0] - success path</span>
  <span class="org-keyword">jmp</span> .ERR_0     <span class="org-comment-delimiter">; </span><span class="org-comment">entry[1] - error path for divide_by_zero</span>
  <span class="org-keyword">jmp</span> .ERR_1     <span class="org-comment-delimiter">; </span><span class="org-comment">entry[2] - error path for overflow</span>
<span class="org-function-name">.SUCCESS</span>:
  # result is in eax
  <span class="org-keyword">mul</span> eax, 2
  <span class="org-keyword">ret</span>
<span class="org-function-name">.ERR_0</span>:
  <span class="org-keyword">mov</span> eax, -1
  <span class="org-keyword">ret</span>
<span class="org-function-name">.ERR_1</span>:
  <span class="org-keyword">mov</span> eax, -2
  <span class="org-keyword">ret</span>
</pre>
</div>

<p>
Note that for simplicity, this is assuming that the divide<sub>by</sub><sub>zero</sub> and overflow
types are empty, trivially destructible types.
</p>

<p>
The callee function could be translated into assembly similar to the following:
</p>

<div class="org-src-container">
<pre class="src src-asm"><span class="org-function-name">divide</span>:
  <span class="org-comment-delimiter">;</span><span class="org-comment"># NOTE: [rsp] points to address of .JUMP_TABLE</span>
  <span class="org-keyword">test</span> esi, esi
  <span class="org-keyword">je</span> .THROW1
  <span class="org-keyword">cmp</span> esi, -1
  <span class="org-keyword">jne</span> .LBL1:
  <span class="org-keyword">cmp</span> edi, 0x7fffffff
  <span class="org-keyword">jne</span> .THROW2
<span class="org-function-name">.LBL1</span>:
  <span class="org-keyword">mov</span> eax, edi
  <span class="org-keyword">cdq</span>
  <span class="org-keyword">idiv</span> esi
  <span class="org-keyword">ret</span>       <span class="org-comment-delimiter">; </span><span class="org-comment">return to entry[0]</span>
<span class="org-function-name">.THROW1</span>:
  <span class="org-comment-delimiter">; </span><span class="org-comment">[rsp] contains address of entry[0] instruction</span>
  <span class="org-comment-delimiter">; </span><span class="org-comment">need to add '5' (size of JMP instruction) to this to get address of entry[1]</span>
  <span class="org-comment-delimiter">; </span><span class="org-comment">do this in-place to avoid using an extra register to compute the address</span>
  <span class="org-keyword">add</span> qword ptr [rsp], 5
  <span class="org-keyword">ret</span>       <span class="org-comment-delimiter">; </span><span class="org-comment">return to entry[1]</span>
<span class="org-function-name">.THROW2</span>:
  <span class="org-comment-delimiter">; </span><span class="org-comment">[rsp] contains address of entry[0] instruction</span>
  <span class="org-comment-delimiter">; </span><span class="org-comment">need to add '10' (size of 2 * JMP instruction) to this to get address of entry[2]</span>
  <span class="org-comment-delimiter">; </span><span class="org-comment">do this in-place to avoid using an extra register to compute the address</span>
  <span class="org-keyword">add</span> qword ptr [rsp], 10
  <span class="org-keyword">ret</span>       <span class="org-comment-delimiter">; </span><span class="org-comment">return to entry[2]</span>
</pre>
</div>

<p>
A few things are worth noting here.
</p>
<ul class="org-ul">
<li>The calling code still just passes arguments in registers, calls the
function with a call-instruction, which returns on the normal return-path
back to the instruction after the call-instruction.</li>
<li>The callee still executes a normal 'ret' instruction to return on the
normal code-path.</li>
<li>On the error return-path, the callee adjusts the return address by adding
a constant to the location on the stack where the return-address is stored.
On x86 this can be done with a single instruction and does not require any
additional registers.</li>
<li>After returning to the appropriate return-address, the caller then needs
to jump to the appropriate location to execute the logic for that code-path.
<ul class="org-ul">
<li>For the success case, this is the one extra instruction that needs to be
executed compared to traditional table-based exception-throwing calling
conventions.</li>
</ul></li>
<li>There is no need for additional exception-unwind-lookup tables or runtime-type-information.
All of the data/logic for handling the exceptions is local and inline within
the caller and callee.</li>
<li>There are no additional branches to execute on the caller side here.
Once the callee has branched to the necessary code path that executes the
<code>throw</code> expression, it returns directly to the code-path in the caller that
handles that case.</li>
</ul>

<p>
Of particular note is that overhead of returning via the exception code-path
is one additional instruction.
</p>

<p>
A slight space-optimisation could be to inline the final code-path (in the above example,
the code-path corresponding to the 'overflow' exception case) in lieu of having a
jump instruction for the final block of code.
</p>

<p>
For example: Inlining the last case into the jump table
</p>
<div class="org-src-container">
<pre class="src src-asm"><span class="org-function-name">example</span>:
  <span class="org-keyword">mov</span> edi, dword ptr [x]   <span class="org-comment-delimiter">; </span><span class="org-comment">Load 'x' into register for param 1</span>
  <span class="org-keyword">mov</span> esi, dword ptr [y]   <span class="org-comment-delimiter">; </span><span class="org-comment">Load 'y' into register for param 2</span>
  <span class="org-keyword">call</span> divide    <span class="org-comment-delimiter">; </span><span class="org-comment">Jump to 'divide' and push address of .JUMP_TABLE onto stack</span>
<span class="org-function-name">.JUMP_TABLE</span>:     <span class="org-comment-delimiter">; </span><span class="org-comment">Each entry is a 'JMP rel32' encoded instruction which is 5 bytes</span>
  <span class="org-keyword">jmp</span> .SUCCESS   <span class="org-comment-delimiter">; </span><span class="org-comment">entry[0] - success path</span>
  <span class="org-keyword">jmp</span> .ERR_0     <span class="org-comment-delimiter">; </span><span class="org-comment">entry[1] - error path for divide_by_zero</span>
<span class="org-function-name">.ERR_1</span>:
  <span class="org-keyword">mov</span> eax, -2.   <span class="org-comment-delimiter">; </span><span class="org-comment">entry[2] - error path for overflow (inlined as last jump table entry)</span>
  <span class="org-keyword">ret</span>
<span class="org-function-name">.SUCCESS</span>:
  <span class="org-comment-delimiter">; </span><span class="org-comment">result is in eax</span>
  <span class="org-keyword">mul</span> eax, 2
  <span class="org-keyword">ret</span>
<span class="org-function-name">.ERR_0</span>:
  <span class="org-keyword">mov</span> eax, -1
  <span class="org-keyword">ret</span>
</pre>
</div>

<p>
One concern with this approach is that the normal return-path is no longer inline
immediately after the call instruction as there is now a number of jmp instructions
interspersed between the call and the logic that handles the success case.
</p>

<p>
This can potentially have a detrimental effect on instruction-cache miss rate,
particularly if the number of possible exception types is large. e.g. if there
were more than 12 possible exception types listed in the signature, each of which
required their own jump table entry, then you're pretty much guaranteed that the
call instruction will live in a different cache-line to the normal return-path
and so may be more likely to result in an instruction-cache miss.
For cases with a small number of exception types, the overhead on the normal
return-path is expected to be small, however.
</p>

<p>
The other (minor) concern is that returning with a <code>ret</code> instruction with a modified
return-address is basically always going to mis-predict the return-address on CPUs
that use a return-address cache to predict the target of <code>ret</code> addresses.
</p>

<p>
While a branch mis-predict would still be much faster than table-based, dynamic
exception throwing, there may be use-cases for which this is significant.
If it becomes an important enough performance problem, future CPU designs could
potentially solve the mis-prediction by introducing a dedicated <code>retn</code> instruction
that encodes the index of the jump table in an immediate value, which would allow
the branch predictor to correctly predict the alternative return-paths.
</p>

<p>
Implementation experience is required to evaluate the actual impact of these issues
on the performance of the normal call-path and on the performance of the error
path.
</p>
</div>
</div>

<div id="outline-container-org8a1806c" class="outline-4">
<h4 id="org8a1806c"><span class="section-number-4">8.1.2.</span> "NOP Stuffing" Jump Tables</h4>
<div class="outline-text-4" id="text-8-1-2">
<p>
Another alternative approach of implementing the jump-table is to somehow embed
a pointer/offset to an external jump-table in a location relative to the call
instruction.
</p>

<p>
On x86/64 there are some <code>nop</code> instruction encodings that have unused bytes
within them and this can be used to encode some data in the instruction stream
without that instruction having any effect on the state of the CPU registers
(other than advancing the instruction pointer).
</p>

<p>
You can place this instruction immediately following a call instruction and
encode into the spare bits of the instruction, an offset to the jump table.
As this instruction is a no-op, you can just immediately follow the instruction
with the logic for handling the normal return-path. In this case, there is
much less of a concern with instruction cache misses.
</p>

<p>
So in the above case, the caller would be replaced with:
</p>
<div class="org-src-container">
<pre class="src src-asm"><span class="org-function-name">example</span>:
  <span class="org-keyword">mov</span> edi, dword ptr [x]   <span class="org-comment-delimiter">; </span><span class="org-comment">Load 'x' into register for param 1</span>
  <span class="org-keyword">mov</span> esi, dword ptr [y]   <span class="org-comment-delimiter">; </span><span class="org-comment">Load 'y' into register for param 2</span>
  <span class="org-keyword">call</span> divide    <span class="org-comment-delimiter">; </span><span class="org-comment">Jump to 'divide' and push address of .JUMP_TABLE onto stack</span>
<span class="org-keyword">.DATA_NOP</span>
  <span class="org-keyword">nop</span> DWORD (.JUMP_TABLE - .DATA_NOP) <span class="org-comment-delimiter">; </span><span class="org-comment">3-byte prefix + 4-bytes jump table offset</span>
  <span class="org-keyword">mul</span> eax, 2
  <span class="org-keyword">ret</span>

<span class="org-function-name">.JUMP_TABLE</span>:     <span class="org-comment-delimiter">; </span><span class="org-comment">Each entry of table is a pointer to return-address</span>
  <span class="org-keyword">data</span> DWORD (.ERR_0 - .DATA_NOP)
  <span class="org-keyword">data</span> DWORD (.ERR_1 - .DATA_NOP)

<span class="org-function-name">.ERR_0</span>:
  <span class="org-keyword">mov</span> eax, -1.  <span class="org-comment-delimiter">; </span><span class="org-comment">entry[1] - error path for divide_by_zero</span>
  <span class="org-keyword">ret</span>

<span class="org-function-name">.ERR_1</span>:
  <span class="org-keyword">mov</span> eax, -2.  <span class="org-comment-delimiter">; </span><span class="org-comment">entry[2] - error path for overflow</span>
  <span class="org-keyword">ret</span>
</pre>
</div>

<p>
Then the callee would be updated to look something like the following:
</p>
<div class="org-src-container">
<pre class="src src-asm"><span class="org-function-name">divide</span>:
  <span class="org-comment-delimiter">; </span><span class="org-comment">NOTE: [rsp] points to address of nop encoding offset to .JUMP_TABLE</span>
  <span class="org-keyword">test</span> esi, esi
  <span class="org-keyword">je</span> .THROW1
  <span class="org-keyword">cmp</span> esi, -1
  <span class="org-keyword">jne</span> .LBL1:
  <span class="org-keyword">cmp</span> edi, 0x7fffffff
  <span class="org-keyword">jne</span> .THROW2
<span class="org-function-name">.LBL1</span>:
  <span class="org-keyword">mov</span> eax, edi
  <span class="org-keyword">cdq</span>
  <span class="org-keyword">idiv</span> esi
  <span class="org-keyword">ret</span>       <span class="org-comment-delimiter">; </span><span class="org-comment">return to nop instruction (normal return)</span>
<span class="org-function-name">.THROW1</span>:
  <span class="org-comment-delimiter">; </span><span class="org-comment">[rsp] contains address of nop instruction (i.e. return address)</span>
  <span class="org-keyword">mov</span> rax, QWORD PTR [rsp]       <span class="org-comment-delimiter">; </span><span class="org-comment">load the address of the nop instruction</span>
  <span class="org-keyword">mov</span> edx, DWORD PTR [rax+3]     <span class="org-comment-delimiter">; </span><span class="org-comment">load the offset-to-jump-table part of the nop instruction (assuming 7 byte encoding, last 4 bytes is offset)</span>
  <span class="org-keyword">mov</span> edx, DWORD PTR [rax+rdx]   <span class="org-comment-delimiter">; </span><span class="org-comment">load the offset in entry[0] of table</span>
  <span class="org-keyword">add</span> QWORD PTR [rsp], rdx       <span class="org-comment-delimiter">; </span><span class="org-comment">add offset to return-address</span>
  <span class="org-keyword">ret</span>                            <span class="org-comment-delimiter">; </span><span class="org-comment">return to unwind path for 'divide_by_zero'</span>
<span class="org-function-name">.THROW2</span>:
  <span class="org-keyword">mov</span> rax, QWORD PTR [rsp]       <span class="org-comment-delimiter">; </span><span class="org-comment">load the address of the nop instruction</span>
  <span class="org-keyword">mov</span> edx, DWORD PTR [rax+3]     <span class="org-comment-delimiter">; </span><span class="org-comment">load the offset-to-jump-table part of the nop instruction (assuming 7 byte encoding, last 4 bytes is offset)</span>
  <span class="org-keyword">mov</span> edx, DWORD PTR [rax+rdx+4] <span class="org-comment-delimiter">; </span><span class="org-comment">load the offset in entry[1] of table</span>
  <span class="org-keyword">add</span> QWORD PTR [rsp], rdx       <span class="org-comment-delimiter">; </span><span class="org-comment">add offset to return-address</span>
  <span class="org-keyword">ret</span>                            <span class="org-comment-delimiter">; </span><span class="org-comment">return to unwind path for 'overflow'</span>
</pre>
</div>

<p>
Note that with this approach, the success return path can now place the
rest of the code inline after the <code>NOP</code> instruction, and so is more likely to
be in-cache.
</p>

<p>
However, this comes at the cost of additional instructions for each of the
exceptional return paths, including one additional memory load to load the
jump table entry's offset.
</p>

<p>
It's unclear whether the "inline jump table" or "nop stuffing jump table"
approach would be more efficient or smaller code-size overall.
Both approaches will need to be tried on a variety of code-bases to evaluate
effects on performance and code-size.
</p>

<p>
Other architectures may have alternative approaches that are possible or may have additional
constraints - these will all need to be investigated.
</p>
</div>
</div>
</div>

<div id="outline-container-orgd40790f" class="outline-3">
<h3 id="orgd40790f"><span class="section-number-3">8.2.</span> Multiple return-value-slots</h3>
<div class="outline-text-3" id="text-8-2">
<p>
The previous section focused mostly on how to implement multiple return-addresses
for a given function in an efficient way. We also need to consider how to return
the exception objects themselves.
</p>

<p>
With the normal return path, there are a couple of common conventions for passing
the return value back to the caller. If the return type is void there is nothing
to do as the return-path does not need to pass a value back.
</p>

<p>
If the return-type is trivially copyable or trivially movable and the return-value
fits within a register or two then the return-value can sometimes be passed back
in designated register(s).
e.g. on x86-64 this is often the eax/rax register
</p>

<p>
Otherwise, in order to support guaranteed copy-elision, the return object will need
to be constructed into storage provided by the caller. For normal return-values
the caller usually provides the address of this storage by passing it as an additional
(hidden) parameter to the function, usually in a register, which the callee then uses
to construct the return object before returning.
</p>

<p>
When returning an exception object from a function with a static exception specifcation
we can use a lot of the same conventions for passing the excepton value back.
</p>

<p>
If the exception object is trivially copyable/movable and empty then we just return to
the corresponding return-address without consuming a register.
</p>

<p>
If the exception object is trivially copyable/movable and fits within a register or two,
then we can put the exception object in a register before returning to corresponding
return-address. The caller can then just read the exception object value from the register(s).
</p>

<p>
If the exception object needs to be placed in memory then to get the same copy-elision
behaviour as for normal return-values the caller needs to provide the address of the
storage for that particular exception type.
</p>

<p>
This presents somewhat of a challenge, because now, instead of passing a single address
for the return value, we potentially need to pass N addresses, one for the return object
and one for each of the exception object types.
</p>

<p>
It is also worth noting here that if the called function accepts a return-value-slot
parameter then the storage for the exception object must be distinct from the storage
for the return-value. This is because an exception might be thrown while constructing
the return-value - the exception-object might need to be constructed while the return-value
is still partially initialized.
</p>

<p>
This paper describes two possible approaches to passing the storage address for
exception objects. Other approaches are certainly possible, this paper does not seek
to provide an exhaustive list of them, but rather to show that efficient implementations
exist and also to discuss some of the tradeoffs.
</p>
</div>
</div>

<div id="outline-container-org289c68a" class="outline-3">
<h3 id="org289c68a"><span class="section-number-3">8.3.</span> Passing an exception-value-slot parameter</h3>
<div class="outline-text-3" id="text-8-3">
<p>
The first approach described is similar to the approach described in [Renwick].
</p>

<p>
If any of the potentially-thrown exception types of the function being called are
non-trivial and thus unable to be returned in registers, the caller passes the
address of storage for any non-trivial exception objects as an additional (hidden)
parameter to the function call. This paramter is referred to has the exception-value-slot.
This is in addition to any return-value-slot parameter.
</p>

<p>
The address must point to storage that is suitably sized and aligned to hold <i>any</i>
of the non-trivial exception types listed in that call's throw specification.
</p>

<p>
If the caller handles all potentially-thrown exceptions locally, and does not
rethrow any of the exceptions to its caller, then the caller can allocate storage
for the exception object within its stack-frame (or coroutine-frame) and then pass
the address of that storage as the exception-value-slot parameter.
</p>

<p>
If the caller does not locally handle all of the exceptions and the caller has
a dynamic exception specification, then this is handled as-if the function had
a <code>try { /function-body/ } template catch (auto&amp; e) { throw std::move(e); }</code>
wrapped around the function body. This then rethrows any static exception objects
that escape the function as dynamic exception objects - initializing the dynamic
exception object by move-constructing it from the static exception object.
</p>

<p>
If the caller itself has a static exception specification and does not locally
handle any of the potentially thrown exceptions then the caller can just pass
through the address passed to it in its exception-value-slot parameter.
</p>

<p>
In this situation, as all of the exception-types are propagated through to the
caller's caller then this implies that the caller's throw-specification is a
super-set of the exception types listed in the callee's throw specification,
otherwise the function would be ill-formed.
Therefore, the storage provided by the caller's caller should already be guaranteed
to be sized and aligned sufficiently to handle any of the thrown exceptions.
</p>

<p>
This leaves the more interesting situation where the caller handles some of the
exceptions and propagates some exceptions to its caller.
</p>

<p>
For example: Assuming <code>A</code>, <code>B</code> and <code>C</code> are non-trivial exception types
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">callee</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>, <span class="org-type">B</span>, <span class="org-type">C</span>);

<span class="org-type">void</span> <span class="org-function-name">caller</span>() <span class="org-keyword">throw</span>(<span class="org-type">C</span>) {
  <span class="org-keyword">try</span> {
    callee();
  }
  <span class="org-keyword">catch</span> (<span class="org-keyword">const</span> <span class="org-type">A</span>&amp; <span class="org-variable-name">a</span>) { print(a); }
  <span class="org-keyword">catch</span> (<span class="org-keyword">const</span> <span class="org-type">B</span>&amp; <span class="org-variable-name">b</span>) { print(b); }
}

<span class="org-type">void</span> <span class="org-function-name">parent_caller</span>() <span class="org-keyword">throw</span>() {
  <span class="org-keyword">try</span> {
    caller();
  }
  <span class="org-keyword">catch</span> (<span class="org-keyword">const</span> <span class="org-type">C</span>&amp; <span class="org-variable-name">c</span>) { print(c); }
}
</pre>
</div>

<p>
In this example, if the size and alignment of the storage provided by <code>parent_caller()</code>
to <code>caller()</code> for the exception object <code>C</code> is also sufficient for storing an object of
either type <code>A</code> or <code>B</code>, then <code>caller()</code> can still pass along the that storage to <code>callee()</code>,
it just needs to make sure that if an <code>A</code> or <code>B</code> is thrown then the exception object is
destroyed before control returns to <code>parent_caller()</code>.
</p>

<p>
For example, it could be lowered to something (roughly) equivalent to the following example.
Note that below, functions with multiple return-addresses are returning an <code>int</code>
to indicate which return-address it should return to. When lowered to assembly,
assume this would instead use one of the approaches described above for returning
to the corresponding return address.
</p>

<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">int</span> <span class="org-function-name">callee</span>(<span class="org-type">void</span>* <span class="org-variable-name">__exception_value_slot</span>);

<span class="org-type">int</span> <span class="org-function-name">caller</span>(<span class="org-type">void</span>* <span class="org-variable-name">__exception_value_slot</span>) {
  <span class="org-keyword">switch</span> (callee(__exception_value_slot)) {
  <span class="org-keyword">case</span> 0: <span class="org-keyword">goto</span> <span class="org-constant">normal_return</span>;
  <span class="org-keyword">case</span> 1: <span class="org-keyword">goto</span> <span class="org-constant">throw_a</span>;
  <span class="org-keyword">case</span> 2: <span class="org-keyword">goto</span> <span class="org-constant">throw_b</span>;
  <span class="org-keyword">case</span> 3: <span class="org-keyword">goto</span> <span class="org-constant">throw_c</span>;
  }

 <span class="org-constant">throw_a</span>:
  <span class="org-keyword">const</span> <span class="org-keyword">auto</span>&amp; <span class="org-variable-name">a</span> = *<span class="org-keyword">reinterpret_cast</span>&lt;<span class="org-type">A</span>*&gt;(__exception_value_slot);
  print(a);
  a.~A();
  <span class="org-keyword">goto</span> <span class="org-constant">normal_return</span>;

 <span class="org-constant">throw_b</span>:
  <span class="org-keyword">const</span> <span class="org-keyword">auto</span>&amp; <span class="org-variable-name">b</span> = *<span class="org-keyword">reinterpret_cast</span>&lt;<span class="org-type">B</span>*&gt;(__exception_value_slot);
  print(b);
  b.~B();
  <span class="org-keyword">goto</span> <span class="org-constant">normal_return</span>;

 <span class="org-constant">throw_c</span>:
  <span class="org-comment-delimiter">// </span><span class="org-comment">Propagate C exception to caller.</span>
  <span class="org-keyword">return</span> 1;

 <span class="org-constant">normal_return</span>:
  <span class="org-keyword">return</span> 0;
}

<span class="org-type">void</span> <span class="org-function-name">parent_caller</span>() {
  <span class="org-keyword">alignof</span>(C) <span class="org-type">unsigned</span> <span class="org-type">char</span> <span class="org-variable-name">__exception_storage</span>[<span class="org-keyword">sizeof</span>(C)];

  <span class="org-keyword">switch</span>(caller(&amp;__exception_storage[0])) {
  <span class="org-keyword">case</span> 0: <span class="org-keyword">goto</span> <span class="org-constant">normal_return</span>;
  <span class="org-keyword">case</span> 1: <span class="org-keyword">goto</span> <span class="org-constant">throw_c</span>;
  }

  <span class="org-constant">throw_c</span>:
    <span class="org-keyword">const</span> <span class="org-keyword">auto</span>&amp; <span class="org-variable-name">c</span> = *<span class="org-keyword">reinterpret_cast</span>&lt;<span class="org-type">C</span>*&gt;(&amp;__exception_storage[0]);
    print(c);
    c.~C();
    <span class="org-keyword">goto</span> <span class="org-constant">normal_return</span>;

  <span class="org-constant">normal_return</span>:
    <span class="org-keyword">return</span>;
}
</pre>
</div>

<p>
However, if, say, the <code>B</code> object was larger than the <code>C</code> object, then the <code>caller()</code>
function cannot just pass the storage passed to its exception-value-slot onto <code>callee()</code>
as this storage is only guaranteed to be able to fit a <code>C</code>.
</p>

<p>
So in this case, the <code>caller()</code> function needs to allocate its own local storage, sufficiently
sized for storing either an <code>A</code>, <code>B</code> or <code>C</code>, and then pass that to <code>callee()</code>.
</p>

<p>
However, this means then that in the casethat <code>callee()</code> throws a <code>C</code>, which we want to propagate
to <code>parent_caller()</code>, then we need to move-construct the <code>C</code> object from <code>caller()</code>'s local storage
to its exception-value-slot.
</p>

<p>
The <code>caller()</code> function from above would need to change to:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">int</span> <span class="org-function-name">caller</span>(<span class="org-type">void</span>* <span class="org-variable-name">__exception_value_slot</span>) {
  alignas(A) alignas(B) alignas(C)
  <span class="org-type">unsigned</span> <span class="org-type">char</span> <span class="org-variable-name">__exception_storage</span>[<span class="org-constant">std</span>::max(<span class="org-keyword">sizeof</span>(A), <span class="org-constant">std</span>::max(<span class="org-keyword">sizeof</span>(B), <span class="org-keyword">sizeof</span>(C)))];

  <span class="org-keyword">switch</span> (callee(&amp;__exception_storage)) {
  <span class="org-keyword">case</span> 0: <span class="org-keyword">goto</span> <span class="org-constant">normal_return</span>;
  <span class="org-keyword">case</span> 1: <span class="org-keyword">goto</span> <span class="org-constant">throw_a</span>;
  <span class="org-keyword">case</span> 2: <span class="org-keyword">goto</span> <span class="org-constant">throw_b</span>;
  <span class="org-keyword">case</span> 3: <span class="org-keyword">goto</span> <span class="org-constant">throw_c</span>;
  }

 <span class="org-constant">throw_a</span>:
  <span class="org-keyword">const</span> <span class="org-keyword">auto</span>&amp; <span class="org-variable-name">a</span> = *<span class="org-keyword">reinterpret_cast</span>&lt;<span class="org-type">A</span>*&gt;(__exception_value_slot);
  print(a);
  a.~A();
  <span class="org-keyword">goto</span> <span class="org-constant">normal_return</span>;

 <span class="org-constant">throw_b</span>:
  <span class="org-keyword">const</span> <span class="org-keyword">auto</span>&amp; <span class="org-variable-name">b</span> = *<span class="org-keyword">reinterpret_cast</span>&lt;<span class="org-type">B</span>*&gt;(__exception_value_slot);
  print(b);
  b.~B();
  <span class="org-keyword">goto</span> <span class="org-constant">normal_return</span>;

 <span class="org-constant">throw_c</span>:
  <span class="org-comment-delimiter">// </span><span class="org-comment">Move exception object to storage for caller.</span>
  <span class="org-type">C</span>&amp; <span class="org-variable-name">__exception_object</span> = *<span class="org-keyword">reinterpret_cast</span>&lt;<span class="org-type">C</span>*&gt;(&amp;__exception_storage[0]);
  ::<span class="org-keyword">new</span>(__exception_value_slot) <span class="org-type">C</span>(<span class="org-constant">std</span>::move(__exception_object));
  __exception_object.~C();
  <span class="org-keyword">return</span> 1;

 <span class="org-constant">normal_return</span>:
  <span class="org-keyword">return</span> 0;
}
</pre>
</div>

<p>
This need to allocate local storage and then move a resulting exception object
into the exception-value-slot storage is also required in the situation where
an exception is caught and then, inside the handler, a new exception object is
thrown and this new exception escapes the function.
</p>

<p>
This is because, at the point of construction of the new exception object
(which will need to be constructed into storage passed in exception-value-slot)
the existing exception object which has been caught is still alive and so
its storage must be distinct from the exception-value slot storage.
</p>

<p>
Using this approach is expected to be highly efficient for cases where all
exceptions are propagated, with the main cost being the need to pass an extra
pointer to the function, using an extra register, possibly causing more spills
of registers to the stack.
</p>

<p>
However, there will also be cases where an exception object must be moved multiple
times from local storage to caller's storage as the exception propagates up the
stack, which has the potential to be a performance issue for large exception objects.
</p>
</div>
</div>

<div id="outline-container-orgeca46de" class="outline-3">
<h3 id="orgeca46de"><span class="section-number-3">8.4.</span> Walking stack to find storage</h3>
<div class="outline-text-3" id="text-8-4">
<p>
If we want to avoid needing to move/copy exception objects as they propagate up the
stack then we need to be able to construct the object in its final location.
However, different exception object types are potentially going to be caught in different
callers up the stack.
</p>

<p>
For example: If <code>foo()</code> throws <code>C</code>, the final storage is in <code>bar()</code>, if it throws <code>B</code>,
the final storage is in <code>baz()</code>, and if it throws <code>A</code>, the final storage is in <code>main()</code>.
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">foo</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>, <span class="org-type">B</span>, <span class="org-type">C</span>);

<span class="org-type">void</span> <span class="org-function-name">bar</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>, <span class="org-type">B</span>) {
  <span class="org-keyword">try</span> { foo(); } <span class="org-keyword">catch</span>(<span class="org-keyword">const</span> <span class="org-type">C</span>&amp;) {}
}

<span class="org-type">void</span> <span class="org-function-name">baz</span>() <span class="org-keyword">throw</span>(<span class="org-type">A</span>) {
  <span class="org-keyword">try</span> { bar(); } <span class="org-keyword">catch</span>(<span class="org-keyword">const</span> <span class="org-type">B</span>&amp;) {}
}

<span class="org-type">int</span> <span class="org-function-name">main</span>() <span class="org-keyword">throw</span>() {
  <span class="org-keyword">try</span> { baz(); } <span class="org-keyword">catch</span>(<span class="org-keyword">const</span> <span class="org-type">A</span>&amp;) {}
}
</pre>
</div>

<p>
Since each of these locations is likely going to have different addresses, this means we
effectively need to pass N exception-object addresses to a call that can potentially throw
N non-trivial exception types.
</p>

<p>
The naiive approach of adding N additional parameters to the function may work for a handful
of exception-types, but the overhead of making a function call increases linearly with the
number of addresses that need to be passed as each call needs to either push onto the stack
or load into registers N different pointers.
</p>

<p>
Instead, we ideally want a solution that has minimal to no overhead on the success path
and runtime overhead on the error path that does not increase with the number of thrown
exception types.
</p>

<p>
To do this, we can leverage either of the jump-table approaches described above and add
an additional entry to the jump-table for each non-trivial exception type.
</p>

<p>
The callee can then call this jump-table entry, passing the address of the parent
stack-frame, to compute the address of the exception object.
</p>

<p>
If the immediate caller handles the exception locally then this returns an address that
is some offset into the stack-frame address. Otherwise, it loads the address of its
caller's stack-frame and then tail-calls the corresponding jump-table entry for the exception-type
from its return-address.
</p>

<p>
For example, given the C++ code above, we might expect the <code>bar()</code> function to be
compiled to something like the following:
</p>
<div class="org-src-container">
<pre class="src src-asm"><span class="org-function-name">bar</span>:
  <span class="org-keyword">push</span> rbp
  <span class="org-keyword">mov</span> rbp, rsp
  <span class="org-keyword">sub</span> rsp, 8    <span class="org-comment-delimiter">; </span><span class="org-comment">allocate storage for C exception</span>

  <span class="org-comment-delimiter">; </span><span class="org-comment">Call foo() with inline jump-table convention</span>
  <span class="org-keyword">call</span> foo
  <span class="org-keyword">jmp</span> .SUCCESS
  <span class="org-keyword">jmp</span> .THROW_A
  <span class="org-keyword">jmp</span> .GET_A
  <span class="org-keyword">jmp</span> .THROW_B
  <span class="org-keyword">jmp</span> .GET_B
  <span class="org-keyword">jmp</span> .THROW_C
  <span class="org-keyword">jmp</span> .GET_C

<span class="org-function-name">.SUCCESS</span>:
<span class="org-function-name">.RETURN</span>:
  <span class="org-keyword">add</span> rsp, 8
  <span class="org-keyword">pop</span> rbp
  <span class="org-keyword">ret</span>

<span class="org-function-name">.THROW_A</span>:
  <span class="org-keyword">add</span> QWORD PTR [rbp+8], 5  <span class="org-comment-delimiter">; </span><span class="org-comment">adjust return-address to entry[1]</span>
  <span class="org-keyword">jmp</span> .RETURN

<span class="org-function-name">.THROW_B</span>:
  <span class="org-keyword">add</span> QWORD PTR [rbp+8], 15 <span class="org-comment-delimiter">; </span><span class="org-comment">adjust return-address to entry[3]</span>
  <span class="org-keyword">jmp</span> .RETURN

<span class="org-function-name">.THROW_C</span>:
  <span class="org-comment-delimiter">; </span><span class="org-comment">C handled locally</span>
  <span class="org-comment-delimiter">; </span><span class="org-comment">Address of exception object in rax</span>
  <span class="org-keyword">mov</span> rdi, rax
  <span class="org-keyword">call</span> C::~C()
  <span class="org-keyword">jmp</span> .SUCCESS

<span class="org-function-name">.GET_A</span>:
  <span class="org-comment-delimiter">; </span><span class="org-comment">Query for address of A exception will call here.</span>
  <span class="org-comment-delimiter">; </span><span class="org-comment">Forward query to caller</span>
  <span class="org-comment-delimiter">; </span><span class="org-comment">Current stack frame in rdi</span>
  <span class="org-keyword">mov</span> rax, QWORD PTR [rdi+8]  <span class="org-comment-delimiter">; </span><span class="org-comment">load return-address</span>
  <span class="org-keyword">mov</span> rdi, QWORD PTR [rdi]    <span class="org-comment-delimiter">; </span><span class="org-comment">load parent frame-ptr</span>
  <span class="org-keyword">add</span> rax, 10                 <span class="org-comment-delimiter">; </span><span class="org-comment">compute address of entry[2]</span>
  <span class="org-keyword">jmp</span> rax                     <span class="org-comment-delimiter">; </span><span class="org-comment">tail-call to entry[2]</span>

<span class="org-function-name">.GET_B</span>:
  <span class="org-comment-delimiter">; </span><span class="org-comment">Query for address of B exception will call here.</span>
  <span class="org-comment-delimiter">; </span><span class="org-comment">Forward query to caller</span>
  <span class="org-keyword">mov</span> rax, QWORD PTR [rdi+8]  <span class="org-comment-delimiter">; </span><span class="org-comment">load return-address</span>
  <span class="org-keyword">mov</span> rdi, QWORD PTR [rdi]    <span class="org-comment-delimiter">; </span><span class="org-comment">load parent frame-ptr</span>
  <span class="org-keyword">add</span> rax, 20                 <span class="org-comment-delimiter">; </span><span class="org-comment">compute address of entry[4]</span>
  <span class="org-keyword">jmp</span> rax                     <span class="org-comment-delimiter">; </span><span class="org-comment">tail-call to entry[4]</span>

<span class="org-function-name">.GET_C</span>:
  <span class="org-comment-delimiter">; </span><span class="org-comment">Query for address of C exception, handle locally</span>
  <span class="org-comment-delimiter">; </span><span class="org-comment">Current stack frame in rdi</span>
  <span class="org-keyword">lea</span> rax, [rdi-8]  <span class="org-comment-delimiter">; </span><span class="org-comment">compute address of storage for C on stack</span>
  <span class="org-keyword">ret</span>               <span class="org-comment-delimiter">; </span><span class="org-comment">return to function that is about to throw</span>
</pre>
</div>

<p>
In the above code, if the call to <code>foo()</code> completes normally then execution
returns to the <code>jmp .SUCCESS</code> and this goes on to return from the function.
The overhead here should be negligible - the direct <code>jmp</code> instruction is the
only additional instruction to be executed on the success path.
</p>

<p>
Otherwise, if the call to <code>foo()</code> throws an exception then first there will
be a call to one of the "GET" jump targets to obtain the address to construct
the exception object in. Then the <code>foo()</code> function will construct the exception
object at that address, perform any local unwinding and then return to the
corresponding "THROW" jump target.
</p>

<p>
In the above example, the GET<sub>A</sub> and GET<sub>B</sub> targets forward through to the corresponding
queries on <code>bar()</code>'s caller's jump table, while GET<sub>C</sub> is able to compute the value
locally. In the case of GET<sub>A</sub>, <code>bar()</code>'s implementation would then forward on to its
caller - <code>main()</code> in the example above.
</p>

<p>
This is effectively doing a stack-walk to find the caller that is willing to provide storage.
Only instead of having a generic stack-walking algorithm in a loop it is performing a series
of tail-jumps to code in each of the callers corresponding to that exception type.
</p>

<p>
The walk is terminated by a GET entry that knows how to compute the address of the object
within its stack-frame.
</p>

<p>
For example: In <code>foo()</code>, code that throws an <code>A</code> exception might look like the following:
</p>
<div class="org-src-container">
<pre class="src src-asm"><span class="org-function-name">foo</span>:
  <span class="org-comment-delimiter">; </span><span class="org-comment">... snip</span>

  <span class="org-comment-delimiter">;;;;</span>
  <span class="org-comment-delimiter">; </span><span class="org-comment">throw A{}</span>
  <span class="org-comment-delimiter">;;;;</span>

  <span class="org-comment-delimiter">; </span><span class="org-comment">first get the address for the exception object</span>
  <span class="org-keyword">mov</span> rax, QWORD PTR [rbp+8] <span class="org-comment-delimiter">; </span><span class="org-comment">load return-address / jump-table-address</span>
  <span class="org-keyword">mov</span> rdi, QWORD PTR [rbp]   <span class="org-comment-delimiter">; </span><span class="org-comment">load parent frame address</span>
  <span class="org-keyword">add</span> rax, 10                <span class="org-comment-delimiter">; </span><span class="org-comment">adjust address to entry[2]</span>
  <span class="org-keyword">call</span> rax                   <span class="org-comment-delimiter">; </span><span class="org-comment">call the address query</span>
  <span class="org-comment-delimiter">; </span><span class="org-comment">when this returns, the address to use will be in rax</span>
  <span class="org-comment-delimiter">; </span><span class="org-comment">construct the A() object</span>
  <span class="org-keyword">mov</span> rdi, rax
  <span class="org-keyword">call</span> A::A()
  <span class="org-comment-delimiter">; </span><span class="org-comment">... any local unwind goes here</span>
  <span class="org-comment-delimiter">; </span><span class="org-comment">now return to entry[1]</span>
  <span class="org-keyword">add</span> QWORD PTR [rbp+8], 5 <span class="org-comment-delimiter">; </span><span class="org-comment">adjust return-address</span>
  <span class="org-keyword">add</span> rsp, 24
  <span class="org-keyword">pop</span> rbp
  <span class="org-keyword">ret</span>

  <span class="org-comment-delimiter">; </span><span class="org-comment">... snip</span>
</pre>
</div>

<p>
Walking the stack like this to obtain the storage location allows constructing the
object in its final place and minimizes the number of moves of the exception object
as it propagates, even if it is caught and rethrown.
</p>

<p>
Once the exception object is constructed, then any local objects in scope are
destroyed and then the function returns to the corresponding entry in the
jump table.
</p>

<p>
Each entry returned to during unwind that is not a handler will just execute
a sequence of calls to destructors before then returning to the corresponding
for that type in its parent's jump-table.
This continues until control returns to some entry that enters a handler for the exception.
</p>

<p>
Some benefits of this appraoch:
</p>
<ul class="org-ul">
<li>No need for external exception tables to be consulted during exception unwinding.</li>
<li>No need for run-time type information.</li>
<li>Less copying/moving of exception objects as it propagates up the stack.</li>
</ul>

<p>
There are a couple of potential down-sides to this approach, which will need to
be quantified once an implementation is available.
</p>
<ul class="org-ul">
<li>The stack walk can potentially incur a number of cache misses during the walk,
depending on how many frames need to be walked.</li>
<li>The stack walk may also incur some branch mis-predictions as it jumps to
different entries up the call-stack.</li>
<li>There is more code-generation required compared to the exception-value-slot
approach. The size of code grows with the number of exception types that might
be thrown from the call.</li>
<li>Worst case overhead of stack walking is where the immediate caller typically handles
buy rarel) conditionally rethrows the exception which then propagates up to a handler
many levels up the call-stack. The stack walk needs to walk all of these frames
to find storage, but rarely benefits from placing the storage at this final handler.</li>
</ul>

<p>
Whether this approach ends up being more or less efficient than the exception-value-slot
may depend on the context and types involved.
</p>
</div>
</div>

<div id="outline-container-org4c177e9" class="outline-3">
<h3 id="org4c177e9"><span class="section-number-3">8.5.</span> Unwinding through scopes with destructors</h3>
<div class="outline-text-3" id="text-8-5">
<p>
When unwinding due to an exception thrown from a function with a static exception specification,
execution will return to an address that handles that particular exception being thrown.
</p>

<p>
The function will then need to call destructors for any in-scope variables, before then either
entering a handler, or propagating the exception to its caller by returning to its
</p>

<p>
In the case that there are multiple exception types that propagate through a function, all of the
code-paths for each exception type will need to call the same set of destructors. Also, there will
be overlap in the set of destructors to call depending on which scope the exception was thrown at.
</p>

<p>
For example: Given the following function, <code>f()</code>.
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-keyword">struct</span> <span class="org-type">X</span> { <span class="org-function-name">X</span>() <span class="org-keyword">throw</span>(); ~<span class="org-function-name">X</span>(); <span class="org-type">int</span> <span class="org-variable-name">data</span>; };
<span class="org-keyword">struct</span> <span class="org-type">Y</span> { <span class="org-function-name">Y</span>() <span class="org-keyword">throw</span>(); ~<span class="org-function-name">Y</span>(); <span class="org-type">int</span> <span class="org-variable-name">data</span>; };
<span class="org-type">void</span> <span class="org-function-name">f</span>(<span class="org-type">X</span>&amp;) <span class="org-keyword">throw</span>(<span class="org-type">A</span>, <span class="org-type">B</span>);
<span class="org-type">void</span> <span class="org-function-name">g</span>(<span class="org-type">Y</span>&amp;) <span class="org-keyword">throw</span>(<span class="org-type">A</span>, <span class="org-type">B</span>);

<span class="org-type">void</span> <span class="org-function-name">caller</span>(<span class="org-type">bool</span> <span class="org-variable-name">cond</span>) <span class="org-keyword">throw</span>(<span class="org-type">A</span>, <span class="org-type">B</span>) {
  <span class="org-type">X</span> <span class="org-variable-name">x</span>;
  f(x);

  <span class="org-type">Y</span> <span class="org-variable-name">y</span>;
  g(y);
}
</pre>
</div>

<p>
If the call to <code>f()</code> throws an <code>A</code> then it needs to call <code>X::~X()</code> and then return to entry[1].
If the call to <code>f()</code> throw a <code>B</code> then it neesd to call <code>X::~X()</code> and then return to entry[3].
If the call to <code>g()</code> throws an <code>A</code> then it needs to call <code>Y::~Y()</code> and <code>X::~X()</code> and then return to entry[1].
If the call to <code>g()</code> throws a <code>B</code> then it needs to call <code>Y::~Y()</code> and <code>X::~X()</code> and then return to entry[3].
</p>

<p>
There is a lot of overlap in these unwind paths which can be merged to avoid bloating
the generated code for these unwind paths with duplicated instructions.
</p>

<p>
For example: the above function could be compiled to the following assembly:
</p>
<div class="org-src-container">
<pre class="src src-asm"><span class="org-function-name">caller</span>:
        <span class="org-keyword">push</span> rbp
        <span class="org-keyword">mov</span> rbp, rsp
        <span class="org-keyword">sub</span> rsp, 8   <span class="org-comment-delimiter">; </span><span class="org-comment">reserve storage for X and Y</span>
        <span class="org-keyword">lea</span> rdi, [rsp+4]
        <span class="org-keyword">call</span> X::X()
        <span class="org-keyword">lea</span> rdi, [rsp+4]
        <span class="org-keyword">call</span> f(X&amp;)
        <span class="org-keyword">jmp</span> .F_SUCCESS
        <span class="org-keyword">jmp</span> .F_THROW_A
        <span class="org-keyword">jmp</span> .GET_A
        <span class="org-keyword">jmp</span> .F_THROW_B
        <span class="org-keyword">jmp</span> .GET_B

<span class="org-function-name">.F_SUCCESS</span>:
        <span class="org-keyword">mov</span> rdi, rsp
        <span class="org-keyword">call</span> Y::Y()
        <span class="org-keyword">mov</span> rdi, rsp
        <span class="org-keyword">call</span> g(Y&amp;)
        <span class="org-keyword">jmp</span> .G_SUCCESS
        <span class="org-keyword">jmp</span> .G_THROW_A
        <span class="org-keyword">jmp</span> .GET_A
        <span class="org-keyword">jmp</span> .G_THROW_B
        <span class="org-keyword">jmp</span> .GET_B

<span class="org-function-name">.G_SUCCESS</span>:
        <span class="org-keyword">mov</span> rdi, rsp
        <span class="org-keyword">call</span> Y::~Y()
        <span class="org-keyword">lea</span> rdi, [rsp+4]
        <span class="org-keyword">call</span> X::~X()
<span class="org-function-name">.RETURN</span>:
        <span class="org-keyword">add</span> rsp, 8
        <span class="org-keyword">pop</span> rbp
        <span class="org-keyword">ret</span>

<span class="org-function-name">.F_THROW_A</span>:
        <span class="org-keyword">add</span> QWORD PTR [rbp+8], 5    <span class="org-comment-delimiter">; </span><span class="org-comment">adjust return-address to entry[1] (type A)</span>
        <span class="org-keyword">jmp</span> .UNWIND1
<span class="org-function-name">.F_THROW_B</span>:
        <span class="org-keyword">add</span> QWORD PTR [rbp+8], 15   <span class="org-comment-delimiter">; </span><span class="org-comment">adjust return-address to entry[3] (type B)</span>
<span class="org-function-name">.UNWIND1</span>:
        <span class="org-keyword">push</span> rax                    <span class="org-comment-delimiter">; </span><span class="org-comment">save address of exception-object</span>
        <span class="org-keyword">jmp</span> .LBL1

<span class="org-function-name">.G_THROW_A</span>:
        <span class="org-keyword">add</span> QWORD PTR [rbp+8], 5    <span class="org-comment-delimiter">; </span><span class="org-comment">adjust return-address to entry[1] (type A)</span>
        <span class="org-keyword">jmp</span> .UNWIND2
<span class="org-function-name">.G_THROW_B</span>:
        <span class="org-keyword">add</span> QWORD PTR [rbp+8], 15   <span class="org-comment-delimiter">; </span><span class="org-comment">adjust return-address to entry[3] (type B)</span>
<span class="org-function-name">.UNWIND2</span>:
        <span class="org-keyword">push</span> rax                    <span class="org-comment-delimiter">; </span><span class="org-comment">save address of exception-object</span>
        <span class="org-keyword">lea</span> rdi, [rsp+8]            <span class="org-comment-delimiter">; </span><span class="org-comment">address of 'y'</span>
        <span class="org-keyword">call</span> Y::~Y()
<span class="org-function-name">.LBL1</span>:
        <span class="org-keyword">lea</span> rdi, [rsp+12]           <span class="org-comment-delimiter">; </span><span class="org-comment">address of 'x'</span>
        <span class="org-keyword">call</span> X::~X()
        <span class="org-keyword">pop</span> rax                     <span class="org-comment-delimiter">; </span><span class="org-comment">restore address of exception-object</span>
        <span class="org-keyword">jmp</span> .RETURN
<span class="org-function-name">.GET_A</span>:
        <span class="org-keyword">mov</span> rax, QWORD PTR [rdi+8]  <span class="org-comment-delimiter">; </span><span class="org-comment">load return address</span>
        <span class="org-keyword">mov</span> rdi, QWORD PTR [rdi]    <span class="org-comment-delimiter">; </span><span class="org-comment">load parent frame ptr</span>
        <span class="org-keyword">add</span> rax, 10                 <span class="org-comment-delimiter">; </span><span class="org-comment">adjust to entry[2]</span>
        <span class="org-keyword">jmp</span> rax                     <span class="org-comment-delimiter">; </span><span class="org-comment">tail-call</span>
<span class="org-function-name">.GET_B</span>:
        <span class="org-keyword">mov</span> rax, QWORD PTR [rdi+8]  <span class="org-comment-delimiter">; </span><span class="org-comment">load return address</span>
        <span class="org-keyword">mov</span> rdi, QWORD PTR [rdi]    <span class="org-comment-delimiter">; </span><span class="org-comment">load parent frame ptr</span>
        <span class="org-keyword">add</span> rax, 20                 <span class="org-comment-delimiter">; </span><span class="org-comment">adjust to entry[4]</span>
        <span class="org-keyword">jmp</span> rax                     <span class="org-comment-delimiter">; </span><span class="org-comment">tail-call</span>
</pre>
</div>

<p>
Notice here how the calls to the destructors during unwind can be rolled together so that
we only need code for calling the destructor of each local object on unwind once, despite
there being 4 different cases that need to be handled.
</p>

<p>
It can do this by first adjusting the return-address to the one corresponding to the
exception type immediately after jumping to the jump-table target and then after this
the code for calling destructors and returning to the caller is the same for all
exception types.
</p>
</div>
</div>

<div id="outline-container-org80c9807" class="outline-3">
<h3 id="org80c9807"><span class="section-number-3">8.6.</span> Interop between static-exception functions and dynamic-exception functions</h3>
<div class="outline-text-3" id="text-8-6">
<p>
There are several cases that need to be considered with regards to interaction
between functions with a checked static-exception specification and functions with
dynamic-exception specifications.
</p>

<p>
When a function with a checked static exception specification calls a functon with a
dynamic-exception specification, the calling must surround the call in a <code>try/catch(...)</code>,
otherise the set of potentially-thrown exceptions computed for the function-body would
make the function ill-formed.
</p>

<p>
The function therefore needs to catch and explicitly either rethrow an exception
whose type is marked <code>final</code> or needs to throw a new exception object.
Both cases would need to initialize a new static exception object in order to
propagate the exception to its caller.
</p>

<p>
For example:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-comment-delimiter">// </span><span class="org-comment">Can potentially throw anything, but docs say it will</span>
<span class="org-comment-delimiter">// </span><span class="org-comment">only throw something inherited from std::bad_alloc</span>
<span class="org-type">void</span> <span class="org-function-name">callee</span>();

<span class="org-type">void</span> <span class="org-function-name">caller</span>() <span class="org-keyword">throw</span>(<span class="org-constant">std</span>::<span class="org-type">bad_alloc</span>) {
  <span class="org-keyword">try</span> {
    callee();
  } <span class="org-keyword">catch</span> (<span class="org-keyword">const</span> <span class="org-constant">std</span>::<span class="org-type">bad_alloc</span>&amp; <span class="org-variable-name">e</span>) {
    <span class="org-comment-delimiter">// </span><span class="org-comment">Rethrow a copy of the exception as a new bad_alloc exception</span>
    <span class="org-keyword">throw</span> e;
  } <span class="org-keyword">catch</span> (...) {
    <span class="org-comment-delimiter">// </span><span class="org-comment">throwing anything else would be a violation of its documented contract</span>
    <span class="org-comment-delimiter">// </span><span class="org-comment">contract_assert(false);</span>
    <span class="org-constant">std</span>::terminate(); <span class="org-comment-delimiter">// </span><span class="org-comment">or nothrow_unreachable()</span>
  }
}
</pre>
</div>

<p>
If the existing dynamic exception facility uses table-based unwind, then the
calling function still needs to have unwind table entries for catching the
exception.
</p>

<p>
When the situation is reversed, and instead a function with a dynamic exception
specification is calling a function with a static exception specification then
if the exception is not handled locally, it must implicitly propgate out of
the calling function.
</p>

<p>
This means that at the boundary of this function, the exception needs to be
translated from a static exception object to a dynamic exception object and
then rethrown. Thus the calling function will need to insert code to allocate
a new dynamic exception and then move-construct the static exception into this
allocated storage.
</p>

<p>
For example, given the following:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">callee</span>() <span class="org-keyword">throw</span>(<span class="org-constant">std</span>::<span class="org-type">bad_alloc</span>, <span class="org-constant">std</span>::<span class="org-type">system_error</span>);

<span class="org-type">void</span> <span class="org-function-name">caller</span>() {
  callee();
}
</pre>
</div>
<p>
the compiler may lower <code>caller()</code> it to something equivalent to the following:
</p>
<div class="org-src-container">
<pre class="src src-c++"><span class="org-type">void</span> <span class="org-function-name">caller</span>() <span class="org-keyword">try</span> {
  callee();
} <span class="org-keyword">template</span> <span class="org-keyword">catch</span> (<span class="org-keyword">auto</span>&amp; <span class="org-variable-name">e</span>) {
  <span class="org-keyword">throw</span> <span class="org-constant">std</span>::move(e); <span class="org-comment-delimiter">// </span><span class="org-comment">rethrow as a new dynamic exception at boundary</span>
}
</pre>
</div>
</div>
</div>

<div id="outline-container-orgb9a86e9" class="outline-3">
<h3 id="orgb9a86e9"><span class="section-number-3">8.7.</span> Virtual function calls</h3>
<div class="outline-text-3" id="text-8-7">
<p>
Virtual functions generally act the same as normal functions do with regards to
static exceptions, with the exception of the case where an override declares a
narrower exception specification than the base class.
</p>

<p>
The following cases need to be handled specially:
</p>
<ul class="org-ul">
<li>the base class function is declared with a dynamic exception specification and
the derived class is declared with a non-empty static exception specification.</li>
<li>the base class function is declared with a non-empty static exception-specification and
the derived class is declared with a static exception specification with a subset of
the exceptions listed in the base class' function declaration.</li>
</ul>

<p>
In both of these cases, the calling convention for calling the override via the
base class interface is different from the calling convention for calling the override
via the derived class interface.
</p>

<p>
Therefore, the use of a thunk is required to adapt between the calling conventions.
</p>

<p>
In the case that the base class signature has a dynamic exception specification and
the derived class has a static exception specification, the thunk will need to
allocate storage on the stack for the static exception, and call the override with
the appropriate jump table for handling each exception type and then if the call
completes with an exception then rethrow the static exception object as a dynamic
exception.
</p>
</div>
</div>

<div id="outline-container-org3ff4e32" class="outline-3">
<h3 id="org3ff4e32"><span class="section-number-3">8.8.</span> Interaction with <code>std::uncaught_exceptions()</code></h3>
<div class="outline-text-3" id="text-8-8">
<p>
During exception unwind due to a thrown static exception object, we will still want the
<code>std::uncaught_exceptions()</code> function to return a value that indicates a new uncaught exception
is in-flight.
</p>

<p>
This means that, after constructing the exception object, but before starting the unwind process,
the function needs to ensure that the thread-local count of uncaught exceptions is incremented.
Then upon entering a handler, after initializing the object in the exception-declartion of the
handler, it needs to decrement the count of uncaught exceptions.
</p>

<p>
For example, on platforms that use the Itanium C++ ABI, the thread-local exception state is
obtained through the following API:
</p>
<div class="org-src-container">
<pre class="src src-c"><span class="org-keyword">struct</span> <span class="org-type">__cxa_exception</span> { <span class="org-comment-delimiter">/* </span><span class="org-comment">fields that describe an exception object</span><span class="org-comment-delimiter"> */</span> };

<span class="org-keyword">struct</span> <span class="org-type">__cxa_eh_globals</span> {
  <span class="org-type">__cxa_exception</span>* <span class="org-variable-name">caughtExceptions</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">linked list of caught exceptions - most recent first</span>
  <span class="org-type">unsigned</span> <span class="org-type">int</span> <span class="org-variable-name">uncaughtExceptions</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">count of thrown but not yet caught exceptions</span>
};

<span class="org-type">__cxa_eh_globals</span>* <span class="org-function-name">__cxa_get_globals</span>(<span class="org-type">void</span>); <span class="org-comment-delimiter">// </span><span class="org-comment">get pointer to thread-local exception state (initializing on first call)</span>
<span class="org-type">__cxa_eh_globals</span>* <span class="org-function-name">__cxa_get_globals_fast</span>(<span class="org-type">void</span>); <span class="org-comment-delimiter">// </span><span class="org-comment">get pointer to thread-local exception state (no-initialization)</span>
</pre>
</div>

<p>
To modify the uncaught exceptions, the program needs to call <code>__cxa_get_globals()</code> and then
increment/decrement the <code>uncaughtExceptions</code> member of the object pointed to by the return value
at the appropriate point during exception throwing/handling.
</p>

<p>
If the <code>__cxa_eh_globals()</code> function is annotated with appropriate attributes (e.g. <code>__attribute__((const))</code>)
which let the compiler assume that it always returns the same value and has no side-effects, then the compiler
can cache the result. If the throwing function is inlined into the handling function and the
compiler can see both throw-site and handler at the same time and can see that there are no
opaque calls or references to the <code>uncaughtExceptions</code> member during unwind, then it can even
optimize out the thread-local access and increment/decrement.
</p>

<p>
It should be relative straight-forward to ensure that an implementation of static exceptions
gives the specified behaviour of <code>std::uncaught_exceptions()</code>.
</p>
</div>
</div>

<div id="outline-container-orgc177aee" class="outline-3">
<h3 id="orgc177aee"><span class="section-number-3">8.9.</span> Static exceptions and the Itanium C++ ABI</h3>
<div class="outline-text-3" id="text-8-9">
<p>
See <a href="https://godbolt.org/z/8578rKh6j">https://godbolt.org/z/8578rKh6j</a> for an proof-of-concept of how a local throw/catch within a function,
which under this proposal would be required to be a static exception object, would interact with
the Itanium C++ ABI and facilities such as <code>std::uncaught_exceptions()</code>, <code>std::current_exception()</code>
and <code>throw;</code>.
</p>

<p>
Support for static exception objects is likely to require some changes to the implementations of
the <code>__cxa_*</code> functions that form the ABI, and thus would require relinking with the ABI libraries
(either statically or dynamically) but should otherwise be able to link against code previously
compiled against the existing ABI.
</p>

<p>
Additional work is required here to validate this approach.
</p>
</div>
</div>
</div>

<div id="outline-container-orgf4a1577" class="outline-2">
<h2 id="orgf4a1577"><span class="section-number-2">9.</span> Acknowledgements</h2>
<div class="outline-text-2" id="text-9">
<p>
Special thanks to Ben Craig and Corentin Jabot for providing feedback on drafts of
this paper.
</p>
</div>
</div>

<div id="outline-container-org55b463f" class="outline-2">
<h2 id="org55b463f"><span class="section-number-2">10.</span> References</h2>
<div class="outline-text-2" id="text-10">
<ul class="org-ul">
<li>[FastCasting] "Fast dynamic casting" (Gibbs, Stroustrup)<br />
<a href="https://www.stroustrup.com/fast_dynamic_casting.pdf">https://www.stroustrup.com/fast_dynamic_casting.pdf</a></li>

<li>[N3227] "Please reconsider <code>noexcept</code>" (Ottosen, 2010)<br />
<a href="https://wg21.link/N3227">https://wg21.link/N3227</a></li>

<li>[N3202] "To which extent can <code>noexcept</code> be deduced?"" (Stroustrup, 2010)<br />
<a href="https://wg21.link/N3202">https://wg21.link/N3202</a></li>

<li>[N3207] "<code>noexcept(auto)</code>" (Merrill, 2010)<br />
<a href="https://wg21.link/N3207">https://wg21.link/N3207</a></li>

<li>[N4473] "<code>noexcept(auto)</code>, again" (Voutilainen, 2015)<br />
<a href="https://wg21.link/N4473">https://wg21.link/N4473</a></li>

<li>[P0133R0] "Putting <code>noexcept(auto)</code> on hold, again" (Voutilainen, 2015)<br />
<a href="https://wg21.link/P0133R0">https://wg21.link/P0133R0</a></li>

<li>[P0709R4] "Zero-overhead deterministic exceptions: Throwing values" (Sutter)<br />
<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0709r4.pdf">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0709r4.pdf</a></li>

<li>[P1947R0] "C++ exceptions and alternatives" (Stroustrup)<br />
<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1947r0.pdf">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1947r0.pdf</a></li>

<li>[P2268R0] "Freestanding Roadmap" (Craig)<br />
<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2268r0.html">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2268r0.html</a></li>

<li>[P2300] "<code>std::execution</code>" (Multiple authors)<br />
<a href="https://isocpp.org/files/papers/P2300R8.html">https://isocpp.org/files/papers/P2300R8.html</a></li>

<li>[P2900R6] "Contracts for C++" (Multiple authors)<br />
<a href="https://isocpp.org/files/papers/P2900R6.pdf">https://isocpp.org/files/papers/P2900R6.pdf</a></li>

<li>[P2830R1] "Standardized Type Ordering" (Nichols, Ažman)<br />
<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2830r1.pdf">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2830r1.pdf</a></li>

<li>[P2809R2] "Trivial infinite loops are not Undefined Behavior" (Bastien)
<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2809r2.html">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2809r2.html</a></li>

<li>[P3068R0] "Allowing exception-throwing in constant evaluation" (Dusíková)<br />
<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3068r0.pdf">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3068r0.pdf</a></li>

<li>[Renwick] "Low-cost deterministic C++ exceptions for embedded systems" (Renwick, Spink, Franke)<br />
<a href="https://dl.acm.org/doi/10.1145/3302516.3307346">https://dl.acm.org/doi/10.1145/3302516.3307346</a></li>
</ul>
</div>
</div>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
<a href="https://github.com/microsoft/cpprestsdk/blob/master/Release/tests/functional/pplx/pplx_test/pplx_op_test.cpp#L198">https://github.com/microsoft/cpprestsdk/blob/master/Release/tests/functional/pplx/pplx_test/pplx_op_test.cpp#L198</a>
</p></div></div>

<div class="footdef"><sup><a id="fn.2" class="footnum" href="#fnr.2" role="doc-backlink">2</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
<a href="https://github.com/zeroc-ice/ice/issues/582">https://github.com/zeroc-ice/ice/issues/582</a>
</p></div></div>


</div>
</div></div>
<div id="postamble" class="status">
<p class="date">Date: 2024-03-16</p>
<p class="author">Author: Lewis Baker</p>
<p class="date">Created: 2024-03-17 Sun 00:22</p>
<p class="validation"><a href="https://validator.w3.org/check?uri=referer">Validate</a></p>
</div>
</body>
</html>