From 27b72e42c3d5a160b098b8d841f56a74cb11383b Mon Sep 17 00:00:00 2001
From: John Kessenich <cepheus@frii.com>
Date: Mon, 14 Oct 2013 22:42:16 +0000
Subject: [PATCH] Implement ES 2.0 (version 100) limitations for non-inductive
 loop detection and array indexes needing "constant-index-expressions"
 (inductive variables and constant expressions).

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@23478 e7fa87d3-cd2b-0410-9028-fcbf551c1848
---
 Test/100Limits.vert                           |  55 +-
 Test/baseResults/100Limits.vert.out           | 600 ++++++++++++------
 Test/baseResults/100LimitsConf.vert.out       |  24 +-
 glslang.vcxproj                               |   1 +
 glslang.vcxproj.filters                       |   3 +
 glslang/Include/intermediate.h                |  25 +-
 glslang/MachineIndependent/Constant.cpp       |   4 +-
 glslang/MachineIndependent/Intermediate.cpp   |   6 +-
 glslang/MachineIndependent/Makefile           |   3 +-
 glslang/MachineIndependent/ParseHelper.cpp    | 153 +++++
 glslang/MachineIndependent/ParseHelper.h      |   9 +
 glslang/MachineIndependent/glslang.y          |   8 +-
 glslang/MachineIndependent/limits.cpp         | 199 ++++++
 .../MachineIndependent/localintermediate.h    |   4 +-
 glslang/MachineIndependent/parseConst.cpp     |   4 +-
 15 files changed, 857 insertions(+), 241 deletions(-)
 create mode 100644 glslang/MachineIndependent/limits.cpp

diff --git a/Test/100Limits.vert b/Test/100Limits.vert
index 7ed1ef820..d23b7e898 100644
--- a/Test/100Limits.vert
+++ b/Test/100Limits.vert
@@ -14,32 +14,46 @@ const vec3 v3 = vec3(2.0);
 
 void foo(inout float a) {}
 
