Functions taking `calldata` arguments are not assignable to function pointers of the same type
- Dominant language
- C++
- Stars
- 25.7k
- Forks
- 6.2k
- Avg merge
- 1d 11h
- Merged PRs (30d)
- 21
Description
## Description
The compiler seems to treat pointers to functions taking `calldata` arguments as if they had `memory` arguments instead. You cannot assign them, pass into a function of use in `abi.encodeCall()` even when the target type exactly matches the type of the function pointer.
## Steps to Reproduce
### `calldata` is not accepted
```solidity
contract C {
function f(function (string calldata) external) external {}
function g(string calldata) external {}
function main() external {
function (string calldata) external ptr = this.g;
abi.encodeCall(this.f, (this.g));
this.f(this.g);
}
}
```
```
Error: Type function (string memory) external is not implicitly convertible to expected type function (string calldata) external.
--> test.sol:6:9:
|
6 | function (string calldata) external ptr = this.g;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: Cannot implicitly convert component at position 0 from "function" to "function".
--> test.sol:7:32:
|
7 | abi.encodeCall(this.f, (this.g));
| ^^^^^^^^
Error: Invalid type for argument in function call. Invalid implicit conversion from function (string memory) external to function (string calldata) external requested.
--> test.sol:8:16:
|
8 | this.f(this.g);
| ^^^^^^
```
### `memory` is accepted instead
On the other hand this compiles without errors:
```solidity
contract C {
function g(bytes calldata b) external returns (bytes calldata) {
return b[2:5];
}
function main() external returns (bytes memory) {
function (bytes memory) external returns (bytes memory) ptr = this.g;
bytes memory b = "123456789";
return ptr(b);
}
}
```
I checked in Remix and it even properly slices the `memory` string argument even though we only support slicing `calldata`.
This should probably be disallowed given that you can't normally pass in `memory` arguments to functions taking `calldata`. Also, when the functions are `internal`, the compiler does produce an error:
```
Error: Type function (bytes calldata) returns (bytes calldata) is not implicitly convertible to expected type function (bytes memory) returns (bytes memory).
--> test.sol:7:9:
|
7 | function (bytes memory) internal returns (bytes memory) ptr = g;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
```
## Environment
- Compiler version: 0.8.12
Contributor guide
Research direction
The payload names no compiler source file or regression test; the diagnostics refer to test.sol. Start by reproducing both Solidity examples with compiler version 0.8.12, then inspect the type-checking path for external function-pointer conversions and abi.encodeCall. Done means the calldata and memory behavior follows consistent function-argument rules and is covered by regression tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, solidity
- Domain
- blockchain, compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100