1 //
2 // Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
3 // Copyright (C) 2016 Google, Inc.
4 //
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
11 // Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 //
14 // Redistributions in binary form must reproduce the above
15 // copyright notice, this list of conditions and the following
16 // disclaimer in the documentation and/or other materials provided
17 // with the distribution.
18 //
19 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
20 // contributors may be used to endorse or promote products derived
21 // from this software without specific prior written permission.
22 //
23 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 // POSSIBILITY OF SUCH DAMAGE.
35 //
36
37 // Implement the TParseContextBase class.
38
39 #include <cstdarg>
40
41 #include "ParseHelper.h"
42
43 extern int yyparse(glslang::TParseContext*);
44
45 namespace glslang {
46
47 //
48 // Used to output syntax, parsing, and semantic errors.
49 //
50
outputMessage(const TSourceLoc & loc,const char * szReason,const char * szToken,const char * szExtraInfoFormat,TPrefixType prefix,va_list args)51 void TParseContextBase::outputMessage(const TSourceLoc& loc, const char* szReason,
52 const char* szToken,
53 const char* szExtraInfoFormat,
54 TPrefixType prefix, va_list args)
55 {
56 const int maxSize = MaxTokenLength + 200;
57 char szExtraInfo[maxSize];
58
59 safe_vsprintf(szExtraInfo, maxSize, szExtraInfoFormat, args);
60
61 infoSink.info.prefix(prefix);
62 infoSink.info.location(loc);
63 infoSink.info << "'" << szToken << "' : " << szReason << " " << szExtraInfo << "\n";
64
65 if (prefix == EPrefixError) {
66 ++numErrors;
67 }
68 }
69
error(const TSourceLoc & loc,const char * szReason,const char * szToken,const char * szExtraInfoFormat,...)70 void C_DECL TParseContextBase::error(const TSourceLoc& loc, const char* szReason, const char* szToken,
71 const char* szExtraInfoFormat, ...)
72 {
73 if (messages & EShMsgOnlyPreprocessor)
74 return;
75 // If enhanced msg readability, only print one error
76 if (messages & EShMsgEnhanced && numErrors > 0)
77 return;
78 va_list args;
79 va_start(args, szExtraInfoFormat);
80 outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args);
81 va_end(args);
82
83 if ((messages & EShMsgCascadingErrors) == 0)
84 currentScanner->setEndOfInput();
85 }
86
warn(const TSourceLoc & loc,const char * szReason,const char * szToken,const char * szExtraInfoFormat,...)87 void C_DECL TParseContextBase::warn(const TSourceLoc& loc, const char* szReason, const char* szToken,
88 const char* szExtraInfoFormat, ...)
89 {
90 if (suppressWarnings())
91 return;
92 va_list args;
93 va_start(args, szExtraInfoFormat);
94 outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixWarning, args);
95 va_end(args);
96 }
97
ppError(const TSourceLoc & loc,const char * szReason,const char * szToken,const char * szExtraInfoFormat,...)98 void C_DECL TParseContextBase::ppError(const TSourceLoc& loc, const char* szReason, const char* szToken,
99 const char* szExtraInfoFormat, ...)
100 {
101 va_list args;
102 va_start(args, szExtraInfoFormat);
103 outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args);
104 va_end(args);
105
106 if ((messages & EShMsgCascadingErrors) == 0)
107 currentScanner->setEndOfInput();
108 }
109
ppWarn(const TSourceLoc & loc,const char * szReason,const char * szToken,const char * szExtraInfoFormat,...)110 void C_DECL TParseContextBase::ppWarn(const TSourceLoc& loc, const char* szReason, const char* szToken,
111 const char* szExtraInfoFormat, ...)
112 {
113 va_list args;
114 va_start(args, szExtraInfoFormat);
115 outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixWarning, args);
116 va_end(args);
117 }
118
119 //
120 // Both test and if necessary, spit out an error, to see if the node is really
121 // an l-value that can be operated on this way.
122 //
123 // Returns true if there was an error.
124 //
lValueErrorCheck(const TSourceLoc & loc,const char * op,TIntermTyped * node)125 bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node)
126 {
127 TIntermBinary* binaryNode = node->getAsBinaryNode();
128
129 const char* symbol = nullptr;
130 TIntermSymbol* symNode = node->getAsSymbolNode();
131 if (symNode != nullptr)
132 symbol = symNode->getName().c_str();
133
134 const char* message = nullptr;
135 switch (node->getQualifier().storage) {
136 case EvqConst: message = "can't modify a const"; break;
137 case EvqConstReadOnly: message = "can't modify a const"; break;
138 case EvqUniform: message = "can't modify a uniform"; break;
139 case EvqBuffer:
140 if (node->getQualifier().isReadOnly())
141 message = "can't modify a readonly buffer";
142 if (node->getQualifier().isShaderRecord())
143 message = "can't modify a shaderrecordnv qualified buffer";
144 break;
145 case EvqHitAttr:
146 if (language != EShLangIntersect)
147 message = "cannot modify hitAttributeNV in this stage";
148 break;
149
150 default:
151 //
152 // Type that can't be written to?
153 //
154 switch (node->getBasicType()) {
155 case EbtSampler:
156 if (extensionTurnedOn(E_GL_ARB_bindless_texture) == false)
157 message = "can't modify a sampler";
158 break;
159 case EbtVoid:
160 message = "can't modify void";
161 break;
162 case EbtAtomicUint:
163 message = "can't modify an atomic_uint";
164 break;
165 case EbtAccStruct:
166 message = "can't modify accelerationStructureNV";
167 break;
168 case EbtRayQuery:
169 message = "can't modify rayQueryEXT";
170 break;
171 case EbtHitObjectNV:
172 message = "can't modify hitObjectNV";
173 break;
174 default:
175 break;
176 }
177 }
178
179 if (message == nullptr && binaryNode == nullptr && symNode == nullptr) {
180 error(loc, " l-value required", op, "", "");
181
182 return true;
183 }
184
185 //
186 // Everything else is okay, no error.
187 //
188 if (message == nullptr)
189 {
190 if (binaryNode) {
191 switch (binaryNode->getOp()) {
192 case EOpIndexDirect:
193 case EOpIndexIndirect: // fall through
194 case EOpIndexDirectStruct: // fall through
195 case EOpVectorSwizzle:
196 case EOpMatrixSwizzle:
197 return lValueErrorCheck(loc, op, binaryNode->getLeft());
198 default:
199 break;
200 }
201 error(loc, " l-value required", op, "", "");
202
203 return true;
204 }
205 return false;
206 }
207
208 //
209 // If we get here, we have an error and a message.
210 //
211 const TIntermTyped* leftMostTypeNode = TIntermediate::traverseLValueBase(node, true);
212
213 if (symNode)
214 error(loc, " l-value required", op, "\"%s\" (%s)", symbol, message);
215 else
216 if (binaryNode && binaryNode->getAsOperator()->getOp() == EOpIndexDirectStruct)
217 if(IsAnonymous(leftMostTypeNode->getAsSymbolNode()->getName()))
218 error(loc, " l-value required", op, "\"%s\" (%s)", leftMostTypeNode->getAsSymbolNode()->getAccessName().c_str(), message);
219 else
220 error(loc, " l-value required", op, "\"%s\" (%s)", leftMostTypeNode->getAsSymbolNode()->getName().c_str(), message);
221 else
222 error(loc, " l-value required", op, "(%s)", message);
223
224 return true;
225 }
226
227 // Test for and give an error if the node can't be read from.
rValueErrorCheck(const TSourceLoc & loc,const char * op,TIntermTyped * node)228 void TParseContextBase::rValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node)
229 {
230 if (! node)
231 return;
232
233 TIntermBinary* binaryNode = node->getAsBinaryNode();
234 const TIntermSymbol* symNode = node->getAsSymbolNode();
235
236 if (node->getQualifier().isWriteOnly()) {
237 const TIntermTyped* leftMostTypeNode = TIntermediate::traverseLValueBase(node, true);
238
239 if (symNode != nullptr)
240 error(loc, "can't read from writeonly object: ", op, symNode->getName().c_str());
241 else if (binaryNode &&
242 (binaryNode->getAsOperator()->getOp() == EOpIndexDirectStruct ||
243 binaryNode->getAsOperator()->getOp() == EOpIndexDirect))
244 if(IsAnonymous(leftMostTypeNode->getAsSymbolNode()->getName()))
245 error(loc, "can't read from writeonly object: ", op, leftMostTypeNode->getAsSymbolNode()->getAccessName().c_str());
246 else
247 error(loc, "can't read from writeonly object: ", op, leftMostTypeNode->getAsSymbolNode()->getName().c_str());
248 else
249 error(loc, "can't read from writeonly object: ", op, "");
250
251 } else {
252 if (binaryNode) {
253 switch (binaryNode->getOp()) {
254 case EOpIndexDirect:
255 case EOpIndexIndirect:
256 case EOpIndexDirectStruct:
257 case EOpVectorSwizzle:
258 case EOpMatrixSwizzle:
259 rValueErrorCheck(loc, op, binaryNode->getLeft());
260 default:
261 break;
262 }
263 }
264 }
265 }
266
267 // Add 'symbol' to the list of deferred linkage symbols, which
268 // are later processed in finish(), at which point the symbol
269 // must still be valid.
270 // It is okay if the symbol's type will be subsequently edited;
271 // the modifications will be tracked.
272 // Order is preserved, to avoid creating novel forward references.
trackLinkage(TSymbol & symbol)273 void TParseContextBase::trackLinkage(TSymbol& symbol)
274 {
275 if (!parsingBuiltins)
276 linkageSymbols.push_back(&symbol);
277 }
278
279 // Ensure index is in bounds, correct if necessary.
280 // Give an error if not.
checkIndex(const TSourceLoc & loc,const TType & type,int & index)281 void TParseContextBase::checkIndex(const TSourceLoc& loc, const TType& type, int& index)
282 {
283 const auto sizeIsSpecializationExpression = [&type]() {
284 return type.containsSpecializationSize() &&
285 type.getArraySizes()->getOuterNode() != nullptr &&
286 type.getArraySizes()->getOuterNode()->getAsSymbolNode() == nullptr; };
287
288 if (index < 0) {
289 error(loc, "", "[", "index out of range '%d'", index);
290 index = 0;
291 } else if (type.isArray()) {
292 if (type.isSizedArray() && !sizeIsSpecializationExpression() &&
293 index >= type.getOuterArraySize()) {
294 error(loc, "", "[", "array index out of range '%d'", index);
295 index = type.getOuterArraySize() - 1;
296 }
297 } else if (type.isVector()) {
298 if (index >= type.getVectorSize()) {
299 error(loc, "", "[", "vector index out of range '%d'", index);
300 index = type.getVectorSize() - 1;
301 }
302 } else if (type.isMatrix()) {
303 if (index >= type.getMatrixCols()) {
304 error(loc, "", "[", "matrix index out of range '%d'", index);
305 index = type.getMatrixCols() - 1;
306 }
307 }
308 }
309
310 // Make a shared symbol have a non-shared version that can be edited by the current
311 // compile, such that editing its type will not change the shared version and will
312 // effect all nodes already sharing it (non-shallow type),
313 // or adopting its full type after being edited (shallow type).
makeEditable(TSymbol * & symbol)314 void TParseContextBase::makeEditable(TSymbol*& symbol)
315 {
316 // copyUp() does a deep copy of the type.
317 symbol = symbolTable.copyUp(symbol);
318
319 // Save it (deferred, so it can be edited first) in the AST for linker use.
320 if (symbol)
321 trackLinkage(*symbol);
322 }
323
324 // Return a writable version of the variable 'name'.
325 //
326 // Return nullptr if 'name' is not found. This should mean
327 // something is seriously wrong (e.g., compiler asking self for
328 // built-in that doesn't exist).
getEditableVariable(const char * name)329 TVariable* TParseContextBase::getEditableVariable(const char* name)
330 {
331 bool builtIn;
332 TSymbol* symbol = symbolTable.find(name, &builtIn);
333
334 assert(symbol != nullptr);
335 if (symbol == nullptr)
336 return nullptr;
337
338 if (builtIn)
339 makeEditable(symbol);
340
341 return symbol->getAsVariable();
342 }
343
344 // Select the best matching function for 'call' from 'candidateList'.
345 //
346 // Assumptions
347 //
348 // There is no exact match, so a selection algorithm needs to run. That is, the
349 // language-specific handler should check for exact match first, to
350 // decide what to do, before calling this selector.
351 //
352 // Input
353 //
354 // * list of candidate signatures to select from
355 // * the call
356 // * a predicate function convertible(from, to) that says whether or not type
357 // 'from' can implicitly convert to type 'to' (it includes the case of what
358 // the calling language would consider a matching type with no conversion
359 // needed)
360 // * a predicate function better(from1, from2, to1, to2) that says whether or
361 // not a conversion from <-> to2 is considered better than a conversion
362 // from <-> to1 (both in and out directions need testing, as declared by the
363 // formal parameter)
364 //
365 // Output
366 //
367 // * best matching candidate (or none, if no viable candidates found)
368 // * whether there was a tie for the best match (ambiguous overload selection,
369 // caller's choice for how to report)
370 //
selectFunction(const TVector<const TFunction * > candidateList,const TFunction & call,std::function<bool (const TType & from,const TType & to,TOperator op,int arg)> convertible,std::function<bool (const TType & from,const TType & to1,const TType & to2)> better,bool & tie)371 const TFunction* TParseContextBase::selectFunction(
372 const TVector<const TFunction*> candidateList,
373 const TFunction& call,
374 std::function<bool(const TType& from, const TType& to, TOperator op, int arg)> convertible,
375 std::function<bool(const TType& from, const TType& to1, const TType& to2)> better,
376 /* output */ bool& tie)
377 {
378 //
379 // Operation
380 //
381 // 1. Prune the input list of candidates down to a list of viable candidates,
382 // where each viable candidate has
383 //
384 // * at least as many parameters as there are calling arguments, with any
385 // remaining parameters being optional or having default values
386 // * each parameter is true under convertible(A, B), where A is the calling
387 // type for in and B is the formal type, and in addition, for out B is the
388 // calling type and A is the formal type
389 //
390 // 2. If there are no viable candidates, return with no match.
391 //
392 // 3. If there is only one viable candidate, it is the best match.
393 //
394 // 4. If there are multiple viable candidates, select the first viable candidate
395 // as the incumbent. Compare the incumbent to the next viable candidate, and if
396 // that candidate is better (bullets below), make it the incumbent. Repeat, with
397 // a linear walk through the viable candidate list. The final incumbent will be
398 // returned as the best match. A viable candidate is better than the incumbent if
399 //
400 // * it has a function argument with a better(...) conversion than the incumbent,
401 // for all directions needed by in and out
402 // * the incumbent has no argument with a better(...) conversion then the
403 // candidate, for either in or out (as needed)
404 //
405 // 5. Check for ambiguity by comparing the best match against all other viable
406 // candidates. If any other viable candidate has a function argument with a
407 // better(...) conversion than the best candidate (for either in or out
408 // directions), return that there was a tie for best.
409 //
410
411 tie = false;
412
413 // 1. prune to viable...
414 TVector<const TFunction*> viableCandidates;
415 for (auto it = candidateList.begin(); it != candidateList.end(); ++it) {
416 const TFunction& candidate = *(*it);
417
418 // to even be a potential match, number of arguments must be >= the number of
419 // fixed (non-default) parameters, and <= the total (including parameter with defaults).
420 if (call.getParamCount() < candidate.getFixedParamCount() ||
421 call.getParamCount() > candidate.getParamCount())
422 continue;
423
424 // see if arguments are convertible
425 bool viable = true;
426
427 // The call can have fewer parameters than the candidate, if some have defaults.
428 const int paramCount = std::min(call.getParamCount(), candidate.getParamCount());
429 for (int param = 0; param < paramCount; ++param) {
430 if (candidate[param].type->getQualifier().isParamInput()) {
431 if (! convertible(*call[param].type, *candidate[param].type, candidate.getBuiltInOp(), param)) {
432 viable = false;
433 break;
434 }
435 }
436 if (candidate[param].type->getQualifier().isParamOutput()) {
437 if (! convertible(*candidate[param].type, *call[param].type, candidate.getBuiltInOp(), param)) {
438 viable = false;
439 break;
440 }
441 }
442 }
443
444 if (viable)
445 viableCandidates.push_back(&candidate);
446 }
447
448 // 2. none viable...
449 if (viableCandidates.size() == 0)
450 return nullptr;
451
452 // 3. only one viable...
453 if (viableCandidates.size() == 1)
454 return viableCandidates.front();
455
456 // 4. find best...
457 const auto betterParam = [&call, &better](const TFunction& can1, const TFunction& can2) -> bool {
458 // is call -> can2 better than call -> can1 for any parameter
459 bool hasBetterParam = false;
460 for (int param = 0; param < call.getParamCount(); ++param) {
461 if (better(*call[param].type, *can1[param].type, *can2[param].type)) {
462 hasBetterParam = true;
463 break;
464 }
465 }
466 return hasBetterParam;
467 };
468
469 const auto equivalentParams = [&call, &better](const TFunction& can1, const TFunction& can2) -> bool {
470 // is call -> can2 equivalent to call -> can1 for all the call parameters?
471 for (int param = 0; param < call.getParamCount(); ++param) {
472 if (better(*call[param].type, *can1[param].type, *can2[param].type) ||
473 better(*call[param].type, *can2[param].type, *can1[param].type))
474 return false;
475 }
476 return true;
477 };
478
479 const TFunction* incumbent = viableCandidates.front();
480 for (auto it = viableCandidates.begin() + 1; it != viableCandidates.end(); ++it) {
481 const TFunction& candidate = *(*it);
482 if (betterParam(*incumbent, candidate) && ! betterParam(candidate, *incumbent))
483 incumbent = &candidate;
484 }
485
486 // 5. ambiguity...
487 for (auto it = viableCandidates.begin(); it != viableCandidates.end(); ++it) {
488 if (incumbent == *it)
489 continue;
490 const TFunction& candidate = *(*it);
491
492 // In the case of default parameters, it may have an identical initial set, which is
493 // also ambiguous
494 if (betterParam(*incumbent, candidate) || equivalentParams(*incumbent, candidate))
495 tie = true;
496 }
497
498 return incumbent;
499 }
500
501 //
502 // Look at a '.' field selector string and change it into numerical selectors
503 // for a vector or scalar.
504 //
505 // Always return some form of swizzle, so the result is always usable.
506 //
parseSwizzleSelector(const TSourceLoc & loc,const TString & compString,int vecSize,TSwizzleSelectors<TVectorSelector> & selector)507 void TParseContextBase::parseSwizzleSelector(const TSourceLoc& loc, const TString& compString, int vecSize,
508 TSwizzleSelectors<TVectorSelector>& selector)
509 {
510 // Too long?
511 if (compString.size() > MaxSwizzleSelectors)
512 error(loc, "vector swizzle too long", compString.c_str(), "");
513
514 // Use this to test that all swizzle characters are from the same swizzle-namespace-set
515 enum {
516 exyzw,
517 ergba,
518 estpq,
519 } fieldSet[MaxSwizzleSelectors];
520
521 // Decode the swizzle string.
522 int size = std::min(MaxSwizzleSelectors, (int)compString.size());
523 for (int i = 0; i < size; ++i) {
524 switch (compString[i]) {
525 case 'x':
526 selector.push_back(0);
527 fieldSet[i] = exyzw;
528 break;
529 case 'r':
530 selector.push_back(0);
531 fieldSet[i] = ergba;
532 break;
533 case 's':
534 selector.push_back(0);
535 fieldSet[i] = estpq;
536 break;
537
538 case 'y':
539 selector.push_back(1);
540 fieldSet[i] = exyzw;
541 break;
542 case 'g':
543 selector.push_back(1);
544 fieldSet[i] = ergba;
545 break;
546 case 't':
547 selector.push_back(1);
548 fieldSet[i] = estpq;
549 break;
550
551 case 'z':
552 selector.push_back(2);
553 fieldSet[i] = exyzw;
554 break;
555 case 'b':
556 selector.push_back(2);
557 fieldSet[i] = ergba;
558 break;
559 case 'p':
560 selector.push_back(2);
561 fieldSet[i] = estpq;
562 break;
563
564 case 'w':
565 selector.push_back(3);
566 fieldSet[i] = exyzw;
567 break;
568 case 'a':
569 selector.push_back(3);
570 fieldSet[i] = ergba;
571 break;
572 case 'q':
573 selector.push_back(3);
574 fieldSet[i] = estpq;
575 break;
576
577 default:
578 error(loc, "unknown swizzle selection", compString.c_str(), "");
579 break;
580 }
581 }
582
583 // Additional error checking.
584 for (int i = 0; i < selector.size(); ++i) {
585 if (selector[i] >= vecSize) {
586 error(loc, "vector swizzle selection out of range", compString.c_str(), "");
587 selector.resize(i);
588 break;
589 }
590
591 if (i > 0 && fieldSet[i] != fieldSet[i-1]) {
592 error(loc, "vector swizzle selectors not from the same set", compString.c_str(), "");
593 selector.resize(i);
594 break;
595 }
596 }
597
598 // Ensure it is valid.
599 if (selector.size() == 0)
600 selector.push_back(0);
601 }
602
603 //
604 // Make the passed-in variable information become a member of the
605 // global uniform block. If this doesn't exist yet, make it.
606 //
growGlobalUniformBlock(const TSourceLoc & loc,TType & memberType,const TString & memberName,TTypeList * typeList)607 void TParseContextBase::growGlobalUniformBlock(const TSourceLoc& loc, TType& memberType, const TString& memberName, TTypeList* typeList)
608 {
609 // Make the global block, if not yet made.
610 if (globalUniformBlock == nullptr) {
611 TQualifier blockQualifier;
612 blockQualifier.clear();
613 blockQualifier.storage = EvqUniform;
614 TType blockType(new TTypeList, *NewPoolTString(getGlobalUniformBlockName()), blockQualifier);
615 setUniformBlockDefaults(blockType);
616 globalUniformBlock = new TVariable(NewPoolTString(""), blockType, true);
617 firstNewMember = 0;
618 }
619
620 // Update with binding and set
621 globalUniformBlock->getWritableType().getQualifier().layoutBinding = globalUniformBinding;
622 globalUniformBlock->getWritableType().getQualifier().layoutSet = globalUniformSet;
623
624 // Check for declarations of this default uniform that already exist due to other compilation units.
625 TSymbol* symbol = symbolTable.find(memberName);
626 if (symbol) {
627 if (memberType != symbol->getType()) {
628 TString err;
629 err += "Redeclaration: already declared as \"" + symbol->getType().getCompleteString() + "\"";
630 error(loc, "", memberName.c_str(), err.c_str());
631 }
632 return;
633 }
634
635 // Add the requested member as a member to the global block.
636 TType* type = new TType;
637 type->shallowCopy(memberType);
638 type->setFieldName(memberName);
639 if (typeList)
640 type->setStruct(typeList);
641 TTypeLoc typeLoc = {type, loc};
642 globalUniformBlock->getType().getWritableStruct()->push_back(typeLoc);
643
644 // Insert into the symbol table.
645 if (firstNewMember == 0) {
646 // This is the first request; we need a normal symbol table insert
647 if (symbolTable.insert(*globalUniformBlock))
648 trackLinkage(*globalUniformBlock);
649 else
650 error(loc, "failed to insert the global constant buffer", "uniform", "");
651 } else {
652 // This is a follow-on request; we need to amend the first insert
653 symbolTable.amend(*globalUniformBlock, firstNewMember);
654 }
655
656 ++firstNewMember;
657 }
658
growAtomicCounterBlock(int binding,const TSourceLoc & loc,TType & memberType,const TString & memberName,TTypeList * typeList)659 void TParseContextBase::growAtomicCounterBlock(int binding, const TSourceLoc& loc, TType& memberType, const TString& memberName, TTypeList* typeList) {
660 // Make the atomic counter block, if not yet made.
661 const auto &at = atomicCounterBuffers.find(binding);
662 if (at == atomicCounterBuffers.end()) {
663 atomicCounterBuffers.insert({binding, (TVariable*)nullptr });
664 atomicCounterBlockFirstNewMember.insert({binding, 0});
665 }
666
667 TVariable*& atomicCounterBuffer = atomicCounterBuffers[binding];
668 int& bufferNewMember = atomicCounterBlockFirstNewMember[binding];
669
670 if (atomicCounterBuffer == nullptr) {
671 TQualifier blockQualifier;
672 blockQualifier.clear();
673 blockQualifier.storage = EvqBuffer;
674
675 char charBuffer[512];
676 if (binding != TQualifier::layoutBindingEnd) {
677 snprintf(charBuffer, 512, "%s_%d", getAtomicCounterBlockName(), binding);
678 } else {
679 snprintf(charBuffer, 512, "%s_0", getAtomicCounterBlockName());
680 }
681
682 TType blockType(new TTypeList, *NewPoolTString(charBuffer), blockQualifier);
683 setUniformBlockDefaults(blockType);
684 blockType.getQualifier().layoutPacking = ElpStd430;
685 atomicCounterBuffer = new TVariable(NewPoolTString(""), blockType, true);
686 // If we arn't auto mapping bindings then set the block to use the same
687 // binding as what the atomic was set to use
688 if (!intermediate.getAutoMapBindings()) {
689 atomicCounterBuffer->getWritableType().getQualifier().layoutBinding = binding;
690 }
691 bufferNewMember = 0;
692
693 atomicCounterBuffer->getWritableType().getQualifier().layoutSet = atomicCounterBlockSet;
694 }
695
696 // Add the requested member as a member to the global block.
697 TType* type = new TType;
698 type->shallowCopy(memberType);
699 type->setFieldName(memberName);
700 if (typeList)
701 type->setStruct(typeList);
702 TTypeLoc typeLoc = {type, loc};
703 atomicCounterBuffer->getType().getWritableStruct()->push_back(typeLoc);
704
705 // Insert into the symbol table.
706 if (bufferNewMember == 0) {
707 // This is the first request; we need a normal symbol table insert
708 if (symbolTable.insert(*atomicCounterBuffer))
709 trackLinkage(*atomicCounterBuffer);
710 else
711 error(loc, "failed to insert the global constant buffer", "buffer", "");
712 } else {
713 // This is a follow-on request; we need to amend the first insert
714 symbolTable.amend(*atomicCounterBuffer, bufferNewMember);
715 }
716
717 ++bufferNewMember;
718 }
719
finish()720 void TParseContextBase::finish()
721 {
722 if (parsingBuiltins)
723 return;
724
725 for (const TString& relaxedSymbol : relaxedSymbols)
726 {
727 TSymbol* symbol = symbolTable.find(relaxedSymbol);
728 TType& type = symbol->getWritableType();
729 for (const TTypeLoc& typeLoc : *type.getStruct())
730 {
731 if (typeLoc.type->isOpaque())
732 {
733 typeLoc.type->getSampler() = TSampler{};
734 typeLoc.type->setBasicType(EbtInt);
735 TString fieldName("/*");
736 fieldName.append(typeLoc.type->getFieldName());
737 fieldName.append("*/");
738 typeLoc.type->setFieldName(fieldName);
739 }
740 }
741 }
742
743 // Transfer the linkage symbols to AST nodes, preserving order.
744 TIntermAggregate* linkage = new TIntermAggregate;
745 for (auto i = linkageSymbols.begin(); i != linkageSymbols.end(); ++i)
746 intermediate.addSymbolLinkageNode(linkage, **i);
747 intermediate.addSymbolLinkageNodes(linkage, getLanguage(), symbolTable);
748 }
749
750 } // end namespace glslang
751