diff --git a/source/basic.tex b/source/basic.tex index 9524265f81..9274dcd517 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -6760,6 +6760,573 @@ \indextext{atomic!operation|)}% \indextext{threads!multiple|)} +\rSec2[except.flow]{Exceptional control flow} + +\rSec3[except.general]{General} +\pnum +In this Clause, ``before'' and ``after'' refer to the +``sequenced before'' relation\iref{intro.execution}. + +\rSec3[except.throw]{Throwing an exception}% +\indextext{exception handling!throwing}% +\indextext{throwing|see{exception handling, throwing}} + +\pnum +Throwing an exception transfers control to a handler. +\begin{note} +An exception can be thrown from one of the following contexts: +\grammarterm{throw-expression}{s}\iref{expr.throw}, +allocation functions\iref{basic.stc.dynamic.allocation}, +\keyword{dynamic_cast}\iref{expr.dynamic.cast}, +\keyword{typeid}\iref{expr.typeid}, +\grammarterm{new-expression}{s}\iref{expr.new}, and standard library +functions\iref{structure.specifications}. +\end{note} +An object is passed and the type of that object determines which handlers +can catch it. +\begin{example} +\begin{codeblock} +throw "Help!"; +\end{codeblock} +can be caught by a +\grammarterm{handler} +of +\keyword{const} +\tcode{\keyword{char}*} +type: +\begin{codeblock} +try { + // ... +} catch(const char* p) { + // handle character string exceptions here +} +\end{codeblock} +and +\begin{codeblock} +class Overflow { +public: + Overflow(char,double,double); +}; + +void f(double x) { + throw Overflow('+',x,3.45e107); +} +\end{codeblock} +can be caught by a handler for exceptions of type +\tcode{Overflow}: +\begin{codeblock} +try { + f(1.2); +} catch(Overflow& oo) { + // handle exceptions of type \tcode{Overflow} here +} +\end{codeblock} +\end{example} + +\pnum +\indextext{exception handling!throwing}% +\indextext{exception handling!handler}% +\indextext{exception handling!nearest handler}% +When an exception is thrown, control is transferred to the nearest handler with +a matching type\iref{except.handle}; ``nearest'' means the handler +for which the +\grammarterm{compound-statement} or +\grammarterm{ctor-initializer} +following the +\keyword{try} +keyword was most recently entered by the thread of control and not yet exited. + +\pnum +Throwing an exception +initializes an object with dynamic storage duration, +called the +\defnx{exception object}{exception handling!exception object}. +If the type of the exception object would be +an incomplete type\iref{basic.types.general}, +an abstract class type\iref{class.abstract}, +or a pointer to an incomplete type other than +\cv{}~\keyword{void}\iref{basic.compound}, +the program is ill-formed. + +\pnum +\indextext{exception handling!memory}% +\indextext{exception handling!rethrowing}% +\indextext{exception handling!exception object}% +The memory for the exception object is +allocated in an unspecified way, except as noted in~\ref{basic.stc.dynamic.allocation}. +If a handler exits by rethrowing, control is passed to another handler for +the same exception object. +The points of potential destruction for the exception object are: +\begin{itemize} +\item +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 \grammarterm{exception-declaration} in the handler; + +\item +when an object of type \tcode{std::exception_ptr}\iref{propagation} +that refers to the exception object is destroyed, +before the destructor of \tcode{std::exception_ptr} returns. +\end{itemize} + +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 happen before that last one\iref{intro.races}. +\begin{note} +No other thread synchronization is implied in exception handling. +\end{note} +The implementation may then +deallocate the memory for the exception object; any such deallocation +is done in an unspecified way. +\begin{note} +A thrown exception does not +propagate to other threads unless caught, stored, and rethrown using +appropriate library functions; see~\ref{propagation} and~\ref{futures}. +\end{note} + +\pnum +\indextext{exception handling!exception object!constructor}% +\indextext{exception handling!exception object!destructor}% +Let \tcode{T} denote the type of the exception object. +Copy-initialization of an object of type \tcode{T} from +an lvalue of type \tcode{const T} in a context unrelated to \tcode{T} +shall be well-formed. +If \tcode{T} is a class type, +the selected constructor is odr-used\iref{basic.def.odr} and +the destructor of \tcode{T} is potentially invoked\iref{class.dtor}. + +\pnum +An exception is considered uncaught +after completing the initialization of the exception object +until completing the activation of a handler for the exception\iref{except.handle}. +\begin{note} +As a consequence, an exception is considered uncaught +during any stack unwinding resulting from it being thrown. +\end{note} + +\pnum +\indextext{exception handling!rethrow}% +\indextext{rethrow|see{exception handling, rethrow}}% +An exception is considered caught when a handler for that exception +becomes active\iref{except.handle}. +\begin{note} +An exception can have active handlers and still be considered uncaught if +it is rethrown. +\end{note} + +\pnum +\indexlibraryglobal{uncaught_exceptions}% +If an exception is rethrown\iref{expr.throw,propagation}, +it is considered uncaught from the point of rethrow +until the rethrown exception is caught. +\begin{note} +The function \tcode{std::uncaught_exceptions}\iref{uncaught.exceptions} +returns the number of uncaught exceptions in the current thread. +\end{note} + +\pnum +\indextext{exception handling!terminate called@\tcode{terminate} called}% +\indextext{\idxcode{terminate}!called}% +If the exception handling mechanism +handling an uncaught exception +directly invokes a function that exits via an +exception, the function \tcode{std::terminate} is invoked\iref{except.terminate}. +\begin{example} +\begin{codeblock} +struct C { + C() { } + C(const C&) { + if (std::uncaught_exceptions()) { + throw 0; // throw during copy to handler's \grammarterm{exception-declaration} object\iref{except.handle} + } + } +}; + +int main() { + try { + throw C(); // calls \tcode{std::terminate} if construction of the handler's + // \grammarterm{exception-declaration} object is not elided\iref{class.copy.elision} + } catch(C) { } +} +\end{codeblock} +\end{example} +\begin{note} +If a destructor directly invoked by stack unwinding exits via an exception, +\tcode{std::terminate} is invoked. +\end{note} + +\rSec3[except.ctor]{Stack unwinding}% +\indextext{exception handling!constructors and destructors}% +\indextext{constructor!exception handling|see{exception handling, constructors and destructors}}% +\indextext{destructor!exception handling|see{exception handling, constructors and destructors}} + +\pnum +\indextext{unwinding!stack}% +As control passes from the point where an exception is thrown +to a handler, +objects are destroyed by a process, +specified in this subclause, called \defn{stack unwinding}. + +\pnum +Each object with automatic storage duration is destroyed if it has been +constructed, but not yet destroyed, +since the try block was entered. +If an exception is thrown during the destruction of temporaries or +local variables for a \keyword{return} statement\iref{stmt.return}, +the destructor for the returned object (if any) is also invoked. +The objects are destroyed in the reverse order of the completion +of their construction. +\begin{example} +\begin{codeblock} +struct A { }; + +struct Y { ~Y() noexcept(false) { throw 0; } }; + +A f() { + try { + A a; + Y y; + A b; + return {}; // \#1 + } catch (...) { + } + return {}; // \#2 +} +\end{codeblock} +At \#1, the returned object of type \tcode{A} is constructed. +Then, the local variable \tcode{b} is destroyed\iref{stmt.jump}. +Next, the local variable \tcode{y} is destroyed, +causing stack unwinding, +resulting in the destruction of the returned object, +followed by the destruction of the local variable \tcode{a}. +Finally, the returned object is constructed again at \#2. +\end{example} + +\pnum +If the initialization of an object +other than by delegating constructor +is terminated by an exception, +the destructor is invoked for +each of the object's subobjects +that were known to be initialized by the object's initialization and +whose initialization has completed\iref{dcl.init}. +\begin{note} +If such an object has a reference member +that extends the lifetime of a temporary object, +this ends the lifetime of the reference member, +so the lifetime of the temporary object is effectively not extended. +\end{note} +\indextext{subobject!initialized, known to be}% +A subobject is \defn{known to be initialized} +if it is not an anonymous union member and +its initialization is specified +\begin{itemize} +\item in \ref{class.base.init} for initialization by constructor, +\item in \ref{class.copy.ctor} for initialization by defaulted copy/move constructor, +\item in \ref{class.inhctor.init} for initialization by inherited constructor, +\item in \ref{dcl.init.aggr} for aggregate initialization, +\item in \ref{expr.prim.lambda.capture} for the initialization of +the closure object when evaluating a \grammarterm{lambda-expression}, +\item in \ref{dcl.init.general} for +default-initialization, value-initialization, or direct-initialization +of an array. +\end{itemize} +\begin{note} +This includes virtual base class subobjects +if the initialization +is for a complete object, and +can include variant members +that were nominated explicitly by +a \grammarterm{mem-initializer} or \grammarterm{designated-initializer-clause} or +that have a default member initializer. +\end{note} +If the destructor of an object is terminated by an exception, +each destructor invocation +that would be performed after executing the body of the destructor\iref{class.dtor} and +that has not yet begun execution +is performed. +\begin{note} +This includes virtual base class subobjects if +the destructor was invoked for a complete object. +\end{note} +The subobjects are destroyed in the reverse order of the completion of +their construction. Such destruction is sequenced before entering a +handler of the \grammarterm{function-try-block} of the constructor or destructor, +if any. + +\pnum +If the \grammarterm{compound-statement} +of the \grammarterm{function-body} +of a delegating constructor +for an object exits via +an exception, the object's destructor is invoked. +Such destruction is sequenced before entering a handler of the +\grammarterm{function-try-block} of a delegating constructor for that object, if any. + +\pnum +\begin{note} +If the object was allocated by a \grammarterm{new-expression}\iref{expr.new}, +the matching deallocation function\iref{basic.stc.dynamic.deallocation}, +if any, is called to free the storage occupied by the object. +\end{note} + +\rSec3[except.handle]{Handling an exception} +\indextext{exception handling!handler|(}% + +\pnum +The +\grammarterm{exception-declaration} +in a +\grammarterm{handler} +describes the type(s) of exceptions that can cause +that +\grammarterm{handler} +to be entered. +\indextext{exception handling!handler!incomplete type in}% +\indextext{exception handling!handler!rvalue reference in}% +\indextext{exception handling!handler!array in}% +\indextext{exception handling!handler!pointer to function in}% +The +\grammarterm{exception-declaration} +shall not denote an incomplete type, an abstract class type, or an rvalue reference type. +The +\grammarterm{exception-declaration} +shall not denote a pointer or reference to an +incomplete type, other than ``pointer to \cv{}~\keyword{void}''. + +\pnum +A handler of type +\indextext{array!handler of type}% +``array of \tcode{T}'' or +\indextext{function!handler of type}% +function type \tcode{T} +is adjusted to be of type +``pointer to \tcode{T}''. + +\pnum +\indextext{exception handling!handler!match|(}% +A +\grammarterm{handler} +is a match for +an exception object +of type +\tcode{E} +if +\begin{itemize} +\item% +The \grammarterm{handler} is of type \cv{}~\tcode{T} or +\cv{}~\tcode{T\&} and +\tcode{E} and \tcode{T} +are the same type (ignoring the top-level \grammarterm{cv-qualifier}{s}), or +\item% +the \grammarterm{handler} is of type \cv{}~\tcode{T} or +\cv{}~\tcode{T\&} and +\tcode{T} is an unambiguous public base class of \tcode{E}, or +\item% +the \grammarterm{handler} is of type \cv{}~\tcode{T} or \tcode{const T\&} +where \tcode{T} is a pointer or pointer-to-member type and +\tcode{E} is a pointer or pointer-to-member type +that can be converted to \tcode{T} by one or more of +\begin{itemize} + +\item% +a standard pointer conversion\iref{conv.ptr} not involving conversions +to pointers to private or protected or ambiguous classes +\item% +a function pointer conversion\iref{conv.fctptr} +\item% +a qualification conversion\iref{conv.qual}, or + +\end{itemize} + +\item +the \grammarterm{handler} is of type \cv{}~\tcode{T} or \tcode{const T\&} where \tcode{T} is a pointer or pointer-to-member type and \tcode{E} is \tcode{std::nullptr_t}. + +\end{itemize} + +\begin{note} +A +\grammarterm{throw-expression} +whose operand is an integer literal with value zero does not match a handler of +pointer or pointer-to-member type. +A handler of reference to array or function type +is never a match for any exception object\iref{expr.throw}. +\end{note} + +\begin{example} +\begin{codeblock} +class Matherr { @\commentellip@ virtual void vf(); }; +class Overflow: public Matherr { @\commentellip@ }; +class Underflow: public Matherr { @\commentellip@ }; +class Zerodivide: public Matherr { @\commentellip@ }; + +void f() { + try { + g(); + } catch (Overflow oo) { + // ... + } catch (Matherr mm) { + // ... + } +} +\end{codeblock} +Here, the +\tcode{Overflow} +handler will catch exceptions of type +\tcode{Overflow} +and the +\tcode{Matherr} +handler will catch exceptions of type +\tcode{Matherr} +and of all types publicly derived from +\tcode{Matherr} +including exceptions of type +\tcode{Underflow} +and +\tcode{Zerodivide}. +\end{example} + +\pnum +The handlers for a try block are tried in order of appearance. +\begin{note} +This makes it possible to write handlers that can never be +executed, for example by placing a handler for a final derived class after +a handler for a corresponding unambiguous public base class. +\end{note} + +\pnum +A +\tcode{...} +in a handler's +\grammarterm{exception-declaration} +specifies a match for any exception. +If present, a +\tcode{...} +handler shall be the last handler for its try block. + +\pnum +If no match is found among the handlers for a try block, +the search for a matching +handler continues in a dynamically surrounding try block +of the same thread. + +\pnum +\indextext{exception handling!terminate called@\tcode{terminate} called}% +\indextext{\idxcode{terminate}!called}% +If the search for a handler +encounters the outermost block of a function with a +non-throwing exception specification, +the function \tcode{std::terminate}\iref{except.terminate} is invoked. +\begin{note} +An implementation is not permitted to reject an expression merely because, when +executed, it throws or might +throw an exception from a function with a non-throwing exception specification. +\end{note} +\begin{example} +\begin{codeblock} +extern void f(); // potentially-throwing + +void g() noexcept { + f(); // valid, even if \tcode{f} throws + throw 42; // valid, effectively a call to \tcode{std::terminate} +} +\end{codeblock} +The call to +\tcode{f} +is well-formed despite the possibility for it to throw an exception. +\end{example} + +\pnum +If no matching handler is found, +the function \tcode{std::terminate} is invoked; +whether or not the stack is unwound before this invocation of +\tcode{std::terminate} is +\impldef{whether stack is unwound before invoking the function \tcode{std::terminate} +when no matching handler is found}\iref{except.terminate} + +\pnum +A handler is considered \defnx{active}{exception handling!handler!active} when +initialization is complete for the parameter (if any) of the catch clause. +\begin{note} +The stack will have been unwound at that point. +\end{note} +Also, an implicit handler is considered active when +the function \tcode{std::terminate} +is entered due to a throw. A handler is no longer considered active when the +catch clause exits. + +\pnum +\indextext{currently handled exception|see{exception handling, currently handled exception}}% +The exception with the most recently activated handler that is +still active is called the +\defnx{currently handled exception}{exception handling!currently handled exception}. + +\pnum +Referring to any non-static member or base class of an object +in the handler for a +\grammarterm{function-try-block} +of a constructor or destructor for that object results in undefined behavior. + +\pnum +Exceptions thrown in destructors of objects with static storage duration or in +constructors of objects associated with non-block variables with static storage duration are not caught by a +\grammarterm{function-try-block} +on +the \tcode{main} function\iref{basic.start.main}. +Exceptions thrown in destructors of objects with thread storage duration or in constructors of objects associated with non-block variables with thread storage duration are not caught by a +\grammarterm{function-try-block} +on the initial function of the thread. + +\pnum +If a \keyword{return} statement\iref{stmt.return} appears in a handler of the +\grammarterm{function-try-block} +of a +constructor, the program is ill-formed. + +\pnum +The currently handled exception +is rethrown if control reaches the end of a handler of the +\grammarterm{function-try-block} +of a constructor or destructor. +Otherwise, flowing off the end of +the \grammarterm{compound-statement} +of a \grammarterm{handler} +of a \grammarterm{function-try-block} +is equivalent to flowing off the end of +the \grammarterm{compound-statement} +of that function (see \ref{stmt.return}). + +\pnum +The variable declared by the \grammarterm{exception-declaration}, of type +\cv{}~\tcode{T} or \cv{}~\tcode{T\&}, is initialized from the exception object, +of type \tcode{E}, as follows: +\begin{itemize} +\item +if \tcode{T} is a base class of \tcode{E}, +the variable is copy-initialized\iref{dcl.init} +from an lvalue of type \tcode{T} designating the corresponding base class subobject +of the exception object; +\item otherwise, the variable is copy-initialized\iref{dcl.init} +from an lvalue of type \tcode{E} designating the exception object. +\end{itemize} + +The lifetime of the variable ends +when the handler exits, after the +destruction of any objects with automatic storage duration initialized +within the handler. + +\pnum +When the handler declares an object, +any changes to that object will not affect the exception object. +When the handler declares a reference to an object, +any changes to the referenced object are changes to the +exception object and will have effect should that object be rethrown.% +\indextext{exception handling!handler!match|)}% +\indextext{exception handling!handler|)} + \rSec2[basic.start]{Start and termination} \rSec3[basic.start.main]{\tcode{main} function} @@ -7194,5 +7761,126 @@ \libheaderref{cstdlib} terminates the program without executing any destructors and without calling the functions passed to \tcode{std::atexit()} or \tcode{std::at_quick_exit()}.% + +\rSec3[except.terminate]{The \tcode{std::terminate} function} + +\pnum +\indextext{\idxcode{terminate}}% +Some errors in a program cannot be recovered from, such as when an exception +is not handled or a \tcode{std::thread} object is destroyed while its thread +function is still running. In such cases, +the function \tcode{std::terminate}\iref{exception.terminate} is invoked. +\begin{note} +These situations are: +\indextext{\idxcode{terminate}!called}% +\begin{itemize} +\item% +when the exception handling mechanism, after completing +the initialization of the exception object +but before +activation of a handler for the exception\iref{except.throw}, +calls a function that exits +via an exception, or + +\item% +when the exception handling mechanism cannot find a handler for a thrown exception\iref{except.handle}, or + +\item when the search for a handler\iref{except.handle} encounters the +outermost block of a function +with a non-throwing exception specification\iref{except.spec}, or + +\item% +when the destruction of an object during stack unwinding\iref{except.ctor} +terminates by throwing an exception, or + +\item% +when initialization of a non-block +variable with static or thread storage duration\iref{basic.start.dynamic} +exits via an exception, or + +\item% +when destruction of an object with static or thread storage duration exits +via an exception\iref{basic.start.term}, or + +\item% +when execution of a function registered with +\tcode{std::atexit} or \tcode{std::at_quick_exit} +exits via an exception\iref{support.start.term}, or + +\item% +when a +\grammarterm{throw-expression}\iref{expr.throw} +with no operand attempts to rethrow an exception and no exception is being +handled\iref{except.throw}, or + +\item% +when the function \tcode{std::nested_exception::rethrow_nested} is called for an object +that has captured no exception\iref{except.nested}, or + +\item% +when execution of the initial function of a thread exits via +an exception\iref{thread.thread.constr}, or + +\item% +for a parallel algorithm whose \tcode{ExecutionPolicy} specifies such +behavior\iref{execpol.seq,execpol.par,execpol.parunseq}, +when execution of an element access function\iref{algorithms.parallel.defns} +of the parallel algorithm exits via an exception\iref{algorithms.parallel.exceptions}, or + +\item% +when the destructor or the move assignment operator is invoked on an object +of type \tcode{std::thread} that refers to +a joinable thread\iref{thread.thread.destr,thread.thread.assign}, or + +\item% +when a call to a \tcode{wait()}, \tcode{wait_until()}, or \tcode{wait_for()} +function on a condition variable\iref{thread.condition.condvar,thread.condition.condvarany} +fails to meet a postcondition, or + +\item% +when a callback invocation exits via an exception +when requesting stop on +a \tcode{std::stop_source} or +a \tcode{std::in\-place_stop_source}\iref{stopsource.mem,stopsource.inplace.mem}, +or in the constructor of +\tcode{std::stop_callback} or +\tcode{std::inplace_stop_callback}\iref{stopcallback.cons,stopcallback.inplace.cons} +when a callback invocation exits via an exception, or + +\item% +when a \tcode{run_loop} object is destroyed +that is still in the \tcode{running} state\iref{exec.run.loop}, or + +\item% +when \tcode{unhandled_stopped} is called on +a \tcode{with_awaitable_senders} object\iref{exec.with.awaitable.senders} +whose continuation is not a handle to a coroutine +whose promise type has an \tcode{unhandled_stopped} member function. + +\end{itemize} + +\end{note} + +\pnum +\indextext{\idxcode{terminate}}% +In the situation where no matching handler is found, it is +\impldef{whether stack is unwound before invoking the function \tcode{std::terminate} +when no matching handler is found} +whether or not the stack is unwound before \tcode{std::terminate} is invoked. +In the situation where the search for a handler\iref{except.handle} encounters the +outermost block of a function +with a non-throwing exception specification\iref{except.spec}, it is +\impldef{whether stack is unwound before invoking the function \tcode{std::terminate} +when a \tcode{noexcept} specification is violated} +whether the stack is unwound, unwound partially, or not unwound at all +before the function \tcode{std::terminate} is invoked. +In all other situations, the stack shall not be unwound before +the function \tcode{std::terminate} +is invoked. +An implementation is not permitted to finish stack unwinding +prematurely based on a determination that the unwind process +will eventually cause an invocation of the function +\tcode{std::terminate}. + \indextext{program!termination|)} \indextext{program execution|)} diff --git a/source/compatibility.tex b/source/compatibility.tex index 93baac8554..9bc289e8c1 100644 --- a/source/compatibility.tex +++ b/source/compatibility.tex @@ -951,6 +951,25 @@ \end{codeblock} \end{example} +\diffref{except.spec} +\change +Remove \tcode{throw()} exception specification. +\rationale +Removal of obsolete feature that has been replaced by \keyword{noexcept}. +\effect +A valid \CppXVII{} function declaration, member function declaration, function +pointer declaration, or function reference declaration that uses \tcode{throw()} +for its exception specification will be rejected as ill-formed in this +revision of \Cpp{}. It should simply be replaced with \keyword{noexcept} for no +change of meaning since \CppXVII{}. +\begin{note} +There is no way to write a function declaration +that is non-throwing in this revision of \Cpp{} +and is also non-throwing in \CppIII{} +except by using the preprocessor to generate +a different token sequence in each case. +\end{note} + \rSec2[diff.cpp17.class]{\ref{class}: classes} \diffref{class.ctor,class.conv.fct} @@ -1134,27 +1153,6 @@ \end{codeblock} \end{example} -\rSec2[diff.cpp17.except]{\ref{except}: exception handling} - -\diffref{except.spec} -\change -Remove \tcode{throw()} exception specification. -\rationale -Removal of obsolete feature that has been replaced by \keyword{noexcept}. -\effect -A valid \CppXVII{} function declaration, member function declaration, function -pointer declaration, or function reference declaration that uses \tcode{throw()} -for its exception specification will be rejected as ill-formed in this -revision of \Cpp{}. It should simply be replaced with \keyword{noexcept} for no -change of meaning since \CppXVII{}. -\begin{note} -There is no way to write a function declaration -that is non-throwing in this revision of \Cpp{} -and is also non-throwing in \CppIII{} -except by using the preprocessor to generate -a different token sequence in each case. -\end{note} - \rSec2[diff.cpp17.library]{\ref{library}: library introduction} \diffref{headers} @@ -1560,6 +1558,27 @@ \end{codeblock} \end{example} +\diffref{except.spec} +\change +Remove dynamic exception specifications. +\rationale +Dynamic exception specifications were a deprecated feature +that was complex and brittle in use. +They interacted badly with the type system, +which became a more significant issue in this revision of \Cpp{} +where (non-dynamic) exception specifications are part of the function type. +\effect +A valid \CppXIV{} function declaration, +member function declaration, +function pointer declaration, +or function reference declaration, +if it has a potentially throwing dynamic exception specification, +is rejected as ill-formed in this revision of \Cpp{}. +Violating a non-throwing dynamic exception specification +calls \tcode{terminate} rather than \tcode{unexpected}, +and it is unspecified whether stack unwinding is performed +prior to such a call. + \rSec2[diff.cpp14.class]{\ref{class}: classes} \diffref{class.inhctor.init} @@ -1613,29 +1632,6 @@ \end{codeblock} \end{example} -\rSec2[diff.cpp14.except]{\ref{except}: exception handling} - -\diffref{except.spec} -\change -Remove dynamic exception specifications. -\rationale -Dynamic exception specifications were a deprecated feature -that was complex and brittle in use. -They interacted badly with the type system, -which became a more significant issue in this revision of \Cpp{} -where (non-dynamic) exception specifications are part of the function type. -\effect -A valid \CppXIV{} function declaration, -member function declaration, -function pointer declaration, -or function reference declaration, -if it has a potentially throwing dynamic exception specification, -is rejected as ill-formed in this revision of \Cpp{}. -Violating a non-throwing dynamic exception specification -calls \tcode{terminate} rather than \tcode{unexpected}, -and it is unspecified whether stack unwinding is performed -prior to such a call. - \rSec2[diff.cpp14.library]{\ref{library}: library introduction} \diffref{headers} diff --git a/source/declarations.tex b/source/declarations.tex index 446aebd3aa..6a960ea03b 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -4109,6 +4109,272 @@ \end{footnote} \indextext{declarator!function|)} +\rSec3[except.spec]{Exception specifications}% +\indextext{exception specification|(} + +\pnum +The predicate indicating whether a function cannot exit via an exception +is called the \defn{exception specification} of the function. +If the predicate is false, +the function has a +\indextext{exception specification!potentially-throwing}% +\defnx{potentially-throwing exception specification}% +{potentially-throwing!exception specification}, +otherwise it has a +\indextext{exception specification!non-throwing}% +\defn{non-throwing exception specification}. +The exception specification is either defined implicitly, +or defined explicitly +by using a \grammarterm{noexcept-specifier} +as a suffix of a function declarator\iref{dcl.fct}. + +\begin{bnf} +\nontermdef{noexcept-specifier}\br + \keyword{noexcept} \terminal{(} constant-expression \terminal{)}\br + \keyword{noexcept}\br +\end{bnf} + +\pnum +\indextext{exception specification!noexcept!constant expression and}% +In a \grammarterm{noexcept-specifier}, the \grammarterm{constant-expression}, +if supplied, shall be a contextually converted constant expression +of type \keyword{bool}\iref{expr.const}; +that constant expression is the exception specification of +the function type in which the \grammarterm{noexcept-specifier} appears. +A \tcode{(} token that follows \keyword{noexcept} is part of the +\grammarterm{noexcept-specifier} and does not commence an +initializer\iref{dcl.init}. +The \grammarterm{noexcept-specifier} \keyword{noexcept} +without a \grammarterm{constant-expression} +is +equivalent to the \grammarterm{noexcept-specifier} +\tcode{\keyword{noexcept}(\keyword{true})}. +\begin{example} +\begin{codeblock} +void f() noexcept(sizeof(char[2])); // error: narrowing conversion of value 2 to type \keyword{bool} +void g() noexcept(sizeof(char)); // OK, conversion of value 1 to type \keyword{bool} is non-narrowing +\end{codeblock} +\end{example} + +\pnum +If a declaration of a function +does not have a \grammarterm{noexcept-specifier}, +the declaration has a potentially throwing exception specification +unless it is a destructor or a deallocation function +or is defaulted on its first declaration, +in which cases the exception specification +is as specified below +and no other declaration for that function +shall have a \grammarterm{noexcept-specifier}. +In an explicit instantiation\iref{temp.explicit} +a \grammarterm{noexcept-specifier} may be specified, +but is not required. +If a \grammarterm{noexcept-specifier} is specified +in an explicit instantiation, +the exception specification shall be the same as +the exception specification of all other declarations of that function. +A diagnostic is required only if the +exception specifications are not the same +within a single translation unit. + +\pnum +\indextext{exception specification!virtual function and}% +If a virtual function has a +non-throwing exception specification, +all declarations, including the definition, of any function +that overrides that virtual function in any derived class +shall have a non-throwing +exception specification, +unless the overriding function is defined as deleted. +\begin{example} +\begin{codeblock} +struct B { + virtual void f() noexcept; + virtual void g(); + virtual void h() noexcept = delete; +}; + +struct D: B { + void f(); // error + void g() noexcept; // OK + void h() = delete; // OK +}; +\end{codeblock} + +The declaration of +\tcode{D::f} +is ill-formed because it +has a potentially-throwing exception specification, +whereas +\tcode{B::f} +has a non-throwing exception specification. +\end{example} + +\pnum +An expression $E$ is +\defnx{potentially-throwing}{potentially-throwing!expression} if +\begin{itemize} +\item +$E$ is a function call\iref{expr.call} +whose \grammarterm{postfix-expression} +has a function type, +or a pointer-to-function type, +with a potentially-throwing exception specification, +or +\item +$E$ implicitly invokes a function +(such as an overloaded operator, +an allocation function in a \grammarterm{new-expression}, +a constructor for a function argument, +or a destructor if $E$ is a full-expression\iref{intro.execution}) +that has a potentially-throwing exception specification, +or +\item +$E$ is a \grammarterm{throw-expression}\iref{expr.throw}, +or +\item +$E$ is a \keyword{dynamic_cast} expression that casts to a reference type and +requires a runtime check\iref{expr.dynamic.cast}, +or +\item +$E$ is a \keyword{typeid} expression applied to a +(possibly parenthesized) built-in unary \tcode{*} operator +applied to a pointer to a +polymorphic class type\iref{expr.typeid}, +or +\item +any of the immediate subexpressions\iref{intro.execution} +of $E$ is potentially-throwing. +\end{itemize} + +\pnum +An implicitly-declared constructor for a class \tcode{X}, +or a constructor without a \grammarterm{noexcept-specifier} +that is defaulted on its first declaration, +has a potentially-throwing exception specification +if and only if +any of the following constructs is potentially-throwing: +\begin{itemize} +\item +the invocation of a constructor selected by overload resolution +in the implicit definition of the constructor +for class \tcode{X} +to initialize a potentially constructed subobject, or +\item +a subexpression of such an initialization, +such as a default argument expression, or, +\item +for a default constructor, a default member initializer. +\end{itemize} +\begin{note} +Even though destructors for fully-constructed subobjects +are invoked when an exception is thrown +during the execution of a constructor\iref{except.ctor}, +their exception specifications do not contribute +to the exception specification of the constructor, +because an exception thrown from such a destructor +would call the function \tcode{std::terminate} +rather than escape the constructor\iref{except.throw,except.terminate}. +\end{note} + +\pnum +The exception specification for an implicitly-declared destructor, +or a destructor without a \grammarterm{noexcept-specifier}, +is potentially-throwing if and only if +any of the destructors +for any of its potentially constructed subobjects +has a potentially-throwing exception specification or +the destructor is virtual and the destructor of any virtual base class +has a potentially-throwing exception specification. + +\pnum +The exception specification for an implicitly-declared assignment operator, +or an assignment-operator without a \grammarterm{noexcept-specifier} +that is defaulted on its first declaration, +is potentially-throwing if and only if +the invocation of any assignment operator +in the implicit definition is potentially-throwing. + +\pnum +A deallocation function\iref{basic.stc.dynamic.deallocation} +with no explicit \grammarterm{noexcept-specifier} +has a non-throwing exception specification. + +\pnum +The exception specification for a comparison operator function\iref{over.binary} +without a \grammarterm{noexcept-specifier} +that is defaulted on its first declaration +is potentially-throwing if and only if +any expression +in the implicit definition is potentially-throwing. + +\pnum +\begin{example} +\begin{codeblock} +struct A { + A(int = (A(5), 0)) noexcept; + A(const A&) noexcept; + A(A&&) noexcept; + ~A(); +}; +struct B { + B() noexcept; + B(const B&) = default; // implicit exception specification is \tcode{\keyword{noexcept}(\keyword{true})} + B(B&&, int = (throw 42, 0)) noexcept; + ~B() noexcept(false); +}; +int n = 7; +struct D : public A, public B { + int * p = new int[n]; + // \tcode{D::D()} potentially-throwing, as the \keyword{new} operator may throw \tcode{bad_alloc} or \tcode{bad_array_new_length} + // \tcode{D::D(const D\&)} non-throwing + // \tcode{D::D(D\&\&)} potentially-throwing, as the default argument for \tcode{B}'s constructor may throw + // \tcode{D::\~D()} potentially-throwing +}; +\end{codeblock} +Furthermore, if +\tcode{A::\~{}A()} +were virtual, +the program would be ill-formed since a function that overrides a virtual +function from a base class +shall not have a potentially-throwing exception specification +if the base class function has a non-throwing exception specification. +\end{example} + +\pnum +An exception specification is considered to be \defnx{needed}{needed!exception specification} when: +\begin{itemize} +\item in an expression, the function is selected by +overload resolution\iref{over.match,over.over}; + +\item the function is odr-used\iref{term.odr.use} or, if it appears in an +unevaluated operand, would be odr-used if the expression were +potentially-evaluated; + +\item the exception specification is compared to that of another +declaration (e.g., an explicit specialization or an overriding virtual +function); + +\item the function is defined; or + +\item the exception specification is needed for a defaulted +function that calls the function. +\begin{note} +A defaulted declaration does not require the +exception specification of a base member function to be evaluated +until the implicit exception specification of the derived +function is needed, but an explicit \grammarterm{noexcept-specifier} needs +the implicit exception specification to compare against. +\end{note} +\end{itemize} +The exception specification of a defaulted +function is evaluated as described above only when needed; similarly, the +\grammarterm{noexcept-specifier} of a specialization of a function +template or member function of a class template is instantiated only when +needed. +% +\indextext{exception specification|)} + \rSec3[dcl.fct.default]{Default arguments}% \indextext{declaration!default argument|(} diff --git a/source/exceptions.tex b/source/exceptions.tex deleted file mode 100644 index a462fe0bff..0000000000 --- a/source/exceptions.tex +++ /dev/null @@ -1,1148 +0,0 @@ -%!TEX root = std.tex -\rSec0[except]{Exception handling}% -\indextext{exception handling|(} - -\gramSec[gram.except]{Exception handling} - -\indextext{exception object|see{exception handling, exception object}}% -\indextext{object!exception|see{exception handling, exception object}} - -\rSec1[except.pre]{Preamble} - -\pnum -Exception handling provides a way of transferring control and information -from a point in the execution of a thread to an exception handler -associated with a point previously passed by the execution. -A handler will be invoked only by throwing an exception -in code executed in the handler's try block -or in functions called from the handler's try block. - -\indextext{\idxcode{try}}% -% -\begin{bnf} -\nontermdef{try-block}\br - \keyword{try} compound-statement handler-seq -\end{bnf} - -\indextext{\idxcode{try}}% -% -\begin{bnf} -\nontermdef{function-try-block}\br - \keyword{try} \opt{ctor-initializer} compound-statement handler-seq -\end{bnf} - -\begin{bnf} -\nontermdef{handler-seq}\br - handler \opt{handler-seq} -\end{bnf} - -\indextext{\idxcode{catch}}% -% -\begin{bnf} -\nontermdef{handler}\br - \keyword{catch} \terminal{(} exception-declaration \terminal{)} compound-statement -\end{bnf} - -\begin{bnf} -\nontermdef{exception-declaration}\br - \opt{attribute-specifier-seq} type-specifier-seq declarator\br - \opt{attribute-specifier-seq} type-specifier-seq \opt{abstract-declarator}\br - \terminal{...} -\end{bnf} - -The optional \grammarterm{attribute-specifier-seq} in an \grammarterm{exception-declaration} -appertains to the parameter of the catch clause\iref{except.handle}. - -\pnum -\indextext{exception handling!try block}% -\indextext{exception handling!handler}% -\indextext{try block|see{exception handling, try block}}% -\indextext{handler|see{exception handling, handler}}% -A \grammarterm{try-block} is a \grammarterm{statement}\iref{stmt.pre}. -\begin{note} -Within this Clause -``try block'' is taken to mean both \grammarterm{try-block} and -\grammarterm{function-try-block}. -\end{note} - -\pnum -\indextext{exception handling!\idxcode{goto}}% -\indextext{exception handling!\idxcode{switch}}% -\indextext{\idxcode{goto}!and try block}% -\indextext{\idxcode{switch}!and try block}% -\indextext{\idxcode{goto}!and handler}% -\indextext{\idxcode{switch}!and handler}% -The \grammarterm{compound-statement} of a try block or of a handler is a -control-flow-limited statement\iref{stmt.label}. -\begin{example} -\begin{codeblock} -void f() { - goto l1; // error - goto l2; // error - try { - goto l1; // OK - goto l2; // error - l1: ; - } catch (...) { - l2: ; - goto l1; // error - goto l2; // OK - } -} - -\end{codeblock} -\end{example} -\indextext{\idxcode{goto}!and try block}% -\indextext{\idxcode{switch}!and try block}% -\indextext{\idxcode{return}!and try block}% -\indextext{\idxcode{continue}!and try block}% -\indextext{\idxcode{goto}!and handler}% -\indextext{\idxcode{switch}!and handler}% -\indextext{\idxcode{return}!and handler}% -\indextext{\idxcode{continue}!and handler}% -A -\keyword{goto}, -\keyword{break}, -\keyword{return}, -or -\keyword{continue} -statement can be used to transfer control out of -a try block or handler. -When this happens, each variable declared in the try block -will be destroyed in the context that -directly contains its declaration. -\begin{example} -\begin{codeblock} -lab: try { - T1 t1; - try { - T2 t2; - if (@\grammarterm{condition}@) - goto lab; - } catch(...) { @\tcode{/* handler 2 */}@ } - } catch(...) { @\tcode{/* handler 1 */}@ } -\end{codeblock} - -Here, executing -\tcode{goto lab;} -will destroy first -\tcode{t2}, -then -\tcode{t1}, -assuming the -\grammarterm{condition} -does not declare a variable. -Any exception thrown while destroying -\tcode{t2} -will result in executing -\tcode{handler 2}; -any exception thrown while destroying -\tcode{t1} -will result in executing -\tcode{handler 1}. -\end{example} - -\pnum -\indextext{function try block|see{exception handling, function try block}}% -\indextext{exception handling!function try block}% -A -\grammarterm{function-try-block} -associates a -\grammarterm{handler-seq} -with the -\grammarterm{ctor-initializer}, -if present, and the -\grammarterm{compound-statement}. -An exception -thrown during the execution of the -\grammarterm{compound-statement} -or, for constructors and destructors, during the initialization or -destruction, respectively, of the class's subobjects, -transfers control to a handler in a -\grammarterm{function-try-block} -in the same way as an exception thrown during the execution of a -\grammarterm{try-block} -transfers control to other handlers. -\begin{example} -\begin{codeblock} -int f(int); -class C { - int i; - double d; -public: - C(int, double); -}; - -C::C(int ii, double id) -try : i(f(ii)), d(id) { - // constructor statements -} catch (...) { - // handles exceptions thrown from the ctor-initializer and from the constructor statements -} -\end{codeblock} -\end{example} - -\pnum -In this Clause, ``before'' and ``after'' refer to the -``sequenced before'' relation\iref{intro.execution}. - -\rSec1[except.throw]{Throwing an exception}% -\indextext{exception handling!throwing}% -\indextext{throwing|see{exception handling, throwing}} - -\pnum -Throwing an exception transfers control to a handler. -\begin{note} -An exception can be thrown from one of the following contexts: -\grammarterm{throw-expression}{s}\iref{expr.throw}, -allocation functions\iref{basic.stc.dynamic.allocation}, -\keyword{dynamic_cast}\iref{expr.dynamic.cast}, -\keyword{typeid}\iref{expr.typeid}, -\grammarterm{new-expression}{s}\iref{expr.new}, and standard library -functions\iref{structure.specifications}. -\end{note} -An object is passed and the type of that object determines which handlers -can catch it. -\begin{example} -\begin{codeblock} -throw "Help!"; -\end{codeblock} -can be caught by a -\grammarterm{handler} -of -\keyword{const} -\tcode{\keyword{char}*} -type: -\begin{codeblock} -try { - // ... -} catch(const char* p) { - // handle character string exceptions here -} -\end{codeblock} -and -\begin{codeblock} -class Overflow { -public: - Overflow(char,double,double); -}; - -void f(double x) { - throw Overflow('+',x,3.45e107); -} -\end{codeblock} -can be caught by a handler for exceptions of type -\tcode{Overflow}: -\begin{codeblock} -try { - f(1.2); -} catch(Overflow& oo) { - // handle exceptions of type \tcode{Overflow} here -} -\end{codeblock} -\end{example} - -\pnum -\indextext{exception handling!throwing}% -\indextext{exception handling!handler}% -\indextext{exception handling!nearest handler}% -When an exception is thrown, control is transferred to the nearest handler with -a matching type\iref{except.handle}; ``nearest'' means the handler -for which the -\grammarterm{compound-statement} or -\grammarterm{ctor-initializer} -following the -\keyword{try} -keyword was most recently entered by the thread of control and not yet exited. - -\pnum -Throwing an exception -initializes an object with dynamic storage duration, -called the -\defnx{exception object}{exception handling!exception object}. -If the type of the exception object would be -an incomplete type\iref{basic.types.general}, -an abstract class type\iref{class.abstract}, -or a pointer to an incomplete type other than -\cv{}~\keyword{void}\iref{basic.compound}, -the program is ill-formed. - -\pnum -\indextext{exception handling!memory}% -\indextext{exception handling!rethrowing}% -\indextext{exception handling!exception object}% -The memory for the exception object is -allocated in an unspecified way, except as noted in~\ref{basic.stc.dynamic.allocation}. -If a handler exits by rethrowing, control is passed to another handler for -the same exception object. -The points of potential destruction for the exception object are: -\begin{itemize} -\item -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 \grammarterm{exception-declaration} in the handler; - -\item -when an object of type \tcode{std::exception_ptr}\iref{propagation} -that refers to the exception object is destroyed, -before the destructor of \tcode{std::exception_ptr} returns. -\end{itemize} - -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 happen before that last one\iref{intro.races}. -\begin{note} -No other thread synchronization is implied in exception handling. -\end{note} -The implementation may then -deallocate the memory for the exception object; any such deallocation -is done in an unspecified way. -\begin{note} -A thrown exception does not -propagate to other threads unless caught, stored, and rethrown using -appropriate library functions; see~\ref{propagation} and~\ref{futures}. -\end{note} - -\pnum -\indextext{exception handling!exception object!constructor}% -\indextext{exception handling!exception object!destructor}% -Let \tcode{T} denote the type of the exception object. -Copy-initialization of an object of type \tcode{T} from -an lvalue of type \tcode{const T} in a context unrelated to \tcode{T} -shall be well-formed. -If \tcode{T} is a class type, -the selected constructor is odr-used\iref{basic.def.odr} and -the destructor of \tcode{T} is potentially invoked\iref{class.dtor}. - -\pnum -\indextext{exception handling!rethrow}% -\indextext{rethrow|see{exception handling, rethrow}}% -An exception is considered caught when a handler for that exception -becomes active\iref{except.handle}. -\begin{note} -An exception can have active handlers and still be considered uncaught if -it is rethrown. -\end{note} - -\pnum -\indextext{exception handling!terminate called@\tcode{terminate} called}% -\indextext{\idxcode{terminate}!called}% -If the exception handling mechanism -handling an uncaught exception\iref{except.uncaught} -directly invokes a function that exits via an -exception, the function \tcode{std::terminate} is invoked\iref{except.terminate}. -\begin{example} -\begin{codeblock} -struct C { - C() { } - C(const C&) { - if (std::uncaught_exceptions()) { - throw 0; // throw during copy to handler's \grammarterm{exception-declaration} object\iref{except.handle} - } - } -}; - -int main() { - try { - throw C(); // calls \tcode{std::terminate} if construction of the handler's - // \grammarterm{exception-declaration} object is not elided\iref{class.copy.elision} - } catch(C) { } -} -\end{codeblock} -\end{example} -\begin{note} -If a destructor directly invoked by stack unwinding exits via an exception, -\tcode{std::terminate} is invoked. -\end{note} - - -\rSec1[except.ctor]{Stack unwinding}% -\indextext{exception handling!constructors and destructors}% -\indextext{constructor!exception handling|see{exception handling, constructors and destructors}}% -\indextext{destructor!exception handling|see{exception handling, constructors and destructors}} - -\pnum -\indextext{unwinding!stack}% -As control passes from the point where an exception is thrown -to a handler, -objects are destroyed by a process, -specified in this subclause, called \defn{stack unwinding}. - -\pnum -Each object with automatic storage duration is destroyed if it has been -constructed, but not yet destroyed, -since the try block was entered. -If an exception is thrown during the destruction of temporaries or -local variables for a \keyword{return} statement\iref{stmt.return}, -the destructor for the returned object (if any) is also invoked. -The objects are destroyed in the reverse order of the completion -of their construction. -\begin{example} -\begin{codeblock} -struct A { }; - -struct Y { ~Y() noexcept(false) { throw 0; } }; - -A f() { - try { - A a; - Y y; - A b; - return {}; // \#1 - } catch (...) { - } - return {}; // \#2 -} -\end{codeblock} -At \#1, the returned object of type \tcode{A} is constructed. -Then, the local variable \tcode{b} is destroyed\iref{stmt.jump}. -Next, the local variable \tcode{y} is destroyed, -causing stack unwinding, -resulting in the destruction of the returned object, -followed by the destruction of the local variable \tcode{a}. -Finally, the returned object is constructed again at \#2. -\end{example} - -\pnum -If the initialization of an object -other than by delegating constructor -is terminated by an exception, -the destructor is invoked for -each of the object's subobjects -that were known to be initialized by the object's initialization and -whose initialization has completed\iref{dcl.init}. -\begin{note} -If such an object has a reference member -that extends the lifetime of a temporary object, -this ends the lifetime of the reference member, -so the lifetime of the temporary object is effectively not extended. -\end{note} -\indextext{subobject!initialized, known to be}% -A subobject is \defn{known to be initialized} -if it is not an anonymous union member and -its initialization is specified -\begin{itemize} -\item in \ref{class.base.init} for initialization by constructor, -\item in \ref{class.copy.ctor} for initialization by defaulted copy/move constructor, -\item in \ref{class.inhctor.init} for initialization by inherited constructor, -\item in \ref{dcl.init.aggr} for aggregate initialization, -\item in \ref{expr.prim.lambda.capture} for the initialization of -the closure object when evaluating a \grammarterm{lambda-expression}, -\item in \ref{dcl.init.general} for -default-initialization, value-initialization, or direct-initialization -of an array. -\end{itemize} -\begin{note} -This includes virtual base class subobjects -if the initialization -is for a complete object, and -can include variant members -that were nominated explicitly by -a \grammarterm{mem-initializer} or \grammarterm{designated-initializer-clause} or -that have a default member initializer. -\end{note} -If the destructor of an object is terminated by an exception, -each destructor invocation -that would be performed after executing the body of the destructor\iref{class.dtor} and -that has not yet begun execution -is performed. -\begin{note} -This includes virtual base class subobjects if -the destructor was invoked for a complete object. -\end{note} -The subobjects are destroyed in the reverse order of the completion of -their construction. Such destruction is sequenced before entering a -handler of the \grammarterm{function-try-block} of the constructor or destructor, -if any. - -\pnum -If the \grammarterm{compound-statement} -of the \grammarterm{function-body} -of a delegating constructor -for an object exits via -an exception, the object's destructor is invoked. -Such destruction is sequenced before entering a handler of the -\grammarterm{function-try-block} of a delegating constructor for that object, if any. - -\pnum -\begin{note} -If the object was allocated by a \grammarterm{new-expression}\iref{expr.new}, -the matching deallocation function\iref{basic.stc.dynamic.deallocation}, -if any, is called to free the storage occupied by the object. -\end{note} - - -\rSec1[except.handle]{Handling an exception} -\indextext{exception handling!handler|(}% - -\pnum -The -\grammarterm{exception-declaration} -in a -\grammarterm{handler} -describes the type(s) of exceptions that can cause -that -\grammarterm{handler} -to be entered. -\indextext{exception handling!handler!incomplete type in}% -\indextext{exception handling!handler!rvalue reference in}% -\indextext{exception handling!handler!array in}% -\indextext{exception handling!handler!pointer to function in}% -The -\grammarterm{exception-declaration} -shall not denote an incomplete type, an abstract class type, or an rvalue reference type. -The -\grammarterm{exception-declaration} -shall not denote a pointer or reference to an -incomplete type, other than ``pointer to \cv{}~\keyword{void}''. - -\pnum -A handler of type -\indextext{array!handler of type}% -``array of \tcode{T}'' or -\indextext{function!handler of type}% -function type \tcode{T} -is adjusted to be of type -``pointer to \tcode{T}''. - -\pnum -\indextext{exception handling!handler!match|(}% -A -\grammarterm{handler} -is a match for -an exception object -of type -\tcode{E} -if -\begin{itemize} -\item% -The \grammarterm{handler} is of type \cv{}~\tcode{T} or -\cv{}~\tcode{T\&} and -\tcode{E} and \tcode{T} -are the same type (ignoring the top-level \grammarterm{cv-qualifier}{s}), or -\item% -the \grammarterm{handler} is of type \cv{}~\tcode{T} or -\cv{}~\tcode{T\&} and -\tcode{T} is an unambiguous public base class of \tcode{E}, or -\item% -the \grammarterm{handler} is of type \cv{}~\tcode{T} or \tcode{const T\&} -where \tcode{T} is a pointer or pointer-to-member type and -\tcode{E} is a pointer or pointer-to-member type -that can be converted to \tcode{T} by one or more of -\begin{itemize} - -\item% -a standard pointer conversion\iref{conv.ptr} not involving conversions -to pointers to private or protected or ambiguous classes -\item% -a function pointer conversion\iref{conv.fctptr} -\item% -a qualification conversion\iref{conv.qual}, or - -\end{itemize} - -\item -the \grammarterm{handler} is of type \cv{}~\tcode{T} or \tcode{const T\&} where \tcode{T} is a pointer or pointer-to-member type and \tcode{E} is \tcode{std::nullptr_t}. - -\end{itemize} - -\begin{note} -A -\grammarterm{throw-expression} -whose operand is an integer literal with value zero does not match a handler of -pointer or pointer-to-member type. -A handler of reference to array or function type -is never a match for any exception object\iref{expr.throw}. -\end{note} - -\begin{example} -\begin{codeblock} -class Matherr { @\commentellip@ virtual void vf(); }; -class Overflow: public Matherr { @\commentellip@ }; -class Underflow: public Matherr { @\commentellip@ }; -class Zerodivide: public Matherr { @\commentellip@ }; - -void f() { - try { - g(); - } catch (Overflow oo) { - // ... - } catch (Matherr mm) { - // ... - } -} -\end{codeblock} -Here, the -\tcode{Overflow} -handler will catch exceptions of type -\tcode{Overflow} -and the -\tcode{Matherr} -handler will catch exceptions of type -\tcode{Matherr} -and of all types publicly derived from -\tcode{Matherr} -including exceptions of type -\tcode{Underflow} -and -\tcode{Zerodivide}. -\end{example} - -\pnum -The handlers for a try block are tried in order of appearance. -\begin{note} -This makes it possible to write handlers that can never be -executed, for example by placing a handler for a final derived class after -a handler for a corresponding unambiguous public base class. -\end{note} - -\pnum -A -\tcode{...} -in a handler's -\grammarterm{exception-declaration} -specifies a match for any exception. -If present, a -\tcode{...} -handler shall be the last handler for its try block. - -\pnum -If no match is found among the handlers for a try block, -the search for a matching -handler continues in a dynamically surrounding try block -of the same thread. - -\pnum -\indextext{exception handling!terminate called@\tcode{terminate} called}% -\indextext{\idxcode{terminate}!called}% -If the search for a handler -encounters the outermost block of a function with a -non-throwing exception specification, -the function \tcode{std::terminate}\iref{except.terminate} is invoked. -\begin{note} -An implementation is not permitted to reject an expression merely because, when -executed, it throws or might -throw an exception from a function with a non-throwing exception specification. -\end{note} -\begin{example} -\begin{codeblock} -extern void f(); // potentially-throwing - -void g() noexcept { - f(); // valid, even if \tcode{f} throws - throw 42; // valid, effectively a call to \tcode{std::terminate} -} -\end{codeblock} -The call to -\tcode{f} -is well-formed despite the possibility for it to throw an exception. -\end{example} - -\pnum -If no matching handler is found, -the function \tcode{std::terminate} is invoked; -whether or not the stack is unwound before this invocation of -\tcode{std::terminate} -is \impldef{stack unwinding before invocation of -\tcode{std::terminate}}\iref{except.terminate}. - -\pnum -A handler is considered \defnx{active}{exception handling!handler!active} when -initialization is complete for the parameter (if any) of the catch clause. -\begin{note} -The stack will have been unwound at that point. -\end{note} -Also, an implicit handler is considered active when -the function \tcode{std::terminate} -is entered due to a throw. A handler is no longer considered active when the -catch clause exits. - -\pnum -\indextext{currently handled exception|see{exception handling, currently handled exception}}% -The exception with the most recently activated handler that is -still active is called the -\defnx{currently handled exception}{exception handling!currently handled exception}. - -\pnum -Referring to any non-static member or base class of an object -in the handler for a -\grammarterm{function-try-block} -of a constructor or destructor for that object results in undefined behavior. - -\pnum -Exceptions thrown in destructors of objects with static storage duration or in -constructors of objects associated with non-block variables with static storage duration are not caught by a -\grammarterm{function-try-block} -on -the \tcode{main} function\iref{basic.start.main}. -Exceptions thrown in destructors of objects with thread storage duration or in constructors of objects associated with non-block variables with thread storage duration are not caught by a -\grammarterm{function-try-block} -on the initial function of the thread. - -\pnum -If a \keyword{return} statement\iref{stmt.return} appears in a handler of the -\grammarterm{function-try-block} -of a -constructor, the program is ill-formed. - -\pnum -The currently handled exception -is rethrown if control reaches the end of a handler of the -\grammarterm{function-try-block} -of a constructor or destructor. -Otherwise, flowing off the end of -the \grammarterm{compound-statement} -of a \grammarterm{handler} -of a \grammarterm{function-try-block} -is equivalent to flowing off the end of -the \grammarterm{compound-statement} -of that function (see \ref{stmt.return}). - -\pnum -The variable declared by the \grammarterm{exception-declaration}, of type -\cv{}~\tcode{T} or \cv{}~\tcode{T\&}, is initialized from the exception object, -of type \tcode{E}, as follows: -\begin{itemize} -\item -if \tcode{T} is a base class of \tcode{E}, -the variable is copy-initialized\iref{dcl.init} -from an lvalue of type \tcode{T} designating the corresponding base class subobject -of the exception object; -\item otherwise, the variable is copy-initialized\iref{dcl.init} -from an lvalue of type \tcode{E} designating the exception object. -\end{itemize} - -The lifetime of the variable ends -when the handler exits, after the -destruction of any objects with automatic storage duration initialized -within the handler. - -\pnum -When the handler declares an object, -any changes to that object will not affect the exception object. -When the handler declares a reference to an object, -any changes to the referenced object are changes to the -exception object and will have effect should that object be rethrown.% -\indextext{exception handling!handler!match|)}% -\indextext{exception handling!handler|)} - -\rSec1[except.spec]{Exception specifications}% -\indextext{exception specification|(} - -\pnum -The predicate indicating whether a function cannot exit via an exception -is called the \defn{exception specification} of the function. -If the predicate is false, -the function has a -\indextext{exception specification!potentially-throwing}% -\defnx{potentially-throwing exception specification}% -{potentially-throwing!exception specification}, -otherwise it has a -\indextext{exception specification!non-throwing}% -\defn{non-throwing exception specification}. -The exception specification is either defined implicitly, -or defined explicitly -by using a \grammarterm{noexcept-specifier} -as a suffix of a function declarator\iref{dcl.fct}. - -\begin{bnf} -\nontermdef{noexcept-specifier}\br - \keyword{noexcept} \terminal{(} constant-expression \terminal{)}\br - \keyword{noexcept}\br -\end{bnf} - -\pnum -\indextext{exception specification!noexcept!constant expression and}% -In a \grammarterm{noexcept-specifier}, the \grammarterm{constant-expression}, -if supplied, shall be a contextually converted constant expression -of type \keyword{bool}\iref{expr.const}; -that constant expression is the exception specification of -the function type in which the \grammarterm{noexcept-specifier} appears. -A \tcode{(} token that follows \keyword{noexcept} is part of the -\grammarterm{noexcept-specifier} and does not commence an -initializer\iref{dcl.init}. -The \grammarterm{noexcept-specifier} \keyword{noexcept} -without a \grammarterm{constant-expression} -is -equivalent to the \grammarterm{noexcept-specifier} -\tcode{\keyword{noexcept}(\keyword{true})}. -\begin{example} -\begin{codeblock} -void f() noexcept(sizeof(char[2])); // error: narrowing conversion of value 2 to type \keyword{bool} -void g() noexcept(sizeof(char)); // OK, conversion of value 1 to type \keyword{bool} is non-narrowing -\end{codeblock} -\end{example} - -\pnum -If a declaration of a function -does not have a \grammarterm{noexcept-specifier}, -the declaration has a potentially throwing exception specification -unless it is a destructor or a deallocation function -or is defaulted on its first declaration, -in which cases the exception specification -is as specified below -and no other declaration for that function -shall have a \grammarterm{noexcept-specifier}. -In an explicit instantiation\iref{temp.explicit} -a \grammarterm{noexcept-specifier} may be specified, -but is not required. -If a \grammarterm{noexcept-specifier} is specified -in an explicit instantiation, -the exception specification shall be the same as -the exception specification of all other declarations of that function. -A diagnostic is required only if the -exception specifications are not the same -within a single translation unit. - -\pnum -\indextext{exception specification!virtual function and}% -If a virtual function has a -non-throwing exception specification, -all declarations, including the definition, of any function -that overrides that virtual function in any derived class -shall have a non-throwing -exception specification, -unless the overriding function is defined as deleted. -\begin{example} -\begin{codeblock} -struct B { - virtual void f() noexcept; - virtual void g(); - virtual void h() noexcept = delete; -}; - -struct D: B { - void f(); // error - void g() noexcept; // OK - void h() = delete; // OK -}; -\end{codeblock} - -The declaration of -\tcode{D::f} -is ill-formed because it -has a potentially-throwing exception specification, -whereas -\tcode{B::f} -has a non-throwing exception specification. -\end{example} - -\pnum -An expression $E$ is -\defnx{potentially-throwing}{potentially-throwing!expression} if -\begin{itemize} -\item -$E$ is a function call\iref{expr.call} -whose \grammarterm{postfix-expression} -has a function type, -or a pointer-to-function type, -with a potentially-throwing exception specification, -or -\item -$E$ implicitly invokes a function -(such as an overloaded operator, -an allocation function in a \grammarterm{new-expression}, -a constructor for a function argument, -or a destructor if $E$ is a full-expression\iref{intro.execution}) -that has a potentially-throwing exception specification, -or -\item -$E$ is a \grammarterm{throw-expression}\iref{expr.throw}, -or -\item -$E$ is a \keyword{dynamic_cast} expression that casts to a reference type and -requires a runtime check\iref{expr.dynamic.cast}, -or -\item -$E$ is a \keyword{typeid} expression applied to a -(possibly parenthesized) built-in unary \tcode{*} operator -applied to a pointer to a -polymorphic class type\iref{expr.typeid}, -or -\item -any of the immediate subexpressions\iref{intro.execution} -of $E$ is potentially-throwing. -\end{itemize} - -\pnum -An implicitly-declared constructor for a class \tcode{X}, -or a constructor without a \grammarterm{noexcept-specifier} -that is defaulted on its first declaration, -has a potentially-throwing exception specification -if and only if -any of the following constructs is potentially-throwing: -\begin{itemize} -\item -the invocation of a constructor selected by overload resolution -in the implicit definition of the constructor -for class \tcode{X} -to initialize a potentially constructed subobject, or -\item -a subexpression of such an initialization, -such as a default argument expression, or, -\item -for a default constructor, a default member initializer. -\end{itemize} -\begin{note} -Even though destructors for fully-constructed subobjects -are invoked when an exception is thrown -during the execution of a constructor\iref{except.ctor}, -their exception specifications do not contribute -to the exception specification of the constructor, -because an exception thrown from such a destructor -would call the function \tcode{std::terminate} -rather than escape the constructor\iref{except.throw,except.terminate}. -\end{note} - -\pnum -The exception specification for an implicitly-declared destructor, -or a destructor without a \grammarterm{noexcept-specifier}, -is potentially-throwing if and only if -any of the destructors -for any of its potentially constructed subobjects -has a potentially-throwing exception specification or -the destructor is virtual and the destructor of any virtual base class -has a potentially-throwing exception specification. - -\pnum -The exception specification for an implicitly-declared assignment operator, -or an assignment-operator without a \grammarterm{noexcept-specifier} -that is defaulted on its first declaration, -is potentially-throwing if and only if -the invocation of any assignment operator -in the implicit definition is potentially-throwing. - -\pnum -A deallocation function\iref{basic.stc.dynamic.deallocation} -with no explicit \grammarterm{noexcept-specifier} -has a non-throwing exception specification. - -\pnum -The exception specification for a comparison operator function\iref{over.binary} -without a \grammarterm{noexcept-specifier} -that is defaulted on its first declaration -is potentially-throwing if and only if -any expression -in the implicit definition is potentially-throwing. - -\pnum -\begin{example} -\begin{codeblock} -struct A { - A(int = (A(5), 0)) noexcept; - A(const A&) noexcept; - A(A&&) noexcept; - ~A(); -}; -struct B { - B() noexcept; - B(const B&) = default; // implicit exception specification is \tcode{\keyword{noexcept}(\keyword{true})} - B(B&&, int = (throw 42, 0)) noexcept; - ~B() noexcept(false); -}; -int n = 7; -struct D : public A, public B { - int * p = new int[n]; - // \tcode{D::D()} potentially-throwing, as the \keyword{new} operator may throw \tcode{bad_alloc} or \tcode{bad_array_new_length} - // \tcode{D::D(const D\&)} non-throwing - // \tcode{D::D(D\&\&)} potentially-throwing, as the default argument for \tcode{B}'s constructor may throw - // \tcode{D::\~D()} potentially-throwing -}; -\end{codeblock} -Furthermore, if -\tcode{A::\~{}A()} -were virtual, -the program would be ill-formed since a function that overrides a virtual -function from a base class -shall not have a potentially-throwing exception specification -if the base class function has a non-throwing exception specification. -\end{example} - -\pnum -An exception specification is considered to be \defnx{needed}{needed!exception specification} when: -\begin{itemize} -\item in an expression, the function is selected by -overload resolution\iref{over.match,over.over}; - -\item the function is odr-used\iref{term.odr.use} or, if it appears in an -unevaluated operand, would be odr-used if the expression were -potentially-evaluated; - -\item the exception specification is compared to that of another -declaration (e.g., an explicit specialization or an overriding virtual -function); - -\item the function is defined; or - -\item the exception specification is needed for a defaulted -function that calls the function. -\begin{note} -A defaulted declaration does not require the -exception specification of a base member function to be evaluated -until the implicit exception specification of the derived -function is needed, but an explicit \grammarterm{noexcept-specifier} needs -the implicit exception specification to compare against. -\end{note} -\end{itemize} -The exception specification of a defaulted -function is evaluated as described above only when needed; similarly, the -\grammarterm{noexcept-specifier} of a specialization of a function -template or member function of a class template is instantiated only when -needed. -% -\indextext{exception specification|)} - -\rSec1[except.special]{Special functions} - -\rSec2[except.special.general]{General} - -\pnum -The function \tcode{std::terminate}\iref{except.terminate} -is used by the exception -handling mechanism for coping with errors related to the exception handling -mechanism itself. The function -\tcode{std::current_exception()}\iref{propagation} and the class -\tcode{std::nested_exception}\iref{except.nested} can be used by a program to -capture the currently handled exception. - -\rSec2[except.terminate]{The \tcode{std::terminate} function} - -\pnum -\indextext{\idxcode{terminate}}% -% FIXME: What does it mean to abandon exception handling? -In some situations, exception handling is abandoned -for less subtle error handling techniques. -\begin{note} -These situations are: -\indextext{\idxcode{terminate}!called}% -\begin{itemize} -\item% -when the exception handling mechanism, after completing -the initialization of the exception object -but before -activation of a handler for the exception\iref{except.throw}, -calls a function that exits -via an exception, or - -\item% -when the exception handling mechanism cannot find a handler for a thrown exception\iref{except.handle}, or - -\item when the search for a handler\iref{except.handle} encounters the -outermost block of a function -with a non-throwing exception specification\iref{except.spec}, or - -\item% -when the destruction of an object during stack unwinding\iref{except.ctor} -terminates by throwing an exception, or - -\item% -when initialization of a non-block -variable with static or thread storage duration\iref{basic.start.dynamic} -exits via an exception, or - -\item% -when destruction of an object with static or thread storage duration exits -via an exception\iref{basic.start.term}, or - -\item% -when execution of a function registered with -\tcode{std::atexit} or \tcode{std::at_quick_exit} -exits via an exception\iref{support.start.term}, or - -\item% -when a -\grammarterm{throw-expression}\iref{expr.throw} -with no operand attempts to rethrow an exception and no exception is being -handled\iref{except.throw}, or - -\item% -when the function \tcode{std::nested_exception::rethrow_nested} is called for an object -that has captured no exception\iref{except.nested}, or - -\item% -when execution of the initial function of a thread exits via -an exception\iref{thread.thread.constr}, or - -\item% -for a parallel algorithm whose \tcode{ExecutionPolicy} specifies such -behavior\iref{execpol.seq,execpol.par,execpol.parunseq}, -when execution of an element access function\iref{algorithms.parallel.defns} -of the parallel algorithm exits via an exception\iref{algorithms.parallel.exceptions}, or - -\item% -when the destructor or the move assignment operator is invoked on an object -of type \tcode{std::thread} that refers to -a joinable thread\iref{thread.thread.destr,thread.thread.assign}, or - -\item% -when a call to a \tcode{wait()}, \tcode{wait_until()}, or \tcode{wait_for()} -function on a condition variable\iref{thread.condition.condvar,thread.condition.condvarany} -fails to meet a postcondition, or - -\item% -when a callback invocation exits via an exception -when requesting stop on -a \tcode{std::stop_source} or -a \tcode{std::in\-place_stop_source}\iref{stopsource.mem,stopsource.inplace.mem}, -or in the constructor of -\tcode{std::stop_callback} or -\tcode{std::inplace_stop_callback}\iref{stopcallback.cons,stopcallback.inplace.cons} -when a callback invocation exits via an exception, or - -\item% -when a \tcode{run_loop} object is destroyed -that is still in the \tcode{running} state\iref{exec.run.loop}, or - -\item% -when \tcode{unhandled_stopped} is called on -a \tcode{with_awaitable_senders} object\iref{exec.with.awaitable.senders} -whose continuation is not a handle to a coroutine -whose promise type has an \tcode{unhandled_stopped} member function. - -\end{itemize} - -\end{note} - -\pnum -\indextext{\idxcode{terminate}}% -In such cases, -the function \tcode{std::terminate} is invoked\iref{exception.terminate}. -In the situation where no matching handler is found, it is -\impldef{stack unwinding before invocation of \tcode{std::terminate}} -whether or not the stack is unwound -before \tcode{std::terminate} is invoked. -In the situation where the search for a handler\iref{except.handle} encounters the -outermost block of a function -with a non-throwing exception specification\iref{except.spec}, it is -\impldef{whether stack is unwound before invoking the function \tcode{std::terminate} -when a \tcode{noexcept} specification is violated} -whether the stack is unwound, unwound partially, or not unwound at all -before the function \tcode{std::terminate} is invoked. -In all other situations, the stack shall not be unwound before -the function \tcode{std::terminate} -is invoked. -An implementation is not permitted to finish stack unwinding -prematurely based on a determination that the unwind process -will eventually cause an invocation of the function -\tcode{std::terminate}. - -\rSec2[except.uncaught]{The \tcode{std::uncaught_exceptions} function}% -\indexlibraryglobal{uncaught_exceptions} - -\pnum -An exception is considered uncaught -after completing the initialization of the exception object\iref{except.throw} -until completing the activation of a handler for the exception\iref{except.handle}. -\begin{note} -As a consequence, an exception is considered uncaught -during any stack unwinding resulting from it being thrown. -\end{note} -If an exception is rethrown\iref{expr.throw,propagation}, -it is considered uncaught from the point of rethrow -until the rethrown exception is caught. -The function \tcode{std::uncaught_exceptions}\iref{uncaught.exceptions} -returns the number of uncaught exceptions in the current thread.% -\indextext{exception handling|)} diff --git a/source/expressions.tex b/source/expressions.tex index 54e40c91a9..6d74239ecb 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -5643,7 +5643,7 @@ \indextext{\idxcode{bad_alloc}}% \indexlibraryglobal{bad_alloc}% \tcode{std::bad_alloc} -exception\iref{basic.stc.dynamic.allocation,except,bad.alloc}; +exception\iref{basic.stc.dynamic.allocation,except.throw,bad.alloc}; it returns a non-null pointer otherwise. If the allocation function has a non-throwing exception specification, it returns null to indicate failure to allocate storage diff --git a/source/lib-intro.tex b/source/lib-intro.tex index d608fa2067..55581f1d7f 100644 --- a/source/lib-intro.tex +++ b/source/lib-intro.tex @@ -53,7 +53,7 @@ The language support library\iref{support} provides components that are required by certain parts of the \Cpp{} language, such as memory allocation\iref{expr.new,expr.delete} and -exception processing\iref{except}. +exception processing\iref{support.exception.general}. \pnum The concepts library\iref{concepts} describes library components that \Cpp{} diff --git a/source/statements.tex b/source/statements.tex index 9940ee28de..4fd6aee9d3 100644 --- a/source/statements.tex +++ b/source/statements.tex @@ -1033,6 +1033,181 @@ \indextext{label}% label\iref{stmt.label} located in the current function. +\rSec1[except.pre]{\keyword{try} blocks} + +\pnum +Exception handling provides a way of transferring control and information +from a point in the execution of a thread to an exception handler +associated with a point previously passed by the execution. +A handler will be invoked only by throwing an exception +in code executed in the handler's try block +or in functions called from the handler's try block. + +\indextext{\idxcode{try}}% +% +\begin{bnf} +\nontermdef{try-block}\br + \keyword{try} compound-statement handler-seq +\end{bnf} + +\indextext{\idxcode{try}}% +% +\begin{bnf} +\nontermdef{function-try-block}\br + \keyword{try} \opt{ctor-initializer} compound-statement handler-seq +\end{bnf} + +\begin{bnf} +\nontermdef{handler-seq}\br + handler \opt{handler-seq} +\end{bnf} + +\indextext{\idxcode{catch}}% +% +\begin{bnf} +\nontermdef{handler}\br + \keyword{catch} \terminal{(} exception-declaration \terminal{)} compound-statement +\end{bnf} + +\begin{bnf} +\nontermdef{exception-declaration}\br + \opt{attribute-specifier-seq} type-specifier-seq declarator\br + \opt{attribute-specifier-seq} type-specifier-seq \opt{abstract-declarator}\br + \terminal{...} +\end{bnf} + +The optional \grammarterm{attribute-specifier-seq} in an \grammarterm{exception-declaration} +appertains to the parameter of the catch clause\iref{except.handle}. + +\pnum +\indextext{exception handling!try block}% +\indextext{exception handling!handler}% +\indextext{try block|see{exception handling, try block}}% +\indextext{handler|see{exception handling, handler}}% +A \grammarterm{try-block} is a \grammarterm{statement}\iref{stmt.pre}. +\begin{note} +Within this Clause +``try block'' is taken to mean both \grammarterm{try-block} and +\grammarterm{function-try-block}. +\end{note} + +\pnum +\indextext{exception handling!\idxcode{goto}}% +\indextext{exception handling!\idxcode{switch}}% +\indextext{\idxcode{goto}!and try block}% +\indextext{\idxcode{switch}!and try block}% +\indextext{\idxcode{goto}!and handler}% +\indextext{\idxcode{switch}!and handler}% +The \grammarterm{compound-statement} of a try block or of a handler is a +control-flow-limited statement\iref{stmt.label}. +\begin{example} +\begin{codeblock} +void f() { + goto l1; // error + goto l2; // error + try { + goto l1; // OK + goto l2; // error + l1: ; + } catch (...) { + l2: ; + goto l1; // error + goto l2; // OK + } +} + +\end{codeblock} +\end{example} +\indextext{\idxcode{goto}!and try block}% +\indextext{\idxcode{switch}!and try block}% +\indextext{\idxcode{return}!and try block}% +\indextext{\idxcode{continue}!and try block}% +\indextext{\idxcode{goto}!and handler}% +\indextext{\idxcode{switch}!and handler}% +\indextext{\idxcode{return}!and handler}% +\indextext{\idxcode{continue}!and handler}% +A +\keyword{goto}, +\keyword{break}, +\keyword{return}, +or +\keyword{continue} +statement can be used to transfer control out of +a try block or handler. +When this happens, each variable declared in the try block +will be destroyed in the context that +directly contains its declaration. +\begin{example} +\begin{codeblock} +lab: try { + T1 t1; + try { + T2 t2; + if (@\grammarterm{condition}@) + goto lab; + } catch(...) { @\tcode{/* handler 2 */}@ } + } catch(...) { @\tcode{/* handler 1 */}@ } +\end{codeblock} + +Here, executing +\tcode{goto lab;} +will destroy first +\tcode{t2}, +then +\tcode{t1}, +assuming the +\grammarterm{condition} +does not declare a variable. +Any exception thrown while destroying +\tcode{t2} +will result in executing +\tcode{handler 2}; +any exception thrown while destroying +\tcode{t1} +will result in executing +\tcode{handler 1}. +\end{example} + +\pnum +\indextext{function try block|see{exception handling, function try block}}% +\indextext{exception handling!function try block}% +A +\grammarterm{function-try-block} +associates a +\grammarterm{handler-seq} +with the +\grammarterm{ctor-initializer}, +if present, and the +\grammarterm{compound-statement}. +An exception +thrown during the execution of the +\grammarterm{compound-statement} +or, for constructors and destructors, during the initialization or +destruction, respectively, of the class's subobjects, +transfers control to a handler in a +\grammarterm{function-try-block} +in the same way as an exception thrown during the execution of a +\grammarterm{try-block} +transfers control to other handlers. +\begin{example} +\begin{codeblock} +int f(int); +class C { + int i; + double d; +public: + C(int, double); +}; + +C::C(int ii, double id) +try : i(f(ii)), d(id) { + // constructor statements +} catch (...) { + // handles exceptions thrown from the ctor-initializer and from the constructor statements +} +\end{codeblock} +\end{example} + \rSec1[stmt.dcl]{Declaration statement}% \indextext{statement!declaration} diff --git a/source/std.tex b/source/std.tex index fea8f0a37c..3a5132f9f8 100644 --- a/source/std.tex +++ b/source/std.tex @@ -120,7 +120,6 @@ \include{classes} \include{overloading} \include{templates} -\include{exceptions} \include{preprocessor} \include{lib-intro} \include{support} diff --git a/source/support.tex b/source/support.tex index 28c15ac913..ef7d0aace1 100644 --- a/source/support.tex +++ b/source/support.tex @@ -3760,6 +3760,15 @@ \pnum The header \libheaderdef{exception} defines several types and functions related to the handling of exceptions in a \Cpp{} program. +The function \tcode{std::terminate}\iref{except.terminate} +is used by the exception +handling mechanism for coping with errors related to the exception handling +mechanism itself. +The function \tcode{std::uncaught_exceptions}\iref{uncaught.exceptions} +reports how many exceptions are uncaught in the current thread. +The function \tcode{std::current_exception}\iref{propagation} and the class +\tcode{std::nested_exception}\iref{except.nested} can be used by a program to +capture the currently handled exception. \rSec2[exception.syn]{Header \tcode{} synopsis} @@ -4013,7 +4022,7 @@ \begin{itemdescr} \pnum \returns -The number of uncaught exceptions\iref{except.uncaught}. +The number of uncaught exceptions\iref{except.throw} in the current thread. \pnum \remarks diff --git a/source/xrefdelta.tex b/source/xrefdelta.tex index 04302a06d0..688ec44f56 100644 --- a/source/xrefdelta.tex +++ b/source/xrefdelta.tex @@ -73,6 +73,14 @@ \removedxref{type.index.members} \removedxref{type.index.hash} +% Dissolving [except] +\removedxref{diff.cpp14.except} +\removedxref{diff.cpp17.except} +\removedxref{except} +\removedxref{except.special} +\removedxref{except.special.general} +\removedxref{gram.except} + %%% Renamed sections. %%% Examples: % @@ -95,6 +103,10 @@ \movedxref{stoptoken.cons}{stopsource} \movedxref{stoptoken.nonmembers}{stopsource} +% https://github.com/cplusplus/draft/pull/7276 +\movedxref{except.uncaught}{except.throw} + + %%% Deprecated features. %%% Example: %