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