diff --git a/Changelog.md b/Changelog.md index 47cb71732..e113a9997 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,8 @@ ### 0.7.6 (unreleased) +Language Features: + * The fallback function can now also have a single ``calldata`` argument (equaling ``msg.data``) and return ``bytes memory`` (which will not be ABI-encoded but returned as-is). + Compiler Features: * SMTChecker: Support named arguments in function calls. * SMTChecker: Support struct constructor. diff --git a/docs/contracts/functions.rst b/docs/contracts/functions.rst index aa9263ff8..8ddb15a44 100644 --- a/docs/contracts/functions.rst +++ b/docs/contracts/functions.rst @@ -275,7 +275,10 @@ A contract can have at most one ``receive`` function, declared using ``receive() external payable { ... }`` (without the ``function`` keyword). This function cannot have arguments, cannot return anything and must have -``external`` visibility and ``payable`` state mutability. It is executed on a +``external`` visibility and ``payable`` state mutability. +It can be virtual, can override and can have modifiers. + +The receive function is executed on a call to the contract with empty calldata. This is the function that is executed on plain Ether transfers (e.g. via ``.send()`` or ``.transfer()``). If no such function exists, but a payable :ref:`fallback function ` @@ -339,15 +342,22 @@ Below you can see an example of a Sink contract that uses function ``receive``. Fallback Function ================= -A contract can have at most one ``fallback`` function, declared using ``fallback () external [payable]`` -(without the ``function`` keyword). -This function cannot have arguments, cannot return anything and must have ``external`` visibility. -It is executed on a call to the contract if none of the other +A contract can have at most one ``fallback`` function, declared using either ``fallback () external [payable]`` +or ``fallback (bytes calldata _input) external [payable] returns (bytes memory _output)`` +(both without the ``function`` keyword). +This function must have ``external`` visibility. A fallback function can be virtual, can override +and can have modifiers. + +The fallback function is executed on a call to the contract if none of the other functions match the given function signature, or if no data was supplied at all and there is no :ref:`receive Ether function `. The fallback function always receives data, but in order to also receive Ether it must be marked ``payable``. +If the version with parameters is used, ``_input`` will contain the full data sent to the contract +(equal to ``msg.data``) and can return data in ``_output``. The returned data will not be +ABI-encoded. Instead it will be returned without modifications (not even padding). + In the worst case, if a payable fallback function is also used in place of a receive function, it can only rely on 2300 gas being available (see :ref:`receive Ether function ` @@ -364,12 +374,11 @@ operations as long as there is enough gas passed on to it. to distinguish Ether transfers from interface confusions. .. note:: - Even though the fallback function cannot have arguments, one can still use ``msg.data`` to retrieve - any payload supplied with the call. - After having checked the first four bytes of ``msg.data``, + If you want to decode the input data, you can check the first four bytes + for the function selector and then you can use ``abi.decode`` together with the array slice syntax to decode ABI-encoded data: - ``(c, d) = abi.decode(msg.data[4:], (uint256, uint256));`` + ``(c, d) = abi.decode(_input[4:], (uint256, uint256));`` Note that this should only be used as a last resort and proper functions should be used instead. diff --git a/docs/grammar/Solidity.g4 b/docs/grammar/Solidity.g4 index 8246ba073..9a99aa475 100644 --- a/docs/grammar/Solidity.g4 +++ b/docs/grammar/Solidity.g4 @@ -84,7 +84,8 @@ contractBodyElement: constructorDefinition | functionDefinition | modifierDefinition - | fallbackReceiveFunctionDefinition + | fallbackFunctionDefinition + | receiveFunctionDefinition | structDefinition | enumDefinition | stateVariableDeclaration @@ -189,9 +190,32 @@ locals[ (Semicolon | body=block); /** - * Definitions of the special fallback and receive functions. + * Definition of the special fallback function. */ -fallbackReceiveFunctionDefinition +fallbackFunctionDefinition +locals[ + boolean visibilitySet = false, + boolean mutabilitySet = false, + boolean virtualSet = false, + boolean overrideSpecifierSet = false, + boolean hasParameters = false +] +: + kind=Fallback LParen (parameterList { $hasParameters = true; } )? RParen + ( + {!$visibilitySet}? External {$visibilitySet = true;} + | {!$mutabilitySet}? stateMutability {$mutabilitySet = true;} + | modifierInvocation + | {!$virtualSet}? Virtual {$virtualSet = true;} + | {!$overrideSpecifierSet}? overrideSpecifier {$overrideSpecifierSet = true;} + )* + ( {$hasParameters}? Returns LParen returnParameters=parameterList RParen | {!$hasParameters}? ) + (Semicolon | body=block); + +/** + * Definition of the special receive function. + */ +receiveFunctionDefinition locals[ boolean visibilitySet = false, boolean mutabilitySet = false, @@ -199,10 +223,10 @@ locals[ boolean overrideSpecifierSet = false ] : - kind=(Fallback | Receive) LParen RParen + kind=Receive LParen RParen ( - {!$visibilitySet}? visibility {$visibilitySet = true;} - | {!$mutabilitySet}? stateMutability {$mutabilitySet = true;} + {!$visibilitySet}? External {$visibilitySet = true;} + | {!$mutabilitySet}? Payable {$mutabilitySet = true;} | modifierInvocation | {!$virtualSet}? Virtual {$virtualSet = true;} | {!$overrideSpecifierSet}? overrideSpecifier {$overrideSpecifierSet = true;} diff --git a/libsolidity/analysis/OverrideChecker.cpp b/libsolidity/analysis/OverrideChecker.cpp index 0bfb032b1..c0cae71e4 100644 --- a/libsolidity/analysis/OverrideChecker.cpp +++ b/libsolidity/analysis/OverrideChecker.cpp @@ -394,6 +394,10 @@ bool OverrideProxy::OverrideComparator::operator<(OverrideComparator const& _oth if (functionKind != _other.functionKind) return *functionKind < *_other.functionKind; + // Parameters do not matter for non-regular functions. + if (functionKind != Token::Function) + return false; + if (!parameterTypes || !_other.parameterTypes) return false; @@ -574,16 +578,19 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr FunctionType const* functionType = _overriding.functionType(); FunctionType const* superType = _super.functionType(); - solAssert(functionType->hasEqualParameterTypes(*superType), "Override doesn't have equal parameters!"); + if (_overriding.functionKind() != Token::Fallback) + { + solAssert(functionType->hasEqualParameterTypes(*superType), "Override doesn't have equal parameters!"); - if (!functionType->hasEqualReturnTypes(*superType)) - overrideError( - _overriding, - _super, - 4822_error, - "Overriding " + _overriding.astNodeName() + " return types differ.", - "Overridden " + _overriding.astNodeName() + " is here:" - ); + if (!functionType->hasEqualReturnTypes(*superType)) + overrideError( + _overriding, + _super, + 4822_error, + "Overriding " + _overriding.astNodeName() + " return types differ.", + "Overridden " + _overriding.astNodeName() + " is here:" + ); + } // Stricter mutability is always okay except when super is Payable if ( diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 0ddd69229..7bc4677e2 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1831,15 +1831,21 @@ void TypeChecker::typeCheckFallbackFunction(FunctionDefinition const& _function) ); if (_function.visibility() != Visibility::External) m_errorReporter.typeError(1159_error, _function.location(), "Fallback function must be defined as \"external\"."); - if (!_function.returnParameters().empty()) + + if (!_function.returnParameters().empty() || !_function.parameters().empty()) { - if (_function.returnParameters().size() > 1 || *type(*_function.returnParameters().front()) != *TypeProvider::bytesMemory()) - m_errorReporter.typeError(5570_error, _function.returnParameterList()->location(), "Fallback function can only have a single \"bytes memory\" return value."); - else - m_errorReporter.typeError(6151_error, _function.returnParameterList()->location(), "Return values for fallback functions are not yet implemented."); + if ( + _function.returnParameters().size() != 1 || + *type(*_function.returnParameters().front()) != *TypeProvider::bytesMemory() || + _function.parameters().size() != 1 || + *type(*_function.parameters().front()) != *TypeProvider::bytesCalldata() + ) + m_errorReporter.typeError( + 5570_error, + _function.returnParameterList()->location(), + "Fallback function either has to have the signature \"fallback()\" or \"fallback(bytes calldata) returns (bytes memory)\"." + ); } - if (!_function.parameters().empty()) - m_errorReporter.typeError(3978_error, _function.parameterList().location(), "Fallback function cannot take parameters."); } void TypeChecker::typeCheckReceiveFunction(FunctionDefinition const& _function) diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index d339e50b9..66c67f59a 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -467,10 +467,21 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac appendCallValueCheck(); solAssert(fallback->isFallback(), ""); - solAssert(FunctionType(*fallback).parameterTypes().empty(), ""); - solAssert(FunctionType(*fallback).returnParameterTypes().empty(), ""); + m_context.setStackOffset(0); + + if (!FunctionType(*fallback).parameterTypes().empty()) + m_context << u256(0) << Instruction::CALLDATASIZE; + fallback->accept(*this); - m_context << Instruction::STOP; + + if (FunctionType(*fallback).returnParameterTypes().empty()) + m_context << Instruction::STOP; + else + { + m_context << Instruction::DUP1 << Instruction::MLOAD << Instruction::SWAP1; + m_context << u256(0x20) << Instruction::ADD; + m_context << Instruction::RETURN; + } } else m_context.appendRevert("Unknown signature and no fallback defined"); @@ -479,6 +490,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac for (auto const& it: interfaceFunctions) { + m_context.setStackOffset(1); FunctionTypePointer const& functionType = it.second; solAssert(functionType->hasDeclaration(), ""); CompilerContext::LocationSetter locationSetter(m_context, functionType->declaration()); @@ -588,7 +600,9 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) // reserve additional slots: [retarg0] ... [retargm] unsigned parametersSize = CompilerUtils::sizeOnStack(_function.parameters()); - if (!_function.isConstructor()) + if (_function.isFallback()) + m_context.adjustStackOffset(static_cast(parametersSize)); + else if (!_function.isConstructor()) // adding 1 for return address. m_context.adjustStackOffset(static_cast(parametersSize) + 1); for (ASTPointer const& variable: _function.parameters()) @@ -628,7 +642,8 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) unsigned const c_returnValuesSize = CompilerUtils::sizeOnStack(_function.returnParameters()); vector stackLayout; - stackLayout.push_back(static_cast(c_returnValuesSize)); // target of return address + if (!_function.isConstructor() && !_function.isFallback()) + stackLayout.push_back(static_cast(c_returnValuesSize)); // target of return address stackLayout += vector(c_argumentsSize, -1); // discard all arguments for (size_t i = 0; i < c_returnValuesSize; ++i) stackLayout.push_back(static_cast(i)); @@ -639,7 +654,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) errinfo_sourceLocation(_function.location()) << errinfo_comment("Stack too deep, try removing local variables.") ); - while (stackLayout.back() != static_cast(stackLayout.size() - 1)) + while (!stackLayout.empty() && stackLayout.back() != static_cast(stackLayout.size() - 1)) if (stackLayout.back() < 0) { m_context << Instruction::POP; diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 46ae3381c..4a8804182 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -652,8 +652,16 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract) { string fallbackCode; if (!fallback->isPayable()) - fallbackCode += callValueCheck(); - fallbackCode += m_context.enqueueFunctionForCodeGeneration(*fallback) + "() stop()"; + fallbackCode += callValueCheck() + "\n"; + if (fallback->parameters().empty()) + fallbackCode += m_context.enqueueFunctionForCodeGeneration(*fallback) + "() stop()"; + else + { + solAssert(fallback->parameters().size() == 1 && fallback->returnParameters().size() == 1, ""); + fallbackCode += "let retval := " + m_context.enqueueFunctionForCodeGeneration(*fallback) + "(0, calldatasize())\n"; + fallbackCode += "return(add(retval, 0x20), mload(retval))\n"; + + } t("fallback", fallbackCode); } diff --git a/test/libsolidity/semanticTests/fallback/falback_return.sol b/test/libsolidity/semanticTests/fallback/falback_return.sol new file mode 100644 index 000000000..2868d85d0 --- /dev/null +++ b/test/libsolidity/semanticTests/fallback/falback_return.sol @@ -0,0 +1,18 @@ +contract A { + uint public x; + fallback () external { + if (x == 2) return; + x++; + } +} +// ==== +// compileViaYul: also +// ---- +// () +// x() -> 1 +// () +// x() -> 2 +// () +// x() -> 2 +// () +// x() -> 2 diff --git a/test/libsolidity/semanticTests/fallback/fallback_argument.sol b/test/libsolidity/semanticTests/fallback/fallback_argument.sol new file mode 100644 index 000000000..1e3433d93 --- /dev/null +++ b/test/libsolidity/semanticTests/fallback/fallback_argument.sol @@ -0,0 +1,17 @@ +contract A { + uint public x; + fallback (bytes calldata _input) external returns (bytes memory) { + x = _input.length; + return ""; + } + function f() public returns (bool, bytes memory) { + (bool success, bytes memory retval) = address(this).call("abc"); + return (success, retval); + } +} +// ==== +// compileViaYul: also +// EVMVersion: >=byzantium +// ---- +// f() -> 0x01, 0x40, 0x00 +// x() -> 3 diff --git a/test/libsolidity/semanticTests/fallback/fallback_argument_to_storage.sol b/test/libsolidity/semanticTests/fallback/fallback_argument_to_storage.sol new file mode 100644 index 000000000..1a995a8cd --- /dev/null +++ b/test/libsolidity/semanticTests/fallback/fallback_argument_to_storage.sol @@ -0,0 +1,16 @@ +contract A { + bytes public x; + fallback (bytes calldata _input) external returns (bytes memory) { + x = _input; + return ""; + } + function f() public returns (bool, bytes memory) { + (bool success, bytes memory retval) = address(this).call("abc"); + return (success, retval); + } +} +// ==== +// EVMVersion: >=byzantium +// ---- +// f() -> 0x01, 0x40, 0x00 +// x() -> 0x20, 3, "abc" diff --git a/test/libsolidity/semanticTests/fallback/fallback_override.sol b/test/libsolidity/semanticTests/fallback/fallback_override.sol new file mode 100644 index 000000000..c1099e151 --- /dev/null +++ b/test/libsolidity/semanticTests/fallback/fallback_override.sol @@ -0,0 +1,19 @@ +contract A { + fallback (bytes calldata _input) virtual external returns (bytes memory) { + return _input; + } +} +contract B is A { + fallback (bytes calldata _input) override external returns (bytes memory) { + return "xyz"; + } + function f() public returns (bool, bytes memory) { + (bool success, bytes memory retval) = address(this).call("abc"); + return (success, retval); + } +} +// ==== +// EVMVersion: >=byzantium +// compileViaYul: also +// ---- +// f() -> 0x01, 0x40, 0x03, 0x78797a0000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/fallback/fallback_override2.sol b/test/libsolidity/semanticTests/fallback/fallback_override2.sol new file mode 100644 index 000000000..e92163476 --- /dev/null +++ b/test/libsolidity/semanticTests/fallback/fallback_override2.sol @@ -0,0 +1,18 @@ +contract A { + fallback (bytes calldata _input) virtual external returns (bytes memory) { + return _input; + } +} +contract B is A { + fallback () override external { + } + function f() public returns (bool, bytes memory) { + (bool success, bytes memory retval) = address(this).call("abc"); + return (success, retval); + } +} +// ==== +// EVMVersion: >=byzantium +// compileViaYul: also +// ---- +// f() -> 1, 0x40, 0x00 diff --git a/test/libsolidity/semanticTests/fallback/fallback_override_multi.sol b/test/libsolidity/semanticTests/fallback/fallback_override_multi.sol new file mode 100644 index 000000000..1e2b3a630 --- /dev/null +++ b/test/libsolidity/semanticTests/fallback/fallback_override_multi.sol @@ -0,0 +1,22 @@ +contract A { + fallback (bytes calldata _input) virtual external returns (bytes memory) { + return _input; + } +} +contract B { + fallback (bytes calldata _input) virtual external returns (bytes memory) { + return "xyz"; + } +} +contract C is B, A { + fallback () external override (B, A) {} + function f() public returns (bool, bytes memory) { + (bool success, bytes memory retval) = address(this).call("abc"); + return (success, retval); + } +} +// ==== +// EVMVersion: >=byzantium +// compileViaYul: also +// ---- +// f() -> 0x01, 0x40, 0x00 diff --git a/test/libsolidity/semanticTests/fallback/fallback_return_data.sol b/test/libsolidity/semanticTests/fallback/fallback_return_data.sol new file mode 100644 index 000000000..130212613 --- /dev/null +++ b/test/libsolidity/semanticTests/fallback/fallback_return_data.sol @@ -0,0 +1,14 @@ +contract A { + fallback (bytes calldata _input) external returns (bytes memory) { + return _input; + } + function f() public returns (bool, bytes memory) { + (bool success, bytes memory retval) = address(this).call("abc"); + return (success, retval); + } +} +// ==== +// compileViaYul: also +// EVMVersion: >=byzantium +// ---- +// f() -> 0x01, 0x40, 0x03, 0x6162630000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/syntaxTests/fallback/arguments.sol b/test/libsolidity/syntaxTests/fallback/arguments.sol index 806874feb..c796161d2 100644 --- a/test/libsolidity/syntaxTests/fallback/arguments.sol +++ b/test/libsolidity/syntaxTests/fallback/arguments.sol @@ -2,4 +2,4 @@ contract C { fallback(uint256) external {} } // ---- -// TypeError 3978: (25-34): Fallback function cannot take parameters. +// TypeError 5570: (44-44): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)". diff --git a/test/libsolidity/syntaxTests/fallback/fallback_duplicate_returns.sol b/test/libsolidity/syntaxTests/fallback/fallback_duplicate_returns.sol new file mode 100644 index 000000000..625c17f98 --- /dev/null +++ b/test/libsolidity/syntaxTests/fallback/fallback_duplicate_returns.sol @@ -0,0 +1,6 @@ +contract C { + fallback(bytes calldata _input) external returns (bytes memory _output) {} + fallback() external {} +} +// ---- +// DeclarationError 7301: (96-118): Only one fallback function is allowed. diff --git a/test/libsolidity/syntaxTests/fallback/fallback_duplicate_returns_inheritance.sol b/test/libsolidity/syntaxTests/fallback/fallback_duplicate_returns_inheritance.sol new file mode 100644 index 000000000..818006a11 --- /dev/null +++ b/test/libsolidity/syntaxTests/fallback/fallback_duplicate_returns_inheritance.sol @@ -0,0 +1,9 @@ +contract C { + fallback(bytes calldata _input) external returns (bytes memory _output) {} +} +contract D is C { + fallback() external {} +} +// ---- +// TypeError 9456: (116-138): Overriding function is missing "override" specifier. +// TypeError 4334: (17-91): Trying to override non-virtual function. Did you forget to add "virtual"? diff --git a/test/libsolidity/syntaxTests/fallback/fallback_duplicate_returns_override.sol b/test/libsolidity/syntaxTests/fallback/fallback_duplicate_returns_override.sol new file mode 100644 index 000000000..32638c082 --- /dev/null +++ b/test/libsolidity/syntaxTests/fallback/fallback_duplicate_returns_override.sol @@ -0,0 +1,7 @@ +contract C { + fallback(bytes calldata _input) external virtual returns (bytes memory _output) {} +} +contract D is C { + fallback() external override {} +} +// ---- diff --git a/test/libsolidity/syntaxTests/fallback/fallback_wrong_data_location.sol b/test/libsolidity/syntaxTests/fallback/fallback_wrong_data_location.sol new file mode 100644 index 000000000..5ddefdf3d --- /dev/null +++ b/test/libsolidity/syntaxTests/fallback/fallback_wrong_data_location.sol @@ -0,0 +1,13 @@ +contract D { + fallback(bytes memory) external returns (bytes memory) {} +} +contract E { + fallback(bytes memory) external returns (bytes calldata) {} +} +contract F { + fallback(bytes calldata) external returns (bytes calldata) {} +} +// ---- +// TypeError 5570: (57-71): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)". +// TypeError 5570: (134-150): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)". +// TypeError 5570: (215-231): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)". diff --git a/test/libsolidity/syntaxTests/fallback/inheritance_multi_base.sol b/test/libsolidity/syntaxTests/fallback/inheritance_multi_base.sol new file mode 100644 index 000000000..330ff156c --- /dev/null +++ b/test/libsolidity/syntaxTests/fallback/inheritance_multi_base.sol @@ -0,0 +1,20 @@ +contract A { + fallback (bytes calldata _input) external returns (bytes memory) { + return _input; + } +} +contract B { + fallback (bytes calldata _input) external returns (bytes memory) { + return "xyz"; + } +} +contract C is B, A { + function f() public returns (bool, bytes memory) { + (bool success, bytes memory retval) = address(this).call("abc"); + return (success, retval); + } +} +// ==== +// EVMVersion: >=byzantium +// ---- +// TypeError 6480: (229-420): Derived contract must override function "". Two or more base classes define function with same name and parameter types. diff --git a/test/libsolidity/syntaxTests/fallback/no_input_no_output.sol b/test/libsolidity/syntaxTests/fallback/no_input_no_output.sol new file mode 100644 index 000000000..868671d2a --- /dev/null +++ b/test/libsolidity/syntaxTests/fallback/no_input_no_output.sol @@ -0,0 +1,9 @@ +contract C { + fallback() external returns (bytes memory _output) {} +} +contract D { + fallback(bytes calldata _input) external {} +} +// ---- +// TypeError 5570: (45-67): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)". +// TypeError 5570: (131-131): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)". diff --git a/test/libsolidity/syntaxTests/fallback/return_value_number.sol b/test/libsolidity/syntaxTests/fallback/return_value_number.sol index c41b837a8..e5d358c73 100644 --- a/test/libsolidity/syntaxTests/fallback/return_value_number.sol +++ b/test/libsolidity/syntaxTests/fallback/return_value_number.sol @@ -2,4 +2,4 @@ contract C { fallback() external returns (bytes memory, bytes memory) {} } // ---- -// TypeError 5570: (45-73): Fallback function can only have a single "bytes memory" return value. +// TypeError 5570: (45-73): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)". diff --git a/test/libsolidity/syntaxTests/fallback/return_value_type.sol b/test/libsolidity/syntaxTests/fallback/return_value_type.sol index a6557139d..01363ebe4 100644 --- a/test/libsolidity/syntaxTests/fallback/return_value_type.sol +++ b/test/libsolidity/syntaxTests/fallback/return_value_type.sol @@ -2,4 +2,4 @@ contract C { fallback() external returns (uint256) {} } // ---- -// TypeError 5570: (45-54): Fallback function can only have a single "bytes memory" return value. +// TypeError 5570: (45-54): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)". diff --git a/test/libsolidity/syntaxTests/fallback/return_value_unsupported.sol b/test/libsolidity/syntaxTests/fallback/return_value_unsupported.sol index 3b90b5ad2..88f181f3f 100644 --- a/test/libsolidity/syntaxTests/fallback/return_value_unsupported.sol +++ b/test/libsolidity/syntaxTests/fallback/return_value_unsupported.sol @@ -2,4 +2,4 @@ contract C { fallback() external returns (bytes memory) {} } // ---- -// TypeError 6151: (45-59): Return values for fallback functions are not yet implemented. +// TypeError 5570: (45-59): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)". diff --git a/test/libsolidity/syntaxTests/fallback/returns.sol b/test/libsolidity/syntaxTests/fallback/returns.sol new file mode 100644 index 000000000..a4d45c522 --- /dev/null +++ b/test/libsolidity/syntaxTests/fallback/returns.sol @@ -0,0 +1,4 @@ +contract C { + fallback(bytes calldata _input) external returns (bytes memory _output) {} +} +// ---- diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/075_fallback_function_with_arguments.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/075_fallback_function_with_arguments.sol index 8beac9f1a..6ed769c88 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/075_fallback_function_with_arguments.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/075_fallback_function_with_arguments.sol @@ -3,4 +3,4 @@ contract C { fallback(uint a) external { x = 2; } } // ---- -// TypeError 3978: (37-45): Fallback function cannot take parameters. +// TypeError 5570: (55-55): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)". diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/077_fallback_function_with_return_parameters.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/077_fallback_function_with_return_parameters.sol index 3ec82b390..268a7e69b 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/077_fallback_function_with_return_parameters.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/077_fallback_function_with_return_parameters.sol @@ -2,4 +2,4 @@ contract C { fallback() external returns (uint) { } } // ---- -// TypeError 5570: (45-51): Fallback function can only have a single "bytes memory" return value. +// TypeError 5570: (45-51): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)".