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/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index fc5ea60..2e2c27e 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -1475,9 +1475,10 @@
                                        const TString &identifier,
                                        const TPublicType &pType,
                                        TIntermTyped *initializer,
-                                       TIntermNode **intermNode)
+                                       TIntermBinary **initNode)
 {
-    ASSERT(intermNode != nullptr);
+    ASSERT(initNode != nullptr);
+    ASSERT(*initNode == nullptr);
     TType type = TType(pType);
 
     TVariable *variable = nullptr;
@@ -1549,7 +1550,7 @@
         if (initializer->getAsConstantUnion())
         {
             variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
-            *intermNode = nullptr;
+            *initNode = nullptr;
             return false;
         }
         else if (initializer->getAsSymbolNode())
@@ -1562,7 +1563,7 @@
             if (constArray)
             {
                 variable->shareConstPointer(constArray);
-                *intermNode = nullptr;
+                *initNode = nullptr;
                 return false;
             }
         }
@@ -1570,8 +1571,8 @@
 
     TIntermSymbol *intermSymbol = intermediate.addSymbol(
         variable->getUniqueId(), variable->getName(), variable->getType(), line);
-    *intermNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
-    if (*intermNode == nullptr)
+    *initNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
+    if (*initNode == nullptr)
     {
         assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
         return true;
@@ -1753,9 +1754,10 @@
     return true;
 }
 
-TIntermAggregate *TParseContext::parseSingleDeclaration(TPublicType &publicType,
-                                                        const TSourceLoc &identifierOrTypeLocation,
-                                                        const TString &identifier)
+TIntermDeclaration *TParseContext::parseSingleDeclaration(
+    TPublicType &publicType,
+    const TSourceLoc &identifierOrTypeLocation,
+    const TString &identifier)
 {
     TType type(publicType);
     if ((mCompileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) &&
@@ -1791,6 +1793,9 @@
 
     mDeferredSingleDeclarationErrorCheck = emptyDeclaration;
 
+    TIntermDeclaration *declaration = new TIntermDeclaration();
+    declaration->setLine(identifierOrTypeLocation);
+
     if (emptyDeclaration)
     {
         if (publicType.isUnsizedArray())
@@ -1811,17 +1816,23 @@
         declareVariable(identifierOrTypeLocation, identifier, type, &variable);
 
         if (variable && symbol)
+        {
             symbol->setId(variable->getUniqueId());
+        }
     }
 
-    return TIntermediate::MakeAggregate(symbol, identifierOrTypeLocation);
+    // We append the symbol even if the declaration is empty, mainly because of struct declarations
+    // that may just declare a type.
+    declaration->appendDeclarator(symbol);
+
+    return declaration;
 }
 
-TIntermAggregate *TParseContext::parseSingleArrayDeclaration(TPublicType &publicType,
-                                                             const TSourceLoc &identifierLocation,
-                                                             const TString &identifier,
-                                                             const TSourceLoc &indexLocation,
-                                                             TIntermTyped *indexExpression)
+TIntermDeclaration *TParseContext::parseSingleArrayDeclaration(TPublicType &publicType,
+                                                               const TSourceLoc &identifierLocation,
+                                                               const TString &identifier,
+                                                               const TSourceLoc &indexLocation,
+                                                               TIntermTyped *indexExpression)
 {
     mDeferredSingleDeclarationErrorCheck = false;
 
@@ -1841,38 +1852,44 @@
     TVariable *variable = nullptr;
     declareVariable(identifierLocation, identifier, arrayType, &variable);
 
+    TIntermDeclaration *declaration = new TIntermDeclaration();
+    declaration->setLine(identifierLocation);
+
     TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
     if (variable && symbol)
+    {
         symbol->setId(variable->getUniqueId());
+        declaration->appendDeclarator(symbol);
+    }
 
-    return TIntermediate::MakeAggregate(symbol, identifierLocation);
+    return declaration;
 }
 
-TIntermAggregate *TParseContext::parseSingleInitDeclaration(const TPublicType &publicType,
-                                                            const TSourceLoc &identifierLocation,
-                                                            const TString &identifier,
-                                                            const TSourceLoc &initLocation,
-                                                            TIntermTyped *initializer)
+TIntermDeclaration *TParseContext::parseSingleInitDeclaration(const TPublicType &publicType,
+                                                              const TSourceLoc &identifierLocation,
+                                                              const TString &identifier,
+                                                              const TSourceLoc &initLocation,
+                                                              TIntermTyped *initializer)
 {
     mDeferredSingleDeclarationErrorCheck = false;
 
     singleDeclarationErrorCheck(publicType, identifierLocation);
 
-    TIntermNode *intermNode = nullptr;
-    if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode))
+    TIntermDeclaration *declaration = new TIntermDeclaration();
+    declaration->setLine(identifierLocation);
+
+    TIntermBinary *initNode = nullptr;
+    if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &initNode))
     {
-        //
-        // Build intermediate representation
-        //
-        return intermNode ? TIntermediate::MakeAggregate(intermNode, initLocation) : nullptr;
+        if (initNode)
+        {
+            declaration->appendDeclarator(initNode);
+        }
     }
