*/ } ul /* Whole unordered list */ { } ul li /* Unordered list item */ { } ol /* Whole ordered list */ { } ol li /* Ordered list item */ { } hr {} /* ---- Some span elements --- */ sub /* Subscripts. Pandoc: H~2~O */ { } sup /* Superscripts. Pandoc: The 2^nd^ try. */ { } em /* Emphasis. Markdown: *emphasis* or _emphasis_ */ { } em > em /* Emphasis within emphasis: *This is all *emphasized* except that* */ { font-style: normal; } blockquote > p > em /* Emphasis within emphasis: *This is all *emphasized* except that* */ { font-style: normal; } blockquote > * > p > em /* Emphasis within emphasis: *This is all *emphasized* except that* */ { font-style: normal; } blockquote > p > ins > em /* Emphasis within emphasis: *This is all *emphasized* except that* */ { font-style: normal; } blockquote > * > p > ins > em /* Emphasis within emphasis: *This is all *emphasized* except that* */ { font-style: normal; } /* ---- Links (anchors) ---- */ a /* All links */ { /* Keep links clean. On screen, they are colored; in print, they do nothing anyway. */ text-decoration: none; } @media screen { a:hover { /* On hover, we indicate a bit more that it is a link. */ text-decoration: underline; } } @media print { a { /* In print, a colored link is useless, so un-style it. */ color: black; background: transparent; } a[href^="http://"]:after, a[href^="https://"]:after { /* However, links that go somewhere else, might be useful to the reader, so for http and https links, print the URL after what was the link text in parens */ content: " (" attr(href) ") "; font-size: 90%; } } /* ---- Images ---- */ img { /* Let it be inline left/right where it wants to be, but verticality make it in the middle to look nicer, but opinions differ, and if in a multi-line paragraph, it might not be so great. */ vertical-align: middle; } div.figure /* Pandoc figure-style image */ { /* Center the image and caption */ margin-left: auto; margin-right: auto; text-align: center; font-style: italic; } p.caption /* Pandoc figure-style caption within div.figure */ { /* Inherits div.figure props by default */ } /* ---- Code blocks and spans ---- */ pre, code { background-color: #fdf7ee; /* BEGIN word wrap */ /* Need all the following to word wrap instead of scroll box */ /* This will override the overflow:auto if present */ white-space: pre-wrap; /* css-3 */ white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */ white-space: -pre-wrap; /* Opera 4-6 */ white-space: -o-pre-wrap; /* Opera 7 */ word-wrap: break-word; /* Internet Explorer 5.5+ */ /* END word wrap */ } pre /* Code blocks */ { /* Distinguish pre blocks from other text by more than the font with a background tint. */ padding: 0.5em; /* Since we have a background color */ border-radius: 5px; /* Softens it */ /* Give it a some definition */ border: 1px solid #aaa; /* Set it off left and right, seems to look a bit nicer when we have a background */ margin-left: 0.5em; margin-right: 0.5em; } pre.yacc, code.yacc { background-color: #f0f0f0; } pre.yacc /* Code blocks */ { /* Distinguish pre blocks from other text by more than the font with a background tint. */ padding: 0.0em; /* Since we have a background color */ border-radius: 5px; /* Softens it */ /* Give it a some definition */ border: 0px solid #aaa; /* Set it off left and right, seems to look a bit nicer when we have a background */ margin-left: 0.0em; margin-right: 0.0em; } @media screen { pre { white-space: pre; /* Dotted looks better on screen and solid seems to print better. */ border: 1px dotted #777; } } code /* All inline code spans */ { } p > code, li > code /* Code spans in paragraphs and tight lists */ { /* Pad a little from adjacent text */ padding-left: 2px; padding-right: 2px; } li > p code /* Code span in a loose list */ { /* We have room for some more background color above and below */ padding: 2px; } span.option { color: blue; text-decoration: underline; } /* ---- Math ---- */ span.math /* Pandoc inline math default and --jsmath inline math */ { /* Tried font-style:italic here, and it messed up MathJax rendering in some browsers. Maybe don't mess with at all. */ } div.math /* Pandoc --jsmath display math */ { } span.LaTeX /* Pandoc --latexmathml math */ { } eq /* Pandoc --gladtex math */ { } /* ---- Tables ---- */ /* A clean textbook-like style with horizontal lines above and below and under the header. Rows highlight on hover to help scanning the table on screen. */ table { border-collapse: collapse; border-spacing: 0; /* IE 6 */ border-bottom: 2pt solid #000; border-top: 2pt solid #000; /* The caption on top will not have a bottom-border */ /* Center */ margin-left: auto; margin-right: auto; } thead /* Entire table header */ { border-bottom: 1pt solid #000; background-color: #eee; /* Does this BG print well? */ } tr.header /* Each header row */ { } tbody /* Entire table body */ { } /* Table body rows */ tr { } tr.odd:hover, tr.even:hover /* Use .odd and .even classes to avoid styling rows in other tables */ { background-color: #eee; } /* Odd and even rows */ tr.odd {} tr.even {} td, th /* Table cells and table header cells */ { vertical-align: top; /* Word */ vertical-align: baseline; /* Others */ padding-left: 0.5em; padding-right: 0.5em; padding-top: 0.2em; padding-bottom: 0.2em; } /* Removes padding on left and right of table for a tight look. Good if thead has no background color*/ /* tr td:last-child, tr th:last-child { padding-right: 0; } tr td:first-child, tr th:first-child { padding-left: 0; } */ th /* Table header cells */ { font-weight: bold; } tfoot /* Table footer (what appears here if caption is on top?) */ { } caption /* This is for a table caption tag, not the p.caption Pandoc uses in a div.figure */ { caption-side: top; border: none; font-size: 0.9em; font-style: italic; text-align: center; margin-bottom: 0.3em; /* Good for when on top */ padding-bottom: 0.2em; } /* ---- Definition lists ---- */ dl /* The whole list */ { border-top: 2pt solid black; padding-top: 0.5em; border-bottom: 2pt solid black; } dt /* Definition term */ { font-weight: bold; } dd+dt /* 2nd or greater term in the list */ { border-top: 1pt solid black; padding-top: 0.5em; } dd /* A definition */ { margin-bottom: 0.5em; } dd+dd /* 2nd or greater definition of a term */ { border-top: 1px solid black; /* To separate multiple definitions */ } /* ---- Footnotes ---- */ a.footnote, a.footnoteRef { /* Pandoc, MultiMarkdown footnote links */ font-size: small; vertical-align: text-top; } a[href^="#fnref"], a.reversefootnote /* Pandoc, MultiMarkdown, ?? footnote back links */ { } @media print { a[href^="#fnref"], a.reversefootnote /* Pandoc, MultiMarkdown */ { /* Don't display these at all in print since the arrow is only something to click on */ display: none; } } div.footnotes /* Pandoc footnotes div at end of the document */ { } div.footnotes li[id^="fn"] /* A footnote item within that div */ { } table tr td,th { border-right: 1px solid; border-left: 1px solid; } /* You can class stuff as "noprint" to not print. Useful since you can't set this media conditional inside an HTML element's style attribute (I think), and you don't want to make another stylesheet that imports this one and adds a class just to do this. */ @media print { .noprint { display:none; } }
2024-12-23
integration into IS ISO/IEC 9899:202y
document number | date | comment |
---|---|---|
n3434 | 202412 | Original proposal |
CC BY, see https://creativecommons.org/licenses/by/4.0
There have been several previous papers on defer features. This paper builds on n3199 and simplifies the approach presented there even more. For motivations of the different choices and for a general introduction please refer to that paper.
References to other works and online information are given throughout as links.
Paper n3199
proposes a design of a defer
feature that
would be close to the existing practice of gcc’s [[gnu::cleanup(…)]]
attribute. While the idea of providing this feature in a TS had even
more traction than to integrate it directly into C2y, there was still
possible consensus to bring it already forward for that milestone.
This paper tries to promote a even simpler version of the feature that has straight-forward and efficient implementations in existing compilers and that avoids the introduction of any ambiguities or even new UB when a compound statement with defer is terminated unexpectedly.
The idea is to simplify the proposed model even further than n3199. The main features of the proposed model are
defer
(called the
anchor block) by existing jump statements, goto
, return
, break
and continue
, and by
falling off at the final }
.defer
blocks in
lexicographic ordering within the same anchor blockdefer
is
terminated by other means than jump statements or fall off.defer
can
only appear as block item in a compound statementWith these restrictions it is then possible to implement the feature efficiently, with the full feature set, with most of the diagnostics and without bending existing keywords
[[gnu::cleanup(...)]]
with some restrictions concerning the accessible local variables
with full access to local variables, but some additional syntactic restrictions in any conforming C compiler when replacing the preprocessor with eĿlipsis.
The first difference of this paper compared to n3199
is to neither have a defer block as a declaration nor as a statement but
as a new type of block item within a compound statement, the
anchor block. Thereby the association of the defer
to the anchor
block follows directly from the syntax; defer blocks are then excluded
from other positions where declarations or statements may appear simply
by the syntax.
So the possible position of a defer block is then different from
for
loopsif
and
switch
statements (voted into C2y)This also helps to clarify the semantics: there is a uniquely identified compound statement for which the termination triggers the execution of the deferred block.
In addition this approach makes implementation of the feature easier. A defer block, because it is known to be a block item of a specific compound statement, may be replaced by an implementation by a mix of declaration, statements and labels. Restricting the deferred block as well to a compound statement followed by a semicolon ensures that implementations may freely choose to provide this feature through a hidden variable with an initializer.
Although the feature itself is specified as language feature, we also
want to enable implementations to just use their existing infrastructure
by providing short wrapper macros, much as it is already done for offsetof
or setjmp
, for example.
Therefore we introduce a new header, <stddefer.h>
,
that must be present for portability reasons and that could be used by
implementations to provide wrappers as will be described below. But we
leave it unspecified if an implementation may provide the feature
without the header, and effectively if the header must contain anything
beyond a trivial macro definition
The major semantic change to previous proposals is to leave it
explicitly unspecified if unexpected termination of the anchor block (by
say, exit
, longjmp
or a signal) executes deferred
blocks or not. Similarly, it leaves it unspecified if and which defer
blocks are executed if goto
or longjmp
are used to execute the anchor block
other than lexicographically.
This eases argumentation about the feature a lot: no new UB is
introduced into the standard. For each defer block there is only one of
two behaviors that is possible: the deferred block is executed or not.
In general the worst that can happen in such situations is that some
resources are not handled properly. This also isn’t new, that is
basically the current situation if a longjmp
jumps beyond the end of the scope of
a VLA.
main
and similar top level functionsn3199
already identified a case, where adding defer blocks needed special
care, namely the main
function. Here
the current specification has it that a return
statement and
a call to exit
are equivalent. With
defer
, special
care has to be taken if that means that return
also executes
the deferred blocks or not in addition to what happens when calling
exit
.
In fact, a similar special case occurs for the top level function of
each thread; it has to be clarified if return
from that
function executes all deferred blocks that have been met. For both cases
(program termination and thread termination) we specify that in case of
a return
all
deferred blocks are executed according to the model, and that it is
unspecified if calling exit
or thrd_exit
has an influence if these are then
executed as well. We also add a specific footnote for the case the main
thread is terminated with
thrd_exit
, a case that is different
from return
and from exit
for that function.
For three of the five implementations (if we count C++ as an
implementation) that have features that come close to what is proposed
here we show how defer
can be
implemented as an object-like macro such that code that looks like
expands to a sequence similar to
that has the required behavior. That is,
is skipped when met during execution, and then only executed later, when the current compound statement is left.
One implementation (in a dedicated preprocessor) reduces the problem
of implementing defer
to a
generation of unique labels and of structured goto
statements that
have the same effect as the defer feature.
Last but not least, VS’s __try
/__finally
is
unfortunately syntactically too different that we would be able to mask
the difference behind a macro; nevertheless the feature that is provided
is semantically very close. Nevertheless it has an interesting secondary
feature __leave
that could also be
integrated into C.
With gcc, an implementation of the described defer feature is possible with compiler versions of at least two decades that provide nested functions and the cleanup attribute as extensions. Written with C23’s attribute feature the inner macro looks as simple as the following:
Here
auto void F(int*);
forward-declares a nested (local) function F
.[[gnu::cleanup(F)]] int V;
establishes this function as a cleanup handler of an auxiliary variable
V
auto void F(int*)
then starts the definition of the local function which is completed with
the user’s compound statement as the function body.For this to work we have to provide unique names F
and V
such that several defer blocks may appear within the same anchor block.
This is ensured by another very common extension __COUNTER__
#define defer __DEFER(__COUNTER__)
#define __DEFER(N) __DEFER_(N)
#define __DEFER_(N) __DEFER__(__DEFER_FUNCTION_ ## N, __DEFER_VARIABLE_ ## N)
That is basically it, a straight application of the [[gnu::cleanup]]
feature that
Indeed, when adding a bit more magic (such as [[gnu::always_inline]]
)
the assembly that is produced is very efficient and avoids function
calls, trampolines and indirections. (See also Omar
Anson’s blog entry on how efficient the cleanup attribute seems to
be implemented in gcc.)
Note that in this implementation of the defer feature the chosen
construct is that of a function definition. Therefore the fact that the
defer
syntax
requires a compound statement for the deferred block is important: it
becomes the function body of a nested function.
Note also, that the implementation as presented above does not
provide all diagnostics that would be recommended by the wording as
proposed. In particular, the gnu compilers do not diagnose jumps that
would jump over declarations with the [[gnu::cleanup]]
attribute. Nevertheless, a similar effect can already be easily be
achieved by some addition to the presented macros, in particular by
using an auxiliary variable of VM type; this is then diagnosed by the
compiler if e.g a goto
jumps over it.
This shows that there is probably already enough infrastructure present
in the compiler that would allow to detect jumps over [[gnu::cleanup]]
.
It would perhaps be good if the gnu compilers could add such a
diagnostic in the future.
Clang does not implement gcc’s nested functions and probably never
will. In contrast to that, it implements so-called blocks from
ObjectiveC. Here our strategy to implement defer
is then a bit
different, since “blocks” are expressions that can be assigned to
variables with special type. We use a typedef
called __df_t
as the type of an auxiliary variable
and a static
function __df_cb
that just executes
the stored block at the termination of the scope.
// We need the "blocks" extension
typedef void (^const __df_t)(void);
[[maybe_unused]]
static inline
void __df_cb(__df_t* __fp) {
(*__fp)();
}
#define __DEFER__(V) [[gnu::cleanup(__df_cb))]] __df_t V = ^void(void)
The wrapper that provides the unique name is then similar to the
above, clang also has the __COUNTER__
extension:
#define defer __DEFER(__COUNTER__)
#define __DEFER(N) __DEFER_(N)
#define __DEFER_(N) __DEFER__(__DEFER_VARIABLE_ ## N)
Unfortunately a block such as
has not the same properties as a nested function: in general access
to outside variables is restrict to be read-only and provides the value
of the variable at the point where the defer
is met, not
when it is executed. To be conforming with this proposal, clang would
need to make some progress, here.
Note that in this implementation of the defer feature the chosen
construct is that of a variable with an initializer. Therefore the ;
that terminates
the defer
syntax is important.
Because the execution model for defer
is very
similar to the execution model for destructors in C++, implementing the
defer feature with the properties as proposed in C++ is a student
excercise. It can be done with a template
class and lambdas.
template<typename T>
struct __df_st : T {
[[gnu::always_inline]]
inline
__df_st(T g) : T(g) {
// empty
}
[[gnu::always_inline]]
inline
~__df_st() {
T::operator()();
}
};
#define __DEFER__(V) __df_st const V = [&](void)->void
Similar to the above implementation with ObjectiveC’s blocks, lambdas
are not declarations but expressions. These expressions have a unique
type for each lambda, which is taken here as a template parameter to the
constructor __df_st<T>::__df_st(T)
.
The destructor __df_st<T>::~__df_st()
of the variable then invokes the lambda when V
leaves its scope. But in contrast to the
version with ObjectiveC’s blocks, the [&]
in
ensures that all outer variables are fully accessible at the point of execution of the lambda. Therefore, such an implementation provides the full functionality.
Note also, that the __COUNTER__
pseudo-macro is also quite commonly implemented by C++ compilers and is
proposed as an addition to
C++26.
eĿlipsis is an enhanced preprocessor that can be used as a drop-in replacement for the compilation phases 1-4. It is tested currently for gcc and clang.
One of the enhancements of eĿlipsis is that it can be used to
instrument bracket constructs such as {}
to count
nestedness and in general to use counters to monitor progress in the
source code. This allows to implement infrastructure for defer
that is
otherwise only dependent of standard C features such as labels, goto
and the setting
of some auxiliary variables.
Being a “preprocessor-only”
implementation of defer
, this
approach has more restrictions than the others that have been presented
above:
return
, break
and continue
could go
wrong when identifying the latest deferred block to jump to. Therefore
some special versions for these statements are provided.goto
can jump to arbitrary positions in the function, so this is not tracked
properly.void
functions has
to be added.These restrictions could be easily removed when implementing a similar strategy in a compiler frontend.
Although the code after replacement is a braid of labels and goto
, inspecting the
generated assembly shows that modern C compilers such as gcc and clang
handle such code well.
__try
and __finally
The VS compilers have another interesting
extension using two successive compound statements, the first
(called “guarded section”) labeled with __try
the second
(called “termination handler”) with __finally
. The
semantics are similar to what is described here, namely the guarded
section would be our anchor block and the termination handler would be
our deferred block. Besides the syntax, there are several differences,
though, that make this extension more difficult to use and more
difficult to standardize:
__try
/__finally
blocks.
This makes the specification of cleanup code in an anchor with several
resources tedious.In addition to the features for defer
that we
specify here, the VS extension is also able to do stack unwinding that
is similar to exception handling in C++. Nevertheless, the strategies
that are applied for __try
/__finally
are meant
to be compatible with the semantics that we propose here, because it is
unspecified if deferred blocks are executed whence an anchor is
terminated by other constructs than by a normal jump.
So with this new feature integrated into C2y, VS compilers would have to work at their frontend, but they should already have most of the infrastructure in place such that later compiler phases should be able to integrate this feature efficiently.
The VS extension offers one other feature, though, that could be
interesting to integrate into the standard at the same time as the defer
feature, namely a __leave
jump
statement. This statement is meant to terminated the innermost guarded
section that contains it such that the execution of the termination
handler then follows immediately. Below we propose an option for a _Leave
statement
that has similar properties.
New text is underlined green, removed text is
stroke-out red.
Add defer
and _Leave
to
the list of keywords and modify p2, last sentence
The spelling of these keywords, their alternate forms, and of
defer
,false
andtrue
inside expressions that are subject to the#
and##
preprocessing operators is unspecified.61)
Modify the beginning of p3:
3 A block is either a primary block, a secondary block, the block associated with a function definition or a defer block; it allows a set of declarations and statements to be grouped into one syntactic unit.
In p1, add the syntax derivation defer-block to block-item.
Add a new clause 6.8.8 with the following contents:
6.8.8 The defer block
Syntax
defer-block:
defer
deferred-block;
deferred-block:
compound-statement
Description
2 Through the syntax each defer block is uniquely associated to a enclosing compound statement (called its anchor block) for which it is an block item of the corresponding block item list; an anchor block may have multiple defer blocks (and thus deferred blocks) that are associated to it. The purpose of a defer block is to defer the execution of the deferred block to the end of the execution of the anchor block; this not withstanding the defer block has the lexical properties induced by its lexical position.
Semantics
3 A deferred block is not executed when the execution of the anchor
block meets a defer block; whenever the execution of an instance of the
anchor block ends by a jump statement or because the closing }
is met, all its
deferred blocks up to the last that has been been met during its
execution (before a jump) are executed in the reverse lexicographical
order in which they have been specified. It is unspecified if and when
deferred blocks are executed
- if the execution of the anchor block ends otherwise, e.g by a call to
exit
orlongjmp
,- if a defer block is met more than once during the same execution of the anchor block, or
- if control flow skips over a defer block.
4 As an exception of the provisions in 5.2.2.3.4 and 7.30.5.5 deferred blocks of the top level function of the execution (usually calledmain
, see 3.2.2.3.2) or of a thread (for example started from a call tothrd_create
, see 7.30.5.1), are executed according to these rules if the execution of the function is terminated by an explicitreturn
statement.FTN)
FTN) In particular, is is unspecified if defer blocks that are associated to the body ofmain
(or similar) are executed if the corresponding thread is detached withthrd_detach
and then terminated withthrd_exit
.
5 It is unspecified if defer blocks are available to the application if
the <stddefer.h>
header (7.22) is not included prior to the first use of the construct.
Recommended practice
6 It is recommended that implementations diagnose the following:
- A deferred block that encloses a label that is a target of a
switch
orgoto
statement that is not enclosed in the deferred block.- A deferred block that encloses a jump statement that jumps to a target that is not enclosed in the deferred block.
- A block item list that contains three block items A … B … C, lexicographically ordered as given or in reverse order C … B … A, where B is a defer block and where A is or encloses a jump statement to or into C.
- An anchor block that encloses a label following its lexicographically first defer block which is a target of a
switch
orgoto
statement that is not enclosed in the anchor block.
7 NOTE 1 This clause only specifies a model of execution where defer blocks of an anchor block are met contiguously in lexicographic order until its execution ends; otherwise it is unspecified if the deferred block of a defer block
- that has been met is executed, or
- that has not been met is executed regardless.
In the model, the possibilities to end the execution of an anchor block are as follows:
- The final
}
of the anchor block is met.- A
_Leave
statement is met.- A
return
statement is met.- A
continue
orbreak
statement is met that is associated to a loop orswitch
statement that encloses the anchor block.- A
goto
statement is met for which the target label is not enclosed in the anchor block.
If the execution ends by a jump statement all deferred blocks of all anchor blocks of the function for which execution has started and is ended by the jump statement are executed in reverse lexicographical order.
8 NOTE 2 If the execution of an anchor block ends because one of the termination functions for the whole execution (for exampleexit
) or for a thread is called, or becauselongjmp
is used to transfer execution to a point outside the anchor, it is unspecified if deferred blocks that had been met are executed. Thus, in such a case the corresponding resource cleanup may be missed and ressources such as allocated memory may leak.
9 NOTE 3 By the syntax, the placement of defer blocks is more restricted than for statements.
- It only appears as one of the elements that are directly associated to a compound statement, its anchor block.
- The deferred block only admits a compound statement and no label between the
defer
keyword and the compound statement.
{ // anchor block
...
defer doit(); // syntax error, not a compound statement
if (something) defer { // syntax error, no direct anchor for defer
doit();
};
if (something) { // anchor block
defer { // valid, but defer is useless
doit();
};
}
defer { // valid, evaluation of condition is deferred
if (something) doit();
};
defer BLA: { // syntax error, label not permitted
if (something) doit();
};
defer {
if (something) BLU: doit(); // valid, label only useful in the deferred block
};
}
In particular, the syntax inhibits that a defer block is a secondary block of a selection statement or iteration statement, whereas a deferred block can contain such a statement.
10 EXAMPLE Consider the following anchor block
{ // anchor block
void* p = malloc(25);
defer { free(p); }; // 1st defer
mtx_lock(&mut);
defer { mtx_unlock(&mut); }; // 2nd defer
static uint64_t critical = 0;
critical++;
defer { critical--; }; // 3rd defer
while (something) cnd_wait(&cond, &mut);
... use p under protection of mut ...
}
It is equivalent to this code without defer
,
{
void* p = malloc(25);
mtx_lock(&mut);
static uint64_t critical = 0;
critical++;
while (something) cnd_wait(&cond, &mut);
... use p under protection of mut ...
{ critical--; } // from 3rd defer
{ mtx_unlock(&mut); } // from 2nd defer
{ free(p); } // from 1st defer
}
only that the deferred blocks are even executed when the anchor block is
left by a jump statement. Thus using defer
here ensures
that
p
,something
andcritical
are only used under the protection of the mutexmut
,critical
then holds the number of threads that are currently within that anchor blockmut
never remains locked whenever the anchor block is left,*p
is deallocated whenever the anchor block is left.
Forward references: Non-local jumps (7.13), the defer construct<stddefer.h>
(7.22), communication with the environment (7.25.5), thethrd_exit
function (7.30.5.5).
Add a new clause 7.22 with the following contents:
7.22 Thedefer
construct<stddefer.h>
1 The header<stddefer.h>
shall ensure that defer blocks are available to the application and provides the macrodefer
which expands to an implementation-defined value with the same functionality as the corresponding keyword.
Recommended practice
2 As specified in 6.8.8, implementations may or may not provide facilities that enable defer blocks through this header. For portability reasons it is recommended that applications that use the defer construct include this header unconditionally.
_Leave
As mentionned above, the _Leave
keyword comes
from the VS compiler and the __try
/__finally
clauses.
There it can be used to terminate the __try
clause by
jumping directly to the __finally
clause.
This construct is not implemented by the other four implementations,
yet. But if WG14 thinks that this could be a helpful addition, the point
in time would be to add it now and not to wait for yet another round of
standardization.
If WG14 finds it usefull the following text should be added to C2y;
if not any mention of _Leave
in the above
wording should be omitted.
add _Leave
to the
keywords
In 6.8.7.1 (Jump statements, General) p1, add the syntax derivation
_Leave
;
to jump-statement.
Add a new clause
6.8.7.6 The _Leave
statement
Constraints
1 A _Leave
statement shall be enclosed in a compound statement with an associated
defer block (6.8.8).
Semantics
2 A _Leave
statement terminates the execution of the innermost enclosing compound
statement with an associated defer block. All deferred blocks of defer
blocks that are associated with that compound statement and that have
been met during that execution are executed as specified in clause
6.8.8.