DOKK Library

Improve type generic programming - proposal for C23

Authors Jens Gustedt

License CC-BY-4.0

Plaintext
                                                                           ISO/IEC JTC 1/SC 22/WG14 N2734 v3
                                                                                        WG 21, SG 22 P2304R2

                                                                 2021-5-15
Improve type generic programming
proposal for C23

Jens Gustedt
INRIA and ICube, Université de Strasbourg, France


C already has a variaty of interfaces for type-generic programming, but lacks a systematic approach that
provides type safety, strong ecapsulation and general usability. This paper is a summary paper for a series
that provides improvements through

    N2735.   type inference for variable definitions (auto feature) and function return
    N2736.   function literals and value closures
    N2738.   type-generic lambdas (with auto parameters)
    N2737.   lvalue closures (pseudo-references for captures)

The aim is to have a complete set of features that allows to easily specify and reuse type-generic code
that can equally be used by applications or by library implementors. All this by remaining faithful to C’s
efficient approach of static types and automatic (stack) allocation of local variables, by avoiding superfluous
indirections and object aliasing, and by forcing no changes to existing ABI.
Changes: v2/R1 and v3/R2 provide updates of the proposed wording. For details of the applied changes see
corresponding papers as indicated above.


Contents


I   Introduction                                                                                             2

II A leveled specification of new features                                                                   4
    II.1 Type inference for variable definitions (auto feature) and function return . .                      4
    II.2 Simple lambdas: function literals and value closures . . . . . . . . . . . . . .                    4
    II.3 Type-generic lambdas (with auto parameters) . . . . . . . . . . . . . . . . .                       4
    II.4 Lvalue closures (pseudo-references for captures) . . . . . . . . . . . . . . . .                    5
    II.5 Type inference from identifiers, value expressions and type expressions . . .                       5

III Existing type-generic features in C                                                                      5
    III.1 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .                5
    III.2 Default promotions and conversions . . . . . . . . . . . . . . . . . . . . . .                     6
           III.2.1 Conversions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .               6
           III.2.2 Promotion and default argument conversion . . . . . . . . . . . . . .                     6
           III.2.3 Default arithmetic conversion . . . . . . . . . . . . . . . . . . . . . .                 7
    III.3 Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .               7
           III.3.1 Macros for type-generic expressions . . . . . . . . . . . . . . . . . . .                 7
           III.3.2 Macros for declarations and definitions . . . . . . . . . . . . . . . . .                 7

        © 2021 by the author(s). Distributed under a Creative Commons Attribution 4.0 International License
  N2734
          :2                                                                          Jens Gustedt
  P2304R2
        III.3.3 Macros placeable as statements . . . . . . . . . . . . . . . . . . . . .         8
   III.4 Variadic functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .      8
   III.5 function pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .     9
   III.6 void pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .     9
   III.7 Type-generic C library functions . . . . . . . . . . . . . . . . . . . . . . . .        9
   III.8 _Generic primary expressions . . . . . . . . . . . . . . . . . . . . . . . . . .       10

IV Missing features                                                                             11
   IV.1 Temporary variables of inferred type . . . . . . . . . . . . . . . . . . . . . .        11
   IV.2 Controlled encapsulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . .      12
   IV.3 Controlled constant propagation . . . . . . . . . . . . . . . . . . . . . . . .         13
   IV.4 Automatic instantiation of function pointers . . . . . . . . . . . . . . . . . .        14
   IV.5 Automatic instantiation of specializations . . . . . . . . . . . . . . . . . . .        14
   IV.6 Direct type inferrence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .      16

V Common extensions in C implementations and in other related program-
ming languages                                                         17
   V.1 Type inferrence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .      18
        V.1.1 auto type inference . . . . . . . . . . . . . . . . . . . . . . . . . . . .       18
        V.1.2 The typeof feature . . . . . . . . . . . . . . . . . . . . . . . . . . . .        19
        V.1.3 The decltype feature . . . . . . . . . . . . . . . . . . . . . . . . . .          19
   V.2 Lambdas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .      20
        V.2.1 Possible syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .       21
        V.2.2 The design space for captures and closures          . . . . . . . . . . . . . .   21
        V.2.3 C++ lambdas         . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .   22
        V.2.4 Objective C’s blocks . . . . . . . . . . . . . . . . . . . . . . . . . . .        23
        V.2.5 Statement expressions . . . . . . . . . . . . . . . . . . . . . . . . . .         24
        V.2.6 Nested functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . .        24

References                                                                                      26

VI Proposed wording                                                                             26

I. INTRODUCTION

With the exception of type casts and pointer conversions to and from void*, C is a program-
ming language with a relatively rigid type system that can provide very useful diagnostics
during compilation, if expected and presented types don’t match. This rigidity can be, on
the other hand, quite constraining when programming general features or algorithms that
                                                                                     N2734
 Improve type generic programming                                                            :3
                                                                                     P2304R2
 potentially can apply to a whole set of types, be they pre-defined by the C standard or
 provided by applications.
 This is probably the main reason, why C has no well established general purpose libraries
 for algorithmic extensions; the interfaces (bsearch and qsort) that the C library provides
 are quite rudimentary. By using pointer conversions to void* they circumvent exactly the
 type safety that would be critical for a safe and secure usage of such generic features.
 To our knowledge, libraries that provide type-generic features only have a relatively re-
 stricted market penetration. In general, they are tedious to implement and to maintain and
 the interfaces they provide to their users may place quite a burden of consistency checks to
 these users.
 On the other hand, some extensions in C implementations and in related programming
 languages have emerged that provide type-genericity in a much more comfortable way. At
 the same time these extensions improve the type-safety of the interfaces and libraries that
 are coded with them.
 An important feature that is proposed here, again, are lambdas. WG14 had talked about
 them already at several occasions [Garst 2010; Crowl 2010; Hedquist 2016; Garst 2016;
 Gustedt 2020b], and one reason why their integration in one form or another did not find
 consensus in 2010 seems to be that, at that time, it had been considered to be too late for
 C11. An important data point for lambdas is also that within C++ that feature has much
 evolved since C++11; they have become an important feature in every-day code (not only
 for C++ but many other programming languages) and their usability has much improved.
 Thus we think that it is time to reconsider them for integration into C23, which is our first
 opportunity to add such a new feature to C since C11.
 The goal of this paper is to provide an argumentation to integrate some of the existing
 extensions into the C programming language, such that we can provide interfaces that

— are type and qualifier safe;
— are comfortable to use as if they were just simple functions;
— are comfortable to implement without excessive case analysis.

 It provides the introduction to four other papers that introduce different aspects of such
 a future approach for type-generic programming in C. Most of the features already have
 been proposed in [Gustedt 2020b] and the intent of these four papers is to make concrete
 proposals to WG14 for the addition of these features, namely

(1)   type inference for variable definitions and function returns,
(2)   simple lambdas,
(3)   type-generic lambdas,
(4)   lvalue closures.

 Additionally, we also anticipate that the typeof feature as proposed by a fifth pa-
 per [Meneide 2020], should be integrated into C.
 This paper is organized as follows. Below, Section II, we will briefly present these five papers
 in subsections of their own. In Section III, we will discuss in more detail the 8 features in
 the C standard that already provide type-genericity. Section IV then discusses the major
 problems that current type-generic programming in C faces and the missing properties that
 we would like to achieve with the proposed extensions. Then, Section V introduces the
 extension that could close the gaps and shows examples of type-generic code using them,
  N2734
          :4                                                                       Jens Gustedt
  P2304R2
and Section VI provides the combinations of all wordings that are proposed by the four
papers in the series.

II. A LEVELED SPECIFICATION OF NEW FEATURES

In the following we briefly present the five papers that should be proposed for C23. The
first (Section II.1) and the fifth (Section II.5) handle two forms of type inference. The first
uses inference from evaluated expressions that undergo lvalue conversion, array-to-pointer
and function-to-pointer decay. The fifth uses direct inference from a wider range of features,
namely identifiers, type names and expressions, without performing any form of conversion.
These two papers should each be independent from all the others, with the notable thematic
connection about type inference between them.
The second paper, Section II.2, introduces a simple version of C++’s lambda feature. In
its proposed form it builds on II.1 for (lack of) the specification of return types, but this
dependency could be circumvented by adding additional C++ syntax for the specification of
return types.
Paper II.3 builds on II.1 and II.2 to provide quite powerful type-generic lambdas.
As an extension of the features proposed in [Gustedt 2020b], paper II.4 builds on II.2 to
provide full access to automatic variables from within a lambda.

II.1. Type inference for variable definitions (auto feature) and function return

C’s declaration syntax currently already allows to omit the type in a variable definition,
as long as the variable is initialized and a storage initializer (such as auto or static)
disambiguates the construct from an assignment. In previous versions of C the interpretation
of such a definition had been to attribute the type int; in current C this is a constraint
violation. We will propose to align C with C++, here, and to change this such the type of the
variable is inferred the type from the initializer expression. In a second alignment with C++
we will also propose to extend this notion of auto type inference to function return types,
namely such that such a return type can be deduced from return statements or be void if
there is none.

II.2. Simple lambdas: function literals and value closures

Since 2011, C++ has a very useful feature called lambdas. These are function-like expressions
that can be defined and called at the same point of a program. The simple lambdas that are
introduced in this paper are of two kind. We call the first function literals, that are lambdas
that interact with their context only via the arguments to a call, no automatic variables of
the context can be evaluated within the function body. If they are not used in a function
call such function literals can be converted to function pointers with the corresponding
prototype. The concept is extended with value closures, namely lambdas that can access
all or part of their context, but by evaluating automatic variables (in a so-called capture)
at the same point where the lambda as a whole is evaluated. The return type of any such
lambda is not provided by the interface specification but it is deduced from the arguments
to a possible call.

II.3. Type-generic lambdas (with auto parameters)

Type-generic lambdas extend the lambda feature such that the parameter types can use the
auto feature and thus be underspecified. This allows lambdas to be a much more general
                                                                                    N2734
Improve type generic programming                                                            :5
                                                                                    P2304R2
tool and eases the programming of type-generic features. The concrete types of the auto
parameters for a specific instance of such a lambda are deduced either from the arguments if
the lambda is used in a function call, or from the target type of a lambda-to-function-pointer
conversion.

II.4. Lvalue closures (pseudo-references for captures)

This paper also introduces C++’s syntax to access automatic variables from within the body
of a lambda and eventually modify the variable. C does not have the concept of references
to which this feature refers in C++, and the intent of this paper is not to introduce references
into C. Therefore we introduce the feature as lvalue capture (in contrast to value capture)
and just refer to the identifiers that name automatic variables and to the possible lvalue
conversion while calling the lambda.

II.5. Type inference from identifiers, value expressions and type expressions

Our hope is that the attempts to integrate gcc’s typeof extension will be successful. We
think that a typeof operator that has similar syntactic properties as the sizeof and alignof
operators and that maintains all type properties such as qualification and derivation (atomic,
array, pointer or function) could be quite useful for type-generic programming and its type
safety.

III. EXISTING TYPE-GENERIC FEATURES IN C

Type-generic features are so deeply integrated into C that most programmers are probably
not even aware of there omnipresence. Below we identify eight different features that do
indeed provide type-genericity, ranging from simple features, such as operators that work for
multiple types, to complicated programmable features, such as generic primary expressions
(_Generic).
The following discussion is not meant to cover all aspects of existing type-generic features,
but to raise awareness for their omnipresence, for their relative complexity, and for their
possible defects.

III.1. Operators

The first type-generic feature of C are operators. For example the binary operators ==
and != are defined for all wide integer types (signed, long, long long and their unsigned
variants), for all floating types (float, double, long double and their complex variants)
and for pointer types, see Tab. I for more details.


          Table I.    Permitted types for binary operators that require equal types
                                                                     pointer
                                             floating           object
           operator       wide integer real complex complete void function
           ==, !=              ×          ×         ×         ×         ×        ×
           -                   ×          ×         ×         ×
           +, *, /             ×          ×         ×
           <, <=, >=, >        ×          ×                   ×
           %, ˆ, &, |          ×
       N2734
               :6                                                                                                                  Jens Gustedt
       P2304R2


                                                                                 wide
                    narrow
                                                      unsigned       unsigned long          unsigned long long
           unsigned char         unsigned short
                                                                 ?                      ?
                             ?                    ?
bool
                                                       signed         signed long            signed long long
            signed char           signed short
                                                                                                 real floating

                                                                         float                   double           long double


                                                                                                                      complex

                                                                                              complex float      complex double   complex long double




    Fig. 1. Upward conversion of arithmetic types. Black arrows conserve values, red arrows may occur for
    integer promotion or default argument conversion, blue arrows are reduction modulo 2N , well-definition of
    grey arrows depends on the platform, green arrows may loose precision

    Thus, expressions of the form a*b+c are by themselves already type-generic and the pro-
    grammer does not have to be aware of the particular type of any of the operands. In addition,
    if the types of the operands do not agree, there is a complicated set of conversions (see be-
    low) that enforces equal types for all these operations. Other binary operators (namely shift
    operators, object pointer addition, array subscripting) can even deal with different operand
    types, even without conversion.

    III.2. Default promotions and conversions

    If operands for the operators in Tab. I don’t agree, or if they are even types for which
    these operands are not supported (narrow integer types such as bool, char or short) a
    complicated set of so-called promotion and conversion rules are set in motion. See Fig. 1
    for an overview.

      III.2.1. Conversions. Whenever an arithmetic argument to a function or the LHS of an
    assignment or initialization has not the requested type of the corresponding parameter,
    there is a whole rule set that provides a conversion from the argument type to the parameter
    type.

1        printf ( " result ␣ is : ␣ % g \ n " , cosf (1) ) ;

    Here, the cosf function has a float parameter and so the int argument 1 is first converted
    to 1.0f.
    Figure 1 shows the upward conversions that are put in place by C. These kind of conversions
    help to avoid to write several versions of the same function and allow to use such a function,
    to a certain extend, with several argument types.

       III.2.2. Promotion and default argument conversion. In the above example, the result of cosf
    is float, too, but printf as a variadic function cannot handle a float. So that value is
    converted to double before being printed.
    Generally, there are certain types of numbers that are not used for arithmetic operators or for
    certain types of function calls, but are always replaced by a wider type. These mechanisms
    are called promotion (for integer types) or default argument conversion (for floating point).
                                                                                         N2734
     Improve type generic programming                                                            :7
                                                                                         P2304R2
        III.2.3. Default arithmetic conversion. To determine the target type of an arithmetic opera-
     tion, these concepts are taken on a second level. Default arithmetic conversion determines a
     common “super” type for binary arithmetic operators. For example, an operation -1 + 1U
     first performs the minus operation to provide a signed int of value −1, then (for arithmetic
     conversion) converts that value to an unsigned int (with value UINT_MAX) and performs the
     addition. The result is an unsigned int of value 0.

     III.3. Macros

     C’s preprocessor has a powerful macro feature that is designed to replace identifiers (so-
     called object macros) and pseudo-function calls by other token sequences. Together with
     default arithmetic promotions it can be used to provide type-generic programming for sev-
     eral categories of tasks:

 — type-generic expressions
 — type-generic declarations and definitions
 — type-generic statements that are not expressions

       III.3.1. Macros for type-generic expressions. A typically type-generic macro has an arithmetic
     expression that is evaluated and that uses default arithmetic conversion to determine a tar-
     get type. For example the following macro computes a grey value from three color channels:

 1       # define GREY (R , G , B ) ((( R ) + ( G ) + ( B ) ) /3)

     It can be used for any type that would be used to represent colors. If used with unsigned
     char the result would typically be int, for float values the result would also be float.
     Naming conventions, here for structure members r, g, and b, can also help to write type
     generic macros.

 1    # define       red ( P ) ( P . r )
 2    # define       green ( P ) ( P . g )
 3    # define       blue ( P ) ( P . b )
 4    # define       grey ( P ) ( GREY ( P .r , P .g , P . b ) )


       III.3.2. Macros for declarations and definitions. Type defitions that then can use the above
     macros can also be provided by macros.

 1    # define declareColor ( N ) typedef struct N N
 2
 3    declareColor ( color8 ) ;
 4    declareColor ( color64 ) ;
 5    declareColor ( colorF ) ;
 6    declareColor ( colorD ) ;
 7
 8
 9    # define defineColor (N , T ) struct N { T r ; T g ; T b ; }
10
11    defineColor ( color8 , uint8_t ) ;
12    defineColor ( color64 , uint64_t ) ;
13    defineColor ( colorF , float ) ;
14    defineColor ( colorD , double ) ;
       N2734
               :8                                                                     Jens Gustedt
       P2304R2




        III.3.3. Macros placeable as statements. Macros can also be used to group together several
     statements for which no value return is expected. Unfortunately, coding properly with this
     technique usually has to trade in some uglyness and maintenance suffering. The following
     presents common practice for generic macro programming in C that can be used for any
     structure type T that has a mtx_t member mut and a data member that is assignment
     compatible with BASE.

 1    # define dataCondStore (T , BASE , P , E , D )                  \
 2       do {                                                         \
 3         T * _pr_p = ( P ) ;                                        \
 4         BASE _pr_expected = ( E ) ;                                \
 5         BASE _pr_desired = ( D ) ;                                 \
 6         bool _pr_c ;                                               \
 7         do {                                                       \
 8            mtx_lock (& _pr_p - > mtx ) ;                           \
 9            _pr_c = ( _pr_p - > data == _pr_expected ) ;            \
10            if ( _pr_c ) _pr_p - > data = _pr_desired ;             \
11            mtx_unlock (& _pr_p - > mtx ) ;                         \
12         } while (! _pr_c ) ;                                       \
13       } while ( false )

     Coded like that, the macro has several advantages:

 — It can syntactically be used in the same places as a void function. This is achieved by the
   crude outer do ... while(false) loop.
 — Macro parameters are evaluated at most once. This is achieved by declaring auxiliary
   variables to evaluate and hold the values of the macro arguments. Note that the definition
   of these auxiliary variables needs knowledge about the types T and BASE.
 — Some additional auxiliary variables (here _pr_c) can be bound to the scope of the macro.

     Additionally, a naming convention for local variables is used as to minimize possible naming
     conflicts with identifiers that might already be defined in the context where the macro is
     used. Nevertheless, such a naming convention is not fool proof. In particular, if the use of
     several such macros is nested, surprising interactions between them may occur.

     III.4. Variadic functions

     Above we also have seen another C standard tool for type-generic interfaces, variadic func-
     tions such as printf:

1         int printf ( char const format [ static 1] , ...) ;

     The ... denotes an arbitrary list of arguments that can be passed to the function, and it
     is mostly up to a convention between the implementor and the user how many and what
     type of arguments a call to the function may receive. There are notable exceptions, though,
     because with the ... notation all arguments that are narrow integers or are float are
     converted, see Figure 1.
                                                                                       N2734
    Improve type generic programming                                                           :9
                                                                                       P2304R2
    For such interfaces in the C standard library modern compilers can usually check the argu-
    ments against the format string. In contrast to that, user specified functions remain usually
    unchecked and can present serious safety problems.

    III.5. function pointers

    Function pointers allow to handle algorithms that can be made dependent of another func-
    tion. For example, here is a generic function that computes an approximation of the deriva-
    tive of function func in point x:

1     typedef double math_f ( double ) ;
2
3    inline double tangent5 ( math_f * func , double x , double ε ) {
4      double h = ε * x ;
5      return ( - func ( x + 2* h ) +8* func ( x + h )
6               -8* func ( x - h ) + func ( x - 2* h ) ) /(12* h ) ;
7    }


    III.6. void pointers

    The C library itself has some interfaces that use function pointers for type-genericity, namely
    bsearch and qsort receive a function pointer to the following function type

1     typedef int compar_t ( void const * , void const *) ;

    with the understanding that the pointer parameters of such a function represent pointers
    to the same object type BASE, depending on the function, and that the return value is less
    than, equal to, or greater than 0 if the first argument compares less than, equivalent to, or
    greater than the second argument.

1    int comparDouble ( void const * A , void const * B ) {
2      double const * a = A ;
3      double const * b = B ;
4      return (* a < * b ) ? -1 : ((* a == * b ) ? 0 : +1) ;
5    }
6
7     double tabd [] = { 1 , 4 , 2 , 3 , };
8     qsort ( tab , sizeof tabd [0] , sizeof tab / sizeof tabd [0] ,
         comparDouble ) ;

    This uses the fact that data pointers can be converted forth and back to void pointers,
    as long as the target qualification is respected. The advantage is that such a comparison
    (and thus search or sorting) interface can then be written quickly. The disadvantage is that
    guaranteeing type safety is solely the job of the user.

    III.7. Type-generic C library functions

    C gained its first explicit type-generic library interface with the introduction of <tgmath.h>
    in C99. The idea here is that a functionality such as the cosine should be presented to the
    user as a single interface, a type-generic macro cos, instead of the three functions cos, cosf
    and cosl for double, float or long double arguments, respectively.
      N2734
              :10                                                                       Jens Gustedt
      P2304R2
    At least for such one-argument functions the expectation seems to be clear, that such a
    functionality should return a value of the same type as the argument. In a sense, such
    type-generic macros are just the extension of C’s operators (which are type-generic) to a
    set of well specified and understood functions. An important property here is that each of
    the type-generic macros in <tgmath.h> represents a finite set of functions in <math.h> or
    <complex.h>. Many implementations implemented these macros by just choosing a function
    pointer by inspecting the size of the argument, using the fact that their representations of
    the argument types all had different sizes.
    Then, C11 gained a whole new set of type-generic functions in <stdatomic.h>. The difficulty
    here is that there is a possibly unbounded number of atomic types, some of which with equal
    size but different semantics, and so the type-generic interfaces cannot simply rely on the
    argument size to map to a finite set of functions. Implementations generally have to rely on
    language extensions to implement these interfaces.

    III.8. _Generic primary expressions

    C11 introduced a new feature, generic primary expressions, that was primarily meant to
    implement type generic macros similar to those in <tgmath.h>, that is to perform a choice of
    a limited set of possibilities, guided by the type of an input expression. By that our example
    for cos from above could be implemented as follows:

1    # define cos ( X )                                    \
2       _Generic (( X ) ,                                  \
3         float : cosf ,                                   \
4         long double : cosl ,                             \
5         default : cos) ( X )

    That is a _Generic expression is used to choose a function pointer that is then applied to
    the argument X. Note that here _Generic only uses X for its type and does not evaluate
    it, that the result type of the _Generic is the type of the chosen expression, and, that the
    library function cos can be used within the macro, because C macros are not recursive.
    Thus, this technique allows an “overload” of some sort of the function cos with the macro
    cos. Another implementation could be as follows:

1    # define cos ( X )                                        \
2       _Generic (( X ) ,                                      \
3         float : cosf (( float ) X ) ,                        \
4         long double : cosl (( long double ) X ) ,            \
5         default : cos(( double ) X ) )

    By this, cosf and cosl themselves could even be macros and the compiler would not have
    to use the corresponding function pointers.
    The concept of generic primary expressions goes much further than for switching between
    different function pointers. For example, the following can do a conversion of a pointer value
    P according to the type of an additional argument X.

1    # define getOrderCP (X , P )                                                   \
2       _Generic (( X ) ,                                                           \
3         float : ( float const *) ( P ) ,                                          \
4         double : ( double const *) ( P ) ,                                        \
5         long double : ( long double const *) ( P ) ,                              \
                                                                                          N2734
    Improve type generic programming                                                              :11
                                                                                          P2304R2
6          unsigned : ( unsigned const *) ( P ) ,                                     \
7          unsigned long : ( unsigned long const *) ( P ) ,                           \
8          ... /* other ordered arithmetic types */ ...                               \
9          )

    Still, the important concepts are the same: X is only used for its type, and the type of the
    expression itself corresponds to the type of the choosen expression.

    IV. MISSING FEATURES

    IV.1. Temporary variables of inferred type

    One of the most important restrictions for type-generic statements above (III.3.3) was that
    the macro needed arguments that encoded the types for which the macro was evaluated. This
    not only inconvenient for the user of these macros but also an important source of errors.
    If the user chooses the wrong type, implicit conversions can impede on the correctness of
    the macro. For our example dataCondStore a wrong choice of the type BASE float instead
    of double could for example have the effect that the equality test never triggers, and thus
    that the inner loop never terminates.
    In accordance with C’s syntax for declarations and in extension of its semantics, C++ has
    a feature that allows to infer the type of a variable from its initializer expression.

1       auto y = cos ( x ) ;

    This eases the use of type-generic functions because now the return value and type can
    be captured in an auxiliary variable, without necessarily having the type of the argument,
    here x, at hand. This can become even more interesting if the return type of type-generic
    functions is just an aggregation of several values for which the type itself is just an artefact:

1    # define div (X , Y )                       \
2       _Generix (( X ) +( Y ) ,                 \
3                 int : div ,                    \
4                 long : ldiv ,                  \
5                 long long : lldiv )            \
6                 (( X ) , ( Y ) )
7
8       auto res = div (38484848448 , 448484844) ;                   // int or long ?
9       auto a = b * res . quot + res . rem ;

    Used in the macro from III.3.3, this can easily remove the need for the specification of the
    types T and BASE:

1    # define dataCondStoreTG (P , E , D )                             \
2       do {                                                           \
3         auto * _pr_p = ( P ) ;                                       \
4         auto _pr_expected = ( E ) ;                                  \
5         auto _pr_desired = ( D ) ;                                   \
6         bool _pr_c ;                                                 \
7         do {                                                         \
8            mtx_lock (& _pr_p - > mtx ) ;                             \
9            _pr_c = ( _pr_p - > data == _pr_expected ) ;              \
       N2734
               :12                                                                     Jens Gustedt
       P2304R2
10           if ( _pr_c ) _pr_p - > data = _pr_desired ;              \
11           mtx_unlock (& _pr_p - > mtx ) ;                          \
12         } while (! _pr_c ) ;                                       \
13       } while ( false )


     IV.2. Controlled encapsulation

     Even as presented now, the macro dataCondStoreTG has a serious flaw that is not as apparent
     as it should be. The assignment of the values of E and D to _pr_expected and _pr_desired
     is not independent. This is, because D itself may be an expression that contains a reference
     to an identifier _pr_expected, and thus the intended evaluation of D (before even entering
     the macro) is never performed, but a completely different value (depending on E) is used
     instead.

1        dataCondStoreTG (P , 4 , 3* _pr_expected ) ;

     The result of the macro then depends on the order of specification of the variables
     _pr_expected and _pr_desired. This kind of interaction is the main reason why we had to
     chose these ugly names with a _pr_ prefix in the first place: they reduce the probability of
     interaction between the code inside the macro and its caller.
     C++ has a feature that is called lambda. In its simplest form (that we call function literal )
     it provides just the possibility to specify an anonymous function that only interacts with
     its context via parameters:

 1    auto const dataCondStore λDD =
 2      []( DD *p , double expected , double desired ) {
 3         bool c ;
 4         do {
 5           mtx_lock (& p - > mtx ) ;
 6           c = (p - > data == expected ) ;
 7           if ( c ) p - > data = desired ;
 8           mtx_unlock (& p - > mtx ) ;
 9         } while (! c ) ;
10      };
11
12       dataCondStore λDD ( pDD , 0.5 , 0.7) ;

     Here, we may now chose “decent” variable and parameter names, because we know that
     they will not interact with a calling context.
     When we combine lambdas with the auto feature for the parameters, this tool becomes even
     more powerful, because now we have in fact a way to describe a type-generic functionality
     without having to worry about the particular types of the arguments nor of an uncontrolled
     interaction with the calling environment.

