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 
validate(TBasicType switchType,TDiagnostics * diagnostics,TIntermBlock * statementList,const TSourceLoc & loc)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 
ValidateSwitch(TBasicType switchType,TDiagnostics * diagnostics)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 
visitSymbol(TIntermSymbol *)89 void ValidateSwitch::visitSymbol(TIntermSymbol *)
90 {
91     if (!mFirstCaseFound)
92         mStatementBeforeCase = true;
93     mLastStatementWasCase = false;
94 }
95 
visitConstantUnion(TIntermConstantUnion *)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 
visitDeclaration(Visit,TIntermDeclaration *)105 bool ValidateSwitch::visitDeclaration(Visit, TIntermDeclaration *)
106 {
107     if (!mFirstCaseFound)
108         mStatementBeforeCase = true;
109     mLastStatementWasCase = false;
110     return true;
111 }
112 
visitBlock(Visit visit,TIntermBlock *)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 
visitBinary(Visit,TIntermBinary *)128 bool ValidateSwitch::visitBinary(Visit, TIntermBinary *)
129 {
130     if (!mFirstCaseFound)
131         mStatementBeforeCase = true;
132     mLastStatementWasCase = false;
133     return true;
134 }
135 
visitUnary(Visit,TIntermUnary *)136 bool ValidateSwitch::visitUnary(Visit, TIntermUnary *)
137 {
138     if (!mFirstCaseFound)
139         mStatementBeforeCase = true;
140     mLastStatementWasCase = false;
141     return true;
142 }
143 
visitTernary(Visit,TIntermTernary *)144 bool ValidateSwitch::visitTernary(Visit, TIntermTernary *)
145 {
146     if (!mFirstCaseFound)
147         mStatementBeforeCase = true;
148     mLastStatementWasCase = false;
149     return true;
150 }
151 
visitSwizzle(Visit,TIntermSwizzle *)152 bool ValidateSwitch::visitSwizzle(Visit, TIntermSwizzle *)
153 {
154     if (!mFirstCaseFound)
155         mStatementBeforeCase = true;
156     mLastStatementWasCase = false;
157     return true;
158 }
159 
visitIfElse(Visit visit,TIntermIfElse *)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 
visitSwitch(Visit,TIntermSwitch *)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 
visitCase(Visit,TIntermCase * node)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 
visitAggregate(Visit visit,TIntermAggregate *)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 
visitLoop(Visit visit,TIntermLoop *)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 
visitBranch(Visit,TIntermBranch *)273 bool ValidateSwitch::visitBranch(Visit, TIntermBranch *)
274 {
275     if (!mFirstCaseFound)
276         mStatementBeforeCase = true;
277     mLastStatementWasCase = false;
278     return true;
279 }
280 
validateInternal(const TSourceLoc & loc)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 
ValidateSwitchStatementList(TBasicType switchType,TDiagnostics * diagnostics,TIntermBlock * statementList,const TSourceLoc & loc)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
316