diff --git a/Changelog.md b/Changelog.md index 608e668e1..473282058 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,7 +1,6 @@ ### 0.9.0 (unreleased) Breaking changes: - * `error` is now a keyword that can only be used for defining errors. * Inline Assembly: Consider functions, function parameters and return variables for shadowing checks. diff --git a/docs/090-breaking-changes.rst b/docs/090-breaking-changes.rst index 229b4cb2a..3df7f21da 100644 --- a/docs/090-breaking-changes.rst +++ b/docs/090-breaking-changes.rst @@ -15,7 +15,7 @@ Silent Changes of the Semantics New Restrictions ================ -- `error` is now a keyword and cannot be used as identifier anymore. +... Interface Changes ================= diff --git a/docs/grammar/SolidityLexer.g4 b/docs/grammar/SolidityLexer.g4 index 77856857c..5a73be85f 100644 --- a/docs/grammar/SolidityLexer.g4 +++ b/docs/grammar/SolidityLexer.g4 @@ -29,7 +29,7 @@ Do: 'do'; Else: 'else'; Emit: 'emit'; Enum: 'enum'; -Error: 'error'; +Error: 'error'; // not a real keyword Revert: 'revert'; // not a real keyword Event: 'event'; External: 'external'; diff --git a/docs/grammar/SolidityParser.g4 b/docs/grammar/SolidityParser.g4 index ccd4c8679..0dbc7339d 100644 --- a/docs/grammar/SolidityParser.g4 +++ b/docs/grammar/SolidityParser.g4 @@ -13,7 +13,6 @@ sourceUnit: ( pragmaDirective | importDirective | contractDefinition - | errorDefinition | interfaceDefinition | libraryDefinition | functionDefinition @@ -380,9 +379,9 @@ tupleExpression: LParen (expression? ( Comma expression?)* ) RParen; inlineArrayExpression: LBrack (expression ( Comma expression)* ) RBrack; /** - * Besides regular non-keyword Identifiers, some keywords like 'from' can also be used as identifiers. + * Besides regular non-keyword Identifiers, some keywords like 'from' and 'error' can also be used as identifiers. */ -identifier: Identifier | From | Revert; +identifier: Identifier | From | Error | Revert; literal: stringLiteral | numberLiteral | booleanLiteral | hexStringLiteral | unicodeStringLiteral; booleanLiteral: True | False; diff --git a/liblangutil/Token.h b/liblangutil/Token.h index 9e534684a..eb8015f4d 100644 --- a/liblangutil/Token.h +++ b/liblangutil/Token.h @@ -156,7 +156,6 @@ namespace solidity::langutil K(Else, "else", 0) \ K(Enum, "enum", 0) \ K(Emit, "emit", 0) \ - K(Error, "error", 0) \ K(Event, "event", 0) \ K(External, "external", 0) \ K(Fallback, "fallback", 0) \ diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index f1b2947fd..3f30a07c9 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -116,12 +116,17 @@ ASTPointer Parser::parse(CharStream& _charStream) case Token::Function: nodes.push_back(parseFunctionDefinition(true)); break; - case Token::Error: - nodes.push_back(parseErrorDefinition()); - break; default: + if ( + // Workaround because `error` is not a keyword. + m_scanner->currentToken() == Token::Identifier && + currentLiteral() == "error" && + m_scanner->peekNextToken() == Token::Identifier && + m_scanner->peekNextNextToken() == Token::LParen + ) + nodes.push_back(parseErrorDefinition()); // Constant variable. - if (variableDeclarationStart() && m_scanner->peekNextToken() != Token::EOS) + else if (variableDeclarationStart() && m_scanner->peekNextToken() != Token::EOS) { VarDeclParserOptions options; options.kind = VarDeclKind::FileLevel; @@ -359,7 +364,13 @@ ASTPointer Parser::parseContractDefinition() subNodes.push_back(parseStructDefinition()); else if (currentTokenValue == Token::Enum) subNodes.push_back(parseEnumDefinition()); - else if (currentTokenValue == Token::Error) + else if ( + // Workaround because `error` is not a keyword. + currentTokenValue == Token::Identifier && + currentLiteral() == "error" && + m_scanner->peekNextToken() == Token::Identifier && + m_scanner->peekNextNextToken() == Token::LParen + ) subNodes.push_back(parseErrorDefinition()); else if (variableDeclarationStart()) { @@ -930,7 +941,7 @@ ASTPointer Parser::parseErrorDefinition() ASTNodeFactory nodeFactory(*this); ASTPointer documentation = parseStructuredDocumentation(); - expectToken(Token::Error); + solAssert(*expectIdentifierToken() == "error", ""); auto&& [name, nameLocation] = expectIdentifierWithLocation(); ASTPointer parameters = parseParameterList({}); diff --git a/test/libsolidity/semanticTests/errors/weird_name.sol b/test/libsolidity/semanticTests/errors/weird_name.sol new file mode 100644 index 000000000..5998dc851 --- /dev/null +++ b/test/libsolidity/semanticTests/errors/weird_name.sol @@ -0,0 +1,11 @@ +error error(uint a); +contract C { + function f() public pure { + revert error(2); + } +} +// ==== +// compileViaYul: also +// compileToEwasm: also +// ---- +// f() -> FAILURE, hex"b48fb6cf", hex"0000000000000000000000000000000000000000000000000000000000000002" diff --git a/test/libsolidity/semanticTests/reverts/error_struct.sol b/test/libsolidity/semanticTests/reverts/error_struct.sol new file mode 100644 index 000000000..d837068a7 --- /dev/null +++ b/test/libsolidity/semanticTests/reverts/error_struct.sol @@ -0,0 +1,18 @@ +struct error { uint error; } +contract C { + error test(); + error _struct; + function f() public { + revert test(); + } + function g(uint x) public returns (uint) { + _struct.error = x; + return _struct.error; + } +} +// ==== +// compileViaYul: also +// compileToEwasm: also +// ---- +// f() -> FAILURE, hex"f8a8fd6d" +// g(uint256): 7 -> 7 diff --git a/test/libsolidity/syntaxTests/errors/struct_named_error.sol b/test/libsolidity/syntaxTests/errors/struct_named_error.sol index 6d9be65c5..0ee82ead6 100644 --- a/test/libsolidity/syntaxTests/errors/struct_named_error.sol +++ b/test/libsolidity/syntaxTests/errors/struct_named_error.sol @@ -1,6 +1,6 @@ +// Test that the parser workaround is not breaking. struct error {uint a;} contract C { error x; } // ---- -// ParserError 2314: (7-12): Expected identifier but got 'error' diff --git a/test/libsolidity/syntaxTests/errors/weird_name.sol b/test/libsolidity/syntaxTests/errors/weird_name.sol deleted file mode 100644 index 873fbfecc..000000000 --- a/test/libsolidity/syntaxTests/errors/weird_name.sol +++ /dev/null @@ -1,8 +0,0 @@ -error error(uint a); -contract C { - function f() public pure { - revert error(2); - } -} -// ---- -// ParserError 2314: (6-11): Expected identifier but got 'error'