+int bar()
+{
+    return 1;
+}
+
 void main()
 {
     while (ga < gb) { }
 
     do { } while (false);
-    
-    for (     ga = 0;              ;         );
-    for ( bool a = false;          ;         );
-    for (float a = 0.0; a == sin(f);         );
-    for (  int a = 0;       a  < 10;   a *= 2);
-    for (  int a = 0;       a <= 20;      ++a)  --a;
+
+    for (           ;              ;         );           // ERROR
+    for (           ;        ga==gb;         );           // ERROR
+    for (           ;              ;      f++);           // ERROR
+    for (     ga = 0;              ;         );           // ERROR
+    for ( bool a = false;          ;         );           // ERROR
+    for (float a = 0.0; a == sin(f);         );           // ERROR
+    for (  int a = 0;       a  < 10;   a *= 2);           // ERROR
+    for (  int a = 0;       a <= 20;      a++)  --a;      // ERROR
+    for (  int a = 0;       a <= 20;      a++)  { if (ga==0) a = 4; } // ERROR
     for (float a = 0.0;   a <= 20.0; a += 2.0);
-    for (float a = 0.0;   a <= 20.0; a += 2.0) foo(a);
+    for (float a = 0.0;   a != 20.0; a -= 2.0)  { if (ga==0) ga = 4; }
+    for (float a = 0.0;   a == 20.0;      a--) for (float a = 0.0;   a == 20.0;      a--);  // two different 'a's, everything okay
+    for (float a = 0.0;   a <= 20.0; a += 2.0);
+    for (float a = 0.0;   a <= 20.0; a += 2.0);
+    for (float a = 0.0;   a > 2.0 * 20.0; a += v3.y);
+    for (float a = 0.0;   a >= 20.0; a += 2.0) foo(a);    // ERROR
 
     int ia[9];
 
-    fsa[ga];
+    fsa[ga];  // ERROR
     fua[ga];
-    am3[ga];
-    av2[ga];
-    va[ga];
-    m2[ga];
-    v3[ga];
-    ia[ga];
-
-    for (  int a = 3; a >= 0; --a) {
+    am3[ga];  // ERROR
+    av2[ga];  // ERROR
+    va[2+ga]; // ERROR
+    m2[ga];   // ERROR
+    v3[ga/2]; // ERROR
+    ia[ga];   // ERROR
+
+    for (int a = 3; a >= 0; a--) {
         fsa[a];
         fua[a+2];
         am3[3*a];
@@ -48,6 +62,15 @@ void main()
         m2[a/2];
         v3[a];
         ia[a];
+        ia[bar()];  // ERROR
     }
 
+    fsa[2];
+    fua[3];
+    am3[2];
+    av2[1];
+    va[1];
+    m2[1];
+    v3[1];
+    ia[3];
 }
diff --git a/Test/baseResults/100Limits.vert.out b/Test/baseResults/100Limits.vert.out
index fe68fd592..4ee83d137 100644
--- a/Test/baseResults/100Limits.vert.out
+++ b/Test/baseResults/100Limits.vert.out
@@ -2,218 +2,424 @@
 0:15  Function Definition: foo(f1; (void)
 0:15    Function Parameters: 
 0:15      'a' (inout highp float)
-0:17  Function Definition: main( (void)
+0:17  Function Definition: bar( (highp int)
 0:17    Function Parameters: 
 0:19    Sequence
-0:19      Loop with condition tested first
-0:19        Loop Condition
-0:19        Compare Less Than (bool)
-0:19          'ga' (highp int)
-0:19          'gb' (highp int)
-0:19        No loop body
-0:21      Loop with condition not tested first
-0:21        Loop Condition
-0:21        Constant:
-0:21          false (const bool)
-0:21        No loop body
-0:23      Sequence
-0:23        move second child to first child (highp int)
-0:23          'ga' (highp int)
-0:23          Constant:
-0:23            0 (const int)
-0:23        Loop with condition tested first
-0:23          No loop condition
-0:23          No loop body
-0:24      Sequence
-0:24        Sequence
-0:24          move second child to first child (bool)
-0:24            'a' (bool)
-0:24            Constant:
-0:24              false (const bool)
-0:24        Loop with condition tested first
-0:24          No loop condition
-0:24          No loop body
-0:25      Sequence
-0:25        Sequence
-0:25          move second child to first child (highp float)
-0:25            'a' (highp float)
-0:25            Constant:
-0:25              0.000000
-0:25        Loop with condition tested first
-0:25          Loop Condition
-0:25          Compare Equal (bool)
-0:25            'a' (highp float)
-0:25            sine (highp float)
-0:25              'f' (highp float)
-0:25          No loop body
-0:26      Sequence
-0:26        Sequence
-0:26          move second child to first child (highp int)
-0:26            'a' (highp int)
-0:26            Constant:
-0:26              0 (const int)
-0:26        Loop with condition tested first
-0:26          Loop Condition
-0:26          Compare Less Than (bool)
-0:26            'a' (highp int)
-0:26            Constant:
-0:26              10 (const int)
-0:26          No loop body
-0:26          Loop Terminal Expression
-0:26          multiply second child into first child (highp int)
-0:26            'a' (highp int)
-0:26            Constant:
-0:26              2 (const int)
-0:27      Sequence
-0:27        Sequence
-0:27          move second child to first child (highp int)
-0:27            'a' (highp int)
-0:27            Constant:
-0:27              0 (const int)
-0:27        Loop with condition tested first
-0:27          Loop Condition
-0:27          Compare Less Than or Equal (bool)
-0:27            'a' (highp int)
-0:27            Constant:
-0:27              20 (const int)
-0:27          Loop Body
-0:27          Pre-Decrement (highp int)
-0:27            'a' (highp int)
-0:27          Loop Terminal Expression
-0:27          Pre-Increment (highp int)
-0:27            'a' (highp int)
+0:19      Branch: Return with expression
+0:19        Constant:
+0:19          1 (const int)
+0:22  Function Definition: main( (void)
+0:22    Function Parameters: 
+0:24    Sequence
+0:24      Loop with condition tested first
+0:24        Loop Condition
+0:24        Compare Less Than (bool)
+0:24          'ga' (highp int)
+0:24          'gb' (highp int)
+0:24        No loop body
+0:26      Loop with condition not tested first
+0:26        Loop Condition
+0:26        Constant:
+0:26          false (const bool)
+0:26        No loop body
 0:28      Sequence
-0:28        Sequence
-0:28          move second child to first child (highp float)
-0:28            'a' (highp float)
-0:28            Constant:
-0:28              0.000000
 0:28        Loop with condition tested first
-0:28          Loop Condition
-0:28          Compare Less Than or Equal (bool)
-0:28            'a' (highp float)
-0:28            Constant:
-0:28              20.000000
+0:28          No loop condition
 0:28          No loop body
-0:28          Loop Terminal Expression
-0:28          add second child into first child (highp float)
-0:28            'a' (highp float)
-0:28            Constant:
-0:28              2.000000
 0:29      Sequence
-0:29        Sequence
-0:29          move second child to first child (highp float)
-0:29            'a' (highp float)
-0:29            Constant:
-0:29              0.000000
 0:29        Loop with condition tested first
 0:29          Loop Condition
-0:29          Compare Less Than or Equal (bool)
-0:29            'a' (highp float)
-0:29            Constant:
-0:29              20.000000
-0:29          Loop Body
-0:29          Function Call: foo(f1; (void)
-0:29            'a' (highp float)
-0:29          Loop Terminal Expression
-0:29          add second child into first child (highp float)
-0:29            'a' (highp float)
-0:29            Constant:
-0:29              2.000000
-0:33      indirect index (uniform lowp sampler2D)
-0:33        'fsa' (uniform 3-element array of lowp sampler2D)
-0:33        'ga' (highp int)
-0:34      indirect index (uniform highp float)
-0:34        'fua' (uniform 10-element array of highp float)
-0:34        'ga' (highp int)
-0:35      indirect index (in highp 3-component vector of float)
-0:35        'am3' (in highp 3X3 matrix of float)
-0:35        'ga' (highp int)
-0:36      indirect index (in highp float)
-0:36        'av2' (in highp 2-component vector of float)
-0:36        'ga' (highp int)
-0:37      indirect index (smooth out highp 4-component vector of float)
-0:37        'va' (smooth out 4-element array of highp 4-component vector of float)
-0:37        'ga' (highp int)
-0:38      indirect index (const highp 2-component vector of float)
-0:38        Constant:
-0:38          1.000000
-0:38          0.000000
-0:38          0.000000
-0:38          1.000000
-0:38        'ga' (highp int)
-0:39      indirect index (const highp float)
-0:39        Constant:
-0:39          2.000000
-0:39          2.000000
-0:39          2.000000
-0:39        'ga' (highp int)
-0:40      indirect index (highp int)
-0:40        'ia' (9-element array of highp int)
-0:40        'ga' (highp int)
+0:29          Compare Equal (bool)
+0:29            'ga' (highp int)
+0:29            'gb' (highp int)
+0:29          No loop body
+0:30      Sequence
+0:30        Loop with condition tested first
+0:30          No loop condition
+0:30          No loop body
+0:30          Loop Terminal Expression
+0:30          Post-Increment (highp float)
+0:30            'f' (highp float)
+0:31      Sequence
+0:31        move second child to first child (highp int)
+0:31          'ga' (highp int)
+0:31          Constant:
+0:31            0 (const int)
+0:31        Loop with condition tested first
+0:31          No loop condition
+0:31          No loop body
+0:32      Sequence
+0:32        Sequence
+0:32          move second child to first child (bool)
+0:32            'a' (bool)
+0:32            Constant:
+0:32              false (const bool)
+0:32        Loop with condition tested first
+0:32          No loop condition
+0:32          No loop body
+0:33      Sequence
+0:33        Sequence
+0:33          move second child to first child (highp float)
+0:33            'a' (highp float)
+0:33            Constant:
+0:33              0.000000
+0:33        Loop with condition tested first
+0:33          Loop Condition
+0:33          Compare Equal (bool)
+0:33            'a' (highp float)
+0:33            sine (highp float)
+0:33              'f' (highp float)
+0:33          No loop body
+0:34      Sequence
+0:34        Sequence
+0:34          move second child to first child (highp int)
+0:34            'a' (highp int)
+0:34            Constant:
+0:34              0 (const int)
+0:34        Loop with condition tested first
+0:34          Loop Condition
+0:34          Compare Less Than (bool)
+0:34            'a' (highp int)
+0:34            Constant:
+0:34              10 (const int)
+0:34          No loop body
+0:34          Loop Terminal Expression
+0:34          multiply second child into first child (highp int)
+0:34            'a' (highp int)
+0:34            Constant:
+0:34              2 (const int)
+0:35      Sequence
+0:35        Sequence
+0:35          move second child to first child (highp int)
+0:35            'a' (highp int)
+0:35            Constant:
+0:35              0 (const int)
+0:35        Loop with condition tested first
+0:35          Loop Condition
+0:35          Compare Less Than or Equal (bool)
+0:35            'a' (highp int)
+0:35            Constant:
+0:35              20 (const int)
+0:35          Loop Body
+0:35          Pre-Decrement (highp int)
+0:35            'a' (highp int)
+0:35          Loop Terminal Expression
+0:35          Post-Increment (highp int)
+0:35            'a' (highp int)
+0:36      Sequence
+0:36        Sequence
+0:36          move second child to first child (highp int)
+0:36            'a' (highp int)
+0:36            Constant:
+0:36              0 (const int)
+0:36        Loop with condition tested first
+0:36          Loop Condition
+0:36          Compare Less Than or Equal (bool)
+0:36            'a' (highp int)
+0:36            Constant:
+0:36              20 (const int)
+0:36          Loop Body
+0:36          Sequence
+0:36            Test condition and select (void)
+0:36              Condition
+0:36              Compare Equal (bool)
+0:36                'ga' (highp int)
+0:36                Constant:
+0:36                  0 (const int)
+0:36              true case
+0:36              move second child to first child (highp int)
+0:36                'a' (highp int)
+0:36                Constant:
+0:36                  4 (const int)
+0:36          Loop Terminal Expression
+0:36          Post-Increment (highp int)
+0:36            'a' (highp int)
+0:37      Sequence
+0:37        Sequence
+0:37          move second child to first child (highp float)
+0:37            'a' (highp float)
+0:37            Constant:
+0:37              0.000000
+0:37        Loop with condition tested first
+0:37          Loop Condition
+0:37          Compare Less Than or Equal (bool)
+0:37            'a' (highp float)
+0:37            Constant:
+0:37              20.000000
+0:37          No loop body
+0:37          Loop Terminal Expression
+0:37          add second child into first child (highp float)
+0:37            'a' (highp float)
+0:37            Constant:
+0:37              2.000000
+0:38      Sequence
+0:38        Sequence
+0:38          move second child to first child (highp float)
+0:38            'a' (highp float)
+0:38            Constant:
+0:38              0.000000
+0:38        Loop with condition tested first
+0:38          Loop Condition
+0:38          Compare Not Equal (bool)
+0:38            'a' (highp float)
+0:38            Constant:
+0:38              20.000000
+0:38          Loop Body
+0:38          Sequence
+0:38            Test condition and select (void)
+0:38              Condition
+0:38              Compare Equal (bool)
+0:38                'ga' (highp int)
+0:38                Constant:
+0:38                  0 (const int)
+0:38              true case
+0:38              move second child to first child (highp int)
+0:38                'ga' (highp int)
+0:38                Constant:
+0:38                  4 (const int)
+0:38          Loop Terminal Expression
+0:38          subtract second child into first child (highp float)
+0:38            'a' (highp float)
+0:38            Constant:
+0:38              2.000000
+0:39      Sequence
+0:39        Sequence
+0:39          move second child to first child (highp float)
+0:39            'a' (highp float)
+0:39            Constant:
+0:39              0.000000
+0:39        Loop with condition tested first
+0:39          Loop Condition
+0:39          Compare Equal (bool)
+0:39            'a' (highp float)
+0:39            Constant:
+0:39              20.000000
+0:39          Loop Body
+0:39          Sequence
+0:39            Sequence
+0:39              move second child to first child (highp float)
+0:39                'a' (highp float)
+0:39                Constant:
+0:39                  0.000000
+0:39            Loop with condition tested first
+0:39              Loop Condition
+0:39              Compare Equal (bool)
+0:39                'a' (highp float)
+0:39                Constant:
+0:39                  20.000000
+0:39              No loop body
+0:39              Loop Terminal Expression
+0:39              Post-Decrement (highp float)
+0:39                'a' (highp float)
+0:39          Loop Terminal Expression
+0:39          Post-Decrement (highp float)
+0:39            'a' (highp float)
+0:40      Sequence
+0:40        Sequence
+0:40          move second child to first child (highp float)
+0:40            'a' (highp float)
+0:40            Constant:
+0:40              0.000000
+0:40        Loop with condition tested first
+0:40          Loop Condition
+0:40          Compare Less Than or Equal (bool)
+0:40            'a' (highp float)
+0:40            Constant:
+0:40              20.000000
+0:40          No loop body
+0:40          Loop Terminal Expression
+0:40          add second child into first child (highp float)
+0:40            'a' (highp float)
+0:40            Constant:
+0:40              2.000000
+0:41      Sequence
+0:41        Sequence
+0:41          move second child to first child (highp float)
+0:41            'a' (highp float)
+0:41            Constant:
+0:41              0.000000
+0:41        Loop with condition tested first
+0:41          Loop Condition
+0:41          Compare Less Than or Equal (bool)
+0:41            'a' (highp float)
+0:41            Constant:
+0:41              20.000000
+0:41          No loop body
+0:41          Loop Terminal Expression
+0:41          add second child into first child (highp float)
+0:41            'a' (highp float)
+0:41            Constant:
+0:41              2.000000
 0:42      Sequence
 0:42        Sequence
-0:42          move second child to first child (highp int)
-0:42            'a' (highp int)
+0:42          move second child to first child (highp float)
+0:42            'a' (highp float)
 0:42            Constant:
-0:42              3 (const int)
+0:42              0.000000
 0:42        Loop with condition tested first
 0:42          Loop Condition
-0:42          Compare Greater Than or Equal (bool)
-0:42            'a' (highp int)
+0:42          Compare Greater Than (bool)
+0:42            'a' (highp float)
 0:42            Constant:
-0:42              0 (const int)
-0:42          Loop Body
-0:43          Sequence
-0:43            indirect index (uniform lowp sampler2D)
-0:43              'fsa' (uniform 3-element array of lowp sampler2D)
-0:43              'a' (highp int)
-0:44            indirect index (uniform highp float)
-0:44              'fua' (uniform 10-element array of highp float)
-0:44              add (highp int)
-0:44                'a' (highp int)
-0:44                Constant:
-0:44                  2 (const int)
-0:45            indirect index (in highp 3-component vector of float)
-0:45              'am3' (in highp 3X3 matrix of float)
-0:45              component-wise multiply (highp int)
-0:45                Constant:
-0:45                  3 (const int)
-0:45                'a' (highp int)
-0:46            indirect index (in highp float)
-0:46              'av2' (in highp 2-component vector of float)
-0:46              component-wise multiply (highp int)
-0:46                Constant:
-0:46                  3 (const int)
-0:46                'a' (highp int)
-0:47            indirect index (smooth out highp 4-component vector of float)
-0:47              'va' (smooth out 4-element array of highp 4-component vector of float)
-0:47              subtract (highp int)
-0:47                'a' (highp int)
-0:47                Constant:
-0:47                  1 (const int)
-0:48            indirect index (const highp 2-component vector of float)
-0:48              Constant:
-0:48                1.000000
-0:48                0.000000
-0:48                0.000000
-0:48                1.000000
-0:48              divide (highp int)
-0:48                'a' (highp int)
-0:48                Constant:
-0:48                  2 (const int)
-0:49            indirect index (const highp float)
-0:49              Constant:
-0:49                2.000000
-0:49                2.000000
-0:49                2.000000
-0:49              'a' (highp int)
-0:50            indirect index (highp int)
-0:50              'ia' (9-element array of highp int)
-0:50              'a' (highp int)
+0:42              40.000000
+0:42          No loop body
 0:42          Loop Terminal Expression
-0:42          Pre-Decrement (highp int)
-0:42            'a' (highp int)
+0:42          add second child into first child (highp float)
+0:42            'a' (highp float)
+0:42            Constant:
+0:42              2.000000
+0:43      Sequence
+0:43        Sequence
+0:43          move second child to first child (highp float)
+0:43            'a' (highp float)
+0:43            Constant:
+0:43              0.000000
+0:43        Loop with condition tested first
+0:43          Loop Condition
+0:43          Compare Greater Than or Equal (bool)
+0:43            'a' (highp float)
+0:43            Constant:
+0:43              20.000000
+0:43          Loop Body
+0:43          Function Call: foo(f1; (void)
+0:43            'a' (highp float)
+0:43          Loop Terminal Expression
+0:43          add second child into first child (highp float)
+0:43            'a' (highp float)
+0:43            Constant:
+0:43              2.000000
+0:47      indirect index (uniform lowp sampler2D)
+0:47        'fsa' (uniform 3-element array of lowp sampler2D)
+0:47        'ga' (highp int)
+0:48      indirect index (uniform highp float)
+0:48        'fua' (uniform 10-element array of highp float)
+0:48        'ga' (highp int)
+0:49      indirect index (in highp 3-component vector of float)
+0:49        'am3' (in highp 3X3 matrix of float)
+0:49        'ga' (highp int)
+0:50      indirect index (in highp float)
+0:50        'av2' (in highp 2-component vector of float)
+0:50        'ga' (highp int)
+0:51      indirect index (smooth out highp 4-component vector of float)
+0:51        'va' (smooth out 4-element array of highp 4-component vector of float)
+0:51        add (highp int)
+0:51          Constant:
+0:51            2 (const int)
+0:51          'ga' (highp int)
+0:52      indirect index (const highp 2-component vector of float)
+0:52        Constant:
+0:52          1.000000
+0:52          0.000000
+0:52          0.000000
+0:52          1.000000
+0:52        'ga' (highp int)
+0:53      indirect index (const highp float)
+0:53        Constant:
+0:53          2.000000
+0:53          2.000000
+0:53          2.000000
+0:53        divide (highp int)
+0:53          'ga' (highp int)
+0:53          Constant:
+0:53            2 (const int)
+0:54      indirect index (highp int)
+0:54        'ia' (9-element array of highp int)
+0:54        'ga' (highp int)
+0:56      Sequence
+0:56        Sequence
+0:56          move second child to first child (highp int)
+0:56            'a' (highp int)
+0:56            Constant:
+0:56              3 (const int)
+0:56        Loop with condition tested first
+0:56          Loop Condition
+0:56          Compare Greater Than or Equal (bool)
+0:56            'a' (highp int)
+0:56            Constant:
+0:56              0 (const int)
+0:56          Loop Body
+0:57          Sequence
+0:57            indirect index (uniform lowp sampler2D)
+0:57              'fsa' (uniform 3-element array of lowp sampler2D)
+0:57              'a' (highp int)
+0:58            indirect index (uniform highp float)
+0:58              'fua' (uniform 10-element array of highp float)
+0:58              add (highp int)
+0:58                'a' (highp int)
+0:58                Constant:
+0:58                  2 (const int)
+0:59            indirect index (in highp 3-component vector of float)
+0:59              'am3' (in highp 3X3 matrix of float)
+0:59              component-wise multiply (highp int)
+0:59                Constant:
+0:59                  3 (const int)
+0:59                'a' (highp int)
+0:60            indirect index (in highp float)
+0:60              'av2' (in highp 2-component vector of float)
+0:60              component-wise multiply (highp int)
+0:60                Constant:
+0:60                  3 (const int)
+0:60                'a' (highp int)
+0:61            indirect index (smooth out highp 4-component vector of float)
+0:61              'va' (smooth out 4-element array of highp 4-component vector of float)
+0:61              subtract (highp int)
+0:61                'a' (highp int)
+0:61                Constant:
+0:61                  1 (const int)
+0:62            indirect index (const highp 2-component vector of float)
+0:62              Constant:
+0:62                1.000000
+0:62                0.000000
+0:62                0.000000
+0:62                1.000000
+0:62              divide (highp int)
+0:62                'a' (highp int)
+0:62                Constant:
+0:62                  2 (const int)
+0:63            indirect index (const highp float)
+0:63              Constant:
+0:63                2.000000
+0:63                2.000000
+0:63                2.000000
+0:63              'a' (highp int)
+0:64            indirect index (highp int)
+0:64              'ia' (9-element array of highp int)
+0:64              'a' (highp int)
+0:65            indirect index (highp int)
+0:65              'ia' (9-element array of highp int)
+0:65              Function Call: bar( (highp int)
+0:56          Loop Terminal Expression
+0:56          Post-Decrement (highp int)
+0:56            'a' (highp int)
+0:68      direct index (uniform lowp sampler2D)
+0:68        'fsa' (uniform 3-element array of lowp sampler2D)
+0:68        Constant:
+0:68          2 (const int)
+0:69      direct index (uniform highp float)
+0:69        'fua' (uniform 10-element array of highp float)
+0:69        Constant:
+0:69          3 (const int)
+0:70      direct index (in highp 3-component vector of float)
+0:70        'am3' (in highp 3X3 matrix of float)
+0:70        Constant:
+0:70          2 (const int)
+0:71      direct index (in highp float)
+0:71        'av2' (in highp 2-component vector of float)
+0:71        Constant:
+0:71          1 (const int)
+0:72      direct index (smooth out highp 4-component vector of float)
+0:72        'va' (smooth out 4-element array of highp 4-component vector of float)
+0:72        Constant:
+0:72          1 (const int)
+0:73      Constant:
+0:73        0.000000
+0:73        1.000000
+0:74      Constant:
+0:74        2.000000
+0:75      direct index (highp int)
+0:75        'ia' (9-element array of highp int)
+0:75        Constant:
+0:75          3 (const int)
 0:?   Linker Objects
 0:?     'ga' (highp int)
 0:?     'gb' (highp int)
diff --git a/Test/baseResults/100LimitsConf.vert.out b/Test/baseResults/100LimitsConf.vert.out
index 0d51c812d..1a87ea8e2 100644
--- a/Test/baseResults/100LimitsConf.vert.out
+++ b/Test/baseResults/100LimitsConf.vert.out
@@ -1,5 +1,23 @@
-ERROR: 0:19: 'limitation' : while loops not available 
-ERROR: 0:21: 'limitation' : do-while loops not available 
-ERROR: 2 compilation errors.  No code generated.
+ERROR: 0:24: 'limitation' : while loops not available 
+ERROR: 0:26: 'limitation' : do-while loops not available 
+ERROR: 0:28: 'limitations' : inductive-loop init-declaration requires the form "type-specifier loop-index = constant-expression" 
+ERROR: 0:29: 'limitations' : inductive-loop init-declaration requires the form "type-specifier loop-index = constant-expression" 
+ERROR: 0:30: 'limitations' : inductive-loop init-declaration requires the form "type-specifier loop-index = constant-expression" 
+ERROR: 0:31: 'limitations' : inductive-loop init-declaration requires the form "type-specifier loop-index = constant-expression" 
+ERROR: 0:32: 'limitations' : inductive loop requires a scalar 'int' or 'float' loop index 
+ERROR: 0:33: 'limitations' : inductive-loop condition requires the form "loop-index <comparison-op> constant-expression" 
+ERROR: 0:34: 'limitations' : inductive-loop termination requires the form "loop-index++, loop-index--, loop-index += constant-expression, or loop-index -= constant-expression" 
+ERROR: 0:35: 'limitations' : inductive loop index modified 
+ERROR: 0:36: 'limitations' : inductive loop index modified 
+ERROR: 0:43: 'limitations' : inductive loop index modified 
+ERROR: 0:47: 'limitations' : Non-constant-index-expression 
+ERROR: 0:49: 'limitations' : Non-constant-index-expression 
+ERROR: 0:50: 'limitations' : Non-constant-index-expression 
+ERROR: 0:51: 'limitations' : Non-constant-index-expression 
+ERROR: 0:52: 'limitations' : Non-constant-index-expression 
+ERROR: 0:53: 'limitations' : Non-constant-index-expression 
+ERROR: 0:54: 'limitations' : Non-constant-index-expression 
+ERROR: 0:65: 'limitations' : Non-constant-index-expression 
+ERROR: 20 compilation errors.  No code generated.
 
 
diff --git a/glslang.vcxproj b/glslang.vcxproj
index dd6f5bbcc..f54d85da8 100644
--- a/glslang.vcxproj
+++ b/glslang.vcxproj
@@ -156,6 +156,7 @@ xcopy /y $(IntDir)$(TargetName)$(TargetExt) Test</Command>
     </ClCompile>
     <ClCompile Include="glslang\MachineIndependent\InfoSink.cpp" />
     <ClCompile Include="glslang\MachineIndependent\Initialize.cpp" />
+    <ClCompile Include="glslang\MachineIndependent\limits.cpp" />
     <ClCompile Include="glslang\MachineIndependent\preprocessor\Pp.cpp" />
     <ClCompile Include="glslang\MachineIndependent\preprocessor\PpAtom.cpp" />
     <ClCompile Include="glslang\MachineIndependent\preprocessor\PpMemory.cpp" />
diff --git a/glslang.vcxproj.filters b/glslang.vcxproj.filters
index 8e98fe6e1..9f1274175 100644
--- a/glslang.vcxproj.filters
+++ b/glslang.vcxproj.filters
@@ -109,6 +109,9 @@
     <ClCompile Include="glslang\MachineIndependent\preprocessor\PpContext.cpp">
       <Filter>Machine Independent\Preprocessor</Filter>
     </ClCompile>
+    <ClCompile Include="glslang\MachineIndependent\limits.cpp">
+      <Filter>Machine Independent</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="glslang\MachineIndependent\Initialize.h">
diff --git a/glslang/Include/intermediate.h b/glslang/Include/intermediate.h
index 549ec8621..a1e012e38 100644
--- a/glslang/Include/intermediate.h
+++ b/glslang/Include/intermediate.h
@@ -316,6 +316,7 @@ enum TOperator {
 };
 
 class TIntermTraverser;
+class TIntermOperator;
 class TIntermAggregate;
 class TIntermUnary;
 class TIntermBinary;
@@ -342,16 +343,17 @@ public:
     virtual glslang::TSourceLoc getLoc() const { return loc; }
     virtual void setLoc(glslang::TSourceLoc l) { loc = l; }
     virtual void traverse(glslang::TIntermTraverser*) = 0;
-    virtual glslang::TIntermTyped*     getAsTyped()         { return 0; }
-    virtual glslang::TIntermConstantUnion*     getAsConstantUnion()         { return 0; }
-    virtual glslang::TIntermAggregate* getAsAggregate()     { return 0; }
-    virtual glslang::TIntermUnary*     getAsUnaryNode()     { return 0; }
-    virtual glslang::TIntermBinary*    getAsBinaryNode()    { return 0; }
-    virtual glslang::TIntermSelection* getAsSelectionNode() { return 0; }
-    virtual glslang::TIntermSwitch*    getAsSwitchNode()    { return 0; }
-    virtual glslang::TIntermMethod*    getAsMethodNode()    { return 0; }
-    virtual glslang::TIntermSymbol*    getAsSymbolNode()    { return 0; }
-    virtual glslang::TIntermBranch*    getAsBranchNode()    { return 0; }
+    virtual glslang::TIntermTyped*         getAsTyped()         { return 0; }
+    virtual glslang::TIntermOperator*      getAsOperator()      { return 0; }
+    virtual glslang::TIntermConstantUnion* getAsConstantUnion() { return 0; }
+    virtual glslang::TIntermAggregate*     getAsAggregate()     { return 0; }
+    virtual glslang::TIntermUnary*         getAsUnaryNode()     { return 0; }
+    virtual glslang::TIntermBinary*        getAsBinaryNode()    { return 0; }
+    virtual glslang::TIntermSelection*     getAsSelectionNode() { return 0; }
+    virtual glslang::TIntermSwitch*        getAsSwitchNode()    { return 0; }
+    virtual glslang::TIntermMethod*        getAsMethodNode()    { return 0; }
+    virtual glslang::TIntermSymbol*        getAsSymbolNode()    { return 0; }
+    virtual glslang::TIntermBranch*        getAsBranchNode()    { return 0; }
     virtual ~TIntermNode() { }
 protected:
     glslang::TSourceLoc loc;
@@ -478,7 +480,7 @@ public:
     TIntermConstantUnion(const TConstUnionArray& ua, const TType& t) : TIntermTyped(t), unionArray(ua) { }
     const TConstUnionArray& getConstArray() const { return unionArray; }
     virtual TIntermConstantUnion* getAsConstantUnion()  { return this; }
-    virtual void traverse(TIntermTraverser* );
+    virtual void traverse(TIntermTraverser*);
     virtual TIntermTyped* fold(TOperator, TIntermTyped*);
     virtual TIntermTyped* fold(TOperator, const TType&);
 protected:
@@ -490,6 +492,7 @@ protected:
 //
 class TIntermOperator : public TIntermTyped {
 public:
+    TIntermOperator* getAsOperator() { return this; }
     TOperator getOp() { return op; }
     bool modifiesState() const;
     bool isConstructor() const;
diff --git a/glslang/MachineIndependent/Constant.cpp b/glslang/MachineIndependent/Constant.cpp
index 218fe9430..3559a921e 100644
--- a/glslang/MachineIndependent/Constant.cpp
+++ b/glslang/MachineIndependent/Constant.cpp
@@ -713,9 +713,9 @@ TIntermTyped* TIntermediate::foldConstructor(TIntermAggregate* aggrNode)
 
     TConstUnionArray unionArray(aggrNode->getType().getObjectSize());
     if (aggrNode->getSequence().size() == 1)
-        error = parseConstTree(aggrNode->getLoc(), aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType(), true);
+        error = parseConstTree(aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType(), true);
     else
-        error = parseConstTree(aggrNode->getLoc(), aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType());
+        error = parseConstTree(aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType());
 
     if (error)
         return aggrNode;
diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp
index 9c1841438..0088dcdee 100644
--- a/glslang/MachineIndependent/Intermediate.cpp
+++ b/glslang/MachineIndependent/Intermediate.cpp
@@ -809,11 +809,11 @@ TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, TSourceLoc loc)
 //
 // Create loop nodes.
 //
-TIntermNode* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, TSourceLoc loc)
+TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, TSourceLoc loc)
 {
-    TIntermNode* node = new TIntermLoop(body, test, terminal, testFirst);
+    TIntermLoop* node = new TIntermLoop(body, test, terminal, testFirst);
     node->setLoc(loc);
-    
+
     return node;
 }
 
diff --git a/glslang/MachineIndependent/Makefile b/glslang/MachineIndependent/Makefile
index 2ed836504..1b6c40457 100644
--- a/glslang/MachineIndependent/Makefile
+++ b/glslang/MachineIndependent/Makefile
@@ -11,7 +11,7 @@ LIBCODEGEN=./../GenericCodeGen/libCodeGen.a
 OBJECTS= Initialize.o IntermTraverse.o \
 	Intermediate.o ParseHelper.o PoolAlloc.o QualifierAlive.o \
 	RemoveTree.o ShaderLang.o intermOut.o parseConst.o SymbolTable.o \
-	InfoSink.o Versions.o Constant.o Scan.o
+	InfoSink.o Versions.o Constant.o Scan.o limits.o
 
 SRCS= gen_glslang_tab.cpp Initialize.cpp IntermTraverse.cpp \
 	Intermediate.cpp ParseHelper.cpp PoolAlloc.cp QualifierAlive.cpp \
@@ -146,3 +146,4 @@ parseConst.o: ../Public/ShaderLang.h
 InfoSink.o: ../Include/InfoSink.h
 Versions.o: ParseHelper.h  Versions.h ../Include/ShHandle.h SymbolTable.h localintermediate.h
 Constant.o: localintermediate.h ../Include/intermediate.h ../Public/ShaderLang.h SymbolTable.h Versions.h
+limits.o:  ParseHelper.h
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index b0de06a9e..6fb2c8d0e 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -154,8 +154,17 @@ bool TParseContext::parseShaderStrings(TPpContext& ppContext, char* strings[], s
             return true;
     }
 
+    anyIndexLimits = ! limits.generalAttributeMatrixVectorIndexing ||
+                     ! limits.generalConstantMatrixVectorIndexing ||
+                     ! limits.generalSamplerIndexing ||
+                     ! limits.generalUniformIndexing ||
+                     ! limits.generalVariableIndexing ||
+                     ! limits.generalVaryingIndexing;
+
     yyparse((void*)this);
 
+    finalize();
+
     return numErrors == 0;
 }
 
@@ -510,6 +519,23 @@ TIntermTyped* TParseContext::handleBracketDereference(TSourceLoc loc, TIntermTyp
             newType.getQualifier().storage = EvqConst;
         newType.dereference();
         result->setType(newType);
+
+        if (anyIndexLimits) {
+            // for ES 2.0 (version 100) limitations for almost all index operations except vertex-shader uniforms
+            if ((! limits.generalSamplerIndexing && base->getBasicType() == EbtSampler) ||
+                (! limits.generalUniformIndexing && base->getQualifier().isUniform() && language != EShLangVertex) ||
+                (! limits.generalAttributeMatrixVectorIndexing && base->getQualifier().isPipeInput() && language == EShLangVertex && (base->getType().isMatrix() || base->getType().isVector())) ||
+                (! limits.generalConstantMatrixVectorIndexing && base->getAsConstantUnion()) ||
+                (! limits.generalVariableIndexing && ! base->getType().getQualifier().isUniform() && 
+                                                     ! base->getType().getQualifier().isPipeInput() && 
+                                                     ! base->getType().getQualifier().isPipeOutput() &&
+                                                       base->getType().getQualifier().storage != EvqConst) ||
+                (! limits.generalVaryingIndexing && (base->getType().getQualifier().isPipeInput() || 
+                                                     base->getType().getQualifier().isPipeOutput()))) {            
+                // it's too early to know what the inductive variables are, save it for post processing
+                needsIndexLimitationChecking.push_back(index);
+            }
+        }
     }
 
     return result;
@@ -1914,6 +1940,133 @@ void TParseContext::arrayObjectCheck(TSourceLoc loc, const TType& type, const ch
     }
 }
 
+//
+// See if this loop satisfies the limitations for ES 2.0 (version 100) for loops in Appendex A:
+//
+// "The loop index has type int or float.
+//
+// "The for statement has the form:
+//     for ( init-declaration ; condition ; expression ) 
+//     init-declaration has the form: type-specifier identifier = constant-expression
+//     condition has the form:  loop-index relational_operator constant-expression
+//         where relational_operator is one of: > >= < <= == or !=
+//     expression [sic] has one of the following forms:
+//         loop-index++
+//         loop-index--
+//         loop-index += constant-expression
+//         loop-index -= constant-expression
+//
+// The body is handled in an AST traversal.
+//
+void TParseContext::inductiveLoopCheck(TSourceLoc loc, TIntermNode* init, TIntermLoop* loop)
+{
+    // loop index init must exist and be a declaration, which shows up in the AST as an aggregate of size 1 of the declaration
+    bool badInit = false;
+    if (! init || ! init->getAsAggregate() || ! init->getAsAggregate()->getSequence().size() == 1)
+        badInit = true;
+    TIntermBinary* binaryInit;
+    if (! badInit) {
+        // get the declaration assignment
+        binaryInit = init->getAsAggregate()->getSequence()[0]->getAsBinaryNode();
+        if (! binaryInit)
+            badInit = true;
+    }
+    if (badInit) {
+        error(loc, "inductive-loop init-declaration requires the form \"type-specifier loop-index = constant-expression\"", "limitations", "");
+        return;
+    }
+
+    // loop index must be type int or float
+    if (! binaryInit->getType().isScalar() || (binaryInit->getBasicType() != EbtInt && binaryInit->getBasicType() != EbtFloat)) {
+        error(loc, "inductive loop requires a scalar 'int' or 'float' loop index", "limitations", "");
+        return;
+    }
+
+    // init is the form "loop-index = constant"
+    if (binaryInit->getOp() != EOpAssign || ! binaryInit->getLeft()->getAsSymbolNode() || ! binaryInit->getRight()->getAsConstantUnion()) {
+        error(loc, "inductive-loop init-declaration requires the form \"type-specifier loop-index = constant-expression\"", "limitations", "");
+        return;
+    }
+    
+    // get the unique id of the loop index
+    int loopIndex = binaryInit->getLeft()->getAsSymbolNode()->getId();
+    inductiveLoopIds.insert(loopIndex);
+    
+    // condition's form must be "loop-index relational-operator constant-expression"
+    bool badCond = ! loop->getTest();
+    if (! badCond) {
+        TIntermBinary* binaryCond = loop->getTest()->getAsBinaryNode();
+        badCond = ! binaryCond;
+        if (! badCond) {
+            switch (binaryCond->getOp()) {
+            case EOpGreaterThan:
+            case EOpGreaterThanEqual:
+            case EOpLessThan:
+            case EOpLessThanEqual:
+            case EOpEqual:
+            case EOpNotEqual:
+                break;
+            default:
+                badCond = true;
+            }
+        }
+        if (binaryCond && (! binaryCond->getLeft()->getAsSymbolNode() ||
+                           binaryCond->getLeft()->getAsSymbolNode()->getId() != loopIndex ||
+                           ! binaryCond->getRight()->getAsConstantUnion()))
+            badCond = true;
+    }
+    if (badCond) {
+        error(loc, "inductive-loop condition requires the form \"loop-index <comparison-op> constant-expression\"", "limitations", "");
+        return;
+    }
+
+    // loop-index++
+    // loop-index--
+    // loop-index += constant-expression
+    // loop-index -= constant-expression
+    bool badTerminal = ! loop->getTerminal();
+    if (! badTerminal) {
+        TIntermUnary* unaryTerminal = loop->getTerminal()->getAsUnaryNode();
+        TIntermBinary* binaryTerminal = loop->getTerminal()->getAsBinaryNode();
+        if (unaryTerminal || binaryTerminal) {
+            switch(loop->getTerminal()->getAsOperator()->getOp()) {
+            case EOpPostDecrement:
+            case EOpPostIncrement:
+            case EOpAddAssign:
+            case EOpSubAssign:
+                break;
+            default:
+                badTerminal = true;
+            }
+        } else
+            badTerminal = true;
+        if (binaryTerminal && (! binaryTerminal->getLeft()->getAsSymbolNode() ||
+                               binaryTerminal->getLeft()->getAsSymbolNode()->getId() != loopIndex ||
+                               ! binaryTerminal->getRight()->getAsConstantUnion()))
+            badTerminal = true;
+        if (unaryTerminal && (! unaryTerminal->getOperand()->getAsSymbolNode() ||
+                              unaryTerminal->getOperand()->getAsSymbolNode()->getId() != loopIndex))
+            badTerminal = true;
+    }
+    if (badTerminal) {
+        error(loc, "inductive-loop termination requires the form \"loop-index++, loop-index--, loop-index += constant-expression, or loop-index -= constant-expression\"", "limitations", "");
+        return;
+    }
+
+    // the body
+    inductiveLoopBodyCheck(loop->getBody(), loopIndex, symbolTable);
+}
+
+//
+// Do any additional error checking, etc., once we know the parsing is done.
+//
+void TParseContext::finalize()
+{
+    // Check on array indexes for ES 2.0 (version 100) limitations.
+    for (size_t i = 0; i < needsIndexLimitationChecking.size(); ++i)
+        constantIndexExpressionCheck(needsIndexLimitationChecking[i]);
+}
+
 //
 // Layout qualifier stuff.
 //
diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h
index 57b99b8d4..4e8d7d8c2 100644
--- a/glslang/MachineIndependent/ParseHelper.h
+++ b/glslang/MachineIndependent/ParseHelper.h
@@ -53,6 +53,8 @@ struct TPragma {
 class TScanContext;
 class TPpContext;
 
+typedef std::set<int> TIdSetType;
+
 //
 // The following are extra variables needed during parsing, grouped together so
 // they can be passed to the parser without needing a global.
@@ -116,6 +118,9 @@ public:
     void nestedBlockCheck(TSourceLoc);
     void nestedStructCheck(TSourceLoc);
     void arrayObjectCheck(TSourceLoc, const TType&, const char* op);
+    void inductiveLoopCheck(TSourceLoc, TIntermNode* init, TIntermLoop* loop);
+    void inductiveLoopBodyCheck(TIntermNode*, int loopIndexId, TSymbolTable&);
+    void constantIndexExpressionCheck(TIntermNode*);
 
     void setLayoutQualifier(TSourceLoc, TPublicType&, TString&);
     void setLayoutQualifier(TSourceLoc, TPublicType&, TString&, int);
@@ -167,6 +172,7 @@ protected:
     void declareArray(TSourceLoc, TString& identifier, const TType&, TSymbol*&, bool& newDeclaration);
     TIntermNode* executeInitializer(TSourceLoc, TString& identifier, TIntermTyped* initializer, TVariable* variable);
     TOperator mapTypeToConstructorOp(const TType&);
+    void finalize();
 
 public:
     //
@@ -213,6 +219,9 @@ protected:
     TQualifier globalInputDefaults;
     TQualifier globalOutputDefaults;
     TString currentCaller;
+    TIdSetType inductiveLoopIds;
+    bool anyIndexLimits;
+    TVector<TIntermTyped*> needsIndexLimitationChecking;
     // TODO: desktop functionality: track use of gl_FragDepth before redeclaration
 };
 
diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y
index 460742d21..e9a4b37c3 100644
--- a/glslang/MachineIndependent/glslang.y
+++ b/glslang/MachineIndependent/glslang.y
@@ -2278,10 +2278,10 @@ iteration_statement
       for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope {
         parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
         $$ = parseContext.intermediate.makeAggregate($4, $2.loc);
-        $$ = parseContext.intermediate.growAggregate(
-                $$,
-                parseContext.intermediate.addLoop($7, reinterpret_cast<TIntermTyped*>($5.node1), reinterpret_cast<TIntermTyped*>($5.node2), true, $1.loc),
-                $1.loc);
+        TIntermLoop* forLoop = parseContext.intermediate.addLoop($7, reinterpret_cast<TIntermTyped*>($5.node1), reinterpret_cast<TIntermTyped*>($5.node2), true, $1.loc);
+        if (! parseContext.limits.nonInductiveForLoops)
+            parseContext.inductiveLoopCheck($1.loc, $4, forLoop);
+        $$ = parseContext.intermediate.growAggregate($$, forLoop, $1.loc);
         $$->getAsAggregate()->setOperator(EOpSequence);
         --parseContext.loopNestingLevel;
     }
diff --git a/glslang/MachineIndependent/limits.cpp b/glslang/MachineIndependent/limits.cpp
new file mode 100644
index 000000000..0c660a87d
--- /dev/null
+++ b/glslang/MachineIndependent/limits.cpp
@@ -0,0 +1,199 @@
+//
+//Copyright (C) 2013 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// Do sub tree walks for
+// 1) inductive loop bodies to see if the inductive variable is modified
+// 2) array-index expressions to see if they are "constant-index-expression"
+//
+// These are per Appendix A of ES 2.0:
+//
+// "Within the body of the loop, the loop index is not statically assigned to nor is it used as the
+// argument to a function out or inout parameter."
+//
+// "The following are constant-index-expressions:
+//  - Constant expressions
+//  - Loop indices as defined in section 4
+//  - Expressions composed of both of the above"
+//
+// N.B.: assuming the last rule excludes function calls
+//
+
+#include "ParseHelper.h"
+
+namespace glslang {
+
+//
+// The inductive loop-body traverser.
+//
+// Just look at things that might modify the loop index.
+//
+
+class TInductiveTraverser : public TIntermTraverser {
+public:
+    TInductiveTraverser(int id, TSymbolTable& st) : loopId(id), symbolTable(st), bad(false)  { }
+    int loopId;           // unique ID of the symbol that's the loop inductive variable
+    TSymbolTable& symbolTable;
+    bool bad;
+    TSourceLoc badLoc;
+};
+
+// check binary operations for those modifying the loop index
+bool InductiveBinary(bool /* preVisit */, TIntermBinary* node, TIntermTraverser* it)
+{
+    TInductiveTraverser* oit = static_cast<TInductiveTraverser*>(it);
+
+    if (node->modifiesState() && node->getLeft()->getAsSymbolNode() && 
+                                 node->getLeft()->getAsSymbolNode()->getId() == oit->loopId) {
+        oit->bad = true;
+        oit->badLoc = node->getLoc();
+    }
+
+    return true;
+}
+
+// check unary operations for those modifying the loop index
+bool InductiveUnary(bool /* preVisit */, TIntermUnary* node, TIntermTraverser* it)
+{
+    TInductiveTraverser* oit = static_cast<TInductiveTraverser*>(it);
+
+    if (node->modifiesState() && node->getOperand()->getAsSymbolNode() && 
+                                 node->getOperand()->getAsSymbolNode()->getId() == oit->loopId) {
+        oit->bad = true;
+        oit->badLoc = node->getLoc();
+    }
+
+    return true;
+}
+
+// check function calls for arguments modifying the loop index
+bool InductiveAggregate(bool /* preVisit */, TIntermAggregate* node, TIntermTraverser* it)
+{
+    TInductiveTraverser* oit = static_cast<TInductiveTraverser*>(it);
+
+    if (node->getOp() == EOpFunctionCall) {
+        // see if an out or inout argument is the loop index
+        const TIntermSequence& args = node->getSequence();
+        for (size_t i = 0; i < args.size(); ++i) {
+            if (args[i]->getAsSymbolNode() && args[i]->getAsSymbolNode()->getId() == oit->loopId) {
+                TSymbol* function = oit->symbolTable.find(node->getName());
+                const TType* type = (*function->getAsFunction())[i].type;
+                if (type->getQualifier().storage == EvqOut ||
+                    type->getQualifier().storage == EvqInOut) {
+                    oit->bad = true;
+                    oit->badLoc = node->getLoc();
+                }
+            }
+        }
+    }
+
+    return true;
+}
+
+//
+// External function to call for loop check.
+//
+void TParseContext::inductiveLoopBodyCheck(TIntermNode* body, int loopId, TSymbolTable& symbolTable)
+{
+    TInductiveTraverser it(loopId, symbolTable);
+
+    if (! body)
+        return;
+
+    it.visitAggregate = InductiveAggregate;
+    it.visitBinary = InductiveBinary;
+    it.visitUnary = InductiveUnary;
+
+    body->traverse(&it);
+
+    if (it.bad)
+        error(it.badLoc, "inductive loop index modified", "limitations", "");
+}
+
+//
+// The "constant-index-expression" tranverser.
+//
+// Just look at things that can form an index.  
+//
+
+class TIndexTraverser : public TIntermTraverser {
+public:
+    TIndexTraverser(const TIdSetType& ids) : inductiveLoopIds(ids), bad(false) { }
+    const TIdSetType& inductiveLoopIds;
+    bool bad;
+    TSourceLoc badLoc;
+};
+
+// make sure symbols are inductive-loop indexes
+void IndexSymbol(TIntermSymbol* symbol, TIntermTraverser* it)
+{
+    TIndexTraverser* oit = static_cast<TIndexTraverser*>(it);
+
+    if (oit->inductiveLoopIds.find(symbol->getId()) == oit->inductiveLoopIds.end()) {
+        oit->bad = true;
+        oit->badLoc = symbol->getLoc();
+    }
+}
+
+// check for function calls, assuming they are bad; spec. doesn't really say
+bool IndexAggregate(bool /* preVisit */, TIntermAggregate* node, TIntermTraverser* it)
+{
+    TIndexTraverser* oit = static_cast<TIndexTraverser*>(it);
+
+    if (node->getOp() == EOpFunctionCall) {
+        oit->bad = true;
+        oit->badLoc = node->getLoc();
+    }
+
+    return true;
+}
+
+//
+// External function to call for loop check.
+//
+void TParseContext::constantIndexExpressionCheck(TIntermNode* index)
+{
+    TIndexTraverser it(inductiveLoopIds);
+
+    it.visitSymbol = IndexSymbol;
+    it.visitAggregate = IndexAggregate;
+
+    index->traverse(&it);
+
+    if (it.bad)
+        error(it.badLoc, "Non-constant-index-expression", "limitations", "");
+}
+
+} // end namespace glslang
diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h
index b8c37274d..f038211a1 100644
--- a/glslang/MachineIndependent/localintermediate.h
+++ b/glslang/MachineIndependent/localintermediate.h
@@ -89,8 +89,8 @@ public:
     TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, TSourceLoc);
     TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, TSourceLoc);
     TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) ;
-    bool parseConstTree(TSourceLoc, TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
-    TIntermNode* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, TSourceLoc);
+    bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
+    TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, TSourceLoc);
     TIntermBranch* addBranch(TOperator, TSourceLoc);
     TIntermBranch* addBranch(TOperator, TIntermTyped*, TSourceLoc);
     TIntermTyped* addSwizzle(TVectorFields&, TSourceLoc);
