diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp index 17d5b8c3e..58ebea7b1 100644 --- a/libsolidity/analysis/GlobalContext.cpp +++ b/libsolidity/analysis/GlobalContext.cpp @@ -73,24 +73,24 @@ inline vector> constructMagicVariable return { magicVarDecl("abi", TypeProvider::magic(MagicType::Kind::ABI)), - magicVarDecl("addmod", TypeProvider::function(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::AddMod, false, StateMutability::Pure)), - magicVarDecl("assert", TypeProvider::function(strings{"bool"}, strings{}, FunctionType::Kind::Assert, false, StateMutability::Pure)), + magicVarDecl("addmod", TypeProvider::function(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::AddMod, StateMutability::Pure)), + magicVarDecl("assert", TypeProvider::function(strings{"bool"}, strings{}, FunctionType::Kind::Assert, StateMutability::Pure)), magicVarDecl("block", TypeProvider::magic(MagicType::Kind::Block)), - magicVarDecl("blockhash", TypeProvider::function(strings{"uint256"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)), - magicVarDecl("ecrecover", TypeProvider::function(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Kind::ECRecover, false, StateMutability::Pure)), - magicVarDecl("gasleft", TypeProvider::function(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft, false, StateMutability::View)), - magicVarDecl("keccak256", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)), + magicVarDecl("blockhash", TypeProvider::function(strings{"uint256"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, StateMutability::View)), + magicVarDecl("ecrecover", TypeProvider::function(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Kind::ECRecover, StateMutability::Pure)), + magicVarDecl("gasleft", TypeProvider::function(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft, StateMutability::View)), + magicVarDecl("keccak256", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, StateMutability::Pure)), magicVarDecl("msg", TypeProvider::magic(MagicType::Kind::Message)), - magicVarDecl("mulmod", TypeProvider::function(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::MulMod, false, StateMutability::Pure)), + magicVarDecl("mulmod", TypeProvider::function(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::MulMod, StateMutability::Pure)), magicVarDecl("now", TypeProvider::uint256()), - magicVarDecl("require", TypeProvider::function(strings{"bool"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)), - magicVarDecl("require", TypeProvider::function(strings{"bool", "string memory"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)), - magicVarDecl("revert", TypeProvider::function(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)), - magicVarDecl("revert", TypeProvider::function(strings{"string memory"}, strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)), - magicVarDecl("ripemd160", TypeProvider::function(strings{"bytes memory"}, strings{"bytes20"}, FunctionType::Kind::RIPEMD160, false, StateMutability::Pure)), + magicVarDecl("require", TypeProvider::function(strings{"bool"}, strings{}, FunctionType::Kind::Require, StateMutability::Pure)), + magicVarDecl("require", TypeProvider::function(strings{"bool", "string memory"}, strings{}, FunctionType::Kind::Require, StateMutability::Pure)), + magicVarDecl("revert", TypeProvider::function(strings(), strings(), FunctionType::Kind::Revert, StateMutability::Pure)), + magicVarDecl("revert", TypeProvider::function(strings{"string memory"}, strings(), FunctionType::Kind::Revert, StateMutability::Pure)), + magicVarDecl("ripemd160", TypeProvider::function(strings{"bytes memory"}, strings{"bytes20"}, FunctionType::Kind::RIPEMD160, StateMutability::Pure)), magicVarDecl("selfdestruct", TypeProvider::function(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)), - magicVarDecl("sha256", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA256, false, StateMutability::Pure)), - magicVarDecl("sha3", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)), + magicVarDecl("sha256", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA256, StateMutability::Pure)), + magicVarDecl("sha3", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, StateMutability::Pure)), magicVarDecl("suicide", TypeProvider::function(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)), magicVarDecl("tx", TypeProvider::magic(MagicType::Kind::Transaction)), // Accepts a MagicType that can be any contract type or an Integer type and returns a @@ -99,8 +99,8 @@ inline vector> constructMagicVariable strings{}, strings{}, FunctionType::Kind::MetaType, - true, - StateMutability::Pure + StateMutability::Pure, + FunctionType::Options::withArbitraryParameters() )), }; } diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index d4cffc00e..94f4b80da 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -2885,7 +2885,6 @@ void TypeChecker::endVisit(NewExpression const& _newExpression) strings(1, ""), strings(1, ""), FunctionType::Kind::ObjectCreation, - false, StateMutability::Pure ); _newExpression.annotation().isPure = true; diff --git a/libsolidity/ast/TypeProvider.cpp b/libsolidity/ast/TypeProvider.cpp index 6183493b4..97d230d2e 100644 --- a/libsolidity/ast/TypeProvider.cpp +++ b/libsolidity/ast/TypeProvider.cpp @@ -445,13 +445,18 @@ FunctionType const* TypeProvider::function( strings const& _parameterTypes, strings const& _returnParameterTypes, FunctionType::Kind _kind, - bool _arbitraryParameters, - StateMutability _stateMutability + StateMutability _stateMutability, + FunctionType::Options _options ) { + // Can only use this constructor for "arbitraryParameters". + solAssert(!_options.valueSet && !_options.gasSet && !_options.saltSet && !_options.bound); return createAndGet( - _parameterTypes, _returnParameterTypes, - _kind, _arbitraryParameters, _stateMutability + _parameterTypes, + _returnParameterTypes, + _kind, + _stateMutability, + std::move(_options) ); } @@ -461,13 +466,9 @@ FunctionType const* TypeProvider::function( strings _parameterNames, strings _returnParameterNames, FunctionType::Kind _kind, - bool _arbitraryParameters, StateMutability _stateMutability, Declaration const* _declaration, - bool _gasSet, - bool _valueSet, - bool _bound, - bool _saltSet + FunctionType::Options _options ) { return createAndGet( @@ -476,13 +477,9 @@ FunctionType const* TypeProvider::function( _parameterNames, _returnParameterNames, _kind, - _arbitraryParameters, _stateMutability, _declaration, - _gasSet, - _valueSet, - _bound, - _saltSet + std::move(_options) ); } diff --git a/libsolidity/ast/TypeProvider.h b/libsolidity/ast/TypeProvider.h index 78b8378ca..b089ff1ef 100644 --- a/libsolidity/ast/TypeProvider.h +++ b/libsolidity/ast/TypeProvider.h @@ -149,8 +149,8 @@ public: strings const& _parameterTypes, strings const& _returnParameterTypes, FunctionType::Kind _kind = FunctionType::Kind::Internal, - bool _arbitraryParameters = false, - StateMutability _stateMutability = StateMutability::NonPayable + StateMutability _stateMutability = StateMutability::NonPayable, + FunctionType::Options _options = {} ); /// @returns a highly customized FunctionType, use with care. @@ -160,13 +160,9 @@ public: strings _parameterNames = strings{}, strings _returnParameterNames = strings{}, FunctionType::Kind _kind = FunctionType::Kind::Internal, - bool _arbitraryParameters = false, StateMutability _stateMutability = StateMutability::NonPayable, Declaration const* _declaration = nullptr, - bool _gasSet = false, - bool _valueSet = false, - bool _bound = false, - bool _saltSet = false + FunctionType::Options _options = {} ); /// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index aa1d5820f..da2811a21 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -470,15 +470,15 @@ MemberList::MemberMap AddressType::nativeMembers(ASTNode const*) const {"balance", TypeProvider::uint256()}, {"code", TypeProvider::array(DataLocation::Memory)}, {"codehash", TypeProvider::fixedBytes(32)}, - {"call", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCall, false, StateMutability::Payable)}, - {"callcode", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCallCode, false, StateMutability::Payable)}, - {"delegatecall", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareDelegateCall, false, StateMutability::NonPayable)}, - {"staticcall", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareStaticCall, false, StateMutability::View)} + {"call", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCall, StateMutability::Payable)}, + {"callcode", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCallCode, StateMutability::Payable)}, + {"delegatecall", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareDelegateCall, StateMutability::NonPayable)}, + {"staticcall", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareStaticCall, StateMutability::View)} }; if (m_stateMutability == StateMutability::Payable) { - members.emplace_back(MemberList::Member{"send", TypeProvider::function(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send, false, StateMutability::NonPayable)}); - members.emplace_back(MemberList::Member{"transfer", TypeProvider::function(strings{"uint"}, strings(), FunctionType::Kind::Transfer, false, StateMutability::NonPayable)}); + members.emplace_back(MemberList::Member{"send", TypeProvider::function(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send, StateMutability::NonPayable)}); + members.emplace_back(MemberList::Member{"transfer", TypeProvider::function(strings{"uint"}, strings(), FunctionType::Kind::Transfer, StateMutability::NonPayable)}); } return members; } @@ -2848,7 +2848,6 @@ FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _c parameterNames, strings{""}, Kind::Creation, - false, stateMutability ); } @@ -2942,11 +2941,11 @@ string FunctionType::richIdentifier() const } id += "_" + stateMutabilityToString(m_stateMutability); id += identifierList(m_parameterTypes) + "returns" + identifierList(m_returnParameterTypes); - if (m_gasSet) + if (gasSet()) id += "gas"; - if (m_valueSet) + if (valueSet()) id += "value"; - if (m_saltSet) + if (saltSet()) id += "salt"; if (bound()) id += "bound_to" + identifierList(selfType()); @@ -3094,11 +3093,11 @@ bool FunctionType::nameable() const { return (m_kind == Kind::Internal || m_kind == Kind::External) && - !m_bound && - !m_arbitraryParameters && - !m_gasSet && - !m_valueSet && - !m_saltSet; + !bound() && + !takesArbitraryParameters() && + !gasSet() && + !valueSet() && + !saltSet(); } vector> FunctionType::makeStackItems() const @@ -3140,11 +3139,11 @@ vector> FunctionType::makeStackItems() const break; } - if (m_gasSet) + if (gasSet()) slots.emplace_back("gas", TypeProvider::uint256()); - if (m_valueSet) + if (valueSet()) slots.emplace_back("value", TypeProvider::uint256()); - if (m_saltSet) + if (saltSet()) slots.emplace_back("salt", TypeProvider::fixedBytes(32)); if (bound()) slots.emplace_back("self", m_parameterTypes.front()); @@ -3176,13 +3175,13 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const if (variable && retParamTypes.get().empty()) return FunctionTypePointer(); + solAssert(!takesArbitraryParameters()); return TypeProvider::function( paramTypes, retParamTypes, m_parameterNames, m_returnParameterNames, m_kind, - m_arbitraryParameters, m_stateMutability, m_declaration ); @@ -3237,12 +3236,9 @@ MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) const strings(1, ""), strings(1, ""), Kind::SetValue, - false, StateMutability::Pure, nullptr, - m_gasSet, - m_valueSet, - m_saltSet + Options::fromFunctionType(*this) ) ); } @@ -3255,12 +3251,9 @@ MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) const strings(1, ""), strings(1, ""), Kind::SetGas, - false, StateMutability::Pure, nullptr, - m_gasSet, - m_valueSet, - m_saltSet + Options::fromFunctionType(*this) ) ); return members; @@ -3288,7 +3281,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) const Type const* FunctionType::encodingType() const { - if (m_gasSet || m_valueSet) + if (gasSet() || valueSet()) return nullptr; // Only external functions can be encoded, internal functions cannot leave code boundaries. if (m_kind == Kind::External) @@ -3307,7 +3300,7 @@ TypeResult FunctionType::interfaceType(bool /*_inLibrary*/) const Type const* FunctionType::mobileType() const { - if (m_valueSet || m_gasSet || m_saltSet || m_bound) + if (valueSet() || gasSet() || saltSet() || bound()) return nullptr; // return function without parameter names @@ -3317,13 +3310,9 @@ Type const* FunctionType::mobileType() const strings(m_parameterTypes.size()), strings(m_returnParameterNames.size()), m_kind, - m_arbitraryParameters, m_stateMutability, m_declaration, - m_gasSet, - m_valueSet, - m_bound, - m_saltSet + Options::fromFunctionType(*this) ); } @@ -3409,7 +3398,7 @@ bool FunctionType::equalExcludingStateMutability(FunctionType const& _other) con return false; //@todo this is ugly, but cannot be prevented right now - if (m_gasSet != _other.m_gasSet || m_valueSet != _other.m_valueSet || m_saltSet != _other.m_saltSet) + if (gasSet() != _other.gasSet() || valueSet() != _other.valueSet() || saltSet() != _other.saltSet()) return false; if (bound() != _other.bound()) @@ -3520,41 +3509,39 @@ TypePointers FunctionType::parseElementaryTypeVector(strings const& _types) Type const* FunctionType::copyAndSetCallOptions(bool _setGas, bool _setValue, bool _setSalt) const { solAssert(m_kind != Kind::Declaration, ""); + Options options = Options::fromFunctionType(*this); + if (_setGas) options.gasSet = true; + if (_setValue) options.valueSet = true; + if (_setSalt) options.saltSet = true; return TypeProvider::function( m_parameterTypes, m_returnParameterTypes, m_parameterNames, m_returnParameterNames, m_kind, - m_arbitraryParameters, m_stateMutability, m_declaration, - m_gasSet || _setGas, - m_valueSet || _setValue, - m_saltSet || _setSalt, - m_bound + options ); } FunctionTypePointer FunctionType::asBoundFunction() const { solAssert(!m_parameterTypes.empty(), ""); - solAssert(!m_gasSet, ""); - solAssert(!m_valueSet, ""); - solAssert(!m_saltSet, ""); + solAssert(!gasSet(), ""); + solAssert(!valueSet(), ""); + solAssert(!saltSet(), ""); + Options options = Options::fromFunctionType(*this); + options.bound = true; return TypeProvider::function( m_parameterTypes, m_returnParameterTypes, m_parameterNames, m_returnParameterNames, m_kind, - m_arbitraryParameters, m_stateMutability, m_declaration, - m_gasSet, - m_valueSet, - m_saltSet, - true + options ); } @@ -3592,13 +3579,9 @@ FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary) m_parameterNames, m_returnParameterNames, kind, - m_arbitraryParameters, m_stateMutability, m_declaration, - m_gasSet, - m_valueSet, - m_saltSet, - m_bound + Options::fromFunctionType(*this) ); } @@ -3803,7 +3786,6 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons strings{string{}}, strings{string{}}, FunctionType::Kind::Wrap, - false, /*_arbitraryParameters */ StateMutability::Pure ) ); @@ -3815,7 +3797,6 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons strings{string{}}, strings{string{}}, FunctionType::Kind::Unwrap, - false, /* _arbitraryParameters */ StateMutability::Pure ) ); @@ -3830,8 +3811,9 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons strings{}, strings{string()}, FunctionType::Kind::BytesConcat, - /* _arbitraryParameters */ true, - StateMutability::Pure + StateMutability::Pure, + nullptr, + FunctionType::Options::withArbitraryParameters() )); return members; @@ -3954,7 +3936,7 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const return MemberList::MemberMap({ {"coinbase", TypeProvider::payableAddress()}, {"timestamp", TypeProvider::uint256()}, - {"blockhash", TypeProvider::function(strings{"uint"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)}, + {"blockhash", TypeProvider::function(strings{"uint"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, StateMutability::View)}, {"difficulty", TypeProvider::uint256()}, {"number", TypeProvider::uint256()}, {"gaslimit", TypeProvider::uint256()}, @@ -3982,8 +3964,9 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const strings{}, strings{1, ""}, FunctionType::Kind::ABIEncode, - true, - StateMutability::Pure + StateMutability::Pure, + nullptr, + FunctionType::Options::withArbitraryParameters() )}, {"encodePacked", TypeProvider::function( TypePointers{}, @@ -3991,8 +3974,9 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const strings{}, strings{1, ""}, FunctionType::Kind::ABIEncodePacked, - true, - StateMutability::Pure + StateMutability::Pure, + nullptr, + FunctionType::Options::withArbitraryParameters() )}, {"encodeWithSelector", TypeProvider::function( TypePointers{TypeProvider::fixedBytes(4)}, @@ -4000,8 +3984,9 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const strings{1, ""}, strings{1, ""}, FunctionType::Kind::ABIEncodeWithSelector, - true, - StateMutability::Pure + StateMutability::Pure, + nullptr, + FunctionType::Options::withArbitraryParameters() )}, {"encodeCall", TypeProvider::function( TypePointers{}, @@ -4009,8 +3994,9 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const strings{}, strings{1, ""}, FunctionType::Kind::ABIEncodeCall, - true, - StateMutability::Pure + StateMutability::Pure, + nullptr, + FunctionType::Options::withArbitraryParameters() )}, {"encodeWithSignature", TypeProvider::function( TypePointers{TypeProvider::array(DataLocation::Memory, true)}, @@ -4018,8 +4004,9 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const strings{1, ""}, strings{1, ""}, FunctionType::Kind::ABIEncodeWithSignature, - true, - StateMutability::Pure + StateMutability::Pure, + nullptr, + FunctionType::Options::withArbitraryParameters() )}, {"decode", TypeProvider::function( TypePointers(), @@ -4027,8 +4014,9 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const strings{}, strings{}, FunctionType::Kind::ABIDecode, - true, - StateMutability::Pure + StateMutability::Pure, + nullptr, + FunctionType::Options::withArbitraryParameters() )} }); case Kind::MetaType: diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 8b3826ca0..2f7e6005b 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -1247,6 +1247,38 @@ public: /// Cannot be called. Declaration, }; + struct Options + { + /// true iff the function takes an arbitrary number of arguments of arbitrary types + bool arbitraryParameters = false; + /// true iff the gas value to be used is on the stack + bool gasSet = false; + /// true iff the value to be sent is on the stack + bool valueSet = false; + /// iff the salt value (for create2) to be used is on the stack + bool saltSet = false; + /// true iff the function is called as arg1.fun(arg2, ..., argn). + /// This is achieved through the "using for" directive. + bool bound = false; + + static Options withArbitraryParameters() + { + Options result; + result.arbitraryParameters = true; + return result; + } + static Options fromFunctionType(FunctionType const& _type) + { + Options result; + result.arbitraryParameters = _type.takesArbitraryParameters(); + result.gasSet = _type.gasSet(); + result.valueSet = _type.valueSet(); + result.saltSet = _type.saltSet(); + result.bound = _type.bound(); + return result; + } + }; + /// Creates the type of a function. /// @arg _kind must be Kind::Internal, Kind::External or Kind::Declaration. @@ -1263,18 +1295,21 @@ public: strings const& _parameterTypes, strings const& _returnParameterTypes, Kind _kind, - bool _arbitraryParameters = false, - StateMutability _stateMutability = StateMutability::NonPayable + StateMutability _stateMutability = StateMutability::NonPayable, + Options _options = Options{false, false, false, false, false} ): FunctionType( parseElementaryTypeVector(_parameterTypes), parseElementaryTypeVector(_returnParameterTypes), strings(_parameterTypes.size(), ""), strings(_returnParameterTypes.size(), ""), _kind, - _arbitraryParameters, - _stateMutability + _stateMutability, + nullptr, + std::move(_options) ) { + // In this constructor, only the "arbitrary Parameters" option should be used. + solAssert(!bound() && !gasSet() && !valueSet() && !saltSet()); } /// Detailed constructor, use with care. @@ -1284,13 +1319,9 @@ public: strings _parameterNames = strings(), strings _returnParameterNames = strings(), Kind _kind = Kind::Internal, - bool _arbitraryParameters = false, StateMutability _stateMutability = StateMutability::NonPayable, Declaration const* _declaration = nullptr, - bool _gasSet = false, - bool _valueSet = false, - bool _saltSet = false, - bool _bound = false + Options _options = Options{false, false, false, false, false} ): m_parameterTypes(std::move(_parameterTypes)), m_returnParameterTypes(std::move(_returnParameterTypes)), @@ -1298,12 +1329,8 @@ public: m_returnParameterNames(std::move(_returnParameterNames)), m_kind(_kind), m_stateMutability(_stateMutability), - m_arbitraryParameters(_arbitraryParameters), - m_gasSet(_gasSet), - m_valueSet(_valueSet), - m_bound(_bound), m_declaration(_declaration), - m_saltSet(_saltSet) + m_options(std::move(_options)) { solAssert( m_parameterNames.size() == m_parameterTypes.size(), @@ -1314,7 +1341,7 @@ public: "Return parameter names list must match return parameter types list!" ); solAssert( - !m_bound || !m_parameterTypes.empty(), + !bound() || !m_parameterTypes.empty(), "Attempted construction of bound function without self type" ); } @@ -1408,7 +1435,7 @@ public: /// The only functions that do not pad are hash functions, the low-level call functions /// and abi.encodePacked. bool padArguments() const; - bool takesArbitraryParameters() const { return m_arbitraryParameters; } + bool takesArbitraryParameters() const { return m_options.arbitraryParameters; } /// true iff the function takes a single bytes parameter and it is passed on without padding. bool takesSinglePackedBytesParameter() const { @@ -1427,10 +1454,10 @@ public: } } - bool gasSet() const { return m_gasSet; } - bool valueSet() const { return m_valueSet; } - bool saltSet() const { return m_saltSet; } - bool bound() const { return m_bound; } + bool gasSet() const { return m_options.gasSet; } + bool valueSet() const { return m_options.valueSet; } + bool saltSet() const { return m_options.saltSet; } + bool bound() const { return m_options.bound; } /// @returns a copy of this type, where gas or value are set manually. This will never set one /// of the parameters to false. @@ -1458,15 +1485,8 @@ private: std::vector 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 - /// true iff the function is called as arg1.fun(arg2, ..., argn). - /// This is achieved through the "using for" directive. - bool const m_bound = false; Declaration const* m_declaration = nullptr; - bool m_saltSet = false; ///< true iff the salt value to be used is on the stack + Options const m_options; }; /** diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 78b6f02b6..34a9a1ee8 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -780,6 +780,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) break; case FunctionType::Kind::Send: case FunctionType::Kind::Transfer: + { _functionCall.expression().accept(*this); // Provide the gas stipend manually at first because we may send zero ether. // Will be zeroed if we send more than zero ether. @@ -788,6 +789,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) // gas <- gas * !value m_context << Instruction::SWAP1 << Instruction::DUP2; m_context << Instruction::ISZERO << Instruction::MUL << Instruction::SWAP1; + FunctionType::Options callOptions; + callOptions.valueSet = true; + callOptions.gasSet = true; appendExternalFunctionCall( FunctionType( TypePointers{}, @@ -795,11 +799,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) strings(), strings(), FunctionType::Kind::BareCall, - false, StateMutability::NonPayable, nullptr, - true, - true + callOptions ), {}, false @@ -812,6 +814,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) m_context.appendConditionalRevert(true); } break; + } case FunctionType::Kind::Selfdestruct: acceptAndConvert(*arguments.front(), *function.parameterTypes().front(), true); m_context << Instruction::SELFDESTRUCT;