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