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