Search code examples
c++language-lawyergotoinitializervariable-declaration

Is jumping over a variable initialization ill-formed or does it cause undefined behaviour?


Consider this code:

void foo()
{
    goto bar;
    int x = 0;
    bar: ;
}

GCC and Clang reject it, because the jump to bar: bypasses variable initialization. MSVC doesn't complain at all (except using x after bar: causes a warning).

We can do a similar thing with a switch:

void foo()
{
    switch (0)
    {
        int x = 0;
        case 0: ;
    }
}

Now all three compilers emit errors.

Are those snippets ill-formed? Or do they cause UB?

I used to think that both were ill-formed, but I can't find the revelant parts of the standard. [stmt.goto] doesn't say anything about this, and neither does [stmt.select].


Solution

  • It's ill-formed when the initialization is non-vacuous.

    [stmt.dcl]

    3 It is possible to transfer into a block, but not in a way that bypasses declarations with initialization (including ones in conditions and init-statements). A program that jumps from a point where a variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has vacuous initialization ([basic.life]). In such a case, the variables with vacuous initialization are constructed in the order of their declaration.

    The initializer makes the initialization non-vacuous. To contrast, this

    void foo()
    {
        goto bar;
        int x; // no initializer
        bar: ;
    }
    

    would be well-formed. Though the usual caveats about using x with an indeterminate value would apply.