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