Alex McCarthy and me have put our heads together and come up with something
that works. This still needs some cleanup, and has broken tests (in the compiler
based "consumed" and "reachable code" analysis, as mentioned in other threads).
We would like to get some feedback on the architecture, and whether the changes
the the CFG make sense or are expected to make problems in corner cases.
The gist of the change is a change to how the CFG is created:
For every temporary, add a new block that runs the dtor, and a decision
block that has the CXXBindTemporaryExpr as terminator. That way, we have one
entry and exit block for each temporary cleanup, and as long as they're chained
in the right order, it'll work.
This is of course suboptimal in multiple ways:
- often we know when one destructor has executed that we must also execute the dtor of things that were generated previously; this makes the code and the CFG significantly more complex, though; the biggest downside seems to be that we potentially generate more states; not sure whether it's worth it
- often we do not actually need a new block (for example, if the temporary is created unconditionally); in that case, we could just run with a single block; again this would make the code more complex though, and I'm not sure it's worth the effort, unless we feel it's an important invariant on the CFG
Now that I think about it, this name is wrong. It's really "HandleCleanupTemporaryBranch" or something. The CXXBindTemporaryExpr just tells you which temporary it is. (And similar for similarly-named functions.)