diff options
Diffstat (limited to 'src/3rdparty/angle/src/compiler/preprocessor')
25 files changed, 938 insertions, 772 deletions
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.cpp b/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.cpp index 68c6e9cea4..c89bc9fa76 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.cpp @@ -4,9 +4,9 @@ // found in the LICENSE file. // -#include "DiagnosticsBase.h" +#include "compiler/preprocessor/DiagnosticsBase.h" -#include <cassert> +#include "common/debug.h" namespace pp { @@ -15,122 +15,128 @@ Diagnostics::~Diagnostics() { } -void Diagnostics::report(ID id, - const SourceLocation &loc, - const std::string &text) +void Diagnostics::report(ID id, const SourceLocation &loc, const std::string &text) { - // TODO(alokp): Keep a count of errors and warnings. print(id, loc, text); } -Diagnostics::Severity Diagnostics::severity(ID id) +bool Diagnostics::isError(ID id) { if ((id > PP_ERROR_BEGIN) && (id < PP_ERROR_END)) - return PP_ERROR; + return true; if ((id > PP_WARNING_BEGIN) && (id < PP_WARNING_END)) - return PP_WARNING; + return false; - assert(false); - return PP_ERROR; + UNREACHABLE(); + return true; } -std::string Diagnostics::message(ID id) +const char *Diagnostics::message(ID id) { switch (id) { - // Errors begin. - case PP_INTERNAL_ERROR: - return "internal error"; - case PP_OUT_OF_MEMORY: - return "out of memory"; - case PP_INVALID_CHARACTER: - return "invalid character"; - case PP_INVALID_NUMBER: - return "invalid number"; - case PP_INTEGER_OVERFLOW: - return "integer overflow"; - case PP_FLOAT_OVERFLOW: - return "float overflow"; - case PP_TOKEN_TOO_LONG: - return "token too long"; - case PP_INVALID_EXPRESSION: - return "invalid expression"; - case PP_DIVISION_BY_ZERO: - return "division by zero"; - case PP_EOF_IN_COMMENT: - return "unexpected end of file found in comment"; - case PP_UNEXPECTED_TOKEN: - return "unexpected token"; - case PP_DIRECTIVE_INVALID_NAME: - return "invalid directive name"; - case PP_MACRO_NAME_RESERVED: - return "macro name is reserved"; - case PP_MACRO_REDEFINED: - return "macro redefined"; - case PP_MACRO_PREDEFINED_REDEFINED: - return "predefined macro redefined"; - case PP_MACRO_PREDEFINED_UNDEFINED: - return "predefined macro undefined"; - case PP_MACRO_UNTERMINATED_INVOCATION: - return "unterminated macro invocation"; - case PP_MACRO_TOO_FEW_ARGS: - return "Not enough arguments for macro"; - case PP_MACRO_TOO_MANY_ARGS: - return "Too many arguments for macro"; - case PP_MACRO_DUPLICATE_PARAMETER_NAMES: - return "duplicate macro parameter name"; - case PP_CONDITIONAL_ENDIF_WITHOUT_IF: - return "unexpected #endif found without a matching #if"; - case PP_CONDITIONAL_ELSE_WITHOUT_IF: - return "unexpected #else found without a matching #if"; - case PP_CONDITIONAL_ELSE_AFTER_ELSE: - return "unexpected #else found after another #else"; - case PP_CONDITIONAL_ELIF_WITHOUT_IF: - return "unexpected #elif found without a matching #if"; - case PP_CONDITIONAL_ELIF_AFTER_ELSE: - return "unexpected #elif found after #else"; - case PP_CONDITIONAL_UNTERMINATED: - return "unexpected end of file found in conditional block"; - case PP_INVALID_EXTENSION_NAME: - return "invalid extension name"; - case PP_INVALID_EXTENSION_BEHAVIOR: - return "invalid extension behavior"; - case PP_INVALID_EXTENSION_DIRECTIVE: - return "invalid extension directive"; - case PP_INVALID_VERSION_NUMBER: - return "invalid version number"; - case PP_INVALID_VERSION_DIRECTIVE: - return "invalid version directive"; - case PP_VERSION_NOT_FIRST_STATEMENT: - return "#version directive must occur before anything else, " - "except for comments and white space"; - case PP_VERSION_NOT_FIRST_LINE_ESSL3: - return "#version directive must occur on the first line of the shader"; - case PP_INVALID_LINE_NUMBER: - return "invalid line number"; - case PP_INVALID_FILE_NUMBER: - return "invalid file number"; - case PP_INVALID_LINE_DIRECTIVE: - return "invalid line directive"; - case PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3: - return "extension directive must occur before any non-preprocessor tokens in ESSL3"; - // Errors end. - // Warnings begin. - case PP_EOF_IN_DIRECTIVE: - return "unexpected end of file found in directive"; - case PP_CONDITIONAL_UNEXPECTED_TOKEN: - return "unexpected token after conditional expression"; - case PP_UNRECOGNIZED_PRAGMA: - return "unrecognized pragma"; - case PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1: - return "extension directive should occur before any non-preprocessor tokens"; - case PP_WARNING_MACRO_NAME_RESERVED: - return "macro name with a double underscore is reserved - unintented behavior is possible"; - // Warnings end. - default: - assert(false); - return ""; + // Errors begin. + case PP_INTERNAL_ERROR: + return "internal error"; + case PP_OUT_OF_MEMORY: + return "out of memory"; + case PP_INVALID_CHARACTER: + return "invalid character"; + case PP_INVALID_NUMBER: + return "invalid number"; + case PP_INTEGER_OVERFLOW: + return "integer overflow"; + case PP_FLOAT_OVERFLOW: + return "float overflow"; + case PP_TOKEN_TOO_LONG: + return "token too long"; + case PP_INVALID_EXPRESSION: + return "invalid expression"; + case PP_DIVISION_BY_ZERO: + return "division by zero"; + case PP_EOF_IN_COMMENT: + return "unexpected end of file found in comment"; + case PP_UNEXPECTED_TOKEN: + return "unexpected token"; + case PP_DIRECTIVE_INVALID_NAME: + return "invalid directive name"; + case PP_MACRO_NAME_RESERVED: + return "macro name is reserved"; + case PP_MACRO_REDEFINED: + return "macro redefined"; + case PP_MACRO_PREDEFINED_REDEFINED: + return "predefined macro redefined"; + case PP_MACRO_PREDEFINED_UNDEFINED: + return "predefined macro undefined"; + case PP_MACRO_UNTERMINATED_INVOCATION: + return "unterminated macro invocation"; + case PP_MACRO_UNDEFINED_WHILE_INVOKED: + return "macro undefined while being invoked"; + case PP_MACRO_TOO_FEW_ARGS: + return "Not enough arguments for macro"; + case PP_MACRO_TOO_MANY_ARGS: + return "Too many arguments for macro"; + case PP_MACRO_DUPLICATE_PARAMETER_NAMES: + return "duplicate macro parameter name"; + case PP_MACRO_INVOCATION_CHAIN_TOO_DEEP: + return "macro invocation chain too deep"; + case PP_CONDITIONAL_ENDIF_WITHOUT_IF: + return "unexpected #endif found without a matching #if"; + case PP_CONDITIONAL_ELSE_WITHOUT_IF: + return "unexpected #else found without a matching #if"; + case PP_CONDITIONAL_ELSE_AFTER_ELSE: + return "unexpected #else found after another #else"; + case PP_CONDITIONAL_ELIF_WITHOUT_IF: + return "unexpected #elif found without a matching #if"; + case PP_CONDITIONAL_ELIF_AFTER_ELSE: + return "unexpected #elif found after #else"; + case PP_CONDITIONAL_UNTERMINATED: + return "unexpected end of file found in conditional block"; + case PP_INVALID_EXTENSION_NAME: + return "invalid extension name"; + case PP_INVALID_EXTENSION_BEHAVIOR: + return "invalid extension behavior"; + case PP_INVALID_EXTENSION_DIRECTIVE: + return "invalid extension directive"; + case PP_INVALID_VERSION_NUMBER: + return "invalid version number"; + case PP_INVALID_VERSION_DIRECTIVE: + return "invalid version directive"; + case PP_VERSION_NOT_FIRST_STATEMENT: + return "#version directive must occur before anything else, " + "except for comments and white space"; + case PP_VERSION_NOT_FIRST_LINE_ESSL3: + return "#version directive must occur on the first line of the shader"; + case PP_INVALID_LINE_NUMBER: + return "invalid line number"; + case PP_INVALID_FILE_NUMBER: + return "invalid file number"; + case PP_INVALID_LINE_DIRECTIVE: + return "invalid line directive"; + case PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3: + return "extension directive must occur before any non-preprocessor tokens in ESSL3"; + case PP_UNDEFINED_SHIFT: + return "shift exponent is negative or undefined"; + case PP_TOKENIZER_ERROR: + return "internal tokenizer error"; + // Errors end. + // Warnings begin. + case PP_EOF_IN_DIRECTIVE: + return "unexpected end of file found in directive"; + case PP_CONDITIONAL_UNEXPECTED_TOKEN: + return "unexpected token after conditional expression"; + case PP_UNRECOGNIZED_PRAGMA: + return "unrecognized pragma"; + case PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1: + return "extension directive should occur before any non-preprocessor tokens"; + case PP_WARNING_MACRO_NAME_RESERVED: + return "macro name with a double underscore is reserved - unintented behavior is " + "possible"; + // Warnings end. + default: + UNREACHABLE(); + return ""; } } diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h b/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h index d26c174f01..ea37614606 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h @@ -19,11 +19,6 @@ struct SourceLocation; class Diagnostics { public: - enum Severity - { - PP_ERROR, - PP_WARNING - }; enum ID { PP_ERROR_BEGIN, @@ -44,9 +39,11 @@ class Diagnostics PP_MACRO_PREDEFINED_REDEFINED, PP_MACRO_PREDEFINED_UNDEFINED, PP_MACRO_UNTERMINATED_INVOCATION, + PP_MACRO_UNDEFINED_WHILE_INVOKED, PP_MACRO_TOO_FEW_ARGS, PP_MACRO_TOO_MANY_ARGS, PP_MACRO_DUPLICATE_PARAMETER_NAMES, + PP_MACRO_INVOCATION_CHAIN_TOO_DEEP, PP_CONDITIONAL_ENDIF_WITHOUT_IF, PP_CONDITIONAL_ELSE_WITHOUT_IF, PP_CONDITIONAL_ELSE_AFTER_ELSE, @@ -65,6 +62,8 @@ class Diagnostics PP_INVALID_FILE_NUMBER, PP_INVALID_LINE_DIRECTIVE, PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3, + PP_UNDEFINED_SHIFT, + PP_TOKENIZER_ERROR, PP_ERROR_END, PP_WARNING_BEGIN, @@ -80,12 +79,10 @@ class Diagnostics void report(ID id, const SourceLocation &loc, const std::string &text); protected: - Severity severity(ID id); - std::string message(ID id); + bool isError(ID id); + const char *message(ID id); - virtual void print(ID id, - const SourceLocation &loc, - const std::string &text) = 0; + virtual void print(ID id, const SourceLocation &loc, const std::string &text) = 0; }; } // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.cpp b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.cpp index ef35c6ed50..049dae9071 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.cpp @@ -4,7 +4,7 @@ // found in the LICENSE file. // -#include "DirectiveHandlerBase.h" +#include "compiler/preprocessor/DirectiveHandlerBase.h" namespace pp { diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h index cf67895764..6c81d015f5 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h @@ -23,8 +23,7 @@ class DirectiveHandler public: virtual ~DirectiveHandler(); - virtual void handleError(const SourceLocation &loc, - const std::string &msg) = 0; + virtual void handleError(const SourceLocation &loc, const std::string &msg) = 0; // Handle pragma of form: #pragma name[(value)] virtual void handlePragma(const SourceLocation &loc, @@ -36,8 +35,7 @@ class DirectiveHandler const std::string &name, const std::string &behavior) = 0; - virtual void handleVersion(const SourceLocation &loc, - int version) = 0; + virtual void handleVersion(const SourceLocation &loc, int version) = 0; }; } // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.cpp b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.cpp index 2faa331378..f6c5763990 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.cpp @@ -4,21 +4,22 @@ // found in the LICENSE file. // -#include "DirectiveParser.h" +#include "compiler/preprocessor/DirectiveParser.h" #include <algorithm> -#include <cassert> #include <cstdlib> #include <sstream> -#include "DiagnosticsBase.h" -#include "DirectiveHandlerBase.h" -#include "ExpressionParser.h" -#include "MacroExpander.h" -#include "Token.h" -#include "Tokenizer.h" +#include "common/debug.h" +#include "compiler/preprocessor/DiagnosticsBase.h" +#include "compiler/preprocessor/DirectiveHandlerBase.h" +#include "compiler/preprocessor/ExpressionParser.h" +#include "compiler/preprocessor/MacroExpander.h" +#include "compiler/preprocessor/Token.h" +#include "compiler/preprocessor/Tokenizer.h" -namespace { +namespace +{ enum DirectiveType { DIRECTIVE_NONE, @@ -39,19 +40,19 @@ enum DirectiveType DirectiveType getDirective(const pp::Token *token) { - const char kDirectiveDefine[] = "define"; - const char kDirectiveUndef[] = "undef"; - const char kDirectiveIf[] = "if"; - const char kDirectiveIfdef[] = "ifdef"; - const char kDirectiveIfndef[] = "ifndef"; - const char kDirectiveElse[] = "else"; - const char kDirectiveElif[] = "elif"; - const char kDirectiveEndif[] = "endif"; - const char kDirectiveError[] = "error"; - const char kDirectivePragma[] = "pragma"; + const char kDirectiveDefine[] = "define"; + const char kDirectiveUndef[] = "undef"; + const char kDirectiveIf[] = "if"; + const char kDirectiveIfdef[] = "ifdef"; + const char kDirectiveIfndef[] = "ifndef"; + const char kDirectiveElse[] = "else"; + const char kDirectiveElif[] = "elif"; + const char kDirectiveEndif[] = "endif"; + const char kDirectiveError[] = "error"; + const char kDirectivePragma[] = "pragma"; const char kDirectiveExtension[] = "extension"; - const char kDirectiveVersion[] = "version"; - const char kDirectiveLine[] = "line"; + const char kDirectiveVersion[] = "version"; + const char kDirectiveLine[] = "line"; if (token->type != pp::Token::IDENTIFIER) return DIRECTIVE_NONE; @@ -90,15 +91,15 @@ bool isConditionalDirective(DirectiveType directive) { switch (directive) { - case DIRECTIVE_IF: - case DIRECTIVE_IFDEF: - case DIRECTIVE_IFNDEF: - case DIRECTIVE_ELSE: - case DIRECTIVE_ELIF: - case DIRECTIVE_ENDIF: - return true; - default: - return false; + case DIRECTIVE_IF: + case DIRECTIVE_IFDEF: + case DIRECTIVE_IFNDEF: + case DIRECTIVE_ELSE: + case DIRECTIVE_ELIF: + case DIRECTIVE_ENDIF: + return true; + default: + return false; } } @@ -110,7 +111,7 @@ bool isEOD(const pp::Token *token) void skipUntilEOD(pp::Lexer *lexer, pp::Token *token) { - while(!isEOD(token)) + while (!isEOD(token)) { lexer->lex(token); } @@ -118,8 +119,8 @@ void skipUntilEOD(pp::Lexer *lexer, pp::Token *token) bool isMacroNameReserved(const std::string &name) { - // Names prefixed with "GL_" are reserved. - return (name.substr(0, 3) == "GL_"); + // Names prefixed with "GL_" and the name "defined" are reserved. + return name == "defined" || (name.substr(0, 3) == "GL_"); } bool hasDoubleUnderscores(const std::string &name) @@ -127,11 +128,10 @@ bool hasDoubleUnderscores(const std::string &name) return (name.find("__") != std::string::npos); } -bool isMacroPredefined(const std::string &name, - const pp::MacroSet ¯oSet) +bool isMacroPredefined(const std::string &name, const pp::MacroSet ¯oSet) { pp::MacroSet::const_iterator iter = macroSet.find(name); - return iter != macroSet.end() ? iter->second.predefined : false; + return iter != macroSet.end() ? iter->second->predefined : false; } } // namespace anonymous @@ -139,17 +139,83 @@ bool isMacroPredefined(const std::string &name, 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) + DirectiveHandler *directiveHandler, + int maxMacroExpansionDepth) : mPastFirstStatement(false), mSeenNonPreprocessorToken(false), mTokenizer(tokenizer), mMacroSet(macroSet), mDiagnostics(diagnostics), mDirectiveHandler(directiveHandler), - mShaderVersion(100) + mShaderVersion(100), + mMaxMacroExpansionDepth(maxMacroExpansionDepth) +{ +} + +DirectiveParser::~DirectiveParser() { } @@ -174,21 +240,20 @@ void DirectiveParser::lex(Token *token) if (!mConditionalStack.empty()) { const ConditionalBlock &block = mConditionalStack.back(); - mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED, - block.location, block.type); + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED, block.location, + block.type); } break; } - } - while (skipping() || (token->type == '\n')); + } while (skipping() || (token->type == '\n')); mPastFirstStatement = true; } void DirectiveParser::parseDirective(Token *token) { - assert(token->type == Token::PP_HASH); + ASSERT(token->type == Token::PP_HASH); mTokenizer->lex(token); if (isEOD(token)) @@ -207,86 +272,83 @@ void DirectiveParser::parseDirective(Token *token) return; } - switch(directive) + switch (directive) { - case DIRECTIVE_NONE: - mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME, - token->location, token->text); - skipUntilEOD(mTokenizer, token); - break; - case DIRECTIVE_DEFINE: - parseDefine(token); - break; - case DIRECTIVE_UNDEF: - parseUndef(token); - break; - case DIRECTIVE_IF: - parseIf(token); - break; - case DIRECTIVE_IFDEF: - parseIfdef(token); - break; - case DIRECTIVE_IFNDEF: - parseIfndef(token); - break; - case DIRECTIVE_ELSE: - parseElse(token); - break; - case DIRECTIVE_ELIF: - parseElif(token); - break; - case DIRECTIVE_ENDIF: - parseEndif(token); - break; - case DIRECTIVE_ERROR: - parseError(token); - break; - case DIRECTIVE_PRAGMA: - parsePragma(token); - break; - case DIRECTIVE_EXTENSION: - parseExtension(token); - break; - case DIRECTIVE_VERSION: - parseVersion(token); - break; - case DIRECTIVE_LINE: - parseLine(token); - break; - default: - assert(false); - break; + case DIRECTIVE_NONE: + mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME, token->location, + token->text); + skipUntilEOD(mTokenizer, token); + break; + case DIRECTIVE_DEFINE: + parseDefine(token); + break; + case DIRECTIVE_UNDEF: + parseUndef(token); + break; + case DIRECTIVE_IF: + parseIf(token); + break; + case DIRECTIVE_IFDEF: + parseIfdef(token); + break; + case DIRECTIVE_IFNDEF: + parseIfndef(token); + break; + case DIRECTIVE_ELSE: + parseElse(token); + break; + case DIRECTIVE_ELIF: + parseElif(token); + break; + case DIRECTIVE_ENDIF: + parseEndif(token); + break; + case DIRECTIVE_ERROR: + parseError(token); + break; + case DIRECTIVE_PRAGMA: + parsePragma(token); + break; + case DIRECTIVE_EXTENSION: + parseExtension(token); + break; + case DIRECTIVE_VERSION: + parseVersion(token); + break; + case DIRECTIVE_LINE: + parseLine(token); + break; + default: + UNREACHABLE(); + break; } skipUntilEOD(mTokenizer, token); if (token->type == Token::LAST) { - mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE, token->location, token->text); } } void DirectiveParser::parseDefine(Token *token) { - assert(getDirective(token) == DIRECTIVE_DEFINE); + ASSERT(getDirective(token) == DIRECTIVE_DEFINE); mTokenizer->lex(token); if (token->type != Token::IDENTIFIER) { - mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text); return; } if (isMacroPredefined(token->text, *mMacroSet)) { - mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED, token->location, + token->text); return; } if (isMacroNameReserved(token->text)) { - mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED, token->location, token->text); return; } // Using double underscores is allowed, but may result in unintended @@ -300,39 +362,37 @@ void DirectiveParser::parseDefine(Token *token) token->text); } - Macro macro; - macro.type = Macro::kTypeObj; - macro.name = token->text; + std::shared_ptr<Macro> macro = std::make_shared<Macro>(); + macro->type = Macro::kTypeObj; + macro->name = token->text; mTokenizer->lex(token); if (token->type == '(' && !token->hasLeadingSpace()) { // Function-like macro. Collect arguments. - macro.type = Macro::kTypeFunc; + macro->type = Macro::kTypeFunc; do { mTokenizer->lex(token); if (token->type != Token::IDENTIFIER) break; - if (std::find(macro.parameters.begin(), macro.parameters.end(), token->text) != macro.parameters.end()) + if (std::find(macro->parameters.begin(), macro->parameters.end(), token->text) != + macro->parameters.end()) { mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES, token->location, token->text); return; } - macro.parameters.push_back(token->text); + macro->parameters.push_back(token->text); mTokenizer->lex(token); // Get ','. - } - while (token->type == ','); + } while (token->type == ','); if (token->type != ')') { - mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, - token->location, - token->text); + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text); return; } mTokenizer->lex(token); // Get ')'. @@ -344,47 +404,51 @@ void DirectiveParser::parseDefine(Token *token) // list. Resetting it also allows us to reuse Token::equals() to // compare macros. token->location = SourceLocation(); - macro.replacements.push_back(*token); + macro->replacements.push_back(*token); mTokenizer->lex(token); } - if (!macro.replacements.empty()) + if (!macro->replacements.empty()) { // Whitespace preceding the replacement list is not considered part of // the replacement list for either form of macro. - macro.replacements.front().setHasLeadingSpace(false); + macro->replacements.front().setHasLeadingSpace(false); } // Check for macro redefinition. - MacroSet::const_iterator iter = mMacroSet->find(macro.name); - if (iter != mMacroSet->end() && !macro.equals(iter->second)) + MacroSet::const_iterator iter = mMacroSet->find(macro->name); + if (iter != mMacroSet->end() && !macro->equals(*iter->second)) { - mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED, - token->location, - macro.name); + mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED, token->location, macro->name); return; } - mMacroSet->insert(std::make_pair(macro.name, macro)); + mMacroSet->insert(std::make_pair(macro->name, macro)); } void DirectiveParser::parseUndef(Token *token) { - assert(getDirective(token) == DIRECTIVE_UNDEF); + ASSERT(getDirective(token) == DIRECTIVE_UNDEF); mTokenizer->lex(token); if (token->type != Token::IDENTIFIER) { - mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text); return; } MacroSet::iterator iter = mMacroSet->find(token->text); if (iter != mMacroSet->end()) { - if (iter->second.predefined) + if (iter->second->predefined) { - mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED, token->location, + token->text); + return; + } + else if (iter->second->expansionCount > 0) + { + mDiagnostics->report(Diagnostics::PP_MACRO_UNDEFINED_WHILE_INVOKED, token->location, + token->text); + return; } else { @@ -395,38 +459,37 @@ void DirectiveParser::parseUndef(Token *token) mTokenizer->lex(token); if (!isEOD(token)) { - mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text); skipUntilEOD(mTokenizer, token); } } void DirectiveParser::parseIf(Token *token) { - assert(getDirective(token) == DIRECTIVE_IF); + ASSERT(getDirective(token) == DIRECTIVE_IF); parseConditionalIf(token); } void DirectiveParser::parseIfdef(Token *token) { - assert(getDirective(token) == DIRECTIVE_IFDEF); + ASSERT(getDirective(token) == DIRECTIVE_IFDEF); parseConditionalIf(token); } void DirectiveParser::parseIfndef(Token *token) { - assert(getDirective(token) == DIRECTIVE_IFNDEF); + ASSERT(getDirective(token) == DIRECTIVE_IFNDEF); parseConditionalIf(token); } void DirectiveParser::parseElse(Token *token) { - assert(getDirective(token) == DIRECTIVE_ELSE); + ASSERT(getDirective(token) == DIRECTIVE_ELSE); if (mConditionalStack.empty()) { - mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF, token->location, + token->text); skipUntilEOD(mTokenizer, token); return; } @@ -440,34 +503,34 @@ void DirectiveParser::parseElse(Token *token) } if (block.foundElseGroup) { - mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE, token->location, + token->text); skipUntilEOD(mTokenizer, token); return; } - block.foundElseGroup = true; - block.skipGroup = block.foundValidGroup; + block.foundElseGroup = true; + block.skipGroup = block.foundValidGroup; block.foundValidGroup = true; // Check if there are extra tokens after #else. mTokenizer->lex(token); if (!isEOD(token)) { - mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location, + token->text); skipUntilEOD(mTokenizer, token); } } void DirectiveParser::parseElif(Token *token) { - assert(getDirective(token) == DIRECTIVE_ELIF); + ASSERT(getDirective(token) == DIRECTIVE_ELIF); if (mConditionalStack.empty()) { - mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF, token->location, + token->text); skipUntilEOD(mTokenizer, token); return; } @@ -481,8 +544,8 @@ void DirectiveParser::parseElif(Token *token) } if (block.foundElseGroup) { - mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE, token->location, + token->text); skipUntilEOD(mTokenizer, token); return; } @@ -495,19 +558,19 @@ void DirectiveParser::parseElif(Token *token) return; } - int expression = parseExpressionIf(token); - block.skipGroup = expression == 0; + int expression = parseExpressionIf(token); + block.skipGroup = expression == 0; block.foundValidGroup = expression != 0; } void DirectiveParser::parseEndif(Token *token) { - assert(getDirective(token) == DIRECTIVE_ENDIF); + ASSERT(getDirective(token) == DIRECTIVE_ENDIF); if (mConditionalStack.empty()) { - mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF, token->location, + token->text); skipUntilEOD(mTokenizer, token); return; } @@ -518,15 +581,15 @@ void DirectiveParser::parseEndif(Token *token) mTokenizer->lex(token); if (!isEOD(token)) { - mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location, + token->text); skipUntilEOD(mTokenizer, token); } } void DirectiveParser::parseError(Token *token) { - assert(getDirective(token) == DIRECTIVE_ERROR); + ASSERT(getDirective(token) == DIRECTIVE_ERROR); std::ostringstream stream; mTokenizer->lex(token); @@ -541,7 +604,7 @@ void DirectiveParser::parseError(Token *token) // Parses pragma of form: #pragma name[(value)]. void DirectiveParser::parsePragma(Token *token) { - assert(getDirective(token) == DIRECTIVE_PRAGMA); + ASSERT(getDirective(token) == DIRECTIVE_PRAGMA); enum State { @@ -563,25 +626,25 @@ void DirectiveParser::parsePragma(Token *token) } while ((token->type != '\n') && (token->type != Token::LAST)) { - switch(state++) + switch (state++) { - case PRAGMA_NAME: - name = token->text; - valid = valid && (token->type == Token::IDENTIFIER); - break; - case LEFT_PAREN: - valid = valid && (token->type == '('); - break; - case PRAGMA_VALUE: - value = token->text; - valid = valid && (token->type == Token::IDENTIFIER); - break; - case RIGHT_PAREN: - valid = valid && (token->type == ')'); - break; - default: - valid = false; - break; + case PRAGMA_NAME: + name = token->text; + valid = valid && (token->type == Token::IDENTIFIER); + break; + case LEFT_PAREN: + valid = valid && (token->type == '('); + break; + case PRAGMA_VALUE: + value = token->text; + valid = valid && (token->type == Token::IDENTIFIER); + break; + case RIGHT_PAREN: + valid = valid && (token->type == ')'); + break; + default: + valid = false; + break; } mTokenizer->lex(token); } @@ -591,8 +654,7 @@ void DirectiveParser::parsePragma(Token *token) (state == RIGHT_PAREN + 1)); // With value. if (!valid) { - mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA, - token->location, name); + mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA, token->location, name); } else if (state > PRAGMA_NAME) // Do not notify for empty pragma. { @@ -602,7 +664,7 @@ void DirectiveParser::parsePragma(Token *token) void DirectiveParser::parseExtension(Token *token) { - assert(getDirective(token) == DIRECTIVE_EXTENSION); + ASSERT(getDirective(token) == DIRECTIVE_EXTENSION); enum State { @@ -620,47 +682,49 @@ void DirectiveParser::parseExtension(Token *token) { switch (state++) { - case EXT_NAME: - if (valid && (token->type != Token::IDENTIFIER)) - { - mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME, - token->location, token->text); - valid = false; - } - if (valid) name = token->text; - break; - case COLON: - if (valid && (token->type != ':')) - { - mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, - token->location, token->text); - valid = false; - } - break; - case EXT_BEHAVIOR: - if (valid && (token->type != Token::IDENTIFIER)) - { - mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR, - token->location, token->text); - valid = false; - } - if (valid) behavior = token->text; - break; - default: - if (valid) - { - mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, - token->location, token->text); - valid = false; - } - break; + case EXT_NAME: + if (valid && (token->type != Token::IDENTIFIER)) + { + mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME, token->location, + token->text); + valid = false; + } + if (valid) + name = token->text; + break; + case COLON: + if (valid && (token->type != ':')) + { + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, + token->text); + valid = false; + } + break; + case EXT_BEHAVIOR: + if (valid && (token->type != Token::IDENTIFIER)) + { + mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR, + token->location, token->text); + valid = false; + } + if (valid) + behavior = token->text; + break; + default: + if (valid) + { + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, + token->text); + valid = false; + } + break; } mTokenizer->lex(token); } if (valid && (state != EXT_BEHAVIOR + 1)) { - mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE, token->location, + token->text); valid = false; } if (valid && mSeenNonPreprocessorToken) @@ -683,12 +747,12 @@ void DirectiveParser::parseExtension(Token *token) void DirectiveParser::parseVersion(Token *token) { - assert(getDirective(token) == DIRECTIVE_VERSION); + ASSERT(getDirective(token) == DIRECTIVE_VERSION); if (mPastFirstStatement) { - mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT, token->location, + token->text); skipUntilEOD(mTokenizer, token); return; } @@ -700,47 +764,47 @@ void DirectiveParser::parseVersion(Token *token) VERSION_ENDLINE }; - bool valid = true; + bool valid = true; int version = 0; - int state = VERSION_NUMBER; + int state = VERSION_NUMBER; mTokenizer->lex(token); while (valid && (token->type != '\n') && (token->type != Token::LAST)) { switch (state) { - case VERSION_NUMBER: - if (token->type != Token::CONST_INT) - { - mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER, - token->location, token->text); - valid = false; - } - if (valid && !token->iValue(&version)) - { - mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW, - token->location, token->text); - valid = false; - } - if (valid) - { - state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE; - } - break; - case VERSION_PROFILE: - if (token->type != Token::IDENTIFIER || token->text != "es") - { - mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, - token->location, token->text); + case VERSION_NUMBER: + if (token->type != Token::CONST_INT) + { + mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER, token->location, + token->text); + valid = false; + } + if (valid && !token->iValue(&version)) + { + mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW, token->location, + token->text); + valid = false; + } + if (valid) + { + state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE; + } + break; + case VERSION_PROFILE: + if (token->type != Token::IDENTIFIER || token->text != "es") + { + mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location, + token->text); + valid = false; + } + state = VERSION_ENDLINE; + break; + default: + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, + token->text); valid = false; - } - state = VERSION_ENDLINE; - break; - default: - mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, - token->location, token->text); - valid = false; - break; + break; } mTokenizer->lex(token); @@ -748,15 +812,15 @@ void DirectiveParser::parseVersion(Token *token) if (valid && (state != VERSION_ENDLINE)) { - mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location, + token->text); valid = false; } if (valid && version >= 300 && token->location.line > 1) { - mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3, token->location, + token->text); valid = false; } @@ -770,13 +834,13 @@ void DirectiveParser::parseVersion(Token *token) void DirectiveParser::parseLine(Token *token) { - assert(getDirective(token) == DIRECTIVE_LINE); + ASSERT(getDirective(token) == DIRECTIVE_LINE); - bool valid = true; + bool valid = true; bool parsedFileNumber = false; int line = 0, file = 0; - MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, false); + MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, mMaxMacroExpansionDepth); // Lex the first token after "#line" so we can check it for EOD. macroExpander.lex(token); @@ -814,8 +878,8 @@ void DirectiveParser::parseLine(Token *token) { if (valid) { - mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, + token->text); valid = false; } skipUntilEOD(mTokenizer, token); @@ -835,14 +899,14 @@ bool DirectiveParser::skipping() const if (mConditionalStack.empty()) return false; - const ConditionalBlock& block = mConditionalStack.back(); + const ConditionalBlock &block = mConditionalStack.back(); return block.skipBlock || block.skipGroup; } void DirectiveParser::parseConditionalIf(Token *token) { ConditionalBlock block; - block.type = token->text; + block.type = token->text; block.location = token->location; if (skipping()) @@ -861,20 +925,20 @@ void DirectiveParser::parseConditionalIf(Token *token) int expression = 0; switch (directive) { - case DIRECTIVE_IF: - expression = parseExpressionIf(token); - break; - case DIRECTIVE_IFDEF: - expression = parseExpressionIfdef(token); - break; - case DIRECTIVE_IFNDEF: - expression = parseExpressionIfdef(token) == 0 ? 1 : 0; - break; - default: - assert(false); - break; + case DIRECTIVE_IF: + expression = parseExpressionIf(token); + break; + case DIRECTIVE_IFDEF: + expression = parseExpressionIfdef(token); + break; + case DIRECTIVE_IFNDEF: + expression = parseExpressionIfdef(token) == 0 ? 1 : 0; + break; + default: + UNREACHABLE(); + break; } - block.skipGroup = expression == 0; + block.skipGroup = expression == 0; block.foundValidGroup = expression != 0; } mConditionalStack.push_back(block); @@ -882,16 +946,16 @@ void DirectiveParser::parseConditionalIf(Token *token) int DirectiveParser::parseExpressionIf(Token *token) { - assert((getDirective(token) == DIRECTIVE_IF) || - (getDirective(token) == DIRECTIVE_ELIF)); + ASSERT((getDirective(token) == DIRECTIVE_IF) || (getDirective(token) == DIRECTIVE_ELIF)); - MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, true); + DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics); + MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics, mMaxMacroExpansionDepth); ExpressionParser expressionParser(¯oExpander, mDiagnostics); int expression = 0; ExpressionParser::ErrorSettings errorSettings; errorSettings.integerLiteralsMustFit32BitSignedRange = false; - errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN; + errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN; bool valid = true; expressionParser.parse(token, &expression, false, errorSettings, &valid); @@ -899,8 +963,8 @@ int DirectiveParser::parseExpressionIf(Token *token) // Check if there are tokens after #if expression. if (!isEOD(token)) { - mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location, + token->text); skipUntilEOD(mTokenizer, token); } @@ -909,27 +973,25 @@ int DirectiveParser::parseExpressionIf(Token *token) int DirectiveParser::parseExpressionIfdef(Token *token) { - assert((getDirective(token) == DIRECTIVE_IFDEF) || - (getDirective(token) == DIRECTIVE_IFNDEF)); + ASSERT((getDirective(token) == DIRECTIVE_IFDEF) || (getDirective(token) == DIRECTIVE_IFNDEF)); mTokenizer->lex(token); if (token->type != Token::IDENTIFIER) { - mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text); skipUntilEOD(mTokenizer, token); return 0; } MacroSet::const_iterator iter = mMacroSet->find(token->text); - int expression = iter != mMacroSet->end() ? 1 : 0; + int expression = iter != mMacroSet->end() ? 1 : 0; // Check if there are tokens after #ifdef expression. mTokenizer->lex(token); if (!isEOD(token)) { - mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location, + token->text); skipUntilEOD(mTokenizer, token); } return expression; diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h index 2888e289ce..29c30a8239 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h @@ -7,10 +7,9 @@ #ifndef COMPILER_PREPROCESSOR_DIRECTIVEPARSER_H_ #define COMPILER_PREPROCESSOR_DIRECTIVEPARSER_H_ -#include "Lexer.h" -#include "Macro.h" -#include "pp_utils.h" -#include "SourceLocation.h" +#include "compiler/preprocessor/Lexer.h" +#include "compiler/preprocessor/Macro.h" +#include "compiler/preprocessor/SourceLocation.h" namespace pp { @@ -25,13 +24,13 @@ class DirectiveParser : public Lexer DirectiveParser(Tokenizer *tokenizer, MacroSet *macroSet, Diagnostics *diagnostics, - DirectiveHandler *directiveHandler); + DirectiveHandler *directiveHandler, + int maxMacroExpansionDepth); + ~DirectiveParser() override; void lex(Token *token) override; private: - PP_DISALLOW_COPY_AND_ASSIGN(DirectiveParser); - void parseDirective(Token *token); void parseDefine(Token *token); void parseUndef(Token *token); @@ -62,22 +61,21 @@ class DirectiveParser : public Lexer bool foundElseGroup; ConditionalBlock() - : skipBlock(false), - skipGroup(false), - foundValidGroup(false), - foundElseGroup(false) + : skipBlock(false), skipGroup(false), foundValidGroup(false), foundElseGroup(false) { } }; bool mPastFirstStatement; - bool mSeenNonPreprocessorToken; // Tracks if a non-preprocessor token has been seen yet. Some macros, such as - // #extension must be declared before all shader code. + bool mSeenNonPreprocessorToken; // Tracks if a non-preprocessor token has been seen yet. Some + // macros, such as + // #extension must be declared before all shader code. std::vector<ConditionalBlock> mConditionalStack; Tokenizer *mTokenizer; MacroSet *mMacroSet; Diagnostics *mDiagnostics; DirectiveHandler *mDirectiveHandler; int mShaderVersion; + int mMaxMacroExpansionDepth; }; } // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h index 841c67b61c..0f2901b878 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h @@ -7,8 +7,8 @@ #ifndef COMPILER_PREPROCESSOR_EXPRESSIONPARSER_H_ #define COMPILER_PREPROCESSOR_EXPRESSIONPARSER_H_ -#include "DiagnosticsBase.h" -#include "pp_utils.h" +#include "common/angleutils.h" +#include "compiler/preprocessor/DiagnosticsBase.h" namespace pp { @@ -16,7 +16,7 @@ namespace pp class Lexer; struct Token; -class ExpressionParser +class ExpressionParser : angle::NonCopyable { public: struct ErrorSettings @@ -34,8 +34,6 @@ class ExpressionParser bool *valid); private: - PP_DISALLOW_COPY_AND_ASSIGN(ExpressionParser); - Lexer *mLexer; Diagnostics *mDiagnostics; }; diff --git a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y index 7b5d9e9cee..68d7cc3958 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y +++ b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y @@ -41,17 +41,15 @@ WHICH GENERATES THE GLSL ES preprocessor expression parser. #include <cassert> #include <sstream> +#include <stdint.h> #include "DiagnosticsBase.h" #include "Lexer.h" #include "Token.h" +#include "common/mathutil.h" -#if defined(_MSC_VER) -typedef __int64 YYSTYPE; -#else -#include <stdint.h> -typedef intmax_t YYSTYPE; -#endif // _MSC_VER +typedef int32_t YYSTYPE; +typedef uint32_t UNSIGNED_TYPE; #define YYENABLE_NLS 0 #define YYLTYPE_IS_TRIVIAL 1 @@ -196,16 +194,57 @@ expression $$ = $1 < $3; } | expression TOK_OP_RIGHT expression { - $$ = $1 >> $3; + if ($3 < 0 || $3 > 31) + { + if (!context->isIgnoringErrors()) + { + std::ostringstream stream; + stream << $1 << " >> " << $3; + std::string text = stream.str(); + context->diagnostics->report(pp::Diagnostics::PP_UNDEFINED_SHIFT, + context->token->location, + text.c_str()); + *(context->valid) = false; + } + $$ = static_cast<YYSTYPE>(0); + } + else if ($1 < 0) + { + // Logical shift right. + $$ = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>($1) >> $3); + } + else + { + $$ = $1 >> $3; + } } | expression TOK_OP_LEFT expression { - $$ = $1 << $3; + if ($3 < 0 || $3 > 31) + { + if (!context->isIgnoringErrors()) + { + std::ostringstream stream; + stream << $1 << " << " << $3; + std::string text = stream.str(); + context->diagnostics->report(pp::Diagnostics::PP_UNDEFINED_SHIFT, + context->token->location, + text.c_str()); + *(context->valid) = false; + } + $$ = static_cast<YYSTYPE>(0); + } + else + { + // Logical shift left. Casting to unsigned is needed to ensure there's no signed integer + // overflow, which some tools treat as an error. + $$ = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>($1) << $3); + } } | expression '-' expression { - $$ = $1 - $3; + $$ = gl::WrappingDiff<YYSTYPE>($1, $3); } | expression '+' expression { - $$ = $1 + $3; + $$ = gl::WrappingSum<YYSTYPE>($1, $3); } | expression '%' expression { if ($3 == 0) @@ -222,6 +261,12 @@ expression } $$ = static_cast<YYSTYPE>(0); } + else if (($1 == std::numeric_limits<YYSTYPE>::min()) && ($3 == -1)) + { + // Check for the special case where the minimum representable number is + // divided by -1. If left alone this has undefined results. + $$ = 0; + } else { $$ = $1 % $3; @@ -242,13 +287,20 @@ expression } $$ = static_cast<YYSTYPE>(0); } + else if (($1 == std::numeric_limits<YYSTYPE>::min()) && ($3 == -1)) + { + // Check for the special case where the minimum representable number is + // divided by -1. If left alone this leads to integer overflow in C++, which + // has undefined results. + $$ = std::numeric_limits<YYSTYPE>::max(); + } else { $$ = $1 / $3; } } | expression '*' expression { - $$ = $1 * $3; + $$ = gl::WrappingMul($1, $3); } | '!' expression %prec TOK_UNARY { $$ = ! $2; @@ -257,7 +309,16 @@ expression $$ = ~ $2; } | '-' expression %prec TOK_UNARY { - $$ = - $2; + // Check for negation of minimum representable integer to prevent undefined signed int + // overflow. + if ($2 == std::numeric_limits<YYSTYPE>::min()) + { + $$ = std::numeric_limits<YYSTYPE>::min(); + } + else + { + $$ = -$2; + } } | '+' expression %prec TOK_UNARY { $$ = + $2; diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Input.cpp b/src/3rdparty/angle/src/compiler/preprocessor/Input.cpp index 5541d46f72..0f2327b823 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Input.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/Input.cpp @@ -4,12 +4,13 @@ // found in the LICENSE file. // -#include "Input.h" +#include "compiler/preprocessor/Input.h" #include <algorithm> -#include <cassert> #include <cstring> +#include "common/debug.h" + namespace pp { @@ -17,9 +18,12 @@ Input::Input() : mCount(0), mString(0) { } -Input::Input(size_t count, const char *const string[], const int length[]) : - mCount(count), - mString(string) +Input::~Input() +{ +} + +Input::Input(size_t count, const char *const string[], const int length[]) + : mCount(count), mString(string) { mLength.reserve(mCount); for (size_t i = 0; i < mCount; ++i) @@ -32,7 +36,7 @@ Input::Input(size_t count, const char *const string[], const int length[]) : const char *Input::skipChar() { // This function should only be called when there is a character to skip. - assert(mReadLoc.cIndex < mLength[mReadLoc.sIndex]); + ASSERT(mReadLoc.cIndex < mLength[mReadLoc.sIndex]); ++mReadLoc.cIndex; if (mReadLoc.cIndex == mLength[mReadLoc.sIndex]) { @@ -61,6 +65,11 @@ size_t Input::read(char *buf, size_t maxSize, int *lineNo) { // Line continuation of backslash + newline. skipChar(); + // Fake an EOF if the line number would overflow. + if (*lineNo == INT_MAX) + { + return 0; + } ++(*lineNo); } else if (c != nullptr && (*c) == '\r') @@ -71,6 +80,11 @@ size_t Input::read(char *buf, size_t maxSize, int *lineNo) { skipChar(); } + // Fake an EOF if the line number would overflow. + if (*lineNo == INT_MAX) + { + return 0; + } ++(*lineNo); } else @@ -86,7 +100,7 @@ size_t Input::read(char *buf, size_t maxSize, int *lineNo) while ((nRead < maxRead) && (mReadLoc.sIndex < mCount)) { size_t size = mLength[mReadLoc.sIndex] - mReadLoc.cIndex; - size = std::min(size, maxSize); + size = std::min(size, maxSize); for (size_t i = 0; i < size; ++i) { // Stop if a possible line continuation is encountered. @@ -94,7 +108,7 @@ size_t Input::read(char *buf, size_t maxSize, int *lineNo) // and increments line number if necessary. if (*(mString[mReadLoc.sIndex] + mReadLoc.cIndex + i) == '\\') { - size = i; + size = i; maxRead = nRead + size; // Stop reading right before the backslash. } } @@ -113,4 +127,3 @@ size_t Input::read(char *buf, size_t maxSize, int *lineNo) } } // namespace pp - diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Input.h b/src/3rdparty/angle/src/compiler/preprocessor/Input.h index a1de7ddd86..8c7c7ee19e 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Input.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Input.h @@ -7,7 +7,7 @@ #ifndef COMPILER_PREPROCESSOR_INPUT_H_ #define COMPILER_PREPROCESSOR_INPUT_H_ -#include <stddef.h> +#include <cstddef> #include <vector> namespace pp @@ -18,20 +18,12 @@ class Input { public: Input(); + ~Input(); Input(size_t count, const char *const string[], const int length[]); - size_t count() const - { - return mCount; - } - const char *string(size_t index) const - { - return mString[index]; - } - size_t length(size_t index) const - { - return mLength[index]; - } + size_t count() const { return mCount; } + const char *string(size_t index) const { return mString[index]; } + size_t length(size_t index) const { return mLength[index]; } size_t read(char *buf, size_t maxSize, int *lineNo); @@ -40,11 +32,7 @@ class Input size_t sIndex; // String index; size_t cIndex; // Char index. - Location() - : sIndex(0), - cIndex(0) - { - } + Location() : sIndex(0), cIndex(0) {} }; const Location &readLoc() const { return mReadLoc; } @@ -55,7 +43,7 @@ class Input // Input. size_t mCount; - const char * const *mString; + const char *const *mString; std::vector<size_t> mLength; Location mReadLoc; diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Lexer.cpp b/src/3rdparty/angle/src/compiler/preprocessor/Lexer.cpp index 7c663ee761..89cb3cf44e 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Lexer.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/Lexer.cpp @@ -4,7 +4,7 @@ // found in the LICENSE file. // -#include "Lexer.h" +#include "compiler/preprocessor/Lexer.h" namespace pp { diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Lexer.h b/src/3rdparty/angle/src/compiler/preprocessor/Lexer.h index 990dc5e21d..775bc0a202 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Lexer.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Lexer.h @@ -7,12 +7,14 @@ #ifndef COMPILER_PREPROCESSOR_LEXER_H_ #define COMPILER_PREPROCESSOR_LEXER_H_ +#include "common/angleutils.h" + namespace pp { struct Token; -class Lexer +class Lexer : angle::NonCopyable { public: virtual ~Lexer(); diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Macro.cpp b/src/3rdparty/angle/src/compiler/preprocessor/Macro.cpp index 4c4d5fd2e2..52e2312fe6 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Macro.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/Macro.cpp @@ -4,40 +4,41 @@ // found in the LICENSE file. // -#include "Macro.h" +#include "compiler/preprocessor/Macro.h" -#include <sstream> - -#include "Token.h" +#include "common/angleutils.h" +#include "compiler/preprocessor/Token.h" namespace pp { +Macro::Macro() : predefined(false), disabled(false), expansionCount(0), type(kTypeObj) +{ +} + +Macro::~Macro() +{ +} + bool Macro::equals(const Macro &other) const { - return (type == other.type) && - (name == other.name) && - (parameters == other.parameters) && + return (type == other.type) && (name == other.name) && (parameters == other.parameters) && (replacements == other.replacements); } void PredefineMacro(MacroSet *macroSet, const char *name, int value) { - std::ostringstream stream; - stream << value; - Token token; token.type = Token::CONST_INT; - token.text = stream.str(); + token.text = ToString(value); - Macro macro; - macro.predefined = true; - macro.type = Macro::kTypeObj; - macro.name = name; - macro.replacements.push_back(token); + std::shared_ptr<Macro> macro = std::make_shared<Macro>(); + macro->predefined = true; + macro->type = Macro::kTypeObj; + macro->name = name; + macro->replacements.push_back(token); (*macroSet)[name] = macro; } } // namespace pp - diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Macro.h b/src/3rdparty/angle/src/compiler/preprocessor/Macro.h index 31ee22c26a..c42e172ef9 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Macro.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Macro.h @@ -8,6 +8,7 @@ #define COMPILER_PREPROCESSOR_MACRO_H_ #include <map> +#include <memory> #include <string> #include <vector> @@ -26,16 +27,13 @@ struct Macro typedef std::vector<std::string> Parameters; typedef std::vector<Token> Replacements; - Macro() - : predefined(false), - disabled(false), - type(kTypeObj) - { - } + Macro(); + ~Macro(); bool equals(const Macro &other) const; bool predefined; mutable bool disabled; + mutable int expansionCount; Type type; std::string name; @@ -43,7 +41,7 @@ struct Macro Replacements replacements; }; -typedef std::map<std::string, Macro> MacroSet; +typedef std::map<std::string, std::shared_ptr<Macro>> MacroSet; void PredefineMacro(MacroSet *macroSet, const char *name, int value); diff --git a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.cpp b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.cpp index e878ee345a..d88d3a6853 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.cpp @@ -4,20 +4,25 @@ // found in the LICENSE file. // -#include "MacroExpander.h" +#include "compiler/preprocessor/MacroExpander.h" #include <algorithm> -#include <sstream> -#include "DiagnosticsBase.h" -#include "Token.h" +#include "common/debug.h" +#include "compiler/preprocessor/DiagnosticsBase.h" +#include "compiler/preprocessor/Token.h" namespace pp { +namespace +{ + +const size_t kMaxContextTokens = 10000; + class TokenLexer : public Lexer { - public: + public: typedef std::vector<Token> TokenVector; TokenLexer(TokenVector *tokens) @@ -39,26 +44,61 @@ class TokenLexer : public Lexer } } - private: - PP_DISALLOW_COPY_AND_ASSIGN(TokenLexer); - + private: TokenVector mTokens; TokenVector::const_iterator mIter; }; +} // anonymous namespace + +class MacroExpander::ScopedMacroReenabler final : angle::NonCopyable +{ + public: + ScopedMacroReenabler(MacroExpander *expander); + ~ScopedMacroReenabler(); + + private: + MacroExpander *mExpander; +}; + +MacroExpander::ScopedMacroReenabler::ScopedMacroReenabler(MacroExpander *expander) + : mExpander(expander) +{ + mExpander->mDeferReenablingMacros = true; +} + +MacroExpander::ScopedMacroReenabler::~ScopedMacroReenabler() +{ + mExpander->mDeferReenablingMacros = false; + for (auto macro : mExpander->mMacrosToReenable) + { + // Copying the string here by using substr is a check for use-after-free. It detects + // use-after-free more reliably than just toggling the disabled flag. + ASSERT(macro->name.substr() != ""); + macro->disabled = false; + } + mExpander->mMacrosToReenable.clear(); +} + MacroExpander::MacroExpander(Lexer *lexer, MacroSet *macroSet, Diagnostics *diagnostics, - bool parseDefined) - : mLexer(lexer), mMacroSet(macroSet), mDiagnostics(diagnostics), mParseDefined(parseDefined) + int allowedMacroExpansionDepth) + : mLexer(lexer), + mMacroSet(macroSet), + mDiagnostics(diagnostics), + mTotalTokensInContexts(0), + mAllowedMacroExpansionDepth(allowedMacroExpansionDepth), + mDeferReenablingMacros(false) { } MacroExpander::~MacroExpander() { - for (std::size_t i = 0; i < mContextStack.size(); ++i) + ASSERT(mMacrosToReenable.empty()); + for (MacroContext *context : mContextStack) { - delete mContextStack[i]; + delete context; } } @@ -66,54 +106,11 @@ void MacroExpander::lex(Token *token) { while (true) { - const char kDefined[] = "defined"; - getToken(token); 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) - { - 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; @@ -121,17 +118,22 @@ void MacroExpander::lex(Token *token) if (iter == mMacroSet->end()) break; - const Macro& macro = iter->second; - if (macro.disabled) + std::shared_ptr<Macro> macro = iter->second; + if (macro->disabled) { // If a particular token is not expanded, it is never expanded. token->setExpansionDisabled(true); break; } - if ((macro.type == Macro::kTypeFunc) && !isNextTokenLeftParen()) + + // Bump the expansion count before peeking if the next token is a '(' + // otherwise there could be a #undef of the macro before the next token. + macro->expansionCount++; + if ((macro->type == Macro::kTypeFunc) && !isNextTokenLeftParen()) { // If the token immediately after the macro name is not a '(', // this macro should not be expanded. + macro->expansionCount--; break; } @@ -160,6 +162,7 @@ void MacroExpander::getToken(Token *token) } else { + ASSERT(mTotalTokensInContexts == 0); mLexer->lex(token); } } @@ -170,11 +173,11 @@ void MacroExpander::ungetToken(const Token &token) { MacroContext *context = mContextStack.back(); context->unget(); - assert(context->replacements[context->index] == token); + ASSERT(context->replacements[context->index] == token); } else { - assert(!mReserveToken.get()); + ASSERT(!mReserveToken.get()); mReserveToken.reset(new Token(token)); } } @@ -190,37 +193,48 @@ bool MacroExpander::isNextTokenLeftParen() return lparen; } -bool MacroExpander::pushMacro(const Macro ¯o, const Token &identifier) +bool MacroExpander::pushMacro(std::shared_ptr<Macro> macro, const Token &identifier) { - assert(!macro.disabled); - assert(!identifier.expansionDisabled()); - assert(identifier.type == Token::IDENTIFIER); - assert(identifier.text == macro.name); + ASSERT(!macro->disabled); + ASSERT(!identifier.expansionDisabled()); + ASSERT(identifier.type == Token::IDENTIFIER); + ASSERT(identifier.text == macro->name); std::vector<Token> replacements; - if (!expandMacro(macro, identifier, &replacements)) + if (!expandMacro(*macro, identifier, &replacements)) return false; // Macro is disabled for expansion until it is popped off the stack. - macro.disabled = true; + macro->disabled = true; MacroContext *context = new MacroContext; - context->macro = ¯o; + context->macro = macro; context->replacements.swap(replacements); mContextStack.push_back(context); + mTotalTokensInContexts += context->replacements.size(); return true; } void MacroExpander::popMacro() { - assert(!mContextStack.empty()); + ASSERT(!mContextStack.empty()); MacroContext *context = mContextStack.back(); mContextStack.pop_back(); - assert(context->empty()); - assert(context->macro->disabled); - context->macro->disabled = false; + ASSERT(context->empty()); + ASSERT(context->macro->disabled); + ASSERT(context->macro->expansionCount > 0); + if (mDeferReenablingMacros) + { + mMacrosToReenable.push_back(context->macro); + } + else + { + context->macro->disabled = false; + } + context->macro->expansionCount--; + mTotalTokensInContexts -= context->replacements.size(); delete context; } @@ -237,33 +251,28 @@ bool MacroExpander::expandMacro(const Macro ¯o, SourceLocation replacementLocation = identifier.location; if (macro.type == Macro::kTypeObj) { - replacements->assign(macro.replacements.begin(), - macro.replacements.end()); + replacements->assign(macro.replacements.begin(), macro.replacements.end()); if (macro.predefined) { const char kLine[] = "__LINE__"; const char kFile[] = "__FILE__"; - assert(replacements->size() == 1); - Token& repl = replacements->front(); + ASSERT(replacements->size() == 1); + Token &repl = replacements->front(); if (macro.name == kLine) { - std::ostringstream stream; - stream << identifier.location.line; - repl.text = stream.str(); + repl.text = ToString(identifier.location.line); } else if (macro.name == kFile) { - std::ostringstream stream; - stream << identifier.location.file; - repl.text = stream.str(); + repl.text = ToString(identifier.location.file); } } } else { - assert(macro.type == Macro::kTypeFunc); + ASSERT(macro.type == Macro::kTypeFunc); std::vector<MacroArg> args; args.reserve(macro.parameters.size()); if (!collectMacroArgs(macro, identifier, &args, &replacementLocation)) @@ -274,7 +283,7 @@ bool MacroExpander::expandMacro(const Macro ¯o, for (std::size_t i = 0; i < replacements->size(); ++i) { - Token& repl = replacements->at(i); + Token &repl = replacements->at(i); if (i == 0) { // The first token in the replacement list inherits the padding @@ -294,45 +303,52 @@ bool MacroExpander::collectMacroArgs(const Macro ¯o, { Token token; getToken(&token); - assert(token.type == '('); + ASSERT(token.type == '('); args->push_back(MacroArg()); - for (int openParens = 1; openParens != 0; ) + + // Defer reenabling macros until args collection is finished to avoid the possibility of + // infinite recursion. Otherwise infinite recursion might happen when expanding the args after + // macros have been popped from the context stack when parsing the args. + ScopedMacroReenabler deferReenablingMacros(this); + + int openParens = 1; + while (openParens != 0) { getToken(&token); if (token.type == Token::LAST) { - mDiagnostics->report(Diagnostics::PP_MACRO_UNTERMINATED_INVOCATION, - identifier.location, identifier.text); + mDiagnostics->report(Diagnostics::PP_MACRO_UNTERMINATED_INVOCATION, identifier.location, + identifier.text); // Do not lose EOF token. ungetToken(token); return false; } - bool isArg = false; // True if token is part of the current argument. + bool isArg = false; // True if token is part of the current argument. switch (token.type) { - case '(': - ++openParens; - isArg = true; - break; - case ')': - --openParens; - isArg = openParens != 0; - *closingParenthesisLocation = token.location; - break; - case ',': - // The individual arguments are separated by comma tokens, but - // the comma tokens between matching inner parentheses do not - // seperate arguments. - if (openParens == 1) - args->push_back(MacroArg()); - isArg = openParens != 1; - break; - default: - isArg = true; - break; + case '(': + ++openParens; + isArg = true; + break; + case ')': + --openParens; + isArg = openParens != 0; + *closingParenthesisLocation = token.location; + break; + case ',': + // The individual arguments are separated by comma tokens, but + // the comma tokens between matching inner parentheses do not + // seperate arguments. + if (openParens == 1) + args->push_back(MacroArg()); + isArg = openParens != 1; + break; + default: + isArg = true; + break; } if (isArg) { @@ -353,9 +369,9 @@ bool MacroExpander::collectMacroArgs(const Macro ¯o, // Validate the number of arguments. if (args->size() != params.size()) { - Diagnostics::ID id = args->size() < macro.parameters.size() ? - Diagnostics::PP_MACRO_TOO_FEW_ARGS : - Diagnostics::PP_MACRO_TOO_MANY_ARGS; + Diagnostics::ID id = args->size() < macro.parameters.size() + ? Diagnostics::PP_MACRO_TOO_FEW_ARGS + : Diagnostics::PP_MACRO_TOO_MANY_ARGS; mDiagnostics->report(id, identifier.location, identifier.text); return false; } @@ -363,11 +379,17 @@ bool MacroExpander::collectMacroArgs(const Macro ¯o, // Pre-expand each argument before substitution. // This step expands each argument individually before they are // inserted into the macro body. - for (std::size_t i = 0; i < args->size(); ++i) + size_t numTokens = 0; + for (auto &arg : *args) { - MacroArg &arg = args->at(i); TokenLexer lexer(&arg); - MacroExpander expander(&lexer, mMacroSet, mDiagnostics, mParseDefined); + if (mAllowedMacroExpansionDepth < 1) + { + mDiagnostics->report(Diagnostics::PP_MACRO_INVOCATION_CHAIN_TOO_DEEP, token.location, + token.text); + return false; + } + MacroExpander expander(&lexer, mMacroSet, mDiagnostics, mAllowedMacroExpansionDepth - 1); arg.clear(); expander.lex(&token); @@ -375,6 +397,12 @@ bool MacroExpander::collectMacroArgs(const Macro ¯o, { arg.push_back(token); expander.lex(&token); + numTokens++; + if (numTokens + mTotalTokensInContexts > kMaxContextTokens) + { + mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token.location, token.text); + return false; + } } } return true; @@ -386,6 +414,14 @@ void MacroExpander::replaceMacroParams(const Macro ¯o, { for (std::size_t i = 0; i < macro.replacements.size(); ++i) { + if (!replacements->empty() && + replacements->size() + mTotalTokensInContexts > kMaxContextTokens) + { + const Token &token = replacements->back(); + mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token.location, token.text); + return; + } + const Token &repl = macro.replacements[i]; if (repl.type != Token::IDENTIFIER) { @@ -396,15 +432,15 @@ void MacroExpander::replaceMacroParams(const Macro ¯o, // TODO(alokp): Optimize this. // There is no need to search for macro params every time. // The param index can be cached with the replacement token. - Macro::Parameters::const_iterator iter = std::find( - macro.parameters.begin(), macro.parameters.end(), repl.text); + Macro::Parameters::const_iterator iter = + std::find(macro.parameters.begin(), macro.parameters.end(), repl.text); if (iter == macro.parameters.end()) { replacements->push_back(repl); continue; } - std::size_t iArg = std::distance(macro.parameters.begin(), iter); + std::size_t iArg = std::distance(macro.parameters.begin(), iter); const MacroArg &arg = args[iArg]; if (arg.empty()) { @@ -418,5 +454,28 @@ void MacroExpander::replaceMacroParams(const Macro ¯o, } } -} // namespace pp +MacroExpander::MacroContext::MacroContext() : macro(0), index(0) +{ +} +MacroExpander::MacroContext::~MacroContext() +{ +} + +bool MacroExpander::MacroContext::empty() const +{ + return index == replacements.size(); +} + +const Token &MacroExpander::MacroContext::get() +{ + return replacements[index++]; +} + +void MacroExpander::MacroContext::unget() +{ + ASSERT(index > 0); + --index; +} + +} // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h index dc870f626f..fae7676fb0 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h @@ -7,13 +7,11 @@ #ifndef COMPILER_PREPROCESSOR_MACROEXPANDER_H_ #define COMPILER_PREPROCESSOR_MACROEXPANDER_H_ -#include <cassert> #include <memory> #include <vector> -#include "Lexer.h" -#include "Macro.h" -#include "pp_utils.h" +#include "compiler/preprocessor/Lexer.h" +#include "compiler/preprocessor/Macro.h" namespace pp { @@ -24,24 +22,23 @@ struct SourceLocation; class MacroExpander : public Lexer { public: - MacroExpander(Lexer *lexer, MacroSet *macroSet, Diagnostics *diagnostics, bool parseDefined); + MacroExpander(Lexer *lexer, + MacroSet *macroSet, + Diagnostics *diagnostics, + int allowedMacroExpansionDepth); ~MacroExpander() override; void lex(Token *token) override; private: - PP_DISALLOW_COPY_AND_ASSIGN(MacroExpander); - void getToken(Token *token); void ungetToken(const Token &token); bool isNextTokenLeftParen(); - bool pushMacro(const Macro ¯o, const Token &identifier); + bool pushMacro(std::shared_ptr<Macro> macro, const Token &identifier); void popMacro(); - bool expandMacro(const Macro ¯o, - const Token &identifier, - std::vector<Token> *replacements); + bool expandMacro(const Macro ¯o, const Token &identifier, std::vector<Token> *replacements); typedef std::vector<Token> MacroArg; bool collectMacroArgs(const Macro ¯o, @@ -54,37 +51,31 @@ class MacroExpander : public Lexer struct MacroContext { - const Macro *macro; + MacroContext(); + ~MacroContext(); + bool empty() const; + const Token &get(); + void unget(); + + std::shared_ptr<Macro> macro; std::size_t index; std::vector<Token> replacements; - - MacroContext() - : macro(0), - index(0) - { - } - bool empty() const - { - return index == replacements.size(); - } - const Token &get() - { - return replacements[index++]; - } - void unget() - { - assert(index > 0); - --index; - } }; Lexer *mLexer; MacroSet *mMacroSet; Diagnostics *mDiagnostics; - bool mParseDefined; std::unique_ptr<Token> mReserveToken; std::vector<MacroContext *> mContextStack; + size_t mTotalTokensInContexts; + + int mAllowedMacroExpansionDepth; + + bool mDeferReenablingMacros; + std::vector<std::shared_ptr<Macro>> mMacrosToReenable; + + class ScopedMacroReenabler; }; } // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.cpp b/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.cpp index aeb9c46f9d..349c7b06c7 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.cpp @@ -4,16 +4,15 @@ // found in the LICENSE file. // -#include "Preprocessor.h" +#include "compiler/preprocessor/Preprocessor.h" -#include <cassert> - -#include "DiagnosticsBase.h" -#include "DirectiveParser.h" -#include "Macro.h" -#include "MacroExpander.h" -#include "Token.h" -#include "Tokenizer.h" +#include "common/debug.h" +#include "compiler/preprocessor/DiagnosticsBase.h" +#include "compiler/preprocessor/DirectiveParser.h" +#include "compiler/preprocessor/Macro.h" +#include "compiler/preprocessor/MacroExpander.h" +#include "compiler/preprocessor/Token.h" +#include "compiler/preprocessor/Tokenizer.h" namespace pp { @@ -26,19 +25,26 @@ struct PreprocessorImpl DirectiveParser directiveParser; MacroExpander macroExpander; - PreprocessorImpl(Diagnostics *diag, DirectiveHandler *directiveHandler) + PreprocessorImpl(Diagnostics *diag, + DirectiveHandler *directiveHandler, + const PreprocessorSettings &settings) : diagnostics(diag), tokenizer(diag), - directiveParser(&tokenizer, ¯oSet, diag, directiveHandler), - macroExpander(&directiveParser, ¯oSet, diag, false) + directiveParser(&tokenizer, + ¯oSet, + diag, + directiveHandler, + settings.maxMacroExpansionDepth), + macroExpander(&directiveParser, ¯oSet, diag, settings.maxMacroExpansionDepth) { } }; Preprocessor::Preprocessor(Diagnostics *diagnostics, - DirectiveHandler *directiveHandler) + DirectiveHandler *directiveHandler, + const PreprocessorSettings &settings) { - mImpl = new PreprocessorImpl(diagnostics, directiveHandler); + mImpl = new PreprocessorImpl(diagnostics, directiveHandler, settings); } Preprocessor::~Preprocessor() @@ -46,9 +52,7 @@ Preprocessor::~Preprocessor() delete mImpl; } -bool Preprocessor::init(size_t count, - const char * const string[], - const int length[]) +bool Preprocessor::init(size_t count, const char *const string[], const int length[]) { static const int kDefaultGLSLVersion = 100; @@ -74,23 +78,23 @@ void Preprocessor::lex(Token *token) mImpl->macroExpander.lex(token); switch (token->type) { - // We should not be returning internal preprocessing tokens. - // Convert preprocessing tokens to compiler tokens or report - // diagnostics. - case Token::PP_HASH: - assert(false); - break; - case Token::PP_NUMBER: - mImpl->diagnostics->report(Diagnostics::PP_INVALID_NUMBER, - token->location, token->text); - break; - case Token::PP_OTHER: - mImpl->diagnostics->report(Diagnostics::PP_INVALID_CHARACTER, - token->location, token->text); - break; - default: - validToken = true; - break; + // We should not be returning internal preprocessing tokens. + // Convert preprocessing tokens to compiler tokens or report + // diagnostics. + case Token::PP_HASH: + UNREACHABLE(); + break; + case Token::PP_NUMBER: + mImpl->diagnostics->report(Diagnostics::PP_INVALID_NUMBER, token->location, + token->text); + break; + case Token::PP_OTHER: + mImpl->diagnostics->report(Diagnostics::PP_INVALID_CHARACTER, token->location, + token->text); + break; + default: + validToken = true; + break; } } } diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.h b/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.h index fe25daa123..2fe504f7f9 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.h @@ -7,9 +7,9 @@ #ifndef COMPILER_PREPROCESSOR_PREPROCESSOR_H_ #define COMPILER_PREPROCESSOR_PREPROCESSOR_H_ -#include <stddef.h> +#include <cstddef> -#include "pp_utils.h" +#include "common/angleutils.h" namespace pp { @@ -19,10 +19,18 @@ class DirectiveHandler; struct PreprocessorImpl; struct Token; -class Preprocessor +struct PreprocessorSettings : private angle::NonCopyable +{ + PreprocessorSettings() : maxMacroExpansionDepth(1000) {} + int maxMacroExpansionDepth; +}; + +class Preprocessor : angle::NonCopyable { public: - Preprocessor(Diagnostics *diagnostics, DirectiveHandler *directiveHandler); + Preprocessor(Diagnostics *diagnostics, + DirectiveHandler *directiveHandler, + const PreprocessorSettings &settings); ~Preprocessor(); // count: specifies the number of elements in the string and length arrays. @@ -34,7 +42,7 @@ class Preprocessor // Each element in the length array may contain the length of the // corresponding string or a value less than 0 to indicate that the string // is null terminated. - bool init(size_t count, const char * const string[], const int length[]); + bool init(size_t count, const char *const string[], const int length[]); // Adds a pre-defined macro. void predefineMacro(const char *name, int value); @@ -44,8 +52,6 @@ class Preprocessor void setMaxTokenSize(size_t maxTokenSize); private: - PP_DISALLOW_COPY_AND_ASSIGN(Preprocessor); - PreprocessorImpl *mImpl; }; diff --git a/src/3rdparty/angle/src/compiler/preprocessor/SourceLocation.h b/src/3rdparty/angle/src/compiler/preprocessor/SourceLocation.h index af8a8d5d19..51908a3b4b 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/SourceLocation.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/SourceLocation.h @@ -12,16 +12,8 @@ namespace pp struct SourceLocation { - SourceLocation() - : file(0), - line(0) - { - } - SourceLocation(int f, int l) - : file(f), - line(l) - { - } + SourceLocation() : file(0), line(0) {} + SourceLocation(int f, int l) : file(f), line(l) {} bool equals(const SourceLocation &other) const { diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Token.cpp b/src/3rdparty/angle/src/compiler/preprocessor/Token.cpp index d102654747..ce0ce94f49 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Token.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/Token.cpp @@ -4,28 +4,25 @@ // found in the LICENSE file. // -#include "Token.h" +#include "compiler/preprocessor/Token.h" -#include <cassert> - -#include "numeric_lex.h" +#include "common/debug.h" +#include "compiler/preprocessor/numeric_lex.h" namespace pp { void Token::reset() { - type = 0; - flags = 0; + type = 0; + flags = 0; location = SourceLocation(); text.clear(); } bool Token::equals(const Token &other) const { - return (type == other.type) && - (flags == other.flags) && - (location == other.location) && + return (type == other.type) && (flags == other.flags) && (location == other.location) && (text == other.text); } @@ -55,19 +52,19 @@ void Token::setExpansionDisabled(bool disable) bool Token::iValue(int *value) const { - assert(type == CONST_INT); + ASSERT(type == CONST_INT); return numeric_lex_int(text, value); } bool Token::uValue(unsigned int *value) const { - assert(type == CONST_INT); + ASSERT(type == CONST_INT); return numeric_lex_int(text, value); } bool Token::fValue(float *value) const { - assert(type == CONST_FLOAT); + ASSERT(type == CONST_FLOAT); return numeric_lex_float(text, value); } diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Token.h b/src/3rdparty/angle/src/compiler/preprocessor/Token.h index 347c47e307..26732ab64d 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Token.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Token.h @@ -10,7 +10,7 @@ #include <ostream> #include <string> -#include "SourceLocation.h" +#include "compiler/preprocessor/SourceLocation.h" namespace pp { @@ -19,7 +19,9 @@ struct Token { enum Type { - LAST = 0, // EOF. + // Calling this ERROR causes a conflict with wingdi.h + GOT_ERROR = -1, + LAST = 0, // EOF. IDENTIFIER = 258, @@ -62,33 +64,20 @@ struct Token EXPANSION_DISABLED = 1 << 2 }; - Token() - : type(0), - flags(0) - { - } + Token() : type(0), flags(0) {} void reset(); bool equals(const Token &other) const; // Returns true if this is the first token on line. // It disregards any leading whitespace. - bool atStartOfLine() const - { - return (flags & AT_START_OF_LINE) != 0; - } + bool atStartOfLine() const { return (flags & AT_START_OF_LINE) != 0; } void setAtStartOfLine(bool start); - bool hasLeadingSpace() const - { - return (flags & HAS_LEADING_SPACE) != 0; - } + bool hasLeadingSpace() const { return (flags & HAS_LEADING_SPACE) != 0; } void setHasLeadingSpace(bool space); - bool expansionDisabled() const - { - return (flags & EXPANSION_DISABLED) != 0; - } + bool expansionDisabled() const { return (flags & EXPANSION_DISABLED) != 0; } void setExpansionDisabled(bool disable); // Converts text into numeric value for CONST_INT and CONST_FLOAT token. @@ -113,7 +102,7 @@ inline bool operator!=(const Token &lhs, const Token &rhs) return !lhs.equals(rhs); } -extern std::ostream &operator<<(std::ostream &out, const Token &token); +std::ostream &operator<<(std::ostream &out, const Token &token); } // namepsace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h index 49e64fa209..af4fd7ce7b 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h @@ -7,9 +7,9 @@ #ifndef COMPILER_PREPROCESSOR_TOKENIZER_H_ #define COMPILER_PREPROCESSOR_TOKENIZER_H_ -#include "Input.h" -#include "Lexer.h" -#include "pp_utils.h" +#include "common/angleutils.h" +#include "compiler/preprocessor/Input.h" +#include "compiler/preprocessor/Lexer.h" namespace pp { @@ -34,9 +34,9 @@ class Tokenizer : public Lexer }; Tokenizer(Diagnostics *diagnostics); - ~Tokenizer(); + ~Tokenizer() override; - bool init(size_t count, const char * const string[], const int length[]); + bool init(size_t count, const char *const string[], const int length[]); void setFileNumber(int file); void setLineNumber(int line); @@ -45,13 +45,12 @@ class Tokenizer : public Lexer void lex(Token *token) override; private: - PP_DISALLOW_COPY_AND_ASSIGN(Tokenizer); bool initScanner(); void destroyScanner(); - void *mHandle; // Scanner handle. - Context mContext; // Scanner extra. - size_t mMaxTokenSize; // Maximum token size + void *mHandle; // Scanner handle. + Context mContext; // Scanner extra. + size_t mMaxTokenSize; // Maximum token size }; } // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l index d316da88b1..096812d45f 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l +++ b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l @@ -27,10 +27,10 @@ IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh. #pragma warning(disable: 4005) #endif -#include "Tokenizer.h" +#include "compiler/preprocessor/Tokenizer.h" -#include "DiagnosticsBase.h" -#include "Token.h" +#include "compiler/preprocessor/DiagnosticsBase.h" +#include "compiler/preprocessor/Token.h" #if defined(__GNUC__) // Triggered by the auto-generated yy_fatal_error function. @@ -110,7 +110,14 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".") "/*" { BEGIN(COMMENT); } <COMMENT>[^*\r\n]+ <COMMENT>"*" -<COMMENT>{NEWLINE} { ++yylineno; } +<COMMENT>{NEWLINE} { + if (yylineno == INT_MAX) + { + *yylval = "Integer overflow on line number"; + return pp::Token::GOT_ERROR; + } + ++yylineno; +} <COMMENT>"*/" { yyextra->leadingSpace = true; BEGIN(INITIAL); @@ -237,13 +244,16 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".") [ \t\v\f]+ { yyextra->leadingSpace = true; } {NEWLINE} { + if (yylineno == INT_MAX) + { + *yylval = "Integer overflow on line number"; + return pp::Token::GOT_ERROR; + } ++yylineno; yylval->assign(1, '\n'); return '\n'; } -\\{NEWLINE} { ++yylineno; } - . { yylval->assign(1, yytext[0]); return pp::Token::PP_OTHER; @@ -267,11 +277,17 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".") yylloc->line = yylineno; yylval->clear(); - if (YY_START == COMMENT) + // Line number overflows fake EOFs to exit early, check for this case. + if (yylineno == INT_MAX) { + yyextra->diagnostics->report(pp::Diagnostics::PP_TOKENIZER_ERROR, + pp::SourceLocation(yyfileno, yylineno), + "Integer overflow on line number"); + } + else if (YY_START == COMMENT) { yyextra->diagnostics->report(pp::Diagnostics::PP_EOF_IN_COMMENT, pp::SourceLocation(yyfileno, yylineno), - ""); + "EOF while in a comment"); } yyterminate(); } @@ -280,9 +296,7 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".") namespace pp { -Tokenizer::Tokenizer(Diagnostics *diagnostics) - : mHandle(0), - mMaxTokenSize(256) +Tokenizer::Tokenizer(Diagnostics *diagnostics) : mHandle(nullptr), mMaxTokenSize(256) { mContext.diagnostics = diagnostics; } @@ -320,7 +334,18 @@ void Tokenizer::setMaxTokenSize(size_t maxTokenSize) void Tokenizer::lex(Token *token) { - token->type = yylex(&token->text, &token->location, mHandle); + int tokenType = yylex(&token->text, &token->location, mHandle); + + if (tokenType == Token::GOT_ERROR) + { + mContext.diagnostics->report(Diagnostics::PP_TOKENIZER_ERROR, token->location, token->text); + token->type = Token::LAST; + } + else + { + token->type = tokenType; + } + if (token->text.size() > mMaxTokenSize) { mContext.diagnostics->report(Diagnostics::PP_TOKEN_TOO_LONG, @@ -339,7 +364,7 @@ void Tokenizer::lex(Token *token) bool Tokenizer::initScanner() { - if ((mHandle == NULL) && yylex_init_extra(&mContext, &mHandle)) + if ((mHandle == nullptr) && yylex_init_extra(&mContext, &mHandle)) return false; yyrestart(0, mHandle); @@ -348,11 +373,11 @@ bool Tokenizer::initScanner() void Tokenizer::destroyScanner() { - if (mHandle == NULL) + if (mHandle == nullptr) return; yylex_destroy(mHandle); - mHandle = NULL; + mHandle = nullptr; } } // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h b/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h index b32e42253f..6ea779ab8f 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h @@ -9,15 +9,15 @@ #ifndef COMPILER_PREPROCESSOR_NUMERICLEX_H_ #define COMPILER_PREPROCESSOR_NUMERICLEX_H_ +#include <cmath> #include <sstream> -namespace pp { +namespace pp +{ inline std::ios::fmtflags numeric_base_int(const std::string &str) { - if ((str.size() >= 2) && - (str[0] == '0') && - (str[1] == 'x' || str[1] == 'X')) + if ((str.size() >= 2) && (str[0] == '0') && (str[1] == 'x' || str[1] == 'X')) { return std::ios::hex; } @@ -33,7 +33,7 @@ inline std::ios::fmtflags numeric_base_int(const std::string &str) // of the correct form. They can only fail if the parsed value is too big, // in which case false is returned. -template<typename IntType> +template <typename IntType> bool numeric_lex_int(const std::string &str, IntType *value) { std::istringstream stream(str); @@ -45,7 +45,7 @@ bool numeric_lex_int(const std::string &str, IntType *value) return !stream.fail(); } -template<typename FloatType> +template <typename FloatType> bool numeric_lex_float(const std::string &str, FloatType *value) { // On 64-bit Intel Android, istringstream is broken. Until this is fixed in @@ -63,10 +63,10 @@ bool numeric_lex_float(const std::string &str, FloatType *value) stream.imbue(std::locale::classic()); stream >> (*value); - return !stream.fail(); + return !stream.fail() && std::isfinite(*value); #endif } -} // namespace pp. +} // namespace pp. -#endif // COMPILER_PREPROCESSOR_NUMERICLEX_H_ +#endif // COMPILER_PREPROCESSOR_NUMERICLEX_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/pp_utils.h b/src/3rdparty/angle/src/compiler/preprocessor/pp_utils.h deleted file mode 100644 index 9fba9385c5..0000000000 --- a/src/3rdparty/angle/src/compiler/preprocessor/pp_utils.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// Copyright (c) 2012 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. -// - -// pp_utils.h: Common preprocessor utilities - -#ifndef COMPILER_PREPROCESSOR_PPUTILS_H_ -#define COMPILER_PREPROCESSOR_PPUTILS_H_ - -// A macro to disallow the copy constructor and operator= functions -// This must be used in the private: declarations for a class. -#define PP_DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName &); \ - void operator=(const TypeName &) - -#endif // COMPILER_PREPROCESSOR_PPUTILS_H_ |