Bug Summary

File:root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp
Warning:line 415, column 13
Value stored to 'visit' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name IntermTraverse.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +sse2 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/angle/targets/translator -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/angle/targets/translator -resource-dir /usr/lib/llvm-21/lib/clang/21 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D _GLIBCXX_ASSERTIONS -D DEBUG=1 -D ANGLE_PLATFORM_EXPORT= -D __NDK_FPABI__= -D ANGLE_SKIP_DXGI_1_2_CHECK -D ANGLE_ENABLE_KEYEDMUTEX -D ANGLE_TRANSLATOR_ESSL_ONLY -D ANGLE_DISABLE_POOL_ALLOC -D ANGLE_ENABLE_APPLE_WORKAROUNDS -D ANGLE_ENABLE_ESSL -D ANGLE_ENABLE_GLSL -D ANGLE_ENABLE_HLSL -D ANGLE_ENABLE_SHARE_CONTEXT_LOCK=1 -D ANGLE_VMA_VERSION=2003000 -D CR_CLANG_REVISION="llvmorg-16-init-6578-g0d30e92f-2" -D DYNAMIC_ANNOTATIONS_ENABLED=0 -D NOMINMAX -D UNICODE -D WINVER=0x0A00 -D _ATL_NO_OPENGL -D _CRT_NONSTDC_NO_WARNINGS -D _CRT_RAND_S -D _CRT_SECURE_NO_DEPRECATE -D _HAS_EXCEPTIONS=0 -D _SCL_SECURE_NO_DEPRECATE -D _SECURE_ATL -D _UNICODE -D _WINSOCK_DEPRECATED_NO_WARNINGS -I /root/firefox-clang/gfx/angle/targets/translator -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/angle/targets/translator -I /root/firefox-clang/gfx/angle/checkout/include -I /root/firefox-clang/gfx/angle/checkout/src -I /root/firefox-clang/gfx/angle/checkout/src/common/third_party/base -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-final-dtor-non-final-class -Wno-implicit-const-int-float-conversion -Wno-range-loop-construct -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2025-06-27-100320-3286336-1 -x c++ /root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp
1//
2// Copyright 2002 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/tree_util/IntermTraverse.h"
8
9#include "compiler/translator/Compiler.h"
10#include "compiler/translator/InfoSink.h"
11#include "compiler/translator/SymbolTable.h"
12#include "compiler/translator/tree_util/IntermNode_util.h"
13#include "compiler/translator/util.h"
14
15namespace sh
16{
17
18// Traverse the intermediate representation tree, and call a node type specific visit function for
19// each node. Traversal is done recursively through the node member function traverse(). Nodes with
20// children can have their whole subtree skipped if preVisit is turned on and the type specific
21// function returns false.
22template <typename T>
23void TIntermTraverser::traverse(T *node)
24{
25 ScopedNodeInTraversalPath addToPath(this, node);
26 if (!addToPath.isWithinDepthLimit())
27 return;
28
29 bool visit = true;
30
31 // Visit the node before children if pre-visiting.
32 if (preVisit)
33 visit = node->visit(PreVisit, this);
34
35 if (visit)
36 {
37 size_t childIndex = 0;
38 size_t childCount = node->getChildCount();
39
40 while (childIndex < childCount && visit)
41 {
42 mCurrentChildIndex = childIndex;
43 node->getChildNode(childIndex)->traverse(this);
44 mCurrentChildIndex = childIndex;
45
46 if (inVisit && childIndex != childCount - 1)
47 {
48 visit = node->visit(InVisit, this);
49 }
50 ++childIndex;
51 }
52
53 if (visit && postVisit)
54 node->visit(PostVisit, this);
55 }
56}
57
58// Instantiate template for RewriteAtomicFunctionExpressions, in case this gets inlined thus not
59// exported from the TU.
60template void TIntermTraverser::traverse(TIntermNode *);
61
62void TIntermNode::traverse(TIntermTraverser *it)
63{
64 it->traverse(this);
65}
66
67void TIntermSymbol::traverse(TIntermTraverser *it)
68{
69 TIntermTraverser::ScopedNodeInTraversalPath addToPath(it, this);
70 it->visitSymbol(this);
71}
72
73void TIntermConstantUnion::traverse(TIntermTraverser *it)
74{
75 TIntermTraverser::ScopedNodeInTraversalPath addToPath(it, this);
76 it->visitConstantUnion(this);
77}
78
79void TIntermFunctionPrototype::traverse(TIntermTraverser *it)
80{
81 TIntermTraverser::ScopedNodeInTraversalPath addToPath(it, this);
82 it->visitFunctionPrototype(this);
83}
84
85void TIntermBinary::traverse(TIntermTraverser *it)
86{
87 it->traverseBinary(this);
88}
89
90void TIntermUnary::traverse(TIntermTraverser *it)
91{
92 it->traverseUnary(this);
93}
94
95void TIntermFunctionDefinition::traverse(TIntermTraverser *it)
96{
97 it->traverseFunctionDefinition(this);
98}
99
100void TIntermBlock::traverse(TIntermTraverser *it)
101{
102 it->traverseBlock(this);
103}
104
105void TIntermAggregate::traverse(TIntermTraverser *it)
106{
107 it->traverseAggregate(this);
108}
109
110void TIntermLoop::traverse(TIntermTraverser *it)
111{
112 it->traverseLoop(this);
113}
114
115void TIntermPreprocessorDirective::traverse(TIntermTraverser *it)
116{
117 it->visitPreprocessorDirective(this);
118}
119
120bool TIntermSymbol::visit(Visit visit, TIntermTraverser *it)
121{
122 it->visitSymbol(this);
123 return false;
124}
125
126bool TIntermConstantUnion::visit(Visit visit, TIntermTraverser *it)
127{
128 it->visitConstantUnion(this);
129 return false;
130}
131
132bool TIntermFunctionPrototype::visit(Visit visit, TIntermTraverser *it)
133{
134 it->visitFunctionPrototype(this);
135 return false;
136}
137
138bool TIntermFunctionDefinition::visit(Visit visit, TIntermTraverser *it)
139{
140 return it->visitFunctionDefinition(visit, this);
141}
142
143bool TIntermUnary::visit(Visit visit, TIntermTraverser *it)
144{
145 return it->visitUnary(visit, this);
146}
147
148bool TIntermSwizzle::visit(Visit visit, TIntermTraverser *it)
149{
150 return it->visitSwizzle(visit, this);
151}
152
153bool TIntermBinary::visit(Visit visit, TIntermTraverser *it)
154{
155 return it->visitBinary(visit, this);
156}
157
158bool TIntermTernary::visit(Visit visit, TIntermTraverser *it)
159{
160 return it->visitTernary(visit, this);
161}
162
163bool TIntermAggregate::visit(Visit visit, TIntermTraverser *it)
164{
165 return it->visitAggregate(visit, this);
166}
167
168bool TIntermDeclaration::visit(Visit visit, TIntermTraverser *it)
169{
170 return it->visitDeclaration(visit, this);
171}
172
173bool TIntermGlobalQualifierDeclaration::visit(Visit visit, TIntermTraverser *it)
174{
175 return it->visitGlobalQualifierDeclaration(visit, this);
176}
177
178bool TIntermBlock::visit(Visit visit, TIntermTraverser *it)
179{
180 return it->visitBlock(visit, this);
181}
182
183bool TIntermIfElse::visit(Visit visit, TIntermTraverser *it)
184{
185 return it->visitIfElse(visit, this);
186}
187
188bool TIntermLoop::visit(Visit visit, TIntermTraverser *it)
189{
190 return it->visitLoop(visit, this);
191}
192
193bool TIntermBranch::visit(Visit visit, TIntermTraverser *it)
194{
195 return it->visitBranch(visit, this);
196}
197
198bool TIntermSwitch::visit(Visit visit, TIntermTraverser *it)
199{
200 return it->visitSwitch(visit, this);
201}
202
203bool TIntermCase::visit(Visit visit, TIntermTraverser *it)
204{
205 return it->visitCase(visit, this);
206}
207
208bool TIntermPreprocessorDirective::visit(Visit visit, TIntermTraverser *it)
209{
210 it->visitPreprocessorDirective(this);
211 return false;
212}
213
214TIntermTraverser::TIntermTraverser(bool preVisit,
215 bool inVisit,
216 bool postVisit,
217 TSymbolTable *symbolTable)
218 : preVisit(preVisit),
219 inVisit(inVisit),
220 postVisit(postVisit),
221 mMaxDepth(0),
222 mMaxAllowedDepth(std::numeric_limits<int>::max()),
223 mInGlobalScope(true),
224 mSymbolTable(symbolTable),
225 mCurrentChildIndex(0)
226{
227 // Only enabling inVisit is not supported.
228 ASSERT(!(inVisit && !preVisit && !postVisit))(!(inVisit && !preVisit && !postVisit) ? static_cast
<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage
(::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv
::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 228, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 228 << "): " << "!(inVisit && !preVisit && !postVisit)"
))
;
229}
230
231TIntermTraverser::~TIntermTraverser() {}
232
233void TIntermTraverser::setMaxAllowedDepth(int depth)
234{
235 mMaxAllowedDepth = depth;
236}
237
238const TIntermBlock *TIntermTraverser::getParentBlock() const
239{
240 if (!mParentBlockStack.empty())
241 {
242 return mParentBlockStack.back().node;
243 }
244 return nullptr;
245}
246
247void TIntermTraverser::pushParentBlock(TIntermBlock *node)
248{
249 mParentBlockStack.push_back(ParentBlock(node, 0));
250}
251
252void TIntermTraverser::incrementParentBlockPos()
253{
254 ++mParentBlockStack.back().pos;
255}
256
257void TIntermTraverser::popParentBlock()
258{
259 ASSERT(!mParentBlockStack.empty())(!mParentBlockStack.empty() ? static_cast<void>(0) : (!
((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL)
)) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify
() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 259, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 259 << "): " << "!mParentBlockStack.empty()"
))
;
260 mParentBlockStack.pop_back();
261}
262
263void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertions)
264{
265 TIntermSequence emptyInsertionsAfter;
266 insertStatementsInParentBlock(insertions, emptyInsertionsAfter);
267}
268
269void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertionsBefore,
270 const TIntermSequence &insertionsAfter)
271{
272 ASSERT(!mParentBlockStack.empty())(!mParentBlockStack.empty() ? static_cast<void>(0) : (!
((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL)
)) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify
() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 272, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 272 << "): " << "!mParentBlockStack.empty()"
))
;
273 ParentBlock &parentBlock = mParentBlockStack.back();
274 if (mPath.back() == parentBlock.node)
275 {
276 ASSERT(mParentBlockStack.size() >= 2u)(mParentBlockStack.size() >= 2u ? static_cast<void>(
0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL
))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify
() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 276, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 276 << "): " << "mParentBlockStack.size() >= 2u"
))
;
277 // The current node is a block node, so the parent block is not the topmost one in the block
278 // stack, but the one below that.
279 parentBlock = mParentBlockStack.at(mParentBlockStack.size() - 2u);
280 }
281 NodeInsertMultipleEntry insert(parentBlock.node, parentBlock.pos, insertionsBefore,
282 insertionsAfter);
283 mInsertions.push_back(insert);
284}
285
286void TIntermTraverser::insertStatementInParentBlock(TIntermNode *statement)
287{
288 TIntermSequence insertions;
289 insertions.push_back(statement);
290 insertStatementsInParentBlock(insertions);
291}
292
293void TIntermTraverser::insertStatementsInBlockAtPosition(TIntermBlock *parent,
294 size_t position,
295 const TIntermSequence &insertionsBefore,
296 const TIntermSequence &insertionsAfter)
297{
298 ASSERT(parent)(parent ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage
(::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv
::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 298, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 298 << "): " << "parent"))
;
299 ASSERT(position >= 0)(position >= 0 ? static_cast<void>(0) : (!((::gl::priv
::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast
<void>(0) : ::gl::priv::LogMessageVoidify() & (::gl
::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 299, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 299 << "): " << "position >= 0"
))
;
300 ASSERT(position < parent->getChildCount())(position < parent->getChildCount() ? static_cast<void
>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl
::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify
() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 300, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 300 << "): " << "position < parent->getChildCount()"
))
;
301
302 mInsertions.emplace_back(parent, position, insertionsBefore, insertionsAfter);
303}
304
305void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter)
306{
307 mInFunctionCallOutParameter = inOutParameter;
308}
309
310bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const
311{
312 return mInFunctionCallOutParameter;
313}
314
315void TIntermTraverser::traverseBinary(TIntermBinary *node)
316{
317 traverse(node);
318}
319
320void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node)
321{
322 ScopedNodeInTraversalPath addToPath(this, node);
323 if (!addToPath.isWithinDepthLimit())
324 return;
325
326 bool visit = true;
327
328 // visit the node before children if pre-visiting.
329 if (preVisit)
330 visit = node->visit(PreVisit, this);
331
332 // Visit the children, in the right order.
333 if (visit)
334 {
335 if (node->isAssignment())
336 {
337 ASSERT(!isLValueRequiredHere())(!isLValueRequiredHere() ? static_cast<void>(0) : (!((::
gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ?
static_cast<void>(0) : ::gl::priv::LogMessageVoidify()
& (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 337, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 337 << "): " << "!isLValueRequiredHere()"
))
;
338 setOperatorRequiresLValue(true);
339 }
340
341 node->getLeft()->traverse(this);
342
343 if (node->isAssignment())
344 setOperatorRequiresLValue(false);
345
346 if (inVisit)
347 visit = node->visit(InVisit, this);
348
349 if (visit)
350 {
351 // Some binary operations like indexing can be inside an expression which must be an
352 // l-value.
353 bool parentOperatorRequiresLValue = operatorRequiresLValue();
354 bool parentInFunctionCallOutParameter = isInFunctionCallOutParameter();
355
356 // Index is not required to be an l-value even when the surrounding expression is
357 // required to be an l-value.
358 TOperator op = node->getOp();
359 if (op == EOpIndexDirect || op == EOpIndexDirectInterfaceBlock ||
360 op == EOpIndexDirectStruct || op == EOpIndexIndirect)
361 {
362 setOperatorRequiresLValue(false);
363 setInFunctionCallOutParameter(false);
364 }
365
366 node->getRight()->traverse(this);
367
368 setOperatorRequiresLValue(parentOperatorRequiresLValue);
369 setInFunctionCallOutParameter(parentInFunctionCallOutParameter);
370
371 // Visit the node after the children, if requested and the traversal
372 // hasn't been cancelled yet.
373 if (postVisit)
374 visit = node->visit(PostVisit, this);
375 }
376 }
377}
378
379void TIntermTraverser::traverseUnary(TIntermUnary *node)
380{
381 traverse(node);
382}
383
384void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node)
385{
386 ScopedNodeInTraversalPath addToPath(this, node);
387 if (!addToPath.isWithinDepthLimit())
388 return;
389
390 bool visit = true;
391
392 if (preVisit)
393 visit = node->visit(PreVisit, this);
394
395 if (visit)
396 {
397 ASSERT(!operatorRequiresLValue())(!operatorRequiresLValue() ? static_cast<void>(0) : (!(
(::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))
) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify
() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 397, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 397 << "): " << "!operatorRequiresLValue()"
))
;
398 switch (node->getOp())
399 {
400 case EOpPostIncrement:
401 case EOpPostDecrement:
402 case EOpPreIncrement:
403 case EOpPreDecrement:
404 setOperatorRequiresLValue(true);
405 break;
406 default:
407 break;
408 }
409
410 node->getOperand()->traverse(this);
411
412 setOperatorRequiresLValue(false);
413
414 if (postVisit)
415 visit = node->visit(PostVisit, this);
Value stored to 'visit' is never read
416 }
417}
418
419// Traverse a function definition node. This keeps track of global scope.
420void TIntermTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node)
421{
422 ScopedNodeInTraversalPath addToPath(this, node);
423 if (!addToPath.isWithinDepthLimit())
424 return;
425
426 bool visit = true;
427
428 if (preVisit)
429 visit = node->visit(PreVisit, this);
430
431 if (visit)
432 {
433 mCurrentChildIndex = 0;
434 node->getFunctionPrototype()->traverse(this);
435 mCurrentChildIndex = 0;
436
437 if (inVisit)
438 visit = node->visit(InVisit, this);
439 if (visit)
440 {
441 mInGlobalScope = false;
442 mCurrentChildIndex = 1;
443 node->getBody()->traverse(this);
444 mCurrentChildIndex = 1;
445 mInGlobalScope = true;
446 if (postVisit)
447 visit = node->visit(PostVisit, this);
448 }
449 }
450}
451
452// Traverse a block node. This keeps track of the position of traversed child nodes within the block
453// so that nodes may be inserted before or after them.
454void TIntermTraverser::traverseBlock(TIntermBlock *node)
455{
456 ScopedNodeInTraversalPath addToPath(this, node);
457 if (!addToPath.isWithinDepthLimit())
458 return;
459
460 pushParentBlock(node);
461
462 bool visit = true;
463
464 TIntermSequence *sequence = node->getSequence();
465
466 if (preVisit)
467 visit = node->visit(PreVisit, this);
468
469 if (visit)
470 {
471 for (size_t childIndex = 0; childIndex < sequence->size(); ++childIndex)
472 {
473 TIntermNode *child = (*sequence)[childIndex];
474 if (visit)
475 {
476 mCurrentChildIndex = childIndex;
477 child->traverse(this);
478 mCurrentChildIndex = childIndex;
479
480 if (inVisit)
481 {
482 if (child != sequence->back())
483 visit = node->visit(InVisit, this);
484 }
485
486 incrementParentBlockPos();
487 }
488 }
489
490 if (visit && postVisit)
491 visit = node->visit(PostVisit, this);
492 }
493
494 popParentBlock();
495}
496
497void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
498{
499 traverse(node);
500}
501
502bool TIntermTraverser::CompareInsertion(const NodeInsertMultipleEntry &a,
503 const NodeInsertMultipleEntry &b)
504{
505 if (a.parent != b.parent)
506 {
507 return a.parent < b.parent;
508 }
509 return a.position < b.position;
510}
511
512bool TIntermTraverser::updateTree(TCompiler *compiler, TIntermNode *node)
513{
514 // Sort the insertions so that insertion position is increasing and same position insertions are
515 // not reordered. The insertions are processed in reverse order so that multiple insertions to
516 // the same parent node are handled correctly.
517 std::stable_sort(mInsertions.begin(), mInsertions.end(), CompareInsertion);
518 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
519 {
520 // If two insertions are to the same position, insert them in the order they were specified.
521 // The std::stable_sort call above will automatically guarantee this.
522 const NodeInsertMultipleEntry &insertion = mInsertions[mInsertions.size() - ii - 1];
523 ASSERT(insertion.parent)(insertion.parent ? static_cast<void>(0) : (!((::gl::priv
::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast
<void>(0) : ::gl::priv::LogMessageVoidify() & (::gl
::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 523, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 523 << "): " << "insertion.parent"
))
;
524 if (!insertion.insertionsAfter.empty())
525 {
526 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
527 insertion.insertionsAfter);
528 ASSERT(inserted)(inserted ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage
(::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv
::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 528, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 528 << "): " << "inserted"
))
;
529 }
530 if (!insertion.insertionsBefore.empty())
531 {
532 bool inserted =
533 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
534 ASSERT(inserted)(inserted ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage
(::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv
::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 534, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 534 << "): " << "inserted"
))
;
535 }
536 }
537 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
538 {
539 const NodeUpdateEntry &replacement = mReplacements[ii];
540 ASSERT(replacement.parent)(replacement.parent ? static_cast<void>(0) : (!((::gl::
priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast
<void>(0) : ::gl::priv::LogMessageVoidify() & (::gl
::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 540, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 540 << "): " << "replacement.parent"
))
;
541 bool replaced =
542 replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
543 ASSERT(replaced)(replaced ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage
(::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv
::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 543, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 543 << "): " << "replaced"
))
;
544
545 // Make sure the precision is not accidentally dropped. It's ok if the precision is not the
546 // same, as the transformations are allowed to replace an expression with one that is
547 // temporarily evaluated at a different (likely higher) precision.
548 TIntermTyped *originalAsTyped = replacement.original->getAsTyped();
549 TIntermTyped *replacementAsTyped =
550 replacement.replacement ? replacement.replacement->getAsTyped() : nullptr;
551 if (originalAsTyped != nullptr && replacementAsTyped != nullptr)
552 {
553 const TType &originalType = originalAsTyped->getType();
554 const TType &replacementType = replacementAsTyped->getType();
555 ASSERT(!IsPrecisionApplicableToType(originalType.getBasicType()) ||(!IsPrecisionApplicableToType(originalType.getBasicType()) ||
!IsPrecisionApplicableToType(replacementType.getBasicType())
|| originalType.getPrecision() == EbpUndefined || replacementType
.getPrecision() != EbpUndefined ? static_cast<void>(0) :
(!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL
))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify
() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 558, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 558 << "): " << "!IsPrecisionApplicableToType(originalType.getBasicType()) || !IsPrecisionApplicableToType(replacementType.getBasicType()) || originalType.getPrecision() == EbpUndefined || replacementType.getPrecision() != EbpUndefined"
))
556 !IsPrecisionApplicableToType(replacementType.getBasicType()) ||(!IsPrecisionApplicableToType(originalType.getBasicType()) ||
!IsPrecisionApplicableToType(replacementType.getBasicType())
|| originalType.getPrecision() == EbpUndefined || replacementType
.getPrecision() != EbpUndefined ? static_cast<void>(0) :
(!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL
))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify
() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 558, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 558 << "): " << "!IsPrecisionApplicableToType(originalType.getBasicType()) || !IsPrecisionApplicableToType(replacementType.getBasicType()) || originalType.getPrecision() == EbpUndefined || replacementType.getPrecision() != EbpUndefined"
))
557 originalType.getPrecision() == EbpUndefined ||(!IsPrecisionApplicableToType(originalType.getBasicType()) ||
!IsPrecisionApplicableToType(replacementType.getBasicType())
|| originalType.getPrecision() == EbpUndefined || replacementType
.getPrecision() != EbpUndefined ? static_cast<void>(0) :
(!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL
))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify
() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 558, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 558 << "): " << "!IsPrecisionApplicableToType(originalType.getBasicType()) || !IsPrecisionApplicableToType(replacementType.getBasicType()) || originalType.getPrecision() == EbpUndefined || replacementType.getPrecision() != EbpUndefined"
))
558 replacementType.getPrecision() != EbpUndefined)(!IsPrecisionApplicableToType(originalType.getBasicType()) ||
!IsPrecisionApplicableToType(replacementType.getBasicType())
|| originalType.getPrecision() == EbpUndefined || replacementType
.getPrecision() != EbpUndefined ? static_cast<void>(0) :
(!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL
))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify
() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 558, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 558 << "): " << "!IsPrecisionApplicableToType(originalType.getBasicType()) || !IsPrecisionApplicableToType(replacementType.getBasicType()) || originalType.getPrecision() == EbpUndefined || replacementType.getPrecision() != EbpUndefined"
))
;
559 }
560
561 if (!replacement.originalBecomesChildOfReplacement)
562 {
563 // In AST traversing, a parent is visited before its children.
564 // After we replace a node, if its immediate child is to
565 // be replaced, we need to make sure we don't update the replaced
566 // node; instead, we update the replacement node.
567 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
568 {
569 NodeUpdateEntry &replacement2 = mReplacements[jj];
570 if (replacement2.parent == replacement.original)
571 replacement2.parent = replacement.replacement;
572 }
573 }
574 }
575 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
576 {
577 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
578 ASSERT(replacement.parent)(replacement.parent ? static_cast<void>(0) : (!((::gl::
priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast
<void>(0) : ::gl::priv::LogMessageVoidify() & (::gl
::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 578, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 578 << "): " << "replacement.parent"
))
;
579 bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
580 replacement.replacements);
581 ASSERT(replaced)(replaced ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage
(::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv
::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 581, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 581 << "): " << "replaced"
))
;
582 }
583
584 clearReplacementQueue();
585
586 return compiler->validateAST(node);
587}
588
589void TIntermTraverser::clearReplacementQueue()
590{
591 mReplacements.clear();
592 mMultiReplacements.clear();
593 mInsertions.clear();
594}
595
596void TIntermTraverser::queueReplacement(TIntermNode *replacement, OriginalNode originalStatus)
597{
598 queueReplacementWithParent(getParentNode(), mPath.back(), replacement, originalStatus);
599}
600
601void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
602 TIntermNode *original,
603 TIntermNode *replacement,
604 OriginalNode originalStatus)
605{
606 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
607 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
608}
609
610void TIntermTraverser::queueAccessChainReplacement(TIntermTyped *replacement)
611{
612 uint32_t ancestorIndex = 0;
613 TIntermTyped *toReplace = nullptr;
614 while (true)
615 {
616 TIntermNode *ancestor = getAncestorNode(ancestorIndex);
617 ASSERT(ancestor != nullptr)(ancestor != nullptr ? static_cast<void>(0) : (!((::gl::
priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast
<void>(0) : ::gl::priv::LogMessageVoidify() & (::gl
::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 617, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 617 << "): " << "ancestor != nullptr"
))
;
618
619 TIntermBinary *asBinary = ancestor->getAsBinaryNode();
620 if (asBinary == nullptr ||
621 (asBinary->getOp() != EOpIndexDirect && asBinary->getOp() != EOpIndexIndirect))
622 {
623 break;
624 }
625
626 replacement = new TIntermBinary(asBinary->getOp(), replacement, asBinary->getRight());
627 toReplace = asBinary;
628
629 ++ancestorIndex;
630 }
631
632 if (toReplace == nullptr)
633 {
634 queueReplacement(replacement, OriginalNode::IS_DROPPED);
635 }
636 else
637 {
638 queueReplacementWithParent(getAncestorNode(ancestorIndex), toReplace, replacement,
639 OriginalNode::IS_DROPPED);
640 }
641}
642
643TLValueTrackingTraverser::TLValueTrackingTraverser(bool preVisitIn,
644 bool inVisitIn,
645 bool postVisitIn,
646 TSymbolTable *symbolTable)
647 : TIntermTraverser(preVisitIn, inVisitIn, postVisitIn, symbolTable),
648 mOperatorRequiresLValue(false),
649 mInFunctionCallOutParameter(false)
650{
651 ASSERT(symbolTable)(symbolTable ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage
(::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv
::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 651, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 651 << "): " << "symbolTable"
))
;
652}
653
654void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
655{
656 ScopedNodeInTraversalPath addToPath(this, node);
657 if (!addToPath.isWithinDepthLimit())
658 return;
659
660 bool visit = true;
661
662 TIntermSequence *sequence = node->getSequence();
663
664 if (preVisit)
665 visit = node->visit(PreVisit, this);
666
667 if (visit)
668 {
669 size_t paramIndex = 0u;
670 for (auto *child : *sequence)
671 {
672 if (visit)
673 {
674 if (node->getFunction())
675 {
676 // Both built-ins and user defined functions should have the function symbol
677 // set.
678 ASSERT(paramIndex < node->getFunction()->getParamCount())(paramIndex < node->getFunction()->getParamCount() ?
static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage
(::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv
::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 678, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 678 << "): " << "paramIndex < node->getFunction()->getParamCount()"
))
;
679 TQualifier qualifier =
680 node->getFunction()->getParam(paramIndex)->getType().getQualifier();
681 setInFunctionCallOutParameter(qualifier == EvqParamOut ||
682 qualifier == EvqParamInOut);
683 ++paramIndex;
684 }
685 else
686 {
687 ASSERT(node->isConstructor())(node->isConstructor() ? static_cast<void>(0) : (!((
::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL)))
? static_cast<void>(0) : ::gl::priv::LogMessageVoidify
() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
, __FUNCTION__, 687, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp"
<< ":" << 687 << "): " << "node->isConstructor()"
))
;
688 }
689 child->traverse(this);
690 if (inVisit)
691 {
692 if (child != sequence->back())
693 visit = node->visit(InVisit, this);
694 }
695 }
696 }
697 setInFunctionCallOutParameter(false);
698
699 if (visit && postVisit)
700 visit = node->visit(PostVisit, this);
701 }
702}
703
704void TIntermTraverser::traverseLoop(TIntermLoop *node)
705{
706 traverse(node);
707}
708} // namespace sh