Support .offset and .length for calldata bytes and string arrays.

This commit is contained in:
chriseth
2020-11-18 01:45:56 +01:00
parent e694cc1b1c
commit 2665eaa4fa
31 changed files with 366 additions and 128 deletions
@@ -180,6 +180,7 @@
"isOffset": true,
"isSlot": false,
"src": "106:8:1",
"suffix": "offset",
"valueSize": 1
},
{
@@ -187,6 +188,7 @@
"isOffset": false,
"isSlot": true,
"src": "128:6:1",
"suffix": "slot",
"valueSize": 1
}
],
@@ -168,6 +168,7 @@
"isOffset": true,
"isSlot": false,
"src": "106:8:1",
"suffix": "offset",
"valueSize": 1
},
{
@@ -175,6 +176,7 @@
"isOffset": false,
"isSlot": true,
"src": "128:6:1",
"suffix": "slot",
"valueSize": 1
}
],
@@ -0,0 +1,8 @@
contract C {
function f(uint[2][] calldata x) public returns (uint[2][] memory r) {
assembly { x.offset := 0x44 x.length := 2 }
r = x;
}
}
// ----
// f(uint256[2][]): 0x0, 1, 8, 7, 6, 5 -> 0x20, 2, 8, 7, 6, 5
@@ -0,0 +1,12 @@
contract C {
function f(uint[2][] calldata x) public returns (uint o, uint l, uint s) {
assembly { l := x.length o := x.offset }
uint[2] calldata t = x[1];
// statically-sized arrays only use one slot, so we read directly.
assembly { s := t }
}
}
// ====
// compileViaYul: also
// ----
// f(uint256[2][]): 0x20, 2, 1, 2, 3, 4 -> 0x44, 2, 0x84
@@ -0,0 +1,10 @@
contract C {
function f(bytes calldata x) public returns (bytes memory) {
assembly { x.offset := 1 x.length := 3 }
return x;
}
}
// ====
// compileViaYul: also
// ----
// f(bytes): 0x20, 0, 0 -> 0x20, 3, 0x5754f80000000000000000000000000000000000000000000000000000000000
@@ -0,0 +1,9 @@
contract C {
function f() public pure returns (bytes calldata x) {
assembly { x.offset := 0 x.length := 4 }
}
}
// ====
// compileViaYul: also
// ----
// f() -> 0x20, 4, 0x26121ff000000000000000000000000000000000000000000000000000000000
@@ -0,0 +1,18 @@
contract C {
function lenBytesRead(bytes calldata x) public returns (uint l) {
assembly { l := x.length }
}
function lenStringRead(string calldata x) public returns (uint l) {
assembly { l := x.length }
}
}
// ====
// compileViaYul: also
// ----
// lenBytesRead(bytes): 0x20, 4, "abcd" -> 4
// lenBytesRead(bytes): 0x20, 0, "abcd" -> 0x00
// lenBytesRead(bytes): 0x20, 0x21, "abcd", "ef" -> 33
// lenStringRead(string): 0x20, 4, "abcd" -> 4
// lenStringRead(string): 0x20, 0, "abcd" -> 0x00
// lenStringRead(string): 0x20, 0x21, "abcd", "ef" -> 33
@@ -0,0 +1,19 @@
contract C {
function f(bytes calldata x) public returns (uint r) {
assembly { r := x.offset }
}
function f(uint, bytes calldata x, uint) public returns (uint r, uint v) {
assembly {
r := x.offset
v := x.length
}
}
}
// ====
// compileViaYul: also
// ----
// f(bytes): 0x20, 0, 0 -> 0x44
// f(bytes): 0x22, 0, 0, 0 -> 0x46
// f(uint256,bytes,uint256): 7, 0x60, 8, 2, 0 -> 0x84, 2
// f(uint256,bytes,uint256): 0, 0, 0 -> 0x24, 0x00
@@ -0,0 +1,18 @@
contract C {
function f(uint, bytes calldata x, uint) public returns (uint r, uint v) {
assembly {
x.offset := 8
x.length := 20
}
assembly {
r := x.offset
v := x.length
}
}
}
// ====
// compileViaYul: also
// ----
// f(uint256,bytes,uint256): 7, 0x60, 8, 2, 0 -> 8, 0x14
// f(uint256,bytes,uint256): 0, 0, 0 -> 8, 0x14
@@ -25,6 +25,8 @@ contract C {
return data().a;
}
}
// ====
// compileViaYul: also
// ----
// get() -> 0
// mappingAccess(uint256): 1 -> 0, 0
@@ -0,0 +1,9 @@
contract C {
function f(uint[] calldata bytesAsCalldata) external {
assembly {
let x := bytesAsCalldata
}
}
}
// ----
// TypeError 1397: (112-127): Call data elements cannot be accessed directly. Use ".offset" and ".length" to access the calldata offset and length of this array and then use "calldatacopy".
@@ -0,0 +1,8 @@
contract C {
function f(uint[] calldata bytesAsCalldata) external pure {
assembly {
let x := bytesAsCalldata.offset
}
}
}
// ----
@@ -0,0 +1,9 @@
contract C {
function f(bytes calldata bytesAsCalldata) external {
assembly {
let x := bytesAsCalldata.slot
}
}
}
// ----
// TypeError 1536: (111-131): Calldata variables only support ".offset" and ".length".
@@ -6,4 +6,4 @@ contract C {
}
}
// ----
// TypeError 2370: (111-126): Call data elements cannot be accessed directly. Copy to a local variable first or use "calldataload" or "calldatacopy" with manually determined offsets and sizes.
// TypeError 1397: (111-126): Call data elements cannot be accessed directly. Use ".offset" and ".length" to access the calldata offset and length of this array and then use "calldatacopy".
@@ -7,4 +7,4 @@ contract test {
}
}
// ----
// TypeError 1408: (89-90): Only local variables are supported. To access storage variables, use the .slot and .offset suffixes.
// TypeError 1408: (89-90): Only local variables are supported. To access storage variables, use the ".slot" and ".offset" suffixes.
@@ -10,4 +10,4 @@ contract test {
}
}
// ----
// TypeError 1408: (80-81): Only local variables are supported. To access storage variables, use the .slot and .offset suffixes.
// TypeError 1408: (80-81): Only local variables are supported. To access storage variables, use the ".slot" and ".offset" suffixes.
@@ -0,0 +1,12 @@
contract test {
uint x = 1;
function f() public {
assembly {
let t := x.length
x.length := 2
}
}
}
// ----
// TypeError 4656: (98-106): State variables only support ".slot" and ".offset".
// TypeError 4656: (119-127): State variables only support ".slot" and ".offset".
@@ -5,4 +5,4 @@ contract c {
}
}
// ----
// TypeError 1408: (75-76): Only local variables are supported. To access storage variables, use the .slot and .offset suffixes.
// TypeError 1408: (75-76): Only local variables are supported. To access storage variables, use the ".slot" and ".offset" suffixes.
@@ -8,4 +8,4 @@ contract C {
}
}
// ----
// TypeError 9068: (118-119): You have to use the .slot or .offset suffix to access storage reference variables.
// TypeError 9068: (118-119): You have to use the ".slot" or ".offset" suffix to access storage reference variables.
@@ -9,5 +9,5 @@ contract C {
}
}
// ----
// DeclarationError 9467: (118-124): Identifier not found. Use ``.slot`` and ``.offset`` to access storage variables.
// DeclarationError 9467: (142-150): Identifier not found. Use ``.slot`` and ``.offset`` to access storage variables.
// DeclarationError 9467: (118-124): Identifier not found. Use ".slot" and ".offset" to access storage variables.
// DeclarationError 9467: (142-150): Identifier not found. Use ".slot" and ".offset" to access storage variables.
@@ -6,4 +6,4 @@ contract C {
}
}
// ----
// TypeError 7944: (84-90): The suffixes .offset and .slot can only be used on storage variables.
// TypeError 7944: (84-90): The suffixes ".offset", ".slot" and ".length" can only be used with variables.
@@ -9,5 +9,5 @@ contract C {
}
}
// ----
// TypeError 3622: (117-123): The suffixes .offset and .slot can only be used on storage variables.
// TypeError 3622: (141-149): The suffixes .offset and .slot can only be used on storage variables.
// TypeError 3622: (117-123): The suffix ".slot" is not supported by this variable or type.
// TypeError 3622: (141-149): The suffix ".offset" is not supported by this variable or type.
@@ -0,0 +1,10 @@
contract C {
function f() pure external {
function() external two_stack_slots;
assembly {
let x := two_stack_slots
}
}
}
// ----
// TypeError 9857: (132-147): Only types that use one stack slot are supported.