-    else
-    {
-        return nullptr;
-    }
+    return declaration;
 }
 
-TIntermAggregate *TParseContext::parseSingleArrayInitDeclaration(
+TIntermDeclaration *TParseContext::parseSingleArrayInitDeclaration(
     TPublicType &publicType,
     const TSourceLoc &identifierLocation,
     const TString &identifier,
@@ -1900,16 +1917,20 @@
     // This ensures useless error messages regarding the variable's non-arrayness won't follow.
     arrayType.setArraySize(size);
 
+    TIntermDeclaration *declaration = new TIntermDeclaration();
+    declaration->setLine(identifierLocation);
+
     // initNode will correspond to the whole of "type b[n] = initializer".
-    TIntermNode *initNode = nullptr;
+    TIntermBinary *initNode = nullptr;
     if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
     {
-        return initNode ? TIntermediate::MakeAggregate(initNode, initLocation) : nullptr;
+        if (initNode)
+        {
+            declaration->appendDeclarator(initNode);
+        }
     }
-    else
-    {
-        return nullptr;
-    }
+
+    return declaration;
 }
 
 TIntermAggregate *TParseContext::parseInvariantDeclaration(
@@ -1967,10 +1988,10 @@
     return aggregate;
 }
 
-TIntermAggregate *TParseContext::parseDeclarator(TPublicType &publicType,
-                                                 TIntermAggregate *aggregateDeclaration,
-                                                 const TSourceLoc &identifierLocation,
-                                                 const TString &identifier)
+void TParseContext::parseDeclarator(TPublicType &publicType,
+                                    const TSourceLoc &identifierLocation,
+                                    const TString &identifier,
+                                    TIntermDeclaration *declarationOut)
 {
     // If the declaration starting this declarator list was empty (example: int,), some checks were
     // not performed.
@@ -1990,17 +2011,18 @@
     TIntermSymbol *symbol =
         intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation);
     if (variable && symbol)
+    {
         symbol->setId(variable->getUniqueId());
-
-    return intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
+        declarationOut->appendDeclarator(symbol);
+    }
 }
 
-TIntermAggregate *TParseContext::parseArrayDeclarator(TPublicType &publicType,
-                                                      TIntermAggregate *aggregateDeclaration,
-                                                      const TSourceLoc &identifierLocation,
-                                                      const TString &identifier,
-                                                      const TSourceLoc &arrayLocation,
-                                                      TIntermTyped *indexExpression)
+void TParseContext::parseArrayDeclarator(TPublicType &publicType,
+                                         const TSourceLoc &identifierLocation,
+                                         const TString &identifier,
+                                         const TSourceLoc &arrayLocation,
+                                         TIntermTyped *indexExpression,
+                                         TIntermDeclaration *declarationOut)
 {
     // If the declaration starting this declarator list was empty (example: int,), some checks were
     // not performed.
@@ -2028,18 +2050,16 @@
         if (variable && symbol)
             symbol->setId(variable->getUniqueId());
 
-        return intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
+        declarationOut->appendDeclarator(symbol);
     }
-
-    return nullptr;
 }
 
