diff --git a/Changelog.md b/Changelog.md index 69e9bcbc2..cfc218237 100644 --- a/Changelog.md +++ b/Changelog.md @@ -12,6 +12,7 @@ Bugfixes: * Code generator: Fix ``ABIEncoderV2`` pragma from the current module affecting inherited functions and applied modifiers. * Type Checker: Fix internal compiler error caused by storage parameters with nested mappings in libraries. * Name Resolver: Fix shadowing/same-name warnings for later declarations. + * Contract Level Checker: Add missing check against inheriting functions with ABIEncoderV2 return types in ABIEncoderV1 contracts. ### 0.7.3 (2020-10-07) diff --git a/docs/layout-of-source-files.rst b/docs/layout-of-source-files.rst index ea14c8330..08f3bb4fe 100644 --- a/docs/layout-of-source-files.rst +++ b/docs/layout-of-source-files.rst @@ -119,6 +119,13 @@ decoding types only supported by the new encoder. The compiler can detect this and will issue an error. Simply enabling ``ABIEncoderV2`` for your contract is enough to make the error go away. +.. note:: + This pragma applies to all the code defined in the file where it is activated, + regardless of where that code ends up eventually. This means that a contract + without the ``ABIEncoderV2`` pragma can still contain code that uses the new encoder + by inheriting it from another contract. This is allowed if the new types are only + used internally and not in external function signatures. + .. _smt_checker: SMTChecker diff --git a/libsolidity/analysis/ContractLevelChecker.cpp b/libsolidity/analysis/ContractLevelChecker.cpp index 47f9af62a..97f3fdc98 100644 --- a/libsolidity/analysis/ContractLevelChecker.cpp +++ b/libsolidity/analysis/ContractLevelChecker.cpp @@ -474,7 +474,7 @@ void ContractLevelChecker::checkBaseABICompatibility(ContractDefinition const& _ auto const& currentLoc = func.second->declaration().location(); - for (TypePointer const& paramType: func.second->parameterTypes() + func.second->parameterTypes()) + for (TypePointer const& paramType: func.second->parameterTypes() + func.second->returnParameterTypes()) if (!TypeChecker::typeSupportedByOldABIEncoder(*paramType, false)) { errors.append("Type only supported by ABIEncoderV2", currentLoc); diff --git a/test/libsolidity/syntaxTests/abiEncoder/v1_inheritance_from_contract_defining_v2_event.sol b/test/libsolidity/syntaxTests/abiEncoder/v1_inheritance_from_contract_defining_v2_event.sol new file mode 100644 index 000000000..a1241fcee --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/v1_inheritance_from_contract_defining_v2_event.sol @@ -0,0 +1,15 @@ +==== Source: A ==== +pragma experimental ABIEncoderV2; + +struct Item { + uint x; +} + +contract C { + event Ev(Item); +} +==== Source: B ==== +import "A"; + +contract D is C {} +// ---- diff --git a/test/libsolidity/syntaxTests/abiEncoder/v1_inheritance_from_contract_defining_v2_function_accepting_struct.sol b/test/libsolidity/syntaxTests/abiEncoder/v1_inheritance_from_contract_defining_v2_function_accepting_struct.sol new file mode 100644 index 000000000..23535eafc --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/v1_inheritance_from_contract_defining_v2_function_accepting_struct.sol @@ -0,0 +1,16 @@ +==== Source: A ==== +pragma experimental ABIEncoderV2; + +contract C { + struct Item { + uint x; + } + + function get(Item memory) external view {} +} +==== Source: B ==== +import "A"; + +contract D is C {} +// ---- +// TypeError 6594: (B:13-31): Contract "D" does not use ABIEncoderV2 but wants to inherit from a contract which uses types that require it. Use "pragma experimental ABIEncoderV2;" for the inheriting contract as well to enable the feature. diff --git a/test/libsolidity/syntaxTests/abiEncoder/v1_inheritance_from_contract_defining_v2_function_returning_struct.sol b/test/libsolidity/syntaxTests/abiEncoder/v1_inheritance_from_contract_defining_v2_function_returning_struct.sol new file mode 100644 index 000000000..ba568504e --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/v1_inheritance_from_contract_defining_v2_function_returning_struct.sol @@ -0,0 +1,16 @@ +==== Source: A ==== +pragma experimental ABIEncoderV2; + +contract C { + struct Item { + uint x; + } + + function get() external view returns(Item memory) {} +} +==== Source: B ==== +import "A"; + +contract D is C {} +// ---- +// TypeError 6594: (B:13-31): Contract "D" does not use ABIEncoderV2 but wants to inherit from a contract which uses types that require it. Use "pragma experimental ABIEncoderV2;" for the inheriting contract as well to enable the feature.