-
Notifications
You must be signed in to change notification settings - Fork 6.3k
Fix string.concat and bytes.concat assignment to a constant variable.
#16341
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
0670546
767c58f
8aa5346
356f582
440a437
fb51ba2
aee6051
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,13 @@ | ||||||||||
| contract A { | ||||||||||
| } | ||||||||||
|
|
||||||||||
| contract B { | ||||||||||
| bytes constant creationCode = type(A).creationCode; | ||||||||||
| bytes constant runtimeCode = type(A).runtimeCode; | ||||||||||
|
|
||||||||||
| function isEmptyCode() public pure returns (bool) { | ||||||||||
| return creationCode.length > 0 && runtimeCode.length > 0; | ||||||||||
|
Comment on lines
+8
to
+9
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The name does not match the condition.
Suggested change
|
||||||||||
| } | ||||||||||
| } | ||||||||||
| // ---- | ||||||||||
| // isEmptyCode() -> true | ||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| contract C { | ||
| function f() public pure { | ||
| bytes.concat(hex"", unicode"", ""); | ||
| function f() public pure returns (bytes memory) { | ||
| return bytes.concat(hex"", unicode"", ""); | ||
| } | ||
| } | ||
| // ---- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| bytes constant aEncoded = abi.encode( | ||
| hex"aaaa" | ||
| ); | ||
|
|
||
| contract A { | ||
| bytes constant a = abi.decode(aEncoded, (bytes)); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| contract A { | ||
| function encoded() private view returns (bytes memory) { | ||
| return abi.encode(hex"aaaa"); | ||
| } | ||
|
|
||
| bytes constant a = abi.decode(encoded(), (bytes)); | ||
| } | ||
| // ---- | ||
| // TypeError 8349: (142-172): Initial value for constant variable has to be compile-time constant. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| contract A { | ||
| function f() external {} | ||
| bytes constant fCallA = abi.encodeCall(A.f, ()); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| contract A { | ||
| function f(uint a) external {} | ||
|
|
||
| function getA() private view returns(uint) { | ||
| return 1; | ||
| } | ||
|
|
||
| bytes constant fCallA = abi.encodeCall(A.f, (getA())); | ||
| } | ||
| // ---- | ||
| // TypeError 8349: (151-180): Initial value for constant variable has to be compile-time constant. |
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be good to use a more regular naming scheme for these tests. Checking if we already have tests covering something is always a challenge and this would make it a bit easier. Here's how I'd name these: General remarks:
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| contract C { | ||
| uint k = 1; | ||
|
|
||
| bytes32 constant a = keccak256(abi.encode(1, k)); | ||
| bytes32 constant b = keccak256(abi.encodePacked(uint(1), k)); | ||
| bytes32 constant c = keccak256(abi.encodeWithSelector(0x12345678, k, 2)); | ||
| bytes32 constant d = keccak256(abi.encodeWithSignature("f()", 1, k)); | ||
| } | ||
| // ---- | ||
| // TypeError 8349: (55-82): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (109-148): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (175-226): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (253-300): Initial value for constant variable has to be compile-time constant. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| bytes32 constant blockhGlobal = blockhash(1); | ||
| bytes32 constant blobhGlobal = blobhash(1); | ||
| uint constant bfGlobal = block.basefee; | ||
| uint constant blobbfGlobal = block.blobbasefee; | ||
| uint constant chainIdGlobal = block.chainid; | ||
| address constant coinbaseGlobal = block.coinbase; | ||
| uint constant diffGlobal = block.difficulty; | ||
| uint constant gaslimitGlobal = block.gaslimit; | ||
| uint constant numberGlobal = block.number; | ||
| uint constant prevrandaoGlobal = block.prevrandao; | ||
| uint constant timestampGlobal = block.timestamp; | ||
| uint constant gGlobal = gasleft(); | ||
| bytes constant dataGlobal = msg.data; | ||
| address constant senderGlobal = msg.sender; | ||
| bytes4 constant sigGlobal = msg.sig; | ||
| uint constant valueGlobal = msg.value; | ||
| uint constant gaspriceGlobal = tx.gasprice; | ||
| address constant originGlobal = tx.origin; | ||
|
|
||
| contract A { | ||
| bytes32 constant blockh = blockhash(1); | ||
| bytes32 constant blobh = blobhash(1); | ||
| uint constant bf = block.basefee; | ||
| uint constant blobbf = block.blobbasefee; | ||
| uint constant chainId = block.chainid; | ||
| address constant coinbase = block.coinbase; | ||
| uint constant diff = block.difficulty; | ||
| uint constant gaslimit = block.gaslimit; | ||
| uint constant number = block.number; | ||
| uint constant prevrandao = block.prevrandao; | ||
| uint constant timestamp = block.timestamp; | ||
| uint constant g = gasleft(); | ||
| bytes constant data = msg.data; | ||
| address constant sender = msg.sender; | ||
| bytes4 constant sig = msg.sig; | ||
| uint constant value = msg.value; | ||
| uint constant gasprice = tx.gasprice; | ||
| address constant origin = tx.origin; | ||
| } | ||
| // ==== | ||
| // EVMVersion: >=cancun | ||
| // ---- | ||
| // TypeError 8349: (32-44): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (77-88): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (115-128): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (159-176): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (208-221): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (257-271): Initial value for constant variable has to be compile-time constant. | ||
| // Warning 8417: (300-316): Since the VM version paris, "difficulty" was replaced by "prevrandao", which now returns a random number based on the beacon chain. | ||
| // TypeError 8349: (300-316): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (349-363): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (394-406): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (441-457): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (491-506): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (532-541): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (571-579): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (613-623): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (653-660): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (690-699): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (732-743): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (777-786): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (832-844): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (875-886): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (911-924): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (953-970): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (1000-1013): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (1047-1061): Initial value for constant variable has to be compile-time constant. | ||
| // Warning 8417: (1088-1104): Since the VM version paris, "difficulty" was replaced by "prevrandao", which now returns a random number based on the beacon chain. | ||
| // TypeError 8349: (1088-1104): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (1135-1149): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (1178-1190): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (1223-1239): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (1271-1286): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (1310-1319): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (1347-1355): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (1387-1397): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (1425-1432): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (1460-1469): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (1500-1511): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (1543-1552): Initial value for constant variable has to be compile-time constant. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| bytes constant abcGlobal = bytes.concat( | ||
| hex"aaaa", | ||
| hex"bbbb", | ||
| hex"cccc" | ||
| ); | ||
|
Comment on lines
+1
to
+5
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For completeness I'd also make one of the arguments a And in |
||
|
|
||
| contract A { | ||
| bytes public constant abc = bytes.concat( | ||
| hex"aaaa", | ||
| hex"bbbb", | ||
| hex"cccc" | ||
| ); | ||
|
|
||
| bytes public constant abcCopy = abc; | ||
| bytes public constant abcGlobalCopy = abcGlobal; | ||
| bytes public constant abcabc = bytes.concat(abc, abcGlobal); | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,20 @@ | ||||||||||||||
| contract A { | ||||||||||||||
| function getData() public view returns (bytes memory) { | ||||||||||||||
| return msg.data; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| bytes constant abData = bytes.concat( | ||||||||||||||
| hex"aaaa", | ||||||||||||||
| hex"bbbb", | ||||||||||||||
| msg.data | ||||||||||||||
| ); | ||||||||||||||
|
Comment on lines
+6
to
+10
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The args in these tests are pretty short, so I'd put them on a single line to make these it less verbose.
Suggested change
|
||||||||||||||
|
|
||||||||||||||
| bytes constant abgetData = bytes.concat( | ||||||||||||||
| hex"aaaa", | ||||||||||||||
| hex"bbbb", | ||||||||||||||
| getData() | ||||||||||||||
| ); | ||||||||||||||
| } | ||||||||||||||
| // ---- | ||||||||||||||
| // TypeError 8349: (133-207): Initial value for constant variable has to be compile-time constant. | ||||||||||||||
| // TypeError 8349: (241-316): Initial value for constant variable has to be compile-time constant. | ||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| contract A { | ||
| uint256 k = 7; | ||
| uint256 constant amod = addmod(1, 8, k); | ||
| uint256 constant mmod = mulmod(1, 8, k); | ||
|
Comment on lines
+2
to
+4
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we have a variant of this test but with constant args?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same for |
||
|
|
||
| bytes data = hex"ffff"; | ||
| bytes32 constant keccak = keccak256(data); | ||
| } | ||
| // ---- | ||
| // TypeError 8349: (60-75): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (105-120): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (181-196): Initial value for constant variable has to be compile-time constant. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| contract A { | ||
| bytes data = hex"ffff"; | ||
| bytes32 constant sha = sha256(data); | ||
| bytes20 constant ripemd = ripemd160(data); | ||
| address constant addr = ecrecover("1234", 1, "0", abi.decode(data, (bytes2))); | ||
| } | ||
| // ---- | ||
| // TypeError 8349: (68-80): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (112-127): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (157-210): Initial value for constant variable has to be compile-time constant. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| bytes32 constant sGlobal = sha256(hex"ffff"); | ||
| address constant addrGlobal = ecrecover("1234", 1, "0", abi.decode("", (bytes2))); | ||
|
Comment on lines
+1
to
+2
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add |
||
|
|
||
| contract A { | ||
| bytes32 constant s = sha256(hex"ffff"); | ||
| address constant addr = ecrecover("1234", 1, "0", abi.decode("", (bytes2))); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| string constant abcGlobal = string.concat( | ||
| "aaaa", | ||
| "bbbb", | ||
| "cccc" | ||
| ); | ||
|
|
||
| contract A { | ||
| string public constant abc = string.concat( | ||
| "aaaa", | ||
| "bbbb", | ||
| "cccc" | ||
| ); | ||
|
|
||
| string public constant abcCopy = abc; | ||
| string public constant abcGlobalCopy = abcGlobal; | ||
| string public constant abcabc = string.concat(abc, abcGlobal); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| contract A { | ||
| string name = "name"; | ||
|
|
||
| function getName() public view returns (string memory) { | ||
| return name; | ||
| } | ||
|
|
||
| string public constant abName = string.concat( | ||
| "aaaa", | ||
| "bbbb", | ||
| name | ||
| ); | ||
|
|
||
| string public constant abgetName = string.concat( | ||
| "aaaa", | ||
| "bbbb", | ||
| getName() | ||
| ); | ||
| } | ||
| // ---- | ||
| // TypeError 8349: (165-230): Initial value for constant variable has to be compile-time constant. | ||
| // TypeError 8349: (272-342): Initial value for constant variable has to be compile-time constant. |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,21 @@ | ||||||||||
| string constant aNameGlobal = type(A).name; | ||||||||||
| bytes4 constant iNameGlobal = type(I).interfaceId; | ||||||||||
| uint256 constant minGlobal = type(uint256).min; | ||||||||||
| uint256 constant maxGlobal = type(uint256).max; | ||||||||||
|
|
||||||||||
| contract B { | ||||||||||
| } | ||||||||||
|
|
||||||||||
| interface I { | ||||||||||
| function hello() external pure; | ||||||||||
| function world(int) external pure; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| contract A { | ||||||||||
| string constant aName = type(A).name; | ||||||||||
| bytes4 constant iName = type(I).interfaceId; | ||||||||||
| uint256 constant min = type(uint256).min; | ||||||||||
| uint256 constant max = type(uint256).max; | ||||||||||
| bytes creationCodeB = type(B).creationCode; | ||||||||||
| bytes runtimeCodeB = type(B).runtimeCode; | ||||||||||
|
Comment on lines
+19
to
+20
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These are not marked
Suggested change
And I'd add them at file level too. |
||||||||||
| } | ||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| contract C layout at uint64(bytes8(bytes.concat("ABCD", "EFGH"))) {} | ||
| // ---- | ||
| // TypeError 1139: (21-65): The base slot of the storage layout must be a compile-time constant expression. | ||
| // TypeError 1505: (21-65): The base slot expression contains elements that are not yet supported by the internal constant evaluator and therefore cannot be evaluated at compilation time. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| contract C layout at uint(keccak256(bytes.concat("ABCD"))) {} | ||
| // ---- | ||
| // TypeError 1139: (21-58): The base slot of the storage layout must be a compile-time constant expression. | ||
| // TypeError 1505: (21-58): The base slot expression contains elements that are not yet supported by the internal constant evaluator and therefore cannot be evaluated at compilation time. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be safer to check for
FunctionType::Kind::StringConcat/FunctionType::Kind::BytesConcatrather than function name.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would also add an assert at the end of this function that for function types the annotation matches the result of
FunctionType::isPure().