Commit 53f076fa by Olli Etuaho

Add basic error checks for switch and case

Check that the case labels have constant scalar integers, and that switch statements are initialized with scalar integers. Also check that case and default labels do not exist outside switch statements. Allow break statements inside switch statements. Tested by manually disabling shading language version checks for switch in a Chromium build and checking that the expected errors are generated. BUG=angle:921 Change-Id: Ibe83d0db52958c493ded5640d4babf670dc02d55 Reviewed-on: https://chromium-review.googlesource.com/251523Reviewed-by: 's avatarZhenyao Mo <zmo@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Tested-by: 's avatarOlli Etuaho <oetuaho@nvidia.com>
parent a3a36664
......@@ -2610,6 +2610,17 @@ TPublicType TParseContext::addStructure(const TSourceLoc& structLine, const TSou
TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &loc)
{
TBasicType switchType = init->getBasicType();
if ((switchType != EbtInt && switchType != EbtUInt) ||
init->isMatrix() ||
init->isArray() ||
init->isVector())
{
error(init->getLine(), "init-expression in a switch statement must be a scalar integer", "switch");
recover();
return nullptr;
}
TIntermSwitch *node = intermediate.addSwitch(init, statementList, loc);
if (node == nullptr)
{
......@@ -2622,6 +2633,32 @@ TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init, TIntermAggregate *st
TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &loc)
{
if (mSwitchNestingLevel == 0)
{
error(loc, "case labels need to be inside switch statements", "case");
recover();
return nullptr;
}
if (condition == nullptr)
{
error(loc, "case label must have a condition", "case");
recover();
return nullptr;
}
if ((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) ||
condition->isMatrix() ||
condition->isArray() ||
condition->isVector())
{
error(condition->getLine(), "case label must be a scalar integer", "case");
recover();
}
TIntermConstantUnion *conditionConst = condition->getAsConstantUnion();
if (conditionConst == nullptr)
{
error(condition->getLine(), "case label must be constant", "case");
recover();
}
TIntermCase *node = intermediate.addCase(condition, loc);
if (node == nullptr)
{
......@@ -2634,6 +2671,12 @@ TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &l
TIntermCase *TParseContext::addDefault(const TSourceLoc &loc)
{
if (mSwitchNestingLevel == 0)
{
error(loc, "default labels need to be inside switch statements", "default");
recover();
return nullptr;
}
TIntermCase *node = intermediate.addCase(nullptr, loc);
if (node == nullptr)
{
......@@ -2703,9 +2746,9 @@ TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc)
}
break;
case EOpBreak:
if (mLoopNestingLevel <= 0)
if (mLoopNestingLevel <= 0 && mSwitchNestingLevel <= 0)
{
error(loc, "break statement only allowed in loops", "");
error(loc, "break statement only allowed in loops and switch statements", "");
recover();
}
break;
......
......@@ -34,6 +34,7 @@ struct TParseContext {
treeRoot(0),
mLoopNestingLevel(0),
structNestingLevel(0),
mSwitchNestingLevel(0),
currentFunctionType(NULL),
mFunctionReturnsValue(false),
checksPrecisionErrors(checksPrecErrors),
......@@ -53,6 +54,7 @@ struct TParseContext {
TIntermNode* treeRoot; // root of parse tree being created
int mLoopNestingLevel; // 0 if outside all loops
int structNestingLevel; // incremented while parsing a struct declaration
int mSwitchNestingLevel; // 0 if outside all switch statements
const TType* currentFunctionType; // the return type of the function that's currently being parsed
bool mFunctionReturnsValue; // true if a non-void function has a return
bool checksPrecisionErrors; // true if an error will be generated when a variable is declared without precision, explicit or implicit.
......
......@@ -1606,8 +1606,9 @@ selection_rest_statement
;
switch_statement
: SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement {
$$ = context->addSwitch($3, $5, @1);
: SWITCH LEFT_PAREN expression RIGHT_PAREN { ++context->mSwitchNestingLevel; } compound_statement {
$$ = context->addSwitch($3, $6, @1);
--context->mSwitchNestingLevel;
}
;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment