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

2

18

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].

Verily answered 27/1, 2020 at 12:26 Comment(5)
Issue would be more trivial if you use x after the jump.Gros
not the standard, but here one can find some information on it: en.cppreference.com/w/cpp/language/goto in particular: "If transfer of control enters the scope of any automatic variables (e.g. by jumping forward over a declaration statement), the program is ill-formed (cannot be compiled), unless ..."Cosmo
Add the /permissive- flag to MSVC and it will complain as well. I don't know though whether MSVC's behavior without that flag is well-defined (I would assume so, otherwise why would they allow it?).Fantinlatour
@Fantinlatour "otherwise why would they allow it" Possibly for backward compatibity, or because they don't care about the standard too much. All major compilers don't conform to the standard under default settings.Verily
https://mcmap.net/q/24147/-can-goto-jump-across-functions-without-destructors-being-calledRileyrilievo
P
21

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.

Persona answered 27/1, 2020 at 12:32 Comment(2)
don't variable declarations have to be the first thing in a scope anyway?Beefcake
@Beefcake - C89 required it. C++ never did, and neither does modern C anymore.Persona
S
4

From goto statement:

If transfer of control enters the scope of any automatic variables (e.g. by jumping forward over a declaration statement), the program is ill-formed (cannot be compiled), unless all variables whose scope is entered have

  1. scalar types declared without initializers
  2. class types with trivial default constructors and trivial destructors declared without initializers
  3. cv-qualified versions of one of the above
  4. arrays of one of the above
Synonym answered 27/1, 2020 at 12:37 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.