• 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 
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