1     # define dataCondStore λ                          \
2        []( auto *p , auto expected , auto desired ) { \
3          bool c ;                                     \
4          do {                                         \
5             mtx_lock (& p - > mtx ) ;                 \
6             c = (p - > data == expected ) ;           \
                                                                                                     N2734
     Improve type generic programming                                                                        :13
                                                                                                     P2304R2
 7              if ( c ) p - > data = desired ;                                 \
 8              mtx_unlock (& p - > mtx ) ;                                     \
 9            } while (! c ) ;                                                  \
10        }
11
12        dataCondStore λ( pDD , 0.5 , 0.7) ;
13        dataCondStore λ( pFF , 0.1 f , 0) ;


     IV.3. Controlled constant propagation

     The above form of lambdas for function literals is introduced by an empty pair of brackets []
     to indicate that the lambda does not access to any automatic variables from the calling
     context. More general forms of lambdas called closures are available in C++ that provide
     access to the calling context.
     The idea is that the body of a closure may use identifiers that are free, that is that don’t
     have a definition that is provided by the lambda itself but by the calling context. C++ has
     a strict policy here, that such free variables must be explicitly named within the brackets,
     or that the bracket should have a = token to allow any such free variables to appear. For
     example a lambda expression as in the following

 1    auto const tangent5λ = [ ε ]( math_f * func , double x ) {
 2       double h = ε * x ;
 3       return ( - func ( x + 2* h ) +8* func ( x + h )
 4                -8* func ( x - h ) + func ( x - 2* h ) ) /(12* h ) ;
 5    };

     captures the value ε from the environment and freezes it for any use of the tangent5λ closure
     to the value at the point of evaluation of the lambda (and not the call).
     An even more extended form of this allows the assignment of any expression to the free
     variables:

 1    # define TANGENT5 (F , E ) [ func = ( F ) , ε = ( E ) ]( double x ) { \
 2       double h = ε * x ;                                                 \
 3       return ( - func ( x + 2* h ) +8* func ( x + h )                    \
 4                -8* func ( x - h ) + func ( x - 2* h ) ) /(12* h ) ;      \
 5    }
 6
 7    int main ( int        argc , char * argv [ static argc +1]) {
 8      auto const          f0 = argc > 1 ? & sin : & cos ; // function pointer
 9      auto const          f1 = TANGENT5 ( f0 , 0 x1E -12) ; // lambda value
10      auto const          f2 = TANGENT5 ( f1 , 0 x1E -12) ; // lambda value
11      auto const          f3 = TANGENT5 ( f2 , 0 x1E -12) ; // lambda value
12
13        for ( double x = 0.01; x < 4; x += 0.5) {
14          printf ( " % g ␣ % g ␣ % g ␣ % g \ n " , f0 ( x ) , f1 ( x ) , f2 ( x ) , f3 ( x ) ) ;
15        }
16    }

     Here, three lambdas are evaluated and assigned to auto variables f1, f2 and f3, respectively.
     By that technique, the compiler is free to optimize the code in the body of the lambda with
       N2734
               :14                                                                    Jens Gustedt
       P2304R2
     respect to the possible values of func and ε, and then to use these optimized versions within
     the for loop as indicated.


     IV.4. Automatic instantiation of function pointers

     Library programmers often need a seamless tool to describe and implement a generic feature,
     and, from time to time, they need the possibility to instantiate a function pointer for a
     certain set of function arguments from there. _Generic provides the complete opposite
     of that: previously unrelated specialized function pointers are stitched together into one
     feature.
     C++’s lambda model allows to provide such a more practical tool, namely it allows to in-
     stantiate function pointers from all function literals.

 1       auto const sortDouble =
 2         // function literal
 3         []( size_t len , double const ar [ static len ]) {
 4              // function pointer
 5              int (* comp ) ( void const * , void const *) =
 6                // function literal
 7                []( void const * A , void const * B ) {
 8                   double const * a = A ;
 9                   double const * b = B ;
10                   // returns -1, 0, or +1, an int
11                   return (* a < * b ) ? -1 : ((* a == * b ) ? 0 : +1) ;
12                };
13                qsort ( ar , sizeof ar [0] , len , comp ) ;
14             );
15             // no return statement , void
16         };
17
18       double tabd [] = { 1 , 4 , 2 , 3 , };
19       sortDouble ( sizeof tab / sizeof tabd [0] , tabd ) ;


     That is, all lambdas without capture can be converted implicitly or explicitly to a function
     pointer with a prototype that is compatible with the parameter and return types of the
     lambda. If such an attempt is made and the parameter types are not compatible, an error
     (constraint violation) occurs and the compilation should abort. In the above example the
     inner lambda has two parameters of type void const* and its return expression has type
     int. Thus its lambda type is convertible to the function pointer type as indicated.
     Such a conversion to a function pointer can be done implicitly as above, in an intialization,
     assignment or by passing a lambda as an argument to a function call. It can also come from
     an explicit conversion, that is a cast operator.


     IV.5. Automatic instantiation of specializations

     When the parameters of a lambda use the auto feature, we have a type-generic lambda,
     that is a lambda that can receive different types of parameters. When such a lambda is
     used, the underspecified parameter types must be completed, such that the compiler can
     instantiate code that has all types fixed at compile time.
                                                                                    N2734
     Improve type generic programming                                                       :15
                                                                                    P2304R2
     If there are no captures, one possibility to determine the parameter types is to assign such
     a type-generic lambda to a function pointer:

 1    # define TANGENT5TG ( auto * func , auto x , auto ε ) {               \
 2       auto h = ε * x ;                                                   \
 3       return ( - func ( x + 2* h ) +8* func ( x + h )                    \
 4                -8* func ( x - h ) + func ( x - 2* h ) ) /(12* h ) ;      \
 5    }
 6
 7    typedef double math_f ( double ) ;
 8    typedef float mathf_f ( float ) ;
 9    typedef long double mathl_f ( long double ) ;
10
11
12    double (* tangent5 ) ( math_f * , double , double ) = TANGENT5TG ;
13    float (* tangent5f ) ( mathf_f * , float , float ) = TANGENT5TG ;
14    long double (* tangent5l ) ( mathl_f * , long double , long double ) =
          TANGENT5TG ;


     Here, again, such a conversion to a function pointer can only be formed if the parameter
     and return types can be made consistent.
     The following shows how an inner lambda can even be made type-generic, such that it
     synthesizes a function pointer on the fly, whenever the outer lambda is instantiated:

 1    # define sortOrder                                                                \
 2         []( size_t len , auto const ar [ static len ]) {                             \
 3             qsort ( ar , sizeof ar [0] , len ,                                       \
 4                []( void const * A , void const * B ) {                               \
 5                   auto const * a = getOrderCP ( ar [0] , A ) ;                       \
 6                   auto const * B = getOrderCP ( ar [0] , B ) ;                       \
 7                   return (* a < * b ) ? -1 : ((* a == * b ) ? 0 : +1) ;              \
 8                }                                                                     \
 9             );                                                                       \
10         }
11
12       void (* sortd ) ( size_t len , double const ar [ static len ])
13         = sortOrder ;
14       void (* sortu ) ( size_t len , unsigned const ar [ static len ])
15         = sortOrder ;
16
17       double tabd [] = { 1 , 4 , 2 , 3 , };
18       // semantically equivalent
19       sortOrder ( sizeof tab / sizeof tabd [0] , tabd ) ;
20       sortd ( sizeof tab / sizeof tabd [0] , tabd ) ;
21
22       unsigned tabu [] = { 1 , 4 , 2 , 3 , };
23       // semantically equivalent
24       sortOrder ( sizeof tabu / sizeof tabu [0] , tabu ) ;
25       sortu ( sizeof tabu / sizeof tabu [0] , tabu ) ;
       N2734
               :16                                                                     Jens Gustedt
       P2304R2
     Here, we use the type-generic macro getOrderCP from above which does not evaluate its first
     argument, ar[0] in this case, but only uses it for its type. Remember that the visiblity rules
     for identifiers from outer scopes are the same as elsewhere, only the access to automatic
     variables is constrained or allowed by the capture clause. Thus, such a use for the type
     inside the inner lambda is allowed, and provides a lambda that is dependent on the type of
     ar[0].


     IV.6. Direct type inferrence

     The possibility of inferring a type via the auto feature has the property that it is only
     possible for an expression that is evaluated in an initializer, and thus it first undergoes
     lvalue, array-to-pointer or function-to-pointer conversion before the type is determined. In
     particular, by this mechanism it is not possible to propagate qualifiers (including _Atomic)
     nor to conserve array dimensions.
     C++ has the decltype operator and many C compilers have a __typeof__ extension that fills
     this gap. For the following we assume a typeof operator that just captures the type of an
     expression or typename that is passed as an argument.

 1       int i ;
 2       // an array of three int
 3       typeof ( i ) iA [] = { 0 , 8 , 9 , };
 4
 5       double A [4];
 6       typedef typeof ( A ) typeA ;
 7       // equivalent definition
 8       typedef double typeA [4];
 9       // equivalent declaration
10       typeA A ;
11       // equivalent declaration
12       typeof ( double [4]) A ;
13       // mutable array of 4 elements intialized to 0
14       typeof ( A ) dA = { 0 };
15       // immutable array of 4 elements
16       typeof ( A ) const cA = { 0 , 1 , 2 , 3 , };
17
18       // infer the type of a function
19       typeof ( sin ) cos ;
20       // equivalent declaration
21       double cos ( double ) ;
22
23       // infer the type of a function pointer and initialize
24       typeof ( sin ) * const ∆ = cos ;
25       // equivalent definition
26       auto * const ∆ = cos ;
27       // equivalent definition
28       const auto ∆ = cos ;
29       // equivalent definition
30       double (* const ∆) ( double ) = cos ;
                                                                                      N2734
     Improve type generic programming                                                         :17
                                                                                      P2304R2
     In particular, for every declared identifier id with external linkage (that is not also thread
     local) the following redundant declaration can be placed anywhere where a declaration is
     allowed.

 1       extern typeof ( id ) id ;

     A typeof operator can be used everywhere where an typedef identifier can be used. It
     can not only applied to type expressions and identifiers as above, but also to any valid
     expression:

 1    # define sortOrder                                                                  \
 2         []( size_t len , auto const ar [ static len ]) {                               \
 3             qsort ( ar , sizeof ar [0] , len ,                                         \
 4                []( void const * A , void const * B ) {                                 \
 5                   typeof ( ar [0]) * a = A ;                                           \
 6                   typeof ( ar [0]) * b = B ;                                           \
 7                   return (* a < * b ) ? -1 : ((* a == * b ) ? 0 : +1) ;                \
 8                }                                                                       \
 9             );                                                                         \
10         }
11
12       void (* sortd ) ( size_t len , double const ar [ static len ])
13         = sortOrder ;
14       void (* sortu ) ( size_t len , unsigned const ar [ static len ])
15         = sortOrder ;
16
17       double tabd [] = { 1 , 4 , 2 , 3 , };
18       // semantically equivalent
19       sortOrder ( sizeof tab / sizeof tabd [0] , tabd ) ;
20       sortd ( sizeof tab / sizeof tabd [0] , tabd ) ;
21
22       unsigned tabu [] = { 1 , 4 , 2 , 3 , };
23       // semantically equivalent
24       sortOrder ( sizeof tabu / sizeof tabu [0] , tabu ) ;
25       sortu ( sizeof tabu / sizeof tabu [0] , tabu ) ;

     By that we are now able to remove the call to getOrderCP from the inner lambda expression.
     The result is a macro sortOrder that can be used to sort any array as long as the elements
     that can be compared with the < operator. The only external reference that remains is the
     C library function qsort. That macro can be used to instantiate a function pointer or it can
     be used directly in a function call.

     V. COMMON EXTENSIONS IN C IMPLEMENTATIONS AND IN OTHER RELATED
        PROGRAMMING LANGUAGES

     In the following we are interested in features that extend current C for type-genericity but
     with one important restriction:

                     Features that are proposed imply no ABI changes.

     In particular, with the proposed changes we do not intend
  N2734
          :18                                                                      Jens Gustedt
  P2304R2
— to   change the ABI for function pointers,
— to   introduce linkage incompatibilities such as mangling,
— to   modify the life-time of automatic objects, or
— to   introduce other managed storage that is different from automatic storage.

There are a lot of features in the field that would need one or several points from the above,
such as C++’s template functions or functor classes, Objective C’s __block storage specifiers,
or gcc’s callable nested functions. All of these approaches have their merits, and this paper
is not written to argue against their integration into C. We simply try first to look into the
features that can do without, such that they might be easily adopted by programmers that
are used to our concepts and implemented more widely than they already are.

V.1. Type inferrence

Besides the possibility of functional expression, declaring parameters, variables and return
values of inferred type is a crucial missing feature for an enhancement of standard C towards
type-genericity. This allows to declare local, auxiliary, variables of a type that is deduced
from parameters and to return dependent values and types from functional constructs.
We found several existing extensions in C or related languages that allow to infer a type from
a given construct. They differ in the way derived type constructions (qualifiers, _Atomic,
arrays or functions) influence the derived type: C++’s auto feature and gcc’s auto_type,
C++’s decltype, and gcc’s typeof.

  V.1.1. auto type inference. This kind of type inference takes up an idea that already exists
in C:

        A type specification may only have incomplete information, and then is completed
        by an initializer.

This is currently possible for array declarations where an incomplete specification of an
array bound may be completed by an initializer:

        double const A [] = { 5. 6 , 7 , }; // array of 3 elements
        double const B [] = { [23] = 0 , }; // array of 24 zeroes

In fact, the maximum index in the initializer determines the size of the array and thereby
completes the array type.
auto type inference pushes this further, such that also the base type of an object definition
can be inferred from the initializer:

        auto b = B [0]; // this is double
        auto a = A ;    // this is double const*

Here, the initializer is considered to be an expression, thus all rules for evaluation of ex-
pressions apply. So, qualifiers and some type derivations are dropped. For example, b is
double, the const is dropped, and A on the RHS undergoes array-to-pointer conversion and
the inferred type for a is double const* and not double const[24].
Since in the places that are interesting here = can have the meaning of an assignment
operator or of an initializer, constructs as the following could be ambiguous:
                                                                                    N2734
 Improve type generic programming                                                           :19
                                                                                    P2304R2
     b = B [0];
     a = A;

 This ambiguity can occur as soon that an attempted declaration has no storage class,
 therefore C++ extends the use of the keyword auto and allows to place it in any declaration
 that is supposed to be completed by an initializer.
 This feature is then extended even further into contexts that don’t even have initializers:

— An auto declaration of a function return type infers the completed return type from a
  return expression, if there is any, or infers a type of void, if there is none.
— An auto declaration of a function or lambda parameter infers the completed parameter
  type from the argument to a function call or from the corresponding parameter in a
  function-pointer conversion.

    V.1.2. The typeof feature. typeof is an extension that has been provided since a long time in
 multiple compilers. A typeof specifier is just a placeholder for a type, similar to a typedef.
 It reproduces the type “as-is” without dropping qualifiers and without decaying functions
 or arrays. With this feature not only qualifiers and atomics do not get dropped, but they
 can even be added.
 It differs (and complements) the auto feature syntactically and semantically. Its general
 forms are

     typeof (expression)
     typeof (type-name)

 and these can be substituted at any place where a type name may occur. With the definitions
 of A and B as above

     auto b = B [0];                          //   this   is double
     auto a = A ;                             //   this   is double const*
     typeof ( B [0]) β;                       //   this   is double const
     typeof ( A ) α;                          //   this   is double const[24]
     typeof ( double const [24]) γ ;          //   same   type

 So here we see that the expressions B[0] and A do not undergo any conversion and so the
 qualifier and the array derivation remain in place.
 There have been some inconsistencies for the type derivation strategies for this operator in
 the past, but it seems that recent compilers interpret types that are given as arguments as
 it is presented above.

   V.1.3. The decltype feature. Since almost a decade C++ has introduced the decltype fea-
 ture which in most aspects that concern the intersection with C is similar to typeof.
 Conceptually, integration into C would be a bit more difficult than for auto. This is because
 for historic reasons C++ here mixes several concepts in an unfortunate way: for some types
 of expressions decltype has a reference type for others it hasn’t. The line of when it does
 this is not where we would expect it to be for C: most lvalues produce a reference type, but
 not all of them. In particular, direct identification of variables or functions (by identifier)
 or of structure or union members leads to direct types, without reference, but surrounding
 them with an expression that conserves their “lvalueness” adds a reference to the type of
 the decltype specification.
      N2734
              :20                                                                     Jens Gustedt
      P2304R2
    It is quite unusual for C to have the type of an expression depend on surrounding (), but
    unfortunately that ship has sailed in C++. Therefore we prefer that a new operator typeof
    be introduced into both languages that clarifies these aspects and that is designed to have
    exactly the same properties in both.

    V.2. Lambdas

    As we have seen above, in C macros can serve for two important type-generic tasks, namely
    the specification of type-generic expressions and the specification of type-generic functions.
    But unfortunately they cannot, without extension, be used in place to specify functional
    units that use the whole expressiveness of the language to do their computation.
    To illustrate that, consider the simple task of specifying a max feature that computes the
    maximum of two values x and y. In essence, we would like this to compute the expression

1       (x < y ? y : x)

    regardless of the type of the two values x and y. As such this is not possible to specify this
    safely with a macro

1       # define BADMAX (X , Y ) (( X ) < ( Y ) ? ( Y ) : ( X ) )

    because such a macro always evaluates one of the argument twice; once in the comparison
    and a second time to evaluate the chosen value. As soon as we pass in argument expressions
    that have side effects (such as i++ or a function call) these effects could be produced twice
    and therefore result in surprising behavior for the unaware user of the interface.
    Also, when we would mix signed and unsigned arguments, the above formula would not
    always compute the mathematical maximum value of the two arguments because a negative
    signed value could be converted to a large positive unsigned value.
    Thus, already for a simple type-generic feature such as max, we would need the possibility
    to define local variables that only have the scope of the max expression, and for which we
    may somehow infer the type from the arguments that are passed to max.
    In a slight abuse of terminology we will borough the term lambda from the domain of
    functional programming to describe a functional feature that is an expression with a lambda
    value of lambda type. Several proposals have already been discussed to integrate lambdas
    into C [Garst 2010; Crowl 2010; Hedquist 2016; Garst 2016].
    Basically, a lambda value can be used in two ways

— It can be moved around as values of objects, that is assigned to variables or returned from
  functions.
— It can replace the function specifier in a function call expression.

    In C++’s lambda notation (that we will propose to adopt below) a max feature can be
    implemented as follows

1       []( auto x ,    auto y ) {
2         if (( x <     0) != ( y < 0) ) {
3            x = (x     < 0) ? 0 : x ;
4            y = (y     < 0) ? 0 : y ;
5         }
                                                                                        N2734
    Improve type generic programming                                                            :21
                                                                                        P2304R2
6           return ( x < y ? y : x ) ;
7       }

    That is, [] introduces a lambda expression, x and y are parameters to the lambda that
    have an underspecified type (indicated by auto) and a return statement in the body of the
    lambda specifies a return value and, implicitly, a return type. The logic of the if statement
    is to capture the case where one of the two parameters is negative and the other is not, and
    then to replace the negative one with the value zero. Thereby the lambda never converts a
    negative signed value to a positive unsigned value.
    Observe, that this lambda does not access any other identifier than its parameters.
    Global identifiers are easy to handle by lambdas as they are handled by any traditional
    C function. For these there are two mechanism in play:

       visibility. This regulates which identifiers can be used and which type they have. In
       particular, visible identifiers can be used in some context (such as sizeof or _Generic)
       without being accessed.
       linkage. This regulates how the object or function behind an identifier is accessible. In
       particular, an object or function with internal linkage is expected to be instantiated
       in the same translation unit, and one with external linkage may refer to another, yet
       unknown, translation unit.

    We will call a lambda as the above that does not access external identifiers other than global
    variables or functions a function literal. This term is chosen because such an expression can
    be used like other literals in C: all information for the lambda value is available at compilation
    time. Such function literal can be moved freely within the scope of the identifiers that are
    used.

      V.2.1. Possible syntax. There are several possibilities to specify syntax for lambdas and
    below we will see three such specifications as they are currently implemented in the field:

— C++ lambdas,
— Objective C blocks,
— gcc’s statement expressions.

    A fourth syntax had been proposed by us in some discussions in WG14, namely to ex-
    tend the notion of compound literals to function types. Syntactically this could be quite
    simple: for a compound literal where the type expression is a function specification, the
    brace-enclosed initializer would be expected to be a function body, just as for an ordinary
    function. The successful presence of gcc’s statement expressions as an extension shows that
    such an addition could be added to C’s syntax tree without much difficulties. But these
    two approaches also share the same insufficiencies, namely the semantic ambiguity how
    references to local variables of the enclosing function would resolve.

       V.2.2. The design space for captures and closures. For an object id with automatic storage
    duration there is currently not much a distinction between the visibility of id and the
    possibility to access the object through id. For the current definition of the language this
    sufficient, but if lambdas are able to refer to identifiers that correspond to objects with
    automatic storage duration, things become more complicated. For example, we might want
    to execute a lambda that accesses a local variable x in a context where x is hidden by
    another variable with the same name. So lambdas that access local variables must use a
    different mechanism to do so.
   N2734
           :22                                                                     Jens Gustedt
   P2304R2
 We call lambdas that access identifiers of the context in which they are evaluated, closures,
 and the identifiers that are such accessed by a closure captures. Since lambdas are inherently
 expressions, within the context of C there are several possible interpretations of such a
 capture. The design space for modeling the capture of local variables with existing C features
 can be described as follows:

(1) The identifier id of type τ is evaluated at the point of evaluation of the capture, and
    the value ν of type τ 0 that is determined is used in place throughout the whole lifetime
    of the closure. Such a capture is called a value capture. A closure that has only value
    captures is called a value closure.
    If τ would be an array type it would not be copyable (there is no such thing as an array
    value in C) and thus it would not fit well in the scheme of a value capture. Therefore,
    generally array types (and maybe other, non-copyable, types) are not allowed as value
    captures.
    A value capture can in principle be made visible with three different models as follows.
    They all have in common that id can never appear where a modifiable lvalue is required,
    such as the LHS of an assignment or as the operand of an increment.

        rvalue capture. A value capture id can be presented as an “rvalue”, that is as
        if it were defined as the result of an expression evaluation (0,id). The address
        of a capture in this model cannot be taken. Although this might seem the most
        natural view for the evaluation of lambda expression in C, we are not aware of an
        implementation that that uses this model.

        immutable capture. A value capture id is a lambda-local object of type τ 00 that
        is initialized with ν, where τ 00 is τ 0 with an additional const-qualification. The
        address of such a capture can be taken and, for example, be passed as argument to
        a function call. But nevertheless the underlying object cannot be modified.

        mutable capture. A value capture id is a lambda-local object of type τ 0 that is
        initialized with ν. Such a capture behaves very similar to a function parameter
        that receives the same value as argument on each function call. Such an object is
        mutable during the execution of the closure, but all changes are lost as soon as
        control is returned to the calling context.

    Note that because τ 0 is a type after an evaluation, in all these models qualification or
    atomicity of τ is dropped.

(2) Throughout the life-time of the closure, id refers to the same object that is visible by
    this name at the point of evaluation of the closure. Such a capture is called an lvalue
    capture. A closure that has at least one lvalue capture is called an lvalue closure. Since
    lvalue captures refer to objects, an lvalue closure cannot have a life-time that exceeds
    any of its lvalue captures. Since id is not evaluated at the same time as the lambda
    expression is formed, it has the same type τ inside the body of the lambda. No qualifiers
    are dropped, type derivations such as atomic or array are maintained.

    V.2.3. C++ lambdas. C++ lambdas are the most general existing extension and they also
 fit well into the constraints that we have set ourselves above, namely to be compatible with
 existing storage classes. Their syntactic form if we don’t consider the possibility of adding
 attributes is
                                                         
     [ capture-list ] ( parameter-list ) opt mutableopt -> return-type opt function-body
                                                                                     N2734
    Improve type generic programming                                                         :23
                                                                                     P2304R2
    Identifiers with automatic storage duration are captured exclusively if they are listed in
    the capture-list or if a default capture is given. This is a list of captures, each of one the
    following forms

                 explicit
                 id                         immutable value capture
                 id = expression            immutable value capture with type and
                                            value of expression
                 &id                        lvalue capture
                 &id = lvalue-expression    object alias
                 default
                                            forbidden
                 =                          immutable value capture
                 &                          lvalue capture

    If the optional keyword mutable is present, all captures that would otherwise be immutable
    value captures are mutable value captures, instead. If -> return-type is present it describes
    the return type of the lambda; if not, the return type is deduced from a return statement
    if there is any, or it is void otherwise. The object alias feature introduces a C++ reference
    variable. For C, these constructs would need some avoidable extension to the syntax and
    object semantic, so we will not use these parts of the syntax in the proposed addition to C.
    The parameter-list can be a usual parameter list with the notable extension that the type
    of a parameter can be underspecified by using the auto feature, see below. A lambda that
    has at least one underspecified parameter is a type-generic lambda.
    Lambda values can be used just as function designators as the left operand of a function call,
    and all rules for arguments to such a call and the rules to convert them transfers naturally
    to a lambda call.
    When used outside the LHS of a function call expression, lambdas are just values of some
    object type that is not further specified. Such a lambda type has no declaration syntax, and
    so the only way to store a lambda value into an object is to use the auto feature:

1       auto const λ = []( double x ) { return x +1; };

    By these precautions, for any C++ lambda the original expression that defined the value is
    always known. So the compiler will always master any aspects of the lambda, in particular
    which variables of the context are used as captures. If a lambda value leaves the scope of
    definition of any of its lvalue captures the compiler can print a diagnosis.
    Function literals are special with respect to these aspects, since they do not have any cap-
    tures. This is why these special lambdas allow for a third operation, they can be converted
    to a function pointer:

1       double (*λp ) ( double ) = λ;
2       double (*κp ) ( double ) = []( double x ) { return x +1; };


      V.2.4. Objective C’s blocks. Objective C [ObjectiveC 2014] has a highly evolved lambda
    feature that they call block, see also [Garst 2009; Garst 2016]. Their syntax is
                                      
                      ˆ return-typeopt ( parameter-list )    opt
                                                                   function-body
  N2734
          :24                                                                        Jens Gustedt
  P2304R2
Besides the obvious syntactic difference, blocks lack an important feature of C++ lambdas,
namely the possibility to specify the policy for captures. If used without other specific
extensions, an Objective C block has the same semantic as a C++ value closure, where any
automatic variable in the surrounding context can be used as immutable value capture.
Such a block can be equivalently defined with a C++ lambda as
                                           
              [ = ] ( parameter-list ) opt -> return-type opt function-body

and in particular the variants that omit the return type have a syntax that only differs on
the token sequence that introduces the feature:

                                
                            ˆ       ( parameter-list )   opt
                                                               function-body
                                
                          [=]       ( parameter-list )   opt
                                                               function-body

An important difference arises though, when it comes to lvalue captures, where Objective C
takes a completely different approach than C++. Here, the property if a capture is a value
or an lvalue capture is attributed to the underlying variable itself, not to the closure that
uses it.
A new storage class for managed storage is introduced, unfortunately also called __block;
__block variables are always lvalue captures. Such variables have a lifetime that is prolonged
even after their defining scope is left, as long as there is any living closure that refers to it.
By this, blocks elegantly resolve the lifetime issues of lvalue closures in C++: by definition
a block will never access a variable after its end-of-life. This elegance comes at the cost of
introducing a new storage class with a substantial implementation cost, a certain runtime
overhead, and a lack of expressiveness for the choice of the access model for each individual
capture.
Because of this extension of the lifetime of lvalue captures, for Objective C it is also much
easier to describe functors as variables of block type. The declaration syntax for these is
similar to function pointers, but using a ˆ token instead of *.

   V.2.5. Statement expressions. Statement expressions are an intuitive extension first intro-
duced by the gcc compiler framework. Their basic idea is to surround a compound statement
with parenthesis and thereby to transform such a compound statement into an expression.
The value of such an expression is the value of the last statement if that is an expres-
sion statement, or void if it is any other form of statement. With statements any list of
C statements (including a terminating ; if necessary), the syntax

                                    ({ statements expression; })

is equivalent to the following function call with a C++ lvalue closure as the left operand

                    [ & ] (void) { statements return expression; } ()

  V.2.6. Nested functions. Gcc and related compiler platforms also implement the feature of
a nested function, that is a function that is declared inside the function body of another
function. Obviously, because they are not expressions, nested functions are not lambdas,
but we will see below how they can be effectively used to implement lambdas. On the other
hand, since they cannot be forward-declared, lambda expressions don’t allow for recursion,
so nested functions clearly are more expressive.
                                                                                  N2734
Improve type generic programming                                                          :25
                                                                                  P2304R2
Nested functions can also capture local variables of the surrounding scope. Because they
are not expressions but definitions, the most natural semantic is that of lvalue captures the
use of such variables, and this is the semantic that gcc applies.
Much as global standard C functions, nested functions decay into function pointers if they
are used other than for the LHS of a function call. This is even for functions that need
access to captures, and thus the ABI must be extended to make this possible. The gcc im-
plementation does that by creating a so-called trampoline as an automatic object, namely
as a small function that collects the local information that is necessary and then calls a con-
ventional function to execute the specified function body. Doing so needs execute rights for
the automatic storage in question, which is widely criticized because of its possible security
impact. On the other hand, this approach is uncritical when it is used without captures,
because then the result of the conversion is a simple, conventional, function pointer.
Provided we have an auto feature as presented in Section V.1.1 and a typeof feature as
in Section V.1.2, the semantics of a wide variety of C++ lambdas can be implemented with
nested functions. For example, with the shnell source-to-source rewriting tool [Gustedt
2020a], we have implemented such a transformation as follows. For a value closure of the
form

           [id0 = expr0 , ..., idk = exprk ] ( parameter-list ) function-body0

a definition of a state type _Uniq_Struct, state variable _Uniq_Capt and a definition of a
local function _Uniq_Func are placed inside the closest compound statement that contains
the lambda expression:

    struct _Unique_Struct {
      typeof (expr0) id0 ;
      ...
      typeof (exprk) idk ;
    } _Uniq_Capt ;
    auto _Uniq_Func ( parameter-list ) function-body1

Here, function-body1 is the same as function-body0, only that the contents is prefixed with
definitions of the captures:

    auto const id0 = _Uniq_Capt . id0 ;
    ...
    auto const idk = _Uniq_Capt . idk ;

The lambda expression itself then has to be replaced by an expression that evaluates all the
expressions to be captured, followed by the name of the function:

       ((_Uniq_Capt = (struct _Uniq_Struct){ expr0, ..., exprk }), _Uniq_Func)

Similarly to the above, value captures of the form idI (without expression) can just use idI
for exprI.
Additionally, a C++ lvalue closure that has either a default & token or individual lvalue
captures &idI can be implemented by just removing these elements from the capture list.
Then, the same restrictions for the lifetime of lvalue captures and lambda values applies to
the rewritten code, and it is up to the programmer to verify this property.
   N2734
           :26                                                                             Jens Gustedt
   P2304R2
 Although this approach covers a wide range of C++ lambdas, such a rewriting strategy has
 some limits:

