Home | Manual | Playground

# Cake - C23 and Beyond

- Intro
- Static analyzer
- Include directories
- Command line
  - OPTIONS
  - -fanalyzer
  - -auto-config
- Output
- Pre-defined macros
  - Pre-defined macros for MSVC compatibility
  - Pre-defined macros for GCC compatibility
- K & R
  - Bitfileld
- C89
  - enums
  - const
  - Function prototypes
- C99
  - C99 restrict pointers
  - C99 Variable-length array (VLA)
  - C99 Flexible array members
  - C99 static and type qualifiers in parameter array declarators
  - C99 Complex and imaginary support
  - C99 Universal character names (\u and \U)
  - C99 Hexadecimal floating constants
  - C99 Compound literals
  - C99 Designated initializers
  - C99 Line comments
  - C99 inline functions
  - C99 _Pragma preprocessing operator
  - C99 __func__ predefined identifier
  - C99 Variadic macros
  - C99 _Bool
- C11 Transformations
  - C11 _Static_assert
  - C11 Anonymous structures and unions
  - C11 _Noreturn
  - C11 Thread_local/Atomic
  - C11 type-generic expressions (_Generic)
  - C11 u' ' U' ' character constants
  - C11 u8"literals"
  - C11 _Alignof or C23 alignof
  - C11 _Alignas or C23 alignas
- C23 Transformations
  - C23 _Decimal32, _Decimal64, and _Decimal128
  - C23 static_assert / single-argument static_assert
  - C23 u8 character prefix
  - C23 No function declarators without prototypes
  - C23 Improved Tag Compatibility
  - C23 Unnamed parameters in function definitions
  - C23 Digit separators
  - C23 Binary literals
  - C23 Introduce the nullptr constant
  - C23 Make false and true first-class language features
  - C23 {} empty initializer
  - C23 auto
  - C23 typeof / typeof_unqual
  - C23 Improved Normal Enumerations
  - C23 constexpr
  - C23 Enhancements to Enumerations
  - C23 Attributes
  - C23 fallthrough attribute
  - C23 deprecated attribute
  - C23 maybe_unused attribute
  - C23 nodiscard attribute
  - C23 [[unsequenced]] and [[reproducible]]
  - C23 __has_attribute
  - C23 __has_include
  - C23 #warning
  - C23 #embed
  - C23 #elifdef #elifndef
  - C23 __VA_OPT__
  - C23 BitInt(N))
  - C23 Compound Literals with storage specifier
  - C23 Variably-modified (VM) types
- C2Y Transformations
  - Obsolete implicitly octal literals
  - Extension - defer
  - Extension - if with initializer
  - Extension typename on _Generic
- Cake Extensions (Not in C23, C2Y)
  - Extension - try catch throw
  - Extension Literal function - lambdas
  - Type traits
  - Extension - Object lifetime checks
  - Extension assert built-in

## Intro

Cake works as an extension for MSVC on Windows and as an extension for GCC on Linux. This approach makes Cake useful in real and existing programs.

When applicable, Cake uses the same command line options of MSVC and GCC.

## Static analyzer

For static analyzer concepts of ownership and nullable pointers visit ownership

## Include directories

On Windows, Cake can be used on the command line similarly to MSVC. Cake reads the `INCLUDE` variable, the same variable used by MSVC to locate the include directories.

Additionally, you can run Cake outside the Visual Studio command prompt by placing the file `cakeconfig.h` in the same directory or above the source files, and specifying the directories using #pragma dir.

If Cake doesn't find `cakeconfig.h` in the local directories, it will try to locate it in the same path as the Cake executable.

The -autoconfig option generates the `cakeconfig.h` automatically on both Windows and Linux.

To manually discover which directories are included, you can run the command:

    echo %INCLUDE%

at Visual Studio command prompt.

To find out what are the directories used by GCC type:

    echo | gcc -E -Wp,-v -

