Merge pull request #12431 from ethereum/fixFun2

Safer constructors for FunctionType
This commit is contained in:
chriseth 2022-01-04 18:18:21 +01:00 committed by GitHub
commit e3bb5ab7b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 142 additions and 139 deletions

View File

@ -73,24 +73,24 @@ inline vector<shared_ptr<MagicVariableDeclaration const>> constructMagicVariable
return { return {
magicVarDecl("abi", TypeProvider::magic(MagicType::Kind::ABI)), magicVarDecl("abi", TypeProvider::magic(MagicType::Kind::ABI)),
magicVarDecl("addmod", TypeProvider::function(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::AddMod, 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, false, StateMutability::Pure)), magicVarDecl("assert", TypeProvider::function(strings{"bool"}, strings{}, FunctionType::Kind::Assert, StateMutability::Pure)),
magicVarDecl("block", TypeProvider::magic(MagicType::Kind::Block)), magicVarDecl("block", TypeProvider::magic(MagicType::Kind::Block)),
magicVarDecl("blockhash", TypeProvider::function(strings{"uint256"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)), 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, false, StateMutability::Pure)), 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, false, StateMutability::View)), magicVarDecl("gasleft", TypeProvider::function(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft, StateMutability::View)),
magicVarDecl("keccak256", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)), magicVarDecl("keccak256", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, StateMutability::Pure)),
magicVarDecl("msg", TypeProvider::magic(MagicType::Kind::Message)), 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("now", TypeProvider::uint256()),
magicVarDecl("require", TypeProvider::function(strings{"bool"}, strings{}, FunctionType::Kind::Require, 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, false, 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, false, StateMutability::Pure)), magicVarDecl("revert", TypeProvider::function(strings(), strings(), FunctionType::Kind::Revert, StateMutability::Pure)),
magicVarDecl("revert", TypeProvider::function(strings{"string memory"}, strings(), FunctionType::Kind::Revert, false, 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, false, 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("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("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, false, 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("suicide", TypeProvider::function(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)),
magicVarDecl("tx", TypeProvider::magic(MagicType::Kind::Transaction)), magicVarDecl("tx", TypeProvider::magic(MagicType::Kind::Transaction)),
// Accepts a MagicType that can be any contract type or an Integer type and returns a // Accepts a MagicType that can be any contract type or an Integer type and returns a
@ -99,8 +99,8 @@ inline vector<shared_ptr<MagicVariableDeclaration const>> constructMagicVariable
strings{}, strings{},
strings{}, strings{},
FunctionType::Kind::MetaType, FunctionType::Kind::MetaType,
true, StateMutability::Pure,
StateMutability::Pure FunctionType::Options::withArbitraryParameters()
)), )),
}; };
} }

View File

@ -2885,7 +2885,6 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
strings(1, ""), strings(1, ""),
strings(1, ""), strings(1, ""),
FunctionType::Kind::ObjectCreation, FunctionType::Kind::ObjectCreation,
false,
StateMutability::Pure StateMutability::Pure
); );
_newExpression.annotation().isPure = true; _newExpression.annotation().isPure = true;

View File

