Merge pull request #3549 from ethereum/fixmultidim

Properly detect which array and struct types are unsupported by the old ABI encoder.
This commit is contained in:
Alex Beregszaszi 2018-03-06 15:51:17 +01:00 committed by GitHub
commit 83dacbf669
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 83 additions and 6 deletions

View File

@ -22,6 +22,7 @@ Bugfixes:
* Standalone Assembly: Do not ignore input after closing brace of top level block. * Standalone Assembly: Do not ignore input after closing brace of top level block.
* Standard JSON: Catch errors properly when invalid "sources" are passed. * Standard JSON: Catch errors properly when invalid "sources" are passed.
* Standard JSON: Ensure that library addresses supplied are of correct length and hex prefixed. * Standard JSON: Ensure that library addresses supplied are of correct length and hex prefixed.
* Type Checker: Properly detect which array and struct types are unsupported by the old ABI encoder.
* Type Checker: Properly warn when using ``_offset`` and ``_slot`` for constants in inline assembly. * Type Checker: Properly warn when using ``_offset`` and ``_slot`` for constants in inline assembly.
* Commandline interface: throw error if option is unknown * Commandline interface: throw error if option is unknown

View File

@ -34,6 +34,29 @@ using namespace std;
using namespace dev; using namespace dev;
using namespace dev::solidity; using namespace dev::solidity;
namespace
{
bool typeSupportedByOldABIEncoder(Type const& _type)
{
if (_type.dataStoredIn(DataLocation::Storage))
return true;
else if (_type.category() == Type::Category::Struct)
return false;
else if (_type.category() == Type::Category::Array)
{
auto const& arrayType = dynamic_cast<ArrayType const&>(_type);
auto base = arrayType.baseType();
if (!typeSupportedByOldABIEncoder(*base))
return false;
else if (base->category() == Type::Category::Array && base->isDynamicallySized())
return false;
}
return true;
}
}
bool TypeChecker::checkTypeRequirements(ASTNode const& _contract) bool TypeChecker::checkTypeRequirements(ASTNode const& _contract)
{ {
@ -561,13 +584,12 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
m_errorReporter.fatalTypeError(var->location(), "Internal or recursive type is not allowed for public or external functions."); m_errorReporter.fatalTypeError(var->location(), "Internal or recursive type is not allowed for public or external functions.");
if ( if (
_function.visibility() > FunctionDefinition::Visibility::Internal && _function.visibility() > FunctionDefinition::Visibility::Internal &&
type(*var)->category() == Type::Category::Struct && !_function.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) &&
!type(*var)->dataStoredIn(DataLocation::Storage) && !typeSupportedByOldABIEncoder(*type(*var))
!_function.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2)
) )
m_errorReporter.typeError( m_errorReporter.typeError(
var->location(), var->location(),
"Structs are only supported in the new experimental ABI encoder. " "This type is only supported in the new experimental ABI encoder. "
"Use \"pragma experimental ABIEncoderV2;\" to enable the feature." "Use \"pragma experimental ABIEncoderV2;\" to enable the feature."
); );

View File

@ -1589,8 +1589,6 @@ bool ArrayType::canBeUsedExternally(bool _inLibrary) const
return true; return true;
else if (!m_baseType->canBeUsedExternally(_inLibrary)) else if (!m_baseType->canBeUsedExternally(_inLibrary))
return false; return false;
else if (m_baseType->category() == Category::Array && m_baseType->isDynamicallySized())
return false;
else else
return true; return true;
} }

View File

@ -978,6 +978,62 @@ BOOST_AUTO_TEST_CASE(functions_with_stucts_of_non_external_types_in_interface_ne
CHECK_ERROR(text, TypeError, "Internal or recursive type is not allowed for public or external functions."); CHECK_ERROR(text, TypeError, "Internal or recursive type is not allowed for public or external functions.");
} }
BOOST_AUTO_TEST_CASE(returning_multi_dimensional_arrays_new_abi)
{
char const* text = R"(
pragma experimental ABIEncoderV2;
contract C {
function f() public pure returns (string[][]) {}
}
)";
CHECK_WARNING(text, "Experimental features");
}
BOOST_AUTO_TEST_CASE(returning_multi_dimensional_arrays)
{
char const* text = R"(
contract C {
function f() public pure returns (string[][]) {}
}
)";
CHECK_ERROR(text, TypeError, "only supported in the new experimental ABI encoder");
}
BOOST_AUTO_TEST_CASE(returning_multi_dimensional_static_arrays)
{
char const* text = R"(
contract C {
function f() public pure returns (uint[][2]) {}
}
)";
CHECK_ERROR(text, TypeError, "only supported in the new experimental ABI encoder");
}
BOOST_AUTO_TEST_CASE(returning_arrays_in_structs_new_abi)
{
char const* text = R"(
pragma experimental ABIEncoderV2;
contract C {
struct S { string[] s; }
function f() public pure returns (S) {}
}
)";
CHECK_WARNING(text, "Experimental features");
}
BOOST_AUTO_TEST_CASE(returning_arrays_in_structs_arrays)
{
char const* text = R"(
contract C {
struct S { string[] s; }
function f() public pure returns (S x) {}
}
)";
CHECK_ERROR(text, TypeError, "only supported in the new experimental ABI encoder");
}
BOOST_AUTO_TEST_CASE(function_external_call_allowed_conversion) BOOST_AUTO_TEST_CASE(function_external_call_allowed_conversion)
{ {
char const* text = R"( char const* text = R"(