Sample of cakeconfig.h

    #ifdef __linux__
    /*
       To find the include directories used my GCC type:
       echo | gcc -E -Wp,-v -
    */
    #pragma dir "/usr/lib/gcc/x86_64-linux-gnu/11/include"
    #pragma dir "/usr/local/include"
    #pragma dir "/usr/include/x86_64-linux-gnu"
    #pragma dir "/usr/include"

    #endif

    #ifdef _WIN32
    /*
       To find the include directories used my  MSVC,
       open Visual Studio Developer Commmand prompt and type:
       echo %INCLUDE%.
       Running Cake inside mscv command prompt uses %INCLUDE% automatically.
    */
    #pragma dir "C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.38.33130/include"
    #pragma dir "C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.38.33130/ATLMFC/include"
    #pragma dir "C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Auxiliary/VS/include"
    #pragma dir "C:/Program Files (x86)/Windows Kits/10/include/10.0.22000.0/ucrt"
    #pragma dir "C:/Program Files (x86)/Windows Kits/10/include/10.0.22000.0/um"
    #pragma dir "C:/Program Files (x86)/Windows Kits/10/include/10.0.22000.0/shared"
    #pragma dir "C:/Program Files (x86)/Windows Kits/10/include/10.0.22000.0/winrt"
    #pragma dir "C:/Program Files (x86)/Windows Kits/10/include/10.0.22000.0/cppwinrt"
    #pragma dir "C:/Program Files (x86)/Windows Kits/NETFXSDK/4.8/include/um"

    #endif

Sample, project `cakeconfig.h`

    //system includes...etc
    #include "C:\Program Files (x86)\cake\cakeconfig.h"

    //project extra includes
    #pragma dir ".\openssl\include"

## Command line

    cake [options] source1.c source2.c ...

    SAMPLES

        cake source.c
        Compiles source.c and outputs /out/source.c

        cake -target=C11 source.c
        Compiles source.c and outputs C11 code at /out/source.c

    cake file.c -o file.cc && cl file.cc
        Compiles file.c and outputs file.cc then use cl to compile file.cc

    cake file.c -direct-compilation -o file.cc && cl file.cc
        Compiles file.c and outputs file.cc for direct compilation then use cl to compile file.cc

### OPTIONS

#### -I (same as GCC and MSVC)

Adds a directory to the list of directories searched for include files

#### -no-output

Cake will not generate output

#### -D (same as GCC and MSVC)

Defines a preprocessing symbol for a source file

#### -E (same as GCC and MSVC)

Copies preprocessor output to standard output

#### -o name.c (same as GCC and MSVC)

Defines the output name. used when we compile one file

#### -dump-tokens

Output tokens before preprocessor

#### -Wname -Wno-name (same as GCC)

Enables or disable warnings. See warnings

#### -disable-assert

disable cake extension where assert is an statement. See extensions

#### -showIncludes

Causes the compiler to output a list of the include files. The option also displays nested include files, that is, the files included by the files that you include.

#### -Wall

Enables all warnings

#### -sarif

Generates sarif files. Sarif Visual Studio plugin https://marketplace.visualstudio.com/items?itemName=WDGIS.MicrosoftSarifViewer

#### -sarif-path

Specifies the Sarif output dir.

Inside "Visual Studio -> External Tools" this command can be used for static analysis.

