Consensus on goto's into catch blocks
Iain Buclaw
ibuclaw at ubuntu.com
Thu Jun 13 12:16:04 PDT 2013
On Thursday, 13 June 2013 at 17:51:51 UTC, H. S. Teoh wrote:
> On Thu, Jun 13, 2013 at 07:35:39PM +0200, Iain Buclaw wrote:
>> Can someone remind me again what was last agreed when I
>> brought this
>> up?
>>
>> I seem to recall that this should be disallowed as is
>> practically
>> always a bug, also, and it skips any initialisation of the
>> exception
>> object. (See: http://dlang.org/statement.html - "It is illegal
>> for a
>> GotoStatement to be used to skip initializations.")
>>
>> Current failing test I want to have removed from the test
>> suite.
>>
>> test/runnable/eh.d:
>> void test8()
>> {
>> int a;
>> goto L2; // gdc Error: cannot goto into catch block
>>
>> try {
>> a += 2;
>> }
>> catch (Exception e) {
>> a += 3;
>> L2: ;
>> a += 100;
>> }
>> assert(a == 100);
>> }
> [...]
>
> Hmph, how did this test end up in test/runnable? What if after
> L2, we
> try to deference e? I can't see any way this code can even be
> remotely
> valid. How did this end up in the test suite?? (Or is this
> supposed to
> test whether the compiler is able to ascertain that e is not
> referenced
> after L2? Does DMD even do that kind of analysis?)
>
I think the test is for the analysis of the try block. The
frontend says: "Right, this try block will not throw, so all
catches can be removed.", or "This try body is empty, so this
entire try/catch statement can be removed" - However this is
plain wrong in that the backend will require to know the bodies
of all the catches in case they are used in some way.
In GDC's case, the compiler will ICE if it finds a goto to a
label that doesn't exist, whereas DMD will happily accept this as
valid and instead die when you try to run the program (oops!).
So since around pre-2.060 I have always #ifdef'd out this
frontend optimisation. But since then analysis has been improved
somewhat, but still misses this edge case.
void test8()
{
int a;
goto L2; // BOOM!
try { }
catch (Exception e) {
L2: ;
a += 100;
}
assert(a == 100);
}
But I have made alterations to fix that. :-)
Where GDC also differs from DMD is that the glue-layer part of
the front-end also has a rudimentary goto/label analyser that
makes sure that you:
- Can't goto into a try block (though testing just now, the try
block requires a throw statement, so the frontend must wrongly
unravel the try {} statement somehow).
- Can't goto into a catch block
- Can't goto into or out of a finally block.
- Can't have case/default in switches nested inside a try block,
Future improvements will be to also include skipped
initialisations.
{
goto L2;
Object o = new Object;
L2:
writeln (o);
}
This also has the benefit of fleshing out these sorts of bugs in
phobos (there are a few, I've already pre-tested it).
(I'm stalling)
But back to the point, to make this analysis work and be valid,
the front-end must either stop unraveling/removing try/catch
blocks, or improve the way it analyses code before doing this
sort of optimisation. I'm sure Walter would prefer the latter
with patches welcome. :o)
Regards
Iain
More information about the Digitalmars-d
mailing list