@ -445,13 +445,18 @@ FunctionType const* TypeProvider::function(
strings const& _parameterTypes, strings const& _parameterTypes,
strings const& _returnParameterTypes, strings const& _returnParameterTypes,
FunctionType::Kind _kind, 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<FunctionType>( return createAndGet<FunctionType>(
_parameterTypes, _returnParameterTypes, _parameterTypes,
_kind, _arbitraryParameters, _stateMutability _returnParameterTypes,
_kind,
_stateMutability,
std::move(_options)
); );
} }
@ -461,13 +466,9 @@ FunctionType const* TypeProvider::function(
strings _parameterNames, strings _parameterNames,
strings _returnParameterNames, strings _returnParameterNames,
FunctionType::Kind _kind, FunctionType::Kind _kind,
bool _arbitraryParameters,
StateMutability _stateMutability, StateMutability _stateMutability,
Declaration const* _declaration, Declaration const* _declaration,
bool _gasSet, FunctionType::Options _options
bool _valueSet,
bool _bound,
bool _saltSet
) )
{ {
return createAndGet<FunctionType>( return createAndGet<FunctionType>(
@ -476,13 +477,9 @@ FunctionType const* TypeProvider::function(
_parameterNames, _parameterNames,
_returnParameterNames, _returnParameterNames,
_kind, _kind,
_arbitraryParameters,
_stateMutability, _stateMutability,
_declaration, _declaration,
_gasSet, std::move(_options)
_valueSet,
_bound,
_saltSet
); );
} }

View File

@ -149,8 +149,8 @@ public:
strings const& _parameterTypes, strings const& _parameterTypes,
strings const& _returnParameterTypes, strings const& _returnParameterTypes,
FunctionType::Kind _kind = FunctionType::Kind::Internal, 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. /// @returns a highly customized FunctionType, use with care.
@ -160,13 +160,9 @@ public:
strings _parameterNames = strings{}, strings _parameterNames = strings{},
strings _returnParameterNames = strings{}, strings _returnParameterNames = strings{},
FunctionType::Kind _kind = FunctionType::Kind::Internal, FunctionType::Kind _kind = FunctionType::Kind::Internal,
bool _arbitraryParameters = false,
StateMutability _stateMutability = StateMutability::NonPayable, StateMutability _stateMutability = StateMutability::NonPayable,
Declaration const* _declaration = nullptr, Declaration const* _declaration = nullptr,
bool _gasSet = false, FunctionType::Options _options = {}
bool _valueSet = false,
bool _bound = false,
bool _saltSet = false
); );
/// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does /// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does

View File

