blob: a9f57ce0d102ea097cee4645c74cbf905ed15e7d [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
Olli Etuaho485eefd2017-02-14 17:40:06 +000069// Get a token from an image argument to use as an error message token.
70const char *GetImageArgumentToken(TIntermTyped *imageNode)
71{
72 ASSERT(IsImage(imageNode->getBasicType()));
73 while (imageNode->getAsBinaryNode() &&
74 (imageNode->getAsBinaryNode()->getOp() == EOpIndexIndirect ||
75 imageNode->getAsBinaryNode()->getOp() == EOpIndexDirect))
76 {
77 imageNode = imageNode->getAsBinaryNode()->getLeft();
78 }
79 TIntermSymbol *imageSymbol = imageNode->getAsSymbolNode();
80 if (imageSymbol)
81 {
82 return imageSymbol->getSymbol().c_str();
83 }
84 return "image";
85}
86
Martin Radev2cc85b32016-08-05 16:22:53 +030087} // namespace
88
Jamie Madillacb4b812016-11-07 13:50:29 -050089TParseContext::TParseContext(TSymbolTable &symt,
90 TExtensionBehavior &ext,
91 sh::GLenum type,
92 ShShaderSpec spec,
93 ShCompileOptions options,
94 bool checksPrecErrors,
Olli Etuaho77ba4082016-12-16 12:01:18 +000095 TDiagnostics *diagnostics,
Jamie Madillacb4b812016-11-07 13:50:29 -050096 const ShBuiltInResources &resources)
97 : intermediate(),
98 symbolTable(symt),
Olli Etuahobb7e5a72017-04-24 10:16:44 +030099 mDeferredNonEmptyDeclarationErrorCheck(false),
Jamie Madillacb4b812016-11-07 13:50:29 -0500100 mShaderType(type),
101 mShaderSpec(spec),
102 mCompileOptions(options),
103 mShaderVersion(100),
104 mTreeRoot(nullptr),
105 mLoopNestingLevel(0),
106 mStructNestingLevel(0),
107 mSwitchNestingLevel(0),
108 mCurrentFunctionType(nullptr),
109 mFunctionReturnsValue(false),
110 mChecksPrecisionErrors(checksPrecErrors),
111 mFragmentPrecisionHighOnESSL1(false),
112 mDefaultMatrixPacking(EmpColumnMajor),
113 mDefaultBlockStorage(sh::IsWebGLBasedSpec(spec) ? EbsStd140 : EbsShared),
Olli Etuaho77ba4082016-12-16 12:01:18 +0000114 mDiagnostics(diagnostics),
Jamie Madillacb4b812016-11-07 13:50:29 -0500115 mDirectiveHandler(ext,
Olli Etuaho77ba4082016-12-16 12:01:18 +0000116 *mDiagnostics,
Jamie Madillacb4b812016-11-07 13:50:29 -0500117 mShaderVersion,
118 mShaderType,
119 resources.WEBGL_debug_shader_precision == 1),
Olli Etuaho77ba4082016-12-16 12:01:18 +0000120 mPreprocessor(mDiagnostics, &mDirectiveHandler, pp::PreprocessorSettings()),
Jamie Madillacb4b812016-11-07 13:50:29 -0500121 mScanner(nullptr),
122 mUsesFragData(false),
123 mUsesFragColor(false),
124 mUsesSecondaryOutputs(false),
125 mMinProgramTexelOffset(resources.MinProgramTexelOffset),
126 mMaxProgramTexelOffset(resources.MaxProgramTexelOffset),
Olli Etuaho09b04a22016-12-15 13:30:26 +0000127 mMultiviewAvailable(resources.OVR_multiview == 1),
Jamie Madillacb4b812016-11-07 13:50:29 -0500128 mComputeShaderLocalSizeDeclared(false),
Olli Etuaho09b04a22016-12-15 13:30:26 +0000129 mNumViews(-1),
130 mMaxNumViews(resources.MaxViewsOVR),
Olli Etuaho43364892017-02-13 16:00:12 +0000131 mMaxImageUnits(resources.MaxImageUnits),
132 mMaxCombinedTextureImageUnits(resources.MaxCombinedTextureImageUnits),
Olli Etuaho6ca2b652017-02-19 18:05:10 +0000133 mMaxUniformLocations(resources.MaxUniformLocations),
Jamie Madillacb4b812016-11-07 13:50:29 -0500134 mDeclaringFunction(false)
135{
136 mComputeShaderLocalSize.fill(-1);
137}
138
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000139//
140// Look at a '.' field selector string and change it into offsets
141// for a vector.
142//
Jamie Madillb98c3a82015-07-23 14:26:04 -0400143bool TParseContext::parseVectorFields(const TString &compString,
144 int vecSize,
145 TVectorFields &fields,
Arun Patole7e7e68d2015-05-22 12:02:25 +0530146 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000147{
Jamie Madillb98c3a82015-07-23 14:26:04 -0400148 fields.num = (int)compString.size();
Arun Patole7e7e68d2015-05-22 12:02:25 +0530149 if (fields.num > 4)
150 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000151 error(line, "illegal vector field selection", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000152 return false;
153 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000154
Jamie Madillb98c3a82015-07-23 14:26:04 -0400155 enum
156 {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000157 exyzw,
158 ergba,
daniel@transgaming.comb3077d02013-01-11 04:12:09 +0000159 estpq
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000160 } fieldSet[4];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000161
Arun Patole7e7e68d2015-05-22 12:02:25 +0530162 for (int i = 0; i < fields.num; ++i)
163 {
164 switch (compString[i])
165 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400166 case 'x':
167 fields.offsets[i] = 0;
168 fieldSet[i] = exyzw;
169 break;
170 case 'r':
171 fields.offsets[i] = 0;
172 fieldSet[i] = ergba;
173 break;
174 case 's':
175 fields.offsets[i] = 0;
176 fieldSet[i] = estpq;
177 break;
178 case 'y':
179 fields.offsets[i] = 1;
180 fieldSet[i] = exyzw;
181 break;
182 case 'g':
183 fields.offsets[i] = 1;
184 fieldSet[i] = ergba;
185 break;
186 case 't':
187 fields.offsets[i] = 1;
188 fieldSet[i] = estpq;
189 break;
190 case 'z':
191 fields.offsets[i] = 2;
192 fieldSet[i] = exyzw;
193 break;
194 case 'b':
195 fields.offsets[i] = 2;
196 fieldSet[i] = ergba;
197 break;
198 case 'p':
199 fields.offsets[i] = 2;
200 fieldSet[i] = estpq;
201 break;
Arun Patole7e7e68d2015-05-22 12:02:25 +0530202
Jamie Madillb98c3a82015-07-23 14:26:04 -0400203 case 'w':
204 fields.offsets[i] = 3;
205 fieldSet[i] = exyzw;
206 break;
207 case 'a':
208 fields.offsets[i] = 3;
209 fieldSet[i] = ergba;
210 break;
211 case 'q':
212 fields.offsets[i] = 3;
213 fieldSet[i] = estpq;
214 break;
215 default:
216 error(line, "illegal vector field selection", compString.c_str());
217 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000218 }
219 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000220
Arun Patole7e7e68d2015-05-22 12:02:25 +0530221 for (int i = 0; i < fields.num; ++i)
222 {
223 if (fields.offsets[i] >= vecSize)
224 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400225 error(line, "vector field selection out of range", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000226 return false;
227 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000228
Arun Patole7e7e68d2015-05-22 12:02:25 +0530229 if (i > 0)
230 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400231 if (fieldSet[i] != fieldSet[i - 1])
Arun Patole7e7e68d2015-05-22 12:02:25 +0530232 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400233 error(line, "illegal - vector component fields not from the same set",
234 compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000235 return false;
236 }
237 }
238 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000239
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000240 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000241}
242
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000243///////////////////////////////////////////////////////////////////////
244//
245// Errors
246//
247////////////////////////////////////////////////////////////////////////
248
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000249//
250// Used by flex/bison to output all syntax and parsing errors.
251//
Olli Etuaho4de340a2016-12-16 09:32:03 +0000252void TParseContext::error(const TSourceLoc &loc, const char *reason, const char *token)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000253{
Olli Etuaho77ba4082016-12-16 12:01:18 +0000254 mDiagnostics->error(loc, reason, token);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000255}
256
Olli Etuaho4de340a2016-12-16 09:32:03 +0000257void TParseContext::warning(const TSourceLoc &loc, const char *reason, const char *token)
Arun Patole7e7e68d2015-05-22 12:02:25 +0530258{
Olli Etuaho77ba4082016-12-16 12:01:18 +0000259 mDiagnostics->warning(loc, reason, token);
alokp@chromium.org044a5cf2010-11-12 15:42:16 +0000260}
261
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200262void TParseContext::outOfRangeError(bool isError,
263 const TSourceLoc &loc,
264 const char *reason,
Olli Etuaho4de340a2016-12-16 09:32:03 +0000265 const char *token)
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200266{
267 if (isError)
268 {
Olli Etuaho4de340a2016-12-16 09:32:03 +0000269 error(loc, reason, token);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200270 }
271 else
272 {
Olli Etuaho4de340a2016-12-16 09:32:03 +0000273 warning(loc, reason, token);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200274 }
275}
276
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000277//
278// Same error message for all places assignments don't work.
279//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530280void TParseContext::assignError(const TSourceLoc &line, const char *op, TString left, TString right)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000281{
Olli Etuaho4de340a2016-12-16 09:32:03 +0000282 std::stringstream reasonStream;
283 reasonStream << "cannot convert from '" << right << "' to '" << left << "'";
284 std::string reason = reasonStream.str();
285 error(line, reason.c_str(), op);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000286}
287
288//
289// Same error message for all places unary operations don't work.
290//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530291void TParseContext::unaryOpError(const TSourceLoc &line, const char *op, TString operand)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000292{
Olli Etuaho4de340a2016-12-16 09:32:03 +0000293 std::stringstream reasonStream;
294 reasonStream << "wrong operand type - no operation '" << op
295 << "' exists that takes an operand of type " << operand
296 << " (or there is no acceptable conversion)";
297 std::string reason = reasonStream.str();
298 error(line, reason.c_str(), op);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000299}
300
301//
302// Same error message for all binary operations don't work.
303//
Jamie Madillb98c3a82015-07-23 14:26:04 -0400304void TParseContext::binaryOpError(const TSourceLoc &line,
305 const char *op,
306 TString left,
307 TString right)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000308{
Olli Etuaho4de340a2016-12-16 09:32:03 +0000309 std::stringstream reasonStream;
310 reasonStream << "wrong operand types - no operation '" << op
311 << "' exists that takes a left-hand operand of type '" << left
312 << "' and a right operand of type '" << right
313 << "' (or there is no acceptable conversion)";
314 std::string reason = reasonStream.str();
315 error(line, reason.c_str(), op);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000316}
317
Olli Etuaho856c4972016-08-08 11:38:39 +0300318void TParseContext::checkPrecisionSpecified(const TSourceLoc &line,
319 TPrecision precision,
320 TBasicType type)
Arun Patole7e7e68d2015-05-22 12:02:25 +0530321{
Jamie Madill6e06b1f2015-05-14 10:01:17 -0400322 if (!mChecksPrecisionErrors)
Olli Etuaho383b7912016-08-05 11:22:59 +0300323 return;
Martin Radev70866b82016-07-22 15:27:42 +0300324
325 if (precision != EbpUndefined && !SupportsPrecision(type))
326 {
327 error(line, "illegal type for precision qualifier", getBasicString(type));
328 }
329
Olli Etuaho183d7e22015-11-20 15:59:09 +0200330 if (precision == EbpUndefined)
Arun Patole7e7e68d2015-05-22 12:02:25 +0530331 {
Olli Etuaho183d7e22015-11-20 15:59:09 +0200332 switch (type)
333 {
334 case EbtFloat:
Jamie Madillb98c3a82015-07-23 14:26:04 -0400335 error(line, "No precision specified for (float)", "");
Olli Etuaho383b7912016-08-05 11:22:59 +0300336 return;
Olli Etuaho183d7e22015-11-20 15:59:09 +0200337 case EbtInt:
338 case EbtUInt:
339 UNREACHABLE(); // there's always a predeclared qualifier
Jamie Madillb98c3a82015-07-23 14:26:04 -0400340 error(line, "No precision specified (int)", "");
Olli Etuaho383b7912016-08-05 11:22:59 +0300341 return;
Olli Etuaho183d7e22015-11-20 15:59:09 +0200342 default:
343 if (IsSampler(type))
344 {
345 error(line, "No precision specified (sampler)", "");
Olli Etuaho383b7912016-08-05 11:22:59 +0300346 return;
Olli Etuaho183d7e22015-11-20 15:59:09 +0200347 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300348 if (IsImage(type))
349 {
350 error(line, "No precision specified (image)", "");
351 return;
352 }
Olli Etuaho183d7e22015-11-20 15:59:09 +0200353 }
daniel@transgaming.coma5d76232010-05-17 09:58:47 +0000354 }
daniel@transgaming.coma5d76232010-05-17 09:58:47 +0000355}
356
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000357// Both test and if necessary, spit out an error, to see if the node is really
358// an l-value that can be operated on this way.
Olli Etuaho856c4972016-08-08 11:38:39 +0300359bool TParseContext::checkCanBeLValue(const TSourceLoc &line, const char *op, TIntermTyped *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000360{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500361 TIntermSymbol *symNode = node->getAsSymbolNode();
362 TIntermBinary *binaryNode = node->getAsBinaryNode();
Olli Etuahob6fa0432016-09-28 16:28:05 +0100363 TIntermSwizzle *swizzleNode = node->getAsSwizzleNode();
364
365 if (swizzleNode)
366 {
367 bool ok = checkCanBeLValue(line, op, swizzleNode->getOperand());
368 if (ok && swizzleNode->hasDuplicateOffsets())
369 {
370 error(line, " l-value of swizzle cannot have duplicate components", op);
371 return false;
372 }
373 return ok;
374 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000375
Arun Patole7e7e68d2015-05-22 12:02:25 +0530376 if (binaryNode)
377 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400378 switch (binaryNode->getOp())
Arun Patole7e7e68d2015-05-22 12:02:25 +0530379 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400380 case EOpIndexDirect:
381 case EOpIndexIndirect:
382 case EOpIndexDirectStruct:
383 case EOpIndexDirectInterfaceBlock:
Olli Etuaho856c4972016-08-08 11:38:39 +0300384 return checkCanBeLValue(line, op, binaryNode->getLeft());
Jamie Madillb98c3a82015-07-23 14:26:04 -0400385 default:
386 break;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000387 }
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000388 error(line, " l-value required", op);
Olli Etuaho8a176262016-08-16 14:23:01 +0300389 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000390 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000391
Arun Patole7e7e68d2015-05-22 12:02:25 +0530392 const char *message = 0;
393 switch (node->getQualifier())
394 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400395 case EvqConst:
396 message = "can't modify a const";
397 break;
398 case EvqConstReadOnly:
399 message = "can't modify a const";
400 break;
401 case EvqAttribute:
402 message = "can't modify an attribute";
403 break;
404 case EvqFragmentIn:
405 message = "can't modify an input";
406 break;
407 case EvqVertexIn:
408 message = "can't modify an input";
409 break;
410 case EvqUniform:
411 message = "can't modify a uniform";
412 break;
413 case EvqVaryingIn:
414 message = "can't modify a varying";
415 break;
416 case EvqFragCoord:
417 message = "can't modify gl_FragCoord";
418 break;
419 case EvqFrontFacing:
420 message = "can't modify gl_FrontFacing";
421 break;
422 case EvqPointCoord:
423 message = "can't modify gl_PointCoord";
424 break;
Martin Radevb0883602016-08-04 17:48:58 +0300425 case EvqNumWorkGroups:
426 message = "can't modify gl_NumWorkGroups";
427 break;
428 case EvqWorkGroupSize:
429 message = "can't modify gl_WorkGroupSize";
430 break;
431 case EvqWorkGroupID:
432 message = "can't modify gl_WorkGroupID";
433 break;
434 case EvqLocalInvocationID:
435 message = "can't modify gl_LocalInvocationID";
436 break;
437 case EvqGlobalInvocationID:
438 message = "can't modify gl_GlobalInvocationID";
439 break;
440 case EvqLocalInvocationIndex:
441 message = "can't modify gl_LocalInvocationIndex";
442 break;
Martin Radev802abe02016-08-04 17:48:32 +0300443 case EvqComputeIn:
444 message = "can't modify work group size variable";
445 break;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400446 default:
447 //
448 // Type that can't be written to?
449 //
450 if (node->getBasicType() == EbtVoid)
451 {
452 message = "can't modify void";
453 }
454 if (IsSampler(node->getBasicType()))
455 {
456 message = "can't modify a sampler";
457 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300458 if (IsImage(node->getBasicType()))
459 {
460 message = "can't modify an image";
461 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000462 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000463
Arun Patole7e7e68d2015-05-22 12:02:25 +0530464 if (message == 0 && binaryNode == 0 && symNode == 0)
465 {
Olli Etuaho4de340a2016-12-16 09:32:03 +0000466 error(line, "l-value required", op);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000467
Olli Etuaho8a176262016-08-16 14:23:01 +0300468 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000469 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000470
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000471 //
472 // Everything else is okay, no error.
473 //
474 if (message == 0)
Olli Etuaho8a176262016-08-16 14:23:01 +0300475 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000476
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000477 //
478 // If we get here, we have an error and a message.
479 //
Arun Patole7e7e68d2015-05-22 12:02:25 +0530480 if (symNode)
481 {
Olli Etuaho4de340a2016-12-16 09:32:03 +0000482 const char *symbol = symNode->getSymbol().c_str();
483 std::stringstream reasonStream;
484 reasonStream << "l-value required (" << message << " \"" << symbol << "\")";
485 std::string reason = reasonStream.str();
486 error(line, reason.c_str(), op);
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000487 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530488 else
489 {
Olli Etuaho4de340a2016-12-16 09:32:03 +0000490 std::stringstream reasonStream;
491 reasonStream << "l-value required (" << message << ")";
492 std::string reason = reasonStream.str();
493 error(line, reason.c_str(), op);
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000494 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000495
Olli Etuaho8a176262016-08-16 14:23:01 +0300496 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000497}
498
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000499// Both test, and if necessary spit out an error, to see if the node is really
500// a constant.
Olli Etuaho856c4972016-08-08 11:38:39 +0300501void TParseContext::checkIsConst(TIntermTyped *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000502{
Olli Etuaho383b7912016-08-05 11:22:59 +0300503 if (node->getQualifier() != EvqConst)
504 {
505 error(node->getLine(), "constant expression required", "");
506 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000507}
508
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000509// Both test, and if necessary spit out an error, to see if the node is really
510// an integer.
Olli Etuaho856c4972016-08-08 11:38:39 +0300511void TParseContext::checkIsScalarInteger(TIntermTyped *node, const char *token)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000512{
Olli Etuaho383b7912016-08-05 11:22:59 +0300513 if (!node->isScalarInt())
514 {
515 error(node->getLine(), "integer expression required", token);
516 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000517}
518
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000519// Both test, and if necessary spit out an error, to see if we are currently
520// globally scoped.
Qiankun Miaof69682b2016-08-16 14:50:42 +0800521bool TParseContext::checkIsAtGlobalLevel(const TSourceLoc &line, const char *token)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000522{
Olli Etuaho856c4972016-08-08 11:38:39 +0300523 if (!symbolTable.atGlobalLevel())
Olli Etuaho383b7912016-08-05 11:22:59 +0300524 {
525 error(line, "only allowed at global scope", token);
Qiankun Miaof69682b2016-08-16 14:50:42 +0800526 return false;
Olli Etuaho383b7912016-08-05 11:22:59 +0300527 }
Qiankun Miaof69682b2016-08-16 14:50:42 +0800528 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000529}
530
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000531// For now, keep it simple: if it starts "gl_", it's reserved, independent
532// of scope. Except, if the symbol table is at the built-in push-level,
533// which is when we are parsing built-ins.
alokp@chromium.org613ef312010-07-21 18:54:22 +0000534// Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a
535// webgl shader.
Olli Etuaho856c4972016-08-08 11:38:39 +0300536bool TParseContext::checkIsNotReserved(const TSourceLoc &line, const TString &identifier)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000537{
Arun Patole7e7e68d2015-05-22 12:02:25 +0530538 static const char *reservedErrMsg = "reserved built-in name";
539 if (!symbolTable.atBuiltInLevel())
540 {
541 if (identifier.compare(0, 3, "gl_") == 0)
542 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000543 error(line, reservedErrMsg, "gl_");
Olli Etuaho8a176262016-08-16 14:23:01 +0300544 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000545 }
Jamie Madillacb4b812016-11-07 13:50:29 -0500546 if (sh::IsWebGLBasedSpec(mShaderSpec))
Arun Patole7e7e68d2015-05-22 12:02:25 +0530547 {
548 if (identifier.compare(0, 6, "webgl_") == 0)
549 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000550 error(line, reservedErrMsg, "webgl_");
Olli Etuaho8a176262016-08-16 14:23:01 +0300551 return false;
alokp@chromium.org613ef312010-07-21 18:54:22 +0000552 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530553 if (identifier.compare(0, 7, "_webgl_") == 0)
554 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000555 error(line, reservedErrMsg, "_webgl_");
Olli Etuaho8a176262016-08-16 14:23:01 +0300556 return false;
alokp@chromium.org613ef312010-07-21 18:54:22 +0000557 }
558 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530559 if (identifier.find("__") != TString::npos)
560 {
561 error(line,
Jamie Madillb98c3a82015-07-23 14:26:04 -0400562 "identifiers containing two consecutive underscores (__) are reserved as "
563 "possible future keywords",
Arun Patole7e7e68d2015-05-22 12:02:25 +0530564 identifier.c_str());
Olli Etuaho8a176262016-08-16 14:23:01 +0300565 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000566 }
567 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000568
Olli Etuaho8a176262016-08-16 14:23:01 +0300569 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000570}
571
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000572// Make sure there is enough data provided to the constructor to build
573// something of the type of the constructor. Also returns the type of
574// the constructor.
Olli Etuaho856c4972016-08-08 11:38:39 +0300575bool TParseContext::checkConstructorArguments(const TSourceLoc &line,
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800576 const TIntermSequence *arguments,
Olli Etuaho856c4972016-08-08 11:38:39 +0300577 TOperator op,
578 const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000579{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000580 bool constructingMatrix = false;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400581 switch (op)
Arun Patole7e7e68d2015-05-22 12:02:25 +0530582 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400583 case EOpConstructMat2:
584 case EOpConstructMat2x3:
585 case EOpConstructMat2x4:
586 case EOpConstructMat3x2:
587 case EOpConstructMat3:
588 case EOpConstructMat3x4:
589 case EOpConstructMat4x2:
590 case EOpConstructMat4x3:
591 case EOpConstructMat4:
592 constructingMatrix = true;
593 break;
594 default:
595 break;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000596 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000597
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000598 //
599 // Note: It's okay to have too many components available, but not okay to have unused
600 // arguments. 'full' will go to true when enough args have been seen. If we loop
601 // again, there is an extra argument, so 'overfull' will become true.
602 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000603
Jamie Madillb98c3a82015-07-23 14:26:04 -0400604 size_t size = 0;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400605 bool full = false;
606 bool overFull = false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000607 bool matrixInMatrix = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500608 bool arrayArg = false;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800609 for (TIntermNode *arg : *arguments)
Arun Patole7e7e68d2015-05-22 12:02:25 +0530610 {
Olli Etuaho72d10202017-01-19 15:58:30 +0000611 const TIntermTyped *argTyped = arg->getAsTyped();
612 size += argTyped->getType().getObjectSize();
Arun Patole7e7e68d2015-05-22 12:02:25 +0530613
Olli Etuaho72d10202017-01-19 15:58:30 +0000614 if (constructingMatrix && argTyped->getType().isMatrix())
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000615 matrixInMatrix = true;
616 if (full)
617 overFull = true;
Olli Etuaho856c4972016-08-08 11:38:39 +0300618 if (op != EOpConstructStruct && !type.isArray() && size >= type.getObjectSize())
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000619 full = true;
Olli Etuaho72d10202017-01-19 15:58:30 +0000620 if (argTyped->getType().isArray())
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000621 arrayArg = true;
622 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530623
Olli Etuaho856c4972016-08-08 11:38:39 +0300624 if (type.isArray())
Olli Etuaho376f1b52015-04-13 13:23:41 +0300625 {
Olli Etuaho856c4972016-08-08 11:38:39 +0300626 // The size of an unsized constructor should already have been determined.
627 ASSERT(!type.isUnsizedArray());
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800628 if (static_cast<size_t>(type.getArraySize()) != arguments->size())
Olli Etuaho376f1b52015-04-13 13:23:41 +0300629 {
630 error(line, "array constructor needs one argument per array element", "constructor");
Olli Etuaho8a176262016-08-16 14:23:01 +0300631 return false;
Olli Etuaho376f1b52015-04-13 13:23:41 +0300632 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000633 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000634
Arun Patole7e7e68d2015-05-22 12:02:25 +0530635 if (arrayArg && op != EOpConstructStruct)
636 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000637 error(line, "constructing from a non-dereferenced array", "constructor");
Olli Etuaho8a176262016-08-16 14:23:01 +0300638 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000639 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000640
Olli Etuaho856c4972016-08-08 11:38:39 +0300641 if (matrixInMatrix && !type.isArray())
Arun Patole7e7e68d2015-05-22 12:02:25 +0530642 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800643 if (arguments->size() != 1)
Arun Patole7e7e68d2015-05-22 12:02:25 +0530644 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400645 error(line, "constructing matrix from matrix can only take one argument",
646 "constructor");
Olli Etuaho8a176262016-08-16 14:23:01 +0300647 return false;
daniel@transgaming.combef0b6d2010-04-29 03:32:39 +0000648 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000649 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000650
Arun Patole7e7e68d2015-05-22 12:02:25 +0530651 if (overFull)
652 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000653 error(line, "too many arguments", "constructor");
Olli Etuaho8a176262016-08-16 14:23:01 +0300654 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000655 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530656
Olli Etuaho856c4972016-08-08 11:38:39 +0300657 if (op == EOpConstructStruct && !type.isArray() &&
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800658 type.getStruct()->fields().size() != arguments->size())
Arun Patole7e7e68d2015-05-22 12:02:25 +0530659 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400660 error(line,
661 "Number of constructor parameters does not match the number of structure fields",
662 "constructor");
Olli Etuaho8a176262016-08-16 14:23:01 +0300663 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000664 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000665
Olli Etuaho856c4972016-08-08 11:38:39 +0300666 if (!type.isMatrix() || !matrixInMatrix)
Arun Patole7e7e68d2015-05-22 12:02:25 +0530667 {
Olli Etuaho856c4972016-08-08 11:38:39 +0300668 if ((op != EOpConstructStruct && size != 1 && size < type.getObjectSize()) ||
669 (op == EOpConstructStruct && size < type.getObjectSize()))
Arun Patole7e7e68d2015-05-22 12:02:25 +0530670 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000671 error(line, "not enough data provided for construction", "constructor");
Olli Etuaho8a176262016-08-16 14:23:01 +0300672 return false;
daniel@transgaming.combef0b6d2010-04-29 03:32:39 +0000673 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000674 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000675
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800676 if (arguments->empty())
Arun Patole7e7e68d2015-05-22 12:02:25 +0530677 {
Olli Etuaho15c2ac32015-11-09 15:51:43 +0200678 error(line, "constructor does not have any arguments", "constructor");
Olli Etuaho8a176262016-08-16 14:23:01 +0300679 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000680 }
Olli Etuaho15c2ac32015-11-09 15:51:43 +0200681
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800682 for (TIntermNode *const &argNode : *arguments)
Arun Patole7e7e68d2015-05-22 12:02:25 +0530683 {
Olli Etuaho15c2ac32015-11-09 15:51:43 +0200684 TIntermTyped *argTyped = argNode->getAsTyped();
685 ASSERT(argTyped != nullptr);
686 if (op != EOpConstructStruct && IsSampler(argTyped->getBasicType()))
687 {
688 error(line, "cannot convert a sampler", "constructor");
Olli Etuaho8a176262016-08-16 14:23:01 +0300689 return false;
Olli Etuaho15c2ac32015-11-09 15:51:43 +0200690 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300691 if (op != EOpConstructStruct && IsImage(argTyped->getBasicType()))
692 {
693 error(line, "cannot convert an image", "constructor");
694 return false;
695 }
Olli Etuaho15c2ac32015-11-09 15:51:43 +0200696 if (argTyped->getBasicType() == EbtVoid)
697 {
698 error(line, "cannot convert a void", "constructor");
Olli Etuaho8a176262016-08-16 14:23:01 +0300699 return false;
Olli Etuaho15c2ac32015-11-09 15:51:43 +0200700 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000701 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000702
Olli Etuaho856c4972016-08-08 11:38:39 +0300703 if (type.isArray())
704 {
705 // GLSL ES 3.00 section 5.4.4: Each argument must be the same type as the element type of
706 // the array.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800707 for (TIntermNode *const &argNode : *arguments)
Olli Etuaho856c4972016-08-08 11:38:39 +0300708 {
709 const TType &argType = argNode->getAsTyped()->getType();
Jamie Madill34bf2d92017-02-06 13:40:59 -0500710 // It has already been checked that the argument is not an array, but we can arrive
711 // here due to prior error conditions.
712 if (argType.isArray())
713 {
714 return false;
715 }
Olli Etuaho856c4972016-08-08 11:38:39 +0300716 if (!argType.sameElementType(type))
717 {
Olli Etuaho4de340a2016-12-16 09:32:03 +0000718 error(line, "Array constructor argument has an incorrect type", "constructor");
Olli Etuaho8a176262016-08-16 14:23:01 +0300719 return false;
Olli Etuaho856c4972016-08-08 11:38:39 +0300720 }
721 }
722 }
723 else if (op == EOpConstructStruct)
724 {
725 const TFieldList &fields = type.getStruct()->fields();
Olli Etuaho856c4972016-08-08 11:38:39 +0300726
727 for (size_t i = 0; i < fields.size(); i++)
728 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800729 if (i >= arguments->size() ||
730 (*arguments)[i]->getAsTyped()->getType() != *fields[i]->type())
Olli Etuaho856c4972016-08-08 11:38:39 +0300731 {
732 error(line, "Structure constructor arguments do not match structure fields",
Olli Etuaho4de340a2016-12-16 09:32:03 +0000733 "constructor");
Olli Etuaho8a176262016-08-16 14:23:01 +0300734 return false;
Olli Etuaho856c4972016-08-08 11:38:39 +0300735 }
736 }
737 }
738
Olli Etuaho8a176262016-08-16 14:23:01 +0300739 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000740}
741
Jamie Madillb98c3a82015-07-23 14:26:04 -0400742// This function checks to see if a void variable has been declared and raise an error message for
743// such a case
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000744//
745// returns true in case of an error
746//
Olli Etuaho856c4972016-08-08 11:38:39 +0300747bool TParseContext::checkIsNonVoid(const TSourceLoc &line,
Jamie Madillb98c3a82015-07-23 14:26:04 -0400748 const TString &identifier,
749 const TBasicType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000750{
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +0300751 if (type == EbtVoid)
752 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000753 error(line, "illegal use of type 'void'", identifier.c_str());
Olli Etuaho8a176262016-08-16 14:23:01 +0300754 return false;
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +0300755 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000756
Olli Etuaho8a176262016-08-16 14:23:01 +0300757 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000758}
759
Jamie Madillb98c3a82015-07-23 14:26:04 -0400760// This function checks to see if the node (for the expression) contains a scalar boolean expression
Olli Etuaho383b7912016-08-05 11:22:59 +0300761// or not.
Olli Etuaho856c4972016-08-08 11:38:39 +0300762void TParseContext::checkIsScalarBool(const TSourceLoc &line, const TIntermTyped *type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000763{
Arun Patole7e7e68d2015-05-22 12:02:25 +0530764 if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector())
765 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000766 error(line, "boolean expression expected", "");
Arun Patole7e7e68d2015-05-22 12:02:25 +0530767 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000768}
769
Jamie Madillb98c3a82015-07-23 14:26:04 -0400770// This function checks to see if the node (for the expression) contains a scalar boolean expression
Olli Etuaho383b7912016-08-05 11:22:59 +0300771// or not.
Olli Etuaho856c4972016-08-08 11:38:39 +0300772void TParseContext::checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000773{
Martin Radev4a9cd802016-09-01 16:51:51 +0300774 if (pType.getBasicType() != EbtBool || pType.isAggregate())
Arun Patole7e7e68d2015-05-22 12:02:25 +0530775 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000776 error(line, "boolean expression expected", "");
Arun Patole7e7e68d2015-05-22 12:02:25 +0530777 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000778}
779
Olli Etuaho856c4972016-08-08 11:38:39 +0300780bool TParseContext::checkIsNotSampler(const TSourceLoc &line,
Martin Radev4a9cd802016-09-01 16:51:51 +0300781 const TTypeSpecifierNonArray &pType,
Jamie Madillb98c3a82015-07-23 14:26:04 -0400782 const char *reason)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000783{
Arun Patole7e7e68d2015-05-22 12:02:25 +0530784 if (pType.type == EbtStruct)
785 {
Martin Radev2cc85b32016-08-05 16:22:53 +0300786 if (ContainsSampler(*pType.userDef))
Arun Patole7e7e68d2015-05-22 12:02:25 +0530787 {
Olli Etuaho4de340a2016-12-16 09:32:03 +0000788 std::stringstream reasonStream;
789 reasonStream << reason << " (structure contains a sampler)";
790 std::string reasonStr = reasonStream.str();
791 error(line, reasonStr.c_str(), getBasicString(pType.type));
Olli Etuaho8a176262016-08-16 14:23:01 +0300792 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000793 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530794
Olli Etuaho8a176262016-08-16 14:23:01 +0300795 return true;
Arun Patole7e7e68d2015-05-22 12:02:25 +0530796 }
797 else if (IsSampler(pType.type))
798 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000799 error(line, reason, getBasicString(pType.type));
Olli Etuaho8a176262016-08-16 14:23:01 +0300800 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000801 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000802
Olli Etuaho8a176262016-08-16 14:23:01 +0300803 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000804}
805
Martin Radev2cc85b32016-08-05 16:22:53 +0300806bool TParseContext::checkIsNotImage(const TSourceLoc &line,
807 const TTypeSpecifierNonArray &pType,
808 const char *reason)
809{
810 if (pType.type == EbtStruct)
811 {
812 if (ContainsImage(*pType.userDef))
813 {
Olli Etuaho4de340a2016-12-16 09:32:03 +0000814 std::stringstream reasonStream;
815 reasonStream << reason << " (structure contains an image)";
816 std::string reasonStr = reasonStream.str();
817 error(line, reasonStr.c_str(), getBasicString(pType.type));
Martin Radev2cc85b32016-08-05 16:22:53 +0300818
819 return false;
820 }
821
822 return true;
823 }
824 else if (IsImage(pType.type))
825 {
826 error(line, reason, getBasicString(pType.type));
827
828 return false;
829 }
830
831 return true;
832}
833
Olli Etuaho856c4972016-08-08 11:38:39 +0300834void TParseContext::checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line,
835 const TPublicType &pType)
Jamie Madill0bd18df2013-06-20 11:55:52 -0400836{
837 if (pType.layoutQualifier.location != -1)
838 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400839 error(line, "location must only be specified for a single input or output variable",
840 "location");
Jamie Madill0bd18df2013-06-20 11:55:52 -0400841 }
Jamie Madill0bd18df2013-06-20 11:55:52 -0400842}
843
Olli Etuaho856c4972016-08-08 11:38:39 +0300844void TParseContext::checkLocationIsNotSpecified(const TSourceLoc &location,
845 const TLayoutQualifier &layoutQualifier)
846{
847 if (layoutQualifier.location != -1)
848 {
Olli Etuaho6ca2b652017-02-19 18:05:10 +0000849 const char *errorMsg = "invalid layout qualifier: only valid on program inputs and outputs";
850 if (mShaderVersion >= 310)
851 {
852 errorMsg =
853 "invalid layout qualifier: only valid on program inputs, outputs, and uniforms";
854 }
855 error(location, errorMsg, "location");
Olli Etuaho856c4972016-08-08 11:38:39 +0300856 }
857}
858
Martin Radev2cc85b32016-08-05 16:22:53 +0300859void TParseContext::checkOutParameterIsNotOpaqueType(const TSourceLoc &line,
860 TQualifier qualifier,
861 const TType &type)
862{
863 checkOutParameterIsNotSampler(line, qualifier, type);
864 checkOutParameterIsNotImage(line, qualifier, type);
865}
866
Olli Etuaho856c4972016-08-08 11:38:39 +0300867void TParseContext::checkOutParameterIsNotSampler(const TSourceLoc &line,
868 TQualifier qualifier,
869 const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000870{
Martin Radev2cc85b32016-08-05 16:22:53 +0300871 ASSERT(qualifier == EvqOut || qualifier == EvqInOut);
872 if (IsSampler(type.getBasicType()))
Arun Patole7e7e68d2015-05-22 12:02:25 +0530873 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000874 error(line, "samplers cannot be output parameters", type.getBasicString());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000875 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000876}
877
Martin Radev2cc85b32016-08-05 16:22:53 +0300878void TParseContext::checkOutParameterIsNotImage(const TSourceLoc &line,
879 TQualifier qualifier,
880 const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000881{
Martin Radev2cc85b32016-08-05 16:22:53 +0300882 ASSERT(qualifier == EvqOut || qualifier == EvqInOut);
883 if (IsImage(type.getBasicType()))
Arun Patole7e7e68d2015-05-22 12:02:25 +0530884 {
Martin Radev2cc85b32016-08-05 16:22:53 +0300885 error(line, "images cannot be output parameters", type.getBasicString());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000886 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000887}
888
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000889// Do size checking for an array type's size.
Olli Etuaho856c4972016-08-08 11:38:39 +0300890unsigned int TParseContext::checkIsValidArraySize(const TSourceLoc &line, TIntermTyped *expr)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000891{
Arun Patole7e7e68d2015-05-22 12:02:25 +0530892 TIntermConstantUnion *constant = expr->getAsConstantUnion();
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000893
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200894 // TODO(oetuaho@nvidia.com): Get rid of the constant == nullptr check here once all constant
895 // expressions can be folded. Right now we don't allow constant expressions that ANGLE can't
896 // fold as array size.
897 if (expr->getQualifier() != EvqConst || constant == nullptr || !constant->isScalarInt())
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000898 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000899 error(line, "array size must be a constant integer expression", "");
Olli Etuaho856c4972016-08-08 11:38:39 +0300900 return 1u;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000901 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000902
Olli Etuaho856c4972016-08-08 11:38:39 +0300903 unsigned int size = 0u;
Nicolas Capens906744a2014-06-06 15:18:07 -0400904
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000905 if (constant->getBasicType() == EbtUInt)
906 {
Olli Etuaho856c4972016-08-08 11:38:39 +0300907 size = constant->getUConst(0);
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000908 }
909 else
910 {
Olli Etuaho856c4972016-08-08 11:38:39 +0300911 int signedSize = constant->getIConst(0);
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000912
Olli Etuaho856c4972016-08-08 11:38:39 +0300913 if (signedSize < 0)
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000914 {
Nicolas Capens906744a2014-06-06 15:18:07 -0400915 error(line, "array size must be non-negative", "");
Olli Etuaho856c4972016-08-08 11:38:39 +0300916 return 1u;
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000917 }
Nicolas Capens906744a2014-06-06 15:18:07 -0400918
Olli Etuaho856c4972016-08-08 11:38:39 +0300919 size = static_cast<unsigned int>(signedSize);
Nicolas Capens906744a2014-06-06 15:18:07 -0400920 }
921
Olli Etuaho856c4972016-08-08 11:38:39 +0300922 if (size == 0u)
Nicolas Capens906744a2014-06-06 15:18:07 -0400923 {
924 error(line, "array size must be greater than zero", "");
Olli Etuaho856c4972016-08-08 11:38:39 +0300925 return 1u;
Nicolas Capens906744a2014-06-06 15:18:07 -0400926 }
927
928 // The size of arrays is restricted here to prevent issues further down the
929 // compiler/translator/driver stack. Shader Model 5 generation hardware is limited to
930 // 4096 registers so this should be reasonable even for aggressively optimizable code.
931 const unsigned int sizeLimit = 65536;
932
Olli Etuaho856c4972016-08-08 11:38:39 +0300933 if (size > sizeLimit)
Nicolas Capens906744a2014-06-06 15:18:07 -0400934 {
935 error(line, "array size too large", "");
Olli Etuaho856c4972016-08-08 11:38:39 +0300936 return 1u;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000937 }
Olli Etuaho856c4972016-08-08 11:38:39 +0300938
939 return size;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000940}
941
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000942// See if this qualifier can be an array.
Olli Etuaho8a176262016-08-16 14:23:01 +0300943bool TParseContext::checkIsValidQualifierForArray(const TSourceLoc &line,
944 const TPublicType &elementQualifier)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000945{
Olli Etuaho8a176262016-08-16 14:23:01 +0300946 if ((elementQualifier.qualifier == EvqAttribute) ||
947 (elementQualifier.qualifier == EvqVertexIn) ||
948 (elementQualifier.qualifier == EvqConst && mShaderVersion < 300))
Olli Etuaho3739d232015-04-08 12:23:44 +0300949 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400950 error(line, "cannot declare arrays of this qualifier",
Olli Etuaho8a176262016-08-16 14:23:01 +0300951 TType(elementQualifier).getQualifierString());
952 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000953 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000954
Olli Etuaho8a176262016-08-16 14:23:01 +0300955 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000956}
957
Olli Etuaho8a176262016-08-16 14:23:01 +0300958// See if this element type can be formed into an array.
959bool TParseContext::checkIsValidTypeForArray(const TSourceLoc &line, const TPublicType &elementType)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000960{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000961 //
962 // Can the type be an array?
963 //
Olli Etuaho8a176262016-08-16 14:23:01 +0300964 if (elementType.array)
Jamie Madill06145232015-05-13 13:10:01 -0400965 {
Olli Etuaho8a176262016-08-16 14:23:01 +0300966 error(line, "cannot declare arrays of arrays",
967 TType(elementType).getCompleteString().c_str());
968 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000969 }
Olli Etuahocc36b982015-07-10 14:14:18 +0300970 // In ESSL1.00 shaders, structs cannot be varying (section 4.3.5). This is checked elsewhere.
971 // In ESSL3.00 shaders, struct inputs/outputs are allowed but not arrays of structs (section
972 // 4.3.4).
Martin Radev4a9cd802016-09-01 16:51:51 +0300973 if (mShaderVersion >= 300 && elementType.getBasicType() == EbtStruct &&
Olli Etuaho8a176262016-08-16 14:23:01 +0300974 sh::IsVarying(elementType.qualifier))
Olli Etuahocc36b982015-07-10 14:14:18 +0300975 {
976 error(line, "cannot declare arrays of structs of this qualifier",
Olli Etuaho8a176262016-08-16 14:23:01 +0300977 TType(elementType).getCompleteString().c_str());
978 return false;
Olli Etuahocc36b982015-07-10 14:14:18 +0300979 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000980
Olli Etuaho8a176262016-08-16 14:23:01 +0300981 return true;
982}
983
984// Check if this qualified element type can be formed into an array.
985bool TParseContext::checkIsValidTypeAndQualifierForArray(const TSourceLoc &indexLocation,
986 const TPublicType &elementType)
987{
988 if (checkIsValidTypeForArray(indexLocation, elementType))
989 {
990 return checkIsValidQualifierForArray(indexLocation, elementType);
991 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000992 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000993}
994
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000995// Enforce non-initializer type/qualifier rules.
Olli Etuaho856c4972016-08-08 11:38:39 +0300996void TParseContext::checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line,
997 const TString &identifier,
998 TPublicType *type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000999{
Olli Etuaho3739d232015-04-08 12:23:44 +03001000 ASSERT(type != nullptr);
1001 if (type->qualifier == EvqConst)
daniel@transgaming.com8abd0b72012-09-27 17:46:07 +00001002 {
1003 // Make the qualifier make sense.
Olli Etuaho3739d232015-04-08 12:23:44 +03001004 type->qualifier = EvqTemporary;
1005
1006 // Generate informative error messages for ESSL1.
1007 // In ESSL3 arrays and structures containing arrays can be constant.
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001008 if (mShaderVersion < 300 && type->isStructureContainingArrays())
daniel@transgaming.com8abd0b72012-09-27 17:46:07 +00001009 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05301010 error(line,
Jamie Madillb98c3a82015-07-23 14:26:04 -04001011 "structures containing arrays may not be declared constant since they cannot be "
1012 "initialized",
Arun Patole7e7e68d2015-05-22 12:02:25 +05301013 identifier.c_str());
daniel@transgaming.com8abd0b72012-09-27 17:46:07 +00001014 }
1015 else
1016 {
1017 error(line, "variables with qualifier 'const' must be initialized", identifier.c_str());
1018 }
Olli Etuaho383b7912016-08-05 11:22:59 +03001019 return;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001020 }
Olli Etuaho376f1b52015-04-13 13:23:41 +03001021 if (type->isUnsizedArray())
1022 {
1023 error(line, "implicitly sized arrays need to be initialized", identifier.c_str());
Olli Etuaho376f1b52015-04-13 13:23:41 +03001024 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001025}
1026
Olli Etuaho2935c582015-04-08 14:32:06 +03001027// Do some simple checks that are shared between all variable declarations,
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001028// and update the symbol table.
1029//
Olli Etuaho2935c582015-04-08 14:32:06 +03001030// Returns true if declaring the variable succeeded.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001031//
Jamie Madillb98c3a82015-07-23 14:26:04 -04001032bool TParseContext::declareVariable(const TSourceLoc &line,
1033 const TString &identifier,
1034 const TType &type,
Olli Etuaho2935c582015-04-08 14:32:06 +03001035 TVariable **variable)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001036{
Olli Etuaho2935c582015-04-08 14:32:06 +03001037 ASSERT((*variable) == nullptr);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001038
Olli Etuaho43364892017-02-13 16:00:12 +00001039 checkBindingIsValid(line, type);
1040
Olli Etuaho856c4972016-08-08 11:38:39 +03001041 bool needsReservedCheck = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001042
Olli Etuaho2935c582015-04-08 14:32:06 +03001043 // gl_LastFragData may be redeclared with a new precision qualifier
1044 if (type.isArray() && identifier.compare(0, 15, "gl_LastFragData") == 0)
1045 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001046 const TVariable *maxDrawBuffers = static_cast<const TVariable *>(
1047 symbolTable.findBuiltIn("gl_MaxDrawBuffers", mShaderVersion));
Olli Etuaho856c4972016-08-08 11:38:39 +03001048 if (static_cast<int>(type.getArraySize()) == maxDrawBuffers->getConstPointer()->getIConst())
Olli Etuaho2935c582015-04-08 14:32:06 +03001049 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001050 if (TSymbol *builtInSymbol = symbolTable.findBuiltIn(identifier, mShaderVersion))
Olli Etuaho2935c582015-04-08 14:32:06 +03001051 {
Olli Etuaho8a176262016-08-16 14:23:01 +03001052 needsReservedCheck = !checkCanUseExtension(line, builtInSymbol->getExtension());
Olli Etuaho2935c582015-04-08 14:32:06 +03001053 }
1054 }
1055 else
1056 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001057 error(line, "redeclaration of gl_LastFragData with size != gl_MaxDrawBuffers",
1058 identifier.c_str());
Olli Etuaho2935c582015-04-08 14:32:06 +03001059 return false;
1060 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001061 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001062
Olli Etuaho8a176262016-08-16 14:23:01 +03001063 if (needsReservedCheck && !checkIsNotReserved(line, identifier))
Olli Etuaho2935c582015-04-08 14:32:06 +03001064 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001065
Olli Etuaho2935c582015-04-08 14:32:06 +03001066 (*variable) = new TVariable(&identifier, type);
1067 if (!symbolTable.declare(*variable))
1068 {
1069 error(line, "redefinition", identifier.c_str());
Jamie Madill1a4b1b32015-07-23 18:27:13 -04001070 *variable = nullptr;
Olli Etuaho2935c582015-04-08 14:32:06 +03001071 return false;
1072 }
1073
Olli Etuaho8a176262016-08-16 14:23:01 +03001074 if (!checkIsNonVoid(line, identifier, type.getBasicType()))
Olli Etuaho2935c582015-04-08 14:32:06 +03001075 return false;
1076
1077 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001078}
1079
Martin Radev70866b82016-07-22 15:27:42 +03001080void TParseContext::checkIsParameterQualifierValid(
1081 const TSourceLoc &line,
1082 const TTypeQualifierBuilder &typeQualifierBuilder,
1083 TType *type)
Arun Patole7e7e68d2015-05-22 12:02:25 +05301084{
Olli Etuaho77ba4082016-12-16 12:01:18 +00001085 TTypeQualifier typeQualifier = typeQualifierBuilder.getParameterTypeQualifier(mDiagnostics);
Martin Radev70866b82016-07-22 15:27:42 +03001086
1087 if (typeQualifier.qualifier == EvqOut || typeQualifier.qualifier == EvqInOut)
Arun Patole7e7e68d2015-05-22 12:02:25 +05301088 {
Martin Radev2cc85b32016-08-05 16:22:53 +03001089 checkOutParameterIsNotOpaqueType(line, typeQualifier.qualifier, *type);
1090 }
1091
1092 if (!IsImage(type->getBasicType()))
1093 {
Olli Etuaho43364892017-02-13 16:00:12 +00001094 checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, line);
Martin Radev2cc85b32016-08-05 16:22:53 +03001095 }
1096 else
1097 {
1098 type->setMemoryQualifier(typeQualifier.memoryQualifier);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001099 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001100
Martin Radev70866b82016-07-22 15:27:42 +03001101 type->setQualifier(typeQualifier.qualifier);
1102
1103 if (typeQualifier.precision != EbpUndefined)
1104 {
1105 type->setPrecision(typeQualifier.precision);
1106 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001107}
1108
Olli Etuaho856c4972016-08-08 11:38:39 +03001109bool TParseContext::checkCanUseExtension(const TSourceLoc &line, const TString &extension)
alokp@chromium.org8815d7f2010-09-09 17:30:03 +00001110{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001111 const TExtensionBehavior &extBehavior = extensionBehavior();
alokp@chromium.org8b851c62012-06-15 16:25:11 +00001112 TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str());
Arun Patole7e7e68d2015-05-22 12:02:25 +05301113 if (iter == extBehavior.end())
1114 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001115 error(line, "extension is not supported", extension.c_str());
Olli Etuaho8a176262016-08-16 14:23:01 +03001116 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001117 }
zmo@google.comf5450912011-09-09 01:37:19 +00001118 // In GLSL ES, an extension's default behavior is "disable".
Arun Patole7e7e68d2015-05-22 12:02:25 +05301119 if (iter->second == EBhDisable || iter->second == EBhUndefined)
1120 {
Olli Etuaho09b04a22016-12-15 13:30:26 +00001121 // TODO(oetuaho@nvidia.com): This is slightly hacky. Might be better if symbols could be
1122 // associated with more than one extension.
1123 if (extension == "GL_OVR_multiview")
1124 {
1125 return checkCanUseExtension(line, "GL_OVR_multiview2");
1126 }
Olli Etuaho4de340a2016-12-16 09:32:03 +00001127 error(line, "extension is disabled", extension.c_str());
Olli Etuaho8a176262016-08-16 14:23:01 +03001128 return false;
alokp@chromium.org8815d7f2010-09-09 17:30:03 +00001129 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05301130 if (iter->second == EBhWarn)
1131 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001132 warning(line, "extension is being used", extension.c_str());
Olli Etuaho8a176262016-08-16 14:23:01 +03001133 return true;
alokp@chromium.org8815d7f2010-09-09 17:30:03 +00001134 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001135
Olli Etuaho8a176262016-08-16 14:23:01 +03001136 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001137}
1138
Olli Etuahobb7e5a72017-04-24 10:16:44 +03001139// ESSL 3.00.6 section 4.8 Empty Declarations: "The combinations of qualifiers that cause
1140// compile-time or link-time errors are the same whether or not the declaration is empty".
1141// This function implements all the checks that are done on qualifiers regardless of if the
1142// declaration is empty.
1143void TParseContext::declarationQualifierErrorCheck(const sh::TQualifier qualifier,
1144 const sh::TLayoutQualifier &layoutQualifier,
1145 const TSourceLoc &location)
1146{
1147 if (qualifier == EvqShared && !layoutQualifier.isEmpty())
1148 {
1149 error(location, "Shared memory declarations cannot have layout specified", "layout");
1150 }
1151
1152 if (layoutQualifier.matrixPacking != EmpUnspecified)
1153 {
1154 error(location, "layout qualifier only valid for interface blocks",
1155 getMatrixPackingString(layoutQualifier.matrixPacking));
1156 return;
1157 }
1158
1159 if (layoutQualifier.blockStorage != EbsUnspecified)
1160 {
1161 error(location, "layout qualifier only valid for interface blocks",
1162 getBlockStorageString(layoutQualifier.blockStorage));
1163 return;
1164 }
1165
1166 if (qualifier == EvqFragmentOut)
1167 {
1168 if (layoutQualifier.location != -1 && layoutQualifier.yuv == true)
1169 {
1170 error(location, "invalid layout qualifier combination", "yuv");
1171 return;
1172 }
1173 }
1174 else
1175 {
1176 checkYuvIsNotSpecified(location, layoutQualifier.yuv);
1177 }
1178
1179 bool canHaveLocation = qualifier == EvqVertexIn || qualifier == EvqFragmentOut;
1180 if (mShaderVersion >= 310 && qualifier == EvqUniform)
1181 {
1182 canHaveLocation = true;
1183 // We're not checking whether the uniform location is in range here since that depends on
1184 // the type of the variable.
1185 // The type can only be fully determined for non-empty declarations.
1186 }
1187 if (!canHaveLocation)
1188 {
1189 checkLocationIsNotSpecified(location, layoutQualifier);
1190 }
1191}
1192
Martin Radevb8b01222016-11-20 23:25:53 +02001193void TParseContext::emptyDeclarationErrorCheck(const TPublicType &publicType,
1194 const TSourceLoc &location)
1195{
1196 if (publicType.isUnsizedArray())
1197 {
1198 // ESSL3 spec section 4.1.9: Array declaration which leaves the size unspecified is an
1199 // error. It is assumed that this applies to empty declarations as well.
1200 error(location, "empty array declaration needs to specify a size", "");
1201 }
Martin Radevb8b01222016-11-20 23:25:53 +02001202}
1203
Olli Etuahobb7e5a72017-04-24 10:16:44 +03001204// These checks are done for all declarations that are non-empty. They're done for non-empty
1205// declarations starting a declarator list, and declarators that follow an empty declaration.
1206void TParseContext::nonEmptyDeclarationErrorCheck(const TPublicType &publicType,
1207 const TSourceLoc &identifierLocation)
Jamie Madilla5efff92013-06-06 11:56:47 -04001208{
Olli Etuahofa33d582015-04-09 14:33:12 +03001209 switch (publicType.qualifier)
1210 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001211 case EvqVaryingIn:
1212 case EvqVaryingOut:
1213 case EvqAttribute:
1214 case EvqVertexIn:
1215 case EvqFragmentOut:
Martin Radev802abe02016-08-04 17:48:32 +03001216 case EvqComputeIn:
Martin Radev4a9cd802016-09-01 16:51:51 +03001217 if (publicType.getBasicType() == EbtStruct)
Jamie Madillb98c3a82015-07-23 14:26:04 -04001218 {
1219 error(identifierLocation, "cannot be used with a structure",
1220 getQualifierString(publicType.qualifier));
Olli Etuaho383b7912016-08-05 11:22:59 +03001221 return;
Jamie Madillb98c3a82015-07-23 14:26:04 -04001222 }
Olli Etuahofa33d582015-04-09 14:33:12 +03001223
Jamie Madillb98c3a82015-07-23 14:26:04 -04001224 default:
1225 break;
Olli Etuahofa33d582015-04-09 14:33:12 +03001226 }
1227
Jamie Madillb98c3a82015-07-23 14:26:04 -04001228 if (publicType.qualifier != EvqUniform &&
Martin Radev4a9cd802016-09-01 16:51:51 +03001229 !checkIsNotSampler(identifierLocation, publicType.typeSpecifierNonArray,
1230 "samplers must be uniform"))
Olli Etuahofa33d582015-04-09 14:33:12 +03001231 {
Olli Etuaho383b7912016-08-05 11:22:59 +03001232 return;
Olli Etuahofa33d582015-04-09 14:33:12 +03001233 }
Martin Radev2cc85b32016-08-05 16:22:53 +03001234 if (publicType.qualifier != EvqUniform &&
1235 !checkIsNotImage(identifierLocation, publicType.typeSpecifierNonArray,
1236 "images must be uniform"))
1237 {
1238 return;
1239 }
Jamie Madilla5efff92013-06-06 11:56:47 -04001240
Andrei Volykhina5527072017-03-22 16:46:30 +03001241 if ((publicType.qualifier != EvqTemporary && publicType.qualifier != EvqGlobal &&
1242 publicType.qualifier != EvqConst) &&
1243 publicType.getBasicType() == EbtYuvCscStandardEXT)
1244 {
1245 error(identifierLocation, "cannot be used with a yuvCscStandardEXT",
1246 getQualifierString(publicType.qualifier));
1247 return;
1248 }
1249
Olli Etuaho6ca2b652017-02-19 18:05:10 +00001250 if (mShaderVersion >= 310 && publicType.qualifier == EvqUniform)
1251 {
Olli Etuaho6ca2b652017-02-19 18:05:10 +00001252 // Valid uniform declarations can't be unsized arrays since uniforms can't be initialized.
1253 // But invalid shaders may still reach here with an unsized array declaration.
1254 if (!publicType.isUnsizedArray())
1255 {
1256 TType type(publicType);
1257 checkUniformLocationInRange(identifierLocation, type.getLocationCount(),
1258 publicType.layoutQualifier);
1259 }
1260 }
Martin Radev2cc85b32016-08-05 16:22:53 +03001261
Olli Etuahobb7e5a72017-04-24 10:16:44 +03001262 // check for layout qualifier issues
1263 const TLayoutQualifier layoutQualifier = publicType.layoutQualifier;
Andrei Volykhina5527072017-03-22 16:46:30 +03001264
Martin Radev2cc85b32016-08-05 16:22:53 +03001265 if (IsImage(publicType.getBasicType()))
1266 {
1267
1268 switch (layoutQualifier.imageInternalFormat)
1269 {
1270 case EiifRGBA32F:
1271 case EiifRGBA16F:
1272 case EiifR32F:
1273 case EiifRGBA8:
1274 case EiifRGBA8_SNORM:
1275 if (!IsFloatImage(publicType.getBasicType()))
1276 {
1277 error(identifierLocation,
1278 "internal image format requires a floating image type",
1279 getBasicString(publicType.getBasicType()));
1280 return;
1281 }
1282 break;
1283 case EiifRGBA32I:
1284 case EiifRGBA16I:
1285 case EiifRGBA8I:
1286 case EiifR32I:
1287 if (!IsIntegerImage(publicType.getBasicType()))
1288 {
1289 error(identifierLocation,
1290 "internal image format requires an integer image type",
1291 getBasicString(publicType.getBasicType()));
1292 return;
1293 }
1294 break;
1295 case EiifRGBA32UI:
1296 case EiifRGBA16UI:
1297 case EiifRGBA8UI:
1298 case EiifR32UI:
1299 if (!IsUnsignedImage(publicType.getBasicType()))
1300 {
1301 error(identifierLocation,
1302 "internal image format requires an unsigned image type",
1303 getBasicString(publicType.getBasicType()));
1304 return;
1305 }
1306 break;
1307 case EiifUnspecified:
1308 error(identifierLocation, "layout qualifier", "No image internal format specified");
1309 return;
1310 default:
1311 error(identifierLocation, "layout qualifier", "unrecognized token");
1312 return;
1313 }
1314
1315 // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
1316 switch (layoutQualifier.imageInternalFormat)
1317 {
1318 case EiifR32F:
1319 case EiifR32I:
1320 case EiifR32UI:
1321 break;
1322 default:
1323 if (!publicType.memoryQualifier.readonly && !publicType.memoryQualifier.writeonly)
1324 {
1325 error(identifierLocation, "layout qualifier",
1326 "Except for images with the r32f, r32i and r32ui format qualifiers, "
1327 "image variables must be qualified readonly and/or writeonly");
1328 return;
1329 }
1330 break;
1331 }
1332 }
1333 else
1334 {
Olli Etuaho43364892017-02-13 16:00:12 +00001335 checkInternalFormatIsNotSpecified(identifierLocation, layoutQualifier.imageInternalFormat);
Martin Radev2cc85b32016-08-05 16:22:53 +03001336
Olli Etuaho43364892017-02-13 16:00:12 +00001337 checkMemoryQualifierIsNotSpecified(publicType.memoryQualifier, identifierLocation);
1338 }
1339}
Martin Radev2cc85b32016-08-05 16:22:53 +03001340
Olli Etuaho43364892017-02-13 16:00:12 +00001341void TParseContext::checkBindingIsValid(const TSourceLoc &identifierLocation, const TType &type)
1342{
1343 TLayoutQualifier layoutQualifier = type.getLayoutQualifier();
1344 int arraySize = type.isArray() ? type.getArraySize() : 1;
1345 if (IsImage(type.getBasicType()))
1346 {
1347 checkImageBindingIsValid(identifierLocation, layoutQualifier.binding, arraySize);
1348 }
1349 else if (IsSampler(type.getBasicType()))
1350 {
1351 checkSamplerBindingIsValid(identifierLocation, layoutQualifier.binding, arraySize);
1352 }
1353 else
1354 {
1355 ASSERT(!IsOpaqueType(type.getBasicType()));
1356 checkBindingIsNotSpecified(identifierLocation, layoutQualifier.binding);
Martin Radev2cc85b32016-08-05 16:22:53 +03001357 }
Jamie Madilla5efff92013-06-06 11:56:47 -04001358}
1359
Olli Etuaho856c4972016-08-08 11:38:39 +03001360void TParseContext::checkLayoutQualifierSupported(const TSourceLoc &location,
1361 const TString &layoutQualifierName,
1362 int versionRequired)
Martin Radev802abe02016-08-04 17:48:32 +03001363{
1364
1365 if (mShaderVersion < versionRequired)
1366 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001367 error(location, "invalid layout qualifier: not supported", layoutQualifierName.c_str());
Martin Radev802abe02016-08-04 17:48:32 +03001368 }
1369}
1370
Olli Etuaho856c4972016-08-08 11:38:39 +03001371bool TParseContext::checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location,
1372 const TLayoutQualifier &layoutQualifier)
Martin Radev802abe02016-08-04 17:48:32 +03001373{
Martin Radev4c4c8e72016-08-04 12:25:34 +03001374 const sh::WorkGroupSize &localSize = layoutQualifier.localSize;
Martin Radev802abe02016-08-04 17:48:32 +03001375 for (size_t i = 0u; i < localSize.size(); ++i)
1376 {
1377 if (localSize[i] != -1)
1378 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001379 error(location,
1380 "invalid layout qualifier: only valid when used with 'in' in a compute shader "
1381 "global layout declaration",
1382 getWorkGroupSizeString(i));
Olli Etuaho8a176262016-08-16 14:23:01 +03001383 return false;
Martin Radev802abe02016-08-04 17:48:32 +03001384 }
1385 }
1386
Olli Etuaho8a176262016-08-16 14:23:01 +03001387 return true;
Martin Radev802abe02016-08-04 17:48:32 +03001388}
1389
Olli Etuaho43364892017-02-13 16:00:12 +00001390void TParseContext::checkInternalFormatIsNotSpecified(const TSourceLoc &location,
Martin Radev2cc85b32016-08-05 16:22:53 +03001391 TLayoutImageInternalFormat internalFormat)
1392{
1393 if (internalFormat != EiifUnspecified)
1394 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001395 error(location, "invalid layout qualifier: only valid when used with images",
1396 getImageInternalFormatString(internalFormat));
Martin Radev2cc85b32016-08-05 16:22:53 +03001397 }
Olli Etuaho43364892017-02-13 16:00:12 +00001398}
1399
1400void TParseContext::checkBindingIsNotSpecified(const TSourceLoc &location, int binding)
1401{
1402 if (binding != -1)
1403 {
1404 error(location,
1405 "invalid layout qualifier: only valid when used with opaque types or blocks",
1406 "binding");
1407 }
1408}
1409
1410void TParseContext::checkImageBindingIsValid(const TSourceLoc &location, int binding, int arraySize)
1411{
1412 // Expects arraySize to be 1 when setting binding for only a single variable.
1413 if (binding >= 0 && binding + arraySize > mMaxImageUnits)
1414 {
1415 error(location, "image binding greater than gl_MaxImageUnits", "binding");
1416 }
1417}
1418
1419void TParseContext::checkSamplerBindingIsValid(const TSourceLoc &location,
1420 int binding,
1421 int arraySize)
1422{
1423 // Expects arraySize to be 1 when setting binding for only a single variable.
1424 if (binding >= 0 && binding + arraySize > mMaxCombinedTextureImageUnits)
1425 {
1426 error(location, "sampler binding greater than maximum texture units", "binding");
1427 }
Martin Radev2cc85b32016-08-05 16:22:53 +03001428}
1429
Olli Etuaho6ca2b652017-02-19 18:05:10 +00001430void TParseContext::checkUniformLocationInRange(const TSourceLoc &location,
1431 int objectLocationCount,
1432 const TLayoutQualifier &layoutQualifier)
1433{
1434 int loc = layoutQualifier.location;
1435 if (loc >= 0 && loc + objectLocationCount > mMaxUniformLocations)
1436 {
1437 error(location, "Uniform location out of range", "location");
1438 }
1439}
1440
Andrei Volykhina5527072017-03-22 16:46:30 +03001441void TParseContext::checkYuvIsNotSpecified(const TSourceLoc &location, bool yuv)
1442{
1443 if (yuv != false)
1444 {
1445 error(location, "invalid layout qualifier: only valid on program outputs", "yuv");
1446 }
1447}
1448
Olli Etuaho383b7912016-08-05 11:22:59 +03001449void TParseContext::functionCallLValueErrorCheck(const TFunction *fnCandidate,
Olli Etuaho856c4972016-08-08 11:38:39 +03001450 TIntermAggregate *fnCall)
Olli Etuahob6e07a62015-02-16 12:22:10 +02001451{
1452 for (size_t i = 0; i < fnCandidate->getParamCount(); ++i)
1453 {
1454 TQualifier qual = fnCandidate->getParam(i).type->getQualifier();
1455 if (qual == EvqOut || qual == EvqInOut)
1456 {
Olli Etuaho856c4972016-08-08 11:38:39 +03001457 TIntermTyped *argument = (*(fnCall->getSequence()))[i]->getAsTyped();
Olli Etuaho8a176262016-08-16 14:23:01 +03001458 if (!checkCanBeLValue(argument->getLine(), "assign", argument))
Olli Etuahob6e07a62015-02-16 12:22:10 +02001459 {
Olli Etuaho856c4972016-08-08 11:38:39 +03001460 error(argument->getLine(),
Olli Etuaho4de340a2016-12-16 09:32:03 +00001461 "Constant value cannot be passed for 'out' or 'inout' parameters.",
Olli Etuahoec9232b2017-03-27 17:01:37 +03001462 fnCall->getFunctionSymbolInfo()->getName().c_str());
Olli Etuaho383b7912016-08-05 11:22:59 +03001463 return;
Olli Etuahob6e07a62015-02-16 12:22:10 +02001464 }
1465 }
1466 }
Olli Etuahob6e07a62015-02-16 12:22:10 +02001467}
1468
Martin Radev70866b82016-07-22 15:27:42 +03001469void TParseContext::checkInvariantVariableQualifier(bool invariant,
1470 const TQualifier qualifier,
1471 const TSourceLoc &invariantLocation)
Olli Etuaho37ad4742015-04-27 13:18:50 +03001472{
Martin Radev70866b82016-07-22 15:27:42 +03001473 if (!invariant)
1474 return;
1475
1476 if (mShaderVersion < 300)
Olli Etuaho37ad4742015-04-27 13:18:50 +03001477 {
Martin Radev70866b82016-07-22 15:27:42 +03001478 // input variables in the fragment shader can be also qualified as invariant
1479 if (!sh::CanBeInvariantESSL1(qualifier))
1480 {
1481 error(invariantLocation, "Cannot be qualified as invariant.", "invariant");
1482 }
1483 }
1484 else
1485 {
1486 if (!sh::CanBeInvariantESSL3OrGreater(qualifier))
1487 {
1488 error(invariantLocation, "Cannot be qualified as invariant.", "invariant");
1489 }
Olli Etuaho37ad4742015-04-27 13:18:50 +03001490 }
1491}
1492
Arun Patole7e7e68d2015-05-22 12:02:25 +05301493bool TParseContext::supportsExtension(const char *extension)
zmo@google.com09c323a2011-08-12 18:22:25 +00001494{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001495 const TExtensionBehavior &extbehavior = extensionBehavior();
alokp@chromium.org73bc2982012-06-19 18:48:05 +00001496 TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
1497 return (iter != extbehavior.end());
alokp@chromium.org8b851c62012-06-15 16:25:11 +00001498}
1499
Arun Patole7e7e68d2015-05-22 12:02:25 +05301500bool TParseContext::isExtensionEnabled(const char *extension) const
Jamie Madill5d287f52013-07-12 15:38:19 -04001501{
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +03001502 return ::IsExtensionEnabled(extensionBehavior(), extension);
Jamie Madill5d287f52013-07-12 15:38:19 -04001503}
1504
Jamie Madillb98c3a82015-07-23 14:26:04 -04001505void TParseContext::handleExtensionDirective(const TSourceLoc &loc,
1506 const char *extName,
1507 const char *behavior)
Jamie Madill075edd82013-07-08 13:30:19 -04001508{
1509 pp::SourceLocation srcLoc;
1510 srcLoc.file = loc.first_file;
1511 srcLoc.line = loc.first_line;
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001512 mDirectiveHandler.handleExtension(srcLoc, extName, behavior);
Jamie Madill075edd82013-07-08 13:30:19 -04001513}
1514
Jamie Madillb98c3a82015-07-23 14:26:04 -04001515void TParseContext::handlePragmaDirective(const TSourceLoc &loc,
1516 const char *name,
1517 const char *value,
1518 bool stdgl)
Jamie Madill075edd82013-07-08 13:30:19 -04001519{
1520 pp::SourceLocation srcLoc;
1521 srcLoc.file = loc.first_file;
1522 srcLoc.line = loc.first_line;
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001523 mDirectiveHandler.handlePragma(srcLoc, name, value, stdgl);
Jamie Madill075edd82013-07-08 13:30:19 -04001524}
1525
Martin Radev4c4c8e72016-08-04 12:25:34 +03001526sh::WorkGroupSize TParseContext::getComputeShaderLocalSize() const
Martin Radev802abe02016-08-04 17:48:32 +03001527{
Martin Radev4c4c8e72016-08-04 12:25:34 +03001528 sh::WorkGroupSize result;
Martin Radev802abe02016-08-04 17:48:32 +03001529 for (size_t i = 0u; i < result.size(); ++i)
1530 {
1531 if (mComputeShaderLocalSizeDeclared && mComputeShaderLocalSize[i] == -1)
1532 {
1533 result[i] = 1;
1534 }
1535 else
1536 {
1537 result[i] = mComputeShaderLocalSize[i];
1538 }
1539 }
1540 return result;
1541}
1542
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001543/////////////////////////////////////////////////////////////////////////////////
1544//
1545// Non-Errors.
1546//
1547/////////////////////////////////////////////////////////////////////////////////
1548
Jamie Madill5c097022014-08-20 16:38:32 -04001549const TVariable *TParseContext::getNamedVariable(const TSourceLoc &location,
1550 const TString *name,
1551 const TSymbol *symbol)
1552{
Yunchao Hed7297bf2017-04-19 15:27:10 +08001553 const TVariable *variable = nullptr;
Jamie Madill5c097022014-08-20 16:38:32 -04001554
1555 if (!symbol)
1556 {
1557 error(location, "undeclared identifier", name->c_str());
Jamie Madill5c097022014-08-20 16:38:32 -04001558 }
1559 else if (!symbol->isVariable())
1560 {
1561 error(location, "variable expected", name->c_str());
Jamie Madill5c097022014-08-20 16:38:32 -04001562 }
1563 else
1564 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001565 variable = static_cast<const TVariable *>(symbol);
Jamie Madill5c097022014-08-20 16:38:32 -04001566
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001567 if (symbolTable.findBuiltIn(variable->getName(), mShaderVersion) &&
Olli Etuaho383b7912016-08-05 11:22:59 +03001568 !variable->getExtension().empty())
Jamie Madill5c097022014-08-20 16:38:32 -04001569 {
Olli Etuaho856c4972016-08-08 11:38:39 +03001570 checkCanUseExtension(location, variable->getExtension());
Jamie Madill5c097022014-08-20 16:38:32 -04001571 }
Jamie Madill14e95b32015-05-07 10:10:41 -04001572
1573 // Reject shaders using both gl_FragData and gl_FragColor
1574 TQualifier qualifier = variable->getType().getQualifier();
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +03001575 if (qualifier == EvqFragData || qualifier == EvqSecondaryFragDataEXT)
Jamie Madill14e95b32015-05-07 10:10:41 -04001576 {
1577 mUsesFragData = true;
1578 }
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +03001579 else if (qualifier == EvqFragColor || qualifier == EvqSecondaryFragColorEXT)
Jamie Madill14e95b32015-05-07 10:10:41 -04001580 {
1581 mUsesFragColor = true;
1582 }
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +03001583 if (qualifier == EvqSecondaryFragDataEXT || qualifier == EvqSecondaryFragColorEXT)
1584 {
1585 mUsesSecondaryOutputs = true;
1586 }
Jamie Madill14e95b32015-05-07 10:10:41 -04001587
1588 // This validation is not quite correct - it's only an error to write to
1589 // both FragData and FragColor. For simplicity, and because users shouldn't
1590 // be rewarded for reading from undefined varaibles, return an error
1591 // if they are both referenced, rather than assigned.
1592 if (mUsesFragData && mUsesFragColor)
1593 {
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +03001594 const char *errorMessage = "cannot use both gl_FragData and gl_FragColor";
1595 if (mUsesSecondaryOutputs)
1596 {
1597 errorMessage =
1598 "cannot use both output variable sets (gl_FragData, gl_SecondaryFragDataEXT)"
1599 " and (gl_FragColor, gl_SecondaryFragColorEXT)";
1600 }
1601 error(location, errorMessage, name->c_str());
Jamie Madill14e95b32015-05-07 10:10:41 -04001602 }
Martin Radevb0883602016-08-04 17:48:58 +03001603
1604 // GLSL ES 3.1 Revision 4, 7.1.3 Compute Shader Special Variables
1605 if (getShaderType() == GL_COMPUTE_SHADER && !mComputeShaderLocalSizeDeclared &&
1606 qualifier == EvqWorkGroupSize)
1607 {
1608 error(location,
1609 "It is an error to use gl_WorkGroupSize before declaring the local group size",
1610 "gl_WorkGroupSize");
1611 }
Jamie Madill5c097022014-08-20 16:38:32 -04001612 }
1613
1614 if (!variable)
1615 {
1616 TType type(EbtFloat, EbpUndefined);
1617 TVariable *fakeVariable = new TVariable(name, type);
1618 symbolTable.declare(fakeVariable);
1619 variable = fakeVariable;
1620 }
1621
1622 return variable;
1623}
1624
Olli Etuaho82c29ed2015-11-03 13:06:54 +02001625TIntermTyped *TParseContext::parseVariableIdentifier(const TSourceLoc &location,
1626 const TString *name,
1627 const TSymbol *symbol)
1628{
1629 const TVariable *variable = getNamedVariable(location, name, symbol);
1630
Olli Etuaho09b04a22016-12-15 13:30:26 +00001631 if (variable->getType().getQualifier() == EvqViewIDOVR && IsWebGLBasedSpec(mShaderSpec) &&
1632 mShaderType == GL_FRAGMENT_SHADER && !isExtensionEnabled("GL_OVR_multiview2"))
1633 {
1634 // WEBGL_multiview spec
1635 error(location, "Need to enable OVR_multiview2 to use gl_ViewID_OVR in fragment shader",
1636 "gl_ViewID_OVR");
1637 }
1638
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001639 if (variable->getConstPointer())
Olli Etuaho82c29ed2015-11-03 13:06:54 +02001640 {
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001641 const TConstantUnion *constArray = variable->getConstPointer();
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001642 return intermediate.addConstantUnion(constArray, variable->getType(), location);
Olli Etuaho82c29ed2015-11-03 13:06:54 +02001643 }
Olli Etuahoaecfa8e2016-12-09 12:47:26 +00001644 else if (variable->getType().getQualifier() == EvqWorkGroupSize &&
1645 mComputeShaderLocalSizeDeclared)
1646 {
1647 // gl_WorkGroupSize can be used to size arrays according to the ESSL 3.10.4 spec, so it
1648 // needs to be added to the AST as a constant and not as a symbol.
1649 sh::WorkGroupSize workGroupSize = getComputeShaderLocalSize();
1650 TConstantUnion *constArray = new TConstantUnion[3];
1651 for (size_t i = 0; i < 3; ++i)
1652 {
1653 constArray[i].setUConst(static_cast<unsigned int>(workGroupSize[i]));
1654 }
1655
1656 ASSERT(variable->getType().getBasicType() == EbtUInt);
1657 ASSERT(variable->getType().getObjectSize() == 3);
1658
1659 TType type(variable->getType());
1660 type.setQualifier(EvqConst);
1661 return intermediate.addConstantUnion(constArray, type, location);
1662 }
Olli Etuaho82c29ed2015-11-03 13:06:54 +02001663 else
1664 {
1665 return intermediate.addSymbol(variable->getUniqueId(), variable->getName(),
1666 variable->getType(), location);
1667 }
1668}
1669
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001670//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001671// Initializers show up in several places in the grammar. Have one set of
1672// code to handle them here.
1673//
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001674// Returns true on error, false if no error
1675//
Jamie Madillb98c3a82015-07-23 14:26:04 -04001676bool TParseContext::executeInitializer(const TSourceLoc &line,
1677 const TString &identifier,
1678 const TPublicType &pType,
1679 TIntermTyped *initializer,
Olli Etuaho13389b62016-10-16 11:48:18 +01001680 TIntermBinary **initNode)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001681{
Olli Etuaho13389b62016-10-16 11:48:18 +01001682 ASSERT(initNode != nullptr);
1683 ASSERT(*initNode == nullptr);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001684 TType type = TType(pType);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001685
Olli Etuaho2935c582015-04-08 14:32:06 +03001686 TVariable *variable = nullptr;
Olli Etuaho376f1b52015-04-13 13:23:41 +03001687 if (type.isUnsizedArray())
1688 {
Olli Etuaho02bd82c2016-11-03 10:29:43 +00001689 // We have not checked yet whether the initializer actually is an array or not.
1690 if (initializer->isArray())
1691 {
1692 type.setArraySize(initializer->getArraySize());
1693 }
1694 else
1695 {
1696 // Having a non-array initializer for an unsized array will result in an error later,
1697 // so we don't generate an error message here.
1698 type.setArraySize(1u);
1699 }
Olli Etuaho376f1b52015-04-13 13:23:41 +03001700 }
Olli Etuaho2935c582015-04-08 14:32:06 +03001701 if (!declareVariable(line, identifier, type, &variable))
1702 {
1703 return true;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001704 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001705
Olli Etuahob0c645e2015-05-12 14:25:36 +03001706 bool globalInitWarning = false;
Jamie Madillb98c3a82015-07-23 14:26:04 -04001707 if (symbolTable.atGlobalLevel() &&
1708 !ValidateGlobalInitializer(initializer, this, &globalInitWarning))
Olli Etuahob0c645e2015-05-12 14:25:36 +03001709 {
1710 // Error message does not completely match behavior with ESSL 1.00, but
1711 // we want to steer developers towards only using constant expressions.
1712 error(line, "global variable initializers must be constant expressions", "=");
1713 return true;
1714 }
1715 if (globalInitWarning)
1716 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001717 warning(
1718 line,
1719 "global variable initializers should be constant expressions "
1720 "(uniforms and globals are allowed in global initializers for legacy compatibility)",
1721 "=");
Olli Etuahob0c645e2015-05-12 14:25:36 +03001722 }
1723
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001724 //
1725 // identifier must be of type constant, a global, or a temporary
1726 //
1727 TQualifier qualifier = variable->getType().getQualifier();
Arun Patole7e7e68d2015-05-22 12:02:25 +05301728 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst))
1729 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001730 error(line, " cannot initialize this type of qualifier ",
1731 variable->getType().getQualifierString());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001732 return true;
1733 }
1734 //
1735 // test for and propagate constant
1736 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001737
Arun Patole7e7e68d2015-05-22 12:02:25 +05301738 if (qualifier == EvqConst)
1739 {
1740 if (qualifier != initializer->getType().getQualifier())
1741 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001742 std::stringstream reasonStream;
1743 reasonStream << "assigning non-constant to '" << variable->getType().getCompleteString()
1744 << "'";
1745 std::string reason = reasonStream.str();
1746 error(line, reason.c_str(), "=");
alokp@chromium.org58e54292010-08-24 21:40:03 +00001747 variable->getType().setQualifier(EvqTemporary);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001748 return true;
1749 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05301750 if (type != initializer->getType())
1751 {
1752 error(line, " non-matching types for const initializer ",
Jamie Madillb98c3a82015-07-23 14:26:04 -04001753 variable->getType().getQualifierString());
alokp@chromium.org58e54292010-08-24 21:40:03 +00001754 variable->getType().setQualifier(EvqTemporary);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001755 return true;
1756 }
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001757
1758 // Save the constant folded value to the variable if possible. For example array
1759 // initializers are not folded, since that way copying the array literal to multiple places
1760 // in the shader is avoided.
1761 // TODO(oetuaho@nvidia.com): Consider constant folding array initialization in cases where
1762 // it would be beneficial.
Arun Patole7e7e68d2015-05-22 12:02:25 +05301763 if (initializer->getAsConstantUnion())
1764 {
Jamie Madill94bf7f22013-07-08 13:31:15 -04001765 variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
Olli Etuaho13389b62016-10-16 11:48:18 +01001766 *initNode = nullptr;
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001767 return false;
Arun Patole7e7e68d2015-05-22 12:02:25 +05301768 }
1769 else if (initializer->getAsSymbolNode())
1770 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001771 const TSymbol *symbol =
1772 symbolTable.find(initializer->getAsSymbolNode()->getSymbol(), 0);
1773 const TVariable *tVar = static_cast<const TVariable *>(symbol);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001774
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001775 const TConstantUnion *constArray = tVar->getConstPointer();
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001776 if (constArray)
1777 {
1778 variable->shareConstPointer(constArray);
Olli Etuaho13389b62016-10-16 11:48:18 +01001779 *initNode = nullptr;
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001780 return false;
1781 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001782 }
1783 }
Olli Etuahoe7847b02015-03-16 11:56:12 +02001784
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001785 TIntermSymbol *intermSymbol = intermediate.addSymbol(
1786 variable->getUniqueId(), variable->getName(), variable->getType(), line);
Olli Etuaho13389b62016-10-16 11:48:18 +01001787 *initNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
1788 if (*initNode == nullptr)
Olli Etuahoe7847b02015-03-16 11:56:12 +02001789 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001790 assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
1791 return true;
Olli Etuahoe7847b02015-03-16 11:56:12 +02001792 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001793
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001794 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001795}
1796
Olli Etuaho0e3aee32016-10-27 12:56:38 +01001797void TParseContext::addFullySpecifiedType(TPublicType *typeSpecifier)
1798{
1799 checkPrecisionSpecified(typeSpecifier->getLine(), typeSpecifier->precision,
1800 typeSpecifier->getBasicType());
1801
1802 if (mShaderVersion < 300 && typeSpecifier->array)
1803 {
1804 error(typeSpecifier->getLine(), "not supported", "first-class array");
1805 typeSpecifier->clearArrayness();
1806 }
1807}
1808
Martin Radev70866b82016-07-22 15:27:42 +03001809TPublicType TParseContext::addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder,
Arun Patole7e7e68d2015-05-22 12:02:25 +05301810 const TPublicType &typeSpecifier)
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001811{
Olli Etuaho77ba4082016-12-16 12:01:18 +00001812 TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics);
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001813
Martin Radev70866b82016-07-22 15:27:42 +03001814 TPublicType returnType = typeSpecifier;
1815 returnType.qualifier = typeQualifier.qualifier;
1816 returnType.invariant = typeQualifier.invariant;
1817 returnType.layoutQualifier = typeQualifier.layoutQualifier;
Martin Radev2cc85b32016-08-05 16:22:53 +03001818 returnType.memoryQualifier = typeQualifier.memoryQualifier;
Martin Radev70866b82016-07-22 15:27:42 +03001819 returnType.precision = typeSpecifier.precision;
1820
1821 if (typeQualifier.precision != EbpUndefined)
1822 {
1823 returnType.precision = typeQualifier.precision;
1824 }
1825
Martin Radev4a9cd802016-09-01 16:51:51 +03001826 checkPrecisionSpecified(typeSpecifier.getLine(), returnType.precision,
1827 typeSpecifier.getBasicType());
Martin Radev70866b82016-07-22 15:27:42 +03001828
Martin Radev4a9cd802016-09-01 16:51:51 +03001829 checkInvariantVariableQualifier(returnType.invariant, returnType.qualifier,
1830 typeSpecifier.getLine());
Martin Radev70866b82016-07-22 15:27:42 +03001831
Martin Radev4a9cd802016-09-01 16:51:51 +03001832 checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), returnType.layoutQualifier);
Martin Radev802abe02016-08-04 17:48:32 +03001833
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001834 if (mShaderVersion < 300)
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001835 {
Olli Etuahoc1ac41b2015-07-10 13:53:46 +03001836 if (typeSpecifier.array)
1837 {
Martin Radev4a9cd802016-09-01 16:51:51 +03001838 error(typeSpecifier.getLine(), "not supported", "first-class array");
Olli Etuahoc1ac41b2015-07-10 13:53:46 +03001839 returnType.clearArrayness();
1840 }
1841
Martin Radev70866b82016-07-22 15:27:42 +03001842 if (returnType.qualifier == EvqAttribute &&
Martin Radev4a9cd802016-09-01 16:51:51 +03001843 (typeSpecifier.getBasicType() == EbtBool || typeSpecifier.getBasicType() == EbtInt))
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001844 {
Martin Radev4a9cd802016-09-01 16:51:51 +03001845 error(typeSpecifier.getLine(), "cannot be bool or int",
Martin Radev70866b82016-07-22 15:27:42 +03001846 getQualifierString(returnType.qualifier));
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001847 }
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001848
Martin Radev70866b82016-07-22 15:27:42 +03001849 if ((returnType.qualifier == EvqVaryingIn || returnType.qualifier == EvqVaryingOut) &&
Martin Radev4a9cd802016-09-01 16:51:51 +03001850 (typeSpecifier.getBasicType() == EbtBool || typeSpecifier.getBasicType() == EbtInt))
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001851 {
Martin Radev4a9cd802016-09-01 16:51:51 +03001852 error(typeSpecifier.getLine(), "cannot be bool or int",
Martin Radev70866b82016-07-22 15:27:42 +03001853 getQualifierString(returnType.qualifier));
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001854 }
1855 }
1856 else
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001857 {
Martin Radev70866b82016-07-22 15:27:42 +03001858 if (!returnType.layoutQualifier.isEmpty())
Olli Etuahoabb0c382015-07-13 12:01:12 +03001859 {
Martin Radev4a9cd802016-09-01 16:51:51 +03001860 checkIsAtGlobalLevel(typeSpecifier.getLine(), "layout");
Olli Etuahoabb0c382015-07-13 12:01:12 +03001861 }
Martin Radev70866b82016-07-22 15:27:42 +03001862 if (sh::IsVarying(returnType.qualifier) || returnType.qualifier == EvqVertexIn ||
1863 returnType.qualifier == EvqFragmentOut)
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001864 {
Martin Radev4a9cd802016-09-01 16:51:51 +03001865 checkInputOutputTypeIsValidES3(returnType.qualifier, typeSpecifier,
1866 typeSpecifier.getLine());
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001867 }
Martin Radev70866b82016-07-22 15:27:42 +03001868 if (returnType.qualifier == EvqComputeIn)
Martin Radev802abe02016-08-04 17:48:32 +03001869 {
Martin Radev4a9cd802016-09-01 16:51:51 +03001870 error(typeSpecifier.getLine(), "'in' can be only used to specify the local group size",
Martin Radev802abe02016-08-04 17:48:32 +03001871 "in");
Martin Radev802abe02016-08-04 17:48:32 +03001872 }
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001873 }
1874
1875 return returnType;
1876}
1877
Olli Etuaho856c4972016-08-08 11:38:39 +03001878void TParseContext::checkInputOutputTypeIsValidES3(const TQualifier qualifier,
1879 const TPublicType &type,
1880 const TSourceLoc &qualifierLocation)
Olli Etuahocc36b982015-07-10 14:14:18 +03001881{
1882 // An input/output variable can never be bool or a sampler. Samplers are checked elsewhere.
Martin Radev4a9cd802016-09-01 16:51:51 +03001883 if (type.getBasicType() == EbtBool)
Olli Etuahocc36b982015-07-10 14:14:18 +03001884 {
1885 error(qualifierLocation, "cannot be bool", getQualifierString(qualifier));
Olli Etuahocc36b982015-07-10 14:14:18 +03001886 }
1887
1888 // Specific restrictions apply for vertex shader inputs and fragment shader outputs.
1889 switch (qualifier)
1890 {
1891 case EvqVertexIn:
1892 // ESSL 3.00 section 4.3.4
1893 if (type.array)
1894 {
1895 error(qualifierLocation, "cannot be array", getQualifierString(qualifier));
Olli Etuahocc36b982015-07-10 14:14:18 +03001896 }
Olli Etuahobb7e5a72017-04-24 10:16:44 +03001897 // Vertex inputs with a struct type are disallowed in nonEmptyDeclarationErrorCheck
Olli Etuahocc36b982015-07-10 14:14:18 +03001898 return;
1899 case EvqFragmentOut:
1900 // ESSL 3.00 section 4.3.6
Martin Radev4a9cd802016-09-01 16:51:51 +03001901 if (type.typeSpecifierNonArray.isMatrix())
Olli Etuahocc36b982015-07-10 14:14:18 +03001902 {
1903 error(qualifierLocation, "cannot be matrix", getQualifierString(qualifier));
Olli Etuahocc36b982015-07-10 14:14:18 +03001904 }
Olli Etuahobb7e5a72017-04-24 10:16:44 +03001905 // Fragment outputs with a struct type are disallowed in nonEmptyDeclarationErrorCheck
Olli Etuahocc36b982015-07-10 14:14:18 +03001906 return;
1907 default:
1908 break;
1909 }
1910
1911 // Vertex shader outputs / fragment shader inputs have a different, slightly more lenient set of
1912 // restrictions.
1913 bool typeContainsIntegers =
Martin Radev4a9cd802016-09-01 16:51:51 +03001914 (type.getBasicType() == EbtInt || type.getBasicType() == EbtUInt ||
1915 type.isStructureContainingType(EbtInt) || type.isStructureContainingType(EbtUInt));
Olli Etuahocc36b982015-07-10 14:14:18 +03001916 if (typeContainsIntegers && qualifier != EvqFlatIn && qualifier != EvqFlatOut)
1917 {
1918 error(qualifierLocation, "must use 'flat' interpolation here",
1919 getQualifierString(qualifier));
Olli Etuahocc36b982015-07-10 14:14:18 +03001920 }
1921
Martin Radev4a9cd802016-09-01 16:51:51 +03001922 if (type.getBasicType() == EbtStruct)
Olli Etuahocc36b982015-07-10 14:14:18 +03001923 {
1924 // ESSL 3.00 sections 4.3.4 and 4.3.6.
1925 // These restrictions are only implied by the ESSL 3.00 spec, but
1926 // the ESSL 3.10 spec lists these restrictions explicitly.
1927 if (type.array)
1928 {
1929 error(qualifierLocation, "cannot be an array of structures",
1930 getQualifierString(qualifier));
Olli Etuahocc36b982015-07-10 14:14:18 +03001931 }
1932 if (type.isStructureContainingArrays())
1933 {
1934 error(qualifierLocation, "cannot be a structure containing an array",
1935 getQualifierString(qualifier));
Olli Etuahocc36b982015-07-10 14:14:18 +03001936 }
1937 if (type.isStructureContainingType(EbtStruct))
1938 {
1939 error(qualifierLocation, "cannot be a structure containing a structure",
1940 getQualifierString(qualifier));
Olli Etuahocc36b982015-07-10 14:14:18 +03001941 }
1942 if (type.isStructureContainingType(EbtBool))
1943 {
1944 error(qualifierLocation, "cannot be a structure containing a bool",
1945 getQualifierString(qualifier));
Olli Etuahocc36b982015-07-10 14:14:18 +03001946 }
1947 }
1948}
1949
Martin Radev2cc85b32016-08-05 16:22:53 +03001950void TParseContext::checkLocalVariableConstStorageQualifier(const TQualifierWrapperBase &qualifier)
1951{
1952 if (qualifier.getType() == QtStorage)
1953 {
1954 const TStorageQualifierWrapper &storageQualifier =
1955 static_cast<const TStorageQualifierWrapper &>(qualifier);
1956 if (!declaringFunction() && storageQualifier.getQualifier() != EvqConst &&
1957 !symbolTable.atGlobalLevel())
1958 {
1959 error(storageQualifier.getLine(),
1960 "Local variables can only use the const storage qualifier.",
1961 storageQualifier.getQualifierString().c_str());
1962 }
1963 }
1964}
1965
Olli Etuaho43364892017-02-13 16:00:12 +00001966void TParseContext::checkMemoryQualifierIsNotSpecified(const TMemoryQualifier &memoryQualifier,
Martin Radev2cc85b32016-08-05 16:22:53 +03001967 const TSourceLoc &location)
1968{
1969 if (memoryQualifier.readonly)
1970 {
1971 error(location, "Only allowed with images.", "readonly");
Martin Radev2cc85b32016-08-05 16:22:53 +03001972 }
1973 if (memoryQualifier.writeonly)
1974 {
1975 error(location, "Only allowed with images.", "writeonly");
Martin Radev2cc85b32016-08-05 16:22:53 +03001976 }
Martin Radev049edfa2016-11-11 14:35:37 +02001977 if (memoryQualifier.coherent)
1978 {
1979 error(location, "Only allowed with images.", "coherent");
Martin Radev049edfa2016-11-11 14:35:37 +02001980 }
1981 if (memoryQualifier.restrictQualifier)
1982 {
1983 error(location, "Only allowed with images.", "restrict");
Martin Radev049edfa2016-11-11 14:35:37 +02001984 }
1985 if (memoryQualifier.volatileQualifier)
1986 {
1987 error(location, "Only allowed with images.", "volatile");
Martin Radev049edfa2016-11-11 14:35:37 +02001988 }
Martin Radev2cc85b32016-08-05 16:22:53 +03001989}
1990
Olli Etuaho13389b62016-10-16 11:48:18 +01001991TIntermDeclaration *TParseContext::parseSingleDeclaration(
1992 TPublicType &publicType,
1993 const TSourceLoc &identifierOrTypeLocation,
1994 const TString &identifier)
Jamie Madill60ed9812013-06-06 11:56:46 -04001995{
Kenneth Russellbccc65d2016-07-19 16:48:43 -07001996 TType type(publicType);
1997 if ((mCompileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) &&
1998 mDirectiveHandler.pragma().stdgl.invariantAll)
1999 {
2000 TQualifier qualifier = type.getQualifier();
2001
2002 // The directive handler has already taken care of rejecting invalid uses of this pragma
2003 // (for example, in ESSL 3.00 fragment shaders), so at this point, flatten it into all
2004 // affected variable declarations:
2005 //
2006 // 1. Built-in special variables which are inputs to the fragment shader. (These are handled
2007 // elsewhere, in TranslatorGLSL.)
2008 //
2009 // 2. Outputs from vertex shaders in ESSL 1.00 and 3.00 (EvqVaryingOut and EvqVertexOut). It
2010 // is actually less likely that there will be bugs in the handling of ESSL 3.00 shaders, but
2011 // the way this is currently implemented we have to enable this compiler option before
2012 // parsing the shader and determining the shading language version it uses. If this were
2013 // implemented as a post-pass, the workaround could be more targeted.
2014 //
2015 // 3. Inputs in ESSL 1.00 fragment shaders (EvqVaryingIn). This is somewhat in violation of
2016 // the specification, but there are desktop OpenGL drivers that expect that this is the
2017 // behavior of the #pragma when specified in ESSL 1.00 fragment shaders.
2018 if (qualifier == EvqVaryingOut || qualifier == EvqVertexOut || qualifier == EvqVaryingIn)
2019 {
2020 type.setInvariant(true);
2021 }
2022 }
2023
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002024 declarationQualifierErrorCheck(publicType.qualifier, publicType.layoutQualifier,
2025 identifierOrTypeLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04002026
Olli Etuahobab4c082015-04-24 16:38:49 +03002027 bool emptyDeclaration = (identifier == "");
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002028 mDeferredNonEmptyDeclarationErrorCheck = emptyDeclaration;
Olli Etuahofa33d582015-04-09 14:33:12 +03002029
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002030 TIntermSymbol *symbol = nullptr;
Olli Etuahobab4c082015-04-24 16:38:49 +03002031 if (emptyDeclaration)
2032 {
Martin Radevb8b01222016-11-20 23:25:53 +02002033 emptyDeclarationErrorCheck(publicType, identifierOrTypeLocation);
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002034 // In most cases we don't need to create a symbol node for an empty declaration.
2035 // But if the empty declaration is declaring a struct type, the symbol node will store that.
2036 if (type.getBasicType() == EbtStruct)
2037 {
2038 symbol = intermediate.addSymbol(0, "", type, identifierOrTypeLocation);
2039 }
Olli Etuahobab4c082015-04-24 16:38:49 +03002040 }
2041 else
Jamie Madill60ed9812013-06-06 11:56:46 -04002042 {
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002043 nonEmptyDeclarationErrorCheck(publicType, identifierOrTypeLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04002044
Olli Etuaho856c4972016-08-08 11:38:39 +03002045 checkCanBeDeclaredWithoutInitializer(identifierOrTypeLocation, identifier, &publicType);
Jamie Madill60ed9812013-06-06 11:56:46 -04002046
Olli Etuaho2935c582015-04-08 14:32:06 +03002047 TVariable *variable = nullptr;
Kenneth Russellbccc65d2016-07-19 16:48:43 -07002048 declareVariable(identifierOrTypeLocation, identifier, type, &variable);
Jamie Madill60ed9812013-06-06 11:56:46 -04002049
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002050 if (variable)
Olli Etuaho13389b62016-10-16 11:48:18 +01002051 {
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002052 symbol = intermediate.addSymbol(variable->getUniqueId(), identifier, type,
2053 identifierOrTypeLocation);
Olli Etuaho13389b62016-10-16 11:48:18 +01002054 }
Jamie Madill60ed9812013-06-06 11:56:46 -04002055 }
2056
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002057 TIntermDeclaration *declaration = new TIntermDeclaration();
2058 declaration->setLine(identifierOrTypeLocation);
2059 if (symbol)
2060 {
2061 declaration->appendDeclarator(symbol);
2062 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002063 return declaration;
Jamie Madill60ed9812013-06-06 11:56:46 -04002064}
2065
Olli Etuaho13389b62016-10-16 11:48:18 +01002066TIntermDeclaration *TParseContext::parseSingleArrayDeclaration(TPublicType &publicType,
2067 const TSourceLoc &identifierLocation,
2068 const TString &identifier,
2069 const TSourceLoc &indexLocation,
2070 TIntermTyped *indexExpression)
Jamie Madill60ed9812013-06-06 11:56:46 -04002071{
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002072 mDeferredNonEmptyDeclarationErrorCheck = false;
Olli Etuahofa33d582015-04-09 14:33:12 +03002073
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002074 declarationQualifierErrorCheck(publicType.qualifier, publicType.layoutQualifier,
2075 identifierLocation);
2076
2077 nonEmptyDeclarationErrorCheck(publicType, identifierLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04002078
Olli Etuaho856c4972016-08-08 11:38:39 +03002079 checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &publicType);
Jamie Madill60ed9812013-06-06 11:56:46 -04002080
Olli Etuaho8a176262016-08-16 14:23:01 +03002081 checkIsValidTypeAndQualifierForArray(indexLocation, publicType);
Jamie Madill60ed9812013-06-06 11:56:46 -04002082
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03002083 TType arrayType(publicType);
Jamie Madill60ed9812013-06-06 11:56:46 -04002084
Olli Etuaho856c4972016-08-08 11:38:39 +03002085 unsigned int size = checkIsValidArraySize(identifierLocation, indexExpression);
Olli Etuahoe7847b02015-03-16 11:56:12 +02002086 // Make the type an array even if size check failed.
2087 // This ensures useless error messages regarding the variable's non-arrayness won't follow.
2088 arrayType.setArraySize(size);
Jamie Madill60ed9812013-06-06 11:56:46 -04002089
Olli Etuaho2935c582015-04-08 14:32:06 +03002090 TVariable *variable = nullptr;
Olli Etuaho383b7912016-08-05 11:22:59 +03002091 declareVariable(identifierLocation, identifier, arrayType, &variable);
Jamie Madill60ed9812013-06-06 11:56:46 -04002092
Olli Etuaho13389b62016-10-16 11:48:18 +01002093 TIntermDeclaration *declaration = new TIntermDeclaration();
2094 declaration->setLine(identifierLocation);
2095
Olli Etuahoe7847b02015-03-16 11:56:12 +02002096 TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04002097 if (variable && symbol)
Olli Etuaho13389b62016-10-16 11:48:18 +01002098 {
Jamie Madill60ed9812013-06-06 11:56:46 -04002099 symbol->setId(variable->getUniqueId());
Olli Etuaho13389b62016-10-16 11:48:18 +01002100 declaration->appendDeclarator(symbol);
2101 }
Jamie Madill60ed9812013-06-06 11:56:46 -04002102
Olli Etuaho13389b62016-10-16 11:48:18 +01002103 return declaration;
Jamie Madill60ed9812013-06-06 11:56:46 -04002104}
2105
Olli Etuaho13389b62016-10-16 11:48:18 +01002106TIntermDeclaration *TParseContext::parseSingleInitDeclaration(const TPublicType &publicType,
2107 const TSourceLoc &identifierLocation,
2108 const TString &identifier,
2109 const TSourceLoc &initLocation,
2110 TIntermTyped *initializer)
Jamie Madill60ed9812013-06-06 11:56:46 -04002111{
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002112 mDeferredNonEmptyDeclarationErrorCheck = false;
Olli Etuahofa33d582015-04-09 14:33:12 +03002113
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002114 declarationQualifierErrorCheck(publicType.qualifier, publicType.layoutQualifier,
2115 identifierLocation);
2116
2117 nonEmptyDeclarationErrorCheck(publicType, identifierLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04002118
Olli Etuaho13389b62016-10-16 11:48:18 +01002119 TIntermDeclaration *declaration = new TIntermDeclaration();
2120 declaration->setLine(identifierLocation);
2121
2122 TIntermBinary *initNode = nullptr;
2123 if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &initNode))
Jamie Madill60ed9812013-06-06 11:56:46 -04002124 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002125 if (initNode)
2126 {
2127 declaration->appendDeclarator(initNode);
2128 }
Jamie Madill60ed9812013-06-06 11:56:46 -04002129 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002130 return declaration;
Jamie Madill60ed9812013-06-06 11:56:46 -04002131}
2132
Olli Etuaho13389b62016-10-16 11:48:18 +01002133TIntermDeclaration *TParseContext::parseSingleArrayInitDeclaration(
Jamie Madillb98c3a82015-07-23 14:26:04 -04002134 TPublicType &publicType,
2135 const TSourceLoc &identifierLocation,
2136 const TString &identifier,
2137 const TSourceLoc &indexLocation,
2138 TIntermTyped *indexExpression,
2139 const TSourceLoc &initLocation,
2140 TIntermTyped *initializer)
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002141{
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002142 mDeferredNonEmptyDeclarationErrorCheck = false;
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002143
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002144 declarationQualifierErrorCheck(publicType.qualifier, publicType.layoutQualifier,
2145 identifierLocation);
2146
2147 nonEmptyDeclarationErrorCheck(publicType, identifierLocation);
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002148
Olli Etuaho8a176262016-08-16 14:23:01 +03002149 checkIsValidTypeAndQualifierForArray(indexLocation, publicType);
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002150
2151 TPublicType arrayType(publicType);
2152
Olli Etuaho856c4972016-08-08 11:38:39 +03002153 unsigned int size = 0u;
Jamie Madillb98c3a82015-07-23 14:26:04 -04002154 // If indexExpression is nullptr, then the array will eventually get its size implicitly from
2155 // the initializer.
Olli Etuaho383b7912016-08-05 11:22:59 +03002156 if (indexExpression != nullptr)
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002157 {
Olli Etuaho856c4972016-08-08 11:38:39 +03002158 size = checkIsValidArraySize(identifierLocation, indexExpression);
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002159 }
2160 // Make the type an array even if size check failed.
2161 // This ensures useless error messages regarding the variable's non-arrayness won't follow.
2162 arrayType.setArraySize(size);
2163
Olli Etuaho13389b62016-10-16 11:48:18 +01002164 TIntermDeclaration *declaration = new TIntermDeclaration();
2165 declaration->setLine(identifierLocation);
2166
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002167 // initNode will correspond to the whole of "type b[n] = initializer".
Olli Etuaho13389b62016-10-16 11:48:18 +01002168 TIntermBinary *initNode = nullptr;
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002169 if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
2170 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002171 if (initNode)
2172 {
2173 declaration->appendDeclarator(initNode);
2174 }
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002175 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002176
2177 return declaration;
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002178}
2179
Olli Etuahobf4e1b72016-12-09 11:30:15 +00002180TIntermInvariantDeclaration *TParseContext::parseInvariantDeclaration(
Martin Radev70866b82016-07-22 15:27:42 +03002181 const TTypeQualifierBuilder &typeQualifierBuilder,
2182 const TSourceLoc &identifierLoc,
2183 const TString *identifier,
2184 const TSymbol *symbol)
Jamie Madill47e3ec02014-08-20 16:38:33 -04002185{
Olli Etuaho77ba4082016-12-16 12:01:18 +00002186 TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics);
Jamie Madill47e3ec02014-08-20 16:38:33 -04002187
Martin Radev70866b82016-07-22 15:27:42 +03002188 if (!typeQualifier.invariant)
2189 {
2190 error(identifierLoc, "Expected invariant", identifier->c_str());
2191 return nullptr;
2192 }
2193 if (!checkIsAtGlobalLevel(identifierLoc, "invariant varying"))
2194 {
2195 return nullptr;
2196 }
Jamie Madill47e3ec02014-08-20 16:38:33 -04002197 if (!symbol)
2198 {
2199 error(identifierLoc, "undeclared identifier declared as invariant", identifier->c_str());
Olli Etuahoe7847b02015-03-16 11:56:12 +02002200 return nullptr;
Jamie Madill47e3ec02014-08-20 16:38:33 -04002201 }
Martin Radev70866b82016-07-22 15:27:42 +03002202 if (!IsQualifierUnspecified(typeQualifier.qualifier))
Jamie Madill47e3ec02014-08-20 16:38:33 -04002203 {
Martin Radev70866b82016-07-22 15:27:42 +03002204 error(identifierLoc, "invariant declaration specifies qualifier",
2205 getQualifierString(typeQualifier.qualifier));
Jamie Madill47e3ec02014-08-20 16:38:33 -04002206 }
Martin Radev70866b82016-07-22 15:27:42 +03002207 if (typeQualifier.precision != EbpUndefined)
2208 {
2209 error(identifierLoc, "invariant declaration specifies precision",
2210 getPrecisionString(typeQualifier.precision));
2211 }
2212 if (!typeQualifier.layoutQualifier.isEmpty())
2213 {
2214 error(identifierLoc, "invariant declaration specifies layout", "'layout'");
2215 }
2216
2217 const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol);
2218 ASSERT(variable);
2219 const TType &type = variable->getType();
2220
2221 checkInvariantVariableQualifier(typeQualifier.invariant, type.getQualifier(),
2222 typeQualifier.line);
Olli Etuaho43364892017-02-13 16:00:12 +00002223 checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line);
Martin Radev70866b82016-07-22 15:27:42 +03002224
2225 symbolTable.addInvariantVarying(std::string(identifier->c_str()));
2226
2227 TIntermSymbol *intermSymbol =
2228 intermediate.addSymbol(variable->getUniqueId(), *identifier, type, identifierLoc);
2229
Olli Etuahobf4e1b72016-12-09 11:30:15 +00002230 return new TIntermInvariantDeclaration(intermSymbol, identifierLoc);
Jamie Madill47e3ec02014-08-20 16:38:33 -04002231}
2232
Olli Etuaho13389b62016-10-16 11:48:18 +01002233void TParseContext::parseDeclarator(TPublicType &publicType,
2234 const TSourceLoc &identifierLocation,
2235 const TString &identifier,
2236 TIntermDeclaration *declarationOut)
Jamie Madill502d66f2013-06-20 11:55:52 -04002237{
Jamie Madillb98c3a82015-07-23 14:26:04 -04002238 // If the declaration starting this declarator list was empty (example: int,), some checks were
2239 // not performed.
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002240 if (mDeferredNonEmptyDeclarationErrorCheck)
Olli Etuahofa33d582015-04-09 14:33:12 +03002241 {
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002242 nonEmptyDeclarationErrorCheck(publicType, identifierLocation);
2243 mDeferredNonEmptyDeclarationErrorCheck = false;
Olli Etuahofa33d582015-04-09 14:33:12 +03002244 }
2245
Olli Etuaho856c4972016-08-08 11:38:39 +03002246 checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType);
Jamie Madill0bd18df2013-06-20 11:55:52 -04002247
Olli Etuaho856c4972016-08-08 11:38:39 +03002248 checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &publicType);
Jamie Madill502d66f2013-06-20 11:55:52 -04002249
Olli Etuaho2935c582015-04-08 14:32:06 +03002250 TVariable *variable = nullptr;
Olli Etuaho43364892017-02-13 16:00:12 +00002251 TType type(publicType);
2252 declareVariable(identifierLocation, identifier, type, &variable);
Olli Etuahoe7847b02015-03-16 11:56:12 +02002253
Olli Etuaho43364892017-02-13 16:00:12 +00002254 TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, type, identifierLocation);
Olli Etuahoe7847b02015-03-16 11:56:12 +02002255 if (variable && symbol)
Olli Etuaho13389b62016-10-16 11:48:18 +01002256 {
Jamie Madill502d66f2013-06-20 11:55:52 -04002257 symbol->setId(variable->getUniqueId());
Olli Etuaho13389b62016-10-16 11:48:18 +01002258 declarationOut->appendDeclarator(symbol);
2259 }
Jamie Madill502d66f2013-06-20 11:55:52 -04002260}
2261
Olli Etuaho13389b62016-10-16 11:48:18 +01002262void TParseContext::parseArrayDeclarator(TPublicType &publicType,
2263 const TSourceLoc &identifierLocation,
2264 const TString &identifier,
2265 const TSourceLoc &arrayLocation,
2266 TIntermTyped *indexExpression,
2267 TIntermDeclaration *declarationOut)
Jamie Madill502d66f2013-06-20 11:55:52 -04002268{
Jamie Madillb98c3a82015-07-23 14:26:04 -04002269 // If the declaration starting this declarator list was empty (example: int,), some checks were
2270 // not performed.
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002271 if (mDeferredNonEmptyDeclarationErrorCheck)
Olli Etuahofa33d582015-04-09 14:33:12 +03002272 {
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002273 nonEmptyDeclarationErrorCheck(publicType, identifierLocation);
2274 mDeferredNonEmptyDeclarationErrorCheck = false;
Olli Etuahofa33d582015-04-09 14:33:12 +03002275 }
Jamie Madill502d66f2013-06-20 11:55:52 -04002276
Olli Etuaho856c4972016-08-08 11:38:39 +03002277 checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType);
Jamie Madill0bd18df2013-06-20 11:55:52 -04002278
Olli Etuaho856c4972016-08-08 11:38:39 +03002279 checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &publicType);
Jamie Madill502d66f2013-06-20 11:55:52 -04002280
Olli Etuaho8a176262016-08-16 14:23:01 +03002281 if (checkIsValidTypeAndQualifierForArray(arrayLocation, publicType))
Jamie Madill502d66f2013-06-20 11:55:52 -04002282 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002283 TType arrayType = TType(publicType);
Olli Etuaho856c4972016-08-08 11:38:39 +03002284 unsigned int size = checkIsValidArraySize(arrayLocation, indexExpression);
Olli Etuaho693c9aa2015-04-07 17:50:36 +03002285 arrayType.setArraySize(size);
Olli Etuahoe7847b02015-03-16 11:56:12 +02002286
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03002287 TVariable *variable = nullptr;
Olli Etuaho383b7912016-08-05 11:22:59 +03002288 declareVariable(identifierLocation, identifier, arrayType, &variable);
Jamie Madill502d66f2013-06-20 11:55:52 -04002289
Jamie Madillb98c3a82015-07-23 14:26:04 -04002290 TIntermSymbol *symbol =
2291 intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03002292 if (variable && symbol)
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03002293 symbol->setId(variable->getUniqueId());
Olli Etuahoe7847b02015-03-16 11:56:12 +02002294
Olli Etuaho13389b62016-10-16 11:48:18 +01002295 declarationOut->appendDeclarator(symbol);
Jamie Madill502d66f2013-06-20 11:55:52 -04002296 }
Jamie Madill502d66f2013-06-20 11:55:52 -04002297}
2298
Olli Etuaho13389b62016-10-16 11:48:18 +01002299void TParseContext::parseInitDeclarator(const TPublicType &publicType,
2300 const TSourceLoc &identifierLocation,
2301 const TString &identifier,
2302 const TSourceLoc &initLocation,
2303 TIntermTyped *initializer,
2304 TIntermDeclaration *declarationOut)
Jamie Madill502d66f2013-06-20 11:55:52 -04002305{
Jamie Madillb98c3a82015-07-23 14:26:04 -04002306 // If the declaration starting this declarator list was empty (example: int,), some checks were
2307 // not performed.
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002308 if (mDeferredNonEmptyDeclarationErrorCheck)
Olli Etuahofa33d582015-04-09 14:33:12 +03002309 {
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002310 nonEmptyDeclarationErrorCheck(publicType, identifierLocation);
2311 mDeferredNonEmptyDeclarationErrorCheck = false;
Olli Etuahofa33d582015-04-09 14:33:12 +03002312 }
Jamie Madill502d66f2013-06-20 11:55:52 -04002313
Olli Etuaho856c4972016-08-08 11:38:39 +03002314 checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType);
Jamie Madill0bd18df2013-06-20 11:55:52 -04002315
Olli Etuaho13389b62016-10-16 11:48:18 +01002316 TIntermBinary *initNode = nullptr;
2317 if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &initNode))
Jamie Madill502d66f2013-06-20 11:55:52 -04002318 {
2319 //
2320 // build the intermediate representation
2321 //
Olli Etuaho13389b62016-10-16 11:48:18 +01002322 if (initNode)
Jamie Madill502d66f2013-06-20 11:55:52 -04002323 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002324 declarationOut->appendDeclarator(initNode);
Jamie Madill502d66f2013-06-20 11:55:52 -04002325 }
Jamie Madill502d66f2013-06-20 11:55:52 -04002326 }
2327}
2328
Olli Etuaho13389b62016-10-16 11:48:18 +01002329void TParseContext::parseArrayInitDeclarator(const TPublicType &publicType,
2330 const TSourceLoc &identifierLocation,
2331 const TString &identifier,
2332 const TSourceLoc &indexLocation,
2333 TIntermTyped *indexExpression,
2334 const TSourceLoc &initLocation,
2335 TIntermTyped *initializer,
2336 TIntermDeclaration *declarationOut)
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002337{
Jamie Madillb98c3a82015-07-23 14:26:04 -04002338 // If the declaration starting this declarator list was empty (example: int,), some checks were
2339 // not performed.
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002340 if (mDeferredNonEmptyDeclarationErrorCheck)
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002341 {
Olli Etuahobb7e5a72017-04-24 10:16:44 +03002342 nonEmptyDeclarationErrorCheck(publicType, identifierLocation);
2343 mDeferredNonEmptyDeclarationErrorCheck = false;
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002344 }
2345
Olli Etuaho856c4972016-08-08 11:38:39 +03002346 checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType);
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002347
Olli Etuaho8a176262016-08-16 14:23:01 +03002348 checkIsValidTypeAndQualifierForArray(indexLocation, publicType);
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002349
2350 TPublicType arrayType(publicType);
2351
Olli Etuaho856c4972016-08-08 11:38:39 +03002352 unsigned int size = 0u;
Jamie Madillb98c3a82015-07-23 14:26:04 -04002353 // If indexExpression is nullptr, then the array will eventually get its size implicitly from
2354 // the initializer.
Olli Etuaho383b7912016-08-05 11:22:59 +03002355 if (indexExpression != nullptr)
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002356 {
Olli Etuaho856c4972016-08-08 11:38:39 +03002357 size = checkIsValidArraySize(identifierLocation, indexExpression);
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002358 }
2359 // Make the type an array even if size check failed.
2360 // This ensures useless error messages regarding the variable's non-arrayness won't follow.
2361 arrayType.setArraySize(size);
2362
2363 // initNode will correspond to the whole of "b[n] = initializer".
Olli Etuaho13389b62016-10-16 11:48:18 +01002364 TIntermBinary *initNode = nullptr;
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002365 if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
2366 {
2367 if (initNode)
2368 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002369 declarationOut->appendDeclarator(initNode);
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002370 }
Olli Etuaho3875ffd2015-04-10 16:45:14 +03002371 }
2372}
2373
Martin Radev70866b82016-07-22 15:27:42 +03002374void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder)
Jamie Madilla295edf2013-06-06 11:56:48 -04002375{
Olli Etuaho77ba4082016-12-16 12:01:18 +00002376 TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics);
Jamie Madilla295edf2013-06-06 11:56:48 -04002377 const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier;
Jamie Madillc2128ff2016-07-04 10:26:17 -04002378
Martin Radev70866b82016-07-22 15:27:42 +03002379 checkInvariantVariableQualifier(typeQualifier.invariant, typeQualifier.qualifier,
2380 typeQualifier.line);
2381
Jamie Madillc2128ff2016-07-04 10:26:17 -04002382 // It should never be the case, but some strange parser errors can send us here.
2383 if (layoutQualifier.isEmpty())
2384 {
2385 error(typeQualifier.line, "Error during layout qualifier parsing.", "?");
Jamie Madillc2128ff2016-07-04 10:26:17 -04002386 return;
2387 }
Jamie Madilla295edf2013-06-06 11:56:48 -04002388
Martin Radev802abe02016-08-04 17:48:32 +03002389 if (!layoutQualifier.isCombinationValid())
Jamie Madilla295edf2013-06-06 11:56:48 -04002390 {
Olli Etuaho43364892017-02-13 16:00:12 +00002391 error(typeQualifier.line, "invalid layout qualifier combination", "layout");
Jamie Madilla295edf2013-06-06 11:56:48 -04002392 return;
2393 }
2394
Olli Etuaho43364892017-02-13 16:00:12 +00002395 checkBindingIsNotSpecified(typeQualifier.line, layoutQualifier.binding);
2396
2397 checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line);
Martin Radev2cc85b32016-08-05 16:22:53 +03002398
2399 checkInternalFormatIsNotSpecified(typeQualifier.line, layoutQualifier.imageInternalFormat);
2400
Andrei Volykhina5527072017-03-22 16:46:30 +03002401 checkYuvIsNotSpecified(typeQualifier.line, layoutQualifier.yuv);
2402
Martin Radev802abe02016-08-04 17:48:32 +03002403 if (typeQualifier.qualifier == EvqComputeIn)
Jamie Madilla295edf2013-06-06 11:56:48 -04002404 {
Martin Radev802abe02016-08-04 17:48:32 +03002405 if (mComputeShaderLocalSizeDeclared &&
2406 !layoutQualifier.isLocalSizeEqual(mComputeShaderLocalSize))
2407 {
2408 error(typeQualifier.line, "Work group size does not match the previous declaration",
2409 "layout");
Martin Radev802abe02016-08-04 17:48:32 +03002410 return;
2411 }
Jamie Madilla295edf2013-06-06 11:56:48 -04002412
Martin Radev802abe02016-08-04 17:48:32 +03002413 if (mShaderVersion < 310)
2414 {
2415 error(typeQualifier.line, "in type qualifier supported in GLSL ES 3.10 only", "layout");
Martin Radev802abe02016-08-04 17:48:32 +03002416 return;
2417 }
Jamie Madill099c0f32013-06-20 11:55:52 -04002418
Martin Radev4c4c8e72016-08-04 12:25:34 +03002419 if (!layoutQualifier.localSize.isAnyValueSet())
Martin Radev802abe02016-08-04 17:48:32 +03002420 {
2421 error(typeQualifier.line, "No local work group size specified", "layout");
Martin Radev802abe02016-08-04 17:48:32 +03002422 return;
2423 }
2424
2425 const TVariable *maxComputeWorkGroupSize = static_cast<const TVariable *>(
2426 symbolTable.findBuiltIn("gl_MaxComputeWorkGroupSize", mShaderVersion));
2427
2428 const TConstantUnion *maxComputeWorkGroupSizeData =
2429 maxComputeWorkGroupSize->getConstPointer();
2430
2431 for (size_t i = 0u; i < layoutQualifier.localSize.size(); ++i)
2432 {
2433 if (layoutQualifier.localSize[i] != -1)
2434 {
2435 mComputeShaderLocalSize[i] = layoutQualifier.localSize[i];
2436 const int maxComputeWorkGroupSizeValue = maxComputeWorkGroupSizeData[i].getIConst();
2437 if (mComputeShaderLocalSize[i] < 1 ||
2438 mComputeShaderLocalSize[i] > maxComputeWorkGroupSizeValue)
2439 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00002440 std::stringstream reasonStream;
2441 reasonStream << "invalid value: Value must be at least 1 and no greater than "
2442 << maxComputeWorkGroupSizeValue;
2443 const std::string &reason = reasonStream.str();
Martin Radev802abe02016-08-04 17:48:32 +03002444
Olli Etuaho4de340a2016-12-16 09:32:03 +00002445 error(typeQualifier.line, reason.c_str(), getWorkGroupSizeString(i));
Martin Radev802abe02016-08-04 17:48:32 +03002446 return;
2447 }
2448 }
2449 }
2450
2451 mComputeShaderLocalSizeDeclared = true;
2452 }
Olli Etuaho09b04a22016-12-15 13:30:26 +00002453 else if (mMultiviewAvailable &&
2454 (isExtensionEnabled("GL_OVR_multiview") || isExtensionEnabled("GL_OVR_multiview2")) &&
2455 typeQualifier.qualifier == EvqVertexIn)
2456 {
2457 // This error is only specified in WebGL, but tightens unspecified behavior in the native
2458 // specification.
2459 if (mNumViews != -1 && layoutQualifier.numViews != mNumViews)
2460 {
2461 error(typeQualifier.line, "Number of views does not match the previous declaration",
2462 "layout");
2463 return;
2464 }
2465
2466 if (layoutQualifier.numViews == -1)
2467 {
2468 error(typeQualifier.line, "No num_views specified", "layout");
2469 return;
2470 }
2471
2472 if (layoutQualifier.numViews > mMaxNumViews)
2473 {
2474 error(typeQualifier.line, "num_views greater than the value of GL_MAX_VIEWS_OVR",
2475 "layout");
2476 return;
2477 }
2478
2479 mNumViews = layoutQualifier.numViews;
2480 }
Martin Radev802abe02016-08-04 17:48:32 +03002481 else
Jamie Madill1566ef72013-06-20 11:55:54 -04002482 {
Olli Etuaho09b04a22016-12-15 13:30:26 +00002483 if (!checkWorkGroupSizeIsNotSpecified(typeQualifier.line, layoutQualifier))
Martin Radev802abe02016-08-04 17:48:32 +03002484 {
Martin Radev802abe02016-08-04 17:48:32 +03002485 return;
2486 }
2487
2488 if (typeQualifier.qualifier != EvqUniform)
2489 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00002490 error(typeQualifier.line, "invalid qualifier: global layout must be uniform",
2491 getQualifierString(typeQualifier.qualifier));
Martin Radev802abe02016-08-04 17:48:32 +03002492 return;
2493 }
2494
2495 if (mShaderVersion < 300)
2496 {
2497 error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 and above",
2498 "layout");
Martin Radev802abe02016-08-04 17:48:32 +03002499 return;
2500 }
2501
Olli Etuaho09b04a22016-12-15 13:30:26 +00002502 checkLocationIsNotSpecified(typeQualifier.line, layoutQualifier);
Martin Radev802abe02016-08-04 17:48:32 +03002503
2504 if (layoutQualifier.matrixPacking != EmpUnspecified)
2505 {
2506 mDefaultMatrixPacking = layoutQualifier.matrixPacking;
2507 }
2508
2509 if (layoutQualifier.blockStorage != EbsUnspecified)
2510 {
2511 mDefaultBlockStorage = layoutQualifier.blockStorage;
2512 }
Jamie Madill1566ef72013-06-20 11:55:54 -04002513 }
Jamie Madilla295edf2013-06-06 11:56:48 -04002514}
2515
Olli Etuaho8ad9e752017-01-16 19:55:20 +00002516TIntermFunctionPrototype *TParseContext::createPrototypeNodeFromFunction(
2517 const TFunction &function,
2518 const TSourceLoc &location,
2519 bool insertParametersToSymbolTable)
2520{
Olli Etuahofe486322017-03-21 09:30:54 +00002521 TIntermFunctionPrototype *prototype =
2522 new TIntermFunctionPrototype(function.getReturnType(), TSymbolUniqueId(function));
Olli Etuaho8ad9e752017-01-16 19:55:20 +00002523 // TODO(oetuaho@nvidia.com): Instead of converting the function information here, the node could
2524 // point to the data that already exists in the symbol table.
2525 prototype->getFunctionSymbolInfo()->setFromFunction(function);
2526 prototype->setLine(location);
2527
2528 for (size_t i = 0; i < function.getParamCount(); i++)
2529 {
2530 const TConstParameter &param = function.getParam(i);
2531
2532 // If the parameter has no name, it's not an error, just don't add it to symbol table (could
2533 // be used for unused args).
2534 if (param.name != nullptr)
2535 {
2536 TVariable *variable = new TVariable(param.name, *param.type);
2537
2538 // Insert the parameter in the symbol table.
2539 if (insertParametersToSymbolTable && !symbolTable.declare(variable))
2540 {
2541 error(location, "redefinition", variable->getName().c_str());
2542 prototype->appendParameter(intermediate.addSymbol(0, "", *param.type, location));
2543 continue;
2544 }
2545 TIntermSymbol *symbol = intermediate.addSymbol(
2546 variable->getUniqueId(), variable->getName(), variable->getType(), location);
2547 prototype->appendParameter(symbol);
2548 }
2549 else
2550 {
2551 prototype->appendParameter(intermediate.addSymbol(0, "", *param.type, location));
2552 }
2553 }
2554 return prototype;
2555}
2556
Olli Etuaho16c745a2017-01-16 17:02:27 +00002557TIntermFunctionPrototype *TParseContext::addFunctionPrototypeDeclaration(
2558 const TFunction &parsedFunction,
2559 const TSourceLoc &location)
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002560{
Olli Etuaho476197f2016-10-11 13:59:08 +01002561 // Note: function found from the symbol table could be the same as parsedFunction if this is the
2562 // first declaration. Either way the instance in the symbol table is used to track whether the
2563 // function is declared multiple times.
2564 TFunction *function = static_cast<TFunction *>(
2565 symbolTable.find(parsedFunction.getMangledName(), getShaderVersion()));
2566 if (function->hasPrototypeDeclaration() && mShaderVersion == 100)
Olli Etuaho5d653182016-01-04 14:43:28 +02002567 {
2568 // ESSL 1.00.17 section 4.2.7.
2569 // Doesn't apply to ESSL 3.00.4: see section 4.2.3.
2570 error(location, "duplicate function prototype declarations are not allowed", "function");
Olli Etuaho5d653182016-01-04 14:43:28 +02002571 }
Olli Etuaho476197f2016-10-11 13:59:08 +01002572 function->setHasPrototypeDeclaration();
Olli Etuaho5d653182016-01-04 14:43:28 +02002573
Olli Etuaho8ad9e752017-01-16 19:55:20 +00002574 TIntermFunctionPrototype *prototype =
2575 createPrototypeNodeFromFunction(*function, location, false);
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002576
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002577 symbolTable.pop();
Olli Etuaho8d8b1082016-01-04 16:44:57 +02002578
2579 if (!symbolTable.atGlobalLevel())
2580 {
2581 // ESSL 3.00.4 section 4.2.4.
2582 error(location, "local function prototype declarations are not allowed", "function");
Olli Etuaho8d8b1082016-01-04 16:44:57 +02002583 }
2584
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002585 return prototype;
2586}
2587
Olli Etuaho336b1472016-10-05 16:37:55 +01002588TIntermFunctionDefinition *TParseContext::addFunctionDefinition(
Olli Etuaho8ad9e752017-01-16 19:55:20 +00002589 TIntermFunctionPrototype *functionPrototype,
Olli Etuaho336b1472016-10-05 16:37:55 +01002590 TIntermBlock *functionBody,
2591 const TSourceLoc &location)
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002592{
Olli Etuahof51fdd22016-10-03 10:03:40 +01002593 // Check that non-void functions have at least one return statement.
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002594 if (mCurrentFunctionType->getBasicType() != EbtVoid && !mFunctionReturnsValue)
2595 {
Olli Etuaho8ad9e752017-01-16 19:55:20 +00002596 error(location, "function does not return a value:",
2597 functionPrototype->getFunctionSymbolInfo()->getName().c_str());
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002598 }
2599
Olli Etuahof51fdd22016-10-03 10:03:40 +01002600 if (functionBody == nullptr)
2601 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01002602 functionBody = new TIntermBlock();
Olli Etuahof51fdd22016-10-03 10:03:40 +01002603 functionBody->setLine(location);
2604 }
Olli Etuaho336b1472016-10-05 16:37:55 +01002605 TIntermFunctionDefinition *functionNode =
Olli Etuaho8ad9e752017-01-16 19:55:20 +00002606 new TIntermFunctionDefinition(functionPrototype, functionBody);
Olli Etuaho336b1472016-10-05 16:37:55 +01002607 functionNode->setLine(location);
Olli Etuahof51fdd22016-10-03 10:03:40 +01002608
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002609 symbolTable.pop();
Olli Etuahof51fdd22016-10-03 10:03:40 +01002610 return functionNode;
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002611}
2612
Olli Etuaho476197f2016-10-11 13:59:08 +01002613void TParseContext::parseFunctionDefinitionHeader(const TSourceLoc &location,
2614 TFunction **function,
Olli Etuaho8ad9e752017-01-16 19:55:20 +00002615 TIntermFunctionPrototype **prototypeOut)
Jamie Madill185fb402015-06-12 15:48:48 -04002616{
Olli Etuaho476197f2016-10-11 13:59:08 +01002617 ASSERT(function);
2618 ASSERT(*function);
Jamie Madillb98c3a82015-07-23 14:26:04 -04002619 const TSymbol *builtIn =
Olli Etuaho476197f2016-10-11 13:59:08 +01002620 symbolTable.findBuiltIn((*function)->getMangledName(), getShaderVersion());
Jamie Madill185fb402015-06-12 15:48:48 -04002621
2622 if (builtIn)
2623 {
Olli Etuaho476197f2016-10-11 13:59:08 +01002624 error(location, "built-in functions cannot be redefined", (*function)->getName().c_str());
Jamie Madill185fb402015-06-12 15:48:48 -04002625 }
Olli Etuaho476197f2016-10-11 13:59:08 +01002626 else
Jamie Madill185fb402015-06-12 15:48:48 -04002627 {
Olli Etuaho476197f2016-10-11 13:59:08 +01002628 TFunction *prevDec = static_cast<TFunction *>(
2629 symbolTable.find((*function)->getMangledName(), getShaderVersion()));
2630
2631 // Note: 'prevDec' could be 'function' if this is the first time we've seen function as it
2632 // would have just been put in the symbol table. Otherwise, we're looking up an earlier
2633 // occurance.
2634 if (*function != prevDec)
2635 {
2636 // Swap the parameters of the previous declaration to the parameters of the function
2637 // definition (parameter names may differ).
2638 prevDec->swapParameters(**function);
2639
2640 // The function definition will share the same symbol as any previous declaration.
2641 *function = prevDec;
2642 }
2643
2644 if ((*function)->isDefined())
2645 {
2646 error(location, "function already has a body", (*function)->getName().c_str());
2647 }
2648
2649 (*function)->setDefined();
Jamie Madill185fb402015-06-12 15:48:48 -04002650 }
Jamie Madill185fb402015-06-12 15:48:48 -04002651
Olli Etuaho8ad9e752017-01-16 19:55:20 +00002652 // Remember the return type for later checking for return statements.
Olli Etuaho476197f2016-10-11 13:59:08 +01002653 mCurrentFunctionType = &((*function)->getReturnType());
Olli Etuahoee63f5d2016-01-04 11:34:54 +02002654 mFunctionReturnsValue = false;
Jamie Madill185fb402015-06-12 15:48:48 -04002655
Olli Etuaho8ad9e752017-01-16 19:55:20 +00002656 *prototypeOut = createPrototypeNodeFromFunction(**function, location, true);
Jamie Madill185fb402015-06-12 15:48:48 -04002657 setLoopNestingLevel(0);
2658}
2659
Jamie Madillb98c3a82015-07-23 14:26:04 -04002660TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TFunction *function)
Jamie Madill185fb402015-06-12 15:48:48 -04002661{
Geoff Lang13e7c7e2015-07-30 14:17:29 +00002662 //
Olli Etuaho5d653182016-01-04 14:43:28 +02002663 // We don't know at this point whether this is a function definition or a prototype.
2664 // The definition production code will check for redefinitions.
2665 // In the case of ESSL 1.00 the prototype production code will also check for redeclarations.
Geoff Lang13e7c7e2015-07-30 14:17:29 +00002666 //
Olli Etuaho5d653182016-01-04 14:43:28 +02002667 // Return types and parameter qualifiers must match in all redeclarations, so those are checked
2668 // here.
Geoff Lang13e7c7e2015-07-30 14:17:29 +00002669 //
2670 TFunction *prevDec =
2671 static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion()));
Olli Etuahoc4a96d62015-07-23 17:37:39 +05302672
Martin Radevda6254b2016-12-14 17:00:36 +02002673 if (getShaderVersion() >= 300 &&
2674 symbolTable.hasUnmangledBuiltInForShaderVersion(function->getName().c_str(),
2675 getShaderVersion()))
Olli Etuahoc4a96d62015-07-23 17:37:39 +05302676 {
Martin Radevda6254b2016-12-14 17:00:36 +02002677 // With ESSL 3.00 and above, names of built-in functions cannot be redeclared as functions.
Olli Etuahoc4a96d62015-07-23 17:37:39 +05302678 // Therefore overloading or redefining builtin functions is an error.
2679 error(location, "Name of a built-in function cannot be redeclared as function",
2680 function->getName().c_str());
Olli Etuahoc4a96d62015-07-23 17:37:39 +05302681 }
2682 else if (prevDec)
Jamie Madill185fb402015-06-12 15:48:48 -04002683 {
2684 if (prevDec->getReturnType() != function->getReturnType())
2685 {
Olli Etuaho476197f2016-10-11 13:59:08 +01002686 error(location, "function must have the same return type in all of its declarations",
Jamie Madill185fb402015-06-12 15:48:48 -04002687 function->getReturnType().getBasicString());
Jamie Madill185fb402015-06-12 15:48:48 -04002688 }
2689 for (size_t i = 0; i < prevDec->getParamCount(); ++i)
2690 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002691 if (prevDec->getParam(i).type->getQualifier() !=
2692 function->getParam(i).type->getQualifier())
Jamie Madill185fb402015-06-12 15:48:48 -04002693 {
Olli Etuaho476197f2016-10-11 13:59:08 +01002694 error(location,
2695 "function must have the same parameter qualifiers in all of its declarations",
Jamie Madill185fb402015-06-12 15:48:48 -04002696 function->getParam(i).type->getQualifierString());
Jamie Madill185fb402015-06-12 15:48:48 -04002697 }
2698 }
2699 }
2700
2701 //
2702 // Check for previously declared variables using the same name.
2703 //
Geoff Lang13e7c7e2015-07-30 14:17:29 +00002704 TSymbol *prevSym = symbolTable.find(function->getName(), getShaderVersion());
Jamie Madill185fb402015-06-12 15:48:48 -04002705 if (prevSym)
2706 {
2707 if (!prevSym->isFunction())
2708 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00002709 error(location, "redefinition of a function", function->getName().c_str());
Jamie Madill185fb402015-06-12 15:48:48 -04002710 }
2711 }
2712 else
2713 {
2714 // Insert the unmangled name to detect potential future redefinition as a variable.
Olli Etuaho476197f2016-10-11 13:59:08 +01002715 symbolTable.getOuterLevel()->insertUnmangled(function);
Jamie Madill185fb402015-06-12 15:48:48 -04002716 }
2717
2718 // We're at the inner scope level of the function's arguments and body statement.
2719 // Add the function prototype to the surrounding scope instead.
2720 symbolTable.getOuterLevel()->insert(function);
2721
Olli Etuaho78d13742017-01-18 13:06:10 +00002722 // Raise error message if main function takes any parameters or return anything other than void
2723 if (function->getName() == "main")
2724 {
2725 if (function->getParamCount() > 0)
2726 {
2727 error(location, "function cannot take any parameter(s)", "main");
2728 }
2729 if (function->getReturnType().getBasicType() != EbtVoid)
2730 {
2731 error(location, "main function cannot return a value",
2732 function->getReturnType().getBasicString());
2733 }
2734 }
2735
Jamie Madill185fb402015-06-12 15:48:48 -04002736 //
Jamie Madillb98c3a82015-07-23 14:26:04 -04002737 // If this is a redeclaration, it could also be a definition, in which case, we want to use the
2738 // variable names from this one, and not the one that's
Jamie Madill185fb402015-06-12 15:48:48 -04002739 // being redeclared. So, pass back up this declaration, not the one in the symbol table.
2740 //
2741 return function;
2742}
2743
Olli Etuaho9de84a52016-06-14 17:36:01 +03002744TFunction *TParseContext::parseFunctionHeader(const TPublicType &type,
2745 const TString *name,
2746 const TSourceLoc &location)
2747{
2748 if (type.qualifier != EvqGlobal && type.qualifier != EvqTemporary)
2749 {
2750 error(location, "no qualifiers allowed for function return",
2751 getQualifierString(type.qualifier));
Olli Etuaho9de84a52016-06-14 17:36:01 +03002752 }
2753 if (!type.layoutQualifier.isEmpty())
2754 {
2755 error(location, "no qualifiers allowed for function return", "layout");
Olli Etuaho9de84a52016-06-14 17:36:01 +03002756 }
Martin Radev2cc85b32016-08-05 16:22:53 +03002757 // make sure a sampler or an image is not involved as well...
Martin Radev4a9cd802016-09-01 16:51:51 +03002758 checkIsNotSampler(location, type.typeSpecifierNonArray,
2759 "samplers can't be function return values");
Martin Radev2cc85b32016-08-05 16:22:53 +03002760 checkIsNotImage(location, type.typeSpecifierNonArray, "images can't be function return values");
Olli Etuahoe29324f2016-06-15 10:58:03 +03002761 if (mShaderVersion < 300)
2762 {
2763 // Array return values are forbidden, but there's also no valid syntax for declaring array
2764 // return values in ESSL 1.00.
Olli Etuaho77ba4082016-12-16 12:01:18 +00002765 ASSERT(type.arraySize == 0 || mDiagnostics->numErrors() > 0);
Olli Etuahoe29324f2016-06-15 10:58:03 +03002766
2767 if (type.isStructureContainingArrays())
2768 {
2769 // ESSL 1.00.17 section 6.1 Function Definitions
2770 error(location, "structures containing arrays can't be function return values",
2771 TType(type).getCompleteString().c_str());
Olli Etuahoe29324f2016-06-15 10:58:03 +03002772 }
2773 }
Olli Etuaho9de84a52016-06-14 17:36:01 +03002774
2775 // Add the function as a prototype after parsing it (we do not support recursion)
2776 return new TFunction(name, new TType(type));
2777}
2778
Jamie Madill06145232015-05-13 13:10:01 -04002779TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn)
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002780{
Jamie Madill06145232015-05-13 13:10:01 -04002781 TPublicType publicType = publicTypeIn;
Martin Radev4a9cd802016-09-01 16:51:51 +03002782 if (publicType.isStructSpecifier())
Olli Etuahobd163f62015-11-13 12:15:38 +02002783 {
Martin Radev4a9cd802016-09-01 16:51:51 +03002784 error(publicType.getLine(), "constructor can't be a structure definition",
2785 getBasicString(publicType.getBasicType()));
Olli Etuahobd163f62015-11-13 12:15:38 +02002786 }
2787
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002788 TOperator op = EOpNull;
Martin Radev4a9cd802016-09-01 16:51:51 +03002789 if (publicType.getUserDef())
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002790 {
2791 op = EOpConstructStruct;
2792 }
2793 else
2794 {
Geoff Lang156d7192016-07-21 16:11:00 -04002795 op = sh::TypeToConstructorOperator(TType(publicType));
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002796 if (op == EOpNull)
2797 {
Martin Radev4a9cd802016-09-01 16:51:51 +03002798 error(publicType.getLine(), "cannot construct this type",
2799 getBasicString(publicType.getBasicType()));
2800 publicType.setBasicType(EbtFloat);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002801 op = EOpConstructFloat;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002802 }
2803 }
2804
Dmitry Skiba7f17a502015-06-22 15:08:39 -07002805 const TType *type = new TType(publicType);
Olli Etuaho72d10202017-01-19 15:58:30 +00002806 return new TFunction(nullptr, type, op);
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002807}
2808
Jamie Madillb98c3a82015-07-23 14:26:04 -04002809// This function is used to test for the correctness of the parameters passed to various constructor
2810// functions and also convert them to the right datatype if it is allowed and required.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002811//
Olli Etuaho856c4972016-08-08 11:38:39 +03002812// 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 +00002813//
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002814TIntermTyped *TParseContext::addConstructor(TIntermSequence *arguments,
Jamie Madillb98c3a82015-07-23 14:26:04 -04002815 TOperator op,
Olli Etuaho72d10202017-01-19 15:58:30 +00002816 TType type,
Arun Patole7e7e68d2015-05-22 12:02:25 +05302817 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002818{
Olli Etuaho856c4972016-08-08 11:38:39 +03002819 if (type.isUnsizedArray())
2820 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002821 if (arguments->empty())
Olli Etuahobbe9fb52016-11-03 17:16:05 +00002822 {
2823 error(line, "implicitly sized array constructor must have at least one argument", "[]");
2824 type.setArraySize(1u);
2825 return TIntermTyped::CreateZero(type);
2826 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002827 type.setArraySize(static_cast<unsigned int>(arguments->size()));
Olli Etuaho856c4972016-08-08 11:38:39 +03002828 }
Olli Etuaho856c4972016-08-08 11:38:39 +03002829
Olli Etuaho72d10202017-01-19 15:58:30 +00002830 if (!checkConstructorArguments(line, arguments, op, type))
Olli Etuaho856c4972016-08-08 11:38:39 +03002831 {
Olli Etuaho72d10202017-01-19 15:58:30 +00002832 return TIntermTyped::CreateZero(type);
Olli Etuaho856c4972016-08-08 11:38:39 +03002833 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02002834
Olli Etuahofe486322017-03-21 09:30:54 +00002835 TIntermAggregate *constructorNode = TIntermAggregate::CreateConstructor(type, op, arguments);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002836 constructorNode->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002837
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002838 TIntermTyped *constConstructor =
2839 intermediate.foldAggregateBuiltIn(constructorNode, mDiagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02002840 if (constConstructor)
2841 {
2842 return constConstructor;
2843 }
2844
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002845 return constructorNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002846}
2847
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002848//
2849// Interface/uniform blocks
2850//
Olli Etuaho13389b62016-10-16 11:48:18 +01002851TIntermDeclaration *TParseContext::addInterfaceBlock(
Martin Radev70866b82016-07-22 15:27:42 +03002852 const TTypeQualifierBuilder &typeQualifierBuilder,
2853 const TSourceLoc &nameLine,
2854 const TString &blockName,
2855 TFieldList *fieldList,
2856 const TString *instanceName,
2857 const TSourceLoc &instanceLine,
2858 TIntermTyped *arrayIndex,
2859 const TSourceLoc &arrayIndexLine)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002860{
Olli Etuaho856c4972016-08-08 11:38:39 +03002861 checkIsNotReserved(nameLine, blockName);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002862
Olli Etuaho77ba4082016-12-16 12:01:18 +00002863 TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics);
Martin Radev70866b82016-07-22 15:27:42 +03002864
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002865 if (typeQualifier.qualifier != EvqUniform)
2866 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00002867 error(typeQualifier.line, "invalid qualifier: interface blocks must be uniform",
2868 getQualifierString(typeQualifier.qualifier));
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002869 }
2870
Martin Radev70866b82016-07-22 15:27:42 +03002871 if (typeQualifier.invariant)
2872 {
2873 error(typeQualifier.line, "invalid qualifier on interface block member", "invariant");
2874 }
2875
Olli Etuaho43364892017-02-13 16:00:12 +00002876 checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line);
2877
2878 // TODO(oetuaho): Remove this and support binding for blocks.
2879 checkBindingIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.binding);
Martin Radev2cc85b32016-08-05 16:22:53 +03002880
Andrei Volykhina5527072017-03-22 16:46:30 +03002881 checkYuvIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.yuv);
2882
Jamie Madill099c0f32013-06-20 11:55:52 -04002883 TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier;
Olli Etuaho856c4972016-08-08 11:38:39 +03002884 checkLocationIsNotSpecified(typeQualifier.line, blockLayoutQualifier);
Jamie Madilla5efff92013-06-06 11:56:47 -04002885
Jamie Madill099c0f32013-06-20 11:55:52 -04002886 if (blockLayoutQualifier.matrixPacking == EmpUnspecified)
2887 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04002888 blockLayoutQualifier.matrixPacking = mDefaultMatrixPacking;
Jamie Madill099c0f32013-06-20 11:55:52 -04002889 }
2890
Jamie Madill1566ef72013-06-20 11:55:54 -04002891 if (blockLayoutQualifier.blockStorage == EbsUnspecified)
2892 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04002893 blockLayoutQualifier.blockStorage = mDefaultBlockStorage;
Jamie Madill1566ef72013-06-20 11:55:54 -04002894 }
2895
Olli Etuaho856c4972016-08-08 11:38:39 +03002896 checkWorkGroupSizeIsNotSpecified(nameLine, blockLayoutQualifier);
Martin Radev802abe02016-08-04 17:48:32 +03002897
Martin Radev2cc85b32016-08-05 16:22:53 +03002898 checkInternalFormatIsNotSpecified(nameLine, blockLayoutQualifier.imageInternalFormat);
2899
Arun Patole7e7e68d2015-05-22 12:02:25 +05302900 TSymbol *blockNameSymbol = new TInterfaceBlockName(&blockName);
2901 if (!symbolTable.declare(blockNameSymbol))
2902 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00002903 error(nameLine, "redefinition of an interface block name", blockName.c_str());
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002904 }
2905
Jamie Madill98493dd2013-07-08 14:39:03 -04002906 // check for sampler types and apply layout qualifiers
Arun Patole7e7e68d2015-05-22 12:02:25 +05302907 for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
2908 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002909 TField *field = (*fieldList)[memberIndex];
Arun Patole7e7e68d2015-05-22 12:02:25 +05302910 TType *fieldType = field->type();
2911 if (IsSampler(fieldType->getBasicType()))
2912 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00002913 error(field->line(),
2914 "unsupported type - sampler types are not allowed in interface blocks",
2915 fieldType->getBasicString());
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002916 }
2917
Martin Radev2cc85b32016-08-05 16:22:53 +03002918 if (IsImage(fieldType->getBasicType()))
2919 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00002920 error(field->line(),
2921 "unsupported type - image types are not allowed in interface blocks",
2922 fieldType->getBasicString());
Martin Radev2cc85b32016-08-05 16:22:53 +03002923 }
2924
Jamie Madill98493dd2013-07-08 14:39:03 -04002925 const TQualifier qualifier = fieldType->getQualifier();
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002926 switch (qualifier)
2927 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002928 case EvqGlobal:
2929 case EvqUniform:
2930 break;
2931 default:
2932 error(field->line(), "invalid qualifier on interface block member",
2933 getQualifierString(qualifier));
Jamie Madillb98c3a82015-07-23 14:26:04 -04002934 break;
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002935 }
Jamie Madilla5efff92013-06-06 11:56:47 -04002936
Martin Radev70866b82016-07-22 15:27:42 +03002937 if (fieldType->isInvariant())
2938 {
2939 error(field->line(), "invalid qualifier on interface block member", "invariant");
2940 }
2941
Jamie Madilla5efff92013-06-06 11:56:47 -04002942 // check layout qualifiers
Jamie Madill98493dd2013-07-08 14:39:03 -04002943 TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier();
Olli Etuaho856c4972016-08-08 11:38:39 +03002944 checkLocationIsNotSpecified(field->line(), fieldLayoutQualifier);
Jamie Madill099c0f32013-06-20 11:55:52 -04002945
Jamie Madill98493dd2013-07-08 14:39:03 -04002946 if (fieldLayoutQualifier.blockStorage != EbsUnspecified)
Jamie Madill1566ef72013-06-20 11:55:54 -04002947 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00002948 error(field->line(), "invalid layout qualifier: cannot be used here",
2949 getBlockStorageString(fieldLayoutQualifier.blockStorage));
Jamie Madill1566ef72013-06-20 11:55:54 -04002950 }
2951
Jamie Madill98493dd2013-07-08 14:39:03 -04002952 if (fieldLayoutQualifier.matrixPacking == EmpUnspecified)
Jamie Madill099c0f32013-06-20 11:55:52 -04002953 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002954 fieldLayoutQualifier.matrixPacking = blockLayoutQualifier.matrixPacking;
Jamie Madill099c0f32013-06-20 11:55:52 -04002955 }
Olli Etuahofb6ab2c2015-07-09 20:55:28 +03002956 else if (!fieldType->isMatrix() && fieldType->getBasicType() != EbtStruct)
Jamie Madill099c0f32013-06-20 11:55:52 -04002957 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00002958 warning(field->line(),
2959 "extraneous layout qualifier: only has an effect on matrix types",
2960 getMatrixPackingString(fieldLayoutQualifier.matrixPacking));
Jamie Madill099c0f32013-06-20 11:55:52 -04002961 }
2962
Jamie Madill98493dd2013-07-08 14:39:03 -04002963 fieldType->setLayoutQualifier(fieldLayoutQualifier);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002964 }
2965
Jamie Madill98493dd2013-07-08 14:39:03 -04002966 // add array index
Olli Etuaho856c4972016-08-08 11:38:39 +03002967 unsigned int arraySize = 0;
2968 if (arrayIndex != nullptr)
Jamie Madill98493dd2013-07-08 14:39:03 -04002969 {
Olli Etuaho856c4972016-08-08 11:38:39 +03002970 arraySize = checkIsValidArraySize(arrayIndexLine, arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04002971 }
2972
Jamie Madillb98c3a82015-07-23 14:26:04 -04002973 TInterfaceBlock *interfaceBlock =
2974 new TInterfaceBlock(&blockName, fieldList, instanceName, arraySize, blockLayoutQualifier);
2975 TType interfaceBlockType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier,
2976 arraySize);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002977
2978 TString symbolName = "";
Jamie Madillb98c3a82015-07-23 14:26:04 -04002979 int symbolId = 0;
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002980
Jamie Madill98493dd2013-07-08 14:39:03 -04002981 if (!instanceName)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002982 {
2983 // define symbols for the members of the interface block
Jamie Madill98493dd2013-07-08 14:39:03 -04002984 for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
2985 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002986 TField *field = (*fieldList)[memberIndex];
Arun Patole7e7e68d2015-05-22 12:02:25 +05302987 TType *fieldType = field->type();
Jamie Madill98493dd2013-07-08 14:39:03 -04002988
2989 // set parent pointer of the field variable
2990 fieldType->setInterfaceBlock(interfaceBlock);
2991
Arun Patole7e7e68d2015-05-22 12:02:25 +05302992 TVariable *fieldVariable = new TVariable(&field->name(), *fieldType);
Jamie Madill98493dd2013-07-08 14:39:03 -04002993 fieldVariable->setQualifier(typeQualifier.qualifier);
2994
Arun Patole7e7e68d2015-05-22 12:02:25 +05302995 if (!symbolTable.declare(fieldVariable))
2996 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00002997 error(field->line(), "redefinition of an interface block member name",
2998 field->name().c_str());
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002999 }
3000 }
3001 }
3002 else
3003 {
Olli Etuaho856c4972016-08-08 11:38:39 +03003004 checkIsNotReserved(instanceLine, *instanceName);
Olli Etuahoe0f623a2015-07-10 11:58:30 +03003005
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003006 // add a symbol for this interface block
Arun Patole7e7e68d2015-05-22 12:02:25 +05303007 TVariable *instanceTypeDef = new TVariable(instanceName, interfaceBlockType, false);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003008 instanceTypeDef->setQualifier(typeQualifier.qualifier);
Jamie Madill98493dd2013-07-08 14:39:03 -04003009
Arun Patole7e7e68d2015-05-22 12:02:25 +05303010 if (!symbolTable.declare(instanceTypeDef))
3011 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00003012 error(instanceLine, "redefinition of an interface block instance name",
3013 instanceName->c_str());
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003014 }
3015
Jamie Madillb98c3a82015-07-23 14:26:04 -04003016 symbolId = instanceTypeDef->getUniqueId();
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003017 symbolName = instanceTypeDef->getName();
3018 }
3019
Olli Etuaho13389b62016-10-16 11:48:18 +01003020 TIntermSymbol *blockSymbol =
3021 intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line);
3022 TIntermDeclaration *declaration = new TIntermDeclaration();
3023 declaration->appendDeclarator(blockSymbol);
3024 declaration->setLine(nameLine);
Jamie Madill98493dd2013-07-08 14:39:03 -04003025
3026 exitStructDeclaration();
Olli Etuaho13389b62016-10-16 11:48:18 +01003027 return declaration;
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003028}
3029
Olli Etuaho383b7912016-08-05 11:22:59 +03003030void TParseContext::enterStructDeclaration(const TSourceLoc &line, const TString &identifier)
kbr@chromium.org476541f2011-10-27 21:14:51 +00003031{
Jamie Madill6e06b1f2015-05-14 10:01:17 -04003032 ++mStructNestingLevel;
kbr@chromium.org476541f2011-10-27 21:14:51 +00003033
3034 // Embedded structure definitions are not supported per GLSL ES spec.
Olli Etuaho4de340a2016-12-16 09:32:03 +00003035 // ESSL 1.00.17 section 10.9. ESSL 3.00.6 section 12.11.
Arun Patole7e7e68d2015-05-22 12:02:25 +05303036 if (mStructNestingLevel > 1)
3037 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00003038 error(line, "Embedded struct definitions are not allowed", "struct");
kbr@chromium.org476541f2011-10-27 21:14:51 +00003039 }
kbr@chromium.org476541f2011-10-27 21:14:51 +00003040}
3041
3042void TParseContext::exitStructDeclaration()
3043{
Jamie Madill6e06b1f2015-05-14 10:01:17 -04003044 --mStructNestingLevel;
kbr@chromium.org476541f2011-10-27 21:14:51 +00003045}
3046
Olli Etuaho8a176262016-08-16 14:23:01 +03003047void TParseContext::checkIsBelowStructNestingLimit(const TSourceLoc &line, const TField &field)
kbr@chromium.org476541f2011-10-27 21:14:51 +00003048{
Jamie Madillacb4b812016-11-07 13:50:29 -05003049 if (!sh::IsWebGLBasedSpec(mShaderSpec))
Arun Patole7e7e68d2015-05-22 12:02:25 +05303050 {
Olli Etuaho8a176262016-08-16 14:23:01 +03003051 return;
kbr@chromium.org476541f2011-10-27 21:14:51 +00003052 }
3053
Arun Patole7e7e68d2015-05-22 12:02:25 +05303054 if (field.type()->getBasicType() != EbtStruct)
3055 {
Olli Etuaho8a176262016-08-16 14:23:01 +03003056 return;
kbr@chromium.org476541f2011-10-27 21:14:51 +00003057 }
3058
3059 // We're already inside a structure definition at this point, so add
3060 // one to the field's struct nesting.
Arun Patole7e7e68d2015-05-22 12:02:25 +05303061 if (1 + field.type()->getDeepestStructNesting() > kWebGLMaxStructNesting)
3062 {
Jamie Madill41a49272014-03-18 16:10:13 -04003063 std::stringstream reasonStream;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003064 reasonStream << "Reference of struct type " << field.type()->getStruct()->name().c_str()
3065 << " exceeds maximum allowed nesting level of " << kWebGLMaxStructNesting;
Jamie Madill41a49272014-03-18 16:10:13 -04003066 std::string reason = reasonStream.str();
Olli Etuaho4de340a2016-12-16 09:32:03 +00003067 error(line, reason.c_str(), field.name().c_str());
Olli Etuaho8a176262016-08-16 14:23:01 +03003068 return;
kbr@chromium.org476541f2011-10-27 21:14:51 +00003069 }
kbr@chromium.org476541f2011-10-27 21:14:51 +00003070}
3071
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00003072//
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003073// Parse an array index expression
3074//
Jamie Madillb98c3a82015-07-23 14:26:04 -04003075TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression,
3076 const TSourceLoc &location,
Arun Patole7e7e68d2015-05-22 12:02:25 +05303077 TIntermTyped *indexExpression)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003078{
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003079 if (!baseExpression->isArray() && !baseExpression->isMatrix() && !baseExpression->isVector())
3080 {
3081 if (baseExpression->getAsSymbolNode())
3082 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05303083 error(location, " left of '[' is not of type array, matrix, or vector ",
3084 baseExpression->getAsSymbolNode()->getSymbol().c_str());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003085 }
3086 else
3087 {
3088 error(location, " left of '[' is not of type array, matrix, or vector ", "expression");
3089 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003090
3091 TConstantUnion *unionArray = new TConstantUnion[1];
3092 unionArray->setFConst(0.0f);
3093 return intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst),
3094 location);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003095 }
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003096
Jamie Madill21c1e452014-12-29 11:33:41 -05003097 TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion();
3098
Olli Etuaho36b05142015-11-12 13:10:42 +02003099 // TODO(oetuaho@nvidia.com): Get rid of indexConstantUnion == nullptr below once ANGLE is able
3100 // to constant fold all constant expressions. Right now we don't allow indexing interface blocks
3101 // or fragment outputs with expressions that ANGLE is not able to constant fold, even if the
3102 // index is a constant expression.
3103 if (indexExpression->getQualifier() != EvqConst || indexConstantUnion == nullptr)
3104 {
3105 if (baseExpression->isInterfaceBlock())
3106 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00003107 error(location,
3108 "array indexes for interface blocks arrays must be constant integral expressions",
3109 "[");
Olli Etuaho36b05142015-11-12 13:10:42 +02003110 }
3111 else if (baseExpression->getQualifier() == EvqFragmentOut)
3112 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00003113 error(location,
3114 "array indexes for fragment outputs must be constant integral expressions", "[");
Olli Etuaho36b05142015-11-12 13:10:42 +02003115 }
Olli Etuaho3e960462015-11-12 15:58:39 +02003116 else if (mShaderSpec == SH_WEBGL2_SPEC && baseExpression->getQualifier() == EvqFragData)
3117 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00003118 error(location, "array index for gl_FragData must be constant zero", "[");
Olli Etuaho3e960462015-11-12 15:58:39 +02003119 }
Olli Etuaho36b05142015-11-12 13:10:42 +02003120 }
3121
Olli Etuaho7c3848e2015-11-04 13:19:17 +02003122 if (indexConstantUnion)
Jamie Madill7164cf42013-07-08 13:30:59 -04003123 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003124 // If an out-of-range index is not qualified as constant, the behavior in the spec is
3125 // undefined. This applies even if ANGLE has been able to constant fold it (ANGLE may
3126 // constant fold expressions that are not constant expressions). The most compatible way to
3127 // handle this case is to report a warning instead of an error and force the index to be in
3128 // the correct range.
Olli Etuaho7c3848e2015-11-04 13:19:17 +02003129 bool outOfRangeIndexIsError = indexExpression->getQualifier() == EvqConst;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003130 int index = indexConstantUnion->getIConst(0);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003131
3132 int safeIndex = -1;
3133
3134 if (baseExpression->isArray())
Jamie Madill7164cf42013-07-08 13:30:59 -04003135 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003136 if (baseExpression->getQualifier() == EvqFragData && index > 0)
Olli Etuaho90892fb2016-07-14 14:44:51 +03003137 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003138 if (mShaderSpec == SH_WEBGL2_SPEC)
3139 {
3140 // Error has been already generated if index is not const.
3141 if (indexExpression->getQualifier() == EvqConst)
3142 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00003143 error(location, "array index for gl_FragData must be constant zero", "[");
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003144 }
3145 safeIndex = 0;
3146 }
3147 else if (!isExtensionEnabled("GL_EXT_draw_buffers"))
3148 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00003149 outOfRangeError(outOfRangeIndexIsError, location,
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003150 "array index for gl_FragData must be zero when "
Olli Etuaho4de340a2016-12-16 09:32:03 +00003151 "GL_EXT_draw_buffers is disabled",
3152 "[");
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003153 safeIndex = 0;
3154 }
Olli Etuaho90892fb2016-07-14 14:44:51 +03003155 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003156 // Only do generic out-of-range check if similar error hasn't already been reported.
3157 if (safeIndex < 0)
Olli Etuaho90892fb2016-07-14 14:44:51 +03003158 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003159 safeIndex = checkIndexOutOfRange(outOfRangeIndexIsError, location, index,
3160 baseExpression->getArraySize(),
Olli Etuaho4de340a2016-12-16 09:32:03 +00003161 "array index out of range");
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003162 }
3163 }
3164 else if (baseExpression->isMatrix())
3165 {
3166 safeIndex = checkIndexOutOfRange(outOfRangeIndexIsError, location, index,
Olli Etuaho90892fb2016-07-14 14:44:51 +03003167 baseExpression->getType().getCols(),
Olli Etuaho4de340a2016-12-16 09:32:03 +00003168 "matrix field selection out of range");
Jamie Madill7164cf42013-07-08 13:30:59 -04003169 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003170 else if (baseExpression->isVector())
Jamie Madill7164cf42013-07-08 13:30:59 -04003171 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003172 safeIndex = checkIndexOutOfRange(outOfRangeIndexIsError, location, index,
3173 baseExpression->getType().getNominalSize(),
Olli Etuaho4de340a2016-12-16 09:32:03 +00003174 "vector field selection out of range");
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003175 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003176
3177 ASSERT(safeIndex >= 0);
3178 // Data of constant unions can't be changed, because it may be shared with other
3179 // constant unions or even builtins, like gl_MaxDrawBuffers. Instead use a new
3180 // sanitized object.
3181 if (safeIndex != index)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003182 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003183 TConstantUnion *safeConstantUnion = new TConstantUnion();
3184 safeConstantUnion->setIConst(safeIndex);
3185 indexConstantUnion->replaceConstantUnion(safeConstantUnion);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003186 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003187
3188 return intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location,
Olli Etuaho77ba4082016-12-16 12:01:18 +00003189 mDiagnostics);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003190 }
Jamie Madill7164cf42013-07-08 13:30:59 -04003191 else
3192 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003193 return intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location,
Olli Etuaho77ba4082016-12-16 12:01:18 +00003194 mDiagnostics);
Jamie Madill7164cf42013-07-08 13:30:59 -04003195 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003196}
3197
Olli Etuaho90892fb2016-07-14 14:44:51 +03003198int TParseContext::checkIndexOutOfRange(bool outOfRangeIndexIsError,
3199 const TSourceLoc &location,
3200 int index,
3201 int arraySize,
Olli Etuaho4de340a2016-12-16 09:32:03 +00003202 const char *reason)
Olli Etuaho90892fb2016-07-14 14:44:51 +03003203{
3204 if (index >= arraySize || index < 0)
3205 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00003206 std::stringstream reasonStream;
3207 reasonStream << reason << " '" << index << "'";
3208 std::string token = reasonStream.str();
3209 outOfRangeError(outOfRangeIndexIsError, location, reason, "[]");
Olli Etuaho90892fb2016-07-14 14:44:51 +03003210 if (index < 0)
3211 {
3212 return 0;
3213 }
3214 else
3215 {
3216 return arraySize - 1;
3217 }
3218 }
3219 return index;
3220}
3221
Jamie Madillb98c3a82015-07-23 14:26:04 -04003222TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpression,
3223 const TSourceLoc &dotLocation,
3224 const TString &fieldString,
3225 const TSourceLoc &fieldLocation)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003226{
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003227 if (baseExpression->isArray())
3228 {
3229 error(fieldLocation, "cannot apply dot operator to an array", ".");
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003230 return baseExpression;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003231 }
3232
3233 if (baseExpression->isVector())
3234 {
3235 TVectorFields fields;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003236 if (!parseVectorFields(fieldString, baseExpression->getNominalSize(), fields,
3237 fieldLocation))
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003238 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003239 fields.num = 1;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003240 fields.offsets[0] = 0;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003241 }
3242
Olli Etuahob6fa0432016-09-28 16:28:05 +01003243 return TIntermediate::AddSwizzle(baseExpression, fields, dotLocation);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003244 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003245 else if (baseExpression->getBasicType() == EbtStruct)
3246 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05303247 const TFieldList &fields = baseExpression->getType().getStruct()->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04003248 if (fields.empty())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003249 {
3250 error(dotLocation, "structure has no fields", "Internal Error");
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003251 return baseExpression;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003252 }
3253 else
3254 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003255 bool fieldFound = false;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003256 unsigned int i;
Jamie Madill98493dd2013-07-08 14:39:03 -04003257 for (i = 0; i < fields.size(); ++i)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003258 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003259 if (fields[i]->name() == fieldString)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003260 {
3261 fieldFound = true;
3262 break;
3263 }
3264 }
3265 if (fieldFound)
3266 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003267 TIntermTyped *index = TIntermTyped::CreateIndexNode(i);
3268 index->setLine(fieldLocation);
3269 return intermediate.addIndex(EOpIndexDirectStruct, baseExpression, index,
Olli Etuaho77ba4082016-12-16 12:01:18 +00003270 dotLocation, mDiagnostics);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003271 }
3272 else
3273 {
3274 error(dotLocation, " no such field in structure", fieldString.c_str());
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003275 return baseExpression;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003276 }
3277 }
3278 }
Jamie Madill98493dd2013-07-08 14:39:03 -04003279 else if (baseExpression->isInterfaceBlock())
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003280 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05303281 const TFieldList &fields = baseExpression->getType().getInterfaceBlock()->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04003282 if (fields.empty())
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003283 {
3284 error(dotLocation, "interface block has no fields", "Internal Error");
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003285 return baseExpression;
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003286 }
3287 else
3288 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003289 bool fieldFound = false;
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003290 unsigned int i;
Jamie Madill98493dd2013-07-08 14:39:03 -04003291 for (i = 0; i < fields.size(); ++i)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003292 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003293 if (fields[i]->name() == fieldString)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003294 {
3295 fieldFound = true;
3296 break;
3297 }
3298 }
3299 if (fieldFound)
3300 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003301 TIntermTyped *index = TIntermTyped::CreateIndexNode(i);
3302 index->setLine(fieldLocation);
3303 return intermediate.addIndex(EOpIndexDirectInterfaceBlock, baseExpression, index,
Olli Etuaho77ba4082016-12-16 12:01:18 +00003304 dotLocation, mDiagnostics);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003305 }
3306 else
3307 {
3308 error(dotLocation, " no such field in interface block", fieldString.c_str());
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003309 return baseExpression;
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003310 }
3311 }
3312 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003313 else
3314 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04003315 if (mShaderVersion < 300)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003316 {
Olli Etuaho56193ce2015-08-12 15:55:09 +03003317 error(dotLocation, " field selection requires structure or vector on left hand side",
Arun Patole7e7e68d2015-05-22 12:02:25 +05303318 fieldString.c_str());
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003319 }
3320 else
3321 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05303322 error(dotLocation,
Olli Etuaho56193ce2015-08-12 15:55:09 +03003323 " field selection requires structure, vector, or interface block on left hand "
3324 "side",
Arun Patole7e7e68d2015-05-22 12:02:25 +05303325 fieldString.c_str());
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003326 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03003327 return baseExpression;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003328 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003329}
3330
Jamie Madillb98c3a82015-07-23 14:26:04 -04003331TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType,
3332 const TSourceLoc &qualifierTypeLine)
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003333{
Martin Radev802abe02016-08-04 17:48:32 +03003334 TLayoutQualifier qualifier = TLayoutQualifier::create();
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003335
3336 if (qualifierType == "shared")
3337 {
Jamie Madillacb4b812016-11-07 13:50:29 -05003338 if (sh::IsWebGLBasedSpec(mShaderSpec))
Olli Etuahof0173152016-10-17 09:05:03 -07003339 {
3340 error(qualifierTypeLine, "Only std140 layout is allowed in WebGL", "shared");
3341 }
Jamie Madilla5efff92013-06-06 11:56:47 -04003342 qualifier.blockStorage = EbsShared;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003343 }
3344 else if (qualifierType == "packed")
3345 {
Jamie Madillacb4b812016-11-07 13:50:29 -05003346 if (sh::IsWebGLBasedSpec(mShaderSpec))
Olli Etuahof0173152016-10-17 09:05:03 -07003347 {
3348 error(qualifierTypeLine, "Only std140 layout is allowed in WebGL", "packed");
3349 }
Jamie Madilla5efff92013-06-06 11:56:47 -04003350 qualifier.blockStorage = EbsPacked;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003351 }
3352 else if (qualifierType == "std140")
3353 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003354 qualifier.blockStorage = EbsStd140;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003355 }
3356 else if (qualifierType == "row_major")
3357 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003358 qualifier.matrixPacking = EmpRowMajor;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003359 }
3360 else if (qualifierType == "column_major")
3361 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003362 qualifier.matrixPacking = EmpColumnMajor;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003363 }
3364 else if (qualifierType == "location")
3365 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00003366 error(qualifierTypeLine, "invalid layout qualifier: location requires an argument",
3367 qualifierType.c_str());
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003368 }
Andrei Volykhina5527072017-03-22 16:46:30 +03003369 else if (qualifierType == "yuv" && isExtensionEnabled("GL_EXT_YUV_target") &&
3370 mShaderType == GL_FRAGMENT_SHADER)
3371 {
3372 qualifier.yuv = true;
3373 }
Martin Radev2cc85b32016-08-05 16:22:53 +03003374 else if (qualifierType == "rgba32f")
3375 {
3376 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3377 qualifier.imageInternalFormat = EiifRGBA32F;
3378 }
3379 else if (qualifierType == "rgba16f")
3380 {
3381 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3382 qualifier.imageInternalFormat = EiifRGBA16F;
3383 }
3384 else if (qualifierType == "r32f")
3385 {
3386 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3387 qualifier.imageInternalFormat = EiifR32F;
3388 }
3389 else if (qualifierType == "rgba8")
3390 {
3391 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3392 qualifier.imageInternalFormat = EiifRGBA8;
3393 }
3394 else if (qualifierType == "rgba8_snorm")
3395 {
3396 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3397 qualifier.imageInternalFormat = EiifRGBA8_SNORM;
3398 }
3399 else if (qualifierType == "rgba32i")
3400 {
3401 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3402 qualifier.imageInternalFormat = EiifRGBA32I;
3403 }
3404 else if (qualifierType == "rgba16i")
3405 {
3406 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3407 qualifier.imageInternalFormat = EiifRGBA16I;
3408 }
3409 else if (qualifierType == "rgba8i")
3410 {
3411 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3412 qualifier.imageInternalFormat = EiifRGBA8I;
3413 }
3414 else if (qualifierType == "r32i")
3415 {
3416 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3417 qualifier.imageInternalFormat = EiifR32I;
3418 }
3419 else if (qualifierType == "rgba32ui")
3420 {
3421 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3422 qualifier.imageInternalFormat = EiifRGBA32UI;
3423 }
3424 else if (qualifierType == "rgba16ui")
3425 {
3426 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3427 qualifier.imageInternalFormat = EiifRGBA16UI;
3428 }
3429 else if (qualifierType == "rgba8ui")
3430 {
3431 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3432 qualifier.imageInternalFormat = EiifRGBA8UI;
3433 }
3434 else if (qualifierType == "r32ui")
3435 {
3436 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3437 qualifier.imageInternalFormat = EiifR32UI;
3438 }
3439
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003440 else
3441 {
3442 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str());
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003443 }
3444
Jamie Madilla5efff92013-06-06 11:56:47 -04003445 return qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003446}
3447
Martin Radev802abe02016-08-04 17:48:32 +03003448void TParseContext::parseLocalSize(const TString &qualifierType,
3449 const TSourceLoc &qualifierTypeLine,
3450 int intValue,
3451 const TSourceLoc &intValueLine,
3452 const std::string &intValueString,
3453 size_t index,
Martin Radev4c4c8e72016-08-04 12:25:34 +03003454 sh::WorkGroupSize *localSize)
Martin Radev802abe02016-08-04 17:48:32 +03003455{
Olli Etuaho856c4972016-08-08 11:38:39 +03003456 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
Martin Radev802abe02016-08-04 17:48:32 +03003457 if (intValue < 1)
3458 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00003459 std::stringstream reasonStream;
3460 reasonStream << "out of range: " << getWorkGroupSizeString(index) << " must be positive";
3461 std::string reason = reasonStream.str();
3462 error(intValueLine, reason.c_str(), intValueString.c_str());
Martin Radev802abe02016-08-04 17:48:32 +03003463 }
3464 (*localSize)[index] = intValue;
3465}
3466
Olli Etuaho09b04a22016-12-15 13:30:26 +00003467void TParseContext::parseNumViews(int intValue,
3468 const TSourceLoc &intValueLine,
3469 const std::string &intValueString,
3470 int *numViews)
3471{
3472 // This error is only specified in WebGL, but tightens unspecified behavior in the native
3473 // specification.
3474 if (intValue < 1)
3475 {
3476 error(intValueLine, "out of range: num_views must be positive", intValueString.c_str());
3477 }
3478 *numViews = intValue;
3479}
3480
Jamie Madillb98c3a82015-07-23 14:26:04 -04003481TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType,
3482 const TSourceLoc &qualifierTypeLine,
Jamie Madillb98c3a82015-07-23 14:26:04 -04003483 int intValue,
Arun Patole7e7e68d2015-05-22 12:02:25 +05303484 const TSourceLoc &intValueLine)
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003485{
Martin Radev802abe02016-08-04 17:48:32 +03003486 TLayoutQualifier qualifier = TLayoutQualifier::create();
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003487
Martin Radev802abe02016-08-04 17:48:32 +03003488 std::string intValueString = Str(intValue);
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003489
Martin Radev802abe02016-08-04 17:48:32 +03003490 if (qualifierType == "location")
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003491 {
Jamie Madill05a80ce2013-06-20 11:55:49 -04003492 // must check that location is non-negative
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003493 if (intValue < 0)
3494 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00003495 error(intValueLine, "out of range: location must be non-negative",
3496 intValueString.c_str());
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003497 }
3498 else
3499 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003500 qualifier.location = intValue;
Olli Etuaho87d410c2016-09-05 13:33:26 +03003501 qualifier.locationsSpecified = 1;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003502 }
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003503 }
Olli Etuaho43364892017-02-13 16:00:12 +00003504 else if (qualifierType == "binding")
3505 {
3506 checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
3507 if (intValue < 0)
3508 {
3509 error(intValueLine, "out of range: binding must be non-negative",
3510 intValueString.c_str());
3511 }
3512 else
3513 {
3514 qualifier.binding = intValue;
3515 }
3516 }
Martin Radev802abe02016-08-04 17:48:32 +03003517 else if (qualifierType == "local_size_x")
3518 {
3519 parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 0u,
3520 &qualifier.localSize);
3521 }
3522 else if (qualifierType == "local_size_y")
3523 {
3524 parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 1u,
3525 &qualifier.localSize);
3526 }
3527 else if (qualifierType == "local_size_z")
3528 {
3529 parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 2u,
3530 &qualifier.localSize);
3531 }
Olli Etuaho09b04a22016-12-15 13:30:26 +00003532 else if (qualifierType == "num_views" && mMultiviewAvailable &&
3533 (isExtensionEnabled("GL_OVR_multiview") || isExtensionEnabled("GL_OVR_multiview2")) &&
3534 mShaderType == GL_VERTEX_SHADER)
3535 {
3536 parseNumViews(intValue, intValueLine, intValueString, &qualifier.numViews);
3537 }
Martin Radev802abe02016-08-04 17:48:32 +03003538 else
3539 {
3540 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str());
Martin Radev802abe02016-08-04 17:48:32 +03003541 }
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003542
Jamie Madilla5efff92013-06-06 11:56:47 -04003543 return qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003544}
3545
Olli Etuaho613b9592016-09-05 12:05:53 +03003546TTypeQualifierBuilder *TParseContext::createTypeQualifierBuilder(const TSourceLoc &loc)
3547{
3548 return new TTypeQualifierBuilder(
3549 new TStorageQualifierWrapper(symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary, loc),
3550 mShaderVersion);
3551}
3552
Jamie Madillb98c3a82015-07-23 14:26:04 -04003553TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier,
Martin Radev802abe02016-08-04 17:48:32 +03003554 TLayoutQualifier rightQualifier,
3555 const TSourceLoc &rightQualifierLocation)
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003556{
Martin Radevc28888b2016-07-22 15:27:42 +03003557 return sh::JoinLayoutQualifiers(leftQualifier, rightQualifier, rightQualifierLocation,
Olli Etuaho77ba4082016-12-16 12:01:18 +00003558 mDiagnostics);
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003559}
3560
Olli Etuaho4de340a2016-12-16 09:32:03 +00003561TFieldList *TParseContext::combineStructFieldLists(TFieldList *processedFields,
3562 const TFieldList *newlyAddedFields,
3563 const TSourceLoc &location)
3564{
3565 for (TField *field : *newlyAddedFields)
3566 {
3567 for (TField *oldField : *processedFields)
3568 {
3569 if (oldField->name() == field->name())
3570 {
3571 error(location, "duplicate field name in structure", field->name().c_str());
3572 }
3573 }
3574 processedFields->push_back(field);
3575 }
3576 return processedFields;
3577}
3578
Martin Radev70866b82016-07-22 15:27:42 +03003579TFieldList *TParseContext::addStructDeclaratorListWithQualifiers(
3580 const TTypeQualifierBuilder &typeQualifierBuilder,
3581 TPublicType *typeSpecifier,
3582 TFieldList *fieldList)
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003583{
Olli Etuaho77ba4082016-12-16 12:01:18 +00003584 TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics);
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003585
Martin Radev70866b82016-07-22 15:27:42 +03003586 typeSpecifier->qualifier = typeQualifier.qualifier;
3587 typeSpecifier->layoutQualifier = typeQualifier.layoutQualifier;
Martin Radev2cc85b32016-08-05 16:22:53 +03003588 typeSpecifier->memoryQualifier = typeQualifier.memoryQualifier;
Martin Radev70866b82016-07-22 15:27:42 +03003589 typeSpecifier->invariant = typeQualifier.invariant;
3590 if (typeQualifier.precision != EbpUndefined)
Arun Patole7e7e68d2015-05-22 12:02:25 +05303591 {
Martin Radev70866b82016-07-22 15:27:42 +03003592 typeSpecifier->precision = typeQualifier.precision;
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003593 }
Martin Radev70866b82016-07-22 15:27:42 +03003594 return addStructDeclaratorList(*typeSpecifier, fieldList);
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003595}
3596
Jamie Madillb98c3a82015-07-23 14:26:04 -04003597TFieldList *TParseContext::addStructDeclaratorList(const TPublicType &typeSpecifier,
3598 TFieldList *fieldList)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003599{
Martin Radev4a9cd802016-09-01 16:51:51 +03003600 checkPrecisionSpecified(typeSpecifier.getLine(), typeSpecifier.precision,
3601 typeSpecifier.getBasicType());
Martin Radev70866b82016-07-22 15:27:42 +03003602
Martin Radev4a9cd802016-09-01 16:51:51 +03003603 checkIsNonVoid(typeSpecifier.getLine(), (*fieldList)[0]->name(), typeSpecifier.getBasicType());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003604
Martin Radev4a9cd802016-09-01 16:51:51 +03003605 checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), typeSpecifier.layoutQualifier);
Martin Radev802abe02016-08-04 17:48:32 +03003606
Arun Patole7e7e68d2015-05-22 12:02:25 +05303607 for (unsigned int i = 0; i < fieldList->size(); ++i)
3608 {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003609 //
3610 // Careful not to replace already known aspects of type, like array-ness
3611 //
Arun Patole7e7e68d2015-05-22 12:02:25 +05303612 TType *type = (*fieldList)[i]->type();
Martin Radev4a9cd802016-09-01 16:51:51 +03003613 type->setBasicType(typeSpecifier.getBasicType());
3614 type->setPrimarySize(typeSpecifier.getPrimarySize());
3615 type->setSecondarySize(typeSpecifier.getSecondarySize());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003616 type->setPrecision(typeSpecifier.precision);
3617 type->setQualifier(typeSpecifier.qualifier);
Jamie Madilla5efff92013-06-06 11:56:47 -04003618 type->setLayoutQualifier(typeSpecifier.layoutQualifier);
Martin Radev2cc85b32016-08-05 16:22:53 +03003619 type->setMemoryQualifier(typeSpecifier.memoryQualifier);
Martin Radev70866b82016-07-22 15:27:42 +03003620 type->setInvariant(typeSpecifier.invariant);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003621
3622 // don't allow arrays of arrays
Arun Patole7e7e68d2015-05-22 12:02:25 +05303623 if (type->isArray())
3624 {
Martin Radev4a9cd802016-09-01 16:51:51 +03003625 checkIsValidTypeForArray(typeSpecifier.getLine(), typeSpecifier);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003626 }
3627 if (typeSpecifier.array)
Olli Etuaho856c4972016-08-08 11:38:39 +03003628 type->setArraySize(static_cast<unsigned int>(typeSpecifier.arraySize));
Martin Radev4a9cd802016-09-01 16:51:51 +03003629 if (typeSpecifier.getUserDef())
Arun Patole7e7e68d2015-05-22 12:02:25 +05303630 {
Martin Radev4a9cd802016-09-01 16:51:51 +03003631 type->setStruct(typeSpecifier.getUserDef()->getStruct());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003632 }
3633
Martin Radev4a9cd802016-09-01 16:51:51 +03003634 checkIsBelowStructNestingLimit(typeSpecifier.getLine(), *(*fieldList)[i]);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003635 }
3636
Jamie Madill98493dd2013-07-08 14:39:03 -04003637 return fieldList;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003638}
3639
Martin Radev4a9cd802016-09-01 16:51:51 +03003640TTypeSpecifierNonArray TParseContext::addStructure(const TSourceLoc &structLine,
3641 const TSourceLoc &nameLine,
3642 const TString *structName,
3643 TFieldList *fieldList)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003644{
Arun Patole7e7e68d2015-05-22 12:02:25 +05303645 TStructure *structure = new TStructure(structName, fieldList);
Jamie Madillb98c3a82015-07-23 14:26:04 -04003646 TType *structureType = new TType(structure);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003647
Jamie Madill9b820842015-02-12 10:40:10 -05003648 // Store a bool in the struct if we're at global scope, to allow us to
3649 // skip the local struct scoping workaround in HLSL.
Jamie Madill9b820842015-02-12 10:40:10 -05003650 structure->setAtGlobalScope(symbolTable.atGlobalLevel());
Jamie Madillbfa91f42014-06-05 15:45:18 -04003651
Jamie Madill98493dd2013-07-08 14:39:03 -04003652 if (!structName->empty())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003653 {
Olli Etuaho856c4972016-08-08 11:38:39 +03003654 checkIsNotReserved(nameLine, *structName);
Arun Patole7e7e68d2015-05-22 12:02:25 +05303655 TVariable *userTypeDef = new TVariable(structName, *structureType, true);
3656 if (!symbolTable.declare(userTypeDef))
3657 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00003658 error(nameLine, "redefinition of a struct", structName->c_str());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003659 }
3660 }
3661
3662 // ensure we do not specify any storage qualifiers on the struct members
Jamie Madill98493dd2013-07-08 14:39:03 -04003663 for (unsigned int typeListIndex = 0; typeListIndex < fieldList->size(); typeListIndex++)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003664 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003665 const TField &field = *(*fieldList)[typeListIndex];
Jamie Madill98493dd2013-07-08 14:39:03 -04003666 const TQualifier qualifier = field.type()->getQualifier();
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003667 switch (qualifier)
3668 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003669 case EvqGlobal:
3670 case EvqTemporary:
3671 break;
3672 default:
3673 error(field.line(), "invalid qualifier on struct member",
3674 getQualifierString(qualifier));
Jamie Madillb98c3a82015-07-23 14:26:04 -04003675 break;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003676 }
Martin Radev70866b82016-07-22 15:27:42 +03003677 if (field.type()->isInvariant())
3678 {
3679 error(field.line(), "invalid qualifier on struct member", "invariant");
3680 }
Martin Radev2cc85b32016-08-05 16:22:53 +03003681 if (IsImage(field.type()->getBasicType()))
3682 {
3683 error(field.line(), "disallowed type in struct", field.type()->getBasicString());
3684 }
3685
Olli Etuaho43364892017-02-13 16:00:12 +00003686 checkMemoryQualifierIsNotSpecified(field.type()->getMemoryQualifier(), field.line());
3687
3688 checkBindingIsNotSpecified(field.line(), field.type()->getLayoutQualifier().binding);
Martin Radev70866b82016-07-22 15:27:42 +03003689
3690 checkLocationIsNotSpecified(field.line(), field.type()->getLayoutQualifier());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003691 }
3692
Martin Radev4a9cd802016-09-01 16:51:51 +03003693 TTypeSpecifierNonArray typeSpecifierNonArray;
3694 typeSpecifierNonArray.initialize(EbtStruct, structLine);
3695 typeSpecifierNonArray.userDef = structureType;
3696 typeSpecifierNonArray.isStructSpecifier = true;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003697 exitStructDeclaration();
3698
Martin Radev4a9cd802016-09-01 16:51:51 +03003699 return typeSpecifierNonArray;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003700}
3701
Jamie Madillb98c3a82015-07-23 14:26:04 -04003702TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init,
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01003703 TIntermBlock *statementList,
Jamie Madillb98c3a82015-07-23 14:26:04 -04003704 const TSourceLoc &loc)
Olli Etuahoa3a36662015-02-17 13:46:51 +02003705{
Olli Etuaho53f076f2015-02-20 10:55:14 +02003706 TBasicType switchType = init->getBasicType();
Jamie Madillb98c3a82015-07-23 14:26:04 -04003707 if ((switchType != EbtInt && switchType != EbtUInt) || init->isMatrix() || init->isArray() ||
Olli Etuaho53f076f2015-02-20 10:55:14 +02003708 init->isVector())
3709 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003710 error(init->getLine(), "init-expression in a switch statement must be a scalar integer",
3711 "switch");
Olli Etuaho53f076f2015-02-20 10:55:14 +02003712 return nullptr;
3713 }
3714
Olli Etuahoac5274d2015-02-20 10:19:08 +02003715 if (statementList)
3716 {
Olli Etuaho77ba4082016-12-16 12:01:18 +00003717 if (!ValidateSwitchStatementList(switchType, mDiagnostics, statementList, loc))
Olli Etuahoac5274d2015-02-20 10:19:08 +02003718 {
Olli Etuahoac5274d2015-02-20 10:19:08 +02003719 return nullptr;
3720 }
3721 }
3722
Olli Etuahoa3a36662015-02-17 13:46:51 +02003723 TIntermSwitch *node = intermediate.addSwitch(init, statementList, loc);
3724 if (node == nullptr)
3725 {
3726 error(loc, "erroneous switch statement", "switch");
Olli Etuahoa3a36662015-02-17 13:46:51 +02003727 return nullptr;
3728 }
3729 return node;
3730}
3731
3732TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &loc)
3733{
Olli Etuaho53f076f2015-02-20 10:55:14 +02003734 if (mSwitchNestingLevel == 0)
3735 {
3736 error(loc, "case labels need to be inside switch statements", "case");
Olli Etuaho53f076f2015-02-20 10:55:14 +02003737 return nullptr;
3738 }
3739 if (condition == nullptr)
3740 {
3741 error(loc, "case label must have a condition", "case");
Olli Etuaho53f076f2015-02-20 10:55:14 +02003742 return nullptr;
3743 }
3744 if ((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) ||
Jamie Madillb98c3a82015-07-23 14:26:04 -04003745 condition->isMatrix() || condition->isArray() || condition->isVector())
Olli Etuaho53f076f2015-02-20 10:55:14 +02003746 {
3747 error(condition->getLine(), "case label must be a scalar integer", "case");
Olli Etuaho53f076f2015-02-20 10:55:14 +02003748 }
3749 TIntermConstantUnion *conditionConst = condition->getAsConstantUnion();
Olli Etuaho7c3848e2015-11-04 13:19:17 +02003750 // TODO(oetuaho@nvidia.com): Get rid of the conditionConst == nullptr check once all constant
3751 // expressions can be folded. Right now we don't allow constant expressions that ANGLE can't
3752 // fold in case labels.
3753 if (condition->getQualifier() != EvqConst || conditionConst == nullptr)
Olli Etuaho53f076f2015-02-20 10:55:14 +02003754 {
3755 error(condition->getLine(), "case label must be constant", "case");
Olli Etuaho53f076f2015-02-20 10:55:14 +02003756 }
Olli Etuahoa3a36662015-02-17 13:46:51 +02003757 TIntermCase *node = intermediate.addCase(condition, loc);
3758 if (node == nullptr)
3759 {
3760 error(loc, "erroneous case statement", "case");
Olli Etuahoa3a36662015-02-17 13:46:51 +02003761 return nullptr;
3762 }
3763 return node;
3764}
3765
3766TIntermCase *TParseContext::addDefault(const TSourceLoc &loc)
3767{
Olli Etuaho53f076f2015-02-20 10:55:14 +02003768 if (mSwitchNestingLevel == 0)
3769 {
3770 error(loc, "default labels need to be inside switch statements", "default");
Olli Etuaho53f076f2015-02-20 10:55:14 +02003771 return nullptr;
3772 }
Olli Etuahoa3a36662015-02-17 13:46:51 +02003773 TIntermCase *node = intermediate.addCase(nullptr, loc);
3774 if (node == nullptr)
3775 {
3776 error(loc, "erroneous default statement", "default");
Olli Etuahoa3a36662015-02-17 13:46:51 +02003777 return nullptr;
3778 }
3779 return node;
3780}
3781
Jamie Madillb98c3a82015-07-23 14:26:04 -04003782TIntermTyped *TParseContext::createUnaryMath(TOperator op,
3783 TIntermTyped *child,
Olli Etuaho2be2d5a2017-01-26 16:34:30 -08003784 const TSourceLoc &loc)
Olli Etuaho69c11b52015-03-26 12:59:00 +02003785{
Olli Etuaho2be2d5a2017-01-26 16:34:30 -08003786 ASSERT(child != nullptr);
Olli Etuaho69c11b52015-03-26 12:59:00 +02003787
3788 switch (op)
3789 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003790 case EOpLogicalNot:
3791 if (child->getBasicType() != EbtBool || child->isMatrix() || child->isArray() ||
3792 child->isVector())
3793 {
Olli Etuaho2be2d5a2017-01-26 16:34:30 -08003794 unaryOpError(loc, GetOperatorString(op), child->getCompleteString());
Jamie Madillb98c3a82015-07-23 14:26:04 -04003795 return nullptr;
3796 }
3797 break;
3798 case EOpBitwiseNot:
3799 if ((child->getBasicType() != EbtInt && child->getBasicType() != EbtUInt) ||
3800 child->isMatrix() || child->isArray())
3801 {
Olli Etuaho2be2d5a2017-01-26 16:34:30 -08003802 unaryOpError(loc, GetOperatorString(op), child->getCompleteString());
Jamie Madillb98c3a82015-07-23 14:26:04 -04003803 return nullptr;
3804 }
3805 break;
3806 case EOpPostIncrement:
3807 case EOpPreIncrement:
3808 case EOpPostDecrement:
3809 case EOpPreDecrement:
3810 case EOpNegative:
3811 case EOpPositive:
3812 if (child->getBasicType() == EbtStruct || child->getBasicType() == EbtBool ||
Martin Radev2cc85b32016-08-05 16:22:53 +03003813 child->isArray() || IsOpaqueType(child->getBasicType()))
Jamie Madillb98c3a82015-07-23 14:26:04 -04003814 {
Olli Etuaho2be2d5a2017-01-26 16:34:30 -08003815 unaryOpError(loc, GetOperatorString(op), child->getCompleteString());
Jamie Madillb98c3a82015-07-23 14:26:04 -04003816 return nullptr;
3817 }
3818 // Operators for built-ins are already type checked against their prototype.
3819 default:
3820 break;
Olli Etuaho69c11b52015-03-26 12:59:00 +02003821 }
3822
Olli Etuahof119a262016-08-19 15:54:22 +03003823 TIntermUnary *node = new TIntermUnary(op, child);
3824 node->setLine(loc);
Olli Etuahof119a262016-08-19 15:54:22 +03003825
Olli Etuaho77ba4082016-12-16 12:01:18 +00003826 TIntermTyped *foldedNode = node->fold(mDiagnostics);
Olli Etuahof119a262016-08-19 15:54:22 +03003827 if (foldedNode)
3828 return foldedNode;
3829
3830 return node;
Olli Etuaho69c11b52015-03-26 12:59:00 +02003831}
3832
Olli Etuaho09b22472015-02-11 11:47:26 +02003833TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc)
3834{
Olli Etuaho2be2d5a2017-01-26 16:34:30 -08003835 TIntermTyped *node = createUnaryMath(op, child, loc);
Olli Etuaho69c11b52015-03-26 12:59:00 +02003836 if (node == nullptr)
Olli Etuaho09b22472015-02-11 11:47:26 +02003837 {
Olli Etuaho09b22472015-02-11 11:47:26 +02003838 return child;
3839 }
3840 return node;
3841}
3842
Jamie Madillb98c3a82015-07-23 14:26:04 -04003843TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op,
3844 TIntermTyped *child,
3845 const TSourceLoc &loc)
Olli Etuaho09b22472015-02-11 11:47:26 +02003846{
Olli Etuaho856c4972016-08-08 11:38:39 +03003847 checkCanBeLValue(loc, GetOperatorString(op), child);
Olli Etuaho09b22472015-02-11 11:47:26 +02003848 return addUnaryMath(op, child, loc);
3849}
3850
Jamie Madillb98c3a82015-07-23 14:26:04 -04003851bool TParseContext::binaryOpCommonCheck(TOperator op,
3852 TIntermTyped *left,
3853 TIntermTyped *right,
3854 const TSourceLoc &loc)
Olli Etuahod6b14282015-03-17 14:31:35 +02003855{
Olli Etuaho244be012016-08-18 15:26:02 +03003856 if (left->getType().getStruct() || right->getType().getStruct())
3857 {
3858 switch (op)
3859 {
3860 case EOpIndexDirectStruct:
3861 ASSERT(left->getType().getStruct());
3862 break;
3863 case EOpEqual:
3864 case EOpNotEqual:
3865 case EOpAssign:
3866 case EOpInitialize:
3867 if (left->getType() != right->getType())
3868 {
3869 return false;
3870 }
3871 break;
3872 default:
3873 error(loc, "Invalid operation for structs", GetOperatorString(op));
3874 return false;
3875 }
3876 }
3877
Olli Etuahod6b14282015-03-17 14:31:35 +02003878 if (left->isArray() || right->isArray())
3879 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04003880 if (mShaderVersion < 300)
Olli Etuahoe79904c2015-03-18 16:56:42 +02003881 {
3882 error(loc, "Invalid operation for arrays", GetOperatorString(op));
3883 return false;
3884 }
3885
3886 if (left->isArray() != right->isArray())
3887 {
3888 error(loc, "array / non-array mismatch", GetOperatorString(op));
3889 return false;
3890 }
3891
3892 switch (op)
3893 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003894 case EOpEqual:
3895 case EOpNotEqual:
3896 case EOpAssign:
3897 case EOpInitialize:
3898 break;
3899 default:
3900 error(loc, "Invalid operation for arrays", GetOperatorString(op));
3901 return false;
Olli Etuahoe79904c2015-03-18 16:56:42 +02003902 }
Olli Etuaho376f1b52015-04-13 13:23:41 +03003903 // At this point, size of implicitly sized arrays should be resolved.
Olli Etuahoe79904c2015-03-18 16:56:42 +02003904 if (left->getArraySize() != right->getArraySize())
3905 {
3906 error(loc, "array size mismatch", GetOperatorString(op));
3907 return false;
3908 }
Olli Etuahod6b14282015-03-17 14:31:35 +02003909 }
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003910
3911 // Check ops which require integer / ivec parameters
3912 bool isBitShift = false;
3913 switch (op)
3914 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003915 case EOpBitShiftLeft:
3916 case EOpBitShiftRight:
3917 case EOpBitShiftLeftAssign:
3918 case EOpBitShiftRightAssign:
3919 // Unsigned can be bit-shifted by signed and vice versa, but we need to
3920 // check that the basic type is an integer type.
3921 isBitShift = true;
3922 if (!IsInteger(left->getBasicType()) || !IsInteger(right->getBasicType()))
3923 {
3924 return false;
3925 }
3926 break;
3927 case EOpBitwiseAnd:
3928 case EOpBitwiseXor:
3929 case EOpBitwiseOr:
3930 case EOpBitwiseAndAssign:
3931 case EOpBitwiseXorAssign:
3932 case EOpBitwiseOrAssign:
3933 // It is enough to check the type of only one operand, since later it
3934 // is checked that the operand types match.
3935 if (!IsInteger(left->getBasicType()))
3936 {
3937 return false;
3938 }
3939 break;
3940 default:
3941 break;
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003942 }
3943
3944 // GLSL ES 1.00 and 3.00 do not support implicit type casting.
3945 // So the basic type should usually match.
3946 if (!isBitShift && left->getBasicType() != right->getBasicType())
3947 {
3948 return false;
3949 }
3950
Olli Etuaho63e1ec52016-08-18 22:05:12 +03003951 // Check that:
3952 // 1. Type sizes match exactly on ops that require that.
3953 // 2. Restrictions for structs that contain arrays or samplers are respected.
3954 // 3. Arithmetic op type dimensionality restrictions for ops other than multiply are respected.
Jamie Madillb98c3a82015-07-23 14:26:04 -04003955 switch (op)
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003956 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003957 case EOpAssign:
3958 case EOpInitialize:
3959 case EOpEqual:
3960 case EOpNotEqual:
3961 // ESSL 1.00 sections 5.7, 5.8, 5.9
3962 if (mShaderVersion < 300 && left->getType().isStructureContainingArrays())
3963 {
3964 error(loc, "undefined operation for structs containing arrays",
3965 GetOperatorString(op));
3966 return false;
3967 }
3968 // Samplers as l-values are disallowed also in ESSL 3.00, see section 4.1.7,
3969 // we interpret the spec so that this extends to structs containing samplers,
3970 // similarly to ESSL 1.00 spec.
3971 if ((mShaderVersion < 300 || op == EOpAssign || op == EOpInitialize) &&
3972 left->getType().isStructureContainingSamplers())
3973 {
3974 error(loc, "undefined operation for structs containing samplers",
3975 GetOperatorString(op));
3976 return false;
3977 }
Martin Radev2cc85b32016-08-05 16:22:53 +03003978
3979 if ((op == EOpAssign || op == EOpInitialize) &&
3980 left->getType().isStructureContainingImages())
3981 {
3982 error(loc, "undefined operation for structs containing images",
3983 GetOperatorString(op));
3984 return false;
3985 }
Olli Etuahoe1805592017-01-02 16:41:20 +00003986 if ((left->getNominalSize() != right->getNominalSize()) ||
3987 (left->getSecondarySize() != right->getSecondarySize()))
3988 {
3989 error(loc, "dimension mismatch", GetOperatorString(op));
3990 return false;
3991 }
3992 break;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003993 case EOpLessThan:
3994 case EOpGreaterThan:
3995 case EOpLessThanEqual:
3996 case EOpGreaterThanEqual:
Olli Etuahoe1805592017-01-02 16:41:20 +00003997 if (!left->isScalar() || !right->isScalar())
Jamie Madillb98c3a82015-07-23 14:26:04 -04003998 {
Olli Etuahoe1805592017-01-02 16:41:20 +00003999 error(loc, "comparison operator only defined for scalars", GetOperatorString(op));
Jamie Madillb98c3a82015-07-23 14:26:04 -04004000 return false;
4001 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03004002 break;
4003 case EOpAdd:
4004 case EOpSub:
4005 case EOpDiv:
4006 case EOpIMod:
4007 case EOpBitShiftLeft:
4008 case EOpBitShiftRight:
4009 case EOpBitwiseAnd:
4010 case EOpBitwiseXor:
4011 case EOpBitwiseOr:
4012 case EOpAddAssign:
4013 case EOpSubAssign:
4014 case EOpDivAssign:
4015 case EOpIModAssign:
4016 case EOpBitShiftLeftAssign:
4017 case EOpBitShiftRightAssign:
4018 case EOpBitwiseAndAssign:
4019 case EOpBitwiseXorAssign:
4020 case EOpBitwiseOrAssign:
4021 if ((left->isMatrix() && right->isVector()) || (left->isVector() && right->isMatrix()))
4022 {
4023 return false;
4024 }
4025
4026 // Are the sizes compatible?
4027 if (left->getNominalSize() != right->getNominalSize() ||
4028 left->getSecondarySize() != right->getSecondarySize())
4029 {
4030 // If the nominal sizes of operands do not match:
4031 // One of them must be a scalar.
4032 if (!left->isScalar() && !right->isScalar())
4033 return false;
4034
4035 // In the case of compound assignment other than multiply-assign,
4036 // the right side needs to be a scalar. Otherwise a vector/matrix
4037 // would be assigned to a scalar. A scalar can't be shifted by a
4038 // vector either.
4039 if (!right->isScalar() &&
4040 (IsAssignment(op) || op == EOpBitShiftLeft || op == EOpBitShiftRight))
4041 return false;
4042 }
4043 break;
Jamie Madillb98c3a82015-07-23 14:26:04 -04004044 default:
4045 break;
Olli Etuaho47fd36a2015-03-19 14:22:24 +02004046 }
4047
Olli Etuahod6b14282015-03-17 14:31:35 +02004048 return true;
4049}
4050
Olli Etuaho1dded802016-08-18 18:13:13 +03004051bool TParseContext::isMultiplicationTypeCombinationValid(TOperator op,
4052 const TType &left,
4053 const TType &right)
4054{
4055 switch (op)
4056 {
4057 case EOpMul:
4058 case EOpMulAssign:
4059 return left.getNominalSize() == right.getNominalSize() &&
4060 left.getSecondarySize() == right.getSecondarySize();
4061 case EOpVectorTimesScalar:
4062 return true;
4063 case EOpVectorTimesScalarAssign:
4064 ASSERT(!left.isMatrix() && !right.isMatrix());
4065 return left.isVector() && !right.isVector();
4066 case EOpVectorTimesMatrix:
4067 return left.getNominalSize() == right.getRows();
4068 case EOpVectorTimesMatrixAssign:
4069 ASSERT(!left.isMatrix() && right.isMatrix());
4070 return left.isVector() && left.getNominalSize() == right.getRows() &&
4071 left.getNominalSize() == right.getCols();
4072 case EOpMatrixTimesVector:
4073 return left.getCols() == right.getNominalSize();
4074 case EOpMatrixTimesScalar:
4075 return true;
4076 case EOpMatrixTimesScalarAssign:
4077 ASSERT(left.isMatrix() && !right.isMatrix());
4078 return !right.isVector();
4079 case EOpMatrixTimesMatrix:
4080 return left.getCols() == right.getRows();
4081 case EOpMatrixTimesMatrixAssign:
4082 ASSERT(left.isMatrix() && right.isMatrix());
4083 // We need to check two things:
4084 // 1. The matrix multiplication step is valid.
4085 // 2. The result will have the same number of columns as the lvalue.
4086 return left.getCols() == right.getRows() && left.getCols() == right.getCols();
4087
4088 default:
4089 UNREACHABLE();
4090 return false;
4091 }
4092}
4093
Jamie Madillb98c3a82015-07-23 14:26:04 -04004094TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op,
4095 TIntermTyped *left,
4096 TIntermTyped *right,
4097 const TSourceLoc &loc)
Olli Etuahofc1806e2015-03-17 13:03:11 +02004098{
Olli Etuaho47fd36a2015-03-19 14:22:24 +02004099 if (!binaryOpCommonCheck(op, left, right, loc))
Olli Etuahod6b14282015-03-17 14:31:35 +02004100 return nullptr;
4101
Olli Etuahofc1806e2015-03-17 13:03:11 +02004102 switch (op)
4103 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04004104 case EOpEqual:
4105 case EOpNotEqual:
Jamie Madillb98c3a82015-07-23 14:26:04 -04004106 case EOpLessThan:
4107 case EOpGreaterThan:
4108 case EOpLessThanEqual:
4109 case EOpGreaterThanEqual:
Jamie Madillb98c3a82015-07-23 14:26:04 -04004110 break;
4111 case EOpLogicalOr:
4112 case EOpLogicalXor:
4113 case EOpLogicalAnd:
Olli Etuaho244be012016-08-18 15:26:02 +03004114 ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() &&
4115 !right->getType().getStruct());
Olli Etuahoe7dc9d72016-11-03 16:58:47 +00004116 if (left->getBasicType() != EbtBool || !left->isScalar() || !right->isScalar())
Jamie Madillb98c3a82015-07-23 14:26:04 -04004117 {
4118 return nullptr;
4119 }
Olli Etuahoe7dc9d72016-11-03 16:58:47 +00004120 // Basic types matching should have been already checked.
4121 ASSERT(right->getBasicType() == EbtBool);
Jamie Madillb98c3a82015-07-23 14:26:04 -04004122 break;
4123 case EOpAdd:
4124 case EOpSub:
4125 case EOpDiv:
4126 case EOpMul:
Olli Etuaho244be012016-08-18 15:26:02 +03004127 ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() &&
4128 !right->getType().getStruct());
4129 if (left->getBasicType() == EbtBool)
Jamie Madillb98c3a82015-07-23 14:26:04 -04004130 {
4131 return nullptr;
4132 }
4133 break;
4134 case EOpIMod:
Olli Etuaho244be012016-08-18 15:26:02 +03004135 ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() &&
4136 !right->getType().getStruct());
Jamie Madillb98c3a82015-07-23 14:26:04 -04004137 // Note that this is only for the % operator, not for mod()
Olli Etuaho244be012016-08-18 15:26:02 +03004138 if (left->getBasicType() == EbtBool || left->getBasicType() == EbtFloat)
Jamie Madillb98c3a82015-07-23 14:26:04 -04004139 {
4140 return nullptr;
4141 }
4142 break;
Jamie Madillb98c3a82015-07-23 14:26:04 -04004143 default:
4144 break;
Olli Etuahofc1806e2015-03-17 13:03:11 +02004145 }
4146
Olli Etuaho1dded802016-08-18 18:13:13 +03004147 if (op == EOpMul)
4148 {
4149 op = TIntermBinary::GetMulOpBasedOnOperands(left->getType(), right->getType());
4150 if (!isMultiplicationTypeCombinationValid(op, left->getType(), right->getType()))
4151 {
4152 return nullptr;
4153 }
4154 }
4155
Olli Etuaho3fdec912016-08-18 15:08:06 +03004156 TIntermBinary *node = new TIntermBinary(op, left, right);
4157 node->setLine(loc);
4158
Olli Etuaho3fdec912016-08-18 15:08:06 +03004159 // See if we can fold constants.
Olli Etuaho77ba4082016-12-16 12:01:18 +00004160 TIntermTyped *foldedNode = node->fold(mDiagnostics);
Olli Etuaho3fdec912016-08-18 15:08:06 +03004161 if (foldedNode)
4162 return foldedNode;
4163
4164 return node;
Olli Etuahofc1806e2015-03-17 13:03:11 +02004165}
4166
Jamie Madillb98c3a82015-07-23 14:26:04 -04004167TIntermTyped *TParseContext::addBinaryMath(TOperator op,
4168 TIntermTyped *left,
4169 TIntermTyped *right,
4170 const TSourceLoc &loc)
Olli Etuaho09b22472015-02-11 11:47:26 +02004171{
Olli Etuahofc1806e2015-03-17 13:03:11 +02004172 TIntermTyped *node = addBinaryMathInternal(op, left, right, loc);
Olli Etuaho09b22472015-02-11 11:47:26 +02004173 if (node == 0)
4174 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04004175 binaryOpError(loc, GetOperatorString(op), left->getCompleteString(),
4176 right->getCompleteString());
Olli Etuaho09b22472015-02-11 11:47:26 +02004177 return left;
4178 }
4179 return node;
4180}
4181
Jamie Madillb98c3a82015-07-23 14:26:04 -04004182TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op,
4183 TIntermTyped *left,
4184 TIntermTyped *right,
4185 const TSourceLoc &loc)
Olli Etuaho09b22472015-02-11 11:47:26 +02004186{
Olli Etuahofc1806e2015-03-17 13:03:11 +02004187 TIntermTyped *node = addBinaryMathInternal(op, left, right, loc);
Olli Etuaho09b22472015-02-11 11:47:26 +02004188 if (node == 0)
4189 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04004190 binaryOpError(loc, GetOperatorString(op), left->getCompleteString(),
4191 right->getCompleteString());
Jamie Madill6ba6ead2015-05-04 14:21:21 -04004192 TConstantUnion *unionArray = new TConstantUnion[1];
Olli Etuaho09b22472015-02-11 11:47:26 +02004193 unionArray->setBConst(false);
Jamie Madillb98c3a82015-07-23 14:26:04 -04004194 return intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst),
4195 loc);
Olli Etuaho09b22472015-02-11 11:47:26 +02004196 }
4197 return node;
4198}
4199
Olli Etuaho13389b62016-10-16 11:48:18 +01004200TIntermBinary *TParseContext::createAssign(TOperator op,
4201 TIntermTyped *left,
4202 TIntermTyped *right,
4203 const TSourceLoc &loc)
Olli Etuahod6b14282015-03-17 14:31:35 +02004204{
Olli Etuaho47fd36a2015-03-19 14:22:24 +02004205 if (binaryOpCommonCheck(op, left, right, loc))
Olli Etuahod6b14282015-03-17 14:31:35 +02004206 {
Olli Etuaho1dded802016-08-18 18:13:13 +03004207 if (op == EOpMulAssign)
4208 {
4209 op = TIntermBinary::GetMulAssignOpBasedOnOperands(left->getType(), right->getType());
4210 if (!isMultiplicationTypeCombinationValid(op, left->getType(), right->getType()))
4211 {
4212 return nullptr;
4213 }
4214 }
Olli Etuaho3fdec912016-08-18 15:08:06 +03004215 TIntermBinary *node = new TIntermBinary(op, left, right);
4216 node->setLine(loc);
4217
Olli Etuaho3fdec912016-08-18 15:08:06 +03004218 return node;
Olli Etuahod6b14282015-03-17 14:31:35 +02004219 }
4220 return nullptr;
4221}
4222
Jamie Madillb98c3a82015-07-23 14:26:04 -04004223TIntermTyped *TParseContext::addAssign(TOperator op,
4224 TIntermTyped *left,
4225 TIntermTyped *right,
4226 const TSourceLoc &loc)
Olli Etuahod6b14282015-03-17 14:31:35 +02004227{
4228 TIntermTyped *node = createAssign(op, left, right, loc);
4229 if (node == nullptr)
4230 {
4231 assignError(loc, "assign", left->getCompleteString(), right->getCompleteString());
Olli Etuahod6b14282015-03-17 14:31:35 +02004232 return left;
4233 }
4234 return node;
4235}
4236
Olli Etuaho0b2d2dc2015-11-04 16:35:32 +02004237TIntermTyped *TParseContext::addComma(TIntermTyped *left,
4238 TIntermTyped *right,
4239 const TSourceLoc &loc)
4240{
Corentin Wallez0d959252016-07-12 17:26:32 -04004241 // WebGL2 section 5.26, the following results in an error:
4242 // "Sequence operator applied to void, arrays, or structs containing arrays"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05004243 if (mShaderSpec == SH_WEBGL2_SPEC &&
4244 (left->isArray() || left->getBasicType() == EbtVoid ||
4245 left->getType().isStructureContainingArrays() || right->isArray() ||
4246 right->getBasicType() == EbtVoid || right->getType().isStructureContainingArrays()))
Corentin Wallez0d959252016-07-12 17:26:32 -04004247 {
4248 error(loc,
4249 "sequence operator is not allowed for void, arrays, or structs containing arrays",
4250 ",");
Corentin Wallez0d959252016-07-12 17:26:32 -04004251 }
4252
Olli Etuaho4db7ded2016-10-13 12:23:11 +01004253 return TIntermediate::AddComma(left, right, loc, mShaderVersion);
Olli Etuaho0b2d2dc2015-11-04 16:35:32 +02004254}
4255
Olli Etuaho49300862015-02-20 14:54:49 +02004256TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc)
4257{
4258 switch (op)
4259 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04004260 case EOpContinue:
4261 if (mLoopNestingLevel <= 0)
4262 {
4263 error(loc, "continue statement only allowed in loops", "");
Jamie Madillb98c3a82015-07-23 14:26:04 -04004264 }
4265 break;
4266 case EOpBreak:
4267 if (mLoopNestingLevel <= 0 && mSwitchNestingLevel <= 0)
4268 {
4269 error(loc, "break statement only allowed in loops and switch statements", "");
Jamie Madillb98c3a82015-07-23 14:26:04 -04004270 }
4271 break;
4272 case EOpReturn:
4273 if (mCurrentFunctionType->getBasicType() != EbtVoid)
4274 {
4275 error(loc, "non-void function must return a value", "return");
Jamie Madillb98c3a82015-07-23 14:26:04 -04004276 }
4277 break;
4278 default:
4279 // No checks for discard
4280 break;
Olli Etuaho49300862015-02-20 14:54:49 +02004281 }
4282 return intermediate.addBranch(op, loc);
4283}
4284
Jamie Madillb98c3a82015-07-23 14:26:04 -04004285TIntermBranch *TParseContext::addBranch(TOperator op,
4286 TIntermTyped *returnValue,
4287 const TSourceLoc &loc)
Olli Etuaho49300862015-02-20 14:54:49 +02004288{
4289 ASSERT(op == EOpReturn);
4290 mFunctionReturnsValue = true;
Jamie Madill6e06b1f2015-05-14 10:01:17 -04004291 if (mCurrentFunctionType->getBasicType() == EbtVoid)
Olli Etuaho49300862015-02-20 14:54:49 +02004292 {
4293 error(loc, "void function cannot return a value", "return");
Olli Etuaho49300862015-02-20 14:54:49 +02004294 }
Jamie Madill6e06b1f2015-05-14 10:01:17 -04004295 else if (*mCurrentFunctionType != returnValue->getType())
Olli Etuaho49300862015-02-20 14:54:49 +02004296 {
4297 error(loc, "function return is not matching type:", "return");
Olli Etuaho49300862015-02-20 14:54:49 +02004298 }
4299 return intermediate.addBranch(op, returnValue, loc);
4300}
4301
Olli Etuahoe1a94c62015-11-16 17:35:25 +02004302void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall)
4303{
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08004304 ASSERT(functionCall->getOp() == EOpCallBuiltInFunction);
Olli Etuahobd674552016-10-06 13:28:42 +01004305 const TString &name = functionCall->getFunctionSymbolInfo()->getName();
Olli Etuahoe1a94c62015-11-16 17:35:25 +02004306 TIntermNode *offset = nullptr;
4307 TIntermSequence *arguments = functionCall->getSequence();
Olli Etuahoec9232b2017-03-27 17:01:37 +03004308 if (name == "texelFetchOffset" || name == "textureLodOffset" ||
4309 name == "textureProjLodOffset" || name == "textureGradOffset" ||
4310 name == "textureProjGradOffset")
Olli Etuahoe1a94c62015-11-16 17:35:25 +02004311 {
4312 offset = arguments->back();
4313 }
Olli Etuahoec9232b2017-03-27 17:01:37 +03004314 else if (name == "textureOffset" || name == "textureProjOffset")
Olli Etuahoe1a94c62015-11-16 17:35:25 +02004315 {
4316 // A bias parameter might follow the offset parameter.
4317 ASSERT(arguments->size() >= 3);
4318 offset = (*arguments)[2];
4319 }
4320 if (offset != nullptr)
4321 {
4322 TIntermConstantUnion *offsetConstantUnion = offset->getAsConstantUnion();
4323 if (offset->getAsTyped()->getQualifier() != EvqConst || !offsetConstantUnion)
4324 {
Olli Etuahoe1a94c62015-11-16 17:35:25 +02004325 error(functionCall->getLine(), "Texture offset must be a constant expression",
Olli Etuahoec9232b2017-03-27 17:01:37 +03004326 name.c_str());
Olli Etuahoe1a94c62015-11-16 17:35:25 +02004327 }
4328 else
4329 {
4330 ASSERT(offsetConstantUnion->getBasicType() == EbtInt);
4331 size_t size = offsetConstantUnion->getType().getObjectSize();
4332 const TConstantUnion *values = offsetConstantUnion->getUnionArrayPointer();
4333 for (size_t i = 0u; i < size; ++i)
4334 {
4335 int offsetValue = values[i].getIConst();
4336 if (offsetValue > mMaxProgramTexelOffset || offsetValue < mMinProgramTexelOffset)
4337 {
4338 std::stringstream tokenStream;
4339 tokenStream << offsetValue;
4340 std::string token = tokenStream.str();
4341 error(offset->getLine(), "Texture offset value out of valid range",
4342 token.c_str());
Olli Etuahoe1a94c62015-11-16 17:35:25 +02004343 }
4344 }
4345 }
4346 }
4347}
4348
Martin Radev2cc85b32016-08-05 16:22:53 +03004349// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
4350void TParseContext::checkImageMemoryAccessForBuiltinFunctions(TIntermAggregate *functionCall)
4351{
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08004352 ASSERT(functionCall->getOp() == EOpCallBuiltInFunction);
Martin Radev2cc85b32016-08-05 16:22:53 +03004353 const TString &name = functionCall->getFunctionSymbolInfo()->getName();
4354
4355 if (name.compare(0, 5, "image") == 0)
4356 {
4357 TIntermSequence *arguments = functionCall->getSequence();
Olli Etuaho485eefd2017-02-14 17:40:06 +00004358 TIntermTyped *imageNode = (*arguments)[0]->getAsTyped();
Martin Radev2cc85b32016-08-05 16:22:53 +03004359
Olli Etuaho485eefd2017-02-14 17:40:06 +00004360 const TMemoryQualifier &memoryQualifier = imageNode->getMemoryQualifier();
Martin Radev2cc85b32016-08-05 16:22:53 +03004361
4362 if (name.compare(5, 5, "Store") == 0)
4363 {
4364 if (memoryQualifier.readonly)
4365 {
4366 error(imageNode->getLine(),
4367 "'imageStore' cannot be used with images qualified as 'readonly'",
Olli Etuaho485eefd2017-02-14 17:40:06 +00004368 GetImageArgumentToken(imageNode));
Martin Radev2cc85b32016-08-05 16:22:53 +03004369 }
4370 }
4371 else if (name.compare(5, 4, "Load") == 0)
4372 {
4373 if (memoryQualifier.writeonly)
4374 {
4375 error(imageNode->getLine(),
4376 "'imageLoad' cannot be used with images qualified as 'writeonly'",
Olli Etuaho485eefd2017-02-14 17:40:06 +00004377 GetImageArgumentToken(imageNode));
Martin Radev2cc85b32016-08-05 16:22:53 +03004378 }
4379 }
4380 }
4381}
4382
4383// GLSL ES 3.10 Revision 4, 13.51 Matching of Memory Qualifiers in Function Parameters
4384void TParseContext::checkImageMemoryAccessForUserDefinedFunctions(
4385 const TFunction *functionDefinition,
4386 const TIntermAggregate *functionCall)
4387{
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08004388 ASSERT(functionCall->getOp() == EOpCallFunctionInAST);
Martin Radev2cc85b32016-08-05 16:22:53 +03004389
4390 const TIntermSequence &arguments = *functionCall->getSequence();
4391
4392 ASSERT(functionDefinition->getParamCount() == arguments.size());
4393
4394 for (size_t i = 0; i < arguments.size(); ++i)
4395 {
Olli Etuaho485eefd2017-02-14 17:40:06 +00004396 TIntermTyped *typedArgument = arguments[i]->getAsTyped();
4397 const TType &functionArgumentType = typedArgument->getType();
Martin Radev2cc85b32016-08-05 16:22:53 +03004398 const TType &functionParameterType = *functionDefinition->getParam(i).type;
4399 ASSERT(functionArgumentType.getBasicType() == functionParameterType.getBasicType());
4400
4401 if (IsImage(functionArgumentType.getBasicType()))
4402 {
4403 const TMemoryQualifier &functionArgumentMemoryQualifier =
4404 functionArgumentType.getMemoryQualifier();
4405 const TMemoryQualifier &functionParameterMemoryQualifier =
4406 functionParameterType.getMemoryQualifier();
4407 if (functionArgumentMemoryQualifier.readonly &&
4408 !functionParameterMemoryQualifier.readonly)
4409 {
4410 error(functionCall->getLine(),
4411 "Function call discards the 'readonly' qualifier from image",
Olli Etuaho485eefd2017-02-14 17:40:06 +00004412 GetImageArgumentToken(typedArgument));
Martin Radev2cc85b32016-08-05 16:22:53 +03004413 }
4414
4415 if (functionArgumentMemoryQualifier.writeonly &&
4416 !functionParameterMemoryQualifier.writeonly)
4417 {
4418 error(functionCall->getLine(),
4419 "Function call discards the 'writeonly' qualifier from image",
Olli Etuaho485eefd2017-02-14 17:40:06 +00004420 GetImageArgumentToken(typedArgument));
Martin Radev2cc85b32016-08-05 16:22:53 +03004421 }
Martin Radev049edfa2016-11-11 14:35:37 +02004422
4423 if (functionArgumentMemoryQualifier.coherent &&
4424 !functionParameterMemoryQualifier.coherent)
4425 {
4426 error(functionCall->getLine(),
4427 "Function call discards the 'coherent' qualifier from image",
Olli Etuaho485eefd2017-02-14 17:40:06 +00004428 GetImageArgumentToken(typedArgument));
Martin Radev049edfa2016-11-11 14:35:37 +02004429 }
4430
4431 if (functionArgumentMemoryQualifier.volatileQualifier &&
4432 !functionParameterMemoryQualifier.volatileQualifier)
4433 {
4434 error(functionCall->getLine(),
4435 "Function call discards the 'volatile' qualifier from image",
Olli Etuaho485eefd2017-02-14 17:40:06 +00004436 GetImageArgumentToken(typedArgument));
Martin Radev049edfa2016-11-11 14:35:37 +02004437 }
Martin Radev2cc85b32016-08-05 16:22:53 +03004438 }
4439 }
4440}
4441
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004442TIntermSequence *TParseContext::createEmptyArgumentsList()
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004443{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004444 return new TIntermSequence();
Olli Etuaho72d10202017-01-19 15:58:30 +00004445}
4446
4447TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall,
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004448 TIntermSequence *arguments,
Olli Etuaho72d10202017-01-19 15:58:30 +00004449 TIntermNode *thisNode,
4450 const TSourceLoc &loc)
4451{
Olli Etuahoffe6edf2015-04-13 17:32:03 +03004452 if (thisNode != nullptr)
4453 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004454 return addMethod(fnCall, arguments, thisNode, loc);
Olli Etuahoffe6edf2015-04-13 17:32:03 +03004455 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004456
4457 TOperator op = fnCall->getBuiltInOp();
4458 if (op != EOpNull)
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004459 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004460 return addConstructor(arguments, op, fnCall->getReturnType(), loc);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004461 }
4462 else
4463 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004464 return addNonConstructorFunctionCall(fnCall, arguments, loc);
4465 }
4466}
4467
4468TIntermTyped *TParseContext::addMethod(TFunction *fnCall,
4469 TIntermSequence *arguments,
4470 TIntermNode *thisNode,
4471 const TSourceLoc &loc)
4472{
4473 TConstantUnion *unionArray = new TConstantUnion[1];
4474 int arraySize = 0;
4475 TIntermTyped *typedThis = thisNode->getAsTyped();
4476 // It's possible for the name pointer in the TFunction to be null in case it gets parsed as
4477 // a constructor. But such a TFunction can't reach here, since the lexer goes into FIELDS
4478 // mode after a dot, which makes type identifiers to be parsed as FIELD_SELECTION instead.
4479 // So accessing fnCall->getName() below is safe.
4480 if (fnCall->getName() != "length")
4481 {
4482 error(loc, "invalid method", fnCall->getName().c_str());
4483 }
4484 else if (!arguments->empty())
4485 {
4486 error(loc, "method takes no parameters", "length");
4487 }
4488 else if (typedThis == nullptr || !typedThis->isArray())
4489 {
4490 error(loc, "length can only be called on arrays", "length");
4491 }
4492 else
4493 {
4494 arraySize = typedThis->getArraySize();
4495 if (typedThis->getAsSymbolNode() == nullptr)
Olli Etuaho72d10202017-01-19 15:58:30 +00004496 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004497 // This code path can be hit with expressions like these:
4498 // (a = b).length()
4499 // (func()).length()
4500 // (int[3](0, 1, 2)).length()
4501 // ESSL 3.00 section 5.9 defines expressions so that this is not actually a valid
4502 // expression.
4503 // It allows "An array name with the length method applied" in contrast to GLSL 4.4
4504 // spec section 5.9 which allows "An array, vector or matrix expression with the
4505 // length method applied".
4506 error(loc, "length can only be called on array names, not on array expressions",
4507 "length");
Olli Etuaho72d10202017-01-19 15:58:30 +00004508 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004509 }
4510 unionArray->setIConst(arraySize);
4511 return intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), loc);
4512}
4513
4514TIntermTyped *TParseContext::addNonConstructorFunctionCall(TFunction *fnCall,
4515 TIntermSequence *arguments,
4516 const TSourceLoc &loc)
4517{
4518 // First find by unmangled name to check whether the function name has been
4519 // hidden by a variable name or struct typename.
4520 // If a function is found, check for one with a matching argument list.
4521 bool builtIn;
4522 const TSymbol *symbol = symbolTable.find(fnCall->getName(), mShaderVersion, &builtIn);
4523 if (symbol != nullptr && !symbol->isFunction())
4524 {
4525 error(loc, "function name expected", fnCall->getName().c_str());
4526 }
4527 else
4528 {
4529 symbol = symbolTable.find(TFunction::GetMangledNameFromCall(fnCall->getName(), *arguments),
4530 mShaderVersion, &builtIn);
4531 if (symbol == nullptr)
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004532 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004533 error(loc, "no matching overloaded function found", fnCall->getName().c_str());
4534 }
4535 else
4536 {
4537 const TFunction *fnCandidate = static_cast<const TFunction *>(symbol);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004538 //
4539 // A declared function.
4540 //
Olli Etuaho383b7912016-08-05 11:22:59 +03004541 if (builtIn && !fnCandidate->getExtension().empty())
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004542 {
Olli Etuaho856c4972016-08-08 11:38:39 +03004543 checkCanUseExtension(loc, fnCandidate->getExtension());
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004544 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004545 TOperator op = fnCandidate->getBuiltInOp();
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004546 if (builtIn && op != EOpNull)
4547 {
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004548 // A function call mapped to a built-in operation.
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004549 if (fnCandidate->getParamCount() == 1)
4550 {
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004551 // Treat it like a built-in unary operator.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004552 TIntermNode *unaryParamNode = arguments->front();
4553 TIntermTyped *callNode = createUnaryMath(op, unaryParamNode->getAsTyped(), loc);
Olli Etuaho2be2d5a2017-01-26 16:34:30 -08004554 ASSERT(callNode != nullptr);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004555 return callNode;
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004556 }
4557 else
4558 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004559 TIntermAggregate *callNode =
Olli Etuahofe486322017-03-21 09:30:54 +00004560 TIntermAggregate::Create(fnCandidate->getReturnType(), op, arguments);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004561 callNode->setLine(loc);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004562
4563 // Some built-in functions have out parameters too.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004564 functionCallLValueErrorCheck(fnCandidate, callNode);
Arun Patole274f0702015-05-05 13:33:30 +05304565
Olli Etuaho7c3848e2015-11-04 13:19:17 +02004566 // See if we can constant fold a built-in. Note that this may be possible even
4567 // if it is not const-qualified.
Olli Etuahof119a262016-08-19 15:54:22 +03004568 TIntermTyped *foldedNode =
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004569 intermediate.foldAggregateBuiltIn(callNode, mDiagnostics);
Arun Patole274f0702015-05-05 13:33:30 +05304570 if (foldedNode)
4571 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004572 return foldedNode;
Arun Patole274f0702015-05-05 13:33:30 +05304573 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004574 return callNode;
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004575 }
4576 }
4577 else
4578 {
4579 // This is a real function call
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004580 TIntermAggregate *callNode = nullptr;
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004581
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08004582 // If builtIn == false, the function is user defined - could be an overloaded
4583 // built-in as well.
4584 // if builtIn == true, it's a builtIn function with no op associated with it.
4585 // This needs to happen after the function info including name is set.
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004586 if (builtIn)
Olli Etuahoe1a94c62015-11-16 17:35:25 +02004587 {
Olli Etuahofe486322017-03-21 09:30:54 +00004588 callNode = TIntermAggregate::CreateBuiltInFunctionCall(*fnCandidate, arguments);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004589 checkTextureOffsetConst(callNode);
4590 checkImageMemoryAccessForBuiltinFunctions(callNode);
Martin Radev2cc85b32016-08-05 16:22:53 +03004591 }
4592 else
4593 {
Olli Etuahofe486322017-03-21 09:30:54 +00004594 callNode = TIntermAggregate::CreateFunctionCall(*fnCandidate, arguments);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004595 checkImageMemoryAccessForUserDefinedFunctions(fnCandidate, callNode);
Olli Etuahoe1a94c62015-11-16 17:35:25 +02004596 }
4597
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004598 functionCallLValueErrorCheck(fnCandidate, callNode);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004599
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004600 callNode->setLine(loc);
4601
4602 return callNode;
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004603 }
4604 }
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004605 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08004606
4607 // Error message was already written. Put on a dummy node for error recovery.
4608 return TIntermTyped::CreateZero(TType(EbtFloat, EbpMedium, EvqConst));
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004609}
4610
Jamie Madillb98c3a82015-07-23 14:26:04 -04004611TIntermTyped *TParseContext::addTernarySelection(TIntermTyped *cond,
Olli Etuahod0bad2c2016-09-09 18:01:16 +03004612 TIntermTyped *trueExpression,
4613 TIntermTyped *falseExpression,
Olli Etuaho52901742015-04-15 13:42:45 +03004614 const TSourceLoc &loc)
4615{
Olli Etuaho856c4972016-08-08 11:38:39 +03004616 checkIsScalarBool(loc, cond);
Olli Etuaho52901742015-04-15 13:42:45 +03004617
Olli Etuahod0bad2c2016-09-09 18:01:16 +03004618 if (trueExpression->getType() != falseExpression->getType())
Olli Etuaho52901742015-04-15 13:42:45 +03004619 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +03004620 binaryOpError(loc, ":", trueExpression->getCompleteString(),
4621 falseExpression->getCompleteString());
4622 return falseExpression;
Olli Etuaho52901742015-04-15 13:42:45 +03004623 }
Olli Etuahode318b22016-10-25 16:18:25 +01004624 if (IsOpaqueType(trueExpression->getBasicType()))
4625 {
4626 // ESSL 1.00 section 4.1.7
4627 // ESSL 3.00 section 4.1.7
4628 // Opaque/sampler types are not allowed in most types of expressions, including ternary.
4629 // Note that structs containing opaque types don't need to be checked as structs are
4630 // forbidden below.
4631 error(loc, "ternary operator is not allowed for opaque types", ":");
4632 return falseExpression;
4633 }
4634
Olli Etuahoa2d53032015-04-15 14:14:44 +03004635 // ESSL1 sections 5.2 and 5.7:
4636 // ESSL3 section 5.7:
4637 // Ternary operator is not among the operators allowed for structures/arrays.
Olli Etuahod0bad2c2016-09-09 18:01:16 +03004638 if (trueExpression->isArray() || trueExpression->getBasicType() == EbtStruct)
Olli Etuahoa2d53032015-04-15 14:14:44 +03004639 {
4640 error(loc, "ternary operator is not allowed for structures or arrays", ":");
Olli Etuahod0bad2c2016-09-09 18:01:16 +03004641 return falseExpression;
Olli Etuahoa2d53032015-04-15 14:14:44 +03004642 }
Corentin Wallez0d959252016-07-12 17:26:32 -04004643 // WebGL2 section 5.26, the following results in an error:
4644 // "Ternary operator applied to void, arrays, or structs containing arrays"
Olli Etuahod0bad2c2016-09-09 18:01:16 +03004645 if (mShaderSpec == SH_WEBGL2_SPEC && trueExpression->getBasicType() == EbtVoid)
Corentin Wallez0d959252016-07-12 17:26:32 -04004646 {
4647 error(loc, "ternary operator is not allowed for void", ":");
Olli Etuahod0bad2c2016-09-09 18:01:16 +03004648 return falseExpression;
Corentin Wallez0d959252016-07-12 17:26:32 -04004649 }
4650
Olli Etuahod0bad2c2016-09-09 18:01:16 +03004651 return TIntermediate::AddTernarySelection(cond, trueExpression, falseExpression, loc);
Olli Etuaho52901742015-04-15 13:42:45 +03004652}
Olli Etuaho49300862015-02-20 14:54:49 +02004653
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00004654//
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004655// Parse an array of strings using yyparse.
4656//
4657// Returns 0 for success.
4658//
Jamie Madillb98c3a82015-07-23 14:26:04 -04004659int PaParseStrings(size_t count,
4660 const char *const string[],
4661 const int length[],
Arun Patole7e7e68d2015-05-22 12:02:25 +05304662 TParseContext *context)
4663{
Yunchao He4f285442017-04-21 12:15:49 +08004664 if ((count == 0) || (string == nullptr))
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004665 return 1;
4666
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004667 if (glslang_initialize(context))
4668 return 1;
4669
alokp@chromium.org408c45e2012-04-05 15:54:43 +00004670 int error = glslang_scan(count, string, length, context);
4671 if (!error)
4672 error = glslang_parse(context);
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004673
alokp@chromium.org73bc2982012-06-19 18:48:05 +00004674 glslang_finalize(context);
alokp@chromium.org8b851c62012-06-15 16:25:11 +00004675
alokp@chromium.org6b495712012-06-29 00:06:58 +00004676 return (error == 0) && (context->numErrors() == 0) ? 0 : 1;
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004677}
Jamie Madill45bcc782016-11-07 13:58:48 -05004678
4679} // namespace sh