Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CPP29 REORG] Dissolve [except] #7320

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
688 changes: 688 additions & 0 deletions source/basic.tex

Large diffs are not rendered by default.

84 changes: 40 additions & 44 deletions source/compatibility.tex
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -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}
Expand Down
266 changes: 266 additions & 0 deletions source/declarations.tex
Original file line number Diff line number Diff line change
Expand Up @@ -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|(}

Expand Down
Loading
Loading