From 7fd9e1189bbbb7c99e81bdc4d733714ac62a15ff Mon Sep 17 00:00:00 2001
From: John Kessenich <cepheus@frii.com>
Date: Wed, 4 Dec 2013 21:48:20 +0000
Subject: [PATCH] Track the flow-control (and {}) nesting level to prevent case
 statements from being a different nesting level than their switch statement.

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@24355 e7fa87d3-cd2b-0410-9028-fcbf551c1848
---
 Test/baseResults/switch.frag.out           | 76 +++++++++++++++++++++-
 Test/switch.frag                           | 26 ++++++++
 glslang/Include/revision.h                 |  4 +-
 glslang/MachineIndependent/ParseHelper.cpp |  3 +-
 glslang/MachineIndependent/ParseHelper.h   |  2 +
 glslang/MachineIndependent/glslang.y       | 37 +++++++++--
 6 files changed, 140 insertions(+), 8 deletions(-)

diff --git a/Test/baseResults/switch.frag.out b/Test/baseResults/switch.frag.out
index 9e6b5f7ff..af810169f 100644
--- a/Test/baseResults/switch.frag.out
+++ b/Test/baseResults/switch.frag.out
@@ -8,7 +8,10 @@ ERROR: 0:63: 'case' : duplicated value
 ERROR: 0:65: 'case' : scalar integer expression required 
 ERROR: 0:67: 'case' : constant expression required 
 ERROR: 0:89: '' : break statement only allowed in switch and loops 
-ERROR: 9 compilation errors.  No code generated.
+ERROR: 0:99: 'case' : cannot be nested inside control flow 
+ERROR: 0:104: 'case' : cannot be nested inside control flow 
+ERROR: 0:108: 'case' : cannot be nested inside control flow 
+ERROR: 12 compilation errors.  No code generated.
 
 
 ERROR: node is still EOpNull!
@@ -189,6 +192,77 @@ ERROR: node is still EOpNull!
 0:86              tangent (highp float)
 0:86                'x' (smooth in highp float)
 0:89      Branch: Break
+0:91      switch
+0:91      condition
+0:91        'c' (uniform mediump int)
+0:91      body
+0:91        Sequence
+0:92          case:  with expression
+0:92            Constant:
+0:92              1 (const int)
+0:?           Sequence
+0:93            move second child to first child (highp float)
+0:93              'f' (highp float)
+0:93              sine (highp float)
+0:93                'x' (smooth in highp float)
+0:94            Branch: Break
+0:95          case:  with expression
+0:95            Constant:
+0:95              2 (const int)
+0:?           Sequence
+0:96            switch
+0:96            condition
+0:96              'd' (uniform mediump int)
+0:96            body
+0:96              Sequence
+0:97                case:  with expression
+0:97                  Constant:
+0:97                    1 (const int)
+0:99                case:  with expression
+0:99                  Constant:
+0:99                    4 (const int)
+0:104                case:  with expression
+0:104                  Constant:
+0:104                    2 (const int)
+0:?                 Sequence
+0:?                   Sequence
+0:100                    Branch: Break
+0:102                  move second child to first child (highp float)
+0:102                    'f' (highp float)
+0:102                    component-wise multiply (highp float)
+0:102                      component-wise multiply (highp float)
+0:102                        'x' (smooth in highp float)
+0:102                        'x' (smooth in highp float)
+0:102                      'x' (smooth in highp float)
+0:103                  Test condition and select (void)
+0:103                    Condition
+0:103                    Compare Less Than (bool)
+0:103                      'c' (uniform mediump int)
+0:103                      'd' (uniform mediump int)
+0:103                    true case
+0:?                     Sequence
+0:105                      move second child to first child (highp float)
+0:105                        'f' (highp float)
+0:105                        component-wise multiply (highp float)
+0:105                          'x' (smooth in highp float)
+0:105                          'x' (smooth in highp float)
+0:107                  Test condition and select (void)
+0:107                    Condition
+0:107                    Compare Less Than (bool)
+0:107                      'd' (uniform mediump int)
+0:107                      'c' (uniform mediump int)
+0:107                    true case
+0:108                    case:  with expression
+0:108                      Constant:
+0:108                        3 (const int)
+0:109                  Branch: Break
+0:111            Branch: Break
+0:112          default: 
+0:?           Sequence
+0:113            move second child to first child (highp float)
+0:113              'f' (highp float)
+0:113              tangent (highp float)
+0:113                'x' (smooth in highp float)
 0:?   Linker Objects
 0:?     'c' (uniform mediump int)
 0:?     'd' (uniform mediump int)
