Skip to content

Commit 5225a5b

Browse files
authored
Merge pull request ethereum#1630 from ethereum/function-to-address
Explicit external function type to address conversion
2 parents c1a675d + ee147e1 commit 5225a5b

7 files changed

+85
-1
lines changed

Changelog.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
### 0.4.10 (unreleased)
22

3+
Features:
4+
* Type system: Support explicit conversion of external function to address.
5+
36
### 0.4.9 (2017-01-31)
47

58
Features:

libsolidity/ast/Types.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -2158,6 +2158,17 @@ bool FunctionType::operator==(Type const& _other) const
21582158
return true;
21592159
}
21602160

2161+
bool FunctionType::isExplicitlyConvertibleTo(Type const& _convertTo) const
2162+
{
2163+
if (m_location == Location::External && _convertTo.category() == Category::Integer)
2164+
{
2165+
IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo);
2166+
if (convertTo.isAddress())
2167+
return true;
2168+
}
2169+
return _convertTo.category() == category();
2170+
}
2171+
21612172
TypePointer FunctionType::unaryOperatorResult(Token::Value _operator) const
21622173
{
21632174
if (_operator == Token::Value::Delete)

libsolidity/ast/Types.h

+1
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,7 @@ class FunctionType: public Type
922922

923923
virtual std::string identifier() const override;
924924
virtual bool operator==(Type const& _other) const override;
925+
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
925926
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
926927
virtual std::string canonicalName(bool /*_addDataLocation*/) const override;
927928
virtual std::string toString(bool _short) const override;

libsolidity/codegen/CompilerUtils.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,20 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
787787
if (_cleanupNeeded)
788788
m_context << Instruction::ISZERO << Instruction::ISZERO;
789789
break;
790+
case Type::Category::Function:
791+
{
792+
if (targetTypeCategory == Type::Category::Integer)
793+
{
794+
IntegerType const& targetType = dynamic_cast<IntegerType const&>(_targetType);
795+
solAssert(targetType.isAddress(), "Function type can only be converted to address.");
796+
FunctionType const& typeOnStack = dynamic_cast<FunctionType const&>(_typeOnStack);
797+
solAssert(typeOnStack.location() == FunctionType::Location::External, "Only external function type can be converted.");
798+
799+
// stack: <address> <function_id>
800+
m_context << Instruction::POP;
801+
break;
802+
}
803+
}
790804
default:
791805
// All other types should not be convertible to non-equal types.
792806
solAssert(_typeOnStack == _targetType, "Invalid type conversion requested.");

libsolidity/codegen/ContractCompiler.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class StackHeightChecker
4242
public:
4343
StackHeightChecker(CompilerContext const& _context):
4444
m_context(_context), stackHeight(m_context.stackHeight()) {}
45-
void check() { solAssert(m_context.stackHeight() == stackHeight, "I sense a disturbance in the stack."); }
45+
void check() { solAssert(m_context.stackHeight() == stackHeight, std::string("I sense a disturbance in the stack: ") + std::to_string(m_context.stackHeight()) + " vs " + std::to_string(stackHeight)); }
4646
private:
4747
CompilerContext const& m_context;
4848
unsigned stackHeight;

test/libsolidity/SolidityEndToEndTest.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -8462,6 +8462,25 @@ BOOST_AUTO_TEST_CASE(function_array_cross_calls)
84628462
BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(5), u256(6), u256(7)));
84638463
}
84648464

8465+
BOOST_AUTO_TEST_CASE(external_function_to_address)
8466+
{
8467+
char const* sourceCode = R"(
8468+
contract C {
8469+
function f() returns (bool) {
8470+
return address(this.f) == address(this);
8471+
}
8472+
function g(function() external cb) returns (address) {
8473+
return address(cb);
8474+
}
8475+
}
8476+
)";
8477+
8478+
compileAndRun(sourceCode, 0, "C");
8479+
BOOST_CHECK(callContractFunction("f()") == encodeArgs(true));
8480+
BOOST_CHECK(callContractFunction("g(function)", fromHex("00000000000000000000000000000000000004226121ff00000000000000000")) == encodeArgs(u160(0x42)));
8481+
}
8482+
8483+
84658484
BOOST_AUTO_TEST_CASE(copy_internal_function_array_to_storage)
84668485
{
84678486
char const* sourceCode = R"(

test/libsolidity/SolidityNameAndTypeResolution.cpp

+36
Original file line numberDiff line numberDiff line change
@@ -4725,6 +4725,42 @@ BOOST_AUTO_TEST_CASE(delete_external_function_type_invalid)
47254725
CHECK_ERROR(text, TypeError, "");
47264726
}
47274727

4728+
BOOST_AUTO_TEST_CASE(external_function_type_to_address)
4729+
{
4730+
char const* text = R"(
4731+
contract C {
4732+
function f() returns (address) {
4733+
return address(this.f);
4734+
}
4735+
}
4736+
)";
4737+
CHECK_SUCCESS(text);
4738+
}
4739+
4740+
BOOST_AUTO_TEST_CASE(internal_function_type_to_address)
4741+
{
4742+
char const* text = R"(
4743+
contract C {
4744+
function f() returns (address) {
4745+
return address(f);
4746+
}
4747+
}
4748+
)";
4749+
CHECK_ERROR(text, TypeError, "Explicit type conversion not allowed");
4750+
}
4751+
4752+
BOOST_AUTO_TEST_CASE(external_function_type_to_uint)
4753+
{
4754+
char const* text = R"(
4755+
contract C {
4756+
function f() returns (uint) {
4757+
return uint(this.f);
4758+
}
4759+
}
4760+
)";
4761+
CHECK_ERROR(text, TypeError, "Explicit type conversion not allowed");
4762+
}
4763+
47284764
BOOST_AUTO_TEST_CASE(invalid_fixed_point_literal)
47294765
{
47304766
char const* text = R"(

0 commit comments

Comments
 (0)