mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Replace casting of external functions to address by a member named "address".
This commit is contained in:
parent
d3ea86b052
commit
9f6fff2120
@ -1,6 +1,7 @@
|
||||
### 0.6.0 (unreleased)
|
||||
|
||||
Breaking changes:
|
||||
* General: Disallow explicit conversions from external function types to ``address`` and add a member called ``address`` to them as replacement.
|
||||
|
||||
|
||||
Language Features:
|
||||
|
@ -9,6 +9,14 @@ For the full list check
|
||||
`the release changelog <https://github.com/ethereum/solidity/releases/tag/v0.6.0>`_.
|
||||
|
||||
|
||||
Syntactic Only Changes
|
||||
======================
|
||||
|
||||
This section lists purely syntactic changes that do not affect the behavior of existing code.
|
||||
|
||||
* Conversions from external function types to ``address`` are now disallowed. Instead external
|
||||
function types have a member called ``address``, similar to the existing ``selector`` member.
|
||||
|
||||
Semantic Only Changes
|
||||
=====================
|
||||
|
||||
@ -27,6 +35,7 @@ How to update your code
|
||||
|
||||
This section gives detailed instructions on how to update prior code for every breaking change.
|
||||
|
||||
* Change ``address(f)`` to ``f.address`` for ``f`` being a variable of external function type.
|
||||
|
||||
Deprecated Elements
|
||||
===================
|
||||
|
@ -2726,8 +2726,6 @@ bool FunctionType::operator==(Type const& _other) const
|
||||
|
||||
BoolResult FunctionType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
||||
{
|
||||
if (m_kind == Kind::External && _convertTo == *TypeProvider::address())
|
||||
return true;
|
||||
return _convertTo.category() == category();
|
||||
}
|
||||
|
||||
@ -2922,7 +2920,10 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con
|
||||
{
|
||||
MemberList::MemberMap members;
|
||||
if (m_kind == Kind::External)
|
||||
{
|
||||
members.emplace_back("selector", TypeProvider::fixedBytes(4));
|
||||
members.emplace_back("address", TypeProvider::address());
|
||||
}
|
||||
if (m_kind != Kind::BareDelegateCall)
|
||||
{
|
||||
if (isPayable())
|
||||
|
@ -1112,16 +1112,8 @@ void CompilerUtils::convertType(
|
||||
m_context << Instruction::ISZERO << Instruction::ISZERO;
|
||||
break;
|
||||
default:
|
||||
if (stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Address)
|
||||
{
|
||||
FunctionType const& typeOnStack = dynamic_cast<FunctionType const&>(_typeOnStack);
|
||||
solAssert(typeOnStack.kind() == FunctionType::Kind::External, "Only external function type can be converted.");
|
||||
|
||||
// stack: <address> <function_id>
|
||||
m_context << Instruction::POP;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we used to allow conversions from function to address
|
||||
solAssert(!(stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Address), "");
|
||||
if (stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Function)
|
||||
{
|
||||
FunctionType const& typeOnStack = dynamic_cast<FunctionType const&>(_typeOnStack);
|
||||
@ -1142,7 +1134,6 @@ void CompilerUtils::convertType(
|
||||
m_context
|
||||
<< ((u256(1) << (8 * _targetType.storageBytes())) - 1)
|
||||
<< Instruction::AND;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1338,6 +1338,13 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
/// need to store it as bytes4
|
||||
utils().leftShiftNumberOnStack(224);
|
||||
}
|
||||
else if (member == "address")
|
||||
{
|
||||
auto const& functionType = dynamic_cast<FunctionType const&>(*_memberAccess.expression().annotation().type);
|
||||
solAssert(functionType.kind() == FunctionType::Kind::External, "");
|
||||
// stack: <address> <function_id>
|
||||
m_context << Instruction::POP;
|
||||
}
|
||||
else
|
||||
solAssert(
|
||||
!!_memberAccess.expression().annotation().type->memberType(member),
|
||||
|
@ -1552,6 +1552,12 @@ ASTPointer<Expression> Parser::parseLeftHandSideExpression(
|
||||
{
|
||||
m_scanner->next();
|
||||
nodeFactory.markEndPosition();
|
||||
if (m_scanner->currentToken() == Token::Address)
|
||||
{
|
||||
expression = nodeFactory.createNode<MemberAccess>(expression, make_shared<ASTString>("address"));
|
||||
m_scanner->next();
|
||||
}
|
||||
else
|
||||
expression = nodeFactory.createNode<MemberAccess>(expression, expectIdentifierToken());
|
||||
break;
|
||||
}
|
||||
|
@ -11201,25 +11201,6 @@ BOOST_AUTO_TEST_CASE(function_array_cross_calls)
|
||||
ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(5), u256(6), u256(7)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(external_function_to_address)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract C {
|
||||
function f() public returns (bool) {
|
||||
return address(this.f) == address(this);
|
||||
}
|
||||
function g(function() external cb) public returns (address) {
|
||||
return address(cb);
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
compileAndRun(sourceCode, 0, "C");
|
||||
ABI_CHECK(callContractFunction("f()"), encodeArgs(true));
|
||||
ABI_CHECK(callContractFunction("g(function)", fromHex("00000000000000000000000000000000000004226121ff00000000000000000")), encodeArgs(u160(0x42)));
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(copy_internal_function_array_to_storage)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
|
@ -0,0 +1,11 @@
|
||||
contract C {
|
||||
function f() public returns (bool) {
|
||||
return this.f.address == address(this);
|
||||
}
|
||||
function g(function() external cb) public returns (address) {
|
||||
return cb.address;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// f() -> true
|
||||
// g(function): hex"00000000000000000000000000000000000004226121ff00000000000000000" -> 0x42
|
@ -1,5 +1,5 @@
|
||||
contract C {
|
||||
function f() public view returns (address) {
|
||||
return address(this.f);
|
||||
return this.f.address;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
contract C {
|
||||
function f() public view returns (address payable) {
|
||||
return address(this.f);
|
||||
return this.f.address;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (85-100): Return argument type address is not implicitly convertible to expected type (type of first return variable) address payable.
|
||||
// TypeError: (85-99): Return argument type address is not implicitly convertible to expected type (type of first return variable) address payable.
|
||||
|
@ -0,0 +1,9 @@
|
||||
contract C {
|
||||
struct S { uint a; }
|
||||
function f() public pure returns(address) {
|
||||
S memory s = S(42);
|
||||
return s.address;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (129-138): Member "address" not found or not visible after argument-dependent lookup in struct C.S memory.
|
@ -0,0 +1,5 @@
|
||||
contract C {
|
||||
struct S { uint address; }
|
||||
}
|
||||
// ----
|
||||
// ParserError: (33-40): Expected identifier but got 'address'
|
Loading…
Reference in New Issue
Block a user