• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2019 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/ValidateAST.h"
8 
9 #include "common/utilities.h"
10 #include "compiler/translator/Diagnostics.h"
11 #include "compiler/translator/ImmutableStringBuilder.h"
12 #include "compiler/translator/Symbol.h"
13 #include "compiler/translator/tree_util/IntermTraverse.h"
14 #include "compiler/translator/tree_util/SpecializationConstant.h"
15 #include "compiler/translator/util.h"
16 
17 namespace sh
18 {
19 
20 namespace
21 {
22 
23 class ValidateAST : public TIntermTraverser
24 {
25   public:
26     static bool validate(TIntermNode *root,
27                          TDiagnostics *diagnostics,
28                          const ValidateASTOptions &options);
29 
30     void visitSymbol(TIntermSymbol *node) override;
31     void visitConstantUnion(TIntermConstantUnion *node) override;
32     bool visitSwizzle(Visit visit, TIntermSwizzle *node) override;
33     bool visitBinary(Visit visit, TIntermBinary *node) override;
34     bool visitUnary(Visit visit, TIntermUnary *node) override;
35     bool visitTernary(Visit visit, TIntermTernary *node) override;
36     bool visitIfElse(Visit visit, TIntermIfElse *node) override;
37     bool visitSwitch(Visit visit, TIntermSwitch *node) override;
38     bool visitCase(Visit visit, TIntermCase *node) override;
39     void visitFunctionPrototype(TIntermFunctionPrototype *node) override;
40     bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
41     bool visitAggregate(Visit visit, TIntermAggregate *node) override;
42     bool visitBlock(Visit visit, TIntermBlock *node) override;
43     bool visitGlobalQualifierDeclaration(Visit visit,
44                                          TIntermGlobalQualifierDeclaration *node) override;
45     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
46     bool visitLoop(Visit visit, TIntermLoop *node) override;
47     bool visitBranch(Visit visit, TIntermBranch *node) override;
48     void visitPreprocessorDirective(TIntermPreprocessorDirective *node) override;
49 
50   private:
51     ValidateAST(TIntermNode *root, TDiagnostics *diagnostics, const ValidateASTOptions &options);
52 
53     // Visit as a generic node
54     void visitNode(Visit visit, TIntermNode *node);
55     // Visit a structure or interface block, and recursively visit its fields of structure type.
56     void visitStructOrInterfaceBlockDeclaration(const TType &type, const TSourceLoc &location);
57     void visitStructUsage(const TType &type, const TSourceLoc &location);
58     // Visit a unary or aggregate node and validate its built-in op against its built-in function.
59     void visitBuiltInFunction(TIntermOperator *op, const TFunction *function);
60     // Visit an aggregate node and validate its function call is to one that's already defined.
61     void visitFunctionCall(TIntermAggregate *node);
62     // Visit a binary node and validate its type against its operands.
63     void validateExpressionTypeBinary(TIntermBinary *node);
64     // Visit a symbol node and validate it's declared previously.
65     void visitVariableNeedingDeclaration(TIntermSymbol *node);
66     // Visit a built-in symbol node and validate it's consistently used across the tree.
67     void visitBuiltInVariable(TIntermSymbol *node);
68 
69     void scope(Visit visit);
70     bool isVariableDeclared(const TVariable *variable);
71     bool variableNeedsDeclaration(const TVariable *variable);
72     const TFieldListCollection *getStructOrInterfaceBlock(const TType &type,
73                                                           ImmutableString *typeNameOut);
74 
75     void expectNonNullChildren(Visit visit, TIntermNode *node, size_t least_count);
76 
77     bool validateInternal();
78 
79     ValidateASTOptions mOptions;
80     TDiagnostics *mDiagnostics;
81 
82     // For validateSingleParent:
83     std::map<TIntermNode *, TIntermNode *> mParent;
84     bool mSingleParentFailed = false;
85 
86     // For validateVariableReferences:
87     std::vector<std::set<const TVariable *>> mDeclaredVariables;
88     std::set<const TInterfaceBlock *> mNamelessInterfaceBlocks;
89     std::map<ImmutableString, const TVariable *> mReferencedBuiltIns;
90     bool mVariableReferencesFailed = false;
91 
92     // For validateBuiltInOps:
93     bool mBuiltInOpsFailed = false;
94 
95     // For validateFunctionCall:
96     std::set<const TFunction *> mDeclaredFunctions;
97     bool mFunctionCallFailed = false;
98 
99     // For validateNoRawFunctionCalls:
100     bool mNoRawFunctionCallsFailed = false;
101 
102     // For validateNullNodes:
103     bool mNullNodesFailed = false;
104 
105     // For validateQualifiers:
106     bool mQualifiersFailed = false;
107 
108     // For validatePrecision:
109     bool mPrecisionFailed = false;
110 
111     // For validateStructUsage:
112     std::vector<std::map<ImmutableString, const TFieldListCollection *>> mStructsAndBlocksByName;
113     bool mStructUsageFailed = false;
114 
115     // For validateExpressionTypes:
116     bool mExpressionTypesFailed = false;
117 
118     // For validateMultiDeclarations:
119     bool mMultiDeclarationsFailed = false;
120 };
121 
IsSameType(const TType & a,const TType & b)122 bool IsSameType(const TType &a, const TType &b)
123 {
124     return a.getBasicType() == b.getBasicType() && a.getNominalSize() == b.getNominalSize() &&
125            a.getSecondarySize() == b.getSecondarySize() && a.getArraySizes() == b.getArraySizes() &&
126            a.getStruct() == b.getStruct() &&
127            (!a.isInterfaceBlock() || a.getInterfaceBlock() == b.getInterfaceBlock());
128 }
129 
validate(TIntermNode * root,TDiagnostics * diagnostics,const ValidateASTOptions & options)130 bool ValidateAST::validate(TIntermNode *root,
131                            TDiagnostics *diagnostics,
132                            const ValidateASTOptions &options)
133 {
134     ValidateAST validate(root, diagnostics, options);
135     root->traverse(&validate);
136     return validate.validateInternal();
137 }
138 
ValidateAST(TIntermNode * root,TDiagnostics * diagnostics,const ValidateASTOptions & options)139 ValidateAST::ValidateAST(TIntermNode *root,
140                          TDiagnostics *diagnostics,
141                          const ValidateASTOptions &options)
142     : TIntermTraverser(true, false, true, nullptr), mOptions(options), mDiagnostics(diagnostics)
143 {
144     bool isTreeRoot = root->getAsBlock() && root->getAsBlock()->isTreeRoot();
145 
146     // Some validations are not applicable unless run on the entire tree.
147     if (!isTreeRoot)
148     {
149         mOptions.validateVariableReferences = false;
150         mOptions.validateFunctionCall       = false;
151     }
152 
153     if (mOptions.validateSingleParent)
154     {
155         mParent[root] = nullptr;
156     }
157 }
158 
visitNode(Visit visit,TIntermNode * node)159 void ValidateAST::visitNode(Visit visit, TIntermNode *node)
160 {
161     if (visit == PreVisit && mOptions.validateSingleParent)
162     {
163         size_t childCount = node->getChildCount();
164         for (size_t i = 0; i < childCount; ++i)
165         {
166             TIntermNode *child = node->getChildNode(i);
167             if (mParent.find(child) != mParent.end())
168             {
169                 // If child is visited twice but through the same parent, the problem is in one of
170                 // the ancestors.
171                 if (mParent[child] != node)
172                 {
173                     mDiagnostics->error(node->getLine(), "Found child with two parents",
174                                         "<validateSingleParent>");
175                     mSingleParentFailed = true;
176                 }
177             }
178 
179             mParent[child] = node;
180         }
181     }
182 }
183 
visitStructOrInterfaceBlockDeclaration(const TType & type,const TSourceLoc & location)184 void ValidateAST::visitStructOrInterfaceBlockDeclaration(const TType &type,
185                                                          const TSourceLoc &location)
186 {
187     if (type.getStruct() == nullptr && type.getInterfaceBlock() == nullptr)
188     {
189         return;
190     }
191 
192     // Make sure the structure or interface block is not doubly defined.
193     ImmutableString typeName("");
194     const TFieldListCollection *structOrBlock = getStructOrInterfaceBlock(type, &typeName);
195 
196     if (structOrBlock)
197     {
198         ASSERT(!typeName.empty());
199 
200         // Allow gl_PerVertex to be doubly-defined.
201         if (typeName == "gl_PerVertex")
202         {
203             if (IsShaderIn(type.getQualifier()))
204             {
205                 typeName = ImmutableString("gl_PerVertex<input>");
206             }
207             else
208             {
209                 ASSERT(IsShaderOut(type.getQualifier()));
210                 typeName = ImmutableString("gl_PerVertex<output>");
211             }
212         }
213 
214         if (mStructsAndBlocksByName.back().find(typeName) != mStructsAndBlocksByName.back().end())
215         {
216             mDiagnostics->error(location,
217                                 "Found redeclaration of struct or interface block with the same "
218                                 "name in the same scope <validateStructUsage>",
219                                 typeName.data());
220             mStructUsageFailed = true;
221         }
222         else
223         {
224             // First encounter.
225             mStructsAndBlocksByName.back()[typeName] = structOrBlock;
226         }
227     }
228 
229     // Recurse the fields of the structure or interface block and check members of structure type.
230     // Note that structOrBlock was previously only set for named structures, so make sure nameless
231     // structs are also recursed.
232     if (structOrBlock == nullptr)
233     {
234         structOrBlock = type.getStruct();
235     }
236     ASSERT(structOrBlock != nullptr);
237 
238     for (const TField *field : structOrBlock->fields())
239     {
240         visitStructUsage(*field->type(), field->line());
241     }
242 }
243 
visitStructUsage(const TType & type,const TSourceLoc & location)244 void ValidateAST::visitStructUsage(const TType &type, const TSourceLoc &location)
245 {
246     if (type.getStruct() == nullptr)
247     {
248         return;
249     }
250 
251     // Make sure the structure being referenced has the same pointer as the closest (in scope)
252     // definition.
253     const TStructure *structure     = type.getStruct();
254     const ImmutableString &typeName = structure->name();
255 
256     bool foundDeclaration = false;
257     for (size_t scopeIndex = mStructsAndBlocksByName.size(); scopeIndex > 0; --scopeIndex)
258     {
259         const std::map<ImmutableString, const TFieldListCollection *> &scopeDecls =
260             mStructsAndBlocksByName[scopeIndex - 1];
261 
262         auto iter = scopeDecls.find(typeName);
263         if (iter != scopeDecls.end())
264         {
265             foundDeclaration = true;
266 
267             if (iter->second != structure)
268             {
269                 mDiagnostics->error(location,
270                                     "Found reference to struct or interface block with doubly "
271                                     "created type <validateStructUsage>",
272                                     typeName.data());
273                 mStructUsageFailed = true;
274             }
275 
276             break;
277         }
278     }
279 
280     if (!foundDeclaration)
281     {
282         mDiagnostics->error(location,
283                             "Found reference to struct or interface block with no declaration "
284                             "<validateStructUsage>",
285                             typeName.data());
286         mStructUsageFailed = true;
287     }
288 }
289 
visitBuiltInFunction(TIntermOperator * node,const TFunction * function)290 void ValidateAST::visitBuiltInFunction(TIntermOperator *node, const TFunction *function)
291 {
292     const TOperator op = node->getOp();
293     if (!BuiltInGroup::IsBuiltIn(op))
294     {
295         return;
296     }
297 
298     ImmutableStringBuilder opValueBuilder(16);
299     opValueBuilder << "op: ";
300     opValueBuilder.appendDecimal(op);
301 
302     ImmutableString opValue = opValueBuilder;
303 
304     if (function == nullptr)
305     {
306         mDiagnostics->error(node->getLine(),
307                             "Found node calling built-in without a reference to the built-in "
308                             "function <validateBuiltInOps>",
309                             opValue.data());
310         mVariableReferencesFailed = true;
311     }
312     else if (function->getBuiltInOp() != op)
313     {
314         mDiagnostics->error(node->getLine(),
315                             "Found node calling built-in with a reference to a different function "
316                             "<validateBuiltInOps>",
317                             opValue.data());
318         mVariableReferencesFailed = true;
319     }
320 }
321 
visitFunctionCall(TIntermAggregate * node)322 void ValidateAST::visitFunctionCall(TIntermAggregate *node)
323 {
324     if (node->getOp() != EOpCallFunctionInAST)
325     {
326         return;
327     }
328 
329     const TFunction *function = node->getFunction();
330 
331     if (function == nullptr)
332     {
333         mDiagnostics->error(node->getLine(),
334                             "Found node calling function without a reference to it",
335                             "<validateFunctionCall>");
336         mFunctionCallFailed = true;
337     }
338     else if (mDeclaredFunctions.find(function) == mDeclaredFunctions.end())
339     {
340         mDiagnostics->error(node->getLine(),
341                             "Found node calling previously undeclared function "
342                             "<validateFunctionCall>",
343                             function->name().data());
344         mFunctionCallFailed = true;
345     }
346 }
347 
validateExpressionTypeBinary(TIntermBinary * node)348 void ValidateAST::validateExpressionTypeBinary(TIntermBinary *node)
349 {
350     switch (node->getOp())
351     {
352         case EOpIndexDirect:
353         case EOpIndexIndirect:
354         {
355             TType expectedType(node->getLeft()->getType());
356             if (!expectedType.isArray())
357             {
358                 // TODO: Validate matrix column selection and vector component selection.
359                 // http://anglebug.com/2733
360                 break;
361             }
362 
363             expectedType.toArrayElementType();
364 
365             if (!IsSameType(node->getType(), expectedType))
366             {
367                 const TSymbol *symbol = expectedType.getStruct();
368                 if (symbol == nullptr)
369                 {
370                     symbol = expectedType.getInterfaceBlock();
371                 }
372                 const char *name = nullptr;
373                 if (symbol)
374                 {
375                     name = symbol->name().data();
376                 }
377                 else if (expectedType.isScalar())
378                 {
379                     name = "<scalar array>";
380                 }
381                 else if (expectedType.isVector())
382                 {
383                     name = "<vector array>";
384                 }
385                 else
386                 {
387                     ASSERT(expectedType.isMatrix());
388                     name = "<matrix array>";
389                 }
390 
391                 mDiagnostics->error(
392                     node->getLine(),
393                     "Found index node with type that is inconsistent with the array being indexed "
394                     "<validateExpressionTypes>",
395                     name);
396                 mExpressionTypesFailed = true;
397             }
398         }
399         break;
400         default:
401             // TODO: Validate other expressions. http://anglebug.com/2733
402             break;
403     }
404 }
405 
visitVariableNeedingDeclaration(TIntermSymbol * node)406 void ValidateAST::visitVariableNeedingDeclaration(TIntermSymbol *node)
407 {
408     const TVariable *variable = &node->variable();
409     const TType &type         = node->getType();
410 
411     // If it's a reference to a field of a nameless interface block, match it by index and name.
412     if (type.getInterfaceBlock() && !type.isInterfaceBlock())
413     {
414         const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
415         const TFieldList &fieldList           = interfaceBlock->fields();
416         const size_t fieldIndex               = type.getInterfaceBlockFieldIndex();
417 
418         if (mNamelessInterfaceBlocks.count(interfaceBlock) == 0)
419         {
420             mDiagnostics->error(node->getLine(),
421                                 "Found reference to undeclared or inconsistenly transformed "
422                                 "nameless interface block <validateVariableReferences>",
423                                 node->getName().data());
424             mVariableReferencesFailed = true;
425         }
426         else if (fieldIndex >= fieldList.size() || node->getName() != fieldList[fieldIndex]->name())
427         {
428             mDiagnostics->error(node->getLine(),
429                                 "Found reference to inconsistenly transformed nameless "
430                                 "interface block field <validateVariableReferences>",
431                                 node->getName().data());
432             mVariableReferencesFailed = true;
433         }
434         return;
435     }
436 
437     const bool isStructDeclaration =
438         type.isStructSpecifier() && variable->symbolType() == SymbolType::Empty;
439 
440     if (!isStructDeclaration && !isVariableDeclared(variable))
441     {
442         mDiagnostics->error(node->getLine(),
443                             "Found reference to undeclared or inconsistently transformed "
444                             "variable <validateVariableReferences>",
445                             node->getName().data());
446         mVariableReferencesFailed = true;
447     }
448 }
449 
visitBuiltInVariable(TIntermSymbol * node)450 void ValidateAST::visitBuiltInVariable(TIntermSymbol *node)
451 {
452     const TVariable *variable = &node->variable();
453     ImmutableString name      = variable->name();
454 
455     if (mOptions.validateVariableReferences)
456     {
457         auto iter = mReferencedBuiltIns.find(name);
458         if (iter == mReferencedBuiltIns.end())
459         {
460             mReferencedBuiltIns[name] = variable;
461             return;
462         }
463 
464         if (variable != iter->second)
465         {
466             mDiagnostics->error(
467                 node->getLine(),
468                 "Found inconsistent references to built-in variable <validateVariableReferences>",
469                 name.data());
470             mVariableReferencesFailed = true;
471         }
472     }
473 
474     if (mOptions.validateQualifiers)
475     {
476         TQualifier qualifier = variable->getType().getQualifier();
477 
478         if ((name == "gl_ClipDistance" && qualifier != EvqClipDistance) ||
479             (name == "gl_CullDistance" && qualifier != EvqCullDistance) ||
480             (name == "gl_LastFragData" && qualifier != EvqLastFragData))
481         {
482             mDiagnostics->error(
483                 node->getLine(),
484                 "Incorrect qualifier applied to redeclared built-in <validateQualifiers>",
485                 name.data());
486             mQualifiersFailed = true;
487         }
488     }
489 }
490 
scope(Visit visit)491 void ValidateAST::scope(Visit visit)
492 {
493     if (mOptions.validateVariableReferences)
494     {
495         if (visit == PreVisit)
496         {
497             mDeclaredVariables.push_back({});
498         }
499         else if (visit == PostVisit)
500         {
501             mDeclaredVariables.pop_back();
502         }
503     }
504 
505     if (mOptions.validateStructUsage)
506     {
507         if (visit == PreVisit)
508         {
509             mStructsAndBlocksByName.push_back({});
510         }
511         else if (visit == PostVisit)
512         {
513             mStructsAndBlocksByName.pop_back();
514         }
515     }
516 }
517 
isVariableDeclared(const TVariable * variable)518 bool ValidateAST::isVariableDeclared(const TVariable *variable)
519 {
520     ASSERT(mOptions.validateVariableReferences);
521 
522     for (const std::set<const TVariable *> &scopeVariables : mDeclaredVariables)
523     {
524         if (scopeVariables.count(variable) > 0)
525         {
526             return true;
527         }
528     }
529 
530     return false;
531 }
532 
variableNeedsDeclaration(const TVariable * variable)533 bool ValidateAST::variableNeedsDeclaration(const TVariable *variable)
534 {
535     // Don't expect declaration for built-in variables.
536     if (gl::IsBuiltInName(variable->name().data()))
537     {
538         return false;
539     }
540 
541     // Additionally, don't expect declaration for Vulkan specialization constants if not enabled.
542     // The declaration of these variables is deferred.
543     if (variable->getType().getQualifier() == EvqSpecConst)
544     {
545         return mOptions.validateSpecConstReferences;
546     }
547 
548     return true;
549 }
550 
getStructOrInterfaceBlock(const TType & type,ImmutableString * typeNameOut)551 const TFieldListCollection *ValidateAST::getStructOrInterfaceBlock(const TType &type,
552                                                                    ImmutableString *typeNameOut)
553 {
554     const TStructure *structure           = type.getStruct();
555     const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
556 
557     ASSERT(structure != nullptr || interfaceBlock != nullptr);
558 
559     // Make sure the structure or interface block is not doubly defined.
560     const TFieldListCollection *structOrBlock = nullptr;
561     if (structure != nullptr && structure->symbolType() != SymbolType::Empty)
562     {
563         structOrBlock = structure;
564         *typeNameOut  = structure->name();
565     }
566     else if (interfaceBlock != nullptr)
567     {
568         structOrBlock = interfaceBlock;
569         *typeNameOut  = interfaceBlock->name();
570     }
571 
572     return structOrBlock;
573 }
574 
expectNonNullChildren(Visit visit,TIntermNode * node,size_t least_count)575 void ValidateAST::expectNonNullChildren(Visit visit, TIntermNode *node, size_t least_count)
576 {
577     if (visit == PreVisit && mOptions.validateNullNodes)
578     {
579         size_t childCount = node->getChildCount();
580         if (childCount < least_count)
581         {
582             mDiagnostics->error(node->getLine(), "Too few children", "<validateNullNodes>");
583             mNullNodesFailed = true;
584         }
585 
586         for (size_t i = 0; i < childCount; ++i)
587         {
588             if (node->getChildNode(i) == nullptr)
589             {
590                 mDiagnostics->error(node->getLine(), "Found nullptr child", "<validateNullNodes>");
591                 mNullNodesFailed = true;
592             }
593         }
594     }
595 }
596 
visitSymbol(TIntermSymbol * node)597 void ValidateAST::visitSymbol(TIntermSymbol *node)
598 {
599     visitNode(PreVisit, node);
600 
601     const TVariable *variable = &node->variable();
602 
603     if (mOptions.validateVariableReferences)
604     {
605         if (variableNeedsDeclaration(variable))
606         {
607             visitVariableNeedingDeclaration(node);
608         }
609     }
610 
611     const bool isBuiltIn = gl::IsBuiltInName(variable->name().data());
612     if (isBuiltIn)
613     {
614         visitBuiltInVariable(node);
615     }
616 
617     if (mOptions.validatePrecision)
618     {
619         if (!isBuiltIn && IsPrecisionApplicableToType(node->getBasicType()) &&
620             node->getType().getPrecision() == EbpUndefined)
621         {
622             // Note that some built-ins don't have a precision.
623             mDiagnostics->error(node->getLine(),
624                                 "Found symbol with undefined precision <validatePrecision>",
625                                 variable->name().data());
626             mPrecisionFailed = true;
627         }
628     }
629 }
630 
visitConstantUnion(TIntermConstantUnion * node)631 void ValidateAST::visitConstantUnion(TIntermConstantUnion *node)
632 {
633     visitNode(PreVisit, node);
634 }
635 
visitSwizzle(Visit visit,TIntermSwizzle * node)636 bool ValidateAST::visitSwizzle(Visit visit, TIntermSwizzle *node)
637 {
638     visitNode(visit, node);
639     return true;
640 }
641 
visitBinary(Visit visit,TIntermBinary * node)642 bool ValidateAST::visitBinary(Visit visit, TIntermBinary *node)
643 {
644     visitNode(visit, node);
645 
646     if (mOptions.validateExpressionTypes && visit == PreVisit)
647     {
648         validateExpressionTypeBinary(node);
649     }
650 
651     return true;
652 }
653 
visitUnary(Visit visit,TIntermUnary * node)654 bool ValidateAST::visitUnary(Visit visit, TIntermUnary *node)
655 {
656     visitNode(visit, node);
657 
658     if (visit == PreVisit && mOptions.validateBuiltInOps)
659     {
660         visitBuiltInFunction(node, node->getFunction());
661     }
662 
663     return true;
664 }
665 
visitTernary(Visit visit,TIntermTernary * node)666 bool ValidateAST::visitTernary(Visit visit, TIntermTernary *node)
667 {
668     visitNode(visit, node);
669     return true;
670 }
671 
visitIfElse(Visit visit,TIntermIfElse * node)672 bool ValidateAST::visitIfElse(Visit visit, TIntermIfElse *node)
673 {
674     visitNode(visit, node);
675     return true;
676 }
677 
visitSwitch(Visit visit,TIntermSwitch * node)678 bool ValidateAST::visitSwitch(Visit visit, TIntermSwitch *node)
679 {
680     visitNode(visit, node);
681     return true;
682 }
683 
visitCase(Visit visit,TIntermCase * node)684 bool ValidateAST::visitCase(Visit visit, TIntermCase *node)
685 {
686     visitNode(visit, node);
687     return true;
688 }
689 
visitFunctionPrototype(TIntermFunctionPrototype * node)690 void ValidateAST::visitFunctionPrototype(TIntermFunctionPrototype *node)
691 {
692     visitNode(PreVisit, node);
693 
694     if (mOptions.validateFunctionCall)
695     {
696         const TFunction *function = node->getFunction();
697         mDeclaredFunctions.insert(function);
698     }
699 
700     const TFunction *function = node->getFunction();
701     const TType &returnType   = function->getReturnType();
702     if (mOptions.validatePrecision && IsPrecisionApplicableToType(returnType.getBasicType()) &&
703         returnType.getPrecision() == EbpUndefined)
704     {
705         mDiagnostics->error(
706             node->getLine(),
707             "Found function with undefined precision on return value <validatePrecision>",
708             function->name().data());
709         mPrecisionFailed = true;
710     }
711 
712     if (mOptions.validateStructUsage)
713     {
714         if (returnType.isStructSpecifier())
715         {
716             visitStructOrInterfaceBlockDeclaration(returnType, node->getLine());
717         }
718         else
719         {
720             visitStructUsage(returnType, node->getLine());
721         }
722     }
723 
724     for (size_t paramIndex = 0; paramIndex < function->getParamCount(); ++paramIndex)
725     {
726         const TVariable *param = function->getParam(paramIndex);
727         const TType &paramType = param->getType();
728 
729         if (mOptions.validateStructUsage)
730         {
731             visitStructUsage(paramType, node->getLine());
732         }
733 
734         if (mOptions.validateQualifiers)
735         {
736             TQualifier qualifier = paramType.getQualifier();
737             if (qualifier != EvqParamIn && qualifier != EvqParamOut && qualifier != EvqParamInOut &&
738                 qualifier != EvqParamConst)
739             {
740                 mDiagnostics->error(node->getLine(),
741                                     "Found function prototype with an invalid qualifier "
742                                     "<validateQualifiers>",
743                                     param->name().data());
744                 mQualifiersFailed = true;
745             }
746         }
747 
748         if (mOptions.validatePrecision && IsPrecisionApplicableToType(paramType.getBasicType()) &&
749             paramType.getPrecision() == EbpUndefined)
750         {
751             mDiagnostics->error(
752                 node->getLine(),
753                 "Found function parameter with undefined precision <validatePrecision>",
754                 param->name().data());
755             mPrecisionFailed = true;
756         }
757     }
758 }
759 
visitFunctionDefinition(Visit visit,TIntermFunctionDefinition * node)760 bool ValidateAST::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
761 {
762     visitNode(visit, node);
763     scope(visit);
764 
765     if (mOptions.validateVariableReferences && visit == PreVisit)
766     {
767         const TFunction *function = node->getFunction();
768 
769         size_t paramCount = function->getParamCount();
770         for (size_t paramIndex = 0; paramIndex < paramCount; ++paramIndex)
771         {
772             const TVariable *variable = function->getParam(paramIndex);
773 
774             if (isVariableDeclared(variable))
775             {
776                 mDiagnostics->error(node->getLine(),
777                                     "Found two declarations of the same function argument "
778                                     "<validateVariableReferences>",
779                                     variable->name().data());
780                 mVariableReferencesFailed = true;
781                 break;
782             }
783 
784             mDeclaredVariables.back().insert(variable);
785         }
786     }
787 
788     return true;
789 }
790 
visitAggregate(Visit visit,TIntermAggregate * node)791 bool ValidateAST::visitAggregate(Visit visit, TIntermAggregate *node)
792 {
793     visitNode(visit, node);
794     expectNonNullChildren(visit, node, 0);
795 
796     if (visit == PreVisit && mOptions.validateBuiltInOps)
797     {
798         visitBuiltInFunction(node, node->getFunction());
799     }
800 
801     if (visit == PreVisit && mOptions.validateFunctionCall)
802     {
803         visitFunctionCall(node);
804     }
805 
806     if (visit == PreVisit && mOptions.validateNoRawFunctionCalls)
807     {
808         if (node->getOp() == EOpCallInternalRawFunction)
809         {
810             mDiagnostics->error(node->getLine(),
811                                 "Found node calling a raw function (deprecated) "
812                                 "<validateNoRawFunctionCalls>",
813                                 node->getFunction()->name().data());
814             mNoRawFunctionCallsFailed = true;
815         }
816     }
817 
818     return true;
819 }
820 
visitBlock(Visit visit,TIntermBlock * node)821 bool ValidateAST::visitBlock(Visit visit, TIntermBlock *node)
822 {
823     visitNode(visit, node);
824     scope(visit);
825     expectNonNullChildren(visit, node, 0);
826     return true;
827 }
828 
visitGlobalQualifierDeclaration(Visit visit,TIntermGlobalQualifierDeclaration * node)829 bool ValidateAST::visitGlobalQualifierDeclaration(Visit visit,
830                                                   TIntermGlobalQualifierDeclaration *node)
831 {
832     visitNode(visit, node);
833 
834     const TVariable *variable = &node->getSymbol()->variable();
835 
836     if (mOptions.validateVariableReferences && variableNeedsDeclaration(variable))
837     {
838         if (!isVariableDeclared(variable))
839         {
840             mDiagnostics->error(node->getLine(),
841                                 "Found reference to undeclared or inconsistently transformed "
842                                 "variable <validateVariableReferences>",
843                                 variable->name().data());
844             mVariableReferencesFailed = true;
845         }
846     }
847     return true;
848 }
849 
visitDeclaration(Visit visit,TIntermDeclaration * node)850 bool ValidateAST::visitDeclaration(Visit visit, TIntermDeclaration *node)
851 {
852     visitNode(visit, node);
853     expectNonNullChildren(visit, node, 0);
854 
855     const TIntermSequence &sequence = *(node->getSequence());
856 
857     if (mOptions.validateMultiDeclarations && sequence.size() > 1)
858     {
859         TIntermSymbol *symbol = sequence[1]->getAsSymbolNode();
860         if (symbol == nullptr)
861         {
862             TIntermBinary *init = sequence[1]->getAsBinaryNode();
863             ASSERT(init && init->getOp() == EOpInitialize);
864             symbol = init->getLeft()->getAsSymbolNode();
865         }
866         ASSERT(symbol);
867 
868         mDiagnostics->error(node->getLine(),
869                             "Found multiple declarations where SeparateDeclarations should have "
870                             "separated them <validateMultiDeclarations>",
871                             symbol->variable().name().data());
872         mMultiDeclarationsFailed = true;
873     }
874 
875     if (visit == PreVisit)
876     {
877         bool validateStructUsage = mOptions.validateStructUsage;
878 
879         for (TIntermNode *instance : sequence)
880         {
881             TIntermSymbol *symbol = instance->getAsSymbolNode();
882             if (symbol == nullptr)
883             {
884                 TIntermBinary *init = instance->getAsBinaryNode();
885                 ASSERT(init && init->getOp() == EOpInitialize);
886                 symbol = init->getLeft()->getAsSymbolNode();
887             }
888             ASSERT(symbol);
889 
890             const TVariable *variable = &symbol->variable();
891             const TType &type         = variable->getType();
892 
893             if (mOptions.validateVariableReferences)
894             {
895                 if (isVariableDeclared(variable))
896                 {
897                     mDiagnostics->error(
898                         node->getLine(),
899                         "Found two declarations of the same variable <validateVariableReferences>",
900                         variable->name().data());
901                     mVariableReferencesFailed = true;
902                     break;
903                 }
904 
905                 mDeclaredVariables.back().insert(variable);
906 
907                 const TInterfaceBlock *interfaceBlock = variable->getType().getInterfaceBlock();
908 
909                 if (variable->symbolType() == SymbolType::Empty && interfaceBlock != nullptr)
910                 {
911                     // Nameless interface blocks can only be declared at the top level.  Their
912                     // fields are matched by field index, and then verified to match by name.
913                     // Conflict in names should have already generated a compile error.
914                     ASSERT(mDeclaredVariables.size() == 1);
915                     ASSERT(mNamelessInterfaceBlocks.count(interfaceBlock) == 0);
916 
917                     mNamelessInterfaceBlocks.insert(interfaceBlock);
918                 }
919             }
920 
921             if (validateStructUsage)
922             {
923                 // Only declare and/or validate the struct once.
924                 validateStructUsage = false;
925 
926                 if (type.isStructSpecifier() || type.isInterfaceBlock())
927                 {
928                     visitStructOrInterfaceBlockDeclaration(type, node->getLine());
929                 }
930                 else
931                 {
932                     visitStructUsage(type, node->getLine());
933                 }
934             }
935 
936             if (gl::IsBuiltInName(variable->name().data()))
937             {
938                 visitBuiltInVariable(symbol);
939             }
940 
941             if (mOptions.validatePrecision && (type.isStructSpecifier() || type.isInterfaceBlock()))
942             {
943                 const TFieldListCollection *structOrBlock = type.getStruct();
944                 if (structOrBlock == nullptr)
945                 {
946                     structOrBlock = type.getInterfaceBlock();
947                 }
948 
949                 for (const TField *field : structOrBlock->fields())
950                 {
951                     const TType *fieldType = field->type();
952                     if (IsPrecisionApplicableToType(fieldType->getBasicType()) &&
953                         fieldType->getPrecision() == EbpUndefined)
954                     {
955                         mDiagnostics->error(
956                             node->getLine(),
957                             "Found block field with undefined precision <validatePrecision>",
958                             field->name().data());
959                         mPrecisionFailed = true;
960                     }
961                 }
962             }
963         }
964     }
965 
966     return true;
967 }
968 
visitLoop(Visit visit,TIntermLoop * node)969 bool ValidateAST::visitLoop(Visit visit, TIntermLoop *node)
970 {
971     visitNode(visit, node);
972     return true;
973 }
974 
visitBranch(Visit visit,TIntermBranch * node)975 bool ValidateAST::visitBranch(Visit visit, TIntermBranch *node)
976 {
977     visitNode(visit, node);
978     return true;
979 }
980 
visitPreprocessorDirective(TIntermPreprocessorDirective * node)981 void ValidateAST::visitPreprocessorDirective(TIntermPreprocessorDirective *node)
982 {
983     visitNode(PreVisit, node);
984 }
985 
validateInternal()986 bool ValidateAST::validateInternal()
987 {
988     return !mSingleParentFailed && !mVariableReferencesFailed && !mBuiltInOpsFailed &&
989            !mFunctionCallFailed && !mNoRawFunctionCallsFailed && !mNullNodesFailed &&
990            !mQualifiersFailed && !mPrecisionFailed && !mStructUsageFailed &&
991            !mExpressionTypesFailed && !mMultiDeclarationsFailed;
992 }
993 
994 }  // anonymous namespace
995 
ValidateAST(TIntermNode * root,TDiagnostics * diagnostics,const ValidateASTOptions & options)996 bool ValidateAST(TIntermNode *root, TDiagnostics *diagnostics, const ValidateASTOptions &options)
997 {
998     // ValidateAST is called after transformations, so if |validateNoMoreTransformations| is set,
999     // it's immediately an error.
1000     if (options.validateNoMoreTransformations)
1001     {
1002         diagnostics->error(kNoSourceLoc, "Unexpected transformation after AST post-processing",
1003                            "<validateNoMoreTransformations>");
1004         return false;
1005     }
1006 
1007     return ValidateAST::validate(root, diagnostics, options);
1008 }
1009 
1010 }  // namespace sh
1011