— The lambda expression cannot be used in all places that are valid for expression. This
  are for example an initializer for a variable that is not the first declared variable in a
  declaration or a controlling expression of a for loop.
— The default token = in the capture list is not implementable by such simple rewriting,
— The function body is not checked for an access of automatic variables that are not listed
  in the capture clause.

 References
 Lawrence Crowl. 2010. Comparing Lambda in C Proposal N1451 and C++ FCD N3092. Technical Report
     N1483. ISO. available at http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1483.htm.
 Blaine Garst. 2009. Apple’s extensions to C. Technical Report N1370. ISO. available at http://www.
     open-std.org/jtc1/sc22/wg14/www/docs/n1370.pdf.
 Blaine Garst. 2010. Blocks proposal. Technical Report N1451. ISO. available at http://www.open-std.org/
     jtc1/sc22/wg14/www/docs/n1451.pdf.
 Blaine Garst. 2016. A Closure for C. Technical Report N2030. ISO. available at http://www.open-std.org/
     jtc1/sc22/wg14/www/docs/n2030.pdf.
 Jens Gustedt. 2020a. C source-to-source compiler enhancement from within. Research Report RR-9375.
     INRIA. https://hal.inria.fr/hal-02998412
 Jens Gustedt. 2020b. A Common C/ C++ Core Specification, rev. 2. Technical Report N2522. ISO. available
     at http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2522.pdf.
 Barry Hedquist. 2016. WG14 Minutes, Kona, HI, USA, 26-29 October, 2015. Technical Report N2093.
     ISO. available at http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2093.pdf.
 JeanHeyd Meneide. 2020. Not-So-Magic - typeof(...) in C. Technical Report N2593. ISO. available at
     http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2593.htm.
 ObjectiveC 2014. Programming with Objective-C. Apple Inc., https://developer.apple.com/library/archive/
     documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html.




 VI. PROPOSED WORDING

 This is the proposed text for the whole series of papers, plus an additional provisional
 version of an integration of parts of the typeof proposal. It is given as diff against C17. A
 factored diff for the specific concerns is provided with each individual paper.

— Additions to the text are marked as ::::::
                                      shown.
— Deletions of text are marked as shown.
     CORE 202101 (E)                      § 5.1.1.3, working draft — May 15, 2021                                C17.. N2734


       5. Each source character set member and escape sequence in character constants and string
          literals is converted to the corresponding member of the execution character set; if there is no
          corresponding member, it is converted to an implementation-defined member other than the
          null (wide) character.8)

       6. Adjacent string literal tokens are concatenated.

       7. White-space characters separating tokens are no longer significant. Each preprocessing token
          is converted into a token. The resulting tokens are syntactically and semantically analyzed and
          translated as a translation unit:; ::::
                                             two :::::::::::
                                                  consecutive [ tokens shall be the initial token sequence of
                                                              ::::::::::::::::::::::::::::::::::::::::
          an  attribute specifier or of a balanced token that ends in two consecutive ] tokens.
          ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::


       8. All external object and function references are resolved. Library components are linked to
          satisfy external references to functions and objects not defined in the current translation. All
          such translator output is collected into a program image which contains information needed
          for execution in its execution environment.

    Forward references: universal character names (6.4.3), lexical elements (6.4), preprocessing direc-
    tives (6.10), trigraph sequences (5.2.1.1), attributes (??), external definitions (6.9).
                                             :::::::::::::

    5.1.1.3 Diagnostics
1   A conforming implementation shall produce at least one diagnostic message (identified in an imple-
    mentation-defined manner) if a preprocessing translation unit or translation unit contains a violation
    of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or
    implementation-defined. Diagnostic messages need not be produced in other circumstances.9)
2   EXAMPLE An implementation is required to issue a diagnostic for the translation unit:

              char i;
              int i;


    because in those cases where wording in this document describes the behavior for a construct as being both a constraint error
    and resulting in undefined behavior, the constraint error is still required to be diagnosed.

    5.1.2     Execution environments
1   Two execution environments are defined: freestanding and hosted. In both cases, program startup
    occurs when a designated C function is called by the execution environment. All objects with static
    storage duration shall be initialized (set to their initial values) before program startup. The manner
    and timing of such initialization are otherwise unspecified. Program termination returns control to
    the execution environment.
    Forward references: storage durations of objects (6.2.4), initialization (6.7.10).

    5.1.2.1 Freestanding environment
1   In a freestanding environment (in which C program execution may take place without any benefit
    of an operating system), the name and type of the function called at program startup are implemen-
    tation-defined. Any library facilities available to a freestanding program, other than the minimal set
    required by Clause 4, are implementation-defined.
2   The effect of program termination in a freestanding environment is implementation-defined.

    5.1.2.2 Hosted environment
1   A hosted environment need not be provided, but shall conform to the following specifications if
    present.
      8) An
          implementation need not convert all non-corresponding source characters to the same execution character.
      9) An
          implementation is encouraged to identify the nature of, and where possible localize, each violation. Of course, an
    implementation is free to produce any number of diagnostic messages, often referred to as warnings, as long as a valid
    program is still correctly translated. It can also successfully translate an invalid program. Annex I lists a few of the more
    common warnings.


     modifications to ISO/IEC 9899:2018, § 5.1.2.2 page 10                                                     Environment
     CORE 202101 (E)                         § 6, working draft — May 15, 2021                                  C17.. N2734




    6. Language

    6.1    Notation
1   In the syntax notation used in this clause, syntactic categories (nonterminals) are indicated by italic
    type, and literal words and character set members (terminals) by bold type. A colon (:) following
    a nonterminal introduces its definition. Alternative definitions are listed on separate lines, except
    when prefaced by the words "one of". An optional symbol is indicated by the subscript "opt", so
    that
               { expressionopt }
    indicates an optional expression enclosed in braces.
2   When syntactic categories are referred to in the main text, they are not italicized and words are
    separated by spaces instead of hyphens.
3   A summary of the language syntax is given in Annex A.

    6.2 Concepts
    6.2.1 Scopes of identifiers
1   An identifier can denote an object; a function; a tag or a member of a structure, union, or enumeration;
    a typedef name; a label name; a macro name; or a macro parameter. The same identifier can denote
    different entities at different points in the program. A member of an enumeration is called an
    enumeration constant. Macro names and macro parameters are not considered further here, because
    prior to the semantic phase of program translation any occurrences of macro names in the source file
    are replaced by the preprocessing token sequences that constitute their macro definitions.
2   For each different entity that an identifier designates, the identifier is visible (i.e., can be used) only
    within a region of program text called its scope. Different entities designated by the same identifier
    either have different scopes, or are in different name spaces. There are four kinds of scopes: function,
    file, block, and function prototype. (A function prototype is a declaration of a function that declares
    the types of its parameters.)
3   A label name is the only kind of identifier that has function scope. It can be used (in a goto statement)
    anywhere in the function body
                                :::::
                                       in which it appears, and is declared implicitly by its syntactic
    appearance (followed by a : and a statement). Each         function body has a function scope that is
                                                         :::::::::::::::::::::::::::::::::::::::::::
    separate from  the function  scope   of any  other function   body. In particular, a label is visible in
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    exactly one function scope (the innermost function body in which it appears) and distinct function
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    bodies  may use the same identifier to designate different labels.29)
    ::::::::::::::::::::::::::::::::::::::::::::::::::::::::

4   Every other identifier has scope determined by the placement of its declaration (in a declarator
    or type specifier). If the declarator or type specifier that declares the identifier appears outside
    of any block or list of parameters, the identifier has file scope, which terminates at the end of the
    translation unit. If the declarator or type specifier that declares the identifier appears inside a block
    or within the list of parameter declarations in a function definition, the identifier has block scope,
    which terminates at the end of the associated block. If the declarator or type specifier that declares
    the identifier appears within the list of parameter declarations in a function prototype (not part
    of a function definition), the identifier has function prototype scope, which terminates at the end of
    the function declarator.30) If an identifier designates two different entities in the same name space,
    the scopes might overlap. If so, the scope of one entity (the inner scope) will end strictly before the
    scope of the other entity (the outer scope). Within the inner scope, the identifier designates the entity
    declared in the inner scope; the entity declared in the outer scope is hidden (and not visible) within
    the inner scope.
      29) As a consequence, it is not possible to specify a goto statement that jumps into or out of a lambda or into another
          ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    function.
    ::::::
      30) Identifiers that are defined in the parameter list of a lambda expression do not have prototype scope, but a scope that
          ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    comprises    the whole body of the lambda.
    :::::::::::::::::::::::::::::



     modifications to ISO/IEC 9899:2018, § 6.2.1 page 28                                                           Language
    N2734 C17..                               § 6.2.2, working draft — May 15, 2021                              CORE 202101 (E)


5   Unless explicitly stated otherwise, where this document uses the term "identifier" to refer to some
    entity (as opposed to the syntactic construct), it refers to the entity in the relevant name space whose
    declaration is visible at the point the identifier occurs.
6   Two identifiers have the same scope if and only if their scopes terminate at the same point.
7   Structure, union, and enumeration tags have scope that begins just after the appearance of the
    tag in a type specifier that declares the tag. Each enumeration constant has scope that begins
    just after the appearance of its defining enumerator in an enumerator list. An              identifier that has
                                                                                             :::::::::::::::::::
    an  underspecified    definition  and that designates   an  object, has a scope   that
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                            starts  at the end of its
    initializer and  from  that point  extends to the  whole   translation  unit (for file
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                           scope   identifiers) or to
    the  whole   block  (for block  scope identifiers); if the same  identifier  declares
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                            another    entity with  a
    scope   that encloses the current block, that declaration is hidden as soon as the inner declarator is
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
         31)
    met.
    ::::
              An  identifier that designates a function with an underspecified definition has a scope that
              ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    starts  after the lexically first return statement in its function body or at the end of the function
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    body   if there is no such return, and from that point extends to the whole translation unit. Any
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    other identifier has scope that begins just after the completion of its declarator.
8   As a special case, a type name (which is not a declaration of an identifier) is considered to have
    a scope that begins just after the place within the type name where the omitted identifier would
    appear were it not omitted.
9   NOTE Properties       of the feature to which an identifier refers are not necessarily uniformly available within its whole scope
              :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    of visibility. Examples    are identifiers of objects or functions with an incomplete type that is only completed in a subscope
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    of its visibility, labels that  are only valid targets of goto statements when the jump does not cross the scope of a VLA,
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    identifiers  of objects to which the access is restricted in specific contexts such as signal handlers or lambda expressions, or
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    library features such as setjmp where the use is restricted to a specific subset of the grammar.
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

    Forward references: declarations (6.7), function calls (6.5.2.2), lambda     expressions (6.5.2.6), func-
                                                                          :::::::::::::::::::::::::
    tion definitions (6.9.1), identifiers (6.4.2), macro replacement (6.10.3), name spaces of identifiers
    (6.2.3), source file inclusion (6.10.2), statements and blocks (6.8).

    6.2.2        Linkages of identifiers
1   An identifier declared in different scopes or in the same scope more than once can be made to refer to
    the same object or function by a process called linkage.32) There are three kinds of linkage: external,
    internal, and none.
2   In the set of translation units and libraries that constitutes an entire program, each declaration of a
    particular identifier with external linkage denotes the same object or function. Within one translation
    unit, each declaration of an identifier with internal linkage denotes the same object or function. Each
    declaration of an identifier with no linkage denotes a unique entity.
3   If the declaration of a file scope identifier for an object or a function contains the storage-class
    specifier static, the identifier has internal linkage.33)
4   For an identifier declared with the storage-class specifier extern in a scope in which a prior dec-
    laration of that identifier is visible,34) if the prior declaration specifies internal or external linkage,
    the linkage of the identifier at the later declaration is the same as the linkage specified at the prior
    declaration. If no prior declaration is visible, or if the prior declaration specifies no linkage, then the
    identifier has external linkage.
5   If the declaration of an identifier for a function has no storage-class specifier, its linkage is determined
    exactly as if it were declared with the storage-class specifier extern. If the declaration of an identifier
    for an object has file scope and no storage-class specifier ::  or:::::
                                                                       only :::
                                                                             the::::::::
                                                                                 specifier:::::
                                                                                             auto , its linkage is
    external.
6   The following identifiers have no linkage: an identifier declared to be anything other than an object
    or a function; an identifier declared to be a function parameter; a block scope identifier for an object
    declared without the storage-class specifier extern.
     31) That means, that the outer declaration is not visible for the initializer.
         :::::::::::::::::::::::::::::::::::::::::::::::::
     32) There is no linkage between different identifiers.
     33) A   function declaration can contain the storage-class specifier static only if it is at file scope; see 6.7.1.
     34) As   specified in 6.2.1, the later declaration might hide the prior declaration.


    Language                                                       modifications to ISO/IEC 9899:2018, § 6.2.2 page 29
     CORE 202101 (E)                        § 6.2.3, working draft — May 15, 2021                                    C17.. N2734


7   If, within a translation unit, the same identifier appears with both internal and external linkage, the
    behavior is undefined.
8             Internal :::
    NOTE ::::::         and::::::
                             external::::::
                                      linkage::
                                              is::::
                                                 used::
                                                      to:::::
                                                         access::::::
                                                                objects ::
                                                                        or :::::::
                                                                            functions:::
                                                                                      that::::
                                                                                           have::a ::::::
                                                                                                    lifetime::
                                                                                                             of:::
                                                                                                                 the :::::
                                                                                                                      whole :::::::
                                                                                                                              program
    execution.   It is therefore usually determined  before the execution  of a program  starts.
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                                 For   variables with  a lifetime that
    is not the whole program execution and that are accessed from lambda expressions an additional mechanism called capture
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    is available that dynamically provides the access to the current instance of such a variable within the active function call
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    that defines it.
    :::::::::::

    Forward references: storage     durations of objects (6.2.4), declarations (6.7), expressions (6.5), exter-
                             :::::::::::::::::::::::::::::::
    nal definitions (6.9), statements (6.8).

    6.2.3        Name spaces of identifiers
1   If more than one declaration of a particular identifier is visible at any point in a translation unit, the
    syntactic context disambiguates uses that refer to different entities. Thus, there are separate name
    spaces for various categories of identifiers, as follows:

      — label names (disambiguated by the syntax of the label declaration and use);
      — the tags of structures, unions, and enumerations (disambiguated by following any35) of the
        keywords struct, union, or enum);
      — the members of structures or unions; each structure or union has a separate name space for its
        members (disambiguated by the type of the expression used to access the member via the . or
       -> operator);

      — all other identifiers, called ordinary identifiers (declared in ordinary declarators or as enumera-
        tion constants).

    Forward references: enumeration specifiers (6.7.2.2), labeled statements (6.8.1), structure and union
    specifiers (6.7.2.1), structure and union members (6.5.2.3), tags (6.7.2.3), the goto statement (6.8.6.1).

    6.2.4        Storage durations of objects
1   An object has a storage duration that determines its lifetime. There are four storage durations: static,
    thread, automatic, and allocated. Allocated storage is described in 7.22.3.
2   The lifetime of an object is the portion of program execution during which storage is guaranteed
    to be reserved for it. An object exists, has a constant address,36) and retains its last-stored value
    throughout its lifetime.37) If an object is referred to outside of its lifetime, the behavior is undefined.
    The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the
    end of its lifetime.
3   An object whose identifier is declared without the storage-class specifier _Thread_local , and either
    with external or internal linkage or with the storage-class specifier static, has static storage duration.
    Its lifetime is the entire execution of the program and its stored value is initialized only once, prior
    to program startup.
4   An object whose identifier is declared with the storage-class specifier _Thread_local has thread
    storage duration. Its lifetime is the entire execution of the thread for which it is created, and its
    stored value is initialized when the thread is started. There is a distinct object per thread, and use of
    the declared name in an expression refers to the object associated with the thread evaluating the
    expression. The result of attempting to indirectly access an object with thread storage duration from
    a thread other than the one with which the object is associated is implementation-defined.
5   An object whose identifier is declared with no linkage and without the storage-class specifier static
    has automatic storage duration, as do some compound literals. The result of attempting to indirectly
    access an object with automatic storage duration from a thread other than the one with which the
    object is associated is implementation-defined.
     35) There  is only one name space for tags even though three are possible.
     36) The  term "constant address" means that two pointers to the object constructed at possibly different times will compare
    equal. The address can be different during two different executions of the same program.
     37) In the case of a volatile object, the last store need not be explicit in the program.




     modifications to ISO/IEC 9899:2018, § 6.2.4 page 30                                                                Language
     N2734 C17..                           § 6.2.5, working draft — May 15, 2021                            CORE 202101 (E)


20   Any number of derived types can be constructed from the object and function types, as follows:

       — An array type describes a contiguously allocated nonempty set of objects with a particular
         member object type, called the element type. The element type shall be complete whenever the
         array type is specified. Array types are characterized by their element type and by the number
         of elements in the array. An array type is said to be derived from its element type, and if its
         element type is T, the array type is sometimes called "array of T". The construction of an array
         type from an element type is called "array type derivation".
       — A structure type describes a sequentially allocated nonempty set of member objects (and, in
         certain circumstances, an incomplete array), each of which has an optionally specified name
         and possibly distinct type.
       — A union type describes an overlapping nonempty set of member objects, each of which has an
         optionally specified name and possibly distinct type.
       — A function type describes a function with specified return type. A function type is characterized
         by its return type and the number and types of its parameters. A function type is said to
         be derived from its return type, and if its return type is T, the function type is sometimes
         called "function returning T". The construction of a function type from a return type is called
         "function type derivation".
       — A lambda type is an object type that describes the value of a lambda expression. A complete
         :::::::::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
         lambda    type is characterized but not determined by a return type that is inferred from the
         ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
         function    body of the lambda expression, and by the number, order, and type of parameters
         ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
         that  are  expected  for function calls, and by the lexical position of the lambda expressions in
         ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
         the  program;   the  function    type that has the same return type and list of parameter types as
         ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
         the  lambda is called the prototype ::
         ::::::::::::::::::::::
                                                 of:::
                                                    the::::::::
                                                        lambda.:::
                                                                 A :::::::
                                                                    lambda ::::
                                                                             type::::
                                                                                  has :::
                                                                                      no ::::::   derivation50)
                                                                                          syntax::::::::::
         and   the lexical position of the originating lambda expression determines its scope of visibility.
         ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
         Objects   of such a type shall only be defined as a capture (of another lambda expression) or by
         ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
         an underspecified declaration for which the lambda type is inferred.51) An
         :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                             object of lambda
                                                                                          ::::::::::::::::::
         type   shall only  be  modified    by simple  assignment  (6.5.16.1). A lambda
         ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                           expression that has
         underspecified    parameters has an incomplete lambda type that can be completed by function
         ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
         call arguments,    or, if it has no captures, in a conversion to a function pointer.
         ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

       — A pointer type may be derived from a function type or an object type, called the referenced type. A
         pointer type describes an object whose value provides a reference to an entity of the referenced
         type. A pointer type derived from the referenced type T is sometimes called "pointer to T".
         The construction of a pointer type from a referenced type is called "pointer type derivation".
         A pointer type is a complete object type.
       — An atomic type describes the type designated by the construct _Atomic (type-name). (Atomic
         types are a conditional feature that implementations need not support; see 6.10.8.3.)

     These methods of constructing derived types can be applied recursively.
21   Arithmetic types and pointer types are collectively called scalar types. Array and structure types are
     collectively called aggregate types.52)
22   An array type of unknown size is an incomplete type. It is completed, for an identifier of that type,
     by specifying the size in a later declaration (with internal or external linkage). A structure or union
     type of unknown content (as described in 6.7.2.3) is an incomplete type. It is completed, for all
     declarations of that type, by declaring the same structure or union tag with its defining content later
     in the same scope.
       50) Not even a typeof type specifier with lambda type can be formed. So there is no syntax to make a lambda type a choice
           ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     in a generic selection other than default
     :::::::::::::::::::::::::::::
       51) Another possibility to create an object that has an effective lambda type is to copy a lambda value into allocated storage
           ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     via simple assignment.
     ::::::::::::::::
       52) Note that aggregate type does not include union type because an object with union type can only contain one member at

     a time.


     Language                                                   modifications to ISO/IEC 9899:2018, § 6.2.5 page 33
     CORE 202101 (E)                      § 6.3.1.8, working draft — May 15, 2021                                       N2734


    complex result value is a positive zero or an unsigned zero.
2   When a value of complex type is converted to a real type other than _Bool ,68) the imaginary part of
    the complex value is discarded and the value of the real part is converted according to the conversion
    rules for the corresponding real type.

    6.3.1.8 Usual arithmetic conversions
1   Many operators that expect operands of arithmetic type cause conversions and yield result types in
    a similar way. The purpose is to determine a common real type for the operands and result. For the
    specified operands, each operand is converted, without change of type domain, to a type whose
    corresponding real type is the common real type. Unless explicitly stated otherwise, the common
    real type is also the corresponding real type of the result, whose type domain is the type domain of
    the operands if they are the same, and complex otherwise. This pattern is called the usual arithmetic
    conversions:

            First, if the corresponding real type of either operand is long double, the other operand
            is converted, without change of type domain, to a type whose corresponding real type is
            long double.

            Otherwise, if the corresponding real type of either operand is double, the other operand is
            converted, without change of type domain, to a type whose corresponding real type is double.
            Otherwise, if the corresponding real type of either operand is float, the other operand is
            converted, without change of type domain, to a type whose corresponding real type is float.69)
            Otherwise, the integer promotions are performed on both operands. Then the following rules
            are applied to the promoted operands:
                 If both operands have the same type, then no further conversion is needed.
                 Otherwise, if both operands have signed integer types or both have unsigned integer
                 types, the operand with the type of lesser integer conversion rank is converted to the type
                 of the operand with greater rank.
                 Otherwise, if the operand that has unsigned integer type has rank greater or equal to
                 the rank of the type of the other operand, then the operand with signed integer type is
                 converted to the type of the operand with unsigned integer type.
                 Otherwise, if the type of the operand with signed integer type can represent all of the
                 values of the type of the operand with unsigned integer type, then the operand with
                 unsigned integer type is converted to the type of the operand with signed integer type.
                 Otherwise, both operands are converted to the unsigned integer type corresponding to
                 the type of the operand with signed integer type.

2   The values of floating operands and of the results of floating expressions may be represented in
    greater range and precision than that required by the type; the types are not changed thereby.70)

    6.3.2       Other operands
    6.3.2.1 Lvalues, arrays, function designators and lambdas
1   An lvalue is an expression (with an object type other than void) that potentially designates an
    object;71) if an lvalue does not designate an object when it is evaluated, the behavior is undefined.
    When an object is said to have a particular type, the type is specified by the lvalue used to designate
      68) See6.3.1.2.
      69) For example, addition of a double _Complex and a float entails just the conversion of the float operand to double
    (and yields a double _Complex result).
      70) The cast and assignment operators are still required to remove extra range and precision.
      71) The name "lvalue" comes originally from the assignment expression E1 = E2, in which the left operand E1 is required to

    be a (modifiable) lvalue. It is perhaps better considered as representing an object "locator value". What is sometimes called
    "rvalue" is in this document described as the "value of an expression".
       An obvious example of an lvalue is an identifier of an object. As a further example, if E is a unary expression that is a
    pointer to an object, *E is an lvalue that designates the object to which E points.


     modifications to ISO/IEC 9899:2018, § 6.3.2.1 page 40                                                          Language
    N2734 C17..                          § 6.3.2.1, working draft — May 15, 2021                           CORE 202101 (E)


    the object. A modifiable lvalue is an lvalue that does not have array type, does not have an incomplete
    type, does not have a const-qualified type, and if it is a structure or union, does not have any
    member (including, recursively, any member or element of all contained aggregates or unions) with
    a const-qualified type.
2   Except when it is the operand of the :::::::      specifier,::::
                                              typeof ::::::::     the sizeof operator, the unary & operator,
    the ++ operator, the-- operator, or the left operand of the . operator or an assignment operator, an
    lvalue that does not have array type is converted to the value stored in the designated object (and is
    no longer an lvalue); this is called lvalue conversion. If the lvalue has qualified type, the value has the
    unqualified version of the type of the lvalue; additionally, if the lvalue has atomic type, the value has
    the non-atomic version of the type of the lvalue; otherwise, the value has the type of the lvalue. If the
    lvalue has an incomplete type and does not have array type, the behavior is undefined. If the lvalue
    designates an object of automatic storage duration that could have been declared with the register
    storage class (never had its address taken), and that object is uninitialized (not declared with an
    initializer and no assignment to it has been performed prior to use), the behavior is undefined.
3   Except when it is the operand of the :::::::        specifier,::::
                                               typeof ::::::::     the :::::
                                                                       unary:sizeof operator, or the unary &
    operator, or is a string literal used to initialize an array, an expression that has type "array of type" is
    converted to an expression with type "pointer to type" that points to the initial element of the array
    object and is not an lvalue. If the array object has register storage class, the behavior is undefined.
4   A function designator is an expression that has function type. Except when it is the operand of the
    typeof  specifier, the sizeof operator,72) or the unary & operator, a function designator with type
    :::::::::::::::::::
    "function returning type" is converted to an expression that has type "pointer to function returning
    type".
5   Other   than specified in the following, lambda types shall not be converted to any other object
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    type.    A complete function literal with a type "lambda with prototype P" can be converted
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    implicitly  or explicitly to an expression that has type "pointer to Q", where Q is a function type
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    that is compatible with P.73) :::
    :::::::::::::::::::::::
                                     For::
                                         a :::::::::::
                                           type-generic::::::::
                                                         function::::::
                                                                     literal ::::::::::
                                                                             expression,::::::
                                                                                           types ::
                                                                                                  of::::::::::::::
                                                                                                      underspecified
    parameters   shall  first be completed   according  to the parameters      of the  target
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                               prototype, that is, for
    each  underspecified parameter there shall be a type specifier of a unique type as described in 6.7.11
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    such  that the adjusted parameter type is the same as the adjusted parameter type of the target
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    function  type; after that, the prototype P of the thus completed lambda expression shall be the target
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    prototype
    :::::::::::
                Q.74) ::::
                      The ::::::::
                           function ::::::
                                     pointer::::::
                                             value :::::::
                                                    behaves:::
                                                             as ::
                                                                if a:::::::::
                                                                      function :F:::
                                                                                   of ::::
                                                                                      type::   with:::::::
                                                                                            P ::::  internal::::::::
                                                                                                             linkage,
    a unique  name,    and  the same  function body  as for λ, where    uses  of identifiers
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                              from  enclosing  blocks
    in expressions    that are  not evaluated  are replaced  by  proper    types   or values,
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                                had  been defined   in
    the translation unit and the function pointer had been formed by function-to-pointer conversion of
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    that function. The only differences are that, if λ is not type-generic, the resulting function pointer
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    is the same for the whole program execution whenever a conversion of λ is met75) and
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                                             that the
                                                                                                        :::::::::::
    function  pointer   needs   not  necessarily to be distinct from     any  other   compatible
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                                   function   pointer
    that provides   the  same   observable
    :::::::::::::::::::::::::::::::::::::::
                                            behavior.
    Forward references: lambda        expressions (6.5.2.6) address and indirection operators (6.5.3.2), as-
                              :::::::::::::::::::::::::
    signment operators (6.5.16), common definitions <stddef.h> (7.19), :::::::        specifier :::::
                                                                             typeof ::::::::    6.7.9, initial-
    ization (6.7.10), postfix increment and decrement operators (6.5.2.4), prefix increment and decrement
    operators (6.5.3.1), the sizeof and _Alignof operators (6.5.3.4), structure and union members
    (6.5.2.3). ,:::::
                 type ::::::::
                      inference::::::::
                                (6.7.11).




     72) Because   this conversion does not occur, the operand of the sizeof operator remains a function designator and violates
    the constraints in 6.5.3.4.
      73) It follows that lambdas of different type cannot be assigned to each other. Thus, in the conversion of a function literal
          ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    to a function pointer, the prototype of the originating lambda expression can be assumed to be known, and a diagnostic can
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    be issued if the prototypes do not aggree.
    :::::::::::::::::::::::::::::
      74) Thus a specification of the target function pointer type in a conversion from a type-generic function literal expression
          ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    that
    ::::::::::::
                        syntax ::
           uses the [*] :::::  for:::
                                   VM:::::
                                        types :
                                              is::::::
                                                 invalid.
      75) Thus a function literal that is not type-generic has properties that are similar to a function declared with static and
          ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    inline    . A possible implementation of the lambda type is to be the the function pointer type to which they convert.
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::



    Language                                                modifications to ISO/IEC 9899:2018, § 6.3.2.1 page 41
     CORE 202101 (E)                       § 6.5.1, working draft — May 15, 2021                                  C17.. N2734


      — a type that is the signed or unsigned type corresponding to the effective type of the object,
      — a type that is the signed or unsigned type corresponding to a qualified version of the effective
        type of the object,
      — an aggregate or union type that includes one of the aforementioned types among its members
        (including, recursively, a member of a subaggregate or contained union), or
      — a character type.