@ -470,15 +470,15 @@ MemberList::MemberMap AddressType::nativeMembers(ASTNode const*) const
{"balance", TypeProvider::uint256()}, {"balance", TypeProvider::uint256()},
{"code", TypeProvider::array(DataLocation::Memory)}, {"code", TypeProvider::array(DataLocation::Memory)},
{"codehash", TypeProvider::fixedBytes(32)}, {"codehash", TypeProvider::fixedBytes(32)},
{"call", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCall, false, StateMutability::Payable)}, {"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, false, 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, false, StateMutability::NonPayable)}, {"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, false, StateMutability::View)} {"staticcall", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareStaticCall, StateMutability::View)}
}; };
if (m_stateMutability == StateMutability::Payable) 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{"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, false, StateMutability::NonPayable)}); members.emplace_back(MemberList::Member{"transfer", TypeProvider::function(strings{"uint"}, strings(), FunctionType::Kind::Transfer, StateMutability::NonPayable)});
} }
return members; return members;
} }
@ -2848,7 +2848,6 @@ FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _c
parameterNames, parameterNames,
strings{""}, strings{""},
Kind::Creation, Kind::Creation,
false,
stateMutability stateMutability
); );
} }
@ -2942,11 +2941,11 @@ string FunctionType::richIdentifier() const
} }
id += "_" + stateMutabilityToString(m_stateMutability); id += "_" + stateMutabilityToString(m_stateMutability);
id += identifierList(m_parameterTypes) + "returns" + identifierList(m_returnParameterTypes); id += identifierList(m_parameterTypes) + "returns" + identifierList(m_returnParameterTypes);
if (m_gasSet) if (gasSet())
id += "gas"; id += "gas";
if (m_valueSet) if (valueSet())
id += "value"; id += "value";
if (m_saltSet) if (saltSet())
id += "salt"; id += "salt";
if (bound()) if (bound())
id += "bound_to" + identifierList(selfType()); id += "bound_to" + identifierList(selfType());
@ -3094,11 +3093,11 @@ bool FunctionType::nameable() const
{ {
return return
(m_kind == Kind::Internal || m_kind == Kind::External) && (m_kind == Kind::Internal || m_kind == Kind::External) &&
!m_bound && !bound() &&
!m_arbitraryParameters && !takesArbitraryParameters() &&
!m_gasSet && !gasSet() &&
!m_valueSet && !valueSet() &&
!m_saltSet; !saltSet();
} }
vector<tuple<string, Type const*>> FunctionType::makeStackItems() const vector<tuple<string, Type const*>> FunctionType::makeStackItems() const
@ -3140,11 +3139,11 @@ vector<tuple<string, Type const*>> FunctionType::makeStackItems() const
break; break;
} }
if (m_gasSet) if (gasSet())
slots.emplace_back("gas", TypeProvider::uint256()); slots.emplace_back("gas", TypeProvider::uint256());
if (m_valueSet) if (valueSet())
slots.emplace_back("value", TypeProvider::uint256()); slots.emplace_back("value", TypeProvider::uint256());
if (m_saltSet) if (saltSet())
slots.emplace_back("salt", TypeProvider::fixedBytes(32)); slots.emplace_back("salt", TypeProvider::fixedBytes(32));
if (bound()) if (bound())
slots.emplace_back("self", m_parameterTypes.front()); slots.emplace_back("self", m_parameterTypes.front());
@ -3176,13 +3175,13 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const
if (variable && retParamTypes.get().empty()) if (variable && retParamTypes.get().empty())
return FunctionTypePointer(); return FunctionTypePointer();
solAssert(!takesArbitraryParameters());
return TypeProvider::function( return TypeProvider::function(
paramTypes, paramTypes,
retParamTypes, retParamTypes,
m_parameterNames, m_parameterNames,
m_returnParameterNames, m_returnParameterNames,
m_kind, m_kind,
m_arbitraryParameters,
m_stateMutability, m_stateMutability,
m_declaration m_declaration
); );
@ -3237,12 +3236,9 @@ MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) const
strings(1, ""), strings(1, ""),
strings(1, ""), strings(1, ""),
Kind::SetValue, Kind::SetValue,
false,
StateMutability::Pure, StateMutability::Pure,
nullptr, nullptr,
m_gasSet, Options::fromFunctionType(*this)
m_valueSet,
m_saltSet
) )
); );
} }
@ -3255,12 +3251,9 @@ MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) const
strings(1, ""), strings(1, ""),
strings(1, ""), strings(1, ""),
Kind::SetGas, Kind::SetGas,
false,
StateMutability::Pure, StateMutability::Pure,
nullptr, nullptr,
m_gasSet, Options::fromFunctionType(*this)
m_valueSet,
m_saltSet
) )
); );
return members; return members;
@ -3288,7 +3281,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) const
Type const* FunctionType::encodingType() const Type const* FunctionType::encodingType() const
{ {
if (m_gasSet || m_valueSet) if (gasSet() || valueSet())
return nullptr; return nullptr;
// Only external functions can be encoded, internal functions cannot leave code boundaries. // Only external functions can be encoded, internal functions cannot leave code boundaries.
if (m_kind == Kind::External) if (m_kind == Kind::External)
@ -3307,7 +3300,7 @@ TypeResult FunctionType::interfaceType(bool /*_inLibrary*/) const
Type const* FunctionType::mobileType() const Type const* FunctionType::mobileType() const
{ {
if (m_valueSet || m_gasSet || m_saltSet || m_bound) if (valueSet() || gasSet() || saltSet() || bound())
return nullptr; return nullptr;
// return function without parameter names // return function without parameter names
@ -3317,13 +3310,9 @@ Type const* FunctionType::mobileType() const
strings(m_parameterTypes.size()), strings(m_parameterTypes.size()),
strings(m_returnParameterNames.size()), strings(m_returnParameterNames.size()),
m_kind, m_kind,
m_arbitraryParameters,
m_stateMutability, m_stateMutability,
m_declaration, m_declaration,
m_gasSet, Options::fromFunctionType(*this)
m_valueSet,
m_bound,
m_saltSet
); );
} }
@ -3409,7 +3398,7 @@ bool FunctionType::equalExcludingStateMutability(FunctionType const& _other) con
return false; return false;
//@todo this is ugly, but cannot be prevented right now //@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; return false;
if (bound() != _other.bound()) 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 Type const* FunctionType::copyAndSetCallOptions(bool _setGas, bool _setValue, bool _setSalt) const
{ {
solAssert(m_kind != Kind::Declaration, ""); 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( return TypeProvider::function(
m_parameterTypes, m_parameterTypes,
m_returnParameterTypes, m_returnParameterTypes,
m_parameterNames, m_parameterNames,
m_returnParameterNames, m_returnParameterNames,
m_kind, m_kind,
m_arbitraryParameters,
m_stateMutability, m_stateMutability,
m_declaration, m_declaration,
m_gasSet || _setGas, options
m_valueSet || _setValue,
m_saltSet || _setSalt,
m_bound
); );
} }
FunctionTypePointer FunctionType::asBoundFunction() const FunctionTypePointer FunctionType::asBoundFunction() const
{ {
solAssert(!m_parameterTypes.empty(), ""); solAssert(!m_parameterTypes.empty(), "");
solAssert(!m_gasSet, ""); solAssert(!gasSet(), "");
solAssert(!m_valueSet, ""); solAssert(!valueSet(), "");
solAssert(!m_saltSet, ""); solAssert(!saltSet(), "");
Options options = Options::fromFunctionType(*this);
options.bound = true;
return TypeProvider::function( return TypeProvider::function(
m_parameterTypes, m_parameterTypes,
m_returnParameterTypes, m_returnParameterTypes,
m_parameterNames, m_parameterNames,
m_returnParameterNames, m_returnParameterNames,
m_kind, m_kind,
m_arbitraryParameters,
m_stateMutability, m_stateMutability,
m_declaration, m_declaration,
m_gasSet, options
m_valueSet,
m_saltSet,
true
); );
} }
@ -3592,13 +3579,9 @@ FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary)
m_parameterNames, m_parameterNames,
m_returnParameterNames, m_returnParameterNames,
kind, kind,
m_arbitraryParameters,
m_stateMutability, m_stateMutability,
m_declaration, m_declaration,
m_gasSet, Options::fromFunctionType(*this)
m_valueSet,
m_saltSet,
m_bound
); );
} }
@ -3803,7 +3786,6 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons
strings{string{}}, strings{string{}},
strings{string{}}, strings{string{}},
FunctionType::Kind::Wrap, FunctionType::Kind::Wrap,
false, /*_arbitraryParameters */
StateMutability::Pure StateMutability::Pure
) )
); );
@ -3815,7 +3797,6 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons
strings{string{}}, strings{string{}},
strings{string{}}, strings{string{}},
FunctionType::Kind::Unwrap, FunctionType::Kind::Unwrap,
false, /* _arbitraryParameters */
StateMutability::Pure StateMutability::Pure
) )
); );
@ -3830,8 +3811,9 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons
strings{}, strings{},
strings{string()}, strings{string()},
FunctionType::Kind::BytesConcat, FunctionType::Kind::BytesConcat,
/* _arbitraryParameters */ true, StateMutability::Pure,
StateMutability::Pure nullptr,
FunctionType::Options::withArbitraryParameters()
)); ));
return members; return members;
@ -3954,7 +3936,7 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
return MemberList::MemberMap({ return MemberList::MemberMap({
{"coinbase", TypeProvider::payableAddress()}, {"coinbase", TypeProvider::payableAddress()},
{"timestamp", TypeProvider::uint256()}, {"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()}, {"difficulty", TypeProvider::uint256()},
{"number", TypeProvider::uint256()}, {"number", TypeProvider::uint256()},
{"gaslimit", TypeProvider::uint256()}, {"gaslimit", TypeProvider::uint256()},
@ -3982,8 +3964,9 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
strings{}, strings{},
strings{1, ""}, strings{1, ""},
FunctionType::Kind::ABIEncode, FunctionType::Kind::ABIEncode,
true, StateMutability::Pure,
StateMutability::Pure nullptr,
FunctionType::Options::withArbitraryParameters()
)}, )},
{"encodePacked", TypeProvider::function( {"encodePacked", TypeProvider::function(
TypePointers{}, TypePointers{},
@ -3991,8 +3974,9 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
strings{}, strings{},
strings{1, ""}, strings{1, ""},
FunctionType::Kind::ABIEncodePacked, FunctionType::Kind::ABIEncodePacked,
true, StateMutability::Pure,
StateMutability::Pure nullptr,
FunctionType::Options::withArbitraryParameters()
)}, )},
{"encodeWithSelector", TypeProvider::function( {"encodeWithSelector", TypeProvider::function(
TypePointers{TypeProvider::fixedBytes(4)}, TypePointers{TypeProvider::fixedBytes(4)},
@ -4000,8 +3984,9 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
strings{1, ""}, strings{1, ""},
strings{1, ""}, strings{1, ""},
FunctionType::Kind::ABIEncodeWithSelector, FunctionType::Kind::ABIEncodeWithSelector,
true, StateMutability::Pure,
StateMutability::Pure nullptr,
FunctionType::Options::withArbitraryParameters()
)}, )},
{"encodeCall", TypeProvider::function( {"encodeCall", TypeProvider::function(
TypePointers{}, TypePointers{},
@ -4009,8 +3994,9 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
strings{}, strings{},
strings{1, ""}, strings{1, ""},
FunctionType::Kind::ABIEncodeCall, FunctionType::Kind::ABIEncodeCall,
true, StateMutability::Pure,
StateMutability::Pure nullptr,
FunctionType::Options::withArbitraryParameters()
)}, )},
{"encodeWithSignature", TypeProvider::function( {"encodeWithSignature", TypeProvider::function(
TypePointers{TypeProvider::array(DataLocation::Memory, true)}, TypePointers{TypeProvider::array(DataLocation::Memory, true)},
@ -4018,8 +4004,9 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
strings{1, ""}, strings{1, ""},
strings{1, ""}, strings{1, ""},
FunctionType::Kind::ABIEncodeWithSignature, FunctionType::Kind::ABIEncodeWithSignature,
true, StateMutability::Pure,
StateMutability::Pure nullptr,
FunctionType::Options::withArbitraryParameters()
)}, )},
{"decode", TypeProvider::function( {"decode", TypeProvider::function(
TypePointers(), TypePointers(),
@ -4027,8 +4014,9 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
strings{}, strings{},
strings{}, strings{},
FunctionType::Kind::ABIDecode, FunctionType::Kind::ABIDecode,
true, StateMutability::Pure,
StateMutability::Pure nullptr,
FunctionType::Options::withArbitraryParameters()
)} )}
}); });
case Kind::MetaType: case Kind::MetaType:

