From 5964c64b2acd90e7403d61cc35303853fc60116c Mon Sep 17 00:00:00 2001
From: steve-lunarg <steve_gh@khasekhemwy.net>
Date: Sat, 30 Jul 2016 07:38:55 -0600
Subject: [PATCH] HLSL: Fix a grammar error related to constructors in
 parenthetical expressions

---
 Test/baseResults/hlsl.constructexpr.frag.out | 129 +++++++++++++++++++
 Test/hlsl.constructexpr.frag                 |  17 +++
 Test/hlsl.init2.frag                         |  23 ++++
 gtests/Hlsl.FromFile.cpp                     |   1 +
 hlsl/hlslGrammar.cpp                         |  38 +++---
 hlsl/hlslTokenStream.cpp                     |  18 +--
 hlsl/hlslTokenStream.h                       |  16 ++-
 7 files changed, 210 insertions(+), 32 deletions(-)
 create mode 100644 Test/baseResults/hlsl.constructexpr.frag.out
 create mode 100644 Test/hlsl.constructexpr.frag
 create mode 100644 Test/hlsl.init2.frag

diff --git a/Test/baseResults/hlsl.constructexpr.frag.out b/Test/baseResults/hlsl.constructexpr.frag.out
new file mode 100644
index 000000000..2eef7c0dc
--- /dev/null
+++ b/Test/baseResults/hlsl.constructexpr.frag.out
@@ -0,0 +1,129 @@
+hlsl.constructexpr.frag
+Shader version: 450
+gl_FragCoord origin is upper left
+0:? Sequence
+0:18  Function Definition: main( (global structure{temp 4-component vector of float color})
+0:4    Function Parameters: 
+0:?     Sequence
+0:6      Constant:
+0:6        3 (const int)
+0:7      Constant:
+0:7        4 (const int)
+0:8      Constant:
+0:8        5 (const int)
+0:9      Constant:
+0:9        6 (const int)
+0:10      Constant:
+0:10        7 (const int)
+0:11      Constant:
+0:11        8 (const int)
+0:12      Comma (temp 2-component vector of float)
+0:?         Constant:
+0:?           9.000000
+0:?           10.000000
+0:?         Constant:
+0:?           11.000000
+0:?           12.000000
+0:15      move second child to first child (temp 4-component vector of float)
+0:15        color: direct index for structure (temp 4-component vector of float)
+0:15          'ps_output' (temp structure{temp 4-component vector of float color})
+0:15          Constant:
+0:15            0 (const int)
+0:15        Constant:
+0:15          1.000000
+0:15          1.000000
+0:15          1.000000
+0:15          1.000000
+0:16      Branch: Return with expression
+0:16        'ps_output' (temp structure{temp 4-component vector of float color})
+0:?   Linker Objects
+
+
+Linked fragment stage:
+
+
+Shader version: 450
+gl_FragCoord origin is upper left
+0:? Sequence
+0:18  Function Definition: main( (global structure{temp 4-component vector of float color})
+0:4    Function Parameters: 
+0:?     Sequence
+0:6      Constant:
+0:6        3 (const int)
+0:7      Constant:
+0:7        4 (const int)
+0:8      Constant:
+0:8        5 (const int)
+0:9      Constant:
+0:9        6 (const int)
+0:10      Constant:
+0:10        7 (const int)
+0:11      Constant:
+0:11        8 (const int)
+0:12      Comma (temp 2-component vector of float)
+0:?         Constant:
+0:?           9.000000
+0:?           10.000000
+0:?         Constant:
+0:?           11.000000
+0:?           12.000000
+0:15      move second child to first child (temp 4-component vector of float)
+0:15        color: direct index for structure (temp 4-component vector of float)
+0:15          'ps_output' (temp structure{temp 4-component vector of float color})
+0:15          Constant:
+0:15            0 (const int)
+0:15        Constant:
+0:15          1.000000
+0:15          1.000000
+0:15          1.000000
+0:15          1.000000
+0:16      Branch: Return with expression
+0:16        'ps_output' (temp structure{temp 4-component vector of float color})
+0:?   Linker Objects
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 32
+
+                              Capability Shader
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Fragment 4  "main"
+                              ExecutionMode 4 OriginUpperLeft
+                              Source HLSL 450
+                              Name 4  "main"
+                              Name 22  "PS_OUTPUT"
+                              MemberName 22(PS_OUTPUT) 0  "color"
+                              Name 24  "ps_output"
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeInt 32 1
+               7:      6(int) Constant 3
+               8:      6(int) Constant 4
+               9:      6(int) Constant 5
+              10:      6(int) Constant 6
+              11:      6(int) Constant 7
+              12:      6(int) Constant 8
+              13:             TypeFloat 32
+              14:             TypeVector 13(float) 2
+              15:   13(float) Constant 1091567616
+              16:   13(float) Constant 1092616192
+              17:   14(fvec2) ConstantComposite 15 16
+              18:   13(float) Constant 1093664768
+              19:   13(float) Constant 1094713344
+              20:   14(fvec2) ConstantComposite 18 19
+              21:             TypeVector 13(float) 4
+   22(PS_OUTPUT):             TypeStruct 21(fvec4)
+              23:             TypePointer Function 22(PS_OUTPUT)
+              25:      6(int) Constant 0
+              26:   13(float) Constant 1065353216
+              27:   21(fvec4) ConstantComposite 26 26 26 26
+              28:             TypePointer Function 21(fvec4)
+         4(main):           2 Function None 3
+               5:             Label
+   24(ps_output):     23(ptr) Variable Function
+              29:     28(ptr) AccessChain 24(ps_output) 25
+                              Store 29 27
+              30:22(PS_OUTPUT) Load 24(ps_output)
+                              ReturnValue 30
+                              FunctionEnd
diff --git a/Test/hlsl.constructexpr.frag b/Test/hlsl.constructexpr.frag
new file mode 100644
index 000000000..7048f62cd
--- /dev/null
+++ b/Test/hlsl.constructexpr.frag
@@ -0,0 +1,17 @@
+struct PS_OUTPUT { float4 color : SV_Target0; };
+
+PS_OUTPUT main()
+{
+    // Evaluates to a sequence: 3, 4, 5, 6, 7, 8, and a float2(9,10), float2(11,12) sequence
+    (int(3));
+    (int(3) + int(1));
+    (int(3) + int(1) + int(1));
+    (((int(6))));
+    (int(7.0));
+    ((int((2)) ? 8 : 8));
+    (float2(9, 10), float2(11, 12));
+
+    PS_OUTPUT ps_output;
+    ps_output.color = 1.0;
+    return ps_output;
+}
diff --git a/Test/hlsl.init2.frag b/Test/hlsl.init2.frag
new file mode 100644
index 000000000..94be5ffeb
--- /dev/null
+++ b/Test/hlsl.init2.frag
@@ -0,0 +1,23 @@
+
+void Test1()
+{
+    struct mystruct { float2 a; };
+    mystruct test1 = {
+        { 1, 2, },          // test trailing commas
+    };
+
+    mystruct test2 = {
+        { { 1, 2, } },      // test unneeded levels
+    };
+
+    float test3 = { 1 } ;   // test scalar initialization
+}
+
+struct PS_OUTPUT { float4 color : SV_Target0; };
+
+PS_OUTPUT main()
+{
+    PS_OUTPUT ps_output;
+    ps_output.color = 1.0;
+    return ps_output;
+}
diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp
index d14be6772..91aa9df2d 100644
--- a/gtests/Hlsl.FromFile.cpp
+++ b/gtests/Hlsl.FromFile.cpp
@@ -80,6 +80,7 @@ INSTANTIATE_TEST_CASE_P(
         {"hlsl.calculatelodunclamped.dx10.frag", "main"},
         {"hlsl.cast.frag", "PixelShaderFunction"},
         {"hlsl.conditional.frag", "PixelShaderFunction"},
+        {"hlsl.constructexpr.frag", "main"},
         {"hlsl.discard.frag", "PixelShaderFunction"},
         {"hlsl.doLoop.frag", "PixelShaderFunction"},
         {"hlsl.float1.frag", "PixelShaderFunction"},
diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp
index e3e5df736..11b6dc152 100755
--- a/hlsl/hlslGrammar.cpp
+++ b/hlsl/hlslGrammar.cpp
@@ -1718,27 +1718,29 @@ bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
     if (acceptTokenClass(EHTokLeftParen)) {
         TType castType;
         if (acceptType(castType)) {
-            if (! acceptTokenClass(EHTokRightParen)) {
-                expected(")");
-                return false;
-            }
+            if (acceptTokenClass(EHTokRightParen)) {
+                // We've matched "(type)" now, get the expression to cast
+                TSourceLoc loc = token.loc;
+                if (! acceptUnaryExpression(node))
+                    return false;
 
-            // We've matched "(type)" now, get the expression to cast
-            TSourceLoc loc = token.loc;
-            if (! acceptUnaryExpression(node))
-                return false;
+                // Hook it up like a constructor
+                TFunction* constructorFunction = parseContext.handleConstructorCall(loc, castType);
+                if (constructorFunction == nullptr) {
+                    expected("type that can be constructed");
+                    return false;
+                }
+                TIntermTyped* arguments = nullptr;
+                parseContext.handleFunctionArgument(constructorFunction, arguments, node);
+                node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
 
-            // Hook it up like a constructor
-            TFunction* constructorFunction = parseContext.handleConstructorCall(loc, castType);
-            if (constructorFunction == nullptr) {
-                expected("type that can be constructed");
-                return false;
+                return true;
+            } else {
+                // This could be a parenthesized constructor, ala (int(3)), and we just accepted
+                // the '(int' part.  We must back up twice.
+                recedeToken();
+                recedeToken();
             }
-            TIntermTyped* arguments = nullptr;
-            parseContext.handleFunctionArgument(constructorFunction, arguments, node);
-            node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
-
-            return true;
         } else {
             // This isn't a type cast, but it still started "(", so if it is a
             // unary expression, it can only be a postfix_expression, so try that.
diff --git a/hlsl/hlslTokenStream.cpp b/hlsl/hlslTokenStream.cpp
index 47f779a81..c915e0b59 100755
--- a/hlsl/hlslTokenStream.cpp
+++ b/hlsl/hlslTokenStream.cpp
@@ -39,27 +39,29 @@ namespace glslang {
 
 void HlslTokenStream::pushPreToken(const HlslToken& tok)
 {
-    assert(preTokenStackSize == 0);
-    preTokenStack = tok;
-    ++preTokenStackSize;
+    assert(preTokenStackSize < tokenBufferSize);
+    preTokenStack[preTokenStackSize++] = tok;
 }
 
 HlslToken HlslTokenStream::popPreToken()
 {
-    assert(preTokenStackSize == 1);
-    --preTokenStackSize;
+    assert(preTokenStackSize > 0);
 
-    return preTokenStack;
+    return preTokenStack[--preTokenStackSize];
 }
 
 void HlslTokenStream::pushTokenBuffer(const HlslToken& tok)
 {
-    tokenBuffer = tok;
+    tokenBuffer[tokenBufferPos] = tok;
+    tokenBufferPos = (tokenBufferPos+1) % tokenBufferSize;
 }
 
 HlslToken HlslTokenStream::popTokenBuffer()
 {
-    return tokenBuffer;
+    // Back up
+    tokenBufferPos = (tokenBufferPos+tokenBufferSize-1) % tokenBufferSize;
+
+    return tokenBuffer[tokenBufferPos];
 }
 
 // Load 'token' with the next token in the stream of tokens.
diff --git a/hlsl/hlslTokenStream.h b/hlsl/hlslTokenStream.h
index 12c2a2a02..ec4288943 100755
--- a/hlsl/hlslTokenStream.h
+++ b/hlsl/hlslTokenStream.h
@@ -43,7 +43,7 @@ namespace glslang {
     class HlslTokenStream {
     public:
         explicit HlslTokenStream(HlslScanContext& scanner)
-            : scanner(scanner), preTokenStackSize(0) { }
+            : scanner(scanner), preTokenStackSize(0), tokenBufferPos(0) { }
         virtual ~HlslTokenStream() { }
 
     public:
@@ -62,20 +62,24 @@ namespace glslang {
 
         HlslScanContext& scanner;         // lexical scanner, to get next token
 
+        // This is the number of tokens we can recedeToken() over.
+        static const int tokenBufferSize = 2;
+
         // Previously scanned tokens, returned for future advances,
         // so logically in front of the token stream.
         // Is logically a stack; needs last in last out semantics.
-        // Currently implemented as a stack of size 1.
-        HlslToken preTokenStack;          
+        // Currently implemented as a stack of size 2.
+        HlslToken preTokenStack[tokenBufferSize];
         int preTokenStackSize;
         void pushPreToken(const HlslToken&);
         HlslToken popPreToken();
 
-        // Previously scanned tokens, not yet return for future advances,
+        // Previously scanned tokens, not yet returned for future advances,
         // but available for that.
         // Is logically a fifo for normal advances, and a stack for recession.
-        // Currently implemented with an intrinsic size of 1.
-        HlslToken tokenBuffer;
+        // Currently implemented with an intrinsic size of 2.
+        HlslToken tokenBuffer[tokenBufferSize];
+        int tokenBufferPos;
         void pushTokenBuffer(const HlslToken&);
         HlslToken popTokenBuffer();
     };
-- 
GitLab