8   A floating expression may be contracted, that is, evaluated as though it were a single opera-
    tion, thereby omitting rounding errors implied by the source code and the expression evalua-
    tion method.100) The FP_CONTRACT pragma in <math.h> provides a way to disallow contracted
    expressions. Otherwise, whether and how expressions are contracted is implementation-defined.101)
    Forward references: the FP_CONTRACT pragma (7.12.2), copying functions (7.24.2).

    6.5.1 Primary expressions
    Syntax
1    primary-expression:
                       identifier
                       constant
                       string-literal
                       ( expression )
                       generic-selection



    Semantics
2   An identifier is a primary expression, provided it has been declared as designating an object (in
    which case it is an lvalue) or a function (in which case it is a function designator).102)
3   A constant is a primary expression. Its type depends on its form and value, as detailed in 6.4.4.
4   A string literal is a primary expression. It is an lvalue with type as detailed in 6.4.5.
5   A parenthesized expression is a primary expression. Its type and value are identical to those of the
    unparenthesized expression. It is an lvalue, a function designator, a::::::::
                                                                          lambda ::::::::::
                                                                                  expression,:or a void
    expression if the unparenthesized expression is, respectively, an lvalue, a function designator, a:
    lambda  expression, or a void expression.
    ::::::::::::::::::

6   A generic selection is a primary expression. Its type and value depend on the selected generic
    association, as detailed in the following subclause.
    Forward references: declarations (6.7).

    6.5.1.1 Generic selection
    Syntax
1    generic-selection:
                           _Generic ( assignment-expression , generic-assoc-list )
     generic-assoc-list:
                        generic-association
                        generic-assoc-list , generic-association
     generic-association:
                        type-name : assignment-expression
     100) The intermediate operations in the contracted expression are evaluated as if to infinite range and precision, while the

    final operation is rounded to the format determined by the expression evaluation method. A contracted expression might
    also omit the raising of floating-point exceptions.
     101) This license is specifically intended to allow implementations to exploit fast machine instructions that combine multiple

    C operators. As contractions potentially undermine predictability, and can even decrease accuracy for containing expressions,
    their use needs to be well-defined and clearly documented.
     102) Thus, an undeclared identifier is a violation of the syntax.




     modifications to ISO/IEC 9899:2018, § 6.5.1.1 page 58                                                           Language
    N2734 C17..                            § 6.5.2, working draft — May 15, 2021            CORE 202101 (E)


                             default : assignment-expression



    Constraints
2   A generic selection shall have no more than one default generic association. The type name in a
    generic association shall specify a complete object type other than a variably modified type. No two
    generic associations in the same generic selection shall specify compatible types. The type of the
    controlling expression is the type of the expression as if it had undergone an lvalue conversion,103)
    array to pointer conversion, or function to pointer conversion. That type shall be compatible with at
    most one of the types named in the generic association list. If a generic selection has no default
    generic association, its controlling expression shall have type compatible with exactly one of the
    types named in its generic association list.

    Semantics
3   The controlling expression of a generic selection is not evaluated. If a generic selection has a generic
    association with a type name that is compatible with the type of the controlling expression, then the
    result expression of the generic selection is the expression in that generic association. Otherwise, the
    result expression of the generic selection is the expression in the default generic association. None
    of the expressions from any other generic association of the generic selection is evaluated.
4   The type and value of a generic selection are identical to those of its result expression. It is an lvalue, a
    function designator, a::::::::
                           lambda ::::::::::
                                   expression,:or a void expression if its result expression is, respectively,
    an lvalue, a function designator, :a:::::::
                                         lambda:::::::::::
                                                expression, or a void expression. ::  A :::::::
                                                                                        generic ::::::::
                                                                                                  selection ::::
                                                                                                            that
    is the operand of a typeof specification behaves as if the selected assignment expression had been
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    the  operand.
    ::::::::::::
5   EXAMPLE The cbrt type-generic macro could be implemented as follows:

                #define cbrt(X) _Generic((X),                              \
                                        long double: cbrtl,                \
                                        default: cbrt,                     \
                                        float: cbrtf                       \
                                        )(X)




    6.5.2 Postfix operators
    Syntax
1    postfix-expression:
                     primary-expression
                     postfix-expression [ expression ]
                     postfix-expression ( argument-expression-listopt )
                     postfix-expression . identifier
                     postfix-expression -> identifier
                     postfix-expression ++
                     postfix-expression -
                     ( type-name ) { initializer-list }
                     ( type-name ) { initializer-list , }
    ::::::::::::::::
                     lambda-expression

     argument-expression-list:
                       assignment-expression
                       argument-expression-list , assignment-expression




    103) An   lvalue conversion drops type qualifiers.


    Language                                              modifications to ISO/IEC 9899:2018, § 6.5.2 page 59
     CORE 202101 (E)                       § 6.5.2.1, working draft — May 15, 2021                                   C17.. N2734


    6.5.2.1 Array subscripting
    Constraints
1   One of the expressions shall have type "pointer to complete object type", the other expression shall
    have integer type, and the result has type "type".

    Semantics
2   A postfix expression followed by an expression in square brackets [] is a subscripted designation of
    an element of an array object. The definition of the subscript operator [] is that E1[E2] is identical
    to (*((E1)+(E2))) . Because of the conversion rules that apply to the binary + operator, if E1 is an
    array object (equivalently, a pointer to the initial element of an array object) and E2 is an integer,
    E1[E2] designates the E2 -th element of E1 (counting from zero).
3   Successive subscript operators designate an element of a multidimensional array object. If E is an
    n-dimensional array (n ≥ 2) with dimensions i × j × · · · × k, then E (used as other than an lvalue) is
    converted to a pointer to an (n − 1)-dimensional array with dimensions j × · · · × k. If the unary *
    operator is applied to this pointer explicitly, or implicitly as a result of subscripting, the result is the
    referenced (n − 1)-dimensional array, which itself is converted into a pointer if used as other than an
    lvalue. It follows from this that arrays are stored in row-major order (last subscript varies fastest).
4   EXAMPLE Consider the array object defined by the declaration

                int x[3][5];

    Here x
    is a 3 × 5 array of
    int s; more precisely, x is an array of three element objects, each of which is an array of five int s. In the expression x[i],
    which is equivalent to (*((x)+(i))) , x is first converted to a pointer to the initial array of five int s. Then i is adjusted
    according to the type of x, which conceptually entails multiplying i by the size of the object to which the pointer points,
    namely an array of five int objects. The results are added and indirection is applied to yield an array of five int s. When
    used in the expression x[i][j], that array is in turn converted to a pointer to the first of the int s, so x[i][j] yields an int.

    Forward references: additive operators (6.5.6), address and indirection operators (6.5.3.2), array
    declarators (6.7.6.2).

    6.5.2.2 Function calls
    Constraints
1   The expression that denotes the called function::::::    expression104) shall have type lambda
                                                     postfix::::::::::                               type
                                                                                             :::::::::::
    or
    ::
       pointer to function type,
                            ::::
                                 returning void or returning  a complete object  type other than an array
    type.
2   If the expression that denotes the called function has a type that ::::::
                                                                       postfix::::::::::
                                                                               expression::
                                                                                          is::
                                                                                             a lambda  or if
                                                                                               :::::::::::
    the  type of the function
    :::::::::::::::::::::
                              includes a prototype, the number  of arguments  shall agree with  the number
    of parameters of   the function or lambda type. Each argument shall have a type such that its value
                     :::::::::::::::::::::::::::
    may be assigned to an object with the unqualified version of the type of its corresponding parameter.

    Semantics
3   A postfix expression followed by parentheses () containing a possibly empty, comma-separated list
    of expressions is a function call. The postfix expression denotes the called function ::
                                                                                          or:::::::
                                                                                             lambda. The
    list of expressions specifies the arguments to the function or lambda.
                                                                :::::::::

4   An argument may be an expression of any complete object type. In preparing for the call to a
    function, the arguments are evaluated, and each parameter is assigned the value of the corresponding
    argument.105)
5   If the expression that denotes the called function has lambda     type or type pointer to function
                                                               :::::::::::::::
    returning an object type, the function call expression has the same type as that object type, and has
    the value determined as specified in 6.8.6.4. Otherwise, the function call has type void.
    104) Most often, this is the result of converting an identifier that is a function designator.
    105) A function or lambda can change the values of its parameters,     but these changes cannot affect the values of the arguments.
                    :::::::
    On the other hand, it is possible to pass a pointer to an object, and the function :: or :::::
                                                                                             lambda:can then change the value of the
    object pointed to. A parameter declared to have array or function type is adjusted to have a pointer type as described in 6.9.1.


     modifications to ISO/IEC 9899:2018, § 6.5.2.2 page 60                                                               Language
     N2734 C17..                          § 6.5.2.3, working draft — May 15, 2021                          CORE 202101 (E)


6    If the expression that denotes the called function has a type that does not include a prototype, the
     integer promotions are performed on each argument, and arguments that have type float are
     promoted to double. These are called the default argument promotions. If the number of arguments
     does not equal the number of parameters, the behavior is undefined. If the function is defined with
     a type that includes a prototype, and either the prototype ends with an ellipsis (, ...) or the types
     of the arguments after promotion are not compatible with the types of the parameters, the behavior
     is undefined. If the function is defined with a type that does not include a prototype, and the types
     of the arguments after promotion are not compatible with those of the parameters after promotion,
     the behavior is undefined, except for the following cases:

       — one promoted type is a signed integer type, the other promoted type is the corresponding
         unsigned integer type, and the value is representable in both types;
       — both types are pointers to qualified or unqualified versions of a character type or void.

7    If the expression that denotes the called function ::is :a:::::::
                                                                lambda:::
                                                                       or ::
                                                                          is :a::::::::
                                                                                function:has a type that does
     include a prototype, the arguments are implicitly converted, as if by assignment, to the types of
     the corresponding parameters, taking the type of each parameter to be the unqualified version of
     its declared type. The ellipsis notation in a function prototype declarator causes argument type
     conversion to stop after the last declared parameter. The default argument promotions are performed
     on trailing arguments.
8    No other conversions are performed implicitly; in particular, the number and types of arguments are
     not compared with those of the parameters in a function definition that does not include a function
     prototype declarator.
9    If the lambda or function is defined with a type that is not compatible with the type (of the expression)
            :::::::::
     pointed to by the expression that denotes the called lambda     or function, the behavior is undefined.
                                                              :::::::::

10   There is a sequence point after the evaluations of the function designator and the actual arguments
     but before the actual call. Every evaluation in the calling function (including other function calls) that
     is not otherwise specifically sequenced before or after the execution of the body of the called function
     or lambda is indeterminately sequenced with respect to the execution of the called function.106)
     ::::::::::

11   Recursive function calls shall be permitted, both directly and indirectly through any chain of other
     functions or lambdas.
               ::::::::::
12   EXAMPLE In the function call

               (*pf[f1()]) (f2(), f3() + f4())

     the functions f1, f2, f3, and f4 can be called in any order. All side effects have to be completed before the function pointed
     to by pf[f1()] is called.

     Forward references: function declarators (including prototypes) (6.7.6.3), function definitions
     (6.9.1), the return statement (6.8.6.4), simple assignment (6.5.16.1).

     6.5.2.3 Structure and union members
     Constraints
1    The first operand of the . operator shall have an atomic, qualified, or unqualified structure or union
     type, and the second operand shall name a member of that type.
2    The first operand of the-> operator shall have type "pointer to atomic, qualified, or unqualified
     structure" or "pointer to atomic, qualified, or unqualified union", and the second operand shall
     name a member of the type pointed to.

     Semantics
3    A postfix expression followed by the . operator and an identifier designates a member of a structure
     or union object. The value is that of the named member,107) and is an lvalue if the first expression is
     106) Inother words, function executions do not "interleave" with each other.
     107) If
           the member used to read the contents of a union object is not the same as the member last used to store a value in the
     object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new


     Language                                                modifications to ISO/IEC 9899:2018, § 6.5.2.3 page 61
     N2734 C17..                            § 6.5.2.6, working draft — May 15, 2021                       CORE 202101 (E)


     The first always has static storage duration and has type array of char, but need not be modifiable; the last two have
     automatic storage duration when they occur within the body of a function, and the first of these two is modifiable.
13   EXAMPLE 6 Like string literals, const-qualified compound literals can be placed into read-only memory and can even be
     shared. For example,

                (const char []){"abc"} == "abc"


     might yield 1 if the literals’ storage is shared.
14   EXAMPLE 7 Since compound literals are unnamed, a single compound literal cannot specify a circularly linked object. For
     example, there is no way to write a self-referential compound literal that could be used as the function argument in place of
     the named object endless_zeros below:

                struct int_list { int car; struct int_list *cdr; };
                struct int_list endless_zeros = {0, &endless_zeros};
                eval(endless_zeros);


15   EXAMPLE 8 Each compound literal creates only a single object in a given scope:

                struct s { int i; };

                int f (void)
                {
                      struct s *p = 0, *q;
                      int j = 0;

                again:
                      q = p, p = &((struct s){ j++ });
                      if (j < 2) goto again;

                         return p == q && q->i == 1;
                }


     The function f() always returns the value 1.
 16 Note that if an iteration statement were used instead of an explicit goto and a labeled statement, the lifetime of the unnamed
    object would be the body of the loop only, and on entry next time around p would have an indeterminate value, which would
    result in undefined behavior.

     Forward references: type names (6.7.7), initialization (6.7.10).

     6.5.2.6 Lambda expressions
     Syntax
1     lambda-expression:
     ::::::::::::::::
                         capture-clause parameter-clauseopt attribute-specifier-sequenceopt function-body

       capture-clause:
     ::::::::::::::::
                      [ capture-listopt ]
     ::::::::::::::::
                      [ default-capture ]

       capture-list:
     ::::::::::::::::
                      capture-list-element
     ::::::::::::::::
                      default-capture
     ::::::::::::::::
                      capture-list , capture-list-element

       default-capture:
     ::::::::::::::::
                      =
     ::::::::::::::::
                      &

      capture-list-element:
     ::::::::::::::::
                         value-capture
     ::::::::::::::::
                         lvalue-capture


     Language                                                modifications to ISO/IEC 9899:2018, § 6.5.2.6 page 65
     CORE 202101 (E)                       § 6.5.2.6, working draft — May 15, 2021                                   C17.. N2734




     value-capture:
    ::::::::::::::::
                     capture
    ::::::::::::::::
                     capture = assignment-expression

     lvalue-capture:
    ::::::::::::::::
                            & capture

     capture:
    ::::::::::::::::
                            identifier

     parameter-clause:
    ::::::::::::::::
                            ( parameter-listopt )



    Constraints
2   A  capture that is listed in the capture list is an explicit capture .::If::::
    ::::::::::::::::::::::::::::::::::::::::::
                                                                                the ::::
                                                                                     first::::::::
                                                                                           element ::  in:::
                                                                                                           the::::::::
                                                                                                               capture
    list is a  default capture,   id is the name  of an object with automatic  storage   duration
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                                      in an  enclosing
    block    that is not an array, id is used within the function body of the lambda without redeclaration
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    and   id is not an explicit capture or a parameter, the effect is as if id were a value capture (for an =
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    token)    or an lvalue capture (for an & token). Such a capture is an implicit capture .::
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                                 If:::
                                                                                                    the::::
                                                                                                         first::::::::
                                                                                                               element
    in  the   capture  list is an = token,  all other elements  shall be lvalue captures;
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                             if it is  an  & token, all
    shall   be  value captures.
    :::::::::::::::::::::

3   Value captures without assignment expression or lvalue captures shall be names of complete objects
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    with automatic   storage duration of a block enclosing the lambda expression that are visible and
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    accessible at the point of evaluation of the lambda expression. Additionally, value captures shall
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    not have an  array type. An identifier shall appear at most once; either as an explicit capture or as a
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    parameter  name   in the parameter list.
    ::::::::::::::::::::::::::::::::::

4   Within  the lambda expression, identifiers (including explicit and implicit captures, and parameters
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    of the lambda)    shall be used according to the usual scoping rules, but outside the assignment
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    expression   of a value capture the following exceptions apply to identifiers that are declared in a
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    block that strictly encloses the lambda expression and that are not lvalue captures:
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::


       — Objects or type definitions with VM type shall not be used.
         ::::::::::::::::::::::::::::::::::::::::::::::::::::


       — Objects with automatic storage duration shall not be evaluated.114)
         ::::::::::::::::::::::::::::::::::::::::::::::::::::::::


5   A variable id is an indirect lvalue capture ::
    :::::::::::::::::
                                                    of :a::::::::
                                                          lambda ::::::::::
                                                                  expression ::::
                                                                              and ::
                                                                                   of :::
                                                                                      the::::::::::::::
                                                                                           corresponding :::::::
                                                                                                            lambda
    value if it is one   of  the implicit or explicit lvalue  captures, or recursively, if
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                           it is the indirect lvalue
    capture  of  one   of the  captures  of lambda   type.  A  lambda value  that has  an
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                           indirect  lvalue capture
    id shall not be used as the expression of a return statement, unless that return statement is itself
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    associated   to another lambda expression for which id is an indirect lvalue capture that refers to the
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                   115)
    same  object.
    :::::::::::
                        If a lambda value with an indirect lvalue capture id is used to initialize an object λ
                        :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    of lambda type and id has been defined with the register storage class, λ shall also have the
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    register    storage class.
    :::::::::::::::::::::

6   After determining the type of all captures and parameters, either directly or because a type-generic
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    lambda   appears in a function-call or conversion to function pointer, the function body shall be such
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    that a return type type according to the rules in 6.8.6.4 can be inferred. If the lambda occurs in a
    :::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

     114) Identifiers of visible automatic objects that are not captures and that do not have a VM type, may still be used if they are
          ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    not  evaluated, for example in sizeof expressions, in typeof specifiers (if they are not lambdas themselves) or as controlling
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    expression    of a generic primary expression.
    :::::::::::::::::::::::::::::::
     115) Since each closure expression may have a unique type, it is generally not possible to assign it to an object with lambda
          ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    value   or to a function pointer that is declared outside of its defining scope or to use it, even indirectly, through a pointer to
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    lambda    value. Therefore the present constraint inhibits the use of an lvalue closure outside of the widest enclosing scope of
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    its defining closure expression in which all its lvalue captures are visible.
    ::::::::::::::::::::::::::::::::::::::::::::::::::::



     modifications to ISO/IEC 9899:2018, § 6.5.2.6 page 66                                                               Language
     N2734 C17..                         § 6.5.2.6, working draft — May 15, 2021                          CORE 202101 (E)


     conversion  to a function pointer, the inferred return type shall be compatible to the specified return
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     type of the function pointer; if additionally the lambda is type-generic, the return type shall be the
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     same  as the specified return type.
     ::::::::::::::::::::::::::::::

7    When    a lambda expression with an underspecified parameter is evaluated as a void expression,
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     the capture clause shall fulfill the constraints as specified above. The parenthesized parameter list
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     shall provide a valid list of declarations of parameters, only that one or more of these may have
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     an underspecified  type. After that shall follow a { token, a balanced token sequence (??), and a }
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
            116)
     token.
     :::::


     Semantics
8    The   optional attribute specifier sequence in a lambda expression appertains to the resulting lambda
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     value.   If the parameter clause is omitted, a clause of the form () is assumed. A lambda expression
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     without    any capture is called a function literal expression:,:::::::::
     :::::::::::::::::::::::::::
                                                                     otherwise::it ::
                                                                                   is :::::
                                                                                      called::
                                                                                             a closure expression :. ::
                                                                                                                     A
     lambda     value originating from a function literal expression is called a function literal :, :::::::::
     ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                                        otherwise::  it
     is called
     :::::::::
                 a closure . A closure that has an indirect lvalue  capture is
                           :::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                               called  an lvalue closure , otherwise
                                                                                                         ::::::::::
     it is a value closure :.
     :::::

9    Similar   to a function definition, a lambda expression forms a single block that comprises all of its
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     parts.   Each  explicit capture and parameter has a scope of visibility that starts immediately after
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     its definition  is completed and extends to the end of the function body. The scope of visibility of
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     implicit  captures is the function body. In particular, captures and parameters are visible throughout
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     the  whole   function body, unless they are redeclared in a depending block within that function body.
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     Value  captures   and parameters have automatic storage duration; in each function call to the formed
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     lambda    value, a new instance of each value capture and parameter is created and initialized in order
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     of  declaration  and has a lifetime until the end of the call, only that the addresses of value captures
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     are  not necessarily  unique.
     ::::::::::::::::::::::::

10   A  lambda expression for which at least one parameter declaration in the parameter list has no type
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     specifier  is a type-generic lambda with
     ::::::::::::
                                               an imcomplete lambda type. It shall only be evaluated as a
                                          ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     void   expression,  be the postfix expression of a function call or, if the capture clause is empty, be the
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     operand    of a conversion to a pointer to function with fully specified parameter types, see 6.3.2.1.
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     For   a void  expression, it has only the side effects that result from the evaluation of the capture
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     clause   and  shall be syntactically correct as indicated in the constraints; the translation may fail, if
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     the  function body is such that no possible function call arguments or target types for a conversion
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     could   successfully complete the lambda type; the lambda expression shall otherwise be ignored.
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

11   For  a function call, the type of an argument (after lvalue, array-to-pointer or function-to-pointer
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     conversion)   to an underspecified parameter shall be such that it can be used to complete the type of
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     that parameter   analogous to 6.7.11, only that the inferred type for an parameter of array or function
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     type  is adjusted  analogously to function declarators (6.7.6.3) to a possibly qualified object pointer
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     type  (for an array) or to a function pointer type (for a function) to match type of the argument. For
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     a conversion   of any arguments, the parameter types shall be those of the function type.
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

12   If a value capture id is defined without an assignment expression, the assignment expression is
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     assumed   to be id itself, referring to the object of automatic storage duration of the enclosing block
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     that exists according to the constraints.117)
     ::::::::::::::::::::::::::::::::::

13   The   implicit or explicit assignment expression E in the definition of a value capture determines
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     a  value
     :::::::::
                  with :::::
               E0:::::   type ::
                               T0,:::::::
                                   which ::is::  after ::::::::
                                              E :::::  possible ::::::
                                                                lvalue,:::::::::::::::
                                                                         array-to-pointer:::  or::::::::::::::::::
                                                                                                 function-to-pointer
     conversion.   The type of the capture is T0 const :::
     ::::::::::::::::::::::::::::::::::::::::::
                                                            and:::
                                                                 its:::::
                                                                     value::is::  for ::
                                                                               E0:::: all:::::::::::
                                                                                          evaluations ::
                                                                                                      in:::
                                                                                                         all ::::::::
                                                                                                             function
     calls  to the lambda   value.    If, within  the  function body,   the  address   of  the
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                               capture  id  or  one of
     its members     is taken,  either  explicitly  by  applying  a unary   &  operator   or
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                             by  an array  to  pointer

      116) That means, besides the validity of the capture clause and the parameter list, an implementation is only required to
           ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     parse  the function body as a token sequence but is not required to diagnose additional constraints, such as the validity of
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     the  use of keywords or identifiers within the function body if these are possibly restricted through a syntax derivation or
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     additional  constraints.
     ::::::::::::::::
      117) The evaluation rules in the next paragraph then stipulate that it is evaluated at the point of evaluation of the lambda
           ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     expression,  and that within the body of the lambda an unmutable auto object of the same name, value and type is made
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     accesssible.
     ::::::::



     Language                                               modifications to ISO/IEC 9899:2018, § 6.5.2.6 page 67
      CORE 202101 (E)                        § 6.5.2.6, working draft — May 15, 2021                                    C17.. N2734


                118)
     conversion,
     ::::::::::
                     and that address is used to modify the underlying object, the behavior is undefined.
                     ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::



14   The  evaluation of the explicit or implicit assignment expressions of value captures takes place
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     during   each evaluation of the lambda expression. The evaluation of assignment expressions for
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     explicit value captures is sequenced in order of declaration; an earlier capture may occur within an
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     assignment    expression of a later one. The objects of automatic storage duration corresponding to
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     implicit  value  captures are evaluated unsequenced among each other. The evaluation of a lambda
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     expression   is sequenced  before any use of the resulting lambda value. For each call to a lambda
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     value,  explicit value captures (with type and value as determined during the evaluation of the
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     lambda    expression) and then parameter types and values are determined in order of declaration.
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     Explicit value   captures and earlier parameters may occur within the declaration of a later one.
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

15   The  object of automatic storage duration id of the surrounding scope that corresponds to an lvalue
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     capture  shall be visible within the function body according to the usual scoping rules and shall be
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     accessible within the function body throughout each call to the lambda. Access to the object within
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     a call to the lambda follows the happens-before relation, in particular modifications to the object
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     that happen before the call are visible within the call, and modifications to the object within the call
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     are visible for all evaluations that happen after the call.119)
     ::::::::::::::::::::::::::::::::::::::::::::::::

16   For  each lambda expression, the return type type is inferred as indicated in the constraints. A
     ::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::::::::::::::
     lambda   expression λ that
     :::::::::::::::::
                                     is not type-generic has an unspecified lambda type L that is the same for
                               ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     every  evaluation   of λ ; as  a result of the expression, a value of type L is formed that identifies λ and
     :::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::
     the  specific set of values     of the identifiers in the capture clause for the evaluation, if any. This is
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     called a lambda value :. ::
     :::::::
                                 It ::
                                    is :::::::::::
                                        unspecified,::::::::
                                                     whether::::
                                                               two::::::::
                                                                    lambda ::::::::::
                                                                              expressions:λ and  κ share the same
                                                                                             :::: ::::::::::::::
     lambda   type  even  if they    are lexically equal  but appear  at different points of
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                             the program.  Objects
     of lambda   type  shall  not   be  modified  other then  by simple
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                         assignment.
17   A  lambda expression λ that
     ::::::::::::::::::::
                                     is generic has an incomplete lambda type that is completed when
                                :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     the  expression  is used  directly in a function call expression or converted to a function pointer.
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     When    used  in a function call, the parameter types are inferred in order of declaration, but after
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     the evaluation of the assignment expressions of the explicit value captures, after which the return
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     type  of the lambda is inferred from the function body. The so completed lambda value is then used
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     in the function call which is sequenced after the evaluation of the lambda expression.
     ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
18   NOTE 1 A     direct function call to a function literal expression can be modeled by first performing a conversion of the
               ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     function literal to a function pointer and then calling that function pointer.
     :::::::::::::::::::::::::::::::::::::::::::::::::::::
19   NOTE 2 : A:::::
                direct:::::::
                       function :::
                                call ::
                                      to::
                                         a :::::
                                           closure:::::::::
                                                   expression ::::
                                                              (that ::::
                                                                    may ::
                                                                         be::::::::::
                                                                            type-generic)::::::
                                                                                          without::::::
                                                                                                  default::::::
                                                                                                          capture::::
                                                                                                                  and ::::
                                                                                                                      with
     parameters
     ::::::::

       [
       ::
         captures-no-default::]::(decl1:
                                       ,:::::
                                         ..., :decln ):::
                                                        {
       ::
         block-item-list
       }(arg
       ::    1, ..., argn:)
              :::::::


     can be modeled with a such a call to a closure expression without parameters
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::

       [ _ArgCap = arg1 , ..., _ArgCapn = argn , captures-no-default ] (void) {
       :::::::::1 ::      :::::::::::::: :::   ::                   :::::::::::
         decl1 ::  _ArgCap1 ;
                = :::::::
       ::                  :
         ...
       :::::
         decln ::  _ArgCapn ;
                = ::::::::
       ::                    :
       ::
         block-item-list
       }()
       :::


     where   _ArgCap 1 , . . . , _ArgCap n are new identifiers that are unique for the translation unit. This equivalence uses the fact
     :::::            ::::               :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     that the  evaluation of the argument expressions arg:
     ::::::::::::::::::::::::::::::::::::
                                                                   , ...:
                                                                 1 :::  , argn::::
                                                                                and:::
                                                                                    the ::::::
                                                                                         original::::::
                                                                                                  closure ::::::::
                                                                                                          expression ::as:a:::::
                                                                                                                            whole:::
                                                                                                                                   can:::
                                                                                                                                        be
     evaluated   without    sequencing    constraints before the actual   function call operation.
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                                    In particular, side effects that occur
     during   the evaluation of any of the arguments or the capture list will not effect one another. This not withstanding, side
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     effects that have an influence about the evaluation of captures in the specified capture list or that determine the type of
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     parameters   occur sequenced as specified in the original closure expression.
     :::::::::::::::::::::::::::::::::::::::::::::::::::::

     118) The capture does not have array type, but if it has a union or structure type, one of its members may have such a type.
          :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     119) That is, evaluation of id results in the same lvalue with the same type and address as for the scope surrounding the
          ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     lambda. In particular, it is possible that the value of such an object becomes indeterminate after a call to longjmp, see 7.13.2.1.
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::



      modifications to ISO/IEC 9899:2018, § 6.5.2.6 page 68                                                                Language
     N2734 C17..                         § 6.5.2.6, working draft — May 15, 2021                        CORE 202101 (E)


     Analogously, a closure expression with lvalue default capture
     ::::::::::::::::::::::::::::::::::::::::::::

      [&,
      ::::
          capture-list]::: (decl1:,:::::
                                    ...,:decln ) {
                                               :::
      ::
        block-item-list
      }(arg
      ::    1, ..., argn:)
             :::::::


     can be modeled as follows
     :::::::::::::::::::

      [&, _ArgCap = arg1 , ..., _ArgCapn = argn , capture-list ] (void) {
      :::::::::::1 ::        :::::::::::::: ::: ::            :::::::::::
        decl       _ArgCap1 ;
                = :::::::
             1 ::
      ::                   :
        ...
      :::::
        decln ::   _ArgCapn ;
                = ::::::::
      ::                     :
      ::
        block-item-list
      }()
      :::



     Recommended practice
