KhronosGroup / GLSL

GLSL Shading Language Specification and Extensions
Other
347 stars 101 forks source link

Clarify GLSL for-loop scoping rules #226

Open johnstiles-google opened 10 months ago

johnstiles-google commented 10 months ago

The following GLSL code compiles in every GLSL implementation I have immediate access to: glslang, WebGL and Apple GLSL.

void main(void)
{
    int y;
    for (int x=0; x<10; ++x) int y;
}

I am trying to understand if this is intentional. The docs (6.3) have the following to say about for-loop scoping: "For both for and while loops, the sub-statement does not introduce a new scope for variable names."

There is no braced-block to introduce a new scope, and the docs explicitly state that the for-loop body does not implicitly introduce a scope.

I believe the answer is that the for-statement itself introduces a scope, since the variable int x=0 needs to disappear at the end of the for-statement. We can get additional evidence of this, because the following program also compiles:

void main(void)
{
    int x;
    for (int x=0; x<10; ++x) {}
}

However, the docs don't explain this rule anywhere. The statement "For both for and while loops, the sub-statement does not introduce a new scope for variable names" should be clarified to explain that the for-statement itself introduces the scope, and the sub-statement inherits that same scope even if braces appear (which would normally introduce a new deeper scope).

johnstiles-google commented 10 months ago

The docs do say "Variables declared in init-expression or condition-expression are only in scope until the end of the sub-statement of the for loop." but don't indicate that the for-statement itself actually introduces a new scope, only that the sub-statement does not introduce one.

Interestingly, the grammar includes statement_no_new_scope to cover this case, but doesn't clearly indicate where scopes are introduced.

johnstiles-google commented 10 months ago

I also discovered Section 4.2 states: "If (a variable) is declared in a while test or a for statement, then it is scoped to the end of the following sub-statement." This is a great clue but it doesn't actually clarify that for-statements are scopes.

In particular, we can demonstrate that in glslang, for-statements are scopes even when they do not declare any variables at all:

void main() {
    int x=1; for (;;) int x=2;
}

This compiles in glslang.