diff --git a/libsolidity/AST.h b/libsolidity/AST.h index da6a7d581..db83cf590 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -968,6 +968,18 @@ private: ParameterList const* m_returnParameters; }; +/** + * @brief The Throw statement to throw that triggers a solidity exception(jump to ErrorTag) + */ +class Throw: public Statement +{ +public: + Throw(SourceLocation const& _location): Statement(_location) {} + virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; + virtual void checkTypeRequirements() override{}; +}; + /** * Definition of a variable as a statement inside a function. It requires a type name (which can * also be "var") but the actual assignment can be missing. diff --git a/libsolidity/ASTForward.h b/libsolidity/ASTForward.h index 0ba485a2f..396cf50a4 100644 --- a/libsolidity/ASTForward.h +++ b/libsolidity/ASTForward.h @@ -64,6 +64,7 @@ class ForStatement; class Continue; class Break; class Return; +class Throw; class VariableDeclarationStatement; class ExpressionStatement; class Expression; diff --git a/libsolidity/ASTJsonConverter.cpp b/libsolidity/ASTJsonConverter.cpp index 3d119a4ea..96e5cf2a5 100644 --- a/libsolidity/ASTJsonConverter.cpp +++ b/libsolidity/ASTJsonConverter.cpp @@ -193,6 +193,12 @@ bool ASTJsonConverter::visit(Return const&) return true; } +bool ASTJsonConverter::visit(Throw const&) +{ + addJsonNode("Throw", {}, true);; + return true; +} + bool ASTJsonConverter::visit(VariableDeclarationStatement const&) { addJsonNode("VariableDefinition", {}, true); @@ -364,6 +370,11 @@ void ASTJsonConverter::endVisit(Return const&) goUp(); } +void ASTJsonConverter::endVisit(Throw const&) +{ + goUp(); +} + void ASTJsonConverter::endVisit(VariableDeclarationStatement const&) { goUp(); diff --git a/libsolidity/ASTJsonConverter.h b/libsolidity/ASTJsonConverter.h index 09217e974..77230d92a 100644 --- a/libsolidity/ASTJsonConverter.h +++ b/libsolidity/ASTJsonConverter.h @@ -63,6 +63,7 @@ public: bool visit(Continue const& _node) override; bool visit(Break const& _node) override; bool visit(Return const& _node) override; + bool visit(Throw const& _node) override; bool visit(VariableDeclarationStatement const& _node) override; bool visit(ExpressionStatement const& _node) override; bool visit(Assignment const& _node) override; @@ -93,6 +94,7 @@ public: void endVisit(Continue const&) override; void endVisit(Break const&) override; void endVisit(Return const&) override; + void endVisit(Throw const&) override; void endVisit(VariableDeclarationStatement const&) override; void endVisit(ExpressionStatement const&) override; void endVisit(Assignment const&) override; diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp index a64e8490b..8ed45d87e 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -221,6 +221,13 @@ bool ASTPrinter::visit(Return const& _node) return goDeeper(); } +bool ASTPrinter::visit(Throw const& _node) +{ + writeLine("Throw"); + printSourcePart(_node); + return goDeeper(); +} + bool ASTPrinter::visit(VariableDeclarationStatement const& _node) { writeLine("VariableDeclarationStatement"); @@ -444,6 +451,11 @@ void ASTPrinter::endVisit(Return const&) m_indentation--; } +void ASTPrinter::endVisit(Throw const&) +{ + m_indentation--; +} + void ASTPrinter::endVisit(VariableDeclarationStatement const&) { m_indentation--; diff --git a/libsolidity/ASTPrinter.h b/libsolidity/ASTPrinter.h index 8c8be1120..a12ec0aab 100644 --- a/libsolidity/ASTPrinter.h +++ b/libsolidity/ASTPrinter.h @@ -72,6 +72,7 @@ public: bool visit(Continue const& _node) override; bool visit(Break const& _node) override; bool visit(Return const& _node) override; + bool visit(Throw const& _node) override; bool visit(VariableDeclarationStatement const& _node) override; bool visit(ExpressionStatement const& _node) override; bool visit(Assignment const& _node) override; @@ -110,6 +111,7 @@ public: void endVisit(Continue const&) override; void endVisit(Break const&) override; void endVisit(Return const&) override; + void endVisit(Throw const&) override; void endVisit(VariableDeclarationStatement const&) override; void endVisit(ExpressionStatement const&) override; void endVisit(Assignment const&) override; diff --git a/libsolidity/ASTVisitor.h b/libsolidity/ASTVisitor.h index f78472208..e665396cb 100644 --- a/libsolidity/ASTVisitor.h +++ b/libsolidity/ASTVisitor.h @@ -69,6 +69,7 @@ public: virtual bool visit(Continue& _node) { return visitNode(_node); } virtual bool visit(Break& _node) { return visitNode(_node); } virtual bool visit(Return& _node) { return visitNode(_node); } + virtual bool visit(Throw& _node) { return visitNode(_node); } virtual bool visit(VariableDeclarationStatement& _node) { return visitNode(_node); } virtual bool visit(ExpressionStatement& _node) { return visitNode(_node); } virtual bool visit(Assignment& _node) { return visitNode(_node); } @@ -108,6 +109,7 @@ public: virtual void endVisit(Continue& _node) { endVisitNode(_node); } virtual void endVisit(Break& _node) { endVisitNode(_node); } virtual void endVisit(Return& _node) { endVisitNode(_node); } + virtual void endVisit(Throw& _node) { endVisitNode(_node); } virtual void endVisit(VariableDeclarationStatement& _node) { endVisitNode(_node); } virtual void endVisit(ExpressionStatement& _node) { endVisitNode(_node); } virtual void endVisit(Assignment& _node) { endVisitNode(_node); } @@ -159,6 +161,7 @@ public: virtual bool visit(Continue const& _node) { return visitNode(_node); } virtual bool visit(Break const& _node) { return visitNode(_node); } virtual bool visit(Return const& _node) { return visitNode(_node); } + virtual bool visit(Throw const& _node) { return visitNode(_node); } virtual bool visit(VariableDeclarationStatement const& _node) { return visitNode(_node); } virtual bool visit(ExpressionStatement const& _node) { return visitNode(_node); } virtual bool visit(Assignment const& _node) { return visitNode(_node); } @@ -198,6 +201,7 @@ public: virtual void endVisit(Continue const& _node) { endVisitNode(_node); } virtual void endVisit(Break const& _node) { endVisitNode(_node); } virtual void endVisit(Return const& _node) { endVisitNode(_node); } + virtual void endVisit(Throw const& _node) { endVisitNode(_node); } virtual void endVisit(VariableDeclarationStatement const& _node) { endVisitNode(_node); } virtual void endVisit(ExpressionStatement const& _node) { endVisitNode(_node); } virtual void endVisit(Assignment const& _node) { endVisitNode(_node); } diff --git a/libsolidity/AST_accept.h b/libsolidity/AST_accept.h index 3557f8779..d07c2cd0b 100644 --- a/libsolidity/AST_accept.h +++ b/libsolidity/AST_accept.h @@ -491,6 +491,18 @@ void Return::accept(ASTConstVisitor& _visitor) const _visitor.endVisit(*this); } +void Throw::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + _visitor.endVisit(*this); +} + +void Throw::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + _visitor.endVisit(*this); +} + void ExpressionStatement::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 9bdf45f81..d65826533 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -606,6 +606,13 @@ bool Compiler::visit(Return const& _return) return false; } +bool Compiler::visit(Throw const& _throw) +{ + CompilerContext::LocationSetter locationSetter(m_context, _throw); + m_context.appendJumpTo(m_context.errorTag()); + return false; +} + bool Compiler::visit(VariableDeclarationStatement const& _variableDeclarationStatement) { StackHeightChecker checker(m_context); diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index 7e1d32229..c7dd7d900 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -112,6 +112,7 @@ private: virtual bool visit(Continue const& _continue) override; virtual bool visit(Break const& _break) override; virtual bool visit(Return const& _return) override; + virtual bool visit(Throw const& _throw) override; virtual bool visit(VariableDeclarationStatement const& _variableDeclarationStatement) override; virtual bool visit(ExpressionStatement const& _expressionStatement) override; virtual bool visit(PlaceholderStatement const&) override; diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 24f7734ca..ac9e04c8e 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -622,6 +622,16 @@ ASTPointer Parser::parseStatement() statement = nodeFactory.createNode(expression); break; } + case Token::Throw: + { + ASTNodeFactory nodeFactory(*this); + ASTPointer expression; + if (m_scanner->next() != Token::Semicolon) + BOOST_THROW_EXCEPTION(createParserError("Throw statement cannot have parameters.")); + + statement = nodeFactory.createNode(/*expression*/); + break; + } case Token::Identifier: if (m_insideModifier && m_scanner->currentLiteral() == "_") { diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 1632a6930..2ea7eb01a 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -171,6 +171,7 @@ namespace solidity K(Returns, "returns", 0) \ K(Storage, "storage", 0) \ K(Struct, "struct", 0) \ + K(Throw, "throw", 0) \ K(Var, "var", 0) \ K(While, "while", 0) \ \ @@ -316,7 +317,6 @@ namespace solidity K(Of, "of", 0) \ K(Relocatable, "relocatable", 0) \ K(Switch, "switch", 0) \ - K(Throw, "throw", 0) \ K(Try, "try", 0) \ K(Type, "type", 0) \ K(TypeOf, "typeof", 0) \ diff --git a/libsolidity/grammar.txt b/libsolidity/grammar.txt index 467aebeea..08a74f458 100644 --- a/libsolidity/grammar.txt +++ b/libsolidity/grammar.txt @@ -34,6 +34,7 @@ ForStatement = 'for' '(' (VardefOrExprStmt)? ';' (Expression)? ';' (ExpressionSt Continue = 'continue' ';' Break = 'break' ';' Return = 'return' Expression? ';' +Throw = 'throw' Expression? ';' VariableDefinition = VariableDeclaration ( = Expression )? ';' Expression = Assignment | UnaryOperation | BinaryOperation | FunctionCall | NewExpression | IndexAccess | diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 2ba6ab85c..9c4d0c5b8 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -5265,6 +5265,24 @@ BOOST_AUTO_TEST_CASE(library_stray_values) BOOST_CHECK(callContractFunction("f(uint256)", u256(33)) == encodeArgs(u256(42))); } +BOOST_AUTO_TEST_CASE(simple_throw) +{ + char const* sourceCode = R"( + contract Test { + function f(uint x) returns (uint) { + if (x > 10) + return x + 10; + else + throw; + return 2; + } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("f(uint256)", u256(11)) == encodeArgs(u256(21))); + BOOST_CHECK(callContractFunction("f(uint256)", u256(1)) == encodeArgs()); +} + BOOST_AUTO_TEST_SUITE_END() }