20   Implementations are encouraged to diagnose any attempt to modify a lambda type object other
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     than by assignment.
     ::::::::::::::::::

21   To  avoid lexical conflicts with the attribute feature (??) the appearance two consecutive [ tokens
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     in the translation unit that do not start an attribute specifier results in undefined behavior (??). It
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     is recommended that implementations that do not accept such a construct issue a diagnosis. For
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     applications, the portable use of a call to a lambda expression as an array subscript, for example, is
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     possible  by surrounding   it with a pair of parenthesis.
     :::::::::::::::::::::::::::::::::::::::::::::::
22   EXAMPLE 1 The    usual scoping rules extend to lambda expressions; the concept of captures only restricts which identifiers
                  :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     may be evaluated or not.
     ::::::::::::::::::

      #include <stdio.h>
      :::::::::::::::::
      static long var;
      ::::::::::::::::
      int main(void) {
      ::::::::::::::::
        [   ](void){ printf("%ld\n", var); }();
      :::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                               // valid, prints 0
                                                              ::::::::::::::::::
        [var](void){ printf("%ld\n", var); }();
      :::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                               // invalid, var is static
                                                              :::::::::::::::::::::::::


          int var = 5;
      ::::::::::::::


        auto const λ = [var](void){ printf("%d\n", var); };      // freeze var
      ::::::::::::::: ::::::::::::::::::::::::::::::::::::: ::::::::::::::::::
        [&var](void){ var = 7; printf("%d\n", var); }();         // valid, prints 7
      ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
        λ();
      ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                 // valid, prints 5
                                                                 ::::::::::::::::::
        [ var](void){ printf("%d\n", var); }();
      ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                 // valid, prints 7
                                                                 ::::::::::::::::::
        [    ](void){ printf("%d\n", var); }();
      ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                 // invalid
                                                                 ::::::::::
        [ var](void){ printf("%zu\n", sizeof var); }();
      ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                 // valid, prints sizeof(int)
                                                                 ::::::::::::::::::::::::::::
        [    ](void){ printf("%zu\n", sizeof var); }();
      ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                 // valid, prints sizeof(int)
                                                                 ::::::::::::::::::::::::::::
        [    ](void){ extern long var; printf("%ld\n", var; }(); // valid, prints 0
      :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::


      }
      :




23   EXAMPLE 2 The following uses a function literal as a comparison function argument for qsort.
               :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

      #define SORTFUNC(TYPE) [](size_t nmemb, TYPE A[nmemb]) {
      ::::::::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::: :
                                                                                       \
        qsort(A, nmemb, sizeof( A[0]),
      :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                       \
              [](void const x, void const:::
      :::::::::::::::::::::*::::::::::::::*
                                              y) {          /* ::::::::::
                                                :::::::::::: ::
                                                                comparison:::::::
                                                                           lambda::::
                                                                                   */ ::
                                                                                       \
                TYPE X = *(TYPE  const*) x;
      :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                       \
                TYPE Y = *(::::
      ::::::::::::::::::::
                           TYPE::::::
                                 const::
                                      *):y:
                                          ;:::::::::::::::::::::::::::::::::::::::::   \
                return (X < Y)  ? -1 : (( X > Y)  ? 1 : 0)
      ::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                          ; /   return of type int  /
                                                              * :::::::::::::::::::::
                                                                                   * ::\
              }
      :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :
                                                                                       \
              );
      :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :
                                                                                       \
        return A;
      :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :
                                                                                       \
        }
      :::
        ...
      :::::
        long C[5] = { 4, 3, 2, 1, 0, };
      ::::::::::::::::::::::::::::::::



     Language                                              modifications to ISO/IEC 9899:2018, § 6.5.2.6 page 69
      CORE 202101 (E)                      § 6.5.2.6, working draft — May 15, 2021                                  C17.. N2734


         SORTFUNC(long)(5, C);                              // lambda → (pointer →) function call
       ::::::::::::::::::::::: :::::::::::::::::::::: :::::::::: ::::::::::::::::::::::::::
         ...
       :::::
         auto const sortDouble = SORTFUNC(double);          // lambda value → lambda object
       :::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::: ::::::::::::::
         double   ( sF ) (size_
                   * ::::::::::::::::::::::::::::::::::::::::::::;: ::::
                               t nmemb , double[ nmemb ]) = sortDouble    //:::::::::::
                                                                             conversion
       ::::::::*::::
         ...
       :::::
         double ::::
       ::::::::*
                  ap ::
                      = ::::::::::
                         sortDouble:::
                                   (4,::(::::::
                                         double[]) { 5, 8.9, 0.1, 99, });
                                                ::::::::::::::::::::::::
         double  B[27]   = { /  some values  ...
       ::::::::::::::::::::*:::::::::::::::::::   */ :::
                                                      };
         sF(27, B);                                        // reuses the same function
       ::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::
         ...
       :::::
         double ::::
       ::::::::*
                  (*sG )(size_t nmemb, double[nmemb]) = SORTFUNC(double); // conversion
                     ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::


     This code evaluates the macro SORTFUNC twice, therefore in total four lambda expressions are formed.
     ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     The  function literals of the "comparison lambdas" are not operands of a function call expression, and so by conversion a
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     pointer   to function is formed and passed to the corresponding call of qsort. Since the respective captures are empty, the
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     effect is as if to define two comparison functions, that could equally well be implemented as static functions with auxiliary
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     names    and  these names could be used to pass the function pointers to qsort.
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::
     The outer lambdas are again without capture. In the first case, for long, the lambda value is subject to a function call, and
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     it is unspecified if the function call uses a specific lambda type or directly uses a function pointer. For the second, a copy
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     of  the lambda value is stored in the variable sortDouble and then converted to a function pointer sF. Other than for the
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     difference  in the function arguments, the effect of calling the lambda value (for the compound literal) or the function pointer
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     (for  array B) is the same.
     ::::::::::::::::::
     For optimization purposes, an implementation may fold lambda values that are expanded at different points of the program
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     such that effectively only one function is generated. For example here the function pointers sF and sG may or may not be
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     equal.
     :::::
24   EXAMPLE 3 Consider the following type-generic function literal that computes the maximum value of two parameters X
               :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     and Y
     :::::
           .

       #define MAXIMUM(X, Y)                               \
       ::::::::::::::::::::: ::::::::::::::::::::::::::::: :
           [](auto a, auto b){                             \
       ::::::::::::::::::::::: ::::::::::::::::::::::::::: :
             return (a < 0)                                \
       :::::::::::::::::::: :::::::::::::::::::::::::::::: :
                    ? ((b <  0) ? ((a < b) ? b : a) : b)
       :::::::::::::::::::: ::::::::::::::::::::::::::::::::
                                                            \
                    : ((b >= 0) ? ((a < b) ? b : a) : a);
       ::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                            \
           }(X , Y)
       ::::::::::::


           auto R = MAXIMUM(-1, -1U);
       :::::::::::::::::::::::::::::
           auto S = MAXIMUM(-1U, -1L);
       ::::::::::::::::::::::::::::::



     After preprocessing, the definition of R, becomes
     :::::::::::::::::::::::::::::::::::

       auto R = [](auto a, auto b){
       :::::::::::::::::::::::::::
         return (a < 0)
       ::::::::::::::::
            ? ((b < 0) ? ((a < b) ? b : a) : b)
       :::::::::::::: ::::::::::::::::::::::::::
            : ((b >= 0) ? ((a < b) ? b : a) : a);
       :::::::::::::::::::::::::::::::::::::::::
         }(-1, -1U);
       :::::::::::::


     To  determine type and value of R, first the type of the parameters in the function call are inferred to be signed int and
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     unsigned    int, respectively. With this information, the type of the return expression becomes the common arithmetic type
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     of the two, which is unsigned int. Thus the return type of the lambda is that type. The resulting lambda value is the first
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     operand  to the function call operator () . So R has the type unsigned int and a value of UINT_MAX.
     ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     For S, a similar deduction shows that the value still is UINT_MAX but the type could be unsigned int (if int and long have
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     the same   width) or long (if long is wider than int).
     :::::::::::::::::::::::::::::::::::::
     As  long as they are integers, regardless of the specific type of the arguments, the type of the expression is always such that
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     the  mathematical maximum of the values fits. So MAXIMUM implements a type-generic maximum macro that is suitable for
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     any  combination of integer types.
     ::::::::::::::::::::::::
25   EXAMPLE 4

       void matmult(size_t k, size_t l, size_t m,
       :::::::::::::::::::::::::::::::::::::::::
                    double const A[k][l], double const B[l][m], double const C[k][m]) {
       ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
         // dot product  with stride of m for B
       ::::::::::::::::::::::::::::::::::::::
         // ensure constant  propagation of l and m
       ::::::::::::::::::::::::::::::::::::::::::
         auto const λδ =  [l,m](double const v[l], double const B[l][m], size_t m0) {
       :::::::::::::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::



      modifications to ISO/IEC 9899:2018, § 6.5.2.6 page 70                                                            Language
    N2734 C17..                           § 6.5.3, working draft — May 15, 2021                            CORE 202101 (E)


          double ret = 0.0;
      ::::::::::::::::::::
          for (size_t i = 0; i < l; ++i) {
      :::::::::::::::::::::::::::::::::::
            ret += v[i] B[i][m0];
      :::::::::::::::::*:::::::::
          }
      :::::
          return ret;
      :::::::::::::::
        };
      ::::
        // vector matrix product
      :::::::::::::::::::::::::
        // ensure constant propagation of l and m, and accessibility of λδ
      ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
        auto const λµ = [l, m, &λδ ](double const v[l], double const B[l][m], double res[m]) {
      :::::::::::::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
          for (size_t m0 = 0; m0 < m; ++m0) {
      ::::::::::::::::::::::::::::::::::::::
            res[m0] = λδ (v, B, m0);
      ::::::::::::::::::::::::::::
          }
      :::::
        };
      ::::
        for (size_t k0 = 0; k0 < k; ++k0) {
      ::::::::::::::::::::::::::::::::::::
          double const ( Ap)[l] = A[k0];
      ::::::::::::::::::*:::::::::::::::
          double (*Cp
      :::::::::::::
                       )[m] = C[k0];
                     ::::::::::::::
          λµ( Ap , B,
             * ::::::::
      ::::::::         *Cp);
                        :::
        }
      :::
      }
      :




    This  function evaluates two closures; λδ :::
    :::::::::::::::::::::::::::
                                               has :a :::::
                                                      return :::
                                                             type::
                                                                  of::::::
                                                                     double,:λµ ::of ::::
                                                                                     void. ::::
                                                                                            Both ::::::
                                                                                                 lambda :::::
                                                                                                         values ::::
                                                                                                                 serve ::::::::
                                                                                                                       repeatedly ::
                                                                                                                                  as
    first operand  to function evaluation  but the evaluation  of the captures is only done
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                              once for each of the closures. For the
    purpose   of optimization, an implementation could generate copies of the underlying functions for each evaluation of such
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    a closure such that the values of the captures l and m are replaced on a machine instruction level.
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

                         type:::::::
    Forward references: ::::  names ::::::
                                     (6.7.7),:::::::::
                                             attributes ::::
                                                        (??).:

    6.5.3     Unary operators
    Syntax
1    unary-expression:
                            postfix-expression
                            ++ unary-expression
                            - unary-expression
                            unary-operator cast-expression
                            sizeof unary-expression
                            sizeof ( type-name )
                            _Alignof ( type-name )

     unary-operator: one of
                          &    *   +    - ˜ !




    6.5.3.1 Prefix increment and decrement operators
    Constraints
1   The operand of the prefix increment or decrement operator shall have atomic, qualified, or unquali-
    fied real or pointer type, and shall be a modifiable lvalue.

    Semantics
2   The value of the operand of the prefix ++ operator is incremented. The result is the new value of the
    operand after incrementation. The expression ++E is equivalent to (E+=1) . See the discussions of
    additive operators and compound assignment for information on constraints, types, side effects,
    and conversions and the effects of operations on pointers.
3   The prefix-- operator is analogous to the prefix ++ operator, except that the value of the operand is
    decremented.
    Forward references: additive operators (6.5.6), compound assignment (6.5.16.2).


    Language                                                modifications to ISO/IEC 9899:2018, § 6.5.3.1 page 71
    CORE 202101 (E)                          § 6.5.5, working draft — May 15, 2021                   N2734


    Constraints
2   Unless the type name specifies a void type, the type name shall specify atomic, qualified, or
    unqualified scalar type, and the operand shall have scalar type:, ::: or, :::
                                                                              the ::::
                                                                                  type::::::
                                                                                       name ::::
                                                                                             shall:::::::
                                                                                                   specify:::
                                                                                                           an
    atomic,  qualified, or unqualified pointer to function with prototype, and the operand is a function
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    literal such a conversion (6.3.2.1) from the function literal to the function pointer type is defined.
    ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

3   Conversions that involve pointers, other than where permitted by the constraints of 6.5.16.1, shall be
    specified by means of an explicit cast.
4   A pointer type shall not be converted to any floating type. A floating type shall not be converted to
    any pointer type.

    Semantics
5   Preceding an expression by a parenthesized type name converts the value of the expression to the
    unqualified version of the named type. This construction is called a cast.122) A cast that specifies no
    conversion has no effect on the type or value of an expression.
6   If the value of the expression is represented with greater range or precision than required by the type
    named by the cast (6.3.1.8), then the cast specifies a conversion even if the type of the expression is
    the same as the named type and removes any extra range and precision.
    Forward references: equality operators (6.5.9), function declarators (including prototypes) (6.7.6.3),
    simple assignment (6.5.16.1), type names (6.7.7).

    6.5.5       Multiplicative operators
    Syntax
1    multiplicative-expression:
                        cast-expression
                        multiplicative-expression * cast-expression
                        multiplicative-expression / cast-expression
                        multiplicative-expression % cast-expression



    Constraints
2   Each of the operands shall have arithmetic type. The operands of the % operator shall have integer
    type.

    Semantics
3   The usual arithmetic conversions are performed on the operands.
4   The result of the binary * operator is the product of the operands.
5   The result of the / operator is the quotient from the division of the first operand by the second; the
    result of the % operator is the remainder. In both operations, if the value of the second operand is
    zero, the behavior is undefined.
6   When integers are divided, the result of the / operator is the algebraic quotient with any fractional
    part discarded.123) If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a;
    otherwise, the behavior of both a/b and a%b is undefined.

    6.5.6 Additive operators
    Syntax
1    additive-expression:
                        multiplicative-expression
                        additive-expression + multiplicative-expression
                        additive-expression - multiplicative-expression
    122) A   cast does not yield an lvalue.
    123) This  is often called "truncation toward zero".


    modifications to ISO/IEC 9899:2018, § 6.5.6 page 74                                          Language
    N2734 C17..                        § 6.5.16.1, working draft — May 15, 2021                         CORE 202101 (E)


    Constraints
2   An assignment operator shall have a modifiable lvalue as its left operand.

    Semantics
3   An assignment operator stores a value in the object designated by the left operand. An assignment
    expression has the value of the left operand after the assignment,129) but is not an lvalue. The type of
    an assignment expression is the type the left operand would have after lvalue conversion. The side
    effect of updating the stored value of the left operand is sequenced after the value computations of
    the left and right operands. The evaluations of the operands are unsequenced.

    6.5.16.1 Simple assignment
    Constraints
1   One of the following shall hold:130)

      — the left operand has atomic, qualified, or unqualified arithmetic type, and the right has
        arithmetic type;

      — the left operand has an atomic, qualified, or unqualified version of a structure or union type
        compatible with the type of the right;

      — the left operand has :::
                             the :::::::::::
                                 unqualified :::::::
                                             version ::
                                                     of :::
                                                        the:::::::
                                                            lambda:::::
                                                                   type ::
                                                                        of:::
                                                                           the::::::
                                                                               right;

      — the left operand has atomic, qualified, or unqualified pointer type, and (considering the type
        ::::::::::::::::::
        the left operand would have after lvalue conversion) both operands are pointers to qualified
        or unqualified versions of compatible types, and the type pointed to by the left has all the
        qualifiers of the type pointed to by the right;

      — the left operand has atomic, qualified, or unqualified pointer type, and (considering the type
        the left operand would have after lvalue conversion) one operand is a pointer to an object type,
        and the other is a pointer to a qualified or unqualified version of void, and the type pointed to
        by the left has all the qualifiers of the type pointed to by the right;

      — the left operand is an atomic, qualified, or unqualified pointer ::  to::::::::
                                                                                function:::::
                                                                                           with :a::::::::::
                                                                                                   prototype,
        the right  operand   is a function literal, and the prototypes of the  function
        ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                          pointer  and of the
        function  literal shall be such that a conversion  from the function literal to the
        ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                            function  pointer
        type is defined;
        ::::::::::::::

      — the left operand is an atomic, qualified, or unqualified pointer, and the right is a null pointer
        :::::::::::::::::::::::::::::::::::::::::::::::::::::::
        constant; or

      — the left operand has type atomic, qualified, or unqualified _Bool , and the right is a pointer.

    Semantics
2   In simple assignment (=), the value of the right operand is converted to the type of the assignment
    expression and replaces the value stored in the object designated by the left operand.
3   If the value being stored in an object is read from another object that overlaps in any way the
    storage of the first object, then the overlap shall be exact and the two objects shall have qualified or
    unqualified versions of a compatible type; otherwise, the behavior is undefined.
4   EXAMPLE 1 In the program fragment

               int f(void);
               char c;
               /* ... */

    129) The  implementation is permitted to read the object to determine the value but is not required to, even when the object
    has volatile-qualified type.
     130) The asymmetric appearance of these constraints with respect to type qualifiers is due to the conversion (specified in

    6.3.2.1) that changes lvalues to "the value of the expression" and thus removes any type qualifiers that were applied to the
    type category of the expression (for example, it removes const but not volatile from the type int volatile * const).


    Language                                             modifications to ISO/IEC 9899:2018, § 6.5.16.1 page 81
     CORE 202101 (E)                    § 6.5.16.2, working draft — May 15, 2021                               C17.. N2734


              if ((c = f()) == -1)
                    /* ... */

    the int value returned by the function could be truncated when stored in the char, and then converted back to int width
    prior to the comparison. In an implementation in which "plain" char has the same range of values as unsigned char (and
    char is narrower than int), the result of the conversion cannot be negative, so the operands of the comparison can never
    compare equal. Therefore, for full portability, the variable c would be declared as int.
5   EXAMPLE 2 In the fragment:

              char c;
              int i;
              long l;

              l = (c = i);

    the value of i is converted to the type of the assignment expression c = i, that is, char type. The value of the expression
    enclosed in parentheses is then converted to the type of the outer assignment expression, that is, long int type.
6   EXAMPLE 3 Consider the fragment:

              const char **cpp;
              char *p;
              const char c = ’A’;

              cpp = &p;             // constraint violation
              *cpp = &c;            // valid
              *p = 0;               // valid

    The first assignment is unsafe because it would allow the following valid code to attempt to change the value of the const
    object c.
7   EXAMPLE 4 Lambda  types can be assigned in a portable way, only if both lambda types originate from the same lambda
                :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    expression.
    ::::::::

          auto λ = [s = 0](){ puts("hello"); };
      ::::::::::: :::::::::::::::::::::::::::::
          auto κ = [s = 0](){ puts("hello"); };
      ::::::::::: :::::::::::::::::::::::::::::
          κ = λ;                                       // invalid, different types
      :::::: ::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::
          auto  λp = (false ? &λ : malloc(sizeof(λ))); // pointer to lambda
      ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
          *λp  = λ;                                    // valid, same type
      ::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::
          (*λ p)();                                    // valid, prints ``hello’’
      ::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::




    6.5.16.2 Compound assignment
    Constraints
1   For the operators += and-= only, either the left operand shall be an atomic, qualified, or unqualified
    pointer to a complete object type, and the right shall have integer type; or the left operand shall have
    atomic, qualified, or unqualified arithmetic type, and the right shall have arithmetic type.
2   For the other operators, the left operand shall have atomic, qualified, or unqualified arithmetic type,
    and (considering the type the left operand would have after lvalue conversion) each operand shall
    have arithmetic type consistent with those allowed by the corresponding binary operator.

    Semantics
3   A compound assignment of the form E1 op= E2 is equivalent to the simple assignment expression
    E1 = E1 op (E2) , except that the lvalue E1 is evaluated only once, and with respect to an inde-
    terminately-sequenced function call, the operation of a compound assignment is a single evalu-
    ation. If E1 has an atomic type, compound assignment is a read-modify-write operation with
    memory_order_seq_cst memory order semantics.
4   NOTE Where a pointer to an atomic object can be formed and E1 and E2 have integer type, this is equivalent to the following
    code sequence where T1 is the type of E1 and T2 is the type of E2:

              T1 *addr = &E1;


     modifications to ISO/IEC 9899:2018, § 6.5.16.2 page 82                                                       Language
      CORE 202101 (E)                        § 6.6, working draft — May 15, 2021                                    C17.. N2734


     6.6 Constant expressions
     Syntax
1     constant-expression:
                         conditional-expression



     Description
2    A constant expression can be evaluated during translation rather than runtime, and accordingly
     may be used in any place that a constant may be.

     Constraints
3    Constant expressions shall not contain assignment, increment, decrement, function-call, or comma
     operators, except when they are contained within a subexpression that is not evaluated.132)
4    Each constant expression shall evaluate to a constant that is in the range of representable values for
     its type.

     Semantics
5    An expression that evaluates to a constant is required in several contexts. If a floating expression
     is evaluated in the translation environment, the arithmetic range and precision shall be at least as
     great as if the expression were being evaluated in the execution environment.133)
6    An integer constant expression134) shall have integer type and shall only have operands that are integer
     constants, enumeration constants, character constants, sizeof expressions whose results are integer
     constants, _Alignof expressions, and floating constants that are the immediate operands of casts.
     Cast operators in an integer constant expression shall only convert arithmetic types to integer types,
     except as part of an operand to the sizeof or _Alignof operator.
7    More latitude is permitted for constant expressions in initializers. Such a constant expression shall
     be, or evaluate to, one of the following:

       — an arithmetic constant expression,

       — a null pointer constant,

       — an address constant, or

       — an address constant for a complete object type plus or minus an integer constant expression.

8    An arithmetic constant expression shall have arithmetic type and shall only have operands that are
     integer constants, floating constants, enumeration constants, character constants, sizeof expressions
     whose results are integer constants, and _Alignof expressions. Cast operators in an arithmetic
     constant expression shall only convert arithmetic types to arithmetic types, except as part of an
     operand to a sizeof or _Alignof operator.
9    An address constant is a null pointer, a pointer to an lvalue designating an object of static storage
     duration, or a pointer to a function designator; it shall be created explicitly using the unary &
     operator or an integer constant cast to pointer type, or implicitly by the use of an expression of array
     or function type. The array-subscript [] and member-access . and-> operators, the address & and
     indirection * unary operators, and pointer casts may be used in the creation of an address constant,
     but the value of an object shall not be accessed by use of these operators.
10   An implementation may accept other forms of constant expressions.
     132) The               typeof, sizeof or _Alignof ::::::
               operand of a ::::::                         alignof:operator is usually not evaluated (6.5.3.4).
     133) The  use of evaluation formats as characterized by FLT_EVAL_METHOD also applies to evaluation in the translation
     environment.
      134) An integer constant expression is required in a number of contexts such as the size of a bit-field member of a structure,

     the value of an enumeration constant, and the size of a non-variable length array. Further constraints that apply to the integer
     constant expressions used in conditional-inclusion preprocessing directives are discussed in 6.10.1.


      modifications to ISO/IEC 9899:2018, § 6.6 page 84                                                                Language
    N2734 C17..                          § 6.7.1, working draft — May 15, 2021                          CORE 202101 (E)


    6.7.1      Storage-class specifiers
    Syntax
1    storage-class-specifier:
                           typedef
                           extern
                           static
                           _Thread_local
                           auto
                           register


    Constraints
2   At most, one storage-class specifier may be given in the declaration specifiers in a declaration, except
    that _Thread_local may appear with static or extern ,::::  and::::
                                                                    that:::::  may:::::::
                                                                         auto ::::   appear ::::
                                                                                             with:::
                                                                                                   all ::::::
                                                                                                       others
                       137)
    but with typedef
    ::::::::::::::::
                      .
3   In the declaration of an object with block scope, if the declaration specifiers include _Thread_local ,
    they shall also include either static or extern. If _Thread_local appears in any declaration of an
    object, it shall be present in every declaration of that object.
4   _Thread_local shall not appear in the declaration specifiers of a function declaration. auto shall
                                                                                            :::::::::
    only appear in the declaration specifiers of an identifier with file scope if the declaration is also a
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    definition or if a definition of that identifier is already visible.
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::


    Semantics
5   The typedef specifier is called a "storage-class specifier" for syntactic convenience only; it is
    discussed in 6.7.8. The meanings of the various linkages and storage durations were discussed in
    6.2.2 and 6.2.4.
6   A declaration of an identifier for an object with storage-class specifier register suggests that
    access to the object be as fast as possible. The extent to which such suggestions are effective is
    implementation-defined.138)
7   The declaration of an identifier for a function that has block scope shall have no explicit storage-class
    specifier other than extern.
8   If an aggregate or union object is declared with a storage-class specifier other than typedef, the
    properties resulting from the storage-class specifier, except with respect to linkage, also apply to the
    members of the object, and so on recursively for any aggregate or union member objects.
9   If auto appears with another storage-class specifier, or if it appears in a declaration at file scope it
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    is ignored for the purpose of determining a storage class or linkage. It then only indicates that the
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    declared  type may be inferred from an initializer (for objects see 6.7.11), or from the function body
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    (for functions see 6.8.6.4).
    :::::::::::::::::::::::

    Forward references: type definitions (6.7.8):, ::::
                                                   type:::::::::
                                                        inference :::::::
                                                                  (6.7.11),::::::::
                                                                            function::::::::::
                                                                                    definitions::::::
                                                                                               (6.9.1).

    6.7.2 Type specifiers
    Syntax
1    type-specifier:
                           void
                           char
                           short
                           int

    137) See"future language directions" (6.11.5).
    138) The implementation can treat any register declaration simply as an auto declaration. However, whether or not
    addressable storage is actually used, the address of any part of an object declared with storage-class specifier register
    cannot be computed, either explicitly (by use of the unary & operator as discussed in 6.5.3.2) or implicitly (by converting
    an array name to a pointer as discussed in 6.3.2.1). Thus, the only operator that can be applied to an array declared with
    storage-class specifier register is sizeof.


    Language                                                modifications to ISO/IEC 9899:2018, § 6.7.2 page 87
    CORE 202101 (E)                 § 6.7.2, working draft — May 15, 2021                      C17.. N2734


                       long
                       float
                       double
                       signed
                       unsigned
                       _Bool
                       _Complex
                     atomic-type-specifier
                     struct-or-union-specifier
                     enum-specifier
                     typedef-name
    ::::::::::::::::
                     typeof-specifier



    Constraints
2   At Unless  stated otherwise, at least one type specifier shall be given in the declaration specifiers in
        ::::::::::::::::::::::::
    each declaration, and in the specifier-qualifier list in each struct declaration and type name. Each list
    of type specifiers shall be one of the following multisets (delimited by commas, when there is more
    than one multiset per item); the type specifiers may occur in any order, possibly intermixed with the
    other declaration specifiers.

      — void
      — char
      — signed char
      — unsigned char
      — short, signed short, short int, or signed short int
      — unsigned short, or unsigned short int
      — int, signed, or signed int
      — unsigned, or unsigned int
      — long, signed long, long int, or signed long int
      — unsigned long, or unsigned long int
      — long long, signed long long, long long int, or signed long long int
      — unsigned long long, or unsigned long long int
      — float
      — double
      — long double
      — _Bool
      — float _Complex
      — double _Complex
      — long double _Complex
      — atomic type specifier
      — struct or union struct or union specifier
                        :::::::::::::::

      — enum enum
             ::::
                  specifier
      — typedef name typedef name
                     :::::::::::::

      — typeof specifier.
        :::::::::::::::


3   The type specifier _Complex shall not be used if the implementation does not support complex types
    (see 6.10.8.3).


    modifications to ISO/IEC 9899:2018, § 6.7.2 page 88                                           Language
    N2734 C17..                          § 6.7.2.1, working draft — May 15, 2021                           CORE 202101 (E)


    Semantics
4   Specifiers for structures, unions, enumerations, and atomic types are discussed in 6.7.2.1 through
    6.7.2.4. Declarations of typedef names are discussed in 6.7.8. The characteristics of the other types
    are discussed in 6.2.5. Declarations  for which the type specifiers are inferred from initializers are
                              ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    discussed  in 6.7.11.
    :::::::::::::::::

5   Each of the comma-separated multisets designates the same type, except that for bit-fields, it is
    implementation-defined whether the specifier int designates the same type as signed int or the
    same type as unsigned int.