diff --git a/Test/switch.frag b/Test/switch.frag
index 05a5a9578..2cb6f21ab 100644
--- a/Test/switch.frag
+++ b/Test/switch.frag
@@ -87,4 +87,30 @@ void main()
     }
 
     break;            // ERROR
+
+    switch (c) {
+    case 1:
+        f = sin(x);
+        break;
+    case 2:
+        switch (d) {
+        case 1:
+            {
+                case 4:        // ERROR
+                    break;
+            }
+            f = x * x * x;
+            if (c < d) {
+                case 2:         // ERROR
+                    f = x * x;
+            }
+            if (d < c)
+                case 3:         // ERROR
+            break;
+        }
+        break;
+    default:
+        f = tan(x);
+    }
+
 }
diff --git a/glslang/Include/revision.h b/glslang/Include/revision.h
index 406a4f38a..87eb33693 100644
--- a/glslang/Include/revision.h
+++ b/glslang/Include/revision.h
@@ -9,5 +9,5 @@
 // source have to figure out how to create revision.h just to get a build
 // going.  However, if it is not updated, it can be a version behind.
 
-#define GLSLANG_REVISION "24349"
-#define GLSLANG_DATE     "2013/12/04 13:41:33"
+#define GLSLANG_REVISION "24353"
+#define GLSLANG_DATE     "2013/12/04 14:01:32"
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index f49fb7262..c3febee0b 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -51,7 +51,7 @@ TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, bool pb,
                              bool fc, EShMessages m) :
             intermediate(interm), symbolTable(symt), infoSink(is), language(L),
             version(v), profile(p), forwardCompatible(fc), messages(m),
-            contextPragma(true, false), loopNestingLevel(0), structNestingLevel(0),
+            contextPragma(true, false), loopNestingLevel(0), controlFlowNestingLevel(0), structNestingLevel(0),
             tokensBeforeEOF(false), limits(resources.limits), currentScanner(0),
             numErrors(0), parsingBuiltins(pb), afterEOF(false),
             anyIndexLimits(false)
@@ -813,6 +813,7 @@ TIntermAggregate* TParseContext::handleFunctionDefinition(TSourceLoc loc, TFunct
     }
     intermediate.setAggregateOperator(paramNodes, EOpParameters, TType(EbtVoid), loc);
     loopNestingLevel = 0;
+    controlFlowNestingLevel = 0;
 
     return paramNodes;
 }
diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h
index 2df405701..ca4778eeb 100644
--- a/glslang/MachineIndependent/ParseHelper.h
+++ b/glslang/MachineIndependent/ParseHelper.h
@@ -219,7 +219,9 @@ public:
     struct TPragma contextPragma;
     int loopNestingLevel;        // 0 if outside all loops
     int structNestingLevel;      // 0 if outside blocks and structures
+    int controlFlowNestingLevel; // 0 if outside all flow control or compound statements; also counts compound statements
     TList<TIntermSequence*> switchSequenceStack;  // case, node, case, case, node, ...; ensure only one node between cases;   stack of them for nesting
+    TList<int> switchLevel;      // the controlFlowNestingLevel the current switch statement is at, which must match the level of its case statements
     const TType* currentFunctionType;  // the return type of the function that's currently being parsed
     bool functionReturnsValue;   // true if a non-void function has a return
     const TString* blockName;
diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y
index 087d7ebef..b718f8e43 100644
--- a/glslang/MachineIndependent/glslang.y
+++ b/glslang/MachineIndependent/glslang.y
@@ -2148,8 +2148,14 @@ simple_statement
 
 compound_statement
     : LEFT_BRACE RIGHT_BRACE { $$ = 0; }
