Consider the fragment:
try {
Foo f;
throw std::move(f);
}
catch (Foo& f) { }
[expr.throw] says that:
the type of the exception object is determined by removing any top-level cv-qualifiers from the static type of the operand and adjusting the type from “array of T” or “function returning T” to “pointer to T” or “pointer to function returning T”, respectively.
which would be Foo&&
. The exception object is then initialized according to [except.throw]:
Throwing an exception copy-initializes (8.5, 12.8) a temporary object, called the exception object. The temporary is an lvalue and is used to initialize the variable declared in the matching handler (15.3). If the type of the exception object would be an incomplete type or a pointer to an incomplete type other than (possibly cv-qualified)
void
the program is ill-formed.
This suggests to me that the exception object is initialized as:
Foo&& __exception_object = std::move(f);
and that the handler would not match. However, both gcc and clang do catch this exception. So what's the actual type of the exception object here? If Foo
, why?