6   A  declaration that contains no type specifier is said to be underspecified. Identifiers that are such
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    declared  have incomplete type. Their type can be completed by type inference from an initialization
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    (for objects) or from return statements in a function body (for return types of functions).
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

    Forward references: atomic type specifiers (6.7.2.4), enumeration specifiers (6.7.2.2), structure and
    union specifiers (6.7.2.1), tags (6.7.2.3), type definitions (6.7.8). :, ::::
                                                                             type:::::::::
                                                                                  inference :::::::
                                                                                            (6.7.11).:

    6.7.2.1 Structure and union specifiers
    Syntax
1    struct-or-union-specifier:
                        struct-or-union identifieropt { struct-declaration-list }
                        struct-or-union identifier
     struct-or-union:
                            struct
                            union
     struct-declaration-list:
                           struct-declaration
                           struct-declaration-list struct-declaration
     struct-declaration:
                           specifier-qualifier-list struct-declarator-listopt ;
                           static_assert-declaration
     specifier-qualifier-list:
                           type-specifier specifier-qualifier-listopt
                           type-qualifier specifier-qualifier-listopt
                           alignment-specifier specifier-qualifier-listopt
     struct-declarator-list:
                           struct-declarator
                           struct-declarator-list , struct-declarator
     struct-declarator:
                           declarator
                           declaratoropt : constant-expression


    Constraints
2   A struct-declaration that does not declare an anonymous structure or anonymous union shall contain
    a struct-declarator-list.
3   A structure or union shall not contain a member with incomplete or function type (hence, a structure
    shall not contain an instance of itself, but may contain a pointer to an instance of itself), except that
    the last member of a structure with more than one named member may have incomplete array type;
    such a structure (and any union containing, possibly recursively, a member that is such a structure)
    shall not be a member of a structure or an element of an array.
4   The expression that specifies the width of a bit-field shall be an integer constant expression with a
    nonnegative value that does not exceed the width of an object of the type that would be specified
    were the colon and expression omitted.139) If the value is zero, the declaration shall have no
    declarator.
     139) While the number of bits in a _Bool object is at least CHAR_BIT, the width (number of sign and value bits) of a _Bool can

    be just 1 bit.


    Language                                                modifications to ISO/IEC 9899:2018, § 6.7.2.1 page 89
     CORE 202101 (E)                    § 6.7.6.1, working draft — May 15, 2021                C17.. N2734



                            * type-qualifier-listopt pointer
     type-qualifier-list:
                        type-qualifier
                        type-qualifier-list type-qualifier
     parameter-type-list:
                        parameter-list
                        parameter-list , ...
     parameter-list:
                        parameter-declaration
                        parameter-list , parameter-declaration
     parameter-declaration:
                        declaration-specifiers declarator
                        declaration-specifiers abstract-declaratoropt
     identifier-list:
                        identifier
                        identifier-list , identifier


    Semantics
2   Each declarator declares one identifier, and asserts that when an operand of the same form as
    the declarator appears in an expression, it designates a function or object with the scope, storage
    duration, and type indicated by the declaration specifiers.
3   A full declarator is a declarator that is not part of another declarator. If, in the nested sequence of
    declarators in a full declarator, there is a declarator specifying a variable length array type, the type
    specified by the full declarator is said to be variably modified. Furthermore, any type derived by
    declarator type derivation from a variably modified type is itself variably modified.
4   In the following subclauses, consider a declaration
              T D1
    where T contains the declaration specifiers that specify a type T (such as int) and D1 is a declarator
    that contains an identifier ident. The type specified for the identifier ident in the various forms of
    declarator is described inductively using this notation.
5   If, in the declaration "T D1", D1 has the form
               identifier
    then the type specified for ident is T.
6   If, in the declaration "T D1", D1 has the form
               (D )
    then ident has the type specified by the declaration "T D". Thus, a declarator in parentheses is
    identical to the unparenthesized declarator, but the binding of complicated declarators may be
    altered by parentheses.

    Implementation limits
7   As discussed in 5.2.4.1, an implementation may limit the number of pointer, array, and function
    declarators that modify an arithmetic, structure, union, or void type, either directly or via one or
    more typedef s.
    Forward references: array declarators (6.7.6.2), type definitions (6.7.8). ,:::::
                                                                                 type ::::::::
                                                                                      inference::::::::
                                                                                                (6.7.11).

    6.7.6.1 Pointer declarators
    Semantics
1   If, in the declaration "T D1", D1 has the form
               * type-qualifier-listopt D
    and the type specified for ident in the declaration "T D" is "derived-declarator-type-list T", then the


     modifications to ISO/IEC 9899:2018, § 6.7.6.1 page 102                                       Language
     N2734 C17..                           § 6.7.6.3, working draft — May 15, 2021                         CORE 202101 (E)


                 }


     Forward references: function declarators (6.7.6.3), function definitions (6.9.1), initialization (6.7.10).

     6.7.6.3 Function declarators (including prototypes)
     Constraints
1    A function declarator shall not specify a return type that is a function type or an array type.
2    The only storage-class specifier specifiers
                                      ::::::::
                                                 that shall occur in a parameter declaration is :::
                                                                                                are::::: and
                                                                                                    auto ::::
     register.
3    An identifier list in a function declarator that is not part of a definition of that function shall be
     empty. A   parameter declaration without type specifier shall not be formed, unless it includes the
             ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     storage class specifier auto and unless it appears in the parameter list of a lambda expression.
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

4    After adjustment, the parameters in a parameter type list in a function declarator that is part of a
     definition of that function shall not have incomplete type.

     Semantics
5    If, in the declaration "T D1", D1 has the form
                  D ( parameter-type-list )
     or
                  D ( identifier-listopt )
     and the type specified for ident in the declaration "T D" is "derived-declarator-type-list T", then the
     type specified for ident is "derived-declarator-type-list function returning the unqualified version of T".

6    A parameter type list specifies the types of, and may declare identifiers for, the parameters of the
     function.
7       After :::
     A :::::   the:::::::::
                   declared :::::
                              types:::
                                    of :::
                                       all ::::::::::
                                           parameters:::::
                                                       have:::::
                                                            been:::::::::::
                                                                  determined:::in :::::
                                                                                  order:::
                                                                                         of :::::::::::
                                                                                            declaration, ::::
                                                                                                          any
     declaration of a parameter as "array of type" shall be adjusted to "qualified pointer to type", where
     the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. If the
     keyword static also appears within the [ and ] of the array type derivation, then for each call to
     the function, the value of the corresponding actual argument shall provide access to the first element
     of an array with at least as many elements as specified by the size expression.
8    A declaration of a parameter as "function returning type" shall be adjusted to "pointer to function
     returning type", as in 6.3.2.1.
9    If the list terminates with an ellipsis (, ...), no information about the number or types of the
     parameters after the comma is supplied.161)
10   The special case of an unnamed parameter of type void as the only item in the list specifies that the
     function has no parameters.
11   If, in a parameter declaration, an identifier can be treated either as a typedef name or as a parameter
     name, it shall be taken as a typedef name.
12   If the function declarator is not part of a definition of that function, parameters may have incomplete
     type and may use the [*] notation in their sequences of declarator specifiers to specify variable
     length array types.
13   The storage-class specifier in the declaration specifiers for a parameter declaration, if present, is
     ignored unless the declared parameter is one of the members of the parameter type list for a function
     definition.
14   An identifier list declares only the identifiers of the parameters of the function. An empty list in
     a function declarator that is part of a definition of that function specifies that the function has no
     parameters. The empty list in a function declarator that is not part of a definition of that function

     161) The   macros defined in the <stdarg.h> header (7.16) can be used to access arguments that correspond to the ellipsis.


     Language                                               modifications to ISO/IEC 9899:2018, § 6.7.6.3 page 105
     CORE 202101 (E)                         § 6.7.8, working draft — May 15, 2021                                    C17.. N2734


    name respectively the types (a) int, (b) pointer to int, (c) array of three pointers to int, (d) pointer to an array of three int s,
    (e) pointer to a variable length array of an unspecified number of int s, (f) function with no parameter specification returning
    a pointer to int, (g) pointer to function with no parameters returning an int, and (h) array of an unspecified number of
    constant pointers to functions, each with one parameter that has type unsigned int and an unspecified number of other
    parameters, returning an int.

    6.7.8      Type definitions
    Syntax
1    typedef-name:
                             identifier



    Constraints
2   If a typedef name specifies a variably modified type then it shall have block scope.

    Semantics
3   In a declaration whose storage-class specifier is typedef, each declarator defines an identifier to
    be a typedef name that denotes the type specified for the identifier in the way described in 6.7.6.
    Any array size expressions associated with variable length array declarators are evaluated each time
    the declaration of the typedef name is reached in the order of execution. A typedef declaration
    does not introduce a new type, only a synonym for the type so specified. That is, in the following
    declarations:

               typedef T type_ident;
               type_ident D;


    type_ident is defined as a typedef name with the type specified by the declaration specifiers in T
    (known as T), and the identifier in D has the type "derived-declarator-type-list T" where the derived-
    declarator-type-list is specified by the declarators of D. A typedef name shares the same name space as
    other identifiers declared in ordinary declarators. ::
                                                        If :::
                                                           the:::::::::
                                                               identifier ::
                                                                          is :::::::::
                                                                             redeclared:::
                                                                                        in ::
                                                                                           an:::::::::
                                                                                              enclosed :::::
                                                                                                       block
    the inner declaration shall not be underspecified.
    ::::::::::::::::::::::::::::::::::::::::::::
4   EXAMPLE 1 After

               typedef int MILES, KLICKSP();
               typedef struct { double hi, lo; } range;

    the constructions

               MILES distance;
               extern KLICKSP *metricp;
               range x;
               range z, *zp;

    are all valid declarations. The type of distance is int, that of metricp is "pointer to function with no parameter specification
    returning int", and that of x and z is the specified structure; zp is a pointer to such a structure. The object distance has a
    type compatible with any other int object.
5   EXAMPLE 2 After the declarations

               typedef struct s1 { int x; } t1, *tp1;
               typedef struct s2 { int x; } t2, *tp2;

    type t1 and the type pointed to by tp1 are compatible. Type t1 is also compatible with type struct s1, but not compatible
    with the types struct s2, t2, the type pointed to by tp2, or int.
6   EXAMPLE 3 The following obscure constructions

               typedef signed int t;
               typedef int plain;
               struct tag {
                     unsigned t:4;


     modifications to ISO/IEC 9899:2018, § 6.7.8 page 108                                                                 Language
    N2734 C17..                            § 6.7.9, working draft — May 15, 2021                             CORE 202101 (E)


                       const t:5;
                       plain r:5;
              };


    declare a typedef name t with type signed int, a typedef name plain with type int, and a structure with three bit-field
    members, one named t that contains values in the range [0, 15], an unnamed const-qualified bit-field which (if it could
    be accessed) would contain values in either the range [−15, +15] or [−16, +15], and one named r that contains values in
    one of the ranges [0, 31], [−15, +15], or [−16, +15]. (The choice of range is implementation-defined.) The first two bit-field
    declarations differ in that unsigned is a type specifier (which forces t to be the name of a structure member), while const is
    a type qualifier (which modifies t which is still visible as a typedef name). If these declarations are followed in an inner scope
    by

              t f(t (t));
              long t;


    then a function f is declared with type "function returning signed int with one unnamed parameter with type pointer
    to function returning signed int with one unnamed parameter with type signed int", and an identifier t with type
    long int.

7   EXAMPLE 4 On the other hand, typedef names can be used to improve code readability. All three of the following
    declarations of the signal function specify exactly the same type, the first without making use of any typedef names.

              typedef void fv(int), (*pfv)(int);

              void (*signal(int, void (*)(int)))(int);
              fv *signal(int, fv *);
              pfv signal(int, pfv);


8   EXAMPLE 5 If a typedef name denotes a variable length array type, the length of the array is fixed at the time the typedef
    name is defined, not each time it is used:

              void copyt(int n)
              {
                    typedef int B[n];   // B                is n ints, n evaluated now
                    n += 1;
                    B a;                // a                is n ints, n without += 1
                    int b[n];           // a                and b are different sizes
                    for (int i = 1; i < n;                  i++)
                          a[i-1] = b[i];
              }



    6.7.9 typeof specifier
    Syntax
1    typeof-specifier:
    ::::::::::::::::
                     typeof ( type-name )
    ::::::::::::::::
                     typeof ( expression )




    Constraints
2   The type name or expression shall be valid and have a function or object type, but not a lambda
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    type. No new type declaration shall be formed by the type name or expression themselves.165)
    ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

    Semantics
3   A typeof specifier can be used in places where other type specifiers are used to declare or define
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    objects, members or functions. It stands in for the unmodified type of the type name or expression,
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    even  where the expression cannot be used for type inference of its type (opaque types, function
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

    165) This could for example happen if the expression contained the forward declaration of a tag type, such as in
         ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                          where::::::::::::::
    (struct newStruct*):0:::::                   has:::
                                struct newStruct:::  not:::
                                                        yet :::
                                                            been:::::::
                                                                 declared,::
                                                                           or::
                                                                              if it uses a compound literal that declares
                                                                                 ::::::::::::::::::::::::::::
    a new structure or union type in its type-name component.
    :::::::::::::::::::::::::::::::::::::::::



    Language                                                  modifications to ISO/IEC 9899:2018, § 6.7.9 page 109
     CORE 202101 (E)                       § 6.7.10, working draft — May 15, 2021                                   C17.. N2734


    types, array types), where a type-qualification should not be dropped, or where an identifier may
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    only be accessed for its type without evaluating it (within lambda expressions).
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

4   If it does not have a variably modified (VM) type, the type name or expression is not evaluated. For
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    VM    types, the same rules for evaluation as for sizeof expressions apply. Analogous to typedef,
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    a  typeof specifier does not introduce a new type, it only acts as a placeholder for the type so
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    specified.
    :::::::::
5          This:::::::
    NOTE :::    construct::is :::::::
                              currently :::::::
                                        proposed:::
                                                  for :::::::
                                                      inclusion :
                                                                in::
                                                                   C.::::
                                                                      C++:::
                                                                           has:a::::::
                                                                                 similar :::::
                                                                                         feature::::::::  but ::::
                                                                                                 decltype ::: which:::::
                                                                                                                    varies:::
                                                                                                                           for
    some important cases, in particular in presence of an lvalue expression.
    :::::::::::::::::::::::::::::::::::::::::::::::::::
6   EXAMPLE

      void f(int);
      ::::::::::::
      typeof(f(5)) g(double x) {             // g has type ``void (double)’’
      :::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::
        printf(" value  %g\n",
      :::::::::::::::::::::::::
                               x);
      }
      :
      typeof(g) :::
      :::::::::*
                  h;:::::::::::::::::::::::: // h has type ``void (*):(::::::
                                             :::::::::::::::::::::::
                                                                       double:)::
                                                                               ’’
      typeof(true  ?  g : nullptr) k;        // k has type ``void
      ::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::
                                                                  ( ) (double )
                                                                   * ::::::::::’’

      void ell(double A[5], typeof(A)*::
      :::::::::::::::::::::::::::::::
                                       B:):
                                          ;:::
                                            // ::::
                                                ell ::::
                                                     has :::::
                                                          type :`:`::::
                                                                   void::(:::::: *,:::::::
                                                                          double::  double** )’’
                                                                                           :::::


      extern typeof(double[]) D;           // D has an incomplete type
      :::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::
      typeof(D) C = { 0.7, 99, };          // C has type double[2]
      ::::::::::::::::::::::::::: :::::::::::::::::::::::::::::::
      typeof(D) D = { 5, 8.9, 0.1, 99, };  // D is completed to double[4]
      :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
      typeof(D) E;                         // E has type double[4]
      :::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::




    For  the definition of g, the expression f(5) has type void, and so this becomes the return type. For h, g stands in for a
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    function  type specifier and the result type for h is a pointer to function. For k, again the expression derivation is used. Here
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    the type is the type of a ternary operator, thus the type of g after function to function pointer conversion. As the result, the
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    type  of k is again a function pointer.
    ::::::::::::::::::::::::::
    For ell the parameter type adjustment takes place before typeof specifier is met. Therefore typeof(A) refers to the type
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    double
    ::::::
             and:::
           *:::  not ::
                     to ::::::::
                        double[5].:

    The extern declaration of D uses the type name derivation. The type name or expression to which a typeof specifier refers
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    has not necessarily to be complete. Here, C first inherits that incomplete type but is then completed by the initializer to
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    have type
    :::::::
              double[2]:  . :::
                            The :::::::::
                                specification ::::::::  can::::
                                              typeof(D):::  then even  be used in the definition of D itself to complete its type to
                                                                 ::::::::::::::::::::::::::::::::::::::::::::
    double[4].:



    6.7.10 Initialization
    Syntax
1    initializer:
                            assignment-expression
                            { initializer-list }
                            { initializer-list , }

     initializer-list:
                            designationopt initializer
                            initializer-list , designationopt initializer

     designation:
                            designator-list =

     designator-list:
                            designator
                            designator-list designator
     designator:
                            [ constant-expression ]
                            . identifier



     modifications to ISO/IEC 9899:2018, § 6.7.10 page 110                                                             Language
     N2734 C17..                           § 6.7.11, working draft — May 15, 2021                           CORE 202101 (E)


                struct S {
                      int i;
                      struct T t;
                };

                struct T x = {.l = 43, .k = 42, };

                void f(void)
                {
                      struct S l = { 1, .t = x, .t.l = 41, };
                }

     The value of l.t.k is 42, because implicit initialization does not override explicit initialization.
37   EXAMPLE 13 Space can be "allocated" from both ends of an array by using a single designator:

                int a[MAX] = {
                      1, 3, 5, 7, 9, [MAX-5] = 8, 6, 4, 2, 0
                };

 38 In the above, if MAX is greater than ten, there will be some zero-valued elements in the middle; if it is less than ten, some of
    the values provided by the first five initializers will be overridden by the second five.
39   EXAMPLE 14 Any member of a union can be initialized:

                union { /* ... */ } u = {.any_member = 42 };


     Forward references: common definitions <stddef.h> (7.19).

     6.7.11 Type inference
     Constraints
1    An underspecified declaration shall contain the storage class specifier auto.
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

2    For an underspecified declaration of identifiers that is not a definition a prior definition for each
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     identifier shall be visible and there shall be a typeof specifier type that if used to replace the auto
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     specifier makes   the adjusted declaration a valid declaration for each of the identifiers.
     ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

3    For an underspecified declaration that is also a definition of an object and that is not the declaration
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     of a parameter, the init-declarator corresponding to the object shall be of one of the forms
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

     ::::::::
              declarator = assignment-expression
     ::::::::
              declarator = { assignment-expression }
     ::::::::
              declarator = { assignment-expression , }
     such  that the declarator does not declare an array. If the assignment expression has lambda type, the
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     declaration  shall only define one object and shall only consist of storage class specifiers, qualifiers,
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     the identifier that is to be declared, and the initializer.
     ::::::::::::::::::::::::::::::::::::::::::::::::

4    Unless  it is the definition of an object with an assignment expression of lambda type as above, for
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     an underspecified    declaration that is also a definition there shall be a typeof specifier type that if
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     used  to replace the auto specifier makes the adjusted declaration a valid declaration.171) ::
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                                    If :it::
                                                                                                           is::::
                                                                                                              the
     definition  of  a function, it shall not additionally define objects and the return type
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                                                              of the function
     after adjustment shall be the same as determined from return statements (or the lack thereof) as
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     in 6.9.1. Otherwise, type shall be such that for all defined objects the assignment expression in
     :::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     the init-declarator, after possible lvalue, array-to-pointer or function-to-pointer conversion, has the
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     non-atomic,    unqualified type of the declared object.172)
     ::::::::::::::::::::::::::::::::::::::::::::::

5    For the correspondence of the declared type of an object and the type of its initializer, integer types
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

      171) The qualification of the type of an lvalue that is the assignment expression, or the fact that it is atomic, can never be
           ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     used   to infer such a property of the type of the defined object.
     ::::::::::::::::::::::::::::::::::::::::::::
      172) For most assignment expressions of integer or floating point type, there are several types that would make such a
           ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     declaration   valid. The second part of the constraint ensures that among these a unique type is determined that does not
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     need   further conversion to be a valid initializer for the object.
     :::::::::::::::::::::::::::::::::::::::::::



     Language                                                 modifications to ISO/IEC 9899:2018, § 6.7.11 page 115
     CORE 202101 (E)                        § 6.7.11, working draft — May 15, 2021                                     C17.. N2734


    of  the same rank and signedness but that are nevertheless different types shall not be considered.173)
    ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    If the assignment-expression is the evaluation of a bit-field designator, the inferred type shall be the
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    standard   integer type that would be chosen by a generic primary expression with the that bit-field
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    as   controlling expression. If type is a VM type, the variable array bounds shall be such that the
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    declared   types  for all defined objects and their assignment expression correspond as required for
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    all possible executions of the current function. If the assignment expression has lambda type, the
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    lambda    type shall be complete, the declaration shall only define one object and shall only consist
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    of  storage  class specifiers, qualifiers, the identifier that is to be declared, and the initializer.
    ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

    Description
6   Although    there is no syntax derivation to form declarators of lambda type, a value λ of lambda
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    type  L can  be used as assignment expression to initialize an underspecified object declaration and
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    as the  return value of an underspecified function. The inferred type then is L, possibly qualified,
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    and  the visibility of L extends to the visibility scope of the declared object or function. Otherwise,
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    provided    the constraints above are respected, in an underspecified declaration the type of the
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    declared   identifiers is the type after the declaration would have been adjusted by a choice for type
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    as described. If the declaration is also an object definition, the assignment expressions that are used
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    to determine types and initial values of the objects are evaluated at most once; the scope rules as
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    described   in 6.2.1 then also prohibit the use of the identifier of an object within the assignment
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    expression   that determines its type and initial value.
    :::::::::::::::::::::::::::::::::::::::::::::::
7   NOTE 1 Because       of the relatively complex syntax and semantics of type specifiers, the requirements for type use a typeof
                ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    specifier. If for example  the identifier or tag name of the type of the initializer expression v in the initializer of x is shadowed
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::



            auto x = v;
      :::::::::::::::




    a type type as required can still be found and the definition can be adjusted as follows:
    ::::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::

            typeof(v) x = v;
      :::::::::::::::::::




    Such a possible adjustment not withstanding, if v is a VM type, the requirements ensure that v is evaluated at most once.
    ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
8   NOTE 2 The   scope of the identifier for which the type is inferred only starts after the end of the initializer (6.2.1), so the
             ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    assignment expression  cannot use the identifier to refer to the object or function that is declared, for example to take its
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    address. Any use of the identifier in the initializer is invalid, even if an entity with the same name exists in an outer scope.
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::


      :::::
            {
            double a = 7;
      ::::::::::::::::::
            double b = 9;
      ::::::::::::::::::
            {
      :::::::
              double b = b    b;     // error, RHS uses uninitialized variable
      :::::::::::::::::::::*:::: :::::::::::::::::::::::::::::::::::::::::::
              printf("%g\n",  a);    // valid, uses "a" from outer scope, prints 7
      :::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::
              auto a   = a    a;     // error, "a" from outer scope is already shadowed
      ::::::::::::::::: ::::*:::: ::::::::::::::::::::::::::::::::::::::::::::::::::::
            }
      :::::::
            {
      :::::::
              auto b   = a    a;     // valid, uses "a" from outer scope
      ::::::::::::::::: ::::*:::: :::::::::::::::::::::::::::::::::::::
              auto a   = b;          // valid, shadows "a" from outer scope
      ::::::::::::::::: :::: ::::::::::::::::::::::::::::::::::::::::::::
              ...
      :::::::::::
              printf("%g\n", a);     // valid, uses "a" from inner scope, prints 49
      :::::::::::::::::::::::::: :::::::::::::::::::::::::::::::::::::::::::::::
            }
      :::::::
            ...
      :::::::::
          }
      :::::




9   NOTE 3 Declarations that are the definition of several objects, may make type inferrence difficult and not portable.
           :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::



     173) This can for example be two different enumerated types that are compatible to the same basic type. Note nevertheless,
          ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    that  enumeration constants have type int, so using these will never lead to the inference of an enumerated type.
    ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::



     modifications to ISO/IEC 9899:2018, § 6.7.11 page 116                                                                Language
     N2734 C17..                           § 6.7.11, working draft — May 15, 2021                             CORE 202101 (E)


           enum A { aVal, } aObj = aVal;
       ::::::::::::::::::::::::::::::::
           enum B { bVal, } bObj = bVal;
       ::::::::::::::::::::::::::::::::
           int au = aObj, bu = bObj; // valid, values have type compatible to int
       ::::::::: ::::::::::::::::::::: :::::::::::::::::::::::::::::::::::::::::
           auto ax = aObj, bx = bObj; // invalid, same rank but different types
       :::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::::::::::::::
           auto ay = aObj;              // valid, ay has type enum::A
       ::::::::::::::::::: :::::::::::::::::::::::::::::::::
           auto by  = bObj;             // valid, by has type enum::B
       ::::::::::::::::::: :::::::::::::::::::::::::::::::::
           auto az  = aVal, bz = bVal;  // valid, az and bz have type int
       :::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::
           struct set { int bits:32; } X = { .bits = 37, };
       :::::::::::::::::::::::::::::::::::::::::::::::::::
           auto k = 37, m = X.bits;     // possibly valid or invalid
       :::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::
           double  aVM[r
       :::::::::::::::::
                        ];
           double bVM[s];
       :::::::::::::::::
           double cVM[3];
       :::::::::::::::::
           double dVM[r];
       :::::::::::::::::
           auto vmPa = &aVM, vmPa = &bVM;     // invalid, different types for r != s
       ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
           auto vmPa  = &aVM, vmPc = &cVM;    // invalid, even if for some executions r is 3
       ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
           auto vmPa  = &aVM, vmPd = &dVM;    // valid, same array sizes in all executions
       ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::




     Here,  the definitions of ax and bx cannot be satified with the same typeof as a replacement for auto; any fixed choice would
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     require  the conversion of at least one of the initializer expressions to the other type. For k and m the difficulty is that both
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     expressions have probably an integer type of the same rank, but, depending on the implementation, X.bits may have a
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     signed   or an unsigned type. For the cases of VM types, the translator will only except linked defininitons if it has a proof
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     that all executions of the current function body will lead to a type that is consistent for all definitions. Such a proof may be
     :::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::
     difficult to obtain and thus the translation may fail even if such a proof exists.
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::
10   EXAMPLE 1 Consider the following file scope definitions:
               ::::::::::::::::::::::::::::::::

       static auto a = 3.5;
       :::::::::::::::::::
       auto * p = &a;
       ::::::::::::::




     They are interpreted as if they had been written as:
     ::::::::::::::::::::::::::::::::::::

       static double a = 3.5;
       :::::::::::::::::::::
       double    p ::
              * ::
       ::::::::
                    = ::
                       &a:;:



     So effectively a is a double and p is a double*.:
     :::::::::::::::::::::::::::::::::
     Both identifiers can later be redeclared as long as such a declaration is consistent with the previous ones. For examples
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     declarations as the following
     :::::::::::::::::::::

           extern auto a;
       :::::::::::::::::
           extern auto p;
       :::::::::::::::::




     may be used in a block scope where the file scope declarations are shadowed by declarations in an enclosing block.
     ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
11   EXAMPLE 2 In     the following, pA is valid because the type of A after array-to-pointer conversion is a pointer type, and qA is
                   :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     valid because it does not declare an array but a pointer to an array.
     :::::::::::::::::::::::::::::::::::::::::::::::

       double A[3] = { 0 };
       :::::::::::::::::::
       auto const    pA ::
                  * :::
       ::::::::::::
                         = :A:;
       auto const (* qA) [3]
       ::::::::::::::::::::::::
                               = &A;



12   EXAMPLE 3 Type     inference can be used to capture the type of a call to a type-generic function and can be used to ensure
                   :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     that the same type as the argument x is used.
     ::::::::::::::::::::::::::::::::

       #include <tgmath.h>
       ::::::::::::::::::
       auto y = cos(x);
       ::::::::::::::::




     If instead the type of y is explicitly specified to a different type than x, a diagnosis of the mismatch is not enforced.
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
13   EXAMPLE 4 A type-generic macro that generalizes the div functions (7.22.6.2) is defined and used as follows.
               :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::



     Language                                                 modifications to ISO/IEC 9899:2018, § 6.7.11 page 117
      CORE 202101 (E)                       § 6.7.12, working draft — May 15, 2021                                    C17.. N2734



       #define div(X, Y) _Generic((X)+(Y), int: div, long: ldiv, long long: lldiv)((X), (Y))
       :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
       auto z = div(x, y);
       ::::::::::::::::::
       auto q = z.quot;
       ::::::::::::::::
       auto r = z.rem;
       :::::::::::::::




14   EXAMPLE 5 Underspecified        definitions of objects may occur in all contexts that allow the initializer syntax as described in
                   :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     the constraints. In particular they can be used to ensure type safety of for-loop controlling expressions.
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

           for (auto i = j; i < 2 j; ++i) {
                                *:::::::::
       ::::::::::::::::::::::::::
             ...
       :::::::::
           }
       :::::




     Here, regardless of the integer rank or signedness of the type of j, i will have the type of j. So, after possible promotion,
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     the two operands of the < operator in the controlling expression are guaranteed to have the same type, and, in particular,
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     the same signedness.
     :::::::::::::::


     6.7.12      Static assertions
     Syntax