-    | LEFT_BRACE { parseContext.symbolTable.push(); }
-      statement_list { parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); }
+    | LEFT_BRACE {
+        parseContext.symbolTable.push();
+        ++parseContext.controlFlowNestingLevel;
+    }
+      statement_list { 
+        parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
+        --parseContext.controlFlowNestingLevel;
+    }
       RIGHT_BRACE {
         if ($3 != 0)
             $3->setOperator(EOpSequence);
@@ -2164,7 +2170,15 @@ statement_no_new_scope
 
 statement_scoped
     : compound_statement  { $$ = $1; }
-    | { parseContext.symbolTable.push(); } simple_statement { parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); } { $$ = $2; }
+    | { 
+        parseContext.symbolTable.push();
+        ++parseContext.controlFlowNestingLevel;
+    } 
+      simple_statement {
+        parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
+        --parseContext.controlFlowNestingLevel;
+        $$ = $2;
+    }
 
 compound_statement_no_new_scope
     // Statement that doesn't create a new scope, for selection_statement, iteration_statement
@@ -2242,11 +2256,13 @@ switch_statement
     : SWITCH LEFT_PAREN expression RIGHT_PAREN {
         // start new switch sequence on the switch stack
         parseContext.switchSequenceStack.push_back(new TIntermSequence);
+        parseContext.switchLevel.push_back(parseContext.controlFlowNestingLevel);
     } 
     LEFT_BRACE switch_statement_list RIGHT_BRACE {
         $$ = parseContext.addSwitch($1.loc, $3, $7);
         delete parseContext.switchSequenceStack.back();
         parseContext.switchSequenceStack.pop_back();
+        parseContext.switchLevel.pop_back();
     }
     ;
 
@@ -2261,6 +2277,10 @@ switch_statement_list
 
 case_label
     : CASE expression COLON {
+        if (parseContext.switchLevel.size() == 0)
+            parseContext.error($1.loc, "cannot appear outside switch statement", "case", "");
+        else if (parseContext.switchLevel.back() != parseContext.controlFlowNestingLevel)
+            parseContext.error($1.loc, "cannot be nested inside control flow", "case", "");
         parseContext.constantValueCheck($2, "case");
         parseContext.integerCheck($2, "case");
         $$ = parseContext.intermediate.addBranch(EOpCase, $2, $1.loc);
@@ -2276,13 +2296,19 @@ iteration_statement
             parseContext.error($1.loc, "while loops not available", "limitation", "");
         parseContext.symbolTable.push();
         ++parseContext.loopNestingLevel;
+        ++parseContext.controlFlowNestingLevel;
     }
       condition RIGHT_PAREN statement_no_new_scope {
         parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
         $$ = parseContext.intermediate.addLoop($6, $4, 0, true, $1.loc);
         --parseContext.loopNestingLevel;
+        --parseContext.controlFlowNestingLevel;
     }
-    | DO { ++parseContext.loopNestingLevel; } statement WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON {
+    | DO { 
+        ++parseContext.loopNestingLevel;
+        ++parseContext.controlFlowNestingLevel;
+    } 
+      statement WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON {
         if (! parseContext.limits.whileLoops)
             parseContext.error($1.loc, "do-while loops not available", "limitation", "");
 
@@ -2290,10 +2316,12 @@ iteration_statement
 
         $$ = parseContext.intermediate.addLoop($3, $6, 0, false, $4.loc);
         --parseContext.loopNestingLevel;
+        --parseContext.controlFlowNestingLevel;
     }
     | FOR LEFT_PAREN {
         parseContext.symbolTable.push();
         ++parseContext.loopNestingLevel;
+        ++parseContext.controlFlowNestingLevel;
     }
       for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope {
         parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
@@ -2304,6 +2332,7 @@ iteration_statement
         $$ = parseContext.intermediate.growAggregate($$, forLoop, $1.loc);
         $$->getAsAggregate()->setOperator(EOpSequence);
         --parseContext.loopNestingLevel;
+        --parseContext.controlFlowNestingLevel;
     }
     ;
 
-- 
GitLab