Split TIntermDeclaration from TIntermAggregate

The new class TIntermDeclaration is now used for struct, interface
block and variable declarations. TIntermDeclaration nodes do not have
a type - rather the type is stored in each child node. The types may
differ in case the declaration is a series of array declarators with
mismatching sizes.

TIntermAggregate is still used for function calls, function
prototypes, function parameter lists and invariant declarations.

BUG=angleproject:1490
TEST=angle_unittests

Change-Id: I0457188f354481470855f61ac1c878fc2579b1d1
Reviewed-on: https://chromium-review.googlesource.com/400023
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/compiler/translator/PruneEmptyDeclarations.cpp b/src/compiler/translator/PruneEmptyDeclarations.cpp
index 4763dd6..133130d 100644
--- a/src/compiler/translator/PruneEmptyDeclarations.cpp
+++ b/src/compiler/translator/PruneEmptyDeclarations.cpp
@@ -18,7 +18,7 @@
     static void apply(TIntermNode *root);
   private:
     PruneEmptyDeclarationsTraverser();
-    bool visitAggregate(Visit, TIntermAggregate *node) override;
+    bool visitDeclaration(Visit, TIntermDeclaration *node) override;
 };
 
 void PruneEmptyDeclarationsTraverser::apply(TIntermNode *root)
@@ -33,74 +33,71 @@
 {
 }
 
-bool PruneEmptyDeclarationsTraverser::visitAggregate(Visit, TIntermAggregate *node)
+bool PruneEmptyDeclarationsTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
 {
-    if (node->getOp() == EOpDeclaration)
+    TIntermSequence *sequence = node->getSequence();
+    if (sequence->size() >= 1)
     {
-        TIntermSequence *sequence = node->getSequence();
-        if (sequence->size() >= 1)
+        TIntermSymbol *sym = sequence->front()->getAsSymbolNode();
+        // Prune declarations without a variable name, unless it's an interface block declaration.
+        if (sym != nullptr && sym->getSymbol() == "" && !sym->isInterfaceBlock())
         {
-            TIntermSymbol *sym = sequence->front()->getAsSymbolNode();
-            // Prune declarations without a variable name, unless it's an interface block declaration.
-            if (sym != nullptr && sym->getSymbol() == "" && !sym->isInterfaceBlock())
+            if (sequence->size() > 1)
             {
-                if (sequence->size() > 1)
+                // Generate a replacement that will remove the empty declarator in the beginning of
+                // a declarator list. Example of a declaration that will be changed:
+                // float, a;
+                // will be changed to
+                // float a;
+                // This applies also to struct declarations.
+                TIntermSequence emptyReplacement;
+                mMultiReplacements.push_back(
+                    NodeReplaceWithMultipleEntry(node, sym, emptyReplacement));
+            }
+            else if (sym->getBasicType() != EbtStruct)
+            {
+                // Single struct declarations may just declare the struct type and no variables, so
+                // they should not be pruned. All other single empty declarations can be pruned
+                // entirely. Example of an empty declaration that will be pruned:
+                // float;
+                TIntermSequence emptyReplacement;
+                TIntermBlock *parentAsBlock = getParentNode()->getAsBlock();
+                // The declaration may be inside a block or in a loop init expression.
+                ASSERT(parentAsBlock != nullptr || getParentNode()->getAsLoopNode() != nullptr);
+                if (parentAsBlock)
                 {
-                    // Generate a replacement that will remove the empty declarator in the beginning of a declarator
-                    // list. Example of a declaration that will be changed:
-                    // float, a;
-                    // will be changed to
-                    // float a;
-                    // This applies also to struct declarations.
-                    TIntermSequence emptyReplacement;
-                    mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(node, sym, emptyReplacement));
+                    mMultiReplacements.push_back(
+                        NodeReplaceWithMultipleEntry(parentAsBlock, node, emptyReplacement));
                 }
-                else if (sym->getBasicType() != EbtStruct)
+                else
                 {
-                    // Single struct declarations may just declare the struct type and no variables, so they should
-                    // not be pruned. All other single empty declarations can be pruned entirely. Example of an empty
-                    // declaration that will be pruned:
-                    // float;
-                    TIntermSequence emptyReplacement;
-                    TIntermBlock *parentAsBlock = getParentNode()->getAsBlock();
-                    // The declaration may be inside a block or in a loop init expression.
-                    ASSERT(parentAsBlock != nullptr || getParentNode()->getAsLoopNode() != nullptr);
-                    if (parentAsBlock)
-                    {
-                        mMultiReplacements.push_back(
-                            NodeReplaceWithMultipleEntry(parentAsBlock, node, emptyReplacement));
-                    }
-                    else
-                    {
-                        queueReplacement(node, nullptr, OriginalNode::IS_DROPPED);
-                    }
+                    queueReplacement(node, nullptr, OriginalNode::IS_DROPPED);
                 }
-                else if (sym->getType().getQualifier() != EvqGlobal &&
-                         sym->getType().getQualifier() != EvqTemporary)
-                {
-                    // We've hit an empty struct declaration with a qualifier, for example like
-                    // this:
-                    // const struct a { int i; };
-                    // NVIDIA GL driver version 367.27 doesn't accept this kind of declarations, so
-                    // we convert the declaration to a regular struct declaration. This is okay,
-                    // since ESSL 1.00 spec section 4.1.8 says about structs that "The optional
-                    // qualifiers only apply to any declarators, and are not part of the type being
-                    // defined for name."
+            }
+            else if (sym->getType().getQualifier() != EvqGlobal &&
+                     sym->getType().getQualifier() != EvqTemporary)
+            {
+                // We've hit an empty struct declaration with a qualifier, for example like
+                // this:
+                // const struct a { int i; };
+                // NVIDIA GL driver version 367.27 doesn't accept this kind of declarations, so
+                // we convert the declaration to a regular struct declaration. This is okay,
+                // since ESSL 1.00 spec section 4.1.8 says about structs that "The optional
+                // qualifiers only apply to any declarators, and are not part of the type being
+                // defined for name."
 
-                    if (mInGlobalScope)
-                    {
-                        sym->getTypePointer()->setQualifier(EvqGlobal);
-                    }
-                    else
-                    {
-                        sym->getTypePointer()->setQualifier(EvqTemporary);
-                    }
+                if (mInGlobalScope)
+                {
+                    sym->getTypePointer()->setQualifier(EvqGlobal);
+                }
+                else
+                {
+                    sym->getTypePointer()->setQualifier(EvqTemporary);
                 }
             }
         }
-        return false;
     }
-    return true;
+    return false;
 }
 
 } // namespace