diff --git a/source/declarations.tex b/source/declarations.tex index 446aebd3aa..2b421e2995 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -4422,6 +4422,272 @@ \indextext{declaration!default argument|)}% \indextext{declarator!meaning of|)} +\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|)} + \rSec1[dcl.init]{Initializers}% \rSec2[dcl.init.general]{General}% diff --git a/source/exceptions.tex b/source/exceptions.tex index a462fe0bff..ac8f480006 100644 --- a/source/exceptions.tex +++ b/source/exceptions.tex @@ -729,272 +729,6 @@ \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}