• Struct Error

    From bart@21:1/5 to All on Wed Jan 22 16:14:08 2025
    Gcc 14.1 gives me an error compiling this code:

    struct vector;
    struct scenet;

    struct vector {
    double x;
    double y;
    double z;
    };

    struct scenet {
    struct vector center;
    double radius;
    struct scenet (*child)[];
    };

    The error is:

    error: array type has incomplete element type 'struct scenet'
    struct scenet (*child)[];
    ^~~~~

    Is there any way to fix this, or is it not possible?

    (This comes from generated code. Idiomatic C would use a T* here rather
    than T(*)[], but that is not an option. Other compilers like tcc, DMC
    and mine have no problem with it.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Harnden@21:1/5 to bart on Wed Jan 22 20:08:07 2025
    On 22/01/2025 16:14, bart wrote:
      struct vector;
      struct scenet;

      struct vector {
          double x;
          double y;
          double z;
      };

      struct scenet {
          struct vector center;
          double radius;
          struct scenet (*child)[];
      };


    The error is:

    error: array type has incomplete element type 'struct scenet'
    struct scenet (*child)[];
    ^~~~~

    Is there any way to fix this, or is it not possible?

    (This comes from generated code. Idiomatic C would use a T* here rather than T(*)[], but that is not an option. Other compilers like tcc, DMC and mine have no problem with it.)


    Clang says: definition of 'struct scenet' is not complete until the
    closing '}'

    Can you loose the parens? 'struct scenet *child[];' is fine (so long as
    it's the last element).

    Otherwise, 'struct scenet **child;' or 'struct scenet *child' -
    depending on whether you mean 'children' or 'next';

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Wed Jan 22 20:05:44 2025
    On 2025-01-22, bart <bc@freeuk.com> wrote:
    Gcc 14.1 gives me an error compiling this code:

    struct vector;
    struct scenet;

    struct vector {
    double x;
    double y;
    double z;
    };

    struct scenet {
    struct vector center;
    double radius;
    struct scenet (*child)[];
    };

    The error is:

    error: array type has incomplete element type 'struct scenet'
    struct scenet (*child)[];
    ^~~~~

    This looks like a bug to me. There is on reason why an
    incomplete array type (a pointer to which /is/ allowed!)
    should be constrained to have a complete element.

    Especially given that it's going to be complete by the time
    it is used (in fact by the time the declaration of struct scenet is
    done).

    Because the array is incomplete, and we have a pointer to it,
    we cannot do arithmetic on it, like child + 1.

    All we can do is dereference it, like (*child) or child[0]
    to get to the array.

    Then when we do child[0][i], then at that time we need the element type
    to be complete.

    Is there any way to fix this, or is it not possible?

    Yes!

    Instead of:

    gcc example.c # fails

    try:

    g++ example.c # succeeds!

    I don't have gcc 14 handy anywhere, but I tried with 7.5 and 11.3,
    Same results.

    Given that the GCC's C++ front-end accepts it, that bolsters
    the case that it should just work in the C front end.

    You've remembered to keep your generator's C output C++ compatible,
    right? You don't use bleeding edge ISO C features, so you should be
    okay.

    However, C++ has function overloading and whatnot, so there
    is name mangling for some global symbols, like names of functions.

    It may be a good idea in the code generator to spit out extern "C"
    in the right places, to keep compatibility between modules
    generated as C and those generated as C++.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ben Bacarisse@21:1/5 to Kaz Kylheku on Wed Jan 22 21:00:52 2025
    Kaz Kylheku <643-408-1753@kylheku.com> writes:

    On 2025-01-22, bart <bc@freeuk.com> wrote:
    Gcc 14.1 gives me an error compiling this code:

    struct vector;
    struct scenet;

    struct vector {
    double x;
    double y;
    double z;
    };

    struct scenet {
    struct vector center;
    double radius;
    struct scenet (*child)[];
    };

    The error is:

    error: array type has incomplete element type 'struct scenet'
    struct scenet (*child)[];
    ^~~~~

    This looks like a bug to me. There is on reason why an
    incomplete array type (a pointer to which /is/ allowed!)
    should be constrained to have a complete element.

    It may be a bug in the standard, but it's not a bug in the compiler:

    6.7.6.2 Array declarators
    Constraints

    ... The element type shall not be an incomplete or function type. ...

    There is no dispensation that avoids this constraint when a pointer to
    such an array is being declared (the constraint is on the array
    declarator) nor when is type will be soon completed.

    --
    Ben.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Lawrence D'Oliveiro@21:1/5 to bart on Wed Jan 22 22:27:27 2025
    On Wed, 22 Jan 2025 16:14:08 +0000, bart wrote:

    struct scenet (*child)[];

    It has no idea how much space to allocate for a scenet at this point.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to bart on Wed Jan 22 20:05:25 2025
    On 2025-01-22, bart <bc@freeuk.com> wrote:
    Gcc 14.1 gives me an error compiling this code:

    struct vector;
    struct scenet;

    struct vector {
    double x;
    double y;
    double z;
    };

    struct scenet {
    struct vector center;
    double radius;
    struct scenet (*child)[];
    };

    6.7.6.2p2: "The element type shall not be an incomplete or function type."

    I have many draft versions of the C standard. n2912.pdf, dated
    2022-06-08, says in 6.7.2.1.p3 about struct types that "... the type is incomplete144) until immediately after the closing brace of the list
    defining the content, and complete thereafter."

    Therefore, struct scenet is not a complete type until the closing brace
    of it's declaration.

    However, that sentence disappeared in n3047.pdf, dated 2022-08-04. Can
    anyone tell me why it was removed? With it gone, I'm not sure it is
    still considered an incomplete type.

    Ignoring for the moment the fact that it's not permitted, why do you
    want to do that? In C code, people usually use pointers to the first
    element of an array rather than pointers to arrays. However, it
    sometimes is a good idea to have a pointer to an array, because that
    makes the length of the array part of the pointer type, which can be
    used to check the validity of the code that uses that pointer to access
    the elements of the array. But in this case, the length of the array is unspecified, so there's no such benefit.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to bart on Wed Jan 22 23:11:54 2025
    bart <bc@freeuk.com> writes:

    Gcc 14.1 gives me an error compiling this code:

    struct vector;
    struct scenet;

    struct vector {
    double x;
    double y;
    double z;
    };

    struct scenet {
    struct vector center;
    double radius;
    struct scenet (*child)[];
    };

    The error is:

    error: array type has incomplete element type 'struct scenet'
    struct scenet (*child)[];
    ^~~~~

    Is there any way to fix this, or is it not possible?

    (This comes from generated code. Idiomatic C would use a T* here
    rather than T(*)[], but that is not an option. Other compilers like
    tcc, DMC and mine have no problem with it.)

    The code shown violates a constraint in the C standard, because
    the element type of the array declarator is an incomplete type
    at the point the 'child' member is declared, so a diagnostic
    is required.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to learningcpp1@gmail.com on Wed Jan 22 23:15:09 2025
    learningcpp1@gmail.com (m137) writes:

    On Thu, 23 Jan 2025 1:05:25 +0000, James Kuyper wrote:

    I have many draft versions of the C standard. n2912.pdf, dated
    2022-06-08, says in 6.7.2.1.p3 about struct types that "... the type is
    incomplete144) until immediately after the closing brace of the list
    defining the content, and complete thereafter."

    Therefore, struct scenet is not a complete type until the closing brace
    of it's declaration.

    However, that sentence disappeared in n3047.pdf, dated 2022-08-04. Can
    anyone tell me why it was removed? With it gone, I'm not sure it is
    still considered an incomplete type.

    It seems to have been moved to N3047 6.2.5(25): "[...] A structure or
    union type of unknown content (as described in 6.7.2.3) is an incomplete type. [...]" (see here: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3047.pdf#page=57).

    That sentence isn't new in 6.2.5; it's been there since before C11.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to James Kuyper on Wed Jan 22 23:31:31 2025
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:

    On 2025-01-22, bart <bc@freeuk.com> wrote:

    Gcc 14.1 gives me an error compiling this code:

    struct vector;
    struct scenet;

    struct vector {
    double x;
    double y;
    double z;
    };

    struct scenet {
    struct vector center;
    double radius;
    struct scenet (*child)[];
    };

    6.7.6.2p2: "The element type shall not be an incomplete or function type."

    I have many draft versions of the C standard. n2912.pdf, dated
    2022-06-08, says in 6.7.2.1.p3 about struct types that "... the type is incomplete144) until immediately after the closing brace of the list
    defining the content, and complete thereafter."

    Therefore, struct scenet is not a complete type until the closing brace
    of it's declaration.

    However, that sentence disappeared in n3047.pdf, dated 2022-08-04. Can anyone tell me why it was removed? [...]

    That clause appears (slightly modified IIANM) in 6.7.2.3 p5.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to All on Thu Jan 23 03:37:24 2025
    On 1/22/25 22:49, m137 wrote:
    On Thu, 23 Jan 2025 1:05:25 +0000, James Kuyper wrote:

    I have many draft versions of the C standard. n2912.pdf, dated
    2022-06-08, says in 6.7.2.1.p3 about struct types that "... the type is
    incomplete144) until immediately after the closing brace of the list
    defining the content, and complete thereafter."

    Therefore, struct scenet is not a complete type until the closing brace
    of it's declaration.

    However, that sentence disappeared in n3047.pdf, dated 2022-08-04. Can
    anyone tell me why it was removed? With it gone, I'm not sure it is
    still considered an incomplete type.

    It seems to have been moved to N3047 6.2.5(25): "[...] A structure or
    union type of unknown content (as described in 6.7.2.3) is an incomplete type. [...]" (see here: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3047.pdf#page=57).

    It would be more accurate to say that it's been moved to 6.7.2.3,
    concerning tags, which is then cross-referenced by 6.2.5:

    "... the type (except enumerated types with a fixed underlying type) is incomplete until immediately after the closing brace of the list
    defining the content for the first time and complete thereafter."

    It was a bit tricky to locate, because "unknown content" sounded like
    the kind of term that the standard defines in one spot and uses
    elsewhere, whereas in fact that term is used only once, and not defined anywhere. Instead, it appears to be referring, by negation, to ther
    terms "structure content", "union constent", and "enumeration content",
    which are defined, but not until a few paragraphs later in 6.7.2.3.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to James Kuyper on Thu Jan 23 10:54:10 2025
    On 23/01/2025 01:05, James Kuyper wrote:
    On 2025-01-22, bart <bc@freeuk.com> wrote:
    Gcc 14.1 gives me an error compiling this code:

    struct vector;
    struct scenet;

    struct vector {
    double x;
    double y;
    double z;
    };

    struct scenet {
    struct vector center;
    double radius;
    struct scenet (*child)[];
    };

    6.7.6.2p2: "The element type shall not be an incomplete or function type."

    I have many draft versions of the C standard. n2912.pdf, dated
    2022-06-08, says in 6.7.2.1.p3 about struct types that "... the type is incomplete144) until immediately after the closing brace of the list
    defining the content, and complete thereafter."

    Therefore, struct scenet is not a complete type until the closing brace
    of it's declaration.

    Wouldn't this also be the case here:

    struct scenet *child;
    };

    The struct is incomplete, but it still knows how to do pointer
    arithmetic with that member. The calculation is not that different from
    the array version (actually, the code from my compiler is identical).


    However, that sentence disappeared in n3047.pdf, dated 2022-08-04. Can
    anyone tell me why it was removed? With it gone, I'm not sure it is
    still considered an incomplete type.

    Ignoring for the moment the fact that it's not permitted, why do you
    want to do that? In C code, people usually use pointers to the first
    element of an array rather than pointers to arrays. However, it
    sometimes is a good idea to have a pointer to an array, because that
    makes the length of the array part of the pointer type, which can be
    used to check the validity of the code that uses that pointer to access
    the elements of the array. But in this case, the length of the array is unspecified, so there's no such benefit.

    I said the code is generated, which means the original language uses a pointer-to-array at that spot.

    That is safer, as you can't mistakenly index a pointer which happens to
    be a reference to a single instance.

    In any case, you should surely be able to choose a T(*)[] type over T*
    if you want, but apparently not inside a self-referential struct.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Lawrence D'Oliveiro@21:1/5 to bart on Thu Jan 23 23:50:28 2025
    On Thu, 23 Jan 2025 10:54:10 +0000, bart wrote:

    Wouldn't this also be the case here:

    struct scenet *child;
    };

    The struct is incomplete, but it still knows how to do pointer
    arithmetic with that member.

    No, because there is no pointer arithmetic involved in processing that declaration.

    Of course you will get a suitable error in a subsequent expression that
    does involve such pointer arithmetic, if the struct has not been fully
    defined by that point.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Lawrence D'Oliveiro on Fri Jan 24 00:37:27 2025
    On 23/01/2025 23:50, Lawrence D'Oliveiro wrote:
    On Thu, 23 Jan 2025 10:54:10 +0000, bart wrote:

    Wouldn't this also be the case here:

    struct scenet *child;
    };

    The struct is incomplete, but it still knows how to do pointer
    arithmetic with that member.

    No, because there is no pointer arithmetic involved in processing that declaration.


    Neither of these member declarations involve any expression:

    ....
    struct scenet *childp;
    struct scenet (*childa)[];
    };

    Yet childp is fine, but childa is a gcc compiler error. Why is that?

    When expressions are used later on, both need to know the size of
    struct, which has been determined by then.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to BGB on Fri Jan 24 00:51:04 2025
    On 23/01/2025 20:58, BGB wrote:
    On 1/23/2025 4:54 AM, bart wrote:
    On 23/01/2025 01:05, James Kuyper wrote:
    On 2025-01-22, bart <bc@freeuk.com> wrote:
    Gcc 14.1 gives me an error compiling this code:

        struct vector;
        struct scenet;

        struct vector {
            double x;
            double y;
            double z;
        };

        struct scenet {
            struct vector center;
            double radius;
            struct scenet (*child)[];
        };

    6.7.6.2p2: "The element type shall not be an incomplete or function
    type."

    I have many draft versions of the C standard. n2912.pdf, dated
    2022-06-08, says in 6.7.2.1.p3 about struct types that "... the type is
    incomplete144) until immediately after the closing brace of the list
    defining the content, and complete thereafter."

    Therefore, struct scenet is not a complete type until the closing brace
    of it's declaration.

    Wouldn't this also be the case here:

        struct scenet *child;
       };

    The struct is incomplete, but it still knows how to do pointer
    arithmetic with that member. The calculation is not that different
    from the array version (actually, the code from my compiler is
    identical).


    Difference is, in this case, "sizeof(struct scenet)" is not relevant to "sizeof(struct scenet *)".


    No, both of these need to know the size of the struct when accessing the
    i'th element:

    ....
    struct scenet *childp;
    struct scenet (*childa)[];
    };

    The only thing you can't do with x->childa is perform pointer arithmetic
    on the whole pointer-to-array, since the array size is zero. But doing (x->childa)[i] should be fine.

    As is clear since other compilers (excluding those that lavishly copy
    gcc's behaviour) have no problem with it.


    Formally, with the parenthesis and array, the size of the struct is considered relevant (even if not strictly so), but is also unknown at
    that point.


    This seems like obscure edge case territory.

    It's a 'pointer to array'; it might be uncommon in C (because of its
    fugly syntax), but it hs hardly obscure!


    Alas, if I could have my way, I might define a simplified subset which
    drops some of these sorts of edge cases (the form with parenthesis would simply become disallowed), but, likely, this wouldn't amount to much.

    T(*)[] is a perfectly valid type; there is no reason to exclude it from
    struct members.

    It is unambiguous in my original language, and can also be in C.


    Say, for a language that is:
    Mostly backwards compatible with existing C code;
    Allows for a smaller and simpler compilers;
    Uses some C# like rules to eliminate the need for checking for typedefs
    to parse stuff.

    Though, one can't go entirely over to C# like behavior if one still
    wants to support traditional separate compilation (so one would still
    have a need for things like function prototypes, header files, and a traditional preprocessor).

    But, then one would basically just end up with C but with people being confused about why things like "unsigned x;" no longer work (making it
    kinda moot).


    And, most people continue to swear by GCC and Clang, unconcerned with
    their multi MLOC codebases, and the overly long time it takes to
    recompile the compiler from source...

    Yeah. I can choose to run my compiler from source each time it is
    invoked; you barely notice the difference! (It adds 70-80ms.)

    This cuts no ice here however.

    Granted, my existing compiler is a bit bigger; sadly, its code footprint
    is more on par with Quake3, and its memory footprint generally a bit
    steep (well, if one wants to run it on an FPGA board with 128MB of total
    RAM; ideally one wants to keep the memory footprint needed to compile a moderate size program in under around 50MB or so; which is an epic fail
    for my compiler as it is...).

    And, as-is, compiling stuff takes a painfully long time on a 50MHz CPU
    (even a moderately small program might take several minutes or more).

    You can't cross-compile on a PC?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Lawrence D'Oliveiro@21:1/5 to bart on Fri Jan 24 00:57:06 2025
    On Fri, 24 Jan 2025 00:37:27 +0000, bart wrote:

    Yet childp is fine, but childa is a gcc compiler error. Why is that?

    Because it needs to know the size of the type to work out the function
    type’s calling convention.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Lawrence D'Oliveiro on Fri Jan 24 01:27:07 2025
    On 24/01/2025 00:57, Lawrence D'Oliveiro wrote:
    On Fri, 24 Jan 2025 00:37:27 +0000, bart wrote:

    Yet childp is fine, but childa is a gcc compiler error. Why is that?

    Because it needs to know the size of the type to work out the function type’s calling convention.

    OK. So you've no idea what you're talking about. That's fine.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Fri Jan 24 09:45:19 2025
    On 24/01/2025 01:51, bart wrote:

    No, both of these need to know the size of the struct when accessing the
    i'th element:

      ....
       struct scenet *childp;
       struct scenet (*childa)[];
     };

    The only thing you can't do with x->childa is perform pointer arithmetic
    on the whole pointer-to-array, since the array size is zero. But doing (x->childa)[i] should be fine.

    As is clear since other compilers (excluding those that lavishly copy
    gcc's behaviour) have no problem with it.


    This is one of these cases where the C language /could/ have been
    defined to allow incomplete types to be used. But the language
    definition (the standards) does not allow it.

    Some C compilers do a poor job of checking C code. Some are lax and
    allow things that the language does not, accepting code that breaks
    syntax and grammar rules or constraints, and happily generating code
    instead of issuing the standards-required diagnostics. (gcc in default
    modes is such a compiler - you need to add appropriate flags to make it
    do a decent job of enforcing standard checking.)

    This raises a few questions :

    1. Should future C standards be modified to be more lenient in the code
    the accept? Was there a good reason for these limitations, and is that
    reason still valid?

    2. Should compilers behave this way, and accept code that can have an
    "obvious" interpretation despite going against the C standards?

    3. Should people write (or generate) C code that relies on the
    non-standard behaviour of some C compilers?


    Certainly some restrictions in the way C was defined were heavily
    influenced by the compiler technology of the day. But others - and I
    suspect this case is one of them - exist because they simplify the
    rules. Writing rules that are detailed enough to allow everything that
    could, theoretically, be supported while also excluding everything else
    can get very complicated. A language standard cannot say "if the
    compiler is smart enough to figure this out, that's okay". A given
    compiler implementation can do that if it wants, but the standards cannot.


    At first glance it sounds like a good idea for compilers to be flexible
    in what they accept. But the risk for that is fragmentation of the
    language. The whole point of standardising a language is to avoid that
    - so that, to a reasonable level at least, it is possible to write code
    that can be compiled with a large range of C compilers. Before C was standardised, the language had already fragmented into lots of variants.
    It is /not/ a good thing that compilers accept code that requires a diagnostic, or have lots of extensions enabled by default. You should
    have to explicitly enable such things with flags - instead of explicitly requesting that the compiler conforms to the standards.

    For some kinds of code, it is entirely appropriate to rely on extensions
    or non-standard features of particular compilers. But this should be
    done as an exception, when there is good reason for it.


    In this particular case, there is not the slightest reason for
    generating something non-standard. The correct response here is to get
    mildly irritated that C does not support the syntax you hoped to
    generate, feel smug that your own language /does/ support such a syntax,
    then change the code generator to produce correct standard C code.


    And gcc is entirely correct here. Other compilers that reject the
    incorrect code are not "slavishly copying gcc's behaviour" - they are
    correctly implementing the C standards. It is compilers that accept
    this code, without requiring flags or other explicit "enable extension" features, that are doing a poor job of being C compilers.

    (gcc often does the wrong thing by default accepting bad code without
    question, but in this case it is correct.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to bart on Fri Jan 24 08:24:18 2025
    On 1/23/2025 4:54 AM, bart wrote:
    On 23/01/2025 01:05, James Kuyper wrote:
    On 2025-01-22, bart <bc@freeuk.com> wrote:
    Gcc 14.1 gives me an error compiling this code:

        struct vector;
        struct scenet;

        struct vector {
            double x;
            double y;
            double z;
        };

        struct scenet {
            struct vector center;
            double radius;
            struct scenet (*child)[];
        };

    6.7.6.2p2: "The element type shall not be an incomplete or function
    type."

    I have many draft versions of the C standard. n2912.pdf, dated
    2022-06-08, says in 6.7.2.1.p3 about struct types that "... the type is
    incomplete144) until immediately after the closing brace of the list
    defining the content, and complete thereafter."

    Therefore, struct scenet is not a complete type until the closing brace
    of it's declaration.

    Wouldn't this also be the case here:

       struct scenet *child;
      };

    The struct is incomplete, but it still knows how to do pointer
    arithmetic with that member. The calculation is not that different from
    the array version (actually, the code from my compiler is identical).

    The difference is that there's an explicit requirement that the element
    type of an array type be complete. As far as I know, there's no such requirement that applies when you have a pointer to incomplete type,
    rather than an array of an incomplete type. If you think otherwise,
    please identify the requirement. I started reviewing all the places
    where the standard says something about complete and incomplete types,
    but there's way too many of them.

    The reason, I think, is the following:
    "A pointer to void shall have the same representation and alignment requirements as a pointer to a character type.53) Similarly, pointers to qualified or unqualified versions of compatible types shall have the
    same representation and alignment requirements. All pointers to
    structure types shall have the same representation and alignment
    requirements as each other. All pointers to union types shall have the
    same representation and alignment requirements as each other. Pointers
    to other types need not have the same representation or alignment requirements." (6.2.5p33)

    This means that, in principle, the representation and alignment of a
    pointer to an array of an incomplete struct type might depend upon the
    unknown content of that struct type, if only through the size of the
    type. So a pointer to an array of an incomplete type presents a possible challenge that isn't a problem for a pointer to an object of that
    incomplete type.
    I'm sure that you're used to platforms where all pointers to object
    types have the same representation and alignment requirements - most
    developers are. However, there are very real platforms where that isn't
    the case, and the C standard goes out of its way to permit conforming implementations of C on such platforms.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to bart on Fri Jan 24 08:43:51 2025
    On 1/23/2025 6:51 PM, bart wrote:
    On 23/01/2025 20:58, BGB wrote:
    On 1/23/2025 4:54 AM, bart wrote:
    On 23/01/2025 01:05, James Kuyper wrote:
    On 2025-01-22, bart <bc@freeuk.com> wrote:
    Gcc 14.1 gives me an error compiling this code:

        struct vector;
        struct scenet;

        struct vector {
            double x;
            double y;
            double z;
        };

        struct scenet {
            struct vector center;
            double radius;
            struct scenet (*child)[];
        };

    6.7.6.2p2: "The element type shall not be an incomplete or function
    type."

    I have many draft versions of the C standard. n2912.pdf, dated
    2022-06-08, says in 6.7.2.1.p3 about struct types that "... the type is >>>> incomplete144) until immediately after the closing brace of the list
    defining the content, and complete thereafter."

    Therefore, struct scenet is not a complete type until the closing brace >>>> of it's declaration.

    Wouldn't this also be the case here:

        struct scenet *child;
       };

    The struct is incomplete, but it still knows how to do pointer
    arithmetic with that member. The calculation is not that different
    from the array version (actually, the code from my compiler is
    identical).


    Difference is, in this case, "sizeof(struct scenet)" is not relevant
    to "sizeof(struct scenet *)".


    No, both of these need to know the size of the struct when accessing the
    i'th element:

      ....
       struct scenet *childp;
       struct scenet (*childa)[];
     };

    The only thing you can't do with x->childa is perform pointer arithmetic
    on the whole pointer-to-array, since the array size is zero. But doing (x->childa)[i] should be fine.

    As is clear since other compilers (excluding those that lavishly copy
    gcc's behaviour) have no problem with it.

    The problem is not what you can do with the pointer, but the alignment
    and representation of the pointer itself. Those are uniquely determined
    for childp by the fact that it's a pointer to a struct type, regardless
    of the content of that type (6.2.5p33). The alignment and representation
    of childa, on the other hand, could depend upon the content of struct
    scenet (in particular, the size of that struct type). It needs to know
    those requirements, in order to complete the definition of struct
    scenet. That's not an insoluble problem: just choose an alignment and representation for childa that allows a pointer to the entire struct to
    have that same alignment and representation - but the standard chose not
    to mandate that it be solved.
    If you've never tried to create a compiler for a platform where it makes
    sense to have pointers to object types with different alignment and representations, depending upon the type that they point at, you
    probably have no idea what would be involved in solving that problem (I certainly don't).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to bart on Fri Jan 24 16:37:40 2025
    On Thu, 23 Jan 2025 10:54:10 +0000
    bart <bc@freeuk.com> wrote:

    On 23/01/2025 01:05, James Kuyper wrote:
    On 2025-01-22, bart <bc@freeuk.com> wrote:
    Gcc 14.1 gives me an error compiling this code:

    struct vector;
    struct scenet;

    struct vector {
    double x;
    double y;
    double z;
    };

    struct scenet {
    struct vector center;
    double radius;
    struct scenet (*child)[];
    };

    6.7.6.2p2: "The element type shall not be an incomplete or function
    type."

    I have many draft versions of the C standard. n2912.pdf, dated
    2022-06-08, says in 6.7.2.1.p3 about struct types that "... the
    type is incomplete144) until immediately after the closing brace of
    the list defining the content, and complete thereafter."

    Therefore, struct scenet is not a complete type until the closing
    brace of it's declaration.

    Wouldn't this also be the case here:

    struct scenet *child;
    };


    Just to point out if it was not said already: the problem is not related specifically to recursive structures. It applies to arrays of
    incomplete types in all circumstances.

    struct bar;
    struct bar (*bag)[]; // error
    typedef struct bar (*bat)[]; // error

    The case of the recursive structure is special only in a sense that it's
    o.k. in C++, because [unlike C] in C++ struct considered complete within
    its own body.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to David Brown on Fri Jan 24 20:31:42 2025
    On 2025-01-24, David Brown <david.brown@hesbynett.no> wrote:
    On 24/01/2025 01:51, bart wrote:

    No, both of these need to know the size of the struct when accessing the
    i'th element:

      ....
       struct scenet *childp;
       struct scenet (*childa)[];
     };

    The only thing you can't do with x->childa is perform pointer arithmetic
    on the whole pointer-to-array, since the array size is zero. But doing
    childa)[i] should be fine.

    As is clear since other compilers (excluding those that lavishly copy
    gcc's behaviour) have no problem with it.


    This is one of these cases where the C language /could/ have been
    defined to allow incomplete types to be used. But the language
    definition (the standards) does not allow it.

    It does; the implementation can issue a required diagnostic,
    and keep chugging along. The behavior becomes undefined, but
    the same implementation can provide its own definition:
    like such that when the type is completed by the time it
    matters, it's all good.

    The language definition only does not allow the implementation to be
    called conforming if it doesn't diagnose the usage, and doesn't allow
    the program's behavior to be well-defined ISO C.

    1. Should future C standards be modified to be more lenient in the code
    the accept? Was there a good reason for these limitations, and is that reason still valid?

    In this particular matter, GNU C++ accepts the code. If that happens to
    be because of how ISO C++ is defined, then that carries substantial
    weight. Why should C require a diagnostic in something that C++
    allows to pass. (C++, whose C-like subset is touted as a "safer C"!)

    Speaking of which, Bart never responded to the workaround I found,
    namely that g++ accepts his code.

    I'm guessing it's too abhorrent to even think about, like inviting the occasional blasphemer into a satanic cult.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Fri Jan 24 22:53:45 2025
    On 24/01/2025 20:31, Kaz Kylheku wrote:
    On 2025-01-24, David Brown <david.brown@hesbynett.no> wrote:
    On 24/01/2025 01:51, bart wrote:

    No, both of these need to know the size of the struct when accessing the >>> i'th element:

      ....
       struct scenet *childp;
       struct scenet (*childa)[];
     };

    The only thing you can't do with x->childa is perform pointer arithmetic >>> on the whole pointer-to-array, since the array size is zero. But doing
    childa)[i] should be fine.

    As is clear since other compilers (excluding those that lavishly copy
    gcc's behaviour) have no problem with it.


    This is one of these cases where the C language /could/ have been
    defined to allow incomplete types to be used. But the language
    definition (the standards) does not allow it.

    It does; the implementation can issue a required diagnostic,
    and keep chugging along. The behavior becomes undefined, but
    the same implementation can provide its own definition:
    like such that when the type is completed by the time it
    matters, it's all good.

    The language definition only does not allow the implementation to be
    called conforming if it doesn't diagnose the usage, and doesn't allow
    the program's behavior to be well-defined ISO C.

    1. Should future C standards be modified to be more lenient in the code
    the accept? Was there a good reason for these limitations, and is that
    reason still valid?

    In this particular matter, GNU C++ accepts the code. If that happens to
    be because of how ISO C++ is defined, then that carries substantial
    weight. Why should C require a diagnostic in something that C++
    allows to pass. (C++, whose C-like subset is touted as a "safer C"!)

    Speaking of which, Bart never responded to the workaround I found,
    namely that g++ accepts his code.

    While gcc gives that one error in the complete program, g++ gives about
    250 errors.

    I just excluded that program from the set of benchmarks I was testing.

    The C transpiler used is a deprecated product and I'm not about to start messing with it now. I thought there might have been a simple tweak I
    could have made manually.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to James Kuyper on Fri Jan 24 23:32:53 2025
    On 24/01/2025 13:43, James Kuyper wrote:
    On 1/23/2025 6:51 PM, bart wrote:
    On 23/01/2025 20:58, BGB wrote:
    On 1/23/2025 4:54 AM, bart wrote:
    On 23/01/2025 01:05, James Kuyper wrote:
    On 2025-01-22, bart <bc@freeuk.com> wrote:
    Gcc 14.1 gives me an error compiling this code:

        struct vector;
        struct scenet;

        struct vector {
            double x;
            double y;
            double z;
        };

        struct scenet {
            struct vector center;
            double radius;
            struct scenet (*child)[];
        };

    6.7.6.2p2: "The element type shall not be an incomplete or function
    type."

    I have many draft versions of the C standard. n2912.pdf, dated
    2022-06-08, says in 6.7.2.1.p3 about struct types that "... the type is >>>>> incomplete144) until immediately after the closing brace of the list >>>>> defining the content, and complete thereafter."

    Therefore, struct scenet is not a complete type until the closing brace >>>>> of it's declaration.

    Wouldn't this also be the case here:

        struct scenet *child;
       };

    The struct is incomplete, but it still knows how to do pointer
    arithmetic with that member. The calculation is not that different
    from the array version (actually, the code from my compiler is
    identical).


    Difference is, in this case, "sizeof(struct scenet)" is not relevant
    to "sizeof(struct scenet *)".


    No, both of these need to know the size of the struct when accessing the
    i'th element:

      ....
       struct scenet *childp;
       struct scenet (*childa)[];
     };

    The only thing you can't do with x->childa is perform pointer arithmetic
    on the whole pointer-to-array, since the array size is zero. But doing
    childa)[i] should be fine.

    As is clear since other compilers (excluding those that lavishly copy
    gcc's behaviour) have no problem with it.

    The problem is not what you can do with the pointer, but the alignment
    and representation of the pointer itself. Those are uniquely determined
    for childp by the fact that it's a pointer to a struct type, regardless
    of the content of that type (6.2.5p33). The alignment and representation
    of childa, on the other hand, could depend upon the content of struct
    scenet (in particular, the size of that struct type). It needs to know
    those requirements, in order to complete the definition of struct
    scenet. That's not an insoluble problem: just choose an alignment and representation for childa that allows a pointer to the entire struct to
    have that same alignment and representation - but the standard chose not
    to mandate that it be solved.
    If you've never tried to create a compiler for a platform where it makes sense to have pointers to object types with different alignment and representations, depending upon the type that they point at, you
    probably have no idea what would be involved in solving that problem (I certainly don't).

    Since the vast majority of machines have no such problems, why should
    this affect the users of those machines?

    It seems perfectly reasonable to me to have a pointer to an unbounded
    array (it's little different to void*), and to be able to use such a
    pointer within a struct.

    C already allows self-referential structs, so that shouldn't be a
    problem either. The calculation required for indexing such an array
    depends on the size of the struct, and this will be known by that point.

    The context here is that of a language where that feature is
    well-defined, using C as an intermediate represention, and compiling for
    a machine where the required pointers are all well-defined (every
    pointer for code or data) is a 64-bit value.

    So gcc's behaviour here is not helpful and not useful; what problem is
    it trying to avoid that would cause chaos on my x64 platform?

    The alighnment of the struct should also not affect the code generated
    for the array access, and itself should not be affected by that choice
    of type.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Kaz Kylheku on Fri Jan 24 20:53:41 2025
    On 1/24/25 15:31, Kaz Kylheku wrote:
    On 2025-01-24, David Brown <david.brown@hesbynett.no> wrote:
    ...
    This is one of these cases where the C language /could/ have been
    defined to allow incomplete types to be used. But the language
    definition (the standards) does not allow it.

    It does; the implementation can issue a required diagnostic,
    and keep chugging along. The behavior becomes undefined, but
    the same implementation can provide its own definition:
    like such that when the type is completed by the time it
    matters, it's all good.

    In that sense, the only thing that the C standard does disallow is
    translation of a correctly formatted #error directive that survives
    conditional compilation (an incorrectly formatted directive would give
    the implementation permission to translate it).

    In more conventional usage, the C standard is said to allow something
    only when its behavior is no worse than "unspecified". If the behavior
    is undefined, the standard imposes no requirements, in which case the implementation is permitted to give your translated code any arbitrary
    behavior it is able to give it.

    That only makes sense if you don't care what your program does - and if
    that is the case, there's no reason to bother writing a new program -
    just execute an arbitrary existing program. Whatever the behavior of
    that arbitrary existing program is, it is behavior that would be
    permitted for the translation of your program.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Michael S on Sun Jan 26 19:14:00 2025
    On 24/01/2025 14:37, Michael S wrote:
    On Thu, 23 Jan 2025 10:54:10 +0000
    bart <bc@freeuk.com> wrote:

    On 23/01/2025 01:05, James Kuyper wrote:
    On 2025-01-22, bart <bc@freeuk.com> wrote:
    Gcc 14.1 gives me an error compiling this code:

    struct vector;
    struct scenet;

    struct vector {
    double x;
    double y;
    double z;
    };

    struct scenet {
    struct vector center;
    double radius;
    struct scenet (*child)[];
    };

    6.7.6.2p2: "The element type shall not be an incomplete or function
    type."

    I have many draft versions of the C standard. n2912.pdf, dated
    2022-06-08, says in 6.7.2.1.p3 about struct types that "... the
    type is incomplete144) until immediately after the closing brace of
    the list defining the content, and complete thereafter."

    Therefore, struct scenet is not a complete type until the closing
    brace of it's declaration.

    Wouldn't this also be the case here:

    struct scenet *child;
    };


    Just to point out if it was not said already: the problem is not related specifically to recursive structures. It applies to arrays of
    incomplete types in all circumstances.

    struct bar;
    struct bar (*bag)[]; // error
    typedef struct bar (*bat)[]; // error

    I don't think anyone has yet explained why that is an error (other than
    C says it is), but not this:

    struct bar *ptr;

    This is a pointer to an incomplete type. Attempts to do ++ptr for
    example will fail later on if that struct has not yet been defined.

    So why not the same for the pointer-to-array versions?

    It just doesn't make sense.

    Is it just because such pointers HAVE to work, otherwise
    self-referential structs become impossible? That would make it a hack,
    in which case why not apply it to arrays too?


    The case of the recursive structure is special only in a sense that it's
    o.k. in C++, because [unlike C] in C++ struct considered complete within
    its own body.

    For non-recursive, you can choose to declare the pointer-to-array after
    the struct has been fully defined.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to bart on Sun Jan 26 23:14:35 2025
    On Sun, 26 Jan 2025 19:14:00 +0000
    bart <bc@freeuk.com> wrote:


    Is it just because such pointers HAVE to work, otherwise
    self-referential structs become impossible?

    More important use case of poiner to incomplete struct is for abstract
    types with implementation completely hidden from the user.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Mon Jan 27 04:05:10 2025
    On 2025-01-26, bart <bc@freeuk.com> wrote:
    On 24/01/2025 14:37, Michael S wrote:
    This is a pointer to an incomplete type. Attempts to do ++ptr for
    example will fail later on if that struct has not yet been defined.

    So why not the same for the pointer-to-array versions?

    It just doesn't make sense.

    You already know that GNU C++ silently accepts it, so this is
    beating a dead horse.

    Sure, something in a type not being specified is not a problem until the information is actually needed for something. We can think about
    a lazy type evaluation system. Functional programming languages
    tend to have them.

    But note that the rule /is/ actually consistent among aggregates.
    Both an array and struct are aggregates. The elements are to
    an array roughly the same thing that members are to a struct.
    A struct may not have members of incomplete type,
    An array may not have elements of incomplete type.

    Your situation is this:

    struct incomplete {
    struct incomplete (*parray)[];
    };

    If we make a pointer to a struct rather than array,
    it's the same kind of problem:

    struct incomplete {
    struct nested_incomplete {
    struct incomplete memb;
    } *pstruct;
    };

    In both cases, we have a pointer to something which
    has an element, or member, of the incomplete type of
    the outer struct which is to contain the pointer.

    If the array version should work, so should the
    struct version.

    The case of the recursive structure is special only in a sense that it's
    o.k. in C++, because [unlike C] in C++ struct considered complete within
    its own body.

    For non-recursive, you can choose to declare the pointer-to-array after
    the struct has been fully defined.

    If a C++ struct is complete within its own body, that means this should
    be possible:

    struct foo {
    struct foo x;
    int y;
    };

    That cannot be the reason why the pointer to array works in GNU C++.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Mon Jan 27 20:19:13 2025
    On 27/01/2025 04:05, Kaz Kylheku wrote:
    On 2025-01-26, bart <bc@freeuk.com> wrote:
    On 24/01/2025 14:37, Michael S wrote:
    This is a pointer to an incomplete type. Attempts to do ++ptr for
    example will fail later on if that struct has not yet been defined.

    So why not the same for the pointer-to-array versions?

    It just doesn't make sense.

    You already know that GNU C++ silently accepts it, so this is
    beating a dead horse.

    C++ is no good to me. My old transpiler (now a deprecated product
    anyway) generated C. Fixing it either means updating the transpiler (and finding some hacky workaround like using casts everywhere) or doing that manually to the generated C. Neither appeal.

    Your situation is this:

    struct incomplete {
    struct incomplete (*parray)[];
    };

    If we make a pointer to a struct rather than array,
    it's the same kind of problem:

    struct incomplete {
    struct nested_incomplete {
    struct incomplete memb;
    } *pstruct;
    };

    In both cases, we have a pointer to something which
    has an element, or member, of the incomplete type of
    the outer struct which is to contain the pointer.

    It's trickier problem: I'm not sure myself what the size should be,
    whereas that was easy to see with my array example. Here even TCC
    reports it as incomplete. How my C compiler tells me the size is 8
    bytes, which sounds reasonable given that the only concrete member in
    there is one 64-bit pointer.

    If the array version should work, so should the
    struct version.

    The case of the recursive structure is special only in a sense that it's >>> o.k. in C++, because [unlike C] in C++ struct considered complete within >>> its own body.

    For non-recursive, you can choose to declare the pointer-to-array after
    the struct has been fully defined.

    If a C++ struct is complete within its own body, that means this should
    be possible:

    struct foo {
    struct foo x;
    int y;
    };

    This one seems impossible, and even C++ fails it. Because you're
    directly including an actual struct within itself.

    Still, my compiler is not bothered by it! It gives an overall size of 16
    bytes and an offset for both x and y of 0. That embedded (incomplete)
    version of struct foo uses the wrong size.

    A similar example in my language gives a recursion failure.

    However, examples like the ones in OP are well-defined: the member
    involved is a single pointer of a fixed size.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to bart on Wed Jan 29 02:59:50 2025
    bart <bc@freeuk.com> writes:

    On 24/01/2025 14:37, Michael S wrote:

    On Thu, 23 Jan 2025 10:54:10 +0000
    bart <bc@freeuk.com> wrote:

    On 23/01/2025 01:05, James Kuyper wrote:

    On 2025-01-22, bart <bc@freeuk.com> wrote:

    Gcc 14.1 gives me an error compiling this code:

    struct vector;
    struct scenet;

    struct vector {
    double x;
    double y;
    double z;
    };

    struct scenet {
    struct vector center;
    double radius;
    struct scenet (*child)[];
    };

    6.7.6.2p2: "The element type shall not be an incomplete or
    function type."

    I have many draft versions of the C standard. n2912.pdf, dated
    2022-06-08, says in 6.7.2.1.p3 about struct types that "... the
    type is incomplete144) until immediately after the closing brace
    of the list defining the content, and complete thereafter."

    Therefore, struct scenet is not a complete type until the closing
    brace of it's declaration.

    Wouldn't this also be the case here:

    struct scenet *child;
    };

    Just to point out if it was not said already: the problem is not
    related specifically to recursive structures. It applies to arrays
    of incomplete types in all circumstances.

    struct bar;
    struct bar (*bag)[]; // error
    typedef struct bar (*bat)[]; // error

    I don't think anyone has yet explained why that is an error (other
    than C says it is), but not this:

    struct bar *ptr;

    This is a pointer to an incomplete type. Attempts to do ++ptr
    for example will fail later on if that struct has not yet been
    defined.

    So why not the same for the pointer-to-array versions?

    The question you should be asking is why did the original C
    standards body make the rule they did?

    The answer might be because this exception to a simple and
    general rule is almost never useful, and never necessary.

    Considering that it has been 35 years since that original rule
    was made, and 2025 is the first time the question has come up,
    the indications are that the original decision was a good one.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Tim Rentsch on Wed Jan 29 11:36:21 2025
    On 29/01/2025 10:59, Tim Rentsch wrote:
    bart <bc@freeuk.com> writes:

    On 24/01/2025 14:37, Michael S wrote:

    On Thu, 23 Jan 2025 10:54:10 +0000
    bart <bc@freeuk.com> wrote:

    On 23/01/2025 01:05, James Kuyper wrote:

    On 2025-01-22, bart <bc@freeuk.com> wrote:

    Gcc 14.1 gives me an error compiling this code:

    struct vector;
    struct scenet;

    struct vector {
    double x;
    double y;
    double z;
    };

    struct scenet {
    struct vector center;
    double radius;
    struct scenet (*child)[];
    };

    6.7.6.2p2: "The element type shall not be an incomplete or
    function type."

    I have many draft versions of the C standard. n2912.pdf, dated
    2022-06-08, says in 6.7.2.1.p3 about struct types that "... the
    type is incomplete144) until immediately after the closing brace
    of the list defining the content, and complete thereafter."

    Therefore, struct scenet is not a complete type until the closing
    brace of it's declaration.

    Wouldn't this also be the case here:

    struct scenet *child;
    };

    Just to point out if it was not said already: the problem is not
    related specifically to recursive structures. It applies to arrays
    of incomplete types in all circumstances.

    struct bar;
    struct bar (*bag)[]; // error
    typedef struct bar (*bat)[]; // error

    I don't think anyone has yet explained why that is an error (other
    than C says it is), but not this:

    struct bar *ptr;

    This is a pointer to an incomplete type. Attempts to do ++ptr
    for example will fail later on if that struct has not yet been
    defined.

    So why not the same for the pointer-to-array versions?

    The question you should be asking is why did the original C
    standards body make the rule they did?

    The answer might be because this exception to a simple and
    general rule is almost never useful, and never necessary.

    Well, you never see such a thing in use, certainly. I wonder why that is!

    When a language outlaws some particular construction, forcing people to
    stick to a particular idiom (the common use of a T* type to work with
    pointers and arrays instead of the more sensible and safer T(*)[]), then clearly you're not going to see such uses in the field.

    Although there are really two parts to it: use of T(*)[] generally
    (outside of self-referential structs) is allowed, but that is still
    rare, presumably because the syntax is too unwieldy. Or people simply
    don't know about it, since everyone uses T*.

    My use-case was within generated code, so that aspect was not relevant.

    Considering that it has been 35 years since that original rule
    was made, and 2025 is the first time the question has come up,
    the indications are that the original decision was a good one.

    We don't know that. Perhaps it comes up all the time, people realise
    they can't use such a construct, and use a different approach.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Damon@21:1/5 to Tim Rentsch on Wed Jan 29 07:32:26 2025
    On 1/29/25 5:59 AM, Tim Rentsch wrote:
    bart <bc@freeuk.com> writes:

    On 24/01/2025 14:37, Michael S wrote:

    On Thu, 23 Jan 2025 10:54:10 +0000
    bart <bc@freeuk.com> wrote:

    On 23/01/2025 01:05, James Kuyper wrote:

    On 2025-01-22, bart <bc@freeuk.com> wrote:

    Gcc 14.1 gives me an error compiling this code:

    struct vector;
    struct scenet;

    struct vector {
    double x;
    double y;
    double z;
    };

    struct scenet {
    struct vector center;
    double radius;
    struct scenet (*child)[];
    };

    6.7.6.2p2: "The element type shall not be an incomplete or
    function type."

    I have many draft versions of the C standard. n2912.pdf, dated
    2022-06-08, says in 6.7.2.1.p3 about struct types that "... the
    type is incomplete144) until immediately after the closing brace
    of the list defining the content, and complete thereafter."

    Therefore, struct scenet is not a complete type until the closing
    brace of it's declaration.

    Wouldn't this also be the case here:

    struct scenet *child;
    };

    Just to point out if it was not said already: the problem is not
    related specifically to recursive structures. It applies to arrays
    of incomplete types in all circumstances.

    struct bar;
    struct bar (*bag)[]; // error
    typedef struct bar (*bat)[]; // error

    I don't think anyone has yet explained why that is an error (other
    than C says it is), but not this:

    struct bar *ptr;

    This is a pointer to an incomplete type. Attempts to do ++ptr
    for example will fail later on if that struct has not yet been
    defined.

    So why not the same for the pointer-to-array versions?

    The question you should be asking is why did the original C
    standards body make the rule they did?

    My guess is that it makes the simplest implementation of a C compiler
    much more complicated. While I don't think it has been explicited
    stated, one goal the original language, and apparently kept by the
    Standards Comittee, has been to make the language fairly simple to
    proceess to get working code. To optimize to make fast, might take more
    work, but to make your first complier for a system should be straight
    forward. I believe a C compiler can still be done with a single pass
    through the source code, with limited look ahead, and only the final
    "link" step needs to be able to handle large chunks of the program.

    Allowing the pointer to array time to be based on an incomplete type
    might make this goal harder.


    The answer might be because this exception to a simple and
    general rule is almost never useful, and never necessary.

    Considering that it has been 35 years since that original rule
    was made, and 2025 is the first time the question has come up,
    the indications are that the original decision was a good one.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Richard Damon on Wed Jan 29 07:52:33 2025
    Richard Damon <richard@damon-family.org> writes:

    On 1/29/25 5:59 AM, Tim Rentsch wrote:

    bart <bc@freeuk.com> writes:

    On 24/01/2025 14:37, Michael S wrote:

    On Thu, 23 Jan 2025 10:54:10 +0000
    bart <bc@freeuk.com> wrote:

    On 23/01/2025 01:05, James Kuyper wrote:

    On 2025-01-22, bart <bc@freeuk.com> wrote:

    Gcc 14.1 gives me an error compiling this code:

    struct vector;
    struct scenet;

    struct vector {
    double x;
    double y;
    double z;
    };

    struct scenet {
    struct vector center;
    double radius;
    struct scenet (*child)[];
    };

    6.7.6.2p2: "The element type shall not be an incomplete or
    function type."

    I have many draft versions of the C standard. n2912.pdf, dated
    2022-06-08, says in 6.7.2.1.p3 about struct types that "... the
    type is incomplete144) until immediately after the closing brace
    of the list defining the content, and complete thereafter."

    Therefore, struct scenet is not a complete type until the closing
    brace of it's declaration.

    Wouldn't this also be the case here:

    struct scenet *child;
    };

    Just to point out if it was not said already: the problem is not
    related specifically to recursive structures. It applies to arrays
    of incomplete types in all circumstances.

    struct bar;
    struct bar (*bag)[]; // error
    typedef struct bar (*bat)[]; // error

    I don't think anyone has yet explained why that is an error (other
    than C says it is), but not this:

    struct bar *ptr;

    This is a pointer to an incomplete type. Attempts to do ++ptr
    for example will fail later on if that struct has not yet been
    defined.

    So why not the same for the pointer-to-array versions?

    The question you should be asking is why did the original C
    standards body make the rule they did?

    My guess is that it makes the simplest implementation of a C compiler
    much more complicated. While I don't think it has been explicited
    stated, one goal the original language, and apparently kept by the
    Standards Comittee, has been to make the language fairly simple to
    proceess to get working code. To optimize to make fast, might take
    more work, but to make your first complier for a system should be
    straight forward. I believe a C compiler can still be done with a
    single pass through the source code, with limited look ahead, and only
    the final "link" step needs to be able to handle large chunks of the
    program.

    Allowing the pointer to array time to be based on an incomplete type
    might make this goal harder.

    Possibly. I suspect the question was never considered, simply
    because it never came up. It's unusual even to have a pointer to
    an array with unknown extent, and an array with an incomplete
    element type is an even weirder beast. It's easy to believe that
    the peculiar circumstances of the situation being asked about
    just never occurred to anyone. Given that, the simple rule in
    the C standard has an obvious and natural appeal.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to bart on Thu Jan 30 11:51:56 2025
    bart <bc@freeuk.com> writes:

    On 29/01/2025 10:59, Tim Rentsch wrote:

    bart <bc@freeuk.com> writes:

    On 24/01/2025 14:37, Michael S wrote:

    On Thu, 23 Jan 2025 10:54:10 +0000
    bart <bc@freeuk.com> wrote:

    On 23/01/2025 01:05, James Kuyper wrote:

    On 2025-01-22, bart <bc@freeuk.com> wrote:

    Gcc 14.1 gives me an error compiling this code:

    struct vector;
    struct scenet;

    struct vector {
    double x;
    double y;
    double z;
    };

    struct scenet {
    struct vector center;
    double radius;
    struct scenet (*child)[];
    };

    6.7.6.2p2: "The element type shall not be an incomplete or
    function type."

    I have many draft versions of the C standard. n2912.pdf, dated
    2022-06-08, says in 6.7.2.1.p3 about struct types that "... the
    type is incomplete144) until immediately after the closing brace
    of the list defining the content, and complete thereafter."

    Therefore, struct scenet is not a complete type until the closing
    brace of it's declaration.

    Wouldn't this also be the case here:

    struct scenet *child;
    };

    Just to point out if it was not said already: the problem is not
    related specifically to recursive structures. It applies to arrays
    of incomplete types in all circumstances.

    struct bar;
    struct bar (*bag)[]; // error
    typedef struct bar (*bat)[]; // error

    I don't think anyone has yet explained why that is an error (other
    than C says it is), but not this:

    struct bar *ptr;

    This is a pointer to an incomplete type. Attempts to do ++ptr
    for example will fail later on if that struct has not yet been
    defined.

    So why not the same for the pointer-to-array versions?

    The question you should be asking is why did the original C
    standards body make the rule they did?

    The answer might be because this exception to a simple and
    general rule is almost never useful, and never necessary.

    Well, you never see such a thing in use, certainly. I wonder why
    that is!

    When a language outlaws some particular construction, forcing
    people to stick to a particular idiom (the common use of a T* type
    to work with pointers and arrays instead of the more sensible and
    safer T(*)[]), then clearly you're not going to see such uses in
    the field.

    Although there are really two parts to it: use of T(*)[]
    generally (outside of self-referential structs) is allowed, but
    that is still rare, presumably because the syntax is too unwieldy.
    Or people simply don't know about it, since everyone uses T*.

    I didn't say this use case isn't used. I said this use case is
    almost never useful.

    Considering that it has been 35 years since that original rule
    was made, and 2025 is the first time the question has come up,
    the indications are that the original decision was a good one.

    We don't know that. Perhaps it comes up all the time, people
    realise they can't use such a construct, and use a different
    approach.

    We don't know that there has never been a person 50 feet tall
    either, but that doesn't mean there has been one.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Andrey Tarasevich@21:1/5 to bart on Sun Feb 2 20:35:59 2025
    On Wed 1/22/2025 8:14 AM, bart wrote:
    Gcc 14.1 gives me an error compiling this code:

      struct vector;
      struct scenet;

      struct vector {
          double x;
          double y;
          double z;
      };

      struct scenet {
          struct vector center;
          double radius;
          struct scenet (*child)[];
      };

    The error is:

      error: array type has incomplete element type 'struct scenet'
       struct scenet (*child)[];
                      ^~~~~

    Is there any way to fix this, or is it not possible?

    C has always been very strict about completeness of the element type in
    array declarations. The element type has to be complete, period.

    Another manifestation of the same issue is demonstrated by the following example

    struct S;
    void foo(struct S a[]) {}

    The function parameter declaration is invalid in C sue to incompleteness
    of `struct S`. Even though the declaration will be implicitly adjusted
    anyway to

    void foo(struct S *a) {}

    and this adjusted version is perfectly valid the in C (despite
    incompleteness of `struct S`), the language still rejects the original
    variant.

    C++ is more lenient in such contexts.

    --
    Best regards,
    Andrey

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)