Mayukh Sarkar
Mayukh Sarkar

Reputation: 2625

Is goto from outside a block past an initialized variable declaration guaranteed to give a compile error?

I have some simple C++ code:

#include <iostream>
int main(){
   {
     int a = 10;
     tag:
     std::cout << a << std::endl;
    }
     goto tag;
    return 0;
 }

Now I know it is not a good idea to use goto and if I jump with goto to some other scope, I will get compile error. I have tried this and it is naturally giving me a compile error which is obvious. But my question is whether there is any way for which this may get into some infinite loop

I am asking this question because of this question

Upvotes: 1

Views: 329

Answers (2)

Jonathan Leffler
Jonathan Leffler

Reputation: 754030

I note that the code in the question is C++ code and not C code. However, the question is dual-tagged with C and C++, which is irksome since the rules for C and C++ are different.

The code fails to compile in C++ but equivalent code compiles in C

The C++ code in the question should not compile. Analogous code written in C should compile, but the net result is an infinite loop.

C++11

In ISO/IEC 14882:2011 (the C++11 standard; I don't have an official copy of the 2014 standard to report on), it says:

6.6.4 The goto statement [stmt.goto]

¶1 The goto statement unconditionally transfers control to the statement labeled by the identifier. The identifier shall be a label (6.1) located in the current function.

6.7 Declaration statement [stmt.dcl]

¶1 A declaration statement introduces one or more new identifiers into a block; it has the form declaration-statement: block-declaration If an identifier introduced by a declaration was previously declared in an outer block, the outer declaration is hidden for the remainder of the block, after which it resumes its force.

¶2 Variables with automatic storage duration (3.7.3) are initialized each time their declaration-statement is executed. Variables with automatic storage duration declared in the block are destroyed on exit from the block (6.6).

¶3 It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps87 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 scalar type, class type with a trivial default constructor and a trivial destructor, a cv-qualified version of one of these types, or an array of one of the preceding types and is declared without an initializer (8.5).

87) The transfer from the condition of a switch statement to a case label is considered a jump in this respect.

Although a plain int is a scalar type, the jump bypasses the initialization and so is not allowed.

C11

In ISO/IEC 9899:2011 (the C11 standard), it says:

6.8.6.1 The goto statement

Constraints
¶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.

Semantics
¶2 A goto statement causes an unconditional jump to the statement prefixed by the named label in the enclosing function.

Note that constraint violations require a diagnostic. Violations of rules in semantics sections do not require a diagnostic.

And in Annex I (Common Warnings), which is an informative annex and not a normative one, it says:

— A block with initialization of an object that has automatic storage duration is jumped into (6.2.4).

And

6.2.4 Storage durations of objects

¶5 An object whose identifier is declared with no linkage and without the storage-class specifier static has automatic storage duration, as do some compound literals. The result of attempting to indirectly access an object with automatic storage duration from a thread other than the one with which the object is associated is implementation-defined.

¶6 For such an object that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way. (Entering an enclosed block or calling a function suspends, but does not end, execution of the current block.) If the block is entered recursively, a new instance of the object is created each time. The initial value of the object is indeterminate. If an initialization is specified for the object, it is performed each time the declaration or compound literal is reached in the execution of the block; otherwise, the value becomes indeterminate each time the declaration is reached.

¶7 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.35) If the scope is entered recursively, a new instance of the object is created each time. The initial value of the object is indeterminate.

35) Leaving the innermost block containing the declaration, or jumping to a point in that block or an embedded block prior to the declaration, leaves the scope of the declaration.

Note that there is no variably modified type (no VLA or variable length array) in the code in the question. Standard C++ does not support the concept of VLAs (though the GNU C++ compiler does allow them as an extension).

Code (goto1.c):

#include <stdio.h>
int main(void)
{
    {
        int a = 10;
tag:
        printf("%d\n", a);
    }
    goto tag;
    return 0;
}

Sample compilation:

$ gcc -std=c11 -O3 -g -Wall -Wextra -Werror goto1.c -o goto1
$

Those are fairly stringent warning options, and GCC utters not a peep — which is permissible behaviour given what the C standard says.

Upvotes: 5

Mad Physicist
Mad Physicist

Reputation: 114330

As the first comment to the question you mention says, the behavior is undefined. That basically means every compiler is free to interpret your code however it wants. Clearly, your compiler sees the problem and throws an error, while a different compiler may allow the code to compile, especially if it's internal representation of scope allows the loop to happen.

Upvotes: 0

Related Questions