1     static_assert-declaration:
                             _Static_assert ( constant-expression , string-literal ) ;


     Constraints
2    The constant expression shall compare unequal to 0.

     Semantics
3    The constant expression shall be an integer constant expression. If the value of the constant expres-
     sion compares unequal to 0, the declaration has no effect. Otherwise, the constraint is violated and
     the implementation shall produce a diagnostic message that includes the text of the string literal,
     except that characters not in the basic source character set are not required to appear in the message.
     Forward references: diagnostics (7.2).




      modifications to ISO/IEC 9899:2018, § 6.7.12 page 118                                                              Language
    N2734 C17..                            § 6.8, working draft — May 15, 2021                          CORE 202101 (E)


    6.8 Statements and blocks
    Syntax
1    statement:
                           labeled-statement
                           compound-statement
                           expression-statement
                           selection-statement
                           iteration-statement
                           jump-statement


    Semantics
2   A statement specifies an action to be performed. Except as indicated, statements are executed in
    sequence.
3   A block allows a set of declarations and statements to be grouped into one syntactic unit. The
    initializers of objects that have automatic storage duration, and the variable length array declarators
    of ordinary identifiers with block scope, are evaluated and the values are stored in the objects
    (including storing an indeterminate value in objects without an initializer) each time the declaration
    is reached in the order of execution, as if it were a statement, and within each declaration in the
    order that declarators appear.
4   A full expression is an expression that is not part of another expression, nor part of a declarator
    or abstract declarator. There is also an implicit full expression in which the non-constant size
    expressions for a variably modified type are evaluated; within that full expression, the evaluation of
    different size expressions are unsequenced with respect to one another. There is a sequence point
    between the evaluation of a full expression and the evaluation of the next full expression to be
    evaluated.
5   NOTE Each of the following is a full expression:

       — a full declarator for a variably modified type,
       — an initializer that is not part of a compound literal,
       — the expression in an expression statement,
       — the controlling expression of a selection statement (if or switch),
       — the controlling expression of a while or do statement,
       — each of the (optional) expressions of a for statement,
       — the (optional) expression in a return statement.

    While a constant expression satisfies the definition of a full expression, evaluating it does not depend on nor produce any
    side effects, so the sequencing implications of being a full expression are not relevant to a constant expression.

    Forward references: expression and null statements (6.8.3), selection statements (6.8.4), iteration
    statements (6.8.5), the return statement (6.8.6.4).

    6.8.1 Labeled statements
    Syntax
1    labeled-statement:
                           identifier : statement
                           case constant-expression : statement
                           default : statement


    Constraints
2   A case or default label shall appear only in a switch statement . that    is associated with the same
                                                                          ::::::::::::::::::::::::::::
                                                                   174)
    function body  as the statement to which the label is
    ::::::::::::::::::::::::::::::::::::::::::::::::::::::
                                                          attached.     Further constraints on such labels
    are discussed under the switch statement.
     174) Thus, a label that appears within a lambda expression may only be associated to a switch statement within the body of
          ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    the  lambda.
    ::::::::



    Language                                                modifications to ISO/IEC 9899:2018, § 6.8.1 page 119
     CORE 202101 (E)                       § 6.8.5.3, working draft — May 15, 2021                                  C17.. N2734


    6.8.5.3 The for statement
1   The statement

                 for (clause-1; expression-2; expression-3) statement


    behaves as follows: The expression expression-2 is the controlling expression that is evaluated before
    each execution of the loop body. The expression expression-3 is evaluated as a void expression after
    each execution of the loop body. If clause-1 is a declaration, the scope of any identifiers it declares
    is the remainder of the declaration and the entire loop, including the other two expressions; it is
    reached in the order of execution before the first evaluation of the controlling expression. If clause-1
    is an expression, it is evaluated as a void expression before the first evaluation of the controlling
    expression.180)
2   Both clause-1 and expression-3 can be omitted. An omitted expression-2 is replaced by a nonzero
    constant.

    6.8.6        Jump statements
    Syntax
1    jump-statement:
                            goto identifier ;
                            continue ;
                            break ;
                            return expressionopt ;
    Constraints
2   No jump statement other than return shall have a target that is found in another function body.181)
    ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

    Semantics
3   A jump statement causes an unconditional jump to another place.

    6.8.6.1 The goto statement
    Constraints
1   The identifier in a goto statement shall name a label located somewhere in the enclosing function
    body.
    :::::
           A goto statement shall not jump from outside the scope of an identifier having a variably
    modified type to inside the scope of that identifier.182)

    Semantics
2   A goto statement causes an unconditional jump to the statement prefixed by the named label in the
    enclosing function.
3   EXAMPLE 1 It is sometimes convenient to jump into the middle of a complicated set of statements. The following outline
    presents one possible approach to a problem based on these three assumptions:

        1. The general initialization code accesses objects only visible to the current function.
        2. The general initialization code is too large to warrant duplication.
        3. The code to determine the next operation is at the head of the loop. (To allow it to be reached by continue statements,
           for example.)

                 /* ... */
                 goto first_time;
                 for (;;) {
    180) Thus,   clause-1 specifies initialization for the loop, possibly declaring one or more variables for use in the loop; the
    controlling expression, expression-2, specifies an evaluation made before each iteration, such that execution of the loop
    continues until the expression compares equal to 0; and expression-3 specifies an operation (such as incrementing) that is
    performed after each iteration.
     181) Thus jump statements other than return may not jump between different functions or cross the boundaries of a lambda
          ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    expression,   that is, they may not jump into or out of the function body of a lambda. Other features such as signals (7.14) and
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    long   jumps  (7.13) may delegate control to points of the program that do not fall under these constraints.
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     182) The visibility of labels is restricted such that a goto statement that jumps into or out of a different function body, even
          ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    if it is nested within a lambda, is a constraint violation.
    :::::::::::::::::::::::::::::::::::::::



     modifications to ISO/IEC 9899:2018, § 6.8.6.1 page 124                                                            Language
    N2734 C17..                        § 6.8.6.2, working draft — May 15, 2021                         CORE 202101 (E)


                     // determine next operation
                     /* ... */
                     if (need to reinitialize) {
                           // reinitialize-only code
                           /* ... */
                     first_time:
                           // general initialization code
                           /* ... */
                           continue;
                     }
                     // handle other operations
                     /* ... */
              }


4   EXAMPLE 2 A goto statement is not allowed to jump past any declarations of objects with variably modified types. A jump
    within the scope, however, is permitted.

             goto lab3;                       // invalid:       going INTO scope of VLA.
             {
                   double a[n];
                   a[j] = 4.4;
             lab3:
                   a[j] = 3.3;
                   goto lab4;                 // valid:      going WITHIN scope of VLA.
                   a[j] = 5.5;
             lab4:
                   a[j] = 6.6;
             }
             goto lab4;                       // invalid:       going INTO scope of VLA.


    6.8.6.2 The continue statement
    Constraints
1   A continue statement shall appear only in or as a loop body . that is associated to the same function
                                                                   :::::::::::::::::::::::::::::::::
          183)
    body.
    :::::

    Semantics
2   A continue statement causes a jump to the loop-continuation portion of the smallest enclosing
    iteration statement; that is, to the end of the loop body. More precisely, in each of the statements


           while (/* ...       */) {            do {                                 for (/* ... */) {
              /* ... */                            /* ... */                            /* ... */
              continue;                            continue;                            continue;
              /* ... */                            /* ... */                            /* ... */
           contin:;                             contin:;                             contin:;
           }                                    } while (/* ...        */);          }



    unless the continue statement shown is in an enclosed iteration statement (in which case it is
    interpreted within that statement), it is equivalent to goto contin;.184)

    6.8.6.3 The break statement
    Constraints
1   A break statement shall appear only in or as a switch body or loop body . ::::
                                                                              that ::
                                                                                   is :::::::::
                                                                                      associated::
                                                                                                 to::::
                                                                                                    the
                         185)
    same   function body.
    ::::::::::::::::::

    183) Thus a continue statement by itself may not be used to terminate the execution of the body of a lambda expresssion.
         ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    184) Following the contin: label is a null statement.
    185) Thus a break statement by itself may not be used terminate the execution of the body of a lambda expresssion.
         ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::



    Language                                            modifications to ISO/IEC 9899:2018, § 6.8.6.3 page 125
     CORE 202101 (E)                     § 6.8.6.4, working draft — May 15, 2021                                 C17.. N2734


    Semantics
2   A break statement terminates execution of the smallest enclosing switch or iteration statement.

    6.8.6.4 The return statement
    Constraints
1   A return statement with an expression shall not appear in a function body
                                                                            :::::
                                                                                 whose return type is
    void . A return statement without an expression shall only appear in a function :::::
                                                                                    body whose return
    type is void.
2   For  a function body that corresponds to an underspecified definition of a function or to a lambda,
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    all return   statements shall provide expressions with a consistent type or none at all. That is, if
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    any return statement has an expression, all return statements shall have an expression (after
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    lvalue,  array-to-pointer or function-to-pointer conversion) with the same type; otherwise all
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    return   expressions shall have no expression.
    :::::::::::::::::::::::::::::::::::::::::

    Semantics
3   A return statement terminates execution of the current function is           associated to the innermost
                                                                               :::::::::::::::::::::::::::
    function body  in which appears. It evaluates   the expression,  if  any, terminates the execution of that
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    function body
    :::::::::::::
                   and returns control  to its caller. A function ; if  it has an expression, the value of the
                                                                  :::::::::::::::::::::::::::::::::::
    expression is returned to the caller as the value of the function call expression. A function body
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    may have any number of return statements.
4   If a return statement with an expression is executed, the value of the expression is returned to the
    caller as the value of the function call expression. If the expression has a type different from the
    return type of the function in which it appears, the value is converted as if by assignment to an
    object having the return type of the function.186)
5   For a lambda or for a function that has an underspecified definition, the return type is determined
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    by the lexically first return statement, if any, that is associated to the function body and is specified
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    as the type of that expression, if any, after lvalue, array-to-pointer, function-to-pointer conversion,
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    or as void if there is no expression.
    ::::::::::::::::::::::::::::::::
6   EXAMPLE In:

              struct s { double i; } f(void);
              union {
                    struct {
                          int f1;
                          struct s f2;
                    } u1;
                    struct {
                          struct s f3;
                          int f4;
                    } u2;
              } g;

              struct s f(void)
              {
                    return g.u1.f2;
              }

              /* ... */
              g.u2.f3 = f();

    there is no undefined behavior, although there would be if the assignment were done directly (without using a function call
    to fetch the value).



     186) The return statement is not an assignment. The overlap restriction of 6.5.16.1 does not apply to the case of function

    return. The representation of floating-point values can have wider range or precision than implied by the type; a cast can be
    used to remove this extra range and precision.


     modifications to ISO/IEC 9899:2018, § 6.8.6.4 page 126                                                         Language
    N2734 C17..                             § 6.9, working draft — May 15, 2021                              CORE 202101 (E)


    6.9 External definitions
    Syntax
1    translation-unit:
                            external-declaration
                            translation-unit external-declaration

     external-declaration:
                        function-definition
                        declaration



    Constraints
2   The storage-class specifiers auto and ::::::::
                                          specifier register shall not appear in the declaration specifiers
    in an external declaration.
3   There shall be no more than one external definition for each identifier declared with internal linkage
    in a translation unit. Moreover, if an identifier declared with internal linkage is used in an expression
    (other than as a part of the operand of a sizeof or _Alignof operator whose result is an integer
    constant),that  is evaluated,187) there shall be exactly one external definition for the identifier in the
               :::::::::::::::
    translation unit.

    Semantics
4   As discussed in 5.1.1.1, the unit of program text after preprocessing is a translation unit, which
    consists of a sequence of external declarations. These are described as "external" because they
    appear outside any function (and hence have file scope). As discussed in 6.7, a declaration that also
    causes storage to be reserved for an object or a function named by the identifier is a definition.
5   An external definition is an external declaration that is also a definition of a function (other than an
    inline definition) or an object. If an identifier declared with external linkage is used in an expression
    (other than as part of the operand of a sizeof or _Alignof operator whose result is an integer
    constant), somewhere in the entire program there shall be exactly one external definition for the
    identifier; otherwise, there shall be no more than one.Thus, if an identifier declared with external
    linkage is not used in an expression, there need be no external definition for it. 188)

    6.9.1 Function definitions
    Syntax
1    function-definition:
                         declaration-specifiers declarator declaration-listopt compound-statement

     declaration-list:
                            declaration
                            declaration-list declaration



    Constraints
2   The identifier declared in a function definition (which is the name of the function) shall have a
    function type, as specified by the declarator portion of the function definition.189)
3   The return type of a function shall be void or a complete object type other than array type.
4   The storage-class specifier, if any, in the declaration specifiers shall be either extern or static :,
    possibly combined with auto .
    :::::::::::::::::::::::::::

     187) Several expressions that are only inspected for their type are not evaluated. This may or may not apply to dependent
          ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    expressions    in _Generic primary expressions, the typeof specifier, the sizeof operator, and the alignof operator.
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     188) Thus, if an identifier declared with external linkage is not used in an expression, there need be no external definition for
          ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    it.
    :



    Language                                                  modifications to ISO/IEC 9899:2018, § 6.9.1 page 127
      CORE 202101 (E)                      § 6.9.1, working draft — May 15, 2021                                   C17.. N2734


5    If the declarator includes a parameter type list, the declaration of each parameter shall include an
     identifier, except for the special case of a parameter list consisting of a single parameter of type void,
     in which case there shall not be an identifier. No declaration list shall follow.
6    If the declarator includes an identifier list, each declaration in the declaration list shall have at least
     one declarator, those declarators shall declare only identifiers from the identifier list, and every
     identifier in the identifier list shall be declared. An identifier declared as a typedef name shall not
     be redeclared as a parameter. The declarations in the declaration list shall contain no storage-class
     specifier other than register and no initializations.
7    An  underspecified function definition shall contain an auto storage class specifier. The return type
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     for such a function is determined as described for the return statement (6.8.6.4) and shall be visible
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     prior to the function definition.
     ::::::::::::::::::::::::::::


     Semantics
8    If auto appears as a storage-class specifier it is ignored for the purpose of determining a storage
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     class or linkage of the function. It then only indicates that the return type of the function may be
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     inferred  from return statements or the lack thereof, see 6.8.6.4.
     ::::::::::::::::::::::::::::::::::::::::::::::::::::::::

9    The declarator in a function definition specifies the name of the function being defined and the
     identifiers of its parameters. If the declarator includes a parameter type list, the list also specifies the
     types of all the parameters; such a declarator (possibly     adjusted by an inferred type specifier) also
                                                        ::::::::::::::::::::::::::::::::::::::::::
     serves as a function prototype for later calls to the same function in the same translation unit. If the
     declarator includes an identifier list,190) the types of the parameters shall be declared in a following
     declaration list. In either case, the type of each parameter is adjusted as described in 6.7.6.3 for a
     parameter type list; the resulting type shall be a complete object type.
10   If a function that accepts a variable number of arguments is defined without a parameter type list
     that ends with the ellipsis notation, the behavior is undefined.
11   Each parameter has automatic storage duration; its identifier is an lvalue.191) The layout of the
     storage for parameters is unspecified.
12   On entry to the function, the size expressions of each variably modified parameter are evaluated
     and the value of each argument expression is converted to the type of the corresponding parameter
     as if by assignment. (Array expressions and function designators as arguments were converted to
     pointers before the call.)
13   After all parameters have been assigned, the compound statement that constitutes the body of the
     function definition is executed.
14   Unless otherwise specified, if the } that terminates a function is reached, and the value of the
     function call is used by the caller, the behavior is undefined.
15   Provided   the constraints above are respected, the return type of an underspecified function
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     definition is adjusted as if the corresponding type specifier had been inserted in the definition.
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     The  type of such a function is incomplete within the function body until the lexically first return
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     statement  that it contains, if any, or until the end of the function body, otherwise.192)
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
16   NOTE In a function definition, the type of the function and its prototype cannot be inherited from a typedef:
          ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

                typedef int F(void);
      :: ::: :::::::::::::::::::: :::::::::::
                                                  //            type F: is "function with no parameters
      :::::::::::::::::::::::::::::::::::::
                                                  //            returning int"
                                                                           :::
             F f,  g;
      :: ::: :::::::::::::::::::::::::::::::
                                                  //            f
                                                                :
                                                                  and g: both have type compatible with F
                                                                                                        :
             F f { /* :::
      :: ::: ::::::::
                       ...:::
                            */::}: :::::::::::::://             WRONG: syntax/constraint error
             F g()  { /
      :: ::: ::::::::::
                          ... */::}: :::::::::::://
                       * ::::::                                 WRONG: declares that :g returns a function
             int  f(void)  { /   ... */::
      :: ::: :::::::::::::::*:::::::
                                          }::::::://            RIGHT: f: has type compatible with :
                                                                                                   F
             int  g() { /   ...
      :: ::: :::::::::::*::::::: * ::: :::::::::://
                                   / }                          RIGHT: g: has type compatible with :
                                                                                                   F
             F  e (void)  { /   ...
               * :::::::::::*:::::::
      :: ::: :::                     */::
                                        }: ::::::://            e
                                                                :
                                                                  returns  a pointer to a function

     189) The intent is that the type category in a function definition cannot be inherited from a typedef:
     190) See "future language directions" (6.11.7).
     191) A parameter identifier cannot be redeclared in the function body except in an enclosed block.
     192) This means that such a function cannot be used for direct recursion before or within the first return statement.
          :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::



      modifications to ISO/IEC 9899:2018, § 6.9.1 page 128                                                            Language
     N2734 C17..                            § 6.9.1, working draft — May 15, 2021                              CORE 202101 (E)


              F ((e))(void) { / ... / }
                * :::::::::::::*:::::::
       :: ::: :::::                  * ::::::   // same: parentheses irrelevant
              int  (
       :: ::: ::::::
                     fp )(void);
                    * :::::::::: :::::::::::::::// fp
                                                   ::
                                                      points to a function that has type F
                                                                                         :
              F  Fp ;
                * ::::::::::::::::::::::::::::
       :: ::: :::
                                                // Fp
                                                   ::
                                                      points to a function that has type F
                                                                                         :


17   EXAMPLE 1 In the following:

                extern int max(int a, int b)
                {
                      return a > b ? a: b;
                }

     extern is the storage-class specifier and int is the type specifier; max(int a, int b) is the function declarator; and

                { return a       >   b ? a: b; }

     is the function body. The following similar definition uses the identifier-list form for the parameter declarations:

                extern int max(a, b)
                int a, b;
                {
                      return a > b ? a: b;
                }

     Here int a, b; is the declaration list for the parameters. The difference between these two definitions is that the first form acts
     as a prototype declaration that forces conversion of the arguments of subsequent calls to the function, whereas the second
     form does not.
18   EXAMPLE 2 To pass one function to another, one might say

                         int f(void);
                         /* ... */
                         g(f);

     Then the definition of g might read

                void g(int (*funcp)(void))
                {
                      /* ... */
                      (*funcp)(); /* or funcp(); ...*/
                }

     or, equivalently,

                void g(int func(void))
                {
                      /* ... */
                      func(); /* or (*func)(); ...*/
                }

19   EXAMPLE 3 Consider the following function that computes the maximum value of two parameters that have integer types
               :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     T and S.
     ::::::

           inline auto max(T, S); // invalid: no definition visible
       ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
           ...
       :::::::
           inline auto max(T a, S b){
       :::::::::::::::::::::::::::::
             return (a < 0)
       :::::::::::::::::::
                    ? ((b < 0) ? ((a < b) ? b : a) : b)
       :::::::::::::::::::: ::::::::::::::::::::::::::::
                    : ((b >= 0) ? ((a < b) ? b : a) : a);
       :::::::::::::::::::::::::::::::::::::::::::::::::
           }
       :::::
           ...
       :::::::
           // valid: definition visible
       :::::::::::::::::::::::::::::::
           extern auto max(T, S); // forces definition to be external
       ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
           auto max(T, S);        // same
       ::::::::::::::::::: ::::::::::::::



     Language                                                   modifications to ISO/IEC 9899:2018, § 6.9.1 page 129
      CORE 202101 (E)                       § 6.9.2, working draft — May 15, 2021                                 C17.. N2734


             auto max();
       ::::::::::::::::::::::::::::::::::
                                             // same



     The   return expression performs default arithmetic conversion to determine a type that can hold the maximum value and
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     is at least as wide as int. The function definition is adjusted to that return type. This property holds regardless if types T
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     and   S have the same or different signedness.
     ::::::::::::::::::::::::::::::::
     The first forward declaration of the function is invalid, because an auto type function declaration that is not a definition
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     is only valid if the definition of the function is visible. In contrast to that, the extern declaration and the two following
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     equivalent ones are valid because they follow the definition and thus the inferred return type is known. Thereby in is
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     ensured   that the translation unit provides an external definition of the function.
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::
20   EXAMPLE 4 The     following function computes the sum over an array of integers of type T and returns the value as the
                 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     promoted type
     ::::::::::::::
                   of T .

           inline
       ::::::::::
           auto sum(size_t n, T A[n]){
       ::::::::::::::::::::::::::::::
             switch(n) {
       :::::::::::::::::
               case 0:
       :::::::::::::::
                  return +((T)0);                             // return the promoted type
       :::::::::::::::::::::::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::::
               case 1:
       :::::::::::::::
                  return +A[0];                               // return the promoted type
       :::::::::::::::::::::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::
               default:
       ::::::::::::::::
                  return sum(n/2, A) + sum(n - n/2, &A[n/2]); // valid recursion
       ::::::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::
             }
       :::::::
           }
       :::::




     If instead sum would have bee defined with a prototype as follows
     :::::::::::::::::::::::::::::::::::::::::::::::

             T sum(size_t n, T A[n]);
       :::::::::::::::::::::::::::




     for a narrow type T such as unsigned char, the return type and result would be different from the previous. In particular,
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     the result of the addition would have been converted back from the promoted type to T before each return, possibly leading
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     to a surprising overall results. Also, specifying the promoted type of a narrow type T explicitly can be tedious because that
     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     type  depends on properties of the execution platform.
     :::::::::::::::::::::::::::::::::::::::


     6.9.2     External object definitions
     Semantics
1    If the declaration of an identifier for an object has file scope and an initializer, the declaration is an
     external definition for the identifier.
2    A declaration of an identifier for an object that has file scope without an initializer, and without a
     storage-class specifier or with the storage-class specifier static, constitutes a tentative definition. If a
     translation unit contains one or more tentative definitions for an identifier, and the translation unit
     contains no external definition for that identifier, then the behavior is exactly as if the translation
     unit contains a file scope declaration of that identifier, with the composite type as of the end of the
     translation unit, with an initializer equal to 0.
3    If the declaration of an identifier for an object is a tentative definition and has internal linkage, the
     declared type shall not be an incomplete type.
4    EXAMPLE 1

               int i1 = 1;                 //   definition, external linkage
               static int i2 = 2;          //   definition, internal linkage
               extern int i3 = 3;          //   definition, external linkage
               int i4;                     //   tentative definition, external linkage
               static int i5;              //   tentative definition, internal linkage

               int i1;                     // valid tentative definition, refers to previous
               int i2;                     // 6.2.2 renders undefined, linkage disagreement
               int i3;                     // valid tentative definition, refers to previous


      modifications to ISO/IEC 9899:2018, § 6.9.2 page 130                                                           Language
     CORE 202101 (E)                       § 7.1.4, working draft — May 15, 2021                                 C17.. N2734


      — If an argument to a function has an invalid value (such as a value outside the domain of the
        function, or a pointer outside the address space of the program, or a null pointer, or a pointer
        to non-modifiable storage when the corresponding parameter is not const-qualified) or a type
        (after default argument promotion) not expected by a function with a variable number of
        arguments, the behavior is undefined.

      — If a function argument is described as being an array, the pointer actually passed to the function
        shall have a value such that all address computations and accesses to objects (that would be
        valid if the pointer did point to the first element of such an array) are in fact valid.

      — Any function declared in a header may be additionally implemented as a function-like macro
        defined in the header, so if a library function is declared explicitly when its header is included,
        one of the techniques shown below can be used to ensure the declaration is not affected by
        such a macro. Any macro definition of a function can be suppressed locally by enclosing
        the name of the function in parentheses, because the name is then not followed by the left
        parenthesis that indicates expansion of a macro function name. For the same syntactic reason,
        it is permitted to take the address of a library function even if it is also defined as a macro.215)
        The use of #undef to remove any macro definition will also ensure that an actual function is
        referred to.

      — Any invocation of a library function that is implemented as a macro shall expand to code that
        evaluates each of its arguments exactly once, fully protected by parentheses where necessary,
        so it is generally safe to use arbitrary expressions as arguments.216)

      — Likewise, those function-like macros described in the following subclauses may be invoked in
        an expression anywhere a function with a compatible return type could be called.217)

      — All object-like macros listed as expanding to integer constant expressions shall additionally be
        suitable for use in #if preprocessing directives.

2   Provided that a library function can be declared without reference to any type defined in a header, it
    is also permissible to declare the function and use it without including its associated header.
3   There is a sequence point immediately before a library function returns.
4   The functions in the standard library are not guaranteed to be reentrant and may modify objects
    with static or thread storage duration.218)
5   Unless explicitly stated otherwise in the detailed descriptions that follow, library functions shall
    prevent data races as follows: A library function shall not directly or indirectly access objects
    accessible by threads other than the current thread unless the objects are accessed directly or
    indirectly via the function’s arguments. A library function shall not directly or indirectly modify
    objects accessible by threads other than the current thread unless the objects are accessed directly
     215) This means that an implementation is required to provide an actual function for each library function, even if it also

    provides a macro for that function.
     216) Such macros might not contain the sequence points that the corresponding function calls do. Nevertheless, it
                                                                                                              ::::::::::::
    is recommended that implementations provide the same sequencing properties as for a function call, by, for example,
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    wrapping    the macro expansion in a suitable lambda expression.
    :::::::::::::::::::::::::::::::::::::::::::::
     217) Because external identifiers and some macro names beginning with an underscore are reserved, implementations can

    provide special semantics for such names. For example, the identifier _BUILTIN_abs could be used to indicate generation of
    in-line code for the abs function. Thus, the appropriate header could specify

              #define abs(x) _BUILTIN_abs(x)

    for a compiler whose code generator will accept it.
      In this manner, a user desiring to guarantee that a given library function such as abs will be a genuine function can write

              #undef abs

    whether the implementation’s header provides a macro implementation of abs or a built-in implementation. The prototype
    for the function, which precedes and is hidden by any macro definition, is thereby revealed also.
     218) Thus, a signal handler cannot, in general, call standard library functions.




     modifications to ISO/IEC 9899:2018, § 7.1.4 page 148                                                              Library
    N2734 C17..                         § 7.13.2.1, working draft — May 15, 2021                           CORE 202101 (E)


    Description
2   The longjmp function restores the environment saved by the most recent invocation of the setjmp
    macro in the same invocation of the program with the corresponding jmp_buf argument. If there
    has been no such invocation, or if the invocation was from another thread of execution, or if the
              body containing the invocation of the setjmp macro has terminated execution278) in the
    function :::::
    interim, or if the invocation of the setjmp macro was within the scope of an identifier with variably
    modified type and execution has left that scope in the interim, the behavior is undefined.
3   All accessible objects have values, and all other components of the abstract machine279) have state,
    as of the time the longjmp function was called, except that the values of objects of automatic
    storage duration that are local to the function containing the invocation of the corresponding setjmp
    macro280) that do not have volatile-qualified type and have been changed between the setjmp
    invocation and longjmp call are indeterminate.

    Returns
4   After longjmp is completed, thread execution continues as if the corresponding invocation of the
    setjmp macro had just returned the value specified by val. The longjmp function cannot cause the
    setjmp macro to return the value 0; if val is 0, the setjmp macro returns the value 1.
5   EXAMPLE The longjmp function that returns control back to the point of the setjmp invocation might cause memory
    associated with a variable length array object to be squandered.

               #include <setjmp.h>
               jmp_buf buf;
               void g(int n);
               void h(int n);
               int n = 6;

               void f(void)
               {
                     int x[n];                    // valid:      f is not terminated
                     setjmp(buf);
                     g(n);
               }

               void g(int n)
               {
                     int a[n];                    // a may remain allocated
                     h(n);
               }

               void h(int n)
               {
                     int b[n];                    // b may remain allocated
                     longjmp(buf, 2);             // might cause memory loss
               }




    278) For  example, by executing a return statement or because another longjmp call has caused a transfer to a setjmp
    invocation in a function ::or :::::
                                  lambda:earlier in the set of nested calls.
     279) This includes, but is not limited to, the floating-point status flags and the state of open files.
     280) Such a function contains the call to setjmp either directly or within a set of nested lambdas. All local variables of the
          ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    function   and the nested lambdas that have been modified between the corresponding calls to setjmp and longjmp function
    ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    are affected.
    :::::::::



    Library                                              modifications to ISO/IEC 9899:2018, § 7.13.2.1 page 207
     CORE 202101 (E)                        § 7.14, working draft — May 15, 2021                                     C17.. N2734


    7.14     Signal handling <signal.h>
1   The header <signal.h> declares a type and two functions and defines several macros, for handling
    various signals (conditions that may be reported during program execution).
