Re: struct declaration in for loop

Discussion in 'C Programming' started by Noob, Jul 4, 2013.

  1. Noob

    Noob Guest

    william wrote:

    > GCC accepts the following code, but clang chokes with "error: declaration of
    > non-local variable in 'for' loop".
    >
    > #include <stdio.h>
    >
    > int main(void) {
    > for (struct { int y; } x = { 0 }; x.y < 10; x.y++) {
    > printf("x.y:%d\n", x.y);
    > }
    >
    > return 0;
    > }
    >
    > I cannot find any justification in the standard for clang to reject that
    > code. It will accept this variation, however:
    >
    > struct foo { int y; };
    >
    > for (struct foo x = { 0 }; x.y < 10; x.y++)
    >
    > Is clang wrong? Is GCC overly permissive?


    Are you asking for C99 or C11 or both?

    Regards.
    Noob, Jul 4, 2013
    #1
    1. Advertising

  2. Noob <root@127.0.0.1> writes:
    > william wrote:
    >> GCC accepts the following code, but clang chokes with "error: declaration of
    >> non-local variable in 'for' loop".
    >>
    >> #include <stdio.h>
    >>
    >> int main(void) {
    >> for (struct { int y; } x = { 0 }; x.y < 10; x.y++) {
    >> printf("x.y:%d\n", x.y);
    >> }
    >>
    >> return 0;
    >> }
    >>
    >> I cannot find any justification in the standard for clang to reject that
    >> code. It will accept this variation, however:
    >>
    >> struct foo { int y; };
    >>
    >> for (struct foo x = { 0 }; x.y < 10; x.y++)
    >>
    >> Is clang wrong? Is GCC overly permissive?

    >
    > Are you asking for C99 or C11 or both?


    Why do you think it matters?

    Both C99 and C11 have the following constraint in 6.8.5p3:

    The declaration part of a for statement shall only declare
    identifiers for objects having storage class auto or register.

    (It's easy to miss, since it's in section 6.8.5, "Iteration
    statements", not 6.8.5.3, "The for statement".)

    I suppose that's ambiguous. If it means that any objects declared
    must have storage class auto or register, then your code is ok.
    If it means that any declared identifiers must be for objects with
    storage class auto or register, then the declaration of the struct
    member "y" violates the constraint. "y" is probably the "non-local
    variable" referred to by clang's error message.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Working, but not speaking, for JetHead Development, Inc.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Jul 4, 2013
    #2
    1. Advertising

  3. Noob

    James Kuyper Guest

    On 07/04/2013 04:06 PM, Keith Thompson wrote:
    > Noob <root@127.0.0.1> writes:
    >> william wrote:
    >>> GCC accepts the following code, but clang chokes with "error: declaration of
    >>> non-local variable in 'for' loop".
    >>>
    >>> #include <stdio.h>
    >>>
    >>> int main(void) {
    >>> for (struct { int y; } x = { 0 }; x.y < 10; x.y++) {
    >>> printf("x.y:%d\n", x.y);
    >>> }
    >>>
    >>> return 0;
    >>> }
    >>>
    >>> I cannot find any justification in the standard for clang to reject that
    >>> code. It will accept this variation, however:
    >>>
    >>> struct foo { int y; };
    >>>
    >>> for (struct foo x = { 0 }; x.y < 10; x.y++)
    >>>
    >>> Is clang wrong? Is GCC overly permissive?

    >>
    >> Are you asking for C99 or C11 or both?

    >
    > Why do you think it matters?
    >
    > Both C99 and C11 have the following constraint in 6.8.5p3:
    >
    > The declaration part of a for statement shall only declare
    > identifiers for objects having storage class auto or register.
    >
    > (It's easy to miss, since it's in section 6.8.5, "Iteration
    > statements", not 6.8.5.3, "The for statement".)
    >
    > I suppose that's ambiguous. If it means that any objects declared
    > must have storage class auto or register, then your code is ok.
    > If it means that any declared identifiers must be for objects with
    > storage class auto or register, then the declaration of the struct
    > member "y" violates the constraint. "y" is probably the "non-local
    > variable" referred to by clang's error message.


    I "know" that the storage duration for x.y depends only upon the
    declaration of x, which has automatic storage duration. However, I
    haven't found a clause that says so explicitly. The closest I've come is:

    "An object whose identifier is declared with no linkage and without the
    storage-class specifier static has automatic storage duration,".

    However, but it takes two identifiers to identify x.y so I'm not how
    6.8.5.3 applies. I believe is should allow such declarations.
    --
    James Kuyper
    James Kuyper, Jul 4, 2013
    #3
  4. Noob

    Tim Rentsch Guest

    James Kuyper <> writes:

    > On 07/04/2013 04:06 PM, Keith Thompson wrote:
    >> Noob <root@127.0.0.1> writes:
    >>> william wrote:
    >>>> GCC accepts the following code, but clang chokes with
    >>>> "error: declaration of non-local variable in 'for' loop".
    >>>>
    >>>> #include <stdio.h>
    >>>>
    >>>> int main(void) {
    >>>> for (struct { int y; } x = { 0 }; x.y < 10; x.y++) {
    >>>> printf("x.y:%d\n", x.y);
    >>>> }
    >>>>
    >>>> return 0;
    >>>> }
    >>>>
    >>>> I cannot find any justification in the standard for clang to
    >>>> reject that code. It will accept this variation, however:
    >>>>
    >>>> struct foo { int y; };
    >>>>
    >>>> for (struct foo x = { 0 }; x.y < 10; x.y++)
    >>>>
    >>>> Is clang wrong? Is GCC overly permissive?
    >>>
    >>> Are you asking for C99 or C11 or both?

    >>
    >> Why do you think it matters?
    >>
    >> Both C99 and C11 have the following constraint in 6.8.5p3:
    >>
    >> The declaration part of a for statement shall only declare
    >> identifiers for objects having storage class auto or register.
    >>
    >> (It's easy to miss, since it's in section 6.8.5, "Iteration
    >> statements", not 6.8.5.3, "The for statement".)
    >>
    >> I suppose that's ambiguous. If it means that any objects declared
    >> must have storage class auto or register, then your code is ok. If
    >> it means that any declared identifiers must be for objects with
    >> storage class auto or register, then the declaration of the struct
    >> member "y" violates the constraint. "y" is probably the "non-local
    >> variable" referred to by clang's error message.

    >
    > I "know" that the storage duration for x.y depends only upon the
    > declaration of x, which has automatic storage duration. However, I
    > haven't found a clause that says so explicitly. The closest I've
    > come is:
    >
    > "An object whose identifier is declared with no linkage and without
    > the storage-class specifier static has automatic storage duration,".


    You want 6.7.1 p8 (or in N1256 it is 6.7.1 p6).
    Tim Rentsch, Jul 5, 2013
    #4
  5. Noob

    Tim Rentsch Guest

    Keith Thompson <> writes:

    > Noob <root@127.0.0.1> writes:
    >> william wrote:
    >>> GCC accepts the following code, but clang chokes with "error:
    >>> declaration of non-local variable in 'for' loop".
    >>>
    >>> #include <stdio.h>
    >>>
    >>> int main(void) {
    >>> for (struct { int y; } x = { 0 }; x.y < 10; x.y++) {
    >>> printf("x.y:%d\n", x.y);
    >>> }
    >>>
    >>> return 0;
    >>> }
    >>>
    >>> I cannot find any justification in the standard for clang to
    >>> reject that code. It will accept this variation, however:
    >>>
    >>> struct foo { int y; };
    >>>
    >>> for (struct foo x = { 0 }; x.y < 10; x.y++)
    >>>
    >>> Is clang wrong? Is GCC overly permissive?

    >>
    >> Are you asking for C99 or C11 or both?

    >
    > Why do you think it matters?
    >
    > Both C99 and C11 have the following constraint in 6.8.5p3:
    >
    > The declaration part of a for statement shall only declare
    > identifiers for objects having storage class auto or register.
    >
    > (It's easy to miss, since it's in section 6.8.5, "Iteration
    > statements", not 6.8.5.3, "The for statement".)


    I'm impressed! Kudos for finding this.

    > I suppose that's ambiguous. If it means that any objects declared
    > must have storage class auto or register, then your code is ok.
    > If it means that any declared identifiers must be for objects with
    > storage class auto or register, then the declaration of the struct
    > member "y" violates the constraint. "y" is probably the "non-local
    > variable" referred to by clang's error message.


    Yes, unfortnately, it can be read either way.

    Surely the first interpretation is what was intended, and the
    second interpretation is just accidental consequence of the
    wording used. But it looks like the possibility for confusion
    is high enough that it's worth bringing up in comp.std.c, or
    emailing Larry Jones, or both.
    Tim Rentsch, Jul 5, 2013
    #5
  6. James Kuyper <> writes:
    > On 07/04/2013 04:06 PM, Keith Thompson wrote:
    >> Noob <root@127.0.0.1> writes:
    >>> william wrote:
    >>>> GCC accepts the following code, but clang chokes with "error: declaration of
    >>>> non-local variable in 'for' loop".
    >>>>
    >>>> #include <stdio.h>
    >>>>
    >>>> int main(void) {
    >>>> for (struct { int y; } x = { 0 }; x.y < 10; x.y++) {
    >>>> printf("x.y:%d\n", x.y);
    >>>> }
    >>>>
    >>>> return 0;
    >>>> }
    >>>>
    >>>> I cannot find any justification in the standard for clang to reject that
    >>>> code. It will accept this variation, however:
    >>>>
    >>>> struct foo { int y; };
    >>>>
    >>>> for (struct foo x = { 0 }; x.y < 10; x.y++)
    >>>>
    >>>> Is clang wrong? Is GCC overly permissive?
    >>>
    >>> Are you asking for C99 or C11 or both?

    >>
    >> Why do you think it matters?
    >>
    >> Both C99 and C11 have the following constraint in 6.8.5p3:
    >>
    >> The declaration part of a for statement shall only declare
    >> identifiers for objects having storage class auto or register.
    >>
    >> (It's easy to miss, since it's in section 6.8.5, "Iteration
    >> statements", not 6.8.5.3, "The for statement".)
    >>
    >> I suppose that's ambiguous. If it means that any objects declared
    >> must have storage class auto or register, then your code is ok.
    >> If it means that any declared identifiers must be for objects with
    >> storage class auto or register, then the declaration of the struct
    >> member "y" violates the constraint. "y" is probably the "non-local
    >> variable" referred to by clang's error message.

    >
    > I "know" that the storage duration for x.y depends only upon the
    > declaration of x, which has automatic storage duration. However, I
    > haven't found a clause that says so explicitly. The closest I've come is:
    >
    > "An object whose identifier is declared with no linkage and without the
    > storage-class specifier static has automatic storage duration,".
    >
    > However, but it takes two identifiers to identify x.y so I'm not how
    > 6.8.5.3 applies. I believe is should allow such declarations.


    The issue isn't the storage duration of x.y, which is clearly automatic.
    The issue is that `int y;` doesn't declare an object; it declares a
    member. It seems that the authors of gcc and clang disagree on whether
    such a declaration is permitted by 6.5.8p3.

    I'll ask in comp.std.c.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Working, but not speaking, for JetHead Development, Inc.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Jul 5, 2013
    #6
  7. Keith Thompson <> writes:
    > James Kuyper <> writes:
    >> On 07/04/2013 04:06 PM, Keith Thompson wrote:
    >>> Noob <root@127.0.0.1> writes:
    >>>> william wrote:
    >>>>> GCC accepts the following code, but clang chokes with "error: declaration of
    >>>>> non-local variable in 'for' loop".
    >>>>>
    >>>>> #include <stdio.h>
    >>>>>
    >>>>> int main(void) {
    >>>>> for (struct { int y; } x = { 0 }; x.y < 10; x.y++) {
    >>>>> printf("x.y:%d\n", x.y);
    >>>>> }
    >>>>>
    >>>>> return 0;
    >>>>> }
    >>>>>
    >>>>> I cannot find any justification in the standard for clang to reject that
    >>>>> code. It will accept this variation, however:
    >>>>>
    >>>>> struct foo { int y; };
    >>>>>
    >>>>> for (struct foo x = { 0 }; x.y < 10; x.y++)
    >>>>>
    >>>>> Is clang wrong? Is GCC overly permissive?
    >>>>
    >>>> Are you asking for C99 or C11 or both?
    >>>
    >>> Why do you think it matters?
    >>>
    >>> Both C99 and C11 have the following constraint in 6.8.5p3:
    >>>
    >>> The declaration part of a for statement shall only declare
    >>> identifiers for objects having storage class auto or register.
    >>>
    >>> (It's easy to miss, since it's in section 6.8.5, "Iteration
    >>> statements", not 6.8.5.3, "The for statement".)
    >>>
    >>> I suppose that's ambiguous. If it means that any objects declared
    >>> must have storage class auto or register, then your code is ok.
    >>> If it means that any declared identifiers must be for objects with
    >>> storage class auto or register, then the declaration of the struct
    >>> member "y" violates the constraint. "y" is probably the "non-local
    >>> variable" referred to by clang's error message.

    >>
    >> I "know" that the storage duration for x.y depends only upon the
    >> declaration of x, which has automatic storage duration. However, I
    >> haven't found a clause that says so explicitly. The closest I've come is:
    >>
    >> "An object whose identifier is declared with no linkage and without the
    >> storage-class specifier static has automatic storage duration,".
    >>
    >> However, but it takes two identifiers to identify x.y so I'm not how
    >> 6.8.5.3 applies. I believe is should allow such declarations.

    >
    > The issue isn't the storage duration of x.y, which is clearly automatic.
    > The issue is that `int y;` doesn't declare an object; it declares a
    > member. It seems that the authors of gcc and clang disagree on whether
    > such a declaration is permitted by 6.5.8p3.
    >
    > I'll ask in comp.std.c.


    I'm holding off on the comp.std.c post for a bit, because I discovered
    this:

    #include <stdio.h>
    int main(void) {
    int i = 0;
    for (typedef int ignored; i < 10; i ++) {
    printf("%d\n", i);
    }
    return 0;
    }

    gcc 4.8.0, invoked with "-std=c99 -pedantic", rejects this with:

    c.c: In function 'main':
    c.c:4:5: error: declaration of non-variable 'ignored' in 'for' loop
    initial declaration
    for (typedef int ignored; i < 10; i ++) {
    ^

    clang 3.0 with the same arguments rejects it with:

    c.c:4:22: error: declaration of non-local variable in 'for' loop
    for (typedef int ignored; i < 10; i ++) {
    ^
    1 error generated.

    clang's error message is poorly worded; it's not a variable declaration
    at all. But the point is that gcc and clang agree that a non-variable
    declaration is not permitted in a for loop header.

    So why does gcc permit a struct declaration, as in:
    for (struct { int y; } x = { 0 }; x.y < 10; x.y++) {
    ?

    "int y;" is not syntactically a "declaration". It's a
    "struct-declaration" and a "declarator". Perhaps that's why gcc's
    internal check for a "declaration of non-variable" misses it, but that's
    sheer speculation on my part.

    I'm leaning toward the idea that this is just a (minor) bug in gcc.

    I also suggest that that paragraph in the standard could be cleaned up a
    bit. Note that any revised wording should still permit multiple objects
    to be declared, as in:

    for (int i = 0, j = 0; i < 10; i++, j = i * i) {
    printf("%d %d\n", i, j);
    }

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Working, but not speaking, for JetHead Development, Inc.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Jul 5, 2013
    #7
  8. Tim Rentsch <> writes:
    > Keith Thompson <> writes:
    >> Noob <root@127.0.0.1> writes:
    >>> william wrote:
    >>>> GCC accepts the following code, but clang chokes with "error:
    >>>> declaration of non-local variable in 'for' loop".
    >>>>
    >>>> #include <stdio.h>
    >>>>
    >>>> int main(void) {
    >>>> for (struct { int y; } x = { 0 }; x.y < 10; x.y++) {
    >>>> printf("x.y:%d\n", x.y);
    >>>> }
    >>>>
    >>>> return 0;
    >>>> }
    >>>>
    >>>> I cannot find any justification in the standard for clang to
    >>>> reject that code. It will accept this variation, however:
    >>>>
    >>>> struct foo { int y; };
    >>>>
    >>>> for (struct foo x = { 0 }; x.y < 10; x.y++)
    >>>>
    >>>> Is clang wrong? Is GCC overly permissive?
    >>>
    >>> Are you asking for C99 or C11 or both?

    >>
    >> Why do you think it matters?
    >>
    >> Both C99 and C11 have the following constraint in 6.8.5p3:
    >>
    >> The declaration part of a for statement shall only declare
    >> identifiers for objects having storage class auto or register.
    >>
    >> (It's easy to miss, since it's in section 6.8.5, "Iteration
    >> statements", not 6.8.5.3, "The for statement".)

    >
    > I'm impressed! Kudos for finding this.
    >
    >> I suppose that's ambiguous. If it means that any objects declared
    >> must have storage class auto or register, then your code is ok.
    >> If it means that any declared identifiers must be for objects with
    >> storage class auto or register, then the declaration of the struct
    >> member "y" violates the constraint. "y" is probably the "non-local
    >> variable" referred to by clang's error message.

    >
    > Yes, unfortnately, it can be read either way.
    >
    > Surely the first interpretation is what was intended, and the
    > second interpretation is just accidental consequence of the
    > wording used. But it looks like the possibility for confusion
    > is high enough that it's worth bringing up in comp.std.c, or
    > emailing Larry Jones, or both.


    So you think that it's intended to permit declarations of things
    other than objects in a for loop header? The restriction to a single
    declaration makes it difficult to *usefully* declare anything other
    than an object; I can't think of a non-contrived example.

    By your interpretation, if I understand you correctly, this would
    be legal (I posted this elsethread):

    #include <stdio.h>
    int main(void) {
    int i = 0;
    for (typedef int ignored; i < 10; i ++) {
    printf("%d\n", i);
    }
    return 0;
    }

    Both gcc and clang reject it.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Working, but not speaking, for JetHead Development, Inc.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Jul 5, 2013
    #8
  9. Noob

    Eric Sosman Guest

    On 7/5/2013 11:31 AM, Keith Thompson wrote:
    > Keith Thompson <> writes:
    >> James Kuyper <> writes:
    >>> On 07/04/2013 04:06 PM, Keith Thompson wrote:
    >>>> Noob <root@127.0.0.1> writes:
    >>>>> william wrote:
    >>>>>> GCC accepts the following code, but clang chokes with "error: declaration of
    >>>>>> non-local variable in 'for' loop".
    >>>>>>
    >>>>>> #include <stdio.h>
    >>>>>>
    >>>>>> int main(void) {
    >>>>>> for (struct { int y; } x = { 0 }; x.y < 10; x.y++) {
    >>>>>> printf("x.y:%d\n", x.y);
    >>>>>> }
    >>>>>>
    >>>>>> return 0;
    >>>>>> }
    >>>>>>
    >>>>>> I cannot find any justification in the standard for clang to reject that
    >>>>>> code. It will accept this variation, however:
    >>>>>>
    >>>>>> struct foo { int y; };
    >>>>>>
    >>>>>> for (struct foo x = { 0 }; x.y < 10; x.y++)
    >>>>>>
    >>>>>> Is clang wrong? Is GCC overly permissive?
    >>>>>
    >>>>> Are you asking for C99 or C11 or both?
    >>>>
    >>>> Why do you think it matters?
    >>>>
    >>>> Both C99 and C11 have the following constraint in 6.8.5p3:
    >>>>
    >>>> The declaration part of a for statement shall only declare
    >>>> identifiers for objects having storage class auto or register.
    >>>>
    >>>> (It's easy to miss, since it's in section 6.8.5, "Iteration
    >>>> statements", not 6.8.5.3, "The for statement".)
    >>>>
    >>>> I suppose that's ambiguous. If it means that any objects declared
    >>>> must have storage class auto or register, then your code is ok.
    >>>> If it means that any declared identifiers must be for objects with
    >>>> storage class auto or register, then the declaration of the struct
    >>>> member "y" violates the constraint. "y" is probably the "non-local
    >>>> variable" referred to by clang's error message.
    >>>
    >>> I "know" that the storage duration for x.y depends only upon the
    >>> declaration of x, which has automatic storage duration. However, I
    >>> haven't found a clause that says so explicitly. The closest I've come is:
    >>>
    >>> "An object whose identifier is declared with no linkage and without the
    >>> storage-class specifier static has automatic storage duration,".
    >>>
    >>> However, but it takes two identifiers to identify x.y so I'm not how
    >>> 6.8.5.3 applies. I believe is should allow such declarations.

    >>
    >> The issue isn't the storage duration of x.y, which is clearly automatic.
    >> The issue is that `int y;` doesn't declare an object; it declares a
    >> member. It seems that the authors of gcc and clang disagree on whether
    >> such a declaration is permitted by 6.5.8p3.
    >>
    >> I'll ask in comp.std.c.

    >
    > I'm holding off on the comp.std.c post for a bit, because I discovered
    > this:
    >
    > #include <stdio.h>
    > int main(void) {
    > int i = 0;
    > for (typedef int ignored; i < 10; i ++) {
    > printf("%d\n", i);
    > }
    > return 0;
    > }
    >
    > gcc 4.8.0, invoked with "-std=c99 -pedantic", rejects this with:
    >
    > c.c: In function 'main':
    > c.c:4:5: error: declaration of non-variable 'ignored' in 'for' loop
    > initial declaration
    > for (typedef int ignored; i < 10; i ++) {
    > ^
    >
    > clang 3.0 with the same arguments rejects it with:
    >
    > c.c:4:22: error: declaration of non-local variable in 'for' loop
    > for (typedef int ignored; i < 10; i ++) {
    > ^
    > 1 error generated.
    >
    > clang's error message is poorly worded; it's not a variable declaration
    > at all. But the point is that gcc and clang agree that a non-variable
    > declaration is not permitted in a for loop header.


    This much makes sense, I think. The storage class `typedef'
    is neither `auto' nor `register', so both compilers are right to
    reject the construct.

    Here's a variation that might shed some light:

    #include <stdio.h>
    int main(void) {
    int i = 0;
    for (struct {int :8;}; i < 10; i ++) {
    printf("%d\n", i);
    }
    return 0;
    }

    I don't have clang, but gcc versions 3.4.4 and 4.4.1 accept it,
    albeit with warnings. It looks more and more like the presence
    of an identifier inside the declared struct may be the crux.

    --
    Eric Sosman
    d
    Eric Sosman, Jul 5, 2013
    #9
  10. Noob

    Eric Sosman Guest

    On 7/5/2013 11:52 AM, Eric Sosman wrote:
    >[...]
    > Here's a variation that might shed some light:
    >
    > #include <stdio.h>
    > int main(void) {
    > int i = 0;
    > for (struct {int :8;}; i < 10; i ++) {
    > printf("%d\n", i);
    > }
    > return 0;
    > }
    >
    > I don't have clang, but gcc versions 3.4.4 and 4.4.1 accept it,
    > albeit with warnings. It looks more and more like the presence
    > of an identifier inside the declared struct may be the crux.


    Similar outcome with `struct {int :8;} ignored;', BTW.

    --
    Eric Sosman
    d
    Eric Sosman, Jul 5, 2013
    #10
  11. Noob

    James Kuyper Guest

    On 07/05/2013 11:38 AM, Keith Thompson wrote:
    > Tim Rentsch <> writes:
    >> Keith Thompson <> writes:
    >>> Noob <root@127.0.0.1> writes:
    >>>> william wrote:
    >>>>> GCC accepts the following code, but clang chokes with "error:
    >>>>> declaration of non-local variable in 'for' loop".
    >>>>>
    >>>>> #include <stdio.h>
    >>>>>
    >>>>> int main(void) {
    >>>>> for (struct { int y; } x = { 0 }; x.y < 10; x.y++) {
    >>>>> printf("x.y:%d\n", x.y);
    >>>>> }
    >>>>>
    >>>>> return 0;
    >>>>> }
    >>>>>
    >>>>> I cannot find any justification in the standard for clang to
    >>>>> reject that code. It will accept this variation, however:
    >>>>>
    >>>>> struct foo { int y; };
    >>>>>
    >>>>> for (struct foo x = { 0 }; x.y < 10; x.y++)

    ....
    >>> Both C99 and C11 have the following constraint in 6.8.5p3:
    >>>
    >>> The declaration part of a for statement shall only declare
    >>> identifiers for objects having storage class auto or register.

    ....
    >>> I suppose that's ambiguous. If it means that any objects declared
    >>> must have storage class auto or register, then your code is ok.
    >>> If it means that any declared identifiers must be for objects with
    >>> storage class auto or register, then the declaration of the struct
    >>> member "y" violates the constraint. "y" is probably the "non-local
    >>> variable" referred to by clang's error message.

    >>
    >> Yes, unfortnately, it can be read either way.
    >>
    >> Surely the first interpretation is what was intended, and the
    >> second interpretation is just accidental consequence of the
    >> wording used. But it looks like the possibility for confusion
    >> is high enough that it's worth bringing up in comp.std.c, or
    >> emailing Larry Jones, or both.

    >
    > So you think that it's intended to permit declarations of things
    > other than objects in a for loop header? The restriction to a single
    > declaration makes it difficult to *usefully* declare anything other
    > than an object; I can't think of a non-contrived example.
    >
    > By your interpretation, if I understand you correctly, this would
    > be legal (I posted this elsethread):
    >
    > #include <stdio.h>
    > int main(void) {
    > int i = 0;
    > for (typedef int ignored; i < 10; i ++) {
    > printf("%d\n", i);
    > }
    > return 0;
    > }


    "typedef int ignored" doesn't declare an object of any kind. It does
    declare a typedef, which seems to me to clearly be a violation of 6.8.5p3.

    struct {int y;} x is the declaration of an object with automatic storage
    duration, namely 'x'. I see "int y" simply as part of the specification
    of the type of x, and not directly a declaration of a object in it's own
    right. However, if you believe that it should be considered a
    declaration of the 'y' sub-object of the object 'x', it still declares
    an object with automatic storage duration. So, I still don't see that as
    a violation of 6.8.5p3. I'd feel differently if it declared a tag for
    the struct, rather than a member, because in that case it's also
    declaring a type. However, a member is inherently part of the object
    it's a member of, and has the same storage duration.

    It's not entirely clear to me that your interpretation is wrong, but
    that's not how I understand it.
    James Kuyper, Jul 5, 2013
    #11
  12. Noob

    Tim Rentsch Guest

    Keith Thompson <> writes:

    > Tim Rentsch <> writes:
    >> Keith Thompson <> writes:
    >>> Noob <root@127.0.0.1> writes:
    >>>> william wrote:
    >>>>> GCC accepts the following code, but clang chokes with "error:
    >>>>> declaration of non-local variable in 'for' loop".
    >>>>>
    >>>>> #include <stdio.h>
    >>>>>
    >>>>> int main(void) {
    >>>>> for (struct { int y; } x = { 0 }; x.y < 10; x.y++) {
    >>>>> printf("x.y:%d\n", x.y);
    >>>>> }
    >>>>>
    >>>>> return 0;
    >>>>> }
    >>>>>
    >>>>> I cannot find any justification in the standard for clang to
    >>>>> reject that code. It will accept this variation, however:
    >>>>>
    >>>>> struct foo { int y; };
    >>>>>
    >>>>> for (struct foo x = { 0 }; x.y < 10; x.y++)
    >>>>>
    >>>>> Is clang wrong? Is GCC overly permissive?
    >>>>
    >>>> Are you asking for C99 or C11 or both?
    >>>
    >>> Why do you think it matters?
    >>>
    >>> Both C99 and C11 have the following constraint in 6.8.5p3:
    >>>
    >>> The declaration part of a for statement shall only declare
    >>> identifiers for objects having storage class auto or register.
    >>>
    >>> (It's easy to miss, since it's in section 6.8.5, "Iteration
    >>> statements", not 6.8.5.3, "The for statement".)

    >>
    >> I'm impressed! Kudos for finding this.
    >>
    >>> I suppose that's ambiguous. If it means that any objects declared
    >>> must have storage class auto or register, then your code is ok.
    >>> If it means that any declared identifiers must be for objects with
    >>> storage class auto or register, then the declaration of the struct
    >>> member "y" violates the constraint. "y" is probably the "non-local
    >>> variable" referred to by clang's error message.

    >>
    >> Yes, unfortnately, it can be read either way.
    >>
    >> Surely the first interpretation is what was intended, and the
    >> second interpretation is just accidental consequence of the
    >> wording used. But it looks like the possibility for confusion
    >> is high enough that it's worth bringing up in comp.std.c, or
    >> emailing Larry Jones, or both.

    >
    > So you think that it's intended to permit declarations of things
    > other than objects in a for loop header?


    No, that was confusing, and I'm glad you asked for clarification.

    > The restriction to a single
    > declaration makes it difficult to *usefully* declare anything other
    > than an object; I can't think of a non-contrived example.
    >
    > By your interpretation, if I understand you correctly, this would
    > be legal (I posted this elsethread):
    >
    > #include <stdio.h>
    > int main(void) {
    > int i = 0;
    > for (typedef int ignored; i < 10; i ++) {
    > printf("%d\n", i);
    > }
    > return 0;
    > }
    >
    > Both gcc and clang reject it.


    In my reading it is correct to reject this program, because the
    storage-class specifier used ('typedef') is not allowed.

    The wording used in 6.8.5 p3 is a little bit careless. Taken
    literally, it would allow only the _declaring_ of variables, but
    not _initializing_ them. That is obviously wrong.

    What I think is meant is something like what is said for
    parameter declarations in a prototype, eg,

    The outermost declaration-specifiers of a for statement shall
    have no storage-class specifier other than auto or register.

    That meaning (even if the phrasing is a little awkward) is
    consistent with the C99 Rationale document, which says

    To simplify the syntax, each loop is limited to a single
    declaration (though this can declare several variables),
    and these must have auto or register storage class.

    Bottom line: I believe the gcc interpretation is right, and the
    clang interpretation (in that one case) is wrong. And the
    wording used in 6.8.5 p3 definitely needs revision, especially
    since at least one implementation has interpreted it wrongly.
    Tim Rentsch, Jul 5, 2013
    #12
  13. Eric Sosman <> writes:
    > On 7/5/2013 11:31 AM, Keith Thompson wrote:
    >> Keith Thompson <> writes:
    >>> James Kuyper <> writes:
    >>>> On 07/04/2013 04:06 PM, Keith Thompson wrote:
    >>>>> Noob <root@127.0.0.1> writes:
    >>>>>> william wrote:
    >>>>>>> GCC accepts the following code, but clang chokes with "error: declaration of
    >>>>>>> non-local variable in 'for' loop".
    >>>>>>>
    >>>>>>> #include <stdio.h>
    >>>>>>>
    >>>>>>> int main(void) {
    >>>>>>> for (struct { int y; } x = { 0 }; x.y < 10; x.y++) {
    >>>>>>> printf("x.y:%d\n", x.y);
    >>>>>>> }
    >>>>>>>
    >>>>>>> return 0;
    >>>>>>> }
    >>>>>>>
    >>>>>>> I cannot find any justification in the standard for clang to reject that
    >>>>>>> code. It will accept this variation, however:
    >>>>>>>
    >>>>>>> struct foo { int y; };
    >>>>>>>
    >>>>>>> for (struct foo x = { 0 }; x.y < 10; x.y++)
    >>>>>>>
    >>>>>>> Is clang wrong? Is GCC overly permissive?
    >>>>>>
    >>>>>> Are you asking for C99 or C11 or both?
    >>>>>
    >>>>> Why do you think it matters?
    >>>>>
    >>>>> Both C99 and C11 have the following constraint in 6.8.5p3:
    >>>>>
    >>>>> The declaration part of a for statement shall only declare
    >>>>> identifiers for objects having storage class auto or register.
    >>>>>
    >>>>> (It's easy to miss, since it's in section 6.8.5, "Iteration
    >>>>> statements", not 6.8.5.3, "The for statement".)
    >>>>>
    >>>>> I suppose that's ambiguous. If it means that any objects declared
    >>>>> must have storage class auto or register, then your code is ok.
    >>>>> If it means that any declared identifiers must be for objects with
    >>>>> storage class auto or register, then the declaration of the struct
    >>>>> member "y" violates the constraint. "y" is probably the "non-local
    >>>>> variable" referred to by clang's error message.
    >>>>
    >>>> I "know" that the storage duration for x.y depends only upon the
    >>>> declaration of x, which has automatic storage duration. However, I
    >>>> haven't found a clause that says so explicitly. The closest I've come is:
    >>>>
    >>>> "An object whose identifier is declared with no linkage and without the
    >>>> storage-class specifier static has automatic storage duration,".
    >>>>
    >>>> However, but it takes two identifiers to identify x.y so I'm not how
    >>>> 6.8.5.3 applies. I believe is should allow such declarations.
    >>>
    >>> The issue isn't the storage duration of x.y, which is clearly automatic.
    >>> The issue is that `int y;` doesn't declare an object; it declares a
    >>> member. It seems that the authors of gcc and clang disagree on whether
    >>> such a declaration is permitted by 6.5.8p3.
    >>>
    >>> I'll ask in comp.std.c.

    >>
    >> I'm holding off on the comp.std.c post for a bit, because I discovered
    >> this:
    >>
    >> #include <stdio.h>
    >> int main(void) {
    >> int i = 0;
    >> for (typedef int ignored; i < 10; i ++) {
    >> printf("%d\n", i);
    >> }
    >> return 0;
    >> }
    >>
    >> gcc 4.8.0, invoked with "-std=c99 -pedantic", rejects this with:
    >>
    >> c.c: In function 'main':
    >> c.c:4:5: error: declaration of non-variable 'ignored' in 'for' loop
    >> initial declaration
    >> for (typedef int ignored; i < 10; i ++) {
    >> ^
    >>
    >> clang 3.0 with the same arguments rejects it with:
    >>
    >> c.c:4:22: error: declaration of non-local variable in 'for' loop
    >> for (typedef int ignored; i < 10; i ++) {
    >> ^
    >> 1 error generated.
    >>
    >> clang's error message is poorly worded; it's not a variable declaration
    >> at all. But the point is that gcc and clang agree that a non-variable
    >> declaration is not permitted in a for loop header.

    >
    > This much makes sense, I think. The storage class `typedef'
    > is neither `auto' nor `register', so both compilers are right to
    > reject the construct.
    >
    > Here's a variation that might shed some light:
    >
    > #include <stdio.h>
    > int main(void) {
    > int i = 0;
    > for (struct {int :8;}; i < 10; i ++) {
    > printf("%d\n", i);
    > }
    > return 0;
    > }
    >
    > I don't have clang, but gcc versions 3.4.4 and 4.4.1 accept it,
    > albeit with warnings. It looks more and more like the presence
    > of an identifier inside the declared struct may be the crux.


    This provides some insight into how gcc and clang operate, but it's
    complicated by N1256 6.7.2.1p7:

    If the struct-declaration-list contains no named members,
    the behavior is undefined.

    and the nearly equivalent N1570 6.7.2.1p8:

    If the struct-declaration-list does not contain any named
    members, either directly or via an anonymous structure or
    anonymous union, the behavior is undefined.

    (I have no idea why a struct or union declaration with no named
    members causes undefined behavior rather than simply being a
    constraint violation.)

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Working, but not speaking, for JetHead Development, Inc.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Jul 5, 2013
    #13
  14. In comp.lang.c James Kuyper <> wrote:
    > On 07/05/2013 11:38 AM, Keith Thompson wrote:


    (snip)
    >> By your interpretation, if I understand you correctly, this would
    >> be legal (I posted this elsethread):


    >> #include <stdio.h>
    >> int main(void) {
    >> int i = 0;
    >> for (typedef int ignored; i < 10; i ++) {
    >> printf("%d\n", i);
    >> }
    >> return 0;
    >> }


    > "typedef int ignored" doesn't declare an object of any kind.
    > It does declare a typedef, which seems to me to clearly be a
    > violation of 6.8.5p3.


    > struct {int y;} x is the declaration of an object with
    > automatic storage duration, namely 'x'. I see "int y" simply
    > as part of the specification of the type of x, and not directly
    > a declaration of a object in it's own right.


    Might be different if it was

    struct z {int y;} x;

    which also declares z as a struct name.

    > However, if you believe that it should be considered a
    > declaration of the 'y' sub-object of the object 'x', it still
    > declares an object with automatic storage duration.
    > So, I still don't see that as a violation of 6.8.5p3.
    > I'd feel differently if it declared a tag for the struct,
    > rather than a member, because in that case it's also
    > declaring a type. However, a member is inherently part of the
    > object it's a member of, and has the same storage duration.


    I agree.

    -- glen
    glen herrmannsfeldt, Jul 5, 2013
    #14
  15. Tim Rentsch <> writes:
    > Keith Thompson <> writes:

    [...]
    >> The restriction to a single
    >> declaration makes it difficult to *usefully* declare anything other
    >> than an object; I can't think of a non-contrived example.
    >>
    >> By your interpretation, if I understand you correctly, this would
    >> be legal (I posted this elsethread):
    >>
    >> #include <stdio.h>
    >> int main(void) {
    >> int i = 0;
    >> for (typedef int ignored; i < 10; i ++) {
    >> printf("%d\n", i);
    >> }
    >> return 0;
    >> }
    >>
    >> Both gcc and clang reject it.

    >
    > In my reading it is correct to reject this program, because the
    > storage-class specifier used ('typedef') is not allowed.
    >
    > The wording used in 6.8.5 p3 is a little bit careless. Taken
    > literally, it would allow only the _declaring_ of variables, but
    > not _initializing_ them. That is obviously wrong.
    >
    > What I think is meant is something like what is said for
    > parameter declarations in a prototype, eg,
    >
    > The outermost declaration-specifiers of a for statement shall
    > have no storage-class specifier other than auto or register.
    >
    > That meaning (even if the phrasing is a little awkward) is
    > consistent with the C99 Rationale document, which says
    >
    > To simplify the syntax, each loop is limited to a single
    > declaration (though this can declare several variables),
    > and these must have auto or register storage class.
    >
    > Bottom line: I believe the gcc interpretation is right, and the
    > clang interpretation (in that one case) is wrong. And the
    > wording used in 6.8.5 p3 definitely needs revision, especially
    > since at least one implementation has interpreted it wrongly.


    I picked "typedef" just because it's a declaration that doesn't
    declare an object. The fact that it's treated as a storage-class
    specifier (for syntactic convenience) confused the point I was
    trying to make.

    My speculation/guess about the intent of 6.8.5p3:

    The declaration part of a for statement shall only declare
    identifiers for objects having storage class auto or register.

    is that a declaration in a for loop header must only declare objects,
    and those objects must only have storage class auto or register.

    That's different from what you're saying, which is that such a
    declaration cannot have a storage class other than register or auto --
    but (implicitly) it needn't be an object declaration. By your
    interpretation, which is consistent with the wording BTW, this would be
    legal:

    int i = 0;
    for (void foo(void); i < 10; i ++) {
    printf("%d\n", i);
    }

    since a function has no storage class.

    My interpretation is not based entirely on the wording in the
    standard; it also accounts for (what I think is) the intended use
    of declarations in for loop headers, namely defining loop iteration
    variables and keeping them local to the loop. I tend to think that
    non-object declarations in for loop headers are not particularly
    useful, and are better placed in a scope surrounding the loop.
    It might be useful to define a type and then an object of that
    type, but that would require multiple declarations, which are not
    permitted, so the type declaration has to go elsewhere.

    There would be something to be said for allowing *any* declaration,
    but 6.8.5p3 is clearly restrictive, and IMHO it makes the most
    sense to permit only object declarations with automatic or register
    storage class.

    The most nearly non-contrived example of something other than an
    object declaration is something like this:

    for (enum { zero, one, two } i = zero; i <= two; i ++) {
    /* ... */
    }

    but even if that's legal (both gcc and clang reject it), I'd still
    rather declare the enum type outside the loop. (I think it's illegal
    because it declares "zero", "one", and "two", which are not objects.)

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Working, but not speaking, for JetHead Development, Inc.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Jul 5, 2013
    #15
  16. James Kuyper <> writes:
    > On 07/05/2013 11:38 AM, Keith Thompson wrote:

    [...]
    >> By your interpretation, if I understand you correctly, this would
    >> be legal (I posted this elsethread):


    (The above was addressed to Tim Rentsch.)

    >> #include <stdio.h>
    >> int main(void) {
    >> int i = 0;
    >> for (typedef int ignored; i < 10; i ++) {
    >> printf("%d\n", i);
    >> }
    >> return 0;
    >> }

    >
    > "typedef int ignored" doesn't declare an object of any kind. It does
    > declare a typedef, which seems to me to clearly be a violation of 6.8.5p3.
    >
    > struct {int y;} x is the declaration of an object with automatic storage
    > duration, namely 'x'. I see "int y" simply as part of the specification
    > of the type of x, and not directly a declaration of a object in it's own
    > right. However, if you believe that it should be considered a
    > declaration of the 'y' sub-object of the object 'x', it still declares
    > an object with automatic storage duration. So, I still don't see that as
    > a violation of 6.8.5p3. I'd feel differently if it declared a tag for
    > the struct, rather than a member, because in that case it's also
    > declaring a type. However, a member is inherently part of the object
    > it's a member of, and has the same storage duration.
    >
    > It's not entirely clear to me that your interpretation is wrong, but
    > that's not how I understand it.


    `int y;` doesn't declare an object. `struct {int y;} x;` obviously does
    declare an object `x`; it also declares another object `x.y`, which is a
    subobject of `x`.

    The problem is that `int y;` declares a struct member, and by at least
    one interpretation that's not allowed in a for loop header; only object
    declarations are allowed, and only with automatic or register storage
    class.

    (On the other hand, `int y;` is not syntactically a "declaration", which
    probably muddies the waters even more.)

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Working, but not speaking, for JetHead Development, Inc.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Jul 5, 2013
    #16
  17. Noob

    Tim Rentsch Guest

    Keith Thompson <> writes:

    > Tim Rentsch <> writes:
    >> Keith Thompson <> writes:

    > [...]
    >>> The restriction to a single
    >>> declaration makes it difficult to *usefully* declare anything other
    >>> than an object; I can't think of a non-contrived example.
    >>>
    >>> By your interpretation, if I understand you correctly, this would
    >>> be legal (I posted this elsethread):
    >>>
    >>> #include <stdio.h>
    >>> int main(void) {
    >>> int i = 0;
    >>> for (typedef int ignored; i < 10; i ++) {
    >>> printf("%d\n", i);
    >>> }
    >>> return 0;
    >>> }
    >>>
    >>> Both gcc and clang reject it.

    >>
    >> In my reading it is correct to reject this program, because the
    >> storage-class specifier used ('typedef') is not allowed.
    >>
    >> The wording used in 6.8.5 p3 is a little bit careless. Taken
    >> literally, it would allow only the _declaring_ of variables, but
    >> not _initializing_ them. That is obviously wrong.
    >>
    >> What I think is meant is something like what is said for
    >> parameter declarations in a prototype, eg,
    >>
    >> The outermost declaration-specifiers of a for statement shall
    >> have no storage-class specifier other than auto or register.
    >>
    >> That meaning (even if the phrasing is a little awkward) is
    >> consistent with the C99 Rationale document, which says
    >>
    >> To simplify the syntax, each loop is limited to a single
    >> declaration (though this can declare several variables),
    >> and these must have auto or register storage class.
    >>
    >> Bottom line: I believe the gcc interpretation is right, and the
    >> clang interpretation (in that one case) is wrong. And the
    >> wording used in 6.8.5 p3 definitely needs revision, especially
    >> since at least one implementation has interpreted it wrongly.

    >
    > I picked "typedef" just because it's a declaration that doesn't
    > declare an object. The fact that it's treated as a storage-class
    > specifier (for syntactic convenience) confused the point I was
    > trying to make.
    >
    > My speculation/guess about the intent of 6.8.5p3:
    >
    > The declaration part of a for statement shall only declare
    > identifiers for objects having storage class auto or register.
    >
    > is that a declaration in a for loop header must only declare
    > objects, and those objects must only have storage class auto or
    > register.
    >
    > That's different from what you're saying, which is that such a
    > declaration cannot have a storage class other than register or auto
    > -- but (implicitly) it needn't be an object declaration.


    Unfortunately what I was trying to say was not quite in sync with
    the phrasing I used to express it.

    > By your interpretation, which is consistent with the wording BTW,
    > this would be legal:
    >
    > int i = 0;
    > for (void foo(void); i < 10; i ++) {
    > printf("%d\n", i);
    > }
    >
    > since a function has no storage class.


    My intended meaning would not allow that. You're right that the
    wording I gave would allow it. That happened because it didn't
    occur to me to consider function declarations, which probably
    also explains why the wording used in the Standard is so awkward.
    Let me take another stab at Standard-ese expressing my intended
    meaning:

    The declaration part of a for statement shall have an
    init-declarator-list, if present, whose top-level declarators
    declare identifiers for objects of automatic storage duration.

    I'm assuming a suitable definition of "top-level declarator",
    which I hope is clear enough that it doesn't need to be explained
    further here (though it probably would in the Standard).

    This phrasing would not allow the function declaration example
    given above. It would allow all of

    for( struct foo *p = 0; p; ) {}
    for( struct { int i;} p = {0}; p.i; ) {}
    for( struct bas { int i;} q = {0}; q.i; ) {}
    for( enum { a, b, c } i = c; i; i-- ) {}
    for( enum foo_e { x, y, z } j = z; j; j-- ) {}
    for( int (*f)( int i, char *v[] ) = 0; f; ) {}

    where 'struct foo' and 'struct bas' have not been previously
    declared (and also if they have been, but that introduces no
    additional information).

    > My interpretation is not based entirely on the wording in the
    > standard; it also accounts for (what I think is) the intended use
    > of declarations in for loop headers, namely defining loop iteration
    > variables and keeping them local to the loop. I tend to think that
    > non-object declarations in for loop headers are not particularly
    > useful, and are better placed in a scope surrounding the loop. It
    > might be useful to define a type and then an object of that type,
    > but that would require multiple declarations, which are not
    > permitted, so the type declaration has to go elsewhere.


    It is possible to define a type, in the sense of defining the
    contents of a struct or union type, and also declare an object of
    that type, in a single declaration. In fact a single declaration
    can declare several objects of the defined type, or types which
    are derived from that type -- eg a struct object, a pointer to
    said type of struct, and an array of said type of struct, all in
    a single declaration that also defines the type.

    Clarification: I mean this is possible in an ordinary, non-for
    declaration. Obviously we still aren't sure what the Standard
    expects for declarations given as for-clauses.

    > There would be something to be said for allowing *any* declaration,
    > but 6.8.5p3 is clearly restrictive, and IMHO it makes the most
    > sense to permit only object declarations with automatic or register
    > storage class.


    For top-level declarators, I agree with you. For declarators
    other than those appearing in the top-level init-declarator-list,
    I think anything allowed in a non-for declaration should also be
    allowed in a for-clause declaration. (That's what I think should
    be true, not necessarily what the Standard means to allow.)

    Incidentally, there is no automatic storage class. Even talking
    about "auto storage class" is somewhat an abuse of language,
    since most declarations don't use the 'auto' specifier. The
    salient property is that the objects should be of automatic
    storage duration, and IMO that is how the Standard should express
    it.

    > The most nearly non-contrived example of something other than an
    > object declaration is something like this:
    >
    > for (enum { zero, one, two } i = zero; i <= two; i ++) {
    > /* ... */
    > }
    >
    > but even if that's legal (both gcc and clang reject it), I'd still
    > rather declare the enum type outside the loop. (I think it's
    > illegal because it declares "zero", "one", and "two", which are not
    > objects.)


    I find gcc's behavior rather confusing. Since it allows defining
    the contents of a structure type, I don't see any reason why it
    should not allow the defining of an enumeration type. It seems
    inconsistent. Furthermore there is this:

    for( int (*f)( int i, char *v[] ) = main; f; f = 0 ) {}

    This for-clause is accepted by gcc, despite the presence of two
    declared identifiers ('i' and 'v') that do not declare objects.
    Perhaps gcc interprets 6.8.5 p3 to mean identifiers declared
    directly in the outermost current scope; that would explain
    why the struct definition and function prototype are accepted,
    whereas the enum definition is not, since its member identifers
    survive into the currently active scope.

    Two other gcc data points:

    for( struct foo *p = 0; p; ) {}

    is not accepted (with no previous declaration of 'struct foo'),
    whereas

    for( struct {int i;} *p = 0; p && p->i; ){}

    is accepted. That's consistent with the idea that identifiers
    that survive (directly) into the currently active scope are
    required by gcc to be identifiers for objects (of automatic
    storage duration).
    Tim Rentsch, Jul 6, 2013
    #17
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Noah
    Replies:
    5
    Views:
    942
  2. Chris Fogelklou
    Replies:
    36
    Views:
    1,335
    Chris Fogelklou
    Apr 20, 2004
  3. Ehud Shapira
    Replies:
    20
    Views:
    1,092
    Ehud Shapira
    Jun 30, 2007
  4. slocum
    Replies:
    3
    Views:
    495
    slocum
    Apr 11, 2008
  5. Isaac Won
    Replies:
    9
    Views:
    343
    Ulrich Eckhardt
    Mar 4, 2013
Loading...

Share This Page