Allow 'defined' in define in non-WebGL.
This is needed to pass dEQP conformance. Several of the harder dEQP
tests around this behaviour are excluded from the mustpass list. This
is presumably because the behaviours weren't implemented portably.
Nevertheless we need to support conformant behaviour for GLES 2.0
Contexts for the most simple uses.
This also leaves the error behaviour intact for WebGL specs.
Bug: angleproject:1335
Change-Id: Ia80b4f71475efa928488ee6c2ee35c566d4602d4
Reviewed-on: https://chromium-review.googlesource.com/c/1242013
Reviewed-by: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/preprocessor/DirectiveParser.cpp b/src/compiler/preprocessor/DirectiveParser.cpp
index 0731a41..739cbd4 100644
--- a/src/compiler/preprocessor/DirectiveParser.cpp
+++ b/src/compiler/preprocessor/DirectiveParser.cpp
@@ -141,72 +141,11 @@
namespace pp
{
-
-class DefinedParser : public Lexer
-{
- public:
- DefinedParser(Lexer *lexer, const MacroSet *macroSet, Diagnostics *diagnostics)
- : mLexer(lexer), mMacroSet(macroSet), mDiagnostics(diagnostics)
- {
- }
-
- protected:
- void lex(Token *token) override
- {
- const char kDefined[] = "defined";
-
- mLexer->lex(token);
- if (token->type != Token::IDENTIFIER)
- return;
- if (token->text != kDefined)
- return;
-
- bool paren = false;
- mLexer->lex(token);
- if (token->type == '(')
- {
- paren = true;
- mLexer->lex(token);
- }
-
- if (token->type != Token::IDENTIFIER)
- {
- mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
- skipUntilEOD(mLexer, token);
- return;
- }
- MacroSet::const_iterator iter = mMacroSet->find(token->text);
- std::string expression = iter != mMacroSet->end() ? "1" : "0";
-
- if (paren)
- {
- mLexer->lex(token);
- if (token->type != ')')
- {
- mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
- token->text);
- skipUntilEOD(mLexer, token);
- return;
- }
- }
-
- // We have a valid defined operator.
- // Convert the current token into a CONST_INT token.
- token->type = Token::CONST_INT;
- token->text = expression;
- }
-
- private:
- Lexer *mLexer;
- const MacroSet *mMacroSet;
- Diagnostics *mDiagnostics;
-};
-
DirectiveParser::DirectiveParser(Tokenizer *tokenizer,
MacroSet *macroSet,
Diagnostics *diagnostics,
DirectiveHandler *directiveHandler,
- int maxMacroExpansionDepth)
+ const PreprocessorSettings &settings)
: mPastFirstStatement(false),
mSeenNonPreprocessorToken(false),
mTokenizer(tokenizer),
@@ -214,7 +153,7 @@
mDiagnostics(diagnostics),
mDirectiveHandler(directiveHandler),
mShaderVersion(100),
- mMaxMacroExpansionDepth(maxMacroExpansionDepth)
+ mSettings(settings)
{
}
@@ -843,7 +782,7 @@
bool parsedFileNumber = false;
int line = 0, file = 0;
- MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, mMaxMacroExpansionDepth);
+ MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, mSettings, false);
// Lex the first token after "#line" so we can check it for EOD.
macroExpander.lex(token);
@@ -951,8 +890,7 @@
{
ASSERT((getDirective(token) == DIRECTIVE_IF) || (getDirective(token) == DIRECTIVE_ELIF));
- DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
- MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics, mMaxMacroExpansionDepth);
+ MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, mSettings, true);
ExpressionParser expressionParser(¯oExpander, mDiagnostics);
int expression = 0;
diff --git a/src/compiler/preprocessor/DirectiveParser.h b/src/compiler/preprocessor/DirectiveParser.h
index 1fd6400..84c6ec4 100644
--- a/src/compiler/preprocessor/DirectiveParser.h
+++ b/src/compiler/preprocessor/DirectiveParser.h
@@ -9,6 +9,7 @@
#include "compiler/preprocessor/Lexer.h"
#include "compiler/preprocessor/Macro.h"
+#include "compiler/preprocessor/Preprocessor.h"
#include "compiler/preprocessor/SourceLocation.h"
namespace angle
@@ -28,7 +29,7 @@
MacroSet *macroSet,
Diagnostics *diagnostics,
DirectiveHandler *directiveHandler,
- int maxMacroExpansionDepth);
+ const PreprocessorSettings &settings);
~DirectiveParser() override;
void lex(Token *token) override;
@@ -78,7 +79,7 @@
Diagnostics *mDiagnostics;
DirectiveHandler *mDirectiveHandler;
int mShaderVersion;
- int mMaxMacroExpansionDepth;
+ const PreprocessorSettings mSettings;
};
} // namespace pp
diff --git a/src/compiler/preprocessor/MacroExpander.cpp b/src/compiler/preprocessor/MacroExpander.cpp
index e4b1968..4156270 100644
--- a/src/compiler/preprocessor/MacroExpander.cpp
+++ b/src/compiler/preprocessor/MacroExpander.cpp
@@ -6,6 +6,7 @@
#include "compiler/preprocessor/MacroExpander.h"
+#include <GLSLANG/ShaderLang.h>
#include <algorithm>
#include "common/debug.h"
@@ -86,12 +87,14 @@
MacroExpander::MacroExpander(Lexer *lexer,
MacroSet *macroSet,
Diagnostics *diagnostics,
- int allowedMacroExpansionDepth)
+ const PreprocessorSettings &settings,
+ bool parseDefined)
: mLexer(lexer),
mMacroSet(macroSet),
mDiagnostics(diagnostics),
+ mParseDefined(parseDefined),
mTotalTokensInContexts(0),
- mAllowedMacroExpansionDepth(allowedMacroExpansionDepth),
+ mSettings(settings),
mDeferReenablingMacros(false)
{
}
@@ -114,6 +117,51 @@
if (token->type != Token::IDENTIFIER)
break;
+ // Defined operator is parsed here since it may be generated by macro expansion.
+ // Defined operator produced by macro expansion has undefined behavior according to C++
+ // spec, which the GLSL spec references (see C++14 draft spec section 16.1.4), but this
+ // behavior is needed for passing dEQP tests, which enforce stricter compatibility between
+ // implementations.
+ if (mParseDefined && token->text == kDefined)
+ {
+ // Defined inside a macro is forbidden in WebGL.
+ if (!mContextStack.empty() && sh::IsWebGLBasedSpec(mSettings.shaderSpec))
+ break;
+
+ bool paren = false;
+ getToken(token);
+ if (token->type == '(')
+ {
+ paren = true;
+ getToken(token);
+ }
+ if (token->type != Token::IDENTIFIER)
+ {
+ mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
+ token->text);
+ break;
+ }
+ auto iter = mMacroSet->find(token->text);
+ std::string expression = iter != mMacroSet->end() ? "1" : "0";
+
+ if (paren)
+ {
+ getToken(token);
+ if (token->type != ')')
+ {
+ mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
+ token->text);
+ break;
+ }
+ }
+
+ // We have a valid defined operator.
+ // Convert the current token into a CONST_INT token.
+ token->type = Token::CONST_INT;
+ token->text = expression;
+ break;
+ }
+
if (token->expansionDisabled())
break;
@@ -386,13 +434,15 @@
for (auto &arg : *args)
{
TokenLexer lexer(&arg);
- if (mAllowedMacroExpansionDepth < 1)
+ if (mSettings.maxMacroExpansionDepth < 1)
{
mDiagnostics->report(Diagnostics::PP_MACRO_INVOCATION_CHAIN_TOO_DEEP, token.location,
token.text);
return false;
}
- MacroExpander expander(&lexer, mMacroSet, mDiagnostics, mAllowedMacroExpansionDepth - 1);
+ PreprocessorSettings nestedSettings(mSettings.shaderSpec);
+ nestedSettings.maxMacroExpansionDepth = mSettings.maxMacroExpansionDepth - 1;
+ MacroExpander expander(&lexer, mMacroSet, mDiagnostics, nestedSettings, mParseDefined);
arg.clear();
expander.lex(&token);
diff --git a/src/compiler/preprocessor/MacroExpander.h b/src/compiler/preprocessor/MacroExpander.h
index e5cde5f..837bd73 100644
--- a/src/compiler/preprocessor/MacroExpander.h
+++ b/src/compiler/preprocessor/MacroExpander.h
@@ -12,6 +12,7 @@
#include "compiler/preprocessor/Lexer.h"
#include "compiler/preprocessor/Macro.h"
+#include "compiler/preprocessor/Preprocessor.h"
namespace angle
{
@@ -28,7 +29,8 @@
MacroExpander(Lexer *lexer,
MacroSet *macroSet,
Diagnostics *diagnostics,
- int allowedMacroExpansionDepth);
+ const PreprocessorSettings &settings,
+ bool parseDefined);
~MacroExpander() override;
void lex(Token *token) override;
@@ -68,12 +70,13 @@
Lexer *mLexer;
MacroSet *mMacroSet;
Diagnostics *mDiagnostics;
+ bool mParseDefined;
std::unique_ptr<Token> mReserveToken;
std::vector<MacroContext *> mContextStack;
size_t mTotalTokensInContexts;
- int mAllowedMacroExpansionDepth;
+ PreprocessorSettings mSettings;
bool mDeferReenablingMacros;
std::vector<std::shared_ptr<Macro>> mMacrosToReenable;
diff --git a/src/compiler/preprocessor/Preprocessor.cpp b/src/compiler/preprocessor/Preprocessor.cpp
index 494a8db..1d833a3 100644
--- a/src/compiler/preprocessor/Preprocessor.cpp
+++ b/src/compiler/preprocessor/Preprocessor.cpp
@@ -33,12 +33,8 @@
const PreprocessorSettings &settings)
: diagnostics(diag),
tokenizer(diag),
- directiveParser(&tokenizer,
- ¯oSet,
- diag,
- directiveHandler,
- settings.maxMacroExpansionDepth),
- macroExpander(&directiveParser, ¯oSet, diag, settings.maxMacroExpansionDepth)
+ directiveParser(&tokenizer, ¯oSet, diag, directiveHandler, settings),
+ macroExpander(&directiveParser, ¯oSet, diag, settings, false)
{
}
};
diff --git a/src/compiler/preprocessor/Preprocessor.h b/src/compiler/preprocessor/Preprocessor.h
index 4551c40..32fe6d3 100644
--- a/src/compiler/preprocessor/Preprocessor.h
+++ b/src/compiler/preprocessor/Preprocessor.h
@@ -9,6 +9,7 @@
#include <cstddef>
+#include "GLSLANG/ShaderLang.h"
#include "common/angleutils.h"
namespace angle
@@ -22,10 +23,17 @@
struct PreprocessorImpl;
struct Token;
-struct PreprocessorSettings : private angle::NonCopyable
+struct PreprocessorSettings final
{
- PreprocessorSettings() : maxMacroExpansionDepth(1000) {}
+ PreprocessorSettings(ShShaderSpec shaderSpec)
+ : maxMacroExpansionDepth(1000), shaderSpec(shaderSpec)
+ {
+ }
+
+ PreprocessorSettings(const PreprocessorSettings &other) = default;
+
int maxMacroExpansionDepth;
+ ShShaderSpec shaderSpec;
};
class Preprocessor : angle::NonCopyable
diff --git a/src/compiler/preprocessor/Token.h b/src/compiler/preprocessor/Token.h
index 6a613d6..7485ade 100644
--- a/src/compiler/preprocessor/Token.h
+++ b/src/compiler/preprocessor/Token.h
@@ -106,6 +106,8 @@
std::ostream &operator<<(std::ostream &out, const Token &token);
+constexpr char kDefined[] = "defined";
+
} // namespace pp
} // namespace angle
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index 43d4162..665c1d7 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -92,11 +92,6 @@
#endif // defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
} // anonymous namespace
-bool IsWebGLBasedSpec(ShShaderSpec spec)
-{
- return (spec == SH_WEBGL_SPEC || spec == SH_WEBGL2_SPEC || spec == SH_WEBGL3_SPEC);
-}
-
bool IsGLSL130OrNewer(ShShaderOutput output)
{
return (output == SH_GLSL_130_OUTPUT || output == SH_GLSL_140_OUTPUT ||
diff --git a/src/compiler/translator/Compiler.h b/src/compiler/translator/Compiler.h
index 2de32e9..2dc0fe6 100644
--- a/src/compiler/translator/Compiler.h
+++ b/src/compiler/translator/Compiler.h
@@ -36,11 +36,6 @@
#endif // ANGLE_ENABLE_HLSL
//
-// Helper function to identify specs that are based on the WebGL spec.
-//
-bool IsWebGLBasedSpec(ShShaderSpec spec);
-
-//
// Helper function to check if the shader type is GLSL.
//
bool IsGLSL130OrNewer(ShShaderOutput output);
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index 784426f..77ed235 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -194,7 +194,7 @@
mShaderVersion,
mShaderType,
resources.WEBGL_debug_shader_precision == 1),
- mPreprocessor(mDiagnostics, &mDirectiveHandler, angle::pp::PreprocessorSettings()),
+ mPreprocessor(mDiagnostics, &mDirectiveHandler, angle::pp::PreprocessorSettings(spec)),
mScanner(nullptr),
mMinProgramTexelOffset(resources.MinProgramTexelOffset),
mMaxProgramTexelOffset(resources.MaxProgramTexelOffset),