xref: /aosp_15_r20/external/angle/src/tests/compiler_tests/Parse_test.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2024 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // Parse_test.cpp:
7 //   Test for parsing erroneous and correct GLSL input.
8 //
9 
10 #include <memory>
11 #include "GLSLANG/ShaderLang.h"
12 #include "angle_gl.h"
13 #include "compiler/translator/glsl/TranslatorESSL.h"
14 #include "gtest/gtest.h"
15 
16 using namespace sh;
17 
18 class ParseTest : public testing::Test
19 {
20   public:
ParseTest()21     ParseTest()
22     {
23         InitBuiltInResources(&mResources);
24         mResources.FragmentPrecisionHigh = 1;
25         mCompileOptions.intermediateTree = true;
26     }
27 
28   protected:
TearDown()29     void TearDown() override { mTranslator.reset(); }
30 
compile(const std::string & shaderString)31     testing::AssertionResult compile(const std::string &shaderString)
32     {
33         if (mTranslator == nullptr)
34         {
35             std::unique_ptr<TranslatorESSL> translator =
36                 std::make_unique<TranslatorESSL>(GL_FRAGMENT_SHADER, mShaderSpec);
37             if (!translator->Init(mResources))
38             {
39                 return testing::AssertionFailure() << "Failed to initialize translator";
40             }
41             mTranslator = std::move(translator);
42         }
43 
44         const char *shaderStrings[] = {shaderString.c_str()};
45         bool compilationSuccess     = mTranslator->compile(shaderStrings, 1, mCompileOptions);
46         mInfoLog                    = mTranslator->getInfoSink().info.str();
47         if (!compilationSuccess)
48         {
49             return testing::AssertionFailure() << "Shader compilation failed " << mInfoLog;
50         }
51         return testing::AssertionSuccess();
52     }
53 
foundErrorInIntermediateTree() const54     bool foundErrorInIntermediateTree() const { return foundInIntermediateTree("ERROR:"); }
55 
foundInIntermediateTree(const char * stringToFind) const56     bool foundInIntermediateTree(const char *stringToFind) const
57     {
58         return mInfoLog.find(stringToFind) != std::string::npos;
59     }
intermediateTree() const60     std::string intermediateTree() const { return mInfoLog; }
61 
62     ShBuiltInResources mResources;
63     ShCompileOptions mCompileOptions{};
64     ShShaderSpec mShaderSpec = SH_WEBGL_SPEC;
65 
66   private:
67 
68     std::unique_ptr<TranslatorESSL> mTranslator;
69     std::string mInfoLog;
70 };
71 
TEST_F(ParseTest,UnsizedArrayConstructorNoCrash)72 TEST_F(ParseTest, UnsizedArrayConstructorNoCrash)
73 {
74     const char kShader[] = R"(#version 310 es\n"
75 int A[];
76 int B[int[][](A)];)";
77     EXPECT_FALSE(compile(kShader));
78     EXPECT_TRUE(foundErrorInIntermediateTree());
79     EXPECT_TRUE(foundInIntermediateTree("constructing from an unsized array"));
80 }
81 
82 TEST_F(ParseTest, UniformBlockNameReferenceConstructorNoCrash)
83 {
84     const char kShader[] = R"(#version 300 es
85 precision mediump float;
86 out float o;
87 uniform a { float r; } UBOA;
88 void main() {
89     o = float(UBOA);
90 })";
91     EXPECT_FALSE(compile(kShader));
92     EXPECT_TRUE(foundErrorInIntermediateTree());
93     EXPECT_TRUE(foundInIntermediateTree(
94         "interface block cannot be used as a constructor argument for this type"));
95 }
96 
97 TEST_F(ParseTest, Precise320NoCrash)
98 {
99     const char kShader[] = R"(#version 320 es
100 precision mediump float;
101 void main(){
102     float t;
103     precise t;
104 })";
105     EXPECT_FALSE(compile(kShader));
106     EXPECT_TRUE(foundErrorInIntermediateTree());
107     EXPECT_TRUE(foundInIntermediateTree("unsupported shader version"));
108 }
109 
110 // Tests that layout(index=0) is parsed in es 100 shaders if an extension like
111 // EXT_shader_framebuffer_fetch is enabled, but this does not cause a crash.
112 TEST_F(ParseTest, ShaderFramebufferFetchLayoutIndexNoCrash)
113 {
114     mResources.EXT_blend_func_extended      = 1;
115     mResources.MaxDualSourceDrawBuffers     = 1;
116     mResources.EXT_shader_framebuffer_fetch = 1;
117     const char kShader[]                    = R"(
118 #extension GL_EXT_blend_func_extended: require
119 #extension GL_EXT_shader_framebuffer_fetch : require
120 layout(index=0)mediump vec4 c;
121 void main() { }
122 )";
123     EXPECT_FALSE(compile(kShader));
124     EXPECT_TRUE(foundErrorInIntermediateTree());
125     EXPECT_TRUE(foundInIntermediateTree("'index' : invalid layout qualifier"));
126 }
127 
128 TEST_F(ParseTest, Radians320NoCrash)
129 {
130     const char kShader[] = R"(#version 320 es
131 precision mediump float;
132 vec4 s() { writeonly vec4 color; radians(color); return vec4(1); })";
133     EXPECT_FALSE(compile(kShader));
134     EXPECT_TRUE(foundErrorInIntermediateTree());
135     EXPECT_TRUE(foundInIntermediateTree("'writeonly' : Only allowed with shader storage blocks,"));
136     EXPECT_TRUE(foundInIntermediateTree(
137         "'radians' : wrong operand type - no operation 'radians' exists that"));
138 }
139 
140 TEST_F(ParseTest, CoherentCoherentNoCrash)
141 {
142     const char kShader[] = R"(#version 310 es
143 uniform highp coherent coherent readonly image2D image1;\n"
144 void main() {
145 })";
146     EXPECT_FALSE(compile(kShader));
147     EXPECT_TRUE(foundErrorInIntermediateTree());
148     EXPECT_TRUE(foundInIntermediateTree("coherent specified multiple times"));
149 }
150 
TEST_F(ParseTest,LargeArrayIndexNoCrash)151 TEST_F(ParseTest, LargeArrayIndexNoCrash)
152 {
153     mShaderSpec          = SH_WEBGL2_SPEC;
154     const char kShader[] = R"(#version 300 es
155 int rr[~1U];
156 out int o;
157 void main() {
158     o = rr[1];
159 })";
160     EXPECT_FALSE(compile(kShader));
161     EXPECT_TRUE(foundErrorInIntermediateTree());
162     EXPECT_TRUE(
163         foundInIntermediateTree("Size of declared variable exceeds implementation-defined limit"));
164 }
165 
166 // Tests that separating variable declaration of multiple instances of a anonymous structure
167 // rewrites the expression types for expressions that use the variables. At the time of writing
168 // the expression types were left referencing the original anonymous function.
TEST_F(ParseTest,SeparateAnonymousFunctionsRewritesExpressions)169 TEST_F(ParseTest, SeparateAnonymousFunctionsRewritesExpressions)
170 {
171     const char kShader[] = R"(
172 struct {
173     mediump vec2 d;
174 } s0, s1;
175 void main() {
176     s0 = s0;
177     s1 = s1;
178 })";
179     EXPECT_TRUE(compile(kShader));
180     EXPECT_FALSE(foundInIntermediateTree("anonymous"));
181 }
182 
183 // Tests that constant folding a division of a void variable does not crash during parsing.
TEST_F(ParseTest,ConstStructWithVoidAndDivNoCrash)184 TEST_F(ParseTest, ConstStructWithVoidAndDivNoCrash)
185 {
186     const char kShader[] = R"(
187 const struct s { void i; } ss = s();
188 void main() {
189     highp vec3 q = ss.i / ss.i;
190 })";
191     EXPECT_FALSE(compile(kShader));
192     EXPECT_TRUE(foundErrorInIntermediateTree());
193     EXPECT_TRUE(foundInIntermediateTree("illegal use of type 'void'"));
194     EXPECT_TRUE(foundInIntermediateTree("constructor does not have any arguments"));
195     EXPECT_TRUE(foundInIntermediateTree("operation with void operands"));
196     EXPECT_TRUE(foundInIntermediateTree(
197         "wrong operand types - no operation '/' exists that takes a left-hand operand of type "
198         "'const void' and a right operand of type 'const void'"));
199     EXPECT_TRUE(foundInIntermediateTree(
200         "cannot convert from 'const void' to 'highp 3-component vector of float'"));
201 }
202 
203 // Tests that division of void variable returns the same errors as division of constant
204 // void variable (see above).
TEST_F(ParseTest,StructWithVoidAndDivErrorCheck)205 TEST_F(ParseTest, StructWithVoidAndDivErrorCheck)
206 {
207     const char kShader[] = R"(
208 struct s { void i; } ss = s();
209 void main() {
210     highp vec3 q = ss.i / ss.i;
211 })";
212     EXPECT_FALSE(compile(kShader));
213     EXPECT_TRUE(foundErrorInIntermediateTree());
214     EXPECT_TRUE(foundInIntermediateTree("illegal use of type 'void'"));
215     EXPECT_TRUE(foundInIntermediateTree("constructor does not have any arguments"));
216     EXPECT_TRUE(foundInIntermediateTree("operation with void operands"));
217     EXPECT_TRUE(foundInIntermediateTree(
218         "wrong operand types - no operation '/' exists that takes a left-hand operand of type "
219         "'void' and a right operand of type 'void'"));
220     EXPECT_TRUE(foundInIntermediateTree(
221         "cannot convert from 'void' to 'highp 3-component vector of float'"));
222 }
223 
224 // Tests that usage of BuildIn struct type name does not crash during parsing.
TEST_F(ParseTest,BuildInStructTypeNameDeclarationNoCrash)225 TEST_F(ParseTest, BuildInStructTypeNameDeclarationNoCrash)
226 {
227     mCompileOptions.validateAST = 1;
228     const char kShader[]        = R"(
229 void main() {
230 gl_DepthRangeParameters testVariable;
231 })";
232     EXPECT_FALSE(compile(kShader));
233     EXPECT_TRUE(foundErrorInIntermediateTree());
234     EXPECT_TRUE(foundInIntermediateTree("reserved built-in name"));
235 }
236 
TEST_F(ParseTest,BuildInStructTypeNameFunctionArgumentNoCrash)237 TEST_F(ParseTest, BuildInStructTypeNameFunctionArgumentNoCrash)
238 {
239     mCompileOptions.validateAST = 1;
240     const char kShader[]        = R"(
241 void testFunction(gl_DepthRangeParameters testParam){}
242 void main() {
243 testFunction(gl_DepthRange);
244 })";
245     EXPECT_FALSE(compile(kShader));
246     EXPECT_TRUE(foundErrorInIntermediateTree());
247     EXPECT_TRUE(foundInIntermediateTree("reserved built-in name"));
248 }
249 
TEST_F(ParseTest,BuildInStructTypeNameFunctionReturnValueNoCrash)250 TEST_F(ParseTest, BuildInStructTypeNameFunctionReturnValueNoCrash)
251 {
252     mCompileOptions.validateAST = 1;
253     const char kShader[]        = R"(
254 gl_DepthRangeParameters testFunction(){return gl_DepthRange;}
255 void main() {
256 testFunction();
257 })";
258     EXPECT_FALSE(compile(kShader));
259     EXPECT_TRUE(foundErrorInIntermediateTree());
260     EXPECT_TRUE(foundInIntermediateTree("reserved built-in name"));
261 }
262 
263 // Tests that imod of const void variable does not crash during parsing.
TEST_F(ParseTest,ConstStructVoidAndImodAndNoCrash)264 TEST_F(ParseTest, ConstStructVoidAndImodAndNoCrash)
265 {
266     const char kShader[] = R"(#version 310 es
267 const struct s { void i; } ss = s();
268 void main() {
269     highp vec3 q = ss.i % ss.i;
270 })";
271     EXPECT_FALSE(compile(kShader));
272     EXPECT_TRUE(foundErrorInIntermediateTree());
273     EXPECT_TRUE(foundInIntermediateTree("illegal use of type 'void'"));
274     EXPECT_TRUE(foundInIntermediateTree("constructor does not have any arguments"));
275     EXPECT_TRUE(foundInIntermediateTree("operation with void operands"));
276     EXPECT_TRUE(foundInIntermediateTree(
277         "wrong operand types - no operation '%' exists that takes a left-hand operand of type "
278         "'const void' and a right operand of type 'const void'"));
279     EXPECT_TRUE(foundInIntermediateTree(
280         "cannot convert from 'const void' to 'highp 3-component vector of float'"));
281 }
282 
TEST_F(ParseTest,HugeUnsizedMultidimensionalArrayConstructorNoCrash)283 TEST_F(ParseTest, HugeUnsizedMultidimensionalArrayConstructorNoCrash)
284 {
285     mCompileOptions.limitExpressionComplexity = true;
286     std::ostringstream shader;
287     shader << R"(#version 310 es
288 int E=int)";
289     for (int i = 0; i < 10000; ++i)
290     {
291         shader << "[]";
292     }
293     shader << "()";
294     EXPECT_FALSE(compile(shader.str()));
295     EXPECT_TRUE(foundErrorInIntermediateTree());
296     EXPECT_TRUE(foundInIntermediateTree("array has too many dimensions"));
297 }
298 
TEST_F(ParseTest,HugeMultidimensionalArrayConstructorNoCrash)299 TEST_F(ParseTest, HugeMultidimensionalArrayConstructorNoCrash)
300 {
301     mCompileOptions.limitExpressionComplexity = true;
302     std::ostringstream shader;
303     shader << R"(#version 310 es
304 int E=int)";
305     for (int i = 0; i < 10000; ++i)
306     {
307         shader << "[1]";
308     }
309 
310     for (int i = 0; i < 10000; ++i)
311     {
312         shader << "(2)";
313     }
314     EXPECT_FALSE(compile(shader.str()));
315     EXPECT_TRUE(foundErrorInIntermediateTree());
316     EXPECT_TRUE(foundInIntermediateTree("array has too many dimensions"));
317 }
318 
TEST_F(ParseTest,DeeplyNestedWhileStatementsNoCrash)319 TEST_F(ParseTest, DeeplyNestedWhileStatementsNoCrash)
320 {
321     mShaderSpec = SH_WEBGL2_SPEC;
322     std::ostringstream shader;
323     shader << R"(#version 300 es
324 void main() {
325 )";
326     for (int i = 0; i < 1700; ++i)
327     {
328         shader << " while(true)";
329     }
330     shader << "; }";
331     EXPECT_FALSE(compile(shader.str()));
332     EXPECT_TRUE(foundErrorInIntermediateTree());
333     EXPECT_TRUE(foundInIntermediateTree("statement is too deeply nested"));
334 }
335 
TEST_F(ParseTest,DeeplyNestedForStatementsNoCrash)336 TEST_F(ParseTest, DeeplyNestedForStatementsNoCrash)
337 {
338     mShaderSpec = SH_WEBGL2_SPEC;
339     std::ostringstream shader;
340     shader << R"(#version 300 es
341 void main() {
342 )";
343     for (int i = 0; i < 1700; ++i)
344     {
345         shader << " for(int i = 0; i < 10; i++)";
346     }
347     shader << "; }";
348     EXPECT_FALSE(compile(shader.str()));
349     EXPECT_TRUE(foundErrorInIntermediateTree());
350     EXPECT_TRUE(foundInIntermediateTree("statement is too deeply nested"));
351 }
352 
TEST_F(ParseTest,DeeplyNestedDoWhileStatementsNoCrash)353 TEST_F(ParseTest, DeeplyNestedDoWhileStatementsNoCrash)
354 {
355     mShaderSpec = SH_WEBGL2_SPEC;
356     std::ostringstream shader;
357     shader << R"(#version 300 es
358 void main() {
359 )";
360     for (int i = 0; i < 1700; ++i)
361     {
362         shader << " do {";
363     }
364     for (int i = 0; i < 1700; ++i)
365     {
366         shader << "} while(true);";
367     }
368     shader << "}";
369     EXPECT_FALSE(compile(shader.str()));
370     EXPECT_TRUE(foundErrorInIntermediateTree());
371     EXPECT_TRUE(foundInIntermediateTree("statement is too deeply nested"));
372 }
373 
TEST_F(ParseTest,DeeplyNestedSwitchStatementsNoCrash)374 TEST_F(ParseTest, DeeplyNestedSwitchStatementsNoCrash)
375 {
376     mShaderSpec = SH_WEBGL2_SPEC;
377     std::ostringstream shader;
378     shader << R"(#version 300 es
379 void main() {
380 )";
381     for (int i = 0; i < 1700; ++i)
382     {
383         shader << " switch(1) { default: int i=0;";
384     }
385     for (int i = 0; i < 1700; ++i)
386     {
387         shader << "}";
388     }
389     shader << "}";
390     EXPECT_FALSE(compile(shader.str()));
391     EXPECT_TRUE(foundErrorInIntermediateTree());
392     EXPECT_TRUE(foundInIntermediateTree("statement is too deeply nested"));
393 }
394 
TEST_F(ParseTest,ManyChainedUnaryExpressionsNoCrash)395 TEST_F(ParseTest, ManyChainedUnaryExpressionsNoCrash)
396 {
397     mCompileOptions.limitExpressionComplexity = true;
398     mShaderSpec                               = SH_WEBGL2_SPEC;
399     std::ostringstream shader;
400     shader << R"(#version 300 es
401 precision mediump float;
402 void main() {
403   int iterations=0;)";
404     for (int i = 0; i < 6000; ++i)
405     {
406         shader << "~";
407     }
408     shader << R"(++iterations;
409 }
410 )";
411     EXPECT_FALSE(compile(shader.str()));
412     EXPECT_TRUE(foundErrorInIntermediateTree());
413     EXPECT_TRUE(foundInIntermediateTree("Expression too complex"));
414 }
415 
TEST_F(ParseTest,ManyChainedAssignmentsNoCrash)416 TEST_F(ParseTest, ManyChainedAssignmentsNoCrash)
417 {
418     mCompileOptions.limitExpressionComplexity = true;
419     mShaderSpec                               = SH_WEBGL2_SPEC;
420     std::ostringstream shader;
421     shader << R"(#version 300 es
422 void main() {
423     int c = 0;
424 )";
425     for (int i = 0; i < 3750; ++i)
426     {
427         shader << "c=\n";
428     }
429     shader << "c+1; }";
430     EXPECT_FALSE(compile(shader.str()));
431     EXPECT_TRUE(foundErrorInIntermediateTree());
432     EXPECT_TRUE(foundInIntermediateTree("Expression too complex"));
433 }
434 
435 // Test that comma expression referring to an uniform block member through instance-name is not an
436 // error.
TEST_F(ParseTest,UniformBlockWorks)437 TEST_F(ParseTest, UniformBlockWorks)
438 {
439     mShaderSpec          = SH_WEBGL2_SPEC;
440     const char kShader[] = R"(#version 300 es
441          uniform B { uint e; } b;
442          void main() { b.e; })";
443 
444     EXPECT_TRUE(compile(kShader));
445 
446     const char kShader2[] = R"(#version 300 es
447          uniform B { uint e; } b;
448          mediump float f() { return .0; }
449          void main() { f(), b.e; })";
450     EXPECT_TRUE(compile(kShader2));
451 
452     const char kShader3[] = R"(#version 300 es
453          uniform B { uint e; };
454          void main() { e; })";
455     EXPECT_TRUE(compile(kShader3));
456 
457     const char kShader4[] = R"(#version 300 es
458         uniform B { uint e; };
459         mediump float f() { return .0; }
460         void main() { f(), e; })";
461     EXPECT_TRUE(compile(kShader4));
462 
463     const char kShader5[] = R"(#version 300 es
464         uniform B { uint e; } b[3];
465         void main() { b[0].e; })";
466     EXPECT_TRUE(compile(kShader5));
467 
468     const char kShader6[] = R"(#version 300 es
469         uniform B { uint e; } b[3];
470         mediump float f() { return .0; }
471         void main() { f(), b[0].e; })";
472     EXPECT_TRUE(compile(kShader6));
473 }
474 
475 // Test that comma expression referring to an uniform block instance-name is an error.
TEST_F(ParseTest,UniformBlockInstanceNameReferenceIsError)476 TEST_F(ParseTest, UniformBlockInstanceNameReferenceIsError)
477 {
478     mShaderSpec = SH_WEBGL2_SPEC;
479 
480     const char kShader[] = R"(#version 300 es
481          precision mediump float;
482          uniform B { uint e; } b;
483          void main() { b; })";
484     EXPECT_FALSE(compile(kShader));
485     EXPECT_TRUE(foundErrorInIntermediateTree());
486     EXPECT_TRUE(
487         foundInIntermediateTree("expression statement is not allowed for interface blocks"));
488 
489     const char kShader2[] = R"(#version 300 es
490          uniform B { uint e; } b;
491          mediump float f() { return .0; }
492          void main() { f(), b; })";
493     EXPECT_FALSE(compile(kShader2));
494     EXPECT_TRUE(foundErrorInIntermediateTree());
495     EXPECT_TRUE(
496         foundInIntermediateTree("',' : sequence operator is not allowed for interface blocks"));
497 }
498 
499 // Test that expression statements resulting in a uniform block instance-name as an array subscript
500 // is an error.
TEST_F(ParseTest,UniformBlockInstanceNameReferenceSubscriptIsError)501 TEST_F(ParseTest, UniformBlockInstanceNameReferenceSubscriptIsError)
502 {
503     mShaderSpec = SH_WEBGL2_SPEC;
504 
505     const char kShader[] = R"(#version 300 es
506          precision mediump float;
507          uniform B { uint e; } b[3];
508          void main() { b[0]; })";
509     EXPECT_FALSE(compile(kShader));
510     EXPECT_TRUE(foundErrorInIntermediateTree());
511     EXPECT_TRUE(
512         foundInIntermediateTree("expression statement is not allowed for interface blocks"));
513     const char kShader2[] = R"(#version 300 es
514          uniform B { uint e; } b[3];
515          mediump float f() { return .0; }
516          void main() { f(), b[0]; })";
517     EXPECT_FALSE(compile(kShader2));
518     EXPECT_TRUE(foundErrorInIntermediateTree());
519     EXPECT_TRUE(
520         foundInIntermediateTree("',' : sequence operator is not allowed for interface blocks"));
521 }
522 
523 // Test that expressions using binary operations on a uniform block instance-name is an error.
TEST_F(ParseTest,UniformBlockInstanceNameOpIsError)524 TEST_F(ParseTest, UniformBlockInstanceNameOpIsError)
525 {
526     mShaderSpec = SH_WEBGL2_SPEC;
527 
528     const char kShader[] = R"(#version 300 es
529         precision mediump float;
530         uniform B { uint e; } b;
531         void main() { b = b; })";
532     EXPECT_FALSE(compile(kShader));
533     EXPECT_TRUE(foundErrorInIntermediateTree());
534     EXPECT_TRUE(
535         foundInIntermediateTree("'assign' : l-value required (can't modify a uniform \"b\")"));
536     EXPECT_TRUE(foundInIntermediateTree("'=' : Invalid operation for interface blocks"));
537     EXPECT_TRUE(foundInIntermediateTree(
538         "'assign' : cannot convert from 'uniform interface block' to 'uniform interface block'"));
539 
540     const char kShader2[] = R"(#version 300 es
541         uniform B { uint e; } b;
542         void main() { b == b; })";
543     EXPECT_FALSE(compile(kShader2));
544     EXPECT_TRUE(foundErrorInIntermediateTree());
545     EXPECT_TRUE(foundInIntermediateTree("'==' : Invalid operation for interface blocks"));
546     EXPECT_TRUE(foundInIntermediateTree(
547         "'==' : wrong operand types - no operation '==' exists that takes a left-hand operand of "
548         "type 'uniform interface block' and a right operand of type 'uniform interface block' (or "
549         "there is no acceptable conversion)"));
550     const char kShader3[] = R"(#version 300 es
551          uniform B { uint e; } b;
552          void main() { b.e > 33u ? b : b; })";
553     EXPECT_FALSE(compile(kShader3));
554     EXPECT_TRUE(foundErrorInIntermediateTree());
555     EXPECT_TRUE(
556         foundInIntermediateTree("'?:' : ternary operator is not allowed for interface blocks"));
557 }
558 
TEST_F(ParseTest,UniformBlockReferenceIsError)559 TEST_F(ParseTest, UniformBlockReferenceIsError)
560 {
561     const char kShader[] = R"(#version 300 es
562         uniform B { uint e; } b;
563         void main() { B; })";
564     EXPECT_FALSE(compile(kShader));
565     EXPECT_TRUE(foundErrorInIntermediateTree());
566     EXPECT_TRUE(foundInIntermediateTree("'B' : variable expected"));
567 
568     const char kShader2[] = R"(#version 300 es
569         uniform B { uint e; };
570         mediump float f() { return .0; }
571         void main() { f(), B; })";
572     EXPECT_FALSE(compile(kShader2));
573     EXPECT_TRUE(foundErrorInIntermediateTree());
574     EXPECT_TRUE(foundInIntermediateTree("'B' : variable expected"));
575 }
576 
577 // Tests that referring to functions is a parse error.
TEST_F(ParseTest,FunctionReferenceIsError)578 TEST_F(ParseTest, FunctionReferenceIsError)
579 {
580     mShaderSpec          = SH_WEBGL2_SPEC;
581     const char kShader[] = R"(#version 300 es
582         mediump float f() { return .0; }
583         void main() { f; })";
584     EXPECT_FALSE(compile(kShader));
585     EXPECT_TRUE(foundErrorInIntermediateTree());
586     EXPECT_TRUE(foundInIntermediateTree("'f' : variable expected"));
587 
588     const char kShader2[] = R"(#version 300 es
589         mediump float f() { return .0; }
590         void main() { f(), f; })";
591     EXPECT_FALSE(compile(kShader2));
592     EXPECT_TRUE(foundErrorInIntermediateTree());
593     EXPECT_TRUE(foundInIntermediateTree("'f' : variable expected"));
594 }
595 
596 // Tests that referring to builtin functions is a parse error.
597 // Shows discrepancy where the error message is unexpected, user defined functions have
598 // better error message.
TEST_F(ParseTest,BuiltinFunctionReferenceIsError)599 TEST_F(ParseTest, BuiltinFunctionReferenceIsError)
600 {
601     mShaderSpec          = SH_WEBGL2_SPEC;
602     const char kShader[] = R"(#version 300 es
603         void main() { sin; })";
604     EXPECT_FALSE(compile(kShader));
605     EXPECT_TRUE(foundErrorInIntermediateTree());
606     EXPECT_TRUE(foundInIntermediateTree("'sin' : undeclared identifier"));
607 
608     const char kShader2[] = R"(#version 300 es
609         void main() { sin(3.0), sin; })";
610     EXPECT_FALSE(compile(kShader2));
611     EXPECT_TRUE(foundErrorInIntermediateTree());
612     EXPECT_TRUE(foundInIntermediateTree("'sin' : undeclared identifier"));
613 }
614 
615 // Tests that unsized array parameters fail.
TEST_F(ParseTest,UnsizedArrayParameterIsError)616 TEST_F(ParseTest, UnsizedArrayParameterIsError)
617 {
618     mShaderSpec          = SH_WEBGL2_SPEC;
619     const char kShader[] = R"(#version 300 es
620 int f(int a[], int i) {
621     return i;
622 }
623 void main() { }
624 )";
625     EXPECT_FALSE(compile(kShader));
626     EXPECT_TRUE(foundErrorInIntermediateTree());
627     EXPECT_TRUE(foundInIntermediateTree("'a' : function parameter array must specify a size"));
628 }
629 
630 // Tests that unsized array parameters fail.
TEST_F(ParseTest,UnsizedArrayParameterIsError2)631 TEST_F(ParseTest, UnsizedArrayParameterIsError2)
632 {
633     mShaderSpec          = SH_GLES3_1_SPEC;
634     const char kShader[] = R"(#version 310 es
635 int f(int []a[1], int i) {
636     return i;
637 }
638 void main() { }
639 )";
640     EXPECT_FALSE(compile(kShader));
641     EXPECT_TRUE(foundErrorInIntermediateTree());
642     EXPECT_TRUE(foundInIntermediateTree("'a' : function parameter array must specify a size"));
643 }
644 
645 // Tests that unnamed, unsized array parameters fail with same error message as named ones.
TEST_F(ParseTest,UnnamedUnsizedArrayParameterIsError)646 TEST_F(ParseTest, UnnamedUnsizedArrayParameterIsError)
647 {
648     mShaderSpec          = SH_WEBGL2_SPEC;
649     const char kShader[] = R"(#version 300 es
650 int f(int[], int i) {
651     return i;
652 }
653 void main() { }
654 )";
655     EXPECT_FALSE(compile(kShader));
656     EXPECT_TRUE(foundErrorInIntermediateTree());
657     EXPECT_TRUE(foundInIntermediateTree("'' : function parameter array must specify a size"));
658 }
659 
660 // Tests that different array notatinos [1]a[2], a[1][2] etc work in parameters.
TEST_F(ParseTest,ArrayParameterVariants)661 TEST_F(ParseTest, ArrayParameterVariants)
662 {
663     mShaderSpec          = SH_GLES3_1_SPEC;
664     const char kShader[] = R"(#version 310 es
665 int f(int[1][2] a) {
666     return a[0][0];
667 }
668 int g(int a[1][2]) {
669     return a[0][0];
670 }
671 int h(int[1]a[2]) {
672     return a[0][0];
673 }
674 void main() {
675     int[1][2] a;
676     int b[1][2];
677     int x1 = f(a);
678     int x2 = f(b);
679     int x3 = g(a);
680     int x4 = g(b);
681 
682     int[1] c[2];
683     int d[2][1];
684     int y1 = h(c);
685     int y2 = h(d);
686 }
687 )";
688     EXPECT_TRUE(compile(kShader));
689 }
690 
691 // Tests that parameters parse the [1]a[2] notation in correct order.
TEST_F(ParseTest,ArrayParameterVariantsMismatchIsError2)692 TEST_F(ParseTest, ArrayParameterVariantsMismatchIsError2)
693 {
694     mShaderSpec          = SH_GLES3_1_SPEC;
695     const char kShader[] = R"(#version 310 es
696 int f(int[1]a[2]) {
697     return a[0][0];
698 }
699 void main() {
700     int[1][2] a;
701     int x = f(a);
702 }
703 )";
704     EXPECT_FALSE(compile(kShader));
705     EXPECT_TRUE(foundErrorInIntermediateTree());
706     EXPECT_TRUE(foundInIntermediateTree("'f' : no matching overloaded function found"));
707 }
708 
709 // Tests that specifying a struct in a function parameter is a parse error.
TEST_F(ParseTest,StructSpecificationFunctionParameterIsError)710 TEST_F(ParseTest, StructSpecificationFunctionParameterIsError)
711 {
712     mShaderSpec          = SH_WEBGL2_SPEC;
713     const char kShader[] = R"(#version 300 es
714 precision highp float;
715 float f(struct S {float f;} a) {
716     return a.f;
717 }
718 void main() { })";
719     EXPECT_FALSE(compile(kShader));
720     EXPECT_TRUE(foundErrorInIntermediateTree());
721     EXPECT_TRUE(
722         foundInIntermediateTree("'a' : Function parameter type cannot be a structure definition"));
723 }
724 
725 // Tests that specifying a struct in a function parameter is the same parse error as with named one.
TEST_F(ParseTest,StructSpecificationUnnamedFunctionParameterIsError)726 TEST_F(ParseTest, StructSpecificationUnnamedFunctionParameterIsError)
727 {
728     mShaderSpec          = SH_WEBGL2_SPEC;
729     const char kShader[] = R"(#version 300 es
730 precision highp float;
731 float f(struct S {float f;}) {
732     return a.f;
733 }
734 void main() { })";
735     EXPECT_FALSE(compile(kShader));
736     EXPECT_TRUE(foundErrorInIntermediateTree());
737     EXPECT_TRUE(
738         foundInIntermediateTree("'' : Function parameter type cannot be a structure definition"));
739 }
740 
741 // Tests that specifying a struct in a function parameter is the same parse error as with named one.
TEST_F(ParseTest,UnnamedStructSpecificationUnnamedFunctionParameterIsError)742 TEST_F(ParseTest, UnnamedStructSpecificationUnnamedFunctionParameterIsError)
743 {
744     mShaderSpec          = SH_WEBGL2_SPEC;
745     const char kShader[] = R"(#version 300 es
746 precision highp float;
747 float f(struct {float f;}) {
748     return a.f;
749 }
750 void main() { })";
751     EXPECT_FALSE(compile(kShader));
752     EXPECT_TRUE(foundErrorInIntermediateTree());
753     EXPECT_TRUE(
754         foundInIntermediateTree("'' : Function parameter type cannot be a structure definition"));
755 }
756 
757 // Tests that specifying a struct in a function parameter is the same parse error as with named one.
TEST_F(ParseTest,UnnamedStructSpecificationFunctionParameterIsError)758 TEST_F(ParseTest, UnnamedStructSpecificationFunctionParameterIsError)
759 {
760     mShaderSpec          = SH_WEBGL2_SPEC;
761     const char kShader[] = R"(#version 300 es
762 precision highp float;
763 float f(struct {float f;} d) {
764     return a.f;
765 }
766 void main() { })";
767     EXPECT_FALSE(compile(kShader));
768     EXPECT_TRUE(foundErrorInIntermediateTree());
769     EXPECT_TRUE(
770         foundInIntermediateTree("'d' : Function parameter type cannot be a structure definition"));
771 }
772 
TEST_F(ParseTest,SeparateStructStructSpecificationFunctionNoCrash)773 TEST_F(ParseTest, SeparateStructStructSpecificationFunctionNoCrash)
774 {
775     mCompileOptions.validateAST = 1;
776     const char kShader[] =
777         R"(struct S{int f;};struct S2{S h;} o() { return S2(S(1)); } void main(){ S2 s2 = o(); })";
778     EXPECT_TRUE(compile(kShader));
779 }
780 
781 // Test showing that prototypes get the function definition variable names.
782 // An example where parser loses information.
TEST_F(ParseTest,VariableNamesInPrototypesUnnamedOut)783 TEST_F(ParseTest, VariableNamesInPrototypesUnnamedOut)
784 {
785     const char kShader[]   = R"(
786 precision highp float;
787 void f(out float, out float);
788 void main()
789 {
790     gl_FragColor = vec4(0.5);
791     f(gl_FragColor.r, gl_FragColor.g);
792 }
793 void f(out float r, out float)
794 {
795     r = 1.0;
796 }
797 )";
798     const char kExpected[] = R"(0:2: Code block
799 0:3:   Function Prototype: 'f' (symbol id 3001) (void)
800 0:3:     parameter: 'r' (symbol id 3006) (out highp float)
801 0:3:     parameter: '' (symbol id 3007) (out highp float)
802 0:4:   Function Definition:
803 0:4:     Function Prototype: 'main' (symbol id 3004) (void)
804 0:5:     Code block
805 0:6:       move second child to first child (mediump 4-component vector of float)
806 0:6:         gl_FragColor (symbol id 2230) (FragColor mediump 4-component vector of float)
807 0:6:         Constant union (const mediump 4-component vector of float)
808 0:6:           0.5 (const float)
809 0:6:           0.5 (const float)
810 0:6:           0.5 (const float)
811 0:6:           0.5 (const float)
812 0:7:       Call a function: 'f' (symbol id 3001) (void)
813 0:7:         vector swizzle (x) (mediump float)
814 0:7:           gl_FragColor (symbol id 2230) (FragColor mediump 4-component vector of float)
815 0:7:         vector swizzle (y) (mediump float)
816 0:7:           gl_FragColor (symbol id 2230) (FragColor mediump 4-component vector of float)
817 0:9:   Function Definition:
818 0:9:     Function Prototype: 'f' (symbol id 3001) (void)
819 0:9:       parameter: 'r' (symbol id 3006) (out highp float)
820 0:9:       parameter: '' (symbol id 3007) (out highp float)
821 0:10:     Code block
822 0:11:       move second child to first child (highp float)
823 0:11:         'r' (symbol id 3006) (out highp float)
824 0:11:         Constant union (const highp float)
825 0:11:           1.0 (const float)
826 )";
827     compile(kShader);
828     EXPECT_EQ(kExpected, intermediateTree());
829 }
830 
TEST_F(ParseTest,ConstInSamplerParamNoCrash)831 TEST_F(ParseTest, ConstInSamplerParamNoCrash)
832 {
833     mCompileOptions.validateAST = 1;
834     const char kShader[]        = R"(void n(const in sampler2D){2;} void main(){})";
835     EXPECT_TRUE(compile(kShader));
836 }
837 
TEST_F(ParseTest,ConstSamplerParamNoCrash)838 TEST_F(ParseTest, ConstSamplerParamNoCrash)
839 {
840     mCompileOptions.validateAST = 1;
841     const char kShader[]        = R"(void n(const sampler2D){2;} void main(){})";
842     EXPECT_TRUE(compile(kShader));
843 }
844 
TEST_F(ParseTest,InConstSamplerParamIsError)845 TEST_F(ParseTest, InConstSamplerParamIsError)
846 {
847     mCompileOptions.validateAST = 1;
848     const char kShader[]        = R"(void n(in const sampler2D){2;} void main(){})";
849     EXPECT_FALSE(compile(kShader));
850     EXPECT_TRUE(foundErrorInIntermediateTree());
851     EXPECT_TRUE(foundInIntermediateTree("'const' : invalid parameter qualifier"));
852 }
853 
TEST_F(ParseTest,UniformBlockInstanceUnsizedArrayIsError)854 TEST_F(ParseTest, UniformBlockInstanceUnsizedArrayIsError)
855 {
856     const char kShader[] = R"(#version 300 es
857 precision mediump float;out vec4 o;uniform a{float r;}u[];void main(){o=vec4(u[0].r+u[1].r+u[1].r);})";
858     EXPECT_FALSE(compile(kShader));
859     EXPECT_TRUE(foundErrorInIntermediateTree());
860     EXPECT_TRUE(
861         foundInIntermediateTree("'u' : implicitly sized arrays only allowed for tessellation "
862                                 "shaders or geometry shader inputs"));
863 }
864 
TEST_F(ParseTest,InputBlockInstanceUnsizedArrayIsError)865 TEST_F(ParseTest, InputBlockInstanceUnsizedArrayIsError)
866 {
867     const char kShader[] = R"(#version 300 es
868 precision mediump float;out vec4 o;in a{float r;}i[];void main(){o=vec4(i[0].r+i[1].r+i[1].r);})";
869     EXPECT_FALSE(compile(kShader));
870     EXPECT_TRUE(foundErrorInIntermediateTree());
871     EXPECT_TRUE(
872         foundInIntermediateTree("'i' : implicitly sized arrays only allowed for tessellation "
873                                 "shaders or geometry shader inputs"));
874 }
875 
TEST_F(ParseTest,OutputBlockInstanceUnsizedArrayIsError)876 TEST_F(ParseTest, OutputBlockInstanceUnsizedArrayIsError)
877 {
878     const char kShader[] = R"(#version 300 es
879 precision mediump float;out a{float r;}o[];void main(){o[0].r=1.0; o[1].r=2.0;})";
880     EXPECT_FALSE(compile(kShader));
881     EXPECT_TRUE(foundErrorInIntermediateTree());
882     EXPECT_TRUE(
883         foundInIntermediateTree("'o' : implicitly sized arrays only allowed for tessellation "
884                                 "shaders or geometry shader inputs"));
885 }
886