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
This commit is contained in:
John Kessenich 2013-12-04 21:48:20 +00:00
parent 3a53006e0e
commit 7fd9e1189b
6 changed files with 140 additions and 8 deletions

View File

@ -8,7 +8,10 @@ ERROR: 0:63: 'case' : duplicated value
ERROR: 0:65: 'case' : scalar integer expression required ERROR: 0:65: 'case' : scalar integer expression required
ERROR: 0:67: 'case' : constant expression required ERROR: 0:67: 'case' : constant expression required
ERROR: 0:89: '' : break statement only allowed in switch and loops 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! ERROR: node is still EOpNull!
@ -189,6 +192,77 @@ ERROR: node is still EOpNull!
0:86 tangent (highp float) 0:86 tangent (highp float)
0:86 'x' (smooth in highp float) 0:86 'x' (smooth in highp float)
0:89 Branch: Break 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:? Linker Objects
0:? 'c' (uniform mediump int) 0:? 'c' (uniform mediump int)
0:? 'd' (uniform mediump int) 0:? 'd' (uniform mediump int)

View File

@ -87,4 +87,30 @@ void main()
} }
break; // ERROR 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);
}
} }

View File

@ -9,5 +9,5 @@
// source have to figure out how to create revision.h just to get a build // 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. // going. However, if it is not updated, it can be a version behind.
#define GLSLANG_REVISION "24349" #define GLSLANG_REVISION "24353"
#define GLSLANG_DATE "2013/12/04 13:41:33" #define GLSLANG_DATE "2013/12/04 14:01:32"

View File

@ -51,7 +51,7 @@ TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, bool pb,
bool fc, EShMessages m) : bool fc, EShMessages m) :
intermediate(interm), symbolTable(symt), infoSink(is), language(L), intermediate(interm), symbolTable(symt), infoSink(is), language(L),
version(v), profile(p), forwardCompatible(fc), messages(m), 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), tokensBeforeEOF(false), limits(resources.limits), currentScanner(0),
numErrors(0), parsingBuiltins(pb), afterEOF(false), numErrors(0), parsingBuiltins(pb), afterEOF(false),
anyIndexLimits(false) anyIndexLimits(false)
@ -813,6 +813,7 @@ TIntermAggregate* TParseContext::handleFunctionDefinition(TSourceLoc loc, TFunct
} }
intermediate.setAggregateOperator(paramNodes, EOpParameters, TType(EbtVoid), loc); intermediate.setAggregateOperator(paramNodes, EOpParameters, TType(EbtVoid), loc);
loopNestingLevel = 0; loopNestingLevel = 0;
controlFlowNestingLevel = 0;
return paramNodes; return paramNodes;
} }

View File

@ -219,7 +219,9 @@ public:
struct TPragma contextPragma; struct TPragma contextPragma;
int loopNestingLevel; // 0 if outside all loops int loopNestingLevel; // 0 if outside all loops
int structNestingLevel; // 0 if outside blocks and structures 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<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 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 bool functionReturnsValue; // true if a non-void function has a return
const TString* blockName; const TString* blockName;

View File

@ -2148,8 +2148,14 @@ simple_statement
compound_statement compound_statement
: LEFT_BRACE RIGHT_BRACE { $$ = 0; } : LEFT_BRACE RIGHT_BRACE { $$ = 0; }
| LEFT_BRACE { parseContext.symbolTable.push(); } | LEFT_BRACE {
statement_list { parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); } parseContext.symbolTable.push();
++parseContext.controlFlowNestingLevel;
}
statement_list {
parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
--parseContext.controlFlowNestingLevel;
}
RIGHT_BRACE { RIGHT_BRACE {
if ($3 != 0) if ($3 != 0)
$3->setOperator(EOpSequence); $3->setOperator(EOpSequence);
@ -2164,7 +2170,15 @@ statement_no_new_scope
statement_scoped statement_scoped
: compound_statement { $$ = $1; } : 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 compound_statement_no_new_scope
// Statement that doesn't create a new scope, for selection_statement, iteration_statement // 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 { : SWITCH LEFT_PAREN expression RIGHT_PAREN {
// start new switch sequence on the switch stack // start new switch sequence on the switch stack
parseContext.switchSequenceStack.push_back(new TIntermSequence); parseContext.switchSequenceStack.push_back(new TIntermSequence);
parseContext.switchLevel.push_back(parseContext.controlFlowNestingLevel);
} }
LEFT_BRACE switch_statement_list RIGHT_BRACE { LEFT_BRACE switch_statement_list RIGHT_BRACE {
$$ = parseContext.addSwitch($1.loc, $3, $7); $$ = parseContext.addSwitch($1.loc, $3, $7);
delete parseContext.switchSequenceStack.back(); delete parseContext.switchSequenceStack.back();
parseContext.switchSequenceStack.pop_back(); parseContext.switchSequenceStack.pop_back();
parseContext.switchLevel.pop_back();
} }
; ;
@ -2261,6 +2277,10 @@ switch_statement_list
case_label case_label
: CASE expression COLON { : 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.constantValueCheck($2, "case");
parseContext.integerCheck($2, "case"); parseContext.integerCheck($2, "case");
$$ = parseContext.intermediate.addBranch(EOpCase, $2, $1.loc); $$ = parseContext.intermediate.addBranch(EOpCase, $2, $1.loc);
@ -2276,13 +2296,19 @@ iteration_statement
parseContext.error($1.loc, "while loops not available", "limitation", ""); parseContext.error($1.loc, "while loops not available", "limitation", "");
parseContext.symbolTable.push(); parseContext.symbolTable.push();
++parseContext.loopNestingLevel; ++parseContext.loopNestingLevel;
++parseContext.controlFlowNestingLevel;
} }
condition RIGHT_PAREN statement_no_new_scope { condition RIGHT_PAREN statement_no_new_scope {
parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
$$ = parseContext.intermediate.addLoop($6, $4, 0, true, $1.loc); $$ = parseContext.intermediate.addLoop($6, $4, 0, true, $1.loc);
--parseContext.loopNestingLevel; --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) if (! parseContext.limits.whileLoops)
parseContext.error($1.loc, "do-while loops not available", "limitation", ""); 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.intermediate.addLoop($3, $6, 0, false, $4.loc);
--parseContext.loopNestingLevel; --parseContext.loopNestingLevel;
--parseContext.controlFlowNestingLevel;
} }
| FOR LEFT_PAREN { | FOR LEFT_PAREN {
parseContext.symbolTable.push(); parseContext.symbolTable.push();
++parseContext.loopNestingLevel; ++parseContext.loopNestingLevel;
++parseContext.controlFlowNestingLevel;
} }
for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope { for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope {
parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
@ -2304,6 +2332,7 @@ iteration_statement
$$ = parseContext.intermediate.growAggregate($$, forLoop, $1.loc); $$ = parseContext.intermediate.growAggregate($$, forLoop, $1.loc);
$$->getAsAggregate()->setOperator(EOpSequence); $$->getAsAggregate()->setOperator(EOpSequence);
--parseContext.loopNestingLevel; --parseContext.loopNestingLevel;
--parseContext.controlFlowNestingLevel;
} }
; ;