This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 117a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2025-04-13
[Moved to DR at the November, 2014 meeting.]
The determination of the exception-specification for an implicitly-declared special member function, as described in 14.5 [except.spec] paragraph 14, does not take into account the fact that nonstatic data member initializers and default arguments in default constructors can contain throw-expressions, which are not part of the exception-specification of any function that is “directly invoked” by the implicit definition. Also, the reference to “directly invoked” functions is not restricted to potentially-evaluated expressions, thus possibly including irrelevant exception-specifications.
Additional note (August, 2012):
The direction established by CWG for resolving this issue was to consider functions called from default arguments and non-static data member initializers in determining the exception-specification. This leads to a problem with ordering: because non-static data member initializers can refer to members declared later, their effect cannot be known until the end of the class. However, a non-static data member initializer could possibly refer to an implicitly-declared constructor, either its own or that of an enclosing class.
Proposed resolution (October, 2012) [SUPERSEDED]:
Add the following two new paragraphs and make the indicated changes to 14.5 [except.spec] paragraph 14:
An inheriting constructor (_N4527_.12.9 [class.inhctor]) and an
implicitly declaredspecial member function (11.4.4 [special])have anexception-specification.If f is an inheriting constructor or an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-id T if and only if T is allowed by the exception-specification of a function directly invoked by f's implicit definition; f allows all exceptions if any function it directly invokes allows all exceptions, and f has the exception-specification noexcept(true) if every function it directly invokes allows no exceptions.[Note: An instantiation of an inheriting constructor template has an implied exception-specification as if it were a non-template inheriting constructor. —end note] [Example:struct A { A(); A(const A&) throw(); A(A&&) throw(); ~A() throw(X); }; struct B { B() throw(); B(const B&) throw(); B(B&&) throw(Y); ~B() throw(Y); }; struct D : public A, public B { // Implicit declaration of D::D(); // Implicit declaration of D::D(const D&) noexcept(true); // Implicit declaration of D::D(D&&) throw(Y); // Implicit declaration of D::~D() throw(X, Y); };Furthermore, if...
Change 7.6.2.7 [expr.unary.noexcept] paragraph 3 as follows:
The result of the noexcept operator is false if
in a potentially-evaluated contextthe expressionwould contain
a potentially evaluated call80 to a function, member function, function pointer, or member function pointer that does not have a non-throwing exception-specification (14.5 [except.spec]), unless the call is a constant expression (7.7 [expr.const]),
a potentially evaluated throw-expression (14.2 [except.throw]),
a potentially evaluated dynamic_cast expression dynamic_cast<T>(v), where T is a reference type, that requires a run-time check (7.6.1.7 [expr.dynamic.cast]), or
a potentially evaluated typeid expression (7.6.1.8 [expr.typeid]) applied to a glvalue expression whose type is a polymorphic class type (11.7.3 [class.virtual]).
Otherwise, the result is true.
(This resolution also resolves issues 1356 and 1465.)
Additional note (October, 2012):
The preceding wording has been modified from the version that was reviewed following the October, 2012 meeting and thus has been returned to "review" status.
Additional note (March, 2013):
It has been suggested that it might be more consistent with other parts of the language, and particularly in view of the deprecation of dynamic-exception-specifications, if a potentially-throwing non-static data member initializer simply made an implicit constructor noexcept(false) instead of giving it a set of potential exception types.
Additional note, April, 2013:
One problem with the approach suggested in the preceding note would be something like the following example:
struct S { virtual ~S() throw(int); }; struct D: S { };
This approach would make the example ill-formed, because the derived class destructor would be declared to throw types not permitted by the base class destructor's exception-specification. A further elaboration on the suggestion above that would not have this objection would be to define all dynamic-exception-specifications as simply equivalent to noexcept(false).
(See also issue 1639.)
Additional note, April, 2013:
The version of this resolution approved in Bristol assumed the underlying text of the C++11 IS; however, the wording of 14.5 [except.spec] paragraph 14 has been changed by previous resolutions, so this and the related issues are being returned to "review" status.
Proposed resolution, February, 2014 [SUPERSEDED]:
Change 14.5 [except.spec] paragraph 5 as follows:
If a virtual function has an exception-specification, all declarations, including the definition, of any function that overrides that virtual function in any derived class shall only allow exceptions that are allowed by the exception-specification of the base class virtual function. [Example:...
Add the following two new paragraphs and change 14.5 [except.spec] paragraph 14 as indicated:
An inheriting constructor (_N4527_.12.9 [class.inhctor]) and an implicitlydeclared special member function (11.4.4 [special])
havean exception-specification.If f is an inheriting constructor or an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-id T if and only if T is allowed by the exception-specification of a function directly invoked by f's implicit definition; f allows all exceptions if any function it directly invokes allows all exceptions, and f has the exception-specification noexcept(true) if every function it directly invokes allows no exceptions. [Note: It follows that f has the exception-specification noexcept(true) if it invokes no other functions. —end note][Note: An instantiation of an inheriting constructor template has an implied exception-specification as if it were a non-template inheriting constructor. —end note] [Example:struct A { A(); A(const A&) throw(); A(A&&) throw(); ~A() throw(X); }; struct B { B() throw(); B(const B&)= default; // Declaration of B::B(const B&) noexcept(true)B(B&&)throw(Y); ~B() throw(Y); }; struct D : public A, public B { // Implicit declaration of D::D(); // Implicit declaration of D::D(const D&) noexcept(true); // Implicit declaration of D::D(D&&) throw(Y); // Implicit declaration of D::~D() throw(X, Y); };Furthermore...
Change 7.6.2.7 [expr.unary.noexcept]paragraph 3 as follows:
The result of the noexcept operator is
falseifin a potentially-evaluated contextthe expressionwould contain
a potentially-evaluated call [[Footnote: This includes implicit calls such as the call to an allocation function in a new-expression. —end footnote] to a function, member function, function pointer, or member function pointer that does not have a non-throwing exception-specification (14.5 [except.spec]), unless the call is a constant expression (7.7 [expr.const]),
a potentially-evaluated throw-expression (14.2 [except.throw]),
a potentially-evaluated dynamic_cast expression dynamic_cast<T>(v), where T is a reference type, that requires a run-time check (7.6.1.7 [expr.dynamic.cast]), or
a potentially-evaluated typeid expression (7.6.1.8 [expr.typeid]) applied to a glvalue expression whose type is a polymorphic class type (11.7.3 [class.virtual]).
Otherwise, the result is true.
(This resolution also resolves issues 1356, 1465, and 1639.)
Additional note, May, 2014:
The current version of the proposed resolution only defines the set of potential exceptions for special member functions; since an inheriting constructor is not a special member function, the exception-specification for an inheriting constructor is no longer specified.
In addition, the structure of the specification of the set of potential exceptions of an expression is unclear. If the bulleted list is intended to be the definition of general statement (“union of all sets of potential exceptions...”), it's incomplete because it doesn't consider exceptions thrown by the evaluation of function arguments in a call, just the exceptions thrown by the function itself; if it's intended to be a list of exceptions to the general rule, the rule about core constant expressions doesn't exclude unselected subexpressions that might throw, so those exceptions are incorrect included in the union.
The issue has been returned to "review" status to allow discussion of these points.
See also the discussion in messages 25290 through 25293.
Proposed resolution (June, 2014):
If a virtual function has an exception-specification, all declarations, including the definition, of any function that overrides that virtual function in any derived class shall only allow exceptions that are allowed by the exception-specification of the base class virtual function. [Example:...
Add the following new paragraphs following 14.5 [except.spec] paragraph 13:
An exception-specification is not considered part of a function's type.
Change 14.5 [except.spec] paragraph 14 as follows:
An inheriting constructor (_N4527_.12.9 [class.inhctor]) and an
implicitly declaredspecial member function (11.4.4 [special]) have an exception-specification.
If f is an inheriting constructor or an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-id T if and only if T is allowed by the exception-specification of a function directly invoked by f's implicit definition; f allows all exceptions if any function it directly invokes allows all exceptions, and f has the exception-specification noexcept(true) if every function it directly invokes allows no exceptions. [Note: It follows that f has the exception-specification noexcept(true) if it invokes no other functions. —end note][Note: An instantiation of an inheriting constructor template has an implied exception-specification as if it were a non-template inheriting constructor. —end note] [Example:struct A { A() ; A(const A&) throw(); A(A&&) throw(); ~A() throw(X); }; struct B { B() throw(); B(const B&) = default; // Declaration of B::B(const B&) noexcept(true) B(B&&)throw(Y); ~B() throw(Y); }; struct D : public A, public B {// Implicit declaration of D::D();// Implicit declaration of D::D(const D&) noexcept(true); // Implicit declaration of D::D(D&&) throw(Y); // Implicit declaration of D::~D() throw(X, Y); };
Change 7.6.2.7 [expr.unary.noexcept] paragraph 3 as follows:
The result of the noexcept operator is
falseifin a potentially-evaluated contextthe expressionwould contain
a potentially-evaluated call83 to a function, member function, function pointer, or member function pointer that does not have a non-throwing exception-specification (14.5 [except.spec]), unless the call is a constant expression (7.7 [expr.const]),
a potentially-evaluated throw-expression (14.2 [except.throw]),
a potentially-evaluated dynamic_cast expression dynamic_cast<T>(v), where T is a reference type, that requires a run-time check (7.6.1.7 [expr.dynamic.cast]), or
a potentially-evaluated typeid expression (7.6.1.8 [expr.typeid]) applied to a glvalue expression whose type is a polymorphic class type (11.7.3 [class.virtual]).
Otherwise, the result is true.
This resolution also resolves issues 1356, 1465, and 1639.