diff --git a/glslang/MachineIndependent/parseConst.cpp b/glslang/MachineIndependent/parseConst.cpp
index e77b96f81..872607b70 100644
--- a/glslang/MachineIndependent/parseConst.cpp
+++ b/glslang/MachineIndependent/parseConst.cpp
@@ -45,7 +45,7 @@ class TConstTraverser : public TIntermTraverser {
 public:
     TConstTraverser(const TConstUnionArray& cUnion, bool singleConstParam, TOperator constructType, const TType& t) : unionArray(cUnion), type(t),
         constructorType(constructType), singleConstantParam(singleConstParam), error(false), isMatrix(false), 
-        matrixCols(0), matrixRows(0) {  index = 0; tOp = EOpNull;}
+        matrixCols(0), matrixRows(0) {  index = 0; tOp = EOpNull; }
     int index;
     TConstUnionArray unionArray;
     TOperator tOp;
@@ -170,7 +170,7 @@ void ParseConstantUnion(TIntermConstantUnion* node, TIntermTraverser* it)
     }
 }
 
-bool TIntermediate::parseConstTree(TSourceLoc line, TIntermNode* root, TConstUnionArray unionArray, TOperator constructorType, const TType& t, bool singleConstantParam)
+bool TIntermediate::parseConstTree(TIntermNode* root, TConstUnionArray unionArray, TOperator constructorType, const TType& t, bool singleConstantParam)
 {
     if (root == 0)
         return false;
-- 
GitLab