1 //
2 // Copyright (c) 2002-2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 #include "compiler/translator/QualifierTypes.h"
8 
9 #include "compiler/translator/Diagnostics.h"
10 
11 #include <algorithm>
12 
13 namespace sh
14 {
15 
16 namespace
17 {
18 
19 // GLSL ES 3.10 does not impose a strict order on type qualifiers and allows multiple layout
20 // declarations.
21 // GLSL ES 3.10 Revision 4, 4.10 Order of Qualification
AreTypeQualifierChecksRelaxed(int shaderVersion)22 bool AreTypeQualifierChecksRelaxed(int shaderVersion)
23 {
24     return shaderVersion >= 310;
25 }
26 
IsScopeQualifier(TQualifier qualifier)27 bool IsScopeQualifier(TQualifier qualifier)
28 {
29     return qualifier == EvqGlobal || qualifier == EvqTemporary;
30 }
31 
IsScopeQualifierWrapper(const TQualifierWrapperBase * qualifier)32 bool IsScopeQualifierWrapper(const TQualifierWrapperBase *qualifier)
33 {
34     if (qualifier->getType() != QtStorage)
35         return false;
36     const TStorageQualifierWrapper *storageQualifier =
37         static_cast<const TStorageQualifierWrapper *>(qualifier);
38     TQualifier q = storageQualifier->getQualifier();
39     return IsScopeQualifier(q);
40 }
41 
42 // Returns true if the invariant for the qualifier sequence holds
IsInvariantCorrect(const TTypeQualifierBuilder::QualifierSequence & qualifiers)43 bool IsInvariantCorrect(const TTypeQualifierBuilder::QualifierSequence &qualifiers)
44 {
45     // We should have at least one qualifier.
46     // The first qualifier always tells the scope.
47     return qualifiers.size() >= 1 && IsScopeQualifierWrapper(qualifiers[0]);
48 }
49 
50 // Returns true if there are qualifiers which have been specified multiple times
51 // If areQualifierChecksRelaxed is set to true, then layout qualifier repetition is allowed.
HasRepeatingQualifiers(const TTypeQualifierBuilder::QualifierSequence & qualifiers,bool areQualifierChecksRelaxed,std::string * errorMessage)52 bool HasRepeatingQualifiers(const TTypeQualifierBuilder::QualifierSequence &qualifiers,
53                             bool areQualifierChecksRelaxed,
54                             std::string *errorMessage)
55 {
56     bool invariantFound     = false;
57     bool precisionFound     = false;
58     bool layoutFound        = false;
59     bool interpolationFound = false;
60 
61     unsigned int locationsSpecified = 0;
62     bool isOut                      = false;
63 
64     // The iteration starts from one since the first qualifier only reveals the scope of the
65     // expression. It is inserted first whenever the sequence gets created.
66     for (size_t i = 1; i < qualifiers.size(); ++i)
67     {
68         switch (qualifiers[i]->getType())
69         {
70             case QtInvariant:
71             {
72                 if (invariantFound)
73                 {
74                     *errorMessage = "The invariant qualifier specified multiple times.";
75                     return true;
76                 }
77                 invariantFound = true;
78                 break;
79             }
80             case QtPrecision:
81             {
82                 if (precisionFound)
83                 {
84                     *errorMessage = "The precision qualifier specified multiple times.";
85                     return true;
86                 }
87                 precisionFound = true;
88                 break;
89             }
90             case QtLayout:
91             {
92                 if (layoutFound && !areQualifierChecksRelaxed)
93                 {
94                     *errorMessage = "The layout qualifier specified multiple times.";
95                     return true;
96                 }
97                 if (invariantFound && !areQualifierChecksRelaxed)
98                 {
99                     // This combination is not correct according to the syntax specified in the
100                     // formal grammar in the ESSL 3.00 spec. In ESSL 3.10 the grammar does not have
101                     // a similar restriction.
102                     *errorMessage =
103                         "The layout qualifier and invariant qualifier cannot coexist in the same "
104                         "declaration according to the grammar.";
105                     return true;
106                 }
107                 layoutFound = true;
108                 const TLayoutQualifier &currentQualifier =
109                     static_cast<const TLayoutQualifierWrapper *>(qualifiers[i])->getQualifier();
110                 locationsSpecified += currentQualifier.locationsSpecified;
111                 break;
112             }
113             case QtInterpolation:
114             {
115                 // 'centroid' is treated as a storage qualifier
116                 // 'flat centroid' will be squashed to 'flat'
117                 // 'smooth centroid' will be squashed to 'centroid'
118                 if (interpolationFound)
119                 {
120                     *errorMessage = "The interpolation qualifier specified multiple times.";
121                     return true;
122                 }
123                 interpolationFound = true;
124                 break;
125             }
126             case QtStorage:
127             {
128                 // Go over all of the storage qualifiers up until the current one and check for
129                 // repetitions.
130                 TQualifier currentQualifier =
131                     static_cast<const TStorageQualifierWrapper *>(qualifiers[i])->getQualifier();
132                 if (currentQualifier == EvqVertexOut || currentQualifier == EvqFragmentOut)
133                 {
134                     isOut = true;
135                 }
136                 for (size_t j = 1; j < i; ++j)
137                 {
138                     if (qualifiers[j]->getType() == QtStorage)
139                     {
140                         const TStorageQualifierWrapper *previousQualifierWrapper =
141                             static_cast<const TStorageQualifierWrapper *>(qualifiers[j]);
142                         TQualifier previousQualifier = previousQualifierWrapper->getQualifier();
143                         if (currentQualifier == previousQualifier)
144                         {
145                             *errorMessage = previousQualifierWrapper->getQualifierString().c_str();
146                             *errorMessage += " specified multiple times";
147                             return true;
148                         }
149                     }
150                 }
151                 break;
152             }
153             case QtMemory:
154             {
155                 // Go over all of the memory qualifiers up until the current one and check for
156                 // repetitions.
157                 // Having both readonly and writeonly in a sequence is valid.
158                 // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
159                 TQualifier currentQualifier =
160                     static_cast<const TMemoryQualifierWrapper *>(qualifiers[i])->getQualifier();
161                 for (size_t j = 1; j < i; ++j)
162                 {
163                     if (qualifiers[j]->getType() == QtMemory)
164                     {
165                         const TMemoryQualifierWrapper *previousQualifierWrapper =
166                             static_cast<const TMemoryQualifierWrapper *>(qualifiers[j]);
167                         TQualifier previousQualifier = previousQualifierWrapper->getQualifier();
168                         if (currentQualifier == previousQualifier)
169                         {
170                             *errorMessage = previousQualifierWrapper->getQualifierString().c_str();
171                             *errorMessage += " specified multiple times";
172                             return true;
173                         }
174                     }
175                 }
176                 break;
177             }
178             default:
179                 UNREACHABLE();
180         }
181     }
182 
183     if (locationsSpecified > 1 && isOut)
184     {
185         // GLSL ES 3.00.6 section 4.3.8.2 Output Layout Qualifiers
186         // GLSL ES 3.10 section 4.4.2 Output Layout Qualifiers
187         // "The qualifier may appear at most once within a declaration."
188         *errorMessage = "Output layout location specified multiple times.";
189         return true;
190     }
191 
192     return false;
193 }
194 
195 // GLSL ES 3.00_6, 4.7 Order of Qualification
196 // The correct order of qualifiers is:
197 // invariant-qualifier interpolation-qualifier storage-qualifier precision-qualifier
198 // layout-qualifier has to be before storage-qualifier.
AreQualifiersInOrder(const TTypeQualifierBuilder::QualifierSequence & qualifiers,std::string * errorMessage)199 bool AreQualifiersInOrder(const TTypeQualifierBuilder::QualifierSequence &qualifiers,
200                           std::string *errorMessage)
201 {
202     bool foundInterpolation = false;
203     bool foundStorage       = false;
204     bool foundPrecision     = false;
205     for (size_t i = 1; i < qualifiers.size(); ++i)
206     {
207         switch (qualifiers[i]->getType())
208         {
209             case QtInvariant:
210                 if (foundInterpolation || foundStorage || foundPrecision)
211                 {
212                     *errorMessage = "The invariant qualifier has to be first in the expression.";
213                     return false;
214                 }
215                 break;
216             case QtInterpolation:
217                 if (foundStorage)
218                 {
219                     *errorMessage = "Storage qualifiers have to be after interpolation qualifiers.";
220                     return false;
221                 }
222                 else if (foundPrecision)
223                 {
224                     *errorMessage =
225                         "Precision qualifiers have to be after interpolation qualifiers.";
226                     return false;
227                 }
228                 foundInterpolation = true;
229                 break;
230             case QtLayout:
231                 if (foundStorage)
232                 {
233                     *errorMessage = "Storage qualifiers have to be after layout qualifiers.";
234                     return false;
235                 }
236                 else if (foundPrecision)
237                 {
238                     *errorMessage = "Precision qualifiers have to be after layout qualifiers.";
239                     return false;
240                 }
241                 break;
242             case QtStorage:
243                 if (foundPrecision)
244                 {
245                     *errorMessage = "Precision qualifiers have to be after storage qualifiers.";
246                     return false;
247                 }
248                 foundStorage = true;
249                 break;
250             case QtMemory:
251                 if (foundPrecision)
252                 {
253                     *errorMessage = "Precision qualifiers have to be after memory qualifiers.";
254                     return false;
255                 }
256                 break;
257             case QtPrecision:
258                 foundPrecision = true;
259                 break;
260             default:
261                 UNREACHABLE();
262         }
263     }
264     return true;
265 }
266 
267 struct QualifierComparator
268 {
operator ()sh::__anon3549eba60111::QualifierComparator269     bool operator()(const TQualifierWrapperBase *q1, const TQualifierWrapperBase *q2)
270     {
271         return q1->getRank() < q2->getRank();
272     }
273 };
274 
SortSequence(TTypeQualifierBuilder::QualifierSequence & qualifiers)275 void SortSequence(TTypeQualifierBuilder::QualifierSequence &qualifiers)
276 {
277     // We need a stable sorting algorithm since the order of layout-qualifier declarations matter.
278     // The sorting starts from index 1, instead of 0, since the element at index 0 tells the scope
279     // and we always want it to be first.
280     std::stable_sort(qualifiers.begin() + 1, qualifiers.end(), QualifierComparator());
281 }
282 
283 // Handles the joining of storage qualifiers for variables.
JoinVariableStorageQualifier(TQualifier * joinedQualifier,TQualifier storageQualifier)284 bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier)
285 {
286     switch (*joinedQualifier)
287     {
288         case EvqGlobal:
289             *joinedQualifier = storageQualifier;
290             break;
291         case EvqTemporary:
292         {
293             switch (storageQualifier)
294             {
295                 case EvqConst:
296                     *joinedQualifier = storageQualifier;
297                     break;
298                 default:
299                     return false;
300             }
301             break;
302         }
303         case EvqSmooth:
304         {
305             switch (storageQualifier)
306             {
307                 case EvqCentroid:
308                     *joinedQualifier = EvqCentroid;
309                     break;
310                 case EvqVertexOut:
311                 case EvqGeometryOut:
312                     *joinedQualifier = EvqSmoothOut;
313                     break;
314                 case EvqFragmentIn:
315                 case EvqGeometryIn:
316                     *joinedQualifier = EvqSmoothIn;
317                     break;
318                 default:
319                     return false;
320             }
321             break;
322         }
323         case EvqFlat:
324         {
325             switch (storageQualifier)
326             {
327                 case EvqCentroid:
328                     *joinedQualifier = EvqFlat;
329                     break;
330                 case EvqVertexOut:
331                 case EvqGeometryOut:
332                     *joinedQualifier = EvqFlatOut;
333                     break;
334                 case EvqFragmentIn:
335                 case EvqGeometryIn:
336                     *joinedQualifier = EvqFlatIn;
337                     break;
338                 default:
339                     return false;
340             }
341             break;
342         }
343         case EvqCentroid:
344         {
345             switch (storageQualifier)
346             {
347                 case EvqVertexOut:
348                 case EvqGeometryOut:
349                     *joinedQualifier = EvqCentroidOut;
350                     break;
351                 case EvqFragmentIn:
352                 case EvqGeometryIn:
353                     *joinedQualifier = EvqCentroidIn;
354                     break;
355                 default:
356                     return false;
357             }
358             break;
359         }
360         default:
361             return false;
362     }
363     return true;
364 }
365 
366 // Handles the joining of storage qualifiers for a parameter in a function.
JoinParameterStorageQualifier(TQualifier * joinedQualifier,TQualifier storageQualifier)367 bool JoinParameterStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier)
368 {
369     switch (*joinedQualifier)
370     {
371         case EvqTemporary:
372             *joinedQualifier = storageQualifier;
373             break;
374         case EvqConst:
375         {
376             switch (storageQualifier)
377             {
378                 case EvqIn:
379                     *joinedQualifier = EvqConstReadOnly;
380                     break;
381                 default:
382                     return false;
383             }
384             break;
385         }
386         default:
387             return false;
388     }
389     return true;
390 }
391 
JoinMemoryQualifier(TMemoryQualifier * joinedMemoryQualifier,TQualifier memoryQualifier)392 bool JoinMemoryQualifier(TMemoryQualifier *joinedMemoryQualifier, TQualifier memoryQualifier)
393 {
394     switch (memoryQualifier)
395     {
396         case EvqReadOnly:
397             joinedMemoryQualifier->readonly = true;
398             break;
399         case EvqWriteOnly:
400             joinedMemoryQualifier->writeonly = true;
401             break;
402         case EvqCoherent:
403             joinedMemoryQualifier->coherent = true;
404             break;
405         case EvqRestrict:
406             joinedMemoryQualifier->restrictQualifier = true;
407             break;
408         case EvqVolatile:
409             // Variables having the volatile qualifier are automatcally treated as coherent as well.
410             // GLSL ES 3.10, Revision 4, 4.9 Memory Access Qualifiers
411             joinedMemoryQualifier->volatileQualifier = true;
412             joinedMemoryQualifier->coherent          = true;
413             break;
414         default:
415             UNREACHABLE();
416     }
417     return true;
418 }
419 
GetVariableTypeQualifierFromSortedSequence(const TTypeQualifierBuilder::QualifierSequence & sortedSequence,TDiagnostics * diagnostics)420 TTypeQualifier GetVariableTypeQualifierFromSortedSequence(
421     const TTypeQualifierBuilder::QualifierSequence &sortedSequence,
422     TDiagnostics *diagnostics)
423 {
424     TTypeQualifier typeQualifier(
425         static_cast<const TStorageQualifierWrapper *>(sortedSequence[0])->getQualifier(),
426         sortedSequence[0]->getLine());
427     for (size_t i = 1; i < sortedSequence.size(); ++i)
428     {
429         const TQualifierWrapperBase *qualifier = sortedSequence[i];
430         bool isQualifierValid                  = false;
431         switch (qualifier->getType())
432         {
433             case QtInvariant:
434                 isQualifierValid        = true;
435                 typeQualifier.invariant = true;
436                 break;
437             case QtInterpolation:
438             {
439                 switch (typeQualifier.qualifier)
440                 {
441                     case EvqGlobal:
442                         isQualifierValid = true;
443                         typeQualifier.qualifier =
444                             static_cast<const TInterpolationQualifierWrapper *>(qualifier)
445                                 ->getQualifier();
446                         break;
447                     default:
448                         isQualifierValid = false;
449                 }
450                 break;
451             }
452             case QtLayout:
453             {
454                 const TLayoutQualifierWrapper *layoutQualifierWrapper =
455                     static_cast<const TLayoutQualifierWrapper *>(qualifier);
456                 isQualifierValid              = true;
457                 typeQualifier.layoutQualifier = sh::JoinLayoutQualifiers(
458                     typeQualifier.layoutQualifier, layoutQualifierWrapper->getQualifier(),
459                     layoutQualifierWrapper->getLine(), diagnostics);
460                 break;
461             }
462             case QtStorage:
463                 isQualifierValid = JoinVariableStorageQualifier(
464                     &typeQualifier.qualifier,
465                     static_cast<const TStorageQualifierWrapper *>(qualifier)->getQualifier());
466                 break;
467             case QtPrecision:
468                 isQualifierValid = true;
469                 typeQualifier.precision =
470                     static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier();
471                 ASSERT(typeQualifier.precision != EbpUndefined);
472                 break;
473             case QtMemory:
474                 isQualifierValid = JoinMemoryQualifier(
475                     &typeQualifier.memoryQualifier,
476                     static_cast<const TMemoryQualifierWrapper *>(qualifier)->getQualifier());
477                 break;
478             default:
479                 UNREACHABLE();
480         }
481         if (!isQualifierValid)
482         {
483             const TString &qualifierString = qualifier->getQualifierString();
484             diagnostics->error(qualifier->getLine(), "invalid qualifier combination",
485                                qualifierString.c_str());
486             break;
487         }
488     }
489     return typeQualifier;
490 }
491 
GetParameterTypeQualifierFromSortedSequence(const TTypeQualifierBuilder::QualifierSequence & sortedSequence,TDiagnostics * diagnostics)492 TTypeQualifier GetParameterTypeQualifierFromSortedSequence(
493     const TTypeQualifierBuilder::QualifierSequence &sortedSequence,
494     TDiagnostics *diagnostics)
495 {
496     TTypeQualifier typeQualifier(EvqTemporary, sortedSequence[0]->getLine());
497     for (size_t i = 1; i < sortedSequence.size(); ++i)
498     {
499         const TQualifierWrapperBase *qualifier = sortedSequence[i];
500         bool isQualifierValid                  = false;
501         switch (qualifier->getType())
502         {
503             case QtInvariant:
504             case QtInterpolation:
505             case QtLayout:
506                 break;
507             case QtMemory:
508                 isQualifierValid = JoinMemoryQualifier(
509                     &typeQualifier.memoryQualifier,
510                     static_cast<const TMemoryQualifierWrapper *>(qualifier)->getQualifier());
511                 break;
512             case QtStorage:
513                 isQualifierValid = JoinParameterStorageQualifier(
514                     &typeQualifier.qualifier,
515                     static_cast<const TStorageQualifierWrapper *>(qualifier)->getQualifier());
516                 break;
517             case QtPrecision:
518                 isQualifierValid = true;
519                 typeQualifier.precision =
520                     static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier();
521                 ASSERT(typeQualifier.precision != EbpUndefined);
522                 break;
523             default:
524                 UNREACHABLE();
525         }
526         if (!isQualifierValid)
527         {
528             const TString &qualifierString = qualifier->getQualifierString();
529             diagnostics->error(qualifier->getLine(), "invalid parameter qualifier",
530                                qualifierString.c_str());
531             break;
532         }
533     }
534 
535     switch (typeQualifier.qualifier)
536     {
537         case EvqIn:
538         case EvqConstReadOnly:  // const in
539         case EvqOut:
540         case EvqInOut:
541             break;
542         case EvqConst:
543             typeQualifier.qualifier = EvqConstReadOnly;
544             break;
545         case EvqTemporary:
546             // no qualifier has been specified, set it to EvqIn which is the default
547             typeQualifier.qualifier = EvqIn;
548             break;
549         default:
550             diagnostics->error(sortedSequence[0]->getLine(), "Invalid parameter qualifier ",
551                                getQualifierString(typeQualifier.qualifier));
552     }
553     return typeQualifier;
554 }
555 }  // namespace
556 
JoinLayoutQualifiers(TLayoutQualifier leftQualifier,TLayoutQualifier rightQualifier,const TSourceLoc & rightQualifierLocation,TDiagnostics * diagnostics)557 TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier,
558                                       TLayoutQualifier rightQualifier,
559                                       const TSourceLoc &rightQualifierLocation,
560                                       TDiagnostics *diagnostics)
561 {
562     TLayoutQualifier joinedQualifier = leftQualifier;
563 
564     if (rightQualifier.location != -1)
565     {
566         joinedQualifier.location = rightQualifier.location;
567         ++joinedQualifier.locationsSpecified;
568     }
569     if (rightQualifier.yuv != false)
570     {
571         joinedQualifier.yuv = rightQualifier.yuv;
572     }
573     if (rightQualifier.binding != -1)
574     {
575         joinedQualifier.binding = rightQualifier.binding;
576     }
577     if (rightQualifier.offset != -1)
578     {
579         joinedQualifier.offset = rightQualifier.offset;
580     }
581     if (rightQualifier.matrixPacking != EmpUnspecified)
582     {
583         joinedQualifier.matrixPacking = rightQualifier.matrixPacking;
584     }
585     if (rightQualifier.blockStorage != EbsUnspecified)
586     {
587         joinedQualifier.blockStorage = rightQualifier.blockStorage;
588     }
589 
590     for (size_t i = 0u; i < rightQualifier.localSize.size(); ++i)
591     {
592         if (rightQualifier.localSize[i] != -1)
593         {
594             if (joinedQualifier.localSize[i] != -1 &&
595                 joinedQualifier.localSize[i] != rightQualifier.localSize[i])
596             {
597                 diagnostics->error(rightQualifierLocation,
598                                    "Cannot have multiple different work group size specifiers",
599                                    getWorkGroupSizeString(i));
600             }
601             joinedQualifier.localSize[i] = rightQualifier.localSize[i];
602         }
603     }
604 
605     if (rightQualifier.numViews != -1)
606     {
607         joinedQualifier.numViews = rightQualifier.numViews;
608     }
609 
610     if (rightQualifier.imageInternalFormat != EiifUnspecified)
611     {
612         joinedQualifier.imageInternalFormat = rightQualifier.imageInternalFormat;
613     }
614 
615     if (rightQualifier.primitiveType != EptUndefined)
616     {
617         if (joinedQualifier.primitiveType != EptUndefined &&
618             joinedQualifier.primitiveType != rightQualifier.primitiveType)
619         {
620             diagnostics->error(rightQualifierLocation,
621                                "Cannot have multiple different primitive specifiers",
622                                getGeometryShaderPrimitiveTypeString(rightQualifier.primitiveType));
623         }
624         joinedQualifier.primitiveType = rightQualifier.primitiveType;
625     }
626 
627     if (rightQualifier.invocations != 0)
628     {
629         if (joinedQualifier.invocations != 0 &&
630             joinedQualifier.invocations != rightQualifier.invocations)
631         {
632             diagnostics->error(rightQualifierLocation,
633                                "Cannot have multiple different invocations specifiers",
634                                "invocations");
635         }
636         joinedQualifier.invocations = rightQualifier.invocations;
637     }
638 
639     if (rightQualifier.maxVertices != -1)
640     {
641         if (joinedQualifier.maxVertices != -1 &&
642             joinedQualifier.maxVertices != rightQualifier.maxVertices)
643         {
644             diagnostics->error(rightQualifierLocation,
645                                "Cannot have multiple different max_vertices specifiers",
646                                "max_vertices");
647         }
648         joinedQualifier.maxVertices = rightQualifier.maxVertices;
649     }
650 
651     return joinedQualifier;
652 }
653 
getRank() const654 unsigned int TInvariantQualifierWrapper::getRank() const
655 {
656     return 0u;
657 }
658 
getRank() const659 unsigned int TInterpolationQualifierWrapper::getRank() const
660 {
661     return 1u;
662 }
663 
getRank() const664 unsigned int TLayoutQualifierWrapper::getRank() const
665 {
666     return 2u;
667 }
668 
getRank() const669 unsigned int TStorageQualifierWrapper::getRank() const
670 {
671     // Force the 'centroid' auxilary storage qualifier to be always first among all storage
672     // qualifiers.
673     if (mStorageQualifier == EvqCentroid)
674     {
675         return 3u;
676     }
677     else
678     {
679         return 4u;
680     }
681 }
682 
getRank() const683 unsigned int TMemoryQualifierWrapper::getRank() const
684 {
685     return 4u;
686 }
687 
getRank() const688 unsigned int TPrecisionQualifierWrapper::getRank() const
689 {
690     return 5u;
691 }
692 
TTypeQualifier(TQualifier scope,const TSourceLoc & loc)693 TTypeQualifier::TTypeQualifier(TQualifier scope, const TSourceLoc &loc)
694     : layoutQualifier(TLayoutQualifier::Create()),
695       memoryQualifier(TMemoryQualifier::Create()),
696       precision(EbpUndefined),
697       qualifier(scope),
698       invariant(false),
699       line(loc)
700 {
701     ASSERT(IsScopeQualifier(qualifier));
702 }
703 
TTypeQualifierBuilder(const TStorageQualifierWrapper * scope,int shaderVersion)704 TTypeQualifierBuilder::TTypeQualifierBuilder(const TStorageQualifierWrapper *scope,
705                                              int shaderVersion)
706     : mShaderVersion(shaderVersion)
707 {
708     ASSERT(IsScopeQualifier(scope->getQualifier()));
709     mQualifiers.push_back(scope);
710 }
711 
appendQualifier(const TQualifierWrapperBase * qualifier)712 void TTypeQualifierBuilder::appendQualifier(const TQualifierWrapperBase *qualifier)
713 {
714     mQualifiers.push_back(qualifier);
715 }
716 
checkSequenceIsValid(TDiagnostics * diagnostics) const717 bool TTypeQualifierBuilder::checkSequenceIsValid(TDiagnostics *diagnostics) const
718 {
719     bool areQualifierChecksRelaxed = AreTypeQualifierChecksRelaxed(mShaderVersion);
720     std::string errorMessage;
721     if (HasRepeatingQualifiers(mQualifiers, areQualifierChecksRelaxed, &errorMessage))
722     {
723         diagnostics->error(mQualifiers[0]->getLine(), errorMessage.c_str(), "qualifier sequence");
724         return false;
725     }
726 
727     if (!areQualifierChecksRelaxed && !AreQualifiersInOrder(mQualifiers, &errorMessage))
728     {
729         diagnostics->error(mQualifiers[0]->getLine(), errorMessage.c_str(), "qualifier sequence");
730         return false;
731     }
732 
733     return true;
734 }
735 
getParameterTypeQualifier(TDiagnostics * diagnostics) const736 TTypeQualifier TTypeQualifierBuilder::getParameterTypeQualifier(TDiagnostics *diagnostics) const
737 {
738     ASSERT(IsInvariantCorrect(mQualifiers));
739     ASSERT(static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier() ==
740            EvqTemporary);
741 
742     if (!checkSequenceIsValid(diagnostics))
743     {
744         return TTypeQualifier(EvqTemporary, mQualifiers[0]->getLine());
745     }
746 
747     // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so
748     // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to
749     // combine the qualifiers.
750     if (AreTypeQualifierChecksRelaxed(mShaderVersion))
751     {
752         // Copy the qualifier sequence so that we can sort them.
753         QualifierSequence sortedQualifierSequence = mQualifiers;
754         SortSequence(sortedQualifierSequence);
755         return GetParameterTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics);
756     }
757     return GetParameterTypeQualifierFromSortedSequence(mQualifiers, diagnostics);
758 }
759 
getVariableTypeQualifier(TDiagnostics * diagnostics) const760 TTypeQualifier TTypeQualifierBuilder::getVariableTypeQualifier(TDiagnostics *diagnostics) const
761 {
762     ASSERT(IsInvariantCorrect(mQualifiers));
763 
764     if (!checkSequenceIsValid(diagnostics))
765     {
766         return TTypeQualifier(
767             static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier(),
768             mQualifiers[0]->getLine());
769     }
770 
771     // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so
772     // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to
773     // combine the qualifiers.
774     if (AreTypeQualifierChecksRelaxed(mShaderVersion))
775     {
776         // Copy the qualifier sequence so that we can sort them.
777         QualifierSequence sortedQualifierSequence = mQualifiers;
778         SortSequence(sortedQualifierSequence);
779         return GetVariableTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics);
780     }
781     return GetVariableTypeQualifierFromSortedSequence(mQualifiers, diagnostics);
782 }
783 
784 }  // namespace sh
785