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