`-Wstyle -msvc-output -no-output -sarif -sarif-path "$(SolutionDir).sarif" $(ItemPath)´

#### -msvc-output

Output is compatible with visual studio IDE. We can click on the error message and IDE selects the line.

### -fanalyzer

This option enables an static analysis of program flow. This is required for some ownership checks

### -auto-config

Generates cakeconfig.h header.

On Windows, it must be generated inside the Visual Studio Command Prompt to read the INCLUDE variable. On Linux, it calls GCC with echo | gcc -v -E - 2>&1 and reads the output.

## Output

One directory called out is created keeping the same directory structure of the input files.

For instance:

    cake c:\project\file1.c

output:

      c:\project
      ├── file1.c
      ├── out
          ├── file1.c

More files..

    cake c:\project\file1.c c:\project\other\file2.c

output

      c:\project
      ├── file1.c
      ├── other
      │   ├── file2.c
      ├── out
          ├── file1.c
          ├── other
              ├── file2.c

## Pre-defined macros

     #define __CAKE__ 202311L
     #define __STDC_VERSION__ 202311L
     #define __STDC_OWNERSHIP__ 1

The define STDC_OWNERSHIP indicates that the compiler suports owneship checks

### Pre-defined macros for MSVC compatibility

https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170#standard-predefined-macros

### Pre-defined macros for GCC compatibility

https://gcc.gnu.org/onlinedocs/cpp/Predefined-Macros.html

## K & R

### Bitfileld

not implemented yet

## C89

C89 https://port70.net/~nsz/c/c89/c89-draft.html

### enums

Implemented. C89 backend. enum specifiers become the corresponding type and the enumerators becomes constants. See C23 enum

### const

Implemented. C89 backend removes const.

### Function prototypes

In C23 the old K&R was removed.

## C99

C99 https://open-std.org/JTC1/SC22/WG14/www/docs/n1124.pdf

     #define __STDC_VERSION__ 199901L  //C99

### C99 restrict pointers

    void f(const char* restrict s);

Backend is removing restrict this. (TODO It will be added with a compiler flag)

N448

### C99 Variable-length array (VLA)

    #include <stdlib.h>
    #include <stdio.h>

    int main() {
        int n = 2;
        int m = 3;
        int (*p)[n][m] = malloc(sizeof * p);

        printf("%zu\n", sizeof(*p));

        free(p);
    }

Becomes C89 (not implemented)

    #include <stdlib.h>
    #include <stdio.h>

    int main() {
        int n = 2;
        int m = 3;

        /*these variables are created to store the dynamic size*/
        const int vla_1_n = n;
        const int vla_1_m = m;

        int (*p)[n][m] = malloc((vla_1_n*vla_1_m)*sizeof(int));

        printf("%zu\n", (vla_1_n*vla_1_m)*sizeof(int));

        free(p);
    }

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n683.htm

### C99 Flexible array members

    struct s {
        int n;
        double d[];
    };

Becomes (not implemented)

    struct s {
        int n;
        double d[1];
    };

    //TODO sizeof

### C99 static and type qualifiers in parameter array declarators

    #include <stdlib.h>

    void F(int a[static 5]) {
    }

    int main()
    {
        F(0);
        F(NULL);
        F(nullptr);

        int a[] = {1, 2, 3};
        F(a);//error

        int b[] = { 1, 2, 3 , 4, 5};
        F(b);

        int c[] = { 1, 2, 3 , 4, 5, 6};
        F(c);
    }

Cake verifies that the argument is an array with at least the specified number of elements. It extends this check to arrays without a static size as well.

### C99 Complex and imaginary support

Not implemented

### C99 Universal character names (\u and \U)

Not implemented

### C99 Hexadecimal floating constants

    double d = 0x1p+1;

Becomes in C89

    double d = 2.000000;

Cake converts hexadecimal floating-point values to decimal floating-point representation using strtod followed by snprintf. This conversion may introduce precision loss.

### C99 Compound literals

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

Becomes in C89

    struct s {
      int i;
    };
    int f(void) {
      struct s * p = 0, * q;
      int j = 0;
      again:
        struct s compound_literal_1 = { j++ };
        q = p, p = & compound_literal_1;
      if (j < 2) goto again;
      return p == q && q -> i == 1;
    }

N716 https://www.open-std.org/jtc1/sc22/wg14/www/docs/n716.htm

### C99 Designated initializers

     int main()
     {
      int a[6] = {[4] = 29, [2] = 15 };

      struct point { int x, y; };

      struct point p = { .y = 2, .x = 3 }
     }

Becomes C89

    int main()
    {
      int a[6] = { 0, 0, 15, 0, 29, 0 };
      struct point { int x, y; };
      struct point p = { 3, 2 }
    }

N494 https://www.open-std.org/jtc1/sc22/wg14/www/docs/n494.pdf

### C99 Line comments

Implemented.

C89 backend n/a.

### C99 inline functions

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n741.htm

### C99 _Pragma preprocessing operator

Not implemented. TODO!

### C99 __func__ predefined identifier

Parsed. C89 not implemented yet. TODO!

### C99 Variadic macros

    #include <stdio.h>

    #define debug(...) fprintf(stderr, __VA_ARGS__)
    #pragma expand debug

    int main()
    {
      int x = 1;
      debug("X = %d\n", 1);
    }

C89 backend n/a

N707 https://www.open-std.org/jtc1/sc22/wg14/www/docs/n707.htm

### C99 _Bool

When compiling to C89 _Bool is replaced by unsigned char.

    //line comments
    int main(void)
    {
        _Bool b = 1;
        return 0;
    }

Becomes in C89

    /*line comments*/
    int main(void)
    {
        unsigned char b = 123;
        return 0;
    }

TODO. Conversion to 1 or 0 at backend.

## C11 Transformations

    #define __STDC_VERSION__ 201112L //C11

https://open-std.org/JTC1/SC22/WG14/www/docs/n1570.pdf

https://files.lhmouse.com/standards/ISO%20C%20N2176.pdf

### C11 _Static_assert

Implemented. C89 backend n/a

### C11 Anonymous structures and unions

    struct v {
      union { /* anonymous union*/
         struct { int i, j; }; /* anonymous structure*/
         struct { long k, l; } w;
      };
      int m;
    } v1;

    int main(){
      v1.i = 2; /* valid*/
      v1.w.k = 5; /* valid*/
    }

C89 backend, names are generated for the anonymous parts.

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1406.pdf

### C11 _Noreturn

    _Noreturn void f () {
      abort(); // ok
    }

C89 backend it is removed.

### C11 Thread_local/Atomic

Parsed but not transformed. C89 backend TODO.

### C11 type-generic expressions (_Generic)

Implemented

N1441 https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1441.htm

    #include <math.h>

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

    #pragma expand cbrt

    int main(void)
    {
        cbrt(1.0);
    }

C89 backend will have the selected expression.

### C11 u' ' U' ' character constants

     int i = U'ç';
     int i2 = u'ç';

C89 backend

     int i = 231u;
     int i2 = ((unsigned short)231);

Important: Cake assume source is utf8 encoded.

### C11 u8"literals"

u8 literals are converted to escape sequences.

    char * s1 = u8"maçã";
    char * s2 = u8"maca";

C89 backend

    char * s1 = "ma\xc3\xa7\xc3\xa3";
    char * s2 = "maca";

N1488 https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1488.htm

Important: Cake assume source is utf8 encoded.

### C11 _Alignof or C23 alignof

     int main()
     {
       int align = alignof(int);
     }

The C89 backend replaces by its constant value.

     int main()
     {
       int align = 4;
     }

### C11 _Alignas or C23 alignas

Not implemented.

## C23 Transformations

https://open-std.org/JTC1/SC22/WG14/www/docs/n3096.pdf

    #define __STDC_VERSION__ 201710L  //C17
    #define __STDC_VERSION__ 202311L  //C23

### C23 _Decimal32, _Decimal64, and _Decimal128

Not implemented. https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1107.htm

### C23 static_assert / single-argument static_assert

Implemented. C89 backend n/a

N1330 https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1330.pdf

### C23 u8 character prefix

Implemented. https://open-std.org/JTC1/SC22/WG14/www/docs/n2418.pdf

    int main(){
        unsigned char c = u8'~';
    }

C89 backend

    int main(){
        unsigned char c = ((unsigned char)'~');
    }

### C23 No function declarators without prototypes

Implemented. https://www.open-std.org/JTC1/SC22/WG14/www/docs/n2841.htm

    int main(){
        func(); //this is an error in C23
    }

See also Remove support for function definitions with identifier lists

https://open-std.org/JTC1/SC22/WG14/www/docs/n2432.pdf

### C23 Improved Tag Compatibility

Not implemented yet.

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3037.pdf

    struct foo { int a; } p;
    void bar(void)
    {
      struct foo { int a; } q;
      q = p;
    }

Becomes < C23

    struct foo { int a; } p;
    void bar(void)
    {
      struct foo  q;
      q = p;
    }

### C23 Unnamed parameters in function definitions

    int f(int );

    int f(int ) {
    }

https://open-std.org/JTC1/SC22/WG14/www/docs/n2480.pdf

C89 backened. We should add a dummy name when generating - Not implemented yet.

### C23 Digit separators

    int main()
    {
        int a = 1000'00;
    }

C89 backend

    int main()
    {
        int a = 100000;
    }

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2626.pdf

### C23 Binary literals

    #define X  0b1010

    int main()
    {
        int a = X;
        int b = 0B1010;
    }

C89 backend it will be decimal

    int main()
    {
        int a = 10;
        int b = 10;
    }

### C23 Introduce the nullptr constant

    int main()
    {
      void * p = nullptr;
      auto p2 = nullptr;
      typeof(nullptr) p3 = nullptr;
    }

C89 backend converts to ((void*)0)

    int main()
    {
      void * p = ((void*)0);
      void  * p2 = ((void*)0);
      void  * p3 = ((void*)0);
    }

https://open-std.org/JTC1/SC22/WG14/www/docs/n3042.htm

### C23 Make false and true first-class language features

Implemented

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2935.pdf

C89 backend. bool specifier is replaced by unsigned char; true by the constant 1 ; false by the constant 0.

### C23 {} empty initializer

    int main()
    {
        struct X {
            int i;
        } x = {};

        x = (struct X) {};

        struct Y
        {
            struct X x;
        } y = { {} };
    }

C89 backend

    int main()
    {
        struct X {
            int i;
        } x = {0};

        x = (struct X) {0};

        struct Y
        {
            struct X x;
        } y = { {0} };
    }

> Note: Cake code is 100% equivalent because it does not make padding bit zero.

### C23 auto

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

    double A[3] = { 0 };
    auto pA = A;
    auto qA = &A;

C89 backend the final type is used.

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

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

https://open-std.org/JTC1/SC22/WG14/www/docs/n3007.htm

### C23 typeof / typeof_unqual

    #define SWAP(a, b) \
      do {\
        typeof(a) temp = a; a = b; b = temp; \
      } while (0)

    #pragma expand SWAP

    int main()
    {
        /*simple case*/
        int a = 1;
        typeof(a) b = 1;

        /*pay attention to the pointer*/
        typeof(int*) p1, p2;

        /*let's expand this macro and see inside*/
        SWAP(a, b);

        /*for anonymous structs we insert a tag*/
        struct { int i; } x;
        typeof(x) x2;
        typeof(x) x3;

       /*Things get a little more complicated*/
       int *array[2];
       typeof(array) a1, a2;

       typeof(array) a3[3];
       typeof(array) *a4[4];

       /*abstract declarator*/
       int k = sizeof(typeof(array));

       /*new way to declare pointer to functions?*/
       typeof(void (int)) * pf = NULL;
    }

C89 backend

    struct _struct_tag_0 {
        int i;
    };

    int (* g1)(int a);
    int (* g2)(int a);
    int *(* f3)(int a);
    int f()
    {
        return 1;
    }

    void f4(int a[2])
    {
        int * p;
    }

    int main()
    {
        int a = 1;
        int b = 1;
        int * p1;
        int * p2;
        int * p3;
        int * p4;
        int p5;
        int * p6;
        do
        {
            int temp = a;
            a = b;
            b = temp;
        }
        while (0);
        struct _struct_tag_0  x;
        struct _struct_tag_0  x2;
        struct _struct_tag_0  x3;
        int *array[2];
        int *a1[2];
        int *a2[2];
        int *a3[3][2];
        int *(*a4[4])[2];
        int k = sizeof (int *[2]);
        void (* pf)(int) = ((void *)0);
    }

    int f5()
    {
        int (* p1)[2] = 0;
        int (* p2)[2] = (int (*)[2])p1;
    }

https://open-std.org/JTC1/SC22/WG14/www/docs/n2927.htm https://open-std.org/JTC1/SC22/WG14/www/docs/n2930.pdf

### C23 Improved Normal Enumerations

//TODO

https://open-std.org/JTC1/SC22/WG14/www/docs/n3029.htm

    enum a {
        a0 = 0xFFFFFFFFFFFFFFFFULL
    };

    static_assert(_Generic(a0,
            unsigned long long: 0,
            int: 1,
            default: 2 == 0));

The type of the enum must be adjusted.

### C23 constexpr

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3018.htm

Cake convert constexpr declarator with a cast and the value. addressof constexpr declarator is not implemented.

    #include <stdio.h>

    constexpr int c = 123;

    constexpr int c2 = c + 1000;

    int a[c];

    constexpr double PI = 3.14;

    static_assert(PI + 1 == 3.14 + 1.0);

    struct Y {
        int a;
        int ar[3];
        int b;
    };

    void T3()
    {
        constexpr struct Y y = { .ar[1] = 2, 3, 4 };
        static_assert(y.a == 0);
        static_assert(y.ar[0] == 0);
        static_assert(y.ar[1] == 2);
        static_assert(y.ar[2] == 3);
        static_assert(y.b == 4);
        static_assert(y.ar[1] + y.ar[2] == 5);
    }

    static_assert("abc"[0] == 'a');

    int main()
    {
        constexpr char ch = 'a';

        printf("%f %c", PI, ch);
    }

C89 backend will replace by constants in places where a constant expression is required.

    struct Y {
        int a;
        int ar[3];
        int b;
    };

    int c = 123;
    int c2 = c + 1000;
    int a[123];
    double PI = 3.140000;
    void T3()
    {
        struct Y  y = {0, 0, 2, 3, 4};
    }

    int printf(char * format, ...);

    int main()
    {
        char ch = 97;
        printf("%f %c", PI, ch);
    }

TODO: Maybe suffix like ULL etc makes the code easier to read.

### C23 Enhancements to Enumerations

    enum X : short {
      A
    };

    int main() {
       enum X x = A;
    }

C89 backend.

    enum X {
      A
    };

    int main() {
       short x = ((short)A);
    }

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3030.htm

### C23 Attributes

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2335.pdf https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2554.pdf

Related: Standard Attributes in C and C++ - Timur Doumler - ACCU 2023 https://youtu.be/EpAEFjbTh3I

### C23 fallthrough attribute

Not implemented C89 backend - n/a

https://open-std.org/JTC1/SC22/WG14/www/docs/n2408.pdf

### C23 deprecated attribute

Partially implemented https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2334.pdf C89 backend - n/a

### C23 maybe_unused attribute

Implemented https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2270.pdf

C89 backend - n/a

### C23 nodiscard attribute

Partially implemented

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2267.pdf

https://open-std.org/JTC1/SC22/WG14/www/docs/n2448.pdf

C89 backend - n/a

### C23 [[unsequenced]] and [[reproducible]]

//TODO

https://open-std.org/JTC1/SC22/WG14/www/docs/n2956.htm

### C23 __has_attribute

Implemented C89 backend - n/a

### C23 __has_include

    #if __has_include(<stdio.h>)
    #warning  YES
    #endif

    #if __has_include(<any.h>)
    #warning  YES
    #else
    #warning  NO
    #endif

Implemented C89 backend - n/a

### C23 #warning

Implemented

    int main()
    {
      #warning my warning message
    }

    Implemented
    C89 backend - n/a

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2686.pdf

### C23 #embed

Partially implemented.

    #include <stdio.h>

    int main()
    {
      static const char file_txt[] = {
       #embed "stdio.h"
       ,0
      };

      printf("%s\n", file_txt);
    }

C89 backend. TODO fix bug.

    https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3017.htm

    #include <stdio.h>

    int main()
    {
      static const char file_txt[] = {
        35,112,114,/*lot more here ...*/ 13,10
       ,0
      };

      printf("%s\n", file_txt);
    }

### C23 #elifdef #elifndef

Implemented

    #define Y

    #ifdef X
    #define VERSION 1
    #elifdef  Y
    #define VERSION 2
    #else
    #define VERSION 3
    #endif

C89 backend - n/a

### C23 __VA_OPT__

Implemented.

    #define F(...) f(0 __VA_OPT__(,) __VA_ARGS__)
    #define G(X, ...) f(0, X __VA_OPT__(,) __VA_ARGS__)
    #define SDEF(sname, ...) S sname __VA_OPT__(= { __VA_ARGS__ })
    #define EMP

    /*maybe this could be automatic if <C23*/
    #pragma expand F
    #pragma expand G
    #pragma expand SDEF
    #pragma expand EMP

    void f(int i, ...) {}

    int main()
    {
      int a = 1;
      int b = 2;
      int c = 3;

      F(a, b, c);
      F();
      F(EMP);
      G(a, b, c);
      G(a, );
      G(a);

    }

C89 backend - n/a

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3033.htm

### C23 BitInt(N))

Not implemented

### C23 Compound Literals with storage specifier

Not implemented yet.

    void F(int *p){}

    int main()
    {
       F((static int []){1, 2, 3, 0})
    }

Becomes (not implemented yet)

    void F(int *p){}

    int main()
    {
        static int _compound_1[] = {1, 2, 3, 0};
        F(_compound_1);
    x   }

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3038.htm

### C23 Variably-modified (VM) types

Not implemented https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2778.pdf

## C2Y Transformations

### Obsolete implicitly octal literals

    static_assert(0o52 == 052);
    static_assert(0O52 == 052);
    static_assert(0O52 == 42);

    int main()
    {
        int i = 0o52;
    }

c89 backend (all constantes are decimals)

### Extension - defer

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3199.htm

defer will call the defer statement before the block exit at inverse order of declaration.

         defer-statement:
            defer secondary-block

For instance:

    #include <stdio.h>

    int main() {
      do {
         FILE* f = fopen("in.txt", "r");
         if (f == NULL) break;
         defer fclose(f);

         FILE* f2 = fopen("out.txt", "w");
         if (f2 == NULL) break;
         defer fclose(f2);
         //...
      }
      while(0);
    }

C89 backend

    int *fopen(char * filename, char * mode);
    int fclose(int * stream);

    int main()
    {
        do
        {
            int * f = fopen("in.txt", "r");
            if (f == ((void *)0))
            {
                break;
            }
            int * f2 = fopen("out.txt", "w");
            if (f2 == ((void *)0))
            {
                fclose(f);
                break;
            }
            fclose(f2);
            fclose(f);
        }
        while (0);
    }

### Extension - if with initializer

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3196.htm

    #include <stdio.h>
    int main()
    {
       int size = 10;
       if (FILE* f = fopen("file.txt", "r"); f)
       {
         /*...*/
         fclose(f);
       }
    }

C89 backend

    int *fopen(char * filename, char * mode);
    int fclose(int * stream);

    int main()
    {
        int size = 10;
        {
            int * f = fopen("file.txt", "r");
            if (f)
            {
                fclose(f);
            }
        }
    }

C++ proposal https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0305r0.html

### Extension typename on _Generic

This feature was created in Cake and now it is part of C2Y!

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3260.pdf

     int main()
    {
        const int * const p;
        static_assert(_Generic(p, const int *: 1));

        /*extension*/
        static_assert(_Generic(int, int : 1));
        static_assert(_Generic(typeof(p), const int * const: 1));
    }

C89 backend see _Generic.

## Cake Extensions (Not in C23, C2Y)

### Extension - try catch throw

       try-statement:
          try secondary-block
          try secondary-block catch secondary-block

    jump-statement:
      throw;

try catch is a external block that we can jump off.

try catch is a LOCAL jump this is on purpose not a limitation.

catch block is optional.

    try
    {
       for (int i = 0 ; i < 10; i++) {
          for (int j = 0 ; j < 10; j++) {
            ...
            if (error) throw;
            ...
          }
       }
    }
    catch
    {
    }

### Extension Literal function - lambdas

Lambdas without capture where implemented using a syntax similar of compound literal for function pointer.

Lambdas are the most complex code transformation so far because sometimes function scope types needs to be transformed to file scope. This is important because manual lambda capture is something we want to use in function scope.

For instance:

    extern char* strdup(const char* s);
    void create_app(const char* appname)
    {
      struct capture {
         char * name;
      } capture = { .name = strdup(appname) };

      (void (void* p)) {
        struct capture* capture = p;
      }(&capture);
    }

C89 backend ```c struct capture { char * name; };

