Coverage Report

Created: 2026-01-09 07:38

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