ValidateSwitch.cpp (9508B)
1 // 2 // Copyright 2002 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 #include "compiler/translator/ValidateSwitch.h" 8 9 #include "compiler/translator/Diagnostics.h" 10 #include "compiler/translator/tree_util/IntermTraverse.h" 11 12 namespace sh 13 { 14 15 namespace 16 { 17 18 const int kMaxAllowedTraversalDepth = 256; 19 20 class ValidateSwitch : public TIntermTraverser 21 { 22 public: 23 static bool validate(TBasicType switchType, 24 TDiagnostics *diagnostics, 25 TIntermBlock *statementList, 26 const TSourceLoc &loc); 27 28 void visitSymbol(TIntermSymbol *) override; 29 void visitConstantUnion(TIntermConstantUnion *) override; 30 bool visitDeclaration(Visit, TIntermDeclaration *) override; 31 bool visitBlock(Visit visit, TIntermBlock *) override; 32 bool visitBinary(Visit, TIntermBinary *) override; 33 bool visitUnary(Visit, TIntermUnary *) override; 34 bool visitTernary(Visit, TIntermTernary *) override; 35 bool visitSwizzle(Visit, TIntermSwizzle *) override; 36 bool visitIfElse(Visit visit, TIntermIfElse *) override; 37 bool visitSwitch(Visit, TIntermSwitch *) override; 38 bool visitCase(Visit, TIntermCase *node) override; 39 bool visitAggregate(Visit, TIntermAggregate *) override; 40 bool visitLoop(Visit visit, TIntermLoop *) override; 41 bool visitBranch(Visit, TIntermBranch *) override; 42 43 private: 44 ValidateSwitch(TBasicType switchType, TDiagnostics *context); 45 46 bool validateInternal(const TSourceLoc &loc); 47 48 TBasicType mSwitchType; 49 TDiagnostics *mDiagnostics; 50 bool mCaseTypeMismatch; 51 bool mFirstCaseFound; 52 bool mStatementBeforeCase; 53 bool mLastStatementWasCase; 54 int mControlFlowDepth; 55 bool mCaseInsideControlFlow; 56 int mDefaultCount; 57 std::set<int> mCasesSigned; 58 std::set<unsigned int> mCasesUnsigned; 59 bool mDuplicateCases; 60 }; 61 62 bool ValidateSwitch::validate(TBasicType switchType, 63 TDiagnostics *diagnostics, 64 TIntermBlock *statementList, 65 const TSourceLoc &loc) 66 { 67 ValidateSwitch validate(switchType, diagnostics); 68 ASSERT(statementList); 69 statementList->traverse(&validate); 70 return validate.validateInternal(loc); 71 } 72 73 ValidateSwitch::ValidateSwitch(TBasicType switchType, TDiagnostics *diagnostics) 74 : TIntermTraverser(true, false, true, nullptr), 75 mSwitchType(switchType), 76 mDiagnostics(diagnostics), 77 mCaseTypeMismatch(false), 78 mFirstCaseFound(false), 79 mStatementBeforeCase(false), 80 mLastStatementWasCase(false), 81 mControlFlowDepth(0), 82 mCaseInsideControlFlow(false), 83 mDefaultCount(0), 84 mDuplicateCases(false) 85 { 86 setMaxAllowedDepth(kMaxAllowedTraversalDepth); 87 } 88 89 void ValidateSwitch::visitSymbol(TIntermSymbol *) 90 { 91 if (!mFirstCaseFound) 92 mStatementBeforeCase = true; 93 mLastStatementWasCase = false; 94 } 95 96 void ValidateSwitch::visitConstantUnion(TIntermConstantUnion *) 97 { 98 // Conditions of case labels are not traversed, so this is some other constant 99 // Could be just a statement like "0;" 100 if (!mFirstCaseFound) 101 mStatementBeforeCase = true; 102 mLastStatementWasCase = false; 103 } 104 105 bool ValidateSwitch::visitDeclaration(Visit, TIntermDeclaration *) 106 { 107 if (!mFirstCaseFound) 108 mStatementBeforeCase = true; 109 mLastStatementWasCase = false; 110 return true; 111 } 112 113 bool ValidateSwitch::visitBlock(Visit visit, TIntermBlock *) 114 { 115 if (getParentNode() != nullptr) 116 { 117 if (!mFirstCaseFound) 118 mStatementBeforeCase = true; 119 mLastStatementWasCase = false; 120 if (visit == PreVisit) 121 ++mControlFlowDepth; 122 if (visit == PostVisit) 123 --mControlFlowDepth; 124 } 125 return true; 126 } 127 128 bool ValidateSwitch::visitBinary(Visit, TIntermBinary *) 129 { 130 if (!mFirstCaseFound) 131 mStatementBeforeCase = true; 132 mLastStatementWasCase = false; 133 return true; 134 } 135 136 bool ValidateSwitch::visitUnary(Visit, TIntermUnary *) 137 { 138 if (!mFirstCaseFound) 139 mStatementBeforeCase = true; 140 mLastStatementWasCase = false; 141 return true; 142 } 143 144 bool ValidateSwitch::visitTernary(Visit, TIntermTernary *) 145 { 146 if (!mFirstCaseFound) 147 mStatementBeforeCase = true; 148 mLastStatementWasCase = false; 149 return true; 150 } 151 152 bool ValidateSwitch::visitSwizzle(Visit, TIntermSwizzle *) 153 { 154 if (!mFirstCaseFound) 155 mStatementBeforeCase = true; 156 mLastStatementWasCase = false; 157 return true; 158 } 159 160 bool ValidateSwitch::visitIfElse(Visit visit, TIntermIfElse *) 161 { 162 if (visit == PreVisit) 163 ++mControlFlowDepth; 164 if (visit == PostVisit) 165 --mControlFlowDepth; 166 if (!mFirstCaseFound) 167 mStatementBeforeCase = true; 168 mLastStatementWasCase = false; 169 return true; 170 } 171 172 bool ValidateSwitch::visitSwitch(Visit, TIntermSwitch *) 173 { 174 if (!mFirstCaseFound) 175 mStatementBeforeCase = true; 176 mLastStatementWasCase = false; 177 // Don't go into nested switch statements 178 return false; 179 } 180 181 bool ValidateSwitch::visitCase(Visit, TIntermCase *node) 182 { 183 const char *nodeStr = node->hasCondition() ? "case" : "default"; 184 if (mControlFlowDepth > 0) 185 { 186 mDiagnostics->error(node->getLine(), "label statement nested inside control flow", nodeStr); 187 mCaseInsideControlFlow = true; 188 } 189 mFirstCaseFound = true; 190 mLastStatementWasCase = true; 191 if (!node->hasCondition()) 192 { 193 ++mDefaultCount; 194 if (mDefaultCount > 1) 195 { 196 mDiagnostics->error(node->getLine(), "duplicate default label", nodeStr); 197 } 198 } 199 else 200 { 201 TIntermConstantUnion *condition = node->getCondition()->getAsConstantUnion(); 202 if (condition == nullptr) 203 { 204 // This can happen in error cases. 205 return false; 206 } 207 TBasicType conditionType = condition->getBasicType(); 208 if (conditionType != mSwitchType) 209 { 210 mDiagnostics->error(condition->getLine(), 211 "case label type does not match switch init-expression type", 212 nodeStr); 213 mCaseTypeMismatch = true; 214 } 215 216 if (conditionType == EbtInt) 217 { 218 int iConst = condition->getIConst(0); 219 if (mCasesSigned.find(iConst) != mCasesSigned.end()) 220 { 221 mDiagnostics->error(condition->getLine(), "duplicate case label", nodeStr); 222 mDuplicateCases = true; 223 } 224 else 225 { 226 mCasesSigned.insert(iConst); 227 } 228 } 229 else if (conditionType == EbtUInt) 230 { 231 unsigned int uConst = condition->getUConst(0); 232 if (mCasesUnsigned.find(uConst) != mCasesUnsigned.end()) 233 { 234 mDiagnostics->error(condition->getLine(), "duplicate case label", nodeStr); 235 mDuplicateCases = true; 236 } 237 else 238 { 239 mCasesUnsigned.insert(uConst); 240 } 241 } 242 // Other types are possible only in error cases, where the error has already been generated 243 // when parsing the case statement. 244 } 245 // Don't traverse the condition of the case statement 246 return false; 247 } 248 249 bool ValidateSwitch::visitAggregate(Visit visit, TIntermAggregate *) 250 { 251 if (getParentNode() != nullptr) 252 { 253 // This is not the statementList node, but some other node. 254 if (!mFirstCaseFound) 255 mStatementBeforeCase = true; 256 mLastStatementWasCase = false; 257 } 258 return true; 259 } 260 261 bool ValidateSwitch::visitLoop(Visit visit, TIntermLoop *) 262 { 263 if (visit == PreVisit) 264 ++mControlFlowDepth; 265 if (visit == PostVisit) 266 --mControlFlowDepth; 267 if (!mFirstCaseFound) 268 mStatementBeforeCase = true; 269 mLastStatementWasCase = false; 270 return true; 271 } 272 273 bool ValidateSwitch::visitBranch(Visit, TIntermBranch *) 274 { 275 if (!mFirstCaseFound) 276 mStatementBeforeCase = true; 277 mLastStatementWasCase = false; 278 return true; 279 } 280 281 bool ValidateSwitch::validateInternal(const TSourceLoc &loc) 282 { 283 if (mStatementBeforeCase) 284 { 285 mDiagnostics->error(loc, "statement before the first label", "switch"); 286 } 287 if (mLastStatementWasCase) 288 { 289 // There have been some differences between versions of GLSL ES specs on whether this should 290 // be an error or not, but as of early 2018 the latest discussion is that this is an error 291 // also on GLSL ES versions newer than 3.00. 292 mDiagnostics->error( 293 loc, "no statement between the last label and the end of the switch statement", 294 "switch"); 295 } 296 if (getMaxDepth() >= kMaxAllowedTraversalDepth) 297 { 298 mDiagnostics->error(loc, "too complex expressions inside a switch statement", "switch"); 299 } 300 return !mStatementBeforeCase && !mLastStatementWasCase && !mCaseInsideControlFlow && 301 !mCaseTypeMismatch && mDefaultCount <= 1 && !mDuplicateCases && 302 getMaxDepth() < kMaxAllowedTraversalDepth; 303 } 304 305 } // anonymous namespace 306 307 bool ValidateSwitchStatementList(TBasicType switchType, 308 TDiagnostics *diagnostics, 309 TIntermBlock *statementList, 310 const TSourceLoc &loc) 311 { 312 return ValidateSwitch::validate(switchType, diagnostics, statementList, loc); 313 } 314 315 } // namespace sh