2   The type defined is

              sig_atomic_t


    which is the (possibly volatile-qualified) integer type of an object that can be accessed as an atomic
    entity, even in the presence of asynchronous interrupts.
3   The macros defined are

              SIG_DFL
              SIG_ERR
              SIG_IGN


    which expand to constant expressions with distinct values that have type compatible with the second
    argument to, and the return value of, the signal function, and whose values compare unequal to
    the address of any declarable function; and the following, which expand to positive integer constant
    expressions with type int and distinct values that are the signal numbers, each corresponding to
    the specified condition:

    SIGABRT abnormal termination, such as is initiated by the abort function

    SIGFPE       an erroneous arithmetic operation, such as zero divide or an operation resulting in
                 overflow
    SIGILL       detection of an invalid function image, such as an invalid instruction
    SIGINT       receipt of an interactive attention signal
    SIGSEGV an invalid access to storage

    SIGTERM a termination request sent to the program

4   An implementation need not generate any of these signals, except as a result of explicit calls to the
    raise function. Additional signals and pointers to undeclarable functions, with macro definitions
    beginning, respectively, with the letters SIG and an uppercase letter or with SIG_ and an uppercase
    letter,281) may also be specified by the implementation. The complete set of signals, their semantics,
    and their default handling is implementation-defined; all signal numbers shall be positive.

    7.14.1 Specify signal handling
    7.14.1.1 The signal function
    Synopsis
1             #include <signal.h>
              void (*signal(int sig, void (*func)(int)))(int);


    Description
2   The signal function chooses one of three ways in which receipt of the signal number sig is to
    be subsequently handled. If the value of func is SIG_DFL, default handling for that signal will
    occur. If the value of func is SIG_IGN, the signal will be ignored. Otherwise, func shall point to a
    function or  shall be the result of a conversion of a function literal to a function pointer. The function
              :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    or lambda    value is then to be called when that signal occurs. :, An invocation of such a function or
    :::::::::::::::::::::                                                                                   ::
    function  literal
    ::::::::::::::
                      because  of a signal, or (recursively) of any further functions :: or::::::::
                                                                                            lambdas:called by
    that invocation (other than functions in the standard library),282) is called a signal handler.
     281) See "future library directions" (7.31.7). The names of the signal numbers reflect the following terms (respectively): abort,

    floating-point exception, illegal instruction, interrupt, segmentation violation, and termination.
     282) This includes functions called indirectly via standard library functions (e.g., a SIGABRT handler called via the abort

    function).


     modifications to ISO/IEC 9899:2018, § 7.14.1.1 page 208                                                               Library
    N2734                                  § 7.14.2, working draft — May 15, 2021                          CORE 202101 (E)


3   When a signal occurs and func points to a function,283) it is implementation-defined whether the
    equivalent of signal(sig, SIG_DFL); is executed or the implementation prevents some imple-
    mentation-defined set of signals (at least including sig) from occurring until the current signal
    handling has completed; in the case of SIGILL, the implementation may alternatively define that
    no action is taken. Then the equivalent of (*func)(sig); is executed. If and when the function
    returns, if the value of sig is SIGFPE, SIGILL, SIGSEGV, or any other implementation-defined value
    corresponding to a computational exception, the behavior is undefined; otherwise the program will
    resume execution at the point it was interrupted.
4   If the signal occurs as the result of calling the abort or raise function, the signal handler shall not
    call the raise function.
5   If the signal occurs other than as the result of calling the abort or raise function, the behavior is
    undefined if the signal handler refers to any object with static or thread storage duration that is
    not a lock-free atomic object other than by assigning a value to an object declared as volatile
    sig_atomic_t, or the signal handler calls any function in the standard library other than

      — the abort function,
      — the _Exit function,
      — the quick_exit function,
      — the functions in <stdatomic.h> (except where explicitly stated otherwise) when the atomic
        arguments are lock-free,
      — the atomic_is_lock_free function with any atomic argument, or
      — the signal function with the first argument equal to the signal number corresponding to the
        signal that caused the invocation of the handler. Furthermore, if such a call to the signal
        function results in a SIG_ERR return, the value of errno is indeterminate.284)

6   At program startup, the equivalent of

              signal(sig, SIG_IGN);


    may be executed for some signals selected in an implementation-defined manner; the equivalent of

              signal(sig, SIG_DFL);


    is executed for all other signals defined by the implementation.
7   Use of this function in a multi-threaded program results in undefined behavior. The implementation
    shall behave as if no library function calls the signal function.

    Returns
8   If the request can be honored, the signal function returns the value of func for the most recent
    successful call to signal for the specified signal sig. Otherwise, a value of SIG_ERR is returned and
    a positive value is stored in errno.
    Forward references: the abort function (7.22.4.1), the exit function (7.22.4.4), the _Exit function
    (7.22.4.5), the quick_exit function (7.22.4.7).

    7.14.2 Send signal
    7.14.2.1 The raise function
    Synopsis
1             #include <signal.h>
              int raise(int sig);

    283) Or, equivalently, it is the result of a conversion of a function literal to a function pointer.
         ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    284) If any signal is generated by an asynchronous signal handler, the behavior is undefined.




    Library                                                 modifications to ISO/IEC 9899:2018, § 7.14.2.1 page 209
     CORE 202101 (E)                        § 7.16, working draft — May 15, 2021                                    C17.. N2734


    7.16     Variable arguments <stdarg.h>
1   The header <stdarg.h> declares a type and defines four macros, for advancing through a list of
    arguments whose number and types are not known to the called function when it is translated.
2   A function may be called with a variable number of arguments of varying types. As described in
    6.9.1, its parameter list contains one or more parameters. The rightmost parameter plays a special
    role in the access mechanism, and will be designated parmN in this description.
3   The type declared is

              va_list


    which is a complete object type suitable for holding information needed by the macros va_start,
    va_arg, va_end, and va_copy . If access to the varying arguments is desired, the called function
    shall declare an object (generally referred to as ap in this subclause) having type va_list. The object
    ap may be passed as an argument to another function ; if that function ::::   call; ::
                                                                                        if :::
                                                                                           the::::::
                                                                                               called ::::::::
                                                                                                      function
    or lambda    invokes the va _arg macro with parameter ap, the value of ap in the calling function or
    ::::::::::                                                                                              ::
    lambda   is indeterminate  and shall  be passed  to the va _end macro prior to any further reference to
    :::::::
    ap.285)
4   NOTE Because       the ... parameter syntax is not valid for lambda expressions, these macros can never be applied directly
             :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    to process  a variable list of arguments to the call of a lambda. In contrast to that, the type va_list itself can be a parameter
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    type of a lambda   expression    to process the argument list of a function.
    ::::::::::::::::::::::::::::::::::::::::::::::::::


    7.16.1 Variable argument list access macros
1   The va_start and va_arg macros described in this subclause shall be implemented as macros,
    not functions. It is unspecified whether va_copy and va_end are macros or identifiers declared
    with external linkage. If a macro definition is suppressed in order to access an actual function,
    or a program defines an external identifier with the same name, the behavior is undefined. Each
    invocation of the va_start and va_copy macros shall be matched by a corresponding invocation of
    the va_end macro in the same function or  lambda expression.
                                           :::::::::::::::::::

    7.16.1.1 The va_arg macro
    Synopsis
1             #include <stdarg.h>
              type va_arg(va_list ap, type);


    Description
2   The va_arg macro expands to an expression that has the specified type and the value of the next
    argument in the call. The parameter ap shall have been initialized by the va_start or va_copy
    macro (without an intervening invocation of the va_end macro for the same ap). Each invocation of
    the va_arg macro modifies ap so that the values of successive arguments are returned in turn. The
    parameter type shall be a type name specified such that the type of a pointer to an object that has the
    specified type can be obtained simply by postfixing a * to type. If there is no actual next argument,
    or if type is not compatible with the type of the actual next argument (as promoted according to the
    default argument promotions), the behavior is undefined, except for the following cases:

      — one type is a signed integer type, the other type is the corresponding unsigned integer type,
        and the value is representable in both types;
      — one type is pointer to void and the other is a pointer to a character type.

    Returns
3   The first invocation of the va_arg macro after that of the va_start macro returns the value of the
    argument after that specified by parmN. Successive invocations return the values of the remaining
    arguments in succession.
     285) It is permitted to create a pointer to a va_list and pass that pointer to another function or lambda, in which case the
                                                                                                       ::::::::
    original calling
                :::::
                      function::or ::::::
                                   lambda can make further use of the original list after the other function returns.


     modifications to ISO/IEC 9899:2018, § 7.16.1.1 page 212                                                              Library
    N2734 C17..                        § 7.16.1.2, working draft — May 15, 2021                         CORE 202101 (E)


    7.16.1.2 The va_copy macro
    Synopsis
1             #include <stdarg.h>
              void va_copy(va_list dest, va_list src);


    Description
2   The va_copy macro initializes dest as a copy of src, as if the va_start macro had been applied
    to dest followed by the same sequence of uses of the va_arg macro as had previously been used
    to reach the present state of src. Neither the va_copy nor va_start macro shall be invoked to
    reinitialize dest without an intervening invocation of the va_end macro for the same dest.

    Returns
3   The va_copy macro returns no value.

    7.16.1.3 The va_end macro
    Synopsis
1             #include <stdarg.h>
              void va_end(va_list ap);


    Description
2   The va_end macro facilitates a normal return from the function whose variable argument list was
    referred to by the expansion of the va_start macro, or the function ::or:::::::
                                                                             lambda::::::::::
                                                                                    expression:containing
                             _                                   _                _
    the expansion of the va copy macro, that initialized the va list ap. The va end macro may modify
    ap so that it is no longer usable (without being reinitialized by the va_start or va_copy macro). If
    there is no corresponding invocation of the va_start or va_copy macro, or if the va_end macro is
    not invoked before the return, the behavior is undefined.

    Returns
3   The va_end macro returns no value.

    7.16.1.4 The va_start macro
    Synopsis
1             #include <stdarg.h>
              void va_start(va_list ap, parmN);


    Description
2   The va_start macro shall be invoked before any access to the unnamed arguments.
3   The va_start macro initializes ap for subsequent use by the va_arg and va_end macros. Neither the
    va_start nor va_copy macro shall be invoked to reinitialize ap without an intervening invocation
    of the va_end macro for the same ap.
4   The parameter parmN is the identifier of the rightmost parameter in the variable parameter list in
    the function definition (the one just before the , ...). If the parameter parmN is declared with the
    register storage class, with a function or array type, or with a type that is not compatible with the
    type that results after application of the default argument promotions, the behavior is undefined.

    Returns
5   The va_start macro returns no value.
6   EXAMPLE 1 The function f1 gathers into an array a list of arguments that are pointers to strings (but not more than MAXARGS
    arguments), then passes the array as a single argument to function f2. The number of pointers is specified by the first
    argument to f1.




    Library                                             modifications to ISO/IEC 9899:2018, § 7.16.1.4 page 213
    N2734 C17..                          § 7.22.4, working draft — May 15, 2021                          CORE 202101 (E)


    Returns
4   The realloc function returns a pointer to the new object (which may have the same value as a
    pointer to the old object), or a null pointer if the new object has not been allocated.

    7.22.4 Communication with the environment
    7.22.4.1 The abort function
    Synopsis
1             #include <stdlib.h>
              _Noreturn void abort(void);



    Description
2   The abort function causes abnormal program termination to occur, unless the signal SIGABRT
    is being caught and the signal handler does not return. Whether open streams with unwritten
    buffered data are flushed, open streams are closed, or temporary files are removed is implementa-
    tion-defined. An implementation-defined form of the status unsuccessful termination is returned to
    the host environment by means of the function call raise(SIGABRT).

    Returns
3   The abort function does not return to its caller.

    7.22.4.2 The atexit function
    Synopsis
1             #include <stdlib.h>
              int atexit(void (*func)(void));



    Description
2   The atexit function registers the function or function literal pointed to by func, to be called without
                                               ::::::::::::::::
                                               330)
    arguments at normal program termination.        It is unspecified whether a call to the atexit function
    that does not happen before the exit function is called will succeed.

    Environmental limits
3   The implementation shall support the registration of at least 32 functions::::::::
                                                                              function ::::::::
                                                                                       pointers.

    Returns
4   The atexit function returns zero if the registration succeeds, nonzero if it fails.
    Forward references: the at_quick_exit function (7.22.4.3), the exit function (7.22.4.4).

    7.22.4.3 The at_quick_exit function
    Synopsis
1             #include <stdlib.h>
              int at_quick_exit(void (*func)(void));



    Description
2   The at_quick_exit function registers the function ::
                                                      or::::::::
                                                         function::::::
                                                                   literal :pointed to by func, to be
                                          _
    called without arguments should quick exit be called.  331)
                                                                It is unspecified whether a call to
    the at_quick_exit function that does not happen before the quick_exit function is called will
    succeed.
     330) The atexit function registrations are distinct from the at_quick_exit registrations, so applications might need to call

    both registration functions with the same argument.
     331) The at_quick_exit function registrations are distinct from the atexit registrations, so applications might need to call

    both registration functions with the same argument.


    Library                                             modifications to ISO/IEC 9899:2018, § 7.22.4.3 page 271
     CORE 202101 (E)                    § 7.22.4.4, working draft — May 15, 2021                               C17.. N2734


    Environmental limits
3   The implementation shall support the registration of at least 32 functions::::::::
                                                                              function ::::::::
                                                                                       pointers.

    Returns
4   The at_quick_exit function returns zero if the registration succeeds, nonzero if it fails.
    Forward references: the quick_exit function (7.22.4.7).

    7.22.4.4 The exit function
    Synopsis
1             #include <stdlib.h>
              _Noreturn void exit(int status);



    Description
2   The exit function causes normal program termination to occur. No functions ::::::::function ::::::::
                                                                                                pointers
    registered by the at_quick_exit function are called. If a program calls the exit function more than
    once, or calls the quick_exit function in addition to the exit function, the behavior is undefined.
3   First, all functions :::::::
                         function::::::::
                                     pointers:registered by the atexit function are called, in the reverse
                                 332)
    order of their registration,      except that a function :::::::
                                                              pointer is called after any previously registered
    functions function   pointers
                ::::::::::::::::
                                    that had  already  been  called   at the time it was registered. If, during
    the call to any such function or    function literal, a call to the longjmp function is made that would
                                      :::::::::::::::
    terminate the call to the registered function or    function literal, the behavior is undefined.
                                                      :::::::::::::::

4   Next, all open streams with unwritten buffered data are flushed, all open streams are closed, and all
    files created by the tmpfile function are removed.
5   Finally, control is returned to the host environment. If the value of status is zero or EXIT_SUCCESS,
    an implementation-defined form of the status successful termination is returned. If the value of
    status is EXIT_FAILURE, an implementation-defined form of the status unsuccessful termination is
    returned. Otherwise the status returned is implementation-defined.

    Returns
6   The exit function cannot return to its caller.

    7.22.4.5 The _Exit function
    Synopsis
1             #include <stdlib.h>
              _Noreturn void _Exit(int status);



    Description
2   The _Exit function causes normal program termination to occur and control to be returned to
    the host environment. No functions ::::::::
                                           function ::::::::
                                                     pointers :registered by the atexit function, the
    at_quick_exit function, or signal handlers registered by the signal function are called. The
    status returned to the host environment is determined in the same way as for the exit function
    (7.22.4.4). Whether open streams with unwritten buffered data are flushed, open streams are closed,
    or temporary files are removed is implementation-defined.

    Returns
3   The _Exit function cannot return to its caller.

    7.22.4.6 The getenv function
    Synopsis
1             #include <stdlib.h>

     332) Each function is called as many times as it was registered, and in the correct order with respect to other registered

    functionsfunction  pointers.
               ::::::::::::



     modifications to ISO/IEC 9899:2018, § 7.22.4.6 page 272                                                         Library
    N2734 C17..                          § 7.22.4.7, working draft — May 15, 2021                            CORE 202101 (E)


                char *getenv(const char *name);


    Description
2   The getenv function searches an environment list, provided by the host environment, for a string that
    matches the string pointed to by name. The set of environment names and the method for altering
    the environment list are implementation-defined. The getenv function need not avoid data races
    with other threads of execution that modify the environment list.333)
3   The implementation shall behave as if no library function calls the getenv function.

    Returns
4   The getenv function returns a pointer to a string associated with the matched list member. The
    string pointed to shall not be modified by the program, but may be overwritten by a subsequent call
    to the getenv function. If the specified name cannot be found, a null pointer is returned.

    7.22.4.7 The quick_exit function
    Synopsis
1               #include <stdlib.h>
                _Noreturn void quick_exit(int status);


    Description
2   The quick_exit function causes normal program termination to occur. No functions :::::::: function
    pointers
    ::::::::
             registered  by the atexit  function or signal handlers registered by the signal  function
    are called. If a program calls the quick_exit function more than once, or calls the exit function
    in addition to the quick_exit function, the behavior is undefined. If a signal is raised while the
    quick_exit function is executing, the behavior is undefined.
3   The quick_exit function first calls all functions ::::::::  pointers:registered by the at_quick_exit
                                                       function :::::::
    function, in the reverse order of their registration,334) except that a function pointer
                                                                                         :::::::
                                                                                                is called after
                                          function ::::::::
    any previously registered functions ::::::::   pointers that had already been called at the time it was
    registered. If, during the call to any such function ::
                                                         or::::::::
                                                            function::::::
                                                                      literal, a call to the longjmp function
    is made that would terminate the call to the registered function :::::::
                                                                         pointer, the behavior is undefined.
4   Then control is returned to the host environment by means of the function call _Exit(status) .

    Returns
5   The quick_exit function cannot return to its caller.

    7.22.4.8 The system function
    Synopsis
1               #include <stdlib.h>
                int system(const char *string);


    Description
2   If string is a null pointer, the system function determines whether the host environment has a
    command processor. If string is not a null pointer, the system function passes the string pointed to
    by string to that command processor to be executed in a manner which the implementation shall
    document; this might then cause the program calling system to behave in a non-conforming manner
    or to terminate.

    Returns
3   If the argument is a null pointer, the system function returns nonzero only if a command processor
    is available. If the argument is not a null pointer, and the system function does return, it returns an
    333) Many implementations provide non-standard functions that modify the environment list.
    334) Eachfunction pointer is called as many times as it was registered, and in the correct order with respect to other registered
                      :::::
    functionsfunction pointers.
              ::::::::::::



    Library                                               modifications to ISO/IEC 9899:2018, § 7.22.4.8 page 273
     CORE 202101 (E)                         § 7.22.5, working draft — May 15, 2021                C17.. N2734


    implementation-defined value.

    7.22.5         Searching and sorting utilities
1   These utilities make use of a comparison function or   function literal to search or sort arrays of
                                                         ::::::::::::::::
    unspecified type. Where an argument declared as size_t nmemb specifies the length of the array
    for a function, nmemb can have the value zero on a call to that function; the comparison function
    or function literal is not called, a search finds no matching element, and sorting performs no
    :::::::::::::::::
    rearrangement. Pointer arguments on such a call shall still have valid values, as described in 7.1.4.
2   The implementation shall ensure that the second argument of the comparison function or   function
                                                                                           ::::::::::
    literal
    ::::::
            (when called from  bsearch  ), or both arguments (when called from qsort), are pointers to
                          335)
    elements of the array.     The first argument when called from bsearch shall equal key.
3   The comparison function :: or::::::::  literal shall not alter the contents of the array. The implementa-
                                  function::::::
    tion may reorder elements of the array between calls to the comparison function ::      or ::::::::
                                                                                               function :::::
                                                                                                        literal,
    but shall not alter the contents of any individual element.
4   When the same objects (consisting of size bytes, irrespective of their current positions in the
    array) are passed more than once to the comparison function or     function literal, the results shall be
                                                                    :::::::::::::::
    consistent with one another. That is, for qsort they shall define a total ordering on the array, and for
    bsearch the same object shall always compare the same way with the key.
5   A sequence point occurs immediately before and immediately after each call to the comparison
    function or function literal, and also between any call to the comparison function ::
             :::::::::::::::
                                                                                       or::::::::
                                                                                          function::::::
                                                                                                   literal
    and any movement of the objects passed as arguments to that call.

    7.22.5.1 The bsearch function
    Synopsis
1                #include <stdlib.h>
                 void *bsearch(const void *key, const void *base,
                       size_t nmemb, size_t size,
                       int (*compar)(const void *, const void *));


    Description
2   The bsearch function searches an array of nmemb objects, the initial element of which is pointed to
    by base, for an element that matches the object pointed to by key. The size of each element of the
    array is specified by size.
3   The comparison function :: or::::::::
                                  function::::::
                                            literal pointed to by compar is called with two arguments that
    point to the key object and to an array element, in that order. The function A        function call shall
                                                                                        :::::::::::::
    return an integer less than, equal to, or greater than zero if the key object is considered, respectively,
    to be less than, to match, or to be greater than the array element. The array shall consist of: all the
    elements that compare less than, all the elements that compare equal to, and all the elements that
    compare greater than the key object, in that order.336)

    Returns
4   The bsearch function returns a pointer to a matching element of the array, or a null pointer if no
    match is found. If two elements compare as equal, which element is matched is unspecified.




    335) That   is, if the value passed is p, then the following expressions are always nonzero:

                 ((char *)p - (char *)base) % size == 0
                 (char *)p >= (char *)base
                 (char *)p < (char *)base + nmemb * size


    336) In   practice, the entire array is sorted according to the comparison function.


     modifications to ISO/IEC 9899:2018, § 7.22.5.1 page 274                                           Library
    N2734 C17..                         § 7.22.5.2, working draft — May 15, 2021                       CORE 202101 (E)


    7.22.5.2 The qsort function
    Synopsis
1               #include <stdlib.h>
                void qsort(void *base, size_t nmemb, size_t size,
                      int (*compar)(const void *, const void *));



    Description
2   The qsort function sorts an array of nmemb objects, the initial element of which is pointed to by
    base. The size of each object is specified by size.
3   The contents of the array are sorted into ascending order according to a comparison function or        ::
    function literal pointed to by compar, which is called with two arguments that point to the objects
    ::::::::::::::
    being compared. The function ::  A ::::::::
                                        function :::
                                                 call:shall return an integer less than, equal to, or greater
    than zero if the first argument is considered to be respectively less than, equal to, or greater than the
    second.
4   If two elements compare as equal, their order in the resulting sorted array is unspecified.

    Returns
5   The qsort function returns no value.

    7.22.6 Integer arithmetic functions
    7.22.6.1 The abs, labs and dlabs functions
    Synopsis
1               #include <stdlib.h>
                int abs(int j);
                long int labs(long int j);
                long long int llabs(long long int j);



    Description
2   The abs, labs, and llabs functions compute the absolute value of an integer j. If the result cannot
    be represented, the behavior is undefined.337)

    Returns
3   The abs, labs, and llabs, functions return the absolute value.

    7.22.6.2 The div, ldiv, and lldiv functions
    Synopsis
1               #include <stdlib.h>
                div_t div(int numer, int denom);
                ldiv_t ldiv(long int numer, long int denom);
                lldiv_t lldiv(long long int numer, long long int denom);



    Description
2   The div, ldiv, and lldiv, functions compute numer/denom and numer%denom in a single operation.

    Returns
3   The div, ldiv, and lldiv functions return a structure of type div_t, ldiv_t, and lldiv_t, respec-
    tively, comprising both the quotient and the remainder. The structures shall contain (in either order)
    the members quot (the quotient) and rem (the remainder), each of which has the same type as
    the arguments numer and denom. If either part of the result cannot be represented, the behavior is
    undefined.
    337) The   absolute value of the most negative number cannot be represented in two’s complement.


    Library                                             modifications to ISO/IEC 9899:2018, § 7.22.6.2 page 275
    N2734 C17..                   § 7.26.2, working draft — May 15, 2021               CORE 202101 (E)


    which is passed to mtx_init to create a mutex object that does not support timeout;

              mtx_recursive


    which is passed to mtx_init to create a mutex object that supports recursive locking;

              mtx_timed


    which is passed to mtx_init to create a mutex object that supports timeout;

              thrd_timedout


    which is returned by a timed wait function to indicate that the time specified in the call was reached
    without acquiring the requested resource;

              thrd_success


    which is returned by a function to indicate that the requested operation succeeded;

              thrd_busy


    which is returned by a function to indicate that the requested operation failed because a resource
    requested by a test and return function is already in use;

              thrd_error


    which is returned by a function to indicate that the requested operation failed; and

              thrd_nomem


    which is returned by a function to indicate that the requested operation failed because it was unable
    to allocate memory.
6   For  function pointers that are passed to the functions call_once, tss_create, and thrd_create
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    calls to the underlying function or function literal are sequenced as if they where directly called by
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    the application from the indicated thread.
    :::::::::::::::::::::::::::::::::::::

    Forward references: date and time (7.27).

    7.26.2 Initialization functions
    7.26.2.1 The call_once function
    Synopsis
1             #include <threads.h>
              void call_once(once_flag *flag, void (*func)(void));


    Description
2   The call_once function uses the once_flag pointed to by flag to ensure that func is called exactly
    once, the first time the call_once function is called with that value of flag. Completion of an
    effective call to the call_once function synchronizes with all subsequent calls to the call_once
    function with the same value of flag.

    Returns
3   The call_once function returns no value.

    7.26.3 Condition variable functions
    7.26.3.1 The cnd_broadcast function


    Library                                    modifications to ISO/IEC 9899:2018, § 7.26.3.1 page 291
N2734                             § A.2.1, working draft — May 15, 2021               CORE 202101 (E)


(6.5.1.1) generic-selection:
                     _Generic ( assignment-expression , generic-assoc-list )
(6.5.1.1) generic-assoc-list:
                      generic-association
                      generic-assoc-list , generic-association
(6.5.1.1) generic-association:
                      type-name : assignment-expression
                      default : assignment-expression
(6.5.2) postfix-expression:
                      primary-expression
                      postfix-expression [ expression ]
                      postfix-expression ( argument-expression-listopt )
                      postfix-expression . identifier
                      postfix-expression -> identifier
                      postfix-expression ++
                      postfix-expression -
                      ( type-name ) { initializer-list }
                      ( type-name ) { initializer-list , }
::::::::::::::::
                      lambda-expression

(6.5.2) argument-expression-list:
                    assignment-expression
                    argument-expression-list , assignment-expression

(6.5.2.6) lambda-expression:
::::::::::::::::
                    capture-clause parameter-clauseopt attribute-specifier-sequenceopt function-body

(6.5.2.6) capture-clause:
::::::::::::::::
                     [ capture-listopt ]
::::::::::::::::
                     [ default-capture ]

(6.5.2.6) capture-list:
::::::::::::::::
                      capture-list-element
::::::::::::::::
                      default-capture
::::::::::::::::
                      capture-list , capture-list-element

(6.5.2.6) default-capture:
::::::::::::::::
                 =
::::::::::::::::
                 &

(6.5.2.6) capture-list-element:
::::::::::::::::
                      value-capture
::::::::::::::::
                      reference-capture

(6.5.2.6) value-capture:
::::::::::::::::
                     capture
::::::::::::::::
                     capture = assignment-expression

(??) reference-capture:
::::::::::::::::
                     & capture

(6.5.2.6) capture:
::::::::::::::::
                     identifier

(6.5.2.6) parameter-clause:
::::::::::::::::
                     ( parameter-listopt )




Language syntax summary                          modifications to ISO/IEC 9899:2018, § A.2.1 page 355
 CORE 202101 (E)                    § A.2.2, working draft — May 15, 2021                         N2734


(6.7.2) type-specifier:
                      void
                      char
                      short
                      int
                      long
                      float
                      double
                      signed
                      unsigned
                      _Bool
                      _Complex
                 atomic-type-specifier
                 struct-or-union-specifier
                 enum-specifier
                 typedef-name
::::::::::::::::
                 typeof-specifier

(6.7.2.1) struct-or-union-specifier:
                     struct-or-union identifieropt { struct-declaration-list }
                     struct-or-union identifier
(6.7.2.1) struct-or-union:
                      struct
                      union

(6.7.2.1) struct-declaration-list:
                      struct-declaration
                      struct-declaration-list struct-declaration
(6.7.2.1) struct-declaration:
                      specifier-qualifier-list struct-declarator-listopt ;
                      static_assert-declaration
(6.7.2.1) specifier-qualifier-list:
                      type-specifier specifier-qualifier-listopt
                      type-qualifier specifier-qualifier-listopt
                      alignment-specifier specifier-qualifier-listopt
(6.7.2.1) struct-declarator-list:
                      struct-declarator
                      struct-declarator-list , struct-declarator
(6.7.2.1) struct-declarator:
                      declarator
                      declaratoropt : constant-expression
(6.7.2.2) enum-specifier:
                      enum identifieropt { enumerator-list }
                      enum identifieropt { enumerator-list , }
                      enum identifier
(6.7.2.2) enumerator-list:
                      enumerator
                      enumerator-list , enumerator
(6.7.2.2) enumerator:
                      enumeration-constant
                      enumeration-constant = constant-expression
(6.7.2.4) atomic-type-specifier:
                      _Atomic ( type-name )
(6.7.3) type-qualifier:
                      const
                      restrict
                      volatile
                      _Atomic


 modifications to ISO/IEC 9899:2018, § A.2.2 page 358                            Language syntax summary