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/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index feae684..3af0e17 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -1519,84 +1519,80 @@
     return false;
 }
 
+bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
+{
+    TInfoSinkBase &out = getInfoSink();
+    if (visit == PreVisit)
+    {
+        TIntermSequence *sequence = node->getSequence();
+        TIntermTyped *variable    = (*sequence)[0]->getAsTyped();
+        ASSERT(sequence->size() == 1);
+
+        if (variable &&
+            (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
+             variable->getQualifier() == EvqConst))
+        {
+            ensureStructDefined(variable->getType());
+
+            if (!variable->getAsSymbolNode() ||
+                variable->getAsSymbolNode()->getSymbol() != "")  // Variable declaration
+            {
+                if (!mInsideFunction)
+                {
+                    out << "static ";
+                }
+
+                out << TypeString(variable->getType()) + " ";
+
+                TIntermSymbol *symbol = variable->getAsSymbolNode();
+
+                if (symbol)
+                {
+                    symbol->traverse(this);
+                    out << ArrayString(symbol->getType());
+                    out << " = " + initializer(symbol->getType());
+                }
+                else
+                {
+                    variable->traverse(this);
+                }
+            }
+            else if (variable->getAsSymbolNode() &&
+                     variable->getAsSymbolNode()->getSymbol() == "")  // Type (struct) declaration
+            {
+                // Already added to constructor map
+            }
+            else
+                UNREACHABLE();
+        }
+        else if (variable && IsVaryingOut(variable->getQualifier()))
+        {
+            for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++)
+            {
+                TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
+
+                if (symbol)
+                {
+                    // Vertex (output) varyings which are declared but not written to should
+                    // still be declared to allow successful linking
+                    mReferencedVaryings[symbol->getSymbol()] = symbol;
+                }
+                else
+                {
+                    (*sit)->traverse(this);
+                }
+            }
+        }
+    }
+    return false;
+}
+
 bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
 {
     TInfoSinkBase &out = getInfoSink();
 
     switch (node->getOp())
     {
-        case EOpDeclaration:
-            if (visit == PreVisit)
-            {
-                TIntermSequence *sequence = node->getSequence();
-                TIntermTyped *variable    = (*sequence)[0]->getAsTyped();
-                ASSERT(sequence->size() == 1);
-
-                if (variable &&
-                    (variable->getQualifier() == EvqTemporary ||
-                     variable->getQualifier() == EvqGlobal || variable->getQualifier() == EvqConst))
-                {
-                    ensureStructDefined(variable->getType());
-
-                    if (!variable->getAsSymbolNode() ||
-                        variable->getAsSymbolNode()->getSymbol() != "")  // Variable declaration
-                    {
-                        if (!mInsideFunction)
-                        {
-                            out << "static ";
-                        }
-
-                        out << TypeString(variable->getType()) + " ";
-
-                        TIntermSymbol *symbol = variable->getAsSymbolNode();
-
-                        if (symbol)
-                        {
-                            symbol->traverse(this);
-                            out << ArrayString(symbol->getType());
-                            out << " = " + initializer(symbol->getType());
-                        }
-                        else
-                        {
-                            variable->traverse(this);
-                        }
-                    }
-                    else if (variable->getAsSymbolNode() &&
-                             variable->getAsSymbolNode()->getSymbol() ==
-                                 "")  // Type (struct) declaration
-                    {
-                        // Already added to constructor map
-                    }
-                    else
-                        UNREACHABLE();
-                }
-                else if (variable && IsVaryingOut(variable->getQualifier()))
-                {
-                    for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end();
-                         sit++)
-                    {
-                        TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
-
-                        if (symbol)
-                        {
-                            // Vertex (output) varyings which are declared but not written to should
-                            // still be declared to allow successful linking
-                            mReferencedVaryings[symbol->getSymbol()] = symbol;
-                        }
-                        else
-                        {
-                            (*sit)->traverse(this);
-                        }
-                    }
-                }
-
-                return false;
-            }
-            else if (visit == InVisit)
-            {
-                out << ", ";
-            }
-            break;
         case EOpInvariantDeclaration:
             // Do not do any translation
             return false;
@@ -2177,39 +2173,6 @@
     return true;
 }
 
-bool OutputHLSL::isSingleStatement(TIntermNode *node)
-{
-    if (node->getAsBlock())
-    {
-        return false;
-    }
-
-    TIntermAggregate *aggregate = node->getAsAggregate();
-    if (aggregate)
-    {
-        if (aggregate->getOp() == EOpDeclaration)
-        {
-            // Declaring multiple comma-separated variables must be considered multiple statements
-            // because each individual declaration has side effects which are visible in the next.
-            return false;
-        }
-        else
-        {
-            for (TIntermSequence::iterator sit = aggregate->getSequence()->begin(); sit != aggregate->getSequence()->end(); sit++)
-            {
-                if (!isSingleStatement(*sit))
-                {
-                    return false;
-                }
-            }
-
-            return true;
-        }
-    }
-
-    return true;
-}
-
 // Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
 // (The D3D documentation says 255 iterations, but the compiler complains at anything more than 254).
 bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
@@ -2227,7 +2190,7 @@
     // Parse index name and intial value
     if (node->getInit())
     {
-        TIntermAggregate *init = node->getInit()->getAsAggregate();
+        TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
 
         if (init)
         {