extern char *strdup(char * s);

static void lambda0(void * p) { struct capture * capture = p; }

void create_app(char * appname) { struct capture capture = {0}; capture.name = strdup(appname); lambda0(&capture); }

    ### Extension #pragma dir

    ```c
    #pragma dir "C:/Program Files (x86)/Windows Kits/10//include/10.0.22000.0/cppwinrt"

pragma dir makes the preprocessor include the directory when searching for includes.

### Type traits

We have some compile time functions to infer properties of types.

    _is_char()
    The three types char, signed char, and unsigned char are collectively called the character types.

    _is_pointer
    Pointer to object or function

    _is_array
    Array type

    _is_function
    A function type describes a function with specified return type.

    _is_floating_point
    float, double, and long double return true

    _is_integral
    The standard signed integer types and standard unsigned integer types are collectively called the
    standard integer types;

    _is_arithmetic
    Integer and floating types are collectively called arithmetic types.

    _is_scalar
    Arithmetic types, pointer types, and the nullptr_t type are collectively called scalar types

Note: Type traits that can be easily created with _Generic will be removed. _

### Extension - Object lifetime checks

See ownership

### Extension assert built-in

In cake assert is an built-in function. The reason is because it works as tips for flow analysis.

For instance, in a linked list when `head` is null `tail` is also null, and `tail->next` always points to null.

Assertion will check these properties in runtime and also make the static analysis assume that assert evaluates to true.

    void list_push_back(struct list* list,
                        struct item* _Owner p_item)
    {
       if (list->head == NULL) {
          list->head = p_item;
       }
       else {
          assert(list->tail != nullptr);
          assert(list->tail->next == nullptr);
          list->tail->next = p_item;
       }
       list->tail = p_item;
    }

However, `assert` is not a "blind override command." In situations like:

        int i = 0;
        assert(i != 0);

In situations where static analysis can identify two or more possible states, assert works as a state selector, similar to what happens in if statements but without the scope.

        void f(int * _Opt p)
        {
            if (p != NULL) {
               //p is not null here...
            }
        }

        void f2(int * _Opt p)
        {
            assert(p != NULL);
            //we assume p is not null here...
        }