4339 – Struct destructor + invariant + struct parameter = horrific error message

D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 4339 - Struct destructor + invariant + struct parameter = horrific error message
Summary: Struct destructor + invariant + struct parameter = horrific error message
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: Other Windows
: P2 critical
Assignee: No Owner
URL:
Keywords: ice-on-valid-code, patch
Depends on:
Blocks:
Reported: 2010年06月17日 00:54 UTC by Don
Modified: 2010年06月28日 14:30 UTC (History)
1 user (show)

See Also:


Attachments
Add an attachment (proposed patch, testcase, etc.)

Note You need to log in before you can comment on or make changes to this issue.
Description Don 2010年06月17日 00:54:17 UTC
I've split this off from the comment in bug 3273, since it has a slightly different cause, since bug 3273 is a regression and this bug is not.
This code fails on 2.022 with "cannot goto forward into different
try block level". No line number, and the code has no goto or try statements. 
So I'm marking this as an ICE. Actually an ICE would be less misleading.
This code has never worked. (Though it compiles with -release).
struct A {
 invariant() { }
 ~this() { }
 void opAssign(A a) {} // workaround for bug 3273
 int blah(A a) { return 0; } // This triggers the error
}
---
Preliminary analysis
---
The generated code for blah() is as follows:
==========
int blah(A a){
try
{
assert(&this,"null this");
__result = 0;
goto __returnLabel;
__returnLabel:
assert(&this); // becomes this.invariant();
return __result;
}
finally
{
a.~this();
}
}
=============
The error message is generated in s2ir.c. All comments below relate to this file.
It generates an error when lblock->Btry != blx->tryblock.
It's failing because lblock->Btry is NULL.
Normally block->Btry is set from blx->tryblock.
labelToBlock(), around s2ir.c(104) has:
 if (!s->lblock)
 { s->lblock = block_calloc(blx);
 if (s->isReturnLabel)
 s->lblock->Btry = NULL; // Why???
Why is it setting it to null? Is it to indicate that we are NOT
guessing the try block? This line needs a comment.
If so, we can fix with this bug with a patch to LabelStatement::toIR()
around line 875:
 if (lblock)
 {
 // We had made a guess about which tryblock the label is in.
 // Error if we guessed wrong.
 // BUG: should fix this
+ if (!lblock->Btry) // We didn't make a guess
+ lblock->Btry = blx->tryblock;
 if (lblock->Btry != blx->tryblock)
 error("cannot goto forward into different try block level");
Comment 1 Walter Bright 2010年06月28日 12:23:57 UTC
The isReturnLabel code is very old. It sets the Btry to NULL to indicate it is outside of any try block. The problem is that years later, the RAII for parameters was added that winds up wrapping the whole function shebang inside a try-finally in order to run the destructors for the parameters in the finally.
Hence, now the return label actually is inside a try block.
The fix should be to set it to NULL only if there aren't parameters that need destruction.
Comment 2 Walter Bright 2010年06月28日 14:30:52 UTC
Better yet, rewrite it to handle forward references correctly.
http://www.dsource.org/projects/dmd/changeset/567 


AltStyle によって変換されたページ (->オリジナル) /