blob: 8807eeecf31e065459015199522fc01e94c8cb61 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Jamie Madill6b9cb252013-10-17 10:45:47 -04007#include "compiler/translator/ParseContext.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +00008
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00009#include <stdarg.h>
apatrick@chromium.org8187fa82010-06-15 22:09:28 +000010#include <stdio.h>
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000011
daniel@transgaming.comb401a922012-10-26 18:58:24 +000012#include "compiler/preprocessor/SourceLocation.h"
Dmitry Skiba01971112015-07-10 14:54:00 -040013#include "compiler/translator/Cache.h"
Olli Etuahoac5274d2015-02-20 10:19:08 +020014#include "compiler/translator/glslang.h"
15#include "compiler/translator/ValidateSwitch.h"
Olli Etuahob0c645e2015-05-12 14:25:36 +030016#include "compiler/translator/ValidateGlobalInitializer.h"
Olli Etuaho37ad4742015-04-27 13:18:50 +030017#include "compiler/translator/util.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000018
Jamie Madill45bcc782016-11-07 13:58:48 -050019namespace sh
20{
21
alokp@chromium.org8b851c62012-06-15 16:25:11 +000022///////////////////////////////////////////////////////////////////////
23//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000024// Sub- vector and matrix fields
25//
26////////////////////////////////////////////////////////////////////////
27
Martin Radev2cc85b32016-08-05 16:22:53 +030028namespace
29{
30
31const int kWebGLMaxStructNesting = 4;
32
33bool ContainsSampler(const TType &type)
34{
35 if (IsSampler(type.getBasicType()))
36 return true;
37
38 if (type.getBasicType() == EbtStruct || type.isInterfaceBlock())
39 {
40 const TFieldList &fields = type.getStruct()->fields();
41 for (unsigned int i = 0; i < fields.size(); ++i)
42 {
43 if (ContainsSampler(*fields[i]->type()))
44 return true;
45 }
46 }
47
48 return false;
49}
50
51bool ContainsImage(const TType &type)
52{
53 if (IsImage(type.getBasicType()))
54 return true;
55
56 if (type.getBasicType() == EbtStruct || type.isInterfaceBlock())
57 {
58 const TFieldList &fields = type.getStruct()->fields();
59 for (unsigned int i = 0; i < fields.size(); ++i)
60 {
61 if (ContainsImage(*fields[i]->type()))
62 return true;
63 }
64 }
65
66 return false;
67}
68
69} // namespace
70
Jamie Madillacb4b812016-11-07 13:50:29 -050071TParseContext::TParseContext(TSymbolTable &symt,
72 TExtensionBehavior &ext,
73 sh::GLenum type,
74 ShShaderSpec spec,
75 ShCompileOptions options,
76 bool checksPrecErrors,
77 TInfoSink &is,
78 const ShBuiltInResources &resources)
79 : intermediate(),
80 symbolTable(symt),
81 mDeferredSingleDeclarationErrorCheck(false),
82 mShaderType(type),
83 mShaderSpec(spec),
84 mCompileOptions(options),
85 mShaderVersion(100),
86 mTreeRoot(nullptr),
87 mLoopNestingLevel(0),
88 mStructNestingLevel(0),
89 mSwitchNestingLevel(0),
90 mCurrentFunctionType(nullptr),
91 mFunctionReturnsValue(false),
92 mChecksPrecisionErrors(checksPrecErrors),
93 mFragmentPrecisionHighOnESSL1(false),
94 mDefaultMatrixPacking(EmpColumnMajor),
95 mDefaultBlockStorage(sh::IsWebGLBasedSpec(spec) ? EbsStd140 : EbsShared),
96 mDiagnostics(is),
97 mDirectiveHandler(ext,
98 mDiagnostics,
99 mShaderVersion,
100 mShaderType,
101 resources.WEBGL_debug_shader_precision == 1),
Olli Etuahof1cf5e62016-11-22 17:36:49 +0000102 mPreprocessor(&mDiagnostics, &mDirectiveHandler, pp::PreprocessorSettings()),
Jamie Madillacb4b812016-11-07 13:50:29 -0500103 mScanner(nullptr),
104 mUsesFragData(false),
105 mUsesFragColor(false),
106 mUsesSecondaryOutputs(false),
107 mMinProgramTexelOffset(resources.MinProgramTexelOffset),
108 mMaxProgramTexelOffset(resources.MaxProgramTexelOffset),
109 mComputeShaderLocalSizeDeclared(false),
110 mDeclaringFunction(false)
111{
112 mComputeShaderLocalSize.fill(-1);
113}
114
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000115//
116// Look at a '.' field selector string and change it into offsets
117// for a vector.
118//
Jamie Madillb98c3a82015-07-23 14:26:04 -0400119bool TParseContext::parseVectorFields(const TString &compString,
120 int vecSize,
121 TVectorFields &fields,
Arun Patole7e7e68d2015-05-22 12:02:25 +0530122 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000123{
Jamie Madillb98c3a82015-07-23 14:26:04 -0400124 fields.num = (int)compString.size();
Arun Patole7e7e68d2015-05-22 12:02:25 +0530125 if (fields.num > 4)
126 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000127 error(line, "illegal vector field selection", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000128 return false;
129 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000130
Jamie Madillb98c3a82015-07-23 14:26:04 -0400131 enum
132 {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000133 exyzw,
134 ergba,
daniel@transgaming.comb3077d02013-01-11 04:12:09 +0000135 estpq
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000136 } fieldSet[4];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000137
Arun Patole7e7e68d2015-05-22 12:02:25 +0530138 for (int i = 0; i < fields.num; ++i)
139 {
140 switch (compString[i])
141 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400142 case 'x':
143 fields.offsets[i] = 0;
144 fieldSet[i] = exyzw;
145 break;
146 case 'r':
147 fields.offsets[i] = 0;
148 fieldSet[i] = ergba;
149 break;
150 case 's':
151 fields.offsets[i] = 0;
152 fieldSet[i] = estpq;
153 break;
154 case 'y':
155 fields.offsets[i] = 1;
156 fieldSet[i] = exyzw;
157 break;
158 case 'g':
159 fields.offsets[i] = 1;
160 fieldSet[i] = ergba;
161 break;
162 case 't':
163 fields.offsets[i] = 1;
164 fieldSet[i] = estpq;
165 break;
166 case 'z':
167 fields.offsets[i] = 2;
168 fieldSet[i] = exyzw;
169 break;
170 case 'b':
171 fields.offsets[i] = 2;
172 fieldSet[i] = ergba;
173 break;
174 case 'p':
175 fields.offsets[i] = 2;
176 fieldSet[i] = estpq;
177 break;
Arun Patole7e7e68d2015-05-22 12:02:25 +0530178
Jamie Madillb98c3a82015-07-23 14:26:04 -0400179 case 'w':
180 fields.offsets[i] = 3;
181 fieldSet[i] = exyzw;
182 break;
183 case 'a':
184 fields.offsets[i] = 3;
185 fieldSet[i] = ergba;
186 break;
187 case 'q':
188 fields.offsets[i] = 3;
189 fieldSet[i] = estpq;
190 break;
191 default:
192 error(line, "illegal vector field selection", compString.c_str());
193 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000194 }
195 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000196
Arun Patole7e7e68d2015-05-22 12:02:25 +0530197 for (int i = 0; i < fields.num; ++i)
198 {
199 if (fields.offsets[i] >= vecSize)
200 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400201 error(line, "vector field selection out of range", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000202 return false;
203 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000204
Arun Patole7e7e68d2015-05-22 12:02:25 +0530205 if (i > 0)
206 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400207 if (fieldSet[i] != fieldSet[i - 1])
Arun Patole7e7e68d2015-05-22 12:02:25 +0530208 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400209 error(line, "illegal - vector component fields not from the same set",
210 compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000211 return false;
212 }
213 }
214 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000215
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000216 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000217}
218
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000219///////////////////////////////////////////////////////////////////////
220//
221// Errors
222//
223////////////////////////////////////////////////////////////////////////
224
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000225
226//
227// Used by flex/bison to output all syntax and parsing errors.
228//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530229void TParseContext::error(const TSourceLoc &loc,
Jamie Madillb98c3a82015-07-23 14:26:04 -0400230 const char *reason,
231 const char *token,
Arun Patole7e7e68d2015-05-22 12:02:25 +0530232 const char *extraInfo)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000233{
Olli Etuaho1cc598f2016-08-18 13:50:30 +0300234 mDiagnostics.error(loc, reason, token, extraInfo);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000235}
236
Arun Patole7e7e68d2015-05-22 12:02:25 +0530237void TParseContext::warning(const TSourceLoc &loc,
Jamie Madillb98c3a82015-07-23 14:26:04 -0400238 const char *reason,
239 const char *token,
Arun Patole7e7e68d2015-05-22 12:02:25 +0530240 const char *extraInfo)
241{
Olli Etuaho1cc598f2016-08-18 13:50:30 +0300242 mDiagnostics.warning(loc, reason, token, extraInfo);
alokp@chromium.org044a5cf2010-11-12 15:42:16 +0000243}
244
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200245void TParseContext::outOfRangeError(bool isError,
246 const TSourceLoc &loc,
247 const char *reason,
248 const char *token,
249 const char *extraInfo)
250{
251 if (isError)
252 {
253 error(loc, reason, token, extraInfo);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200254 }
255 else
256 {
257 warning(loc, reason, token, extraInfo);
258 }
259}
260
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000261//
262// Same error message for all places assignments don't work.
263//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530264void TParseContext::assignError(const TSourceLoc &line, const char *op, TString left, TString right)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000265{
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000266 std::stringstream extraInfoStream;
267 extraInfoStream << "cannot convert from '" << right << "' to '" << left << "'";
268 std::string extraInfo = extraInfoStream.str();
269 error(line, "", op, extraInfo.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000270}
271
272//
273// Same error message for all places unary operations don't work.
274//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530275void TParseContext::unaryOpError(const TSourceLoc &line, const char *op, TString operand)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000276{
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000277 std::stringstream extraInfoStream;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400278 extraInfoStream << "no operation '" << op << "' exists that takes an operand of type "
279 << operand << " (or there is no acceptable conversion)";
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000280 std::string extraInfo = extraInfoStream.str();
281 error(line, " wrong operand type", op, extraInfo.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000282}
283
284//
285// Same error message for all binary operations don't work.
286//
Jamie Madillb98c3a82015-07-23 14:26:04 -0400287void TParseContext::binaryOpError(const TSourceLoc &line,
288 const char *op,
289 TString left,
290 TString right)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000291{
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000292 std::stringstream extraInfoStream;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400293 extraInfoStream << "no operation '" << op << "' exists that takes a left-hand operand of type '"
294 << left << "' and a right operand of type '" << right
295 << "' (or there is no acceptable conversion)";
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000296 std::string extraInfo = extraInfoStream.str();
Arun Patole7e7e68d2015-05-22 12:02:25 +0530297 error(line, " wrong operand types ", op, extraInfo.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000298}
299
Olli Etuaho856c4972016-08-08 11:38:39 +0300300void TParseContext::checkPrecisionSpecified(const TSourceLoc &line,
301 TPrecision precision,
302 TBasicType type)
Arun Patole7e7e68d2015-05-22 12:02:25 +0530303{
Jamie Madill6e06b1f2015-05-14 10:01:17 -0400304 if (!mChecksPrecisionErrors)
Olli Etuaho383b7912016-08-05 11:22:59 +0300305 return;
Martin Radev70866b82016-07-22 15:27:42 +0300306
307 if (precision != EbpUndefined && !SupportsPrecision(type))
308 {
309 error(line, "illegal type for precision qualifier", getBasicString(type));
310 }
311
Olli Etuaho183d7e22015-11-20 15:59:09 +0200312 if (precision == EbpUndefined)
Arun Patole7e7e68d2015-05-22 12:02:25 +0530313 {
Olli Etuaho183d7e22015-11-20 15:59:09 +0200314 switch (type)
315 {
316 case EbtFloat:
Jamie Madillb98c3a82015-07-23 14:26:04 -0400317 error(line, "No precision specified for (float)", "");
Olli Etuaho383b7912016-08-05 11:22:59 +0300318 return;
Olli Etuaho183d7e22015-11-20 15:59:09 +0200319 case EbtInt:
320 case EbtUInt:
321 UNREACHABLE(); // there's always a predeclared qualifier
Jamie Madillb98c3a82015-07-23 14:26:04 -0400322 error(line, "No precision specified (int)", "");
Olli Etuaho383b7912016-08-05 11:22:59 +0300323 return;
Olli Etuaho183d7e22015-11-20 15:59:09 +0200324 default:
325 if (IsSampler(type))
326 {
327 error(line, "No precision specified (sampler)", "");
Olli Etuaho383b7912016-08-05 11:22:59 +0300328 return;
Olli Etuaho183d7e22015-11-20 15:59:09 +0200329 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300330 if (IsImage(type))
331 {
332 error(line, "No precision specified (image)", "");
333 return;
334 }
Olli Etuaho183d7e22015-11-20 15:59:09 +0200335 }
daniel@transgaming.coma5d76232010-05-17 09:58:47 +0000336 }
daniel@transgaming.coma5d76232010-05-17 09:58:47 +0000337}
338
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000339// Both test and if necessary, spit out an error, to see if the node is really
340// an l-value that can be operated on this way.
Olli Etuaho856c4972016-08-08 11:38:39 +0300341bool TParseContext::checkCanBeLValue(const TSourceLoc &line, const char *op, TIntermTyped *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000342{
Jamie Madillb98c3a82015-07-23 14:26:04 -0400343 TIntermSymbol *symNode = node->getAsSymbolNode();
Arun Patole7e7e68d2015-05-22 12:02:25 +0530344 TIntermBinary *binaryNode = node->getAsBinaryNode();
Olli Etuahob6fa0432016-09-28 16:28:05 +0100345 TIntermSwizzle *swizzleNode = node->getAsSwizzleNode();
346
347 if (swizzleNode)
348 {
349 bool ok = checkCanBeLValue(line, op, swizzleNode->getOperand());
350 if (ok && swizzleNode->hasDuplicateOffsets())
351 {
352 error(line, " l-value of swizzle cannot have duplicate components", op);
353 return false;
354 }
355 return ok;
356 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000357
Arun Patole7e7e68d2015-05-22 12:02:25 +0530358 if (binaryNode)
359 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400360 switch (binaryNode->getOp())
Arun Patole7e7e68d2015-05-22 12:02:25 +0530361 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400362 case EOpIndexDirect:
363 case EOpIndexIndirect:
364 case EOpIndexDirectStruct:
365 case EOpIndexDirectInterfaceBlock:
Olli Etuaho856c4972016-08-08 11:38:39 +0300366 return checkCanBeLValue(line, op, binaryNode->getLeft());
Jamie Madillb98c3a82015-07-23 14:26:04 -0400367 default:
368 break;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000369 }
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000370 error(line, " l-value required", op);
Olli Etuaho8a176262016-08-16 14:23:01 +0300371 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000372 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000373
Arun Patole7e7e68d2015-05-22 12:02:25 +0530374 const char *symbol = 0;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000375 if (symNode != 0)
376 symbol = symNode->getSymbol().c_str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000377
Arun Patole7e7e68d2015-05-22 12:02:25 +0530378 const char *message = 0;
379 switch (node->getQualifier())
380 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400381 case EvqConst:
382 message = "can't modify a const";
383 break;
384 case EvqConstReadOnly:
385 message = "can't modify a const";
386 break;
387 case EvqAttribute:
388 message = "can't modify an attribute";
389 break;
390 case EvqFragmentIn:
391 message = "can't modify an input";
392 break;
393 case EvqVertexIn:
394 message = "can't modify an input";
395 break;
396 case EvqUniform:
397 message = "can't modify a uniform";
398 break;
399 case EvqVaryingIn:
400 message = "can't modify a varying";
401 break;
402 case EvqFragCoord:
403 message = "can't modify gl_FragCoord";
404 break;
405 case EvqFrontFacing:
406 message = "can't modify gl_FrontFacing";
407 break;
408 case EvqPointCoord:
409 message = "can't modify gl_PointCoord";
410 break;
Martin Radevb0883602016-08-04 17:48:58 +0300411 case EvqNumWorkGroups:
412 message = "can't modify gl_NumWorkGroups";
413 break;
414 case EvqWorkGroupSize:
415 message = "can't modify gl_WorkGroupSize";
416 break;
417 case EvqWorkGroupID:
418 message = "can't modify gl_WorkGroupID";
419 break;
420 case EvqLocalInvocationID:
421 message = "can't modify gl_LocalInvocationID";
422 break;
423 case EvqGlobalInvocationID:
424 message = "can't modify gl_GlobalInvocationID";
425 break;
426 case EvqLocalInvocationIndex:
427 message = "can't modify gl_LocalInvocationIndex";
428 break;
Martin Radev802abe02016-08-04 17:48:32 +0300429 case EvqComputeIn:
430 message = "can't modify work group size variable";
431 break;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400432 default:
433 //
434 // Type that can't be written to?
435 //
436 if (node->getBasicType() == EbtVoid)
437 {
438 message = "can't modify void";
439 }
440 if (IsSampler(node->getBasicType()))
441 {
442 message = "can't modify a sampler";
443 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300444 if (IsImage(node->getBasicType()))
445 {
446 message = "can't modify an image";
447 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000448 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000449
Arun Patole7e7e68d2015-05-22 12:02:25 +0530450 if (message == 0 && binaryNode == 0 && symNode == 0)
451 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000452 error(line, " l-value required", op);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000453
Olli Etuaho8a176262016-08-16 14:23:01 +0300454 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000455 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000456
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000457 //
458 // Everything else is okay, no error.
459 //
460 if (message == 0)
Olli Etuaho8a176262016-08-16 14:23:01 +0300461 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000462
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000463 //
464 // If we get here, we have an error and a message.
465 //
Arun Patole7e7e68d2015-05-22 12:02:25 +0530466 if (symNode)
467 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000468 std::stringstream extraInfoStream;
469 extraInfoStream << "\"" << symbol << "\" (" << message << ")";
470 std::string extraInfo = extraInfoStream.str();
471 error(line, " l-value required", op, extraInfo.c_str());
472 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530473 else
474 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000475 std::stringstream extraInfoStream;
476 extraInfoStream << "(" << message << ")";
477 std::string extraInfo = extraInfoStream.str();
478 error(line, " l-value required", op, extraInfo.c_str());
479 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000480
Olli Etuaho8a176262016-08-16 14:23:01 +0300481 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000482}
483
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000484// Both test, and if necessary spit out an error, to see if the node is really
485// a constant.
Olli Etuaho856c4972016-08-08 11:38:39 +0300486void TParseContext::checkIsConst(TIntermTyped *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000487{
Olli Etuaho383b7912016-08-05 11:22:59 +0300488 if (node->getQualifier() != EvqConst)
489 {
490 error(node->getLine(), "constant expression required", "");
491 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000492}
493
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000494// Both test, and if necessary spit out an error, to see if the node is really
495// an integer.
Olli Etuaho856c4972016-08-08 11:38:39 +0300496void TParseContext::checkIsScalarInteger(TIntermTyped *node, const char *token)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000497{
Olli Etuaho383b7912016-08-05 11:22:59 +0300498 if (!node->isScalarInt())
499 {
500 error(node->getLine(), "integer expression required", token);
501 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000502}
503
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000504// Both test, and if necessary spit out an error, to see if we are currently
505// globally scoped.
Qiankun Miaof69682b2016-08-16 14:50:42 +0800506bool TParseContext::checkIsAtGlobalLevel(const TSourceLoc &line, const char *token)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000507{
Olli Etuaho856c4972016-08-08 11:38:39 +0300508 if (!symbolTable.atGlobalLevel())
Olli Etuaho383b7912016-08-05 11:22:59 +0300509 {
510 error(line, "only allowed at global scope", token);
Qiankun Miaof69682b2016-08-16 14:50:42 +0800511 return false;
Olli Etuaho383b7912016-08-05 11:22:59 +0300512 }
Qiankun Miaof69682b2016-08-16 14:50:42 +0800513 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000514}
515
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000516// For now, keep it simple: if it starts "gl_", it's reserved, independent
517// of scope. Except, if the symbol table is at the built-in push-level,
518// which is when we are parsing built-ins.
alokp@chromium.org613ef312010-07-21 18:54:22 +0000519// Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a
520// webgl shader.
Olli Etuaho856c4972016-08-08 11:38:39 +0300521bool TParseContext::checkIsNotReserved(const TSourceLoc &line, const TString &identifier)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000522{
Arun Patole7e7e68d2015-05-22 12:02:25 +0530523 static const char *reservedErrMsg = "reserved built-in name";
524 if (!symbolTable.atBuiltInLevel())
525 {
526 if (identifier.compare(0, 3, "gl_") == 0)
527 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000528 error(line, reservedErrMsg, "gl_");
Olli Etuaho8a176262016-08-16 14:23:01 +0300529 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000530 }
Jamie Madillacb4b812016-11-07 13:50:29 -0500531 if (sh::IsWebGLBasedSpec(mShaderSpec))
Arun Patole7e7e68d2015-05-22 12:02:25 +0530532 {
533 if (identifier.compare(0, 6, "webgl_") == 0)
534 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000535 error(line, reservedErrMsg, "webgl_");
Olli Etuaho8a176262016-08-16 14:23:01 +0300536 return false;
alokp@chromium.org613ef312010-07-21 18:54:22 +0000537 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530538 if (identifier.compare(0, 7, "_webgl_") == 0)
539 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000540 error(line, reservedErrMsg, "_webgl_");
Olli Etuaho8a176262016-08-16 14:23:01 +0300541 return false;
alokp@chromium.org613ef312010-07-21 18:54:22 +0000542 }
543 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530544 if (identifier.find("__") != TString::npos)
545 {
546 error(line,
Jamie Madillb98c3a82015-07-23 14:26:04 -0400547 "identifiers containing two consecutive underscores (__) are reserved as "
548 "possible future keywords",
Arun Patole7e7e68d2015-05-22 12:02:25 +0530549 identifier.c_str());
Olli Etuaho8a176262016-08-16 14:23:01 +0300550 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000551 }
552 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000553
Olli Etuaho8a176262016-08-16 14:23:01 +0300554 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000555}
556
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000557// Make sure there is enough data provided to the constructor to build
558// something of the type of the constructor. Also returns the type of
559// the constructor.
Olli Etuaho856c4972016-08-08 11:38:39 +0300560bool TParseContext::checkConstructorArguments(const TSourceLoc &line,
561 TIntermNode *argumentsNode,
562 const TFunction &function,
563 TOperator op,
564 const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000565{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000566 bool constructingMatrix = false;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400567 switch (op)
Arun Patole7e7e68d2015-05-22 12:02:25 +0530568 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400569 case EOpConstructMat2:
570 case EOpConstructMat2x3:
571 case EOpConstructMat2x4:
572 case EOpConstructMat3x2:
573 case EOpConstructMat3:
574 case EOpConstructMat3x4:
575 case EOpConstructMat4x2:
576 case EOpConstructMat4x3:
577 case EOpConstructMat4:
578 constructingMatrix = true;
579 break;
580 default:
581 break;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000582 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000583
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000584 //
585 // Note: It's okay to have too many components available, but not okay to have unused
586 // arguments. 'full' will go to true when enough args have been seen. If we loop
587 // again, there is an extra argument, so 'overfull' will become true.
588 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000589
Jamie Madillb98c3a82015-07-23 14:26:04 -0400590 size_t size = 0;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400591 bool full = false;
592 bool overFull = false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000593 bool matrixInMatrix = false;
594 bool arrayArg = false;
Arun Patole7e7e68d2015-05-22 12:02:25 +0530595 for (size_t i = 0; i < function.getParamCount(); ++i)
596 {
Dmitry Skibaefa3d8e2015-06-22 14:52:10 -0700597 const TConstParameter &param = function.getParam(i);
alokp@chromium.orgb19403a2010-09-08 17:56:26 +0000598 size += param.type->getObjectSize();
Arun Patole7e7e68d2015-05-22 12:02:25 +0530599
alokp@chromium.orgb19403a2010-09-08 17:56:26 +0000600 if (constructingMatrix && param.type->isMatrix())
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000601 matrixInMatrix = true;
602 if (full)
603 overFull = true;
Olli Etuaho856c4972016-08-08 11:38:39 +0300604 if (op != EOpConstructStruct && !type.isArray() && size >= type.getObjectSize())
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000605 full = true;
alokp@chromium.orgb19403a2010-09-08 17:56:26 +0000606 if (param.type->isArray())
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000607 arrayArg = true;
608 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530609
Olli Etuaho856c4972016-08-08 11:38:39 +0300610 if (type.isArray())
Olli Etuaho376f1b52015-04-13 13:23:41 +0300611 {
Olli Etuaho856c4972016-08-08 11:38:39 +0300612 // The size of an unsized constructor should already have been determined.
613 ASSERT(!type.isUnsizedArray());
614 if (static_cast<size_t>(type.getArraySize()) != function.getParamCount())
Olli Etuaho376f1b52015-04-13 13:23:41 +0300615 {
616 error(line, "array constructor needs one argument per array element", "constructor");
Olli Etuaho8a176262016-08-16 14:23:01 +0300617 return false;
Olli Etuaho376f1b52015-04-13 13:23:41 +0300618 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000619 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000620
Arun Patole7e7e68d2015-05-22 12:02:25 +0530621 if (arrayArg && op != EOpConstructStruct)
622 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000623 error(line, "constructing from a non-dereferenced array", "constructor");
Olli Etuaho8a176262016-08-16 14:23:01 +0300624 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000625 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000626
Olli Etuaho856c4972016-08-08 11:38:39 +0300627 if (matrixInMatrix && !type.isArray())
Arun Patole7e7e68d2015-05-22 12:02:25 +0530628 {
629 if (function.getParamCount() != 1)
630 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400631 error(line, "constructing matrix from matrix can only take one argument",
632 "constructor");
Olli Etuaho8a176262016-08-16 14:23:01 +0300633 return false;
daniel@transgaming.combef0b6d2010-04-29 03:32:39 +0000634 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000635 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000636
Arun Patole7e7e68d2015-05-22 12:02:25 +0530637 if (overFull)
638 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000639 error(line, "too many arguments", "constructor");
Olli Etuaho8a176262016-08-16 14:23:01 +0300640 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000641 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530642
Olli Etuaho856c4972016-08-08 11:38:39 +0300643 if (op == EOpConstructStruct && !type.isArray() &&
644 type.getStruct()->fields().size() != function.getParamCount())
Arun Patole7e7e68d2015-05-22 12:02:25 +0530645 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400646 error(line,
647 "Number of constructor parameters does not match the number of structure fields",
648 "constructor");
Olli Etuaho8a176262016-08-16 14:23:01 +0300649 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000650 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000651
Olli Etuaho856c4972016-08-08 11:38:39 +0300652 if (!type.isMatrix() || !matrixInMatrix)
Arun Patole7e7e68d2015-05-22 12:02:25 +0530653 {
Olli Etuaho856c4972016-08-08 11:38:39 +0300654 if ((op != EOpConstructStruct && size != 1 && size < type.getObjectSize()) ||
655 (op == EOpConstructStruct && size < type.getObjectSize()))
Arun Patole7e7e68d2015-05-22 12:02:25 +0530656 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000657 error(line, "not enough data provided for construction", "constructor");
Olli Etuaho8a176262016-08-16 14:23:01 +0300658 return false;
daniel@transgaming.combef0b6d2010-04-29 03:32:39 +0000659 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000660 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000661
Olli Etuaho15c2ac32015-11-09 15:51:43 +0200662 if (argumentsNode == nullptr)
Arun Patole7e7e68d2015-05-22 12:02:25 +0530663 {
Olli Etuaho15c2ac32015-11-09 15:51:43 +0200664 error(line, "constructor does not have any arguments", "constructor");
Olli Etuaho8a176262016-08-16 14:23:01 +0300665 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000666 }
Olli Etuaho15c2ac32015-11-09 15:51:43 +0200667
668 TIntermAggregate *argumentsAgg = argumentsNode->getAsAggregate();
669 for (TIntermNode *&argNode : *argumentsAgg->getSequence())
Arun Patole7e7e68d2015-05-22 12:02:25 +0530670 {
Olli Etuaho15c2ac32015-11-09 15:51:43 +0200671 TIntermTyped *argTyped = argNode->getAsTyped();
672 ASSERT(argTyped != nullptr);
673 if (op != EOpConstructStruct && IsSampler(argTyped->getBasicType()))
674 {
675 error(line, "cannot convert a sampler", "constructor");
Olli Etuaho8a176262016-08-16 14:23:01 +0300676 return false;
Olli Etuaho15c2ac32015-11-09 15:51:43 +0200677 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300678 if (op != EOpConstructStruct && IsImage(argTyped->getBasicType()))
679 {
680 error(line, "cannot convert an image", "constructor");
681 return false;
682 }
Olli Etuaho15c2ac32015-11-09 15:51:43 +0200683 if (argTyped->getBasicType() == EbtVoid)
684 {
685 error(line, "cannot convert a void", "constructor");
Olli Etuaho8a176262016-08-16 14:23:01 +0300686 return false;
Olli Etuaho15c2ac32015-11-09 15:51:43 +0200687 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000688 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000689
Olli Etuaho856c4972016-08-08 11:38:39 +0300690 if (type.isArray())
691 {
692 // GLSL ES 3.00 section 5.4.4: Each argument must be the same type as the element type of
693 // the array.
694 for (TIntermNode *&argNode : *argumentsAgg->getSequence())
695 {
696 const TType &argType = argNode->getAsTyped()->getType();
697 // It has already been checked that the argument is not an array.
698 ASSERT(!argType.isArray());
699 if (!argType.sameElementType(type))
700 {
701 error(line, "Array constructor argument has an incorrect type", "Error");
Olli Etuaho8a176262016-08-16 14:23:01 +0300702 return false;
Olli Etuaho856c4972016-08-08 11:38:39 +0300703 }
704 }
705 }
706 else if (op == EOpConstructStruct)
707 {
708 const TFieldList &fields = type.getStruct()->fields();
709 TIntermSequence *args = argumentsAgg->getSequence();
710
711 for (size_t i = 0; i < fields.size(); i++)
712 {
713 if (i >= args->size() || (*args)[i]->getAsTyped()->getType() != *fields[i]->type())
714 {
715 error(line, "Structure constructor arguments do not match structure fields",
716 "Error");
Olli Etuaho8a176262016-08-16 14:23:01 +0300717 return false;
Olli Etuaho856c4972016-08-08 11:38:39 +0300718 }
719 }
720 }
721
Olli Etuaho8a176262016-08-16 14:23:01 +0300722 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000723}
724
Jamie Madillb98c3a82015-07-23 14:26:04 -0400725// This function checks to see if a void variable has been declared and raise an error message for
726// such a case
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000727//
728// returns true in case of an error
729//
Olli Etuaho856c4972016-08-08 11:38:39 +0300730bool TParseContext::checkIsNonVoid(const TSourceLoc &line,
Jamie Madillb98c3a82015-07-23 14:26:04 -0400731 const TString &identifier,
732 const TBasicType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000733{
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +0300734 if (type == EbtVoid)
735 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000736 error(line, "illegal use of type 'void'", identifier.c_str());
Olli Etuaho8a176262016-08-16 14:23:01 +0300737 return false;
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +0300738 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000739
Olli Etuaho8a176262016-08-16 14:23:01 +0300740 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000741}
742
Jamie Madillb98c3a82015-07-23 14:26:04 -0400743// This function checks to see if the node (for the expression) contains a scalar boolean expression
Olli Etuaho383b7912016-08-05 11:22:59 +0300744// or not.
Olli Etuaho856c4972016-08-08 11:38:39 +0300745void TParseContext::checkIsScalarBool(const TSourceLoc &line, const TIntermTyped *type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000746{
Arun Patole7e7e68d2015-05-22 12:02:25 +0530747 if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector())
748 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000749 error(line, "boolean expression expected", "");
Arun Patole7e7e68d2015-05-22 12:02:25 +0530750 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000751}
752
Jamie Madillb98c3a82015-07-23 14:26:04 -0400753// This function checks to see if the node (for the expression) contains a scalar boolean expression
Olli Etuaho383b7912016-08-05 11:22:59 +0300754// or not.
Olli Etuaho856c4972016-08-08 11:38:39 +0300755void TParseContext::checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000756{
Martin Radev4a9cd802016-09-01 16:51:51 +0300757 if (pType.getBasicType() != EbtBool || pType.isAggregate())
Arun Patole7e7e68d2015-05-22 12:02:25 +0530758 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000759 error(line, "boolean expression expected", "");
Arun Patole7e7e68d2015-05-22 12:02:25 +0530760 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000761}
762
Olli Etuaho856c4972016-08-08 11:38:39 +0300763bool TParseContext::checkIsNotSampler(const TSourceLoc &line,
Martin Radev4a9cd802016-09-01 16:51:51 +0300764 const TTypeSpecifierNonArray &pType,
Jamie Madillb98c3a82015-07-23 14:26:04 -0400765 const char *reason)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000766{
Arun Patole7e7e68d2015-05-22 12:02:25 +0530767 if (pType.type == EbtStruct)
768 {
Martin Radev2cc85b32016-08-05 16:22:53 +0300769 if (ContainsSampler(*pType.userDef))
Arun Patole7e7e68d2015-05-22 12:02:25 +0530770 {
alokp@chromium.org58e54292010-08-24 21:40:03 +0000771 error(line, reason, getBasicString(pType.type), "(structure contains a sampler)");
Olli Etuaho8a176262016-08-16 14:23:01 +0300772 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000773 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530774
Olli Etuaho8a176262016-08-16 14:23:01 +0300775 return true;
Arun Patole7e7e68d2015-05-22 12:02:25 +0530776 }
777 else if (IsSampler(pType.type))
778 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000779 error(line, reason, getBasicString(pType.type));
Olli Etuaho8a176262016-08-16 14:23:01 +0300780 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000781 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000782
Olli Etuaho8a176262016-08-16 14:23:01 +0300783 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000784}
785
Martin Radev2cc85b32016-08-05 16:22:53 +0300786bool TParseContext::checkIsNotImage(const TSourceLoc &line,
787 const TTypeSpecifierNonArray &pType,
788 const char *reason)
789{
790 if (pType.type == EbtStruct)
791 {
792 if (ContainsImage(*pType.userDef))
793 {
794 error(line, reason, getBasicString(pType.type), "(structure contains an image)");
795
796 return false;
797 }
798
799 return true;
800 }
801 else if (IsImage(pType.type))
802 {
803 error(line, reason, getBasicString(pType.type));
804
805 return false;
806 }
807
808 return true;
809}
810
Olli Etuaho856c4972016-08-08 11:38:39 +0300811void TParseContext::checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line,
812 const TPublicType &pType)
Jamie Madill0bd18df2013-06-20 11:55:52 -0400813{
814 if (pType.layoutQualifier.location != -1)
815 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400816 error(line, "location must only be specified for a single input or output variable",
817 "location");
Jamie Madill0bd18df2013-06-20 11:55:52 -0400818 }
Jamie Madill0bd18df2013-06-20 11:55:52 -0400819}
820
Olli Etuaho856c4972016-08-08 11:38:39 +0300821void TParseContext::checkLocationIsNotSpecified(const TSourceLoc &location,
822 const TLayoutQualifier &layoutQualifier)
823{
824 if (layoutQualifier.location != -1)
825 {
826 error(location, "invalid layout qualifier:", "location",
827 "only valid on program inputs and outputs");
828 }
829}
830
Martin Radev2cc85b32016-08-05 16:22:53 +0300831void TParseContext::checkOutParameterIsNotOpaqueType(const TSourceLoc &line,
832 TQualifier qualifier,
833 const TType &type)
834{
835 checkOutParameterIsNotSampler(line, qualifier, type);
836 checkOutParameterIsNotImage(line, qualifier, type);
837}
838
Olli Etuaho856c4972016-08-08 11:38:39 +0300839void TParseContext::checkOutParameterIsNotSampler(const TSourceLoc &line,
840 TQualifier qualifier,
841 const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000842{
Martin Radev2cc85b32016-08-05 16:22:53 +0300843 ASSERT(qualifier == EvqOut || qualifier == EvqInOut);
844 if (IsSampler(type.getBasicType()))
Arun Patole7e7e68d2015-05-22 12:02:25 +0530845 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000846 error(line, "samplers cannot be output parameters", type.getBasicString());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000847 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000848}
849
Martin Radev2cc85b32016-08-05 16:22:53 +0300850void TParseContext::checkOutParameterIsNotImage(const TSourceLoc &line,
851 TQualifier qualifier,
852 const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000853{
Martin Radev2cc85b32016-08-05 16:22:53 +0300854 ASSERT(qualifier == EvqOut || qualifier == EvqInOut);
855 if (IsImage(type.getBasicType()))
Arun Patole7e7e68d2015-05-22 12:02:25 +0530856 {
Martin Radev2cc85b32016-08-05 16:22:53 +0300857 error(line, "images cannot be output parameters", type.getBasicString());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000858 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000859}
860
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000861// Do size checking for an array type's size.
Olli Etuaho856c4972016-08-08 11:38:39 +0300862unsigned int TParseContext::checkIsValidArraySize(const TSourceLoc &line, TIntermTyped *expr)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000863{
Arun Patole7e7e68d2015-05-22 12:02:25 +0530864 TIntermConstantUnion *constant = expr->getAsConstantUnion();
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000865
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200866 // TODO(oetuaho@nvidia.com): Get rid of the constant == nullptr check here once all constant
867 // expressions can be folded. Right now we don't allow constant expressions that ANGLE can't
868 // fold as array size.
869 if (expr->getQualifier() != EvqConst || constant == nullptr || !constant->isScalarInt())
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000870 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000871 error(line, "array size must be a constant integer expression", "");
Olli Etuaho856c4972016-08-08 11:38:39 +0300872 return 1u;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000873 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000874
Olli Etuaho856c4972016-08-08 11:38:39 +0300875 unsigned int size = 0u;
Nicolas Capens906744a2014-06-06 15:18:07 -0400876
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000877 if (constant->getBasicType() == EbtUInt)
878 {
Olli Etuaho856c4972016-08-08 11:38:39 +0300879 size = constant->getUConst(0);
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000880 }
881 else
882 {
Olli Etuaho856c4972016-08-08 11:38:39 +0300883 int signedSize = constant->getIConst(0);
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000884
Olli Etuaho856c4972016-08-08 11:38:39 +0300885 if (signedSize < 0)
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000886 {
Nicolas Capens906744a2014-06-06 15:18:07 -0400887 error(line, "array size must be non-negative", "");
Olli Etuaho856c4972016-08-08 11:38:39 +0300888 return 1u;
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000889 }
Nicolas Capens906744a2014-06-06 15:18:07 -0400890
Olli Etuaho856c4972016-08-08 11:38:39 +0300891 size = static_cast<unsigned int>(signedSize);
Nicolas Capens906744a2014-06-06 15:18:07 -0400892 }
893
Olli Etuaho856c4972016-08-08 11:38:39 +0300894 if (size == 0u)
Nicolas Capens906744a2014-06-06 15:18:07 -0400895 {
896 error(line, "array size must be greater than zero", "");
Olli Etuaho856c4972016-08-08 11:38:39 +0300897 return 1u;
Nicolas Capens906744a2014-06-06 15:18:07 -0400898 }
899
900 // The size of arrays is restricted here to prevent issues further down the
901 // compiler/translator/driver stack. Shader Model 5 generation hardware is limited to
902 // 4096 registers so this should be reasonable even for aggressively optimizable code.
903 const unsigned int sizeLimit = 65536;
904
Olli Etuaho856c4972016-08-08 11:38:39 +0300905 if (size > sizeLimit)
Nicolas Capens906744a2014-06-06 15:18:07 -0400906 {
907 error(line, "array size too large", "");
Olli Etuaho856c4972016-08-08 11:38:39 +0300908 return 1u;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000909 }
Olli Etuaho856c4972016-08-08 11:38:39 +0300910
911 return size;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000912}
913
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000914// See if this qualifier can be an array.
Olli Etuaho8a176262016-08-16 14:23:01 +0300915bool TParseContext::checkIsValidQualifierForArray(const TSourceLoc &line,
916 const TPublicType &elementQualifier)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000917{
Olli Etuaho8a176262016-08-16 14:23:01 +0300918 if ((elementQualifier.qualifier == EvqAttribute) ||
919 (elementQualifier.qualifier == EvqVertexIn) ||
920 (elementQualifier.qualifier == EvqConst && mShaderVersion < 300))
Olli Etuaho3739d232015-04-08 12:23:44 +0300921 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400922 error(line, "cannot declare arrays of this qualifier",
Olli Etuaho8a176262016-08-16 14:23:01 +0300923 TType(elementQualifier).getQualifierString());
924 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000925 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000926
Olli Etuaho8a176262016-08-16 14:23:01 +0300927 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000928}
929
Olli Etuaho8a176262016-08-16 14:23:01 +0300930// See if this element type can be formed into an array.
931bool TParseContext::checkIsValidTypeForArray(const TSourceLoc &line, const TPublicType &elementType)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000932{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000933 //
934 // Can the type be an array?
935 //
Olli Etuaho8a176262016-08-16 14:23:01 +0300936 if (elementType.array)
Jamie Madill06145232015-05-13 13:10:01 -0400937 {
Olli Etuaho8a176262016-08-16 14:23:01 +0300938 error(line, "cannot declare arrays of arrays",
939 TType(elementType).getCompleteString().c_str());
940 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000941 }
Olli Etuahocc36b982015-07-10 14:14:18 +0300942 // In ESSL1.00 shaders, structs cannot be varying (section 4.3.5). This is checked elsewhere.
943 // In ESSL3.00 shaders, struct inputs/outputs are allowed but not arrays of structs (section
944 // 4.3.4).
Martin Radev4a9cd802016-09-01 16:51:51 +0300945 if (mShaderVersion >= 300 && elementType.getBasicType() == EbtStruct &&
Olli Etuaho8a176262016-08-16 14:23:01 +0300946 sh::IsVarying(elementType.qualifier))
Olli Etuahocc36b982015-07-10 14:14:18 +0300947 {
948 error(line, "cannot declare arrays of structs of this qualifier",
Olli Etuaho8a176262016-08-16 14:23:01 +0300949 TType(elementType).getCompleteString().c_str());
950 return false;
Olli Etuahocc36b982015-07-10 14:14:18 +0300951 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000952
Olli Etuaho8a176262016-08-16 14:23:01 +0300953 return true;
954}
955
956// Check if this qualified element type can be formed into an array.
957bool TParseContext::checkIsValidTypeAndQualifierForArray(const TSourceLoc &indexLocation,
958 const TPublicType &elementType)
959{
960 if (checkIsValidTypeForArray(indexLocation, elementType))
961 {
962 return checkIsValidQualifierForArray(indexLocation, elementType);
963 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000964 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000965}
966
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000967// Enforce non-initializer type/qualifier rules.
Olli Etuaho856c4972016-08-08 11:38:39 +0300968void TParseContext::checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line,
969 const TString &identifier,
970 TPublicType *type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000971{
Olli Etuaho3739d232015-04-08 12:23:44 +0300972 ASSERT(type != nullptr);
973 if (type->qualifier == EvqConst)
daniel@transgaming.com8abd0b72012-09-27 17:46:07 +0000974 {
975 // Make the qualifier make sense.
Olli Etuaho3739d232015-04-08 12:23:44 +0300976 type->qualifier = EvqTemporary;
977
978 // Generate informative error messages for ESSL1.
979 // In ESSL3 arrays and structures containing arrays can be constant.
Jamie Madill6e06b1f2015-05-14 10:01:17 -0400980 if (mShaderVersion < 300 && type->isStructureContainingArrays())
daniel@transgaming.com8abd0b72012-09-27 17:46:07 +0000981 {
Arun Patole7e7e68d2015-05-22 12:02:25 +0530982 error(line,
Jamie Madillb98c3a82015-07-23 14:26:04 -0400983 "structures containing arrays may not be declared constant since they cannot be "
984 "initialized",
Arun Patole7e7e68d2015-05-22 12:02:25 +0530985 identifier.c_str());
daniel@transgaming.com8abd0b72012-09-27 17:46:07 +0000986 }
987 else
988 {
989 error(line, "variables with qualifier 'const' must be initialized", identifier.c_str());
990 }
Olli Etuaho383b7912016-08-05 11:22:59 +0300991 return;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000992 }
Olli Etuaho376f1b52015-04-13 13:23:41 +0300993 if (type->isUnsizedArray())
994 {
995 error(line, "implicitly sized arrays need to be initialized", identifier.c_str());
Olli Etuaho376f1b52015-04-13 13:23:41 +0300996 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000997}
998
Olli Etuaho2935c582015-04-08 14:32:06 +0300999// Do some simple checks that are shared between all variable declarations,
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001000// and update the symbol table.
1001//
Olli Etuaho2935c582015-04-08 14:32:06 +03001002// Returns true if declaring the variable succeeded.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001003//
Jamie Madillb98c3a82015-07-23 14:26:04 -04001004bool TParseContext::declareVariable(const TSourceLoc &line,
1005 const TString &identifier,
1006 const TType &type,
Olli Etuaho2935c582015-04-08 14:32:06 +03001007 TVariable **variable)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001008{
Olli Etuaho2935c582015-04-08 14:32:06 +03001009 ASSERT((*variable) == nullptr);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001010
Olli Etuaho856c4972016-08-08 11:38:39 +03001011 bool needsReservedCheck = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001012
Olli Etuaho2935c582015-04-08 14:32:06 +03001013 // gl_LastFragData may be redeclared with a new precision qualifier
1014 if (type.isArray() && identifier.compare(0, 15, "gl_LastFragData") == 0)
1015 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001016 const TVariable *maxDrawBuffers = static_cast<const TVariable *>(
1017 symbolTable.findBuiltIn("gl_MaxDrawBuffers", mShaderVersion));
Olli Etuaho856c4972016-08-08 11:38:39 +03001018 if (static_cast<int>(type.getArraySize()) == maxDrawBuffers->getConstPointer()->getIConst())
Olli Etuaho2935c582015-04-08 14:32:06 +03001019 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001020 if (TSymbol *builtInSymbol = symbolTable.findBuiltIn(identifier, mShaderVersion))
Olli Etuaho2935c582015-04-08 14:32:06 +03001021 {
Olli Etuaho8a176262016-08-16 14:23:01 +03001022 needsReservedCheck = !checkCanUseExtension(line, builtInSymbol->getExtension());
Olli Etuaho2935c582015-04-08 14:32:06 +03001023 }
1024 }
1025 else
1026 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001027 error(line, "redeclaration of gl_LastFragData with size != gl_MaxDrawBuffers",
1028 identifier.c_str());
Olli Etuaho2935c582015-04-08 14:32:06 +03001029 return false;
1030 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001031 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001032
Olli Etuaho8a176262016-08-16 14:23:01 +03001033 if (needsReservedCheck && !checkIsNotReserved(line, identifier))
Olli Etuaho2935c582015-04-08 14:32:06 +03001034 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001035
Olli Etuaho2935c582015-04-08 14:32:06 +03001036 (*variable) = new TVariable(&identifier, type);
1037 if (!symbolTable.declare(*variable))
1038 {
1039 error(line, "redefinition", identifier.c_str());
Jamie Madill1a4b1b32015-07-23 18:27:13 -04001040 *variable = nullptr;
Olli Etuaho2935c582015-04-08 14:32:06 +03001041 return false;
1042 }
1043
Olli Etuaho8a176262016-08-16 14:23:01 +03001044 if (!checkIsNonVoid(line, identifier, type.getBasicType()))
Olli Etuaho2935c582015-04-08 14:32:06 +03001045 return false;
1046
1047 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001048}
1049
Martin Radev70866b82016-07-22 15:27:42 +03001050void TParseContext::checkIsParameterQualifierValid(
1051 const TSourceLoc &line,
1052 const TTypeQualifierBuilder &typeQualifierBuilder,
1053 TType *type)
Arun Patole7e7e68d2015-05-22 12:02:25 +05301054{
Olli Etuaho613b9592016-09-05 12:05:53 +03001055 TTypeQualifier typeQualifier = typeQualifierBuilder.getParameterTypeQualifier(&mDiagnostics);
Martin Radev70866b82016-07-22 15:27:42 +03001056
1057 if (typeQualifier.qualifier == EvqOut || typeQualifier.qualifier == EvqInOut)
Arun Patole7e7e68d2015-05-22 12:02:25 +05301058 {
Martin Radev2cc85b32016-08-05 16:22:53 +03001059 checkOutParameterIsNotOpaqueType(line, typeQualifier.qualifier, *type);
1060 }
1061
1062 if (!IsImage(type->getBasicType()))
1063 {
1064 checkIsMemoryQualifierNotSpecified(typeQualifier.memoryQualifier, line);
1065 }
1066 else
1067 {
1068 type->setMemoryQualifier(typeQualifier.memoryQualifier);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001069 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001070
Martin Radev70866b82016-07-22 15:27:42 +03001071 type->setQualifier(typeQualifier.qualifier);
1072
1073 if (typeQualifier.precision != EbpUndefined)
1074 {
1075 type->setPrecision(typeQualifier.precision);
1076 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001077}
1078
Olli Etuaho856c4972016-08-08 11:38:39 +03001079bool TParseContext::checkCanUseExtension(const TSourceLoc &line, const TString &extension)
alokp@chromium.org8815d7f2010-09-09 17:30:03 +00001080{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001081 const TExtensionBehavior &extBehavior = extensionBehavior();
alokp@chromium.org8b851c62012-06-15 16:25:11 +00001082 TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str());
Arun Patole7e7e68d2015-05-22 12:02:25 +05301083 if (iter == extBehavior.end())
1084 {
alokp@chromium.org8815d7f2010-09-09 17:30:03 +00001085 error(line, "extension", extension.c_str(), "is not supported");
Olli Etuaho8a176262016-08-16 14:23:01 +03001086 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001087 }
zmo@google.comf5450912011-09-09 01:37:19 +00001088 // In GLSL ES, an extension's default behavior is "disable".
Arun Patole7e7e68d2015-05-22 12:02:25 +05301089 if (iter->second == EBhDisable || iter->second == EBhUndefined)
1090 {
alokp@chromium.org8815d7f2010-09-09 17:30:03 +00001091 error(line, "extension", extension.c_str(), "is disabled");
Olli Etuaho8a176262016-08-16 14:23:01 +03001092 return false;
alokp@chromium.org8815d7f2010-09-09 17:30:03 +00001093 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05301094 if (iter->second == EBhWarn)
1095 {
alokp@chromium.org8b851c62012-06-15 16:25:11 +00001096 warning(line, "extension", extension.c_str(), "is being used");
Olli Etuaho8a176262016-08-16 14:23:01 +03001097 return true;
alokp@chromium.org8815d7f2010-09-09 17:30:03 +00001098 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001099
Olli Etuaho8a176262016-08-16 14:23:01 +03001100 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001101}
1102
Jamie Madillb98c3a82015-07-23 14:26:04 -04001103// These checks are common for all declarations starting a declarator list, and declarators that
1104// follow an empty declaration.
Olli Etuaho383b7912016-08-05 11:22:59 +03001105void TParseContext::singleDeclarationErrorCheck(const TPublicType &publicType,
Jamie Madillb98c3a82015-07-23 14:26:04 -04001106 const TSourceLoc &identifierLocation)
Jamie Madilla5efff92013-06-06 11:56:47 -04001107{
Olli Etuahofa33d582015-04-09 14:33:12 +03001108 switch (publicType.qualifier)
1109 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001110 case EvqVaryingIn:
1111 case EvqVaryingOut:
1112 case EvqAttribute:
1113 case EvqVertexIn:
1114 case EvqFragmentOut:
Martin Radev802abe02016-08-04 17:48:32 +03001115 case EvqComputeIn:
Martin Radev4a9cd802016-09-01 16:51:51 +03001116 if (publicType.getBasicType() == EbtStruct)
Jamie Madillb98c3a82015-07-23 14:26:04 -04001117 {
1118 error(identifierLocation, "cannot be used with a structure",
1119 getQualifierString(publicType.qualifier));
Olli Etuaho383b7912016-08-05 11:22:59 +03001120 return;
Jamie Madillb98c3a82015-07-23 14:26:04 -04001121 }
Olli Etuahofa33d582015-04-09 14:33:12 +03001122
Jamie Madillb98c3a82015-07-23 14:26:04 -04001123 default:
1124 break;
Olli Etuahofa33d582015-04-09 14:33:12 +03001125 }
1126
Jamie Madillb98c3a82015-07-23 14:26:04 -04001127 if (publicType.qualifier != EvqUniform &&
Martin Radev4a9cd802016-09-01 16:51:51 +03001128 !checkIsNotSampler(identifierLocation, publicType.typeSpecifierNonArray,
1129 "samplers must be uniform"))
Olli Etuahofa33d582015-04-09 14:33:12 +03001130 {
Olli Etuaho383b7912016-08-05 11:22:59 +03001131 return;
Olli Etuahofa33d582015-04-09 14:33:12 +03001132 }
Martin Radev2cc85b32016-08-05 16:22:53 +03001133 if (publicType.qualifier != EvqUniform &&
1134 !checkIsNotImage(identifierLocation, publicType.typeSpecifierNonArray,
1135 "images must be uniform"))
1136 {
1137 return;
1138 }
Jamie Madilla5efff92013-06-06 11:56:47 -04001139
1140 // check for layout qualifier issues
1141 const TLayoutQualifier layoutQualifier = publicType.layoutQualifier;
1142
1143 if (layoutQualifier.matrixPacking != EmpUnspecified)
1144 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001145 error(identifierLocation, "layout qualifier",
1146 getMatrixPackingString(layoutQualifier.matrixPacking),
Olli Etuahofa33d582015-04-09 14:33:12 +03001147 "only valid for interface blocks");
Olli Etuaho383b7912016-08-05 11:22:59 +03001148 return;
Jamie Madilla5efff92013-06-06 11:56:47 -04001149 }
1150
1151 if (layoutQualifier.blockStorage != EbsUnspecified)
1152 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001153 error(identifierLocation, "layout qualifier",
1154 getBlockStorageString(layoutQualifier.blockStorage),
Olli Etuahofa33d582015-04-09 14:33:12 +03001155 "only valid for interface blocks");
Olli Etuaho383b7912016-08-05 11:22:59 +03001156 return;
Jamie Madilla5efff92013-06-06 11:56:47 -04001157 }
1158
Olli Etuaho383b7912016-08-05 11:22:59 +03001159 if (publicType.qualifier != EvqVertexIn && publicType.qualifier != EvqFragmentOut)
Jamie Madilla5efff92013-06-06 11:56:47 -04001160 {
Olli Etuaho856c4972016-08-08 11:38:39 +03001161 checkLocationIsNotSpecified(identifierLocation, publicType.layoutQualifier);
Jamie Madilla5efff92013-06-06 11:56:47 -04001162 }
Martin Radev2cc85b32016-08-05 16:22:53 +03001163
1164 if (IsImage(publicType.getBasicType()))
1165 {
1166
1167 switch (layoutQualifier.imageInternalFormat)
1168 {
1169 case EiifRGBA32F:
1170 case EiifRGBA16F:
1171 case EiifR32F:
1172 case EiifRGBA8:
1173 case EiifRGBA8_SNORM:
1174 if (!IsFloatImage(publicType.getBasicType()))
1175 {
1176 error(identifierLocation,
1177 "internal image format requires a floating image type",
1178 getBasicString(publicType.getBasicType()));
1179 return;
1180 }
1181 break;
1182 case EiifRGBA32I:
1183 case EiifRGBA16I:
1184 case EiifRGBA8I:
1185 case EiifR32I:
1186 if (!IsIntegerImage(publicType.getBasicType()))
1187 {
1188 error(identifierLocation,
1189 "internal image format requires an integer image type",
1190 getBasicString(publicType.getBasicType()));
1191 return;
1192 }
1193 break;
1194 case EiifRGBA32UI:
1195 case EiifRGBA16UI:
1196 case EiifRGBA8UI:
1197 case EiifR32UI:
1198 if (!IsUnsignedImage(publicType.getBasicType()))
1199 {
1200 error(identifierLocation,
1201 "internal image format requires an unsigned image type",
1202 getBasicString(publicType.getBasicType()));
1203 return;
1204 }
1205 break;
1206 case EiifUnspecified:
1207 error(identifierLocation, "layout qualifier", "No image internal format specified");
1208 return;
1209 default:
1210 error(identifierLocation, "layout qualifier", "unrecognized token");
1211 return;
1212 }
1213
1214 // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
1215 switch (layoutQualifier.imageInternalFormat)
1216 {
1217 case EiifR32F:
1218 case EiifR32I:
1219 case EiifR32UI:
1220 break;
1221 default:
1222 if (!publicType.memoryQualifier.readonly && !publicType.memoryQualifier.writeonly)
1223 {
1224 error(identifierLocation, "layout qualifier",
1225 "Except for images with the r32f, r32i and r32ui format qualifiers, "
1226 "image variables must be qualified readonly and/or writeonly");
1227 return;
1228 }
1229 break;
1230 }
1231 }
1232 else
1233 {
1234
1235 if (!checkInternalFormatIsNotSpecified(identifierLocation,
1236 layoutQualifier.imageInternalFormat))
1237 {
1238 return;
1239 }
1240
1241 if (!checkIsMemoryQualifierNotSpecified(publicType.memoryQualifier, identifierLocation))
1242 {
1243 return;
1244 }
1245 }
Jamie Madilla5efff92013-06-06 11:56:47 -04001246}
1247
Olli Etuaho856c4972016-08-08 11:38:39 +03001248void TParseContext::checkLayoutQualifierSupported(const TSourceLoc &location,
1249 const TString &layoutQualifierName,
1250 int versionRequired)
Martin Radev802abe02016-08-04 17:48:32 +03001251{
1252
1253 if (mShaderVersion < versionRequired)
1254 {
1255 error(location, "invalid layout qualifier:", layoutQualifierName.c_str(), "not supported");
Martin Radev802abe02016-08-04 17:48:32 +03001256 }
1257}
1258
Olli Etuaho856c4972016-08-08 11:38:39 +03001259bool TParseContext::checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location,
1260 const TLayoutQualifier &layoutQualifier)
Martin Radev802abe02016-08-04 17:48:32 +03001261{
Martin Radev4c4c8e72016-08-04 12:25:34 +03001262 const sh::WorkGroupSize &localSize = layoutQualifier.localSize;
Martin Radev802abe02016-08-04 17:48:32 +03001263 for (size_t i = 0u; i < localSize.size(); ++i)
1264 {
1265 if (localSize[i] != -1)
1266 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03001267 error(location, "invalid layout qualifier:", getWorkGroupSizeString(i),
Martin Radev802abe02016-08-04 17:48:32 +03001268 "only valid when used with 'in' in a compute shader global layout declaration");
Olli Etuaho8a176262016-08-16 14:23:01 +03001269 return false;
Martin Radev802abe02016-08-04 17:48:32 +03001270 }
1271 }
1272
Olli Etuaho8a176262016-08-16 14:23:01 +03001273 return true;
Martin Radev802abe02016-08-04 17:48:32 +03001274}
1275
Martin Radev2cc85b32016-08-05 16:22:53 +03001276bool TParseContext::checkInternalFormatIsNotSpecified(const TSourceLoc &location,
1277 TLayoutImageInternalFormat internalFormat)
1278{
1279 if (internalFormat != EiifUnspecified)
1280 {
1281 error(location, "invalid layout qualifier:", getImageInternalFormatString(internalFormat),
1282 "only valid when used with images");
1283 return false;
1284 }
1285 return true;
1286}
1287
Olli Etuaho383b7912016-08-05 11:22:59 +03001288void TParseContext::functionCallLValueErrorCheck(const TFunction *fnCandidate,
Olli Etuaho856c4972016-08-08 11:38:39 +03001289 TIntermAggregate *fnCall)
Olli Etuahob6e07a62015-02-16 12:22:10 +02001290{
1291 for (size_t i = 0; i < fnCandidate->getParamCount(); ++i)
1292 {
1293 TQualifier qual = fnCandidate->getParam(i).type->getQualifier();
1294 if (qual == EvqOut || qual == EvqInOut)
1295 {
Olli Etuaho856c4972016-08-08 11:38:39 +03001296 TIntermTyped *argument = (*(fnCall->getSequence()))[i]->getAsTyped();
Olli Etuaho8a176262016-08-16 14:23:01 +03001297 if (!checkCanBeLValue(argument->getLine(), "assign", argument))
Olli Etuahob6e07a62015-02-16 12:22:10 +02001298 {
Olli Etuaho856c4972016-08-08 11:38:39 +03001299 error(argument->getLine(),
Jamie Madillb98c3a82015-07-23 14:26:04 -04001300 "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error");
Olli Etuaho383b7912016-08-05 11:22:59 +03001301 return;
Olli Etuahob6e07a62015-02-16 12:22:10 +02001302 }
1303 }
1304 }
Olli Etuahob6e07a62015-02-16 12:22:10 +02001305}
1306
Martin Radev70866b82016-07-22 15:27:42 +03001307void TParseContext::checkInvariantVariableQualifier(bool invariant,
1308 const TQualifier qualifier,
1309 const TSourceLoc &invariantLocation)
Olli Etuaho37ad4742015-04-27 13:18:50 +03001310{
Martin Radev70866b82016-07-22 15:27:42 +03001311 if (!invariant)
1312 return;
1313
1314 if (mShaderVersion < 300)
Olli Etuaho37ad4742015-04-27 13:18:50 +03001315 {
Martin Radev70866b82016-07-22 15:27:42 +03001316 // input variables in the fragment shader can be also qualified as invariant
1317 if (!sh::CanBeInvariantESSL1(qualifier))
1318 {
1319 error(invariantLocation, "Cannot be qualified as invariant.", "invariant");
1320 }
1321 }
1322 else
1323 {
1324 if (!sh::CanBeInvariantESSL3OrGreater(qualifier))
1325 {
1326 error(invariantLocation, "Cannot be qualified as invariant.", "invariant");
1327 }
Olli Etuaho37ad4742015-04-27 13:18:50 +03001328 }
1329}
1330
Arun Patole7e7e68d2015-05-22 12:02:25 +05301331bool TParseContext::supportsExtension(const char *extension)
zmo@google.com09c323a2011-08-12 18:22:25 +00001332{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001333 const TExtensionBehavior &extbehavior = extensionBehavior();
alokp@chromium.org73bc2982012-06-19 18:48:05 +00001334 TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
1335 return (iter != extbehavior.end());
alokp@chromium.org8b851c62012-06-15 16:25:11 +00001336}
1337
Arun Patole7e7e68d2015-05-22 12:02:25 +05301338bool TParseContext::isExtensionEnabled(const char *extension) const
Jamie Madill5d287f52013-07-12 15:38:19 -04001339{
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +03001340 return ::IsExtensionEnabled(extensionBehavior(), extension);
Jamie Madill5d287f52013-07-12 15:38:19 -04001341}
1342
Jamie Madillb98c3a82015-07-23 14:26:04 -04001343void TParseContext::handleExtensionDirective(const TSourceLoc &loc,
1344 const char *extName,
1345 const char *behavior)
Jamie Madill075edd82013-07-08 13:30:19 -04001346{
1347 pp::SourceLocation srcLoc;
1348 srcLoc.file = loc.first_file;
1349 srcLoc.line = loc.first_line;
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001350 mDirectiveHandler.handleExtension(srcLoc, extName, behavior);
Jamie Madill075edd82013-07-08 13:30:19 -04001351}
1352
Jamie Madillb98c3a82015-07-23 14:26:04 -04001353void TParseContext::handlePragmaDirective(const TSourceLoc &loc,
1354 const char *name,
1355 const char *value,
1356 bool stdgl)
Jamie Madill075edd82013-07-08 13:30:19 -04001357{
1358 pp::SourceLocation srcLoc;
1359 srcLoc.file = loc.first_file;
1360 srcLoc.line = loc.first_line;
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001361 mDirectiveHandler.handlePragma(srcLoc, name, value, stdgl);
Jamie Madill075edd82013-07-08 13:30:19 -04001362}
1363
Martin Radev4c4c8e72016-08-04 12:25:34 +03001364sh::WorkGroupSize TParseContext::getComputeShaderLocalSize() const
Martin Radev802abe02016-08-04 17:48:32 +03001365{
Martin Radev4c4c8e72016-08-04 12:25:34 +03001366 sh::WorkGroupSize result;
Martin Radev802abe02016-08-04 17:48:32 +03001367 for (size_t i = 0u; i < result.size(); ++i)
1368 {
1369 if (mComputeShaderLocalSizeDeclared && mComputeShaderLocalSize[i] == -1)
1370 {
1371 result[i] = 1;
1372 }
1373 else
1374 {
1375 result[i] = mComputeShaderLocalSize[i];
1376 }
1377 }
1378 return result;
1379}
1380
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001381/////////////////////////////////////////////////////////////////////////////////
1382//
1383// Non-Errors.
1384//
1385/////////////////////////////////////////////////////////////////////////////////
1386
Jamie Madill5c097022014-08-20 16:38:32 -04001387const TVariable *TParseContext::getNamedVariable(const TSourceLoc &location,
1388 const TString *name,
1389 const TSymbol *symbol)
1390{
1391 const TVariable *variable = NULL;
1392
1393 if (!symbol)
1394 {
1395 error(location, "undeclared identifier", name->c_str());
Jamie Madill5c097022014-08-20 16:38:32 -04001396 }
1397 else if (!symbol->isVariable())
1398 {
1399 error(location, "variable expected", name->c_str());
Jamie Madill5c097022014-08-20 16:38:32 -04001400 }
1401 else
1402 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001403 variable = static_cast<const TVariable *>(symbol);
Jamie Madill5c097022014-08-20 16:38:32 -04001404
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001405 if (symbolTable.findBuiltIn(variable->getName(), mShaderVersion) &&
Olli Etuaho383b7912016-08-05 11:22:59 +03001406 !variable->getExtension().empty())
Jamie Madill5c097022014-08-20 16:38:32 -04001407 {
Olli Etuaho856c4972016-08-08 11:38:39 +03001408 checkCanUseExtension(location, variable->getExtension());
Jamie Madill5c097022014-08-20 16:38:32 -04001409 }
Jamie Madill14e95b32015-05-07 10:10:41 -04001410
1411 // Reject shaders using both gl_FragData and gl_FragColor
1412 TQualifier qualifier = variable->getType().getQualifier();
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +03001413 if (qualifier == EvqFragData || qualifier == EvqSecondaryFragDataEXT)
Jamie Madill14e95b32015-05-07 10:10:41 -04001414 {
1415 mUsesFragData = true;
1416 }
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +03001417 else if (qualifier == EvqFragColor || qualifier == EvqSecondaryFragColorEXT)
Jamie Madill14e95b32015-05-07 10:10:41 -04001418 {
1419 mUsesFragColor = true;
1420 }
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +03001421 if (qualifier == EvqSecondaryFragDataEXT || qualifier == EvqSecondaryFragColorEXT)
1422 {
1423 mUsesSecondaryOutputs = true;
1424 }
Jamie Madill14e95b32015-05-07 10:10:41 -04001425
1426 // This validation is not quite correct - it's only an error to write to
1427 // both FragData and FragColor. For simplicity, and because users shouldn't
1428 // be rewarded for reading from undefined varaibles, return an error
1429 // if they are both referenced, rather than assigned.
1430 if (mUsesFragData && mUsesFragColor)
1431 {
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +03001432 const char *errorMessage = "cannot use both gl_FragData and gl_FragColor";
1433 if (mUsesSecondaryOutputs)
1434 {
1435 errorMessage =
1436 "cannot use both output variable sets (gl_FragData, gl_SecondaryFragDataEXT)"
1437 " and (gl_FragColor, gl_SecondaryFragColorEXT)";
1438 }
1439 error(location, errorMessage, name->c_str());
Jamie Madill14e95b32015-05-07 10:10:41 -04001440 }
Martin Radevb0883602016-08-04 17:48:58 +03001441
1442 // GLSL ES 3.1 Revision 4, 7.1.3 Compute Shader Special Variables
1443 if (getShaderType() == GL_COMPUTE_SHADER && !mComputeShaderLocalSizeDeclared &&
1444 qualifier == EvqWorkGroupSize)
1445 {
1446 error(location,
1447 "It is an error to use gl_WorkGroupSize before declaring the local group size",
1448 "gl_WorkGroupSize");
1449 }
Jamie Madill5c097022014-08-20 16:38:32 -04001450 }
1451
1452 if (!variable)
1453 {
1454 TType type(EbtFloat, EbpUndefined);
1455 TVariable *fakeVariable = new TVariable(name, type);
1456 symbolTable.declare(fakeVariable);
1457 variable = fakeVariable;
1458 }
1459
1460 return variable;
1461}
1462
Olli Etuaho82c29ed2015-11-03 13:06:54 +02001463TIntermTyped *TParseContext::parseVariableIdentifier(const TSourceLoc &location,
1464 const TString *name,
1465 const TSymbol *symbol)
1466{
1467 const TVariable *variable = getNamedVariable(location, name, symbol);
1468
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001469 if (variable->getConstPointer())
Olli Etuaho82c29ed2015-11-03 13:06:54 +02001470 {
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001471 const TConstantUnion *constArray = variable->getConstPointer();
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001472 return intermediate.addConstantUnion(constArray, variable->getType(), location);
Olli Etuaho82c29ed2015-11-03 13:06:54 +02001473 }
Olli Etuahoaecfa8e2016-12-09 12:47:26 +00001474 else if (variable->getType().getQualifier() == EvqWorkGroupSize &&
1475 mComputeShaderLocalSizeDeclared)
1476 {
1477 // gl_WorkGroupSize can be used to size arrays according to the ESSL 3.10.4 spec, so it
1478 // needs to be added to the AST as a constant and not as a symbol.
1479 sh::WorkGroupSize workGroupSize = getComputeShaderLocalSize();
1480 TConstantUnion *constArray = new TConstantUnion[3];
1481 for (size_t i = 0; i < 3; ++i)
1482 {
1483 constArray[i].setUConst(static_cast<unsigned int>(workGroupSize[i]));
1484 }
1485
1486 ASSERT(variable->getType().getBasicType() == EbtUInt);
1487 ASSERT(variable->getType().getObjectSize() == 3);
1488
1489 TType type(variable->getType());
1490 type.setQualifier(EvqConst);
1491 return intermediate.addConstantUnion(constArray, type, location);
1492 }
Olli Etuaho82c29ed2015-11-03 13:06:54 +02001493 else
1494 {
1495 return intermediate.addSymbol(variable->getUniqueId(), variable->getName(),
1496 variable->getType(), location);
1497 }
1498}
1499
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001500//
1501// Look up a function name in the symbol table, and make sure it is a function.
1502//
1503// Return the function symbol if found, otherwise 0.
1504//
Jamie Madillb98c3a82015-07-23 14:26:04 -04001505const TFunction *TParseContext::findFunction(const TSourceLoc &line,
1506 TFunction *call,
1507 int inputShaderVersion,
Arun Patole7e7e68d2015-05-22 12:02:25 +05301508 bool *builtIn)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001509{
alokp@chromium.org0a576182010-08-09 17:16:27 +00001510 // First find by unmangled name to check whether the function name has been
1511 // hidden by a variable name or struct typename.
Nicolas Capensd4a9b8d2013-07-18 11:01:22 -04001512 // If a function is found, check for one with a matching argument list.
Arun Patole7e7e68d2015-05-22 12:02:25 +05301513 const TSymbol *symbol = symbolTable.find(call->getName(), inputShaderVersion, builtIn);
1514 if (symbol == 0 || symbol->isFunction())
1515 {
Austin Kinross3ae64652015-01-26 15:51:39 -08001516 symbol = symbolTable.find(call->getMangledName(), inputShaderVersion, builtIn);
alokp@chromium.org0a576182010-08-09 17:16:27 +00001517 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001518
Arun Patole7e7e68d2015-05-22 12:02:25 +05301519 if (symbol == 0)
1520 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001521 error(line, "no matching overloaded function found", call->getName().c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001522 return 0;
1523 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001524
Arun Patole7e7e68d2015-05-22 12:02:25 +05301525 if (!symbol->isFunction())
1526 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001527 error(line, "function name expected", call->getName().c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001528 return 0;
1529 }
alokp@chromium.org0a576182010-08-09 17:16:27 +00001530
Jamie Madillb98c3a82015-07-23 14:26:04 -04001531 return static_cast<const TFunction *>(symbol);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001532}
1533
1534//
1535// Initializers show up in several places in the grammar. Have one set of
1536// code to handle them here.
1537//
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001538// Returns true on error, false if no error
1539//
Jamie Madillb98c3a82015-07-23 14:26:04 -04001540bool TParseContext::executeInitializer(const TSourceLoc &line,
1541 const TString &identifier,
1542 const TPublicType &pType,
1543 TIntermTyped *initializer,
Olli Etuaho13389b62016-10-16 11:48:18 +01001544 TIntermBinary **initNode)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001545{
Olli Etuaho13389b62016-10-16 11:48:18 +01001546 ASSERT(initNode != nullptr);
1547 ASSERT(*initNode == nullptr);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001548 TType type = TType(pType);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001549
Olli Etuaho2935c582015-04-08 14:32:06 +03001550 TVariable *variable = nullptr;
Olli Etuaho376f1b52015-04-13 13:23:41 +03001551 if (type.isUnsizedArray())
1552 {
Olli Etuaho02bd82c2016-11-03 10:29:43 +00001553 // We have not checked yet whether the initializer actually is an array or not.
1554 if (initializer->isArray())
1555 {
1556 type.setArraySize(initializer->getArraySize());
1557 }
1558 else
1559 {
1560 // Having a non-array initializer for an unsized array will result in an error later,
1561 // so we don't generate an error message here.
1562 type.setArraySize(1u);
1563 }
Olli Etuaho376f1b52015-04-13 13:23:41 +03001564 }
Olli Etuaho2935c582015-04-08 14:32:06 +03001565 if (!declareVariable(line, identifier, type, &variable))
1566 {
1567 return true;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001568 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001569
Olli Etuahob0c645e2015-05-12 14:25:36 +03001570 bool globalInitWarning = false;
Jamie Madillb98c3a82015-07-23 14:26:04 -04001571 if (symbolTable.atGlobalLevel() &&
1572 !ValidateGlobalInitializer(initializer, this, &globalInitWarning))
Olli Etuahob0c645e2015-05-12 14:25:36 +03001573 {
1574 // Error message does not completely match behavior with ESSL 1.00, but
1575 // we want to steer developers towards only using constant expressions.
1576 error(line, "global variable initializers must be constant expressions", "=");
1577 return true;
1578 }
1579 if (globalInitWarning)
1580 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001581 warning(
1582 line,
1583 "global variable initializers should be constant expressions "
1584 "(uniforms and globals are allowed in global initializers for legacy compatibility)",
1585 "=");
Olli Etuahob0c645e2015-05-12 14:25:36 +03001586 }
1587
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001588 //
1589 // identifier must be of type constant, a global, or a temporary
1590 //
1591 TQualifier qualifier = variable->getType().getQualifier();
Arun Patole7e7e68d2015-05-22 12:02:25 +05301592 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst))
1593 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001594 error(line, " cannot initialize this type of qualifier ",
1595 variable->getType().getQualifierString());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001596 return true;
1597 }
1598 //
1599 // test for and propagate constant
1600 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001601
Arun Patole7e7e68d2015-05-22 12:02:25 +05301602 if (qualifier == EvqConst)
1603 {
1604 if (qualifier != initializer->getType().getQualifier())
1605 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001606 std::stringstream extraInfoStream;
1607 extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
1608 std::string extraInfo = extraInfoStream.str();
1609 error(line, " assigning non-constant to", "=", extraInfo.c_str());
alokp@chromium.org58e54292010-08-24 21:40:03 +00001610 variable->getType().setQualifier(EvqTemporary);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001611 return true;
1612 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05301613 if (type != initializer->getType())
1614 {
1615 error(line, " non-matching types for const initializer ",
Jamie Madillb98c3a82015-07-23 14:26:04 -04001616 variable->getType().getQualifierString());
alokp@chromium.org58e54292010-08-24 21:40:03 +00001617 variable->getType().setQualifier(EvqTemporary);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001618 return true;
1619 }
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001620
1621 // Save the constant folded value to the variable if possible. For example array
1622 // initializers are not folded, since that way copying the array literal to multiple places
1623 // in the shader is avoided.
1624 // TODO(oetuaho@nvidia.com): Consider constant folding array initialization in cases where
1625 // it would be beneficial.
Arun Patole7e7e68d2015-05-22 12:02:25 +05301626 if (initializer->getAsConstantUnion())
1627 {
Jamie Madill94bf7f22013-07-08 13:31:15 -04001628 variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
Olli Etuaho13389b62016-10-16 11:48:18 +01001629 *initNode = nullptr;
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001630 return false;
Arun Patole7e7e68d2015-05-22 12:02:25 +05301631 }
1632 else if (initializer->getAsSymbolNode())
1633 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001634 const TSymbol *symbol =
1635 symbolTable.find(initializer->getAsSymbolNode()->getSymbol(), 0);
1636 const TVariable *tVar = static_cast<const TVariable *>(symbol);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001637
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001638 const TConstantUnion *constArray = tVar->getConstPointer();
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001639 if (constArray)
1640 {
1641 variable->shareConstPointer(constArray);
Olli Etuaho13389b62016-10-16 11:48:18 +01001642 *initNode = nullptr;
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001643 return false;
1644 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001645 }
1646 }
Olli Etuahoe7847b02015-03-16 11:56:12 +02001647
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001648 TIntermSymbol *intermSymbol = intermediate.addSymbol(
1649 variable->getUniqueId(), variable->getName(), variable->getType(), line);
Olli Etuaho13389b62016-10-16 11:48:18 +01001650 *initNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
1651 if (*initNode == nullptr)
Olli Etuahoe7847b02015-03-16 11:56:12 +02001652 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001653 assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
1654 return true;
Olli Etuahoe7847b02015-03-16 11:56:12 +02001655 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001656
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001657 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001658}
1659
Olli Etuaho0e3aee32016-10-27 12:56:38 +01001660void TParseContext::addFullySpecifiedType(TPublicType *typeSpecifier)
1661{
1662 checkPrecisionSpecified(typeSpecifier->getLine(), typeSpecifier->precision,
1663 typeSpecifier->getBasicType());
1664
1665 if (mShaderVersion < 300 && typeSpecifier->array)
1666 {
1667 error(typeSpecifier->getLine(), "not supported", "first-class array");
1668 typeSpecifier->clearArrayness();
1669 }
1670}
1671
Martin Radev70866b82016-07-22 15:27:42 +03001672TPublicType TParseContext::addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder,
Arun Patole7e7e68d2015-05-22 12:02:25 +05301673 const TPublicType &typeSpecifier)
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001674{
Olli Etuaho613b9592016-09-05 12:05:53 +03001675 TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001676
Martin Radev70866b82016-07-22 15:27:42 +03001677 TPublicType returnType = typeSpecifier;
1678 returnType.qualifier = typeQualifier.qualifier;
1679 returnType.invariant = typeQualifier.invariant;
1680 returnType.layoutQualifier = typeQualifier.layoutQualifier;
Martin Radev2cc85b32016-08-05 16:22:53 +03001681 returnType.memoryQualifier = typeQualifier.memoryQualifier;
Martin Radev70866b82016-07-22 15:27:42 +03001682 returnType.precision = typeSpecifier.precision;
1683
1684 if (typeQualifier.precision != EbpUndefined)
1685 {
1686 returnType.precision = typeQualifier.precision;
1687 }
1688
Martin Radev4a9cd802016-09-01 16:51:51 +03001689 checkPrecisionSpecified(typeSpecifier.getLine(), returnType.precision,
1690 typeSpecifier.getBasicType());
Martin Radev70866b82016-07-22 15:27:42 +03001691
Martin Radev4a9cd802016-09-01 16:51:51 +03001692 checkInvariantVariableQualifier(returnType.invariant, returnType.qualifier,
1693 typeSpecifier.getLine());
Martin Radev70866b82016-07-22 15:27:42 +03001694
Martin Radev4a9cd802016-09-01 16:51:51 +03001695 checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), returnType.layoutQualifier);
Martin Radev802abe02016-08-04 17:48:32 +03001696
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001697 if (mShaderVersion < 300)
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001698 {
Olli Etuahoc1ac41b2015-07-10 13:53:46 +03001699 if (typeSpecifier.array)
1700 {
Martin Radev4a9cd802016-09-01 16:51:51 +03001701 error(typeSpecifier.getLine(), "not supported", "first-class array");
Olli Etuahoc1ac41b2015-07-10 13:53:46 +03001702 returnType.clearArrayness();
1703 }
1704
Martin Radev70866b82016-07-22 15:27:42 +03001705 if (returnType.qualifier == EvqAttribute &&
Martin Radev4a9cd802016-09-01 16:51:51 +03001706 (typeSpecifier.getBasicType() == EbtBool || typeSpecifier.getBasicType() == EbtInt))
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001707 {
Martin Radev4a9cd802016-09-01 16:51:51 +03001708 error(typeSpecifier.getLine(), "cannot be bool or int",
Martin Radev70866b82016-07-22 15:27:42 +03001709 getQualifierString(returnType.qualifier));
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001710 }
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001711
Martin Radev70866b82016-07-22 15:27:42 +03001712 if ((returnType.qualifier == EvqVaryingIn || returnType.qualifier == EvqVaryingOut) &&
Martin Radev4a9cd802016-09-01 16:51:51 +03001713 (typeSpecifier.getBasicType() == EbtBool || typeSpecifier.getBasicType() == EbtInt))
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001714 {
Martin Radev4a9cd802016-09-01 16:51:51 +03001715 error(typeSpecifier.getLine(), "cannot be bool or int",
Martin Radev70866b82016-07-22 15:27:42 +03001716 getQualifierString(returnType.qualifier));
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001717 }
1718 }
1719 else
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001720 {
Martin Radev70866b82016-07-22 15:27:42 +03001721 if (!returnType.layoutQualifier.isEmpty())
Olli Etuahoabb0c382015-07-13 12:01:12 +03001722 {
Martin Radev4a9cd802016-09-01 16:51:51 +03001723 checkIsAtGlobalLevel(typeSpecifier.getLine(), "layout");
Olli Etuahoabb0c382015-07-13 12:01:12 +03001724 }
Martin Radev70866b82016-07-22 15:27:42 +03001725 if (sh::IsVarying(returnType.qualifier) || returnType.qualifier == EvqVertexIn ||
1726 returnType.qualifier == EvqFragmentOut)
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001727 {
Martin Radev4a9cd802016-09-01 16:51:51 +03001728 checkInputOutputTypeIsValidES3(returnType.qualifier, typeSpecifier,
1729 typeSpecifier.getLine());
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001730 }
Martin Radev70866b82016-07-22 15:27:42 +03001731 if (returnType.qualifier == EvqComputeIn)
Martin Radev802abe02016-08-04 17:48:32 +03001732 {
Martin Radev4a9cd802016-09-01 16:51:51 +03001733 error(typeSpecifier.getLine(), "'in' can be only used to specify the local group size",
Martin Radev802abe02016-08-04 17:48:32 +03001734 "in");
Martin Radev802abe02016-08-04 17:48:32 +03001735 }
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001736 }
1737
1738 return returnType;
1739}
1740
Olli Etuaho856c4972016-08-08 11:38:39 +03001741void TParseContext::checkInputOutputTypeIsValidES3(const TQualifier qualifier,
1742 const TPublicType &type,
1743 const TSourceLoc &qualifierLocation)
Olli Etuahocc36b982015-07-10 14:14:18 +03001744{
1745 // An input/output variable can never be bool or a sampler. Samplers are checked elsewhere.
Martin Radev4a9cd802016-09-01 16:51:51 +03001746 if (type.getBasicType() == EbtBool)
Olli Etuahocc36b982015-07-10 14:14:18 +03001747 {
1748 error(qualifierLocation, "cannot be bool", getQualifierString(qualifier));
Olli Etuahocc36b982015-07-10 14:14:18 +03001749 }
1750
1751 // Specific restrictions apply for vertex shader inputs and fragment shader outputs.
1752 switch (qualifier)
1753 {
1754 case EvqVertexIn:
1755 // ESSL 3.00 section 4.3.4
1756 if (type.array)
1757 {
1758 error(qualifierLocation, "cannot be array", getQualifierString(qualifier));
Olli Etuahocc36b982015-07-10 14:14:18 +03001759 }
1760 // Vertex inputs with a struct type are disallowed in singleDeclarationErrorCheck
1761 return;
1762 case EvqFragmentOut:
1763 // ESSL 3.00 section 4.3.6
Martin Radev4a9cd802016-09-01 16:51:51 +03001764 if (type.typeSpecifierNonArray.isMatrix())
Olli Etuahocc36b982015-07-10 14:14:18 +03001765 {
1766 error(qualifierLocation, "cannot be matrix", getQualifierString(qualifier));
Olli Etuahocc36b982015-07-10 14:14:18 +03001767 }
1768 // Fragment outputs with a struct type are disallowed in singleDeclarationErrorCheck
1769 return;
1770 default:
1771 break;
1772 }
1773
1774 // Vertex shader outputs / fragment shader inputs have a different, slightly more lenient set of
1775 // restrictions.
1776 bool typeContainsIntegers =
Martin Radev4a9cd802016-09-01 16:51:51 +03001777 (type.getBasicType() == EbtInt || type.getBasicType() == EbtUInt ||
1778 type.isStructureContainingType(EbtInt) || type.isStructureContainingType(EbtUInt));
Olli Etuahocc36b982015-07-10 14:14:18 +03001779 if (typeContainsIntegers && qualifier != EvqFlatIn && qualifier != EvqFlatOut)
1780 {
1781 error(qualifierLocation, "must use 'flat' interpolation here",
1782 getQualifierString(qualifier));
Olli Etuahocc36b982015-07-10 14:14:18 +03001783 }
1784
Martin Radev4a9cd802016-09-01 16:51:51 +03001785 if (type.getBasicType() == EbtStruct)
Olli Etuahocc36b982015-07-10 14:14:18 +03001786 {
1787 // ESSL 3.00 sections 4.3.4 and 4.3.6.
1788 // These restrictions are only implied by the ESSL 3.00 spec, but
1789 // the ESSL 3.10 spec lists these restrictions explicitly.
1790 if (type.array)
1791 {
1792 error(qualifierLocation, "cannot be an array of structures",
1793 getQualifierString(qualifier));
Olli Etuahocc36b982015-07-10 14:14:18 +03001794 }
1795 if (type.isStructureContainingArrays())
1796 {
1797 error(qualifierLocation, "cannot be a structure containing an array",
1798 getQualifierString(qualifier));
Olli Etuahocc36b982015-07-10 14:14:18 +03001799 }
1800 if (type.isStructureContainingType(EbtStruct))
1801 {
1802 error(qualifierLocation, "cannot be a structure containing a structure",
1803 getQualifierString(qualifier));
Olli Etuahocc36b982015-07-10 14:14:18 +03001804 }
1805 if (type.isStructureContainingType(EbtBool))
1806 {
1807 error(qualifierLocation, "cannot be a structure containing a bool",
1808 getQualifierString(qualifier));
Olli Etuahocc36b982015-07-10 14:14:18 +03001809 }
1810 }
1811}
1812
Martin Radev2cc85b32016-08-05 16:22:53 +03001813void TParseContext::checkLocalVariableConstStorageQualifier(const TQualifierWrapperBase &qualifier)
1814{
1815 if (qualifier.getType() == QtStorage)
1816 {
1817 const TStorageQualifierWrapper &storageQualifier =
1818 static_cast<const TStorageQualifierWrapper &>(qualifier);
1819 if (!declaringFunction() && storageQualifier.getQualifier() != EvqConst &&
1820 !symbolTable.atGlobalLevel())
1821 {
1822 error(storageQualifier.getLine(),
1823 "Local variables can only use the const storage qualifier.",
1824 storageQualifier.getQualifierString().c_str());
1825 }
1826 }
1827}
1828
1829bool TParseContext::checkIsMemoryQualifierNotSpecified(const TMemoryQualifier &memoryQualifier,
1830 const TSourceLoc &location)
1831{
1832 if (memoryQualifier.readonly)
1833 {
1834 error(location, "Only allowed with images.", "readonly");
1835 return false;
1836 }
1837 if (memoryQualifier.writeonly)
1838 {
1839 error(location, "Only allowed with images.", "writeonly");
1840 return false;
1841 }
Martin Radev049edfa2016-11-11 14:35:37 +02001842 if (memoryQualifier.coherent)
1843 {
1844 error(location, "Only allowed with images.", "coherent");
1845 return false;
1846 }
1847 if (memoryQualifier.restrictQualifier)
1848 {
1849 error(location, "Only allowed with images.", "restrict");
1850 return false;
1851 }
1852 if (memoryQualifier.volatileQualifier)
1853 {
1854 error(location, "Only allowed with images.", "volatile");
1855 return false;
1856 }
Martin Radev2cc85b32016-08-05 16:22:53 +03001857 return true;
1858}
1859
Olli Etuaho13389b62016-10-16 11:48:18 +01001860TIntermDeclaration *TParseContext::parseSingleDeclaration(
1861 TPublicType &publicType,
1862 const TSourceLoc &identifierOrTypeLocation,
1863 const TString &identifier)
Jamie Madill60ed9812013-06-06 11:56:46 -04001864{
Kenneth Russellbccc65d2016-07-19 16:48:43 -07001865 TType type(publicType);
1866 if ((mCompileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) &&
1867 mDirectiveHandler.pragma().stdgl.invariantAll)
1868 {
1869 TQualifier qualifier = type.getQualifier();
1870
1871 // The directive handler has already taken care of rejecting invalid uses of this pragma
1872 // (for example, in ESSL 3.00 fragment shaders), so at this point, flatten it into all
1873 // affected variable declarations:
1874 //
1875 // 1. Built-in special variables which are inputs to the fragment shader. (These are handled
1876 // elsewhere, in TranslatorGLSL.)
1877 //
1878 // 2. Outputs from vertex shaders in ESSL 1.00 and 3.00 (EvqVaryingOut and EvqVertexOut). It
1879 // is actually less likely that there will be bugs in the handling of ESSL 3.00 shaders, but
1880 // the way this is currently implemented we have to enable this compiler option before
1881 // parsing the shader and determining the shading language version it uses. If this were
1882 // implemented as a post-pass, the workaround could be more targeted.
1883 //
1884 // 3. Inputs in ESSL 1.00 fragment shaders (EvqVaryingIn). This is somewhat in violation of
1885 // the specification, but there are desktop OpenGL drivers that expect that this is the
1886 // behavior of the #pragma when specified in ESSL 1.00 fragment shaders.
1887 if (qualifier == EvqVaryingOut || qualifier == EvqVertexOut || qualifier == EvqVaryingIn)
1888 {
1889 type.setInvariant(true);
1890 }
1891 }
1892
1893 TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, type, identifierOrTypeLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001894
Olli Etuahobab4c082015-04-24 16:38:49 +03001895 bool emptyDeclaration = (identifier == "");
Olli Etuahofa33d582015-04-09 14:33:12 +03001896
Olli Etuahobab4c082015-04-24 16:38:49 +03001897 mDeferredSingleDeclarationErrorCheck = emptyDeclaration;
1898
Olli Etuaho13389b62016-10-16 11:48:18 +01001899 TIntermDeclaration *declaration = new TIntermDeclaration();
1900 declaration->setLine(identifierOrTypeLocation);
1901
Olli Etuahobab4c082015-04-24 16:38:49 +03001902 if (emptyDeclaration)
1903 {
1904 if (publicType.isUnsizedArray())
1905 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001906 // ESSL3 spec section 4.1.9: Array declaration which leaves the size unspecified is an
1907 // error. It is assumed that this applies to empty declarations as well.
1908 error(identifierOrTypeLocation, "empty array declaration needs to specify a size",
1909 identifier.c_str());
Olli Etuahobab4c082015-04-24 16:38:49 +03001910 }
1911 }
1912 else
Jamie Madill60ed9812013-06-06 11:56:46 -04001913 {
Olli Etuaho383b7912016-08-05 11:22:59 +03001914 singleDeclarationErrorCheck(publicType, identifierOrTypeLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001915
Olli Etuaho856c4972016-08-08 11:38:39 +03001916 checkCanBeDeclaredWithoutInitializer(identifierOrTypeLocation, identifier, &publicType);
Jamie Madill60ed9812013-06-06 11:56:46 -04001917
Olli Etuaho2935c582015-04-08 14:32:06 +03001918 TVariable *variable = nullptr;
Kenneth Russellbccc65d2016-07-19 16:48:43 -07001919 declareVariable(identifierOrTypeLocation, identifier, type, &variable);
Jamie Madill60ed9812013-06-06 11:56:46 -04001920
1921 if (variable && symbol)
Olli Etuaho13389b62016-10-16 11:48:18 +01001922 {
Jamie Madill60ed9812013-06-06 11:56:46 -04001923 symbol->setId(variable->getUniqueId());
Olli Etuaho13389b62016-10-16 11:48:18 +01001924 }
Jamie Madill60ed9812013-06-06 11:56:46 -04001925 }
1926
Olli Etuaho13389b62016-10-16 11:48:18 +01001927 // We append the symbol even if the declaration is empty, mainly because of struct declarations
1928 // that may just declare a type.
1929 declaration->appendDeclarator(symbol);
1930
1931 return declaration;
Jamie Madill60ed9812013-06-06 11:56:46 -04001932}
1933
Olli Etuaho13389b62016-10-16 11:48:18 +01001934TIntermDeclaration *TParseContext::parseSingleArrayDeclaration(TPublicType &publicType,
1935 const TSourceLoc &identifierLocation,
1936 const TString &identifier,
1937 const TSourceLoc &indexLocation,
1938 TIntermTyped *indexExpression)
Jamie Madill60ed9812013-06-06 11:56:46 -04001939{
Olli Etuahofa33d582015-04-09 14:33:12 +03001940 mDeferredSingleDeclarationErrorCheck = false;
1941
Olli Etuaho383b7912016-08-05 11:22:59 +03001942 singleDeclarationErrorCheck(publicType, identifierLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001943
Olli Etuaho856c4972016-08-08 11:38:39 +03001944 checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &publicType);
Jamie Madill60ed9812013-06-06 11:56:46 -04001945
Olli Etuaho8a176262016-08-16 14:23:01 +03001946 checkIsValidTypeAndQualifierForArray(indexLocation, publicType);
Jamie Madill60ed9812013-06-06 11:56:46 -04001947
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001948 TType arrayType(publicType);
Jamie Madill60ed9812013-06-06 11:56:46 -04001949
Olli Etuaho856c4972016-08-08 11:38:39 +03001950 unsigned int size = checkIsValidArraySize(identifierLocation, indexExpression);
Olli Etuahoe7847b02015-03-16 11:56:12 +02001951 // Make the type an array even if size check failed.
1952 // This ensures useless error messages regarding the variable's non-arrayness won't follow.
1953 arrayType.setArraySize(size);
Jamie Madill60ed9812013-06-06 11:56:46 -04001954
Olli Etuaho2935c582015-04-08 14:32:06 +03001955 TVariable *variable = nullptr;
Olli Etuaho383b7912016-08-05 11:22:59 +03001956 declareVariable(identifierLocation, identifier, arrayType, &variable);
Jamie Madill60ed9812013-06-06 11:56:46 -04001957
Olli Etuaho13389b62016-10-16 11:48:18 +01001958 TIntermDeclaration *declaration = new TIntermDeclaration();
1959 declaration->setLine(identifierLocation);
1960
Olli Etuahoe7847b02015-03-16 11:56:12 +02001961 TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001962 if (variable && symbol)
Olli Etuaho13389b62016-10-16 11:48:18 +01001963 {
Jamie Madill60ed9812013-06-06 11:56:46 -04001964 symbol->setId(variable->getUniqueId());
Olli Etuaho13389b62016-10-16 11:48:18 +01001965 declaration->appendDeclarator(symbol);
1966 }
Jamie Madill60ed9812013-06-06 11:56:46 -04001967
Olli Etuaho13389b62016-10-16 11:48:18 +01001968 return declaration;
Jamie Madill60ed9812013-06-06 11:56:46 -04001969}
1970
Olli Etuaho13389b62016-10-16 11:48:18 +01001971TIntermDeclaration *TParseContext::parseSingleInitDeclaration(const TPublicType &publicType,
1972 const TSourceLoc &identifierLocation,
1973 const TString &identifier,
1974 const TSourceLoc &initLocation,
1975 TIntermTyped *initializer)
Jamie Madill60ed9812013-06-06 11:56:46 -04001976{
Olli Etuahofa33d582015-04-09 14:33:12 +03001977 mDeferredSingleDeclarationErrorCheck = false;
1978
Olli Etuaho383b7912016-08-05 11:22:59 +03001979 singleDeclarationErrorCheck(publicType, identifierLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001980
Olli Etuaho13389b62016-10-16 11:48:18 +01001981 TIntermDeclaration *declaration = new TIntermDeclaration();
1982 declaration->setLine(identifierLocation);
1983
1984 TIntermBinary *initNode = nullptr;
1985 if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &initNode))
Jamie Madill60ed9812013-06-06 11:56:46 -04001986 {
Olli Etuaho13389b62016-10-16 11:48:18 +01001987 if (initNode)
1988 {
1989 declaration->appendDeclarator(initNode);
1990 }
Jamie Madill60ed9812013-06-06 11:56:46 -04001991 }
Olli Etuaho13389b62016-10-16 11:48:18 +01001992 return declaration;
Jamie Madill60ed9812013-06-06 11:56:46 -04001993}
1994
Olli Etuaho13389b62016-10-16 11:48:18 +01001995TIntermDeclaration *TParseContext::parseSingleArrayInitDeclaration(
Jamie Madillb98c3a82015-07-23 14:26:04 -04001996 TPublicType &publicType,
1997 const TSourceLoc &identifierLocation,
1998 const TString &identifier,
1999 const TSourceLoc &indexLocation,
2000 TIntermTyped *indexExpression,
2001 const TSourceLoc &initLocation,
2002 TIntermTyped *initializer)
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002003{
2004 mDeferredSingleDeclarationErrorCheck = false;
2005
Olli Etuaho383b7912016-08-05 11:22:59 +03002006 singleDeclarationErrorCheck(publicType, identifierLocation);
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002007
Olli Etuaho8a176262016-08-16 14:23:01 +03002008 checkIsValidTypeAndQualifierForArray(indexLocation, publicType);
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002009
2010 TPublicType arrayType(publicType);
2011
Olli Etuaho856c4972016-08-08 11:38:39 +03002012 unsigned int size = 0u;
Jamie Madillb98c3a82015-07-23 14:26:04 -04002013 // If indexExpression is nullptr, then the array will eventually get its size implicitly from
2014 // the initializer.
Olli Etuaho383b7912016-08-05 11:22:59 +03002015 if (indexExpression != nullptr)
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002016 {
Olli Etuaho856c4972016-08-08 11:38:39 +03002017 size = checkIsValidArraySize(identifierLocation, indexExpression);
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002018 }
2019 // Make the type an array even if size check failed.
2020 // This ensures useless error messages regarding the variable's non-arrayness won't follow.
2021 arrayType.setArraySize(size);
2022
Olli Etuaho13389b62016-10-16 11:48:18 +01002023 TIntermDeclaration *declaration = new TIntermDeclaration();
2024 declaration->setLine(identifierLocation);
2025
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002026 // initNode will correspond to the whole of "type b[n] = initializer".
Olli Etuaho13389b62016-10-16 11:48:18 +01002027 TIntermBinary *initNode = nullptr;
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002028 if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
2029 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002030 if (initNode)
2031 {
2032 declaration->appendDeclarator(initNode);
2033 }
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002034 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002035
2036 return declaration;
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002037}
2038
Martin Radev70866b82016-07-22 15:27:42 +03002039TIntermAggregate *TParseContext::parseInvariantDeclaration(
2040 const TTypeQualifierBuilder &typeQualifierBuilder,
2041 const TSourceLoc &identifierLoc,
2042 const TString *identifier,
2043 const TSymbol *symbol)
Jamie Madill47e3ec02014-08-20 16:38:33 -04002044{
Olli Etuaho613b9592016-09-05 12:05:53 +03002045 TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
Jamie Madill47e3ec02014-08-20 16:38:33 -04002046
Martin Radev70866b82016-07-22 15:27:42 +03002047 if (!typeQualifier.invariant)
2048 {
2049 error(identifierLoc, "Expected invariant", identifier->c_str());
2050 return nullptr;
2051 }
2052 if (!checkIsAtGlobalLevel(identifierLoc, "invariant varying"))
2053 {
2054 return nullptr;
2055 }
Jamie Madill47e3ec02014-08-20 16:38:33 -04002056 if (!symbol)
2057 {
2058 error(identifierLoc, "undeclared identifier declared as invariant", identifier->c_str());
Olli Etuahoe7847b02015-03-16 11:56:12 +02002059 return nullptr;
Jamie Madill47e3ec02014-08-20 16:38:33 -04002060 }
Martin Radev70866b82016-07-22 15:27:42 +03002061 if (!IsQualifierUnspecified(typeQualifier.qualifier))
Jamie Madill47e3ec02014-08-20 16:38:33 -04002062 {
Martin Radev70866b82016-07-22 15:27:42 +03002063 error(identifierLoc, "invariant declaration specifies qualifier",
2064 getQualifierString(typeQualifier.qualifier));
Jamie Madill47e3ec02014-08-20 16:38:33 -04002065 }
Martin Radev70866b82016-07-22 15:27:42 +03002066 if (typeQualifier.precision != EbpUndefined)
2067 {
2068 error(identifierLoc, "invariant declaration specifies precision",
2069 getPrecisionString(typeQualifier.precision));
2070 }
2071 if (!typeQualifier.layoutQualifier.isEmpty())
2072 {
2073 error(identifierLoc, "invariant declaration specifies layout", "'layout'");
2074 }
2075
2076 const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol);
2077 ASSERT(variable);
2078 const TType &type = variable->getType();
2079
2080 checkInvariantVariableQualifier(typeQualifier.invariant, type.getQualifier(),
2081 typeQualifier.line);
Martin Radev2cc85b32016-08-05 16:22:53 +03002082 checkIsMemoryQualifierNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line);
Martin Radev70866b82016-07-22 15:27:42 +03002083
2084 symbolTable.addInvariantVarying(std::string(identifier->c_str()));
2085
2086 TIntermSymbol *intermSymbol =
2087 intermediate.addSymbol(variable->getUniqueId(), *identifier, type, identifierLoc);
2088
Olli Etuaho32db19b2016-10-04 14:43:16 +01002089 TIntermAggregate *aggregate = TIntermediate::MakeAggregate(intermSymbol, identifierLoc);
Martin Radev70866b82016-07-22 15:27:42 +03002090 aggregate->setOp(EOpInvariantDeclaration);
2091 return aggregate;
Jamie Madill47e3ec02014-08-20 16:38:33 -04002092}
2093
Olli Etuaho13389b62016-10-16 11:48:18 +01002094void TParseContext::parseDeclarator(TPublicType &publicType,
2095 const TSourceLoc &identifierLocation,
2096 const TString &identifier,
2097 TIntermDeclaration *declarationOut)
Jamie Madill502d66f2013-06-20 11:55:52 -04002098{
Jamie Madillb98c3a82015-07-23 14:26:04 -04002099 // If the declaration starting this declarator list was empty (example: int,), some checks were
2100 // not performed.
Olli Etuahofa33d582015-04-09 14:33:12 +03002101 if (mDeferredSingleDeclarationErrorCheck)
2102 {
Olli Etuaho383b7912016-08-05 11:22:59 +03002103 singleDeclarationErrorCheck(publicType, identifierLocation);
Olli Etuahofa33d582015-04-09 14:33:12 +03002104 mDeferredSingleDeclarationErrorCheck = false;
2105 }
2106
Olli Etuaho856c4972016-08-08 11:38:39 +03002107 checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType);
Jamie Madill0bd18df2013-06-20 11:55:52 -04002108
Olli Etuaho856c4972016-08-08 11:38:39 +03002109 checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &publicType);
Jamie Madill502d66f2013-06-20 11:55:52 -04002110
Olli Etuaho2935c582015-04-08 14:32:06 +03002111 TVariable *variable = nullptr;
Olli Etuaho383b7912016-08-05 11:22:59 +03002112 declareVariable(identifierLocation, identifier, TType(publicType), &variable);
Olli Etuahoe7847b02015-03-16 11:56:12 +02002113
Jamie Madillb98c3a82015-07-23 14:26:04 -04002114 TIntermSymbol *symbol =
2115 intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation);
Olli Etuahoe7847b02015-03-16 11:56:12 +02002116 if (variable && symbol)
Olli Etuaho13389b62016-10-16 11:48:18 +01002117 {
Jamie Madill502d66f2013-06-20 11:55:52 -04002118 symbol->setId(variable->getUniqueId());
Olli Etuaho13389b62016-10-16 11:48:18 +01002119 declarationOut->appendDeclarator(symbol);
2120 }
Jamie Madill502d66f2013-06-20 11:55:52 -04002121}
2122
Olli Etuaho13389b62016-10-16 11:48:18 +01002123void TParseContext::parseArrayDeclarator(TPublicType &publicType,
2124 const TSourceLoc &identifierLocation,
2125 const TString &identifier,
2126 const TSourceLoc &arrayLocation,
2127 TIntermTyped *indexExpression,
2128 TIntermDeclaration *declarationOut)
Jamie Madill502d66f2013-06-20 11:55:52 -04002129{
Jamie Madillb98c3a82015-07-23 14:26:04 -04002130 // If the declaration starting this declarator list was empty (example: int,), some checks were
2131 // not performed.
Olli Etuahofa33d582015-04-09 14:33:12 +03002132 if (mDeferredSingleDeclarationErrorCheck)
2133 {
Olli Etuaho383b7912016-08-05 11:22:59 +03002134 singleDeclarationErrorCheck(publicType, identifierLocation);
Olli Etuahofa33d582015-04-09 14:33:12 +03002135 mDeferredSingleDeclarationErrorCheck = false;
2136 }
Jamie Madill502d66f2013-06-20 11:55:52 -04002137
Olli Etuaho856c4972016-08-08 11:38:39 +03002138 checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType);
Jamie Madill0bd18df2013-06-20 11:55:52 -04002139
Olli Etuaho856c4972016-08-08 11:38:39 +03002140 checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &publicType);
Jamie Madill502d66f2013-06-20 11:55:52 -04002141
Olli Etuaho8a176262016-08-16 14:23:01 +03002142 if (checkIsValidTypeAndQualifierForArray(arrayLocation, publicType))
Jamie Madill502d66f2013-06-20 11:55:52 -04002143 {
Olli Etuahoe7847b02015-03-16 11:56:12 +02002144 TType arrayType = TType(publicType);
Olli Etuaho856c4972016-08-08 11:38:39 +03002145 unsigned int size = checkIsValidArraySize(arrayLocation, indexExpression);
Olli Etuaho693c9aa2015-04-07 17:50:36 +03002146 arrayType.setArraySize(size);
Olli Etuahoe7847b02015-03-16 11:56:12 +02002147
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03002148 TVariable *variable = nullptr;
Olli Etuaho383b7912016-08-05 11:22:59 +03002149 declareVariable(identifierLocation, identifier, arrayType, &variable);
Jamie Madill502d66f2013-06-20 11:55:52 -04002150
Jamie Madillb98c3a82015-07-23 14:26:04 -04002151 TIntermSymbol *symbol =
2152 intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03002153 if (variable && symbol)
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03002154 symbol->setId(variable->getUniqueId());
Olli Etuahoe7847b02015-03-16 11:56:12 +02002155
Olli Etuaho13389b62016-10-16 11:48:18 +01002156 declarationOut->appendDeclarator(symbol);
Jamie Madill502d66f2013-06-20 11:55:52 -04002157 }
Jamie Madill502d66f2013-06-20 11:55:52 -04002158}
2159
Olli Etuaho13389b62016-10-16 11:48:18 +01002160void TParseContext::parseInitDeclarator(const TPublicType &publicType,
2161 const TSourceLoc &identifierLocation,
2162 const TString &identifier,
2163 const TSourceLoc &initLocation,
2164 TIntermTyped *initializer,
2165 TIntermDeclaration *declarationOut)
Jamie Madill502d66f2013-06-20 11:55:52 -04002166{
Jamie Madillb98c3a82015-07-23 14:26:04 -04002167 // If the declaration starting this declarator list was empty (example: int,), some checks were
2168 // not performed.
Olli Etuahofa33d582015-04-09 14:33:12 +03002169 if (mDeferredSingleDeclarationErrorCheck)
2170 {
Olli Etuaho383b7912016-08-05 11:22:59 +03002171 singleDeclarationErrorCheck(publicType, identifierLocation);
Olli Etuahofa33d582015-04-09 14:33:12 +03002172 mDeferredSingleDeclarationErrorCheck = false;
2173 }
Jamie Madill502d66f2013-06-20 11:55:52 -04002174
Olli Etuaho856c4972016-08-08 11:38:39 +03002175 checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType);
Jamie Madill0bd18df2013-06-20 11:55:52 -04002176
Olli Etuaho13389b62016-10-16 11:48:18 +01002177 TIntermBinary *initNode = nullptr;
2178 if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &initNode))
Jamie Madill502d66f2013-06-20 11:55:52 -04002179 {
2180 //
2181 // build the intermediate representation
2182 //
Olli Etuaho13389b62016-10-16 11:48:18 +01002183 if (initNode)
Jamie Madill502d66f2013-06-20 11:55:52 -04002184 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002185 declarationOut->appendDeclarator(initNode);
Jamie Madill502d66f2013-06-20 11:55:52 -04002186 }
Jamie Madill502d66f2013-06-20 11:55:52 -04002187 }
2188}
2189
Olli Etuaho13389b62016-10-16 11:48:18 +01002190void TParseContext::parseArrayInitDeclarator(const TPublicType &publicType,
2191 const TSourceLoc &identifierLocation,
2192 const TString &identifier,
2193 const TSourceLoc &indexLocation,
2194 TIntermTyped *indexExpression,
2195 const TSourceLoc &initLocation,
2196 TIntermTyped *initializer,
2197 TIntermDeclaration *declarationOut)
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002198{
Jamie Madillb98c3a82015-07-23 14:26:04 -04002199 // If the declaration starting this declarator list was empty (example: int,), some checks were
2200 // not performed.
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002201 if (mDeferredSingleDeclarationErrorCheck)
2202 {
Olli Etuaho383b7912016-08-05 11:22:59 +03002203 singleDeclarationErrorCheck(publicType, identifierLocation);
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002204 mDeferredSingleDeclarationErrorCheck = false;
2205 }
2206
Olli Etuaho856c4972016-08-08 11:38:39 +03002207 checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType);
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002208
Olli Etuaho8a176262016-08-16 14:23:01 +03002209 checkIsValidTypeAndQualifierForArray(indexLocation, publicType);
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002210
2211 TPublicType arrayType(publicType);
2212
Olli Etuaho856c4972016-08-08 11:38:39 +03002213 unsigned int size = 0u;
Jamie Madillb98c3a82015-07-23 14:26:04 -04002214 // If indexExpression is nullptr, then the array will eventually get its size implicitly from
2215 // the initializer.
Olli Etuaho383b7912016-08-05 11:22:59 +03002216 if (indexExpression != nullptr)
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002217 {
Olli Etuaho856c4972016-08-08 11:38:39 +03002218 size = checkIsValidArraySize(identifierLocation, indexExpression);
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002219 }
2220 // Make the type an array even if size check failed.
2221 // This ensures useless error messages regarding the variable's non-arrayness won't follow.
2222 arrayType.setArraySize(size);
2223
2224 // initNode will correspond to the whole of "b[n] = initializer".
Olli Etuaho13389b62016-10-16 11:48:18 +01002225 TIntermBinary *initNode = nullptr;
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002226 if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
2227 {
2228 if (initNode)
2229 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002230 declarationOut->appendDeclarator(initNode);
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002231 }
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002232 }
2233}
2234
Martin Radev70866b82016-07-22 15:27:42 +03002235void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder)
Jamie Madilla295edf2013-06-06 11:56:48 -04002236{
Olli Etuaho613b9592016-09-05 12:05:53 +03002237 TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
Jamie Madilla295edf2013-06-06 11:56:48 -04002238 const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier;
Jamie Madillc2128ff2016-07-04 10:26:17 -04002239
Martin Radev70866b82016-07-22 15:27:42 +03002240 checkInvariantVariableQualifier(typeQualifier.invariant, typeQualifier.qualifier,
2241 typeQualifier.line);
2242
Jamie Madillc2128ff2016-07-04 10:26:17 -04002243 // It should never be the case, but some strange parser errors can send us here.
2244 if (layoutQualifier.isEmpty())
2245 {
2246 error(typeQualifier.line, "Error during layout qualifier parsing.", "?");
Jamie Madillc2128ff2016-07-04 10:26:17 -04002247 return;
2248 }
Jamie Madilla295edf2013-06-06 11:56:48 -04002249
Martin Radev802abe02016-08-04 17:48:32 +03002250 if (!layoutQualifier.isCombinationValid())
Jamie Madilla295edf2013-06-06 11:56:48 -04002251 {
Martin Radev802abe02016-08-04 17:48:32 +03002252 error(typeQualifier.line, "invalid combination:", "layout");
Jamie Madilla295edf2013-06-06 11:56:48 -04002253 return;
2254 }
2255
Martin Radev2cc85b32016-08-05 16:22:53 +03002256 checkIsMemoryQualifierNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line);
2257
2258 checkInternalFormatIsNotSpecified(typeQualifier.line, layoutQualifier.imageInternalFormat);
2259
Martin Radev802abe02016-08-04 17:48:32 +03002260 if (typeQualifier.qualifier == EvqComputeIn)
Jamie Madilla295edf2013-06-06 11:56:48 -04002261 {
Martin Radev802abe02016-08-04 17:48:32 +03002262 if (mComputeShaderLocalSizeDeclared &&
2263 !layoutQualifier.isLocalSizeEqual(mComputeShaderLocalSize))
2264 {
2265 error(typeQualifier.line, "Work group size does not match the previous declaration",
2266 "layout");
Martin Radev802abe02016-08-04 17:48:32 +03002267 return;
2268 }
Jamie Madilla295edf2013-06-06 11:56:48 -04002269
Martin Radev802abe02016-08-04 17:48:32 +03002270 if (mShaderVersion < 310)
2271 {
2272 error(typeQualifier.line, "in type qualifier supported in GLSL ES 3.10 only", "layout");
Martin Radev802abe02016-08-04 17:48:32 +03002273 return;
2274 }
Jamie Madill099c0f32013-06-20 11:55:52 -04002275
Martin Radev4c4c8e72016-08-04 12:25:34 +03002276 if (!layoutQualifier.localSize.isAnyValueSet())
Martin Radev802abe02016-08-04 17:48:32 +03002277 {
2278 error(typeQualifier.line, "No local work group size specified", "layout");
Martin Radev802abe02016-08-04 17:48:32 +03002279 return;
2280 }
2281
2282 const TVariable *maxComputeWorkGroupSize = static_cast<const TVariable *>(
2283 symbolTable.findBuiltIn("gl_MaxComputeWorkGroupSize", mShaderVersion));
2284
2285 const TConstantUnion *maxComputeWorkGroupSizeData =
2286 maxComputeWorkGroupSize->getConstPointer();
2287
2288 for (size_t i = 0u; i < layoutQualifier.localSize.size(); ++i)
2289 {
2290 if (layoutQualifier.localSize[i] != -1)
2291 {
2292 mComputeShaderLocalSize[i] = layoutQualifier.localSize[i];
2293 const int maxComputeWorkGroupSizeValue = maxComputeWorkGroupSizeData[i].getIConst();
2294 if (mComputeShaderLocalSize[i] < 1 ||
2295 mComputeShaderLocalSize[i] > maxComputeWorkGroupSizeValue)
2296 {
2297 std::stringstream errorMessageStream;
2298 errorMessageStream << "Value must be at least 1 and no greater than "
2299 << maxComputeWorkGroupSizeValue;
2300 const std::string &errorMessage = errorMessageStream.str();
2301
Martin Radev4c4c8e72016-08-04 12:25:34 +03002302 error(typeQualifier.line, "invalid value:", getWorkGroupSizeString(i),
Martin Radev802abe02016-08-04 17:48:32 +03002303 errorMessage.c_str());
Martin Radev802abe02016-08-04 17:48:32 +03002304 return;
2305 }
2306 }
2307 }
2308
2309 mComputeShaderLocalSizeDeclared = true;
2310 }
2311 else
Jamie Madill1566ef72013-06-20 11:55:54 -04002312 {
Martin Radev802abe02016-08-04 17:48:32 +03002313
Olli Etuaho8a176262016-08-16 14:23:01 +03002314 if (!checkWorkGroupSizeIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier))
Martin Radev802abe02016-08-04 17:48:32 +03002315 {
Martin Radev802abe02016-08-04 17:48:32 +03002316 return;
2317 }
2318
2319 if (typeQualifier.qualifier != EvqUniform)
2320 {
2321 error(typeQualifier.line, "invalid qualifier:",
2322 getQualifierString(typeQualifier.qualifier), "global layout must be uniform");
Martin Radev802abe02016-08-04 17:48:32 +03002323 return;
2324 }
2325
2326 if (mShaderVersion < 300)
2327 {
2328 error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 and above",
2329 "layout");
Martin Radev802abe02016-08-04 17:48:32 +03002330 return;
2331 }
2332
Olli Etuaho856c4972016-08-08 11:38:39 +03002333 checkLocationIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier);
Martin Radev802abe02016-08-04 17:48:32 +03002334
2335 if (layoutQualifier.matrixPacking != EmpUnspecified)
2336 {
2337 mDefaultMatrixPacking = layoutQualifier.matrixPacking;
2338 }
2339
2340 if (layoutQualifier.blockStorage != EbsUnspecified)
2341 {
2342 mDefaultBlockStorage = layoutQualifier.blockStorage;
2343 }
Jamie Madill1566ef72013-06-20 11:55:54 -04002344 }
Jamie Madilla295edf2013-06-06 11:56:48 -04002345}
2346
Olli Etuaho476197f2016-10-11 13:59:08 +01002347TIntermAggregate *TParseContext::addFunctionPrototypeDeclaration(const TFunction &parsedFunction,
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002348 const TSourceLoc &location)
2349{
Olli Etuaho476197f2016-10-11 13:59:08 +01002350 // Note: function found from the symbol table could be the same as parsedFunction if this is the
2351 // first declaration. Either way the instance in the symbol table is used to track whether the
2352 // function is declared multiple times.
2353 TFunction *function = static_cast<TFunction *>(
2354 symbolTable.find(parsedFunction.getMangledName(), getShaderVersion()));
2355 if (function->hasPrototypeDeclaration() && mShaderVersion == 100)
Olli Etuaho5d653182016-01-04 14:43:28 +02002356 {
2357 // ESSL 1.00.17 section 4.2.7.
2358 // Doesn't apply to ESSL 3.00.4: see section 4.2.3.
2359 error(location, "duplicate function prototype declarations are not allowed", "function");
Olli Etuaho5d653182016-01-04 14:43:28 +02002360 }
Olli Etuaho476197f2016-10-11 13:59:08 +01002361 function->setHasPrototypeDeclaration();
Olli Etuaho5d653182016-01-04 14:43:28 +02002362
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002363 TIntermAggregate *prototype = new TIntermAggregate;
Olli Etuaho476197f2016-10-11 13:59:08 +01002364 // TODO(oetuaho@nvidia.com): Instead of converting the function information here, the node could
2365 // point to the data that already exists in the symbol table.
2366 prototype->setType(function->getReturnType());
Olli Etuahobd674552016-10-06 13:28:42 +01002367 prototype->getFunctionSymbolInfo()->setFromFunction(*function);
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002368
Olli Etuaho476197f2016-10-11 13:59:08 +01002369 for (size_t i = 0; i < function->getParamCount(); i++)
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002370 {
Olli Etuaho476197f2016-10-11 13:59:08 +01002371 const TConstParameter &param = function->getParam(i);
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002372 if (param.name != 0)
2373 {
2374 TVariable variable(param.name, *param.type);
2375
2376 TIntermSymbol *paramSymbol = intermediate.addSymbol(
2377 variable.getUniqueId(), variable.getName(), variable.getType(), location);
2378 prototype = intermediate.growAggregate(prototype, paramSymbol, location);
2379 }
2380 else
2381 {
2382 TIntermSymbol *paramSymbol = intermediate.addSymbol(0, "", *param.type, location);
2383 prototype = intermediate.growAggregate(prototype, paramSymbol, location);
2384 }
2385 }
2386
2387 prototype->setOp(EOpPrototype);
2388
2389 symbolTable.pop();
Olli Etuaho8d8b1082016-01-04 16:44:57 +02002390
2391 if (!symbolTable.atGlobalLevel())
2392 {
2393 // ESSL 3.00.4 section 4.2.4.
2394 error(location, "local function prototype declarations are not allowed", "function");
Olli Etuaho8d8b1082016-01-04 16:44:57 +02002395 }
2396
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002397 return prototype;
2398}
2399
Olli Etuaho336b1472016-10-05 16:37:55 +01002400TIntermFunctionDefinition *TParseContext::addFunctionDefinition(
2401 const TFunction &function,
2402 TIntermAggregate *functionParameters,
2403 TIntermBlock *functionBody,
2404 const TSourceLoc &location)
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002405{
Olli Etuahof51fdd22016-10-03 10:03:40 +01002406 // Check that non-void functions have at least one return statement.
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002407 if (mCurrentFunctionType->getBasicType() != EbtVoid && !mFunctionReturnsValue)
2408 {
2409 error(location, "function does not return a value:", "", function.getName().c_str());
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002410 }
2411
Olli Etuahof51fdd22016-10-03 10:03:40 +01002412 if (functionBody == nullptr)
2413 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01002414 functionBody = new TIntermBlock();
Olli Etuahof51fdd22016-10-03 10:03:40 +01002415 functionBody->setLine(location);
2416 }
Olli Etuaho336b1472016-10-05 16:37:55 +01002417 TIntermFunctionDefinition *functionNode =
2418 new TIntermFunctionDefinition(function.getReturnType(), functionParameters, functionBody);
2419 functionNode->setLine(location);
Olli Etuahof51fdd22016-10-03 10:03:40 +01002420
Olli Etuahobd674552016-10-06 13:28:42 +01002421 functionNode->getFunctionSymbolInfo()->setFromFunction(function);
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002422
2423 symbolTable.pop();
Olli Etuahof51fdd22016-10-03 10:03:40 +01002424 return functionNode;
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002425}
2426
Olli Etuaho476197f2016-10-11 13:59:08 +01002427void TParseContext::parseFunctionDefinitionHeader(const TSourceLoc &location,
2428 TFunction **function,
2429 TIntermAggregate **aggregateOut)
Jamie Madill185fb402015-06-12 15:48:48 -04002430{
Olli Etuaho476197f2016-10-11 13:59:08 +01002431 ASSERT(function);
2432 ASSERT(*function);
Jamie Madillb98c3a82015-07-23 14:26:04 -04002433 const TSymbol *builtIn =
Olli Etuaho476197f2016-10-11 13:59:08 +01002434 symbolTable.findBuiltIn((*function)->getMangledName(), getShaderVersion());
Jamie Madill185fb402015-06-12 15:48:48 -04002435
2436 if (builtIn)
2437 {
Olli Etuaho476197f2016-10-11 13:59:08 +01002438 error(location, "built-in functions cannot be redefined", (*function)->getName().c_str());
Jamie Madill185fb402015-06-12 15:48:48 -04002439 }
Olli Etuaho476197f2016-10-11 13:59:08 +01002440 else
Jamie Madill185fb402015-06-12 15:48:48 -04002441 {
Olli Etuaho476197f2016-10-11 13:59:08 +01002442 TFunction *prevDec = static_cast<TFunction *>(
2443 symbolTable.find((*function)->getMangledName(), getShaderVersion()));
2444
2445 // Note: 'prevDec' could be 'function' if this is the first time we've seen function as it
2446 // would have just been put in the symbol table. Otherwise, we're looking up an earlier
2447 // occurance.
2448 if (*function != prevDec)
2449 {
2450 // Swap the parameters of the previous declaration to the parameters of the function
2451 // definition (parameter names may differ).
2452 prevDec->swapParameters(**function);
2453
2454 // The function definition will share the same symbol as any previous declaration.
2455 *function = prevDec;
2456 }
2457
2458 if ((*function)->isDefined())
2459 {
2460 error(location, "function already has a body", (*function)->getName().c_str());
2461 }
2462
2463 (*function)->setDefined();
Jamie Madill185fb402015-06-12 15:48:48 -04002464 }
Jamie Madill185fb402015-06-12 15:48:48 -04002465
2466 // Raise error message if main function takes any parameters or return anything other than void
Olli Etuaho476197f2016-10-11 13:59:08 +01002467 if ((*function)->getName() == "main")
Jamie Madill185fb402015-06-12 15:48:48 -04002468 {
Olli Etuaho476197f2016-10-11 13:59:08 +01002469 if ((*function)->getParamCount() > 0)
Jamie Madill185fb402015-06-12 15:48:48 -04002470 {
Olli Etuaho476197f2016-10-11 13:59:08 +01002471 error(location, "function cannot take any parameter(s)",
2472 (*function)->getName().c_str());
Jamie Madill185fb402015-06-12 15:48:48 -04002473 }
Olli Etuaho476197f2016-10-11 13:59:08 +01002474 if ((*function)->getReturnType().getBasicType() != EbtVoid)
Jamie Madill185fb402015-06-12 15:48:48 -04002475 {
Olli Etuaho476197f2016-10-11 13:59:08 +01002476 error(location, "", (*function)->getReturnType().getBasicString(),
Jamie Madillb98c3a82015-07-23 14:26:04 -04002477 "main function cannot return a value");
Jamie Madill185fb402015-06-12 15:48:48 -04002478 }
2479 }
2480
2481 //
2482 // Remember the return type for later checking for RETURN statements.
2483 //
Olli Etuaho476197f2016-10-11 13:59:08 +01002484 mCurrentFunctionType = &((*function)->getReturnType());
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002485 mFunctionReturnsValue = false;
Jamie Madill185fb402015-06-12 15:48:48 -04002486
2487 //
2488 // Insert parameters into the symbol table.
2489 // If the parameter has no name, it's not an error, just don't insert it
2490 // (could be used for unused args).
2491 //
2492 // Also, accumulate the list of parameters into the HIL, so lower level code
2493 // knows where to find parameters.
2494 //
2495 TIntermAggregate *paramNodes = new TIntermAggregate;
Olli Etuaho476197f2016-10-11 13:59:08 +01002496 for (size_t i = 0; i < (*function)->getParamCount(); i++)
Jamie Madill185fb402015-06-12 15:48:48 -04002497 {
Olli Etuaho476197f2016-10-11 13:59:08 +01002498 const TConstParameter &param = (*function)->getParam(i);
Jamie Madill185fb402015-06-12 15:48:48 -04002499 if (param.name != 0)
2500 {
2501 TVariable *variable = new TVariable(param.name, *param.type);
2502 //
2503 // Insert the parameters with name in the symbol table.
2504 //
Jamie Madill1a4b1b32015-07-23 18:27:13 -04002505 if (!symbolTable.declare(variable))
2506 {
Jamie Madill185fb402015-06-12 15:48:48 -04002507 error(location, "redefinition", variable->getName().c_str());
Jamie Madill1a4b1b32015-07-23 18:27:13 -04002508 paramNodes = intermediate.growAggregate(
2509 paramNodes, intermediate.addSymbol(0, "", *param.type, location), location);
2510 continue;
Jamie Madill185fb402015-06-12 15:48:48 -04002511 }
2512
2513 //
2514 // Add the parameter to the HIL
2515 //
Jamie Madillb98c3a82015-07-23 14:26:04 -04002516 TIntermSymbol *symbol = intermediate.addSymbol(
2517 variable->getUniqueId(), variable->getName(), variable->getType(), location);
Jamie Madill185fb402015-06-12 15:48:48 -04002518
2519 paramNodes = intermediate.growAggregate(paramNodes, symbol, location);
2520 }
2521 else
2522 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002523 paramNodes = intermediate.growAggregate(
2524 paramNodes, intermediate.addSymbol(0, "", *param.type, location), location);
Jamie Madill185fb402015-06-12 15:48:48 -04002525 }
2526 }
2527 intermediate.setAggregateOperator(paramNodes, EOpParameters, location);
2528 *aggregateOut = paramNodes;
2529 setLoopNestingLevel(0);
2530}
2531
Jamie Madillb98c3a82015-07-23 14:26:04 -04002532TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TFunction *function)
Jamie Madill185fb402015-06-12 15:48:48 -04002533{
Geoff Lang13e7c7e2015-07-30 14:17:29 +00002534 //
Olli Etuaho5d653182016-01-04 14:43:28 +02002535 // We don't know at this point whether this is a function definition or a prototype.
2536 // The definition production code will check for redefinitions.
2537 // In the case of ESSL 1.00 the prototype production code will also check for redeclarations.
Geoff Lang13e7c7e2015-07-30 14:17:29 +00002538 //
Olli Etuaho5d653182016-01-04 14:43:28 +02002539 // Return types and parameter qualifiers must match in all redeclarations, so those are checked
2540 // here.
Geoff Lang13e7c7e2015-07-30 14:17:29 +00002541 //
2542 TFunction *prevDec =
2543 static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion()));
Olli Etuahoc4a96d62015-07-23 17:37:39 +05302544
2545 if (getShaderVersion() >= 300 && symbolTable.hasUnmangledBuiltIn(function->getName().c_str()))
2546 {
2547 // With ESSL 3.00, names of built-in functions cannot be redeclared as functions.
2548 // Therefore overloading or redefining builtin functions is an error.
2549 error(location, "Name of a built-in function cannot be redeclared as function",
2550 function->getName().c_str());
Olli Etuahoc4a96d62015-07-23 17:37:39 +05302551 }
2552 else if (prevDec)
Jamie Madill185fb402015-06-12 15:48:48 -04002553 {
2554 if (prevDec->getReturnType() != function->getReturnType())
2555 {
Olli Etuaho476197f2016-10-11 13:59:08 +01002556 error(location, "function must have the same return type in all of its declarations",
Jamie Madill185fb402015-06-12 15:48:48 -04002557 function->getReturnType().getBasicString());
Jamie Madill185fb402015-06-12 15:48:48 -04002558 }
2559 for (size_t i = 0; i < prevDec->getParamCount(); ++i)
2560 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002561 if (prevDec->getParam(i).type->getQualifier() !=
2562 function->getParam(i).type->getQualifier())
Jamie Madill185fb402015-06-12 15:48:48 -04002563 {
Olli Etuaho476197f2016-10-11 13:59:08 +01002564 error(location,
2565 "function must have the same parameter qualifiers in all of its declarations",
Jamie Madill185fb402015-06-12 15:48:48 -04002566 function->getParam(i).type->getQualifierString());
Jamie Madill185fb402015-06-12 15:48:48 -04002567 }
2568 }
2569 }
2570
2571 //
2572 // Check for previously declared variables using the same name.
2573 //
Geoff Lang13e7c7e2015-07-30 14:17:29 +00002574 TSymbol *prevSym = symbolTable.find(function->getName(), getShaderVersion());
Jamie Madill185fb402015-06-12 15:48:48 -04002575 if (prevSym)
2576 {
2577 if (!prevSym->isFunction())
2578 {
2579 error(location, "redefinition", function->getName().c_str(), "function");
Jamie Madill185fb402015-06-12 15:48:48 -04002580 }
2581 }
2582 else
2583 {
2584 // Insert the unmangled name to detect potential future redefinition as a variable.
Olli Etuaho476197f2016-10-11 13:59:08 +01002585 symbolTable.getOuterLevel()->insertUnmangled(function);
Jamie Madill185fb402015-06-12 15:48:48 -04002586 }
2587
2588 // We're at the inner scope level of the function's arguments and body statement.
2589 // Add the function prototype to the surrounding scope instead.
2590 symbolTable.getOuterLevel()->insert(function);
2591
2592 //
Jamie Madillb98c3a82015-07-23 14:26:04 -04002593 // If this is a redeclaration, it could also be a definition, in which case, we want to use the
2594 // variable names from this one, and not the one that's
Jamie Madill185fb402015-06-12 15:48:48 -04002595 // being redeclared. So, pass back up this declaration, not the one in the symbol table.
2596 //
2597 return function;
2598}
2599
Olli Etuaho9de84a52016-06-14 17:36:01 +03002600TFunction *TParseContext::parseFunctionHeader(const TPublicType &type,
2601 const TString *name,
2602 const TSourceLoc &location)
2603{
2604 if (type.qualifier != EvqGlobal && type.qualifier != EvqTemporary)
2605 {
2606 error(location, "no qualifiers allowed for function return",
2607 getQualifierString(type.qualifier));
Olli Etuaho9de84a52016-06-14 17:36:01 +03002608 }
2609 if (!type.layoutQualifier.isEmpty())
2610 {
2611 error(location, "no qualifiers allowed for function return", "layout");
Olli Etuaho9de84a52016-06-14 17:36:01 +03002612 }
Martin Radev2cc85b32016-08-05 16:22:53 +03002613 // make sure a sampler or an image is not involved as well...
Martin Radev4a9cd802016-09-01 16:51:51 +03002614 checkIsNotSampler(location, type.typeSpecifierNonArray,
2615 "samplers can't be function return values");
Martin Radev2cc85b32016-08-05 16:22:53 +03002616 checkIsNotImage(location, type.typeSpecifierNonArray, "images can't be function return values");
Olli Etuahoe29324f2016-06-15 10:58:03 +03002617 if (mShaderVersion < 300)
2618 {
2619 // Array return values are forbidden, but there's also no valid syntax for declaring array
2620 // return values in ESSL 1.00.
2621 ASSERT(type.arraySize == 0 || mDiagnostics.numErrors() > 0);
2622
2623 if (type.isStructureContainingArrays())
2624 {
2625 // ESSL 1.00.17 section 6.1 Function Definitions
2626 error(location, "structures containing arrays can't be function return values",
2627 TType(type).getCompleteString().c_str());
Olli Etuahoe29324f2016-06-15 10:58:03 +03002628 }
2629 }
Olli Etuaho9de84a52016-06-14 17:36:01 +03002630
2631 // Add the function as a prototype after parsing it (we do not support recursion)
2632 return new TFunction(name, new TType(type));
2633}
2634
Jamie Madill06145232015-05-13 13:10:01 -04002635TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn)
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002636{
Jamie Madill06145232015-05-13 13:10:01 -04002637 TPublicType publicType = publicTypeIn;
Martin Radev4a9cd802016-09-01 16:51:51 +03002638 if (publicType.isStructSpecifier())
Olli Etuahobd163f62015-11-13 12:15:38 +02002639 {
Martin Radev4a9cd802016-09-01 16:51:51 +03002640 error(publicType.getLine(), "constructor can't be a structure definition",
2641 getBasicString(publicType.getBasicType()));
Olli Etuahobd163f62015-11-13 12:15:38 +02002642 }
2643
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002644 TOperator op = EOpNull;
Martin Radev4a9cd802016-09-01 16:51:51 +03002645 if (publicType.getUserDef())
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002646 {
2647 op = EOpConstructStruct;
2648 }
2649 else
2650 {
Geoff Lang156d7192016-07-21 16:11:00 -04002651 op = sh::TypeToConstructorOperator(TType(publicType));
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002652 if (op == EOpNull)
2653 {
Martin Radev4a9cd802016-09-01 16:51:51 +03002654 error(publicType.getLine(), "cannot construct this type",
2655 getBasicString(publicType.getBasicType()));
2656 publicType.setBasicType(EbtFloat);
Jamie Madillb98c3a82015-07-23 14:26:04 -04002657 op = EOpConstructFloat;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002658 }
2659 }
2660
2661 TString tempString;
Dmitry Skiba7f17a502015-06-22 15:08:39 -07002662 const TType *type = new TType(publicType);
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002663 return new TFunction(&tempString, type, op);
2664}
2665
Jamie Madillb98c3a82015-07-23 14:26:04 -04002666// This function is used to test for the correctness of the parameters passed to various constructor
2667// functions and also convert them to the right datatype if it is allowed and required.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002668//
Olli Etuaho856c4972016-08-08 11:38:39 +03002669// Returns a node to add to the tree regardless of if an error was generated or not.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002670//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002671TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments,
Jamie Madillb98c3a82015-07-23 14:26:04 -04002672 TOperator op,
2673 TFunction *fnCall,
Arun Patole7e7e68d2015-05-22 12:02:25 +05302674 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002675{
Olli Etuaho856c4972016-08-08 11:38:39 +03002676 TType type = fnCall->getReturnType();
2677 if (type.isUnsizedArray())
2678 {
Olli Etuahobbe9fb52016-11-03 17:16:05 +00002679 if (fnCall->getParamCount() == 0)
2680 {
2681 error(line, "implicitly sized array constructor must have at least one argument", "[]");
2682 type.setArraySize(1u);
2683 return TIntermTyped::CreateZero(type);
2684 }
Olli Etuaho856c4972016-08-08 11:38:39 +03002685 type.setArraySize(static_cast<unsigned int>(fnCall->getParamCount()));
2686 }
2687 bool constType = true;
2688 for (size_t i = 0; i < fnCall->getParamCount(); ++i)
2689 {
2690 const TConstParameter &param = fnCall->getParam(i);
2691 if (param.type->getQualifier() != EvqConst)
2692 constType = false;
2693 }
2694 if (constType)
2695 type.setQualifier(EvqConst);
2696
Olli Etuaho8a176262016-08-16 14:23:01 +03002697 if (!checkConstructorArguments(line, arguments, *fnCall, op, type))
Olli Etuaho856c4972016-08-08 11:38:39 +03002698 {
2699 TIntermTyped *dummyNode = intermediate.setAggregateOperator(nullptr, op, line);
2700 dummyNode->setType(type);
2701 return dummyNode;
2702 }
Olli Etuaho15c2ac32015-11-09 15:51:43 +02002703 TIntermAggregate *constructor = arguments->getAsAggregate();
2704 ASSERT(constructor != nullptr);
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002705
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002706 // Turn the argument list itself into a constructor
Olli Etuaho15c2ac32015-11-09 15:51:43 +02002707 constructor->setOp(op);
2708 constructor->setLine(line);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02002709 ASSERT(constructor->isConstructor());
2710
2711 // Need to set type before setPrecisionFromChildren() because bool doesn't have precision.
Olli Etuaho856c4972016-08-08 11:38:39 +03002712 constructor->setType(type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002713
Olli Etuaho21203702014-11-13 16:16:21 +02002714 // Structs should not be precision qualified, the individual members may be.
2715 // Built-in types on the other hand should be precision qualified.
2716 if (op != EOpConstructStruct)
2717 {
2718 constructor->setPrecisionFromChildren();
Olli Etuaho856c4972016-08-08 11:38:39 +03002719 type.setPrecision(constructor->getPrecision());
Olli Etuaho21203702014-11-13 16:16:21 +02002720 }
2721
Olli Etuaho856c4972016-08-08 11:38:39 +03002722 constructor->setType(type);
2723
Olli Etuahof119a262016-08-19 15:54:22 +03002724 TIntermTyped *constConstructor = intermediate.foldAggregateBuiltIn(constructor, &mDiagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02002725 if (constConstructor)
2726 {
2727 return constConstructor;
2728 }
2729
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002730 return constructor;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002731}
2732
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002733//
2734// Interface/uniform blocks
2735//
Olli Etuaho13389b62016-10-16 11:48:18 +01002736TIntermDeclaration *TParseContext::addInterfaceBlock(
Martin Radev70866b82016-07-22 15:27:42 +03002737 const TTypeQualifierBuilder &typeQualifierBuilder,
2738 const TSourceLoc &nameLine,
2739 const TString &blockName,
2740 TFieldList *fieldList,
2741 const TString *instanceName,
2742 const TSourceLoc &instanceLine,
2743 TIntermTyped *arrayIndex,
2744 const TSourceLoc &arrayIndexLine)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002745{
Olli Etuaho856c4972016-08-08 11:38:39 +03002746 checkIsNotReserved(nameLine, blockName);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002747
Olli Etuaho613b9592016-09-05 12:05:53 +03002748 TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
Martin Radev70866b82016-07-22 15:27:42 +03002749
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002750 if (typeQualifier.qualifier != EvqUniform)
2751 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05302752 error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier),
2753 "interface blocks must be uniform");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002754 }
2755
Martin Radev70866b82016-07-22 15:27:42 +03002756 if (typeQualifier.invariant)
2757 {
2758 error(typeQualifier.line, "invalid qualifier on interface block member", "invariant");
2759 }
2760
Martin Radev2cc85b32016-08-05 16:22:53 +03002761 checkIsMemoryQualifierNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line);
2762
Jamie Madill099c0f32013-06-20 11:55:52 -04002763 TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier;
Olli Etuaho856c4972016-08-08 11:38:39 +03002764 checkLocationIsNotSpecified(typeQualifier.line, blockLayoutQualifier);
Jamie Madilla5efff92013-06-06 11:56:47 -04002765
Jamie Madill099c0f32013-06-20 11:55:52 -04002766 if (blockLayoutQualifier.matrixPacking == EmpUnspecified)
2767 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04002768 blockLayoutQualifier.matrixPacking = mDefaultMatrixPacking;
Jamie Madill099c0f32013-06-20 11:55:52 -04002769 }
2770
Jamie Madill1566ef72013-06-20 11:55:54 -04002771 if (blockLayoutQualifier.blockStorage == EbsUnspecified)
2772 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04002773 blockLayoutQualifier.blockStorage = mDefaultBlockStorage;
Jamie Madill1566ef72013-06-20 11:55:54 -04002774 }
2775
Olli Etuaho856c4972016-08-08 11:38:39 +03002776 checkWorkGroupSizeIsNotSpecified(nameLine, blockLayoutQualifier);
Martin Radev802abe02016-08-04 17:48:32 +03002777
Martin Radev2cc85b32016-08-05 16:22:53 +03002778 checkInternalFormatIsNotSpecified(nameLine, blockLayoutQualifier.imageInternalFormat);
2779
Arun Patole7e7e68d2015-05-22 12:02:25 +05302780 TSymbol *blockNameSymbol = new TInterfaceBlockName(&blockName);
2781 if (!symbolTable.declare(blockNameSymbol))
2782 {
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002783 error(nameLine, "redefinition", blockName.c_str(), "interface block name");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002784 }
2785
Jamie Madill98493dd2013-07-08 14:39:03 -04002786 // check for sampler types and apply layout qualifiers
Arun Patole7e7e68d2015-05-22 12:02:25 +05302787 for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
2788 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002789 TField *field = (*fieldList)[memberIndex];
Arun Patole7e7e68d2015-05-22 12:02:25 +05302790 TType *fieldType = field->type();
2791 if (IsSampler(fieldType->getBasicType()))
2792 {
2793 error(field->line(), "unsupported type", fieldType->getBasicString(),
2794 "sampler types are not allowed in interface blocks");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002795 }
2796
Martin Radev2cc85b32016-08-05 16:22:53 +03002797 if (IsImage(fieldType->getBasicType()))
2798 {
2799 error(field->line(), "unsupported type", fieldType->getBasicString(),
2800 "image types are not allowed in interface blocks");
2801 }
2802
Jamie Madill98493dd2013-07-08 14:39:03 -04002803 const TQualifier qualifier = fieldType->getQualifier();
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002804 switch (qualifier)
2805 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002806 case EvqGlobal:
2807 case EvqUniform:
2808 break;
2809 default:
2810 error(field->line(), "invalid qualifier on interface block member",
2811 getQualifierString(qualifier));
Jamie Madillb98c3a82015-07-23 14:26:04 -04002812 break;
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002813 }
Jamie Madilla5efff92013-06-06 11:56:47 -04002814
Martin Radev70866b82016-07-22 15:27:42 +03002815 if (fieldType->isInvariant())
2816 {
2817 error(field->line(), "invalid qualifier on interface block member", "invariant");
2818 }
2819
Jamie Madilla5efff92013-06-06 11:56:47 -04002820 // check layout qualifiers
Jamie Madill98493dd2013-07-08 14:39:03 -04002821 TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier();
Olli Etuaho856c4972016-08-08 11:38:39 +03002822 checkLocationIsNotSpecified(field->line(), fieldLayoutQualifier);
Jamie Madill099c0f32013-06-20 11:55:52 -04002823
Jamie Madill98493dd2013-07-08 14:39:03 -04002824 if (fieldLayoutQualifier.blockStorage != EbsUnspecified)
Jamie Madill1566ef72013-06-20 11:55:54 -04002825 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002826 error(field->line(), "invalid layout qualifier:",
2827 getBlockStorageString(fieldLayoutQualifier.blockStorage), "cannot be used here");
Jamie Madill1566ef72013-06-20 11:55:54 -04002828 }
2829
Jamie Madill98493dd2013-07-08 14:39:03 -04002830 if (fieldLayoutQualifier.matrixPacking == EmpUnspecified)
Jamie Madill099c0f32013-06-20 11:55:52 -04002831 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002832 fieldLayoutQualifier.matrixPacking = blockLayoutQualifier.matrixPacking;
Jamie Madill099c0f32013-06-20 11:55:52 -04002833 }
Olli Etuahofb6ab2c2015-07-09 20:55:28 +03002834 else if (!fieldType->isMatrix() && fieldType->getBasicType() != EbtStruct)
Jamie Madill099c0f32013-06-20 11:55:52 -04002835 {
Olli Etuahofb6ab2c2015-07-09 20:55:28 +03002836 warning(field->line(), "extraneous layout qualifier:",
Jamie Madillb98c3a82015-07-23 14:26:04 -04002837 getMatrixPackingString(fieldLayoutQualifier.matrixPacking),
2838 "only has an effect on matrix types");
Jamie Madill099c0f32013-06-20 11:55:52 -04002839 }
2840
Jamie Madill98493dd2013-07-08 14:39:03 -04002841 fieldType->setLayoutQualifier(fieldLayoutQualifier);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002842 }
2843
Jamie Madill98493dd2013-07-08 14:39:03 -04002844 // add array index
Olli Etuaho856c4972016-08-08 11:38:39 +03002845 unsigned int arraySize = 0;
2846 if (arrayIndex != nullptr)
Jamie Madill98493dd2013-07-08 14:39:03 -04002847 {
Olli Etuaho856c4972016-08-08 11:38:39 +03002848 arraySize = checkIsValidArraySize(arrayIndexLine, arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04002849 }
2850
Jamie Madillb98c3a82015-07-23 14:26:04 -04002851 TInterfaceBlock *interfaceBlock =
2852 new TInterfaceBlock(&blockName, fieldList, instanceName, arraySize, blockLayoutQualifier);
2853 TType interfaceBlockType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier,
2854 arraySize);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002855
2856 TString symbolName = "";
Jamie Madillb98c3a82015-07-23 14:26:04 -04002857 int symbolId = 0;
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002858
Jamie Madill98493dd2013-07-08 14:39:03 -04002859 if (!instanceName)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002860 {
2861 // define symbols for the members of the interface block
Jamie Madill98493dd2013-07-08 14:39:03 -04002862 for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
2863 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002864 TField *field = (*fieldList)[memberIndex];
Arun Patole7e7e68d2015-05-22 12:02:25 +05302865 TType *fieldType = field->type();
Jamie Madill98493dd2013-07-08 14:39:03 -04002866
2867 // set parent pointer of the field variable
2868 fieldType->setInterfaceBlock(interfaceBlock);
2869
Arun Patole7e7e68d2015-05-22 12:02:25 +05302870 TVariable *fieldVariable = new TVariable(&field->name(), *fieldType);
Jamie Madill98493dd2013-07-08 14:39:03 -04002871 fieldVariable->setQualifier(typeQualifier.qualifier);
2872
Arun Patole7e7e68d2015-05-22 12:02:25 +05302873 if (!symbolTable.declare(fieldVariable))
2874 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002875 error(field->line(), "redefinition", field->name().c_str(),
2876 "interface block member name");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002877 }
2878 }
2879 }
2880 else
2881 {
Olli Etuaho856c4972016-08-08 11:38:39 +03002882 checkIsNotReserved(instanceLine, *instanceName);
Olli Etuahoe0f623a2015-07-10 11:58:30 +03002883
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002884 // add a symbol for this interface block
Arun Patole7e7e68d2015-05-22 12:02:25 +05302885 TVariable *instanceTypeDef = new TVariable(instanceName, interfaceBlockType, false);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002886 instanceTypeDef->setQualifier(typeQualifier.qualifier);
Jamie Madill98493dd2013-07-08 14:39:03 -04002887
Arun Patole7e7e68d2015-05-22 12:02:25 +05302888 if (!symbolTable.declare(instanceTypeDef))
2889 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002890 error(instanceLine, "redefinition", instanceName->c_str(),
2891 "interface block instance name");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002892 }
2893
Jamie Madillb98c3a82015-07-23 14:26:04 -04002894 symbolId = instanceTypeDef->getUniqueId();
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002895 symbolName = instanceTypeDef->getName();
2896 }
2897
Olli Etuaho13389b62016-10-16 11:48:18 +01002898 TIntermSymbol *blockSymbol =
2899 intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line);
2900 TIntermDeclaration *declaration = new TIntermDeclaration();
2901 declaration->appendDeclarator(blockSymbol);
2902 declaration->setLine(nameLine);
Jamie Madill98493dd2013-07-08 14:39:03 -04002903
2904 exitStructDeclaration();
Olli Etuaho13389b62016-10-16 11:48:18 +01002905 return declaration;
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002906}
2907
Olli Etuaho383b7912016-08-05 11:22:59 +03002908void TParseContext::enterStructDeclaration(const TSourceLoc &line, const TString &identifier)
kbr@chromium.org476541f2011-10-27 21:14:51 +00002909{
Jamie Madill6e06b1f2015-05-14 10:01:17 -04002910 ++mStructNestingLevel;
kbr@chromium.org476541f2011-10-27 21:14:51 +00002911
2912 // Embedded structure definitions are not supported per GLSL ES spec.
2913 // They aren't allowed in GLSL either, but we need to detect this here
2914 // so we don't rely on the GLSL compiler to catch it.
Arun Patole7e7e68d2015-05-22 12:02:25 +05302915 if (mStructNestingLevel > 1)
2916 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002917 error(line, "", "Embedded struct definitions are not allowed");
kbr@chromium.org476541f2011-10-27 21:14:51 +00002918 }
kbr@chromium.org476541f2011-10-27 21:14:51 +00002919}
2920
2921void TParseContext::exitStructDeclaration()
2922{
Jamie Madill6e06b1f2015-05-14 10:01:17 -04002923 --mStructNestingLevel;
kbr@chromium.org476541f2011-10-27 21:14:51 +00002924}
2925
Olli Etuaho8a176262016-08-16 14:23:01 +03002926void TParseContext::checkIsBelowStructNestingLimit(const TSourceLoc &line, const TField &field)
kbr@chromium.org476541f2011-10-27 21:14:51 +00002927{
Jamie Madillacb4b812016-11-07 13:50:29 -05002928 if (!sh::IsWebGLBasedSpec(mShaderSpec))
Arun Patole7e7e68d2015-05-22 12:02:25 +05302929 {
Olli Etuaho8a176262016-08-16 14:23:01 +03002930 return;
kbr@chromium.org476541f2011-10-27 21:14:51 +00002931 }
2932
Arun Patole7e7e68d2015-05-22 12:02:25 +05302933 if (field.type()->getBasicType() != EbtStruct)
2934 {
Olli Etuaho8a176262016-08-16 14:23:01 +03002935 return;
kbr@chromium.org476541f2011-10-27 21:14:51 +00002936 }
2937
2938 // We're already inside a structure definition at this point, so add
2939 // one to the field's struct nesting.
Arun Patole7e7e68d2015-05-22 12:02:25 +05302940 if (1 + field.type()->getDeepestStructNesting() > kWebGLMaxStructNesting)
2941 {
Jamie Madill41a49272014-03-18 16:10:13 -04002942 std::stringstream reasonStream;
Jamie Madillb98c3a82015-07-23 14:26:04 -04002943 reasonStream << "Reference of struct type " << field.type()->getStruct()->name().c_str()
2944 << " exceeds maximum allowed nesting level of " << kWebGLMaxStructNesting;
Jamie Madill41a49272014-03-18 16:10:13 -04002945 std::string reason = reasonStream.str();
2946 error(line, reason.c_str(), field.name().c_str(), "");
Olli Etuaho8a176262016-08-16 14:23:01 +03002947 return;
kbr@chromium.org476541f2011-10-27 21:14:51 +00002948 }
kbr@chromium.org476541f2011-10-27 21:14:51 +00002949}
2950
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00002951//
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002952// Parse an array index expression
2953//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002954TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression,
2955 const TSourceLoc &location,
Arun Patole7e7e68d2015-05-22 12:02:25 +05302956 TIntermTyped *indexExpression)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002957{
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002958 if (!baseExpression->isArray() && !baseExpression->isMatrix() && !baseExpression->isVector())
2959 {
2960 if (baseExpression->getAsSymbolNode())
2961 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05302962 error(location, " left of '[' is not of type array, matrix, or vector ",
2963 baseExpression->getAsSymbolNode()->getSymbol().c_str());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002964 }
2965 else
2966 {
2967 error(location, " left of '[' is not of type array, matrix, or vector ", "expression");
2968 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03002969
2970 TConstantUnion *unionArray = new TConstantUnion[1];
2971 unionArray->setFConst(0.0f);
2972 return intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst),
2973 location);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002974 }
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002975
Jamie Madill21c1e452014-12-29 11:33:41 -05002976 TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion();
2977
Olli Etuaho36b05142015-11-12 13:10:42 +02002978 // TODO(oetuaho@nvidia.com): Get rid of indexConstantUnion == nullptr below once ANGLE is able
2979 // to constant fold all constant expressions. Right now we don't allow indexing interface blocks
2980 // or fragment outputs with expressions that ANGLE is not able to constant fold, even if the
2981 // index is a constant expression.
2982 if (indexExpression->getQualifier() != EvqConst || indexConstantUnion == nullptr)
2983 {
2984 if (baseExpression->isInterfaceBlock())
2985 {
2986 error(
2987 location, "", "[",
2988 "array indexes for interface blocks arrays must be constant integral expressions");
Olli Etuaho36b05142015-11-12 13:10:42 +02002989 }
2990 else if (baseExpression->getQualifier() == EvqFragmentOut)
2991 {
2992 error(location, "", "[",
2993 "array indexes for fragment outputs must be constant integral expressions");
Olli Etuaho36b05142015-11-12 13:10:42 +02002994 }
Olli Etuaho3e960462015-11-12 15:58:39 +02002995 else if (mShaderSpec == SH_WEBGL2_SPEC && baseExpression->getQualifier() == EvqFragData)
2996 {
2997 error(location, "", "[", "array index for gl_FragData must be constant zero");
Olli Etuaho3e960462015-11-12 15:58:39 +02002998 }
Olli Etuaho36b05142015-11-12 13:10:42 +02002999 }
3000
Olli Etuaho7c3848e2015-11-04 13:19:17 +02003001 if (indexConstantUnion)
Jamie Madill7164cf42013-07-08 13:30:59 -04003002 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003003 // If an out-of-range index is not qualified as constant, the behavior in the spec is
3004 // undefined. This applies even if ANGLE has been able to constant fold it (ANGLE may
3005 // constant fold expressions that are not constant expressions). The most compatible way to
3006 // handle this case is to report a warning instead of an error and force the index to be in
3007 // the correct range.
Olli Etuaho7c3848e2015-11-04 13:19:17 +02003008 bool outOfRangeIndexIsError = indexExpression->getQualifier() == EvqConst;
Jamie Madill21c1e452014-12-29 11:33:41 -05003009 int index = indexConstantUnion->getIConst(0);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003010
3011 int safeIndex = -1;
3012
3013 if (baseExpression->isArray())
Jamie Madill7164cf42013-07-08 13:30:59 -04003014 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003015 if (baseExpression->getQualifier() == EvqFragData && index > 0)
Olli Etuaho90892fb2016-07-14 14:44:51 +03003016 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003017 if (mShaderSpec == SH_WEBGL2_SPEC)
3018 {
3019 // Error has been already generated if index is not const.
3020 if (indexExpression->getQualifier() == EvqConst)
3021 {
3022 error(location, "", "[",
3023 "array index for gl_FragData must be constant zero");
3024 }
3025 safeIndex = 0;
3026 }
3027 else if (!isExtensionEnabled("GL_EXT_draw_buffers"))
3028 {
3029 outOfRangeError(outOfRangeIndexIsError, location, "", "[",
3030 "array index for gl_FragData must be zero when "
3031 "GL_EXT_draw_buffers is disabled");
3032 safeIndex = 0;
3033 }
Olli Etuaho90892fb2016-07-14 14:44:51 +03003034 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003035 // Only do generic out-of-range check if similar error hasn't already been reported.
3036 if (safeIndex < 0)
Olli Etuaho90892fb2016-07-14 14:44:51 +03003037 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003038 safeIndex = checkIndexOutOfRange(outOfRangeIndexIsError, location, index,
3039 baseExpression->getArraySize(),
3040 "array index out of range", "[]");
3041 }
3042 }
3043 else if (baseExpression->isMatrix())
3044 {
3045 safeIndex = checkIndexOutOfRange(outOfRangeIndexIsError, location, index,
Olli Etuaho90892fb2016-07-14 14:44:51 +03003046 baseExpression->getType().getCols(),
3047 "matrix field selection out of range", "[]");
Jamie Madill7164cf42013-07-08 13:30:59 -04003048 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003049 else if (baseExpression->isVector())
Jamie Madill7164cf42013-07-08 13:30:59 -04003050 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003051 safeIndex = checkIndexOutOfRange(outOfRangeIndexIsError, location, index,
3052 baseExpression->getType().getNominalSize(),
3053 "vector field selection out of range", "[]");
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003054 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003055
3056 ASSERT(safeIndex >= 0);
3057 // Data of constant unions can't be changed, because it may be shared with other
3058 // constant unions or even builtins, like gl_MaxDrawBuffers. Instead use a new
3059 // sanitized object.
3060 if (safeIndex != index)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003061 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003062 TConstantUnion *safeConstantUnion = new TConstantUnion();
3063 safeConstantUnion->setIConst(safeIndex);
3064 indexConstantUnion->replaceConstantUnion(safeConstantUnion);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003065 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003066
3067 return intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location,
3068 &mDiagnostics);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003069 }
Jamie Madill7164cf42013-07-08 13:30:59 -04003070 else
3071 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003072 return intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location,
3073 &mDiagnostics);
Jamie Madill7164cf42013-07-08 13:30:59 -04003074 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003075}
3076
Olli Etuaho90892fb2016-07-14 14:44:51 +03003077int TParseContext::checkIndexOutOfRange(bool outOfRangeIndexIsError,
3078 const TSourceLoc &location,
3079 int index,
3080 int arraySize,
3081 const char *reason,
3082 const char *token)
3083{
3084 if (index >= arraySize || index < 0)
3085 {
3086 std::stringstream extraInfoStream;
3087 extraInfoStream << "'" << index << "'";
3088 std::string extraInfo = extraInfoStream.str();
3089 outOfRangeError(outOfRangeIndexIsError, location, reason, token, extraInfo.c_str());
3090 if (index < 0)
3091 {
3092 return 0;
3093 }
3094 else
3095 {
3096 return arraySize - 1;
3097 }
3098 }
3099 return index;
3100}
3101
Jamie Madillb98c3a82015-07-23 14:26:04 -04003102TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpression,
3103 const TSourceLoc &dotLocation,
3104 const TString &fieldString,
3105 const TSourceLoc &fieldLocation)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003106{
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003107 if (baseExpression->isArray())
3108 {
3109 error(fieldLocation, "cannot apply dot operator to an array", ".");
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003110 return baseExpression;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003111 }
3112
3113 if (baseExpression->isVector())
3114 {
3115 TVectorFields fields;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003116 if (!parseVectorFields(fieldString, baseExpression->getNominalSize(), fields,
3117 fieldLocation))
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003118 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003119 fields.num = 1;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003120 fields.offsets[0] = 0;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003121 }
3122
Olli Etuahob6fa0432016-09-28 16:28:05 +01003123 return TIntermediate::AddSwizzle(baseExpression, fields, dotLocation);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003124 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003125 else if (baseExpression->getBasicType() == EbtStruct)
3126 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05303127 const TFieldList &fields = baseExpression->getType().getStruct()->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04003128 if (fields.empty())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003129 {
3130 error(dotLocation, "structure has no fields", "Internal Error");
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003131 return baseExpression;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003132 }
3133 else
3134 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003135 bool fieldFound = false;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003136 unsigned int i;
Jamie Madill98493dd2013-07-08 14:39:03 -04003137 for (i = 0; i < fields.size(); ++i)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003138 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003139 if (fields[i]->name() == fieldString)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003140 {
3141 fieldFound = true;
3142 break;
3143 }
3144 }
3145 if (fieldFound)
3146 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003147 TIntermTyped *index = TIntermTyped::CreateIndexNode(i);
3148 index->setLine(fieldLocation);
3149 return intermediate.addIndex(EOpIndexDirectStruct, baseExpression, index,
3150 dotLocation, &mDiagnostics);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003151 }
3152 else
3153 {
3154 error(dotLocation, " no such field in structure", fieldString.c_str());
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003155 return baseExpression;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003156 }
3157 }
3158 }
Jamie Madill98493dd2013-07-08 14:39:03 -04003159 else if (baseExpression->isInterfaceBlock())
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003160 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05303161 const TFieldList &fields = baseExpression->getType().getInterfaceBlock()->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04003162 if (fields.empty())
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003163 {
3164 error(dotLocation, "interface block has no fields", "Internal Error");
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003165 return baseExpression;
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003166 }
3167 else
3168 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003169 bool fieldFound = false;
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003170 unsigned int i;
Jamie Madill98493dd2013-07-08 14:39:03 -04003171 for (i = 0; i < fields.size(); ++i)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003172 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003173 if (fields[i]->name() == fieldString)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003174 {
3175 fieldFound = true;
3176 break;
3177 }
3178 }
3179 if (fieldFound)
3180 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003181 TIntermTyped *index = TIntermTyped::CreateIndexNode(i);
3182 index->setLine(fieldLocation);
3183 return intermediate.addIndex(EOpIndexDirectInterfaceBlock, baseExpression, index,
3184 dotLocation, &mDiagnostics);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003185 }
3186 else
3187 {
3188 error(dotLocation, " no such field in interface block", fieldString.c_str());
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003189 return baseExpression;
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003190 }
3191 }
3192 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003193 else
3194 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04003195 if (mShaderVersion < 300)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003196 {
Olli Etuaho56193ce2015-08-12 15:55:09 +03003197 error(dotLocation, " field selection requires structure or vector on left hand side",
Arun Patole7e7e68d2015-05-22 12:02:25 +05303198 fieldString.c_str());
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003199 }
3200 else
3201 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05303202 error(dotLocation,
Olli Etuaho56193ce2015-08-12 15:55:09 +03003203 " field selection requires structure, vector, or interface block on left hand "
3204 "side",
Arun Patole7e7e68d2015-05-22 12:02:25 +05303205 fieldString.c_str());
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003206 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003207 return baseExpression;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003208 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003209}
3210
Jamie Madillb98c3a82015-07-23 14:26:04 -04003211TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType,
3212 const TSourceLoc &qualifierTypeLine)
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003213{
Martin Radev802abe02016-08-04 17:48:32 +03003214 TLayoutQualifier qualifier = TLayoutQualifier::create();
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003215
3216 if (qualifierType == "shared")
3217 {
Jamie Madillacb4b812016-11-07 13:50:29 -05003218 if (sh::IsWebGLBasedSpec(mShaderSpec))
Olli Etuahof0173152016-10-17 09:05:03 -07003219 {
3220 error(qualifierTypeLine, "Only std140 layout is allowed in WebGL", "shared");
3221 }
Jamie Madilla5efff92013-06-06 11:56:47 -04003222 qualifier.blockStorage = EbsShared;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003223 }
3224 else if (qualifierType == "packed")
3225 {
Jamie Madillacb4b812016-11-07 13:50:29 -05003226 if (sh::IsWebGLBasedSpec(mShaderSpec))
Olli Etuahof0173152016-10-17 09:05:03 -07003227 {
3228 error(qualifierTypeLine, "Only std140 layout is allowed in WebGL", "packed");
3229 }
Jamie Madilla5efff92013-06-06 11:56:47 -04003230 qualifier.blockStorage = EbsPacked;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003231 }
3232 else if (qualifierType == "std140")
3233 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003234 qualifier.blockStorage = EbsStd140;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003235 }
3236 else if (qualifierType == "row_major")
3237 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003238 qualifier.matrixPacking = EmpRowMajor;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003239 }
3240 else if (qualifierType == "column_major")
3241 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003242 qualifier.matrixPacking = EmpColumnMajor;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003243 }
3244 else if (qualifierType == "location")
3245 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003246 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(),
3247 "location requires an argument");
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003248 }
Martin Radev2cc85b32016-08-05 16:22:53 +03003249 else if (qualifierType == "rgba32f")
3250 {
3251 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3252 qualifier.imageInternalFormat = EiifRGBA32F;
3253 }
3254 else if (qualifierType == "rgba16f")
3255 {
3256 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3257 qualifier.imageInternalFormat = EiifRGBA16F;
3258 }
3259 else if (qualifierType == "r32f")
3260 {
3261 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3262 qualifier.imageInternalFormat = EiifR32F;
3263 }
3264 else if (qualifierType == "rgba8")
3265 {
3266 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3267 qualifier.imageInternalFormat = EiifRGBA8;
3268 }
3269 else if (qualifierType == "rgba8_snorm")
3270 {
3271 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3272 qualifier.imageInternalFormat = EiifRGBA8_SNORM;
3273 }
3274 else if (qualifierType == "rgba32i")
3275 {
3276 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3277 qualifier.imageInternalFormat = EiifRGBA32I;
3278 }
3279 else if (qualifierType == "rgba16i")
3280 {
3281 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3282 qualifier.imageInternalFormat = EiifRGBA16I;
3283 }
3284 else if (qualifierType == "rgba8i")
3285 {
3286 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3287 qualifier.imageInternalFormat = EiifRGBA8I;
3288 }
3289 else if (qualifierType == "r32i")
3290 {
3291 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3292 qualifier.imageInternalFormat = EiifR32I;
3293 }
3294 else if (qualifierType == "rgba32ui")
3295 {
3296 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3297 qualifier.imageInternalFormat = EiifRGBA32UI;
3298 }
3299 else if (qualifierType == "rgba16ui")
3300 {
3301 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3302 qualifier.imageInternalFormat = EiifRGBA16UI;
3303 }
3304 else if (qualifierType == "rgba8ui")
3305 {
3306 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3307 qualifier.imageInternalFormat = EiifRGBA8UI;
3308 }
3309 else if (qualifierType == "r32ui")
3310 {
3311 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3312 qualifier.imageInternalFormat = EiifR32UI;
3313 }
3314
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003315 else
3316 {
3317 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str());
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003318 }
3319
Jamie Madilla5efff92013-06-06 11:56:47 -04003320 return qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003321}
3322
Martin Radev802abe02016-08-04 17:48:32 +03003323void TParseContext::parseLocalSize(const TString &qualifierType,
3324 const TSourceLoc &qualifierTypeLine,
3325 int intValue,
3326 const TSourceLoc &intValueLine,
3327 const std::string &intValueString,
3328 size_t index,
Martin Radev4c4c8e72016-08-04 12:25:34 +03003329 sh::WorkGroupSize *localSize)
Martin Radev802abe02016-08-04 17:48:32 +03003330{
Olli Etuaho856c4972016-08-08 11:38:39 +03003331 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
Martin Radev802abe02016-08-04 17:48:32 +03003332 if (intValue < 1)
3333 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03003334 std::string errorMessage = std::string(getWorkGroupSizeString(index)) + " must be positive";
Martin Radev802abe02016-08-04 17:48:32 +03003335 error(intValueLine, "out of range:", intValueString.c_str(), errorMessage.c_str());
Martin Radev802abe02016-08-04 17:48:32 +03003336 }
3337 (*localSize)[index] = intValue;
3338}
3339
Jamie Madillb98c3a82015-07-23 14:26:04 -04003340TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType,
3341 const TSourceLoc &qualifierTypeLine,
Jamie Madillb98c3a82015-07-23 14:26:04 -04003342 int intValue,
Arun Patole7e7e68d2015-05-22 12:02:25 +05303343 const TSourceLoc &intValueLine)
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003344{
Martin Radev802abe02016-08-04 17:48:32 +03003345 TLayoutQualifier qualifier = TLayoutQualifier::create();
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003346
Martin Radev802abe02016-08-04 17:48:32 +03003347 std::string intValueString = Str(intValue);
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003348
Martin Radev802abe02016-08-04 17:48:32 +03003349 if (qualifierType == "location")
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003350 {
Jamie Madill05a80ce2013-06-20 11:55:49 -04003351 // must check that location is non-negative
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003352 if (intValue < 0)
3353 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003354 error(intValueLine, "out of range:", intValueString.c_str(),
3355 "location must be non-negative");
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003356 }
3357 else
3358 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003359 qualifier.location = intValue;
Olli Etuaho87d410c2016-09-05 13:33:26 +03003360 qualifier.locationsSpecified = 1;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003361 }
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003362 }
Martin Radev802abe02016-08-04 17:48:32 +03003363 else if (qualifierType == "local_size_x")
3364 {
3365 parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 0u,
3366 &qualifier.localSize);
3367 }
3368 else if (qualifierType == "local_size_y")
3369 {
3370 parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 1u,
3371 &qualifier.localSize);
3372 }
3373 else if (qualifierType == "local_size_z")
3374 {
3375 parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 2u,
3376 &qualifier.localSize);
3377 }
3378 else
3379 {
3380 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str());
Martin Radev802abe02016-08-04 17:48:32 +03003381 }
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003382
Jamie Madilla5efff92013-06-06 11:56:47 -04003383 return qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003384}
3385
Olli Etuaho613b9592016-09-05 12:05:53 +03003386TTypeQualifierBuilder *TParseContext::createTypeQualifierBuilder(const TSourceLoc &loc)
3387{
3388 return new TTypeQualifierBuilder(
3389 new TStorageQualifierWrapper(symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary, loc),
3390 mShaderVersion);
3391}
3392
Jamie Madillb98c3a82015-07-23 14:26:04 -04003393TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier,
Martin Radev802abe02016-08-04 17:48:32 +03003394 TLayoutQualifier rightQualifier,
3395 const TSourceLoc &rightQualifierLocation)
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003396{
Martin Radevc28888b2016-07-22 15:27:42 +03003397 return sh::JoinLayoutQualifiers(leftQualifier, rightQualifier, rightQualifierLocation,
3398 &mDiagnostics);
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003399}
3400
Martin Radev70866b82016-07-22 15:27:42 +03003401TFieldList *TParseContext::addStructDeclaratorListWithQualifiers(
3402 const TTypeQualifierBuilder &typeQualifierBuilder,
3403 TPublicType *typeSpecifier,
3404 TFieldList *fieldList)
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003405{
Olli Etuaho613b9592016-09-05 12:05:53 +03003406 TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003407
Martin Radev70866b82016-07-22 15:27:42 +03003408 typeSpecifier->qualifier = typeQualifier.qualifier;
3409 typeSpecifier->layoutQualifier = typeQualifier.layoutQualifier;
Martin Radev2cc85b32016-08-05 16:22:53 +03003410 typeSpecifier->memoryQualifier = typeQualifier.memoryQualifier;
Martin Radev70866b82016-07-22 15:27:42 +03003411 typeSpecifier->invariant = typeQualifier.invariant;
3412 if (typeQualifier.precision != EbpUndefined)
Arun Patole7e7e68d2015-05-22 12:02:25 +05303413 {
Martin Radev70866b82016-07-22 15:27:42 +03003414 typeSpecifier->precision = typeQualifier.precision;
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003415 }
Martin Radev70866b82016-07-22 15:27:42 +03003416 return addStructDeclaratorList(*typeSpecifier, fieldList);
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003417}
3418
Jamie Madillb98c3a82015-07-23 14:26:04 -04003419TFieldList *TParseContext::addStructDeclaratorList(const TPublicType &typeSpecifier,
3420 TFieldList *fieldList)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003421{
Martin Radev4a9cd802016-09-01 16:51:51 +03003422 checkPrecisionSpecified(typeSpecifier.getLine(), typeSpecifier.precision,
3423 typeSpecifier.getBasicType());
Martin Radev70866b82016-07-22 15:27:42 +03003424
Martin Radev4a9cd802016-09-01 16:51:51 +03003425 checkIsNonVoid(typeSpecifier.getLine(), (*fieldList)[0]->name(), typeSpecifier.getBasicType());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003426
Martin Radev4a9cd802016-09-01 16:51:51 +03003427 checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), typeSpecifier.layoutQualifier);
Martin Radev802abe02016-08-04 17:48:32 +03003428
Arun Patole7e7e68d2015-05-22 12:02:25 +05303429 for (unsigned int i = 0; i < fieldList->size(); ++i)
3430 {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003431 //
3432 // Careful not to replace already known aspects of type, like array-ness
3433 //
Arun Patole7e7e68d2015-05-22 12:02:25 +05303434 TType *type = (*fieldList)[i]->type();
Martin Radev4a9cd802016-09-01 16:51:51 +03003435 type->setBasicType(typeSpecifier.getBasicType());
3436 type->setPrimarySize(typeSpecifier.getPrimarySize());
3437 type->setSecondarySize(typeSpecifier.getSecondarySize());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003438 type->setPrecision(typeSpecifier.precision);
3439 type->setQualifier(typeSpecifier.qualifier);
Jamie Madilla5efff92013-06-06 11:56:47 -04003440 type->setLayoutQualifier(typeSpecifier.layoutQualifier);
Martin Radev2cc85b32016-08-05 16:22:53 +03003441 type->setMemoryQualifier(typeSpecifier.memoryQualifier);
Martin Radev70866b82016-07-22 15:27:42 +03003442 type->setInvariant(typeSpecifier.invariant);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003443
3444 // don't allow arrays of arrays
Arun Patole7e7e68d2015-05-22 12:02:25 +05303445 if (type->isArray())
3446 {
Martin Radev4a9cd802016-09-01 16:51:51 +03003447 checkIsValidTypeForArray(typeSpecifier.getLine(), typeSpecifier);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003448 }
3449 if (typeSpecifier.array)
Olli Etuaho856c4972016-08-08 11:38:39 +03003450 type->setArraySize(static_cast<unsigned int>(typeSpecifier.arraySize));
Martin Radev4a9cd802016-09-01 16:51:51 +03003451 if (typeSpecifier.getUserDef())
Arun Patole7e7e68d2015-05-22 12:02:25 +05303452 {
Martin Radev4a9cd802016-09-01 16:51:51 +03003453 type->setStruct(typeSpecifier.getUserDef()->getStruct());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003454 }
3455
Martin Radev4a9cd802016-09-01 16:51:51 +03003456 checkIsBelowStructNestingLimit(typeSpecifier.getLine(), *(*fieldList)[i]);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003457 }
3458
Jamie Madill98493dd2013-07-08 14:39:03 -04003459 return fieldList;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003460}
3461
Martin Radev4a9cd802016-09-01 16:51:51 +03003462TTypeSpecifierNonArray TParseContext::addStructure(const TSourceLoc &structLine,
3463 const TSourceLoc &nameLine,
3464 const TString *structName,
3465 TFieldList *fieldList)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003466{
Arun Patole7e7e68d2015-05-22 12:02:25 +05303467 TStructure *structure = new TStructure(structName, fieldList);
Jamie Madillb98c3a82015-07-23 14:26:04 -04003468 TType *structureType = new TType(structure);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003469
Jamie Madill9b820842015-02-12 10:40:10 -05003470 // Store a bool in the struct if we're at global scope, to allow us to
3471 // skip the local struct scoping workaround in HLSL.
Jamie Madill9b820842015-02-12 10:40:10 -05003472 structure->setAtGlobalScope(symbolTable.atGlobalLevel());
Jamie Madillbfa91f42014-06-05 15:45:18 -04003473
Jamie Madill98493dd2013-07-08 14:39:03 -04003474 if (!structName->empty())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003475 {
Olli Etuaho856c4972016-08-08 11:38:39 +03003476 checkIsNotReserved(nameLine, *structName);
Arun Patole7e7e68d2015-05-22 12:02:25 +05303477 TVariable *userTypeDef = new TVariable(structName, *structureType, true);
3478 if (!symbolTable.declare(userTypeDef))
3479 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003480 error(nameLine, "redefinition", structName->c_str(), "struct");
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003481 }
3482 }
3483
3484 // ensure we do not specify any storage qualifiers on the struct members
Jamie Madill98493dd2013-07-08 14:39:03 -04003485 for (unsigned int typeListIndex = 0; typeListIndex < fieldList->size(); typeListIndex++)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003486 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003487 const TField &field = *(*fieldList)[typeListIndex];
Jamie Madill98493dd2013-07-08 14:39:03 -04003488 const TQualifier qualifier = field.type()->getQualifier();
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003489 switch (qualifier)
3490 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003491 case EvqGlobal:
3492 case EvqTemporary:
3493 break;
3494 default:
3495 error(field.line(), "invalid qualifier on struct member",
3496 getQualifierString(qualifier));
Jamie Madillb98c3a82015-07-23 14:26:04 -04003497 break;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003498 }
Martin Radev70866b82016-07-22 15:27:42 +03003499 if (field.type()->isInvariant())
3500 {
3501 error(field.line(), "invalid qualifier on struct member", "invariant");
3502 }
Martin Radev2cc85b32016-08-05 16:22:53 +03003503 if (IsImage(field.type()->getBasicType()))
3504 {
3505 error(field.line(), "disallowed type in struct", field.type()->getBasicString());
3506 }
3507
3508 checkIsMemoryQualifierNotSpecified(field.type()->getMemoryQualifier(), field.line());
Martin Radev70866b82016-07-22 15:27:42 +03003509
3510 checkLocationIsNotSpecified(field.line(), field.type()->getLayoutQualifier());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003511 }
3512
Martin Radev4a9cd802016-09-01 16:51:51 +03003513 TTypeSpecifierNonArray typeSpecifierNonArray;
3514 typeSpecifierNonArray.initialize(EbtStruct, structLine);
3515 typeSpecifierNonArray.userDef = structureType;
3516 typeSpecifierNonArray.isStructSpecifier = true;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003517 exitStructDeclaration();
3518
Martin Radev4a9cd802016-09-01 16:51:51 +03003519 return typeSpecifierNonArray;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003520}
3521
Jamie Madillb98c3a82015-07-23 14:26:04 -04003522TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init,
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01003523 TIntermBlock *statementList,
Jamie Madillb98c3a82015-07-23 14:26:04 -04003524 const TSourceLoc &loc)
Olli Etuahoa3a36662015-02-17 13:46:51 +02003525{
Olli Etuaho53f076f2015-02-20 10:55:14 +02003526 TBasicType switchType = init->getBasicType();
Jamie Madillb98c3a82015-07-23 14:26:04 -04003527 if ((switchType != EbtInt && switchType != EbtUInt) || init->isMatrix() || init->isArray() ||
Olli Etuaho53f076f2015-02-20 10:55:14 +02003528 init->isVector())
3529 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003530 error(init->getLine(), "init-expression in a switch statement must be a scalar integer",
3531 "switch");
Olli Etuaho53f076f2015-02-20 10:55:14 +02003532 return nullptr;
3533 }
3534
Olli Etuahoac5274d2015-02-20 10:19:08 +02003535 if (statementList)
3536 {
3537 if (!ValidateSwitch::validate(switchType, this, statementList, loc))
3538 {
Olli Etuahoac5274d2015-02-20 10:19:08 +02003539 return nullptr;
3540 }
3541 }
3542
Olli Etuahoa3a36662015-02-17 13:46:51 +02003543 TIntermSwitch *node = intermediate.addSwitch(init, statementList, loc);
3544 if (node == nullptr)
3545 {
3546 error(loc, "erroneous switch statement", "switch");
Olli Etuahoa3a36662015-02-17 13:46:51 +02003547 return nullptr;
3548 }
3549 return node;
3550}
3551
3552TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &loc)
3553{
Olli Etuaho53f076f2015-02-20 10:55:14 +02003554 if (mSwitchNestingLevel == 0)
3555 {
3556 error(loc, "case labels need to be inside switch statements", "case");
Olli Etuaho53f076f2015-02-20 10:55:14 +02003557 return nullptr;
3558 }
3559 if (condition == nullptr)
3560 {
3561 error(loc, "case label must have a condition", "case");
Olli Etuaho53f076f2015-02-20 10:55:14 +02003562 return nullptr;
3563 }
3564 if ((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) ||
Jamie Madillb98c3a82015-07-23 14:26:04 -04003565 condition->isMatrix() || condition->isArray() || condition->isVector())
Olli Etuaho53f076f2015-02-20 10:55:14 +02003566 {
3567 error(condition->getLine(), "case label must be a scalar integer", "case");
Olli Etuaho53f076f2015-02-20 10:55:14 +02003568 }
3569 TIntermConstantUnion *conditionConst = condition->getAsConstantUnion();
Olli Etuaho7c3848e2015-11-04 13:19:17 +02003570 // TODO(oetuaho@nvidia.com): Get rid of the conditionConst == nullptr check once all constant
3571 // expressions can be folded. Right now we don't allow constant expressions that ANGLE can't
3572 // fold in case labels.
3573 if (condition->getQualifier() != EvqConst || conditionConst == nullptr)
Olli Etuaho53f076f2015-02-20 10:55:14 +02003574 {
3575 error(condition->getLine(), "case label must be constant", "case");
Olli Etuaho53f076f2015-02-20 10:55:14 +02003576 }
Olli Etuahoa3a36662015-02-17 13:46:51 +02003577 TIntermCase *node = intermediate.addCase(condition, loc);
3578 if (node == nullptr)
3579 {
3580 error(loc, "erroneous case statement", "case");
Olli Etuahoa3a36662015-02-17 13:46:51 +02003581 return nullptr;
3582 }
3583 return node;
3584}
3585
3586TIntermCase *TParseContext::addDefault(const TSourceLoc &loc)
3587{
Olli Etuaho53f076f2015-02-20 10:55:14 +02003588 if (mSwitchNestingLevel == 0)
3589 {
3590 error(loc, "default labels need to be inside switch statements", "default");
Olli Etuaho53f076f2015-02-20 10:55:14 +02003591 return nullptr;
3592 }
Olli Etuahoa3a36662015-02-17 13:46:51 +02003593 TIntermCase *node = intermediate.addCase(nullptr, loc);
3594 if (node == nullptr)
3595 {
3596 error(loc, "erroneous default statement", "default");
Olli Etuahoa3a36662015-02-17 13:46:51 +02003597 return nullptr;
3598 }
3599 return node;
3600}
3601
Jamie Madillb98c3a82015-07-23 14:26:04 -04003602TIntermTyped *TParseContext::createUnaryMath(TOperator op,
3603 TIntermTyped *child,
3604 const TSourceLoc &loc,
3605 const TType *funcReturnType)
Olli Etuaho69c11b52015-03-26 12:59:00 +02003606{
3607 if (child == nullptr)
3608 {
3609 return nullptr;
3610 }
3611
3612 switch (op)
3613 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003614 case EOpLogicalNot:
3615 if (child->getBasicType() != EbtBool || child->isMatrix() || child->isArray() ||
3616 child->isVector())
3617 {
3618 return nullptr;
3619 }
3620 break;
3621 case EOpBitwiseNot:
3622 if ((child->getBasicType() != EbtInt && child->getBasicType() != EbtUInt) ||
3623 child->isMatrix() || child->isArray())
3624 {
3625 return nullptr;
3626 }
3627 break;
3628 case EOpPostIncrement:
3629 case EOpPreIncrement:
3630 case EOpPostDecrement:
3631 case EOpPreDecrement:
3632 case EOpNegative:
3633 case EOpPositive:
3634 if (child->getBasicType() == EbtStruct || child->getBasicType() == EbtBool ||
Martin Radev2cc85b32016-08-05 16:22:53 +03003635 child->isArray() || IsOpaqueType(child->getBasicType()))
Jamie Madillb98c3a82015-07-23 14:26:04 -04003636 {
3637 return nullptr;
3638 }
3639 // Operators for built-ins are already type checked against their prototype.
3640 default:
3641 break;
Olli Etuaho69c11b52015-03-26 12:59:00 +02003642 }
3643
Olli Etuahof119a262016-08-19 15:54:22 +03003644 TIntermUnary *node = new TIntermUnary(op, child);
3645 node->setLine(loc);
Olli Etuahof119a262016-08-19 15:54:22 +03003646
3647 TIntermTyped *foldedNode = node->fold(&mDiagnostics);
3648 if (foldedNode)
3649 return foldedNode;
3650
3651 return node;
Olli Etuaho69c11b52015-03-26 12:59:00 +02003652}
3653
Olli Etuaho09b22472015-02-11 11:47:26 +02003654TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc)
3655{
Olli Etuahof6c694b2015-03-26 14:50:53 +02003656 TIntermTyped *node = createUnaryMath(op, child, loc, nullptr);
Olli Etuaho69c11b52015-03-26 12:59:00 +02003657 if (node == nullptr)
Olli Etuaho09b22472015-02-11 11:47:26 +02003658 {
3659 unaryOpError(loc, GetOperatorString(op), child->getCompleteString());
Olli Etuaho09b22472015-02-11 11:47:26 +02003660 return child;
3661 }
3662 return node;
3663}
3664
Jamie Madillb98c3a82015-07-23 14:26:04 -04003665TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op,
3666 TIntermTyped *child,
3667 const TSourceLoc &loc)
Olli Etuaho09b22472015-02-11 11:47:26 +02003668{
Olli Etuaho856c4972016-08-08 11:38:39 +03003669 checkCanBeLValue(loc, GetOperatorString(op), child);
Olli Etuaho09b22472015-02-11 11:47:26 +02003670 return addUnaryMath(op, child, loc);
3671}
3672
Jamie Madillb98c3a82015-07-23 14:26:04 -04003673bool TParseContext::binaryOpCommonCheck(TOperator op,
3674 TIntermTyped *left,
3675 TIntermTyped *right,
3676 const TSourceLoc &loc)
Olli Etuahod6b14282015-03-17 14:31:35 +02003677{
Olli Etuaho244be012016-08-18 15:26:02 +03003678 if (left->getType().getStruct() || right->getType().getStruct())
3679 {
3680 switch (op)
3681 {
3682 case EOpIndexDirectStruct:
3683 ASSERT(left->getType().getStruct());
3684 break;
3685 case EOpEqual:
3686 case EOpNotEqual:
3687 case EOpAssign:
3688 case EOpInitialize:
3689 if (left->getType() != right->getType())
3690 {
3691 return false;
3692 }
3693 break;
3694 default:
3695 error(loc, "Invalid operation for structs", GetOperatorString(op));
3696 return false;
3697 }
3698 }
3699
Olli Etuahod6b14282015-03-17 14:31:35 +02003700 if (left->isArray() || right->isArray())
3701 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04003702 if (mShaderVersion < 300)
Olli Etuahoe79904c2015-03-18 16:56:42 +02003703 {
3704 error(loc, "Invalid operation for arrays", GetOperatorString(op));
3705 return false;
3706 }
3707
3708 if (left->isArray() != right->isArray())
3709 {
3710 error(loc, "array / non-array mismatch", GetOperatorString(op));
3711 return false;
3712 }
3713
3714 switch (op)
3715 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003716 case EOpEqual:
3717 case EOpNotEqual:
3718 case EOpAssign:
3719 case EOpInitialize:
3720 break;
3721 default:
3722 error(loc, "Invalid operation for arrays", GetOperatorString(op));
3723 return false;
Olli Etuahoe79904c2015-03-18 16:56:42 +02003724 }
Olli Etuaho376f1b52015-04-13 13:23:41 +03003725 // At this point, size of implicitly sized arrays should be resolved.
Olli Etuahoe79904c2015-03-18 16:56:42 +02003726 if (left->getArraySize() != right->getArraySize())
3727 {
3728 error(loc, "array size mismatch", GetOperatorString(op));
3729 return false;
3730 }
Olli Etuahod6b14282015-03-17 14:31:35 +02003731 }
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003732
3733 // Check ops which require integer / ivec parameters
3734 bool isBitShift = false;
3735 switch (op)
3736 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003737 case EOpBitShiftLeft:
3738 case EOpBitShiftRight:
3739 case EOpBitShiftLeftAssign:
3740 case EOpBitShiftRightAssign:
3741 // Unsigned can be bit-shifted by signed and vice versa, but we need to
3742 // check that the basic type is an integer type.
3743 isBitShift = true;
3744 if (!IsInteger(left->getBasicType()) || !IsInteger(right->getBasicType()))
3745 {
3746 return false;
3747 }
3748 break;
3749 case EOpBitwiseAnd:
3750 case EOpBitwiseXor:
3751 case EOpBitwiseOr:
3752 case EOpBitwiseAndAssign:
3753 case EOpBitwiseXorAssign:
3754 case EOpBitwiseOrAssign:
3755 // It is enough to check the type of only one operand, since later it
3756 // is checked that the operand types match.
3757 if (!IsInteger(left->getBasicType()))
3758 {
3759 return false;
3760 }
3761 break;
3762 default:
3763 break;
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003764 }
3765
3766 // GLSL ES 1.00 and 3.00 do not support implicit type casting.
3767 // So the basic type should usually match.
3768 if (!isBitShift && left->getBasicType() != right->getBasicType())
3769 {
3770 return false;
3771 }
3772
Olli Etuaho63e1ec52016-08-18 22:05:12 +03003773 // Check that:
3774 // 1. Type sizes match exactly on ops that require that.
3775 // 2. Restrictions for structs that contain arrays or samplers are respected.
3776 // 3. Arithmetic op type dimensionality restrictions for ops other than multiply are respected.
Jamie Madillb98c3a82015-07-23 14:26:04 -04003777 switch (op)
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003778 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003779 case EOpAssign:
3780 case EOpInitialize:
3781 case EOpEqual:
3782 case EOpNotEqual:
3783 // ESSL 1.00 sections 5.7, 5.8, 5.9
3784 if (mShaderVersion < 300 && left->getType().isStructureContainingArrays())
3785 {
3786 error(loc, "undefined operation for structs containing arrays",
3787 GetOperatorString(op));
3788 return false;
3789 }
3790 // Samplers as l-values are disallowed also in ESSL 3.00, see section 4.1.7,
3791 // we interpret the spec so that this extends to structs containing samplers,
3792 // similarly to ESSL 1.00 spec.
3793 if ((mShaderVersion < 300 || op == EOpAssign || op == EOpInitialize) &&
3794 left->getType().isStructureContainingSamplers())
3795 {
3796 error(loc, "undefined operation for structs containing samplers",
3797 GetOperatorString(op));
3798 return false;
3799 }
Martin Radev2cc85b32016-08-05 16:22:53 +03003800
3801 if ((op == EOpAssign || op == EOpInitialize) &&
3802 left->getType().isStructureContainingImages())
3803 {
3804 error(loc, "undefined operation for structs containing images",
3805 GetOperatorString(op));
3806 return false;
3807 }
Jamie Madillb98c3a82015-07-23 14:26:04 -04003808 case EOpLessThan:
3809 case EOpGreaterThan:
3810 case EOpLessThanEqual:
3811 case EOpGreaterThanEqual:
3812 if ((left->getNominalSize() != right->getNominalSize()) ||
3813 (left->getSecondarySize() != right->getSecondarySize()))
3814 {
3815 return false;
3816 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03003817 break;
3818 case EOpAdd:
3819 case EOpSub:
3820 case EOpDiv:
3821 case EOpIMod:
3822 case EOpBitShiftLeft:
3823 case EOpBitShiftRight:
3824 case EOpBitwiseAnd:
3825 case EOpBitwiseXor:
3826 case EOpBitwiseOr:
3827 case EOpAddAssign:
3828 case EOpSubAssign:
3829 case EOpDivAssign:
3830 case EOpIModAssign:
3831 case EOpBitShiftLeftAssign:
3832 case EOpBitShiftRightAssign:
3833 case EOpBitwiseAndAssign:
3834 case EOpBitwiseXorAssign:
3835 case EOpBitwiseOrAssign:
3836 if ((left->isMatrix() && right->isVector()) || (left->isVector() && right->isMatrix()))
3837 {
3838 return false;
3839 }
3840
3841 // Are the sizes compatible?
3842 if (left->getNominalSize() != right->getNominalSize() ||
3843 left->getSecondarySize() != right->getSecondarySize())
3844 {
3845 // If the nominal sizes of operands do not match:
3846 // One of them must be a scalar.
3847 if (!left->isScalar() && !right->isScalar())
3848 return false;
3849
3850 // In the case of compound assignment other than multiply-assign,
3851 // the right side needs to be a scalar. Otherwise a vector/matrix
3852 // would be assigned to a scalar. A scalar can't be shifted by a
3853 // vector either.
3854 if (!right->isScalar() &&
3855 (IsAssignment(op) || op == EOpBitShiftLeft || op == EOpBitShiftRight))
3856 return false;
3857 }
3858 break;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003859 default:
3860 break;
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003861 }
3862
Olli Etuahod6b14282015-03-17 14:31:35 +02003863 return true;
3864}
3865
Olli Etuaho1dded802016-08-18 18:13:13 +03003866bool TParseContext::isMultiplicationTypeCombinationValid(TOperator op,
3867 const TType &left,
3868 const TType &right)
3869{
3870 switch (op)
3871 {
3872 case EOpMul:
3873 case EOpMulAssign:
3874 return left.getNominalSize() == right.getNominalSize() &&
3875 left.getSecondarySize() == right.getSecondarySize();
3876 case EOpVectorTimesScalar:
3877 return true;
3878 case EOpVectorTimesScalarAssign:
3879 ASSERT(!left.isMatrix() && !right.isMatrix());
3880 return left.isVector() && !right.isVector();
3881 case EOpVectorTimesMatrix:
3882 return left.getNominalSize() == right.getRows();
3883 case EOpVectorTimesMatrixAssign:
3884 ASSERT(!left.isMatrix() && right.isMatrix());
3885 return left.isVector() && left.getNominalSize() == right.getRows() &&
3886 left.getNominalSize() == right.getCols();
3887 case EOpMatrixTimesVector:
3888 return left.getCols() == right.getNominalSize();
3889 case EOpMatrixTimesScalar:
3890 return true;
3891 case EOpMatrixTimesScalarAssign:
3892 ASSERT(left.isMatrix() && !right.isMatrix());
3893 return !right.isVector();
3894 case EOpMatrixTimesMatrix:
3895 return left.getCols() == right.getRows();
3896 case EOpMatrixTimesMatrixAssign:
3897 ASSERT(left.isMatrix() && right.isMatrix());
3898 // We need to check two things:
3899 // 1. The matrix multiplication step is valid.
3900 // 2. The result will have the same number of columns as the lvalue.
3901 return left.getCols() == right.getRows() && left.getCols() == right.getCols();
3902
3903 default:
3904 UNREACHABLE();
3905 return false;
3906 }
3907}
3908
Jamie Madillb98c3a82015-07-23 14:26:04 -04003909TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op,
3910 TIntermTyped *left,
3911 TIntermTyped *right,
3912 const TSourceLoc &loc)
Olli Etuahofc1806e2015-03-17 13:03:11 +02003913{
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003914 if (!binaryOpCommonCheck(op, left, right, loc))
Olli Etuahod6b14282015-03-17 14:31:35 +02003915 return nullptr;
3916
Olli Etuahofc1806e2015-03-17 13:03:11 +02003917 switch (op)
3918 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003919 case EOpEqual:
3920 case EOpNotEqual:
3921 break;
3922 case EOpLessThan:
3923 case EOpGreaterThan:
3924 case EOpLessThanEqual:
3925 case EOpGreaterThanEqual:
Olli Etuaho244be012016-08-18 15:26:02 +03003926 ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() &&
3927 !right->getType().getStruct());
3928 if (left->isMatrix() || left->isVector())
Jamie Madillb98c3a82015-07-23 14:26:04 -04003929 {
3930 return nullptr;
3931 }
3932 break;
3933 case EOpLogicalOr:
3934 case EOpLogicalXor:
3935 case EOpLogicalAnd:
Olli Etuaho244be012016-08-18 15:26:02 +03003936 ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() &&
3937 !right->getType().getStruct());
Olli Etuahoe7dc9d72016-11-03 16:58:47 +00003938 if (left->getBasicType() != EbtBool || !left->isScalar() || !right->isScalar())
Jamie Madillb98c3a82015-07-23 14:26:04 -04003939 {
3940 return nullptr;
3941 }
Olli Etuahoe7dc9d72016-11-03 16:58:47 +00003942 // Basic types matching should have been already checked.
3943 ASSERT(right->getBasicType() == EbtBool);
Jamie Madillb98c3a82015-07-23 14:26:04 -04003944 break;
3945 case EOpAdd:
3946 case EOpSub:
3947 case EOpDiv:
3948 case EOpMul:
Olli Etuaho244be012016-08-18 15:26:02 +03003949 ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() &&
3950 !right->getType().getStruct());
3951 if (left->getBasicType() == EbtBool)
Jamie Madillb98c3a82015-07-23 14:26:04 -04003952 {
3953 return nullptr;
3954 }
3955 break;
3956 case EOpIMod:
Olli Etuaho244be012016-08-18 15:26:02 +03003957 ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() &&
3958 !right->getType().getStruct());
Jamie Madillb98c3a82015-07-23 14:26:04 -04003959 // Note that this is only for the % operator, not for mod()
Olli Etuaho244be012016-08-18 15:26:02 +03003960 if (left->getBasicType() == EbtBool || left->getBasicType() == EbtFloat)
Jamie Madillb98c3a82015-07-23 14:26:04 -04003961 {
3962 return nullptr;
3963 }
3964 break;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003965 default:
3966 break;
Olli Etuahofc1806e2015-03-17 13:03:11 +02003967 }
3968
Olli Etuaho1dded802016-08-18 18:13:13 +03003969 if (op == EOpMul)
3970 {
3971 op = TIntermBinary::GetMulOpBasedOnOperands(left->getType(), right->getType());
3972 if (!isMultiplicationTypeCombinationValid(op, left->getType(), right->getType()))
3973 {
3974 return nullptr;
3975 }
3976 }
3977
Olli Etuaho3fdec912016-08-18 15:08:06 +03003978 TIntermBinary *node = new TIntermBinary(op, left, right);
3979 node->setLine(loc);
3980
Olli Etuaho3fdec912016-08-18 15:08:06 +03003981 // See if we can fold constants.
3982 TIntermTyped *foldedNode = node->fold(&mDiagnostics);
3983 if (foldedNode)
3984 return foldedNode;
3985
3986 return node;
Olli Etuahofc1806e2015-03-17 13:03:11 +02003987}
3988
Jamie Madillb98c3a82015-07-23 14:26:04 -04003989TIntermTyped *TParseContext::addBinaryMath(TOperator op,
3990 TIntermTyped *left,
3991 TIntermTyped *right,
3992 const TSourceLoc &loc)
Olli Etuaho09b22472015-02-11 11:47:26 +02003993{
Olli Etuahofc1806e2015-03-17 13:03:11 +02003994 TIntermTyped *node = addBinaryMathInternal(op, left, right, loc);
Olli Etuaho09b22472015-02-11 11:47:26 +02003995 if (node == 0)
3996 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003997 binaryOpError(loc, GetOperatorString(op), left->getCompleteString(),
3998 right->getCompleteString());
Olli Etuaho09b22472015-02-11 11:47:26 +02003999 return left;
4000 }
4001 return node;
4002}
4003
Jamie Madillb98c3a82015-07-23 14:26:04 -04004004TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op,
4005 TIntermTyped *left,
4006 TIntermTyped *right,
4007 const TSourceLoc &loc)
Olli Etuaho09b22472015-02-11 11:47:26 +02004008{
Olli Etuahofc1806e2015-03-17 13:03:11 +02004009 TIntermTyped *node = addBinaryMathInternal(op, left, right, loc);
Olli Etuaho09b22472015-02-11 11:47:26 +02004010 if (node == 0)
4011 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04004012 binaryOpError(loc, GetOperatorString(op), left->getCompleteString(),
4013 right->getCompleteString());
Jamie Madill6ba6ead2015-05-04 14:21:21 -04004014 TConstantUnion *unionArray = new TConstantUnion[1];
Olli Etuaho09b22472015-02-11 11:47:26 +02004015 unionArray->setBConst(false);
Jamie Madillb98c3a82015-07-23 14:26:04 -04004016 return intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst),
4017 loc);
Olli Etuaho09b22472015-02-11 11:47:26 +02004018 }
4019 return node;
4020}
4021
Olli Etuaho13389b62016-10-16 11:48:18 +01004022TIntermBinary *TParseContext::createAssign(TOperator op,
4023 TIntermTyped *left,
4024 TIntermTyped *right,
4025 const TSourceLoc &loc)
Olli Etuahod6b14282015-03-17 14:31:35 +02004026{
Olli Etuaho47fd36a2015-03-19 14:22:24 +02004027 if (binaryOpCommonCheck(op, left, right, loc))
Olli Etuahod6b14282015-03-17 14:31:35 +02004028 {
Olli Etuaho1dded802016-08-18 18:13:13 +03004029 if (op == EOpMulAssign)
4030 {
4031 op = TIntermBinary::GetMulAssignOpBasedOnOperands(left->getType(), right->getType());
4032 if (!isMultiplicationTypeCombinationValid(op, left->getType(), right->getType()))
4033 {
4034 return nullptr;
4035 }
4036 }
Olli Etuaho3fdec912016-08-18 15:08:06 +03004037 TIntermBinary *node = new TIntermBinary(op, left, right);
4038 node->setLine(loc);
4039
Olli Etuaho3fdec912016-08-18 15:08:06 +03004040 return node;
Olli Etuahod6b14282015-03-17 14:31:35 +02004041 }
4042 return nullptr;
4043}
4044
Jamie Madillb98c3a82015-07-23 14:26:04 -04004045TIntermTyped *TParseContext::addAssign(TOperator op,
4046 TIntermTyped *left,
4047 TIntermTyped *right,
4048 const TSourceLoc &loc)
Olli Etuahod6b14282015-03-17 14:31:35 +02004049{
4050 TIntermTyped *node = createAssign(op, left, right, loc);
4051 if (node == nullptr)
4052 {
4053 assignError(loc, "assign", left->getCompleteString(), right->getCompleteString());
Olli Etuahod6b14282015-03-17 14:31:35 +02004054 return left;
4055 }
4056 return node;
4057}
4058
Olli Etuaho0b2d2dc2015-11-04 16:35:32 +02004059TIntermTyped *TParseContext::addComma(TIntermTyped *left,
4060 TIntermTyped *right,
4061 const TSourceLoc &loc)
4062{
Corentin Wallez0d959252016-07-12 17:26:32 -04004063 // WebGL2 section 5.26, the following results in an error:
4064 // "Sequence operator applied to void, arrays, or structs containing arrays"
4065 if (mShaderSpec == SH_WEBGL2_SPEC && (left->isArray() || left->getBasicType() == EbtVoid ||
4066 left->getType().isStructureContainingArrays() ||
4067 right->isArray() || right->getBasicType() == EbtVoid ||
4068 right->getType().isStructureContainingArrays()))
4069 {
4070 error(loc,
4071 "sequence operator is not allowed for void, arrays, or structs containing arrays",
4072 ",");
Corentin Wallez0d959252016-07-12 17:26:32 -04004073 }
4074
Olli Etuaho4db7ded2016-10-13 12:23:11 +01004075 return TIntermediate::AddComma(left, right, loc, mShaderVersion);
Olli Etuaho0b2d2dc2015-11-04 16:35:32 +02004076}
4077
Olli Etuaho49300862015-02-20 14:54:49 +02004078TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc)
4079{
4080 switch (op)
4081 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04004082 case EOpContinue:
4083 if (mLoopNestingLevel <= 0)
4084 {
4085 error(loc, "continue statement only allowed in loops", "");
Jamie Madillb98c3a82015-07-23 14:26:04 -04004086 }
4087 break;
4088 case EOpBreak:
4089 if (mLoopNestingLevel <= 0 && mSwitchNestingLevel <= 0)
4090 {
4091 error(loc, "break statement only allowed in loops and switch statements", "");
Jamie Madillb98c3a82015-07-23 14:26:04 -04004092 }
4093 break;
4094 case EOpReturn:
4095 if (mCurrentFunctionType->getBasicType() != EbtVoid)
4096 {
4097 error(loc, "non-void function must return a value", "return");
Jamie Madillb98c3a82015-07-23 14:26:04 -04004098 }
4099 break;
4100 default:
4101 // No checks for discard
4102 break;
Olli Etuaho49300862015-02-20 14:54:49 +02004103 }
4104 return intermediate.addBranch(op, loc);
4105}
4106
Jamie Madillb98c3a82015-07-23 14:26:04 -04004107TIntermBranch *TParseContext::addBranch(TOperator op,
4108 TIntermTyped *returnValue,
4109 const TSourceLoc &loc)
Olli Etuaho49300862015-02-20 14:54:49 +02004110{
4111 ASSERT(op == EOpReturn);
4112 mFunctionReturnsValue = true;
Jamie Madill6e06b1f2015-05-14 10:01:17 -04004113 if (mCurrentFunctionType->getBasicType() == EbtVoid)
Olli Etuaho49300862015-02-20 14:54:49 +02004114 {
4115 error(loc, "void function cannot return a value", "return");
Olli Etuaho49300862015-02-20 14:54:49 +02004116 }
Jamie Madill6e06b1f2015-05-14 10:01:17 -04004117 else if (*mCurrentFunctionType != returnValue->getType())
Olli Etuaho49300862015-02-20 14:54:49 +02004118 {
4119 error(loc, "function return is not matching type:", "return");
Olli Etuaho49300862015-02-20 14:54:49 +02004120 }
4121 return intermediate.addBranch(op, returnValue, loc);
4122}
4123
Olli Etuahoe1a94c62015-11-16 17:35:25 +02004124void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall)
4125{
4126 ASSERT(!functionCall->isUserDefined());
Olli Etuahobd674552016-10-06 13:28:42 +01004127 const TString &name = functionCall->getFunctionSymbolInfo()->getName();
Olli Etuahoe1a94c62015-11-16 17:35:25 +02004128 TIntermNode *offset = nullptr;
4129 TIntermSequence *arguments = functionCall->getSequence();
4130 if (name.compare(0, 16, "texelFetchOffset") == 0 ||
4131 name.compare(0, 16, "textureLodOffset") == 0 ||
4132 name.compare(0, 20, "textureProjLodOffset") == 0 ||
4133 name.compare(0, 17, "textureGradOffset") == 0 ||
4134 name.compare(0, 21, "textureProjGradOffset") == 0)
4135 {
4136 offset = arguments->back();
4137 }
4138 else if (name.compare(0, 13, "textureOffset") == 0 ||
4139 name.compare(0, 17, "textureProjOffset") == 0)
4140 {
4141 // A bias parameter might follow the offset parameter.
4142 ASSERT(arguments->size() >= 3);
4143 offset = (*arguments)[2];
4144 }
4145 if (offset != nullptr)
4146 {
4147 TIntermConstantUnion *offsetConstantUnion = offset->getAsConstantUnion();
4148 if (offset->getAsTyped()->getQualifier() != EvqConst || !offsetConstantUnion)
4149 {
4150 TString unmangledName = TFunction::unmangleName(name);
4151 error(functionCall->getLine(), "Texture offset must be a constant expression",
4152 unmangledName.c_str());
Olli Etuahoe1a94c62015-11-16 17:35:25 +02004153 }
4154 else
4155 {
4156 ASSERT(offsetConstantUnion->getBasicType() == EbtInt);
4157 size_t size = offsetConstantUnion->getType().getObjectSize();
4158 const TConstantUnion *values = offsetConstantUnion->getUnionArrayPointer();
4159 for (size_t i = 0u; i < size; ++i)
4160 {
4161 int offsetValue = values[i].getIConst();
4162 if (offsetValue > mMaxProgramTexelOffset || offsetValue < mMinProgramTexelOffset)
4163 {
4164 std::stringstream tokenStream;
4165 tokenStream << offsetValue;
4166 std::string token = tokenStream.str();
4167 error(offset->getLine(), "Texture offset value out of valid range",
4168 token.c_str());
Olli Etuahoe1a94c62015-11-16 17:35:25 +02004169 }
4170 }
4171 }
4172 }
4173}
4174
Martin Radev2cc85b32016-08-05 16:22:53 +03004175// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
4176void TParseContext::checkImageMemoryAccessForBuiltinFunctions(TIntermAggregate *functionCall)
4177{
4178 ASSERT(!functionCall->isUserDefined());
4179 const TString &name = functionCall->getFunctionSymbolInfo()->getName();
4180
4181 if (name.compare(0, 5, "image") == 0)
4182 {
4183 TIntermSequence *arguments = functionCall->getSequence();
4184 TIntermNode *imageNode = (*arguments)[0];
4185 TIntermSymbol *imageSymbol = imageNode->getAsSymbolNode();
4186
4187 const TMemoryQualifier &memoryQualifier = imageSymbol->getMemoryQualifier();
4188
4189 if (name.compare(5, 5, "Store") == 0)
4190 {
4191 if (memoryQualifier.readonly)
4192 {
4193 error(imageNode->getLine(),
4194 "'imageStore' cannot be used with images qualified as 'readonly'",
4195 imageSymbol->getSymbol().c_str());
4196 }
4197 }
4198 else if (name.compare(5, 4, "Load") == 0)
4199 {
4200 if (memoryQualifier.writeonly)
4201 {
4202 error(imageNode->getLine(),
4203 "'imageLoad' cannot be used with images qualified as 'writeonly'",
4204 imageSymbol->getSymbol().c_str());
4205 }
4206 }
4207 }
4208}
4209
4210// GLSL ES 3.10 Revision 4, 13.51 Matching of Memory Qualifiers in Function Parameters
4211void TParseContext::checkImageMemoryAccessForUserDefinedFunctions(
4212 const TFunction *functionDefinition,
4213 const TIntermAggregate *functionCall)
4214{
4215 ASSERT(functionCall->isUserDefined());
4216
4217 const TIntermSequence &arguments = *functionCall->getSequence();
4218
4219 ASSERT(functionDefinition->getParamCount() == arguments.size());
4220
4221 for (size_t i = 0; i < arguments.size(); ++i)
4222 {
4223 const TType &functionArgumentType = arguments[i]->getAsTyped()->getType();
4224 const TType &functionParameterType = *functionDefinition->getParam(i).type;
4225 ASSERT(functionArgumentType.getBasicType() == functionParameterType.getBasicType());
4226
4227 if (IsImage(functionArgumentType.getBasicType()))
4228 {
4229 const TMemoryQualifier &functionArgumentMemoryQualifier =
4230 functionArgumentType.getMemoryQualifier();
4231 const TMemoryQualifier &functionParameterMemoryQualifier =
4232 functionParameterType.getMemoryQualifier();
4233 if (functionArgumentMemoryQualifier.readonly &&
4234 !functionParameterMemoryQualifier.readonly)
4235 {
4236 error(functionCall->getLine(),
4237 "Function call discards the 'readonly' qualifier from image",
4238 arguments[i]->getAsSymbolNode()->getSymbol().c_str());
4239 }
4240
4241 if (functionArgumentMemoryQualifier.writeonly &&
4242 !functionParameterMemoryQualifier.writeonly)
4243 {
4244 error(functionCall->getLine(),
4245 "Function call discards the 'writeonly' qualifier from image",
4246 arguments[i]->getAsSymbolNode()->getSymbol().c_str());
4247 }
Martin Radev049edfa2016-11-11 14:35:37 +02004248
4249 if (functionArgumentMemoryQualifier.coherent &&
4250 !functionParameterMemoryQualifier.coherent)
4251 {
4252 error(functionCall->getLine(),
4253 "Function call discards the 'coherent' qualifier from image",
4254 arguments[i]->getAsSymbolNode()->getSymbol().c_str());
4255 }
4256
4257 if (functionArgumentMemoryQualifier.volatileQualifier &&
4258 !functionParameterMemoryQualifier.volatileQualifier)
4259 {
4260 error(functionCall->getLine(),
4261 "Function call discards the 'volatile' qualifier from image",
4262 arguments[i]->getAsSymbolNode()->getSymbol().c_str());
4263 }
Martin Radev2cc85b32016-08-05 16:22:53 +03004264 }
4265 }
4266}
4267
Jamie Madillb98c3a82015-07-23 14:26:04 -04004268TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall,
4269 TIntermNode *paramNode,
4270 TIntermNode *thisNode,
4271 const TSourceLoc &loc,
4272 bool *fatalError)
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004273{
Jamie Madillb98c3a82015-07-23 14:26:04 -04004274 *fatalError = false;
4275 TOperator op = fnCall->getBuiltInOp();
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004276 TIntermTyped *callNode = nullptr;
4277
Olli Etuahoffe6edf2015-04-13 17:32:03 +03004278 if (thisNode != nullptr)
4279 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -04004280 TConstantUnion *unionArray = new TConstantUnion[1];
Jamie Madillb98c3a82015-07-23 14:26:04 -04004281 int arraySize = 0;
Olli Etuahoffe6edf2015-04-13 17:32:03 +03004282 TIntermTyped *typedThis = thisNode->getAsTyped();
4283 if (fnCall->getName() != "length")
4284 {
4285 error(loc, "invalid method", fnCall->getName().c_str());
Olli Etuahoffe6edf2015-04-13 17:32:03 +03004286 }
4287 else if (paramNode != nullptr)
4288 {
4289 error(loc, "method takes no parameters", "length");
Olli Etuahoffe6edf2015-04-13 17:32:03 +03004290 }
4291 else if (typedThis == nullptr || !typedThis->isArray())
4292 {
4293 error(loc, "length can only be called on arrays", "length");
Olli Etuahoffe6edf2015-04-13 17:32:03 +03004294 }
4295 else
4296 {
Olli Etuaho96e67382015-04-23 14:27:02 +03004297 arraySize = typedThis->getArraySize();
Olli Etuaho39282e12015-04-23 15:41:48 +03004298 if (typedThis->getAsSymbolNode() == nullptr)
Olli Etuahoffe6edf2015-04-13 17:32:03 +03004299 {
Olli Etuaho39282e12015-04-23 15:41:48 +03004300 // This code path can be hit with expressions like these:
Olli Etuahoffe6edf2015-04-13 17:32:03 +03004301 // (a = b).length()
Olli Etuaho39282e12015-04-23 15:41:48 +03004302 // (func()).length()
4303 // (int[3](0, 1, 2)).length()
Jamie Madillb98c3a82015-07-23 14:26:04 -04004304 // ESSL 3.00 section 5.9 defines expressions so that this is not actually a valid
4305 // expression.
4306 // It allows "An array name with the length method applied" in contrast to GLSL 4.4
4307 // spec section 5.9 which allows "An array, vector or matrix expression with the
4308 // length method applied".
4309 error(loc, "length can only be called on array names, not on array expressions",
4310 "length");
Olli Etuahoffe6edf2015-04-13 17:32:03 +03004311 }
4312 }
Olli Etuaho96e67382015-04-23 14:27:02 +03004313 unionArray->setIConst(arraySize);
Jamie Madillb98c3a82015-07-23 14:26:04 -04004314 callNode =
4315 intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), loc);
Olli Etuahoffe6edf2015-04-13 17:32:03 +03004316 }
4317 else if (op != EOpNull)
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004318 {
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004319 // Then this should be a constructor.
Olli Etuaho856c4972016-08-08 11:38:39 +03004320 callNode = addConstructor(paramNode, op, fnCall, loc);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004321 }
4322 else
4323 {
4324 //
4325 // Not a constructor. Find it in the symbol table.
4326 //
Arun Patole7e7e68d2015-05-22 12:02:25 +05304327 const TFunction *fnCandidate;
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004328 bool builtIn;
Jamie Madill6e06b1f2015-05-14 10:01:17 -04004329 fnCandidate = findFunction(loc, fnCall, mShaderVersion, &builtIn);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004330 if (fnCandidate)
4331 {
4332 //
4333 // A declared function.
4334 //
Olli Etuaho383b7912016-08-05 11:22:59 +03004335 if (builtIn && !fnCandidate->getExtension().empty())
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004336 {
Olli Etuaho856c4972016-08-08 11:38:39 +03004337 checkCanUseExtension(loc, fnCandidate->getExtension());
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004338 }
4339 op = fnCandidate->getBuiltInOp();
4340 if (builtIn && op != EOpNull)
4341 {
4342 //
4343 // A function call mapped to a built-in operation.
4344 //
4345 if (fnCandidate->getParamCount() == 1)
4346 {
4347 //
4348 // Treat it like a built-in unary operator.
4349 //
Olli Etuaho15c2ac32015-11-09 15:51:43 +02004350 TIntermAggregate *paramAgg = paramNode->getAsAggregate();
4351 paramNode = paramAgg->getSequence()->front();
Jamie Madillb98c3a82015-07-23 14:26:04 -04004352 callNode = createUnaryMath(op, paramNode->getAsTyped(), loc,
4353 &fnCandidate->getReturnType());
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004354 if (callNode == nullptr)
4355 {
4356 std::stringstream extraInfoStream;
Jamie Madillb98c3a82015-07-23 14:26:04 -04004357 extraInfoStream
4358 << "built in unary operator function. Type: "
4359 << static_cast<TIntermTyped *>(paramNode)->getCompleteString();
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004360 std::string extraInfo = extraInfoStream.str();
Jamie Madillb98c3a82015-07-23 14:26:04 -04004361 error(paramNode->getLine(), " wrong operand type", "Internal Error",
4362 extraInfo.c_str());
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004363 *fatalError = true;
4364 return nullptr;
4365 }
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004366 }
4367 else
4368 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04004369 TIntermAggregate *aggregate =
4370 intermediate.setAggregateOperator(paramNode, op, loc);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004371 aggregate->setType(fnCandidate->getReturnType());
4372 aggregate->setPrecisionFromChildren();
Olli Etuahob1edc4f2015-11-02 17:20:03 +02004373 if (aggregate->areChildrenConstQualified())
4374 {
4375 aggregate->getTypePointer()->setQualifier(EvqConst);
4376 }
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004377
4378 // Some built-in functions have out parameters too.
4379 functionCallLValueErrorCheck(fnCandidate, aggregate);
Arun Patole274f0702015-05-05 13:33:30 +05304380
Olli Etuaho7c3848e2015-11-04 13:19:17 +02004381 // See if we can constant fold a built-in. Note that this may be possible even
4382 // if it is not const-qualified.
Olli Etuahof119a262016-08-19 15:54:22 +03004383 TIntermTyped *foldedNode =
4384 intermediate.foldAggregateBuiltIn(aggregate, &mDiagnostics);
Arun Patole274f0702015-05-05 13:33:30 +05304385 if (foldedNode)
4386 {
Arun Patole274f0702015-05-05 13:33:30 +05304387 callNode = foldedNode;
4388 }
Olli Etuahob43846e2015-06-02 18:18:57 +03004389 else
4390 {
4391 callNode = aggregate;
4392 }
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004393 }
4394 }
4395 else
4396 {
4397 // This is a real function call
Jamie Madillb98c3a82015-07-23 14:26:04 -04004398 TIntermAggregate *aggregate =
4399 intermediate.setAggregateOperator(paramNode, EOpFunctionCall, loc);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004400 aggregate->setType(fnCandidate->getReturnType());
4401
Jamie Madillb98c3a82015-07-23 14:26:04 -04004402 // this is how we know whether the given function is a builtIn function or a user
4403 // defined function
4404 // if builtIn == false, it's a userDefined -> could be an overloaded
4405 // builtIn function also
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004406 // if builtIn == true, it's definitely a builtIn function with EOpNull
4407 if (!builtIn)
4408 aggregate->setUserDefined();
Olli Etuahobd674552016-10-06 13:28:42 +01004409 aggregate->getFunctionSymbolInfo()->setFromFunction(*fnCandidate);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004410
Olli Etuahobd674552016-10-06 13:28:42 +01004411 // This needs to happen after the function info including name is set
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004412 if (builtIn)
Olli Etuahoe1a94c62015-11-16 17:35:25 +02004413 {
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004414 aggregate->setBuiltInFunctionPrecision();
4415
Olli Etuahoe1a94c62015-11-16 17:35:25 +02004416 checkTextureOffsetConst(aggregate);
Martin Radev2cc85b32016-08-05 16:22:53 +03004417
4418 checkImageMemoryAccessForBuiltinFunctions(aggregate);
4419 }
4420 else
4421 {
4422 checkImageMemoryAccessForUserDefinedFunctions(fnCandidate, aggregate);
Olli Etuahoe1a94c62015-11-16 17:35:25 +02004423 }
4424
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004425 callNode = aggregate;
4426
4427 functionCallLValueErrorCheck(fnCandidate, aggregate);
4428 }
4429 }
4430 else
4431 {
4432 // error message was put out by findFunction()
4433 // Put on a dummy node for error recovery
Jamie Madill6ba6ead2015-05-04 14:21:21 -04004434 TConstantUnion *unionArray = new TConstantUnion[1];
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004435 unionArray->setFConst(0.0f);
Jamie Madillb98c3a82015-07-23 14:26:04 -04004436 callNode = intermediate.addConstantUnion(unionArray,
4437 TType(EbtFloat, EbpUndefined, EvqConst), loc);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004438 }
4439 }
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004440 return callNode;
4441}
4442
Jamie Madillb98c3a82015-07-23 14:26:04 -04004443TIntermTyped *TParseContext::addTernarySelection(TIntermTyped *cond,
Olli Etuahod0bad2c2016-09-09 18:01:16 +03004444 TIntermTyped *trueExpression,
4445 TIntermTyped *falseExpression,
Olli Etuaho52901742015-04-15 13:42:45 +03004446 const TSourceLoc &loc)
4447{
Olli Etuaho856c4972016-08-08 11:38:39 +03004448 checkIsScalarBool(loc, cond);
Olli Etuaho52901742015-04-15 13:42:45 +03004449
Olli Etuahod0bad2c2016-09-09 18:01:16 +03004450 if (trueExpression->getType() != falseExpression->getType())
Olli Etuaho52901742015-04-15 13:42:45 +03004451 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +03004452 binaryOpError(loc, ":", trueExpression->getCompleteString(),
4453 falseExpression->getCompleteString());
4454 return falseExpression;
Olli Etuaho52901742015-04-15 13:42:45 +03004455 }
Olli Etuahode318b22016-10-25 16:18:25 +01004456 if (IsOpaqueType(trueExpression->getBasicType()))
4457 {
4458 // ESSL 1.00 section 4.1.7
4459 // ESSL 3.00 section 4.1.7
4460 // Opaque/sampler types are not allowed in most types of expressions, including ternary.
4461 // Note that structs containing opaque types don't need to be checked as structs are
4462 // forbidden below.
4463 error(loc, "ternary operator is not allowed for opaque types", ":");
4464 return falseExpression;
4465 }
4466
Olli Etuahoa2d53032015-04-15 14:14:44 +03004467 // ESSL1 sections 5.2 and 5.7:
4468 // ESSL3 section 5.7:
4469 // Ternary operator is not among the operators allowed for structures/arrays.
Olli Etuahod0bad2c2016-09-09 18:01:16 +03004470 if (trueExpression->isArray() || trueExpression->getBasicType() == EbtStruct)
Olli Etuahoa2d53032015-04-15 14:14:44 +03004471 {
4472 error(loc, "ternary operator is not allowed for structures or arrays", ":");
Olli Etuahod0bad2c2016-09-09 18:01:16 +03004473 return falseExpression;
Olli Etuahoa2d53032015-04-15 14:14:44 +03004474 }
Corentin Wallez0d959252016-07-12 17:26:32 -04004475 // WebGL2 section 5.26, the following results in an error:
4476 // "Ternary operator applied to void, arrays, or structs containing arrays"
Olli Etuahod0bad2c2016-09-09 18:01:16 +03004477 if (mShaderSpec == SH_WEBGL2_SPEC && trueExpression->getBasicType() == EbtVoid)
Corentin Wallez0d959252016-07-12 17:26:32 -04004478 {
4479 error(loc, "ternary operator is not allowed for void", ":");
Olli Etuahod0bad2c2016-09-09 18:01:16 +03004480 return falseExpression;
Corentin Wallez0d959252016-07-12 17:26:32 -04004481 }
4482
Olli Etuahod0bad2c2016-09-09 18:01:16 +03004483 return TIntermediate::AddTernarySelection(cond, trueExpression, falseExpression, loc);
Olli Etuaho52901742015-04-15 13:42:45 +03004484}
Olli Etuaho49300862015-02-20 14:54:49 +02004485
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00004486//
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004487// Parse an array of strings using yyparse.
4488//
4489// Returns 0 for success.
4490//
Jamie Madillb98c3a82015-07-23 14:26:04 -04004491int PaParseStrings(size_t count,
4492 const char *const string[],
4493 const int length[],
Arun Patole7e7e68d2015-05-22 12:02:25 +05304494 TParseContext *context)
4495{
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004496 if ((count == 0) || (string == NULL))
4497 return 1;
4498
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004499 if (glslang_initialize(context))
4500 return 1;
4501
alokp@chromium.org408c45e2012-04-05 15:54:43 +00004502 int error = glslang_scan(count, string, length, context);
4503 if (!error)
4504 error = glslang_parse(context);
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004505
alokp@chromium.org73bc2982012-06-19 18:48:05 +00004506 glslang_finalize(context);
alokp@chromium.org8b851c62012-06-15 16:25:11 +00004507
alokp@chromium.org6b495712012-06-29 00:06:58 +00004508 return (error == 0) && (context->numErrors() == 0) ? 0 : 1;
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004509}
Jamie Madill45bcc782016-11-07 13:58:48 -05004510
4511} // namespace sh