[cfe-dev] [LLVMdev] [LLVMDev] Object in a try-catch block not being destroyed even after an exception

Richard Smith richard at metafoo.co.uk
Tue Jun 19 18:25:42 PDT 2012


On Tue, Jun 19, 2012 at 4:48 PM, John McCall <rjmccall at apple.com> wrote:
> On Jun 19, 2012, at 3:27 PM, Richard Smith wrote:
>> 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)). Also, even if we were to imagine
they have automatic storage duration, then the GCC optimizations which
reuse their storage after their lifetime ends are non-conforming,
because "the storage for these entities lasts until the block in which
they are created exits" (3.7.3/1). I don't think anyone wants that.

> 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.

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.



More information about the cfe-dev mailing list