diff options
author | Alex Beregszaszi <alex@rtfs.hu> | 2017-08-14 22:36:47 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-14 22:36:47 +0800 |
commit | 0a04a35a2e02437ae038af41c947b3e829946bca (patch) | |
tree | 345679632d47ede35d47a799146e76e43afe7297 | |
parent | 4d9790b6d5a490d30ed55b69fa117bc568fa4c64 (diff) | |
parent | a26a5f20ce46800f8deff5724b5c101bb9b5fc1d (diff) | |
download | dexon-solidity-0a04a35a2e02437ae038af41c947b3e829946bca.tar dexon-solidity-0a04a35a2e02437ae038af41c947b3e829946bca.tar.gz dexon-solidity-0a04a35a2e02437ae038af41c947b3e829946bca.tar.bz2 dexon-solidity-0a04a35a2e02437ae038af41c947b3e829946bca.tar.lz dexon-solidity-0a04a35a2e02437ae038af41c947b3e829946bca.tar.xz dexon-solidity-0a04a35a2e02437ae038af41c947b3e829946bca.tar.zst dexon-solidity-0a04a35a2e02437ae038af41c947b3e829946bca.zip |
Merge pull request #2722 from ethereum/statemutability
Introduce state mutability (to replace const/payable)
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 2 | ||||
-rw-r--r-- | libsolidity/ast/AST.h | 28 | ||||
-rw-r--r-- | libsolidity/ast/ASTEnums.h | 52 | ||||
-rw-r--r-- | libsolidity/ast/ASTForward.h | 1 | ||||
-rw-r--r-- | libsolidity/ast/Types.cpp | 53 | ||||
-rw-r--r-- | libsolidity/ast/Types.h | 21 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.cpp | 3 | ||||
-rw-r--r-- | libsolidity/parsing/Parser.cpp | 54 | ||||
-rw-r--r-- | libsolidity/parsing/Parser.h | 5 | ||||
-rw-r--r-- | libsolidity/parsing/Token.h | 1 | ||||
-rw-r--r-- | test/libsolidity/SolidityNameAndTypeResolution.cpp | 9 | ||||
-rw-r--r-- | test/libsolidity/SolidityParser.cpp | 17 |
12 files changed, 141 insertions, 105 deletions
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 8dd45a90..dbc95c4f 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -500,8 +500,6 @@ bool TypeChecker::visit(FunctionDefinition const& _function) m_errorReporter.typeError(_function.location(), "Library functions cannot be payable."); if (!_function.isConstructor() && !_function.isFallback() && !_function.isPartOfExternalInterface()) m_errorReporter.typeError(_function.location(), "Internal functions cannot be payable."); - if (_function.isDeclaredConst()) - m_errorReporter.typeError(_function.location(), "Functions cannot be constant and payable at the same time."); } for (ASTPointer<VariableDeclaration> const& var: _function.parameters() + _function.returnParameters()) { diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index d32cf573..8a577c0c 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -28,6 +28,7 @@ #include <libsolidity/ast/Types.h> #include <libsolidity/interface/Exceptions.h> #include <libsolidity/ast/ASTAnnotations.h> +#include <libsolidity/ast/ASTEnums.h> #include <libevmasm/SourceLocation.h> #include <libevmasm/Instruction.h> @@ -584,21 +585,19 @@ public: SourceLocation const& _location, ASTPointer<ASTString> const& _name, Declaration::Visibility _visibility, + StateMutability _stateMutability, bool _isConstructor, ASTPointer<ASTString> const& _documentation, ASTPointer<ParameterList> const& _parameters, - bool _isDeclaredConst, std::vector<ASTPointer<ModifierInvocation>> const& _modifiers, ASTPointer<ParameterList> const& _returnParameters, - bool _isPayable, ASTPointer<Block> const& _body ): CallableDeclaration(_location, _name, _visibility, _parameters, _returnParameters), Documented(_documentation), ImplementationOptional(_body != nullptr), + m_stateMutability(_stateMutability), m_isConstructor(_isConstructor), - m_isDeclaredConst(_isDeclaredConst), - m_isPayable(_isPayable), m_functionModifiers(_modifiers), m_body(_body) {} @@ -606,10 +605,11 @@ public: virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; + StateMutability stateMutability() const { return m_stateMutability; } bool isConstructor() const { return m_isConstructor; } bool isFallback() const { return name().empty(); } - bool isDeclaredConst() const { return m_isDeclaredConst; } - bool isPayable() const { return m_isPayable; } + bool isDeclaredConst() const { return m_stateMutability == StateMutability::View; } + bool isPayable() const { return m_stateMutability == StateMutability::Payable; } std::vector<ASTPointer<ModifierInvocation>> const& modifiers() const { return m_functionModifiers; } std::vector<ASTPointer<VariableDeclaration>> const& returnParameters() const { return m_returnParameters->parameters(); } Block const& body() const { solAssert(m_body, ""); return *m_body; } @@ -634,9 +634,8 @@ public: virtual FunctionDefinitionAnnotation& annotation() const override; private: + StateMutability m_stateMutability; bool m_isConstructor; - bool m_isDeclaredConst; - bool m_isPayable; std::vector<ASTPointer<ModifierInvocation>> m_functionModifiers; ASTPointer<Block> m_body; }; @@ -896,11 +895,10 @@ public: ASTPointer<ParameterList> const& _parameterTypes, ASTPointer<ParameterList> const& _returnTypes, Declaration::Visibility _visibility, - bool _isDeclaredConst, - bool _isPayable + StateMutability _stateMutability ): TypeName(_location), m_parameterTypes(_parameterTypes), m_returnTypes(_returnTypes), - m_visibility(_visibility), m_isDeclaredConst(_isDeclaredConst), m_isPayable(_isPayable) + m_visibility(_visibility), m_stateMutability(_stateMutability) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; @@ -914,15 +912,15 @@ public: { return m_visibility == Declaration::Visibility::Default ? Declaration::Visibility::Internal : m_visibility; } - bool isDeclaredConst() const { return m_isDeclaredConst; } - bool isPayable() const { return m_isPayable; } + StateMutability stateMutability() const { return m_stateMutability; } + bool isDeclaredConst() const { return m_stateMutability == StateMutability::View; } + bool isPayable() const { return m_stateMutability == StateMutability::Payable; } private: ASTPointer<ParameterList> m_parameterTypes; ASTPointer<ParameterList> m_returnTypes; Declaration::Visibility m_visibility; - bool m_isDeclaredConst; - bool m_isPayable; + StateMutability m_stateMutability; }; /** diff --git a/libsolidity/ast/ASTEnums.h b/libsolidity/ast/ASTEnums.h new file mode 100644 index 00000000..f7c75878 --- /dev/null +++ b/libsolidity/ast/ASTEnums.h @@ -0,0 +1,52 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see <http://www.gnu.org/licenses/>. +*/ +/** + * @date 2017 + * Enums for AST classes. + */ + +#pragma once + +#include <libsolidity/interface/Exceptions.h> + +#include <string> + +namespace dev +{ +namespace solidity +{ + +// How a function can mutate the EVM state. +enum class StateMutability { View, NonPayable, Payable }; + +inline std::string stateMutabilityToString(StateMutability const& _stateMutability) +{ + switch(_stateMutability) + { + case StateMutability::View: + return "view"; + case StateMutability::NonPayable: + return "nonpayable"; + case StateMutability::Payable: + return "payable"; + default: + solAssert(false, "Unknown state mutability."); + } +} + +} +} diff --git a/libsolidity/ast/ASTForward.h b/libsolidity/ast/ASTForward.h index cfeeaa58..15735368 100644 --- a/libsolidity/ast/ASTForward.h +++ b/libsolidity/ast/ASTForward.h @@ -95,6 +95,5 @@ using ASTPointer = std::shared_ptr<T>; using ASTString = std::string; - } } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index a66ccda5..6c2e55f6 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -477,8 +477,8 @@ MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) cons if (isAddress()) return { {"balance", make_shared<IntegerType >(256)}, - {"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareCall, true, false, true)}, - {"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareCallCode, true, false, true)}, + {"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareCall, true, StateMutability::Payable)}, + {"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareCallCode, true, StateMutability::Payable)}, {"delegatecall", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareDelegateCall, true)}, {"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)}, {"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Kind::Transfer)} @@ -2000,8 +2000,7 @@ TypePointer TupleType::closestTemporaryType(TypePointer const& _targetType) cons FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal): m_kind(_isInternal ? Kind::Internal : Kind::External), - m_isConstant(_function.isDeclaredConst()), - m_isPayable(_isInternal ? false : _function.isPayable()), + m_stateMutability(_function.stateMutability()), m_declaration(&_function) { TypePointers params; @@ -2009,6 +2008,9 @@ FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal TypePointers retParams; vector<string> retParamNames; + if (_isInternal && m_stateMutability == StateMutability::Payable) + m_stateMutability = StateMutability::NonPayable; + params.reserve(_function.parameters().size()); paramNames.reserve(_function.parameters().size()); for (ASTPointer<VariableDeclaration> const& var: _function.parameters()) @@ -2030,7 +2032,7 @@ FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal } FunctionType::FunctionType(VariableDeclaration const& _varDecl): - m_kind(Kind::External), m_isConstant(true), m_declaration(&_varDecl) + m_kind(Kind::External), m_stateMutability(StateMutability::View), m_declaration(&_varDecl) { TypePointers paramTypes; vector<string> paramNames; @@ -2090,7 +2092,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl): } FunctionType::FunctionType(EventDefinition const& _event): - m_kind(Kind::Event), m_isConstant(true), m_declaration(&_event) + m_kind(Kind::Event), m_stateMutability(StateMutability::View), m_declaration(&_event) { TypePointers params; vector<string> paramNames; @@ -2107,14 +2109,10 @@ FunctionType::FunctionType(EventDefinition const& _event): FunctionType::FunctionType(FunctionTypeName const& _typeName): m_kind(_typeName.visibility() == VariableDeclaration::Visibility::External ? Kind::External : Kind::Internal), - m_isConstant(_typeName.isDeclaredConst()), - m_isPayable(_typeName.isPayable()) + m_stateMutability(_typeName.stateMutability()) { if (_typeName.isPayable()) - { solAssert(m_kind == Kind::External, "Internal payable function type used."); - solAssert(!m_isConstant, "Payable constant function"); - } for (auto const& t: _typeName.parameterTypes()) { solAssert(t->annotation().type, "Type not set for parameter."); @@ -2142,7 +2140,7 @@ FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _c FunctionDefinition const* constructor = _contract.constructor(); TypePointers parameters; strings parameterNames; - bool payable = false; + StateMutability stateMutability = StateMutability::NonPayable; if (constructor) { @@ -2151,7 +2149,8 @@ FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _c parameterNames.push_back(var->name()); parameters.push_back(var->annotation().type); } - payable = constructor->isPayable(); + if (constructor->isPayable()) + stateMutability = StateMutability::Payable; } return make_shared<FunctionType>( parameters, @@ -2161,8 +2160,7 @@ FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _c Kind::Creation, false, nullptr, - false, - payable + stateMutability ); } @@ -2241,8 +2239,8 @@ bool FunctionType::operator==(Type const& _other) const FunctionType const& other = dynamic_cast<FunctionType const&>(_other); if ( m_kind != other.m_kind || - m_isConstant != other.isConstant() || - m_isPayable != other.isPayable() || + isConstant() != other.isConstant() || + isPayable() != other.isPayable() || m_parameterTypes.size() != other.m_parameterTypes.size() || m_returnParameterTypes.size() != other.m_returnParameterTypes.size() ) @@ -2304,9 +2302,9 @@ string FunctionType::toString(bool _short) const for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it) name += (*it)->toString(_short) + (it + 1 == m_parameterTypes.end() ? "" : ","); name += ")"; - if (m_isConstant) + if (isConstant()) name += " constant"; - if (m_isPayable) + if (isPayable()) name += " payable"; if (m_kind == Kind::External) name += " external"; @@ -2420,8 +2418,7 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const m_kind, m_arbitraryParameters, m_declaration, - m_isConstant, - m_isPayable + m_stateMutability ); } @@ -2438,7 +2435,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con MemberList::MemberMap members; if (m_kind != Kind::BareDelegateCall && m_kind != Kind::DelegateCall) { - if (m_isPayable) + if (isPayable()) members.push_back(MemberList::Member( "value", make_shared<FunctionType>( @@ -2449,8 +2446,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con Kind::SetValue, false, nullptr, - false, - false, + StateMutability::NonPayable, m_gasSet, m_valueSet ) @@ -2467,8 +2463,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con Kind::SetGas, false, nullptr, - false, - false, + StateMutability::NonPayable, m_gasSet, m_valueSet ) @@ -2604,8 +2599,7 @@ TypePointer FunctionType::copyAndSetGasOrValue(bool _setGas, bool _setValue) con m_kind, m_arbitraryParameters, m_declaration, - m_isConstant, - m_isPayable, + m_stateMutability, m_gasSet || _setGas, m_valueSet || _setValue, m_bound @@ -2654,8 +2648,7 @@ FunctionTypePointer FunctionType::asMemberFunction(bool _inLibrary, bool _bound) kind, m_arbitraryParameters, m_declaration, - m_isConstant, - m_isPayable, + m_stateMutability, m_gasSet, m_valueSet, _bound diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 8c9232c6..56546a82 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -24,6 +24,7 @@ #include <libsolidity/interface/Exceptions.h> #include <libsolidity/ast/ASTForward.h> +#include <libsolidity/ast/ASTEnums.h> #include <libsolidity/parsing/Token.h> #include <libdevcore/Common.h> @@ -889,8 +890,7 @@ public: strings const& _returnParameterTypes, Kind _kind = Kind::Internal, bool _arbitraryParameters = false, - bool _constant = false, - bool _payable = false + StateMutability _stateMutability = StateMutability::NonPayable ): FunctionType( parseElementaryTypeVector(_parameterTypes), parseElementaryTypeVector(_returnParameterTypes), @@ -899,8 +899,7 @@ public: _kind, _arbitraryParameters, nullptr, - _constant, - _payable + _stateMutability ) { } @@ -917,8 +916,7 @@ public: Kind _kind = Kind::Internal, bool _arbitraryParameters = false, Declaration const* _declaration = nullptr, - bool _isConstant = false, - bool _isPayable = false, + StateMutability _stateMutability = StateMutability::NonPayable, bool _gasSet = false, bool _valueSet = false, bool _bound = false @@ -928,12 +926,11 @@ public: m_parameterNames(_parameterNames), m_returnParameterNames(_returnParameterNames), m_kind(_kind), + m_stateMutability(_stateMutability), m_arbitraryParameters(_arbitraryParameters), m_gasSet(_gasSet), m_valueSet(_valueSet), m_bound(_bound), - m_isConstant(_isConstant), - m_isPayable(_isPayable), m_declaration(_declaration) { solAssert( @@ -985,6 +982,7 @@ public: /// @returns true if the ABI is used for this call (only meaningful for external calls) bool isBareCall() const; Kind const& kind() const { return m_kind; } + StateMutability stateMutability() const { return m_stateMutability; } /// @returns the external signature of this function type given the function name std::string externalSignature() const; /// @returns the external identifier of this function (the hash of the signature). @@ -995,12 +993,12 @@ public: return *m_declaration; } bool hasDeclaration() const { return !!m_declaration; } - bool isConstant() const { return m_isConstant; } + bool isConstant() const { return m_stateMutability == StateMutability::View; } /// @returns true if the the result of this function only depends on its arguments /// and it does not modify the state. /// Currently, this will only return true for internal functions like keccak and ecrecover. bool isPure() const; - bool isPayable() const { return m_isPayable; } + bool isPayable() const { return m_stateMutability == StateMutability::Payable; } /// @return A shared pointer of an ASTString. /// Can contain a nullptr in which case indicates absence of documentation ASTPointer<ASTString> documentation() const; @@ -1033,13 +1031,12 @@ private: std::vector<std::string> m_parameterNames; std::vector<std::string> m_returnParameterNames; Kind const m_kind; + StateMutability m_stateMutability = StateMutability::NonPayable; /// true if the function takes an arbitrary number of arguments of arbitrary types bool const m_arbitraryParameters = false; bool const m_gasSet = false; ///< true iff the gas value to be used is on the stack bool const m_valueSet = false; ///< true iff the value to be sent is on the stack bool const m_bound = false; ///< true iff the function is called as arg1.fun(arg2, ..., argn) - bool m_isConstant = false; - bool m_isPayable = false; Declaration const* m_declaration = nullptr; }; diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 521d485f..55d35c44 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -645,8 +645,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) FunctionType::Kind::BareCall, false, nullptr, - false, - false, + StateMutability::NonPayable, true, true ), diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 066e3a29..32bd0966 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -307,6 +307,19 @@ Declaration::Visibility Parser::parseVisibilitySpecifier(Token::Value _token) return visibility; } +StateMutability Parser::parseStateMutability(Token::Value _token) +{ + StateMutability stateMutability(StateMutability::NonPayable); + if (_token == Token::Payable) + stateMutability = StateMutability::Payable; + else if (_token == Token::Constant) + stateMutability = StateMutability::View; + else + solAssert(false, "Invalid state mutability specifier."); + m_scanner->next(); + return stateMutability; +} + Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyName, bool _allowModifiers) { FunctionHeaderParserResult result; @@ -321,23 +334,7 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyN while (true) { Token::Value token = m_scanner->currentToken(); - if (token == Token::Constant) - { - if (result.isDeclaredConst) - parserError(string("Multiple \"constant\" specifiers.")); - - result.isDeclaredConst = true; - m_scanner->next(); - } - else if (m_scanner->currentToken() == Token::Payable) - { - if (result.isPayable) - parserError(string("Multiple \"payable\" specifiers.")); - - result.isPayable = true; - m_scanner->next(); - } - else if (_allowModifiers && token == Token::Identifier) + if (_allowModifiers && token == Token::Identifier) { // This can either be a modifier (function declaration) or the name of the // variable (function type name plus variable). @@ -364,6 +361,20 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyN else result.visibility = parseVisibilitySpecifier(token); } + else if (Token::isStateMutabilitySpecifier(token)) + { + if (result.stateMutability != StateMutability::NonPayable) + { + parserError(string( + "State mutability already specified as \"" + + stateMutabilityToString(result.stateMutability) + + "\"." + )); + m_scanner->next(); + } + else + result.stateMutability = parseStateMutability(token); + } else break; } @@ -408,13 +419,12 @@ ASTPointer<ASTNode> Parser::parseFunctionDefinitionOrFunctionTypeStateVariable(A return nodeFactory.createNode<FunctionDefinition>( header.name, header.visibility, + header.stateMutability, c_isConstructor, docstring, header.parameters, - header.isDeclaredConst, header.modifiers, header.returnParameters, - header.isPayable, block ); } @@ -425,8 +435,7 @@ ASTPointer<ASTNode> Parser::parseFunctionDefinitionOrFunctionTypeStateVariable(A header.parameters, header.returnParameters, header.visibility, - header.isDeclaredConst, - header.isPayable + header.stateMutability ); type = parseTypeNameSuffix(type, nodeFactory); VarDeclParserOptions options; @@ -751,8 +760,7 @@ ASTPointer<FunctionTypeName> Parser::parseFunctionType() header.parameters, header.returnParameters, header.visibility, - header.isDeclaredConst, - header.isPayable + header.stateMutability ); } diff --git a/libsolidity/parsing/Parser.h b/libsolidity/parsing/Parser.h index 82ab91a6..97e60baa 100644 --- a/libsolidity/parsing/Parser.h +++ b/libsolidity/parsing/Parser.h @@ -60,8 +60,7 @@ private: ASTPointer<ParameterList> parameters; ASTPointer<ParameterList> returnParameters; Declaration::Visibility visibility = Declaration::Visibility::Default; - bool isDeclaredConst = false; - bool isPayable = false; + StateMutability stateMutability = StateMutability::NonPayable; std::vector<ASTPointer<ModifierInvocation>> modifiers; }; @@ -73,7 +72,7 @@ private: ASTPointer<ContractDefinition> parseContractDefinition(Token::Value _expectedKind); ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier(); Declaration::Visibility parseVisibilitySpecifier(Token::Value _token); - std::string visibilitySpecifierName(Declaration::Visibility _visibility); + StateMutability parseStateMutability(Token::Value _token); FunctionHeaderParserResult parseFunctionHeader(bool _forceEmptyName, bool _allowModifiers); ASTPointer<ASTNode> parseFunctionDefinitionOrFunctionTypeStateVariable(ASTString const* _contractName); ASTPointer<FunctionDefinition> parseFunctionDefinition(ASTString const* _contractName); diff --git a/libsolidity/parsing/Token.h b/libsolidity/parsing/Token.h index 468cbcb7..efbe5e9e 100644 --- a/libsolidity/parsing/Token.h +++ b/libsolidity/parsing/Token.h @@ -290,6 +290,7 @@ public: static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; } static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Internal; } static bool isLocationSpecifier(Value op) { return op == Memory || op == Storage; } + static bool isStateMutabilitySpecifier(Value op) { return op == Constant || op == Payable; } static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == SubEther; } static bool isTimeSubdenomination(Value op) { return op == SubSecond || op == SubMinute || op == SubHour || op == SubDay || op == SubWeek || op == SubYear; } static bool isReservedKeyword(Value op) { return (Abstract <= op && op <= TypeOf); } diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 13843afa..51d60596 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -4771,15 +4771,6 @@ BOOST_AUTO_TEST_CASE(function_variable_mixin) CHECK_ERROR(text, DeclarationError, "Identifier already declared."); } - -BOOST_AUTO_TEST_CASE(payable_constant_conflict) -{ - char const* text = R"( - contract C { function f() payable constant {} } - )"; - CHECK_ERROR(text, TypeError, "Functions cannot be constant and payable at the same time."); -} - BOOST_AUTO_TEST_CASE(calling_payable) { char const* text = R"( diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp index 3890ca21..75cad8d9 100644 --- a/test/libsolidity/SolidityParser.cpp +++ b/test/libsolidity/SolidityParser.cpp @@ -906,22 +906,23 @@ BOOST_AUTO_TEST_CASE(multiple_visibility_specifiers) CHECK_PARSE_ERROR(text, "Visibility already specified as \"private\"."); } -BOOST_AUTO_TEST_CASE(multiple_payable_specifiers) +BOOST_AUTO_TEST_CASE(multiple_statemutability_specifiers) { char const* text = R"( contract c { function f() payable payable {} })"; - CHECK_PARSE_ERROR(text, "Multiple \"payable\" specifiers."); -} - -BOOST_AUTO_TEST_CASE(multiple_constant_specifiers) -{ - char const* text = R"( + CHECK_PARSE_ERROR(text, "State mutability already specified as \"payable\"."); + text = R"( contract c { function f() constant constant {} })"; - CHECK_PARSE_ERROR(text, "Multiple \"constant\" specifiers."); + CHECK_PARSE_ERROR(text, "State mutability already specified as \"view\"."); + text = R"( + contract c { + function f() payable constant {} + })"; + CHECK_PARSE_ERROR(text, "State mutability already specified as \"payable\"."); } BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations) |