Search code examples
cstructcompiler-errorscompiler-construction

Invalid initializer error with anonymous structs


I have this code here:

Void() aba ()
{
}
#define std_Dynamic_Array(T) struct{Int32() count; Int32() capacity; T* memory; }
Void() no_body_func (Int32() b);
Int32() test_func (Int32()*** a)
{
}
Int32() test_func2 (Int32() x)
{
}
Int32() b = 33;
#define v_macro(T) struct{Int32() count; Int32() capacity; T* memory; } v (std_Dynamic_Array(T)* m) \
{ \
    Int32() l = 44; \
}
Void() _main ()
{
    Int64() a = 5;
    b = 22;
    Int32() c = test_func2(6);
    Int32() inner_func (Int32()* a)
    {
        Int32() g = 3;
    }
    Int32()* x = &b;
    inner_func(x);
    Int32() j = *x;
    Float32() f = 33.000000;
    std_Dynamic_Array(Int64()) da = {.count = 4};
    v_macro(Int64());
    std_Dynamic_Array(Int64()) k = v(&da);
}

int main(int argc, char ** argv)
{

    return 0;
}

I'm playing around with writing my own compiler that can generate C code as one of the targets. My problem is that I'm getting this weird error:

tests/simple.c:34:36: error: invalid initializer
   34 |     std_Dynamic_Array(Int64()) k = v(&da);
      |                                    ^

Here's code generated by gcc -E ...

void aba ()
{
}

void no_body_func (int b);
int test_func (int*** a)
{
}
int test_func2 (int x)
{
}
int b = 33;




void _main ()
{
    long long a = 5;
    b = 22;
    int c = test_func2(6);
    int inner_func (int* a)
    {
        int g = 3;
    }
    int* x = &b;
    inner_func(x);
    int j = *x;
    float f = 33.000000;
    struct{int count; int capacity; long long* memory; } da = {.count = 4};
    struct{int count; int capacity; long long* memory; } v (struct{int count; int capacity; long long* memory; }* m) { int l = 44; };
    struct{int count; int capacity; long long* memory; } k = v(&da);
}

int main(int argc, char ** argv)
{

    return 0;
}

Why is this error happening? Both v's return type and k's type expand to struct{int count; int capacity; long long* memory; } , so why does GCC treat them as different types? What can I possibly do to fix this? Also:

  1. I don't care about code readability, this is generated code meant for GCC, not for humans to deal with.
  2. If the solution requires the most hacky GCC trickery known to man and language extensions, so be it. The C target outputs code that will work strictly with GCC, no need to worry about clang, MSVC, ICC, etc.

I know I could probably solve this by generating some typedefs, but I want to avoid that. For now at least.

Thanks!!


Solution

  • Every definition of a structure creates a distinct type, and this is a deliberate and desirable feature of C. If we have:

    typedef struct { double a, b; } GeometricPoint;
    typedef struct { double a, b; } ComplexNumber;
    

    then we want GeometricPoint and ComplexNumber to be different types so that one cannot be accidentally assigned to the other, even if their layout is identical.

    Everywhere in your code that you have struct{int count; int capacity; long long* memory; }, you have a different type, and each of these types is incompatible with the others, and thus you get warnings and errors when trying to assign one to another, to pass one as an argument for another, or to try assignments or argument passing with pointers to them.

    To fix this, declare the structure once with a tag:

    struct MyStructure { int count; int capacity; long long *memory; };
    

    and then use only struct with the tag, struct MyStructure, throughout the rest of the code. Alternately, you can use a typedef:

    typedef struct { int count; int capacity; long long *memory; } MyStructure;
    

    and then use the typedef name, MyStructure, throughout the rest of the code.