View File

@ -1247,6 +1247,38 @@ public:
/// Cannot be called. /// Cannot be called.
Declaration, 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. /// Creates the type of a function.
/// @arg _kind must be Kind::Internal, Kind::External or Kind::Declaration. /// @arg _kind must be Kind::Internal, Kind::External or Kind::Declaration.
@ -1263,18 +1295,21 @@ public:
strings const& _parameterTypes, strings const& _parameterTypes,
strings const& _returnParameterTypes, strings const& _returnParameterTypes,
Kind _kind, Kind _kind,
bool _arbitraryParameters = false, StateMutability _stateMutability = StateMutability::NonPayable,
StateMutability _stateMutability = StateMutability::NonPayable Options _options = Options{false, false, false, false, false}
): FunctionType( ): FunctionType(
parseElementaryTypeVector(_parameterTypes), parseElementaryTypeVector(_parameterTypes),
parseElementaryTypeVector(_returnParameterTypes), parseElementaryTypeVector(_returnParameterTypes),
strings(_parameterTypes.size(), ""), strings(_parameterTypes.size(), ""),
strings(_returnParameterTypes.size(), ""), strings(_returnParameterTypes.size(), ""),
_kind, _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. /// Detailed constructor, use with care.
@ -1284,13 +1319,9 @@ public:
strings _parameterNames = strings(), strings _parameterNames = strings(),
strings _returnParameterNames = strings(), strings _returnParameterNames = strings(),
Kind _kind = Kind::Internal, Kind _kind = Kind::Internal,
bool _arbitraryParameters = false,
StateMutability _stateMutability = StateMutability::NonPayable, StateMutability _stateMutability = StateMutability::NonPayable,
Declaration const* _declaration = nullptr, Declaration const* _declaration = nullptr,
bool _gasSet = false, Options _options = Options{false, false, false, false, false}
bool _valueSet = false,
bool _saltSet = false,
bool _bound = false
): ):
m_parameterTypes(std::move(_parameterTypes)), m_parameterTypes(std::move(_parameterTypes)),
m_returnParameterTypes(std::move(_returnParameterTypes)), m_returnParameterTypes(std::move(_returnParameterTypes)),
@ -1298,12 +1329,8 @@ public:
m_returnParameterNames(std::move(_returnParameterNames)), m_returnParameterNames(std::move(_returnParameterNames)),
m_kind(_kind), m_kind(_kind),
m_stateMutability(_stateMutability), m_stateMutability(_stateMutability),
m_arbitraryParameters(_arbitraryParameters),
m_gasSet(_gasSet),
m_valueSet(_valueSet),
m_bound(_bound),
m_declaration(_declaration), m_declaration(_declaration),
m_saltSet(_saltSet) m_options(std::move(_options))
{ {
solAssert( solAssert(
m_parameterNames.size() == m_parameterTypes.size(), m_parameterNames.size() == m_parameterTypes.size(),
@ -1314,7 +1341,7 @@ public:
"Return parameter names list must match return parameter types list!" "Return parameter names list must match return parameter types list!"
); );
solAssert( solAssert(
!m_bound || !m_parameterTypes.empty(), !bound() || !m_parameterTypes.empty(),
"Attempted construction of bound function without self type" "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 /// The only functions that do not pad are hash functions, the low-level call functions
/// and abi.encodePacked. /// and abi.encodePacked.
bool padArguments() const; 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. /// true iff the function takes a single bytes parameter and it is passed on without padding.
bool takesSinglePackedBytesParameter() const bool takesSinglePackedBytesParameter() const
{ {
@ -1427,10 +1454,10 @@ public:
} }
} }
bool gasSet() const { return m_gasSet; } bool gasSet() const { return m_options.gasSet; }
bool valueSet() const { return m_valueSet; } bool valueSet() const { return m_options.valueSet; }
bool saltSet() const { return m_saltSet; } bool saltSet() const { return m_options.saltSet; }
bool bound() const { return m_bound; } 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 /// @returns a copy of this type, where gas or value are set manually. This will never set one
/// of the parameters to false. /// of the parameters to false.
@ -1458,15 +1485,8 @@ private:
std::vector<std::string> m_returnParameterNames; std::vector<std::string> m_returnParameterNames;
Kind const m_kind; Kind const m_kind;
StateMutability m_stateMutability = StateMutability::NonPayable; 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; 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;
}; };
/** /**

View File

@ -780,6 +780,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
break; break;
case FunctionType::Kind::Send: case FunctionType::Kind::Send:
case FunctionType::Kind::Transfer: case FunctionType::Kind::Transfer:
{
_functionCall.expression().accept(*this); _functionCall.expression().accept(*this);
// Provide the gas stipend manually at first because we may send zero ether. // Provide the gas stipend manually at first because we may send zero ether.
// Will be zeroed if we send more than 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 // gas <- gas * !value
m_context << Instruction::SWAP1 << Instruction::DUP2; m_context << Instruction::SWAP1 << Instruction::DUP2;
m_context << Instruction::ISZERO << Instruction::MUL << Instruction::SWAP1; m_context << Instruction::ISZERO << Instruction::MUL << Instruction::SWAP1;
FunctionType::Options callOptions;
callOptions.valueSet = true;
callOptions.gasSet = true;
appendExternalFunctionCall( appendExternalFunctionCall(
FunctionType( FunctionType(
TypePointers{}, TypePointers{},
@ -795,11 +799,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
strings(), strings(),
strings(), strings(),
FunctionType::Kind::BareCall, FunctionType::Kind::BareCall,
false,
StateMutability::NonPayable, StateMutability::NonPayable,
nullptr, nullptr,
true, callOptions
true
), ),
{}, {},
false false
@ -812,6 +814,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
m_context.appendConditionalRevert(true); m_context.appendConditionalRevert(true);
} }
break; break;
}
case FunctionType::Kind::Selfdestruct: case FunctionType::Kind::Selfdestruct:
acceptAndConvert(*arguments.front(), *function.parameterTypes().front(), true); acceptAndConvert(*arguments.front(), *function.parameterTypes().front(), true);
m_context << Instruction::SELFDESTRUCT; m_context << Instruction::SELFDESTRUCT;