Since C++17, the meaning of prvalue has changed, which makes copy elision guaranteed in some cases. From cppreference, the copy/move constructors need not be present or accessible in that case.
When an exception is thrown, the exception object is copy-initialized, and the copy/move may be subject to copy elision. But is it required that the copy/move constructor must be available at this time?
From [except.throw]:
When the thrown object is a class object, the constructor selected for the copy-initialization as well as the constructor selected for a copy-initialization considering the thrown object as an lvalue shall be non-deleted and accessible, even if the copy/move operation is elided ([class.copy.elision]). The destructor is potentially invoked ([class.dtor]).
The standard mentions that the corresponding constructor must be non-deleted and accessible, even if it is elided.
However, I tested and found that both GCC and Clang allow to throw when the corresponding constructor is deleted:
struct A {
A() = default;
A(A&&) = delete;
};
try {
throw A{}; // copy elision
} catch(...) {}
The code compiles, but it does not seem to meet the requirements of the standard. If I lower the version from C++17 to C++14, they will both report errors:
struct A {
A() = default;
A(A&&) = delete;
};
try {
throw A{}; // error: call to deleted constructor of 'A'
} catch(...) {}
Is my understanding of the standard wrong, or is it just the compiler relaxing the restrictions?