b is constructed, since its constructor has finished.
However, the problem seems to be a bit more subtle. When we get to the
destructors at the end of the full-expression, the two 'a' temporaries
and 'tmp' have been constructed. In normal execution, we would then
destroy the 'a' temporaries in reverse construction order, and then
destroy the 'tmp' object at the end of its scope.
Now, GCC seems to believe that after the first '~a' call throws, we
should destroy 'tmp' and then destroy the 'a' temporary. Perhaps it's
trying to enforce reverse construction order ('tmp' was constructed
after the 'a' temporaries), per 15.2/1. However, that paragraph does
not directly apply, since temporaries don't have automatic storage
duration (see core issue 365).
I don't find the reasoning in this core issue convincing, and I agree
with Steve Adamczyk's comment that it's really just their object lifetime
that's a bit odd, not their storage duration.
The problem, as I see it, is that the standard currently specifies
that they have static storage duration (because they are objects
"implicitly created by the implementation" (3.7/2), but they're not
"block-scope variables" (3.7.3/1)).
The choice of wording in [basic.stc] is not accidental: a temporary is an
object but not a variable. I do not believe [basic.stc.auto] is intended to be
exhaustive.
[class.temporary]p5 strongly suggests (but no, it does not state directly) that
the storage duration of a temporary varies by how it's used, e.g. being
increased when bound as the initializer of a reference of static duration.
Note the places which discuss objects "with the same storage duration" as
the temporary.
As an aside, the standard does not seem to require us to destroy a variable
of *static* storage duration if the destructor of a temporary required during
initialization throws — and yet I believe it does require us to repeat
initialization in this case. So really there's quite a bit of poor drafting in
this area.
I believe the intent of the standard is quite clearly to have the local
variable destroyed in reverse order of construction w.r.t. the temporaries,
much like a return value must be.
That does not match my expectation, which is that in:
S s(T(), T());
the T temporaries should *always* be destroyed before the S object is.
Having an inconsistency in destruction order (depending on whether one
of the ~T() calls throws) does not seem useful, and I don't see any
way to read the standard in which it is mandated. Indeed, consider the
following (credit to Chandler for the argument, any flaws in conveying
it are my own):
* The destructors for local variables are only invoked "As control
passes from a throw-expression to a handler".
* The evaluation of the throw-expression's full-expression is
sequenced-before the evaluation of the handler.
* Therefore the throw-expression and its temporaries are destroyed
before control passes.
* Therefore the temporaries are destroyed before the objects of
automatic storage duration are.
Er. I am reading your argument as:
end-throw-expression < begin-passing-control < destroy-locals < end-passing-control < begin-handler
end-throw-expression < begin-handler
(implicitly) destroy-throw-expression-temporaries < end-throw-expression
therefore
end-throw-expression < begin-passing-control
destroy-throw-expression-temporaries < begin-passing-control
destroy-throw-expression-temporaries < destroy-locals
This is all nicely tautological, but it doesn't seem to argue for anything,
and it certainly doesn't contradict the proposition that, during unwind,
local objects are always destroyed in the reverse of the order in which
they were constructed.
It is also somewhat irrelevant because you cannot have a throw lexically
in the full-expression for an initializer and have that throw evaluated
after the completion of the variable's constructor.
Also, your premises are wrong, because the operand of a
throw-expression is not itself a full-expression, so the destruction of
"its temporaries" does not occur until unwinding begins, i.e. during
the passing of control from the throw-expression to the handler.
We are then clearly controlled by [class.temporary]p3, and [except.ctor]p3
(terminate on throw) applies.
I would also like to put forward the hypothesis that the change
suggested would, in practice, only ever break code, because almost all
code is going to be set up to correctly handle the case where the
temporaries are destroyed before the local variable. Hence I'd like to
understand the motivation for GCC's behavior, in case there are cases
where it is important to destroy the T temporary after the S object is
destroyed.
This is equally true of return values: along the normal path, all the local
variables will be destroyed before the return value is, and yet the unwind
path is necessarily different.
John.