A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3434.htm below:

Even simpler defer for direct integration

when the item is inside a

*/ } 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; } }

target

integration into IS ISO/IEC 9899:202y

document history n3434 202412 Original proposal license

CC BY, see https://creativecommons.org/licenses/by/4.0

previous papers on defer

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.

Motivation

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.

Approach

The idea is to simplify the proposed model even further than n3199. The main features of the proposed model are

With 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

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.

Syntax Defer blocks as block items

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

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.

Library implementations

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

Semantics Other control flow

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.

Termination of main and similar top level functions

n3199 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.

Implementation experience

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

compiler magic; some other compiler magic { some code };

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.

gcc: the cleanup attribute and nested functions

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:

#define __DEFER__(F, V)      \
  auto void F(int*);         \
  [[gnu::cleanup(F)]] int V; \
  auto void F(int*)

Here

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: the cleanup attribute and ObjectiveC’s “blocks”

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

^void(void) { some code }

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.

Portability to C++

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

[&](void)->void { some code }

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: a preprocessor approach

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:

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:

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.

Suggested wording.

New text is underlined green, removed text is stroke-out red.

6.4.2 Keywords

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 and true inside expressions that are subject to the # and ## preprocessing operators is unspecified.61)

6.8.1 Statements and blocks, general

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.

6.8.3 Compound statement

In p1, add the syntax derivation defer-block to block-item.

6.8.8 The defer block

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
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 called main, see 3.2.2.3.2) or of a thread (for example started from a call to thrd_create, see 7.30.5.1), are executed according to these rules if the execution of the function is terminated by an explicit return statement.FTN)
FTN) In particular, is is unspecified if defer blocks that are associated to the body of main (or similar) are executed if the corresponding thread is detached with thrd_detach and then terminated with thrd_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:

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
In the model, the possibilities to end the execution of an anchor block are as follows:
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 example exit) or for a thread is called, or because longjmp 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.
{                                   // 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
Forward references: Non-local jumps (7.13), the defer construct <stddefer.h> (7.22), communication with the environment (7.25.5), the thrd_exit function (7.30.5.5).
new 7.22 for integration as a library feature

Add a new clause 7.22 with the following contents:

7.22 The defer construct <stddefer.h>
1 The header <stddefer.h> shall ensure that defer blocks are available to the application and provides the macro defer 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.
A new jump construct _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.

keywords

add _Leave to the keywords

Add a new clause

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.

RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4