Home | History | Annotate | Download | only in compiler
      1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //    http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include "ValidateSwitch.h"
     16 
     17 #include "ParseHelper.h"
     18 
     19 bool ValidateSwitch::validate(TBasicType switchType, TParseContext *context,
     20 	TIntermAggregate *statementList, const TSourceLoc &loc)
     21 {
     22 	ValidateSwitch validate(switchType, context);
     23 	ASSERT(statementList);
     24 	statementList->traverse(&validate);
     25 	return validate.validateInternal(loc);
     26 }
     27 
     28 ValidateSwitch::ValidateSwitch(TBasicType switchType, TParseContext *context)
     29 	: TIntermTraverser(true, false, true),
     30 	  mSwitchType(switchType),
     31 	  mContext(context),
     32 	  mCaseTypeMismatch(false),
     33 	  mFirstCaseFound(false),
     34 	  mStatementBeforeCase(false),
     35 	  mLastStatementWasCase(false),
     36 	  mControlFlowDepth(0),
     37 	  mCaseInsideControlFlow(false),
     38 	  mDefaultCount(0),
     39 	  mDuplicateCases(false)
     40 {}
     41 
     42 void ValidateSwitch::visitSymbol(TIntermSymbol *)
     43 {
     44 	if (!mFirstCaseFound)
     45 		mStatementBeforeCase = true;
     46 	mLastStatementWasCase = false;
     47 }
     48 
     49 void ValidateSwitch::visitConstantUnion(TIntermConstantUnion *)
     50 {
     51 	// Conditions of case labels are not traversed, so this is some other constant
     52 	// Could be just a statement like "0;"
     53 	if (!mFirstCaseFound)
     54 		mStatementBeforeCase = true;
     55 	mLastStatementWasCase = false;
     56 }
     57 
     58 bool ValidateSwitch::visitBinary(Visit, TIntermBinary *)
     59 {
     60 	if (!mFirstCaseFound)
     61 		mStatementBeforeCase = true;
     62 	mLastStatementWasCase = false;
     63 	return true;
     64 }
     65 
     66 bool ValidateSwitch::visitUnary(Visit, TIntermUnary *)
     67 {
     68 	if (!mFirstCaseFound)
     69 		mStatementBeforeCase = true;
     70 	mLastStatementWasCase = false;
     71 	return true;
     72 }
     73 
     74 bool ValidateSwitch::visitSelection(Visit visit, TIntermSelection *)
     75 {
     76 	if (visit == PreVisit)
     77 		++mControlFlowDepth;
     78 	if (visit == PostVisit)
     79 		--mControlFlowDepth;
     80 	if (!mFirstCaseFound)
     81 		mStatementBeforeCase = true;
     82 	mLastStatementWasCase = false;
     83 	return true;
     84 }
     85 
     86 bool ValidateSwitch::visitSwitch(Visit, TIntermSwitch *)
     87 {
     88 	if (!mFirstCaseFound)
     89 		mStatementBeforeCase = true;
     90 	mLastStatementWasCase = false;
     91 	// Don't go into nested switch statements
     92 	return false;
     93 }
     94 
     95 bool ValidateSwitch::visitCase(Visit, TIntermCase *node)
     96 {
     97 	const char *nodeStr = node->hasCondition() ? "case" : "default";
     98 	if (mControlFlowDepth > 0)
     99 	{
    100 		mContext->error(node->getLine(), "label statement nested inside control flow", nodeStr);
    101 		mCaseInsideControlFlow = true;
    102 	}
    103 	mFirstCaseFound = true;
    104 	mLastStatementWasCase = true;
    105 	if (!node->hasCondition())
    106 	{
    107 		++mDefaultCount;
    108 		if (mDefaultCount > 1)
    109 		{
    110 			mContext->error(node->getLine(), "duplicate default label", nodeStr);
    111 		}
    112 	}
    113 	else
    114 	{
    115 		TIntermConstantUnion *condition = node->getCondition()->getAsConstantUnion();
    116 		if (condition == nullptr)
    117 		{
    118 			// This can happen in error cases.
    119 			return false;
    120 		}
    121 		TBasicType conditionType = condition->getBasicType();
    122 		if (conditionType != mSwitchType)
    123 		{
    124 			mContext->error(condition->getLine(),
    125 				"case label type does not match switch init-expression type", nodeStr);
    126 			mCaseTypeMismatch = true;
    127 		}
    128 
    129 		if (conditionType == EbtInt)
    130 		{
    131 			int iConst = condition->getIConst(0);
    132 			if (mCasesSigned.find(iConst) != mCasesSigned.end())
    133 			{
    134 				mContext->error(condition->getLine(), "duplicate case label", nodeStr);
    135 				mDuplicateCases = true;
    136 			}
    137 			else
    138 			{
    139 				mCasesSigned.insert(iConst);
    140 			}
    141 		}
    142 		else if (conditionType == EbtUInt)
    143 		{
    144 			unsigned int uConst = condition->getUConst(0);
    145 			if (mCasesUnsigned.find(uConst) != mCasesUnsigned.end())
    146 			{
    147 				mContext->error(condition->getLine(), "duplicate case label", nodeStr);
    148 				mDuplicateCases = true;
    149 			}
    150 			else
    151 			{
    152 				mCasesUnsigned.insert(uConst);
    153 			}
    154 		}
    155 		// Other types are possible only in error cases, where the error has already been generated
    156 		// when parsing the case statement.
    157 	}
    158 	// Don't traverse the condition of the case statement
    159 	return false;
    160 }
    161 
    162 bool ValidateSwitch::visitAggregate(Visit visit, TIntermAggregate *)
    163 {
    164 	if (getParentNode() != nullptr)
    165 	{
    166 		// This is not the statementList node, but some other node.
    167 		if (!mFirstCaseFound)
    168 			mStatementBeforeCase = true;
    169 		mLastStatementWasCase = false;
    170 	}
    171 	return true;
    172 }
    173 
    174 bool ValidateSwitch::visitLoop(Visit visit, TIntermLoop *)
    175 {
    176 	if (visit == PreVisit)
    177 		++mControlFlowDepth;
    178 	if (visit == PostVisit)
    179 		--mControlFlowDepth;
    180 	if (!mFirstCaseFound)
    181 		mStatementBeforeCase = true;
    182 	mLastStatementWasCase = false;
    183 	return true;
    184 }
    185 
    186 bool ValidateSwitch::visitBranch(Visit, TIntermBranch *)
    187 {
    188 	if (!mFirstCaseFound)
    189 		mStatementBeforeCase = true;
    190 	mLastStatementWasCase = false;
    191 	return true;
    192 }
    193 
    194 bool ValidateSwitch::validateInternal(const TSourceLoc &loc)
    195 {
    196 	if (mStatementBeforeCase)
    197 	{
    198 		mContext->error(loc,
    199 			"statement before the first label", "switch");
    200 	}
    201 	if (mLastStatementWasCase)
    202 	{
    203 		mContext->error(loc,
    204 			"no statement between the last label and the end of the switch statement", "switch");
    205 	}
    206 	return !mStatementBeforeCase && !mLastStatementWasCase && !mCaseInsideControlFlow &&
    207 		!mCaseTypeMismatch && mDefaultCount <= 1 && !mDuplicateCases;
    208 }
    209