From 8317eb03838975e5ef5890e68d9d4bc6a4f009eb Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 14 Oct 2016 19:28:15 +0100 Subject: [PATCH 1/3] Add test case for bound types without self --- .../SolidityNameAndTypeResolution.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 76141f415..1691b1c5a 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -4020,6 +4020,25 @@ BOOST_AUTO_TEST_CASE(invalid_array_as_statement) BOOST_CHECK(expectError(text, false) == Error::Type::TypeError); } +BOOST_AUTO_TEST_CASE(using_directive_for_missing_selftype) +{ + char const* text = R"( + library B { + function b() {} + } + + contract A { + using B for bytes; + + function a() { + bytes memory x; + x.b(); + } + } + )"; + BOOST_CHECK(expectError(text, false) == Error::Type::TypeError); +} + BOOST_AUTO_TEST_SUITE_END() } From 003359a0b651b78809c37a3b0b96d0a7ff7131d6 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 14 Oct 2016 19:30:04 +0100 Subject: [PATCH 2/3] Ensure that bound functions cannot be defined without self type --- Changelog.md | 1 + libsolidity/ast/Types.cpp | 3 +++ libsolidity/ast/Types.h | 10 ++++++++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Changelog.md b/Changelog.md index fb3b23c78..a5a85eb5c 100644 --- a/Changelog.md +++ b/Changelog.md @@ -8,6 +8,7 @@ Features: Bugfixes: * Disallow unknown options in `solc` + * Proper type checking for bound functions. * Code Generator: expect zero stack increase after `super` as an expression * Inline assembly: support the `address` opcode * Inline assembly: fix parsing of assignment after a label. diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index edb0fbe44..5d3d4f1a7 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2069,6 +2069,9 @@ TypePointer FunctionType::copyAndSetGasOrValue(bool _setGas, bool _setValue) con FunctionTypePointer FunctionType::asMemberFunction(bool _inLibrary, bool _bound) const { + if (_bound && m_parameterTypes.empty()) + return FunctionTypePointer(); + TypePointers parameterTypes; for (auto const& t: m_parameterTypes) { diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index f65d25fbd..3f94d11a6 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -872,7 +872,12 @@ public: m_isConstant(_isConstant), m_isPayable(_isPayable), m_declaration(_declaration) - {} + { + solAssert( + !m_bound || !m_parameterTypes.empty(), + "Attempted construction of bound function without self type" + ); + } TypePointers parameterTypes() const; std::vector parameterNames() const; @@ -940,8 +945,9 @@ public: /// removed and the location of reference types is changed from CallData to Memory. /// This is needed if external functions are called on other contracts, as they cannot return /// dynamic values. + /// Returns empty shared pointer on a failure. Namely, if a bound function has no parameters. /// @param _inLibrary if true, uses DelegateCall as location. - /// @param _bound if true, the argumenst are placed as `arg1.functionName(arg2, ..., argn)`. + /// @param _bound if true, the arguments are placed as `arg1.functionName(arg2, ..., argn)`. FunctionTypePointer asMemberFunction(bool _inLibrary, bool _bound = false) const; private: From fdd1108c1c2e316d143f44d048f1686be2e2eb3a Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 14 Oct 2016 19:30:38 +0100 Subject: [PATCH 3/3] Omit non-convertible bound functions --- libsolidity/ast/Types.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 5d3d4f1a7..068cc138b 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -241,7 +241,8 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition seenFunctions.insert(function); FunctionType funType(*function, false); if (auto fun = funType.asMemberFunction(true, true)) - members.push_back(MemberList::Member(function->name(), fun, function)); + if (_type.isImplicitlyConvertibleTo(*fun->selfType())) + members.push_back(MemberList::Member(function->name(), fun, function)); } } return members;