Translator: Fix assert in ScalarizeVecAndMatConstructorArgs

This transformation assumed that precision can be derived for constants
in every possible scenario, but that's not true.  The fuzzer produced
the following code:

    void main()
    {
        mat4 m;
        mat2(0, bvec3(m));
    }

In the above, the constant 0 legimitately has no precision.  The assert
was in a function that attempted to make a temporary out of the
constant, which this commit changes to use the original constant as-is.

Bug: chromium:1246781
Change-Id: I6f247264e5213cfd9449fdfb1dc312d02b99f2f1
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3149191
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Tim Van Patten <timvp@google.com>
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
diff --git a/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.cpp b/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.cpp
index c711fbc..195ca53 100644
--- a/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.cpp
+++ b/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.cpp
@@ -27,12 +27,12 @@
 namespace
 {
 
-TIntermBinary *ConstructVectorIndexBinaryNode(TIntermSymbol *symbolNode, int index)
+TIntermBinary *ConstructVectorIndexBinaryNode(TIntermTyped *symbolNode, int index)
 {
     return new TIntermBinary(EOpIndexDirect, symbolNode, CreateIndexNode(index));
 }
 
-TIntermBinary *ConstructMatrixIndexBinaryNode(TIntermSymbol *symbolNode, int colIndex, int rowIndex)
+TIntermBinary *ConstructMatrixIndexBinaryNode(TIntermTyped *symbolNode, int colIndex, int rowIndex)
 {
     TIntermBinary *colVectorNode = ConstructVectorIndexBinaryNode(symbolNode, colIndex);
 
@@ -63,7 +63,7 @@
     //   vec4 v(1, s0[0][0], s0[0][1], s0[0][2]);
     // This function is to create nodes for "mat4 s0 = m;" and insert it to the code sequence. This
     // way the possible side effects of the constructor argument will only be evaluated once.
-    TVariable *createTempVariable(TIntermTyped *original);
+    TIntermTyped *createTempVariable(TIntermTyped *original);
 
     std::vector<TIntermSequence> mBlockStack;
 
@@ -123,10 +123,10 @@
         ASSERT(size > 0);
         TIntermTyped *originalArg = originalArgNode->getAsTyped();
         ASSERT(originalArg);
-        TVariable *argVariable = createTempVariable(originalArg);
+        TIntermTyped *argVariable = createTempVariable(originalArg);
         if (originalArg->isScalar())
         {
-            sequence->push_back(CreateTempSymbolNode(argVariable));
+            sequence->push_back(argVariable);
             size--;
         }
         else if (originalArg->isVector())
@@ -137,15 +137,14 @@
                 size -= repeat;
                 for (int index = 0; index < repeat; ++index)
                 {
-                    TIntermSymbol *symbolNode = CreateTempSymbolNode(argVariable);
-                    TIntermBinary *newNode    = ConstructVectorIndexBinaryNode(symbolNode, index);
+                    TIntermBinary *newNode =
+                        ConstructVectorIndexBinaryNode(argVariable->deepCopy(), index);
                     sequence->push_back(newNode);
                 }
             }
             else
             {
-                TIntermSymbol *symbolNode = CreateTempSymbolNode(argVariable);
-                sequence->push_back(symbolNode);
+                sequence->push_back(argVariable);
                 size -= originalArg->getNominalSize();
             }
         }
@@ -159,9 +158,8 @@
                 size -= repeat;
                 while (repeat > 0)
                 {
-                    TIntermSymbol *symbolNode = CreateTempSymbolNode(argVariable);
                     TIntermBinary *newNode =
-                        ConstructMatrixIndexBinaryNode(symbolNode, colIndex, rowIndex);
+                        ConstructMatrixIndexBinaryNode(argVariable->deepCopy(), colIndex, rowIndex);
                     sequence->push_back(newNode);
                     rowIndex++;
                     if (rowIndex >= originalArg->getRows())
@@ -174,15 +172,14 @@
             }
             else
             {
-                TIntermSymbol *symbolNode = CreateTempSymbolNode(argVariable);
-                sequence->push_back(symbolNode);
+                sequence->push_back(argVariable);
                 size -= originalArg->getCols() * originalArg->getRows();
             }
         }
     }
 }
 
-TVariable *ScalarizeArgsTraverser::createTempVariable(TIntermTyped *original)
+TIntermTyped *ScalarizeArgsTraverser::createTempVariable(TIntermTyped *original)
 {
     ASSERT(original);
 
@@ -190,9 +187,16 @@
     type->setQualifier(EvqTemporary);
 
     // The precision of the constant must have been retained (or derived), which will now apply to
-    // the temp variable.
-    ASSERT(!IsPrecisionApplicableToType(type->getBasicType()) ||
-           type->getPrecision() != EbpUndefined);
+    // the temp variable.  In some cases, the precision cannot be derived, so use the constant as
+    // is.  For example, in the following standalone statement, the precision of the constant 0
+    // cannot be determined:
+    //
+    //      mat2(0, bvec3(m));
+    //
+    if (IsPrecisionApplicableToType(type->getBasicType()) && type->getPrecision() == EbpUndefined)
+    {
+        return original;
+    }
 
     TVariable *variable = CreateTempVariable(mSymbolTable, type);
 
@@ -201,7 +205,7 @@
     TIntermDeclaration *declaration = CreateTempInitDeclarationNode(variable, original);
     sequence.push_back(declaration);
 
-    return variable;
+    return CreateTempSymbolNode(variable);
 }
 
 }  // namespace
diff --git a/src/tests/compiler_tests/ScalarizeVecAndMatConstructorArgs_test.cpp b/src/tests/compiler_tests/ScalarizeVecAndMatConstructorArgs_test.cpp
index 6518e2a..80b0582 100644
--- a/src/tests/compiler_tests/ScalarizeVecAndMatConstructorArgs_test.cpp
+++ b/src/tests/compiler_tests/ScalarizeVecAndMatConstructorArgs_test.cpp
@@ -116,4 +116,21 @@
     EXPECT_TRUE(foundInCodeInOrder(expectedStrings));
 }
 
+// Verifies that constructors without precision don't cause issues.
+TEST_F(ScalarizeVecAndMatConstructorArgsTest, ConstructorWithoutPrecision)
+{
+    const std::string shaderString =
+        R"(
+        precision mediump float;
+
+        uniform float u;
+
+        void main()
+        {
+            mat4 m = mat4(u);
+            mat2(0, bvec3(m));
+        })";
+    compile(shaderString);
+}
+
 }  // anonymous namespace