It is non portable, that's true. But defer [1] is at least undergoing discussions w/the standard committee. Didn't make it into C23 but maybe next time.
That's not very practical if you have several operations to perform, you'd have to create a specialized function each time. So no, that extension is not an alternative to designing a new flow control feature. (And it is not new, other languages have it already.)
>I also have some ideas how to make this defer implementation work with break and continue, but that is unfortunately a bit more nasty.
This is the kind of things better done in the compiler, I implemented the n3199 variant of defer[1], along with [[gnu::cleanup]], in a small C compiler with about 200 LOC by extending the VLA de-allocation algorithm, the process is archived at [2].
Thanks for the pointer! Definitively, on the long run these things should go into compilers directly, yes.
BTW, the break continue stuff now works in the development branch.
I notice that in that implementation there is an addition to the compiler state with indirections, whereas in ellipsis all is done with just three local variables; two per-function for knowing if we have to unwind completely and for the return value, and one per loop construct to know if we have to unwind there. All the rest is static information about nestedness and lexicographic ordering of code that can be deduced very early (here in the preprocessor). The result of all of this is a very organized braid of gotos, that in general are mostly optimized out.
I love the idea of having a defer statement in general for C, but given the complexity of C scopes it's a little hard to wrangle (switch statements in particular break a lot of assumptions about how scopes should work).
I would prefer a directly scoped syntax similar for a for statement, something like
defer (void * p = malloc(17); free(p)) {
...
}
This gets more cumbersome as you have more such scopes in a function, but it gives a sane bounding. You can sort of do this now with a properly constructed for loop so that it cleans up on regular exit from the loop, but it can't handle exception exits (returns, breaks, and god forbid goto or longjmp).
This would be much more restrictive that what is proposed, because usually you would add `defer` statements as you go in a block, when you allocate more resources for example.
Also usually you should be able to have several actions,
defer {
one;
two;
}
And the bounding in the proposed feature is sane, I think, it is the surrounding compound statement (AKA `{ ... }` block).
You can implement an acceptable defer with the standard preprocessor and some switch abuse.
The only annoying part is needing to use "defer_return" and such instead of the proper keywords.
Unlike most defer implementations for C this doesn't need a function-scope fixed sized block, it's all properly scoped, the switch effectively models a state machine. Similar tricks can be used to implement yield and such.
https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attribute...