diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 1bcfdcdc8..54c37e923 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -583,13 +583,18 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) if (auto referenceType = dynamic_cast(varType)) { - auto result = referenceType->validForLocation(referenceType->location()); + BoolResult result = referenceType->validForLocation(referenceType->location()); if (result) { bool isLibraryStorageParameter = (_variable.isLibraryFunctionParameter() && referenceType->location() == DataLocation::Storage); bool callDataCheckRequired = ((_variable.isConstructorParameter() || _variable.isPublicCallableParameter()) && !isLibraryStorageParameter); if (callDataCheckRequired) - result = referenceType->validForLocation(DataLocation::CallData); + { + if (!referenceType->interfaceType(false)) + solAssert(m_errorReporter.hasErrors(), ""); + else + result = referenceType->validForLocation(DataLocation::CallData); + } } if (!result) { diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 2ee749f1a..c043e19b3 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -769,6 +769,8 @@ public: bool isPointer() const; /// @returns true if this is valid to be stored in data location _loc + /// The function mostly checks sizes. For calldata, this should only be called + /// if the type has an interfaceType. virtual BoolResult validForLocation(DataLocation _loc) const = 0; bool operator==(ReferenceType const& _other) const diff --git a/test/libsolidity/syntaxTests/abiEncoder/external_functions_taking_internal_types_struct_array_with_function_type.sol b/test/libsolidity/syntaxTests/abiEncoder/external_functions_taking_internal_types_struct_array_with_function_type.sol new file mode 100644 index 000000000..ad46b4abe --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/external_functions_taking_internal_types_struct_array_with_function_type.sol @@ -0,0 +1,8 @@ +pragma abicoder v2; + +contract C { + struct S { function() internal a; } + function f(S[2] memory) public {} +} +// ---- +// TypeError 4103: (89-100): Internal type is not allowed for public or external functions. diff --git a/test/libsolidity/syntaxTests/abiEncoder/external_functions_taking_internal_types_struct_with_array_of_function_types.sol b/test/libsolidity/syntaxTests/abiEncoder/external_functions_taking_internal_types_struct_with_array_of_function_types.sol new file mode 100644 index 000000000..ca0610e69 --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/external_functions_taking_internal_types_struct_with_array_of_function_types.sol @@ -0,0 +1,8 @@ +pragma abicoder v2; + +contract C { + struct S { function() internal[2] a; } + function f(S memory) public {} +} +// ---- +// TypeError 4103: (92-100): Internal type is not allowed for public or external functions.