A funclet EH pad may be exited by an unwind edge, which may be a
cleanupret exiting its cleanuppad, an invoke exiting a funclet, or an
unwind out of a nested funclet transitively exiting its parent. Funclet
EH personalities require all such exceptional exits from a given funclet to
have the same unwind destination, and EH preparation / state numbering /
table generation implicitly depends on this. Formalize it as a rule of
the IR in the LangRef and verifier.
Details
Diff Detail
Event Timeline
Is there any way to get back the tests we lost in test/CodeGen/WinEH/wineh-no-demotion.ll ? Those tests are nice because they stress instances where we might add another edge to a funclet (those tests show this by cloning an invoke).
docs/ExceptionHandling.rst | ||
---|---|---|
837 | Making sure I understand this, you are saying that a catchswitch can say it unwinds to caller but it must, at runtime, handle all exceptions that can actually occur in order to produce defined behavior. Is that right? I can understand why we would want to allow call instructions with no declared unwind destination, but I'm not sure I see why we wouldn't require the unwind destination of a catchswitch to match its parent's destination. Is it to avoid having the catchswitch block appear to be a predecessor of a block that it can never reach? It seems to me that it would be better to add a nounwind variant of the catchswitch. |
Yes, looks like the tests can stay if I just remove the funclet bundles from the to-be-cloned invokes, so I've updated to do that.
docs/ExceptionHandling.rst | ||
---|---|---|
837 | Yes, you're understanding correctly. When we have catchswitch A unwinding to pad B and we discover that pad B is immediately unreachable, to me it makes more sense to allow stomping out the edge and leaving catchswitch A as "unwinds to caller" like we do than it does to require that code to snoop around and see if catchswitch A has a parent pad and if an unwind edge which leaves the parent can be found and redirect catchswitch A to that edge's successor for consistency -- in addition to requiring a not-rocket-science but nonetheless nontrivial search for the parent's unwind successor, it also requires suddenly giving that successor a new predecessor and doing who-knows-what updates to maintain SSA etc in the face of that. I absolutely agree that it would be nicer to have a nounwind variant of catchswitch, not just for this but also to be able to express catch-all over funclet EH in a way that the CFG reflects naturally. I think it's a nontrivial undertaking (though easier now that we have parent tokens and funclet bundles than it would have been before), and not the top of my priority list. Happy to review patches, though :). |
docs/ExceptionHandling.rst | ||
---|---|---|
837 | OK. That's a reasonable explanation. Another nice-to-have would be some pass that would insert a cleanup pad with a trap instruction in this situation for debugging/testing purposes. | |
lib/IR/Verifier.cpp | ||
3117 | I haven't taken the time to think through it yet but you may know, is it possible to skip over FPI and/or UnwindParent below while walking the pad-parent chain? I think I could make some IR that would do that for just this function. I just don't know if it would be flagged as invalid somewhere else. |
lib/IR/Verifier.cpp | ||
---|---|---|
3117 | I did give it some thought, and yes my goal was that any such cases would be quiet here but would get flagged in visitEHPadPredecessors when looking at the same unwind edge from its successor. |
Making sure I understand this, you are saying that a catchswitch can say it unwinds to caller but it must, at runtime, handle all exceptions that can actually occur in order to produce defined behavior. Is that right?
I can understand why we would want to allow call instructions with no declared unwind destination, but I'm not sure I see why we wouldn't require the unwind destination of a catchswitch to match its parent's destination. Is it to avoid having the catchswitch block appear to be a predecessor of a block that it can never reach?
It seems to me that it would be better to add a nounwind variant of the catchswitch.