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