Hash :
474a08c0
Author :
Date :
2016-06-28T10:49:46
Remove qualifiers from empty struct declarations in output
Empty struct declarations with qualifiers are rejected by NVIDIA GL
driver version 367.27. For example this kind of construct that is
expected to be accepted by the WebGL conformance tests is rejected:
const struct a {
int i;
};
Since qualifiers do not carry meaning unless a struct declaration
has declarators, they can be simply omitted from the translator
output in this kind of cases to work around this driver issue.
New unit test is added to check that pruning empty declarations works
correctly.
BUG=angleproject:1430
BUG=622492
TEST=WebGL conformance tests, angle_unittests
Change-Id: Id83f83124ae597fcdfa15100d336c2c207d9449c
Reviewed-on: https://chromium-review.googlesource.com/356362
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
//
// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// The PruneEmptyDeclarations function prunes unnecessary empty declarations and declarators from the AST.
#include "compiler/translator/PruneEmptyDeclarations.h"
#include "compiler/translator/IntermNode.h"
namespace
{
class PruneEmptyDeclarationsTraverser : private TIntermTraverser
{
public:
static void apply(TIntermNode *root);
private:
PruneEmptyDeclarationsTraverser();
bool visitAggregate(Visit, TIntermAggregate *node) override;
};
void PruneEmptyDeclarationsTraverser::apply(TIntermNode *root)
{
PruneEmptyDeclarationsTraverser prune;
root->traverse(&prune);
prune.updateTree();
}
PruneEmptyDeclarationsTraverser::PruneEmptyDeclarationsTraverser()
: TIntermTraverser(true, false, false)
{
}
bool PruneEmptyDeclarationsTraverser::visitAggregate(Visit, TIntermAggregate *node)
{
if (node->getOp() == EOpDeclaration)
{
TIntermSequence *sequence = node->getSequence();
if (sequence->size() >= 1)
{
TIntermSymbol *sym = sequence->front()->getAsSymbolNode();
// Prune declarations without a variable name, unless it's an interface block declaration.
if (sym != nullptr && sym->getSymbol() == "" && !sym->isInterfaceBlock())
{
if (sequence->size() > 1)
{
// Generate a replacement that will remove the empty declarator in the beginning of a declarator
// list. Example of a declaration that will be changed:
// float, a;
// will be changed to
// float a;
// This applies also to struct declarations.
TIntermSequence emptyReplacement;
mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(node, sym, emptyReplacement));
}
else if (sym->getBasicType() != EbtStruct)
{
// Single struct declarations may just declare the struct type and no variables, so they should
// not be pruned. All other single empty declarations can be pruned entirely. Example of an empty
// declaration that will be pruned:
// float;
TIntermSequence emptyReplacement;
TIntermAggregate *parentAgg = getParentNode()->getAsAggregate();
ASSERT(parentAgg != nullptr);
mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentAgg, node, emptyReplacement));
}
else if (sym->getType().getQualifier() != EvqGlobal &&
sym->getType().getQualifier() != EvqTemporary)
{
// We've hit an empty struct declaration with a qualifier, for example like
// this:
// const struct a { int i; };
// NVIDIA GL driver version 367.27 doesn't accept this kind of declarations, so
// we convert the declaration to a regular struct declaration. This is okay,
// since ESSL 1.00 spec section 4.1.8 says about structs that "The optional
// qualifiers only apply to any declarators, and are not part of the type being
// defined for name."
if (mInGlobalScope)
{
sym->getTypePointer()->setQualifier(EvqGlobal);
}
else
{
sym->getTypePointer()->setQualifier(EvqTemporary);
}
}
}
}
return false;
}
return true;
}
} // namespace
void PruneEmptyDeclarations(TIntermNode *root)
{
PruneEmptyDeclarationsTraverser::apply(root);
}