This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++17 status.

### 2484. `rethrow_if_nested()` is doubly unimplementable

Section: 17.10.8 [except.nested] Status: C++17 Submitter: Stephan T. Lavavej Opened: 2015-03-27 Last modified: 2017-07-30

Priority: 2

View all other issues in [except.nested].

View all issues with C++17 status.

Discussion:

`rethrow_if_nested()` wants to determine "If the dynamic type of `e` is publicly and unambiguously derived from `nested_exception`", but 7.6.1.7 [expr.dynamic.cast] specifies that `dynamic_cast` has a couple of limitations.

First, nonpolymorphic inputs. These could be non-classes, or nonpolymorphic classes. The Standardese handles non-classes, although implementers need special logic. (If `E` is `int`, the dynamic type can't possibly derive from `nested_exception`. Implementers need to detect this and avoid `dynamic_cast`, which would be ill-formed due to 7.6.1.7 [expr.dynamic.cast]/2.) The Standardese is defective when `E` is a nonpolymorphic class. Consider the following example:

>     struct Nonpolymorphic { };
>     struct MostDerived : Nonpolymorphic, nested_exception { };
>     MostDerived md;
>     const Nonpolymorphic& np = md;
>     rethrow_if_nested(np);

According to 3.19 [defns.dynamic.type], the dynamic type of `np` is `MostDerived`. However, it's physically impossible to discover this, and attempting to do so will lead to an ill-formed `dynamic_cast` (7.6.1.7 [expr.dynamic.cast]/6). The Standardese must be changed to say that if `E` is nonpolymorphic, nothing happens.

Second, statically good but dynamically bad inputs. Consider the following example:

>     struct Nested1 : nested_exception { };
>     struct Nested2 : nested_exception { };
>     struct Ambiguous : Nested1, Nested2 { };
>     Ambiguous amb;
>     const Nested1& n1 = amb;
>     rethrow_if_nested(n1);

Here, the static type `Nested1` is good (i.e. publicly and unambiguously derived from `nested_exception`), but the dynamic type `Ambiguous` is bad. The Standardese currently says that we have to detect the dynamic badness, but `dynamic_cast` won't let us. 7.6.1.7 [expr.dynamic.cast]/3 and /5 are special cases (identity-casting and upcasting, respectively) that activate before the "run-time check" behavior that we want (/6 and below). Statically good inputs succeed (regardless of the dynamic type) and statically bad inputs are ill-formed (implementers must use type traits to avoid this).

It might be possible to implement this with clever trickery involving virtual base classes, but implementers shouldn't be asked to do that. It would definitely be possible to implement this with a compiler hook (a special version of `dynamic_cast`), but implementers shouldn't be asked to do so much work for such an unimportant case. (This case is pathological because the usual way of adding `nested_exception` inheritance is `throw_with_nested()`, which avoids creating bad inheritance.) The Standardese should be changed to say that statically good inputs are considered good.

Finally, we want `is_base_of`'s "base class or same class" semantics. If the static type is `nested_exception`, we have to consider it good due to `dynamic_cast`'s identity-casting behavior. And if the dynamic type is `nested_exception`, it is definitely good.

[2015-05, Lenexa]

WB: so the `is_polymorphic` trait must be used?
STL and JW: yes, that must be used to decide whether to try using `dynamic_cast` or not.
JW: I'd already made this fix in our implementation
STL: the harder case also involves `dynamic_cast`. should not try using `dynamic_cast` if we can statically detect it is OK, doing the `dynamic_cast` might fail.
STL: finally, want "is the same or derived from" behaviour of `is_base_of`
WB: should there be an "else no effect" at the end? We have "Otherwise, if ..." and nothing saying what if the condition is false.
TP I agree.
MC: move to Ready and bring to motion on Friday
7 in favor, none opposed

Proposed resolution:

This wording is relative to N4296.

1. Change 17.10.8 [except.nested] as depicted:

   >     template <class E> void rethrow_if_nested(const E& e);

   > > -9- Effects: If `E` is not a polymorphic class type, there is no effect. Otherwise, if the static type or the dynamic type of `e` is `nested_exception` or is publicly and unambiguously derived from `nested_exception`, calls `dynamic_cast<const nested_exception&>(e).rethrow_nested()`.