tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ValidateAST.cpp (38163B)


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