-TIntermAggregate *TParseContext::parseInitDeclarator(const TPublicType &publicType,
-                                                     TIntermAggregate *aggregateDeclaration,
-                                                     const TSourceLoc &identifierLocation,
-                                                     const TString &identifier,
-                                                     const TSourceLoc &initLocation,
-                                                     TIntermTyped *initializer)
+void TParseContext::parseInitDeclarator(const TPublicType &publicType,
+                                        const TSourceLoc &identifierLocation,
+                                        const TString &identifier,
+                                        const TSourceLoc &initLocation,
+                                        TIntermTyped *initializer,
+                                        TIntermDeclaration *declarationOut)
 {
     // If the declaration starting this declarator list was empty (example: int,), some checks were
     // not performed.
@@ -2051,35 +2071,27 @@
 
     checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType);
 
-    TIntermNode *intermNode = nullptr;
-    if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode))
+    TIntermBinary *initNode = nullptr;
+    if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &initNode))
     {
         //
         // build the intermediate representation
         //
-        if (intermNode)
+        if (initNode)
         {
-            return intermediate.growAggregate(aggregateDeclaration, intermNode, initLocation);
+            declarationOut->appendDeclarator(initNode);
         }
-        else
-        {
-            return aggregateDeclaration;
-        }
-    }
-    else
-    {
-        return nullptr;
     }
 }
 
-TIntermAggregate *TParseContext::parseArrayInitDeclarator(const TPublicType &publicType,
-                                                          TIntermAggregate *aggregateDeclaration,
-                                                          const TSourceLoc &identifierLocation,
-                                                          const TString &identifier,
-                                                          const TSourceLoc &indexLocation,
-                                                          TIntermTyped *indexExpression,
-                                                          const TSourceLoc &initLocation,
-                                                          TIntermTyped *initializer)
+void TParseContext::parseArrayInitDeclarator(const TPublicType &publicType,
+                                             const TSourceLoc &identifierLocation,
+                                             const TString &identifier,
+                                             const TSourceLoc &indexLocation,
+                                             TIntermTyped *indexExpression,
+                                             const TSourceLoc &initLocation,
+                                             TIntermTyped *initializer,
+                                             TIntermDeclaration *declarationOut)
 {
     // If the declaration starting this declarator list was empty (example: int,), some checks were
     // not performed.
@@ -2107,21 +2119,13 @@
     arrayType.setArraySize(size);
 
     // initNode will correspond to the whole of "b[n] = initializer".
-    TIntermNode *initNode = nullptr;
+    TIntermBinary *initNode = nullptr;
     if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
     {
         if (initNode)
         {
-            return intermediate.growAggregate(aggregateDeclaration, initNode, initLocation);
+            declarationOut->appendDeclarator(initNode);
         }
-        else
-        {
-            return aggregateDeclaration;
-        }
-    }
-    else
-    {
-        return nullptr;
     }
 }
 
@@ -2620,7 +2624,7 @@
 //
 // Interface/uniform blocks
 //
-TIntermAggregate *TParseContext::addInterfaceBlock(
+TIntermDeclaration *TParseContext::addInterfaceBlock(
     const TTypeQualifierBuilder &typeQualifierBuilder,
     const TSourceLoc &nameLine,
     const TString &blockName,
@@ -2782,13 +2786,14 @@
         symbolName = instanceTypeDef->getName();
     }
 
-    TIntermAggregate *aggregate = TIntermediate::MakeAggregate(
-        intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line),
-        nameLine);
-    aggregate->setOp(EOpDeclaration);
+    TIntermSymbol *blockSymbol =
+        intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line);
+    TIntermDeclaration *declaration = new TIntermDeclaration();
+    declaration->appendDeclarator(blockSymbol);
+    declaration->setLine(nameLine);
 
     exitStructDeclaration();
-    return aggregate;
+    return declaration;
 }
 
 void TParseContext::enterStructDeclaration(const TSourceLoc &line, const TString &identifier)
@@ -3903,10 +3908,10 @@
     return node;
 }
 
-TIntermTyped *TParseContext::createAssign(TOperator op,
-                                          TIntermTyped *left,
-                                          TIntermTyped *right,
-                                          const TSourceLoc &loc)
+TIntermBinary *TParseContext::createAssign(TOperator op,
+                                           TIntermTyped *left,
+                                           TIntermTyped *right,
+                                           const TSourceLoc &loc)
 {
     if (binaryOpCommonCheck(op, left, right, loc))
     {