The _Context
keyword can be used to bind the entire
local state of the following scope block or declaration to struct
fields, this shall be refered to as a context scope. This is done by
turning all local declarations into aliases to a field in a struct, see
semantics for what that means. In addition to this, a
_Continuation
keyword is defined, labels can now be
referenced using &&
, and the result has the
_Label
type, and it is possible to jump to those using a
computed goto*
.
The folowing shows how this can be used for a simple generator which returns numbers.
int mycounter(struct state*const state);
struct mycounter {
int variable;
_Continuation typeof(mycounter)* next;
};
int mycounter(struct state*const state) _Context(state) {
int variable = 1;
while(true){
variable += 1;
state->next = &&next;
return variable; next:;
}
}
int main(){
struct mycounter counter_state = {.next=mycounter;};
printf("%d\n", counter_state.next(&counter_state)); // 1
printf("%d\n", counter_state.next(&counter_state)); // 2
printf("%d\n", counter_state.next(&counter_state)); // 3
}
Any scope inside a context scope is a context scope too.
The exact type of a referenced label is implementation defined, but
it is to be available only inside functions and usable using the
_Label
keyword, which can be used to refer to that type,
and the type may depend on the function type. A label reference can be
jumped to using goto*
. It bahaves exactly like a goto to
the label directly. A label reference can be stored in a variable with
_Label
type. A label reference can be implicitly converted
into the _Continuation
function type of the enclosing
function if the function block has context scope. The
_Continuation
keyword is a function-specifier. It can be
called like a regular function, but it can not be jumped to using goto.
When a _Continuation
function is called, and it refers to a
function label, the function is called normally, except that it starts
at that label. A function pointer can also be implicitly converted into
a compatible _Continuation
function type, but not the other
way around. If the resulting _Continuation
function pointer
is called, it behaves no different from a regular function call.
A context scope may have one or more pointers to structs associated
with it, which shall be refered to as context objects. These are
provided using an assignment-expression of the _Context
specifier. Those assignment-expression are always reevaluated when the
associated context scope is entered, even if this happens by calling
goto, or by calling a function or a _Continuation
(This
does not include other scopes or context scopes contained within that
scope). The assignment expression is never reevaluated inside of the
context scope. If any context object pointer is invalid or null, the
bahaviour is undefined.
Local variables with automatic storage duration in a context scope
have different semantics from regular variables. Each variable
declaration in context scope must match, and is then associated to, a
field of one of the context objects, with the last added / closest
context object being checked first. Both, the name and the type of the
declaration, must match, if they don’t, an error must be generated, even
if there are no context objects at all. It is allowed to use the const
version of the type in the declaration. The lifetime af the variable
will be the same as the object it references. Accessing the variable is
semantically exactly equivalent to dereferencing and accessing the field
of the referenced struct associated_struct_ptr->field
.
It is an error to declare a variable shadowing another variable if both
reference the same field of the same struct in the same context
scope.
In a context scope, at the point where a local variable with automatic storage duration would normally be initialised, that still happens, except that it is now technically an assignment to the associated struct field.
Skipping over the declaration of variables in a context scope by goto or other means behaves as follows. They still just refer to pre existing variables rather than defining a new one, and accessing them must still behave es expected of accessing that object. The variables are are not initialised again in this case, no assignment to the associated struct field takes place.
context-specifier: _Context( assignment-expressionopt ) (6.7) declaration-specifiers: storage-class-specifier declaration-specifiersopt type-specifier declaration-specifiersopt type-qualifier declaration-specifiersopt function-specifier declaration-specifiersopt alignment-specifier declaration-specifiersopt context-specifier declaration-specifiersopt (6.7.4) function-specifier: inline _Noreturn _Continuation (6.8.2) compound-statement: context-specifieropt { block-item-listopt } (6.8.5) iteration-statement: while ( expression ) statement do statement while ( expression ) ; context-specifieropt for ( expressionopt ; expressionopt ; expressionopt ) statement context-specifieropt for ( declaration expressionopt ; expressionopt ) statement