Search code examples
cscopegoto

Using goto to jump to inner or sibling scope


Is it allowed to jump to a label that's inside an inner scope or a sibling scope? If so, is it allowed to use variables declared in that scope?

Consider this code:

int cond(void);
void use(int);

void foo() 
{
    {
        int y = 2;
        label:
        use(y);
    }

    {
        int z = 3;
        use(z);

        /* jump to sibling scope: */
        if(cond()) goto label;
    }

    /* jump to inner scope: */
    if(cond()) goto label;
}

Are these gotos legal?

If so, is y guaranteed to exist when I jump to label and to hold the last value assigned to it (2)?

Or is the compiler allowed to assume y won't be used after it goes out of scope, which means a single memory location may be used for both y and z?

If this code's behavior is undefined, how can I get GCC to emit a warning about it?


Solution

  • From the C99 standard (emphasis mine):

    6.2.4 Storage durations of objects

    [6] For such an object that does have a variable length array type, its lifetime extends from the declaration of the object until execution of the program leaves the scope of the declaration. ... If the scope is entered recursively, a new instance of the object is created each time. The initial value of the object is indeterminate.

    6.8.6.1 The goto statement

    [1] The identifier in a goto statement shall name a label located somewhere in the enclosing function. A goto statement shall not jump from outside the scope of an identifier having a variably modified type to inside the scope of that identifier.

    [4] ... A goto statement is not allowed to jump past any declarations of objects with variably modified types.

    Conclusion

    1. y is not a variably modified type, so, according to the standard, the jumps are legal.

    2. y is guaranteed to exist, however, the jumps skip the initialization (y = 2), so the value of y is indeterminate.

    3. You can use -Wjump-misses-init to get GCC to emit a warning like the following:

      warning: jump skips variable initialization [-Wjump-misses-init]


    In C++, the jumps are not legal, C++ does not allow to skip the initialization of y.