diff --git a/.circleci/config.yml b/.circleci/config.yml index 65e7113a38e2..bcfc99cd7f90 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -504,28 +504,14 @@ defaults: binary_type: solcjs compile_only: 1 nodejs_version: '14' - - job_native_compile_ext_gnosis: &job_native_compile_ext_gnosis - <<: *workflow_ubuntu2004_static - name: t_native_compile_ext_gnosis - project: gnosis - binary_type: native - compile_only: 1 - nodejs_version: '14' - job_native_test_ext_gnosis: &job_native_test_ext_gnosis - <<: *workflow_emscripten + <<: *workflow_ubuntu2004_static name: t_native_test_ext_gnosis project: gnosis binary_type: native - # NOTE: Tests do not start on node.js 14 ("ganache-cli exited early with code 1"). - nodejs_version: '12' - - job_native_test_ext_gnosis_v2: &job_native_test_ext_gnosis_v2 - <<: *workflow_ubuntu2004_static - name: t_native_test_ext_gnosis_v2 - project: gnosis-v2 - binary_type: native - # NOTE: Tests do not start on node.js 14 ("ganache-cli exited early with code 1"). - nodejs_version: '12' + # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" + nodejs_version: '16' - job_native_test_ext_zeppelin: &job_native_test_ext_zeppelin <<: *workflow_ubuntu2004_static name: t_native_test_ext_zeppelin @@ -1065,6 +1051,20 @@ jobs: t_ubu_release_cli: &t_ubu_release_cli <<: *t_ubu_cli + t_ubu_locale: + <<: *base_ubuntu2004_small + steps: + - checkout + - attach_workspace: + at: build + - run: + name: Install all locales + command: | + apt update --assume-yes + apt install locales-all --assume-yes --no-install-recommends + - run: test/localeTest.sh build/solc/solc + - gitter_notify_failure_unless_pr + t_ubu_asan_cli: # Runs slightly faster on medium but we only run it nightly so efficiency matters more. <<: *base_ubuntu2004_small @@ -1449,6 +1449,7 @@ workflows: # Ubuntu build and tests - b_ubu: *workflow_trigger_on_tags - t_ubu_cli: *workflow_ubuntu2004 + - t_ubu_locale: *workflow_ubuntu2004 - t_ubu_soltest_all: *workflow_ubuntu2004 - t_ubu_soltest_enforce_yul: *workflow_ubuntu2004 - b_ubu_clang: *workflow_trigger_on_tags @@ -1466,12 +1467,8 @@ workflows: - t_ems_ext_hardhat: *workflow_emscripten - t_ems_ext: *job_ems_compile_ext_colony - - t_ems_ext: *job_native_compile_ext_gnosis - # FIXME: Gnosis tests are pretty flaky right now. They often fail on CircleCI due to random ProviderError - # and there are also other less frequent problems. See https://github.com/gnosis/safe-contracts/issues/216. - #-t_ems_ext: *job_native_test_ext_gnosis - - t_ems_ext: *job_native_test_ext_gnosis_v2 + - t_ems_ext: *job_native_test_ext_gnosis - t_ems_ext: *job_native_test_ext_zeppelin - t_ems_ext: *job_native_test_ext_ens - t_ems_ext: *job_native_test_ext_trident @@ -1488,8 +1485,7 @@ workflows: <<: *workflow_trigger_on_tags requires: - t_ems_compile_ext_colony - - t_native_compile_ext_gnosis - - t_native_test_ext_gnosis_v2 + - t_native_test_ext_gnosis - t_native_test_ext_zeppelin - t_native_test_ext_ens - t_native_test_ext_trident diff --git a/CMakeLists.txt b/CMakeLists.txt index fc7320c72d3e..759f69a538ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ include(EthPolicy) eth_policy() # project name and version should be set after cmake_policy CMP0048 -set(PROJECT_VERSION "0.8.13") +set(PROJECT_VERSION "0.8.14") # OSX target needed in order to support std::visit set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14") project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX) diff --git a/Changelog.md b/Changelog.md index 181c386aa09e..32d76774a887 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,13 +1,42 @@ -### 0.8.13 (unreleased) +### 0.8.14 (unreleased) + +Language Features: + + +Compiler Features: + * Peephole Optimizer: Remove operations without side effects before simple terminations. + + +Bugfixes: + + + +### 0.8.13 (2022-03-16) + +Important Bugfixes: + * Code Generator: Correctly encode literals used in ``abi.encodeCall`` in place of fixed bytes arguments. + Language Features: * General: Allow annotating inline assembly as memory-safe to allow optimizations and stack limit evasion that rely on respecting Solidity's memory model. + * General: ``using M for Type;`` is allowed at file level and ``M`` can now also be a brace-enclosed list of free functions or library functions. + * General: ``using ... for T global;`` is allowed at file level where the user-defined type ``T`` has been defined, resulting in the effect of the statement being available everywhere ``T`` is available. Compiler Features: -* JSON-AST: Added selector field for errors and events. + * Commandline Interface: Allow the use of ``--via-ir`` in place of ``--experimental-via-ir``. + * Compilation via Yul IR is no longer marked as experimental. + * JSON-AST: Added selector field for errors and events. + * LSP: Implements goto-definition. + * Peephole Optimizer: Optimize comparisons in front of conditional jumps and conditional jumps across a single unconditional jump. + * Yul EVM Code Transform: Avoid unnecessary ``pop``s on terminating control flow. + * Yul Optimizer: Remove ``sstore`` and ``mstore`` operations that are never read from. + Bugfixes: + * General: Fix internal error for locales with unusual capitalization rules. Locale set in the environment is now completely ignored. + * Type Checker: Fix incorrect type checker errors when importing overloaded functions. + * Yul IR Code Generation: Optimize embedded creation code with correct settings. This fixes potential mismatches between the constructor code of a contract compiled in isolation and the bytecode in ``type(C).creationCode``, resp. the bytecode used for ``new C(...)``. ### 0.8.12 (2022-02-16) diff --git a/cmake/EthUtils.cmake b/cmake/EthUtils.cmake index fca41107ebcc..44b92f4a0aa1 100644 --- a/cmake/EthUtils.cmake +++ b/cmake/EthUtils.cmake @@ -48,3 +48,11 @@ function(detect_stray_source_files FILELIST DIRECTORY) message(SEND_ERROR "The following source files are present but are not compiled: ${sources}") endif() endfunction(detect_stray_source_files) + +# CreateExportedFunctionsForEMSDK(OUTPUT_VARIABLE Symbol1 Symbol2 ... SymbolN) +function(CreateExportedFunctionsForEMSDK OUTPUT_VARIABLE) + list(TRANSFORM ARGN PREPEND "\"_") + list(TRANSFORM ARGN APPEND "\"") + list(JOIN ARGN "," ARGN) + set(${OUTPUT_VARIABLE} "[${ARGN}]" PARENT_SCOPE) +endfunction() diff --git a/docs/assembly.rst b/docs/assembly.rst index 746da43c130e..0876229b1441 100644 --- a/docs/assembly.rst +++ b/docs/assembly.rst @@ -45,10 +45,10 @@ Solidity language without a compiler change. pragma solidity >=0.4.16 <0.9.0; library GetCode { - function at(address _addr) public view returns (bytes memory code) { + function at(address addr) public view returns (bytes memory code) { assembly { // retrieve the size of the code, this needs assembly - let size := extcodesize(_addr) + let size := extcodesize(addr) // allocate output byte array - this could also be done without assembly // by using code = new bytes(size) code := mload(0x40) @@ -57,7 +57,7 @@ Solidity language without a compiler change. // store length in memory mstore(code, size) // actually retrieve the code, this needs assembly - extcodecopy(_addr, add(code, 0x20), 0, size) + extcodecopy(addr, add(code, 0x20), 0, size) } } } @@ -74,43 +74,43 @@ efficient code, for example: library VectorSum { // This function is less efficient because the optimizer currently fails to // remove the bounds checks in array access. - function sumSolidity(uint[] memory _data) public pure returns (uint sum) { - for (uint i = 0; i < _data.length; ++i) - sum += _data[i]; + function sumSolidity(uint[] memory data) public pure returns (uint sum) { + for (uint i = 0; i < data.length; ++i) + sum += data[i]; } // We know that we only access the array in bounds, so we can avoid the check. // 0x20 needs to be added to an array because the first slot contains the // array length. - function sumAsm(uint[] memory _data) public pure returns (uint sum) { - for (uint i = 0; i < _data.length; ++i) { + function sumAsm(uint[] memory data) public pure returns (uint sum) { + for (uint i = 0; i < data.length; ++i) { assembly { - sum := add(sum, mload(add(add(_data, 0x20), mul(i, 0x20)))) + sum := add(sum, mload(add(add(data, 0x20), mul(i, 0x20)))) } } } // Same as above, but accomplish the entire code within inline assembly. - function sumPureAsm(uint[] memory _data) public pure returns (uint sum) { + function sumPureAsm(uint[] memory data) public pure returns (uint sum) { assembly { // Load the length (first 32 bytes) - let len := mload(_data) + let len := mload(data) // Skip over the length field. // // Keep temporary variable so it can be incremented in place. // - // NOTE: incrementing _data would result in an unusable - // _data variable after this assembly block - let data := add(_data, 0x20) + // NOTE: incrementing data would result in an unusable + // data variable after this assembly block + let dataElementLocation := add(data, 0x20) // Iterate until the bound is not met. for - { let end := add(data, mul(len, 0x20)) } - lt(data, end) - { data := add(data, 0x20) } + { let end := add(dataElementLocation, mul(len, 0x20)) } + lt(dataElementLocation, end) + { data := add(dataElementLocation, 0x20) } { - sum := add(sum, mload(data)) + sum := add(sum, mload(dataElementLocation)) } } } diff --git a/docs/bugs.json b/docs/bugs.json index 0b72c05c7d96..9e24175b4b4e 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -1,4 +1,15 @@ [ + { + "uid": "SOL-2022-1", + "name": "AbiEncodeCallLiteralAsFixedBytesBug", + "summary": "Literals used for a fixed length bytes parameter in ``abi.encodeCall`` were encoded incorrectly.", + "description": "For the encoding, the compiler only considered the types of the expressions in the second argument of ``abi.encodeCall`` itself, but not the parameter types of the function given as first argument. In almost all cases the abi encoding of the type of the expression matches the abi encoding of the parameter type of the given function. This is because the type checker ensures the expression is implicitly convertible to the respective parameter type. However this is not true for number literals used for fixed bytes types shorter than 32 bytes, nor for string literals used for any fixed bytes type. Number literals were encoded as numbers instead of being shifted to become left-aligned. String literals were encoded as dynamically sized memory strings instead of being converted to a left-aligned bytes value.", + "link": "https://blog.soliditylang.org/2022/03/16/encodecall-bug/", + "introduced": "0.8.11", + "fixed": "0.8.13", + "severity": "very low" + + }, { "uid": "SOL-2021-4", "name": "UserDefinedValueTypesBug", @@ -8,7 +19,6 @@ "introduced": "0.8.8", "fixed": "0.8.9", "severity": "very low" - }, { "uid": "SOL-2021-3", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 0aae3f1ac4ed..7b9a7fc3d524 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -1549,13 +1549,21 @@ "released": "2021-11-09" }, "0.8.11": { - "bugs": [], + "bugs": [ + "AbiEncodeCallLiteralAsFixedBytesBug" + ], "released": "2021-12-20" }, "0.8.12": { - "bugs": [], + "bugs": [ + "AbiEncodeCallLiteralAsFixedBytesBug" + ], "released": "2022-02-16" }, + "0.8.13": { + "bugs": [], + "released": "2022-03-16" + }, "0.8.2": { "bugs": [ "SignedImmutables", diff --git a/docs/common-patterns.rst b/docs/common-patterns.rst index 86c81dbfb966..1793ebd2f27a 100644 --- a/docs/common-patterns.rst +++ b/docs/common-patterns.rst @@ -163,9 +163,9 @@ restrictions highly readable. // prepend a check that only passes // if the function is called from // a certain address. - modifier onlyBy(address _account) + modifier onlyBy(address account) { - if (msg.sender != _account) + if (msg.sender != account) revert Unauthorized(); // Do not forget the "_;"! It will // be replaced by the actual function @@ -173,17 +173,17 @@ restrictions highly readable. _; } - /// Make `_newOwner` the new owner of this + /// Make `newOwner` the new owner of this /// contract. - function changeOwner(address _newOwner) + function changeOwner(address newOwner) public onlyBy(owner) { - owner = _newOwner; + owner = newOwner; } - modifier onlyAfter(uint _time) { - if (block.timestamp < _time) + modifier onlyAfter(uint time) { + if (block.timestamp < time) revert TooEarly(); _; } @@ -205,21 +205,21 @@ restrictions highly readable. // refunded, but only after the function body. // This was dangerous before Solidity version 0.4.0, // where it was possible to skip the part after `_;`. - modifier costs(uint _amount) { - if (msg.value < _amount) + modifier costs(uint amount) { + if (msg.value < amount) revert NotEnoughEther(); _; - if (msg.value > _amount) - payable(msg.sender).transfer(msg.value - _amount); + if (msg.value > amount) + payable(msg.sender).transfer(msg.value - amount); } - function forceOwnerChange(address _newOwner) + function forceOwnerChange(address newOwner) public payable costs(200 ether) { - owner = _newOwner; + owner = newOwner; // just some example condition if (uint160(owner) & 0 == 1) // This did not refund for Solidity @@ -315,8 +315,8 @@ function finishes. uint public creationTime = block.timestamp; - modifier atStage(Stages _stage) { - if (stage != _stage) + modifier atStage(Stages stage_) { + if (stage != stage_) revert FunctionInvalidAtThisStage(); _; } diff --git a/docs/contracts/constant-state-variables.rst b/docs/contracts/constant-state-variables.rst index b67068d635a4..e917cad7f608 100644 --- a/docs/contracts/constant-state-variables.rst +++ b/docs/contracts/constant-state-variables.rst @@ -41,14 +41,14 @@ Not all types for constants and immutables are implemented at this time. The onl uint immutable maxBalance; address immutable owner = msg.sender; - constructor(uint _decimals, address _reference) { - decimals = _decimals; + constructor(uint decimals_, address ref) { + decimals = decimals_; // Assignments to immutables can even access the environment. - maxBalance = _reference.balance; + maxBalance = ref.balance; } - function isBalanceTooHigh(address _other) public view returns (bool) { - return _other.balance > maxBalance; + function isBalanceTooHigh(address other) public view returns (bool) { + return other.balance > maxBalance; } } diff --git a/docs/contracts/creating-contracts.rst b/docs/contracts/creating-contracts.rst index f1fd3b0b5052..f574a5a6aae0 100644 --- a/docs/contracts/creating-contracts.rst +++ b/docs/contracts/creating-contracts.rst @@ -48,7 +48,7 @@ This means that cyclic creation dependencies are impossible. // This is the constructor which registers the // creator and the assigned name. - constructor(bytes32 _name) { + constructor(bytes32 name_) { // State variables are accessed via their name // and not via e.g. `this.owner`. Functions can // be accessed directly or through `this.f`, @@ -65,7 +65,7 @@ This means that cyclic creation dependencies are impossible. // no real way to verify that. // This does not create a new contract. creator = TokenCreator(msg.sender); - name = _name; + name = name_; } function changeName(bytes32 newName) public { diff --git a/docs/contracts/events.rst b/docs/contracts/events.rst index 6e99a332bcf0..27df4dde162a 100644 --- a/docs/contracts/events.rst +++ b/docs/contracts/events.rst @@ -80,18 +80,18 @@ four indexed arguments rather than three. contract ClientReceipt { event Deposit( - address indexed _from, - bytes32 indexed _id, - uint _value + address indexed from, + bytes32 indexed id, + uint value ); - function deposit(bytes32 _id) public payable { + function deposit(bytes32 id) public payable { // Events are emitted using `emit`, followed by // the name of the event and the arguments // (if any) in parentheses. Any such invocation // (even deeply nested) can be detected from // the JavaScript API by filtering for `Deposit`. - emit Deposit(msg.sender, _id, msg.value); + emit Deposit(msg.sender, id, msg.value); } } @@ -126,9 +126,9 @@ The output of the above looks like the following (trimmed): { "returnValues": { - "_from": "0x1111…FFFFCCCC", - "_id": "0x50…sd5adb20", - "_value": "0x420042" + "from": "0x1111…FFFFCCCC", + "id": "0x50…sd5adb20", + "value": "0x420042" }, "raw": { "data": "0x7f…91385", diff --git a/docs/contracts/function-modifiers.rst b/docs/contracts/function-modifiers.rst index 0d4c8e8c266b..2445895e41b0 100644 --- a/docs/contracts/function-modifiers.rst +++ b/docs/contracts/function-modifiers.rst @@ -72,8 +72,8 @@ if they are marked ``virtual``. For details, please see registeredAddresses[msg.sender] = true; } - function changePrice(uint _price) public onlyOwner { - price = _price; + function changePrice(uint price_) public onlyOwner { + price = price_; } } diff --git a/docs/contracts/functions.rst b/docs/contracts/functions.rst index cada0e5d9414..8957d0f547c0 100644 --- a/docs/contracts/functions.rst +++ b/docs/contracts/functions.rst @@ -17,17 +17,17 @@ that call them, similar to internal library functions. // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.1 <0.9.0; - function sum(uint[] memory _arr) pure returns (uint s) { - for (uint i = 0; i < _arr.length; i++) - s += _arr[i]; + function sum(uint[] memory arr) pure returns (uint s) { + for (uint i = 0; i < arr.length; i++) + s += arr[i]; } contract ArrayExample { bool found; - function f(uint[] memory _arr) public { + function f(uint[] memory arr) public { // This calls the free function internally. // The compiler will add its code to the contract. - uint s = sum(_arr); + uint s = sum(arr); require(s >= 10); found = true; } @@ -65,8 +65,8 @@ with two integers, you would use something like the following: contract Simple { uint sum; - function taker(uint _a, uint _b) public { - sum = _a + _b; + function taker(uint a, uint b) public { + sum = a + b; } } @@ -99,13 +99,13 @@ two integers passed as function parameters, then you use something like: pragma solidity >=0.4.16 <0.9.0; contract Simple { - function arithmetic(uint _a, uint _b) + function arithmetic(uint a, uint b) public pure returns (uint sum, uint product) { - sum = _a + _b; - product = _a * _b; + sum = a + b; + product = a * b; } } @@ -126,12 +126,12 @@ statement: pragma solidity >=0.4.16 <0.9.0; contract Simple { - function arithmetic(uint _a, uint _b) + function arithmetic(uint a, uint b) public pure returns (uint sum, uint product) { - return (_a + _b, _a * _b); + return (a + b, a * b); } } @@ -362,7 +362,7 @@ Fallback Function ----------------- 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)`` +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. @@ -373,8 +373,8 @@ 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 +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 @@ -397,7 +397,7 @@ operations as long as there is enough gas passed on to it. 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(_input[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. @@ -486,13 +486,13 @@ The following example shows overloading of the function pragma solidity >=0.4.16 <0.9.0; contract A { - function f(uint _in) public pure returns (uint out) { - out = _in; + function f(uint value) public pure returns (uint out) { + out = value; } - function f(uint _in, bool _really) public pure returns (uint out) { - if (_really) - out = _in; + function f(uint value, bool really) public pure returns (uint out) { + if (really) + out = value; } } @@ -506,12 +506,12 @@ externally visible functions differ by their Solidity types but not by their ext // This will not compile contract A { - function f(B _in) public pure returns (B out) { - out = _in; + function f(B value) public pure returns (B out) { + out = value; } - function f(address _in) public pure returns (address out) { - out = _in; + function f(address value) public pure returns (address out) { + out = value; } } @@ -539,12 +539,12 @@ candidate, resolution fails. pragma solidity >=0.4.16 <0.9.0; contract A { - function f(uint8 _in) public pure returns (uint8 out) { - out = _in; + function f(uint8 val) public pure returns (uint8 out) { + out = val; } - function f(uint256 _in) public pure returns (uint256 out) { - out = _in; + function f(uint256 val) public pure returns (uint256 out) { + out = val; } } diff --git a/docs/contracts/inheritance.rst b/docs/contracts/inheritance.rst index b77feda0a1e2..54817837c47d 100644 --- a/docs/contracts/inheritance.rst +++ b/docs/contracts/inheritance.rst @@ -421,8 +421,8 @@ equivalent to ``constructor() {}``. For example: abstract contract A { uint public a; - constructor(uint _a) { - a = _a; + constructor(uint a_) { + a = a_; } } @@ -459,7 +459,7 @@ derived contracts need to specify all of them. This can be done in two ways: contract Base { uint x; - constructor(uint _x) { x = _x; } + constructor(uint x_) { x = x_; } } // Either directly specify in the inheritance list... @@ -469,12 +469,12 @@ derived contracts need to specify all of them. This can be done in two ways: // or through a "modifier" of the derived constructor. contract Derived2 is Base { - constructor(uint _y) Base(_y * _y) {} + constructor(uint y) Base(y * y) {} } One way is directly in the inheritance list (``is Base(7)``). The other is in the way a modifier is invoked as part of -the derived constructor (``Base(_y * _y)``). The first way to +the derived constructor (``Base(y * y)``). The first way to do it is more convenient if the constructor argument is a constant and defines the behaviour of the contract or describes it. The second way has to be used if the diff --git a/docs/contracts/interfaces.rst b/docs/contracts/interfaces.rst index a4581a15f9dc..cc71cf64e652 100644 --- a/docs/contracts/interfaces.rst +++ b/docs/contracts/interfaces.rst @@ -10,7 +10,7 @@ Interfaces are similar to abstract contracts, but they cannot have any functions There are further restrictions: - They cannot inherit from other contracts, but they can inherit from other interfaces. -- All declared functions must be external. +- All declared functions must be external in the interface, even if they are public in the contract. - They cannot declare a constructor. - They cannot declare state variables. - They cannot declare modifiers. diff --git a/docs/contracts/libraries.rst b/docs/contracts/libraries.rst index 76bedba49b12..c40284b49904 100644 --- a/docs/contracts/libraries.rst +++ b/docs/contracts/libraries.rst @@ -146,16 +146,16 @@ custom types without the overhead of external function calls: r.limbs[0] = x; } - function add(bigint memory _a, bigint memory _b) internal pure returns (bigint memory r) { - r.limbs = new uint[](max(_a.limbs.length, _b.limbs.length)); + function add(bigint memory a, bigint memory b) internal pure returns (bigint memory r) { + r.limbs = new uint[](max(a.limbs.length, b.limbs.length)); uint carry = 0; for (uint i = 0; i < r.limbs.length; ++i) { - uint a = limb(_a, i); - uint b = limb(_b, i); + uint limbA = limb(a, i); + uint limbB = limb(b, i); unchecked { - r.limbs[i] = a + b + carry; + r.limbs[i] = limbA + limbB + carry; - if (a + b < a || (a + b == type(uint).max && carry > 0)) + if (limbA + limbB < limbA || (limbA + limbB == type(uint).max && carry > 0)) carry = 1; else carry = 0; @@ -172,8 +172,8 @@ custom types without the overhead of external function calls: } } - function limb(bigint memory _a, uint _limb) internal pure returns (uint) { - return _limb < _a.limbs.length ? _a.limbs[_limb] : 0; + function limb(bigint memory a, uint index) internal pure returns (uint) { + return index < a.limbs.length ? a.limbs[index] : 0; } function max(uint a, uint b) private pure returns (uint) { diff --git a/docs/contracts/using-for.rst b/docs/contracts/using-for.rst index af6750f87d2d..2c2817f1503b 100644 --- a/docs/contracts/using-for.rst +++ b/docs/contracts/using-for.rst @@ -6,71 +6,96 @@ Using For ********* -The directive ``using A for B;`` can be used to attach library -functions (from the library ``A``) to any type (``B``) -in the context of a contract. +The directive ``using A for B;`` can be used to attach +functions (``A``) as member functions to any type (``B``). These functions will receive the object they are called on as their first parameter (like the ``self`` variable in Python). -The effect of ``using A for *;`` is that the functions from -the library ``A`` are attached to *any* type. +It is valid either at file level or inside a contract, +at contract level. -In both situations, *all* functions in the library are attached, +The first part, ``A``, can be one of: + +- a list of file-level or library functions (``using {f, g, h, L.t} for uint;``) - + only those functions will be attached to the type. +- the name of a library (``using L for uint;``) - + all functions (both public and internal ones) of the library are attached to the type + +At file level, the second part, ``B``, has to be an explicit type (without data location specifier). +Inside contracts, you can also use ``using L for *;``, +which has the effect that all functions of the library ``L`` +are attached to *all* types. + +If you specify a library, *all* functions in the library are attached, even those where the type of the first parameter does not match the type of the object. The type is checked at the point the function is called and function overload resolution is performed. +If you use a list of functions (``using {f, g, h, L.t} for uint;``), +then the type (``uint``) has to be implicitly convertible to the +first parameter of each of these functions. This check is +performed even if none of these functions are called. + The ``using A for B;`` directive is active only within the current -contract, including within all of its functions, and has no effect -outside of the contract in which it is used. The directive -may only be used inside a contract, not inside any of its functions. +scope (either the contract or the current module/source unit), +including within all of its functions, and has no effect +outside of the contract or module in which it is used. + +When the directive is used at file level and applied to a +user-defined type which was defined at file level in the same file, +the word ``global`` can be added at the end. This will have the +effect that the functions are attached to the type everywhere +the type is available (including other files), not only in the +scope of the using statement. Let us rewrite the set example from the -:ref:`libraries` in this way: +:ref:`libraries` section in this way, using file-level functions +instead of library functions. .. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 - pragma solidity >=0.6.0 <0.9.0; + pragma solidity ^0.8.13; - - // This is the same code as before, just without comments struct Data { mapping(uint => bool) flags; } + // Now we attach functions to the type. + // The attached functions can be used throughout the rest of the module. + // If you import the module, you have to + // repeat the using directive there, for example as + // import "flags.sol" as Flags; + // using {Flags.insert, Flags.remove, Flags.contains} + // for Flags.Data; + using {insert, remove, contains} for Data; + + function insert(Data storage self, uint value) + returns (bool) + { + if (self.flags[value]) + return false; // already there + self.flags[value] = true; + return true; + } - library Set { - function insert(Data storage self, uint value) - public - returns (bool) - { - if (self.flags[value]) - return false; // already there - self.flags[value] = true; - return true; - } - - function remove(Data storage self, uint value) - public - returns (bool) - { - if (!self.flags[value]) - return false; // not there - self.flags[value] = false; - return true; - } + function remove(Data storage self, uint value) + returns (bool) + { + if (!self.flags[value]) + return false; // not there + self.flags[value] = false; + return true; + } - function contains(Data storage self, uint value) - public - view - returns (bool) - { - return self.flags[value]; - } + function contains(Data storage self, uint value) + public + view + returns (bool) + { + return self.flags[value]; } contract C { - using Set for Data; // this is the crucial change Data knownValues; function register(uint value) public { @@ -82,12 +107,13 @@ Let us rewrite the set example from the } } -It is also possible to extend elementary types in that way: +It is also possible to extend built-in types in that way. +In this example, we will use a library. .. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 - pragma solidity >=0.6.8 <0.9.0; + pragma solidity ^0.8.13; library Search { function indexOf(uint[] storage self, uint value) @@ -100,22 +126,22 @@ It is also possible to extend elementary types in that way: return type(uint).max; } } + using Search for uint[]; contract C { - using Search for uint[]; uint[] data; function append(uint value) public { data.push(value); } - function replace(uint _old, uint _new) public { + function replace(uint from, uint to) public { // This performs the library function call - uint index = data.indexOf(_old); + uint index = data.indexOf(from); if (index == type(uint).max) - data.push(_new); + data.push(to); else - data[index] = _new; + data[index] = to; } } diff --git a/docs/control-structures.rst b/docs/control-structures.rst index 0ce7d21e33ec..de3b58485ca9 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -283,7 +283,7 @@ which only need to be created if there is a dispute. salt, keccak256(abi.encodePacked( type(D).creationCode, - arg + abi.encode(arg) )) ))))); diff --git a/docs/grammar/SolidityLexer.g4 b/docs/grammar/SolidityLexer.g4 index 653255ae364a..9250835dd23f 100644 --- a/docs/grammar/SolidityLexer.g4 +++ b/docs/grammar/SolidityLexer.g4 @@ -47,6 +47,7 @@ FixedBytes: 'bytes25' | 'bytes26' | 'bytes27' | 'bytes28' | 'bytes29' | 'bytes30' | 'bytes31' | 'bytes32'; For: 'for'; Function: 'function'; +Global: 'global'; // not a real keyword Hex: 'hex'; If: 'if'; Immutable: 'immutable'; diff --git a/docs/grammar/SolidityParser.g4 b/docs/grammar/SolidityParser.g4 index e41bb2ba9d17..92718b97523f 100644 --- a/docs/grammar/SolidityParser.g4 +++ b/docs/grammar/SolidityParser.g4 @@ -12,6 +12,7 @@ options { tokenVocab=SolidityLexer; } sourceUnit: ( pragmaDirective | importDirective + | usingDirective | contractDefinition | interfaceDefinition | libraryDefinition @@ -311,10 +312,10 @@ errorDefinition: Semicolon; /** - * Using directive to bind library functions to types. - * Can occur within contracts and libraries. + * Using directive to bind library functions and free functions to types. + * Can occur within contracts and libraries and at the file level. */ -usingDirective: Using identifierPath For (Mul | typeName) Semicolon; +usingDirective: Using (identifierPath | (LBrace identifierPath (Comma identifierPath)* RBrace)) For (Mul | typeName) Global? Semicolon; /** * A type name can be an elementary type, a function type, a mapping type, a user-defined type * (e.g. a contract or struct) or an array type. @@ -388,7 +389,7 @@ inlineArrayExpression: LBrack (expression ( Comma expression)* ) RBrack; /** * Besides regular non-keyword Identifiers, some keywords like 'from' and 'error' can also be used as identifiers. */ -identifier: Identifier | From | Error | Revert; +identifier: Identifier | From | Error | Revert | Global; literal: stringLiteral | numberLiteral | booleanLiteral | hexStringLiteral | unicodeStringLiteral; booleanLiteral: True | False; diff --git a/docs/internals/layout_in_storage.rst b/docs/internals/layout_in_storage.rst index 4682d640c150..599cd03d3e74 100644 --- a/docs/internals/layout_in_storage.rst +++ b/docs/internals/layout_in_storage.rst @@ -140,8 +140,7 @@ by checking if the lowest bit is set: short (not set) and long (set). .. note:: Handling invalidly encoded slots is currently not supported but may be added in the future. - If you are compiling via the experimental IR-based compiler pipeline, reading an invalidly encoded - slot results in a ``Panic(0x22)`` error. + If you are compiling via IR, reading an invalidly encoded slot results in a ``Panic(0x22)`` error. JSON Output =========== diff --git a/docs/internals/optimizer.rst b/docs/internals/optimizer.rst index a7eff7346bda..1d6c214e5faa 100644 --- a/docs/internals/optimizer.rst +++ b/docs/internals/optimizer.rst @@ -23,7 +23,7 @@ call completely. Currently, the parameter ``--optimize`` activates the opcode-based optimizer for the generated bytecode and the Yul optimizer for the Yul code generated internally, for example for ABI coder v2. One can use ``solc --ir-optimized --optimize`` to produce an -optimized experimental Yul IR for a Solidity source. Similarly, one can use ``solc --strict-assembly --optimize`` +optimized Yul IR for a Solidity source. Similarly, one can use ``solc --strict-assembly --optimize`` for a stand-alone Yul mode. You can find more details on both optimizer modules and their optimization steps below. diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst index 94188a097436..7adbfaedbaa1 100644 --- a/docs/introduction-to-smart-contracts.rst +++ b/docs/introduction-to-smart-contracts.rst @@ -168,8 +168,8 @@ following: .. code-block:: solidity - function balances(address _account) external view returns (uint) { - return balances[_account]; + function balances(address account) external view returns (uint) { + return balances[account]; } You can use this function to query the balance of a single account. diff --git a/docs/ir-breaking-changes.rst b/docs/ir-breaking-changes.rst index 3fce53b3b81c..2b5905a96bb5 100644 --- a/docs/ir-breaking-changes.rst +++ b/docs/ir-breaking-changes.rst @@ -15,11 +15,7 @@ The IR-based code generator was introduced with an aim to not only allow code generation to be more transparent and auditable but also to enable more powerful optimization passes that span across functions. -Currently, the IR-based code generator is still marked experimental, -but it supports all language features and has received a lot of testing, -so we consider it almost ready for production use. - -You can enable it on the command line using ``--experimental-via-ir`` +You can enable it on the command line using ``--via-ir`` or with the option ``{"viaIR": true}`` in standard-json and we encourage everyone to try it out! @@ -34,6 +30,48 @@ Semantic Only Changes This section lists the changes that are semantic-only, thus potentially hiding new and different behavior in existing code. +- The order of state variable initialization has changed in case of inheritance. + + The order used to be: + + - All state variables are zero-initialized at the beginning. + - Evaluate base constructor arguments from most derived to most base contract. + - Initialize all state variables in the whole inheritance hierarchy from most base to most derived. + - Run the constructor, if present, for all contracts in the linearized hierarchy from most base to most derived. + + New order: + + - All state variables are zero-initialized at the beginning. + - Evaluate base constructor arguments from most derived to most base contract. + - For every contract in order from most base to most derived in the linearized hierarchy: + + 1. Initialize state variables. + 2. Run the constructor (if present). + + This causes differences in contracts where the initial value of a state + variable relies on the result of the constructor in another contract: + + .. code-block:: solidity + + // SPDX-License-Identifier: GPL-3.0 + pragma solidity >=0.7.1; + + contract A { + uint x; + constructor() { + x = 42; + } + function f() public view returns(uint256) { + return x; + } + } + contract B is A { + uint public y = f(); + } + + Previously, ``y`` would be set to 0. This is due to the fact that we would first initialize state variables: First, ``x`` is set to 0, and when initializing ``y``, ``f()`` would return 0 causing ``y`` to be 0 as well. + With the new rules, ``y`` will be set to 42. We first initialize ``x`` to 0, then call A's constructor which sets ``x`` to 42. Finally, when initializing ``y``, ``f()`` returns 42 causing ``y`` to be 42. + - When storage structs are deleted, every storage slot that contains a member of the struct is set to zero entirely. Formerly, padding space was left untouched. @@ -78,8 +116,8 @@ hiding new and different behavior in existing code. // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0; contract C { - function f(uint _a) public pure mod() returns (uint _r) { - _r = _a++; + function f(uint a) public pure mod() returns (uint r) { + r = a++; } modifier mod() { _; _; } } @@ -116,47 +154,6 @@ hiding new and different behavior in existing code. - New code generator: ``0`` as all parameters, including return parameters, will be re-initialized before each ``_;`` evaluation. -- The order of contract initialization has changed in case of inheritance. - - The order used to be: - - - All state variables are zero-initialized at the beginning. - - Evaluate base constructor arguments from most derived to most base contract. - - Initialize all state variables in the whole inheritance hierarchy from most base to most derived. - - Run the constructor, if present, for all contracts in the linearized hierarchy from most base to most derived. - - New order: - - - All state variables are zero-initialized at the beginning. - - Evaluate base constructor arguments from most derived to most base contract. - - For every contract in order from most base to most derived in the linearized hierarchy execute: - - 1. If present at declaration, initial values are assigned to state variables. - 2. Constructor, if present. - -This causes differences in some contracts, for example: - - .. code-block:: solidity - - // SPDX-License-Identifier: GPL-3.0 - pragma solidity >=0.7.1; - - contract A { - uint x; - constructor() { - x = 42; - } - function f() public view returns(uint256) { - return x; - } - } - contract B is A { - uint public y = f(); - } - - Previously, ``y`` would be set to 0. This is due to the fact that we would first initialize state variables: First, ``x`` is set to 0, and when initializing ``y``, ``f()`` would return 0 causing ``y`` to be 0 as well. - With the new rules, ``y`` will be set to 42. We first initialize ``x`` to 0, then call A's constructor which sets ``x`` to 42. Finally, when initializing ``y``, ``f()`` returns 42 causing ``y`` to be 42. - - Copying ``bytes`` arrays from memory to storage is implemented in a different way. The old code generator always copies full words, while the new one cuts the byte array after its end. The old behaviour can lead to dirty data being copied after @@ -170,7 +167,7 @@ This causes differences in some contracts, for example: contract C { bytes x; - function f() public returns (uint _r) { + function f() public returns (uint r) { bytes memory m = "tmp"; assembly { mstore(m, 8) @@ -178,7 +175,7 @@ This causes differences in some contracts, for example: } x = m; assembly { - _r := sload(x.slot) + r := sload(x.slot) } } } @@ -201,8 +198,8 @@ This causes differences in some contracts, for example: // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.1; contract C { - function preincr_u8(uint8 _a) public pure returns (uint8) { - return ++_a + _a; + function preincr_u8(uint8 a) public pure returns (uint8) { + return ++a + a; } } @@ -222,11 +219,11 @@ This causes differences in some contracts, for example: // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.1; contract C { - function add(uint8 _a, uint8 _b) public pure returns (uint8) { - return _a + _b; + function add(uint8 a, uint8 b) public pure returns (uint8) { + return a + b; } - function g(uint8 _a, uint8 _b) public pure returns (uint8) { - return add(++_a + ++_b, _a + _b); + function g(uint8 a, uint8 b) public pure returns (uint8) { + return add(++a + ++b, a + b); } } @@ -325,13 +322,13 @@ For example: // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.1; contract C { - function f(uint8 _a) public pure returns (uint _r1, uint _r2) + function f(uint8 a) public pure returns (uint r1, uint r2) { - _a = ~_a; + a = ~a; assembly { - _r1 := _a + r1 := a } - _r2 = _a; + r2 = a; } } @@ -340,6 +337,6 @@ The function ``f(1)`` returns the following values: - Old code generator: (``fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe``, ``00000000000000000000000000000000000000000000000000000000000000fe``) - New code generator: (``00000000000000000000000000000000000000000000000000000000000000fe``, ``00000000000000000000000000000000000000000000000000000000000000fe``) -Note that, unlike the new code generator, the old code generator does not perform a cleanup after the bit-not assignment (``_a = ~_a``). -This results in different values being assigned (within the inline assembly block) to return value ``_r1`` between the old and new code generators. -However, both code generators perform a cleanup before the new value of ``_a`` is assigned to ``_r2``. +Note that, unlike the new code generator, the old code generator does not perform a cleanup after the bit-not assignment (``a = ~a``). +This results in different values being assigned (within the inline assembly block) to return value ``r1`` between the old and new code generators. +However, both code generators perform a cleanup before the new value of ``a`` is assigned to ``r2``. diff --git a/docs/layout-of-source-files.rst b/docs/layout-of-source-files.rst index 921211248bbf..729951142a46 100644 --- a/docs/layout-of-source-files.rst +++ b/docs/layout-of-source-files.rst @@ -3,8 +3,8 @@ Layout of a Solidity Source File ******************************** Source files can contain an arbitrary number of -:ref:`contract definitions`, import_ directives, -:ref:`pragma directives` and +:ref:`contract definitions`, import_ , +:ref:`pragma` and :ref:`using for` directives and :ref:`struct`, :ref:`enum`, :ref:`function`, :ref:`error` and :ref:`constant variable` definitions. diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst index 09770c5707cb..ceadfd0bc022 100644 --- a/docs/security-considerations.rst +++ b/docs/security-considerations.rst @@ -210,9 +210,9 @@ using a second proxy: contract ProxyWithMoreFunctionality { PermissionlessProxy proxy; - function callOther(address _addr, bytes memory _payload) public + function callOther(address addr, bytes memory payload) public returns (bool, bytes memory) { - return proxy.callOther(_addr, _payload); + return proxy.callOther(addr, payload); } // Other functions and other functionality } @@ -220,9 +220,9 @@ using a second proxy: // This is the full contract, it has no other functionality and // requires no privileges to work. contract PermissionlessProxy { - function callOther(address _addr, bytes memory _payload) public + function callOther(address addr, bytes memory payload) public returns (bool, bytes memory) { - return _addr.call(_payload); + return addr.call(payload); } } @@ -331,17 +331,17 @@ field of a ``struct`` that is the base type of a dynamic storage array. The contract Map { mapping (uint => uint)[] array; - function allocate(uint _newMaps) public { - for (uint i = 0; i < _newMaps; i++) + function allocate(uint newMaps) public { + for (uint i = 0; i < newMaps; i++) array.push(); } - function writeMap(uint _map, uint _key, uint _value) public { - array[_map][_key] = _value; + function writeMap(uint map, uint key, uint value) public { + array[map][key] = value; } - function readMap(uint _map, uint _key) public view returns (uint) { - return array[_map][_key]; + function readMap(uint map, uint key) public view returns (uint) { + return array[map][key]; } function eraseMaps() public { diff --git a/docs/smtchecker.rst b/docs/smtchecker.rst index 791659897e4a..5093408a7efd 100644 --- a/docs/smtchecker.rst +++ b/docs/smtchecker.rst @@ -82,12 +82,12 @@ Overflow uint immutable x; uint immutable y; - function add(uint _x, uint _y) internal pure returns (uint) { - return _x + _y; + function add(uint x_, uint y_) internal pure returns (uint) { + return x_ + y_; } - constructor(uint _x, uint _y) { - (x, y) = (_x, _y); + constructor(uint x_, uint y_) { + (x, y) = (x_, y_); } function stateAdd() public view returns (uint) { @@ -116,7 +116,7 @@ Here, it reports the following: Overflow.add(1, 115792089237316195423570985008687907853269984665640564039457584007913129639935) -- internal call --> o.sol:9:20: | - 9 | return _x + _y; + 9 | return x_ + y_; | ^^^^^^^ If we add ``require`` statements that filter out overflow cases, @@ -131,12 +131,12 @@ the SMTChecker proves that no overflow is reachable (by not reporting warnings): uint immutable x; uint immutable y; - function add(uint _x, uint _y) internal pure returns (uint) { - return _x + _y; + function add(uint x_, uint y_) internal pure returns (uint) { + return x_ + y_; } - constructor(uint _x, uint _y) { - (x, y) = (_x, _y); + constructor(uint x_, uint y_) { + (x, y) = (x_, y_); } function stateAdd() public view returns (uint) { @@ -155,7 +155,7 @@ An assertion represents an invariant in your code: a property that must be true The code below defines a function ``f`` that guarantees no overflow. Function ``inv`` defines the specification that ``f`` is monotonically increasing: -for every possible pair ``(_a, _b)``, if ``_b > _a`` then ``f(_b) > f(_a)``. +for every possible pair ``(a, b)``, if ``b > a`` then ``f(b) > f(a)``. Since ``f`` is indeed monotonically increasing, the SMTChecker proves that our property is correct. You are encouraged to play with the property and the function definition to see what results come out! @@ -166,14 +166,14 @@ definition to see what results come out! pragma solidity >=0.8.0; contract Monotonic { - function f(uint _x) internal pure returns (uint) { - require(_x < type(uint128).max); - return _x * 42; + function f(uint x) internal pure returns (uint) { + require(x < type(uint128).max); + return x * 42; } - function inv(uint _a, uint _b) public pure { - require(_b > _a); - assert(f(_b) > f(_a)); + function inv(uint a, uint b) public pure { + require(b > a); + assert(f(b) > f(a)); } } @@ -188,14 +188,14 @@ equal every element in the array. pragma solidity >=0.8.0; contract Max { - function max(uint[] memory _a) public pure returns (uint) { + function max(uint[] memory a) public pure returns (uint) { uint m = 0; - for (uint i = 0; i < _a.length; ++i) - if (_a[i] > m) - m = _a[i]; + for (uint i = 0; i < a.length; ++i) + if (a[i] > m) + m = a[i]; - for (uint i = 0; i < _a.length; ++i) - assert(m >= _a[i]); + for (uint i = 0; i < a.length; ++i) + assert(m >= a[i]); return m; } @@ -222,15 +222,15 @@ For example, changing the code to pragma solidity >=0.8.0; contract Max { - function max(uint[] memory _a) public pure returns (uint) { - require(_a.length >= 5); + function max(uint[] memory a) public pure returns (uint) { + require(a.length >= 5); uint m = 0; - for (uint i = 0; i < _a.length; ++i) - if (_a[i] > m) - m = _a[i]; + for (uint i = 0; i < a.length; ++i) + if (a[i] > m) + m = a[i]; - for (uint i = 0; i < _a.length; ++i) - assert(m > _a[i]); + for (uint i = 0; i < a.length; ++i) + assert(m > a[i]); return m; } @@ -243,7 +243,7 @@ gives us: Warning: CHC: Assertion violation happens here. Counterexample: - _a = [0, 0, 0, 0, 0] + a = [0, 0, 0, 0, 0] = 0 Transaction trace: @@ -251,7 +251,7 @@ gives us: Test.max([0, 0, 0, 0, 0]) --> max.sol:14:4: | - 14 | assert(m > _a[i]); + 14 | assert(m > a[i]); State Properties @@ -383,9 +383,9 @@ anything, including reenter the caller contract. Unknown immutable unknown; - constructor(Unknown _u) { - require(address(_u) != address(0)); - unknown = _u; + constructor(Unknown u) { + require(address(u) != address(0)); + unknown = u; } modifier mutex { @@ -395,8 +395,8 @@ anything, including reenter the caller contract. lock = false; } - function set(uint _x) mutex public { - x = _x; + function set(uint x_) mutex public { + x = x_; } function run() mutex public { @@ -754,15 +754,15 @@ not mean loss of proving power. { function f( bytes32 hash, - uint8 _v1, uint8 _v2, - bytes32 _r1, bytes32 _r2, - bytes32 _s1, bytes32 _s2 + uint8 v1, uint8 v2, + bytes32 r1, bytes32 r2, + bytes32 s1, bytes32 s2 ) public pure returns (address) { - address a1 = ecrecover(hash, _v1, _r1, _s1); - require(_v1 == _v2); - require(_r1 == _r2); - require(_s1 == _s2); - address a2 = ecrecover(hash, _v2, _r2, _s2); + address a1 = ecrecover(hash, v1, r1, s1); + require(v1 == v2); + require(r1 == r2); + require(s1 == s2); + address a2 = ecrecover(hash, v2, r2, s2); assert(a1 == a2); return a1; } diff --git a/docs/types/mapping-types.rst b/docs/types/mapping-types.rst index 399523cf22fc..1c94b20ab5f7 100644 --- a/docs/types/mapping-types.rst +++ b/docs/types/mapping-types.rst @@ -4,12 +4,12 @@ Mapping Types ============= -Mapping types use the syntax ``mapping(_KeyType => _ValueType)`` and variables -of mapping type are declared using the syntax ``mapping(_KeyType => _ValueType) _VariableName``. -The ``_KeyType`` can be any +Mapping types use the syntax ``mapping(KeyType => ValueType)`` and variables +of mapping type are declared using the syntax ``mapping(KeyType => ValueType) VariableName``. +The ``KeyType`` can be any built-in value type, ``bytes``, ``string``, or any contract or enum type. Other user-defined or complex types, such as mappings, structs or array types are not allowed. -``_ValueType`` can be any type, including mappings, arrays and structs. +``ValueType`` can be any type, including mappings, arrays and structs. You can think of mappings as `hash tables `_, which are virtually initialised such that every possible key exists and is mapped to a value whose @@ -29,10 +29,10 @@ of contract functions that are publicly visible. These restrictions are also true for arrays and structs that contain mappings. You can mark state variables of mapping type as ``public`` and Solidity creates a -:ref:`getter ` for you. The ``_KeyType`` becomes a parameter for the getter. -If ``_ValueType`` is a value type or a struct, the getter returns ``_ValueType``. -If ``_ValueType`` is an array or a mapping, the getter has one parameter for -each ``_KeyType``, recursively. +:ref:`getter ` for you. The ``KeyType`` becomes a parameter for the getter. +If ``ValueType`` is a value type or a struct, the getter returns ``ValueType``. +If ``ValueType`` is an array or a mapping, the getter has one parameter for +each ``KeyType``, recursively. In the example below, the ``MappingExample`` contract defines a public ``balances`` mapping, with the key type an ``address``, and a value type a ``uint``, mapping diff --git a/docs/types/operators.rst b/docs/types/operators.rst index 450963e11d8c..be5f0d45683d 100644 --- a/docs/types/operators.rst +++ b/docs/types/operators.rst @@ -26,6 +26,23 @@ except for comparison operators where the result is always ``bool``. The operators ``**`` (exponentiation), ``<<`` and ``>>`` use the type of the left operand for the operation and the result. +Ternary Operator +---------------- +The ternary operator is used in expressions of the form `` ? : ``. +It evaluates one of the latter two given expressions depending upon the result of the evaluation of the main ````. +If ```` evaluates to ``true``, then ```` will be evaluated, otherwise ```` is evaluated. + +The result of the ternary operator does not have a rational number type, even if all of its operands are rational number literals. +The result type is determined from the types of the two operands in the same way as above, converting to their mobile type first if required. + +As a consequence, ``255 + (true ? 1 : 0)`` will revert due to arithmetic overflow. +The reason is that ``(true ? 1 : 0)`` is of ``uint8`` type, which forces the addition to be performed in ``uint8`` as well, +and 256 exceeds the range allowed for this type. + +Another consequence is that an expression like ``1.5 + 1.5`` is valid but ``1.5 + (true ? 1.5 : 2.5)`` is not. +This is because the former is a rational expression evaluated in unlimited precision and only its final value matters. +The latter involves a conversion of a fractional rational number to an integer, which is currently disallowed. + .. index:: assignment, lvalue, ! compound operators Compound and Increment/Decrement Operators diff --git a/docs/types/reference-types.rst b/docs/types/reference-types.rst index f595612c024f..74b6daa7ff6f 100644 --- a/docs/types/reference-types.rst +++ b/docs/types/reference-types.rst @@ -511,21 +511,21 @@ Array slices are useful to ABI-decode secondary data passed in function paramete /// @dev Address of the client contract managed by proxy i.e., this contract address client; - constructor(address _client) { - client = _client; + constructor(address client_) { + client = client_; } /// Forward call to "setOwner(address)" that is implemented by client /// after doing basic validation on the address argument. - function forward(bytes calldata _payload) external { - bytes4 sig = bytes4(_payload[:4]); - // Due to truncating behaviour, bytes4(_payload) performs identically. - // bytes4 sig = bytes4(_payload); + function forward(bytes calldata payload) external { + bytes4 sig = bytes4(payload[:4]); + // Due to truncating behaviour, bytes4(payload) performs identically. + // bytes4 sig = bytes4(payload); if (sig == bytes4(keccak256("setOwner(address)"))) { - address owner = abi.decode(_payload[4:], (address)); + address owner = abi.decode(payload[4:], (address)); require(owner != address(0), "Address of owner cannot be zero."); } - (bool status,) = client.delegatecall(_payload); + (bool status,) = client.delegatecall(payload); require(status, "Forwarded call failed."); } } diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index 0d6a30cd62c3..8f10094078d3 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -463,7 +463,7 @@ There is no additional semantic meaning added to a number literal containing und the underscores are ignored. Number literal expressions retain arbitrary precision until they are converted to a non-literal type (i.e. by -using them together with a non-literal expression or by explicit conversion). +using them together with anything else than a number literal expression (like boolean literals) or by explicit conversion). This means that computations do not overflow and divisions do not truncate in number literal expressions. @@ -471,6 +471,15 @@ For example, ``(2**800 + 1) - 2**800`` results in the constant ``1`` (of type `` although intermediate results would not even fit the machine word size. Furthermore, ``.5 * 8`` results in the integer ``4`` (although non-integers were used in between). +.. warning:: + While most operators produce a literal expression when applied to literals, there are certain operators that do not follow this pattern: + + - Ternary operator (``... ? ... : ...``), + - Array subscript (``[]``). + + You might expect expressions like ``255 + (true ? 1 : 0)`` or ``255 + [1, 2, 3][0]`` to be equivalent to using the literal 256 + directly, but in fact they are computed within the type ``uint8`` and can overflow. + Any operator that can be applied to integers can also be applied to number literal expressions as long as the operands are integers. If any of the two is fractional, bit operations are disallowed and exponentiation is disallowed if the exponent is fractional (because that might result in diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index 067c96c96f62..3c2ec38f9b18 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -298,7 +298,7 @@ Input Description // tangerineWhistle, spuriousDragon, byzantium, constantinople, petersburg, istanbul or berlin "evmVersion": "byzantium", // Optional: Change compilation pipeline to go through the Yul intermediate representation. - // This is a highly EXPERIMENTAL feature, not to be used for production. This is false by default. + // This is false by default. "viaIR": true, // Optional: Debugging settings "debug": { diff --git a/docs/yul.rst b/docs/yul.rst index e4775ee4d0b7..8a584db1d4fe 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -1124,6 +1124,11 @@ regular strings in native encoding. For code, Above, ``Block`` refers to ``Block`` in the Yul code grammar explained in the previous chapter. +.. note:: + + An object with a name that ends in ``_deployed`` is treated as deployed code by the Yul optimizer. + The only consequence of this is a different gas cost heuristic in the optimizer. + .. note:: Data objects or sub-objects whose names contain a ``.`` can be defined @@ -1172,17 +1177,17 @@ An example Yul Object is shown below: // now return the runtime object (the currently // executing code is the constructor code) - size := datasize("runtime") + size := datasize("Contract1_deployed") offset := allocate(size) // This will turn into a memory->memory copy for Ewasm and // a codecopy for EVM - datacopy(offset, dataoffset("runtime"), size) + datacopy(offset, dataoffset("Contract1_deployed"), size) return(offset, size) } data "Table2" hex"4123" - object "runtime" { + object "Contract1_deployed" { code { function allocate(size) -> ptr { ptr := mload(0x40) @@ -1204,7 +1209,7 @@ An example Yul Object is shown below: // code here ... } - object "runtime" { + object "Contract2_deployed" { code { // code here ... } diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 55d23e283fbb..6d7b97cc4a7e 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -415,9 +415,8 @@ map const& Assembly::optimiseInternal( for (size_t subId = 0; subId < m_subs.size(); ++subId) { OptimiserSettings settings = _settings; - // Disable creation mode for sub-assemblies. - settings.isCreation = false; - map const& subTagReplacements = m_subs[subId]->optimiseInternal( + Assembly& sub = *m_subs[subId]; + map const& subTagReplacements = sub.optimiseInternal( settings, JumpdestRemover::referencedTags(m_items, subId) ); @@ -436,7 +435,7 @@ map const& Assembly::optimiseInternal( m_items, _tagsReferencedFromOutside, _settings.expectedExecutionsPerDeployment, - _settings.isCreation, + isCreation(), _settings.evmVersion }.optimise(); @@ -537,8 +536,8 @@ map const& Assembly::optimiseInternal( if (_settings.runConstantOptimiser) ConstantOptimisationMethod::optimiseConstants( - _settings.isCreation, - _settings.isCreation ? 1 : _settings.expectedExecutionsPerDeployment, + isCreation(), + isCreation() ? 1 : _settings.expectedExecutionsPerDeployment, _settings.evmVersion, *this ); diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index 97807e22382c..11bc16662979 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -48,7 +48,7 @@ using AssemblyPointer = std::shared_ptr; class Assembly { public: - explicit Assembly(std::string _name = std::string()):m_name(std::move(_name)) { } + Assembly(bool _creation, std::string _name): m_creation(_creation), m_name(std::move(_name)) { } AssemblyItem newTag() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(Tag, m_usedTags++); } AssemblyItem newPushTag() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(PushTag, m_usedTags++); } @@ -117,7 +117,6 @@ class Assembly struct OptimiserSettings { - bool isCreation = false; bool runInliner = false; bool runJumpdestRemover = false; bool runPeephole = false; @@ -157,6 +156,8 @@ class Assembly std::vector decodeSubPath(size_t _subObjectId) const; size_t encodeSubPath(std::vector const& _subPath); + bool isCreation() const { return m_creation; } + protected: /// Does the same operations as @a optimise, but should only be applied to a sub and /// returns the replaced tags. Also takes an argument containing the tags of this assembly @@ -214,6 +215,8 @@ class Assembly mutable std::vector m_tagPositionsInBytecode; int m_deposit = 0; + /// True, if the assembly contains contract creation code. + bool const m_creation = false; /// Internal name of the assembly object, only used with the Yul backend /// currently std::string m_name; diff --git a/libevmasm/CommonSubexpressionEliminator.cpp b/libevmasm/CommonSubexpressionEliminator.cpp index 8a4e9f6e3763..397d20f16982 100644 --- a/libevmasm/CommonSubexpressionEliminator.cpp +++ b/libevmasm/CommonSubexpressionEliminator.cpp @@ -219,7 +219,7 @@ void CSECodeGenerator::addDependencies(Id _c) { if (m_classPositions.count(_c)) return; // it is already on the stack - if (m_neededBy.count(_c)) + if (m_neededBy.find(_c) != m_neededBy.end()) return; // we already computed the dependencies for _c ExpressionClasses::Expression expr = m_expressionClasses.representative(_c); assertThrow(expr.item, OptimizerException, ""); @@ -300,8 +300,8 @@ void CSECodeGenerator::addDependencies(Id _c) void CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced) { - for (auto it: m_classPositions) - for (auto p: it.second) + for (auto const& it: m_classPositions) + for (int p: it.second) if (p > m_stackHeight) { assertThrow(false, OptimizerException, ""); diff --git a/libevmasm/CommonSubexpressionEliminator.h b/libevmasm/CommonSubexpressionEliminator.h index 88e559719320..51a5d74b22a3 100644 --- a/libevmasm/CommonSubexpressionEliminator.h +++ b/libevmasm/CommonSubexpressionEliminator.h @@ -24,11 +24,12 @@ #pragma once -#include #include +#include #include #include -#include +#include +#include #include #include #include @@ -154,11 +155,11 @@ class CSECodeGenerator /// Current height of the stack relative to the start. int m_stackHeight = 0; /// If (b, a) is in m_requests then b is needed to compute a. - std::multimap m_neededBy; + std::unordered_multimap m_neededBy; /// Current content of the stack. std::map m_stack; /// Current positions of equivalence classes, equal to the empty set if already deleted. - std::map> m_classPositions; + std::unordered_map> m_classPositions; /// The actual equivalence class items and how to compute them. ExpressionClasses& m_expressionClasses; diff --git a/libevmasm/PeepholeOptimiser.cpp b/libevmasm/PeepholeOptimiser.cpp index 8e4a09fcc185..334903c92b51 100644 --- a/libevmasm/PeepholeOptimiser.cpp +++ b/libevmasm/PeepholeOptimiser.cpp @@ -41,51 +41,28 @@ struct OptimiserState std::back_insert_iterator out; }; -template -struct ApplyRule +template +struct FunctionParameterCount; +template +struct FunctionParameterCount { + static constexpr auto value = sizeof...(Args); }; + template -struct ApplyRule -{ - static bool applyRule(AssemblyItems::const_iterator _in, std::back_insert_iterator _out) - { - return Method::applySimple(_in[0], _in[1], _in[2], _in[3], _out); - } -}; -template -struct ApplyRule -{ - static bool applyRule(AssemblyItems::const_iterator _in, std::back_insert_iterator _out) - { - return Method::applySimple(_in[0], _in[1], _in[2], _out); - } -}; -template -struct ApplyRule -{ - static bool applyRule(AssemblyItems::const_iterator _in, std::back_insert_iterator _out) - { - return Method::applySimple(_in[0], _in[1], _out); - } -}; -template -struct ApplyRule +struct SimplePeepholeOptimizerMethod { - static bool applyRule(AssemblyItems::const_iterator _in, std::back_insert_iterator _out) + template + static bool applyRule(AssemblyItems::const_iterator _in, back_insert_iterator _out, index_sequence) { - return Method::applySimple(_in[0], _out); + return Method::applySimple(_in[Indices]..., _out); } -}; - -template -struct SimplePeepholeOptimizerMethod -{ static bool apply(OptimiserState& _state) { + static constexpr size_t WindowSize = FunctionParameterCount::value - 1; if ( _state.i + WindowSize <= _state.items.size() && - ApplyRule::applyRule(_state.items.begin() + static_cast(_state.i), _state.out) + applyRule(_state.items.begin() + static_cast(_state.i), _state.out, make_index_sequence{}) ) { _state.i += WindowSize; @@ -96,7 +73,7 @@ struct SimplePeepholeOptimizerMethod } }; -struct Identity: SimplePeepholeOptimizerMethod +struct Identity: SimplePeepholeOptimizerMethod { static bool applySimple(AssemblyItem const& _item, std::back_insert_iterator _out) { @@ -105,7 +82,7 @@ struct Identity: SimplePeepholeOptimizerMethod } }; -struct PushPop: SimplePeepholeOptimizerMethod +struct PushPop: SimplePeepholeOptimizerMethod { static bool applySimple(AssemblyItem const& _push, AssemblyItem const& _pop, std::back_insert_iterator) { @@ -118,7 +95,7 @@ struct PushPop: SimplePeepholeOptimizerMethod } }; -struct OpPop: SimplePeepholeOptimizerMethod +struct OpPop: SimplePeepholeOptimizerMethod { static bool applySimple( AssemblyItem const& _op, @@ -140,7 +117,65 @@ struct OpPop: SimplePeepholeOptimizerMethod } }; -struct DoubleSwap: SimplePeepholeOptimizerMethod +struct OpStop: SimplePeepholeOptimizerMethod +{ + static bool applySimple( + AssemblyItem const& _op, + AssemblyItem const& _stop, + std::back_insert_iterator _out + ) + { + if (_stop == Instruction::STOP) + { + if (_op.type() == Operation) + { + Instruction instr = _op.instruction(); + if (!instructionInfo(instr).sideEffects) + { + *_out = {Instruction::STOP, _op.location()}; + return true; + } + } + else if (_op.type() == Push) + { + *_out = {Instruction::STOP, _op.location()}; + return true; + } + } + return false; + } +}; + +struct OpReturnRevert: SimplePeepholeOptimizerMethod +{ + static bool applySimple( + AssemblyItem const& _op, + AssemblyItem const& _push, + AssemblyItem const& _pushOrDup, + AssemblyItem const& _returnRevert, + std::back_insert_iterator _out + ) + { + if ( + (_returnRevert == Instruction::RETURN || _returnRevert == Instruction::REVERT) && + _push.type() == Push && + (_pushOrDup.type() == Push || _pushOrDup == dupInstruction(1)) + ) + if ( + (_op.type() == Operation && !instructionInfo(_op.instruction()).sideEffects) || + _op.type() == Push + ) + { + *_out = _push; + *_out = _pushOrDup; + *_out = _returnRevert; + return true; + } + return false; + } +}; + +struct DoubleSwap: SimplePeepholeOptimizerMethod { static size_t applySimple(AssemblyItem const& _s1, AssemblyItem const& _s2, std::back_insert_iterator) { @@ -148,7 +183,7 @@ struct DoubleSwap: SimplePeepholeOptimizerMethod } }; -struct DoublePush: SimplePeepholeOptimizerMethod +struct DoublePush: SimplePeepholeOptimizerMethod { static bool applySimple(AssemblyItem const& _push1, AssemblyItem const& _push2, std::back_insert_iterator _out) { @@ -163,7 +198,7 @@ struct DoublePush: SimplePeepholeOptimizerMethod } }; -struct CommutativeSwap: SimplePeepholeOptimizerMethod +struct CommutativeSwap: SimplePeepholeOptimizerMethod { static bool applySimple(AssemblyItem const& _swap, AssemblyItem const& _op, std::back_insert_iterator _out) { @@ -181,7 +216,7 @@ struct CommutativeSwap: SimplePeepholeOptimizerMethod } }; -struct SwapComparison: SimplePeepholeOptimizerMethod +struct SwapComparison: SimplePeepholeOptimizerMethod { static bool applySimple(AssemblyItem const& _swap, AssemblyItem const& _op, std::back_insert_iterator _out) { @@ -207,7 +242,7 @@ struct SwapComparison: SimplePeepholeOptimizerMethod }; /// Remove swapN after dupN -struct DupSwap: SimplePeepholeOptimizerMethod +struct DupSwap: SimplePeepholeOptimizerMethod { static size_t applySimple( AssemblyItem const& _dupN, @@ -230,7 +265,7 @@ struct DupSwap: SimplePeepholeOptimizerMethod }; -struct IsZeroIsZeroJumpI: SimplePeepholeOptimizerMethod +struct IsZeroIsZeroJumpI: SimplePeepholeOptimizerMethod { static size_t applySimple( AssemblyItem const& _iszero1, @@ -256,7 +291,66 @@ struct IsZeroIsZeroJumpI: SimplePeepholeOptimizerMethod } }; -struct JumpToNext: SimplePeepholeOptimizerMethod +struct EqIsZeroJumpI: SimplePeepholeOptimizerMethod +{ + static size_t applySimple( + AssemblyItem const& _eq, + AssemblyItem const& _iszero, + AssemblyItem const& _pushTag, + AssemblyItem const& _jumpi, + std::back_insert_iterator _out + ) + { + if ( + _eq == Instruction::EQ && + _iszero == Instruction::ISZERO && + _pushTag.type() == PushTag && + _jumpi == Instruction::JUMPI + ) + { + *_out = AssemblyItem(Instruction::SUB, _eq.location()); + *_out = _pushTag; + *_out = _jumpi; + return true; + } + else + return false; + } +}; + +// push_tag_1 jumpi push_tag_2 jump tag_1: -> iszero push_tag_2 jumpi tag_1: +struct DoubleJump: SimplePeepholeOptimizerMethod +{ + static size_t applySimple( + AssemblyItem const& _pushTag1, + AssemblyItem const& _jumpi, + AssemblyItem const& _pushTag2, + AssemblyItem const& _jump, + AssemblyItem const& _tag1, + std::back_insert_iterator _out + ) + { + if ( + _pushTag1.type() == PushTag && + _jumpi == Instruction::JUMPI && + _pushTag2.type() == PushTag && + _jump == Instruction::JUMP && + _tag1.type() == Tag && + _pushTag1.data() == _tag1.data() + ) + { + *_out = AssemblyItem(Instruction::ISZERO, _jumpi.location()); + *_out = _pushTag2; + *_out = _jumpi; + *_out = _tag1; + return true; + } + else + return false; + } +}; + +struct JumpToNext: SimplePeepholeOptimizerMethod { static size_t applySimple( AssemblyItem const& _pushTag, @@ -282,7 +376,7 @@ struct JumpToNext: SimplePeepholeOptimizerMethod } }; -struct TagConjunctions: SimplePeepholeOptimizerMethod +struct TagConjunctions: SimplePeepholeOptimizerMethod { static bool applySimple( AssemblyItem const& _pushTag, @@ -317,7 +411,7 @@ struct TagConjunctions: SimplePeepholeOptimizerMethod } }; -struct TruthyAnd: SimplePeepholeOptimizerMethod +struct TruthyAnd: SimplePeepholeOptimizerMethod { static bool applySimple( AssemblyItem const& _push, @@ -394,8 +488,8 @@ bool PeepholeOptimiser::optimise() while (state.i < m_items.size()) applyMethods( state, - PushPop(), OpPop(), DoublePush(), DoubleSwap(), CommutativeSwap(), SwapComparison(), - DupSwap(), IsZeroIsZeroJumpI(), JumpToNext(), UnreachableCode(), + PushPop(), OpPop(), OpStop(), OpReturnRevert(), DoublePush(), DoubleSwap(), CommutativeSwap(), SwapComparison(), + DupSwap(), IsZeroIsZeroJumpI(), EqIsZeroJumpI(), DoubleJump(), JumpToNext(), UnreachableCode(), TagConjunctions(), TruthyAnd(), Identity() ); if (m_optimisedItems.size() < m_items.size() || ( diff --git a/libevmasm/SemanticInformation.cpp b/libevmasm/SemanticInformation.cpp index 8a1266bcf06e..acbcaa5c0f3c 100644 --- a/libevmasm/SemanticInformation.cpp +++ b/libevmasm/SemanticInformation.cpp @@ -121,7 +121,9 @@ vector SemanticInformation::readWriteOperations( Location::Memory, Effect::Write, paramCount - 2, - paramCount - 1, + // Length is in paramCount - 1, but it is only a max length, + // there is no guarantee that the full area is written to. + {}, {} }); return operations; diff --git a/libsolc/CMakeLists.txt b/libsolc/CMakeLists.txt index 776b97ca5088..fce54dd24bb6 100644 --- a/libsolc/CMakeLists.txt +++ b/libsolc/CMakeLists.txt @@ -1,8 +1,17 @@ if (EMSCRIPTEN) + CreateExportedFunctionsForEMSDK( + ExportedFunctions + solidity_license + solidity_version + solidity_compile + solidity_alloc + solidity_free + solidity_reset + ) # Specify which functions to export in soljson.js. # Note that additional Emscripten-generated methods needed by solc-js are # defined to be exported in cmake/EthCompilerSettings.cmake. - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXPORTED_FUNCTIONS='[\"_solidity_license\",\"_solidity_version\",\"_solidity_compile\",\"_solidity_alloc\",\"_solidity_free\",\"_solidity_reset\"]'") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXPORTED_FUNCTIONS='${ExportedFunctions}'") add_executable(soljson libsolc.cpp libsolc.h) target_link_libraries(soljson PRIVATE solidity) else() diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index ff82cd9fb5e2..3d2845463c9c 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -155,12 +155,18 @@ set(sources interface/StorageLayout.h interface/Version.cpp interface/Version.h - lsp/LanguageServer.cpp - lsp/LanguageServer.h lsp/FileRepository.cpp lsp/FileRepository.h + lsp/GotoDefinition.cpp + lsp/GotoDefinition.h + lsp/HandlerBase.cpp + lsp/HandlerBase.h + lsp/LanguageServer.cpp + lsp/LanguageServer.h lsp/Transport.cpp lsp/Transport.h + lsp/Utils.cpp + lsp/Utils.h parsing/DocStringParser.cpp parsing/DocStringParser.h parsing/Parser.cpp diff --git a/libsolidity/analysis/ControlFlowAnalyzer.cpp b/libsolidity/analysis/ControlFlowAnalyzer.cpp index 0c64ac3b5b61..e80964acebab 100644 --- a/libsolidity/analysis/ControlFlowAnalyzer.cpp +++ b/libsolidity/analysis/ControlFlowAnalyzer.cpp @@ -129,7 +129,7 @@ void ControlFlowAnalyzer::checkUninitializedAccess(CFGNode const* _entry, CFGNod // Propagate changes to all exits and queue them for traversal, if needed. for (auto const& exit: currentNode->exits) if ( - auto exists = valueOrNullptr(nodeInfos, exit); + auto exists = util::valueOrNullptr(nodeInfos, exit); nodeInfos[exit].propagateFrom(nodeInfo) || !exists ) nodesToTraverse.insert(exit); diff --git a/libsolidity/analysis/ControlFlowBuilder.cpp b/libsolidity/analysis/ControlFlowBuilder.cpp index 3de1ecca54ed..7c568b18e180 100644 --- a/libsolidity/analysis/ControlFlowBuilder.cpp +++ b/libsolidity/analysis/ControlFlowBuilder.cpp @@ -457,8 +457,7 @@ void ControlFlowBuilder::operator()(yul::Switch const& _switch) } mergeFlow(nodes); - bool hasDefault = util::contains_if(_switch.cases, [](yul::Case const& _case) { return !_case.value; }); - if (!hasDefault) + if (!hasDefaultCase(_switch)) connect(beforeSwitch, m_currentNode); } diff --git a/libsolidity/analysis/ControlFlowRevertPruner.cpp b/libsolidity/analysis/ControlFlowRevertPruner.cpp index 9a44be57af97..ae9c18a13a9e 100644 --- a/libsolidity/analysis/ControlFlowRevertPruner.cpp +++ b/libsolidity/analysis/ControlFlowRevertPruner.cpp @@ -57,7 +57,7 @@ void ControlFlowRevertPruner::run() void ControlFlowRevertPruner::findRevertStates() { - std::set pendingFunctions = keys(m_functions); + std::set pendingFunctions = util::keys(m_functions); // We interrupt the search whenever we encounter a call to a function with (yet) unknown // revert behaviour. The ``wakeUp`` data structure contains information about which // searches to restart once we know about the behaviour. diff --git a/libsolidity/analysis/DeclarationTypeChecker.cpp b/libsolidity/analysis/DeclarationTypeChecker.cpp index ba989972cb42..4fb2104352f7 100644 --- a/libsolidity/analysis/DeclarationTypeChecker.cpp +++ b/libsolidity/analysis/DeclarationTypeChecker.cpp @@ -25,6 +25,7 @@ #include #include +#include #include @@ -451,12 +452,39 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable) bool DeclarationTypeChecker::visit(UsingForDirective const& _usingFor) { - ContractDefinition const* library = dynamic_cast( - _usingFor.libraryName().annotation().referencedDeclaration - ); + if (_usingFor.usesBraces()) + { + for (ASTPointer const& function: _usingFor.functionsOrLibrary()) + if (auto functionDefinition = dynamic_cast(function->annotation().referencedDeclaration)) + { + if (!functionDefinition->isFree() && !( + dynamic_cast(functionDefinition->scope()) && + dynamic_cast(functionDefinition->scope())->isLibrary() + )) + m_errorReporter.typeError( + 4167_error, + function->location(), + "Only file-level functions and library functions can be bound to a type in a \"using\" statement" + ); + } + else + m_errorReporter.fatalTypeError(8187_error, function->location(), "Expected function name." ); + } + else + { + ContractDefinition const* library = dynamic_cast( + _usingFor.functionsOrLibrary().front()->annotation().referencedDeclaration + ); + if (!library || !library->isLibrary()) + m_errorReporter.fatalTypeError( + 4357_error, + _usingFor.functionsOrLibrary().front()->location(), + "Library name expected. If you want to attach a function, use '{...}'." + ); + } - if (!library || !library->isLibrary()) - m_errorReporter.fatalTypeError(4357_error, _usingFor.libraryName().location(), "Library name expected."); + // We do not visit _usingFor.functions() because it will lead to an error since + // library names cannot be mentioned stand-alone. if (_usingFor.typeName()) _usingFor.typeName()->accept(*this); diff --git a/libsolidity/analysis/FunctionCallGraph.cpp b/libsolidity/analysis/FunctionCallGraph.cpp index 26523712844f..45da1b4f0d45 100644 --- a/libsolidity/analysis/FunctionCallGraph.cpp +++ b/libsolidity/analysis/FunctionCallGraph.cpp @@ -97,7 +97,7 @@ CallGraph FunctionCallGraphBuilder::buildDeployedGraph( // assigned to state variables and as such may be reachable after deployment as well. builder.m_currentNode = CallGraph::SpecialNode::InternalDispatch; set defaultNode; - for (CallGraph::Node const& dispatchTarget: valueOrDefault(_creationGraph.edges, CallGraph::SpecialNode::InternalDispatch, defaultNode)) + for (CallGraph::Node const& dispatchTarget: util::valueOrDefault(_creationGraph.edges, CallGraph::SpecialNode::InternalDispatch, defaultNode)) { solAssert(!holds_alternative(dispatchTarget), ""); solAssert(get(dispatchTarget) != nullptr, ""); diff --git a/libsolidity/analysis/PostTypeChecker.cpp b/libsolidity/analysis/PostTypeChecker.cpp index d08ee78b711d..b5b973aa4c15 100644 --- a/libsolidity/analysis/PostTypeChecker.cpp +++ b/libsolidity/analysis/PostTypeChecker.cpp @@ -411,12 +411,12 @@ struct ReservedErrorSelector: public PostTypeChecker::Checker ); else { - uint32_t selector = selectorFromSignature32(_error.functionType(true)->externalSignature()); + uint32_t selector = util::selectorFromSignature32(_error.functionType(true)->externalSignature()); if (selector == 0 || ~selector == 0) m_errorReporter.syntaxError( 2855_error, _error.location(), - "The selector 0x" + toHex(toCompactBigEndian(selector, 4)) + " is reserved. Please rename the error to avoid the collision." + "The selector 0x" + util::toHex(toCompactBigEndian(selector, 4)) + " is reserved. Please rename the error to avoid the collision." ); } } diff --git a/libsolidity/analysis/PostTypeContractLevelChecker.cpp b/libsolidity/analysis/PostTypeContractLevelChecker.cpp index 32927188fcaa..38a192c22638 100644 --- a/libsolidity/analysis/PostTypeContractLevelChecker.cpp +++ b/libsolidity/analysis/PostTypeContractLevelChecker.cpp @@ -52,7 +52,7 @@ bool PostTypeContractLevelChecker::check(ContractDefinition const& _contract) for (ErrorDefinition const* error: _contract.interfaceErrors()) { string signature = error->functionType(true)->externalSignature(); - uint32_t hash = selectorFromSignature32(signature); + uint32_t hash = util::selectorFromSignature32(signature); // Fail if there is a different signature for the same hash. if (!errorHashes[hash].empty() && !errorHashes[hash].count(signature)) { diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp index 589787a89387..bdf138e202df 100644 --- a/libsolidity/analysis/SyntaxChecker.cpp +++ b/libsolidity/analysis/SyntaxChecker.cpp @@ -403,6 +403,42 @@ void SyntaxChecker::endVisit(ContractDefinition const&) m_currentContractKind = std::nullopt; } +bool SyntaxChecker::visit(UsingForDirective const& _usingFor) +{ + if (!m_currentContractKind && !_usingFor.typeName()) + m_errorReporter.syntaxError( + 8118_error, + _usingFor.location(), + "The type has to be specified explicitly at file level (cannot use '*')." + ); + else if (_usingFor.usesBraces() && !_usingFor.typeName()) + m_errorReporter.syntaxError( + 3349_error, + _usingFor.location(), + "The type has to be specified explicitly when attaching specific functions." + ); + if (_usingFor.global() && !_usingFor.typeName()) + m_errorReporter.syntaxError( + 2854_error, + _usingFor.location(), + "Can only globally bind functions to specific types." + ); + if (_usingFor.global() && m_currentContractKind) + m_errorReporter.syntaxError( + 3367_error, + _usingFor.location(), + "\"global\" can only be used at file level." + ); + if (m_currentContractKind == ContractKind::Interface) + m_errorReporter.syntaxError( + 9088_error, + _usingFor.location(), + "The \"using for\" directive is not allowed inside interfaces." + ); + + return true; +} + bool SyntaxChecker::visit(FunctionDefinition const& _function) { solAssert(_function.isFree() == (m_currentContractKind == std::nullopt), ""); diff --git a/libsolidity/analysis/SyntaxChecker.h b/libsolidity/analysis/SyntaxChecker.h index ca36ed992c83..f221df09fcac 100644 --- a/libsolidity/analysis/SyntaxChecker.h +++ b/libsolidity/analysis/SyntaxChecker.h @@ -88,6 +88,9 @@ class SyntaxChecker: private ASTConstVisitor bool visit(ContractDefinition const& _contract) override; void endVisit(ContractDefinition const& _contract) override; + + bool visit(UsingForDirective const& _usingFor) override; + bool visit(FunctionDefinition const& _function) override; bool visit(FunctionTypeName const& _node) override; diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 955c66f840bc..43334563be8d 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -267,6 +268,11 @@ TypePointers TypeChecker::typeCheckMetaTypeFunctionAndRetrieveReturnType(Functio return {TypeProvider::meta(dynamic_cast(*firstArgType).actualType())}; } +bool TypeChecker::visit(ImportDirective const&) +{ + return false; +} + void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance) { auto base = dynamic_cast(&dereference(_inheritance.name())); @@ -659,7 +665,7 @@ void TypeChecker::visitManually( if (auto const* modifierContract = dynamic_cast(modifierDecl->scope())) if (m_currentContract) { - if (!contains(m_currentContract->annotation().linearizedBaseContracts, modifierContract)) + if (!util::contains(m_currentContract->annotation().linearizedBaseContracts, modifierContract)) m_errorReporter.typeError( 9428_error, _modifier.location(), @@ -2143,7 +2149,7 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa functionPointerType->declaration().scope() == m_currentContract ) msg += " Did you forget to prefix \"this.\"?"; - else if (contains( + else if (util::contains( m_currentContract->annotation().linearizedBaseContracts, functionPointerType->declaration().scope() ) && functionPointerType->declaration().scope() != m_currentContract) @@ -2204,9 +2210,9 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa "Cannot implicitly convert component at position " + to_string(i) + " from \"" + - argType.canonicalName() + + argType.toString() + "\" to \"" + - functionPointerType->parameterTypes()[i]->canonicalName() + + functionPointerType->parameterTypes()[i]->toString() + "\"" + (result.message().empty() ? "." : ": " + result.message()) ); @@ -3626,12 +3632,89 @@ void TypeChecker::endVisit(Literal const& _literal) void TypeChecker::endVisit(UsingForDirective const& _usingFor) { - if (m_currentContract->isInterface()) - m_errorReporter.typeError( - 9088_error, - _usingFor.location(), - "The \"using for\" directive is not allowed inside interfaces." + if (!_usingFor.usesBraces()) + { + solAssert(_usingFor.functionsOrLibrary().size() == 1); + ContractDefinition const* library = dynamic_cast( + _usingFor.functionsOrLibrary().front()->annotation().referencedDeclaration ); + solAssert(library && library->isLibrary()); + // No type checking for libraries + return; + } + + if (!_usingFor.typeName()) + { + solAssert(m_errorReporter.hasErrors()); + return; + } + + solAssert(_usingFor.typeName()->annotation().type); + Type const* normalizedType = TypeProvider::withLocationIfReference( + DataLocation::Storage, + _usingFor.typeName()->annotation().type + ); + solAssert(normalizedType); + + if (_usingFor.global()) + { + if (m_currentContract) + solAssert(m_errorReporter.hasErrors()); + if (Declaration const* typeDefinition = _usingFor.typeName()->annotation().type->typeDefinition()) + { + if (typeDefinition->scope() != m_currentSourceUnit) + m_errorReporter.typeError( + 4117_error, + _usingFor.location(), + "Can only use \"global\" with types defined in the same source unit at file level." + ); + } + else + m_errorReporter.typeError( + 8841_error, + _usingFor.location(), + "Can only use \"global\" with user-defined types." + ); + } + + + for (ASTPointer const& path: _usingFor.functionsOrLibrary()) + { + solAssert(path->annotation().referencedDeclaration); + FunctionDefinition const& functionDefinition = + dynamic_cast(*path->annotation().referencedDeclaration); + + solAssert(functionDefinition.type()); + + if (functionDefinition.parameters().empty()) + m_errorReporter.fatalTypeError( + 4731_error, + path->location(), + "The function \"" + joinHumanReadable(path->path(), ".") + "\" " + + "does not have any parameters, and therefore cannot be bound to the type \"" + + (normalizedType ? normalizedType->toString(true) : "*") + "\"." + ); + + FunctionType const* functionType = dynamic_cast(*functionDefinition.type()).asBoundFunction(); + solAssert(functionType && functionType->selfType(), ""); + BoolResult result = normalizedType->isImplicitlyConvertibleTo( + *TypeProvider::withLocationIfReference(DataLocation::Storage, functionType->selfType()) + ); + if (!result) + m_errorReporter.typeError( + 3100_error, + path->location(), + "The function \"" + joinHumanReadable(path->path(), ".") + "\" "+ + "cannot be bound to the type \"" + _usingFor.typeName()->annotation().type->toString() + + "\" because the type cannot be implicitly converted to the first argument" + + " of the function (\"" + functionType->selfType()->toString() + "\")" + + ( + result.message().empty() ? + "." : + ": " + result.message() + ) + ); + } } void TypeChecker::checkErrorAndEventParameters(CallableDeclaration const& _callable) diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h index 969ee4394043..2ef6b818be6e 100644 --- a/libsolidity/analysis/TypeChecker.h +++ b/libsolidity/analysis/TypeChecker.h @@ -125,6 +125,8 @@ class TypeChecker: private ASTConstVisitor FunctionType const* _functionType ); + bool visit(ImportDirective const&) override; + void endVisit(InheritanceSpecifier const& _inheritance) override; void endVisit(ModifierDefinition const& _modifier) override; bool visit(FunctionDefinition const& _function) override; diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp index 3179a8eb705b..7483af8922cf 100644 --- a/libsolidity/analysis/ViewPureChecker.cpp +++ b/libsolidity/analysis/ViewPureChecker.cpp @@ -134,6 +134,11 @@ bool ViewPureChecker::check() return !m_errors; } +bool ViewPureChecker::visit(ImportDirective const&) +{ + return false; +} + bool ViewPureChecker::visit(FunctionDefinition const& _funDef) { solAssert(!m_currentFunction, ""); diff --git a/libsolidity/analysis/ViewPureChecker.h b/libsolidity/analysis/ViewPureChecker.h index dfbb2f7478ba..b0abe8fd8322 100644 --- a/libsolidity/analysis/ViewPureChecker.h +++ b/libsolidity/analysis/ViewPureChecker.h @@ -50,6 +50,8 @@ class ViewPureChecker: private ASTConstVisitor langutil::SourceLocation location; }; + bool visit(ImportDirective const&) override; + bool visit(FunctionDefinition const& _funDef) override; void endVisit(FunctionDefinition const& _funDef) override; bool visit(ModifierDefinition const& _modifierDef) override; diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 2a7609de858f..be6f2fe9be66 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -221,7 +221,7 @@ vector const ContractDefinition::usedInterfaceEvents() c { solAssert(annotation().creationCallGraph.set(), ""); - return convertContainer>( + return util::convertContainer>( (*annotation().creationCallGraph)->emittedEvents + (*annotation().deployedCallGraph)->emittedEvents ); @@ -239,7 +239,7 @@ vector ContractDefinition::interfaceErrors(bool _require result += (*annotation().creationCallGraph)->usedErrors + (*annotation().deployedCallGraph)->usedErrors; - return convertContainer>(move(result)); + return util::convertContainer>(move(result)); } vector, FunctionTypePointer>> const& ContractDefinition::interfaceFunctionList(bool _includeInheritedFunctions) const diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 4893c212f093..4eba73c5d85d 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -630,9 +631,20 @@ class InheritanceSpecifier: public ASTNode }; /** - * `using LibraryName for uint` will attach all functions from the library LibraryName - * to `uint` if the first parameter matches the type. `using LibraryName for *` attaches - * the function to any matching type. + * Using for directive: + * + * 1. `using LibraryName for T` attaches all functions from the library `LibraryName` to the type `T` + * 2. `using LibraryName for *` attaches to all types. + * 3. `using {f1, f2, ..., fn} for T` attaches the functions `f1`, `f2`, ..., + * `fn`, respectively to `T`. + * + * For version 3, T has to be implicitly convertible to the first parameter type of + * all functions, and this is checked at the point of the using statement. For versions 1 and + * 2, this check is only done when a function is called. + * + * Finally, `using {f1, f2, ..., fn} for T global` is also valid at file level, as long as T is + * a user-defined type defined in the same file at file level. In this case, the methods are + * attached to all objects of that type regardless of scope. */ class UsingForDirective: public ASTNode { @@ -640,24 +652,36 @@ class UsingForDirective: public ASTNode UsingForDirective( int64_t _id, SourceLocation const& _location, - ASTPointer _libraryName, - ASTPointer _typeName + std::vector> _functions, + bool _usesBraces, + ASTPointer _typeName, + bool _global ): - ASTNode(_id, _location), m_libraryName(std::move(_libraryName)), m_typeName(std::move(_typeName)) + ASTNode(_id, _location), + m_functions(_functions), + m_usesBraces(_usesBraces), + m_typeName(std::move(_typeName)), + m_global{_global} { - solAssert(m_libraryName != nullptr, "Name cannot be null."); } void accept(ASTVisitor& _visitor) override; void accept(ASTConstVisitor& _visitor) const override; - IdentifierPath const& libraryName() const { return *m_libraryName; } /// @returns the type name the library is attached to, null for `*`. TypeName const* typeName() const { return m_typeName.get(); } + /// @returns a list of functions or the single library. + std::vector> const& functionsOrLibrary() const { return m_functions; } + bool usesBraces() const { return m_usesBraces; } + bool global() const { return m_global; } + private: - ASTPointer m_libraryName; + /// Either the single library or a list of functions. + std::vector> m_functions; + bool m_usesBraces; ASTPointer m_typeName; + bool m_global = false; }; class StructDefinition: public Declaration, public ScopeOpener diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index 0d6901ef277e..3497a2ea8242 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -47,7 +47,6 @@ namespace solidity::frontend class Type; class ArrayType; -using namespace util; struct CallGraph; @@ -91,13 +90,13 @@ struct StructurallyDocumentedAnnotation struct SourceUnitAnnotation: ASTAnnotation { /// The "absolute" (in the compiler sense) path of this source unit. - SetOnce path; + util::SetOnce path; /// The exported symbols (all global symbols). - SetOnce>> exportedSymbols; + util::SetOnce>> exportedSymbols; /// Experimental features. std::set experimentalFeatures; /// Using the new ABI coder. Set to `false` if using ABI coder v1. - SetOnce useABICoderV2; + util::SetOnce useABICoderV2; }; struct ScopableAnnotation @@ -127,7 +126,7 @@ struct DeclarationAnnotation: ASTAnnotation, ScopableAnnotation struct ImportAnnotation: DeclarationAnnotation { /// The absolute path of the source unit to import. - SetOnce absolutePath; + util::SetOnce absolutePath; /// The actual source unit. SourceUnit const* sourceUnit = nullptr; }; @@ -135,7 +134,7 @@ struct ImportAnnotation: DeclarationAnnotation struct TypeDeclarationAnnotation: DeclarationAnnotation { /// The name of this type, prefixed by proper namespaces if globally accessible. - SetOnce canonicalName; + util::SetOnce canonicalName; }; struct StructDeclarationAnnotation: TypeDeclarationAnnotation @@ -162,9 +161,9 @@ struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, StructurallyDocu /// These can either be inheritance specifiers or modifier invocations. std::map baseConstructorArguments; /// A graph with edges representing calls between functions that may happen during contract construction. - SetOnce> creationCallGraph; + util::SetOnce> creationCallGraph; /// A graph with edges representing calls between functions that may happen in a deployed contract. - SetOnce> deployedCallGraph; + util::SetOnce> deployedCallGraph; /// List of contracts whose bytecode is referenced by this contract, e.g. through "new". /// The Value represents the ast node that referenced the contract. @@ -223,7 +222,7 @@ struct InlineAssemblyAnnotation: StatementAnnotation /// True, if the assembly block was annotated to be memory-safe. bool markedMemorySafe = false; /// True, if the assembly block involves any memory opcode or assigns to variables in memory. - SetOnce hasMemoryEffects; + util::SetOnce hasMemoryEffects; }; struct BlockAnnotation: StatementAnnotation, ScopableAnnotation @@ -256,7 +255,7 @@ struct IdentifierPathAnnotation: ASTAnnotation /// Referenced declaration, set during reference resolution stage. Declaration const* referencedDeclaration = nullptr; /// What kind of lookup needs to be done (static, virtual, super) find the declaration. - SetOnce requiredLookup; + util::SetOnce requiredLookup; }; struct ExpressionAnnotation: ASTAnnotation @@ -264,11 +263,11 @@ struct ExpressionAnnotation: ASTAnnotation /// Inferred type of the expression. Type const* type = nullptr; /// Whether the expression is a constant variable - SetOnce isConstant; + util::SetOnce isConstant; /// Whether the expression is pure, i.e. compile-time constant. - SetOnce isPure; + util::SetOnce isPure; /// Whether it is an LValue (i.e. something that can be assigned to). - SetOnce isLValue; + util::SetOnce isLValue; /// Whether the expression is used in a context where the LValue is actually required. bool willBeWrittenTo = false; /// Whether the expression is an lvalue that is only assigned. @@ -295,7 +294,7 @@ struct IdentifierAnnotation: ExpressionAnnotation /// Referenced declaration, set at latest during overload resolution stage. Declaration const* referencedDeclaration = nullptr; /// What kind of lookup needs to be done (static, virtual, super) find the declaration. - SetOnce requiredLookup; + util::SetOnce requiredLookup; /// List of possible declarations it could refer to (can contain duplicates). std::vector candidateDeclarations; /// List of possible declarations it could refer to. @@ -307,7 +306,7 @@ struct MemberAccessAnnotation: ExpressionAnnotation /// Referenced declaration, set at latest during overload resolution stage. Declaration const* referencedDeclaration = nullptr; /// What kind of lookup needs to be done (static, virtual, super) find the declaration. - SetOnce requiredLookup; + util::SetOnce requiredLookup; }; struct BinaryOperationAnnotation: ExpressionAnnotation diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 6b48797d1546..4338cc64f5b4 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -311,10 +312,26 @@ bool ASTJsonConverter::visit(InheritanceSpecifier const& _node) bool ASTJsonConverter::visit(UsingForDirective const& _node) { - setJsonNode(_node, "UsingForDirective", { - make_pair("libraryName", toJson(_node.libraryName())), + vector> attributes = { make_pair("typeName", _node.typeName() ? toJson(*_node.typeName()) : Json::nullValue) - }); + }; + if (_node.usesBraces()) + { + Json::Value functionList; + for (auto const& function: _node.functionsOrLibrary()) + { + Json::Value functionNode; + functionNode["function"] = toJson(*function); + functionList.append(move(functionNode)); + } + attributes.emplace_back("functionList", move(functionList)); + } + else + attributes.emplace_back("libraryName", toJson(*_node.functionsOrLibrary().front())); + attributes.emplace_back("global", _node.global()); + + setJsonNode(_node, "UsingForDirective", move(attributes)); + return false; } @@ -505,7 +522,7 @@ bool ASTJsonConverter::visit(EventDefinition const& _node) _attributes.emplace_back( make_pair( "eventSelector", - toHex(u256(h256::Arith(util::keccak256(_node.functionType(true)->externalSignature())))) + toHex(u256(util::h256::Arith(util::keccak256(_node.functionType(true)->externalSignature())))) )); setJsonNode(_node, "EventDefinition", std::move(_attributes)); diff --git a/libsolidity/ast/ASTJsonImporter.cpp b/libsolidity/ast/ASTJsonImporter.cpp index d71864f348f0..2f36cdead4aa 100644 --- a/libsolidity/ast/ASTJsonImporter.cpp +++ b/libsolidity/ast/ASTJsonImporter.cpp @@ -348,10 +348,19 @@ ASTPointer ASTJsonImporter::createInheritanceSpecifier(Jso ASTPointer ASTJsonImporter::createUsingForDirective(Json::Value const& _node) { + vector> functions; + if (_node.isMember("libraryName")) + functions.emplace_back(createIdentifierPath(_node["libraryName"])); + else if (_node.isMember("functionList")) + for (Json::Value const& function: _node["functionList"]) + functions.emplace_back(createIdentifierPath(function["function"])); + return createASTNode( _node, - createIdentifierPath(member(_node, "libraryName")), - _node["typeName"].isNull() ? nullptr : convertJsonToASTNode(_node["typeName"]) + move(functions), + !_node.isMember("libraryName"), + _node["typeName"].isNull() ? nullptr : convertJsonToASTNode(_node["typeName"]), + memberAsBool(_node, "global") ); } diff --git a/libsolidity/ast/ASTUtils.cpp b/libsolidity/ast/ASTUtils.cpp index 3ed47d6f2e83..2b7ea74277b2 100644 --- a/libsolidity/ast/ASTUtils.cpp +++ b/libsolidity/ast/ASTUtils.cpp @@ -18,12 +18,35 @@ #include #include +#include #include namespace solidity::frontend { +ASTNode const* locateInnermostASTNode(int _offsetInFile, SourceUnit const& _sourceUnit) +{ + ASTNode const* innermostMatch = nullptr; + auto locator = SimpleASTVisitor( + [&](ASTNode const& _node) -> bool + { + // In the AST parent location always covers the whole child location. + // The parent is visited first so to get the innermost node we simply + // take the last one that still contains the offset. + + if (!_node.location().containsOffset(_offsetInFile)) + return false; + + innermostMatch = &_node; + return true; + }, + [](ASTNode const&) {} + ); + _sourceUnit.accept(locator); + return innermostMatch; +} + bool isConstantVariableRecursive(VariableDeclaration const& _varDecl) { solAssert(_varDecl.isConstant(), "Constant variable expected"); diff --git a/libsolidity/ast/ASTUtils.h b/libsolidity/ast/ASTUtils.h index 5b1a7d4e5225..2bfbb8fe9c7b 100644 --- a/libsolidity/ast/ASTUtils.h +++ b/libsolidity/ast/ASTUtils.h @@ -21,9 +21,11 @@ namespace solidity::frontend { -class VariableDeclaration; +class ASTNode; class Declaration; class Expression; +class SourceUnit; +class VariableDeclaration; /// Find the topmost referenced constant variable declaration when the given variable /// declaration value is an identifier. Works only for constant variable declarations. @@ -33,4 +35,7 @@ VariableDeclaration const* rootConstVariableDeclaration(VariableDeclaration cons /// Returns true if the constant variable declaration is recursive. bool isConstantVariableRecursive(VariableDeclaration const& _varDecl); +/// Returns the innermost AST node that covers the given location or nullptr if not found. +ASTNode const* locateInnermostASTNode(int _offsetInFile, SourceUnit const& _sourceUnit); + } diff --git a/libsolidity/ast/AST_accept.h b/libsolidity/ast/AST_accept.h index fa42c2dc680a..6dab08f00951 100644 --- a/libsolidity/ast/AST_accept.h +++ b/libsolidity/ast/AST_accept.h @@ -194,7 +194,7 @@ void UsingForDirective::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) { - m_libraryName->accept(_visitor); + listAccept(functionsOrLibrary(), _visitor); if (m_typeName) m_typeName->accept(_visitor); } @@ -205,7 +205,7 @@ void UsingForDirective::accept(ASTConstVisitor& _visitor) const { if (_visitor.visit(*this)) { - m_libraryName->accept(_visitor); + listAccept(functionsOrLibrary(), _visitor); if (m_typeName) m_typeName->accept(_visitor); } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index c84d79785fca..cedac68f3255 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -331,30 +332,55 @@ Type const* Type::fullEncodingType(bool _inLibraryCall, bool _encoderV2, bool) c MemberList::MemberMap Type::boundFunctions(Type const& _type, ASTNode const& _scope) { vector usingForDirectives; - if (auto const* sourceUnit = dynamic_cast(&_scope)) - usingForDirectives += ASTNode::filteredNodes(sourceUnit->nodes()); - else if (auto const* contract = dynamic_cast(&_scope)) - usingForDirectives += - contract->usingForDirectives() + - ASTNode::filteredNodes(contract->sourceUnit().nodes()); + SourceUnit const* sourceUnit = dynamic_cast(&_scope); + if (auto const* contract = dynamic_cast(&_scope)) + { + sourceUnit = &contract->sourceUnit(); + usingForDirectives += contract->usingForDirectives(); + } else - solAssert(false, ""); + solAssert(sourceUnit, ""); + usingForDirectives += ASTNode::filteredNodes(sourceUnit->nodes()); + + if (Declaration const* typeDefinition = _type.typeDefinition()) + if (auto const* sourceUnit = dynamic_cast(typeDefinition->scope())) + for (auto usingFor: ASTNode::filteredNodes(sourceUnit->nodes())) + // We do not yet compare the type name because of normalization. + if (usingFor->global() && usingFor->typeName()) + usingForDirectives.emplace_back(usingFor); // Normalise data location of type. DataLocation typeLocation = DataLocation::Storage; if (auto refType = dynamic_cast(&_type)) typeLocation = refType->location(); - set seenFunctions; MemberList::MemberMap members; + set> seenFunctions; + auto addFunction = [&](FunctionDefinition const& _function, optional _name = {}) + { + if (!_name) + _name = _function.name(); + Type const* functionType = + _function.libraryFunction() ? _function.typeViaContractName() : _function.type(); + solAssert(functionType, ""); + FunctionType const* asBoundFunction = + dynamic_cast(*functionType).asBoundFunction(); + solAssert(asBoundFunction, ""); + + if (_type.isImplicitlyConvertibleTo(*asBoundFunction->selfType())) + if (seenFunctions.insert(make_pair(*_name, &_function)).second) + members.emplace_back(&_function, asBoundFunction, *_name); + }; + for (UsingForDirective const* ufd: usingForDirectives) { // Convert both types to pointers for comparison to see if the `using for` // directive applies. // Further down, we check more detailed for each function if `_type` is // convertible to the function parameter type. - if (ufd->typeName() && + if ( + ufd->typeName() && *TypeProvider::withLocationIfReference(typeLocation, &_type, true) != *TypeProvider::withLocationIfReference( typeLocation, @@ -363,20 +389,28 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ASTNode const& _sc ) ) continue; - auto const& library = dynamic_cast( - *ufd->libraryName().annotation().referencedDeclaration - ); - for (FunctionDefinition const* function: library.definedFunctions()) + + for (auto const& pathPointer: ufd->functionsOrLibrary()) { - if (!function->isOrdinary() || !function->isVisibleAsLibraryMember() || seenFunctions.count(function)) - continue; - seenFunctions.insert(function); - if (function->parameters().empty()) - continue; - FunctionTypePointer fun = - dynamic_cast(*function->typeViaContractName()).asBoundFunction(); - if (_type.isImplicitlyConvertibleTo(*fun->selfType())) - members.emplace_back(function, fun); + solAssert(pathPointer); + Declaration const* declaration = pathPointer->annotation().referencedDeclaration; + solAssert(declaration); + + if (ContractDefinition const* library = dynamic_cast(declaration)) + { + solAssert(library->isLibrary()); + for (FunctionDefinition const* function: library->definedFunctions()) + { + if (!function->isOrdinary() || !function->isVisibleAsLibraryMember() || function->parameters().empty()) + continue; + addFunction(*function); + } + } + else + addFunction( + dynamic_cast(*declaration), + pathPointer->path().back() + ); } } @@ -2341,6 +2375,11 @@ TypeResult StructType::interfaceType(bool _inLibrary) const return *m_interfaceType_library; } +Declaration const* StructType::typeDefinition() const +{ + return &structDefinition(); +} + BoolResult StructType::validForLocation(DataLocation _loc) const { for (auto const& member: m_struct.members()) @@ -2473,6 +2512,11 @@ Type const* EnumType::encodingType() const return TypeProvider::uint(8); } +Declaration const* EnumType::typeDefinition() const +{ + return &enumDefinition(); +} + TypeResult EnumType::unaryOperatorResult(Token _operator) const { return _operator == Token::Delete ? TypeProvider::emptyTuple() : nullptr; @@ -2541,6 +2585,11 @@ Type const& UserDefinedValueType::underlyingType() const return *type; } +Declaration const* UserDefinedValueType::typeDefinition() const +{ + return &m_definition; +} + string UserDefinedValueType::richIdentifier() const { return "t_userDefinedValueType" + parenthesizeIdentifier(m_definition.name()) + to_string(m_definition.id()); diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 9b030f65a531..9b3080769167 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -369,6 +369,10 @@ class Type /// are returned without modification. virtual TypeResult interfaceType(bool /*_inLibrary*/) const { return nullptr; } + /// @returns the declaration of a user defined type (enum, struct, user defined value type). + /// Returns nullptr otherwise. + virtual Declaration const* typeDefinition() const { return nullptr; } + /// Clears all internally cached values (if any). virtual void clearCache() const; @@ -1004,6 +1008,8 @@ class StructType: public ReferenceType Type const* encodingType() const override; TypeResult interfaceType(bool _inLibrary) const override; + Declaration const* typeDefinition() const override; + BoolResult validForLocation(DataLocation _loc) const override; bool recursive() const; @@ -1069,6 +1075,8 @@ class EnumType: public Type return _inLibrary ? this : encodingType(); } + Declaration const* typeDefinition() const override; + EnumDefinition const& enumDefinition() const { return m_enum; } /// @returns the value that the string has in the Enum unsigned int memberValue(ASTString const& _member) const; @@ -1101,6 +1109,9 @@ class UserDefinedValueType: public Type TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; } Type const* encodingType() const override { return &underlyingType(); } TypeResult interfaceType(bool /* _inLibrary */) const override {return &underlyingType(); } + + Declaration const* typeDefinition() const override; + std::string richIdentifier() const override; bool operator==(Type const& _other) const override; diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 700f53d1f7d8..99b87e5a7014 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -403,7 +403,7 @@ void CompilerContext::appendInlineAssembly( { if (_insideFunction) return false; - return contains(_localVariables, _identifier.name.str()); + return util::contains(_localVariables, _identifier.name.str()); }; identifierAccess.generateCode = [&]( yul::Identifier const& _identifier, @@ -572,8 +572,7 @@ void CompilerContext::updateSourceLocation() evmasm::Assembly::OptimiserSettings CompilerContext::translateOptimiserSettings(OptimiserSettings const& _settings) { // Constructing it this way so that we notice changes in the fields. - evmasm::Assembly::OptimiserSettings asmSettings{false, false, false, false, false, false, false, m_evmVersion, 0}; - asmSettings.isCreation = true; + evmasm::Assembly::OptimiserSettings asmSettings{false, false, false, false, false, false, m_evmVersion, 0}; asmSettings.runInliner = _settings.runInliner; asmSettings.runJumpdestRemover = _settings.runJumpdestRemover; asmSettings.runPeephole = _settings.runPeephole; diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index cd71d5a4d367..a796ac60b2d5 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -65,7 +65,7 @@ class CompilerContext RevertStrings _revertStrings, CompilerContext* _runtimeContext = nullptr ): - m_asm(std::make_shared()), + m_asm(std::make_shared(_runtimeContext != nullptr, std::string{})), m_evmVersion(_evmVersion), m_revertStrings(_revertStrings), m_reservedMemory{0}, diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 5abc646367ae..d2c71e2aff35 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -235,7 +235,7 @@ size_t ContractCompiler::deployLibrary(ContractDefinition const& _contract) m_context.pushSubroutineOffset(m_context.runtimeSub()); // This code replaces the address added by appendDeployTimeAddress(). m_context.appendInlineAssembly( - Whiskers(R"( + util::Whiskers(R"( { // If code starts at 11, an mstore(0) writes to the full PUSH20 plus data // without the need for a shift. @@ -672,7 +672,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) BOOST_THROW_EXCEPTION( StackTooDeepError() << errinfo_sourceLocation(_function.location()) << - errinfo_comment("Stack too deep, try removing local variables.") + util::errinfo_comment("Stack too deep, try removing local variables.") ); while (!stackLayout.empty() && stackLayout.back() != static_cast(stackLayout.size() - 1)) if (stackLayout.back() < 0) @@ -842,7 +842,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) BOOST_THROW_EXCEPTION( StackTooDeepError() << errinfo_sourceLocation(_inlineAssembly.location()) << - errinfo_comment("Stack too deep, try removing local variables.") + util::errinfo_comment("Stack too deep, try removing local variables.") ); _assembly.appendInstruction(dupInstruction(stackDiff)); } @@ -916,7 +916,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) BOOST_THROW_EXCEPTION( StackTooDeepError() << errinfo_sourceLocation(_inlineAssembly.location()) << - errinfo_comment("Stack too deep(" + to_string(stackDiff) + "), try removing local variables.") + util::errinfo_comment("Stack too deep(" + to_string(stackDiff) + "), try removing local variables.") ); _assembly.appendInstruction(swapInstruction(stackDiff)); _assembly.appendInstruction(Instruction::POP); @@ -1045,7 +1045,7 @@ void ContractCompiler::handleCatch(vector> const& _ca solAssert(m_context.evmVersion().supportsReturndata(), ""); // stack: - m_context << Instruction::DUP1 << selectorFromSignature32("Error(string)") << Instruction::EQ; + m_context << Instruction::DUP1 << util::selectorFromSignature32("Error(string)") << Instruction::EQ; m_context << Instruction::ISZERO; m_context.appendConditionalJumpTo(panicTag); m_context << Instruction::POP; // remove selector @@ -1077,7 +1077,7 @@ void ContractCompiler::handleCatch(vector> const& _ca solAssert(m_context.evmVersion().supportsReturndata(), ""); // stack: - m_context << selectorFromSignature32("Panic(uint256)") << Instruction::EQ; + m_context << util::selectorFromSignature32("Panic(uint256)") << Instruction::EQ; m_context << Instruction::ISZERO; m_context.appendConditionalJumpTo(fallbackTag); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index e4ad4cf7e04b..21cb45e77551 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -268,7 +268,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& BOOST_THROW_EXCEPTION( StackTooDeepError() << errinfo_sourceLocation(_varDecl.location()) << - errinfo_comment("Stack too deep.") + util::errinfo_comment("Stack too deep.") ); m_context << dupInstruction(retSizeOnStack + 1); m_context.appendJump(evmasm::AssemblyItem::JumpType::OutOfFunction); @@ -350,7 +350,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) BOOST_THROW_EXCEPTION( StackTooDeepError() << errinfo_sourceLocation(_assignment.location()) << - errinfo_comment("Stack too deep, try removing local variables.") + util::errinfo_comment("Stack too deep, try removing local variables.") ); // value [lvalue_ref] updated_value for (unsigned i = 0; i < itemSize; ++i) @@ -1258,6 +1258,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) function.kind() == FunctionType::Kind::ABIEncodeWithSignature; TypePointers argumentTypes; + TypePointers targetTypes; ASTNode::listAccept(arguments, *this); @@ -1265,14 +1266,17 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) { solAssert(arguments.size() == 2); - auto const functionPtr = dynamic_cast(arguments[0]->annotation().type); - solAssert(functionPtr); - // Account for tuples with one component which become that component if (auto const tupleType = dynamic_cast(arguments[1]->annotation().type)) argumentTypes = tupleType->components(); else argumentTypes.emplace_back(arguments[1]->annotation().type); + + auto functionPtr = dynamic_cast(arguments[0]->annotation().type); + solAssert(functionPtr); + functionPtr = functionPtr->asExternallyCallableFunction(false); + solAssert(functionPtr); + targetTypes = functionPtr->parameterTypes(); } else for (unsigned i = 0; i < arguments.size(); ++i) @@ -1292,12 +1296,12 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) if (isPacked) { solAssert(!function.padArguments(), ""); - utils().packedEncode(argumentTypes, TypePointers()); + utils().packedEncode(argumentTypes, targetTypes); } else { solAssert(function.padArguments(), ""); - utils().abiEncode(argumentTypes, TypePointers()); + utils().abiEncode(argumentTypes, targetTypes); } utils().fetchFreeMemoryPointer(); // stack: [] @@ -1452,7 +1456,7 @@ bool ExpressionCompiler::visit(FunctionCallOptions const& _functionCallOptions) solAssert(false, "Unexpected option name!"); acceptAndConvert(*_functionCallOptions.options()[i], *requiredType); - solAssert(!contains(presentOptions, newOption), ""); + solAssert(!util::contains(presentOptions, newOption), ""); ptrdiff_t insertPos = presentOptions.end() - lower_bound(presentOptions.begin(), presentOptions.end(), newOption); utils().moveIntoStack(static_cast(insertPos), 1); @@ -2862,7 +2866,7 @@ void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaratio else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.location()) - << errinfo_comment("Identifier type not supported or identifier not found.")); + << util::errinfo_comment("Identifier type not supported or identifier not found.")); } void ExpressionCompiler::setLValueToStorageItem(Expression const& _expression) diff --git a/libsolidity/codegen/LValue.cpp b/libsolidity/codegen/LValue.cpp index bd9252953771..379e9818b661 100644 --- a/libsolidity/codegen/LValue.cpp +++ b/libsolidity/codegen/LValue.cpp @@ -50,7 +50,7 @@ void StackVariable::retrieveValue(SourceLocation const& _location, bool) const BOOST_THROW_EXCEPTION( StackTooDeepError() << errinfo_sourceLocation(_location) << - errinfo_comment("Stack too deep, try removing local variables.") + util::errinfo_comment("Stack too deep, try removing local variables.") ); solAssert(stackPos + 1 >= m_size, "Size and stack pos mismatch."); for (unsigned i = 0; i < m_size; ++i) @@ -64,7 +64,7 @@ void StackVariable::storeValue(Type const&, SourceLocation const& _location, boo BOOST_THROW_EXCEPTION( StackTooDeepError() << errinfo_sourceLocation(_location) << - errinfo_comment("Stack too deep, try removing local variables.") + util::errinfo_comment("Stack too deep, try removing local variables.") ); else if (stackDiff > 0) for (unsigned i = 0; i < m_size; ++i) @@ -436,7 +436,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc BOOST_THROW_EXCEPTION( InternalCompilerError() << errinfo_sourceLocation(_location) - << errinfo_comment("Invalid non-value type for assignment.")); + << util::errinfo_comment("Invalid non-value type for assignment.")); } } diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index cb187b424c65..cb62cc292a7b 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -93,7 +93,7 @@ pair IRGenerator::run( map const& _otherYulSources ) { - string const ir = yul::reindent(generate(_contract, _cborMetadata, _otherYulSources)); + string ir = yul::reindent(generate(_contract, _cborMetadata, _otherYulSources)); yul::AssemblyStack asmStack( m_evmVersion, @@ -113,15 +113,7 @@ pair IRGenerator::run( } asmStack.optimize(); - string warning = - "/*=====================================================*\n" - " * WARNING *\n" - " * Solidity to Yul compilation is still EXPERIMENTAL *\n" - " * It can result in LOSS OF FUNDS or worse *\n" - " * !USE AT YOUR OWN RISK! *\n" - " *=====================================================*/\n\n"; - - return {warning + ir, warning + asmStack.print(m_context.soliditySourceProvider())}; + return {move(ir), asmStack.print(m_context.soliditySourceProvider())}; } string IRGenerator::generate( @@ -234,7 +226,7 @@ string IRGenerator::generate( t("deployedFunctions", m_context.functionCollector().requestedFunctions()); t("deployedSubObjects", subObjectSources(m_context.subObjectsCreated())); t("metadataName", yul::Object::metadataName()); - t("cborMetadata", toHex(_cborMetadata)); + t("cborMetadata", util::toHex(_cborMetadata)); t("useSrcMapDeployed", formatUseSrcMap(m_context)); @@ -788,7 +780,7 @@ pair>> IRGenerator::evalua { bool operator()(ContractDefinition const* _c1, ContractDefinition const* _c2) const { - solAssert(contains(linearizedBaseContracts, _c1) && contains(linearizedBaseContracts, _c2), ""); + solAssert(util::contains(linearizedBaseContracts, _c1) && util::contains(linearizedBaseContracts, _c2), ""); auto it1 = find(linearizedBaseContracts.begin(), linearizedBaseContracts.end(), _c1); auto it2 = find(linearizedBaseContracts.begin(), linearizedBaseContracts.end(), _c2); return it1 < it2; diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 9092739e998c..9e48c811c6c5 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -1160,10 +1160,22 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) for (auto const& argument: argumentsOfEncodeFunction) { argumentTypes.emplace_back(&type(*argument)); - targetTypes.emplace_back(type(*argument).fullEncodingType(false, true, isPacked)); argumentVars += IRVariable(*argument).stackSlots(); } + if (functionType->kind() == FunctionType::Kind::ABIEncodeCall) + { + auto encodedFunctionType = dynamic_cast(arguments.front()->annotation().type); + solAssert(encodedFunctionType); + encodedFunctionType = encodedFunctionType->asExternallyCallableFunction(false); + solAssert(encodedFunctionType); + targetTypes = encodedFunctionType->parameterTypes(); + } + else + for (auto const& argument: argumentsOfEncodeFunction) + targetTypes.emplace_back(type(*argument).fullEncodingType(false, true, isPacked)); + + if (functionType->kind() == FunctionType::Kind::ABIEncodeCall) { auto const& selectorType = dynamic_cast(type(*arguments.front())); diff --git a/libsolidity/formal/CHC.cpp b/libsolidity/formal/CHC.cpp index cbadc2c1dd27..58deaad4ad7a 100644 --- a/libsolidity/formal/CHC.cpp +++ b/libsolidity/formal/CHC.cpp @@ -1498,7 +1498,7 @@ smtutil::Expression CHC::predicate(FunctionCall const& _funCall) auto const* contract = function->annotation().contract; auto const& hierarchy = m_currentContract->annotation().linearizedBaseContracts; - solAssert(kind != FunctionType::Kind::Internal || function->isFree() || (contract && contract->isLibrary()) || contains(hierarchy, contract), ""); + solAssert(kind != FunctionType::Kind::Internal || function->isFree() || (contract && contract->isLibrary()) || util::contains(hierarchy, contract), ""); bool usesStaticCall = function->stateMutability() == StateMutability::Pure || function->stateMutability() == StateMutability::View; diff --git a/libsolidity/formal/Invariants.cpp b/libsolidity/formal/Invariants.cpp index 9dad0722cd48..10d342ed474a 100644 --- a/libsolidity/formal/Invariants.cpp +++ b/libsolidity/formal/Invariants.cpp @@ -48,7 +48,7 @@ map> collectInvariants( map> equalities; // Collect equalities where one of the sides is a predicate we're interested in. - BreadthFirstSearch{{&_proof}}.run([&](auto&& _expr, auto&& _addChild) { + util::BreadthFirstSearch{{&_proof}}.run([&](auto&& _expr, auto&& _addChild) { if (_expr->name == "=") for (auto const& t: targets) { diff --git a/libsolidity/formal/Predicate.cpp b/libsolidity/formal/Predicate.cpp index 6e0eb4f3b9d1..91513a00c089 100644 --- a/libsolidity/formal/Predicate.cpp +++ b/libsolidity/formal/Predicate.cpp @@ -350,7 +350,7 @@ vector> Predicate::summaryStateValues(vector stateArgs(stateFirst, stateLast); solAssert(stateArgs.size() == stateVars->size(), ""); - auto stateTypes = applyMap(*stateVars, [&](auto const& _var) { return _var->type(); }); + auto stateTypes = util::applyMap(*stateVars, [&](auto const& _var) { return _var->type(); }); return formatExpressions(stateArgs, stateTypes); } @@ -412,7 +412,7 @@ pair>, vector> Predicate::lo auto first = _args.end() - static_cast(localVars.size()); vector outValues(first, _args.end()); - auto mask = applyMap( + auto mask = util::applyMap( localVars, [this](auto _var) { auto varScope = dynamic_cast(_var->scope()); @@ -422,7 +422,7 @@ pair>, vector> Predicate::lo auto localVarsInScope = util::filter(localVars, mask); auto outValuesInScope = util::filter(outValues, mask); - auto outTypes = applyMap(localVarsInScope, [](auto _var) { return _var->type(); }); + auto outTypes = util::applyMap(localVarsInScope, [](auto _var) { return _var->type(); }); return {formatExpressions(outValuesInScope, outTypes), localVarsInScope}; } @@ -496,7 +496,7 @@ optional Predicate::expressionToString(smtutil::Expression const& _expr, if (_expr.name == "0") return "0x0"; // For some reason the code below returns "0x" for "0". - return toHex(toCompactBigEndian(bigint(_expr.name)), HexPrefix::Add, HexCase::Lower); + return util::toHex(toCompactBigEndian(bigint(_expr.name)), util::HexPrefix::Add, util::HexCase::Lower); } catch (out_of_range const&) { diff --git a/libsolidity/formal/SMTEncoder.cpp b/libsolidity/formal/SMTEncoder.cpp index 76342ba08eb5..7cc978d28c65 100644 --- a/libsolidity/formal/SMTEncoder.cpp +++ b/libsolidity/formal/SMTEncoder.cpp @@ -115,6 +115,12 @@ void SMTEncoder::endVisit(ContractDefinition const& _contract) m_context.popSolver(); } +bool SMTEncoder::visit(ImportDirective const&) +{ + // do not visit because the identifier therein will confuse us. + return false; +} + void SMTEncoder::endVisit(VariableDeclaration const& _varDecl) { // State variables are handled by the constructor. @@ -313,7 +319,7 @@ bool SMTEncoder::visit(InlineAssembly const& _inlineAsm) { auto const& vars = _assignment.variableNames; for (auto const& identifier: vars) - if (auto externalInfo = valueOrNullptr(externalReferences, &identifier)) + if (auto externalInfo = util::valueOrNullptr(externalReferences, &identifier)) if (auto varDecl = dynamic_cast(externalInfo->declaration)) assignedVars.insert(varDecl); } diff --git a/libsolidity/formal/SMTEncoder.h b/libsolidity/formal/SMTEncoder.h index fe84189beb20..84a80461d627 100644 --- a/libsolidity/formal/SMTEncoder.h +++ b/libsolidity/formal/SMTEncoder.h @@ -136,6 +136,7 @@ class SMTEncoder: public ASTConstVisitor // because the order of expression evaluation is undefined // TODO: or just force a certain order, but people might have a different idea about that. + bool visit(ImportDirective const& _node) override; bool visit(ContractDefinition const& _node) override; void endVisit(ContractDefinition const& _node) override; void endVisit(VariableDeclaration const& _node) override; diff --git a/libsolidity/formal/SymbolicState.cpp b/libsolidity/formal/SymbolicState.cpp index 6612723d065f..b1fd7978fa38 100644 --- a/libsolidity/formal/SymbolicState.cpp +++ b/libsolidity/formal/SymbolicState.cpp @@ -211,7 +211,7 @@ void SymbolicState::buildABIFunctions(set const& _abiFuncti auto argTypes = [](auto const& _args) { - return applyMap(_args, [](auto arg) { return arg->annotation().type; }); + return util::applyMap(_args, [](auto arg) { return arg->annotation().type; }); }; /// Since each abi.* function may have a different number of input/output parameters, diff --git a/libsolidity/formal/SymbolicTypes.cpp b/libsolidity/formal/SymbolicTypes.cpp index b9041c6bd4cb..e40ff924511f 100644 --- a/libsolidity/formal/SymbolicTypes.cpp +++ b/libsolidity/formal/SymbolicTypes.cpp @@ -580,7 +580,7 @@ optional symbolicTypeConversion(frontend::Type const* _from return smtutil::Expression(size_t(0)); auto bytesVec = util::asBytes(strType->value()); bytesVec.resize(fixedBytesType->numBytes(), 0); - return smtutil::Expression(u256(toHex(bytesVec, util::HexPrefix::Add))); + return smtutil::Expression(u256(util::toHex(bytesVec, util::HexPrefix::Add))); } return std::nullopt; diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 7a8bc4ddbf91..de5bea1374b1 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -278,7 +278,7 @@ void CompilerStack::setMetadataHash(MetadataHash _metadataHash) void CompilerStack::selectDebugInfo(DebugInfoSelection _debugInfoSelection) { if (m_stackState >= CompilationSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must select debug info components before compilation.")); + BOOST_THROW_EXCEPTION(CompilerError() << util::errinfo_comment("Must select debug info components before compilation.")); m_debugInfoSelection = _debugInfoSelection; } @@ -573,7 +573,7 @@ bool CompilerStack::analyze() if (noErrors) { ModelChecker modelChecker(m_errorReporter, *this, m_smtlib2Responses, m_modelCheckerSettings, m_readFile); - auto allSources = applyMap(m_sourceOrder, [](Source const* _source) { return _source->ast; }); + auto allSources = util::applyMap(m_sourceOrder, [](Source const* _source) { return _source->ast; }); modelChecker.enableAllEnginesIfPragmaPresent(allSources); modelChecker.checkRequestedSourcesAndContracts(allSources); for (Source const* source: m_sourceOrder) @@ -1030,7 +1030,7 @@ Json::Value CompilerStack::interfaceSymbols(string const& _contractName) const for (ErrorDefinition const* error: contractDefinition(_contractName).interfaceErrors()) { string signature = error->functionType(true)->externalSignature(); - interfaceSymbols["errors"][signature] = toHex(toCompactBigEndian(selectorFromSignature32(signature), 4)); + interfaceSymbols["errors"][signature] = util::toHex(toCompactBigEndian(util::selectorFromSignature32(signature), 4)); } for (EventDefinition const* event: ranges::concat_view( @@ -1040,7 +1040,7 @@ Json::Value CompilerStack::interfaceSymbols(string const& _contractName) const if (!event->isAnonymous()) { string signature = event->functionType(true)->externalSignature(); - interfaceSymbols["events"][signature] = toHex(u256(h256::Arith(keccak256(signature)))); + interfaceSymbols["events"][signature] = toHex(u256(h256::Arith(util::keccak256(signature)))); } return interfaceSymbols; @@ -1494,7 +1494,7 @@ string CompilerStack::createMetadata(Contract const& _contract, bool _forIR) con continue; solAssert(s.second.charStream, "Character stream not available"); - meta["sources"][s.first]["keccak256"] = "0x" + toHex(s.second.keccak256().asBytes()); + meta["sources"][s.first]["keccak256"] = "0x" + util::toHex(s.second.keccak256().asBytes()); if (optional licenseString = s.second.ast->licenseString()) meta["sources"][s.first]["license"] = *licenseString; if (m_metadataLiteralSources) @@ -1502,7 +1502,7 @@ string CompilerStack::createMetadata(Contract const& _contract, bool _forIR) con else { meta["sources"][s.first]["urls"] = Json::arrayValue; - meta["sources"][s.first]["urls"].append("bzz-raw://" + toHex(s.second.swarmHash().asBytes())); + meta["sources"][s.first]["urls"].append("bzz-raw://" + util::toHex(s.second.swarmHash().asBytes())); meta["sources"][s.first]["urls"].append(s.second.ipfsUrl()); } } @@ -1565,7 +1565,7 @@ string CompilerStack::createMetadata(Contract const& _contract, bool _forIR) con meta["settings"]["libraries"] = Json::objectValue; for (auto const& library: m_libraries) - meta["settings"]["libraries"][library.first] = "0x" + toHex(library.second.asBytes()); + meta["settings"]["libraries"][library.first] = "0x" + util::toHex(library.second.asBytes()); meta["output"]["abi"] = contractABI(_contract); meta["output"]["userdoc"] = natspecUser(_contract); @@ -1677,7 +1677,7 @@ bytes CompilerStack::createCBORMetadata(Contract const& _contract, bool _forIR) else solAssert(m_metadataHash == MetadataHash::None, "Invalid metadata hash"); - if (experimentalMode || _forIR) + if (experimentalMode) encoder.pushBool("experimental", true); if (m_metadataFormat == MetadataFormat::WithReleaseVersionTag) encoder.pushBytes("solc", VersionCompactBytes); diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index c1f15a480426..e5bc9b345828 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -189,7 +189,7 @@ class CompilerStack: public langutil::CharStreamProvider /// Enable EVM Bytecode generation. This is enabled by default. void enableEvmBytecodeGeneration(bool _enable = true) { m_generateEvmBytecode = _enable; } - /// Enable experimental generation of Yul IR code. + /// Enable generation of Yul IR code. void enableIRGeneration(bool _enable = true) { m_generateIR = _enable; } /// Enable experimental generation of Ewasm code. If enabled, IR is also generated. @@ -373,8 +373,8 @@ class CompilerStack: public langutil::CharStreamProvider std::shared_ptr evmRuntimeAssembly; evmasm::LinkerObject object; ///< Deployment object (includes the runtime sub-object). evmasm::LinkerObject runtimeObject; ///< Runtime object. - std::string yulIR; ///< Experimental Yul IR code. - std::string yulIROptimized; ///< Optimized experimental Yul IR code. + std::string yulIR; ///< Yul IR code. + std::string yulIROptimized; ///< Optimized Yul IR code. std::string ewasm; ///< Experimental Ewasm text representation evmasm::LinkerObject ewasmObject; ///< Experimental Ewasm code util::LazyInit metadata; ///< The metadata json that will be hashed into the chain. @@ -447,8 +447,7 @@ class CompilerStack: public langutil::CharStreamProvider /// Can only be called after state is SourcesSet. Source const& source(std::string const& _sourceName) const; - /// @param _forIR If true, include a flag that indicates that the bytecode comes from the - /// experimental IR codegen. + /// @param _forIR If true, include a flag that indicates that the bytecode comes from IR codegen. /// @returns the metadata JSON as a compact string for the given contract. std::string createMetadata(Contract const& _contract, bool _forIR) const; diff --git a/libsolidity/interface/OptimiserSettings.h b/libsolidity/interface/OptimiserSettings.h index e1c35e9ea23c..e233048c18f1 100644 --- a/libsolidity/interface/OptimiserSettings.h +++ b/libsolidity/interface/OptimiserSettings.h @@ -55,7 +55,7 @@ struct OptimiserSettings "xa[rul]" // Prune a bit more in SSA "xa[r]cL" // Turn into SSA again and simplify "gvif" // Run full inliner - "CTUca[r]LsTFOtfDnca[r]Iulc" // SSA plus simplify + "CTUca[r]LSsTFOtfDnca[r]Iulc" // SSA plus simplify "]" "jmul[jul] VcTOcul jmul"; // Make source short and pretty diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 93ac20b03c87..31400ccadc15 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -1448,10 +1448,6 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) return output; } - // TODO: move this warning to AssemblyStack - output["errors"] = Json::arrayValue; - output["errors"].append(formatError(Error::Severity::Warning, "Warning", "general", "Yul is still experimental. Please use the output with care.")); - string contractName = stack.parserResult()->name.str(); bool const wildcardMatchesExperimental = true; diff --git a/libsolidity/lsp/GotoDefinition.cpp b/libsolidity/lsp/GotoDefinition.cpp new file mode 100644 index 000000000000..26fb686dbb6e --- /dev/null +++ b/libsolidity/lsp/GotoDefinition.cpp @@ -0,0 +1,66 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +#include +#include // for RequestError +#include +#include +#include + +#include + +#include +#include +#include + +using namespace solidity::frontend; +using namespace solidity::langutil; +using namespace solidity::lsp; +using namespace std; + +void GotoDefinition::operator()(MessageID _id, Json::Value const& _args) +{ + auto const [sourceUnitName, lineColumn] = extractSourceUnitNameAndLineColumn(_args); + + ASTNode const* sourceNode = m_server.astNodeAtSourceLocation(sourceUnitName, lineColumn); + + vector locations; + if (auto const* expression = dynamic_cast(sourceNode)) + { + // Handles all expressions that can have one or more declaration annotation. + if (auto const* declaration = referencedDeclaration(expression)) + if (auto location = declarationLocation(declaration)) + locations.emplace_back(move(location.value())); + } + else if (auto const* identifierPath = dynamic_cast(sourceNode)) + { + if (auto const* declaration = identifierPath->annotation().referencedDeclaration) + if (auto location = declarationLocation(declaration)) + locations.emplace_back(move(location.value())); + } + else if (auto const* importDirective = dynamic_cast(sourceNode)) + { + auto const& path = *importDirective->annotation().absolutePath; + if (fileRepository().sourceUnits().count(path)) + locations.emplace_back(SourceLocation{0, 0, make_shared(path)}); + } + + Json::Value reply = Json::arrayValue; + for (SourceLocation const& location: locations) + reply.append(toJson(location)); + client().reply(_id, reply); +} diff --git a/libsolidity/lsp/GotoDefinition.h b/libsolidity/lsp/GotoDefinition.h new file mode 100644 index 000000000000..453da3f1561c --- /dev/null +++ b/libsolidity/lsp/GotoDefinition.h @@ -0,0 +1,31 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +#include + +namespace solidity::lsp +{ + +class GotoDefinition: public HandlerBase +{ +public: + explicit GotoDefinition(LanguageServer& _server): HandlerBase(_server) {} + + void operator()(MessageID, Json::Value const&); +}; + +} diff --git a/libsolidity/lsp/HandlerBase.cpp b/libsolidity/lsp/HandlerBase.cpp new file mode 100644 index 000000000000..0da19aad355f --- /dev/null +++ b/libsolidity/lsp/HandlerBase.cpp @@ -0,0 +1,78 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +#include + +#include +#include +#include +#include + +#include + +#include + +using namespace solidity::langutil; +using namespace solidity::lsp; +using namespace solidity::util; +using namespace std; + +Json::Value HandlerBase::toRange(SourceLocation const& _location) const +{ + if (!_location.hasText()) + return toJsonRange({}, {}); + + solAssert(_location.sourceName, ""); + langutil::CharStream const& stream = charStreamProvider().charStream(*_location.sourceName); + LineColumn start = stream.translatePositionToLineColumn(_location.start); + LineColumn end = stream.translatePositionToLineColumn(_location.end); + return toJsonRange(start, end); +} + +Json::Value HandlerBase::toJson(SourceLocation const& _location) const +{ + solAssert(_location.sourceName); + Json::Value item = Json::objectValue; + item["uri"] = fileRepository().sourceUnitNameToClientPath(*_location.sourceName); + item["range"] = toRange(_location); + return item; +} + +pair HandlerBase::extractSourceUnitNameAndLineColumn(Json::Value const& _args) const +{ + string const uri = _args["textDocument"]["uri"].asString(); + string const sourceUnitName = fileRepository().clientPathToSourceUnitName(uri); + if (!fileRepository().sourceUnits().count(sourceUnitName)) + BOOST_THROW_EXCEPTION( + RequestError(ErrorCode::RequestFailed) << + errinfo_comment("Unknown file: " + uri) + ); + + auto const lineColumn = parseLineColumn(_args["position"]); + if (!lineColumn) + BOOST_THROW_EXCEPTION( + RequestError(ErrorCode::RequestFailed) << + errinfo_comment(fmt::format( + "Unknown position {line}:{column} in file: {file}", + fmt::arg("line", lineColumn.value().line), + fmt::arg("column", lineColumn.value().column), + fmt::arg("file", sourceUnitName) + )) + ); + + return {sourceUnitName, *lineColumn}; +} diff --git a/libsolidity/lsp/HandlerBase.h b/libsolidity/lsp/HandlerBase.h new file mode 100644 index 000000000000..3ca1679be658 --- /dev/null +++ b/libsolidity/lsp/HandlerBase.h @@ -0,0 +1,56 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +#pragma once + +#include +#include + +#include +#include + +#include + +namespace solidity::lsp +{ + +class Transport; + +/** + * Helper base class for implementing handlers. + */ +class HandlerBase +{ +public: + explicit HandlerBase(LanguageServer& _server): m_server{_server} {} + + Json::Value toRange(langutil::SourceLocation const& _location) const; + Json::Value toJson(langutil::SourceLocation const& _location) const; + + /// @returns source unit name and the line column position as extracted + /// from the JSON-RPC parameters. + std::pair extractSourceUnitNameAndLineColumn(Json::Value const& _params) const; + + langutil::CharStreamProvider const& charStreamProvider() const noexcept { return m_server.charStreamProvider(); } + FileRepository const& fileRepository() const noexcept { return m_server.fileRepository(); } + Transport& client() const noexcept { return m_server.client(); } + +protected: + LanguageServer& m_server; +}; + +} diff --git a/libsolidity/lsp/LanguageServer.cpp b/libsolidity/lsp/LanguageServer.cpp index fb704d819274..671476ab0558 100644 --- a/libsolidity/lsp/LanguageServer.cpp +++ b/libsolidity/lsp/LanguageServer.cpp @@ -21,6 +21,11 @@ #include #include #include +#include +#include + +// LSP feature implementations +#include #include #include @@ -48,31 +53,6 @@ using namespace solidity::frontend; namespace { -Json::Value toJson(LineColumn _pos) -{ - Json::Value json = Json::objectValue; - json["line"] = max(_pos.line, 0); - json["character"] = max(_pos.column, 0); - - return json; -} - -Json::Value toJsonRange(LineColumn const& _start, LineColumn const& _end) -{ - Json::Value json; - json["start"] = toJson(_start); - json["end"] = toJson(_end); - return json; -} - -optional parseLineColumn(Json::Value const& _lineColumn) -{ - if (_lineColumn.isObject() && _lineColumn["line"].isInt() && _lineColumn["character"].isInt()) - return LineColumn{_lineColumn["line"].asInt(), _lineColumn["character"].asInt()}; - else - return nullopt; -} - int toDiagnosticSeverity(Error::Type _errorType) { // 1=Error, 2=Warning, 3=Info, 4=Hint @@ -97,9 +77,11 @@ LanguageServer::LanguageServer(Transport& _transport): {"initialize", bind(&LanguageServer::handleInitialize, this, _1, _2)}, {"initialized", [](auto, auto) {}}, {"shutdown", [this](auto, auto) { m_state = State::ShutdownRequested; }}, + {"textDocument/definition", GotoDefinition(*this) }, {"textDocument/didOpen", bind(&LanguageServer::handleTextDocumentDidOpen, this, _2)}, {"textDocument/didChange", bind(&LanguageServer::handleTextDocumentDidChange, this, _2)}, {"textDocument/didClose", bind(&LanguageServer::handleTextDocumentDidClose, this, _2)}, + {"textDocument/implementation", GotoDefinition(*this) }, {"workspace/didChangeConfiguration", bind(&LanguageServer::handleWorkspaceDidChangeConfiguration, this, _2)}, }, m_fileRepository("/" /* basePath */), @@ -107,55 +89,14 @@ LanguageServer::LanguageServer(Transport& _transport): { } -optional LanguageServer::parsePosition( - string const& _sourceUnitName, - Json::Value const& _position -) const +Json::Value LanguageServer::toRange(SourceLocation const& _location) { - if (!m_fileRepository.sourceUnits().count(_sourceUnitName)) - return nullopt; - - if (optional lineColumn = parseLineColumn(_position)) - if (optional const offset = CharStream::translateLineColumnToPosition( - m_fileRepository.sourceUnits().at(_sourceUnitName), - *lineColumn - )) - return SourceLocation{*offset, *offset, make_shared(_sourceUnitName)}; - return nullopt; + return HandlerBase(*this).toRange(_location); } -optional LanguageServer::parseRange(string const& _sourceUnitName, Json::Value const& _range) const +Json::Value LanguageServer::toJson(SourceLocation const& _location) { - if (!_range.isObject()) - return nullopt; - optional start = parsePosition(_sourceUnitName, _range["start"]); - optional end = parsePosition(_sourceUnitName, _range["end"]); - if (!start || !end) - return nullopt; - solAssert(*start->sourceName == *end->sourceName); - start->end = end->end; - return start; -} - -Json::Value LanguageServer::toRange(SourceLocation const& _location) const -{ - if (!_location.hasText()) - return toJsonRange({}, {}); - - solAssert(_location.sourceName, ""); - CharStream const& stream = m_compilerStack.charStream(*_location.sourceName); - LineColumn start = stream.translatePositionToLineColumn(_location.start); - LineColumn end = stream.translatePositionToLineColumn(_location.end); - return toJsonRange(start, end); -} - -Json::Value LanguageServer::toJson(SourceLocation const& _location) const -{ - solAssert(_location.sourceName); - Json::Value item = Json::objectValue; - item["uri"] = m_fileRepository.sourceUnitNameToClientPath(*_location.sourceName); - item["range"] = toRange(_location); - return item; + return HandlerBase(*this).toJson(_location); } void LanguageServer::changeConfiguration(Json::Value const& _settings) @@ -253,7 +194,7 @@ bool LanguageServer::run() string const methodName = (*jsonMessage)["method"].asString(); id = (*jsonMessage)["id"]; - if (auto handler = valueOrDefault(m_handlers, methodName)) + if (auto handler = util::valueOrDefault(m_handlers, methodName)) handler(id, (*jsonMessage)["params"]); else m_client.error(id, ErrorCode::MethodNotFound, "Unknown method " + methodName); @@ -316,8 +257,10 @@ void LanguageServer::handleInitialize(MessageID _id, Json::Value const& _args) Json::Value replyArgs; replyArgs["serverInfo"]["name"] = "solc"; replyArgs["serverInfo"]["version"] = string(VersionNumber); - replyArgs["capabilities"]["textDocumentSync"]["openClose"] = true; + replyArgs["capabilities"]["definitionProvider"] = true; + replyArgs["capabilities"]["implementationProvider"] = true; replyArgs["capabilities"]["textDocumentSync"]["change"] = 2; // 0=none, 1=full, 2=incremental + replyArgs["capabilities"]["textDocumentSync"]["openClose"] = true; m_client.reply(_id, move(replyArgs)); } @@ -371,11 +314,11 @@ void LanguageServer::handleTextDocumentDidChange(Json::Value const& _args) string text = jsonContentChange["text"].asString(); if (jsonContentChange["range"].isObject()) // otherwise full content update { - optional change = parseRange(sourceUnitName, jsonContentChange["range"]); + optional change = parseRange(m_fileRepository, sourceUnitName, jsonContentChange["range"]); lspAssert( change && change->hasText(), ErrorCode::RequestFailed, - "Invalid source range: " + jsonCompactPrint(jsonContentChange["range"]) + "Invalid source range: " + util::jsonCompactPrint(jsonContentChange["range"]) ); string buffer = m_fileRepository.sourceUnits().at(sourceUnitName); @@ -403,3 +346,19 @@ void LanguageServer::handleTextDocumentDidClose(Json::Value const& _args) compileAndUpdateDiagnostics(); } + +ASTNode const* LanguageServer::astNodeAtSourceLocation(std::string const& _sourceUnitName, LineColumn const& _filePos) +{ + if (m_compilerStack.state() < CompilerStack::AnalysisPerformed) + return nullptr; + + if (!m_fileRepository.sourceUnits().count(_sourceUnitName)) + return nullptr; + + if (optional sourcePos = + m_compilerStack.charStream(_sourceUnitName).translateLineColumnToPosition(_filePos)) + return locateInnermostASTNode(*sourcePos, m_compilerStack.ast(_sourceUnitName)); + else + return nullptr; +} + diff --git a/libsolidity/lsp/LanguageServer.h b/libsolidity/lsp/LanguageServer.h index a3ab37198838..d2ad09367752 100644 --- a/libsolidity/lsp/LanguageServer.h +++ b/libsolidity/lsp/LanguageServer.h @@ -57,6 +57,11 @@ class LanguageServer /// @return boolean indicating normal or abnormal termination. bool run(); + FileRepository& fileRepository() noexcept { return m_fileRepository; } + Transport& client() noexcept { return m_client; } + frontend::ASTNode const* astNodeAtSourceLocation(std::string const& _sourceUnitName, langutil::LineColumn const& _filePos); + langutil::CharStreamProvider const& charStreamProvider() const noexcept { return m_compilerStack; } + private: /// Checks if the server is initialized (to be used by messages that need it to be initialized). /// Reports an error and returns false if not. @@ -66,28 +71,19 @@ class LanguageServer void handleTextDocumentDidOpen(Json::Value const& _args); void handleTextDocumentDidChange(Json::Value const& _args); void handleTextDocumentDidClose(Json::Value const& _args); + void handleGotoDefinition(MessageID _id, Json::Value const& _args); /// Invoked when the server user-supplied configuration changes (initiated by the client). void changeConfiguration(Json::Value const&); /// Compile everything until after analysis phase. void compile(); + using MessageHandler = std::function; - std::optional parsePosition( - std::string const& _sourceUnitName, - Json::Value const& _position - ) const; - /// @returns the source location given a source unit name and an LSP Range object, - /// or nullopt on failure. - std::optional parseRange( - std::string const& _sourceUnitName, - Json::Value const& _range - ) const; - Json::Value toRange(langutil::SourceLocation const& _location) const; - Json::Value toJson(langutil::SourceLocation const& _location) const; + Json::Value toRange(langutil::SourceLocation const& _location); + Json::Value toJson(langutil::SourceLocation const& _location); // LSP related member fields - using MessageHandler = std::function; enum class State { Started, Initialized, ShutdownRequested, ExitRequested, ExitWithoutShutdown }; State m_state = State::Started; diff --git a/libsolidity/lsp/Transport.h b/libsolidity/lsp/Transport.h index 2d0b49517adf..82fe43909979 100644 --- a/libsolidity/lsp/Transport.h +++ b/libsolidity/lsp/Transport.h @@ -69,7 +69,7 @@ class RequestError: public util::Exception { \ BOOST_THROW_EXCEPTION( \ RequestError(errorCode) << \ - errinfo_comment(errorMessage) \ + util::errinfo_comment(errorMessage) \ ); \ } diff --git a/libsolidity/lsp/Utils.cpp b/libsolidity/lsp/Utils.cpp new file mode 100644 index 000000000000..624d1f150250 --- /dev/null +++ b/libsolidity/lsp/Utils.cpp @@ -0,0 +1,118 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#include +#include +#include +#include +#include + +#include +#include + +namespace solidity::lsp +{ + +using namespace frontend; +using namespace langutil; +using namespace std; + +optional parseLineColumn(Json::Value const& _lineColumn) +{ + if (_lineColumn.isObject() && _lineColumn["line"].isInt() && _lineColumn["character"].isInt()) + return LineColumn{_lineColumn["line"].asInt(), _lineColumn["character"].asInt()}; + else + return nullopt; +} + +Json::Value toJson(LineColumn const& _pos) +{ + Json::Value json = Json::objectValue; + json["line"] = max(_pos.line, 0); + json["character"] = max(_pos.column, 0); + + return json; +} + +Json::Value toJsonRange(LineColumn const& _start, LineColumn const& _end) +{ + Json::Value json; + json["start"] = toJson(_start); + json["end"] = toJson(_end); + return json; +} + +Declaration const* referencedDeclaration(Expression const* _expression) +{ + if (auto const* identifier = dynamic_cast(_expression)) + if (Declaration const* referencedDeclaration = identifier->annotation().referencedDeclaration) + return referencedDeclaration; + + if (auto const* memberAccess = dynamic_cast(_expression)) + if (memberAccess->annotation().referencedDeclaration) + return memberAccess->annotation().referencedDeclaration; + + return nullptr; +} + +optional declarationLocation(Declaration const* _declaration) +{ + if (!_declaration) + return nullopt; + + if (_declaration->nameLocation().isValid()) + return _declaration->nameLocation(); + + if (_declaration->location().isValid()) + return _declaration->location(); + + return nullopt; +} + +optional parsePosition( + FileRepository const& _fileRepository, + string const& _sourceUnitName, + Json::Value const& _position +) +{ + if (!_fileRepository.sourceUnits().count(_sourceUnitName)) + return nullopt; + + if (optional lineColumn = parseLineColumn(_position)) + if (optional const offset = CharStream::translateLineColumnToPosition( + _fileRepository.sourceUnits().at(_sourceUnitName), + *lineColumn + )) + return SourceLocation{*offset, *offset, make_shared(_sourceUnitName)}; + return nullopt; +} + +optional parseRange(FileRepository const& _fileRepository, string const& _sourceUnitName, Json::Value const& _range) +{ + if (!_range.isObject()) + return nullopt; + optional start = parsePosition(_fileRepository, _sourceUnitName, _range["start"]); + optional end = parsePosition(_fileRepository, _sourceUnitName, _range["end"]); + if (!start || !end) + return nullopt; + solAssert(*start->sourceName == *end->sourceName); + start->end = end->end; + return start; +} + +} diff --git a/libsolidity/lsp/Utils.h b/libsolidity/lsp/Utils.h new file mode 100644 index 000000000000..3594efba248d --- /dev/null +++ b/libsolidity/lsp/Utils.h @@ -0,0 +1,79 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#pragma once + +#include + +#include + +#include + +#include +#include + +#if !defined(NDEBUG) +#include +#define lspDebug(message) (std::ofstream("/tmp/solc.log", std::ios::app) << (message) << std::endl) +#else +#define lspDebug(message) do {} while (0) +#endif + +namespace solidity::langutil +{ +class CharStreamProvider; +} + +namespace solidity::lsp +{ + +class FileRepository; + +std::optional parseLineColumn(Json::Value const& _lineColumn); +Json::Value toJson(langutil::LineColumn const& _pos); +Json::Value toJsonRange(langutil::LineColumn const& _start, langutil::LineColumn const& _end); + +/// @returns the source location given a source unit name and an LSP Range object, +/// or nullopt on failure. +std::optional parsePosition( + FileRepository const& _fileRepository, + std::string const& _sourceUnitName, + Json::Value const& _position +); + +/// @returns the source location given a source unit name and an LSP Range object, +/// or nullopt on failure. +std::optional parseRange( + FileRepository const& _fileRepository, + std::string const& _sourceUnitName, + Json::Value const& _range +); + +/// Extracts the resolved declaration of the given expression AST node. +/// +/// This may for example be the type declaration of an identifier, +/// or the type declaration of a structured member identifier. +/// +/// @returns the resolved type declaration if found, or nullptr otherwise. +frontend::Declaration const* referencedDeclaration(frontend::Expression const* _expression); + +/// @returns the location of the declaration's name, if present, or the location of the complete +/// declaration otherwise. If the input declaration is nullptr, std::nullopt is returned instead. +std::optional declarationLocation(frontend::Declaration const* _declaration); + +} diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index b1d7e7ccad18..a1b49a81f30b 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -117,6 +117,9 @@ ASTPointer Parser::parse(CharStream& _charStream) case Token::Type: nodes.push_back(parseUserDefinedValueTypeDefinition()); break; + case Token::Using: + nodes.push_back(parseUsingDirective()); + break; case Token::Function: nodes.push_back(parseFunctionDefinition(true)); break; @@ -962,16 +965,37 @@ ASTPointer Parser::parseUsingDirective() ASTNodeFactory nodeFactory(*this); expectToken(Token::Using); - ASTPointer library(parseIdentifierPath()); + + vector> functions; + bool const usesBraces = m_scanner->currentToken() == Token::LBrace; + if (usesBraces) + { + do + { + advance(); + functions.emplace_back(parseIdentifierPath()); + } + while (m_scanner->currentToken() == Token::Comma); + expectToken(Token::RBrace); + } + else + functions.emplace_back(parseIdentifierPath()); + ASTPointer typeName; expectToken(Token::For); if (m_scanner->currentToken() == Token::Mul) advance(); else typeName = parseTypeName(); + bool global = false; + if (m_scanner->currentToken() == Token::Identifier && currentLiteral() == "global") + { + global = true; + advance(); + } nodeFactory.markEndPosition(); expectToken(Token::Semicolon); - return nodeFactory.createNode(library, typeName); + return nodeFactory.createNode(move(functions), usesBraces, typeName, global); } ASTPointer Parser::parseModifierInvocation() diff --git a/libsolutil/IpfsHash.cpp b/libsolutil/IpfsHash.cpp index a34ee035bd64..dbf411dc783d 100644 --- a/libsolutil/IpfsHash.cpp +++ b/libsolutil/IpfsHash.cpp @@ -59,7 +59,7 @@ bytes encodeLinkData(bytes const& _data) string base58Encode(bytes const& _data) { static string const alphabet{"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"}; - bigint data(toHex(_data, HexPrefix::Add)); + bigint data(util::toHex(_data, HexPrefix::Add)); string output; while (data) { diff --git a/libyul/AST.h b/libyul/AST.h index 1c7b8e02a1d0..71419d807faa 100644 --- a/libyul/AST.h +++ b/libyul/AST.h @@ -144,4 +144,13 @@ template inline std::shared_ptr debugDataOf(std return std::visit([](auto const& _arg) { return debugDataOf(_arg); }, _node); } +inline bool hasDefaultCase(Switch const& _switch) +{ + return std::any_of( + _switch.cases.begin(), + _switch.cases.end(), + [](Case const& _case) { return !_case.value; } + ); +} + } diff --git a/libyul/AssemblyStack.cpp b/libyul/AssemblyStack.cpp index 30ad58d7730c..3fefb9cafc5a 100644 --- a/libyul/AssemblyStack.cpp +++ b/libyul/AssemblyStack.cpp @@ -38,6 +38,7 @@ #include #include +#include #include using namespace std; @@ -71,8 +72,7 @@ evmasm::Assembly::OptimiserSettings translateOptimiserSettings( ) { // Constructing it this way so that we notice changes in the fields. - evmasm::Assembly::OptimiserSettings asmSettings{false, false, false, false, false, false, false, _evmVersion, 0}; - asmSettings.isCreation = true; + evmasm::Assembly::OptimiserSettings asmSettings{false, false, false, false, false, false, _evmVersion, 0}; asmSettings.runInliner = _settings.runInliner; asmSettings.runJumpdestRemover = _settings.runJumpdestRemover; asmSettings.runPeephole = _settings.runPeephole; @@ -194,7 +194,10 @@ void AssemblyStack::optimize(Object& _object, bool _isCreation) yulAssert(_object.analysisInfo, ""); for (auto& subNode: _object.subObjects) if (auto subObject = dynamic_cast(subNode.get())) - optimize(*subObject, false); + { + bool isCreation = !boost::ends_with(subObject->name.str(), "_deployed"); + optimize(*subObject, isCreation); + } Dialect const& dialect = languageToDialect(m_language, m_evmVersion); unique_ptr meter; @@ -281,7 +284,7 @@ AssemblyStack::assembleEVMWithDeployed(optional _deployName) const yulAssert(m_parserResult->code, ""); yulAssert(m_parserResult->analysisInfo, ""); - evmasm::Assembly assembly; + evmasm::Assembly assembly(true, {}); EthAssemblyAdapter adapter(assembly); compileEVM(adapter, m_optimiserSettings.optimizeStackAllocation); diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt index fde673e3d851..806f094fe73d 100644 --- a/libyul/CMakeLists.txt +++ b/libyul/CMakeLists.txt @@ -179,6 +179,8 @@ add_library(yul optimiser/UnusedAssignEliminator.h optimiser/UnusedStoreBase.cpp optimiser/UnusedStoreBase.h + optimiser/UnusedStoreEliminator.cpp + optimiser/UnusedStoreEliminator.h optimiser/Rematerialiser.cpp optimiser/Rematerialiser.h optimiser/SMTSolver.cpp diff --git a/libyul/Object.cpp b/libyul/Object.cpp index ed456ab53d2f..cf68ff765fd1 100644 --- a/libyul/Object.cpp +++ b/libyul/Object.cpp @@ -91,13 +91,13 @@ string Object::toString( set Object::qualifiedDataNames() const { set qualifiedNames = - name.empty() || contains(name.str(), '.') ? + name.empty() || util::contains(name.str(), '.') ? set{} : set{name}; for (shared_ptr const& subObjectNode: subObjects) { yulAssert(qualifiedNames.count(subObjectNode->name) == 0, ""); - if (contains(subObjectNode->name.str(), '.')) + if (util::contains(subObjectNode->name.str(), '.')) continue; qualifiedNames.insert(subObjectNode->name); if (auto const* subObject = dynamic_cast(subObjectNode.get())) diff --git a/libyul/backends/evm/AbstractAssembly.h b/libyul/backends/evm/AbstractAssembly.h index 66d5333e22ac..2d7be90019ea 100644 --- a/libyul/backends/evm/AbstractAssembly.h +++ b/libyul/backends/evm/AbstractAssembly.h @@ -98,7 +98,7 @@ class AbstractAssembly /// Append the assembled size as a constant. virtual void appendAssemblySize() = 0; /// Creates a new sub-assembly, which can be referenced using dataSize and dataOffset. - virtual std::pair, SubID> createSubAssembly(std::string _name = "") = 0; + virtual std::pair, SubID> createSubAssembly(bool _creation, std::string _name = "") = 0; /// Appends the offset of the given sub-assembly or data. virtual void appendDataOffset(std::vector const& _subPath) = 0; /// Appends the size of the given sub-assembly or data. diff --git a/libyul/backends/evm/ControlFlowGraph.h b/libyul/backends/evm/ControlFlowGraph.h index 6196697fc4ea..8ca2076a0438 100644 --- a/libyul/backends/evm/ControlFlowGraph.h +++ b/libyul/backends/evm/ControlFlowGraph.h @@ -195,6 +195,14 @@ struct CFG std::shared_ptr debugData; std::vector entries; std::vector operations; + /// True, if the block is the beginning of a disconnected subgraph. That is, if no block that is reachable + /// from this block is an ancestor of this block. In other words, this is true, if this block is the target + /// of a cut-edge/bridge in the CFG or if the block itself terminates. + bool isStartOfSubGraph = false; + /// True, if there is a path from this block to a function return. + bool needsCleanStack = false; + /// If the block starts a sub-graph and does not lead to a function return, we are free to add junk to it. + bool allowsJunk() const { return isStartOfSubGraph && !needsCleanStack; } std::variant exit = MainExit{}; }; @@ -205,6 +213,7 @@ struct CFG BasicBlock* entry = nullptr; std::vector parameters; std::vector returnVariables; + std::vector exits; }; /// The main entry point, i.e. the start of the outermost Yul block. diff --git a/libyul/backends/evm/ControlFlowGraphBuilder.cpp b/libyul/backends/evm/ControlFlowGraphBuilder.cpp index df271bb8d8a3..855d96fbd332 100644 --- a/libyul/backends/evm/ControlFlowGraphBuilder.cpp +++ b/libyul/backends/evm/ControlFlowGraphBuilder.cpp @@ -48,7 +48,7 @@ using namespace std; namespace { -// Removes edges to blocks that are not reachable. +/// Removes edges to blocks that are not reachable. void cleanUnreachable(CFG& _cfg) { // Determine which blocks are reachable from the entry. @@ -77,7 +77,8 @@ void cleanUnreachable(CFG& _cfg) return !reachabilityCheck.visited.count(entry); }); } -// Sets the ``recursive`` member to ``true`` for all recursive function calls. + +/// Sets the ``recursive`` member to ``true`` for all recursive function calls. void markRecursiveCalls(CFG& _cfg) { map> callsPerBlock; @@ -124,6 +125,84 @@ void markRecursiveCalls(CFG& _cfg) }); } } + +/// Marks each cut-vertex in the CFG, i.e. each block that begins a disconnected sub-graph of the CFG. +/// Entering such a block means that control flow will never return to a previously visited block. +void markStartsOfSubGraphs(CFG& _cfg) +{ + vector entries; + entries.emplace_back(_cfg.entry); + for (auto&& functionInfo: _cfg.functionInfo | ranges::views::values) + entries.emplace_back(functionInfo.entry); + for (auto& entry: entries) + { + /** + * Detect bridges following Algorithm 1 in https://arxiv.org/pdf/2108.07346.pdf + * and mark the bridge targets as starts of sub-graphs. + */ + set visited; + map disc; + map low; + map parent; + size_t time = 0; + auto dfs = [&](CFG::BasicBlock* _u, auto _recurse) -> void { + visited.insert(_u); + disc[_u] = low[_u] = time; + time++; + + vector children = _u->entries; + visit(util::GenericVisitor{ + [&](CFG::BasicBlock::Jump const& _jump) { + children.emplace_back(_jump.target); + }, + [&](CFG::BasicBlock::ConditionalJump const& _jump) { + children.emplace_back(_jump.zero); + children.emplace_back(_jump.nonZero); + }, + [&](CFG::BasicBlock::FunctionReturn const&) {}, + [&](CFG::BasicBlock::Terminated const&) { _u->isStartOfSubGraph = true; }, + [&](CFG::BasicBlock::MainExit const&) { _u->isStartOfSubGraph = true; } + }, _u->exit); + yulAssert(!util::contains(children, _u)); + + for (CFG::BasicBlock* v: children) + if (!visited.count(v)) + { + parent[v] = _u; + _recurse(v, _recurse); + low[_u] = min(low[_u], low[v]); + if (low[v] > disc[_u]) + { + // _u <-> v is a cut edge in the undirected graph + bool edgeVtoU = util::contains(_u->entries, v); + bool edgeUtoV = util::contains(v->entries, _u); + if (edgeVtoU && !edgeUtoV) + // Cut edge v -> _u + _u->isStartOfSubGraph = true; + else if (edgeUtoV && !edgeVtoU) + // Cut edge _u -> v + v->isStartOfSubGraph = true; + } + } + else if (v != parent[_u]) + low[_u] = min(low[_u], disc[v]); + }; + dfs(entry, dfs); + } +} + +/// Marks each block that needs to maintain a clean stack. That is each block that has an outgoing +/// path to a function return. +void markNeedsCleanStack(CFG& _cfg) +{ + for (auto& functionInfo: _cfg.functionInfo | ranges::views::values) + for (CFG::BasicBlock* exit: functionInfo.exits) + util::BreadthFirstSearch{{exit}}.run([&](CFG::BasicBlock* _block, auto _addChild) { + _block->needsCleanStack = true; + for (CFG::BasicBlock* entry: _block->entries) + _addChild(entry); + }); +} } std::unique_ptr ControlFlowGraphBuilder::build( @@ -141,6 +220,8 @@ std::unique_ptr ControlFlowGraphBuilder::build( cleanUnreachable(*result); markRecursiveCalls(*result); + markStartsOfSubGraphs(*result); + markNeedsCleanStack(*result); // TODO: It might be worthwhile to run some further simplifications on the graph itself here. // E.g. if there is a jump to a node that has the jumping node as its only entry, the nodes can be fused, etc. @@ -379,6 +460,7 @@ void ControlFlowGraphBuilder::operator()(Leave const& leave_) { yulAssert(m_currentFunction.has_value(), ""); m_currentBlock->exit = CFG::BasicBlock::FunctionReturn{debugDataOf(leave_), *m_currentFunction}; + (*m_currentFunction)->exits.emplace_back(m_currentBlock); m_currentBlock = &m_graph.makeBlock(debugDataOf(*m_currentBlock)); } @@ -395,6 +477,7 @@ void ControlFlowGraphBuilder::operator()(FunctionDefinition const& _function) builder.m_currentFunction = &functionInfo; builder.m_currentBlock = functionInfo.entry; builder(_function.body); + functionInfo.exits.emplace_back(builder.m_currentBlock); builder.m_currentBlock->exit = CFG::BasicBlock::FunctionReturn{debugDataOf(_function), &functionInfo}; } @@ -423,7 +506,8 @@ void ControlFlowGraphBuilder::registerFunction(FunctionDefinition const& _functi std::get(virtualFunctionScope->identifiers.at(_retVar.name)), _retVar.debugData }; - }) | ranges::to + }) | ranges::to, + {} })).second; yulAssert(inserted); } diff --git a/libyul/backends/evm/EVMObjectCompiler.cpp b/libyul/backends/evm/EVMObjectCompiler.cpp index c3c95d8bc51a..4dbf5cc1a3e7 100644 --- a/libyul/backends/evm/EVMObjectCompiler.cpp +++ b/libyul/backends/evm/EVMObjectCompiler.cpp @@ -30,6 +30,8 @@ #include #include +#include + using namespace solidity::yul; using namespace std; @@ -48,7 +50,8 @@ void EVMObjectCompiler::run(Object& _object, bool _optimize) for (auto const& subNode: _object.subObjects) if (auto* subObject = dynamic_cast(subNode.get())) { - auto subAssemblyAndID = m_assembly.createSubAssembly(subObject->name.str()); + bool isCreation = !boost::ends_with(subObject->name.str(), "_deployed"); + auto subAssemblyAndID = m_assembly.createSubAssembly(isCreation, subObject->name.str()); context.subIDs[subObject->name] = subAssemblyAndID.second; subObject->subId = subAssemblyAndID.second; compile(*subObject, *subAssemblyAndID.first, m_dialect, _optimize); @@ -86,7 +89,7 @@ void EVMObjectCompiler::run(Object& _object, bool _optimize) if (memoryGuardCalls.empty()) msg += "\nNo memoryguard was present. " "Consider using memory-safe assembly only and annotating it via " - "\"/// @solidity memory-safe-assembly\"."; + "'assembly (\"memory-safe\") { ... }'."; else msg += "\nmemoryguard was present."; stackError << util::errinfo_comment(msg); diff --git a/libyul/backends/evm/EthAssemblyAdapter.cpp b/libyul/backends/evm/EthAssemblyAdapter.cpp index 1c41534b25dd..5d7b4cbf45f6 100644 --- a/libyul/backends/evm/EthAssemblyAdapter.cpp +++ b/libyul/backends/evm/EthAssemblyAdapter.cpp @@ -122,9 +122,9 @@ void EthAssemblyAdapter::appendAssemblySize() m_assembly.appendProgramSize(); } -pair, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly(string _name) +pair, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly(bool _creation, string _name) { - shared_ptr assembly{make_shared(std::move(_name))}; + shared_ptr assembly{make_shared(_creation, std::move(_name))}; auto sub = m_assembly.newSub(assembly); return {make_shared(*assembly), static_cast(sub.data())}; } diff --git a/libyul/backends/evm/EthAssemblyAdapter.h b/libyul/backends/evm/EthAssemblyAdapter.h index c11b375f680b..87047ccbf4e9 100644 --- a/libyul/backends/evm/EthAssemblyAdapter.h +++ b/libyul/backends/evm/EthAssemblyAdapter.h @@ -55,7 +55,7 @@ class EthAssemblyAdapter: public AbstractAssembly void appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpType _jumpType) override; void appendJumpToIf(LabelID _labelId, JumpType _jumpType) override; void appendAssemblySize() override; - std::pair, SubID> createSubAssembly(std::string _name = {}) override; + std::pair, SubID> createSubAssembly(bool _creation, std::string _name = {}) override; void appendDataOffset(std::vector const& _subPath) override; void appendDataSize(std::vector const& _subPath) override; SubID appendData(bytes const& _data) override; diff --git a/libyul/backends/evm/NoOutputAssembly.cpp b/libyul/backends/evm/NoOutputAssembly.cpp index 62c0ad11987b..e26204201455 100644 --- a/libyul/backends/evm/NoOutputAssembly.cpp +++ b/libyul/backends/evm/NoOutputAssembly.cpp @@ -98,7 +98,7 @@ void NoOutputAssembly::appendAssemblySize() appendInstruction(evmasm::Instruction::PUSH1); } -pair, AbstractAssembly::SubID> NoOutputAssembly::createSubAssembly(std::string) +pair, AbstractAssembly::SubID> NoOutputAssembly::createSubAssembly(bool, std::string) { yulAssert(false, "Sub assemblies not implemented."); return {}; diff --git a/libyul/backends/evm/NoOutputAssembly.h b/libyul/backends/evm/NoOutputAssembly.h index b41d7f4a6bf0..1103392ef92c 100644 --- a/libyul/backends/evm/NoOutputAssembly.h +++ b/libyul/backends/evm/NoOutputAssembly.h @@ -65,7 +65,7 @@ class NoOutputAssembly: public AbstractAssembly void appendJumpToIf(LabelID _labelId, JumpType _jumpType) override; void appendAssemblySize() override; - std::pair, SubID> createSubAssembly(std::string _name = "") override; + std::pair, SubID> createSubAssembly(bool _creation, std::string _name = "") override; void appendDataOffset(std::vector const& _subPath) override; void appendDataSize(std::vector const& _subPath) override; SubID appendData(bytes const& _data) override; diff --git a/libyul/backends/evm/StackLayoutGenerator.cpp b/libyul/backends/evm/StackLayoutGenerator.cpp index 50dcee5deca5..4f9a1e2a1966 100644 --- a/libyul/backends/evm/StackLayoutGenerator.cpp +++ b/libyul/backends/evm/StackLayoutGenerator.cpp @@ -23,6 +23,8 @@ #include +#include + #include #include #include @@ -400,6 +402,7 @@ void StackLayoutGenerator::processEntryPoint(CFG::BasicBlock const& _entry) } stitchConditionalJumps(_entry); + fillInJunk(_entry); } optional StackLayoutGenerator::getExitLayoutOrStageDependencies( @@ -703,3 +706,110 @@ Stack StackLayoutGenerator::compressStack(Stack _stack) while (firstDupOffset); return _stack; } + +void StackLayoutGenerator::fillInJunk(CFG::BasicBlock const& _block) +{ + /// Recursively adds junk to the subgraph starting on @a _entry. + /// Since it is only called on cut-vertices, the full subgraph retains proper stack balance. + auto addJunkRecursive = [&](CFG::BasicBlock const* _entry, size_t _numJunk) { + util::BreadthFirstSearch breadthFirstSearch{{_entry}}; + breadthFirstSearch.run([&](CFG::BasicBlock const* _block, auto _addChild) { + auto& blockInfo = m_layout.blockInfos.at(_block); + blockInfo.entryLayout = Stack{_numJunk, JunkSlot{}} + move(blockInfo.entryLayout); + for (auto const& operation: _block->operations) + { + auto& operationEntryLayout = m_layout.operationEntryLayout.at(&operation); + operationEntryLayout = Stack{_numJunk, JunkSlot{}} + move(operationEntryLayout); + } + blockInfo.exitLayout = Stack{_numJunk, JunkSlot{}} + move(blockInfo.exitLayout); + + std::visit(util::GenericVisitor{ + [&](CFG::BasicBlock::MainExit const&) {}, + [&](CFG::BasicBlock::Jump const& _jump) + { + _addChild(_jump.target); + }, + [&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) + { + _addChild(_conditionalJump.zero); + _addChild(_conditionalJump.nonZero); + }, + [&](CFG::BasicBlock::FunctionReturn const&) { yulAssert(false); }, + [&](CFG::BasicBlock::Terminated const&) {}, + }, _block->exit); + }); + }; + /// @returns the number of operations required to transform @a _source to @a _target. + auto evaluateTransform = [](Stack _source, Stack const& _target) -> size_t { + size_t opGas = 0; + auto swap = [&](unsigned _swapDepth) + { + if (_swapDepth > 16) + opGas += 1000; + else + opGas += evmasm::GasMeter::runGas(evmasm::swapInstruction(_swapDepth)); + }; + auto dupOrPush = [&](StackSlot const& _slot) + { + if (canBeFreelyGenerated(_slot)) + opGas += evmasm::GasMeter::runGas(evmasm::pushInstruction(32)); + else + { + auto depth = util::findOffset(_source | ranges::views::reverse, _slot); + yulAssert(depth); + if (*depth < 16) + opGas += evmasm::GasMeter::runGas(evmasm::dupInstruction(static_cast(*depth + 1))); + else + opGas += 1000; + } + }; + auto pop = [&]() { opGas += evmasm::GasMeter::runGas(evmasm::Instruction::POP); }; + createStackLayout(_source, _target, swap, dupOrPush, pop); + return opGas; + }; + /// Traverses the CFG and at each block that allows junk, i.e. that is a cut-vertex that never leads to a function + /// return, checks if adding junk reduces the shuffling cost upon entering and if so recursively adds junk + /// to the spanned subgraph. + util::BreadthFirstSearch{{&_block}}.run([&](CFG::BasicBlock const* _block, auto _addChild) { + std::visit(util::GenericVisitor{ + [&](CFG::BasicBlock::MainExit const&) {}, + [&](CFG::BasicBlock::Jump const& _jump) + { + _addChild(_jump.target); + }, + [&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) + { + for (CFG::BasicBlock* exit: {_conditionalJump.zero, _conditionalJump.nonZero}) + if (exit->allowsJunk()) + { + auto& blockInfo = m_layout.blockInfos.at(exit); + Stack entryLayout = blockInfo.entryLayout; + Stack nextLayout = exit->operations.empty() ? blockInfo.exitLayout : m_layout.operationEntryLayout.at(&exit->operations.front()); + + size_t bestCost = evaluateTransform(entryLayout, nextLayout); + size_t bestNumJunk = 0; + size_t maxJunk = entryLayout.size(); + for (size_t numJunk = 1; numJunk <= maxJunk; ++numJunk) + { + size_t cost = evaluateTransform(entryLayout, Stack{numJunk, JunkSlot{}} + nextLayout); + if (cost < bestCost) + { + bestCost = cost; + bestNumJunk = numJunk; + } + } + + if (bestNumJunk > 0) + { + addJunkRecursive(exit, bestNumJunk); + blockInfo.entryLayout = entryLayout; + } + } + _addChild(_conditionalJump.zero); + _addChild(_conditionalJump.nonZero); + }, + [&](CFG::BasicBlock::FunctionReturn const&) {}, + [&](CFG::BasicBlock::Terminated const&) {}, + }, _block->exit); + }); +} diff --git a/libyul/backends/evm/StackLayoutGenerator.h b/libyul/backends/evm/StackLayoutGenerator.h index 803e4935445d..34cac6d39def 100644 --- a/libyul/backends/evm/StackLayoutGenerator.h +++ b/libyul/backends/evm/StackLayoutGenerator.h @@ -111,6 +111,9 @@ class StackLayoutGenerator /// stack @a _stack. static Stack compressStack(Stack _stack); + //// Fills in junk when entering branches that do not need a clean stack in case the result is cheaper. + void fillInJunk(CFG::BasicBlock const& _block); + StackLayout& m_layout; }; diff --git a/libyul/optimiser/CommonSubexpressionEliminator.cpp b/libyul/optimiser/CommonSubexpressionEliminator.cpp index 16cdfd89357c..d25beb6bdd19 100644 --- a/libyul/optimiser/CommonSubexpressionEliminator.cpp +++ b/libyul/optimiser/CommonSubexpressionEliminator.cpp @@ -95,10 +95,10 @@ void CommonSubexpressionEliminator::visit(Expression& _e) if (Identifier const* identifier = get_if(&_e)) { YulString identifierName = identifier->name; - if (m_value.count(identifierName)) + if (AssignedValue const* assignedValue = variableValue(identifierName)) { - assertThrow(m_value.at(identifierName).value, OptimizerException, ""); - if (Identifier const* value = get_if(m_value.at(identifierName).value)) + assertThrow(assignedValue->value, OptimizerException, ""); + if (Identifier const* value = get_if(assignedValue->value)) if (inScope(value->name)) _e = Identifier{debugDataOf(_e), value->name}; } @@ -106,7 +106,7 @@ void CommonSubexpressionEliminator::visit(Expression& _e) else { // TODO this search is rather inefficient. - for (auto const& [variable, value]: m_value) + for (auto const& [variable, value]: allValues()) { assertThrow(value.value, OptimizerException, ""); // Prevent using the default value of return variables diff --git a/libyul/optimiser/ControlFlowSimplifier.cpp b/libyul/optimiser/ControlFlowSimplifier.cpp index 443a2a9be118..cfd59d09ae21 100644 --- a/libyul/optimiser/ControlFlowSimplifier.cpp +++ b/libyul/optimiser/ControlFlowSimplifier.cpp @@ -60,13 +60,7 @@ void removeEmptyDefaultFromSwitch(Switch& _switchStmt) void removeEmptyCasesFromSwitch(Switch& _switchStmt) { - bool hasDefault = std::any_of( - _switchStmt.cases.begin(), - _switchStmt.cases.end(), - [](Case const& _case) { return !_case.value; } - ); - - if (hasDefault) + if (hasDefaultCase(_switchStmt)) return; ranges::actions::remove_if( diff --git a/libyul/optimiser/DataFlowAnalyzer.cpp b/libyul/optimiser/DataFlowAnalyzer.cpp index af25cde59214..65cdf31c323a 100644 --- a/libyul/optimiser/DataFlowAnalyzer.cpp +++ b/libyul/optimiser/DataFlowAnalyzer.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -47,7 +48,7 @@ DataFlowAnalyzer::DataFlowAnalyzer( ): m_dialect(_dialect), m_functionSideEffects(std::move(_functionSideEffects)), - m_knowledgeBase(_dialect, m_value) + m_knowledgeBase(_dialect, [this](YulString _var) { return variableValue(_var); }) { if (auto const* builtin = _dialect.memoryStoreFunction(YulString{})) m_storeFunctionName[static_cast(StoreLoadLocation::Memory)] = builtin->name; @@ -64,20 +65,20 @@ void DataFlowAnalyzer::operator()(ExpressionStatement& _statement) if (auto vars = isSimpleStore(StoreLoadLocation::Storage, _statement)) { ASTModifier::operator()(_statement); - cxx20::erase_if(m_storage, mapTuple([&](auto&& key, auto&& value) { + cxx20::erase_if(m_state.storage, mapTuple([&](auto&& key, auto&& value) { return !m_knowledgeBase.knownToBeDifferent(vars->first, key) && !m_knowledgeBase.knownToBeEqual(vars->second, value); })); - m_storage[vars->first] = vars->second; + m_state.storage[vars->first] = vars->second; } else if (auto vars = isSimpleStore(StoreLoadLocation::Memory, _statement)) { ASTModifier::operator()(_statement); - cxx20::erase_if(m_memory, mapTuple([&](auto&& key, auto&& /* value */) { + cxx20::erase_if(m_state.memory, mapTuple([&](auto&& key, auto&& /* value */) { return !m_knowledgeBase.knownToBeDifferentByAtLeast32(vars->first, key); })); - m_memory[vars->first] = vars->second; + m_state.memory[vars->first] = vars->second; } else { @@ -116,8 +117,8 @@ void DataFlowAnalyzer::operator()(VariableDeclaration& _varDecl) void DataFlowAnalyzer::operator()(If& _if) { clearKnowledgeIfInvalidated(*_if.condition); - unordered_map storage = m_storage; - unordered_map memory = m_memory; + unordered_map storage = m_state.storage; + unordered_map memory = m_state.memory; ASTModifier::operator()(_if); @@ -133,8 +134,8 @@ void DataFlowAnalyzer::operator()(Switch& _switch) set assignedVariables; for (auto& _case: _switch.cases) { - unordered_map storage = m_storage; - unordered_map memory = m_memory; + unordered_map storage = m_state.storage; + unordered_map memory = m_state.memory; (*this)(_case.body); joinKnowledge(storage, memory); @@ -153,11 +154,8 @@ void DataFlowAnalyzer::operator()(FunctionDefinition& _fun) { // Save all information. We might rather reinstantiate this class, // but this could be difficult if it is subclassed. - ScopedSaveAndRestore valueResetter(m_value, {}); + ScopedSaveAndRestore stateResetter(m_state, {}); ScopedSaveAndRestore loopDepthResetter(m_loopDepth, 0u); - ScopedSaveAndRestore referencesResetter(m_references, {}); - ScopedSaveAndRestore storageResetter(m_storage, {}); - ScopedSaveAndRestore memoryResetter(m_memory, {}); pushScope(true); for (auto const& parameter: _fun.parameters) @@ -218,6 +216,22 @@ void DataFlowAnalyzer::operator()(Block& _block) assertThrow(numScopes == m_variableScopes.size(), OptimizerException, ""); } +optional DataFlowAnalyzer::storageValue(YulString _key) const +{ + if (YulString const* value = util::valueOrNullptr(m_state.storage, _key)) + return *value; + else + return nullopt; +} + +optional DataFlowAnalyzer::memoryValue(YulString _key) const +{ + if (YulString const* value = util::valueOrNullptr(m_state.memory, _key)) + return *value; + else + return nullopt; +} + void DataFlowAnalyzer::handleAssignment(set const& _variables, Expression* _value, bool _isDeclaration) { if (!_isDeclaration) @@ -242,17 +256,17 @@ void DataFlowAnalyzer::handleAssignment(set const& _variables, Expres auto const& referencedVariables = movableChecker.referencedVariables(); for (auto const& name: _variables) { - m_references[name] = referencedVariables; + m_state.references[name] = referencedVariables; if (!_isDeclaration) { // assignment to slot denoted by "name" - m_storage.erase(name); + m_state.storage.erase(name); // assignment to slot contents denoted by "name" - cxx20::erase_if(m_storage, mapTuple([&name](auto&& /* key */, auto&& value) { return value == name; })); + cxx20::erase_if(m_state.storage, mapTuple([&name](auto&& /* key */, auto&& value) { return value == name; })); // assignment to slot denoted by "name" - m_memory.erase(name); + m_state.memory.erase(name); // assignment to slot contents denoted by "name" - cxx20::erase_if(m_memory, mapTuple([&name](auto&& /* key */, auto&& value) { return value == name; })); + cxx20::erase_if(m_state.memory, mapTuple([&name](auto&& /* key */, auto&& value) { return value == name; })); } } @@ -265,9 +279,9 @@ void DataFlowAnalyzer::handleAssignment(set const& _variables, Expres // On the other hand, if we knew the value in the slot // already, then the sload() / mload() would have been replaced by a variable anyway. if (auto key = isSimpleLoad(StoreLoadLocation::Memory, *_value)) - m_memory[*key] = variable; + m_state.memory[*key] = variable; else if (auto key = isSimpleLoad(StoreLoadLocation::Storage, *_value)) - m_storage[*key] = variable; + m_state.storage[*key] = variable; } } } @@ -281,8 +295,8 @@ void DataFlowAnalyzer::popScope() { for (auto const& name: m_variableScopes.back().variables) { - m_value.erase(name); - m_references.erase(name); + m_state.value.erase(name); + m_state.references.erase(name); } m_variableScopes.pop_back(); } @@ -308,44 +322,44 @@ void DataFlowAnalyzer::clearValues(set _variables) auto eraseCondition = mapTuple([&_variables](auto&& key, auto&& value) { return _variables.count(key) || _variables.count(value); }); - cxx20::erase_if(m_storage, eraseCondition); - cxx20::erase_if(m_memory, eraseCondition); + cxx20::erase_if(m_state.storage, eraseCondition); + cxx20::erase_if(m_state.memory, eraseCondition); // Also clear variables that reference variables to be cleared. for (auto const& variableToClear: _variables) - for (auto const& [ref, names]: m_references) + for (auto const& [ref, names]: m_state.references) if (names.count(variableToClear)) _variables.emplace(ref); // Clear the value and update the reference relation. for (auto const& name: _variables) { - m_value.erase(name); - m_references.erase(name); + m_state.value.erase(name); + m_state.references.erase(name); } } void DataFlowAnalyzer::assignValue(YulString _variable, Expression const* _value) { - m_value[_variable] = {_value, m_loopDepth}; + m_state.value[_variable] = {_value, m_loopDepth}; } void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Block const& _block) { SideEffectsCollector sideEffects(m_dialect, _block, &m_functionSideEffects); if (sideEffects.invalidatesStorage()) - m_storage.clear(); + m_state.storage.clear(); if (sideEffects.invalidatesMemory()) - m_memory.clear(); + m_state.memory.clear(); } void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Expression const& _expr) { SideEffectsCollector sideEffects(m_dialect, _expr, &m_functionSideEffects); if (sideEffects.invalidatesStorage()) - m_storage.clear(); + m_state.storage.clear(); if (sideEffects.invalidatesMemory()) - m_memory.clear(); + m_state.memory.clear(); } void DataFlowAnalyzer::joinKnowledge( @@ -353,8 +367,8 @@ void DataFlowAnalyzer::joinKnowledge( unordered_map const& _olderMemory ) { - joinKnowledgeHelper(m_storage, _olderStorage); - joinKnowledgeHelper(m_memory, _olderMemory); + joinKnowledgeHelper(m_state.storage, _olderStorage); + joinKnowledgeHelper(m_state.memory, _olderMemory); } void DataFlowAnalyzer::joinKnowledgeHelper( @@ -364,10 +378,10 @@ void DataFlowAnalyzer::joinKnowledgeHelper( { // We clear if the key does not exist in the older map or if the value is different. // This also works for memory because _older is an "older version" - // of m_memory and thus any overlapping write would have cleared the keys - // that are not known to be different inside m_memory already. + // of m_state.memory and thus any overlapping write would have cleared the keys + // that are not known to be different inside m_state.memory already. cxx20::erase_if(_this, mapTuple([&_older](auto&& key, auto&& currentValue){ - YulString const* oldValue = valueOrNullptr(_older, key); + YulString const* oldValue = util::valueOrNullptr(_older, key); return !oldValue || *oldValue != currentValue; })); } @@ -386,8 +400,8 @@ bool DataFlowAnalyzer::inScope(YulString _variableName) const optional DataFlowAnalyzer::valueOfIdentifier(YulString const& _name) { - if (m_value.count(_name)) - if (Literal const* literal = get_if(m_value.at(_name).value)) + if (AssignedValue const* value = variableValue(_name)) + if (Literal const* literal = get_if(value->value)) return valueOfLiteral(*literal); return nullopt; } diff --git a/libyul/optimiser/DataFlowAnalyzer.h b/libyul/optimiser/DataFlowAnalyzer.h index deaa71f89025..a8463360b13a 100644 --- a/libyul/optimiser/DataFlowAnalyzer.h +++ b/libyul/optimiser/DataFlowAnalyzer.h @@ -29,6 +29,7 @@ #include // Needed for m_zero below. #include +#include #include #include @@ -38,6 +39,7 @@ namespace solidity::yul { struct Dialect; struct SideEffects; +class KnowledgeBase; /// Value assigned to a variable. struct AssignedValue @@ -98,6 +100,13 @@ class DataFlowAnalyzer: public ASTModifier void operator()(ForLoop&) override; void operator()(Block& _block) override; + /// @returns the current value of the given variable, if known - always movable. + AssignedValue const* variableValue(YulString _variable) const { return util::valueOrNullptr(m_state.value, _variable); } + std::set const* references(YulString _variable) const { return util::valueOrNullptr(m_state.references, _variable); } + std::map const& allValues() const { return m_state.value; } + std::optional storageValue(YulString _key) const; + std::optional memoryValue(YulString _key) const; + protected: /// Registers the assignment. void handleAssignment(std::set const& _names, Expression* _value, bool _isDeclaration); @@ -164,14 +173,20 @@ class DataFlowAnalyzer: public ASTModifier /// if this is not provided or the function is not found. std::map m_functionSideEffects; - /// Current values of variables, always movable. - std::map m_value; - /// m_references[a].contains(b) <=> the current expression assigned to a references b - std::unordered_map> m_references; +private: + struct State + { + /// Current values of variables, always movable. + std::map value; + /// m_references[a].contains(b) <=> the current expression assigned to a references b + std::unordered_map> references; - std::unordered_map m_storage; - std::unordered_map m_memory; + std::unordered_map storage; + std::unordered_map memory; + }; + State m_state; +protected: KnowledgeBase m_knowledgeBase; YulString m_storeFunctionName[static_cast(StoreLoadLocation::Last) + 1]; diff --git a/libyul/optimiser/EqualStoreEliminator.cpp b/libyul/optimiser/EqualStoreEliminator.cpp index dcba98ce4f53..542d8d50b322 100644 --- a/libyul/optimiser/EqualStoreEliminator.cpp +++ b/libyul/optimiser/EqualStoreEliminator.cpp @@ -54,13 +54,13 @@ void EqualStoreEliminator::visit(Statement& _statement) { if (auto vars = isSimpleStore(StoreLoadLocation::Storage, *expression)) { - if (auto const* currentValue = valueOrNullptr(m_storage, vars->first)) + if (optional currentValue = storageValue(vars->first)) if (*currentValue == vars->second) m_pendingRemovals.insert(&_statement); } else if (auto vars = isSimpleStore(StoreLoadLocation::Memory, *expression)) { - if (auto const* currentValue = valueOrNullptr(m_memory, vars->first)) + if (optional currentValue = memoryValue(vars->first)) if (*currentValue == vars->second) m_pendingRemovals.insert(&_statement); } diff --git a/libyul/optimiser/ExpressionSimplifier.cpp b/libyul/optimiser/ExpressionSimplifier.cpp index 736ebe4b9356..8c3a038f102c 100644 --- a/libyul/optimiser/ExpressionSimplifier.cpp +++ b/libyul/optimiser/ExpressionSimplifier.cpp @@ -38,6 +38,10 @@ void ExpressionSimplifier::visit(Expression& _expression) { ASTModifier::visit(_expression); - while (auto const* match = SimplificationRules::findFirstMatch(_expression, m_dialect, m_value)) + while (auto const* match = SimplificationRules::findFirstMatch( + _expression, + m_dialect, + [this](YulString _var) { return variableValue(_var); } + )) _expression = match->action().toExpression(debugDataOf(_expression)); } diff --git a/libyul/optimiser/KnowledgeBase.cpp b/libyul/optimiser/KnowledgeBase.cpp index 5b5c07ddad88..460f6707ff13 100644 --- a/libyul/optimiser/KnowledgeBase.cpp +++ b/libyul/optimiser/KnowledgeBase.cpp @@ -80,8 +80,8 @@ bool KnowledgeBase::knownToBeZero(YulString _a) optional KnowledgeBase::valueIfKnownConstant(YulString _a) { - if (m_variableValues.count(_a)) - if (Literal const* literal = get_if(m_variableValues.at(_a).value)) + if (AssignedValue const* value = m_variableValues(_a)) + if (Literal const* literal = get_if(value->value)) return valueOfLiteral(*literal); return {}; } diff --git a/libyul/optimiser/KnowledgeBase.h b/libyul/optimiser/KnowledgeBase.h index 75e060eb1b1d..999d0e312bc4 100644 --- a/libyul/optimiser/KnowledgeBase.h +++ b/libyul/optimiser/KnowledgeBase.h @@ -28,6 +28,7 @@ #include #include +#include namespace solidity::yul { @@ -37,15 +38,16 @@ struct AssignedValue; /** * Class that can answer questions about values of variables and their relations. - * - * The reference to the map of values provided at construction is assumed to be updating. */ class KnowledgeBase { public: - KnowledgeBase(Dialect const& _dialect, std::map const& _variableValues): + KnowledgeBase( + Dialect const& _dialect, + std::function _variableValues + ): m_dialect(_dialect), - m_variableValues(_variableValues) + m_variableValues(std::move(_variableValues)) {} bool knownToBeDifferent(YulString _a, YulString _b); @@ -60,7 +62,7 @@ class KnowledgeBase Expression simplifyRecursively(Expression _expression); Dialect const& m_dialect; - std::map const& m_variableValues; + std::function m_variableValues; size_t m_counter = 0; }; diff --git a/libyul/optimiser/LoadResolver.cpp b/libyul/optimiser/LoadResolver.cpp index 550ca6fb369a..abcfbaabb869 100644 --- a/libyul/optimiser/LoadResolver.cpp +++ b/libyul/optimiser/LoadResolver.cpp @@ -82,12 +82,12 @@ void LoadResolver::tryResolve( YulString key = std::get(_arguments.at(0)).name; if (_location == StoreLoadLocation::Storage) { - if (auto value = util::valueOrNullptr(m_storage, key)) + if (auto value = storageValue(key)) if (inScope(*value)) _e = Identifier{debugDataOf(_e), *value}; } else if (!m_containsMSize && _location == StoreLoadLocation::Memory) - if (auto value = util::valueOrNullptr(m_memory, key)) + if (auto value = memoryValue(key)) if (inScope(*value)) _e = Identifier{debugDataOf(_e), *value}; } @@ -129,10 +129,10 @@ void LoadResolver::tryEvaluateKeccak( if (costOfLiteral > costOfKeccak) return; - auto memoryValue = util::valueOrNullptr(m_memory, memoryKey->name); - if (memoryValue && inScope(*memoryValue)) + optional value = memoryValue(memoryKey->name); + if (value && inScope(*value)) { - optional memoryContent = valueOfIdentifier(*memoryValue); + optional memoryContent = valueOfIdentifier(*value); optional byteLength = valueOfIdentifier(length->name); if (memoryContent && byteLength && *byteLength <= 32) { diff --git a/libyul/optimiser/NameCollector.cpp b/libyul/optimiser/NameCollector.cpp index eca509f43c62..c2a82d494645 100644 --- a/libyul/optimiser/NameCollector.cpp +++ b/libyul/optimiser/NameCollector.cpp @@ -30,18 +30,22 @@ using namespace solidity::util; void NameCollector::operator()(VariableDeclaration const& _varDecl) { - for (auto const& var: _varDecl.variables) - m_names.emplace(var.name); + if (m_collectWhat != OnlyFunctions) + for (auto const& var: _varDecl.variables) + m_names.emplace(var.name); } -void NameCollector::operator ()(FunctionDefinition const& _funDef) +void NameCollector::operator()(FunctionDefinition const& _funDef) { - if (m_collectWhat == VariablesAndFunctions) + if (m_collectWhat != OnlyVariables) m_names.emplace(_funDef.name); - for (auto const& arg: _funDef.parameters) - m_names.emplace(arg.name); - for (auto const& ret: _funDef.returnVariables) - m_names.emplace(ret.name); + if (m_collectWhat != OnlyFunctions) + { + for (auto const& arg: _funDef.parameters) + m_names.emplace(arg.name); + for (auto const& ret: _funDef.returnVariables) + m_names.emplace(ret.name); + } ASTWalker::operator ()(_funDef); } diff --git a/libyul/optimiser/NameCollector.h b/libyul/optimiser/NameCollector.h index 8c9dc14ff859..34dd5f9b3007 100644 --- a/libyul/optimiser/NameCollector.h +++ b/libyul/optimiser/NameCollector.h @@ -35,7 +35,7 @@ namespace solidity::yul class NameCollector: public ASTWalker { public: - enum CollectWhat { VariablesAndFunctions, OnlyVariables }; + enum CollectWhat { VariablesAndFunctions, OnlyVariables, OnlyFunctions }; explicit NameCollector( Block const& _block, diff --git a/libyul/optimiser/Rematerialiser.cpp b/libyul/optimiser/Rematerialiser.cpp index f1597a7f2057..7dff1df80f30 100644 --- a/libyul/optimiser/Rematerialiser.cpp +++ b/libyul/optimiser/Rematerialiser.cpp @@ -37,16 +37,6 @@ void Rematerialiser::run(Dialect const& _dialect, Block& _ast, set _v Rematerialiser{_dialect, _ast, std::move(_varsToAlwaysRematerialize), _onlySelectedVariables}(_ast); } -void Rematerialiser::run( - Dialect const& _dialect, - FunctionDefinition& _function, - set _varsToAlwaysRematerialize, - bool _onlySelectedVariables -) -{ - Rematerialiser{_dialect, _function, std::move(_varsToAlwaysRematerialize), _onlySelectedVariables}(_function); -} - Rematerialiser::Rematerialiser( Dialect const& _dialect, Block& _ast, @@ -60,35 +50,21 @@ Rematerialiser::Rematerialiser( { } -Rematerialiser::Rematerialiser( - Dialect const& _dialect, - FunctionDefinition& _function, - set _varsToAlwaysRematerialize, - bool _onlySelectedVariables -): - DataFlowAnalyzer(_dialect), - m_referenceCounts(ReferencesCounter::countReferences(_function)), - m_varsToAlwaysRematerialize(std::move(_varsToAlwaysRematerialize)), - m_onlySelectedVariables(_onlySelectedVariables) -{ -} - void Rematerialiser::visit(Expression& _e) { if (holds_alternative(_e)) { Identifier& identifier = std::get(_e); YulString name = identifier.name; - if (m_value.count(name)) + if (AssignedValue const* value = variableValue(name)) { - assertThrow(m_value.at(name).value, OptimizerException, ""); - AssignedValue const& value = m_value.at(name); + assertThrow(value->value, OptimizerException, ""); size_t refs = m_referenceCounts[name]; - size_t cost = CodeCost::codeCost(m_dialect, *value.value); + size_t cost = CodeCost::codeCost(m_dialect, *value->value); if ( ( !m_onlySelectedVariables && ( - (refs <= 1 && value.loopDepth == m_loopDepth) || + (refs <= 1 && value->loopDepth == m_loopDepth) || cost == 0 || (refs <= 5 && cost <= 1 && m_loopDepth == 0) ) @@ -96,13 +72,14 @@ void Rematerialiser::visit(Expression& _e) ) { assertThrow(m_referenceCounts[name] > 0, OptimizerException, ""); - if (ranges::all_of(m_references[name], [&](auto const& ref) { return inScope(ref); })) + auto variableReferences = references(name); + if (!variableReferences || ranges::all_of(*variableReferences, [&](auto const& ref) { return inScope(ref); })) { // update reference counts m_referenceCounts[name]--; - for (auto const& ref: ReferencesCounter::countReferences(*value.value)) + for (auto const& ref: ReferencesCounter::countReferences(*value->value)) m_referenceCounts[ref.first] += ref.second; - _e = (ASTCopier{}).translate(*value.value); + _e = (ASTCopier{}).translate(*value->value); } } } @@ -116,12 +93,11 @@ void LiteralRematerialiser::visit(Expression& _e) { Identifier& identifier = std::get(_e); YulString name = identifier.name; - if (m_value.count(name)) + if (AssignedValue const* value = variableValue(name)) { - Expression const* value = m_value.at(name).value; - assertThrow(value, OptimizerException, ""); - if (holds_alternative(*value)) - _e = *value; + assertThrow(value->value, OptimizerException, ""); + if (holds_alternative(*value->value)) + _e = *value->value; } } DataFlowAnalyzer::visit(_e); diff --git a/libyul/optimiser/Rematerialiser.h b/libyul/optimiser/Rematerialiser.h index d1ebb1595132..592f79d1be89 100644 --- a/libyul/optimiser/Rematerialiser.h +++ b/libyul/optimiser/Rematerialiser.h @@ -53,12 +53,6 @@ class Rematerialiser: public DataFlowAnalyzer std::set _varsToAlwaysRematerialize = {}, bool _onlySelectedVariables = false ); - static void run( - Dialect const& _dialect, - FunctionDefinition& _function, - std::set _varsToAlwaysRematerialize = {}, - bool _onlySelectedVariables = false - ); protected: Rematerialiser( @@ -67,12 +61,6 @@ class Rematerialiser: public DataFlowAnalyzer std::set _varsToAlwaysRematerialize = {}, bool _onlySelectedVariables = false ); - Rematerialiser( - Dialect const& _dialect, - FunctionDefinition& _function, - std::set _varsToAlwaysRematerialize = {}, - bool _onlySelectedVariables = false - ); using DataFlowAnalyzer::operator(); diff --git a/libyul/optimiser/SimplificationRules.cpp b/libyul/optimiser/SimplificationRules.cpp index 3e906fcdff26..9d0144750dd3 100644 --- a/libyul/optimiser/SimplificationRules.cpp +++ b/libyul/optimiser/SimplificationRules.cpp @@ -41,7 +41,7 @@ using namespace solidity::yul; SimplificationRules::Rule const* SimplificationRules::findFirstMatch( Expression const& _expr, Dialect const& _dialect, - map const& _ssaValues + function const& _ssaValues ) { auto instruction = instructionAndArguments(_dialect, _expr); @@ -138,7 +138,7 @@ void Pattern::setMatchGroup(unsigned _group, map& _ bool Pattern::matches( Expression const& _expr, Dialect const& _dialect, - map const& _ssaValues + function const& _ssaValues ) const { Expression const* expr = &_expr; @@ -148,8 +148,8 @@ bool Pattern::matches( if (m_kind != PatternKind::Any && holds_alternative(_expr)) { YulString varName = std::get(_expr).name; - if (_ssaValues.count(varName)) - if (Expression const* new_expr = _ssaValues.at(varName).value) + if (AssignedValue const* value = _ssaValues(varName)) + if (Expression const* new_expr = value->value) expr = new_expr; } assertThrow(expr, OptimizerException, ""); diff --git a/libyul/optimiser/SimplificationRules.h b/libyul/optimiser/SimplificationRules.h index 77018bb3809c..7444c47fb87a 100644 --- a/libyul/optimiser/SimplificationRules.h +++ b/libyul/optimiser/SimplificationRules.h @@ -62,7 +62,7 @@ class SimplificationRules static Rule const* findFirstMatch( Expression const& _expr, Dialect const& _dialect, - std::map const& _ssaValues + std::function const& _ssaValues ); /// Checks whether the rulelist is non-empty. This is usually enforced @@ -119,7 +119,7 @@ class Pattern bool matches( Expression const& _expr, Dialect const& _dialect, - std::map const& _ssaValues + std::function const& _ssaValues ) const; std::vector arguments() const { return m_arguments; } diff --git a/libyul/optimiser/StackCompressor.cpp b/libyul/optimiser/StackCompressor.cpp index 2deef5234a4d..b3402e4d7b6b 100644 --- a/libyul/optimiser/StackCompressor.cpp +++ b/libyul/optimiser/StackCompressor.cpp @@ -50,41 +50,51 @@ namespace /** * Class that discovers all variables that can be fully eliminated by rematerialization, * and the corresponding approximate costs. + * + * Prerequisite: Disambiguator, Function Grouper */ class RematCandidateSelector: public DataFlowAnalyzer { public: explicit RematCandidateSelector(Dialect const& _dialect): DataFlowAnalyzer(_dialect) {} - /// @returns a map from rematerialisation costs to a vector of variables to rematerialise + /// @returns a map from function name to rematerialisation costs to a vector of variables to rematerialise /// and variables that occur in their expression. /// While the map is sorted by cost, the contained vectors are sorted by the order of occurrence. - map>>> candidates() + map>> candidates() { - map>>> cand; - for (auto const& candidate: m_candidates) + map>> cand; + for (auto const& [functionName, candidate]: m_candidates) { if (size_t const* cost = util::valueOrNullptr(m_expressionCodeCost, candidate)) { size_t numRef = m_numReferences[candidate]; - cand[*cost * numRef].emplace_back(candidate, m_references[candidate]); + cand[functionName][*cost * numRef].emplace_back(candidate); } } return cand; } using DataFlowAnalyzer::operator(); + void operator()(FunctionDefinition& _function) override + { + yulAssert(m_currentFunctionName.empty()); + m_currentFunctionName = _function.name; + DataFlowAnalyzer::operator()(_function); + m_currentFunctionName = {}; + } + void operator()(VariableDeclaration& _varDecl) override { DataFlowAnalyzer::operator()(_varDecl); if (_varDecl.variables.size() == 1) { YulString varName = _varDecl.variables.front().name; - if (m_value.count(varName)) + if (AssignedValue const* value = variableValue(varName)) { yulAssert(!m_expressionCodeCost.count(varName), ""); - m_candidates.emplace_back(varName); - m_expressionCodeCost[varName] = CodeCost::codeCost(m_dialect, *m_value[varName].value); + m_candidates.emplace_back(m_currentFunctionName, varName); + m_expressionCodeCost[varName] = CodeCost::codeCost(m_dialect, *value->value); } } } @@ -105,7 +115,7 @@ class RematCandidateSelector: public DataFlowAnalyzer YulString name = std::get(_e).name; if (m_expressionCodeCost.count(name)) { - if (!m_value.count(name)) + if (!variableValue(name)) rematImpossible(name); else ++m_numReferences[name]; @@ -121,8 +131,10 @@ class RematCandidateSelector: public DataFlowAnalyzer m_expressionCodeCost.erase(_variable); } - /// All candidate variables in order of occurrence. - vector m_candidates; + YulString m_currentFunctionName = {}; + + /// All candidate variables by function name, in order of occurrence. + vector> m_candidates; /// Candidate variables and the code cost of their value. map m_expressionCodeCost; /// Number of references to each candidate variable. @@ -131,86 +143,95 @@ class RematCandidateSelector: public DataFlowAnalyzer /// Selects at most @a _numVariables among @a _candidates. set chooseVarsToEliminate( - map>>> const& _candidates, + map> const& _candidates, size_t _numVariables ) { set varsToEliminate; for (auto&& [cost, candidates]: _candidates) - for (auto&& [candidate, references]: candidates) + for (auto&& candidate: candidates) { if (varsToEliminate.size() >= _numVariables) return varsToEliminate; - // If a variable we would like to eliminate references another one - // we already selected for elimination, then stop selecting - // candidates. If we would add that variable, then the cost calculation - // for the previous variable would be off. Furthermore, we - // do not skip the variable because it would be better to properly re-compute - // the costs of all other variables instead. - for (YulString const& referencedVar: references) - if (varsToEliminate.count(referencedVar)) - return varsToEliminate; varsToEliminate.insert(candidate); } return varsToEliminate; } -template void eliminateVariables( Dialect const& _dialect, - ASTNode& _node, - size_t _numVariables, + Block& _ast, + map const& _numVariables, bool _allowMSizeOptimization ) { RematCandidateSelector selector{_dialect}; - selector(_node); - Rematerialiser::run(_dialect, _node, chooseVarsToEliminate(selector.candidates(), _numVariables)); - UnusedPruner::runUntilStabilised(_dialect, _node, _allowMSizeOptimization); + selector(_ast); + map>> candidates = selector.candidates(); + + set varsToEliminate; + for (auto const& [functionName, numVariables]: _numVariables) + { + yulAssert(numVariables > 0); + varsToEliminate += chooseVarsToEliminate(candidates[functionName], static_cast(numVariables)); + } + + Rematerialiser::run(_dialect, _ast, move(varsToEliminate)); + // Do not remove functions. + set allFunctions = NameCollector{_ast, NameCollector::OnlyFunctions}.names(); + UnusedPruner::runUntilStabilised(_dialect, _ast, _allowMSizeOptimization, nullptr, allFunctions); } -void eliminateVariables( +void eliminateVariablesOptimizedCodegen( Dialect const& _dialect, - Block& _block, - vector const& _unreachables, + Block& _ast, + map> const& _unreachables, bool _allowMSizeOptimization ) { + if (std::all_of(_unreachables.begin(), _unreachables.end(), [](auto const& _item) { return _item.second.empty(); })) + return; + RematCandidateSelector selector{_dialect}; - selector(_block); - std::map candidates; - for (auto [cost, candidatesWithCost]: selector.candidates()) - for (auto candidate: candidatesWithCost) - candidates[get<0>(candidate)] = cost; + selector(_ast); + + map candidates; + for (auto const& [functionName, candidatesInFunction]: selector.candidates()) + for (auto [cost, candidatesWithCost]: candidatesInFunction) + for (auto candidate: candidatesWithCost) + candidates[candidate] = cost; set varsToEliminate; // TODO: this currently ignores the fact that variables may reference other variables we want to eliminate. - for (auto const& unreachable: _unreachables) - { - map> suitableCandidates; - size_t neededSlots = unreachable.deficit; - for (auto varName: unreachable.variableChoices) - { - if (varsToEliminate.count(varName)) - --neededSlots; - else if (size_t* cost = util::valueOrNullptr(candidates, varName)) - if (!util::contains(suitableCandidates[*cost], varName)) - suitableCandidates[*cost].emplace_back(varName); - } - for (auto candidatesByCost: suitableCandidates) + for (auto const& [functionName, unreachables]: _unreachables) + for (auto const& unreachable: unreachables) { - for (auto candidate: candidatesByCost.second) - if (neededSlots--) - varsToEliminate.emplace(candidate); - else + map> suitableCandidates; + size_t neededSlots = unreachable.deficit; + for (auto varName: unreachable.variableChoices) + { + if (varsToEliminate.count(varName)) + --neededSlots; + else if (size_t* cost = util::valueOrNullptr(candidates, varName)) + if (!util::contains(suitableCandidates[*cost], varName)) + suitableCandidates[*cost].emplace_back(varName); + } + for (auto candidatesByCost: suitableCandidates) + { + for (auto candidate: candidatesByCost.second) + if (neededSlots--) + varsToEliminate.emplace(candidate); + else + break; + if (!neededSlots) break; - if (!neededSlots) - break; + } } - } - Rematerialiser::run(_dialect, _block, std::move(varsToEliminate), true); - UnusedPruner::runUntilStabilised(_dialect, _block, _allowMSizeOptimization); + Rematerialiser::run(_dialect, _ast, std::move(varsToEliminate), true); + // Do not remove functions. + set allFunctions = NameCollector{_ast, NameCollector::OnlyFunctions}.names(); + UnusedPruner::runUntilStabilised(_dialect, _ast, _allowMSizeOptimization, nullptr, allFunctions); } } @@ -238,21 +259,12 @@ bool StackCompressor::run( { yul::AsmAnalysisInfo analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(_dialect, _object); unique_ptr cfg = ControlFlowGraphBuilder::build(analysisInfo, _dialect, *_object.code); - Block& mainBlock = std::get(_object.code->statements.at(0)); - if ( - auto stackTooDeepErrors = StackLayoutGenerator::reportStackTooDeep(*cfg, YulString{}); - !stackTooDeepErrors.empty() - ) - eliminateVariables(_dialect, mainBlock, stackTooDeepErrors, allowMSizeOptimzation); - for (size_t i = 1; i < _object.code->statements.size(); ++i) - { - auto& fun = std::get(_object.code->statements[i]); - if ( - auto stackTooDeepErrors = StackLayoutGenerator::reportStackTooDeep(*cfg, fun.name); - !stackTooDeepErrors.empty() - ) - eliminateVariables(_dialect, fun.body, stackTooDeepErrors, allowMSizeOptimzation); - } + eliminateVariablesOptimizedCodegen( + _dialect, + *_object.code, + StackLayoutGenerator::reportStackTooDeep(*cfg), + allowMSizeOptimzation + ); } else for (size_t iterations = 0; iterations < _maxIterations; iterations++) @@ -260,32 +272,12 @@ bool StackCompressor::run( map stackSurplus = CompilabilityChecker(_dialect, _object, _optimizeStackAllocation).stackDeficit; if (stackSurplus.empty()) return true; - - if (stackSurplus.count(YulString{})) - { - yulAssert(stackSurplus.at({}) > 0, "Invalid surplus value."); - eliminateVariables( - _dialect, - std::get(_object.code->statements.at(0)), - static_cast(stackSurplus.at({})), - allowMSizeOptimzation - ); - } - - for (size_t i = 1; i < _object.code->statements.size(); ++i) - { - auto& fun = std::get(_object.code->statements[i]); - if (!stackSurplus.count(fun.name)) - continue; - - yulAssert(stackSurplus.at(fun.name) > 0, "Invalid surplus value."); - eliminateVariables( - _dialect, - fun, - static_cast(stackSurplus.at(fun.name)), - allowMSizeOptimzation - ); - } + eliminateVariables( + _dialect, + *_object.code, + stackSurplus, + allowMSizeOptimzation + ); } return false; } diff --git a/libyul/optimiser/StructuralSimplifier.cpp b/libyul/optimiser/StructuralSimplifier.cpp index 5b1ae2550a72..ca8f942392c4 100644 --- a/libyul/optimiser/StructuralSimplifier.cpp +++ b/libyul/optimiser/StructuralSimplifier.cpp @@ -55,6 +55,30 @@ OptionalStatements replaceConstArgSwitch(Switch& _switchStmt, u256 const& _const return optional>{vector{}}; } +optional hasLiteralValue(Expression const& _expression) +{ + if (holds_alternative(_expression)) + return valueOfLiteral(std::get(_expression)); + else + return std::optional(); +} + +bool expressionAlwaysTrue(Expression const& _expression) +{ + if (std::optional value = hasLiteralValue(_expression)) + return *value != 0; + else + return false; +} + +bool expressionAlwaysFalse(Expression const& _expression) +{ + if (std::optional value = hasLiteralValue(_expression)) + return *value == 0; + else + return false; +} + } void StructuralSimplifier::run(OptimiserStepContext&, Block& _ast) @@ -103,27 +127,3 @@ void StructuralSimplifier::simplify(std::vector& _statements) } ); } - -bool StructuralSimplifier::expressionAlwaysTrue(Expression const& _expression) -{ - if (std::optional value = hasLiteralValue(_expression)) - return *value != 0; - else - return false; -} - -bool StructuralSimplifier::expressionAlwaysFalse(Expression const& _expression) -{ - if (std::optional value = hasLiteralValue(_expression)) - return *value == 0; - else - return false; -} - -std::optional StructuralSimplifier::hasLiteralValue(Expression const& _expression) const -{ - if (holds_alternative(_expression)) - return valueOfLiteral(std::get(_expression)); - else - return std::optional(); -} diff --git a/libyul/optimiser/StructuralSimplifier.h b/libyul/optimiser/StructuralSimplifier.h index 3fd59efde42c..734b2e53af8e 100644 --- a/libyul/optimiser/StructuralSimplifier.h +++ b/libyul/optimiser/StructuralSimplifier.h @@ -18,7 +18,6 @@ #pragma once #include -#include #include #include @@ -50,9 +49,6 @@ class StructuralSimplifier: public ASTModifier StructuralSimplifier() = default; void simplify(std::vector& _statements); - bool expressionAlwaysTrue(Expression const& _expression); - bool expressionAlwaysFalse(Expression const& _expression); - std::optional hasLiteralValue(Expression const& _expression) const; }; } diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp index 0f2194061308..181c9bdcbae4 100644 --- a/libyul/optimiser/Suite.cpp +++ b/libyul/optimiser/Suite.cpp @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -222,6 +223,7 @@ map> const& OptimiserSuite::allSteps() LoadResolver, LoopInvariantCodeMotion, UnusedAssignEliminator, + UnusedStoreEliminator, ReasoningBasedSimplifier, Rematerialiser, SSAReverser, @@ -264,6 +266,7 @@ map const& OptimiserSuite::stepNameToAbbreviationMap() {LoopInvariantCodeMotion::name, 'M'}, {ReasoningBasedSimplifier::name, 'R'}, {UnusedAssignEliminator::name, 'r'}, + {UnusedStoreEliminator::name, 'S'}, {Rematerialiser::name, 'm'}, {SSAReverser::name, 'V'}, {SSATransform::name, 'a'}, diff --git a/libyul/optimiser/UnusedStoreEliminator.cpp b/libyul/optimiser/UnusedStoreEliminator.cpp new file mode 100644 index 000000000000..343bd720a1b1 --- /dev/null +++ b/libyul/optimiser/UnusedStoreEliminator.cpp @@ -0,0 +1,379 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +/** + * Optimiser component that removes stores to memory and storage slots that are not used + * or overwritten later on. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +using namespace std; +using namespace solidity; +using namespace solidity::yul; + +/// Variable names for special constants that can never appear in actual Yul code. +static string const zero{"@ 0"}; +static string const one{"@ 1"}; +static string const thirtyTwo{"@ 32"}; + + +void UnusedStoreEliminator::run(OptimiserStepContext& _context, Block& _ast) +{ + map functionSideEffects = SideEffectsPropagator::sideEffects( + _context.dialect, + CallGraphGenerator::callGraph(_ast) + ); + + SSAValueTracker ssaValues; + ssaValues(_ast); + map values; + for (auto const& [name, expression]: ssaValues.values()) + values[name] = AssignedValue{expression, {}}; + Expression const zeroLiteral{Literal{{}, LiteralKind::Number, YulString{"0"}, {}}}; + Expression const oneLiteral{Literal{{}, LiteralKind::Number, YulString{"1"}, {}}}; + Expression const thirtyTwoLiteral{Literal{{}, LiteralKind::Number, YulString{"32"}, {}}}; + values[YulString{zero}] = AssignedValue{&zeroLiteral, {}}; + values[YulString{one}] = AssignedValue{&oneLiteral, {}}; + values[YulString{thirtyTwo}] = AssignedValue{&thirtyTwoLiteral, {}}; + + bool const ignoreMemory = MSizeFinder::containsMSize(_context.dialect, _ast); + UnusedStoreEliminator rse{ + _context.dialect, + functionSideEffects, + ControlFlowSideEffectsCollector{_context.dialect, _ast}.functionSideEffectsNamed(), + values, + ignoreMemory + }; + rse(_ast); + rse.changeUndecidedTo(State::Unused, Location::Memory); + rse.changeUndecidedTo(State::Used, Location::Storage); + rse.scheduleUnusedForDeletion(); + + StatementRemover remover(rse.m_pendingRemovals); + remover(_ast); +} + +void UnusedStoreEliminator::operator()(FunctionCall const& _functionCall) +{ + UnusedStoreBase::operator()(_functionCall); + + for (Operation const& op: operationsFromFunctionCall(_functionCall)) + applyOperation(op); + + ControlFlowSideEffects sideEffects; + if (auto builtin = m_dialect.builtin(_functionCall.functionName.name)) + sideEffects = builtin->controlFlowSideEffects; + else + sideEffects = m_controlFlowSideEffects.at(_functionCall.functionName.name); + + if (!sideEffects.canContinue) + { + changeUndecidedTo(State::Unused, Location::Memory); + changeUndecidedTo(sideEffects.canTerminate ? State::Used : State::Unused, Location::Storage); + } +} + +void UnusedStoreEliminator::operator()(FunctionDefinition const& _functionDefinition) +{ + ScopedSaveAndRestore storeOperations(m_storeOperations, {}); + UnusedStoreBase::operator()(_functionDefinition); +} + + +void UnusedStoreEliminator::operator()(Leave const&) +{ + changeUndecidedTo(State::Used); +} + +void UnusedStoreEliminator::visit(Statement const& _statement) +{ + using evmasm::Instruction; + + UnusedStoreBase::visit(_statement); + + auto const* exprStatement = get_if(&_statement); + if (!exprStatement) + return; + + FunctionCall const* funCall = get_if(&exprStatement->expression); + yulAssert(funCall); + optional instruction = toEVMInstruction(m_dialect, funCall->functionName.name); + if (!instruction) + return; + + if (!ranges::all_of(funCall->arguments, [](Expression const& _expr) -> bool { + return get_if(&_expr) || get_if(&_expr); + })) + return; + + // We determine if this is a store instruction without additional side-effects + // both by querying a combination of semantic information and by listing the instructions. + // This way the assert below should be triggered on any change. + using evmasm::SemanticInformation; + bool isStorageWrite = (*instruction == Instruction::SSTORE); + bool isMemoryWrite = + *instruction == Instruction::EXTCODECOPY || + *instruction == Instruction::CODECOPY || + *instruction == Instruction::CALLDATACOPY || + *instruction == Instruction::RETURNDATACOPY || + *instruction == Instruction::MSTORE || + *instruction == Instruction::MSTORE8; + bool isCandidateForRemoval = + SemanticInformation::otherState(*instruction) != SemanticInformation::Write && ( + SemanticInformation::storage(*instruction) == SemanticInformation::Write || + (!m_ignoreMemory && SemanticInformation::memory(*instruction) == SemanticInformation::Write) + ); + yulAssert(isCandidateForRemoval == (isStorageWrite || (!m_ignoreMemory && isMemoryWrite))); + if (isCandidateForRemoval) + { + m_stores[YulString{}].insert({&_statement, State::Undecided}); + vector operations = operationsFromFunctionCall(*funCall); + yulAssert(operations.size() == 1, ""); + m_storeOperations[&_statement] = move(operations.front()); + } +} + +void UnusedStoreEliminator::finalizeFunctionDefinition(FunctionDefinition const&) +{ + changeUndecidedTo(State::Used); + scheduleUnusedForDeletion(); +} + +vector UnusedStoreEliminator::operationsFromFunctionCall( + FunctionCall const& _functionCall +) const +{ + using evmasm::Instruction; + + YulString functionName = _functionCall.functionName.name; + SideEffects sideEffects; + if (BuiltinFunction const* f = m_dialect.builtin(functionName)) + sideEffects = f->sideEffects; + else + sideEffects = m_functionSideEffects.at(functionName); + + optional instruction = toEVMInstruction(m_dialect, functionName); + if (!instruction) + { + vector result; + // Unknown read is worse than unknown write. + if (sideEffects.memory != SideEffects::Effect::None) + result.emplace_back(Operation{Location::Memory, Effect::Read, {}, {}}); + if (sideEffects.storage != SideEffects::Effect::None) + result.emplace_back(Operation{Location::Storage, Effect::Read, {}, {}}); + return result; + } + + using evmasm::SemanticInformation; + + return util::applyMap( + SemanticInformation::readWriteOperations(*instruction), + [&](SemanticInformation::Operation const& _op) -> Operation + { + yulAssert(!(_op.lengthParameter && _op.lengthConstant)); + yulAssert(_op.effect != Effect::None); + Operation ourOp{_op.location, _op.effect, {}, {}}; + if (_op.startParameter) + ourOp.start = identifierNameIfSSA(_functionCall.arguments.at(*_op.startParameter)); + if (_op.lengthParameter) + ourOp.length = identifierNameIfSSA(_functionCall.arguments.at(*_op.lengthParameter)); + if (_op.lengthConstant) + switch (*_op.lengthConstant) + { + case 1: ourOp.length = YulString(one); break; + case 32: ourOp.length = YulString(thirtyTwo); break; + default: yulAssert(false); + } + return ourOp; + } + ); +} + +void UnusedStoreEliminator::applyOperation(UnusedStoreEliminator::Operation const& _operation) +{ + for (auto& [statement, state]: m_stores[YulString{}]) + if (state == State::Undecided) + { + Operation const& storeOperation = m_storeOperations.at(statement); + if (_operation.effect == Effect::Read && !knownUnrelated(storeOperation, _operation)) + state = State::Used; + else if (_operation.effect == Effect::Write && knownCovered(storeOperation, _operation)) + state = State::Unused; + } +} + +bool UnusedStoreEliminator::knownUnrelated( + UnusedStoreEliminator::Operation const& _op1, + UnusedStoreEliminator::Operation const& _op2 +) const +{ + KnowledgeBase knowledge(m_dialect, [this](YulString _var) { return util::valueOrNullptr(m_ssaValues, _var); }); + + if (_op1.location != _op2.location) + return true; + if (_op1.location == Location::Storage) + { + if (_op1.start && _op2.start) + { + yulAssert( + _op1.length && + _op2.length && + knowledge.valueIfKnownConstant(*_op1.length) == 1 && + knowledge.valueIfKnownConstant(*_op2.length) == 1 + ); + return knowledge.knownToBeDifferent(*_op1.start, *_op2.start); + } + } + else + { + yulAssert(_op1.location == Location::Memory, ""); + if ( + (_op1.length && knowledge.knownToBeZero(*_op1.length)) || + (_op2.length && knowledge.knownToBeZero(*_op2.length)) + ) + return true; + + if (_op1.start && _op1.length && _op2.start) + { + optional length1 = knowledge.valueIfKnownConstant(*_op1.length); + optional start1 = knowledge.valueIfKnownConstant(*_op1.start); + optional start2 = knowledge.valueIfKnownConstant(*_op2.start); + if ( + (length1 && start1 && start2) && + *start1 + *length1 >= *start1 && // no overflow + *start1 + *length1 <= *start2 + ) + return true; + } + if (_op2.start && _op2.length && _op1.start) + { + optional length2 = knowledge.valueIfKnownConstant(*_op2.length); + optional start2 = knowledge.valueIfKnownConstant(*_op2.start); + optional start1 = knowledge.valueIfKnownConstant(*_op1.start); + if ( + (length2 && start2 && start1) && + *start2 + *length2 >= *start2 && // no overflow + *start2 + *length2 <= *start1 + ) + return true; + } + + if (_op1.start && _op1.length && _op2.start && _op2.length) + { + optional length1 = knowledge.valueIfKnownConstant(*_op1.length); + optional length2 = knowledge.valueIfKnownConstant(*_op2.length); + if ( + (length1 && *length1 <= 32) && + (length2 && *length2 <= 32) && + knowledge.knownToBeDifferentByAtLeast32(*_op1.start, *_op2.start) + ) + return true; + } + } + + return false; +} + +bool UnusedStoreEliminator::knownCovered( + UnusedStoreEliminator::Operation const& _covered, + UnusedStoreEliminator::Operation const& _covering +) const +{ + if (_covered.location != _covering.location) + return false; + if ( + (_covered.start && _covered.start == _covering.start) && + (_covered.length && _covered.length == _covering.length) + ) + return true; + if (_covered.location == Location::Memory) + { + KnowledgeBase knowledge(m_dialect, [this](YulString _var) { return util::valueOrNullptr(m_ssaValues, _var); }); + + if (_covered.length && knowledge.knownToBeZero(*_covered.length)) + return true; + + // Condition (i = cover_i_ng, e = cover_e_d): + // i.start <= e.start && e.start + e.length <= i.start + i.length + if (!_covered.start || !_covering.start || !_covered.length || !_covering.length) + return false; + optional coveredLength = knowledge.valueIfKnownConstant(*_covered.length); + optional coveringLength = knowledge.valueIfKnownConstant(*_covering.length); + if (knowledge.knownToBeEqual(*_covered.start, *_covering.start)) + if (coveredLength && coveringLength && *coveredLength <= *coveringLength) + return true; + optional coveredStart = knowledge.valueIfKnownConstant(*_covered.start); + optional coveringStart = knowledge.valueIfKnownConstant(*_covering.start); + if (coveredStart && coveringStart && coveredLength && coveringLength) + if ( + *coveringStart <= *coveredStart && + *coveringStart + *coveringLength >= *coveringStart && // no overflow + *coveredStart + *coveredLength >= *coveredStart && // no overflow + *coveredStart + *coveredLength <= *coveringStart + *coveringLength + ) + return true; + + // TODO for this we probably need a non-overflow assumption as above. + // Condition (i = cover_i_ng, e = cover_e_d): + // i.start <= e.start && e.start + e.length <= i.start + i.length + } + return false; +} + +void UnusedStoreEliminator::changeUndecidedTo( + State _newState, + optional _onlyLocation) +{ + for (auto& [statement, state]: m_stores[YulString{}]) + if ( + state == State::Undecided && + (_onlyLocation == nullopt || *_onlyLocation == m_storeOperations.at(statement).location) + ) + state = _newState; +} + +optional UnusedStoreEliminator::identifierNameIfSSA(Expression const& _expression) const +{ + if (Identifier const* identifier = get_if(&_expression)) + if (m_ssaValues.count(identifier->name)) + return {identifier->name}; + return nullopt; +} + +void UnusedStoreEliminator::scheduleUnusedForDeletion() +{ + for (auto const& [statement, state]: m_stores[YulString{}]) + if (state == State::Unused) + m_pendingRemovals.insert(statement); +} diff --git a/libyul/optimiser/UnusedStoreEliminator.h b/libyul/optimiser/UnusedStoreEliminator.h new file mode 100644 index 000000000000..dc3065e45b01 --- /dev/null +++ b/libyul/optimiser/UnusedStoreEliminator.h @@ -0,0 +1,119 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +/** + * Optimiser component that removes stores to memory and storage slots that are not used + * or overwritten later on. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include +#include + +namespace solidity::yul +{ +struct Dialect; +struct AssignedValue; + +/** + * Optimizer component that removes sstore statements if they + * are overwritten in all code paths or never read from. + * + * The m_store member of UnusedStoreBase is only used with the empty yul string + * as key in the first dimension. + * + * Best run in SSA form. + * + * Prerequisite: Disambiguator, ForLoopInitRewriter. + */ +class UnusedStoreEliminator: public UnusedStoreBase +{ +public: + static constexpr char const* name{"UnusedStoreEliminator"}; + static void run(OptimiserStepContext& _context, Block& _ast); + + explicit UnusedStoreEliminator( + Dialect const& _dialect, + std::map const& _functionSideEffects, + std::map _controlFlowSideEffects, + std::map const& _ssaValues, + bool _ignoreMemory + ): + UnusedStoreBase(_dialect), + m_ignoreMemory(_ignoreMemory), + m_functionSideEffects(_functionSideEffects), + m_controlFlowSideEffects(_controlFlowSideEffects), + m_ssaValues(_ssaValues) + {} + + using UnusedStoreBase::operator(); + void operator()(FunctionCall const& _functionCall) override; + void operator()(FunctionDefinition const&) override; + void operator()(Leave const&) override; + + using UnusedStoreBase::visit; + void visit(Statement const& _statement) override; + + using Location = evmasm::SemanticInformation::Location; + using Effect = evmasm::SemanticInformation::Effect; + struct Operation + { + Location location; + Effect effect; + /// Start of affected area. Unknown if not provided. + std::optional start; + /// Length of affected area, unknown if not provided. + /// Unused for storage. + std::optional length; + }; + +private: + void shortcutNestedLoop(TrackedStores const&) override + { + // We might only need to do this for newly introduced stores in the loop. + changeUndecidedTo(State::Used); + } + void finalizeFunctionDefinition(FunctionDefinition const&) override; + + std::vector operationsFromFunctionCall(FunctionCall const& _functionCall) const; + void applyOperation(Operation const& _operation); + bool knownUnrelated(Operation const& _op1, Operation const& _op2) const; + bool knownCovered(Operation const& _covered, Operation const& _covering) const; + + void changeUndecidedTo(State _newState, std::optional _onlyLocation = std::nullopt); + void scheduleUnusedForDeletion(); + + std::optional identifierNameIfSSA(Expression const& _expression) const; + + bool const m_ignoreMemory; + std::map const& m_functionSideEffects; + std::map m_controlFlowSideEffects; + std::map const& m_ssaValues; + + std::map m_storeOperations; +}; + +} diff --git a/scripts/common_cmdline.sh b/scripts/common_cmdline.sh index 3efeadc03daf..d364f644488f 100644 --- a/scripts/common_cmdline.sh +++ b/scripts/common_cmdline.sh @@ -69,7 +69,6 @@ function compileFull local exit_code=$? local errors; errors=$(grep -v -E \ -e 'Warning: This is a pre-release compiler version|Warning: Experimental features are turned on|pragma experimental ABIEncoderV2|^ +--> |^ +\||^[0-9]+ +\| ' \ - -e 'Warning: Yul is still experimental. Please use the output with care.' \ -e '^No text representation found.$' < "$stderr_path" ) diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 24e4ee7dd8a3..52ac69c6c47a 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -64,6 +64,7 @@ #include +#include #include #include #include @@ -464,7 +465,7 @@ void CommandLineInterface::readInputFiles() for (auto const& [sourceUnitName, normalizedInputPaths]: collisions) { message += sourceUnitName + " matches: "; - message += joinHumanReadable(normalizedInputPaths | ranges::views::transform(pathToQuotedString)) + "\n"; + message += util::joinHumanReadable(normalizedInputPaths | ranges::views::transform(pathToQuotedString)) + "\n"; } solThrow(CommandLineValidationError, message); @@ -653,7 +654,7 @@ void CommandLineInterface::processInput() assemble(m_options.assembly.inputLanguage, m_options.assembly.targetMachine); break; case InputMode::Linker: - link(); + link(m_fileReader, m_options.linker.libraries); writeLinkedFiles(); break; case InputMode::Compiler: @@ -693,7 +694,7 @@ void CommandLineInterface::compile() m_compiler->setModelCheckerSettings(m_options.modelChecker.settings); m_compiler->setRemappings(m_options.input.remappings); m_compiler->setLibraries(m_options.linker.libraries); - m_compiler->setViaIR(m_options.output.experimentalViaIR); + m_compiler->setViaIR(m_options.output.viaIR); m_compiler->setEVMVersion(m_options.output.evmVersion); m_compiler->setRevertStringBehaviour(m_options.output.revertStrings); if (m_options.output.debugInfoSelection.has_value()) @@ -916,67 +917,137 @@ void CommandLineInterface::serveLSP() solThrow(CommandLineExecutionError, "LSP terminated abnormally."); } -void CommandLineInterface::link() +static bool isBytecodeString(string s) { - solAssert(m_options.input.mode == InputMode::Linker, ""); + if (s.empty()) + return false; + size_t placeholderAddressStart = s.find("__"); + if (placeholderAddressStart == string::npos) + return false; + placeholderAddressStart += 3; + + size_t placeholderAddressEnd = s.find("__", placeholderAddressStart + 1) - 2; + + for (size_t i = 0; i < s.size(); i++) + { + // inside the markers can contain anything, outside the hex digits is hex characters and spaces only + if (i >= placeholderAddressStart && i <= placeholderAddressEnd) + continue; + + if (!isxdigit(s[i]) && s[i] != ' ' && s[i] != '$' && s[i] != '_') + return false; + } + return true; +} + +static size_t validateBytecode(string const& s, string const& fileName, string const& openingMarker, string const& closingMarker) +{ + size_t firstMarker = s.find(openingMarker); + size_t lastMarker = firstMarker + (openingMarker.size() - 1); + + while (s.find(closingMarker, lastMarker) != string::npos) + lastMarker = s.find(closingMarker, lastMarker) + 1; + + if (lastMarker == firstMarker + (openingMarker.size() - 1)) + solThrow( + CommandLineExecutionError, + "Error in binary object file " + fileName + " unbounded placeholder at " + to_string(firstMarker) + "\n" + ); + + lastMarker = lastMarker + openingMarker.size() - 1; + + if ((lastMarker - firstMarker) != 40) + { + solThrow( + CommandLineExecutionError, + "Error in binary object file \"" + fileName + "\" placeholder of invalid length found in column " + to_string(firstMarker) + ".\n" + + " Placeholders must be exactly 40 characters long, including address markers __$ and $__.\n" + ); + } + + return firstMarker; +} + +static size_t validateBytecode(string const& s, string const& fileName, string const& openingMarker) +{ + return validateBytecode(s, fileName, openingMarker, openingMarker); +} + +void CommandLineInterface::link(frontend::FileReader& fileReader, map const& libraries) +{ // Map from how the libraries will be named inside the bytecode to their addresses. map librariesReplacements; int const placeholderSize = 40; // 20 bytes or 40 hex characters - for (auto const& library: m_options.linker.libraries) + for (auto const& library: libraries) { string const& name = library.first; - // Library placeholders are 40 hex digits (20 bytes) that start and end with '__'. - // This leaves 36 characters for the library identifier. The identifier used to - // be just the cropped or '_'-padded library name, but this changed to - // the cropped hex representation of the hash of the library name. - // We support both ways of linking here. - librariesReplacements["__" + evmasm::LinkerObject::libraryPlaceholder(name) + "__"] = library.second; - - string replacement = "__"; - for (size_t i = 0; i < placeholderSize - 4; ++i) - replacement.push_back(i < name.size() ? name[i] : '_'); - replacement += "__"; - librariesReplacements[replacement] = library.second; + librariesReplacements[name] = library.second; } - FileReader::StringMap sourceCodes = m_fileReader.sourceUnits(); + FileReader::StringMap sourceCodes = fileReader.sourceUnits(); + for (auto& src: sourceCodes) { - auto end = src.second.end(); - for (auto it = src.second.begin(); it != end;) + // Map from how the libraries will be named inside the bytecodeIter to their addresses. + map linkReferences; + + if (src.second.empty()) + // no bytecode + continue; + + vector sourceLines; + boost::split(sourceLines, src.second, boost::is_any_of("\n")); + auto bytecodeIter = find_if(sourceLines.begin(), sourceLines.end(), isBytecodeString); + + if (bytecodeIter == sourceLines.end()) + continue; + + for (auto const& library: libraries) { - while (it != end && *it != '_') ++it; - if (it == end) break; - if ( - end - it < placeholderSize || - *(it + 1) != '_' || - *(it + placeholderSize - 2) != '_' || - *(it + placeholderSize - 1) != '_' - ) - solThrow( - CommandLineExecutionError, - "Error in binary object file " + src.first + " at position " + to_string(it - src.second.begin()) + "\n" + - '"' + string(it, it + min(placeholderSize, static_cast(end - it))) + "\" is not a valid link reference." - ); - - string foundPlaceholder(it, it + placeholderSize); - if (librariesReplacements.count(foundPlaceholder)) + string const& name = library.first; + + size_t startMarkerOffset = string::npos; + if (bytecodeIter->find("__$__") != string::npos) + startMarkerOffset = validateBytecode(*bytecodeIter, src.first, "__$__"); + + if (bytecodeIter->find("__$") != string::npos) + startMarkerOffset = validateBytecode(*bytecodeIter, src.first, "__$", "$__"); + + if (bytecodeIter->find("__") != string::npos) + startMarkerOffset = validateBytecode(*bytecodeIter, src.first, "__"); + + if (startMarkerOffset == string::npos) + // no markers found + continue; + + string foundPlaceholder = bytecodeIter->substr(startMarkerOffset,placeholderSize); + bytecodeIter->replace(startMarkerOffset, placeholderSize, "0000000000000000000000000000000000000000"); + + if (startMarkerOffset != bytecodeIter->length()) { - string hexStr(toHex(librariesReplacements.at(foundPlaceholder).asBytes())); - copy(hexStr.begin(), hexStr.end(), it); + // Divide by 2 because it's going to be converted to bytes + linkReferences[startMarkerOffset / 2] = name; } else - serr() << "Reference \"" << foundPlaceholder << "\" in file \"" << src.first << "\" still unresolved." << endl; - it += placeholderSize; + serr() << "Reference \"" << foundPlaceholder << "\" in file \"" << src.first << "\" still unresolved."<< endl; } + + evmasm::LinkerObject linkerObject = {fromHex(*bytecodeIter),linkReferences,{},{}}; + + linkerObject.link(librariesReplacements); + bytecodeIter->replace(bytecodeIter->begin(), bytecodeIter->end(), toHex(linkerObject.bytecode)); + + string resolvedBytecode = boost::algorithm::join(sourceLines, "\n"); + src.second = resolvedBytecode; + // Remove hints for resolved libraries. - for (auto const& library: m_options.linker.libraries) + for (auto const& library: libraries) boost::algorithm::erase_all(src.second, "\n" + libraryPlaceholderHint(library.first)); while (!src.second.empty() && *prev(src.second.end()) == '\n') src.second.resize(src.second.size() - 1); } - m_fileReader.setSourceUnits(move(sourceCodes)); + fileReader.setSourceUnits(move(sourceCodes)); } void CommandLineInterface::writeLinkedFiles() @@ -1017,8 +1088,6 @@ void CommandLineInterface::assemble(yul::AssemblyStack::Language _language, yul: { solAssert(m_options.input.mode == InputMode::Assembler, ""); - serr() << "Warning: Yul is still experimental. Please use the output with care." << endl; - bool successful = true; map assemblyStacks; for (auto const& src: m_fileReader.sourceUnits()) diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index 951731825cc6..9ea0ed584068 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -78,12 +78,13 @@ class CommandLineInterface FileReader const& fileReader() const { return m_fileReader; } std::optional const& standardJsonInput() const { return m_standardJsonInput; } + void link(frontend::FileReader& fileReader, std::map const& libraries); + private: void printVersion(); void printLicense(); void compile(); void serveLSP(); - void link(); void writeLinkedFiles(); /// @returns the ``// -> name`` hint for library placeholders. static std::string libraryPlaceholderHint(std::string const& _libraryName); diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index 65c7d7862152..4cc346737ffd 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -47,6 +47,7 @@ static string const g_strErrorRecovery = "error-recovery"; static string const g_strEVM = "evm"; static string const g_strEVMVersion = "evm-version"; static string const g_strEwasm = "ewasm"; +static string const g_strViaIR = "via-ir"; static string const g_strExperimentalViaIR = "experimental-via-ir"; static string const g_strGas = "gas"; static string const g_strHelp = "help"; @@ -166,7 +167,7 @@ ostream& operator<<(ostream& _out, CompilerOutputs const& _selection) if (_selection.*component) serializedSelection.push_back(CompilerOutputs::componentName(component)); - return _out << joinHumanReadable(serializedSelection, ","); + return _out << util::joinHumanReadable(serializedSelection, ","); } string const& CompilerOutputs::componentName(bool CompilerOutputs::* _component) @@ -197,7 +198,7 @@ ostream& operator<<(ostream& _out, CombinedJsonRequests const& _requests) if (_requests.*component) serializedRequests.push_back(CombinedJsonRequests::componentName(component)); - return _out << joinHumanReadable(serializedRequests, ","); + return _out << util::joinHumanReadable(serializedRequests, ","); } string const& CombinedJsonRequests::componentName(bool CombinedJsonRequests::* _component) @@ -225,7 +226,7 @@ bool CommandLineOptions::operator==(CommandLineOptions const& _other) const noex output.dir == _other.output.dir && output.overwriteFiles == _other.output.overwriteFiles && output.evmVersion == _other.output.evmVersion && - output.experimentalViaIR == _other.output.experimentalViaIR && + output.viaIR == _other.output.viaIR && output.revertStrings == _other.output.revertStrings && output.debugInfoSelection == _other.output.debugInfoSelection && output.stopAfter == _other.output.stopAfter && @@ -343,17 +344,17 @@ void CommandLineParser::parseLibraryOption(string const& _input) try { if (fs::is_regular_file(_input)) - data = readFileAsString(_input); + data = util::readFileAsString(_input); } catch (fs::filesystem_error const&) { // Thrown e.g. if path is too long. } - catch (FileNotFound const&) + catch (util::FileNotFound const&) { // Should not happen if `fs::is_regular_file` is correct. } - catch (NotAFile const&) + catch (util::NotAFile const&) { // Should not happen if `fs::is_regular_file` is correct. } @@ -418,15 +419,15 @@ void CommandLineParser::parseLibraryOption(string const& _input) "Invalid length for address for library \"" + libName + "\": " + to_string(addrString.length()) + " instead of 40 characters." ); - if (!passesAddressChecksum(addrString, false)) + if (!util::passesAddressChecksum(addrString, false)) solThrow( CommandLineValidationError, "Invalid checksum on address for library \"" + libName + "\": " + addrString + "\n" - "The correct checksum is " + getChecksummedAddress(addrString) + "The correct checksum is " + util::getChecksummedAddress(addrString) ); - bytes binAddr = fromHex(addrString); - h160 address(binAddr, h160::AlignRight); - if (binAddr.size() > 20 || address == h160()) + bytes binAddr = util::fromHex(addrString); + util::h160 address(binAddr, util::h160::AlignRight); + if (binAddr.size() > 20 || address == util::h160()) solThrow( CommandLineValidationError, "Invalid address for library \"" + libName + "\": " + addrString @@ -461,9 +462,9 @@ void CommandLineParser::parseOutputSelection() solAssert(false); case InputMode::Compiler: case InputMode::CompilerWithASTImport: - return contains(compilerModeOutputs, _outputName); + return util::contains(compilerModeOutputs, _outputName); case InputMode::Assembler: - return contains(assemblerModeOutputs, _outputName); + return util::contains(assemblerModeOutputs, _outputName); case InputMode::StandardJson: case InputMode::Linker: return false; @@ -578,19 +579,23 @@ General Information)").c_str(), ) ( g_strExperimentalViaIR.c_str(), - "Turn on experimental compilation mode via the IR (EXPERIMENTAL)." + "Deprecated synonym of --via-ir." + ) + ( + g_strViaIR.c_str(), + "Turn on compilation mode via the IR." ) ( g_strRevertStrings.c_str(), - po::value()->value_name(joinHumanReadable(g_revertStringsArgs, ",")), + po::value()->value_name(util::joinHumanReadable(g_revertStringsArgs, ",")), "Strip revert (and require) reason strings or add additional debugging information." ) ( g_strDebugInfo.c_str(), - po::value()->default_value(toString(DebugInfoSelection::Default())), + po::value()->default_value(util::toString(DebugInfoSelection::Default())), ("Debug info components to be included in the produced EVM assembly and Yul code. " "Value can be all, none or a comma-separated list containing one or more of the " - "following components: " + joinHumanReadable(DebugInfoSelection::componentMap() | ranges::views::keys) + ".").c_str() + "following components: " + util::joinHumanReadable(DebugInfoSelection::componentMap() | ranges::views::keys) + ".").c_str() ) ( g_strStopAfter.c_str(), @@ -648,12 +653,12 @@ General Information)").c_str(), assemblyModeOptions.add_options() ( g_strMachine.c_str(), - po::value()->value_name(joinHumanReadable(g_machineArgs, ",")), + po::value()->value_name(util::joinHumanReadable(g_machineArgs, ",")), "Target machine in assembly or Yul mode." ) ( g_strYulDialect.c_str(), - po::value()->value_name(joinHumanReadable(g_yulDialectArgs, ",")), + po::value()->value_name(util::joinHumanReadable(g_yulDialectArgs, ",")), "Input dialect to use in assembly or yul mode." ) ; @@ -706,8 +711,8 @@ General Information)").c_str(), (CompilerOutputs::componentName(&CompilerOutputs::binary).c_str(), "Binary of the contracts in hex.") (CompilerOutputs::componentName(&CompilerOutputs::binaryRuntime).c_str(), "Binary of the runtime part of the contracts in hex.") (CompilerOutputs::componentName(&CompilerOutputs::abi).c_str(), "ABI specification of the contracts.") - (CompilerOutputs::componentName(&CompilerOutputs::ir).c_str(), "Intermediate Representation (IR) of all contracts (EXPERIMENTAL).") - (CompilerOutputs::componentName(&CompilerOutputs::irOptimized).c_str(), "Optimized intermediate Representation (IR) of all contracts (EXPERIMENTAL).") + (CompilerOutputs::componentName(&CompilerOutputs::ir).c_str(), "Intermediate Representation (IR) of all contracts.") + (CompilerOutputs::componentName(&CompilerOutputs::irOptimized).c_str(), "Optimized intermediate Representation (IR) of all contracts.") (CompilerOutputs::componentName(&CompilerOutputs::ewasm).c_str(), "Ewasm text representation of all contracts (EXPERIMENTAL).") (CompilerOutputs::componentName(&CompilerOutputs::ewasmIR).c_str(), "Intermediate representation (IR) converted to a form that can be translated directly into Ewasm text representation (EXPERIMENTAL).") (CompilerOutputs::componentName(&CompilerOutputs::signatureHashes).c_str(), "Function signature hashes of the contracts.") @@ -726,7 +731,7 @@ General Information)").c_str(), ) ( g_strCombinedJson.c_str(), - po::value()->value_name(joinHumanReadable(CombinedJsonRequests::componentMap() | ranges::views::keys, ",")), + po::value()->value_name(util::joinHumanReadable(CombinedJsonRequests::componentMap() | ranges::views::keys, ",")), "Output a single json document containing the specified information." ) ; @@ -736,7 +741,7 @@ General Information)").c_str(), metadataOptions.add_options() ( g_strMetadataHash.c_str(), - po::value()->value_name(joinHumanReadable(g_metadataHashArgs, ",")), + po::value()->value_name(util::joinHumanReadable(g_metadataHashArgs, ",")), "Choose hash method for the bytecode metadata or disable it." ) ( @@ -906,6 +911,7 @@ void CommandLineParser::processArgs() // TODO: This should eventually contain all options. {g_strErrorRecovery, {InputMode::Compiler, InputMode::CompilerWithASTImport}}, {g_strExperimentalViaIR, {InputMode::Compiler, InputMode::CompilerWithASTImport}}, + {g_strViaIR, {InputMode::Compiler, InputMode::CompilerWithASTImport}} }; vector invalidOptionsForCurrentInputMode; for (auto const& [optionName, inputModes]: validOptionInputModeCombinations) @@ -1011,11 +1017,11 @@ void CommandLineParser::processArgs() if (m_args.count(g_strPrettyJson) > 0) { - m_options.formatting.json.format = JsonFormat::Pretty; + m_options.formatting.json.format = util::JsonFormat::Pretty; } if (!m_args[g_strJsonIndent].defaulted()) { - m_options.formatting.json.format = JsonFormat::Pretty; + m_options.formatting.json.format = util::JsonFormat::Pretty; m_options.formatting.json.indent = m_args[g_strJsonIndent].as(); } @@ -1256,7 +1262,7 @@ void CommandLineParser::processArgs() m_args.count(g_strModelCheckerSolvers) || m_args.count(g_strModelCheckerTargets) || m_args.count(g_strModelCheckerTimeout); - m_options.output.experimentalViaIR = (m_args.count(g_strExperimentalViaIR) > 0); + m_options.output.viaIR = (m_args.count(g_strExperimentalViaIR) > 0 || m_args.count(g_strViaIR) > 0); if (m_options.input.mode == InputMode::Compiler) m_options.input.errorRecovery = (m_args.count(g_strErrorRecovery) > 0); @@ -1289,7 +1295,7 @@ size_t CommandLineParser::countEnabledOptions(vector const& _optionNames string CommandLineParser::joinOptionNames(vector const& _optionNames, string _separator) { - return joinHumanReadable( + return util::joinHumanReadable( _optionNames | ranges::views::transform([](string const& _option){ return "--" + _option; }), _separator ); diff --git a/solc/CommandLineParser.h b/solc/CommandLineParser.h index 791e7f1c10cc..9723d5e06e9c 100644 --- a/solc/CommandLineParser.h +++ b/solc/CommandLineParser.h @@ -182,7 +182,7 @@ struct CommandLineOptions boost::filesystem::path dir; bool overwriteFiles = false; langutil::EVMVersion evmVersion; - bool experimentalViaIR = false; + bool viaIR = false; RevertStrings revertStrings = RevertStrings::Default; std::optional debugInfoSelection; CompilerStack::State stopAfter = CompilerStack::State::CompilationSuccessful; diff --git a/solc/main.cpp b/solc/main.cpp index ce69d20a79c5..50a6a8fc52a7 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -27,40 +27,16 @@ #include -#include #include using namespace std; using namespace solidity; -/* -The equivalent of setlocale(LC_ALL, "C") is called before any user code is run. -If the user has an invalid environment setting then it is possible for the call -to set locale to fail, so there are only two possible actions, the first is to -throw a runtime exception and cause the program to quit (default behaviour), -or the second is to modify the environment to something sensible (least -surprising behaviour). - -The follow code produces the least surprising behaviour. It will use the user -specified default locale if it is valid, and if not then it will modify the -environment the process is running in to use a sensible default. This also means -that users do not need to install language packs for their OS. -*/ -static void setDefaultOrCLocale() -{ -#if __unix__ - if (!std::setlocale(LC_ALL, "")) - { - setenv("LC_ALL", "C", 1); - } -#endif -} int main(int argc, char** argv) { try { - setDefaultOrCLocale(); solidity::frontend::CommandLineInterface cli(cin, cout, cerr); return cli.run(argc, argv) ? 0 : 1; } diff --git a/test/CommonSyntaxTest.cpp b/test/CommonSyntaxTest.cpp index d28ec16754f5..5b66aea30239 100644 --- a/test/CommonSyntaxTest.cpp +++ b/test/CommonSyntaxTest.cpp @@ -42,11 +42,10 @@ namespace int parseUnsignedInteger(string::iterator& _it, string::iterator _end) { - auto isDigit = [](char _c) -> bool {return isdigit(_c, std::locale::classic());}; - if (_it == _end || !isDigit(*_it)) + if (_it == _end || !util::isDigit(*_it)) BOOST_THROW_EXCEPTION(runtime_error("Invalid test expectation. Source location expected.")); int result = 0; - while (_it != _end && isDigit(*_it)) + while (_it != _end && util::isDigit(*_it)) { result *= 10; result += *_it - '0'; @@ -84,9 +83,9 @@ TestCase::TestResult CommonSyntaxTest::conclude(ostream& _stream, string const& void CommonSyntaxTest::printExpectationAndError(ostream& _stream, string const& _linePrefix, bool _formatted) { string nextIndentLevel = _linePrefix + " "; - AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl; + util::AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl; printErrorList(_stream, m_expectations, nextIndentLevel, _formatted); - AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl; + util::AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl; printErrorList(_stream, m_errorList, nextIndentLevel, _formatted); } @@ -105,8 +104,8 @@ void CommonSyntaxTest::printSource(ostream& _stream, string const& _linePrefix, continue; if (outputSourceNames) - _stream << _linePrefix << formatting::CYAN << "==== Source: " << name << " ====" << formatting::RESET << endl; - vector sourceFormatting(source.length(), formatting::RESET); + _stream << _linePrefix << util::formatting::CYAN << "==== Source: " << name << " ====" << util::formatting::RESET << endl; + vector sourceFormatting(source.length(), util::formatting::RESET); for (auto const& error: m_errorList) if (error.sourceName == name && error.locationStart >= 0 && error.locationEnd >= 0) { @@ -116,11 +115,11 @@ void CommonSyntaxTest::printSource(ostream& _stream, string const& _linePrefix, for (int i = error.locationStart; i < error.locationEnd; i++) if (isWarning) { - if (sourceFormatting[static_cast(i)] == formatting::RESET) - sourceFormatting[static_cast(i)] = formatting::ORANGE_BACKGROUND_256; + if (sourceFormatting[static_cast(i)] == util::formatting::RESET) + sourceFormatting[static_cast(i)] = util::formatting::ORANGE_BACKGROUND_256; } else - sourceFormatting[static_cast(i)] = formatting::RED_BACKGROUND; + sourceFormatting[static_cast(i)] = util::formatting::RED_BACKGROUND; } _stream << _linePrefix << sourceFormatting.front() << source.front(); @@ -132,12 +131,12 @@ void CommonSyntaxTest::printSource(ostream& _stream, string const& _linePrefix, _stream << source[i]; else { - _stream << formatting::RESET << endl; + _stream << util::formatting::RESET << endl; if (i + 1 < source.length()) _stream << _linePrefix << sourceFormatting[i]; } } - _stream << formatting::RESET; + _stream << util::formatting::RESET; } else { @@ -158,12 +157,12 @@ void CommonSyntaxTest::printErrorList( ) { if (_errorList.empty()) - AnsiColorized(_stream, _formatted, {BOLD, GREEN}) << _linePrefix << "Success" << endl; + util::AnsiColorized(_stream, _formatted, {BOLD, GREEN}) << _linePrefix << "Success" << endl; else for (auto const& error: _errorList) { { - AnsiColorized scope(_stream, _formatted, {BOLD, (error.type == "Warning") ? YELLOW : RED}); + util::AnsiColorized scope(_stream, _formatted, {BOLD, (error.type == "Warning") ? YELLOW : RED}); _stream << _linePrefix << error.type; if (error.errorId.has_value()) _stream << ' ' << error.errorId->error; @@ -185,7 +184,7 @@ void CommonSyntaxTest::printErrorList( } } -string CommonSyntaxTest::errorMessage(Exception const& _e) +string CommonSyntaxTest::errorMessage(util::Exception const& _e) { if (_e.comment() && !_e.comment()->empty()) return boost::replace_all_copy(*_e.comment(), "\n", "\\n"); @@ -195,7 +194,6 @@ string CommonSyntaxTest::errorMessage(Exception const& _e) vector CommonSyntaxTest::parseExpectations(istream& _stream) { - auto isDigit = [](char _c) -> bool {return isdigit(_c, std::locale::classic());}; vector expectations; string line; while (getline(_stream, line)) @@ -215,7 +213,7 @@ vector CommonSyntaxTest::parseExpectations(istream& _stream) skipWhitespace(it, line.end()); optional errorId; - if (it != line.end() && isDigit(*it)) + if (it != line.end() && util::isDigit(*it)) errorId = ErrorId{static_cast(parseUnsignedInteger(it, line.end()))}; expect(it, line.end(), ':'); @@ -228,7 +226,7 @@ vector CommonSyntaxTest::parseExpectations(istream& _stream) if (it != line.end() && *it == '(') { ++it; - if (it != line.end() && !isDigit(*it)) + if (it != line.end() && !util::isDigit(*it)) { auto sourceNameStart = it; while (it != line.end() && *it != ':') diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index d33dd208c13b..6798a83f8856 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -339,7 +339,7 @@ function test_via_ir_equivalence() ) asm_output_via_ir=$( echo "$solidity_code" | - msg_on_error --no-stderr "$SOLC" - --experimental-via-ir --asm --debug-info location "${optimizer_flags[@]}" | + msg_on_error --no-stderr "$SOLC" - --via-ir --asm --debug-info location "${optimizer_flags[@]}" | sed '/^======= /d' | sed '/^EVM assembly:$/d' ) @@ -355,7 +355,7 @@ function test_via_ir_equivalence() ) bin_output_via_ir=$( echo "$solidity_code" | - msg_on_error --no-stderr "$SOLC" - --experimental-via-ir --bin "${optimizer_flags[@]}" | + msg_on_error --no-stderr "$SOLC" - --via-ir --bin "${optimizer_flags[@]}" | sed '/^======= /d' | sed '/^Binary:$/d' ) @@ -588,7 +588,7 @@ printTask "Testing assemble, yul, strict-assembly and optimize..." test_solc_assembly_output "{ let x := 0 }" "{ { } }" "--strict-assembly --optimize" ) -printTask "Testing the eqivalence of --experimental-via-ir and a two-stage compilation..." +printTask "Testing the eqivalence of --via-ir and a two-stage compilation..." ( printTask " - Smoke test" test_via_ir_equivalence "contract C {}" diff --git a/test/cmdlineTests/constant_optimizer_yul/output b/test/cmdlineTests/constant_optimizer_yul/output index 2a769811a6db..9c7faa732272 100644 --- a/test/cmdlineTests/constant_optimizer_yul/output +++ b/test/cmdlineTests/constant_optimizer_yul/output @@ -1,11 +1,4 @@ Optimized IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"constant_optimizer_yul/input.sol" object "C_12" { code { @@ -27,7 +20,6 @@ object "C_12" { code { { /// @src 0:61:418 "contract C {..." - mstore(64, memoryguard(0x80)) if callvalue() { revert(0, 0) } /// @src 0:279:410 "assembly {..." sstore(0, 0x1000000000000000000000000000000000000000000000) diff --git a/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all/output b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all/output index 7775ff69caef..af83c9f36a92 100644 --- a/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all/output +++ b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all/output @@ -54,13 +54,6 @@ sub_0: assembly { } IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"debug_info_in_yul_and_evm_asm_print_all/input.sol" object "C_6" { @@ -176,13 +169,6 @@ object "C_6" { Optimized IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"debug_info_in_yul_and_evm_asm_print_all/input.sol" object "C_6" { code { @@ -201,16 +187,14 @@ object "C_6" { code { { /// @src 0:60:101 "contract C {..." - let _1 := memoryguard(0x80) - mstore(64, _1) if iszero(lt(calldatasize(), 4)) { - let _2 := 0 - if eq(0x26121ff0, shr(224, calldataload(_2))) + let _1 := 0 + if eq(0x26121ff0, shr(224, calldataload(_1))) { - if callvalue() { revert(_2, _2) } - if slt(add(calldatasize(), not(3)), _2) { revert(_2, _2) } - return(_1, _2) + if callvalue() { revert(_1, _1) } + if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } + return(memoryguard(0x80), _1) } } revert(0, 0) diff --git a/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_location_only/output b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_location_only/output index 35f680d92303..dc4ea45fd7bd 100644 --- a/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_location_only/output +++ b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_location_only/output @@ -54,13 +54,6 @@ sub_0: assembly { } IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"debug_info_in_yul_and_evm_asm_print_location_only/input.sol" object "C_6" { @@ -175,13 +168,6 @@ object "C_6" { Optimized IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"debug_info_in_yul_and_evm_asm_print_location_only/input.sol" object "C_6" { code { @@ -200,16 +186,14 @@ object "C_6" { code { { /// @src 0:60:101 - let _1 := memoryguard(0x80) - mstore(64, _1) if iszero(lt(calldatasize(), 4)) { - let _2 := 0 - if eq(0x26121ff0, shr(224, calldataload(_2))) + let _1 := 0 + if eq(0x26121ff0, shr(224, calldataload(_1))) { - if callvalue() { revert(_2, _2) } - if slt(add(calldatasize(), not(3)), _2) { revert(_2, _2) } - return(_1, _2) + if callvalue() { revert(_1, _1) } + if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } + return(memoryguard(0x80), _1) } } revert(0, 0) diff --git a/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_none/output b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_none/output index 93fad04216b9..b2ad57c30857 100644 --- a/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_none/output +++ b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_none/output @@ -51,13 +51,6 @@ sub_0: assembly { } IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"debug_info_in_yul_and_evm_asm_print_none/input.sol" object "C_6" { @@ -166,13 +159,6 @@ object "C_6" { Optimized IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"debug_info_in_yul_and_evm_asm_print_none/input.sol" object "C_6" { code { @@ -189,16 +175,14 @@ object "C_6" { object "C_6_deployed" { code { { - let _1 := memoryguard(0x80) - mstore(64, _1) if iszero(lt(calldatasize(), 4)) { - let _2 := 0 - if eq(0x26121ff0, shr(224, calldataload(_2))) + let _1 := 0 + if eq(0x26121ff0, shr(224, calldataload(_1))) { - if callvalue() { revert(_2, _2) } - if slt(add(calldatasize(), not(3)), _2) { revert(_2, _2) } - return(_1, _2) + if callvalue() { revert(_1, _1) } + if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } + return(memoryguard(0x80), _1) } } revert(0, 0) diff --git a/test/cmdlineTests/debug_info_in_yul_snippet_escaping/output b/test/cmdlineTests/debug_info_in_yul_snippet_escaping/output index 82a74384e791..04a354e2edbc 100644 --- a/test/cmdlineTests/debug_info_in_yul_snippet_escaping/output +++ b/test/cmdlineTests/debug_info_in_yul_snippet_escaping/output @@ -1,11 +1,4 @@ IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"debug_info_in_yul_snippet_escaping/input.sol" object "C_2" { @@ -70,13 +63,6 @@ object "C_2" { Optimized IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"debug_info_in_yul_snippet_escaping/input.sol" object "C_2" { code { @@ -95,7 +81,6 @@ object "C_2" { code { { /// @src 0:265:278 "contract C {}" - mstore(64, memoryguard(0x80)) revert(0, 0) } } @@ -104,13 +89,6 @@ object "C_2" { } IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"debug_info_in_yul_snippet_escaping/input.sol" object "D_27" { @@ -368,12 +346,6 @@ object "D_27" { /// @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..." } - /*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ /// @use-src 0:"debug_info_in_yul_snippet_escaping/input.sol" object "C_2" { @@ -443,13 +415,6 @@ object "D_27" { Optimized IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"debug_info_in_yul_snippet_escaping/input.sol" object "D_27" { code { @@ -559,7 +524,6 @@ object "D_27" { code { { /// @src 0:265:278 "contract C {}" - mstore(64, memoryguard(0x80)) revert(0, 0) } } diff --git a/test/cmdlineTests/dup_opt_peephole/output b/test/cmdlineTests/dup_opt_peephole/output index 593d330f83f9..2f75f2bdda9f 100644 --- a/test/cmdlineTests/dup_opt_peephole/output +++ b/test/cmdlineTests/dup_opt_peephole/output @@ -46,8 +46,6 @@ sub_0: assembly { /* "dup_opt_peephole/input.sol":150:162 sstore(0, x) */ sstore /* "dup_opt_peephole/input.sol":107:166 {... */ - pop - /* "dup_opt_peephole/input.sol":60:171 contract C {... */ stop auxdata: diff --git a/test/cmdlineTests/evm_to_wasm/err b/test/cmdlineTests/evm_to_wasm/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/evm_to_wasm/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/evm_to_wasm_break/err b/test/cmdlineTests/evm_to_wasm_break/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/evm_to_wasm_break/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/evm_to_wasm_output_selection_asm_only/err b/test/cmdlineTests/evm_to_wasm_output_selection_asm_only/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/evm_to_wasm_output_selection_asm_only/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/evm_to_wasm_output_selection_ewasm_ir_only/err b/test/cmdlineTests/evm_to_wasm_output_selection_ewasm_ir_only/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/evm_to_wasm_output_selection_ewasm_ir_only/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/evm_to_wasm_output_selection_ewasm_only/err b/test/cmdlineTests/evm_to_wasm_output_selection_ewasm_only/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/evm_to_wasm_output_selection_ewasm_only/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/exp_base_literal/output b/test/cmdlineTests/exp_base_literal/output index 7b6e6e628d48..24e5d29be756 100644 --- a/test/cmdlineTests/exp_base_literal/output +++ b/test/cmdlineTests/exp_base_literal/output @@ -1,11 +1,4 @@ IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"exp_base_literal/input.sol" object "C_81" { diff --git a/test/cmdlineTests/function_debug_info_via_yul/args b/test/cmdlineTests/function_debug_info_via_yul/args index ab626e663ccb..7b0bf90f1428 100644 --- a/test/cmdlineTests/function_debug_info_via_yul/args +++ b/test/cmdlineTests/function_debug_info_via_yul/args @@ -1 +1 @@ ---experimental-via-ir --optimize --combined-json function-debug,function-debug-runtime --pretty-json +--via-ir --optimize --combined-json function-debug,function-debug-runtime --pretty-json diff --git a/test/cmdlineTests/function_debug_info_via_yul/output b/test/cmdlineTests/function_debug_info_via_yul/output index 495c82d5be67..97125e4b9579 100644 --- a/test/cmdlineTests/function_debug_info_via_yul/output +++ b/test/cmdlineTests/function_debug_info_via_yul/output @@ -13,7 +13,7 @@ }, "calldata_array_index_access_uint256_dyn_calldata": { - "entryPoint": 152, + "entryPoint": 144, "parameterSlots": 2, "returnSlots": 1 } diff --git a/test/cmdlineTests/inline_assembly_function_name_clash/args b/test/cmdlineTests/inline_assembly_function_name_clash/args index 4299d023e862..a4e76abf25c4 100644 --- a/test/cmdlineTests/inline_assembly_function_name_clash/args +++ b/test/cmdlineTests/inline_assembly_function_name_clash/args @@ -1 +1 @@ ---experimental-via-ir --combined-json function-debug-runtime --pretty-json --json-indent 4 \ No newline at end of file +--via-ir --combined-json function-debug-runtime --pretty-json --json-indent 4 \ No newline at end of file diff --git a/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output b/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output index 330e208f4523..84fd9d0bc35f 100644 --- a/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output +++ b/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output @@ -1,11 +1,4 @@ Optimized IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"ir_compiler_inheritance_nosubobjects/input.sol" object "C_7" { code { @@ -24,7 +17,6 @@ object "C_7" { code { { /// @src 0:82:117 "contract C {..." - mstore(64, memoryguard(0x80)) revert(0, 0) } } @@ -33,13 +25,6 @@ object "C_7" { } Optimized IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"ir_compiler_inheritance_nosubobjects/input.sol" object "D_10" { code { @@ -58,7 +43,6 @@ object "D_10" { code { { /// @src 0:118:137 "contract D is C {..." - mstore(64, memoryguard(0x80)) revert(0, 0) } } diff --git a/test/cmdlineTests/ir_compiler_subobjects/output b/test/cmdlineTests/ir_compiler_subobjects/output index fbedf38db8d7..5cacb6c16bea 100644 --- a/test/cmdlineTests/ir_compiler_subobjects/output +++ b/test/cmdlineTests/ir_compiler_subobjects/output @@ -1,11 +1,4 @@ Optimized IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"ir_compiler_subobjects/input.sol" object "C_3" { code { @@ -24,7 +17,6 @@ object "C_3" { code { { /// @src 0:82:95 "contract C {}" - mstore(64, memoryguard(0x80)) revert(0, 0) } } @@ -33,13 +25,6 @@ object "C_3" { } Optimized IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"ir_compiler_subobjects/input.sol" object "D_16" { code { @@ -110,7 +95,6 @@ object "D_16" { code { { /// @src 0:82:95 "contract C {}" - mstore(64, memoryguard(0x80)) revert(0, 0) } } diff --git a/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output b/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output index d9b769a124b4..41f353269f0f 100644 --- a/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output +++ b/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output @@ -1,21 +1,10 @@ Optimized IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"ir_with_assembly_no_memoryguard_creation/input.sol" object "D_12" { code { { /// @src 0:82:175 "contract D {..." - mstore(64, 128) if callvalue() { revert(0, 0) } - /// @src 0:115:139 "assembly { mstore(0,0) }" - mstore(0, 0) - /// @src 0:82:175 "contract D {..." let _1 := datasize("D_12_deployed") codecopy(128, dataoffset("D_12_deployed"), _1) return(128, _1) @@ -26,16 +15,14 @@ object "D_12" { code { { /// @src 0:82:175 "contract D {..." - let _1 := memoryguard(0x80) - mstore(64, _1) if iszero(lt(calldatasize(), 4)) { - let _2 := 0 - if eq(0x26121ff0, shr(224, calldataload(_2))) + let _1 := 0 + if eq(0x26121ff0, shr(224, calldataload(_1))) { - if callvalue() { revert(_2, _2) } - if slt(add(calldatasize(), not(3)), _2) { revert(_2, _2) } - return(_1, _2) + if callvalue() { revert(_1, _1) } + if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } + return(memoryguard(0x80), _1) } } revert(0, 0) diff --git a/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/output b/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/output index 9a07c7861f18..c406d4f7edbf 100644 --- a/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/output +++ b/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/output @@ -1,11 +1,4 @@ Optimized IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"ir_with_assembly_no_memoryguard_runtime/input.sol" object "D_8" { code { @@ -24,7 +17,6 @@ object "D_8" { code { { /// @src 0:82:166 "contract D {..." - mstore(64, 128) if iszero(lt(calldatasize(), 4)) { let _1 := 0 @@ -32,8 +24,6 @@ object "D_8" { { if callvalue() { revert(_1, _1) } if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } - /// @src 0:134:158 "assembly { mstore(0,0) }" - mstore(/** @src 0:82:166 "contract D {..." */ _1, _1) return(128, _1) } } diff --git a/test/cmdlineTests/keccak_optimization_deploy_code/output b/test/cmdlineTests/keccak_optimization_deploy_code/output index 4abb046f6301..8b89ea5b6329 100644 --- a/test/cmdlineTests/keccak_optimization_deploy_code/output +++ b/test/cmdlineTests/keccak_optimization_deploy_code/output @@ -1,17 +1,9 @@ Optimized IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"keccak_optimization_deploy_code/input.sol" object "C_12" { code { { /// @src 0:62:463 "contract C {..." - mstore(64, 128) if callvalue() { revert(0, 0) } /// @src 0:103:275 "assembly {..." mstore(0, 100) @@ -27,10 +19,8 @@ object "C_12" { code { { /// @src 0:62:463 "contract C {..." - mstore(64, 128) if callvalue() { revert(0, 0) } /// @src 0:317:454 "assembly {..." - mstore(0, 100) sstore(0, 17385872270140913825666367956517731270094621555228275961425792378517567244498) /// @src 0:62:463 "contract C {..." stop() diff --git a/test/cmdlineTests/keccak_optimization_low_runs/output b/test/cmdlineTests/keccak_optimization_low_runs/output index f5df14027a47..c308d737b2f5 100644 --- a/test/cmdlineTests/keccak_optimization_low_runs/output +++ b/test/cmdlineTests/keccak_optimization_low_runs/output @@ -1,11 +1,4 @@ Optimized IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"keccak_optimization_low_runs/input.sol" object "C_7" { code { @@ -24,7 +17,6 @@ object "C_7" { code { { /// @src 0:62:285 "contract C {..." - mstore(64, 128) if callvalue() { revert(0, 0) } /// @src 0:109:277 "assembly {..." mstore(0, 100) diff --git a/test/cmdlineTests/linking_standard_yul/output.json b/test/cmdlineTests/linking_standard_yul/output.json index 7816df4ecf75..89fa9901cf17 100644 --- a/test/cmdlineTests/linking_standard_yul/output.json +++ b/test/cmdlineTests/linking_standard_yul/output.json @@ -1 +1 @@ -{"contracts":{"A":{"a":{"evm":{"bytecode":{"linkReferences":{},"object":""}}}}},"errors":[{"component":"general","formattedMessage":"Yul is still experimental. Please use the output with care.","message":"Yul is still experimental. Please use the output with care.","severity":"warning","type":"Warning"}]} +{"contracts":{"A":{"a":{"evm":{"bytecode":{"linkReferences":{},"object":""}}}}},} diff --git a/test/cmdlineTests/linking_standard_yul_quote_in_file_name/output.json b/test/cmdlineTests/linking_standard_yul_quote_in_file_name/output.json index 7816df4ecf75..89fa9901cf17 100644 --- a/test/cmdlineTests/linking_standard_yul_quote_in_file_name/output.json +++ b/test/cmdlineTests/linking_standard_yul_quote_in_file_name/output.json @@ -1 +1 @@ -{"contracts":{"A":{"a":{"evm":{"bytecode":{"linkReferences":{},"object":""}}}}},"errors":[{"component":"general","formattedMessage":"Yul is still experimental. Please use the output with care.","message":"Yul is still experimental. Please use the output with care.","severity":"warning","type":"Warning"}]} +{"contracts":{"A":{"a":{"evm":{"bytecode":{"linkReferences":{},"object":""}}}}},} diff --git a/test/cmdlineTests/linking_standard_yul_unresolved_references/output.json b/test/cmdlineTests/linking_standard_yul_unresolved_references/output.json index 4dab68351529..ec597c396ec0 100644 --- a/test/cmdlineTests/linking_standard_yul_unresolved_references/output.json +++ b/test/cmdlineTests/linking_standard_yul_unresolved_references/output.json @@ -1 +1 @@ -{"contracts":{"A":{"a":{"evm":{"bytecode":{"linkReferences":{"contract/test.sol":{"L2":[{"length":20,"start":22}]}},"object":"__$fb58009a6b1ecea3b9d99bedd645df4ec3$__"}}}}},"errors":[{"component":"general","formattedMessage":"Yul is still experimental. Please use the output with care.","message":"Yul is still experimental. Please use the output with care.","severity":"warning","type":"Warning"}]} +{"contracts":{"A":{"a":{"evm":{"bytecode":{"linkReferences":{"contract/test.sol":{"L2":[{"length":20,"start":22}]}},"object":"__$fb58009a6b1ecea3b9d99bedd645df4ec3$__"}}}}},} diff --git a/test/cmdlineTests/linking_strict_assembly/err b/test/cmdlineTests/linking_strict_assembly/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/linking_strict_assembly/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/linking_strict_assembly_qualified_library_qualified_reference/err b/test/cmdlineTests/linking_strict_assembly_qualified_library_qualified_reference/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/linking_strict_assembly_qualified_library_qualified_reference/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/linking_strict_assembly_qualified_library_unqualified_reference/err b/test/cmdlineTests/linking_strict_assembly_qualified_library_unqualified_reference/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/linking_strict_assembly_qualified_library_unqualified_reference/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/linking_strict_assembly_same_library_name_different_files/err b/test/cmdlineTests/linking_strict_assembly_same_library_name_different_files/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/linking_strict_assembly_same_library_name_different_files/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/linking_strict_assembly_same_library_name_different_files_in_link_references/err b/test/cmdlineTests/linking_strict_assembly_same_library_name_different_files_in_link_references/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/linking_strict_assembly_same_library_name_different_files_in_link_references/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/linking_strict_assembly_unqualified_library_qualified_reference/err b/test/cmdlineTests/linking_strict_assembly_unqualified_library_qualified_reference/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/linking_strict_assembly_unqualified_library_qualified_reference/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/linking_strict_assembly_unqualified_library_unqualified_reference/err b/test/cmdlineTests/linking_strict_assembly_unqualified_library_unqualified_reference/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/linking_strict_assembly_unqualified_library_unqualified_reference/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/linking_strict_assembly_unresolved_references/err b/test/cmdlineTests/linking_strict_assembly_unresolved_references/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/linking_strict_assembly_unresolved_references/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/name_simplifier/output b/test/cmdlineTests/name_simplifier/output index 3dabe9c8d2d3..219d76769252 100644 --- a/test/cmdlineTests/name_simplifier/output +++ b/test/cmdlineTests/name_simplifier/output @@ -1,11 +1,4 @@ Optimized IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"name_simplifier/input.sol" object "C_59" { code { diff --git a/test/cmdlineTests/object_compiler/err b/test/cmdlineTests/object_compiler/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/object_compiler/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/optimizer_array_sload/output b/test/cmdlineTests/optimizer_array_sload/output index 8404525f8cec..bb0d0bf4024b 100644 --- a/test/cmdlineTests/optimizer_array_sload/output +++ b/test/cmdlineTests/optimizer_array_sload/output @@ -1,11 +1,4 @@ Optimized IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"optimizer_array_sload/input.sol" object "Arraysum_34" { code { diff --git a/test/cmdlineTests/optimizer_user_yul/output b/test/cmdlineTests/optimizer_user_yul/output index f6e7705c7959..689e82ddb4e4 100644 --- a/test/cmdlineTests/optimizer_user_yul/output +++ b/test/cmdlineTests/optimizer_user_yul/output @@ -58,10 +58,9 @@ tag_6: /* "optimizer_user_yul/input.sol":384:392 sload(5) */ dup1 /* "optimizer_user_yul/input.sol":376:509 for { } sload(5) { } {... */ - tag_8 + iszero + tag_6 jumpi - jump(tag_6) -tag_8: /* "optimizer_user_yul/input.sol":380:383 { } */ pop /* "optimizer_user_yul/input.sol":340:513 {... */ diff --git a/test/cmdlineTests/revert_strings/output b/test/cmdlineTests/revert_strings/output index 31b3db33b69b..0f16ff9d0f8f 100644 --- a/test/cmdlineTests/revert_strings/output +++ b/test/cmdlineTests/revert_strings/output @@ -1,11 +1,4 @@ IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"revert_strings/input.sol" object "C_15" { diff --git a/test/cmdlineTests/standard_debug_info_in_evm_asm_via_ir_location/output.json b/test/cmdlineTests/standard_debug_info_in_evm_asm_via_ir_location/output.json index 238934a3f023..3490a73426c8 100644 --- a/test/cmdlineTests/standard_debug_info_in_evm_asm_via_ir_location/output.json +++ b/test/cmdlineTests/standard_debug_info_in_evm_asm_via_ir_location/output.json @@ -1,8 +1,5 @@ {"contracts":{"C":{"C":{"evm":{"assembly":" /* \"C\":79:428 contract C... */ 0xa0 - dup1 - 0x40 - mstore jumpi(tag_6, callvalue) 0x1f bytecodeSize @@ -61,15 +58,10 @@ assignImmutable(\"0xe4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10\") return tag_6: - pop 0x00 dup1 revert tag_4: - pop - pop - pop - pop mstore(0x00, shl(0xe0, 0x4e487b71)) mstore(0x04, 0x41) revert(0x00, 0x24) @@ -118,15 +110,12 @@ sub_0: assembly { tag_2 jump\t// in tag_9: - swap1 - pop jumpi(tag_19, callvalue) dup1 add(calldatasize, not(0x03)) slt tag_19 jumpi - pop 0x20 /* \"C\":290:298 immutVar */ immutable(\"0xe4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10\") @@ -224,21 +213,16 @@ sub_0: assembly { jumpi /* \"C\":79:428 contract C... */ tag_37: - /* \"C\":392:411 stateVar + this.f() */ - pop - pop tag_38 /* \"C\":392:422 stateVar + this.f() + immutVar */ tag_39 /* \"C\":392:411 stateVar + this.f() */ - swap2 - /* \"C\":79:428 contract C... */ tag_40 - /* \"C\":392:411 stateVar + this.f() */ - swap4 + dup6 + dup8 tag_5 jump\t// in - tag_38: + tag_40: /* \"C\":414:422 immutVar */ immutable(\"0xe4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10\") /* \"C\":392:422 stateVar + this.f() + immutVar */ @@ -259,7 +243,7 @@ sub_0: assembly { add swap1 jump - tag_40: + tag_38: sub swap1 return @@ -303,10 +287,10 @@ sub_0: assembly { /* \"C\":79:428 contract C... */ swap4 /* \"C\":392:411 stateVar + this.f() */ - tag_38 + tag_40 /* \"C\":79:428 contract C... */ swap4 - tag_40 + tag_38 swap7 0x40 mstore @@ -328,12 +312,7 @@ sub_0: assembly { mstore mstore(0x04, 0x41) 0x24 - swap5 - pop - swap3 - pop - pop - pop + swap1 revert /* \"C\":403:411 this.f() */ tag_41: @@ -343,10 +322,6 @@ sub_0: assembly { jump(tag_42) tag_34: /* \"C\":79:428 contract C... */ - swap3 - pop - pop - pop mload(0x40) swap1 returndatasize @@ -422,25 +397,16 @@ sub_0: assembly { swap2 sub slt - tag_53 + tag_8 jumpi mload swap1 jump\t// out - tag_53: - pop - pop - 0x00 - dup1 - revert auxdata: } "}}},"D":{"D":{"evm":{"assembly":" /* \"D\":91:166 contract D is C(3)... */ 0xa0 - dup1 - 0x40 - mstore jumpi(tag_6, callvalue) 0x1f bytecodeSize @@ -498,15 +464,10 @@ tag_8: assignImmutable(\"0xe4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10\") return tag_6: - pop 0x00 dup1 revert tag_4: - pop - pop - pop - pop mstore(0x00, shl(0xe0, 0x4e487b71)) mstore(0x04, 0x41) revert(0x00, 0x24) @@ -514,13 +475,8 @@ tag_4: tag_1: /* \"C\":147:149 42 */ mstore(0x80, 0x2a) - /* \"D\":107:108 3 */ - 0x03 - /* \"C\":203:219 stateVar = _init */ - 0x00 - /* \"D\":91:166 contract D is C(3)... */ - sstore sub(shl(0xff, 0x01), 0x04) + /* \"D\":91:166 contract D is C(3)... */ dup2 sgt 0x01 @@ -531,27 +487,15 @@ tag_1: 0x03 /* \"D\":91:166 contract D is C(3)... */ add - /* \"C\":203:219 stateVar = _init */ 0x00 - /* \"D\":91:166 contract D is C(3)... */ sstore /* \"D\":113:164 constructor(int _init2)... */ jump\t// out /* \"D\":91:166 contract D is C(3)... */ tag_9: - pop - pop - shl(0xe0, 0x4e487b71) - /* \"C\":203:219 stateVar = _init */ - 0x00 - /* \"D\":91:166 contract D is C(3)... */ - mstore + mstore(0x00, shl(0xe0, 0x4e487b71)) mstore(0x04, 0x11) - 0x24 - /* \"C\":203:219 stateVar = _init */ - 0x00 - /* \"D\":91:166 contract D is C(3)... */ - revert + revert(0x00, 0x24) stop sub_0: assembly { @@ -597,15 +541,12 @@ sub_0: assembly { tag_2 jump\t// in tag_9: - swap1 - pop jumpi(tag_19, callvalue) dup1 add(calldatasize, not(0x03)) slt tag_19 jumpi - pop 0x20 /* \"C\":290:298 immutVar */ immutable(\"0xe4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10\") @@ -703,21 +644,16 @@ sub_0: assembly { jumpi /* \"D\":91:166 contract D is C(3)... */ tag_37: - /* \"C\":392:411 stateVar + this.f() */ - pop - pop tag_38 /* \"C\":392:422 stateVar + this.f() + immutVar */ tag_39 /* \"C\":392:411 stateVar + this.f() */ - swap2 - /* \"D\":91:166 contract D is C(3)... */ tag_40 - /* \"C\":392:411 stateVar + this.f() */ - swap4 + dup6 + dup8 tag_5 jump\t// in - tag_38: + tag_40: /* \"C\":414:422 immutVar */ immutable(\"0xe4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10\") /* \"C\":392:422 stateVar + this.f() + immutVar */ @@ -738,7 +674,7 @@ sub_0: assembly { add swap1 jump - tag_40: + tag_38: sub swap1 return @@ -782,10 +718,10 @@ sub_0: assembly { /* \"D\":91:166 contract D is C(3)... */ swap4 /* \"C\":392:411 stateVar + this.f() */ - tag_38 + tag_40 /* \"D\":91:166 contract D is C(3)... */ swap4 - tag_40 + tag_38 swap7 0x40 mstore @@ -807,12 +743,7 @@ sub_0: assembly { mstore mstore(0x04, 0x41) 0x24 - swap5 - pop - swap3 - pop - pop - pop + swap1 revert /* \"C\":403:411 this.f() */ tag_41: @@ -822,10 +753,6 @@ sub_0: assembly { jump(tag_42) tag_34: /* \"D\":91:166 contract D is C(3)... */ - swap3 - pop - pop - pop mload(0x40) swap1 returndatasize @@ -901,17 +828,11 @@ sub_0: assembly { swap2 sub slt - tag_53 + tag_8 jumpi mload swap1 jump\t// out - tag_53: - pop - pop - 0x00 - dup1 - revert auxdata: } diff --git a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_all/output.json b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_all/output.json index 16236251d308..30895c160acd 100644 --- a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_all/output.json +++ b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_all/output.json @@ -60,14 +60,7 @@ sub_0: assembly { } " }, - "ir": "/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - - + "ir": " /// @use-src 0:\"C\" object \"C_6\" { code { @@ -181,14 +174,7 @@ object \"C_6\" { } ", - "irOptimized": "/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - -/// @use-src 0:\"C\" + "irOptimized": "/// @use-src 0:\"C\" object \"C_6\" { code { { @@ -206,16 +192,14 @@ object \"C_6\" { code { { /// @src 0:60:101 \"contract C {...\" - let _1 := memoryguard(0x80) - mstore(64, _1) if iszero(lt(calldatasize(), 4)) { - let _2 := 0 - if eq(0x26121ff0, shr(224, calldataload(_2))) + let _1 := 0 + if eq(0x26121ff0, shr(224, calldataload(_1))) { - if callvalue() { revert(_2, _2) } - if slt(add(calldatasize(), not(3)), _2) { revert(_2, _2) } - return(_1, _2) + if callvalue() { revert(_1, _1) } + if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } + return(memoryguard(0x80), _1) } } revert(0, 0) diff --git a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_location_only/output.json b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_location_only/output.json index d017c8e9c24c..6ee9874d386b 100644 --- a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_location_only/output.json +++ b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_location_only/output.json @@ -60,14 +60,7 @@ sub_0: assembly { } " }, - "ir": "/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - - + "ir": " /// @use-src 0:\"C\" object \"C_6\" { code { @@ -180,14 +173,7 @@ object \"C_6\" { } ", - "irOptimized": "/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - -/// @use-src 0:\"C\" + "irOptimized": "/// @use-src 0:\"C\" object \"C_6\" { code { { @@ -205,16 +191,14 @@ object \"C_6\" { code { { /// @src 0:60:101 - let _1 := memoryguard(0x80) - mstore(64, _1) if iszero(lt(calldatasize(), 4)) { - let _2 := 0 - if eq(0x26121ff0, shr(224, calldataload(_2))) + let _1 := 0 + if eq(0x26121ff0, shr(224, calldataload(_1))) { - if callvalue() { revert(_2, _2) } - if slt(add(calldatasize(), not(3)), _2) { revert(_2, _2) } - return(_1, _2) + if callvalue() { revert(_1, _1) } + if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } + return(memoryguard(0x80), _1) } } revert(0, 0) diff --git a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_none/output.json b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_none/output.json index afe07fad9350..a32ee058062a 100644 --- a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_none/output.json +++ b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_none/output.json @@ -57,14 +57,7 @@ sub_0: assembly { } " }, - "ir": "/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - - + "ir": " /// @use-src 0:\"C\" object \"C_6\" { code { @@ -171,14 +164,7 @@ object \"C_6\" { } ", - "irOptimized": "/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - -/// @use-src 0:\"C\" + "irOptimized": "/// @use-src 0:\"C\" object \"C_6\" { code { { @@ -194,16 +180,14 @@ object \"C_6\" { object \"C_6_deployed\" { code { { - let _1 := memoryguard(0x80) - mstore(64, _1) if iszero(lt(calldatasize(), 4)) { - let _2 := 0 - if eq(0x26121ff0, shr(224, calldataload(_2))) + let _1 := 0 + if eq(0x26121ff0, shr(224, calldataload(_1))) { - if callvalue() { revert(_2, _2) } - if slt(add(calldatasize(), not(3)), _2) { revert(_2, _2) } - return(_1, _2) + if callvalue() { revert(_1, _1) } + if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } + return(memoryguard(0x80), _1) } } revert(0, 0) diff --git a/test/cmdlineTests/standard_debug_info_in_yul_location/output.json b/test/cmdlineTests/standard_debug_info_in_yul_location/output.json index f593301bcc26..a57dbdc35cf3 100644 --- a/test/cmdlineTests/standard_debug_info_in_yul_location/output.json +++ b/test/cmdlineTests/standard_debug_info_in_yul_location/output.json @@ -1,11 +1,4 @@ -{"contracts":{"C":{"C":{"ir":"/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - - +{"contracts":{"C":{"C":{"ir":" /// @use-src 0:\"C\" object \"C_54\" { code { @@ -609,20 +602,12 @@ object \"C_54\" { } -","irOptimized":"/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - -/// @use-src 0:\"C\" +","irOptimized":"/// @use-src 0:\"C\" object \"C_54\" { code { { /// @src 0:79:435 \"contract C...\" let _1 := memoryguard(0xa0) - mstore(64, _1) if callvalue() { revert(0, 0) } let programSize := datasize(\"C_54\") let argSize := sub(codesize(), programSize) @@ -777,14 +762,7 @@ object \"C_54\" { data \".metadata\" hex\"\" } } -"}},"D":{"D":{"ir":"/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - - +"}},"D":{"D":{"ir":" /// @use-src 0:\"C\", 1:\"D\" object \"D_72\" { code { @@ -1456,20 +1434,12 @@ object \"D_72\" { } -","irOptimized":"/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - -/// @use-src 0:\"C\", 1:\"D\" +","irOptimized":"/// @use-src 0:\"C\", 1:\"D\" object \"D_72\" { code { { /// @src 1:91:166 \"contract D is C(3)...\" let _1 := memoryguard(0xa0) - mstore(64, _1) if callvalue() { revert(0, 0) } let programSize := datasize(\"D_72\") let argSize := sub(codesize(), programSize) @@ -1500,15 +1470,13 @@ object \"D_72\" { /// @src 0:154:156 \"42\" mstore(128, 0x2a) /// @src 1:91:166 \"contract D is C(3)...\" - sstore(/** @src 0:210:226 \"stateVar = _init\" */ 0x00, /** @src 1:107:108 \"3\" */ 0x03) - /// @src 1:91:166 \"contract D is C(3)...\" if and(1, sgt(var_init2, sub(shl(255, 1), 4))) { - mstore(/** @src 0:210:226 \"stateVar = _init\" */ 0x00, /** @src 1:91:166 \"contract D is C(3)...\" */ shl(224, 0x4e487b71)) + mstore(0, shl(224, 0x4e487b71)) mstore(4, 0x11) - revert(/** @src 0:210:226 \"stateVar = _init\" */ 0x00, /** @src 1:91:166 \"contract D is C(3)...\" */ 0x24) + revert(0, 0x24) } - sstore(/** @src 0:210:226 \"stateVar = _init\" */ 0x00, /** @src 1:91:166 \"contract D is C(3)...\" */ add(/** @src 1:107:108 \"3\" */ 0x03, /** @src 1:91:166 \"contract D is C(3)...\" */ var_init2)) + sstore(/** @src -1:-1:-1 */ 0, /** @src 1:91:166 \"contract D is C(3)...\" */ add(/** @src 1:107:108 \"3\" */ 0x03, /** @src 1:91:166 \"contract D is C(3)...\" */ var_init2)) } } /// @use-src 0:\"C\", 1:\"D\" diff --git a/test/cmdlineTests/standard_irOptimized_requested/output.json b/test/cmdlineTests/standard_irOptimized_requested/output.json index 85b861602053..f919764114b7 100644 --- a/test/cmdlineTests/standard_irOptimized_requested/output.json +++ b/test/cmdlineTests/standard_irOptimized_requested/output.json @@ -1,11 +1,4 @@ -{"contracts":{"A":{"C":{"irOptimized":"/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - -/// @use-src 0:\"A\" +{"contracts":{"A":{"C":{"irOptimized":"/// @use-src 0:\"A\" object \"C_7\" { code { /// @src 0:79:121 \"contract C { function f() public pure {} }\" diff --git a/test/cmdlineTests/standard_ir_requested/output.json b/test/cmdlineTests/standard_ir_requested/output.json index 1e7f8dec3b40..78e2aebce681 100644 --- a/test/cmdlineTests/standard_ir_requested/output.json +++ b/test/cmdlineTests/standard_ir_requested/output.json @@ -1,11 +1,4 @@ -{"contracts":{"A":{"C":{"ir":"/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - - +{"contracts":{"A":{"C":{"ir":" /// @use-src 0:\"A\" object \"C_7\" { code { diff --git a/test/cmdlineTests/standard_viair_requested/output.json b/test/cmdlineTests/standard_viair_requested/output.json index 881a4bad4958..f08a5d3027c1 100644 --- a/test/cmdlineTests/standard_viair_requested/output.json +++ b/test/cmdlineTests/standard_viair_requested/output.json @@ -1,11 +1,4 @@ -{"contracts":{"A":{"C":{"evm":{"bytecode":{"generatedSources":[],"object":""},"deployedBytecode":{"object":""}},"ir":"/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - - +{"contracts":{"A":{"C":{"evm":{"bytecode":{"generatedSources":[],"object":""},"deployedBytecode":{"object":""}},"ir":" /// @use-src 0:\"A\" object \"C_3\" { code { @@ -67,14 +60,7 @@ object \"C_3\" { } -"},"D":{"evm":{"bytecode":{"generatedSources":[],"object":""},"deployedBytecode":{"object":""}},"ir":"/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - - +"},"D":{"evm":{"bytecode":{"generatedSources":[],"object":""},"deployedBytecode":{"object":""}},"ir":" /// @use-src 0:\"A\" object \"D_16\" { code { @@ -207,12 +193,6 @@ object \"D_16\" { /// @src 0:93:146 \"contract D { function f() public { C c = new C(); } }\" } - /*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ /// @use-src 0:\"A\" object \"C_3\" { diff --git a/test/cmdlineTests/standard_yul/output.json b/test/cmdlineTests/standard_yul/output.json index 671b8ffa7c94..63da252cd236 100644 --- a/test/cmdlineTests/standard_yul/output.json +++ b/test/cmdlineTests/standard_yul/output.json @@ -26,4 +26,4 @@ sstore(add(x, 0), 0) } } -"}}},"errors":[{"component":"general","formattedMessage":"Yul is still experimental. Please use the output with care.","message":"Yul is still experimental. Please use the output with care.","severity":"warning","type":"Warning"}]} +"}}},} diff --git a/test/cmdlineTests/standard_yul_debug_info_print_all/output.json b/test/cmdlineTests/standard_yul_debug_info_print_all/output.json index b57bc9188916..70122b9a7c8a 100644 --- a/test/cmdlineTests/standard_yul_debug_info_print_all/output.json +++ b/test/cmdlineTests/standard_yul_debug_info_print_all/output.json @@ -23,14 +23,4 @@ tag_3: } } }, - "errors": - [ - { - "component": "general", - "formattedMessage": "Yul is still experimental. Please use the output with care.", - "message": "Yul is still experimental. Please use the output with care.", - "severity": "warning", - "type": "Warning" - } - ] -} + } diff --git a/test/cmdlineTests/standard_yul_debug_info_print_location_only/output.json b/test/cmdlineTests/standard_yul_debug_info_print_location_only/output.json index 0ce9fd2de36c..e7b1a694366b 100644 --- a/test/cmdlineTests/standard_yul_debug_info_print_location_only/output.json +++ b/test/cmdlineTests/standard_yul_debug_info_print_location_only/output.json @@ -23,14 +23,4 @@ tag_3: } } }, - "errors": - [ - { - "component": "general", - "formattedMessage": "Yul is still experimental. Please use the output with care.", - "message": "Yul is still experimental. Please use the output with care.", - "severity": "warning", - "type": "Warning" - } - ] -} + } diff --git a/test/cmdlineTests/standard_yul_debug_info_print_none/output.json b/test/cmdlineTests/standard_yul_debug_info_print_none/output.json index 8203ee0a2646..b8b5ff913052 100644 --- a/test/cmdlineTests/standard_yul_debug_info_print_none/output.json +++ b/test/cmdlineTests/standard_yul_debug_info_print_none/output.json @@ -21,14 +21,4 @@ tag_3: } } }, - "errors": - [ - { - "component": "general", - "formattedMessage": "Yul is still experimental. Please use the output with care.", - "message": "Yul is still experimental. Please use the output with care.", - "severity": "warning", - "type": "Warning" - } - ] -} + } diff --git a/test/cmdlineTests/standard_yul_embedded_object_name/output.json b/test/cmdlineTests/standard_yul_embedded_object_name/output.json index 32a2a647a030..0967ef424bce 100644 --- a/test/cmdlineTests/standard_yul_embedded_object_name/output.json +++ b/test/cmdlineTests/standard_yul_embedded_object_name/output.json @@ -1 +1 @@ -{"errors":[{"component":"general","formattedMessage":"Yul is still experimental. Please use the output with care.","message":"Yul is still experimental. Please use the output with care.","severity":"warning","type":"Warning"}]} +{} diff --git a/test/cmdlineTests/standard_yul_immutable_references/output.json b/test/cmdlineTests/standard_yul_immutable_references/output.json index 42361097de78..fe9bd66a6552 100644 --- a/test/cmdlineTests/standard_yul_immutable_references/output.json +++ b/test/cmdlineTests/standard_yul_immutable_references/output.json @@ -39,14 +39,4 @@ } } }, - "errors": - [ - { - "component": "general", - "formattedMessage": "Yul is still experimental. Please use the output with care.", - "message": "Yul is still experimental. Please use the output with care.", - "severity": "warning", - "type": "Warning" - } - ] -} + } diff --git a/test/cmdlineTests/standard_yul_invalid_object_name/output.json b/test/cmdlineTests/standard_yul_invalid_object_name/output.json index 32a2a647a030..0967ef424bce 100644 --- a/test/cmdlineTests/standard_yul_invalid_object_name/output.json +++ b/test/cmdlineTests/standard_yul_invalid_object_name/output.json @@ -1 +1 @@ -{"errors":[{"component":"general","formattedMessage":"Yul is still experimental. Please use the output with care.","message":"Yul is still experimental. Please use the output with care.","severity":"warning","type":"Warning"}]} +{} diff --git a/test/cmdlineTests/standard_yul_object/output.json b/test/cmdlineTests/standard_yul_object/output.json index 49aaa6a747d7..96903c45227c 100644 --- a/test/cmdlineTests/standard_yul_object/output.json +++ b/test/cmdlineTests/standard_yul_object/output.json @@ -28,4 +28,4 @@ data_4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45 616263 } data \"DataName\" hex\"616263\" } -"}}},"errors":[{"component":"general","formattedMessage":"Yul is still experimental. Please use the output with care.","message":"Yul is still experimental. Please use the output with care.","severity":"warning","type":"Warning"}]} +"}}},} diff --git a/test/cmdlineTests/standard_yul_object_name/output.json b/test/cmdlineTests/standard_yul_object_name/output.json index 45280c8a1bf4..b4a9e36856df 100644 --- a/test/cmdlineTests/standard_yul_object_name/output.json +++ b/test/cmdlineTests/standard_yul_object_name/output.json @@ -43,4 +43,4 @@ sub_0: assembly { code { revert(0, 0) } } } -"}}},"errors":[{"component":"general","formattedMessage":"Yul is still experimental. Please use the output with care.","message":"Yul is still experimental. Please use the output with care.","severity":"warning","type":"Warning"}]} +"}}},} diff --git a/test/cmdlineTests/standard_yul_optimiserSteps/output.json b/test/cmdlineTests/standard_yul_optimiserSteps/output.json index 4071589cbe84..c4b5f6e0e01d 100644 --- a/test/cmdlineTests/standard_yul_optimiserSteps/output.json +++ b/test/cmdlineTests/standard_yul_optimiserSteps/output.json @@ -21,4 +21,4 @@ } } } -"}}},"errors":[{"component":"general","formattedMessage":"Yul is still experimental. Please use the output with care.","message":"Yul is still experimental. Please use the output with care.","severity":"warning","type":"Warning"}]} +"}}},} diff --git a/test/cmdlineTests/standard_yul_optimized/output.json b/test/cmdlineTests/standard_yul_optimized/output.json index 371a0816b6a8..40fd18d2b183 100644 --- a/test/cmdlineTests/standard_yul_optimized/output.json +++ b/test/cmdlineTests/standard_yul_optimized/output.json @@ -16,4 +16,4 @@ ","irOptimized":"object \"object\" { code { { sstore(mload(0), 0) } } } -"}}},"errors":[{"component":"general","formattedMessage":"Yul is still experimental. Please use the output with care.","message":"Yul is still experimental. Please use the output with care.","severity":"warning","type":"Warning"}]} +"}}},} diff --git a/test/cmdlineTests/standard_yul_stack_opt/output.json b/test/cmdlineTests/standard_yul_stack_opt/output.json index f041adaa866b..1bc924d9592f 100644 --- a/test/cmdlineTests/standard_yul_stack_opt/output.json +++ b/test/cmdlineTests/standard_yul_stack_opt/output.json @@ -12,4 +12,4 @@ sstore /* \"A\":0:72 */ stop -"}}}},"errors":[{"component":"general","formattedMessage":"Yul is still experimental. Please use the output with care.","message":"Yul is still experimental. Please use the output with care.","severity":"warning","type":"Warning"}]} +"}}}},} diff --git a/test/cmdlineTests/standard_yul_stack_opt_disabled/output.json b/test/cmdlineTests/standard_yul_stack_opt_disabled/output.json index a4670cf26108..8fa9f92ce0e4 100644 --- a/test/cmdlineTests/standard_yul_stack_opt_disabled/output.json +++ b/test/cmdlineTests/standard_yul_stack_opt_disabled/output.json @@ -15,4 +15,4 @@ /* \"A\":0:72 */ pop pop -"}}}},"errors":[{"component":"general","formattedMessage":"Yul is still experimental. Please use the output with care.","message":"Yul is still experimental. Please use the output with care.","severity":"warning","type":"Warning"}]} +"}}}},} diff --git a/test/cmdlineTests/strict_asm_debug_info_print_all/err b/test/cmdlineTests/strict_asm_debug_info_print_all/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/strict_asm_debug_info_print_all/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/strict_asm_debug_info_print_location_only/err b/test/cmdlineTests/strict_asm_debug_info_print_location_only/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/strict_asm_debug_info_print_location_only/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/strict_asm_debug_info_print_none/err b/test/cmdlineTests/strict_asm_debug_info_print_none/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/strict_asm_debug_info_print_none/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/strict_asm_jump/err b/test/cmdlineTests/strict_asm_jump/err index 866361af4db2..c0001f382533 100644 --- a/test/cmdlineTests/strict_asm_jump/err +++ b/test/cmdlineTests/strict_asm_jump/err @@ -1,4 +1,3 @@ -Warning: Yul is still experimental. Please use the output with care. Error: Function "jump" not found. --> strict_asm_jump/input.yul:1:3: | diff --git a/test/cmdlineTests/strict_asm_only_cr/err b/test/cmdlineTests/strict_asm_only_cr/err index 62ebc300d70b..0879e4f212db 100644 --- a/test/cmdlineTests/strict_asm_only_cr/err +++ b/test/cmdlineTests/strict_asm_only_cr/err @@ -1,4 +1,3 @@ -Warning: Yul is still experimental. Please use the output with care. Error: Expected keyword "object". --> strict_asm_only_cr/input.yul:1:2: | diff --git a/test/cmdlineTests/strict_asm_optimizer_steps/err b/test/cmdlineTests/strict_asm_optimizer_steps/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/strict_asm_optimizer_steps/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/strict_asm_output_selection_asm_only/err b/test/cmdlineTests/strict_asm_output_selection_asm_only/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/strict_asm_output_selection_asm_only/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/strict_asm_output_selection_bin_only/err b/test/cmdlineTests/strict_asm_output_selection_bin_only/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/strict_asm_output_selection_bin_only/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/strict_asm_output_selection_ewasm_ir_only/err b/test/cmdlineTests/strict_asm_output_selection_ewasm_ir_only/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/strict_asm_output_selection_ewasm_ir_only/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/strict_asm_output_selection_ewasm_only/err b/test/cmdlineTests/strict_asm_output_selection_ewasm_only/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/strict_asm_output_selection_ewasm_only/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/strict_asm_output_selection_ir_optimized_only/err b/test/cmdlineTests/strict_asm_output_selection_ir_optimized_only/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/strict_asm_output_selection_ir_optimized_only/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/viair_abicoder_v1/output b/test/cmdlineTests/viair_abicoder_v1/output index c71c535daa3c..1c4d6c90e260 100644 --- a/test/cmdlineTests/viair_abicoder_v1/output +++ b/test/cmdlineTests/viair_abicoder_v1/output @@ -1,11 +1,4 @@ IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"viair_abicoder_v1/input.sol" object "test_11" { diff --git a/test/cmdlineTests/viair_subobject_optimization/args b/test/cmdlineTests/viair_subobject_optimization/args new file mode 100644 index 000000000000..51e6fa5196d2 --- /dev/null +++ b/test/cmdlineTests/viair_subobject_optimization/args @@ -0,0 +1 @@ +--experimental-via-ir --optimize --asm \ No newline at end of file diff --git a/test/cmdlineTests/viair_subobject_optimization/input.sol b/test/cmdlineTests/viair_subobject_optimization/input.sol new file mode 100644 index 000000000000..74549134a6fd --- /dev/null +++ b/test/cmdlineTests/viair_subobject_optimization/input.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >0.0.0; + +contract C { + constructor(uint x) { + // In earlier versions of the compiler, the resulting assembly pushed the constant + // 0xFFFFFFFFFFFFFFFF42 directly in the subassembly of D, while it was optimized to + // ``sub(shl(0x48, 0x01), 0xbe)`` when C was compiled in isolation. + // Now the assembly is expected to contain two instances of ``sub(shl(0x48, 0x01), 0xbe)``, + // one in the creation code of ``C`` directly, one in a subassembly of ``D``. + // The constant 0xFFFFFFFFFFFFFFFF42 should not occur in the assembly output at all. + if (x == 0xFFFFFFFFFFFFFFFF42) + revert(); + } +} +contract D { + function f() public pure returns (bytes memory) { + return type(C).creationCode; + } +} diff --git a/test/cmdlineTests/viair_subobject_optimization/output b/test/cmdlineTests/viair_subobject_optimization/output new file mode 100644 index 000000000000..5d4e894801c7 --- /dev/null +++ b/test/cmdlineTests/viair_subobject_optimization/output @@ -0,0 +1,353 @@ + +======= viair_subobject_optimization/input.sol:C ======= +EVM assembly: + /* "viair_subobject_optimization/input.sol":61:668 contract C {... */ + 0x80 + jumpi(tag_6, callvalue) + 0x1f + bytecodeSize + codesize + dup2 + swap1 + sub + swap2 + dup3 + add + not(0x1f) + and + dup4 + add + swap2 + sub(shl(0x40, 0x01), 0x01) + dup4 + gt + dup5 + dup5 + lt + or + tag_4 + jumpi + dup1 + dup5 + swap3 + 0x20 + swap5 + 0x40 + mstore + dup4 + codecopy + dup2 + add + sub + slt + tag_6 + jumpi + tag_8 + swap1 + mload + tag_1 + jump // in +tag_8: + mload(0x40) + dataSize(sub_0) + swap1 + dup2 + dataOffset(sub_0) + dup3 + codecopy + return +tag_6: + 0x00 + dup1 + revert +tag_4: + mstore(0x00, shl(0xe0, 0x4e487b71)) + mstore(0x04, 0x41) + revert(0x00, 0x24) + /* "viair_subobject_optimization/input.sol":76:666 constructor(uint x) {... */ +tag_1: + sub(shl(0x48, 0x01), 0xbe) + /* "viair_subobject_optimization/input.sol":620:645 x == 0xFFFFFFFFFFFFFFFF42 */ + eq + /* "viair_subobject_optimization/input.sol":616:661 if (x == 0xFFFFFFFFFFFFFFFF42)... */ + tag_6 + jumpi + /* "viair_subobject_optimization/input.sol":76:666 constructor(uint x) {... */ + jump // out +stop + +sub_0: assembly { + /* "viair_subobject_optimization/input.sol":61:668 contract C {... */ + 0x00 + dup1 + revert + + auxdata: +} + + +======= viair_subobject_optimization/input.sol:D ======= +EVM assembly: + /* "viair_subobject_optimization/input.sol":669:772 contract D {... */ + 0x80 + dup1 + 0x40 + mstore + jumpi(tag_1, callvalue) + dataSize(sub_0) + swap1 + dup2 + dataOffset(sub_0) + dup3 + codecopy + return +tag_1: + 0x00 + dup1 + revert +stop + +sub_0: assembly { + /* "viair_subobject_optimization/input.sol":669:772 contract D {... */ + 0x80 + jumpi(tag_2, iszero(lt(calldatasize, 0x04))) + 0x00 + dup1 + revert + tag_2: + 0x00 + swap1 + dup2 + calldataload + 0xe0 + shr + 0x26121ff0 + eq + tag_4 + jumpi + 0x00 + dup1 + revert + tag_4: + jumpi(tag_8, callvalue) + dup2 + add(calldatasize, not(0x03)) + slt + tag_8 + jumpi + /* "viair_subobject_optimization/input.sol":745:765 type(C).creationCode */ + dataSize(sub_0) + /* "viair_subobject_optimization/input.sol":669:772 contract D {... */ + 0x3f + dup2 + add + not(0x1f) + and + dup3 + add + 0xffffffffffffffff + dup2 + gt + dup4 + dup3 + lt + or + tag_10 + jumpi + tag_12 + swap4 + pop + 0x40 + mstore + /* "viair_subobject_optimization/input.sol":745:765 type(C).creationCode */ + dup1 + dup3 + mstore + dataOffset(sub_0) + 0x20 + dup4 + add + codecopy + /* "viair_subobject_optimization/input.sol":669:772 contract D {... */ + mload(0x40) + swap2 + dup3 + swap2 + dup3 + tag_1 + jump // in + tag_12: + sub + swap1 + return + tag_10: + shl(0xe0, 0x4e487b71) + dup5 + mstore + mstore(0x04, 0x41) + 0x24 + dup5 + revert + tag_8: + pop + dup1 + revert + tag_1: + swap2 + swap1 + swap2 + 0x20 + dup1 + dup3 + mstore + dup4 + mload + swap1 + dup2 + dup2 + dup5 + add + mstore + 0x00 + swap5 + tag_13: + dup3 + dup7 + lt + tag_14 + jumpi + pop + pop + dup1 + 0x40 + swap4 + swap5 + gt + tag_16 + jumpi + tag_17: + 0x1f + add + not(0x1f) + and + add + add + swap1 + jump // out + tag_16: + 0x00 + dup4 + dup3 + dup5 + add + add + mstore + jump(tag_17) + tag_14: + dup6 + dup2 + add + dup3 + add + mload + dup5 + dup8 + add + 0x40 + add + mstore + swap5 + dup2 + add + swap5 + jump(tag_13) + stop + + sub_0: assembly { + /* "viair_subobject_optimization/input.sol":61:668 contract C {... */ + 0x80 + jumpi(tag_6, callvalue) + 0x1f + bytecodeSize + codesize + dup2 + swap1 + sub + swap2 + dup3 + add + not(0x1f) + and + dup4 + add + swap2 + sub(shl(0x40, 0x01), 0x01) + dup4 + gt + dup5 + dup5 + lt + or + tag_4 + jumpi + dup1 + dup5 + swap3 + 0x20 + swap5 + 0x40 + mstore + dup4 + codecopy + dup2 + add + sub + slt + tag_6 + jumpi + tag_8 + swap1 + mload + tag_1 + jump // in + tag_8: + mload(0x40) + dataSize(sub_0) + swap1 + dup2 + dataOffset(sub_0) + dup3 + codecopy + return + tag_6: + 0x00 + dup1 + revert + tag_4: + mstore(0x00, shl(0xe0, 0x4e487b71)) + mstore(0x04, 0x41) + revert(0x00, 0x24) + /* "viair_subobject_optimization/input.sol":76:666 constructor(uint x) {... */ + tag_1: + sub(shl(0x48, 0x01), 0xbe) + /* "viair_subobject_optimization/input.sol":620:645 x == 0xFFFFFFFFFFFFFFFF42 */ + eq + /* "viair_subobject_optimization/input.sol":616:661 if (x == 0xFFFFFFFFFFFFFFFF42)... */ + tag_6 + jumpi + /* "viair_subobject_optimization/input.sol":76:666 constructor(uint x) {... */ + jump // out + stop + + sub_0: assembly { + /* "viair_subobject_optimization/input.sol":61:668 contract C {... */ + 0x00 + dup1 + revert + + auxdata: + } + } + + auxdata: +} diff --git a/test/cmdlineTests/viair_subobjects/args b/test/cmdlineTests/viair_subobjects/args index 1a5580b80bb8..5331d83ac444 100644 --- a/test/cmdlineTests/viair_subobjects/args +++ b/test/cmdlineTests/viair_subobjects/args @@ -1 +1 @@ ---ir-optimized --experimental-via-ir --optimize --bin --bin-runtime \ No newline at end of file +--ir-optimized --via-ir --optimize --bin --bin-runtime \ No newline at end of file diff --git a/test/cmdlineTests/viair_subobjects/output b/test/cmdlineTests/viair_subobjects/output index 4b388665cf37..51fdae92449d 100644 --- a/test/cmdlineTests/viair_subobjects/output +++ b/test/cmdlineTests/viair_subobjects/output @@ -5,13 +5,6 @@ Binary: Binary of the runtime part: Optimized IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"viair_subobjects/input.sol" object "C_3" { code { @@ -30,7 +23,6 @@ object "C_3" { code { { /// @src 0:82:95 "contract C {}" - mstore(64, memoryguard(0x80)) revert(0, 0) } } @@ -45,13 +37,6 @@ Binary: Binary of the runtime part: Optimized IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"viair_subobjects/input.sol" object "D_16" { code { @@ -122,7 +107,6 @@ object "D_16" { code { { /// @src 0:82:95 "contract C {}" - mstore(64, memoryguard(0x80)) revert(0, 0) } } diff --git a/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/err b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/wasm_to_wasm_memory_instructions_alignment/err b/test/cmdlineTests/wasm_to_wasm_memory_instructions_alignment/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/wasm_to_wasm_memory_instructions_alignment/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/yul_function_name_clashes/err b/test/cmdlineTests/yul_function_name_clashes/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/yul_function_name_clashes/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/yul_function_name_clashes_different_params/err b/test/cmdlineTests/yul_function_name_clashes_different_params/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/yul_function_name_clashes_different_params/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/yul_optimize_runs/err b/test/cmdlineTests/yul_optimize_runs/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/yul_optimize_runs/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/yul_optimize_runs/input.yul b/test/cmdlineTests/yul_optimize_runs/input.yul index 07c602a4a587..6088853e604f 100644 --- a/test/cmdlineTests/yul_optimize_runs/input.yul +++ b/test/cmdlineTests/yul_optimize_runs/input.yul @@ -1,10 +1,10 @@ object "RunsTest1" { code { // Deploy the contract - datacopy(0, dataoffset("Runtime"), datasize("Runtime")) - return(0, datasize("Runtime")) + datacopy(0, dataoffset("Runtime_deployed"), datasize("Runtime_deployed")) + return(0, datasize("Runtime_deployed")) } - object "Runtime" { + object "Runtime_deployed" { code { let funcSel := shl(224, 0xabc12345) sstore(0, funcSel) diff --git a/test/cmdlineTests/yul_optimize_runs/output b/test/cmdlineTests/yul_optimize_runs/output index b95184440df6..6f4ba83907cd 100644 --- a/test/cmdlineTests/yul_optimize_runs/output +++ b/test/cmdlineTests/yul_optimize_runs/output @@ -5,12 +5,12 @@ Pretty printed source: object "RunsTest1" { code { { - let _1 := datasize("Runtime") - datacopy(0, dataoffset("Runtime"), _1) + let _1 := datasize("Runtime_deployed") + datacopy(0, dataoffset("Runtime_deployed"), _1) return(0, _1) } } - object "Runtime" { + object "Runtime_deployed" { code { { sstore(0, 0xabc1234500000000000000000000000000000000000000000000000000000000) @@ -24,28 +24,28 @@ Binary representation: 602580600c6000396000f3fe7fabc123450000000000000000000000000000000000000000000000000000000060005500 Text representation: - /* "yul_optimize_runs/input.yul":106:125 */ + /* "yul_optimize_runs/input.yul":115:143 */ dataSize(sub_0) - /* "yul_optimize_runs/input.yul":83:104 */ + /* "yul_optimize_runs/input.yul":83:113 */ dup1 dataOffset(sub_0) /* "yul_optimize_runs/input.yul":80:81 */ 0x00 - /* "yul_optimize_runs/input.yul":71:126 */ + /* "yul_optimize_runs/input.yul":71:144 */ codecopy /* "yul_optimize_runs/input.yul":80:81 */ 0x00 - /* "yul_optimize_runs/input.yul":135:165 */ + /* "yul_optimize_runs/input.yul":153:192 */ return stop sub_0: assembly { - /* "yul_optimize_runs/input.yul":237:257 */ + /* "yul_optimize_runs/input.yul":273:293 */ 0xabc1234500000000000000000000000000000000000000000000000000000000 - /* "yul_optimize_runs/input.yul":277:278 */ + /* "yul_optimize_runs/input.yul":313:314 */ 0x00 - /* "yul_optimize_runs/input.yul":270:288 */ + /* "yul_optimize_runs/input.yul":306:324 */ sstore - /* "yul_optimize_runs/input.yul":208:298 */ + /* "yul_optimize_runs/input.yul":244:334 */ stop } diff --git a/test/cmdlineTests/yul_optimizer_steps/output b/test/cmdlineTests/yul_optimizer_steps/output index a88ce164ac67..bb68a48fa809 100644 --- a/test/cmdlineTests/yul_optimizer_steps/output +++ b/test/cmdlineTests/yul_optimizer_steps/output @@ -1,11 +1,4 @@ Optimized IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"yul_optimizer_steps/input.sol" object "C_7" { code { diff --git a/test/cmdlineTests/yul_optimizer_steps_nested_brackets/output b/test/cmdlineTests/yul_optimizer_steps_nested_brackets/output index 5b7c3fdb0158..1e19c3a5c8a3 100644 --- a/test/cmdlineTests/yul_optimizer_steps_nested_brackets/output +++ b/test/cmdlineTests/yul_optimizer_steps_nested_brackets/output @@ -1,11 +1,4 @@ Optimized IR: -/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - /// @use-src 0:"yul_optimizer_steps_nested_brackets/input.sol" object "C_6" { code { diff --git a/test/cmdlineTests/yul_string_format_ascii/output.json b/test/cmdlineTests/yul_string_format_ascii/output.json index 46dd577ebdac..3ff8779ffa73 100644 --- a/test/cmdlineTests/yul_string_format_ascii/output.json +++ b/test/cmdlineTests/yul_string_format_ascii/output.json @@ -1,11 +1,4 @@ -{"contracts":{"A":{"C":{"ir":"/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - - +{"contracts":{"A":{"C":{"ir":" /// @use-src 0:\"A\" object \"C_11\" { code { diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json index 0ffffa3a4343..a5aaa8633dd2 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json @@ -1,11 +1,4 @@ -{"contracts":{"A":{"C":{"ir":"/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - - +{"contracts":{"A":{"C":{"ir":" /// @use-src 0:\"A\" object \"C_11\" { code { diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json index 1fb10701555c..4cb4408cabbb 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json @@ -1,11 +1,4 @@ -{"contracts":{"A":{"C":{"ir":"/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - - +{"contracts":{"A":{"C":{"ir":" /// @use-src 0:\"A\" object \"C_11\" { code { diff --git a/test/cmdlineTests/yul_string_format_ascii_long/output.json b/test/cmdlineTests/yul_string_format_ascii_long/output.json index bf757e6855aa..e019e5c2fc28 100644 --- a/test/cmdlineTests/yul_string_format_ascii_long/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_long/output.json @@ -1,11 +1,4 @@ -{"contracts":{"A":{"C":{"ir":"/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - - +{"contracts":{"A":{"C":{"ir":" /// @use-src 0:\"A\" object \"C_11\" { code { diff --git a/test/cmdlineTests/yul_string_format_hex/output.json b/test/cmdlineTests/yul_string_format_hex/output.json index 0ff492ce4eb8..a4e1b1463c09 100644 --- a/test/cmdlineTests/yul_string_format_hex/output.json +++ b/test/cmdlineTests/yul_string_format_hex/output.json @@ -1,11 +1,4 @@ -{"contracts":{"A":{"C":{"ir":"/*=====================================================* - * WARNING * - * Solidity to Yul compilation is still EXPERIMENTAL * - * It can result in LOSS OF FUNDS or worse * - * !USE AT YOUR OWN RISK! * - *=====================================================*/ - - +{"contracts":{"A":{"C":{"ir":" /// @use-src 0:\"A\" object \"C_11\" { code { diff --git a/test/cmdlineTests/yul_to_wasm_source_location_crash/err b/test/cmdlineTests/yul_to_wasm_source_location_crash/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/yul_to_wasm_source_location_crash/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/yul_verbatim/err b/test/cmdlineTests/yul_verbatim/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/yul_verbatim/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/yul_verbatim_msize/err b/test/cmdlineTests/yul_verbatim_msize/err deleted file mode 100644 index 014a1178fa22..000000000000 --- a/test/cmdlineTests/yul_verbatim_msize/err +++ /dev/null @@ -1 +0,0 @@ -Warning: Yul is still experimental. Please use the output with care. diff --git a/test/externalTests.sh b/test/externalTests.sh index b3b46460bfd8..2c4c6f76cd60 100755 --- a/test/externalTests.sh +++ b/test/externalTests.sh @@ -39,7 +39,6 @@ printTask "Running external tests..." "{$REPO_ROOT}/test/externalTests/zeppelin.sh" "$@" "{$REPO_ROOT}/test/externalTests/gnosis.sh" "$@" -"{$REPO_ROOT}/test/externalTests/gnosis-v2.sh" "$@" "{$REPO_ROOT}/test/externalTests/colony.sh" "$@" "{$REPO_ROOT}/test/externalTests/ens.sh" "$@" "{$REPO_ROOT}/test/externalTests/trident.sh" "$@" diff --git a/test/externalTests/common.sh b/test/externalTests/common.sh index e4e1e3adfd87..9c68c882885d 100644 --- a/test/externalTests/common.sh +++ b/test/externalTests/common.sh @@ -233,7 +233,6 @@ function force_truffle_compiler_settings function name_hardhat_default_export { local config_file="$1" - local config_var_name="$2" local import="import {HardhatUserConfig} from 'hardhat/types';" local config="const config: HardhatUserConfig = {" @@ -241,6 +240,29 @@ function name_hardhat_default_export echo "export default config;" >> "$config_file" } +function force_hardhat_timeout +{ + local config_file="$1" + local config_var_name="$2" + local new_timeout="$3" + + printLog "Configuring Hardhat..." + echo "-------------------------------------" + echo "Timeout: ${new_timeout}" + echo "-------------------------------------" + + if [[ $config_file == *\.js ]]; then + [[ $config_var_name == "" ]] || assertFail + echo "module.exports.mocha = module.exports.mocha || {timeout: ${new_timeout}}" + echo "module.exports.mocha.timeout = ${new_timeout}" + else + [[ $config_file == *\.ts ]] || assertFail + [[ $config_var_name != "" ]] || assertFail + echo "${config_var_name}.mocha = ${config_var_name}.mocha ?? {timeout: ${new_timeout}};" + echo "${config_var_name}.mocha!.timeout = ${new_timeout}" + fi >> "$config_file" +} + function force_hardhat_compiler_binary { local config_file="$1" diff --git a/test/externalTests/elementfi.sh b/test/externalTests/elementfi.sh index 37d5b74104d6..74ed93a5c2bf 100755 --- a/test/externalTests/elementfi.sh +++ b/test/externalTests/elementfi.sh @@ -42,13 +42,12 @@ function elementfi_test local config_file="hardhat.config.ts" local config_var=config - local compile_only_presets=( - ir-optimize-evm+yul # Compiles but tests fail. See https://github.com/nomiclabs/hardhat/issues/2115 - ) + local compile_only_presets=() local settings_presets=( "${compile_only_presets[@]}" #ir-no-optimize # Compilation fails with "YulException: Variable var_amount_9311 is 10 slot(s) too deep inside the stack." #ir-optimize-evm-only # Compilation fails with "YulException: Variable var_amount_9311 is 10 slot(s) too deep inside the stack." + ir-optimize-evm+yul legacy-no-optimize legacy-optimize-evm-only legacy-optimize-evm+yul @@ -89,6 +88,19 @@ function elementfi_test # TODO: Remove when https://github.com/element-fi/elf-contracts/issues/243 is fixed. sed -i 's|^\s*require(_expiration - block\.timestamp < _unitSeconds);\s*$||g' contracts/ConvergentCurvePool.sol + # Disable tests that won't pass on the ir presets due to Hardhat heuristics. Note that this also disables + # them for other presets but that's fine - we want same code run for benchmarks to be comparable. + # TODO: Remove this when Hardhat adjusts heuristics for IR (https://github.com/nomiclabs/hardhat/issues/2115). + sed -i 's|it(\("fails to withdraw more shares than in balance"\)|it.skip(\1|g' test/compoundAssetProxyTest.ts + sed -i 's|it(\("should prevent withdrawal of Principal Tokens and Interest Tokens before the tranche expires "\)|it.skip(\1|g' test/trancheTest.ts + sed -i 's|it(\("should prevent withdrawal of more Principal Tokens and Interest Tokens than the user has"\)|it.skip(\1|g' test/trancheTest.ts + + # This test file is very flaky. There's one particular cases that fails randomly (see + # https://github.com/element-fi/elf-contracts/issues/240) but some others also depends on an external + # service which makes tests time out when that service is down. + # "ProviderError: Too Many Requests error received from eth-mainnet.alchemyapi.io" + rm test/mockERC20YearnVaultTest.ts + # Several tests fail unless we use the exact versions hard-coded in package-lock.json #neutralize_package_lock diff --git a/test/externalTests/euler.sh b/test/externalTests/euler.sh index b3b505051cad..39283bcd54f8 100755 --- a/test/externalTests/euler.sh +++ b/test/externalTests/euler.sh @@ -32,7 +32,10 @@ BINARY_PATH="$2" SELECTED_PRESETS="$3" function compile_fn { npm run compile; } -function test_fn { npx --no hardhat --no-compile test; } +function test_fn { + # The default timeout of 20000 ms is too short for unoptimized code (https://github.com/ethereum/solidity/pull/12765). + TEST_TIMEOUT=100000 npx --no hardhat --no-compile test +} function euler_test { diff --git a/test/externalTests/gnosis-v2.sh b/test/externalTests/gnosis-v2.sh deleted file mode 100755 index 6b0915b6a038..000000000000 --- a/test/externalTests/gnosis-v2.sh +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env bash - -# ------------------------------------------------------------------------------ -# This file is part of solidity. -# -# solidity is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# solidity is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with solidity. If not, see -# -# (c) 2020 solidity contributors. -#------------------------------------------------------------------------------ - -set -e - -source scripts/common.sh -source test/externalTests/common.sh - -REPO_ROOT=$(realpath "$(dirname "$0")/../..") - -verify_input "$@" -BINARY_TYPE="$1" -BINARY_PATH="$2" -SELECTED_PRESETS="$3" - -function compile_fn { npx truffle compile; } -function test_fn { npm test; } - -function gnosis_safe_test -{ - local repo="https://github.com/solidity-external-tests/safe-contracts.git" - local ref_type=branch - local ref="v2_080" - local config_file="truffle-config.js" - - local compile_only_presets=( - legacy-no-optimize # Compiles but migrations run out of gas: "Error: while migrating GnosisSafe: Returned error: base fee exceeds gas limit" - ) - local settings_presets=( - "${compile_only_presets[@]}" - #ir-no-optimize # Compilation fails with "YulException: Variable var_call_430_mpos is 1 slot(s) too deep inside the stack." - #ir-optimize-evm-only # Compilation fails with "YulException: Variable var_call_430_mpos is 1 slot(s) too deep inside the stack." - ir-optimize-evm+yul - legacy-optimize-evm-only - legacy-optimize-evm+yul - ) - - [[ $SELECTED_PRESETS != "" ]] || SELECTED_PRESETS=$(circleci_select_steps_multiarg "${settings_presets[@]}") - print_presets_or_exit "$SELECTED_PRESETS" - - setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$ref_type" "$ref" "$DIR" - [[ $BINARY_TYPE == native ]] && replace_global_solc "$BINARY_PATH" - - sed -i 's|github:gnosis/mock-contract#sol_0_5_0|github:solidity-external-tests/mock-contract#master_080|g' package.json - sed -i -E 's|"@gnosis.pm/util-contracts": "[^"]+"|"@gnosis.pm/util-contracts": "github:solidity-external-tests/util-contracts#solc-7_080"|g' package.json - - neutralize_package_lock - neutralize_package_json_hooks - force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc/dist" "$(first_word "$SELECTED_PRESETS")" - npm install --package-lock - npm install eth-gas-reporter - - replace_version_pragmas - [[ $BINARY_TYPE == solcjs ]] && force_solc_modules "${DIR}/solc/dist" - - for preset in $SELECTED_PRESETS; do - truffle_run_test "$config_file" "$BINARY_TYPE" "${DIR}/solc/dist" "$preset" "${compile_only_presets[*]}" compile_fn test_fn - store_benchmark_report truffle gnosis2 "$repo" "$preset" - done -} - -external_test Gnosis-Safe-V2 gnosis_safe_test diff --git a/test/externalTests/gnosis.sh b/test/externalTests/gnosis.sh index 82d1892f2d0a..ccfc6cf5c1c3 100755 --- a/test/externalTests/gnosis.sh +++ b/test/externalTests/gnosis.sh @@ -31,15 +31,16 @@ BINARY_TYPE="$1" BINARY_PATH="$2" SELECTED_PRESETS="$3" -function compile_fn { npx truffle compile; } +function compile_fn { npm run build; } function test_fn { npm test; } function gnosis_safe_test { - local repo="https://github.com/solidity-external-tests/safe-contracts.git" + local repo="https://github.com/gnosis/safe-contracts.git" local ref_type=branch - local ref="development_080" - local config_file="truffle-config.js" + local ref=main + local config_file="hardhat.config.ts" + local config_var=userConfig local compile_only_presets=() local settings_presets=( @@ -47,8 +48,8 @@ function gnosis_safe_test #ir-no-optimize # Compilation fails with "YulException: Variable var_call_430_mpos is 1 slot(s) too deep inside the stack." #ir-optimize-evm-only # Compilation fails with "YulException: Variable var_call_430_mpos is 1 slot(s) too deep inside the stack." ir-optimize-evm+yul - #legacy-no-optimize # Compilation fails with "Stack too deep" error - #legacy-optimize-evm-only # Compilation fails with "Stack too deep" error + legacy-no-optimize + legacy-optimize-evm-only legacy-optimize-evm+yul ) @@ -59,20 +60,33 @@ function gnosis_safe_test download_project "$repo" "$ref_type" "$ref" "$DIR" [[ $BINARY_TYPE == native ]] && replace_global_solc "$BINARY_PATH" - sed -i 's|github:gnosis/mock-contract#sol_0_5_0|github:solidity-external-tests/mock-contract#master_080|g' package.json + # NOTE: The patterns below intentionally have hard-coded versions. + # When the upstream updates them, there's a chance we can just remove the regex. + sed -i 's|"@gnosis\.pm/mock-contract": "\^4\.0\.0"|"@gnosis.pm/mock-contract": "github:solidity-external-tests/mock-contract#master_080"|g' package.json + sed -i 's|"@openzeppelin/contracts": "\^3\.4\.0"|"@openzeppelin/contracts": "^4.0.0"|g' package.json + + # Disable two tests failing due to Hardhat's heuristics not yet updated to handle solc 0.8.10. + # TODO: Remove this when Hardhat implements them (https://github.com/nomiclabs/hardhat/issues/2051). + sed -i "s|\(it\)\(('should revert if called directly', async () => {\)|\1.skip\2|g" test/handlers/CompatibilityFallbackHandler.spec.ts + + # Disable tests that won't pass on the ir presets due to Hardhat heuristics. Note that this also disables + # them for other presets but that's fine - we want same code run for benchmarks to be comparable. + # TODO: Remove this when Hardhat adjusts heuristics for IR (https://github.com/nomiclabs/hardhat/issues/2115). + sed -i "s|\(it\)\(('should not allow to call setup on singleton'\)|\1.skip\2|g" test/core/GnosisSafe.Setup.spec.ts neutralize_package_lock neutralize_package_json_hooks - force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc/dist" "$(first_word "$SELECTED_PRESETS")" - npm install --package-lock - npm install eth-gas-reporter + force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH" + force_hardhat_compiler_settings "$config_file" "$(first_word "$SELECTED_PRESETS")" "$config_var" + npm install + npm install hardhat-gas-reporter replace_version_pragmas [[ $BINARY_TYPE == solcjs ]] && force_solc_modules "${DIR}/solc/dist" for preset in $SELECTED_PRESETS; do - truffle_run_test "$config_file" "$BINARY_TYPE" "${DIR}/solc/dist" "$preset" "${compile_only_presets[*]}" compile_fn test_fn - store_benchmark_report truffle gnosis "$repo" "$preset" + hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn "$config_var" + store_benchmark_report hardhat gnosis "$repo" "$preset" done } diff --git a/test/externalTests/prb-math.sh b/test/externalTests/prb-math.sh index 01bdb76f183f..1d0a0dd86a32 100755 --- a/test/externalTests/prb-math.sh +++ b/test/externalTests/prb-math.sh @@ -43,13 +43,12 @@ function prb_math_test local config_file="hardhat.config.ts" local config_var="config" - local compile_only_presets=( - ir-optimize-evm+yul # Compiles but tests fail. See https://github.com/nomiclabs/hardhat/issues/2115 - ) + local compile_only_presets=() local settings_presets=( "${compile_only_presets[@]}" #ir-no-optimize # Compilation fails with "YulException: Variable var_y_1960 is 8 slot(s) too deep inside the stack." #ir-optimize-evm-only # Compilation fails with "YulException: Variable var_y_1960 is 8 slot(s) too deep inside the stack." + ir-optimize-evm+yul legacy-optimize-evm-only legacy-optimize-evm+yul legacy-no-optimize @@ -68,6 +67,26 @@ function prb_math_test # yarn.lock. Remove the config to restore Yarn 1.x. rm .yarnrc.yml + # Disable tests that won't pass on the ir presets due to Hardhat heuristics. Note that this also disables + # them for other presets but that's fine - we want same code run for benchmarks to be comparable. + # TODO: Remove this when Hardhat adjusts heuristics for IR (https://github.com/nomiclabs/hardhat/issues/2115). + pushd test/contracts/prbMathUd60x18/pure/ + sed -i 's|context(\("when the sum overflows"\)|context.skip(\1|g' add.test.ts + sed -i 's|context(\("when the sum does not overflow"\)|context.skip(\1|g' add.test.ts + sed -i 's|context(\("when both operands are zero"\)|context.skip(\1|g' avg.test.ts + sed -i 's|context(\("when one operand is zero and the other is not zero"\)|context.skip(\1|g' avg.test.ts + sed -i 's|context(\("when the denominator is zero"\)|context.skip(\1|g' div.test.ts + sed -i 's|context(\("when x is zero"\)|context.skip(\1|g' inv.test.ts + popd + pushd test/contracts/prbMathSd59x18/pure/ + sed -i 's|context(\("when the sum overflows"\)|context.skip(\1|g' add.test.ts + sed -i 's|context(\("when the sum underflows"\)|context.skip(\1|g' add.test.ts + sed -i 's|context(\("when the denominator is zero"\)|context.skip(\1|g' div.test.ts + sed -i 's|context(\("when x is zero"\)|context.skip(\1|g' inv.test.ts + sed -i 's|context(\("when the difference underflows"\)|context.skip(\1|g' sub.test.ts + sed -i 's|context(\("when the difference overflows"\)|context.skip(\1|g' sub.test.ts + popd + neutralize_package_lock neutralize_package_json_hooks force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH" diff --git a/test/externalTests/zeppelin.sh b/test/externalTests/zeppelin.sh index 4094c6936472..ab79a877593f 100755 --- a/test/externalTests/zeppelin.sh +++ b/test/externalTests/zeppelin.sh @@ -41,13 +41,12 @@ function zeppelin_test local ref="master" local config_file="hardhat.config.js" - local compile_only_presets=( - ir-optimize-evm+yul # Compiles but tests fail. See https://github.com/nomiclabs/hardhat/issues/2115 - ) + local compile_only_presets=() local settings_presets=( "${compile_only_presets[@]}" #ir-no-optimize # Compilation fails with "YulException: Variable var_account_852 is 4 slot(s) too deep inside the stack." #ir-optimize-evm-only # Compilation fails with "YulException: Variable var_account_852 is 4 slot(s) too deep inside the stack." + ir-optimize-evm+yul legacy-no-optimize legacy-optimize-evm-only legacy-optimize-evm+yul @@ -59,6 +58,19 @@ function zeppelin_test setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" download_project "$repo" "$ref_type" "$ref" "$DIR" + # Disable tests that won't pass on the ir presets due to Hardhat heuristics. Note that this also disables + # them for other presets but that's fine - we want same code run for benchmarks to be comparable. + # TODO: Remove this when Hardhat adjusts heuristics for IR (https://github.com/nomiclabs/hardhat/issues/2115). + pushd test/utils/ + sed -i "s|it(\('reverts \)|it.skip(\1|g" math/SafeMath.test.js + sed -i "s|it(\('reverts \)|it.skip(\1|g" math/SignedSafeMath.test.js + sed -i "s|it(\('reverts \)|it.skip(\1|g" structs/EnumerableSet.behavior.js + popd + + # In some cases Hardhat does not detect revert reasons properly via IR. + # TODO: Remove this when https://github.com/NomicFoundation/hardhat/issues/2453 gets fixed. + sed -i "s|it(\('reverts if the current value is 0'\)|it.skip(\1|g" test/utils/Counters.test.js + neutralize_package_json_hooks force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH" force_hardhat_compiler_settings "$config_file" "$(first_word "$SELECTED_PRESETS")" diff --git a/test/formal/redundant_store_unrelated.py b/test/formal/redundant_store_unrelated.py new file mode 100644 index 000000000000..2961d0099cba --- /dev/null +++ b/test/formal/redundant_store_unrelated.py @@ -0,0 +1,63 @@ +import sys +from z3 import Solver, Int, unsat + +""" +Tests that the conditions inside RedundantStoreEliminator::knownUnrelated +only return "unrelated" incorrectly if one of the operation reverts +due to large memory access. +""" + +n_bits = 256 + +solver = Solver() +solver.set("timeout", 60000) + +def restrict(x): + solver.add(x >= 0) + solver.add(x < 2**n_bits) + +def restrictedInt(x): + var = Int(x) + restrict(var) + return var + +start1 = restrictedInt('start1') +length1 = restrictedInt('length1') +start2 = restrictedInt('start2') +length2 = restrictedInt('length2') + +k = Int('k') +diff = Int('diff') +solver.add(diff == start2 - start1 + k * 2**n_bits) +restrict(diff) +# diff is the result of sub(start2, start1) in EVM + +# These are the conditions in the code. +solver.add(diff >= length1) +solver.add(diff <= 2**(n_bits-1)) + +# We check that the two conditions are conflicting: +# - overlap +# - start1 is small + +# Overlap: +# x is a potential point where the memory operations +# overlap. +# Note that we do not use wrapping arithmetic +# here, because it is not done in the EVM either. +# For example calldatacopy(2**256 - 2, 0, 10) +# (copy 10 bytes from calldata position zero to memory +# position 2**256 - 2) would not write to memory position +# zero either. +x = Int('x') +solver.add(start1 <= x) +solver.add(x < start1 + length1) +solver.add(start2 <= x) +solver.add(x < start2 + length2) + +# start1 is "small": +solver.add(start1 < 2**(n_bits-1)) + +if solver.check() != unsat: + print("Expected unsat but got something else") + sys.exit(1) diff --git a/test/libevmasm/Assembler.cpp b/test/libevmasm/Assembler.cpp index 78e598bcab89..3a31678164b9 100644 --- a/test/libevmasm/Assembler.cpp +++ b/test/libevmasm/Assembler.cpp @@ -58,11 +58,11 @@ BOOST_AUTO_TEST_CASE(all_assembly_items) { "root.asm", 0 }, { "sub.asm", 1 } }; - Assembly _assembly; + Assembly _assembly{false, {}}; auto root_asm = make_shared("root.asm"); _assembly.setSourceLocation({1, 3, root_asm}); - Assembly _subAsm; + Assembly _subAsm{false, {}}; auto sub_asm = make_shared("sub.asm"); _subAsm.setSourceLocation({6, 8, sub_asm}); // PushImmutable @@ -197,7 +197,7 @@ BOOST_AUTO_TEST_CASE(immutables_and_its_source_maps) { *subName, 1 } }; - auto subAsm = make_shared(); + auto subAsm = make_shared(false, string{}); for (char i = 0; i < numImmutables; ++i) { for (int r = 0; r < numActualRefs; ++r) @@ -207,7 +207,7 @@ BOOST_AUTO_TEST_CASE(immutables_and_its_source_maps) } } - Assembly assembly; + Assembly assembly{true, {}}; for (char i = 1; i <= numImmutables; ++i) { assembly.setSourceLocation({10*i, 10*i + 3+i, assemblyName}); @@ -256,11 +256,11 @@ BOOST_AUTO_TEST_CASE(immutable) { "root.asm", 0 }, { "sub.asm", 1 } }; - Assembly _assembly; + Assembly _assembly{true, {}}; auto root_asm = make_shared("root.asm"); _assembly.setSourceLocation({1, 3, root_asm}); - Assembly _subAsm; + Assembly _subAsm{false, {}}; auto sub_asm = make_shared("sub.asm"); _subAsm.setSourceLocation({6, 8, sub_asm}); _subAsm.appendImmutable("someImmutable"); @@ -349,10 +349,10 @@ BOOST_AUTO_TEST_CASE(immutable) BOOST_AUTO_TEST_CASE(subobject_encode_decode) { - Assembly assembly; + Assembly assembly{true, {}}; - shared_ptr subAsmPtr = make_shared(); - shared_ptr subSubAsmPtr = make_shared(); + shared_ptr subAsmPtr = make_shared(false, string{}); + shared_ptr subSubAsmPtr = make_shared(false, string{}); assembly.appendSubroutine(subAsmPtr); subAsmPtr->appendSubroutine(subSubAsmPtr); diff --git a/test/libevmasm/Optimiser.cpp b/test/libevmasm/Optimiser.cpp index c8bb93c41d78..44fbde9274ea 100644 --- a/test/libevmasm/Optimiser.cpp +++ b/test/libevmasm/Optimiser.cpp @@ -1250,8 +1250,8 @@ BOOST_AUTO_TEST_CASE(jumpdest_removal_subassemblies) // tag unifications (due to block deduplication) is also // visible at the super-assembly. - Assembly main; - AssemblyPointer sub = make_shared(); + Assembly main{false, {}}; + AssemblyPointer sub = make_shared(true, string{}); sub->append(u256(1)); auto t1 = sub->newTag(); @@ -1278,7 +1278,6 @@ BOOST_AUTO_TEST_CASE(jumpdest_removal_subassemblies) main.append(u256(8)); Assembly::OptimiserSettings settings; - settings.isCreation = false; settings.runInliner = false; settings.runJumpdestRemover = true; settings.runPeephole = true; @@ -1287,7 +1286,7 @@ BOOST_AUTO_TEST_CASE(jumpdest_removal_subassemblies) settings.runConstantOptimiser = true; settings.evmVersion = solidity::test::CommonOptions::get().evmVersion(); settings.expectedExecutionsPerDeployment = OptimiserSettings{}.expectedExecutionsPerDeployment; -; + main.optimise(settings); AssemblyItems expectationMain{ diff --git a/test/libsolidity/ASTJSON/address_payable.json b/test/libsolidity/ASTJSON/address_payable.json index 22090ee290f4..9aec1e510cfa 100644 --- a/test/libsolidity/ASTJSON/address_payable.json +++ b/test/libsolidity/ASTJSON/address_payable.json @@ -423,18 +423,19 @@ "isPure": true, "lValueRequested": false, "nodeType": "ElementaryTypeNameExpression", - "src": "239:7:1", + "src": "239:8:1", "typeDescriptions": { - "typeIdentifier": "t_type$_t_address_$", - "typeString": "type(address)" + "typeIdentifier": "t_type$_t_address_payable_$", + "typeString": "type(address payable)" }, "typeName": { "id": 31, "name": "address", "nodeType": "ElementaryTypeName", - "src": "239:7:1", + "src": "239:8:1", + "stateMutability": "payable", "typeDescriptions": {} } }, @@ -450,8 +451,8 @@ "tryCall": false, "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" + "typeIdentifier": "t_address_payable", + "typeString": "address payable" } }, "src": "232:17:1", diff --git a/test/libsolidity/ASTJSON/address_payable.sol b/test/libsolidity/ASTJSON/address_payable.sol index f7cc66cb568e..28c9c8a20da4 100644 --- a/test/libsolidity/ASTJSON/address_payable.sol +++ b/test/libsolidity/ASTJSON/address_payable.sol @@ -4,7 +4,7 @@ contract C { address payable a = m[arg]; r = arg; address c = address(this); - m[c] = address(0); + m[c] = payable(0); } } diff --git a/test/libsolidity/ASTJSON/address_payable_parseOnly.json b/test/libsolidity/ASTJSON/address_payable_parseOnly.json index 85e06e90cdfe..39e91de1cc10 100644 --- a/test/libsolidity/ASTJSON/address_payable_parseOnly.json +++ b/test/libsolidity/ASTJSON/address_payable_parseOnly.json @@ -268,14 +268,15 @@ { "id": 32, "nodeType": "ElementaryTypeNameExpression", - "src": "239:7:1", + "src": "239:8:1", "typeDescriptions": {}, "typeName": { "id": 31, "name": "address", "nodeType": "ElementaryTypeName", - "src": "239:7:1", + "src": "239:8:1", + "stateMutability": "payable", "typeDescriptions": {} } }, diff --git a/test/libsolidity/ASTJSON/assembly/nested_functions.json b/test/libsolidity/ASTJSON/assembly/nested_functions.json index aea5e54d0951..41a18a1d0ebb 100644 --- a/test/libsolidity/ASTJSON/assembly/nested_functions.json +++ b/test/libsolidity/ASTJSON/assembly/nested_functions.json @@ -17,6 +17,7 @@ "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", + "fullyImplemented": true, "id": 8, "linearizedBaseContracts": [ @@ -32,21 +33,21 @@ { "id": 6, "nodeType": "Block", - "src": "57:97:1", + "src": "57:95:1", "statements": [ { "AST": { "nodeType": "YulBlock", - "src": "72:78:1", + "src": "72:76:1", "statements": [ { "body": { "nodeType": "YulBlock", - "src": "94:50:1", + "src": "94:35:1", "statements": [ { @@ -59,43 +60,53 @@ "name": "f2", "nodeType": "YulFunctionDefinition", "src": "104:17:1" - }, - { - "nodeType": "YulAssignment", - "src": "130:6:1", - "value": - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "135:1:1", - "type": "", - "value": "2" - }, - "variableNames": - [ - { - "name": "x", - "nodeType": "YulIdentifier", - "src": "130:1:1" - } - ] } ] }, "name": "f1", "nodeType": "YulFunctionDefinition", - "src": "80:64:1" + "src": "80:49:1" + }, + { + "nodeType": "YulAssignment", + "src": "136:6:1", + "value": + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "141:1:1", + "type": "", + "value": "2" + }, + "variableNames": + [ + { + "name": "x", + "nodeType": "YulIdentifier", + "src": "136:1:1" + } + ] } ] }, "evmVersion": %EVMVERSION%, - "externalReferences": [], + "externalReferences": + [ + { + "declaration": 3, + "isOffset": false, + "isSlot": false, + "src": "136:1:1", + "valueSize": 1 + } + ], "id": 5, "nodeType": "InlineAssembly", - "src": "63:87:1" + "src": "63:85:1" } ] }, + "functionSelector": "26121ff0", "id": 7, "implemented": true, "kind": "function", @@ -127,14 +138,22 @@ "src": "49:6:1", "stateVariable": false, "storageLocation": "default", - "typeDescriptions": {}, + "typeDescriptions": + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, "typeName": { "id": 2, "name": "uint", "nodeType": "ElementaryTypeName", "src": "49:4:1", - "typeDescriptions": {} + "typeDescriptions": + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } }, "visibility": "internal" } @@ -142,16 +161,16 @@ "src": "48:8:1" }, "scope": 8, - "src": "15:139:1", + "src": "15:137:1", "stateMutability": "pure", "virtual": false, "visibility": "public" } ], "scope": 9, - "src": "0:156:1", + "src": "0:154:1", "usedErrors": [] } ], - "src": "0:157:1" + "src": "0:155:1" } diff --git a/test/libsolidity/ASTJSON/assembly/nested_functions.sol b/test/libsolidity/ASTJSON/assembly/nested_functions.sol index 412dd05a4863..396efa0bf8a2 100644 --- a/test/libsolidity/ASTJSON/assembly/nested_functions.sol +++ b/test/libsolidity/ASTJSON/assembly/nested_functions.sol @@ -3,8 +3,8 @@ contract C { assembly { function f1() { function f2() { } - x := 2 } + x := 2 } } } diff --git a/test/libsolidity/ASTJSON/assembly/nested_functions_parseOnly.json b/test/libsolidity/ASTJSON/assembly/nested_functions_parseOnly.json index af50716650e0..f5f554608006 100644 --- a/test/libsolidity/ASTJSON/assembly/nested_functions_parseOnly.json +++ b/test/libsolidity/ASTJSON/assembly/nested_functions_parseOnly.json @@ -20,21 +20,21 @@ { "id": 6, "nodeType": "Block", - "src": "57:97:1", + "src": "57:95:1", "statements": [ { "AST": { "nodeType": "YulBlock", - "src": "72:78:1", + "src": "72:76:1", "statements": [ { "body": { "nodeType": "YulBlock", - "src": "94:50:1", + "src": "94:35:1", "statements": [ { @@ -47,32 +47,32 @@ "name": "f2", "nodeType": "YulFunctionDefinition", "src": "104:17:1" - }, - { - "nodeType": "YulAssignment", - "src": "130:6:1", - "value": - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "135:1:1", - "type": "", - "value": "2" - }, - "variableNames": - [ - { - "name": "x", - "nodeType": "YulIdentifier", - "src": "130:1:1" - } - ] } ] }, "name": "f1", "nodeType": "YulFunctionDefinition", - "src": "80:64:1" + "src": "80:49:1" + }, + { + "nodeType": "YulAssignment", + "src": "136:6:1", + "value": + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "141:1:1", + "type": "", + "value": "2" + }, + "variableNames": + [ + { + "name": "x", + "nodeType": "YulIdentifier", + "src": "136:1:1" + } + ] } ] }, @@ -80,7 +80,7 @@ "externalReferences": [], "id": 5, "nodeType": "InlineAssembly", - "src": "63:87:1" + "src": "63:85:1" } ] }, @@ -128,15 +128,15 @@ ], "src": "48:8:1" }, - "src": "15:139:1", + "src": "15:137:1", "stateMutability": "pure", "virtual": false, "visibility": "public" } ], - "src": "0:156:1", + "src": "0:154:1", "usedErrors": [] } ], - "src": "0:157:1" + "src": "0:155:1" } diff --git a/test/libsolidity/ASTJSON/assembly/switch.json b/test/libsolidity/ASTJSON/assembly/switch.json index 85dcb313f25a..f78699ef647d 100644 --- a/test/libsolidity/ASTJSON/assembly/switch.json +++ b/test/libsolidity/ASTJSON/assembly/switch.json @@ -17,6 +17,7 @@ "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", + "fullyImplemented": true, "id": 6, "linearizedBaseContracts": [ @@ -56,7 +57,7 @@ "variables": [ { - "name": "f", + "name": "v", "nodeType": "YulTypedName", "src": "79:1:1", "type": "" @@ -87,7 +88,7 @@ "variableNames": [ { - "name": "f", + "name": "v", "nodeType": "YulIdentifier", "src": "141:1:1" } @@ -127,7 +128,7 @@ "variableNames": [ { - "name": "f", + "name": "v", "nodeType": "YulIdentifier", "src": "172:1:1" } @@ -158,29 +159,14 @@ ] }, "evmVersion": %EVMVERSION%, - "externalReferences": - [ - { - "declaration": 5, - "isOffset": false, - "isSlot": false, - "src": "141:1:1", - "valueSize": 18446744073709551615 - }, - { - "declaration": 5, - "isOffset": false, - "isSlot": false, - "src": "172:1:1", - "valueSize": 18446744073709551615 - } - ], + "externalReferences": [], "id": 3, "nodeType": "InlineAssembly", "src": "52:138:1" } ] }, + "functionSelector": "26121ff0", "id": 5, "implemented": true, "kind": "function", diff --git a/test/libsolidity/ASTJSON/assembly/switch.sol b/test/libsolidity/ASTJSON/assembly/switch.sol index 640c5b51c7eb..c04d311b09e4 100644 --- a/test/libsolidity/ASTJSON/assembly/switch.sol +++ b/test/libsolidity/ASTJSON/assembly/switch.sol @@ -1,10 +1,10 @@ contract C { function f() pure public { assembly { - let f := 0 + let v := 0 switch calldatasize() - case 0 { f := 1 } - default { f := 2 } + case 0 { v := 1 } + default { v := 2 } } } } diff --git a/test/libsolidity/ASTJSON/assembly/switch_parseOnly.json b/test/libsolidity/ASTJSON/assembly/switch_parseOnly.json index 93e671c10035..54d38b6383e1 100644 --- a/test/libsolidity/ASTJSON/assembly/switch_parseOnly.json +++ b/test/libsolidity/ASTJSON/assembly/switch_parseOnly.json @@ -44,7 +44,7 @@ "variables": [ { - "name": "f", + "name": "v", "nodeType": "YulTypedName", "src": "79:1:1", "type": "" @@ -75,7 +75,7 @@ "variableNames": [ { - "name": "f", + "name": "v", "nodeType": "YulIdentifier", "src": "141:1:1" } @@ -115,7 +115,7 @@ "variableNames": [ { - "name": "f", + "name": "v", "nodeType": "YulIdentifier", "src": "172:1:1" } diff --git a/test/libsolidity/ASTJSON/event_with_variables_of_internal_types.json b/test/libsolidity/ASTJSON/event_with_variables_of_internal_types.json deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/test/libsolidity/ASTJSON/fail_after_parsing.sol b/test/libsolidity/ASTJSON/fail_after_parsing.sol new file mode 100644 index 000000000000..b3b53a7c1611 --- /dev/null +++ b/test/libsolidity/ASTJSON/fail_after_parsing.sol @@ -0,0 +1,16 @@ +function g() public; + +interface I { + struct S { S s; } + + function f(E storage e) { + error E; + emit E(); + + ++c; + uint calldata c = 123.4; + } +} + +// ---- +// failAfter: Parsed diff --git a/test/libsolidity/ASTJSON/fail_after_parsing_parseOnly.json b/test/libsolidity/ASTJSON/fail_after_parsing_parseOnly.json new file mode 100644 index 000000000000..a5c7669ef51a --- /dev/null +++ b/test/libsolidity/ASTJSON/fail_after_parsing_parseOnly.json @@ -0,0 +1,283 @@ +{ + "absolutePath": "a", + "id": 30, + "nodeType": "SourceUnit", + "nodes": + [ + { + "id": 3, + "implemented": false, + "kind": "freeFunction", + "modifiers": [], + "name": "g", + "nameLocation": "9:1:1", + "nodeType": "FunctionDefinition", + "parameters": + { + "id": 1, + "nodeType": "ParameterList", + "parameters": [], + "src": "10:2:1" + }, + "returnParameters": + { + "id": 2, + "nodeType": "ParameterList", + "parameters": [], + "src": "19:0:1" + }, + "src": "0:20:1", + "stateMutability": "nonpayable", + "virtual": false, + "visibility": "public" + }, + { + "abstract": false, + "baseContracts": [], + "contractDependencies": [], + "contractKind": "interface", + "id": 29, + "name": "I", + "nameLocation": "31:1:1", + "nodeType": "ContractDefinition", + "nodes": + [ + { + "id": 7, + "members": + [ + { + "constant": false, + "id": 6, + "mutability": "mutable", + "name": "s", + "nameLocation": "52:1:1", + "nodeType": "VariableDeclaration", + "src": "50:3:1", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": {}, + "typeName": + { + "id": 5, + "nodeType": "UserDefinedTypeName", + "pathNode": + { + "id": 4, + "name": "S", + "nodeType": "IdentifierPath", + "src": "50:1:1" + }, + "src": "50:1:1", + "typeDescriptions": {} + }, + "visibility": "internal" + } + ], + "name": "S", + "nameLocation": "46:1:1", + "nodeType": "StructDefinition", + "src": "39:17:1", + "visibility": "public" + }, + { + "body": + { + "id": 27, + "nodeType": "Block", + "src": "85:88:1", + "statements": + [ + { + "assignments": + [ + 15 + ], + "declarations": + [ + { + "constant": false, + "id": 15, + "mutability": "mutable", + "name": "E", + "nameLocation": "101:1:1", + "nodeType": "VariableDeclaration", + "src": "95:7:1", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": {}, + "typeName": + { + "id": 14, + "nodeType": "UserDefinedTypeName", + "pathNode": + { + "id": 13, + "name": "error", + "nodeType": "IdentifierPath", + "src": "95:5:1" + }, + "src": "95:5:1", + "typeDescriptions": {} + }, + "visibility": "internal" + } + ], + "id": 16, + "nodeType": "VariableDeclarationStatement", + "src": "95:7:1" + }, + { + "eventCall": + { + "arguments": [], + "expression": + { + "id": 17, + "name": "E", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "src": "117:1:1", + "typeDescriptions": {} + }, + "id": 18, + "names": [], + "nodeType": "FunctionCall", + "src": "117:3:1", + "tryCall": false, + "typeDescriptions": {} + }, + "id": 19, + "nodeType": "EmitStatement", + "src": "112:8:1" + }, + { + "expression": + { + "id": 21, + "nodeType": "UnaryOperation", + "operator": "++", + "prefix": true, + "src": "130:3:1", + "subExpression": + { + "id": 20, + "name": "c", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "src": "132:1:1", + "typeDescriptions": {} + }, + "typeDescriptions": {} + }, + "id": 22, + "nodeType": "ExpressionStatement", + "src": "130:3:1" + }, + { + "assignments": + [ + 24 + ], + "declarations": + [ + { + "constant": false, + "id": 24, + "mutability": "mutable", + "name": "c", + "nameLocation": "157:1:1", + "nodeType": "VariableDeclaration", + "src": "143:15:1", + "stateVariable": false, + "storageLocation": "calldata", + "typeDescriptions": {}, + "typeName": + { + "id": 23, + "name": "uint", + "nodeType": "ElementaryTypeName", + "src": "143:4:1", + "typeDescriptions": {} + }, + "visibility": "internal" + } + ], + "id": 26, + "initialValue": + { + "hexValue": "3132332e34", + "id": 25, + "kind": "number", + "nodeType": "Literal", + "src": "161:5:1", + "typeDescriptions": {}, + "value": "123.4" + }, + "nodeType": "VariableDeclarationStatement", + "src": "143:23:1" + } + ] + }, + "id": 28, + "implemented": true, + "kind": "function", + "modifiers": [], + "name": "f", + "nameLocation": "70:1:1", + "nodeType": "FunctionDefinition", + "parameters": + { + "id": 11, + "nodeType": "ParameterList", + "parameters": + [ + { + "constant": false, + "id": 10, + "mutability": "mutable", + "name": "e", + "nameLocation": "82:1:1", + "nodeType": "VariableDeclaration", + "src": "72:11:1", + "stateVariable": false, + "storageLocation": "storage", + "typeDescriptions": {}, + "typeName": + { + "id": 9, + "nodeType": "UserDefinedTypeName", + "pathNode": + { + "id": 8, + "name": "E", + "nodeType": "IdentifierPath", + "src": "72:1:1" + }, + "src": "72:1:1", + "typeDescriptions": {} + }, + "visibility": "internal" + } + ], + "src": "71:13:1" + }, + "returnParameters": + { + "id": 12, + "nodeType": "ParameterList", + "parameters": [], + "src": "85:0:1" + }, + "src": "61:112:1", + "stateMutability": "nonpayable", + "virtual": false, + "visibility": "public" + } + ], + "src": "21:154:1", + "usedErrors": [] + } + ], + "src": "0:176:1" +} diff --git a/test/libsolidity/ASTJSON/function_type.json b/test/libsolidity/ASTJSON/function_type.json index cef79e70be4f..924f9cdb9a63 100644 --- a/test/libsolidity/ASTJSON/function_type.json +++ b/test/libsolidity/ASTJSON/function_type.json @@ -33,7 +33,7 @@ { "id": 15, "nodeType": "Block", - "src": "120:2:1", + "src": "127:2:1", "statements": [] }, "functionSelector": "d6cd4974", @@ -144,7 +144,7 @@ "nameLocation": "-1:-1:-1", "nodeType": "VariableDeclaration", "scope": 16, - "src": "79:40:1", + "src": "86:40:1", "stateVariable": false, "storageLocation": "default", "typeDescriptions": @@ -161,7 +161,7 @@ "id": 8, "nodeType": "ParameterList", "parameters": [], - "src": "87:2:1" + "src": "94:2:1" }, "returnParameterTypes": { @@ -177,7 +177,7 @@ "nameLocation": "-1:-1:-1", "nodeType": "VariableDeclaration", "scope": 12, - "src": "113:4:1", + "src": "120:4:1", "stateVariable": false, "storageLocation": "default", "typeDescriptions": @@ -190,7 +190,7 @@ "id": 9, "name": "uint", "nodeType": "ElementaryTypeName", - "src": "113:4:1", + "src": "120:4:1", "typeDescriptions": { "typeIdentifier": "t_uint256", @@ -200,9 +200,9 @@ "visibility": "internal" } ], - "src": "112:6:1" + "src": "119:6:1" }, - "src": "79:40:1", + "src": "86:40:1", "stateMutability": "view", "typeDescriptions": { @@ -214,19 +214,19 @@ "visibility": "internal" } ], - "src": "78:41:1" + "src": "85:41:1" }, "scope": 17, - "src": "13:109:1", + "src": "13:116:1", "stateMutability": "nonpayable", "virtual": false, "visibility": "public" } ], "scope": 18, - "src": "0:124:1", + "src": "0:131:1", "usedErrors": [] } ], - "src": "0:125:1" + "src": "0:132:1" } diff --git a/test/libsolidity/ASTJSON/function_type.sol b/test/libsolidity/ASTJSON/function_type.sol index bed2742b2aa3..176cea37400b 100644 --- a/test/libsolidity/ASTJSON/function_type.sol +++ b/test/libsolidity/ASTJSON/function_type.sol @@ -1,3 +1,3 @@ -contract C { function f(function() external payable returns (uint) x) returns (function() external view returns (uint)) {} } +contract C { function f(function() external payable returns (uint) x) public returns (function() external view returns (uint)) {} } // ---- diff --git a/test/libsolidity/ASTJSON/function_type_parseOnly.json b/test/libsolidity/ASTJSON/function_type_parseOnly.json index e47f24ad18db..fd1d7637b071 100644 --- a/test/libsolidity/ASTJSON/function_type_parseOnly.json +++ b/test/libsolidity/ASTJSON/function_type_parseOnly.json @@ -20,7 +20,7 @@ { "id": 15, "nodeType": "Block", - "src": "120:2:1", + "src": "127:2:1", "statements": [] }, "id": 16, @@ -111,7 +111,7 @@ "name": "", "nameLocation": "-1:-1:-1", "nodeType": "VariableDeclaration", - "src": "79:40:1", + "src": "86:40:1", "stateVariable": false, "storageLocation": "default", "typeDescriptions": {}, @@ -124,7 +124,7 @@ "id": 8, "nodeType": "ParameterList", "parameters": [], - "src": "87:2:1" + "src": "94:2:1" }, "returnParameterTypes": { @@ -139,7 +139,7 @@ "name": "", "nameLocation": "-1:-1:-1", "nodeType": "VariableDeclaration", - "src": "113:4:1", + "src": "120:4:1", "stateVariable": false, "storageLocation": "default", "typeDescriptions": {}, @@ -148,15 +148,15 @@ "id": 9, "name": "uint", "nodeType": "ElementaryTypeName", - "src": "113:4:1", + "src": "120:4:1", "typeDescriptions": {} }, "visibility": "internal" } ], - "src": "112:6:1" + "src": "119:6:1" }, - "src": "79:40:1", + "src": "86:40:1", "stateMutability": "view", "typeDescriptions": {}, "visibility": "external" @@ -164,17 +164,17 @@ "visibility": "internal" } ], - "src": "78:41:1" + "src": "85:41:1" }, - "src": "13:109:1", + "src": "13:116:1", "stateMutability": "nonpayable", "virtual": false, "visibility": "public" } ], - "src": "0:124:1", + "src": "0:131:1", "usedErrors": [] } ], - "src": "0:125:1" + "src": "0:132:1" } diff --git a/test/libsolidity/ASTJSON/non_utf8.json b/test/libsolidity/ASTJSON/non_utf8.json index 2f7145fda54e..0e2a56f84b24 100644 --- a/test/libsolidity/ASTJSON/non_utf8.json +++ b/test/libsolidity/ASTJSON/non_utf8.json @@ -4,10 +4,10 @@ { "C": [ - 9 + 15 ] }, - "id": 10, + "id": 16, "nodeType": "SourceUnit", "nodes": [ @@ -18,10 +18,10 @@ "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, - "id": 9, + "id": 15, "linearizedBaseContracts": [ - 9 + 15 ], "name": "C", "nameLocation": "9:1:1", @@ -31,9 +31,9 @@ { "body": { - "id": 7, + "id": 13, "nodeType": "Block", - "src": "33:30:1", + "src": "33:45:1", "statements": [ { @@ -50,7 +50,7 @@ "name": "x", "nameLocation": "49:1:1", "nodeType": "VariableDeclaration", - "scope": 7, + "scope": 13, "src": "35:15:1", "stateVariable": false, "storageLocation": "memory", @@ -74,31 +74,131 @@ "visibility": "internal" } ], - "id": 6, + "id": 12, "initialValue": { - "hexValue": "ff", - "id": 5, + "arguments": + [ + { + "arguments": + [ + { + "hexValue": "ff", + "id": 9, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "hexString", + "lValueRequested": false, + "nodeType": "Literal", + "src": "66:7:1", + "typeDescriptions": + { + "typeIdentifier": "t_stringliteral_8b1a944cf13a9a1c08facb2c9e98623ef3254d2ddb48113885c3e8e97fec8db9", + "typeString": "literal_string hex\"ff\"" + } + } + ], + "expression": + { + "argumentTypes": + [ + { + "typeIdentifier": "t_stringliteral_8b1a944cf13a9a1c08facb2c9e98623ef3254d2ddb48113885c3e8e97fec8db9", + "typeString": "literal_string hex\"ff\"" + } + ], + "id": 8, + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "nodeType": "ElementaryTypeNameExpression", + "src": "60:5:1", + "typeDescriptions": + { + "typeIdentifier": "t_type$_t_bytes_storage_ptr_$", + "typeString": "type(bytes storage pointer)" + }, + "typeName": + { + "id": 7, + "name": "bytes", + "nodeType": "ElementaryTypeName", + "src": "60:5:1", + "typeDescriptions": {} + } + }, + "id": 10, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "typeConversion", + "lValueRequested": false, + "names": [], + "nodeType": "FunctionCall", + "src": "60:14:1", + "tryCall": false, + "typeDescriptions": + { + "typeIdentifier": "t_bytes_memory_ptr", + "typeString": "bytes memory" + } + } + ], + "expression": + { + "argumentTypes": + [ + { + "typeIdentifier": "t_bytes_memory_ptr", + "typeString": "bytes memory" + } + ], + "id": 6, + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "nodeType": "ElementaryTypeNameExpression", + "src": "53:6:1", + "typeDescriptions": + { + "typeIdentifier": "t_type$_t_string_storage_ptr_$", + "typeString": "type(string storage pointer)" + }, + "typeName": + { + "id": 5, + "name": "string", + "nodeType": "ElementaryTypeName", + "src": "53:6:1", + "typeDescriptions": {} + } + }, + "id": 11, "isConstant": false, "isLValue": false, "isPure": true, - "kind": "hexString", + "kind": "typeConversion", "lValueRequested": false, - "nodeType": "Literal", - "src": "53:7:1", + "names": [], + "nodeType": "FunctionCall", + "src": "53:22:1", + "tryCall": false, "typeDescriptions": { - "typeIdentifier": "t_stringliteral_8b1a944cf13a9a1c08facb2c9e98623ef3254d2ddb48113885c3e8e97fec8db9", - "typeString": "literal_string hex\"ff\"" + "typeIdentifier": "t_string_memory_ptr", + "typeString": "string memory" } }, "nodeType": "VariableDeclarationStatement", - "src": "35:25:1" + "src": "35:40:1" } ] }, "functionSelector": "26121ff0", - "id": 8, + "id": 14, "implemented": true, "kind": "function", "modifiers": [], @@ -119,17 +219,17 @@ "parameters": [], "src": "33:0:1" }, - "scope": 9, - "src": "13:50:1", + "scope": 15, + "src": "13:65:1", "stateMutability": "nonpayable", "virtual": false, "visibility": "public" } ], - "scope": 10, - "src": "0:65:1", + "scope": 16, + "src": "0:80:1", "usedErrors": [] } ], - "src": "0:66:1" + "src": "0:81:1" } diff --git a/test/libsolidity/ASTJSON/non_utf8.sol b/test/libsolidity/ASTJSON/non_utf8.sol index 3651a05fd62e..0f14102ccefd 100644 --- a/test/libsolidity/ASTJSON/non_utf8.sol +++ b/test/libsolidity/ASTJSON/non_utf8.sol @@ -1,3 +1,3 @@ -contract C { function f() public { string memory x = hex"ff"; } } +contract C { function f() public { string memory x = string(bytes(hex"ff")); } } // ---- diff --git a/test/libsolidity/ASTJSON/non_utf8_parseOnly.json b/test/libsolidity/ASTJSON/non_utf8_parseOnly.json index e33388a0715f..df358ae362f9 100644 --- a/test/libsolidity/ASTJSON/non_utf8_parseOnly.json +++ b/test/libsolidity/ASTJSON/non_utf8_parseOnly.json @@ -1,6 +1,6 @@ { "absolutePath": "a", - "id": 10, + "id": 16, "nodeType": "SourceUnit", "nodes": [ @@ -9,7 +9,7 @@ "baseContracts": [], "contractDependencies": [], "contractKind": "contract", - "id": 9, + "id": 15, "name": "C", "nameLocation": "9:1:1", "nodeType": "ContractDefinition", @@ -18,9 +18,9 @@ { "body": { - "id": 7, + "id": 13, "nodeType": "Block", - "src": "33:30:1", + "src": "33:45:1", "statements": [ { @@ -52,22 +52,74 @@ "visibility": "internal" } ], - "id": 6, + "id": 12, "initialValue": { - "hexValue": "ff", - "id": 5, - "kind": "hexString", - "nodeType": "Literal", - "src": "53:7:1", + "arguments": + [ + { + "arguments": + [ + { + "hexValue": "ff", + "id": 9, + "kind": "hexString", + "nodeType": "Literal", + "src": "66:7:1", + "typeDescriptions": {} + } + ], + "expression": + { + "id": 8, + "nodeType": "ElementaryTypeNameExpression", + "src": "60:5:1", + "typeDescriptions": {}, + "typeName": + { + "id": 7, + "name": "bytes", + "nodeType": "ElementaryTypeName", + "src": "60:5:1", + "typeDescriptions": {} + } + }, + "id": 10, + "names": [], + "nodeType": "FunctionCall", + "src": "60:14:1", + "tryCall": false, + "typeDescriptions": {} + } + ], + "expression": + { + "id": 6, + "nodeType": "ElementaryTypeNameExpression", + "src": "53:6:1", + "typeDescriptions": {}, + "typeName": + { + "id": 5, + "name": "string", + "nodeType": "ElementaryTypeName", + "src": "53:6:1", + "typeDescriptions": {} + } + }, + "id": 11, + "names": [], + "nodeType": "FunctionCall", + "src": "53:22:1", + "tryCall": false, "typeDescriptions": {} }, "nodeType": "VariableDeclarationStatement", - "src": "35:25:1" + "src": "35:40:1" } ] }, - "id": 8, + "id": 14, "implemented": true, "kind": "function", "modifiers": [], @@ -88,15 +140,15 @@ "parameters": [], "src": "33:0:1" }, - "src": "13:50:1", + "src": "13:65:1", "stateMutability": "nonpayable", "virtual": false, "visibility": "public" } ], - "src": "0:65:1", + "src": "0:80:1", "usedErrors": [] } ], - "src": "0:66:1" + "src": "0:81:1" } diff --git a/test/libsolidity/ASTJSON/not_existing_import.json b/test/libsolidity/ASTJSON/not_existing_import.json deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/test/libsolidity/ASTJSON/not_existing_import.sol b/test/libsolidity/ASTJSON/not_existing_import.sol index 6353c7527bde..7251a02b84a5 100644 --- a/test/libsolidity/ASTJSON/not_existing_import.sol +++ b/test/libsolidity/ASTJSON/not_existing_import.sol @@ -6,3 +6,4 @@ contract C is NotExisting.X } // ---- +// failAfter: Parsed diff --git a/test/libsolidity/ASTJSON/source_location.json b/test/libsolidity/ASTJSON/source_location.json index 0591a30cc8a2..df51e49c6f6b 100644 --- a/test/libsolidity/ASTJSON/source_location.json +++ b/test/libsolidity/ASTJSON/source_location.json @@ -33,7 +33,7 @@ { "id": 10, "nodeType": "Block", - "src": "26:20:1", + "src": "33:20:1", "statements": [ { @@ -48,10 +48,10 @@ "id": 4, "mutability": "mutable", "name": "x", - "nameLocation": "33:1:1", + "nameLocation": "40:1:1", "nodeType": "VariableDeclaration", "scope": 10, - "src": "28:6:1", + "src": "35:6:1", "stateVariable": false, "storageLocation": "default", "typeDescriptions": @@ -64,7 +64,7 @@ "id": 3, "name": "uint", "nodeType": "ElementaryTypeName", - "src": "28:4:1", + "src": "35:4:1", "typeDescriptions": { "typeIdentifier": "t_uint256", @@ -85,7 +85,7 @@ "kind": "number", "lValueRequested": false, "nodeType": "Literal", - "src": "37:1:1", + "src": "44:1:1", "typeDescriptions": { "typeIdentifier": "t_rational_2_by_1", @@ -94,7 +94,7 @@ "value": "2" }, "nodeType": "VariableDeclarationStatement", - "src": "28:10:1" + "src": "35:10:1" }, { "expression": @@ -107,7 +107,7 @@ "nodeType": "UnaryOperation", "operator": "++", "prefix": false, - "src": "40:3:1", + "src": "47:3:1", "subExpression": { "id": 7, @@ -115,7 +115,7 @@ "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": 4, - "src": "40:1:1", + "src": "47:1:1", "typeDescriptions": { "typeIdentifier": "t_uint256", @@ -130,7 +130,7 @@ }, "id": 9, "nodeType": "ExpressionStatement", - "src": "40:3:1" + "src": "47:3:1" } ] }, @@ -154,19 +154,19 @@ "id": 2, "nodeType": "ParameterList", "parameters": [], - "src": "26:0:1" + "src": "33:0:1" }, "scope": 12, - "src": "13:33:1", + "src": "13:40:1", "stateMutability": "nonpayable", "virtual": false, "visibility": "public" } ], "scope": 13, - "src": "0:48:1", + "src": "0:55:1", "usedErrors": [] } ], - "src": "0:49:1" + "src": "0:56:1" } diff --git a/test/libsolidity/ASTJSON/source_location.sol b/test/libsolidity/ASTJSON/source_location.sol index 0960bcde6b49..756998e43a83 100644 --- a/test/libsolidity/ASTJSON/source_location.sol +++ b/test/libsolidity/ASTJSON/source_location.sol @@ -1,3 +1,3 @@ -contract C { function f() { uint x = 2; x++; } } +contract C { function f() public { uint x = 2; x++; } } // ---- diff --git a/test/libsolidity/ASTJSON/source_location_parseOnly.json b/test/libsolidity/ASTJSON/source_location_parseOnly.json index decc215fe243..88835788b85f 100644 --- a/test/libsolidity/ASTJSON/source_location_parseOnly.json +++ b/test/libsolidity/ASTJSON/source_location_parseOnly.json @@ -20,7 +20,7 @@ { "id": 10, "nodeType": "Block", - "src": "26:20:1", + "src": "33:20:1", "statements": [ { @@ -35,9 +35,9 @@ "id": 4, "mutability": "mutable", "name": "x", - "nameLocation": "33:1:1", + "nameLocation": "40:1:1", "nodeType": "VariableDeclaration", - "src": "28:6:1", + "src": "35:6:1", "stateVariable": false, "storageLocation": "default", "typeDescriptions": {}, @@ -46,7 +46,7 @@ "id": 3, "name": "uint", "nodeType": "ElementaryTypeName", - "src": "28:4:1", + "src": "35:4:1", "typeDescriptions": {} }, "visibility": "internal" @@ -59,12 +59,12 @@ "id": 5, "kind": "number", "nodeType": "Literal", - "src": "37:1:1", + "src": "44:1:1", "typeDescriptions": {}, "value": "2" }, "nodeType": "VariableDeclarationStatement", - "src": "28:10:1" + "src": "35:10:1" }, { "expression": @@ -73,21 +73,21 @@ "nodeType": "UnaryOperation", "operator": "++", "prefix": false, - "src": "40:3:1", + "src": "47:3:1", "subExpression": { "id": 7, "name": "x", "nodeType": "Identifier", "overloadedDeclarations": [], - "src": "40:1:1", + "src": "47:1:1", "typeDescriptions": {} }, "typeDescriptions": {} }, "id": 9, "nodeType": "ExpressionStatement", - "src": "40:3:1" + "src": "47:3:1" } ] }, @@ -110,17 +110,17 @@ "id": 2, "nodeType": "ParameterList", "parameters": [], - "src": "26:0:1" + "src": "33:0:1" }, - "src": "13:33:1", + "src": "13:40:1", "stateMutability": "nonpayable", "virtual": false, "visibility": "public" } ], - "src": "0:48:1", + "src": "0:55:1", "usedErrors": [] } ], - "src": "0:49:1" + "src": "0:56:1" } diff --git a/test/libsolidity/ASTJSON/used_errors.json b/test/libsolidity/ASTJSON/used_errors.json index a0e8e28ba472..f00336d20936 100644 --- a/test/libsolidity/ASTJSON/used_errors.json +++ b/test/libsolidity/ASTJSON/used_errors.json @@ -39,7 +39,7 @@ { "id": 8, "nodeType": "Block", - "src": "24:15:1", + "src": "29:15:1", "statements": [ { @@ -54,7 +54,7 @@ "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": 2, - "src": "33:1:1", + "src": "38:1:1", "typeDescriptions": { "typeIdentifier": "t_function_error_pure$__$returns$__$", @@ -69,7 +69,7 @@ "lValueRequested": false, "names": [], "nodeType": "FunctionCall", - "src": "33:3:1", + "src": "38:3:1", "tryCall": false, "typeDescriptions": { @@ -79,7 +79,7 @@ }, "id": 7, "nodeType": "RevertStatement", - "src": "26:10:1" + "src": "31:10:1" } ] }, @@ -102,11 +102,11 @@ "id": 4, "nodeType": "ParameterList", "parameters": [], - "src": "24:0:1" + "src": "29:0:1" }, "scope": 20, - "src": "11:28:1", - "stateMutability": "nonpayable", + "src": "11:33:1", + "stateMutability": "pure", "virtual": false, "visibility": "internal" }, @@ -123,7 +123,7 @@ 19 ], "name": "C", - "nameLocation": "49:1:1", + "nameLocation": "54:1:1", "nodeType": "ContractDefinition", "nodes": [ @@ -131,23 +131,23 @@ "errorSelector": "2bc80f3a", "id": 11, "name": "T", - "nameLocation": "63:1:1", + "nameLocation": "68:1:1", "nodeType": "ErrorDefinition", "parameters": { "id": 10, "nodeType": "ParameterList", "parameters": [], - "src": "64:2:1" + "src": "69:2:1" }, - "src": "57:10:1" + "src": "62:10:1" }, { "body": { "id": 17, "nodeType": "Block", - "src": "92:8:1", + "src": "97:8:1", "statements": [ { @@ -162,11 +162,11 @@ "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": 9, - "src": "94:1:1", + "src": "99:1:1", "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$__$returns$__$", - "typeString": "function ()" + "typeIdentifier": "t_function_internal_pure$__$returns$__$", + "typeString": "function () pure" } }, "id": 15, @@ -177,7 +177,7 @@ "lValueRequested": false, "names": [], "nodeType": "FunctionCall", - "src": "94:3:1", + "src": "99:3:1", "tryCall": false, "typeDescriptions": { @@ -187,7 +187,7 @@ }, "id": 16, "nodeType": "ExpressionStatement", - "src": "94:3:1" + "src": "99:3:1" } ] }, @@ -197,31 +197,31 @@ "kind": "function", "modifiers": [], "name": "h", - "nameLocation": "81:1:1", + "nameLocation": "86:1:1", "nodeType": "FunctionDefinition", "parameters": { "id": 12, "nodeType": "ParameterList", "parameters": [], - "src": "82:2:1" + "src": "87:2:1" }, "returnParameters": { "id": 13, "nodeType": "ParameterList", "parameters": [], - "src": "92:0:1" + "src": "97:0:1" }, "scope": 19, - "src": "72:28:1", + "src": "77:28:1", "stateMutability": "nonpayable", "virtual": false, "visibility": "public" } ], "scope": 20, - "src": "40:62:1", + "src": "45:62:1", "usedErrors": [ 2, @@ -229,5 +229,5 @@ ] } ], - "src": "0:103:1" + "src": "0:108:1" } diff --git a/test/libsolidity/ASTJSON/used_errors.sol b/test/libsolidity/ASTJSON/used_errors.sol index ead3e2dcf4d0..24c03982fed6 100644 --- a/test/libsolidity/ASTJSON/used_errors.sol +++ b/test/libsolidity/ASTJSON/used_errors.sol @@ -1,5 +1,5 @@ error X(); -function f() { revert X(); } +function f() pure { revert X(); } contract C { error T(); function h() public { f(); } diff --git a/test/libsolidity/ASTJSON/used_errors_parseOnly.json b/test/libsolidity/ASTJSON/used_errors_parseOnly.json index 58b476005f05..b7500b445e15 100644 --- a/test/libsolidity/ASTJSON/used_errors_parseOnly.json +++ b/test/libsolidity/ASTJSON/used_errors_parseOnly.json @@ -23,7 +23,7 @@ { "id": 8, "nodeType": "Block", - "src": "24:15:1", + "src": "29:15:1", "statements": [ { @@ -36,19 +36,19 @@ "name": "X", "nodeType": "Identifier", "overloadedDeclarations": [], - "src": "33:1:1", + "src": "38:1:1", "typeDescriptions": {} }, "id": 6, "names": [], "nodeType": "FunctionCall", - "src": "33:3:1", + "src": "38:3:1", "tryCall": false, "typeDescriptions": {} }, "id": 7, "nodeType": "RevertStatement", - "src": "26:10:1" + "src": "31:10:1" } ] }, @@ -71,10 +71,10 @@ "id": 4, "nodeType": "ParameterList", "parameters": [], - "src": "24:0:1" + "src": "29:0:1" }, - "src": "11:28:1", - "stateMutability": "nonpayable", + "src": "11:33:1", + "stateMutability": "pure", "virtual": false, "visibility": "internal" }, @@ -85,30 +85,30 @@ "contractKind": "contract", "id": 19, "name": "C", - "nameLocation": "49:1:1", + "nameLocation": "54:1:1", "nodeType": "ContractDefinition", "nodes": [ { "id": 11, "name": "T", - "nameLocation": "63:1:1", + "nameLocation": "68:1:1", "nodeType": "ErrorDefinition", "parameters": { "id": 10, "nodeType": "ParameterList", "parameters": [], - "src": "64:2:1" + "src": "69:2:1" }, - "src": "57:10:1" + "src": "62:10:1" }, { "body": { "id": 17, "nodeType": "Block", - "src": "92:8:1", + "src": "97:8:1", "statements": [ { @@ -121,19 +121,19 @@ "name": "f", "nodeType": "Identifier", "overloadedDeclarations": [], - "src": "94:1:1", + "src": "99:1:1", "typeDescriptions": {} }, "id": 15, "names": [], "nodeType": "FunctionCall", - "src": "94:3:1", + "src": "99:3:1", "tryCall": false, "typeDescriptions": {} }, "id": 16, "nodeType": "ExpressionStatement", - "src": "94:3:1" + "src": "99:3:1" } ] }, @@ -142,31 +142,31 @@ "kind": "function", "modifiers": [], "name": "h", - "nameLocation": "81:1:1", + "nameLocation": "86:1:1", "nodeType": "FunctionDefinition", "parameters": { "id": 12, "nodeType": "ParameterList", "parameters": [], - "src": "82:2:1" + "src": "87:2:1" }, "returnParameters": { "id": 13, "nodeType": "ParameterList", "parameters": [], - "src": "92:0:1" + "src": "97:0:1" }, - "src": "72:28:1", + "src": "77:28:1", "stateMutability": "nonpayable", "virtual": false, "visibility": "public" } ], - "src": "40:62:1", + "src": "45:62:1", "usedErrors": [] } ], - "src": "0:103:1" + "src": "0:108:1" } diff --git a/test/libsolidity/ASTJSON/using_for_directive.json b/test/libsolidity/ASTJSON/using_for_directive.json index b935b262b1cf..c9052b0d7d61 100644 --- a/test/libsolidity/ASTJSON/using_for_directive.json +++ b/test/libsolidity/ASTJSON/using_for_directive.json @@ -4,17 +4,52 @@ { "C": [ - 5 + 13 ], "L": [ - 1 + 4 + ], + "f": + [ + 10 ] }, - "id": 6, + "id": 14, "nodeType": "SourceUnit", "nodes": [ + { + "functionList": + [ + { + "function": + { + "id": 1, + "name": "f", + "nodeType": "IdentifierPath", + "referencedDeclaration": 10, + "src": "7:1:1" + } + } + ], + "global": false, + "id": 3, + "nodeType": "UsingForDirective", + "src": "0:19:1", + "typeName": + { + "id": 2, + "name": "uint", + "nodeType": "ElementaryTypeName", + "src": "14:4:1", + "typeDescriptions": + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + } + }, { "abstract": false, "baseContracts": [], @@ -22,19 +57,86 @@ "contractDependencies": [], "contractKind": "library", "fullyImplemented": true, - "id": 1, + "id": 4, "linearizedBaseContracts": [ - 1 + 4 ], "name": "L", - "nameLocation": "8:1:1", + "nameLocation": "28:1:1", "nodeType": "ContractDefinition", "nodes": [], - "scope": 6, - "src": "0:12:1", + "scope": 14, + "src": "20:12:1", "usedErrors": [] }, + { + "body": + { + "id": 9, + "nodeType": "Block", + "src": "50:2:1", + "statements": [] + }, + "id": 10, + "implemented": true, + "kind": "freeFunction", + "modifiers": [], + "name": "f", + "nameLocation": "42:1:1", + "nodeType": "FunctionDefinition", + "parameters": + { + "id": 7, + "nodeType": "ParameterList", + "parameters": + [ + { + "constant": false, + "id": 6, + "mutability": "mutable", + "name": "", + "nameLocation": "-1:-1:-1", + "nodeType": "VariableDeclaration", + "scope": 10, + "src": "44:4:1", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "typeName": + { + "id": 5, + "name": "uint", + "nodeType": "ElementaryTypeName", + "src": "44:4:1", + "typeDescriptions": + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "visibility": "internal" + } + ], + "src": "43:6:1" + }, + "returnParameters": + { + "id": 8, + "nodeType": "ParameterList", + "parameters": [], + "src": "50:0:1" + }, + "scope": 14, + "src": "33:19:1", + "stateMutability": "nonpayable", + "virtual": false, + "visibility": "internal" + }, { "abstract": false, "baseContracts": [], @@ -42,46 +144,35 @@ "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, - "id": 5, + "id": 13, "linearizedBaseContracts": [ - 5 + 13 ], "name": "C", - "nameLocation": "22:1:1", + "nameLocation": "62:1:1", "nodeType": "ContractDefinition", "nodes": [ { - "id": 4, + "global": false, + "id": 12, "libraryName": { - "id": 2, + "id": 11, "name": "L", "nodeType": "IdentifierPath", - "referencedDeclaration": 1, - "src": "32:1:1" + "referencedDeclaration": 4, + "src": "72:1:1" }, "nodeType": "UsingForDirective", - "src": "26:17:1", - "typeName": - { - "id": 3, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "38:4:1", - "typeDescriptions": - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } + "src": "66:14:1" } ], - "scope": 6, - "src": "13:32:1", + "scope": 14, + "src": "53:29:1", "usedErrors": [] } ], - "src": "0:46:1" + "src": "0:83:1" } diff --git a/test/libsolidity/ASTJSON/using_for_directive.sol b/test/libsolidity/ASTJSON/using_for_directive.sol index be6e5288f4b4..30e40252a403 100644 --- a/test/libsolidity/ASTJSON/using_for_directive.sol +++ b/test/libsolidity/ASTJSON/using_for_directive.sol @@ -1,3 +1,6 @@ -library L {} contract C { using L for uint; } +using {f} for uint; +library L {} +function f(uint) {} +contract C { using L for *; } // ---- diff --git a/test/libsolidity/ASTJSON/using_for_directive_parseOnly.json b/test/libsolidity/ASTJSON/using_for_directive_parseOnly.json index b4b016ac1594..d704b4e8154d 100644 --- a/test/libsolidity/ASTJSON/using_for_directive_parseOnly.json +++ b/test/libsolidity/ASTJSON/using_for_directive_parseOnly.json @@ -1,57 +1,133 @@ { "absolutePath": "a", - "id": 6, + "id": 14, "nodeType": "SourceUnit", "nodes": [ + { + "functionList": + [ + { + "function": + { + "id": 1, + "name": "f", + "nodeType": "IdentifierPath", + "src": "7:1:1" + } + } + ], + "global": false, + "id": 3, + "nodeType": "UsingForDirective", + "src": "0:19:1", + "typeName": + { + "id": 2, + "name": "uint", + "nodeType": "ElementaryTypeName", + "src": "14:4:1", + "typeDescriptions": {} + } + }, { "abstract": false, "baseContracts": [], "contractDependencies": [], "contractKind": "library", - "id": 1, + "id": 4, "name": "L", - "nameLocation": "8:1:1", + "nameLocation": "28:1:1", "nodeType": "ContractDefinition", "nodes": [], - "src": "0:12:1", + "src": "20:12:1", "usedErrors": [] }, + { + "body": + { + "id": 9, + "nodeType": "Block", + "src": "50:2:1", + "statements": [] + }, + "id": 10, + "implemented": true, + "kind": "freeFunction", + "modifiers": [], + "name": "f", + "nameLocation": "42:1:1", + "nodeType": "FunctionDefinition", + "parameters": + { + "id": 7, + "nodeType": "ParameterList", + "parameters": + [ + { + "constant": false, + "id": 6, + "mutability": "mutable", + "name": "", + "nameLocation": "-1:-1:-1", + "nodeType": "VariableDeclaration", + "src": "44:4:1", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": {}, + "typeName": + { + "id": 5, + "name": "uint", + "nodeType": "ElementaryTypeName", + "src": "44:4:1", + "typeDescriptions": {} + }, + "visibility": "internal" + } + ], + "src": "43:6:1" + }, + "returnParameters": + { + "id": 8, + "nodeType": "ParameterList", + "parameters": [], + "src": "50:0:1" + }, + "src": "33:19:1", + "stateMutability": "nonpayable", + "virtual": false, + "visibility": "internal" + }, { "abstract": false, "baseContracts": [], "contractDependencies": [], "contractKind": "contract", - "id": 5, + "id": 13, "name": "C", - "nameLocation": "22:1:1", + "nameLocation": "62:1:1", "nodeType": "ContractDefinition", "nodes": [ { - "id": 4, + "global": false, + "id": 12, "libraryName": { - "id": 2, + "id": 11, "name": "L", "nodeType": "IdentifierPath", - "src": "32:1:1" + "src": "72:1:1" }, "nodeType": "UsingForDirective", - "src": "26:17:1", - "typeName": - { - "id": 3, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "38:4:1", - "typeDescriptions": {} - } + "src": "66:14:1" } ], - "src": "13:32:1", + "src": "53:29:1", "usedErrors": [] } ], - "src": "0:46:1" + "src": "0:83:1" } diff --git a/test/libsolidity/ASTJSONTest.cpp b/test/libsolidity/ASTJSONTest.cpp index 82c6e7e18664..14e2c2a8a477 100644 --- a/test/libsolidity/ASTJSONTest.cpp +++ b/test/libsolidity/ASTJSONTest.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -49,6 +50,30 @@ namespace string const sourceDelimiter("==== Source: "); +string compilerStateToString(CompilerStack::State _state) +{ + switch (_state) + { + case CompilerStack::State::Empty: return "Empty"; + case CompilerStack::State::SourcesSet: return "SourcesSet"; + case CompilerStack::State::Parsed: return "Parsed"; + case CompilerStack::State::ParsedAndImported: return "ParsedAndImported"; + case CompilerStack::State::AnalysisPerformed: return "AnalysisPerformed"; + case CompilerStack::State::CompilationSuccessful: return "CompilationSuccessful"; + } + soltestAssert(false, "Unexpected value of state parameter"); +} + +CompilerStack::State stringToCompilerState(const string& _state) +{ + for (unsigned int i = CompilerStack::State::Empty; i <= CompilerStack::State::CompilationSuccessful; ++i) + { + if (_state == compilerStateToString(CompilerStack::State(i))) + return CompilerStack::State(i); + } + BOOST_THROW_EXCEPTION(runtime_error("Unsupported compiler state (" + _state + ") in test contract file")); +} + void replaceVersionWithTag(string& _input) { boost::algorithm::replace_all( @@ -69,20 +94,30 @@ void replaceTagWithVersion(string& _input) } - -ASTJSONTest::ASTJSONTest(string const& _filename) +void ASTJSONTest::generateTestVariants(string const& _filename) { - if (!boost::algorithm::ends_with(_filename, ".sol")) - BOOST_THROW_EXCEPTION(runtime_error("Invalid test contract file name: \"" + _filename + "\".")); - string_view baseName = _filename; baseName.remove_suffix(4); - m_variants = { - TestVariant(baseName, CompilerStack::State::Parsed), - TestVariant(baseName, CompilerStack::State::AnalysisPerformed), + const std::vector variantCompileStates = { + CompilerStack::State::Parsed, + CompilerStack::State::AnalysisPerformed }; + for (const auto state: variantCompileStates) + { + auto variant = TestVariant(baseName, state); + if (boost::filesystem::exists(variant.astFilename())) + { + variant.expectation = readFileAsString(variant.astFilename()); + boost::replace_all(variant.expectation, "\r\n", "\n"); + m_variants.push_back(variant); + } + } +} + +void ASTJSONTest::fillSources(string const& _filename) +{ ifstream file(_filename); if (!file) BOOST_THROW_EXCEPTION(runtime_error("Cannot open test contract: \"" + _filename + "\".")); @@ -92,6 +127,7 @@ ASTJSONTest::ASTJSONTest(string const& _filename) string source; string line; string const delimiter("// ----"); + string const failMarker("// failAfter:"); while (getline(file, line)) { if (boost::algorithm::starts_with(line, sourceDelimiter)) @@ -105,20 +141,55 @@ ASTJSONTest::ASTJSONTest(string const& _filename) ); source = string(); } + else if (boost::algorithm::starts_with(line, failMarker)) + { + string state = line.substr(failMarker.size()); + boost::algorithm::trim(state); + if (m_expectedFailAfter.has_value()) + BOOST_THROW_EXCEPTION(runtime_error("Duplicated \"failAfter\" directive")); + m_expectedFailAfter = stringToCompilerState(state); + + } else if (!line.empty() && !boost::algorithm::starts_with(line, delimiter)) source += line + "\n"; } - m_sources.emplace_back(sourceName.empty() ? "a" : sourceName, source); file.close(); +} - for (TestVariant& variant: m_variants) +void ASTJSONTest::validateTestConfiguration() const +{ + if (m_variants.empty()) + BOOST_THROW_EXCEPTION(runtime_error("No file with expected result found.")); + + if (m_expectedFailAfter.has_value()) { - variant.expectation = readFileAsString(variant.astFilename()); - boost::replace_all(variant.expectation, "\r\n", "\n"); + auto unexpectedTestVariant = std::find_if( + m_variants.begin(), m_variants.end(), + [failAfter = m_expectedFailAfter](TestVariant v) { return v.stopAfter > failAfter; } + ); + + if (unexpectedTestVariant != m_variants.end()) + BOOST_THROW_EXCEPTION( + runtime_error( + string("Unexpected JSON file: ") + unexpectedTestVariant->astFilename() + + " in \"failAfter: " + + compilerStateToString(m_expectedFailAfter.value()) + "\" scenario." + ) + ); } } +ASTJSONTest::ASTJSONTest(string const& _filename) +{ + if (!boost::algorithm::ends_with(_filename, ".sol")) + BOOST_THROW_EXCEPTION(runtime_error("Invalid test contract file name: \"" + _filename + "\".")); + + generateTestVariants(_filename); + fillSources(_filename); + validateTestConfiguration(); +} + TestCase::TestResult ASTJSONTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted) { CompilerStack c; @@ -141,13 +212,12 @@ TestCase::TestResult ASTJSONTest::run(ostream& _stream, string const& _linePrefi if (!c.parseAndAnalyze(variant.stopAfter)) { - // Ignore non-fatal analysis errors, we only want to export. - if (c.state() > CompilerStack::State::Parsed) - continue; - - SourceReferenceFormatter formatter(_stream, c, _formatted, false); - formatter.printErrorInformation(c.errors()); - return TestResult::FatalError; + if (!m_expectedFailAfter.has_value() || m_expectedFailAfter.value() + 1 != c.state()) + { + SourceReferenceFormatter formatter(_stream, c, _formatted, false); + formatter.printErrorInformation(c.errors()); + return TestResult::FatalError; + } } resultsMatch = resultsMatch && runTest( diff --git a/test/libsolidity/ASTJSONTest.h b/test/libsolidity/ASTJSONTest.h index 3365de589df3..648f3bbc3234 100644 --- a/test/libsolidity/ASTJSONTest.h +++ b/test/libsolidity/ASTJSONTest.h @@ -89,7 +89,12 @@ class ASTJSONTest: public TestCase std::string const& _variant ) const; + void generateTestVariants(std::string const& _filename); + void fillSources(std::string const& _filename); + void validateTestConfiguration() const; + std::vector m_variants; + std::optional m_expectedFailAfter; std::vector> m_sources; }; diff --git a/test/libsolidity/Metadata.cpp b/test/libsolidity/Metadata.cpp index d37398637073..9cbf73f842f1 100644 --- a/test/libsolidity/Metadata.cpp +++ b/test/libsolidity/Metadata.cpp @@ -373,13 +373,7 @@ BOOST_AUTO_TEST_CASE(metadata_viair) CompilerStack::MetadataFormat::WithReleaseVersionTag ); - if (_viaIR) - { - BOOST_CHECK(parsedCBORMetadata.count("experimental") == 1); - BOOST_CHECK(parsedCBORMetadata.at("experimental") == "true"); - } - else - BOOST_CHECK(parsedCBORMetadata.count("experimental") == 0); + BOOST_CHECK(parsedCBORMetadata.count("experimental") == 0); }; check(sourceCode, true); diff --git a/test/libsolidity/SemanticTest.cpp b/test/libsolidity/SemanticTest.cpp index 1f07f177d477..3c26f5a97e64 100644 --- a/test/libsolidity/SemanticTest.cpp +++ b/test/libsolidity/SemanticTest.cpp @@ -70,10 +70,10 @@ SemanticTest::SemanticTest( static set const legacyRunTriggers{"also", "false", "default"}; string compileViaYul = m_reader.stringSetting("compileViaYul", "default"); - if (!contains(compileViaYulAllowedValues, compileViaYul)) + if (!util::contains(compileViaYulAllowedValues, compileViaYul)) BOOST_THROW_EXCEPTION(runtime_error("Invalid compileViaYul value: " + compileViaYul + ".")); - m_testCaseWantsYulRun = contains(yulRunTriggers, compileViaYul); - m_testCaseWantsLegacyRun = contains(legacyRunTriggers, compileViaYul); + m_testCaseWantsYulRun = util::contains(yulRunTriggers, compileViaYul); + m_testCaseWantsLegacyRun = util::contains(legacyRunTriggers, compileViaYul); // Do not enforce via yul and ewasm, if via yul was explicitly denied. if (compileViaYul == "false") @@ -189,7 +189,7 @@ vector SemanticTest::makeSideEffectHooks() const { vector result; for (auto const& argument: _call.arguments.parameters) - result.emplace_back(toHex(argument.rawBytes)); + result.emplace_back(util::toHex(argument.rawBytes)); return result; } return {}; diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 314d4283e0de..7509bed3c0ad 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -84,6 +84,34 @@ struct SolidityEndToEndTestExecutionFramework: public SolidityExecutionFramework BOOST_FIXTURE_TEST_SUITE(SolidityEndToEndTest, SolidityEndToEndTestExecutionFramework) +BOOST_AUTO_TEST_CASE(creation_code_optimizer) +{ + string codeC = R"( + contract C { + constructor(uint x) { + if (x == 0xFFFFFFFFFFFFFFFF42) + revert(); + } + } + )"; + string codeD = R"( + contract D { + function f() public pure returns (bytes memory) { + return type(C).creationCode; + } + } + )"; + + m_metadataHash = CompilerStack::MetadataHash::None; + ALSO_VIA_YUL({ + bytes bytecodeC = compileContract(codeC); + reset(); + compileAndRun(codeC + codeD); + ABI_CHECK(callContractFunction("f()"), encodeArgs(0x20, bytecodeC.size()) + encode(bytecodeC, false)); + m_doEwasmTestrun = false; + }) +} + unsigned constexpr roundTo32(unsigned _num) { return (_num + 31) / 32 * 32; @@ -4074,12 +4102,12 @@ BOOST_AUTO_TEST_CASE(strip_reason_strings) m_optimiserSettings == OptimiserSettings::none() ) // check that the reason string IS part of the binary. - BOOST_CHECK(toHex(m_output).find("736f6d6520726561736f6e") != std::string::npos); + BOOST_CHECK(util::toHex(m_output).find("736f6d6520726561736f6e") != std::string::npos); m_revertStrings = RevertStrings::Strip; compileAndRun(sourceCode, 0, "C"); // check that the reason string is NOT part of the binary. - BOOST_CHECK(toHex(m_output).find("736f6d6520726561736f6e") == std::string::npos); + BOOST_CHECK(util::toHex(m_output).find("736f6d6520726561736f6e") == std::string::npos); ABI_CHECK(callContractFunction("f(bool)", true), encodeArgs(7)); ABI_CHECK(callContractFunction("f(bool)", false), encodeArgs()); diff --git a/test/libsolidity/SolidityExecutionFramework.cpp b/test/libsolidity/SolidityExecutionFramework.cpp index f3921613f47e..7ff226a69407 100644 --- a/test/libsolidity/SolidityExecutionFramework.cpp +++ b/test/libsolidity/SolidityExecutionFramework.cpp @@ -62,6 +62,7 @@ bytes SolidityExecutionFramework::multiSourceCompileContract( m_compiler.enableEvmBytecodeGeneration(!m_compileViaYul); m_compiler.enableIRGeneration(m_compileViaYul); m_compiler.setRevertStringBehaviour(m_revertStrings); + m_compiler.setMetadataHash(m_metadataHash); if (!m_compiler.compile()) { // The testing framework expects an exception for diff --git a/test/libsolidity/SolidityExecutionFramework.h b/test/libsolidity/SolidityExecutionFramework.h index e0e02cf95ad3..202addffafce 100644 --- a/test/libsolidity/SolidityExecutionFramework.h +++ b/test/libsolidity/SolidityExecutionFramework.h @@ -75,11 +75,12 @@ class SolidityExecutionFramework: public solidity::test::ExecutionFramework /// the latter only if it is forced. static std::string addPreamble(std::string const& _sourceCode); protected: - - solidity::frontend::CompilerStack m_compiler; + using CompilerStack = solidity::frontend::CompilerStack; + CompilerStack m_compiler; bool m_compileViaYul = false; bool m_compileToEwasm = false; bool m_showMetadata = false; + CompilerStack::MetadataHash m_metadataHash = CompilerStack::MetadataHash::IPFS; RevertStrings m_revertStrings = RevertStrings::Default; }; diff --git a/test/libsolidity/SolidityExpressionCompiler.cpp b/test/libsolidity/SolidityExpressionCompiler.cpp index 5f7b8d4724ef..4fef140e8f89 100644 --- a/test/libsolidity/SolidityExpressionCompiler.cpp +++ b/test/libsolidity/SolidityExpressionCompiler.cpp @@ -350,7 +350,7 @@ BOOST_AUTO_TEST_CASE(arithmetic) uint8_t(Instruction::JUMPDEST), uint8_t(Instruction::PUSH32) } + - fromHex("4E487B7100000000000000000000000000000000000000000000000000000000") + + util::fromHex("4E487B7100000000000000000000000000000000000000000000000000000000") + bytes{ uint8_t(Instruction::PUSH1), 0x0, uint8_t(Instruction::MSTORE), diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp index eb4102b1502d..a1580fb539be 100644 --- a/test/libsolidity/SolidityOptimizer.cpp +++ b/test/libsolidity/SolidityOptimizer.cpp @@ -98,8 +98,8 @@ class OptimizerTestFramework: public SolidityExecutionFramework BOOST_CHECK_MESSAGE(!optimizedOutput.empty(), "No optimized output for " + _sig); BOOST_CHECK_MESSAGE(!nonOptimizedOutput.empty(), "No un-optimized output for " + _sig); BOOST_CHECK_MESSAGE(nonOptimizedOutput == optimizedOutput, "Computed values do not match." - "\nNon-Optimized: " + toHex(nonOptimizedOutput) + - "\nOptimized: " + toHex(optimizedOutput)); + "\nNon-Optimized: " + util::toHex(nonOptimizedOutput) + + "\nOptimized: " + util::toHex(optimizedOutput)); } /// @returns the number of instructions in the given bytecode, not taking the metadata hash diff --git a/test/libsolidity/analysis/FunctionCallGraph.cpp b/test/libsolidity/analysis/FunctionCallGraph.cpp index 30477aa2e43c..7b67aeb44eec 100644 --- a/test/libsolidity/analysis/FunctionCallGraph.cpp +++ b/test/libsolidity/analysis/FunctionCallGraph.cpp @@ -47,6 +47,7 @@ #include using namespace std; +using namespace solidity::util; using namespace solidity::langutil; using namespace solidity::frontend; diff --git a/test/libsolidity/lsp/goto_definition.sol b/test/libsolidity/lsp/goto_definition.sol new file mode 100644 index 000000000000..675c1297ce80 --- /dev/null +++ b/test/libsolidity/lsp/goto_definition.sol @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.0; + +import "./lib.sol"; + +interface I +{ + function f(uint x) external returns (uint); +} + +contract IA is I +{ + function f(uint x) public pure override returns (uint) { return x + 1; } +} + +contract IB is I +{ + function f(uint x) public pure override returns (uint) { return x + 2; } +} + +library IntLib +{ + function add(int self, int b) public pure returns (int) { return self + b; } +} + +contract C +{ + I obj; + function virtual_inheritance() public payable + { + obj = new IA(); + obj.f(1); // goto-definition should jump to definition of interface. + } + + using IntLib for *; + function using_for(int i) pure public + { + i.add(5); + 14.add(4); + } + + function useLib(uint n) public payable returns (uint) + { + return Lib.add(n, 1); + } + + function enums(Color c) public pure returns (Color d) + { + Color e = Color.Red; + if (c == e) + d = Color.Green; + else + d = c; + } + + type Price is uint128; + function udlTest() public pure returns (uint128) + { + Price p = Price.wrap(128); + return Price.unwrap(p); + } + + function structCtorTest(uint8 v) public pure returns (uint8 result) + { + RGBColor memory c = RGBColor(v, 2 * v, 3 * v); + result = c.red; + } +} diff --git a/test/libsolidity/lsp/goto_definition_imports.sol b/test/libsolidity/lsp/goto_definition_imports.sol new file mode 100644 index 000000000000..b3df921fe1f1 --- /dev/null +++ b/test/libsolidity/lsp/goto_definition_imports.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.0; + +import {Weather as Wetter} from "./lib.sol"; +import "./lib.sol" as That; + +contract C +{ + function test_symbol_alias() public pure returns (Wetter result) + { + result = Wetter.Sunny; + } + + function test_library_alias() public pure returns (That.Color result) + { + That.Color color = That.Color.Red; + result = color; + } +} diff --git a/test/libsolidity/lsp/lib.sol b/test/libsolidity/lsp/lib.sol index f4fb51e77b24..22efe6ca2ab9 100644 --- a/test/libsolidity/lsp/lib.sol +++ b/test/libsolidity/lsp/lib.sol @@ -1,6 +1,25 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.0; +/// Some Error type E. +error E(uint, uint); + +enum Weather { + Sunny, + Cloudy, + Rainy +} + +/// Some custom Color enum type holding 3 colors. +enum Color { + /// Red color. + Red, + /// Green color. + Green, + /// Blue color. + Blue +} + library Lib { function add(uint a, uint b) public pure returns (uint result) @@ -13,3 +32,10 @@ library Lib uint unused; } } + +struct RGBColor +{ + uint8 red; + uint8 green; + uint8 blue; +} diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_storage.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_storage.sol index 06f9bcbbfce8..07f4ab2756d7 100644 --- a/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_storage.sol +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_storage.sol @@ -24,6 +24,6 @@ contract C { // compileViaYul: also // ---- // f() -> 0x20, 0x8, 0x40, 0x3, 0x9, 0xa, 0xb -// gas irOptimized: 203312 -// gas legacy: 206084 -// gas legacyOptimized: 203068 +// gas irOptimized: 203310 +// gas legacy: 206075 +// gas legacyOptimized: 203059 diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_calldata_slice.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_calldata_slice.sol index c386cf3e84f4..8503e5790ab2 100644 --- a/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_calldata_slice.sol +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_calldata_slice.sol @@ -60,10 +60,10 @@ contract C { // compileViaYul: also // ---- // test_bytes() -> -// gas irOptimized: 371919 -// gas legacy: 418955 -// gas legacyOptimized: 326783 +// gas irOptimized: 371912 +// gas legacy: 416585 +// gas legacyOptimized: 322043 // test_uint256() -> -// gas irOptimized: 523001 -// gas legacy: 586784 -// gas legacyOptimized: 451529 +// gas irOptimized: 523016 +// gas legacy: 583100 +// gas legacyOptimized: 444161 diff --git a/test/libsolidity/semanticTests/abiEncoderV1/struct/struct_storage_ptr.sol b/test/libsolidity/semanticTests/abiEncoderV1/struct/struct_storage_ptr.sol index cc1a182c9f3b..cfdecd7a04c0 100644 --- a/test/libsolidity/semanticTests/abiEncoderV1/struct/struct_storage_ptr.sol +++ b/test/libsolidity/semanticTests/abiEncoderV1/struct/struct_storage_ptr.sol @@ -26,6 +26,6 @@ contract C { // ---- // library: L // f() -> 8, 7, 1, 2, 7, 12 -// gas irOptimized: 167696 +// gas irOptimized: 167691 // gas legacy: 169347 // gas legacyOptimized: 167269 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_calldata_slice.sol b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_calldata_slice.sol index 9deed97f1d81..2710f202d0c8 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_calldata_slice.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_calldata_slice.sol @@ -61,10 +61,10 @@ contract C { // compileViaYul: also // ---- // test_bytes() -> -// gas irOptimized: 371919 -// gas legacy: 418955 -// gas legacyOptimized: 326783 +// gas irOptimized: 371912 +// gas legacy: 416585 +// gas legacyOptimized: 322043 // test_uint256() -> -// gas irOptimized: 523001 -// gas legacy: 586784 -// gas legacyOptimized: 451529 +// gas irOptimized: 523016 +// gas legacy: 583100 +// gas legacyOptimized: 444161 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2.sol b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2.sol index 82ece5f3f35a..e1e2d0ab64d9 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2.sol @@ -53,6 +53,6 @@ contract C { // f2() -> 0x20, 0xa0, 0x1, 0x60, 0x2, 0x3, "abc" // f3() -> 0x20, 0xa0, 0x1, 0x60, 0x2, 0x3, "abc" // f4() -> 0x20, 0x160, 0x1, 0x80, 0xc0, 0x2, 0x3, "abc", 0x7, 0x40, 0x2, 0x2, 0x3 -// gas irOptimized: 113299 +// gas irOptimized: 113277 // gas legacy: 114900 // gas legacyOptimized: 112606 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.sol b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.sol index eec062f56b15..b7d917dbf9c2 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.sol @@ -32,6 +32,6 @@ contract C is B { // compileViaYul: also // ---- // test() -> 77 -// gas irOptimized: 119919 +// gas irOptimized: 119711 // gas legacy: 155093 // gas legacyOptimized: 111550 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array.sol index cf5958d456dc..63ee9bd029c0 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array.sol @@ -21,6 +21,6 @@ contract C { // f(uint256[][1]): 32, 32, 0 -> true // f(uint256[][1]): 32, 32, 1, 42 -> true // f(uint256[][1]): 32, 32, 8, 421, 422, 423, 424, 425, 426, 427, 428 -> true -// gas irOptimized: 171842 -// gas legacy: 141644 -// gas legacyOptimized: 121532 +// gas irOptimized: 171829 +// gas legacy: 140672 +// gas legacyOptimized: 119588 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/storage_array_encoding.sol b/test/libsolidity/semanticTests/abiEncoderV2/storage_array_encoding.sol index 1f1e977201f4..5499c2594e1e 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/storage_array_encoding.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/storage_array_encoding.sol @@ -19,10 +19,10 @@ contract C { // compileViaYul: also // ---- // h(uint256[2][]): 0x20, 3, 123, 124, 223, 224, 323, 324 -> 32, 256, 0x20, 3, 123, 124, 223, 224, 323, 324 -// gas irOptimized: 180931 +// gas irOptimized: 180924 // gas legacy: 184929 // gas legacyOptimized: 181504 // i(uint256[2][2]): 123, 124, 223, 224 -> 32, 128, 123, 124, 223, 224 -// gas irOptimized: 112539 +// gas irOptimized: 112520 // gas legacy: 115468 // gas legacyOptimized: 112988 diff --git a/test/libsolidity/semanticTests/abiencodedecode/abi_decode_simple_storage.sol b/test/libsolidity/semanticTests/abiencodedecode/abi_decode_simple_storage.sol index b6c6ad5f0361..027ae4e1691c 100644 --- a/test/libsolidity/semanticTests/abiencodedecode/abi_decode_simple_storage.sol +++ b/test/libsolidity/semanticTests/abiencodedecode/abi_decode_simple_storage.sol @@ -12,5 +12,5 @@ contract C { // ---- // f(bytes): 0x20, 0x80, 0x21, 0x40, 0x7, "abcdefg" -> 0x21, 0x40, 0x7, "abcdefg" // gas irOptimized: 135918 -// gas legacy: 137190 -// gas legacyOptimized: 136082 +// gas legacy: 137181 +// gas legacyOptimized: 136073 diff --git a/test/libsolidity/semanticTests/abiencodedecode/abi_encode_call_uint_bytes.sol b/test/libsolidity/semanticTests/abiencodedecode/abi_encode_call_uint_bytes.sol new file mode 100644 index 000000000000..d19a457f97a9 --- /dev/null +++ b/test/libsolidity/semanticTests/abiencodedecode/abi_encode_call_uint_bytes.sol @@ -0,0 +1,21 @@ +contract C { + function removeSignature(bytes calldata x) external pure returns (bytes memory) { + return x[4:]; + } + function g(bytes2, bytes2, bytes2) public {} + function h(uint16, uint16) public {} + function f() public returns (bytes memory) { + uint16 x = 0x1234; + return this.removeSignature(abi.encodeCall(this.g, (0x1234, "ab", bytes2(x)))); + } + function f2() public returns (bytes memory) { + bytes2 x = 0x1234; + return this.removeSignature(abi.encodeCall(this.h, (0x1234, uint16(x)))); + } +} +// ==== +// compileViaYul: also +// EVMVersion: >homestead +// ---- +// f() -> 0x20, 0x60, 0x1234000000000000000000000000000000000000000000000000000000000000, 0x6162000000000000000000000000000000000000000000000000000000000000, 0x1234000000000000000000000000000000000000000000000000000000000000 +// f2() -> 0x20, 0x40, 0x1234, 0x1234 diff --git a/test/libsolidity/semanticTests/array/arrays_complex_from_and_to_storage.sol b/test/libsolidity/semanticTests/array/arrays_complex_from_and_to_storage.sol index 7a2a06a2e685..8d1851c81721 100644 --- a/test/libsolidity/semanticTests/array/arrays_complex_from_and_to_storage.sol +++ b/test/libsolidity/semanticTests/array/arrays_complex_from_and_to_storage.sol @@ -14,7 +14,7 @@ contract Test { // compileViaYul: also // ---- // set(uint24[3][]): 0x20, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12 -> 0x06 -// gas irOptimized: 189871 +// gas irOptimized: 189800 // gas legacy: 211149 // gas legacyOptimized: 206054 // data(uint256,uint256): 0x02, 0x02 -> 0x09 diff --git a/test/libsolidity/semanticTests/array/byte_array_storage_layout.sol b/test/libsolidity/semanticTests/array/byte_array_storage_layout.sol index 2c238a54b0a1..b176c7e866c0 100644 --- a/test/libsolidity/semanticTests/array/byte_array_storage_layout.sol +++ b/test/libsolidity/semanticTests/array/byte_array_storage_layout.sol @@ -48,8 +48,8 @@ contract c { // storageEmpty -> 0 // test_long() -> 67 // gas irOptimized: 89148 -// gas legacy: 103590 -// gas legacyOptimized: 101044 +// gas legacy: 103039 +// gas legacyOptimized: 100493 // storageEmpty -> 0 // test_pop() -> 1780731860627700044960722568376592200742329637303199754547598369979433020 // gas legacy: 61930 diff --git a/test/libsolidity/semanticTests/array/byte_array_transitional_2.sol b/test/libsolidity/semanticTests/array/byte_array_transitional_2.sol index 31879057a784..f0b0d1bc0c1a 100644 --- a/test/libsolidity/semanticTests/array/byte_array_transitional_2.sol +++ b/test/libsolidity/semanticTests/array/byte_array_transitional_2.sol @@ -19,6 +19,6 @@ contract c { // compileViaYul: also // ---- // test() -> 0 -// gas irOptimized: 158143 -// gas legacy: 189715 -// gas legacyOptimized: 184472 +// gas irOptimized: 157949 +// gas legacy: 188576 +// gas legacyOptimized: 183333 diff --git a/test/libsolidity/semanticTests/array/bytes_length_member.sol b/test/libsolidity/semanticTests/array/bytes_length_member.sol index aaf990ef6859..b4e018e6590a 100644 --- a/test/libsolidity/semanticTests/array/bytes_length_member.sol +++ b/test/libsolidity/semanticTests/array/bytes_length_member.sol @@ -15,7 +15,7 @@ contract c { // ---- // getLength() -> 0 // set(): 1, 2 -> true -// gas irOptimized: 110439 -// gas legacy: 110726 -// gas legacyOptimized: 110567 +// gas irOptimized: 110435 +// gas legacy: 110723 +// gas legacyOptimized: 110564 // getLength() -> 68 diff --git a/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol b/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol index 945de3cfea2a..42d14ba2424c 100644 --- a/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol +++ b/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol @@ -11,7 +11,7 @@ contract C { // compileViaYul: also // ---- // constructor(): 1, 2, 3 -> -// gas irOptimized: 143598 +// gas irOptimized: 142640 // gas legacy: 183490 // gas legacyOptimized: 151938 // a(uint256): 0 -> 1 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_calldata_storage.sol b/test/libsolidity/semanticTests/array/copying/array_copy_calldata_storage.sol index 6c876286b5de..f80da3500847 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_calldata_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_calldata_storage.sol @@ -22,7 +22,7 @@ contract c { // compileViaYul: also // ---- // store(uint256[9],uint8[3][]): 21, 22, 23, 24, 25, 26, 27, 28, 29, 0x140, 4, 1, 2, 3, 11, 12, 13, 21, 22, 23, 31, 32, 33 -> 32 -// gas irOptimized: 650647 +// gas irOptimized: 650608 // gas legacy: 694515 // gas legacyOptimized: 694013 // retrieve() -> 9, 28, 9, 28, 4, 3, 32 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_different_packing.sol b/test/libsolidity/semanticTests/array/copying/array_copy_different_packing.sol index 81607a26439c..04b3b8e84fc2 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_different_packing.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_different_packing.sol @@ -21,6 +21,6 @@ contract c { // compileViaYul: also // ---- // test() -> 0x01000000000000000000000000000000000000000000000000, 0x02000000000000000000000000000000000000000000000000, 0x03000000000000000000000000000000000000000000000000, 0x04000000000000000000000000000000000000000000000000, 0x05000000000000000000000000000000000000000000000000 -// gas irOptimized: 212571 -// gas legacy: 221883 -// gas legacyOptimized: 220734 +// gas irOptimized: 212564 +// gas legacy: 221856 +// gas legacyOptimized: 220680 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_including_array.sol b/test/libsolidity/semanticTests/array/copying/array_copy_including_array.sol index 1c030debaf10..92495b157855 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_including_array.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_including_array.sol @@ -37,12 +37,12 @@ contract c { // compileViaYul: also // ---- // test() -> 0x02000202 -// gas irOptimized: 4652058 -// gas legacy: 4578341 -// gas legacyOptimized: 4548354 +// gas irOptimized: 4652048 +// gas legacy: 4578320 +// gas legacyOptimized: 4548312 // storageEmpty -> 1 // clear() -> 0, 0 -// gas irOptimized: 4483175 -// gas legacy: 4410769 -// gas legacyOptimized: 4382531 +// gas irOptimized: 4483170 +// gas legacy: 4410748 +// gas legacyOptimized: 4382489 // storageEmpty -> 1 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_nested_array.sol b/test/libsolidity/semanticTests/array/copying/array_copy_nested_array.sol index 0e05c4ea8eac..88fed0d9be22 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_nested_array.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_nested_array.sol @@ -15,6 +15,6 @@ contract c { // compileViaYul: also // ---- // test(uint256[2][]): 32, 3, 7, 8, 9, 10, 11, 12 -> 10 -// gas irOptimized: 690205 +// gas irOptimized: 690203 // gas legacy: 686268 // gas legacyOptimized: 685688 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_different_base.sol b/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_different_base.sol index cad3c9d49235..bd45f49a98e5 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_different_base.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_different_base.sol @@ -19,6 +19,6 @@ contract c { // compileViaYul: also // ---- // test() -> 5, 4 -// gas irOptimized: 225956 +// gas irOptimized: 225954 // gas legacy: 233801 // gas legacyOptimized: 232816 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_dyn_dyn.sol b/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_dyn_dyn.sol index b4b3929746b0..f90d4b85200e 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_dyn_dyn.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_dyn_dyn.sol @@ -17,7 +17,7 @@ contract c { // ---- // setData1(uint256,uint256,uint256): 10, 5, 4 -> // copyStorageStorage() -> -// gas irOptimized: 111406 +// gas irOptimized: 111387 // gas legacy: 109278 // gas legacyOptimized: 109268 // getData2(uint256): 5 -> 10, 4 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_static_static.sol b/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_static_static.sol index c865b82280b1..ad12cad129d5 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_static_static.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_static_static.sol @@ -18,6 +18,6 @@ contract c { // compileViaYul: also // ---- // test() -> 8, 0 -// gas irOptimized: 236090 +// gas irOptimized: 236079 // gas legacy: 234695 // gas legacyOptimized: 234103 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_struct.sol b/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_struct.sol index db26b4d472c7..676736dc1116 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_struct.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_struct.sol @@ -19,7 +19,7 @@ contract c { // compileViaYul: also // ---- // test() -> 4, 5 -// gas irOptimized: 238826 +// gas irOptimized: 238799 // gas legacy: 238736 // gas legacyOptimized: 237159 // storageEmpty -> 1 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_target_leftover.sol b/test/libsolidity/semanticTests/array/copying/array_copy_target_leftover.sol index 1daa061a52ba..5325e9cdfa5e 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_target_leftover.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_target_leftover.sol @@ -21,5 +21,5 @@ contract c { // ---- // test() -> 0xffffffff, 0x0000000000000000000000000a00090008000700060005000400030002000100, 0x0000000000000000000000000000000000000000000000000000000000000000 // gas irOptimized: 129167 -// gas legacy: 186406 -// gas legacyOptimized: 166126 +// gas legacy: 186184 +// gas legacyOptimized: 165682 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_target_simple.sol b/test/libsolidity/semanticTests/array/copying/array_copy_target_simple.sol index c87f70244ce1..68817ba4c12e 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_target_simple.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_target_simple.sol @@ -22,6 +22,6 @@ contract c { // compileViaYul: also // ---- // test() -> 0x01000000000000000000000000000000000000000000000000, 0x02000000000000000000000000000000000000000000000000, 0x03000000000000000000000000000000000000000000000000, 0x04000000000000000000000000000000000000000000000000, 0x0 -// gas irOptimized: 294772 -// gas legacy: 303653 -// gas legacyOptimized: 301999 +// gas irOptimized: 294770 +// gas legacy: 303626 +// gas legacyOptimized: 301945 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_target_simple_2.sol b/test/libsolidity/semanticTests/array/copying/array_copy_target_simple_2.sol index c39f8027574e..346b1c469b9c 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_target_simple_2.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_target_simple_2.sol @@ -22,6 +22,6 @@ contract c { // compileViaYul: also // ---- // test() -> 0x01000000000000000000000000000000000000000000000000, 0x02000000000000000000000000000000000000000000000000, 0x03000000000000000000000000000000000000000000000000, 0x04000000000000000000000000000000000000000000000000, 0x00 -// gas irOptimized: 273963 -// gas legacy: 276381 -// gas legacyOptimized: 275453 +// gas irOptimized: 273961 +// gas legacy: 276360 +// gas legacyOptimized: 275411 diff --git a/test/libsolidity/semanticTests/array/copying/array_nested_calldata_to_storage.sol b/test/libsolidity/semanticTests/array/copying/array_nested_calldata_to_storage.sol index f3f3e82366b6..834f4d28c67e 100644 --- a/test/libsolidity/semanticTests/array/copying/array_nested_calldata_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/array_nested_calldata_to_storage.sol @@ -40,8 +40,8 @@ contract c { // test1(uint256[][]): 0x20, 2, 0x40, 0x40, 2, 23, 42 -> 2, 65 // gas irOptimized: 181298 // test2(uint256[][2]): 0x20, 0x40, 0x40, 2, 23, 42 -> 2, 65 -// gas irOptimized: 157936 +// gas irOptimized: 157929 // test3(uint256[2][]): 0x20, 2, 23, 42, 23, 42 -> 2, 65 // gas irOptimized: 135098 // test4(uint256[2][2]): 23, 42, 23, 42 -> 65 -// gas irOptimized: 111362 +// gas irOptimized: 111346 diff --git a/test/libsolidity/semanticTests/array/copying/array_nested_memory_to_storage.sol b/test/libsolidity/semanticTests/array/copying/array_nested_memory_to_storage.sol index e8b460b4f714..e199d37bc057 100644 --- a/test/libsolidity/semanticTests/array/copying/array_nested_memory_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/array_nested_memory_to_storage.sol @@ -46,6 +46,6 @@ contract Test { // test1() -> 3 // test2() -> 6 // test3() -> 24 -// gas irOptimized: 133597 +// gas irOptimized: 133590 // gas legacy: 134295 // gas legacyOptimized: 133383 diff --git a/test/libsolidity/semanticTests/array/copying/array_of_function_external_storage_to_storage_dynamic.sol b/test/libsolidity/semanticTests/array/copying/array_of_function_external_storage_to_storage_dynamic.sol index d872534cdc5d..e358feaf7b86 100644 --- a/test/libsolidity/semanticTests/array/copying/array_of_function_external_storage_to_storage_dynamic.sol +++ b/test/libsolidity/semanticTests/array/copying/array_of_function_external_storage_to_storage_dynamic.sol @@ -47,7 +47,7 @@ contract C { // compileViaYul: also // ---- // copyExternalStorageArrayOfFunctionType() -> true -// gas irOptimized: 104669 -// gas legacy: 108725 -// gas legacyOptimized: 102441 +// gas irOptimized: 104659 +// gas legacy: 108722 +// gas legacyOptimized: 102438 // copyInternalArrayOfFunctionType() -> true diff --git a/test/libsolidity/semanticTests/array/copying/array_of_function_external_storage_to_storage_dynamic_different_mutability.sol b/test/libsolidity/semanticTests/array/copying/array_of_function_external_storage_to_storage_dynamic_different_mutability.sol index 71399a281e22..551ed4616ce3 100644 --- a/test/libsolidity/semanticTests/array/copying/array_of_function_external_storage_to_storage_dynamic_different_mutability.sol +++ b/test/libsolidity/semanticTests/array/copying/array_of_function_external_storage_to_storage_dynamic_different_mutability.sol @@ -50,8 +50,8 @@ contract C { // compileViaYul: also // ---- // copyExternalStorageArraysOfFunctionType() -> true -// gas irOptimized: 104342 -// gas legacy: 108462 -// gas legacyOptimized: 102174 +// gas irOptimized: 104332 +// gas legacy: 108459 +// gas legacyOptimized: 102171 // copyInternalArrayOfFunctionType() -> true // gas legacy: 104178 diff --git a/test/libsolidity/semanticTests/array/copying/array_of_struct_calldata_to_storage.sol b/test/libsolidity/semanticTests/array/copying/array_of_struct_calldata_to_storage.sol index b3d950ffa8f0..c4aa6ac4b78e 100644 --- a/test/libsolidity/semanticTests/array/copying/array_of_struct_calldata_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/array_of_struct_calldata_to_storage.sol @@ -17,4 +17,4 @@ contract C { // compileViaYul: true // ---- // f((uint128,uint64,uint128)[]): 0x20, 3, 0, 0, 12, 0, 11, 0, 10, 0, 0 -> 10, 11, 12 -// gas irOptimized: 121048 +// gas irOptimized: 121019 diff --git a/test/libsolidity/semanticTests/array/copying/array_of_struct_memory_to_storage.sol b/test/libsolidity/semanticTests/array/copying/array_of_struct_memory_to_storage.sol index 2fe2715876fe..0c554a32fe8e 100644 --- a/test/libsolidity/semanticTests/array/copying/array_of_struct_memory_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/array_of_struct_memory_to_storage.sol @@ -19,4 +19,4 @@ contract C { // compileViaYul: true // ---- // f() -> 10, 11, 12 -// gas irOptimized: 119149 +// gas irOptimized: 119148 diff --git a/test/libsolidity/semanticTests/array/copying/bytes_inside_mappings.sol b/test/libsolidity/semanticTests/array/copying/bytes_inside_mappings.sol index ae2698551a8f..26ad58f4cc5a 100644 --- a/test/libsolidity/semanticTests/array/copying/bytes_inside_mappings.sol +++ b/test/libsolidity/semanticTests/array/copying/bytes_inside_mappings.sol @@ -8,12 +8,12 @@ contract c { // ---- // set(uint256): 1, 2 -> true // gas irOptimized: 110604 -// gas legacy: 111091 -// gas legacyOptimized: 110736 +// gas legacy: 111088 +// gas legacyOptimized: 110733 // set(uint256): 2, 2, 3, 4, 5 -> true // gas irOptimized: 177564 -// gas legacy: 178021 -// gas legacyOptimized: 177666 +// gas legacy: 178018 +// gas legacyOptimized: 177663 // storageEmpty -> 0 // copy(uint256,uint256): 1, 2 -> true // storageEmpty -> 0 diff --git a/test/libsolidity/semanticTests/array/copying/bytes_storage_to_storage.sol b/test/libsolidity/semanticTests/array/copying/bytes_storage_to_storage.sol index 87974f053abf..29a017e08943 100644 --- a/test/libsolidity/semanticTests/array/copying/bytes_storage_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/bytes_storage_to_storage.sol @@ -19,25 +19,25 @@ contract c { // ---- // f(uint256): 0 -> 0x20, 0x00 // f(uint256): 31 -> 0x20, 0x1f, 0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e00 -// gas irOptimized: 121741 -// gas legacy: 124364 -// gas legacyOptimized: 119898 +// gas irOptimized: 121735 +// gas legacy: 123884 +// gas legacyOptimized: 119139 // f(uint256): 32 -> 0x20, 0x20, 1780731860627700044960722568376592200742329637303199754547598369979440671 -// gas irOptimized: 130733 -// gas legacy: 135431 -// gas legacyOptimized: 130829 +// gas irOptimized: 130727 +// gas legacy: 134936 +// gas legacyOptimized: 130046 // f(uint256): 33 -> 0x20, 33, 1780731860627700044960722568376592200742329637303199754547598369979440671, 0x2000000000000000000000000000000000000000000000000000000000000000 -// gas irOptimized: 137732 -// gas legacy: 142238 -// gas legacyOptimized: 137518 +// gas irOptimized: 137726 +// gas legacy: 141728 +// gas legacyOptimized: 136711 // f(uint256): 63 -> 0x20, 0x3f, 1780731860627700044960722568376592200742329637303199754547598369979440671, 14532552714582660066924456880521368950258152170031413196862950297402215316992 -// gas irOptimized: 152352 -// gas legacy: 160728 -// gas legacyOptimized: 152168 +// gas irOptimized: 152346 +// gas legacy: 159768 +// gas legacyOptimized: 150641 // f(uint256): 12 -> 0x20, 0x0c, 0x0102030405060708090a0b0000000000000000000000000000000000000000 // gas legacy: 59345 // gas legacyOptimized: 57279 // f(uint256): 129 -> 0x20, 0x81, 1780731860627700044960722568376592200742329637303199754547598369979440671, 0x202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f, 29063324697304692433803953038474361308315562010425523193971352996434451193439, 0x606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f, -57896044618658097711785492504343953926634992332820282019728792003956564819968 -// gas irOptimized: 406089 -// gas legacy: 423017 -// gas legacyOptimized: 406021 +// gas irOptimized: 406083 +// gas legacy: 421067 +// gas legacyOptimized: 402910 diff --git a/test/libsolidity/semanticTests/array/copying/calldata_array_dynamic_to_storage.sol b/test/libsolidity/semanticTests/array/copying/calldata_array_dynamic_to_storage.sol index 7c0b3bdbbd78..d15044005317 100644 --- a/test/libsolidity/semanticTests/array/copying/calldata_array_dynamic_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/calldata_array_dynamic_to_storage.sol @@ -11,6 +11,6 @@ contract C { // compileViaYul: also // ---- // f(uint256[]): 0x20, 0x03, 0x1, 0x2, 0x3 -> 0x1 -// gas irOptimized: 111161 +// gas irOptimized: 111159 // gas legacy: 111565 // gas legacyOptimized: 111347 diff --git a/test/libsolidity/semanticTests/array/copying/copy_byte_array_in_struct_to_storage.sol b/test/libsolidity/semanticTests/array/copying/copy_byte_array_in_struct_to_storage.sol index 72a837d1b05d..05f8bd2bf9a3 100644 --- a/test/libsolidity/semanticTests/array/copying/copy_byte_array_in_struct_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/copy_byte_array_in_struct_to_storage.sol @@ -37,12 +37,12 @@ contract C { // compileViaYul: also // ---- // f() -> 0x40, 0x80, 6, 0x6162636465660000000000000000000000000000000000000000000000000000, 0x49, 0x3132333435363738393031323334353637383930313233343536373839303120, 0x3132333435363738393031323334353637383930313233343536373839303120, 0x3132333435363738390000000000000000000000000000000000000000000000 -// gas irOptimized: 179899 -// gas legacy: 180694 -// gas legacyOptimized: 180088 +// gas irOptimized: 179895 +// gas legacy: 180676 +// gas legacyOptimized: 180070 // g() -> 0x40, 0xc0, 0x49, 0x3132333435363738393031323334353637383930313233343536373839303120, 0x3132333435363738393031323334353637383930313233343536373839303120, 0x3132333435363738390000000000000000000000000000000000000000000000, 0x11, 0x3132333435363738393233343536373839000000000000000000000000000000 // gas irOptimized: 107274 -// gas legacy: 107895 -// gas legacyOptimized: 107254 +// gas legacy: 107877 +// gas legacyOptimized: 107236 // h() -> 0x40, 0x60, 0x00, 0x00 // storageEmpty -> 1 diff --git a/test/libsolidity/semanticTests/array/copying/copy_byte_array_to_storage.sol b/test/libsolidity/semanticTests/array/copying/copy_byte_array_to_storage.sol index b73f3dc448f3..41a5e99093b8 100644 --- a/test/libsolidity/semanticTests/array/copying/copy_byte_array_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/copy_byte_array_to_storage.sol @@ -48,6 +48,6 @@ contract C { // compileViaYul: also // ---- // f() -> 0xff -// gas irOptimized: 121145 -// gas legacy: 128035 -// gas legacyOptimized: 123476 +// gas irOptimized: 121123 +// gas legacy: 128005 +// gas legacyOptimized: 123446 diff --git a/test/libsolidity/semanticTests/array/copying/copy_function_internal_storage_array.sol b/test/libsolidity/semanticTests/array/copying/copy_function_internal_storage_array.sol index 7550a92256ec..4c223d30c29f 100644 --- a/test/libsolidity/semanticTests/array/copying/copy_function_internal_storage_array.sol +++ b/test/libsolidity/semanticTests/array/copying/copy_function_internal_storage_array.sol @@ -18,6 +18,6 @@ contract C { // compileViaYul: also // ---- // test() -> 7 -// gas irOptimized: 124041 +// gas irOptimized: 124034 // gas legacy: 205196 // gas legacyOptimized: 204987 diff --git a/test/libsolidity/semanticTests/array/copying/copy_removes_bytes_data.sol b/test/libsolidity/semanticTests/array/copying/copy_removes_bytes_data.sol index 8d8bd4d50680..cf8023a2f4c9 100644 --- a/test/libsolidity/semanticTests/array/copying/copy_removes_bytes_data.sol +++ b/test/libsolidity/semanticTests/array/copying/copy_removes_bytes_data.sol @@ -9,9 +9,9 @@ contract c { // compileViaYul: also // ---- // set(): 1, 2, 3, 4, 5 -> true -// gas irOptimized: 177390 -// gas legacy: 177656 -// gas legacyOptimized: 177496 +// gas irOptimized: 177386 +// gas legacy: 177653 +// gas legacyOptimized: 177493 // storageEmpty -> 0 // reset() -> true // storageEmpty -> 1 diff --git a/test/libsolidity/semanticTests/array/copying/copying_bytes_multiassign.sol b/test/libsolidity/semanticTests/array/copying/copying_bytes_multiassign.sol index 7b2af96071f4..09457bb74bac 100644 --- a/test/libsolidity/semanticTests/array/copying/copying_bytes_multiassign.sol +++ b/test/libsolidity/semanticTests/array/copying/copying_bytes_multiassign.sol @@ -22,8 +22,8 @@ contract sender { // ---- // (): 7 -> // gas irOptimized: 110954 -// gas legacy: 111082 -// gas legacyOptimized: 111027 +// gas legacy: 111071 +// gas legacyOptimized: 111016 // val() -> 0 // forward(bool): true -> true // val() -> 0x80 diff --git a/test/libsolidity/semanticTests/array/copying/memory_dyn_2d_bytes_to_storage.sol b/test/libsolidity/semanticTests/array/copying/memory_dyn_2d_bytes_to_storage.sol index 3d4623b79da1..8908caa55f38 100644 --- a/test/libsolidity/semanticTests/array/copying/memory_dyn_2d_bytes_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/memory_dyn_2d_bytes_to_storage.sol @@ -20,6 +20,6 @@ contract C { // compileViaYul: also // ---- // f() -> 3 -// gas irOptimized: 129916 -// gas legacy: 130307 -// gas legacyOptimized: 129363 +// gas irOptimized: 129910 +// gas legacy: 130181 +// gas legacyOptimized: 129198 diff --git a/test/libsolidity/semanticTests/array/copying/storage_memory_nested.sol b/test/libsolidity/semanticTests/array/copying/storage_memory_nested.sol index ec58360cd860..c9c72543c311 100644 --- a/test/libsolidity/semanticTests/array/copying/storage_memory_nested.sol +++ b/test/libsolidity/semanticTests/array/copying/storage_memory_nested.sol @@ -19,6 +19,6 @@ contract C { // compileViaYul: also // ---- // f() -> 1, 2, 3, 4, 5, 6, 7 -// gas irOptimized: 207785 -// gas legacy: 212325 -// gas legacyOptimized: 211486 +// gas irOptimized: 207781 +// gas legacy: 212313 +// gas legacyOptimized: 211462 diff --git a/test/libsolidity/semanticTests/array/copying/storage_memory_nested_bytes.sol b/test/libsolidity/semanticTests/array/copying/storage_memory_nested_bytes.sol index f94b442f36a9..35fd24fd8084 100644 --- a/test/libsolidity/semanticTests/array/copying/storage_memory_nested_bytes.sol +++ b/test/libsolidity/semanticTests/array/copying/storage_memory_nested_bytes.sol @@ -14,5 +14,5 @@ contract C { // ---- // f() -> 0x20, 0x02, 0x40, 0x80, 3, 0x6162630000000000000000000000000000000000000000000000000000000000, 0x99, 44048183304486788312148433451363384677562265908331949128489393215789685032262, 32241931068525137014058842823026578386641954854143559838526554899205067598957, 49951309422467613961193228765530489307475214998374779756599339590522149884499, 0x54555658595a6162636465666768696a6b6c6d6e6f707172737475767778797a, 0x4142434445464748494a4b4c4d4e4f5051525354555658595a00000000000000 // gas irOptimized: 202840 -// gas legacy: 204459 -// gas legacyOptimized: 203437 +// gas legacy: 204441 +// gas legacyOptimized: 203419 diff --git a/test/libsolidity/semanticTests/array/copying/storage_memory_nested_from_pointer.sol b/test/libsolidity/semanticTests/array/copying/storage_memory_nested_from_pointer.sol index ece6f7969f56..8f98822e7006 100644 --- a/test/libsolidity/semanticTests/array/copying/storage_memory_nested_from_pointer.sol +++ b/test/libsolidity/semanticTests/array/copying/storage_memory_nested_from_pointer.sol @@ -20,6 +20,6 @@ contract C { // compileViaYul: also // ---- // f() -> 1, 2, 3, 4, 5, 6, 7 -// gas irOptimized: 207785 -// gas legacy: 212330 -// gas legacyOptimized: 211491 +// gas irOptimized: 207781 +// gas legacy: 212318 +// gas legacyOptimized: 211467 diff --git a/test/libsolidity/semanticTests/array/copying/storage_memory_nested_struct.sol b/test/libsolidity/semanticTests/array/copying/storage_memory_nested_struct.sol index 556fb5a61b41..d9a50e73d2ab 100644 --- a/test/libsolidity/semanticTests/array/copying/storage_memory_nested_struct.sol +++ b/test/libsolidity/semanticTests/array/copying/storage_memory_nested_struct.sol @@ -26,6 +26,6 @@ contract C { // compileViaYul: also // ---- // f() -> 11, 0x0c, 1, 0x15, 22, 4 -// gas irOptimized: 291850 +// gas irOptimized: 291848 // gas legacy: 293516 // gas legacyOptimized: 290263 diff --git a/test/libsolidity/semanticTests/array/copying/storage_memory_packed_dyn.sol b/test/libsolidity/semanticTests/array/copying/storage_memory_packed_dyn.sol index abcd72ee102c..f954701d5a76 100644 --- a/test/libsolidity/semanticTests/array/copying/storage_memory_packed_dyn.sol +++ b/test/libsolidity/semanticTests/array/copying/storage_memory_packed_dyn.sol @@ -15,6 +15,6 @@ contract C { // compileViaYul: also // ---- // f() -> 2, 3, 4 -// gas irOptimized: 114120 -// gas legacy: 126449 -// gas legacyOptimized: 120902 +// gas irOptimized: 114114 +// gas legacy: 126350 +// gas legacyOptimized: 120704 diff --git a/test/libsolidity/semanticTests/array/create_memory_array.sol b/test/libsolidity/semanticTests/array/create_memory_array.sol index 8072526abc10..e107bd68a4c1 100644 --- a/test/libsolidity/semanticTests/array/create_memory_array.sol +++ b/test/libsolidity/semanticTests/array/create_memory_array.sol @@ -20,6 +20,6 @@ contract C { // compileViaYul: also // ---- // f() -> "A", 8, 4, "B" -// gas irOptimized: 130594 +// gas irOptimized: 130592 // gas legacy: 121398 // gas legacyOptimized: 115494 diff --git a/test/libsolidity/semanticTests/array/delete/bytes_delete_element.sol b/test/libsolidity/semanticTests/array/delete/bytes_delete_element.sol index 149e8768d70b..f6208ea6f979 100644 --- a/test/libsolidity/semanticTests/array/delete/bytes_delete_element.sol +++ b/test/libsolidity/semanticTests/array/delete/bytes_delete_element.sol @@ -18,6 +18,6 @@ contract c { // compileViaYul: also // ---- // test1() -> true -// gas irOptimized: 225894 -// gas legacy: 255577 -// gas legacyOptimized: 248611 +// gas irOptimized: 225890 +// gas legacy: 254650 +// gas legacyOptimized: 247384 diff --git a/test/libsolidity/semanticTests/array/delete/delete_storage_array_packed.sol b/test/libsolidity/semanticTests/array/delete/delete_storage_array_packed.sol index 82c8d6b6cceb..8d0f6358e3f4 100644 --- a/test/libsolidity/semanticTests/array/delete/delete_storage_array_packed.sol +++ b/test/libsolidity/semanticTests/array/delete/delete_storage_array_packed.sol @@ -16,4 +16,4 @@ contract C { // compileViaYul: also // ---- // f() -> 0, 0, 0 -// gas irOptimized: 91098 +// gas irOptimized: 90992 diff --git a/test/libsolidity/semanticTests/array/dynamic_array_cleanup.sol b/test/libsolidity/semanticTests/array/dynamic_array_cleanup.sol index 019a3fca0dbf..01ba8dcfe306 100644 --- a/test/libsolidity/semanticTests/array/dynamic_array_cleanup.sol +++ b/test/libsolidity/semanticTests/array/dynamic_array_cleanup.sol @@ -16,9 +16,9 @@ contract c { // ---- // storageEmpty -> 1 // fill() -> -// gas irOptimized: 519886 -// gas legacy: 521773 -// gas legacyOptimized: 517048 +// gas irOptimized: 519884 +// gas legacy: 521710 +// gas legacyOptimized: 516922 // storageEmpty -> 0 // halfClear() -> // storageEmpty -> 0 diff --git a/test/libsolidity/semanticTests/array/dynamic_arrays_in_storage.sol b/test/libsolidity/semanticTests/array/dynamic_arrays_in_storage.sol index 4ed8c050b431..be8f6eff3169 100644 --- a/test/libsolidity/semanticTests/array/dynamic_arrays_in_storage.sol +++ b/test/libsolidity/semanticTests/array/dynamic_arrays_in_storage.sol @@ -44,7 +44,7 @@ contract c { // ---- // getLengths() -> 0, 0 // setLengths(uint256,uint256): 48, 49 -> -// gas irOptimized: 111304 +// gas irOptimized: 111295 // gas legacy: 108571 // gas legacyOptimized: 100417 // getLengths() -> 48, 49 diff --git a/test/libsolidity/semanticTests/array/dynamic_multi_array_cleanup.sol b/test/libsolidity/semanticTests/array/dynamic_multi_array_cleanup.sol index cf310f86ddaa..5bbd9e207019 100644 --- a/test/libsolidity/semanticTests/array/dynamic_multi_array_cleanup.sol +++ b/test/libsolidity/semanticTests/array/dynamic_multi_array_cleanup.sol @@ -18,7 +18,7 @@ contract c { // ---- // storageEmpty -> 1 // fill() -> 8 -// gas irOptimized: 122534 +// gas irOptimized: 122531 // gas legacy: 121756 // gas legacyOptimized: 120687 // storageEmpty -> 0 diff --git a/test/libsolidity/semanticTests/array/fixed_array_cleanup.sol b/test/libsolidity/semanticTests/array/fixed_array_cleanup.sol index b09cb581207e..fba3119e1a33 100644 --- a/test/libsolidity/semanticTests/array/fixed_array_cleanup.sol +++ b/test/libsolidity/semanticTests/array/fixed_array_cleanup.sol @@ -13,9 +13,9 @@ contract c { // ---- // storageEmpty -> 1 // fill() -> -// gas irOptimized: 465544 -// gas legacy: 471460 -// gas legacyOptimized: 467520 +// gas irOptimized: 465542 +// gas legacy: 471400 +// gas legacyOptimized: 467400 // storageEmpty -> 0 // clear() -> // storageEmpty -> 1 diff --git a/test/libsolidity/semanticTests/array/fixed_arrays_as_return_type.sol b/test/libsolidity/semanticTests/array/fixed_arrays_as_return_type.sol index fcf41823e7e6..3ce5f1a8da63 100644 --- a/test/libsolidity/semanticTests/array/fixed_arrays_as_return_type.sol +++ b/test/libsolidity/semanticTests/array/fixed_arrays_as_return_type.sol @@ -21,6 +21,6 @@ contract B { // compileViaYul: also // ---- // f() -> 2, 3, 4, 5, 6, 1000, 1001, 1002, 1003, 1004 -// gas irOptimized: 130152 -// gas legacy: 234943 -// gas legacyOptimized: 132863 +// gas irOptimized: 127910 +// gas legacy: 234719 +// gas legacyOptimized: 132639 diff --git a/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol b/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol index 07a054514a39..3f66dca6fe79 100644 --- a/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol +++ b/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol @@ -11,7 +11,7 @@ contract Creator { // compileViaYul: also // ---- // constructor(): 1, 2, 3, 4 -> -// gas irOptimized: 129908 +// gas irOptimized: 129013 // gas legacy: 176789 // gas legacyOptimized: 129585 // r() -> 4 diff --git a/test/libsolidity/semanticTests/array/function_array_cross_calls.sol b/test/libsolidity/semanticTests/array/function_array_cross_calls.sol index 73f9799d4349..087ecf0a8356 100644 --- a/test/libsolidity/semanticTests/array/function_array_cross_calls.sol +++ b/test/libsolidity/semanticTests/array/function_array_cross_calls.sol @@ -45,6 +45,6 @@ contract C { // compileViaYul: also // ---- // test() -> 5, 6, 7 -// gas irOptimized: 298983 -// gas legacy: 452172 -// gas legacyOptimized: 285017 +// gas irOptimized: 292502 +// gas legacy: 452136 +// gas legacyOptimized: 284945 diff --git a/test/libsolidity/semanticTests/array/pop/array_pop_array_transition.sol b/test/libsolidity/semanticTests/array/pop/array_pop_array_transition.sol index f2a98f99381f..3b066cfaab04 100644 --- a/test/libsolidity/semanticTests/array/pop/array_pop_array_transition.sol +++ b/test/libsolidity/semanticTests/array/pop/array_pop_array_transition.sol @@ -25,7 +25,7 @@ contract c { // compileViaYul: also // ---- // test() -> 1, 2, 3 -// gas irOptimized: 2271482 -// gas legacy: 2273722 -// gas legacyOptimized: 2262396 +// gas irOptimized: 2271044 +// gas legacy: 2273434 +// gas legacyOptimized: 2261820 // storageEmpty -> 1 diff --git a/test/libsolidity/semanticTests/array/pop/array_pop_uint16_transition.sol b/test/libsolidity/semanticTests/array/pop/array_pop_uint16_transition.sol index 4be29a15d30d..6ec59a75e56c 100644 --- a/test/libsolidity/semanticTests/array/pop/array_pop_uint16_transition.sol +++ b/test/libsolidity/semanticTests/array/pop/array_pop_uint16_transition.sol @@ -21,6 +21,6 @@ contract c { // ---- // test() -> 38, 28, 18 // gas irOptimized: 188649 -// gas legacy: 189780 -// gas legacyOptimized: 178870 +// gas legacy: 189492 +// gas legacyOptimized: 178294 // storageEmpty -> 1 diff --git a/test/libsolidity/semanticTests/array/pop/array_pop_uint24_transition.sol b/test/libsolidity/semanticTests/array/pop/array_pop_uint24_transition.sol index 08a403174557..06f3c6cc939c 100644 --- a/test/libsolidity/semanticTests/array/pop/array_pop_uint24_transition.sol +++ b/test/libsolidity/semanticTests/array/pop/array_pop_uint24_transition.sol @@ -20,7 +20,7 @@ contract c { // compileViaYul: also // ---- // test() -> 20, 10 -// gas irOptimized: 159175 -// gas legacy: 159459 -// gas legacyOptimized: 153281 +// gas irOptimized: 159169 +// gas legacy: 159279 +// gas legacyOptimized: 152921 // storageEmpty -> 1 diff --git a/test/libsolidity/semanticTests/array/pop/byte_array_pop_copy_long.sol b/test/libsolidity/semanticTests/array/pop/byte_array_pop_copy_long.sol index 387d21872c76..227eb6afd76c 100644 --- a/test/libsolidity/semanticTests/array/pop/byte_array_pop_copy_long.sol +++ b/test/libsolidity/semanticTests/array/pop/byte_array_pop_copy_long.sol @@ -12,6 +12,6 @@ contract c { // compileViaYul: also // ---- // test() -> 0x20, 29, 0x0303030303030303030303030303030303030303030303030303030303000000 -// gas irOptimized: 109503 -// gas legacy: 127309 -// gas legacyOptimized: 124136 +// gas irOptimized: 109499 +// gas legacy: 126728 +// gas legacyOptimized: 123444 diff --git a/test/libsolidity/semanticTests/array/pop/byte_array_pop_long_storage_empty.sol b/test/libsolidity/semanticTests/array/pop/byte_array_pop_long_storage_empty.sol index c911b1b7c36c..146a4dfc34e6 100644 --- a/test/libsolidity/semanticTests/array/pop/byte_array_pop_long_storage_empty.sol +++ b/test/libsolidity/semanticTests/array/pop/byte_array_pop_long_storage_empty.sol @@ -18,7 +18,7 @@ contract c { // compileViaYul: also // ---- // test() -> true -// gas irOptimized: 196545 -// gas legacy: 229864 -// gas legacyOptimized: 210964 +// gas irOptimized: 196541 +// gas legacy: 228685 +// gas legacyOptimized: 209662 // storageEmpty -> 1 diff --git a/test/libsolidity/semanticTests/array/pop/byte_array_pop_long_storage_empty_garbage_ref.sol b/test/libsolidity/semanticTests/array/pop/byte_array_pop_long_storage_empty_garbage_ref.sol index 38c0c84d6356..d5d004f5fdd0 100644 --- a/test/libsolidity/semanticTests/array/pop/byte_array_pop_long_storage_empty_garbage_ref.sol +++ b/test/libsolidity/semanticTests/array/pop/byte_array_pop_long_storage_empty_garbage_ref.sol @@ -17,7 +17,7 @@ contract c { // compileViaYul: also // ---- // test() -> -// gas irOptimized: 142640 -// gas legacy: 165363 -// gas legacyOptimized: 159446 +// gas irOptimized: 142639 +// gas legacy: 164430 +// gas legacyOptimized: 157898 // storageEmpty -> 1 diff --git a/test/libsolidity/semanticTests/array/pop/byte_array_pop_masking_long.sol b/test/libsolidity/semanticTests/array/pop/byte_array_pop_masking_long.sol index 6d314fb27eb2..fb05db350736 100644 --- a/test/libsolidity/semanticTests/array/pop/byte_array_pop_masking_long.sol +++ b/test/libsolidity/semanticTests/array/pop/byte_array_pop_masking_long.sol @@ -12,6 +12,6 @@ contract c { // compileViaYul: also // ---- // test() -> 0x20, 33, 0x303030303030303030303030303030303030303030303030303030303030303, 0x0300000000000000000000000000000000000000000000000000000000000000 -// gas irOptimized: 108493 -// gas legacy: 126187 -// gas legacyOptimized: 123261 +// gas irOptimized: 108487 +// gas legacy: 125610 +// gas legacyOptimized: 122582 diff --git a/test/libsolidity/semanticTests/array/push/array_push_nested_from_calldata.sol b/test/libsolidity/semanticTests/array/push/array_push_nested_from_calldata.sol index a4be5ad9010d..05299ae55671 100644 --- a/test/libsolidity/semanticTests/array/push/array_push_nested_from_calldata.sol +++ b/test/libsolidity/semanticTests/array/push/array_push_nested_from_calldata.sol @@ -14,6 +14,6 @@ contract C { // compileViaYul: also // ---- // f(uint120[]): 0x20, 3, 1, 2, 3 -> 1 -// gas irOptimized: 113267 +// gas irOptimized: 113256 // gas legacy: 113686 // gas legacyOptimized: 113499 diff --git a/test/libsolidity/semanticTests/array/push/array_push_struct_from_calldata.sol b/test/libsolidity/semanticTests/array/push/array_push_struct_from_calldata.sol index 7546a664bde4..a7b8d6d9d1ac 100644 --- a/test/libsolidity/semanticTests/array/push/array_push_struct_from_calldata.sol +++ b/test/libsolidity/semanticTests/array/push/array_push_struct_from_calldata.sol @@ -18,6 +18,6 @@ contract c { // compileViaYul: also // ---- // test((uint16,uint16,uint16[3],uint16[])): 0x20, 2, 3, 0, 0, 4, 0xC0, 4, 0, 0, 5, 0, 0 -> 2, 3, 4, 5 -// gas irOptimized: 138732 +// gas irOptimized: 138691 // gas legacy: 145150 // gas legacyOptimized: 139171 diff --git a/test/libsolidity/semanticTests/array/push/byte_array_push_transition.sol b/test/libsolidity/semanticTests/array/push/byte_array_push_transition.sol index 78c817d4460c..c4f7cb44a52b 100644 --- a/test/libsolidity/semanticTests/array/push/byte_array_push_transition.sol +++ b/test/libsolidity/semanticTests/array/push/byte_array_push_transition.sol @@ -17,6 +17,6 @@ contract c { // compileViaYul: also // ---- // test() -> 0 -// gas irOptimized: 176848 -// gas legacy: 218028 -// gas legacyOptimized: 205124 +// gas irOptimized: 176495 +// gas legacy: 216790 +// gas legacyOptimized: 203886 diff --git a/test/libsolidity/semanticTests/array/push/nested_bytes_push.sol b/test/libsolidity/semanticTests/array/push/nested_bytes_push.sol index 262ba724a555..7c4bdcb9a29a 100644 --- a/test/libsolidity/semanticTests/array/push/nested_bytes_push.sol +++ b/test/libsolidity/semanticTests/array/push/nested_bytes_push.sol @@ -16,5 +16,5 @@ contract C { // ---- // f() -> // gas irOptimized: 179590 -// gas legacy: 180620 -// gas legacyOptimized: 180403 +// gas legacy: 180602 +// gas legacyOptimized: 180385 diff --git a/test/libsolidity/semanticTests/array/push/push_no_args_2d.sol b/test/libsolidity/semanticTests/array/push/push_no_args_2d.sol index 761bf3ee3bca..5b470e829b3b 100644 --- a/test/libsolidity/semanticTests/array/push/push_no_args_2d.sol +++ b/test/libsolidity/semanticTests/array/push/push_no_args_2d.sol @@ -29,15 +29,15 @@ contract C { // ---- // l() -> 0 // f(uint256,uint256): 42, 64 -> -// gas irOptimized: 112528 -// gas legacy: 108234 -// gas legacyOptimized: 102245 +// gas irOptimized: 112517 +// gas legacy: 108105 +// gas legacyOptimized: 101987 // l() -> 1 // ll(uint256): 0 -> 43 // a(uint256,uint256): 0, 42 -> 64 // f(uint256,uint256): 84, 128 -> -// gas irOptimized: 116400 -// gas legacy: 107780 +// gas irOptimized: 116389 +// gas legacy: 107525 // gas legacyOptimized: 96331 // l() -> 2 // ll(uint256): 1 -> 85 diff --git a/test/libsolidity/semanticTests/array/push/push_no_args_bytes.sol b/test/libsolidity/semanticTests/array/push/push_no_args_bytes.sol index 830f25b02f07..713c44ec143a 100644 --- a/test/libsolidity/semanticTests/array/push/push_no_args_bytes.sol +++ b/test/libsolidity/semanticTests/array/push/push_no_args_bytes.sol @@ -23,9 +23,9 @@ contract C { // ---- // l() -> 0 // g(uint256): 70 -> -// gas irOptimized: 185936 -// gas legacy: 184991 -// gas legacyOptimized: 180608 +// gas irOptimized: 185922 +// gas legacy: 183811 +// gas legacyOptimized: 179218 // l() -> 70 // a(uint256): 69 -> left(69) // f() -> diff --git a/test/libsolidity/semanticTests/array/reusing_memory.sol b/test/libsolidity/semanticTests/array/reusing_memory.sol index ee91ce7f7b39..455d6f9484bf 100644 --- a/test/libsolidity/semanticTests/array/reusing_memory.sol +++ b/test/libsolidity/semanticTests/array/reusing_memory.sol @@ -26,6 +26,6 @@ contract Main { // compileViaYul: also // ---- // f(uint256): 0x34 -> 0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 -// gas irOptimized: 113598 +// gas irOptimized: 113198 // gas legacy: 126596 // gas legacyOptimized: 113823 diff --git a/test/libsolidity/semanticTests/calldata/copy_from_calldata_removes_bytes_data.sol b/test/libsolidity/semanticTests/calldata/copy_from_calldata_removes_bytes_data.sol index 7773c6832c80..b8dbff46a897 100644 --- a/test/libsolidity/semanticTests/calldata/copy_from_calldata_removes_bytes_data.sol +++ b/test/libsolidity/semanticTests/calldata/copy_from_calldata_removes_bytes_data.sol @@ -11,9 +11,9 @@ contract c { // compileViaYul: also // ---- // (): 1, 2, 3, 4, 5 -> -// gas irOptimized: 155181 -// gas legacy: 155254 -// gas legacyOptimized: 155217 +// gas irOptimized: 155170 +// gas legacy: 155249 +// gas legacyOptimized: 155212 // checkIfDataIsEmpty() -> false // sendMessage() -> true, 0x40, 0 // checkIfDataIsEmpty() -> true diff --git a/test/libsolidity/semanticTests/constructor/arrays_in_constructors.sol b/test/libsolidity/semanticTests/constructor/arrays_in_constructors.sol index cc303899a16c..82050efa216c 100644 --- a/test/libsolidity/semanticTests/constructor/arrays_in_constructors.sol +++ b/test/libsolidity/semanticTests/constructor/arrays_in_constructors.sol @@ -26,6 +26,6 @@ contract Creator { // compileViaYul: also // ---- // f(uint256,address[]): 7, 0x40, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 -> 7, 8 -// gas irOptimized: 443960 +// gas irOptimized: 437093 // gas legacy: 590683 // gas legacyOptimized: 448326 diff --git a/test/libsolidity/semanticTests/constructor/bytes_in_constructors_packer.sol b/test/libsolidity/semanticTests/constructor/bytes_in_constructors_packer.sol index ffe0fb8c2579..bdd5c6eb506c 100644 --- a/test/libsolidity/semanticTests/constructor/bytes_in_constructors_packer.sol +++ b/test/libsolidity/semanticTests/constructor/bytes_in_constructors_packer.sol @@ -26,6 +26,6 @@ contract Creator { // compileViaYul: also // ---- // f(uint256,bytes): 7, 0x40, 78, "abcdefghijklmnopqrstuvwxyzabcdef", "ghijklmnopqrstuvwxyzabcdefghijkl", "mnopqrstuvwxyz" -> 7, "h" -// gas irOptimized: 300804 -// gas legacy: 428917 -// gas legacyOptimized: 298128 +// gas irOptimized: 293203 +// gas legacy: 428711 +// gas legacyOptimized: 297922 diff --git a/test/libsolidity/semanticTests/constructor/bytes_in_constructors_unpacker.sol b/test/libsolidity/semanticTests/constructor/bytes_in_constructors_unpacker.sol index 1a93f53b3f8e..d0b3f64cbcd3 100644 --- a/test/libsolidity/semanticTests/constructor/bytes_in_constructors_unpacker.sol +++ b/test/libsolidity/semanticTests/constructor/bytes_in_constructors_unpacker.sol @@ -10,8 +10,8 @@ contract Test { // compileViaYul: also // ---- // constructor(): 7, 0x40, 78, "abcdefghijklmnopqrstuvwxyzabcdef", "ghijklmnopqrstuvwxyzabcdefghijkl", "mnopqrstuvwxyz" -> -// gas irOptimized: 291443 -// gas legacy: 309842 -// gas legacyOptimized: 260801 +// gas irOptimized: 283829 +// gas legacy: 309607 +// gas legacyOptimized: 260566 // m_x() -> 7 // m_s() -> 0x20, 78, "abcdefghijklmnopqrstuvwxyzabcdef", "ghijklmnopqrstuvwxyzabcdefghijkl", "mnopqrstuvwxyz" diff --git a/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol b/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol index 2206fd351b3d..701f4accb1ed 100644 --- a/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol +++ b/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol @@ -19,7 +19,7 @@ contract Main { // compileViaYul: also // ---- // constructor(): "abc", true -// gas irOptimized: 107175 +// gas irOptimized: 106683 // gas legacy: 145838 // gas legacyOptimized: 104017 // getFlag() -> true diff --git a/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol b/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol index f6fab1092db7..0c38107cc805 100644 --- a/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol +++ b/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol @@ -12,7 +12,7 @@ contract C { // compileViaYul: also // ---- // constructor(): 1, 2, 3, 4 -> -// gas irOptimized: 174905 +// gas irOptimized: 174020 // gas legacy: 221377 // gas legacyOptimized: 177671 // a() -> 1 diff --git a/test/libsolidity/semanticTests/constructor/no_callvalue_check.sol b/test/libsolidity/semanticTests/constructor/no_callvalue_check.sol index 3fdbb078540e..9908b2386c6c 100644 --- a/test/libsolidity/semanticTests/constructor/no_callvalue_check.sol +++ b/test/libsolidity/semanticTests/constructor/no_callvalue_check.sol @@ -19,6 +19,6 @@ contract C { // compileViaYul: also // ---- // f(), 2000 ether -> true -// gas irOptimized: 123037 +// gas irOptimized: 120037 // gas legacy: 123226 // gas legacyOptimized: 123092 diff --git a/test/libsolidity/semanticTests/constructor_inheritance_init_order.sol b/test/libsolidity/semanticTests/constructor_inheritance_init_order.sol index 2518deb92543..4f9984503b2e 100644 --- a/test/libsolidity/semanticTests/constructor_inheritance_init_order.sol +++ b/test/libsolidity/semanticTests/constructor_inheritance_init_order.sol @@ -15,5 +15,5 @@ contract B is A { // compileViaYul: true // ---- // constructor() -> -// gas irOptimized: 122017 +// gas irOptimized: 121557 // y() -> 42 diff --git a/test/libsolidity/semanticTests/constructor_inheritance_init_order_2.sol b/test/libsolidity/semanticTests/constructor_inheritance_init_order_2.sol index 68506528b677..a583bd39fbdd 100644 --- a/test/libsolidity/semanticTests/constructor_inheritance_init_order_2.sol +++ b/test/libsolidity/semanticTests/constructor_inheritance_init_order_2.sol @@ -12,7 +12,7 @@ contract B is A { // compileViaYul: also // ---- // constructor() -> -// gas irOptimized: 122017 +// gas irOptimized: 121557 // gas legacy: 135046 // gas legacyOptimized: 116176 // y() -> 42 diff --git a/test/libsolidity/semanticTests/constructor_with_params.sol b/test/libsolidity/semanticTests/constructor_with_params.sol index cb619277457c..ca4cf5a0545f 100644 --- a/test/libsolidity/semanticTests/constructor_with_params.sol +++ b/test/libsolidity/semanticTests/constructor_with_params.sol @@ -11,7 +11,7 @@ contract C { // compileViaYul: also // ---- // constructor(): 2, 0 -> -// gas irOptimized: 104227 +// gas irOptimized: 103630 // gas legacy: 117158 // i() -> 2 // k() -> 0 diff --git a/test/libsolidity/semanticTests/constructor_with_params_diamond_inheritance.sol b/test/libsolidity/semanticTests/constructor_with_params_diamond_inheritance.sol index 8f891116e420..3e9ae1ab2a61 100644 --- a/test/libsolidity/semanticTests/constructor_with_params_diamond_inheritance.sol +++ b/test/libsolidity/semanticTests/constructor_with_params_diamond_inheritance.sol @@ -23,7 +23,7 @@ contract D is B, C { // compileViaYul: also // ---- // constructor(): 2, 0 -> -// gas irOptimized: 160166 +// gas irOptimized: 156071 // gas legacy: 170665 // gas legacyOptimized: 145396 // i() -> 2 diff --git a/test/libsolidity/semanticTests/constructor_with_params_inheritance.sol b/test/libsolidity/semanticTests/constructor_with_params_inheritance.sol index 3d90783f8216..ede647d608b8 100644 --- a/test/libsolidity/semanticTests/constructor_with_params_inheritance.sol +++ b/test/libsolidity/semanticTests/constructor_with_params_inheritance.sol @@ -14,7 +14,7 @@ contract D is C { // compileViaYul: also // ---- // constructor(): 2, 0 -> -// gas irOptimized: 124844 +// gas irOptimized: 124199 // gas legacy: 139250 // gas legacyOptimized: 119367 // i() -> 2 diff --git a/test/libsolidity/semanticTests/events/event_dynamic_array_storage.sol b/test/libsolidity/semanticTests/events/event_dynamic_array_storage.sol index b5db5ca2b1ee..dedffe232f85 100644 --- a/test/libsolidity/semanticTests/events/event_dynamic_array_storage.sol +++ b/test/libsolidity/semanticTests/events/event_dynamic_array_storage.sol @@ -15,6 +15,6 @@ contract C { // ---- // createEvent(uint256): 42 -> // ~ emit E(uint256[]): 0x20, 0x03, 0x2a, 0x2b, 0x2c -// gas irOptimized: 114746 +// gas irOptimized: 114741 // gas legacy: 116393 // gas legacyOptimized: 114415 diff --git a/test/libsolidity/semanticTests/events/event_dynamic_array_storage_v2.sol b/test/libsolidity/semanticTests/events/event_dynamic_array_storage_v2.sol index f833ba37a7b7..947e5ad9e597 100644 --- a/test/libsolidity/semanticTests/events/event_dynamic_array_storage_v2.sol +++ b/test/libsolidity/semanticTests/events/event_dynamic_array_storage_v2.sol @@ -16,6 +16,6 @@ contract C { // ---- // createEvent(uint256): 42 -> // ~ emit E(uint256[]): 0x20, 0x03, 0x2a, 0x2b, 0x2c -// gas irOptimized: 114746 +// gas irOptimized: 114741 // gas legacy: 116393 // gas legacyOptimized: 114415 diff --git a/test/libsolidity/semanticTests/events/event_emit_from_other_contract.sol b/test/libsolidity/semanticTests/events/event_emit_from_other_contract.sol index 5ec47a4a9c19..0f685b783af8 100644 --- a/test/libsolidity/semanticTests/events/event_emit_from_other_contract.sol +++ b/test/libsolidity/semanticTests/events/event_emit_from_other_contract.sol @@ -17,7 +17,7 @@ contract C { // compileViaYul: also // ---- // constructor() -> -// gas irOptimized: 173672 +// gas irOptimized: 173094 // gas legacy: 250376 // gas legacyOptimized: 174522 // deposit(bytes32), 18 wei: 0x1234 -> diff --git a/test/libsolidity/semanticTests/events/event_indexed_string.sol b/test/libsolidity/semanticTests/events/event_indexed_string.sol index d35db93c4619..5d3ad5840484 100644 --- a/test/libsolidity/semanticTests/events/event_indexed_string.sol +++ b/test/libsolidity/semanticTests/events/event_indexed_string.sol @@ -20,5 +20,5 @@ contract C { // deposit() -> // ~ emit E(string,uint256[4]): #0xa7fb06bb999a5eb9aff9e0779953f4e1e4ce58044936c2f51c7fb879b85c08bd, #0xe755d8cc1a8cde16a2a31160dcd8017ac32d7e2f13215b29a23cdae40a78aa81 // gas irOptimized: 343396 -// gas legacy: 390742 -// gas legacyOptimized: 376774 +// gas legacy: 388679 +// gas legacyOptimized: 374441 diff --git a/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol b/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol index e6d6c478bce0..58087a3b5534 100644 --- a/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol +++ b/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol @@ -76,9 +76,9 @@ contract FixedFeeRegistrar is Registrar { // compileViaYul: also // ---- // constructor() -// gas irOptimized: 413485 -// gas legacy: 936897 -// gas legacyOptimized: 490983 +// gas irOptimized: 402812 +// gas legacy: 935817 +// gas legacyOptimized: 489951 // reserve(string), 69 ether: 0x20, 3, "abc" -> // ~ emit Changed(string): #0x4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45 // gas irOptimized: 45967 diff --git a/test/libsolidity/semanticTests/externalContracts/base64.sol b/test/libsolidity/semanticTests/externalContracts/base64.sol index fd17c5d78b38..7101af5941d6 100644 --- a/test/libsolidity/semanticTests/externalContracts/base64.sol +++ b/test/libsolidity/semanticTests/externalContracts/base64.sol @@ -34,9 +34,9 @@ contract test { // compileViaYul: also // ---- // constructor() -// gas irOptimized: 450044 -// gas legacy: 766936 -// gas legacyOptimized: 543094 +// gas irOptimized: 443542 +// gas legacy: 765640 +// gas legacyOptimized: 541810 // encode_inline_asm(bytes): 0x20, 0 -> 0x20, 0 // encode_inline_asm(bytes): 0x20, 1, "f" -> 0x20, 4, "Zg==" // encode_inline_asm(bytes): 0x20, 2, "fo" -> 0x20, 4, "Zm8=" @@ -52,10 +52,10 @@ contract test { // encode_no_asm(bytes): 0x20, 5, "fooba" -> 0x20, 8, "Zm9vYmE=" // encode_no_asm(bytes): 0x20, 6, "foobar" -> 0x20, 8, "Zm9vYmFy" // encode_inline_asm_large() -// gas irOptimized: 1385047 -// gas legacy: 1658033 -// gas legacyOptimized: 1210033 +// gas irOptimized: 1385042 +// gas legacy: 1652033 +// gas legacyOptimized: 1201033 // encode_no_asm_large() -// gas irOptimized: 3335101 -// gas legacy: 4801077 -// gas legacyOptimized: 2929077 +// gas irOptimized: 3335099 +// gas legacy: 4777077 +// gas legacyOptimized: 2890077 diff --git a/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol b/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol index d98e73792042..9e3211ecb47f 100644 --- a/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol +++ b/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol @@ -178,35 +178,35 @@ contract DepositContract is IDepositContract, ERC165 { // compileViaYul: also // ---- // constructor() -// gas irOptimized: 1543359 -// gas legacy: 2436584 -// gas legacyOptimized: 1776483 +// gas irOptimized: 1529797 +// gas legacy: 2435803 +// gas legacyOptimized: 1775425 // supportsInterface(bytes4): 0x0 -> 0 // supportsInterface(bytes4): 0xffffffff00000000000000000000000000000000000000000000000000000000 -> false # defined to be false by ERC-165 # // supportsInterface(bytes4): 0x01ffc9a700000000000000000000000000000000000000000000000000000000 -> true # ERC-165 id # // supportsInterface(bytes4): 0x8564090700000000000000000000000000000000000000000000000000000000 -> true # the deposit interface id # // get_deposit_root() -> 0xd70a234731285c6804c2a4f56711ddb8c82c99740f207854891028af34e27e5e -// gas irOptimized: 122135 -// gas legacy: 150465 -// gas legacyOptimized: 122798 +// gas irOptimized: 122134 +// gas legacy: 150273 +// gas legacyOptimized: 122510 // get_deposit_count() -> 0x20, 8, 0 # TODO: check balance and logs after each deposit # // deposit(bytes,bytes,bytes,bytes32), 32 ether: 0 -> FAILURE # Empty input # // get_deposit_root() -> 0xd70a234731285c6804c2a4f56711ddb8c82c99740f207854891028af34e27e5e -// gas irOptimized: 122135 -// gas legacy: 150465 -// gas legacyOptimized: 122798 +// gas irOptimized: 122134 +// gas legacy: 150273 +// gas legacyOptimized: 122510 // get_deposit_count() -> 0x20, 8, 0 // deposit(bytes,bytes,bytes,bytes32), 1 ether: 0x80, 0xe0, 0x120, 0xaa4a8d0b7d9077248630f1a4701ae9764e42271d7f22b7838778411857fd349e, 0x30, 0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f73292, 0x67a8811c397529dac52ae1342ba58c9500000000000000000000000000000000, 0x20, 0x00f50428677c60f997aadeab24aabf7fceaef491c96a52b463ae91f95611cf71, 0x60, 0xa29d01cc8c6296a8150e515b5995390ef841dc18948aa3e79be6d7c1851b4cbb, 0x5d6ff49fa70b9c782399506a22a85193151b9b691245cebafd2063012443c132, 0x4b6c36debaedefb7b2d71b0503ffdc00150aaffd42e63358238ec888901738b8 -> # txhash: 0x7085c586686d666e8bb6e9477a0f0b09565b2060a11f1c4209d3a52295033832 # // ~ emit DepositEvent(bytes,bytes,bytes,bytes,bytes): 0xa0, 0x0100, 0x0140, 0x0180, 0x0200, 0x30, 0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f73292, 0x67a8811c397529dac52ae1342ba58c9500000000000000000000000000000000, 0x20, 0xf50428677c60f997aadeab24aabf7fceaef491c96a52b463ae91f95611cf71, 0x08, 0xca9a3b00000000000000000000000000000000000000000000000000000000, 0x60, 0xa29d01cc8c6296a8150e515b5995390ef841dc18948aa3e79be6d7c1851b4cbb, 0x5d6ff49fa70b9c782399506a22a85193151b9b691245cebafd2063012443c132, 0x4b6c36debaedefb7b2d71b0503ffdc00150aaffd42e63358238ec888901738b8, 0x08, 0x00 // get_deposit_root() -> 0x2089653123d9c721215120b6db6738ba273bbc5228ac093b1f983badcdc8a438 -// gas irOptimized: 122114 -// gas legacy: 150475 -// gas legacyOptimized: 122811 +// gas irOptimized: 122113 +// gas legacy: 150283 +// gas legacyOptimized: 122523 // get_deposit_count() -> 0x20, 8, 0x0100000000000000000000000000000000000000000000000000000000000000 // deposit(bytes,bytes,bytes,bytes32), 32 ether: 0x80, 0xe0, 0x120, 0xdbd986dc85ceb382708cf90a3500f500f0a393c5ece76963ac3ed72eccd2c301, 0x30, 0xb2ce0f79f90e7b3a113ca5783c65756f96c4b4673c2b5c1eb4efc22280259441, 0x06d601211e8866dc5b50dc48a244dd7c00000000000000000000000000000000, 0x20, 0x00344b6c73f71b11c56aba0d01b7d8ad83559f209d0a4101a515f6ad54c89771, 0x60, 0x945caaf82d18e78c033927d51f452ebcd76524497b91d7a11219cb3db6a1d369, 0x7595fc095ce489e46b2ef129591f2f6d079be4faaf345a02c5eb133c072e7c56, 0x0c6c3617eee66b4b878165c502357d49485326bc6b31bc96873f308c8f19c09d -> # txhash: 0x404d8e109822ce448e68f45216c12cb051b784d068fbe98317ab8e50c58304ac # // ~ emit DepositEvent(bytes,bytes,bytes,bytes,bytes): 0xa0, 0x0100, 0x0140, 0x0180, 0x0200, 0x30, 0xb2ce0f79f90e7b3a113ca5783c65756f96c4b4673c2b5c1eb4efc22280259441, 0x06d601211e8866dc5b50dc48a244dd7c00000000000000000000000000000000, 0x20, 0x344b6c73f71b11c56aba0d01b7d8ad83559f209d0a4101a515f6ad54c89771, 0x08, 0x40597307000000000000000000000000000000000000000000000000000000, 0x60, 0x945caaf82d18e78c033927d51f452ebcd76524497b91d7a11219cb3db6a1d369, 0x7595fc095ce489e46b2ef129591f2f6d079be4faaf345a02c5eb133c072e7c56, 0x0c6c3617eee66b4b878165c502357d49485326bc6b31bc96873f308c8f19c09d, 0x08, 0x0100000000000000000000000000000000000000000000000000000000000000 // get_deposit_root() -> 0x40255975859377d912c53aa853245ebd939bdd2b33a28e084babdcc1ed8238ee -// gas irOptimized: 122114 -// gas legacy: 150475 -// gas legacyOptimized: 122811 +// gas irOptimized: 122113 +// gas legacy: 150283 +// gas legacyOptimized: 122523 // get_deposit_count() -> 0x20, 8, 0x0200000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol b/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol index 56abe4a9dcf1..e45d3360e373 100644 --- a/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol +++ b/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol @@ -50,9 +50,9 @@ contract test { // compileViaYul: also // ---- // constructor() -// gas irOptimized: 1938339 -// gas legacy: 2480887 -// gas legacyOptimized: 1874490 +// gas irOptimized: 1926032 +// gas legacy: 2478955 +// gas legacyOptimized: 1877737 // div(int256,int256): 3141592653589793238, 88714123 -> 35412542528203691288251815328 // gas irOptimized: 22137 // gas legacy: 22767 diff --git a/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol b/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol index 0488179f1d1c..c37fe52b56c9 100644 --- a/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol +++ b/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol @@ -50,9 +50,9 @@ contract test { // compileViaYul: also // ---- // constructor() -// gas irOptimized: 1792108 -// gas legacy: 2250130 -// gas legacyOptimized: 1746528 +// gas irOptimized: 1780841 +// gas legacy: 2248594 +// gas legacyOptimized: 1749096 // div(uint256,uint256): 3141592653589793238, 88714123 -> 35412542528203691288251815328 // gas irOptimized: 22004 // gas legacy: 22497 diff --git a/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol b/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol index 45976217b595..b1c4c0169a01 100644 --- a/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol +++ b/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol @@ -35,9 +35,9 @@ contract test { // compileViaYul: also // ---- // constructor() -// gas irOptimized: 465789 -// gas legacy: 672749 -// gas legacyOptimized: 479606 +// gas irOptimized: 455866 +// gas legacy: 671453 +// gas legacyOptimized: 480242 // prb_pi() -> 3141592656369545286 // gas irOptimized: 57478 // gas legacy: 98903 diff --git a/test/libsolidity/semanticTests/externalContracts/snark.sol b/test/libsolidity/semanticTests/externalContracts/snark.sol index 8f6b939fdff9..05b4ddb25a35 100644 --- a/test/libsolidity/semanticTests/externalContracts/snark.sol +++ b/test/libsolidity/semanticTests/externalContracts/snark.sol @@ -298,5 +298,5 @@ contract Test { // verifyTx() -> true // ~ emit Verified(string): 0x20, 0x16, "Successfully verified." // gas irOptimized: 95261 -// gas legacy: 114094 +// gas legacy: 113731 // gas legacyOptimized: 83670 diff --git a/test/libsolidity/semanticTests/externalContracts/strings.sol b/test/libsolidity/semanticTests/externalContracts/strings.sol index a16f884e8bf7..ce582e7c94f5 100644 --- a/test/libsolidity/semanticTests/externalContracts/strings.sol +++ b/test/libsolidity/semanticTests/externalContracts/strings.sol @@ -51,9 +51,9 @@ contract test { // compileViaYul: also // ---- // constructor() -// gas irOptimized: 707330 -// gas legacy: 1130761 -// gas legacyOptimized: 750416 +// gas irOptimized: 691317 +// gas legacy: 1127730 +// gas legacyOptimized: 753807 // toSlice(string): 0x20, 11, "hello world" -> 11, 0xa0 // gas irOptimized: 22660 // gas legacy: 23190 @@ -71,6 +71,6 @@ contract test { // gas legacy: 31621 // gas legacyOptimized: 27914 // benchmark(string,bytes32): 0x40, 0x0842021, 8, "solidity" -> 0x2020 -// gas irOptimized: 2040045 -// gas legacy: 4381235 -// gas legacyOptimized: 2317529 +// gas irOptimized: 2040019 +// gas legacy: 4356286 +// gas legacyOptimized: 2268278 diff --git a/test/libsolidity/semanticTests/functionCall/creation_function_call_with_args.sol b/test/libsolidity/semanticTests/functionCall/creation_function_call_with_args.sol index 685d8a7de516..0f1b635239ad 100644 --- a/test/libsolidity/semanticTests/functionCall/creation_function_call_with_args.sol +++ b/test/libsolidity/semanticTests/functionCall/creation_function_call_with_args.sol @@ -17,7 +17,7 @@ contract D { // compileViaYul: also // ---- // constructor(): 2 -> -// gas irOptimized: 203967 +// gas irOptimized: 200217 // gas legacy: 245842 // gas legacyOptimized: 195676 // f() -> 2 diff --git a/test/libsolidity/semanticTests/functionCall/creation_function_call_with_salt.sol b/test/libsolidity/semanticTests/functionCall/creation_function_call_with_salt.sol index a768a2836d70..462e9ad76c10 100644 --- a/test/libsolidity/semanticTests/functionCall/creation_function_call_with_salt.sol +++ b/test/libsolidity/semanticTests/functionCall/creation_function_call_with_salt.sol @@ -18,7 +18,7 @@ contract D { // compileViaYul: also // ---- // constructor(): 2 -> -// gas irOptimized: 204130 +// gas irOptimized: 200380 // gas legacy: 246202 // gas legacyOptimized: 195914 // f() -> 2 diff --git a/test/libsolidity/semanticTests/functionCall/external_call_to_nonexisting.sol b/test/libsolidity/semanticTests/functionCall/external_call_to_nonexisting.sol index 030aeaa10b2f..79c3adccb1b5 100644 --- a/test/libsolidity/semanticTests/functionCall/external_call_to_nonexisting.sol +++ b/test/libsolidity/semanticTests/functionCall/external_call_to_nonexisting.sol @@ -25,9 +25,9 @@ contract C { // compileViaYul: also // ---- // constructor(), 1 ether -> -// gas irOptimized: 315341 -// gas legacy: 465314 -// gas legacyOptimized: 304481 +// gas irOptimized: 303935 +// gas legacy: 464030 +// gas legacyOptimized: 304049 // f(uint256): 0 -> FAILURE // f(uint256): 1 -> FAILURE // f(uint256): 2 -> FAILURE diff --git a/test/libsolidity/semanticTests/functionCall/external_call_to_nonexisting_debugstrings.sol b/test/libsolidity/semanticTests/functionCall/external_call_to_nonexisting_debugstrings.sol index cfbf1bcc13dd..2e9be2ff5ffd 100644 --- a/test/libsolidity/semanticTests/functionCall/external_call_to_nonexisting_debugstrings.sol +++ b/test/libsolidity/semanticTests/functionCall/external_call_to_nonexisting_debugstrings.sol @@ -27,9 +27,9 @@ contract C { // revertStrings: debug // ---- // constructor(), 1 ether -> -// gas irOptimized: 452673 -// gas legacy: 834272 -// gas legacyOptimized: 510004 +// gas irOptimized: 446871 +// gas legacy: 832976 +// gas legacyOptimized: 509560 // f(uint256): 0 -> FAILURE, hex"08c379a0", 0x20, 37, "Target contract does not contain", " code" // f(uint256): 1 -> FAILURE, hex"08c379a0", 0x20, 37, "Target contract does not contain", " code" // f(uint256): 2 -> FAILURE, hex"08c379a0", 0x20, 37, "Target contract does not contain", " code" diff --git a/test/libsolidity/semanticTests/functionCall/failed_create.sol b/test/libsolidity/semanticTests/functionCall/failed_create.sol index 2ebf8740d2f7..19fd10bf65bc 100644 --- a/test/libsolidity/semanticTests/functionCall/failed_create.sol +++ b/test/libsolidity/semanticTests/functionCall/failed_create.sol @@ -18,9 +18,9 @@ contract C { // compileViaYul: also // ---- // constructor(), 20 wei -// gas irOptimized: 219285 -// gas legacy: 294569 -// gas legacyOptimized: 174699 +// gas irOptimized: 212583 +// gas legacy: 294335 +// gas legacyOptimized: 174279 // f(uint256): 20 -> 1370859564726510389319704988634906228201275401179 // x() -> 1 // f(uint256): 20 -> FAILURE diff --git a/test/libsolidity/semanticTests/functionCall/gas_and_value_basic.sol b/test/libsolidity/semanticTests/functionCall/gas_and_value_basic.sol index 4321753d6897..40de1b509289 100644 --- a/test/libsolidity/semanticTests/functionCall/gas_and_value_basic.sol +++ b/test/libsolidity/semanticTests/functionCall/gas_and_value_basic.sol @@ -41,7 +41,7 @@ contract test { // compileViaYul: also // ---- // constructor(), 20 wei -> -// gas irOptimized: 283040 +// gas irOptimized: 270609 // gas legacy: 402654 // gas legacyOptimized: 274470 // sendAmount(uint256): 5 -> 5 diff --git a/test/libsolidity/semanticTests/functionCall/gas_and_value_brace_syntax.sol b/test/libsolidity/semanticTests/functionCall/gas_and_value_brace_syntax.sol index 2f89517b7a0d..6b3f99deec5e 100644 --- a/test/libsolidity/semanticTests/functionCall/gas_and_value_brace_syntax.sol +++ b/test/libsolidity/semanticTests/functionCall/gas_and_value_brace_syntax.sol @@ -40,7 +40,7 @@ contract test { // compileViaYul: also // ---- // constructor(), 20 wei -> -// gas irOptimized: 283040 +// gas irOptimized: 270609 // gas legacy: 402654 // gas legacyOptimized: 274470 // sendAmount(uint256): 5 -> 5 diff --git a/test/libsolidity/semanticTests/functionCall/mapping_array_internal_argument.sol b/test/libsolidity/semanticTests/functionCall/mapping_array_internal_argument.sol index f1e2f111666c..f422b43d92cb 100644 --- a/test/libsolidity/semanticTests/functionCall/mapping_array_internal_argument.sol +++ b/test/libsolidity/semanticTests/functionCall/mapping_array_internal_argument.sol @@ -20,7 +20,7 @@ contract test { // compileViaYul: also // ---- // set(uint8,uint8,uint8,uint8,uint8): 1, 21, 22, 42, 43 -> 0, 0, 0, 0 -// gas irOptimized: 111929 +// gas irOptimized: 111909 // gas legacy: 113806 // gas legacyOptimized: 111781 // get(uint8): 1 -> 21, 22, 42, 43 diff --git a/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol b/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol index 617a6dec289a..a3d93043de05 100644 --- a/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol +++ b/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol @@ -19,7 +19,7 @@ contract Main { // compileViaYul: also // ---- // constructor(), 20 wei -> -// gas irOptimized: 102862 +// gas irOptimized: 100264 // gas legacy: 116691 // gas legacyOptimized: 100361 // s() -> true diff --git a/test/libsolidity/semanticTests/immutable/multi_creation.sol b/test/libsolidity/semanticTests/immutable/multi_creation.sol index e834663d0d71..a66c86027c29 100644 --- a/test/libsolidity/semanticTests/immutable/multi_creation.sol +++ b/test/libsolidity/semanticTests/immutable/multi_creation.sol @@ -29,7 +29,7 @@ contract C { // compileViaYul: also // ---- // f() -> 3, 7, 5 -// gas irOptimized: 127347 +// gas irOptimized: 126136 // gas legacy: 151334 // gas legacyOptimized: 125166 // x() -> 7 diff --git a/test/libsolidity/semanticTests/immutable/use_scratch.sol b/test/libsolidity/semanticTests/immutable/use_scratch.sol index e065f3f0131a..9dec4093577a 100644 --- a/test/libsolidity/semanticTests/immutable/use_scratch.sol +++ b/test/libsolidity/semanticTests/immutable/use_scratch.sol @@ -17,7 +17,7 @@ contract C { // compileViaYul: also // ---- // constructor(): 3 -> -// gas irOptimized: 131042 +// gas irOptimized: 127454 // gas legacy: 209361 // gas legacyOptimized: 139324 // f() -> 84, 23 diff --git a/test/libsolidity/semanticTests/inheritance/inherited_function_calldata_memory_interface.sol b/test/libsolidity/semanticTests/inheritance/inherited_function_calldata_memory_interface.sol index a1565099296b..2ce71c31fe80 100644 --- a/test/libsolidity/semanticTests/inheritance/inherited_function_calldata_memory_interface.sol +++ b/test/libsolidity/semanticTests/inheritance/inherited_function_calldata_memory_interface.sol @@ -25,6 +25,6 @@ contract B { // compileViaYul: also // ---- // g() -> 42 -// gas irOptimized: 111794 +// gas irOptimized: 101944 // gas legacy: 185053 // gas legacyOptimized: 114598 diff --git a/test/libsolidity/semanticTests/inheritance/value_for_constructor.sol b/test/libsolidity/semanticTests/inheritance/value_for_constructor.sol index e6f94bdcfff1..b38e9a6ad45c 100644 --- a/test/libsolidity/semanticTests/inheritance/value_for_constructor.sol +++ b/test/libsolidity/semanticTests/inheritance/value_for_constructor.sol @@ -42,7 +42,7 @@ contract Main { // compileViaYul: also // ---- // constructor(), 22 wei -> -// gas irOptimized: 284287 +// gas irOptimized: 277680 // gas legacy: 402045 // gas legacyOptimized: 266772 // getFlag() -> true diff --git a/test/libsolidity/semanticTests/isoltestTesting/balance_other_contract.sol b/test/libsolidity/semanticTests/isoltestTesting/balance_other_contract.sol index 8d37ed809f95..b02e48804fb8 100644 --- a/test/libsolidity/semanticTests/isoltestTesting/balance_other_contract.sol +++ b/test/libsolidity/semanticTests/isoltestTesting/balance_other_contract.sol @@ -18,7 +18,7 @@ contract ClientReceipt { // compileViaYul: also // ---- // constructor(), 2000 wei -> -// gas irOptimized: 188162 +// gas irOptimized: 183544 // gas legacy: 235195 // gas legacyOptimized: 176766 // balance -> 1500 diff --git a/test/libsolidity/semanticTests/libraries/internal_types_in_library.sol b/test/libsolidity/semanticTests/libraries/internal_types_in_library.sol index ac61fad71cd6..9cf5f65ff282 100644 --- a/test/libsolidity/semanticTests/libraries/internal_types_in_library.sol +++ b/test/libsolidity/semanticTests/libraries/internal_types_in_library.sol @@ -25,6 +25,6 @@ contract Test { // ---- // library: Lib // f() -> 4, 0x11 -// gas irOptimized: 115874 -// gas legacy: 135952 -// gas legacyOptimized: 119643 +// gas irOptimized: 115868 +// gas legacy: 135820 +// gas legacyOptimized: 119448 diff --git a/test/libsolidity/semanticTests/libraries/using_library_mappings_public.sol b/test/libsolidity/semanticTests/libraries/using_library_mappings_public.sol index e8d22c279c36..6304e12d8cee 100644 --- a/test/libsolidity/semanticTests/libraries/using_library_mappings_public.sol +++ b/test/libsolidity/semanticTests/libraries/using_library_mappings_public.sol @@ -22,6 +22,6 @@ contract Test { // ---- // library: Lib // f() -> 1, 0, 0x2a, 0x17, 0, 0x63 -// gas irOptimized: 119561 +// gas irOptimized: 119499 // gas legacy: 124793 // gas legacyOptimized: 119694 diff --git a/test/libsolidity/semanticTests/libraries/using_library_structs.sol b/test/libsolidity/semanticTests/libraries/using_library_structs.sol index 116887fd591a..1f1ac6eb0c08 100644 --- a/test/libsolidity/semanticTests/libraries/using_library_structs.sol +++ b/test/libsolidity/semanticTests/libraries/using_library_structs.sol @@ -23,5 +23,5 @@ contract Test { // ---- // library: Lib // f() -> 7, 8 -// gas irOptimized: 101820 +// gas irOptimized: 101818 // gas legacy: 101504 diff --git a/test/libsolidity/semanticTests/literals/ternary_operator_with_literal_types_overflow.sol b/test/libsolidity/semanticTests/literals/ternary_operator_with_literal_types_overflow.sol new file mode 100644 index 000000000000..22d61c6c5168 --- /dev/null +++ b/test/libsolidity/semanticTests/literals/ternary_operator_with_literal_types_overflow.sol @@ -0,0 +1,19 @@ +contract TestTernary +{ + function h() pure public returns (uint16 b) + { + b = (true ? 63 : 255) + (false ? 63 : 255); + } + + function g() pure public returns (uint16 a) + { + bool t = true; + bool f = false; + a = (t ? 63 : 255) + (f ? 63 : 255); + } +} +// ==== +// compileViaYul: also +// ---- +// g() -> FAILURE, hex"4e487b71", 0x11 +// h() -> FAILURE, hex"4e487b71", 0x11 diff --git a/test/libsolidity/semanticTests/multiSource/import_overloaded_function.sol b/test/libsolidity/semanticTests/multiSource/import_overloaded_function.sol new file mode 100644 index 000000000000..503f65680291 --- /dev/null +++ b/test/libsolidity/semanticTests/multiSource/import_overloaded_function.sol @@ -0,0 +1,15 @@ +==== Source: A ==== +function sub(uint256 x, uint256 y) pure returns (uint) { return 1; } +function sub(uint256 x) pure returns (uint) { return 2; } +==== Source: B ==== +import {sub} from "A"; +contract C +{ + function f() public pure returns (uint, uint) { + return (sub(1, 2), sub(2)); + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 1, 2 diff --git a/test/libsolidity/semanticTests/salted_create/salted_create.sol b/test/libsolidity/semanticTests/salted_create/salted_create.sol index 5374d23521c7..51b987c2cafb 100644 --- a/test/libsolidity/semanticTests/salted_create/salted_create.sol +++ b/test/libsolidity/semanticTests/salted_create/salted_create.sol @@ -22,6 +22,6 @@ contract A { // ---- // different_salt() -> true // same_salt() -> true -// gas irOptimized: 98438914 +// gas irOptimized: 98438898 // gas legacy: 98439116 // gas legacyOptimized: 98438970 diff --git a/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol b/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol index 4ce8b5149c87..6613e471bda8 100644 --- a/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol +++ b/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol @@ -22,6 +22,6 @@ contract A { // compileViaYul: also // ---- // f(), 10 ether -> 3007, 3008, 3009 -// gas irOptimized: 272413 +// gas irOptimized: 271831 // gas legacy: 422501 // gas legacyOptimized: 287472 diff --git a/test/libsolidity/semanticTests/smoke/constructor.sol b/test/libsolidity/semanticTests/smoke/constructor.sol index a6e812e9a082..3003c5d8d9ed 100644 --- a/test/libsolidity/semanticTests/smoke/constructor.sol +++ b/test/libsolidity/semanticTests/smoke/constructor.sol @@ -14,7 +14,7 @@ contract C { // compileViaYul: also // ---- // constructor(), 2 wei: 3 -> -// gas irOptimized: 111699 +// gas irOptimized: 107627 // gas legacy: 151416 // gas legacyOptimized: 108388 // state() -> 3 diff --git a/test/libsolidity/semanticTests/state/blockhash_basic.sol b/test/libsolidity/semanticTests/state/blockhash_basic.sol index 9abeb90aa021..829a8695d308 100644 --- a/test/libsolidity/semanticTests/state/blockhash_basic.sol +++ b/test/libsolidity/semanticTests/state/blockhash_basic.sol @@ -14,7 +14,7 @@ contract C { // compileViaYul: also // ---- // constructor() -// gas irOptimized: 115297 +// gas irOptimized: 111584 // gas legacy: 155081 // gas legacyOptimized: 107997 // genesisHash() -> 0x3737373737373737373737373737373737373737373737373737373737373737 diff --git a/test/libsolidity/semanticTests/structs/calldata/calldata_struct_with_nested_array_to_storage.sol b/test/libsolidity/semanticTests/structs/calldata/calldata_struct_with_nested_array_to_storage.sol index 6e65cd239478..c5f2e7343442 100644 --- a/test/libsolidity/semanticTests/structs/calldata/calldata_struct_with_nested_array_to_storage.sol +++ b/test/libsolidity/semanticTests/structs/calldata/calldata_struct_with_nested_array_to_storage.sol @@ -18,6 +18,6 @@ contract C { // compileViaYul: also // ---- // f(uint32,(uint128,uint256[][2],uint32)): 55, 0x40, 77, 0x60, 88, 0x40, 0x40, 2, 1, 2 -> 55, 77, 1, 2, 88 -// gas irOptimized: 203312 +// gas irOptimized: 203299 // gas legacy: 209194 // gas legacyOptimized: 203583 diff --git a/test/libsolidity/semanticTests/structs/conversion/recursive_storage_memory.sol b/test/libsolidity/semanticTests/structs/conversion/recursive_storage_memory.sol index c23a15ec0a3e..509fd29ed840 100644 --- a/test/libsolidity/semanticTests/structs/conversion/recursive_storage_memory.sol +++ b/test/libsolidity/semanticTests/structs/conversion/recursive_storage_memory.sol @@ -25,6 +25,6 @@ contract CopyTest { // compileViaYul: also // ---- // run() -> 2, 23, 42 -// gas irOptimized: 194005 +// gas irOptimized: 194003 // gas legacy: 186016 // gas legacyOptimized: 184668 diff --git a/test/libsolidity/semanticTests/structs/copy_struct_array_from_storage.sol b/test/libsolidity/semanticTests/structs/copy_struct_array_from_storage.sol index 258ff350b33b..876a7f6c8e4b 100644 --- a/test/libsolidity/semanticTests/structs/copy_struct_array_from_storage.sol +++ b/test/libsolidity/semanticTests/structs/copy_struct_array_from_storage.sol @@ -88,7 +88,7 @@ contract Test { // compileViaYul: also // ---- // test1() -> true -// gas irOptimized: 150545 +// gas irOptimized: 150533 // gas legacy: 150266 // gas legacyOptimized: 149875 // test2() -> true diff --git a/test/libsolidity/semanticTests/structs/memory_structs_nested_load.sol b/test/libsolidity/semanticTests/structs/memory_structs_nested_load.sol index 5dd4d48a639e..89f575577978 100644 --- a/test/libsolidity/semanticTests/structs/memory_structs_nested_load.sol +++ b/test/libsolidity/semanticTests/structs/memory_structs_nested_load.sol @@ -69,7 +69,7 @@ contract Test { // compileViaYul: also // ---- // load() -> 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 -// gas irOptimized: 111432 +// gas irOptimized: 111425 // gas legacy: 112999 // gas legacyOptimized: 110881 // store() -> 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 diff --git a/test/libsolidity/semanticTests/structs/struct_containing_bytes_copy_and_delete.sol b/test/libsolidity/semanticTests/structs/struct_containing_bytes_copy_and_delete.sol index 6b5d1f022468..f77156d64350 100644 --- a/test/libsolidity/semanticTests/structs/struct_containing_bytes_copy_and_delete.sol +++ b/test/libsolidity/semanticTests/structs/struct_containing_bytes_copy_and_delete.sol @@ -26,8 +26,8 @@ contract c { // storageEmpty -> 1 // set(uint256,bytes,uint256): 12, 0x60, 13, 33, "12345678901234567890123456789012", "3" -> true // gas irOptimized: 133728 -// gas legacy: 134436 -// gas legacyOptimized: 133879 +// gas legacy: 134433 +// gas legacyOptimized: 133876 // test(uint256): 32 -> "3" // storageEmpty -> 0 // copy() -> true diff --git a/test/libsolidity/semanticTests/structs/struct_copy.sol b/test/libsolidity/semanticTests/structs/struct_copy.sol index 03a063bb8fed..f7083c7a0b4c 100644 --- a/test/libsolidity/semanticTests/structs/struct_copy.sol +++ b/test/libsolidity/semanticTests/structs/struct_copy.sol @@ -43,7 +43,7 @@ contract c { // gas legacyOptimized: 110006 // retrieve(uint256): 7 -> 1, 3, 4, 2 // copy(uint256,uint256): 7, 8 -> true -// gas irOptimized: 118597 +// gas irOptimized: 118581 // gas legacy: 119166 // gas legacyOptimized: 118622 // retrieve(uint256): 7 -> 1, 3, 4, 2 diff --git a/test/libsolidity/semanticTests/structs/struct_copy_via_local.sol b/test/libsolidity/semanticTests/structs/struct_copy_via_local.sol index 21757ea407db..4305687b7c77 100644 --- a/test/libsolidity/semanticTests/structs/struct_copy_via_local.sol +++ b/test/libsolidity/semanticTests/structs/struct_copy_via_local.sol @@ -21,6 +21,6 @@ contract c { // compileViaYul: also // ---- // test() -> true -// gas irOptimized: 110186 +// gas irOptimized: 110177 // gas legacy: 110627 // gas legacyOptimized: 109706 diff --git a/test/libsolidity/semanticTests/structs/struct_delete_storage_with_array.sol b/test/libsolidity/semanticTests/structs/struct_delete_storage_with_array.sol index 44acf38e4d44..bdb60b877b20 100644 --- a/test/libsolidity/semanticTests/structs/struct_delete_storage_with_array.sol +++ b/test/libsolidity/semanticTests/structs/struct_delete_storage_with_array.sol @@ -44,7 +44,7 @@ contract C { // compileViaYul: also // ---- // f() -> -// gas irOptimized: 121624 +// gas irOptimized: 121619 // gas legacy: 122132 // gas legacyOptimized: 121500 // g() -> diff --git a/test/libsolidity/semanticTests/structs/struct_delete_storage_with_arrays_small.sol b/test/libsolidity/semanticTests/structs/struct_delete_storage_with_arrays_small.sol index 6f88df3949b5..abc10d8aa8c3 100644 --- a/test/libsolidity/semanticTests/structs/struct_delete_storage_with_arrays_small.sol +++ b/test/libsolidity/semanticTests/structs/struct_delete_storage_with_arrays_small.sol @@ -27,4 +27,4 @@ contract C { // compileViaYul: true // ---- // f() -> 0 -// gas irOptimized: 111896 +// gas irOptimized: 112129 diff --git a/test/libsolidity/semanticTests/structs/struct_memory_to_storage_function_ptr.sol b/test/libsolidity/semanticTests/structs/struct_memory_to_storage_function_ptr.sol index fe791a68ddee..6c317598b95e 100644 --- a/test/libsolidity/semanticTests/structs/struct_memory_to_storage_function_ptr.sol +++ b/test/libsolidity/semanticTests/structs/struct_memory_to_storage_function_ptr.sol @@ -32,6 +32,6 @@ contract C { // compileViaYul: also // ---- // f() -> 42, 23, 34, 42, 42 -// gas irOptimized: 110966 +// gas irOptimized: 110843 // gas legacy: 112021 // gas legacyOptimized: 110548 diff --git a/test/libsolidity/semanticTests/structs/structs.sol b/test/libsolidity/semanticTests/structs/structs.sol index 3356eac164d9..412b71d39f01 100644 --- a/test/libsolidity/semanticTests/structs/structs.sol +++ b/test/libsolidity/semanticTests/structs/structs.sol @@ -32,7 +32,7 @@ contract test { // ---- // check() -> false // set() -> -// gas irOptimized: 134432 +// gas irOptimized: 134411 // gas legacy: 135277 // gas legacyOptimized: 134064 // check() -> true diff --git a/test/libsolidity/semanticTests/userDefinedValueType/calldata.sol b/test/libsolidity/semanticTests/userDefinedValueType/calldata.sol index 56ad74c54037..433470160d71 100644 --- a/test/libsolidity/semanticTests/userDefinedValueType/calldata.sol +++ b/test/libsolidity/semanticTests/userDefinedValueType/calldata.sol @@ -51,12 +51,12 @@ contract C { // compileViaYul: also // ---- // test_f() -> true -// gas irOptimized: 122364 -// gas legacy: 126168 -// gas legacyOptimized: 123199 +// gas irOptimized: 122329 +// gas legacy: 126150 +// gas legacyOptimized: 123163 // test_g() -> true // gas irOptimized: 95980 -// gas legacy: 101311 +// gas legacy: 101281 // gas legacyOptimized: 96566 // addresses(uint256): 0 -> 0x18 // addresses(uint256): 1 -> 0x19 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/calldata_to_storage.sol b/test/libsolidity/semanticTests/userDefinedValueType/calldata_to_storage.sol index 433d1969c657..0305fd473be1 100644 --- a/test/libsolidity/semanticTests/userDefinedValueType/calldata_to_storage.sol +++ b/test/libsolidity/semanticTests/userDefinedValueType/calldata_to_storage.sol @@ -25,7 +25,7 @@ contract C { // ---- // s() -> 0, 0, 0x00, 0 // f((uint8,uint16,bytes2,uint8)): 1, 0xff, "ab", 15 -> -// gas irOptimized: 44786 +// gas irOptimized: 44405 // gas legacy: 47200 // gas legacyOptimized: 44923 // s() -> 1, 0xff, 0x6162000000000000000000000000000000000000000000000000000000000000, 15 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol b/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol index c2c5f3cdc150..d65af8e8cc52 100644 --- a/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol +++ b/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol @@ -115,8 +115,8 @@ contract ERC20 { // ---- // constructor() // ~ emit Transfer(address,address,uint256): #0x00, #0x1212121212121212121212121212120000000012, 0x14 -// gas irOptimized: 423885 -// gas legacy: 861559 +// gas irOptimized: 418388 +// gas legacy: 860880 // gas legacyOptimized: 420959 // totalSupply() -> 20 // gas irOptimized: 23415 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/memory_to_storage.sol b/test/libsolidity/semanticTests/userDefinedValueType/memory_to_storage.sol index 04e993682371..b250bea87c4d 100644 --- a/test/libsolidity/semanticTests/userDefinedValueType/memory_to_storage.sol +++ b/test/libsolidity/semanticTests/userDefinedValueType/memory_to_storage.sol @@ -25,7 +25,7 @@ contract C { // ---- // s() -> 0, 0, 0x00, 0 // f((uint8,uint16,bytes2,uint8)): 1, 0xff, "ab", 15 -> -// gas irOptimized: 44536 +// gas irOptimized: 44473 // gas legacy: 46213 // gas legacyOptimized: 44671 // s() -> 1, 0xff, 0x6162000000000000000000000000000000000000000000000000000000000000, 15 diff --git a/test/libsolidity/semanticTests/using/calldata_memory_copy.sol b/test/libsolidity/semanticTests/using/calldata_memory_copy.sol new file mode 100644 index 000000000000..493cfc29b02f --- /dev/null +++ b/test/libsolidity/semanticTests/using/calldata_memory_copy.sol @@ -0,0 +1,19 @@ + +contract C { + function f(uint[] calldata arr) external returns (uint) { + return arr.sum(); + } +} + +function sum(uint[] memory arr) returns (uint result) { + for(uint i = 0; i < arr.length; i++) { + result += arr[i]; + } +} + +using {sum} for uint[]; + +// ==== +// compileViaYul: also +// ---- +// f(uint256[]): 0x20, 3, 1, 2, 8 -> 11 diff --git a/test/libsolidity/semanticTests/using/free_function_braces.sol b/test/libsolidity/semanticTests/using/free_function_braces.sol new file mode 100644 index 000000000000..e522ff61b2b5 --- /dev/null +++ b/test/libsolidity/semanticTests/using/free_function_braces.sol @@ -0,0 +1,26 @@ +function id(uint x) pure returns (uint) { + return x; +} + +function zero(uint) pure returns (uint) { + return 0; +} + +contract C { + function f(uint z) pure external returns(uint) { + return z.id(); + } + + function g(uint z) pure external returns (uint) { + return z.zero(); + } + + using {id, zero} for uint; +} +// ==== +// compileViaYul: also +// ---- +// f(uint256): 10 -> 10 +// g(uint256): 10 -> 0 +// f(uint256): 256 -> 0x0100 +// g(uint256): 256 -> 0 diff --git a/test/libsolidity/semanticTests/using/free_function_multi.sol b/test/libsolidity/semanticTests/using/free_function_multi.sol new file mode 100644 index 000000000000..bf71e4d44b63 --- /dev/null +++ b/test/libsolidity/semanticTests/using/free_function_multi.sol @@ -0,0 +1,27 @@ +contract C { + function f(uint z) pure external returns(uint) { + return z.id(); + } + + using {id, zero, zero, id} for uint; + + function g(uint z) pure external returns (uint) { + return z.zero(); + } +} + +function id(uint x) pure returns (uint) { + return x; +} + +function zero(uint) pure returns (uint) { + return 0; +} + +// ==== +// compileViaYul: also +// ---- +// f(uint256): 10 -> 10 +// g(uint256): 10 -> 0 +// f(uint256): 256 -> 0x0100 +// g(uint256): 256 -> 0 diff --git a/test/libsolidity/semanticTests/using/free_functions_individual.sol b/test/libsolidity/semanticTests/using/free_functions_individual.sol new file mode 100644 index 000000000000..334b427e1317 --- /dev/null +++ b/test/libsolidity/semanticTests/using/free_functions_individual.sol @@ -0,0 +1,30 @@ +using {zero} for uint; + +contract C { + using {id} for uint; + + function f(uint z) pure external returns(uint) { + return z.id(); + } + + function g(uint z) pure external returns (uint) { + return z.zero(); + } +} + +function id(uint x) pure returns (uint) { + return x; +} + +function zero(uint) pure returns (uint) { + return 0; +} + + +// ==== +// compileViaYul: also +// ---- +// f(uint256): 10 -> 10 +// g(uint256): 10 -> 0 +// f(uint256): 256 -> 0x0100 +// g(uint256): 256 -> 0 diff --git a/test/libsolidity/semanticTests/using/imported_functions.sol b/test/libsolidity/semanticTests/using/imported_functions.sol new file mode 100644 index 000000000000..d99e558fdc84 --- /dev/null +++ b/test/libsolidity/semanticTests/using/imported_functions.sol @@ -0,0 +1,19 @@ +==== Source: A ==== +function inc(uint x) pure returns (uint) { + return x + 1; +} + +==== Source: B ==== +contract C { + function f(uint x) public returns (uint) { + return x.f() + x.inc(); + } +} +using {A.inc, f} for uint; +import {inc as f} from "A"; +import "A" as A; +// ==== +// compileViaYul: also +// ---- +// f(uint256): 5 -> 12 +// f(uint256): 10 -> 0x16 diff --git a/test/libsolidity/semanticTests/using/library_through_module.sol b/test/libsolidity/semanticTests/using/library_through_module.sol new file mode 100644 index 000000000000..6102f5a7074c --- /dev/null +++ b/test/libsolidity/semanticTests/using/library_through_module.sol @@ -0,0 +1,34 @@ +==== Source: A ==== +library L { + function id(uint x) internal pure returns (uint) { + return x; + } + function one_ext(uint) pure external returns(uint) { + return 1; + } + function empty() pure internal { + } + +} + +==== Source: B ==== +contract C { + using M.L for uint; + function f(uint x) public pure returns (uint) { + return x.id(); + } + function g(uint x) public pure returns (uint) { + return x.one_ext(); + } +} + +import "A" as M; + +// ==== +// compileViaYul: also +// ---- +// library: "A":L +// f(uint256): 5 -> 5 +// f(uint256): 10 -> 10 +// g(uint256): 5 -> 1 +// g(uint256): 10 -> 1 diff --git a/test/libsolidity/semanticTests/using/module_renamed.sol b/test/libsolidity/semanticTests/using/module_renamed.sol new file mode 100644 index 000000000000..d648e88d1af7 --- /dev/null +++ b/test/libsolidity/semanticTests/using/module_renamed.sol @@ -0,0 +1,26 @@ +==== Source: A ==== +function f(uint x) pure returns (uint) { + return x + 2; +} +function g(uint x) pure returns (uint) { + return x + 8; +} + +==== Source: B ==== +import {f as g, g as f} from "A"; + +==== Source: C ==== +contract C { + function test(uint x, uint y) public pure returns (uint, uint) { + return (x.f(), y.g()); + } +} + +using {M.g, M.f} for uint; + +import "B" as M; + +// ==== +// compileViaYul: also +// ---- +// test(uint256,uint256): 1, 1 -> 9, 3 diff --git a/test/libsolidity/semanticTests/using/recursive_import.sol b/test/libsolidity/semanticTests/using/recursive_import.sol new file mode 100644 index 000000000000..09d27db60f30 --- /dev/null +++ b/test/libsolidity/semanticTests/using/recursive_import.sol @@ -0,0 +1,25 @@ +==== Source: A ==== +import {T as U} from "A"; +import "A" as X; + +type T is uint; +function f(T x) pure returns (T) { return T.wrap(T.unwrap(x) + 1); } +function g(T x) pure returns (uint) { return T.unwrap(x) + 10; } + +using { f } for X.X.U global; +using { g } for T global; + +function cr() pure returns (T) {} + +==== Source: B ==== +import { cr } from "A"; + +contract C { + function f() public returns (uint) { + return cr().f().g(); + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 11 diff --git a/test/libsolidity/semanticTests/using/using_global_for_global.sol b/test/libsolidity/semanticTests/using/using_global_for_global.sol new file mode 100644 index 000000000000..7d7809d2ae4d --- /dev/null +++ b/test/libsolidity/semanticTests/using/using_global_for_global.sol @@ -0,0 +1,20 @@ +==== Source: A ==== +type global is uint; +using { f } for global global; +function f(global x) pure returns (global) { return global.wrap(global.unwrap(x) + 1); } +==== Source: B ==== +import { global } from "A"; + +function g(global x) pure returns (global) { return global.wrap(global.unwrap(x) + 10); } + +contract C { + using { g } for global; + function f(global r) public pure returns (global) { + return r.f().g(); + } +} + +// ==== +// compileViaYul: also +// ---- +// f(uint256): 100 -> 111 \ No newline at end of file diff --git a/test/libsolidity/semanticTests/using/using_global_invisible.sol b/test/libsolidity/semanticTests/using/using_global_invisible.sol new file mode 100644 index 000000000000..e4bf286eebff --- /dev/null +++ b/test/libsolidity/semanticTests/using/using_global_invisible.sol @@ -0,0 +1,45 @@ +==== Source: A ==== +type T is uint; +using L for T global; +library L { + function inc(T x) internal pure returns (T) { + return T.wrap(T.unwrap(x) + 1); + } + function dec(T x) external pure returns (T) { + return T.wrap(T.unwrap(x) - 1); + } +} +using {unwrap} for T global; +function unwrap(T x) pure returns (uint) { + return T.unwrap(x); +} + +==== Source: B ==== +contract C { + function f() public pure returns (T r1) { + r1 = r1.inc().inc(); + } +} + +import {T} from "A"; + +==== Source: C ==== +import {C} from "B"; + +contract D { + function test() public returns (uint) { + C c = new C(); + // This tests that bound functions are available + // even if the type is not available by name. + // This is a regular function call, a + // public and an internal library call + // and a free function call. + return c.f().inc().inc().dec().unwrap(); + } +} +// ==== +// compileViaYul: also +// ---- +// library: "A":L +// test() -> 3 +// gas legacy: 130369 diff --git a/test/libsolidity/semanticTests/using/using_global_library.sol b/test/libsolidity/semanticTests/using/using_global_library.sol new file mode 100644 index 000000000000..747ed6bd0434 --- /dev/null +++ b/test/libsolidity/semanticTests/using/using_global_library.sol @@ -0,0 +1,27 @@ +==== Source: A ==== +type T is uint; +using L for T global; +library L { + function inc(T x) internal pure returns (T) { + return T.wrap(T.unwrap(x) + 1); + } + function dec(T x) external pure returns (T) { + return T.wrap(T.unwrap(x) - 1); + } +} + +==== Source: B ==== +contract C { + function f() public pure returns (T r1, T r2) { + r1 = r1.inc().inc(); + r2 = r1.dec(); + } +} + +import {T} from "A"; + +// ==== +// compileViaYul: also +// ---- +// library: "A":L +// f() -> 2, 1 diff --git a/test/libsolidity/semanticTests/various/address_code.sol b/test/libsolidity/semanticTests/various/address_code.sol index 38e0fb13f10c..2adf3171605b 100644 --- a/test/libsolidity/semanticTests/various/address_code.sol +++ b/test/libsolidity/semanticTests/various/address_code.sol @@ -17,9 +17,9 @@ contract C { // compileViaYul: also // ---- // constructor() -> -// gas irOptimized: 199723 -// gas legacy: 241124 -// gas legacyOptimized: 155549 +// gas irOptimized: 192317 +// gas legacy: 240889 +// gas legacyOptimized: 155314 // initCode() -> 0x20, 0 // f() -> true // g() -> 0 diff --git a/test/libsolidity/semanticTests/various/contract_binary_dependencies.sol b/test/libsolidity/semanticTests/various/contract_binary_dependencies.sol index 57942979ae46..9ff4fe5e22ad 100644 --- a/test/libsolidity/semanticTests/various/contract_binary_dependencies.sol +++ b/test/libsolidity/semanticTests/various/contract_binary_dependencies.sol @@ -21,4 +21,4 @@ contract C { // compileViaYul: also // ---- // constructor() -> -// gas irOptimized: 104337 +// gas irOptimized: 101063 diff --git a/test/libsolidity/semanticTests/various/destructuring_assignment.sol b/test/libsolidity/semanticTests/various/destructuring_assignment.sol index cc93152eadca..23b6c9e58de9 100644 --- a/test/libsolidity/semanticTests/various/destructuring_assignment.sol +++ b/test/libsolidity/semanticTests/various/destructuring_assignment.sol @@ -36,6 +36,6 @@ contract C { // compileViaYul: also // ---- // f(bytes): 0x20, 0x5, "abcde" -> 0 -// gas irOptimized: 240691 -// gas legacy: 240358 -// gas legacyOptimized: 239682 +// gas irOptimized: 240662 +// gas legacy: 240349 +// gas legacyOptimized: 239673 diff --git a/test/libsolidity/semanticTests/various/erc20.sol b/test/libsolidity/semanticTests/various/erc20.sol index 9ba4e3cb73f7..109a27578fee 100644 --- a/test/libsolidity/semanticTests/various/erc20.sol +++ b/test/libsolidity/semanticTests/various/erc20.sol @@ -98,8 +98,8 @@ contract ERC20 { // ---- // constructor() // ~ emit Transfer(address,address,uint256): #0x00, #0x1212121212121212121212121212120000000012, 0x14 -// gas irOptimized: 419330 -// gas legacy: 833310 +// gas irOptimized: 413852 +// gas legacy: 832643 // gas legacyOptimized: 416135 // totalSupply() -> 20 // gas irOptimized: 23415 diff --git a/test/libsolidity/semanticTests/various/senders_balance.sol b/test/libsolidity/semanticTests/various/senders_balance.sol index 1c456f1d4844..0e0e59996bc1 100644 --- a/test/libsolidity/semanticTests/various/senders_balance.sol +++ b/test/libsolidity/semanticTests/various/senders_balance.sol @@ -19,7 +19,7 @@ contract D { // compileViaYul: also // ---- // constructor(), 27 wei -> -// gas irOptimized: 178933 +// gas irOptimized: 175157 // gas legacy: 222977 // gas legacyOptimized: 169779 // f() -> 27 diff --git a/test/libsolidity/semanticTests/various/skip_dynamic_types_for_structs.sol b/test/libsolidity/semanticTests/various/skip_dynamic_types_for_structs.sol index 30a2d9f65a6e..971d83407bab 100644 --- a/test/libsolidity/semanticTests/various/skip_dynamic_types_for_structs.sol +++ b/test/libsolidity/semanticTests/various/skip_dynamic_types_for_structs.sol @@ -22,6 +22,6 @@ contract C { // compileViaYul: also // ---- // g() -> 2, 6 -// gas irOptimized: 178812 -// gas legacy: 180762 -// gas legacyOptimized: 179481 +// gas irOptimized: 178805 +// gas legacy: 180753 +// gas legacyOptimized: 179472 diff --git a/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure.sol b/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure.sol index 06faab88247e..90dd3a6f72a1 100644 --- a/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure.sol +++ b/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure.sol @@ -38,10 +38,10 @@ contract D { // f() -> 0x1 # This should work, next should throw # // gas legacy: 103716 // fview() -> FAILURE -// gas irOptimized: 98438625 +// gas irOptimized: 98438619 // gas legacy: 98438801 // gas legacyOptimized: 98438594 // fpure() -> FAILURE -// gas irOptimized: 98438625 +// gas irOptimized: 98438619 // gas legacy: 98438801 // gas legacyOptimized: 98438595 diff --git a/test/libsolidity/semanticTests/various/value_complex.sol b/test/libsolidity/semanticTests/various/value_complex.sol index 5d8bda5dd7ed..c868652a0fe8 100644 --- a/test/libsolidity/semanticTests/various/value_complex.sol +++ b/test/libsolidity/semanticTests/various/value_complex.sol @@ -22,7 +22,7 @@ contract test { // compileViaYul: also // ---- // constructor(), 20 wei -> -// gas irOptimized: 192113 +// gas irOptimized: 190275 // gas legacy: 265006 // gas legacyOptimized: 182842 // sendAmount(uint256): 5 -> 8 diff --git a/test/libsolidity/semanticTests/various/value_insane.sol b/test/libsolidity/semanticTests/various/value_insane.sol index 0b2b1735b2be..c304732bb96f 100644 --- a/test/libsolidity/semanticTests/various/value_insane.sol +++ b/test/libsolidity/semanticTests/various/value_insane.sol @@ -21,7 +21,7 @@ contract test { // compileViaYul: also // ---- // constructor(), 20 wei -> -// gas irOptimized: 194261 +// gas irOptimized: 191991 // gas legacy: 266728 // gas legacyOptimized: 184762 // sendAmount(uint256): 5 -> 8 diff --git a/test/libsolidity/semanticTests/viaYul/array_memory_index_access.sol b/test/libsolidity/semanticTests/viaYul/array_memory_index_access.sol index 6ef403dcc633..5bd5fe137d2c 100644 --- a/test/libsolidity/semanticTests/viaYul/array_memory_index_access.sol +++ b/test/libsolidity/semanticTests/viaYul/array_memory_index_access.sol @@ -28,9 +28,9 @@ contract C { // index(uint256): 10 -> true // index(uint256): 20 -> true // index(uint256): 0xFF -> true -// gas irOptimized: 138410 -// gas legacy: 248854 -// gas legacyOptimized: 152638 +// gas irOptimized: 137634 +// gas legacy: 247324 +// gas legacyOptimized: 149578 // accessIndex(uint256,int256): 10, 1 -> 2 // accessIndex(uint256,int256): 10, 0 -> 1 // accessIndex(uint256,int256): 10, 11 -> FAILURE, hex"4e487b71", 0x32 diff --git a/test/libsolidity/semanticTests/viaYul/array_storage_index_access.sol b/test/libsolidity/semanticTests/viaYul/array_storage_index_access.sol index 24d0e9f14503..31cf4ad69096 100644 --- a/test/libsolidity/semanticTests/viaYul/array_storage_index_access.sol +++ b/test/libsolidity/semanticTests/viaYul/array_storage_index_access.sol @@ -18,33 +18,33 @@ contract C { // ---- // test_indices(uint256): 1 -> // test_indices(uint256): 129 -> -// gas irOptimized: 3032986 -// gas legacy: 3071205 -// gas legacyOptimized: 3011873 +// gas irOptimized: 3032985 +// gas legacy: 3070431 +// gas legacyOptimized: 3010325 // test_indices(uint256): 5 -> -// gas irOptimized: 367642 -// gas legacy: 369241 -// gas legacyOptimized: 366149 +// gas irOptimized: 367641 +// gas legacy: 369211 +// gas legacyOptimized: 366089 // test_indices(uint256): 10 -> // test_indices(uint256): 15 -> // gas irOptimized: 72860 // test_indices(uint256): 0xFF -> -// gas irOptimized: 3438610 -// gas legacy: 3514167 -// gas legacyOptimized: 3398107 +// gas irOptimized: 3438609 +// gas legacy: 3512637 +// gas legacyOptimized: 3395047 // test_indices(uint256): 1000 -> -// gas irOptimized: 18318372 -// gas legacy: 18617999 -// gas legacyOptimized: 18178944 +// gas irOptimized: 18318371 +// gas legacy: 18611999 +// gas legacyOptimized: 18166944 // test_indices(uint256): 129 -> -// gas irOptimized: 2733570 -// gas legacy: 2772735 -// gas legacyOptimized: 2716547 +// gas irOptimized: 2733569 +// gas legacy: 2771961 +// gas legacyOptimized: 2714999 // test_indices(uint256): 128 -> -// gas irOptimized: 426682 -// gas legacy: 467272 -// gas legacyOptimized: 418424 +// gas irOptimized: 426681 +// gas legacy: 466504 +// gas legacyOptimized: 416888 // test_indices(uint256): 1 -> -// gas irOptimized: 363074 -// gas legacy: 363407 -// gas legacyOptimized: 361811 +// gas irOptimized: 363073 +// gas legacy: 363401 +// gas legacyOptimized: 361799 diff --git a/test/libsolidity/semanticTests/viaYul/array_storage_index_boundary_test.sol b/test/libsolidity/semanticTests/viaYul/array_storage_index_boundary_test.sol index 975130c5179b..ea64676a83b3 100644 --- a/test/libsolidity/semanticTests/viaYul/array_storage_index_boundary_test.sol +++ b/test/libsolidity/semanticTests/viaYul/array_storage_index_boundary_test.sol @@ -18,11 +18,11 @@ contract C { // test_boundary_check(uint256,uint256): 1, 1 -> FAILURE, hex"4e487b71", 0x32 // test_boundary_check(uint256,uint256): 10, 10 -> FAILURE, hex"4e487b71", 0x32 // test_boundary_check(uint256,uint256): 256, 256 -> FAILURE, hex"4e487b71", 0x32 -// gas irOptimized: 137849 +// gas irOptimized: 137834 // gas legacy: 131830 // gas legacyOptimized: 112054 // test_boundary_check(uint256,uint256): 256, 255 -> 0 -// gas irOptimized: 140028 +// gas irOptimized: 140017 // gas legacy: 134149 // gas legacyOptimized: 114233 // test_boundary_check(uint256,uint256): 256, 0xFFFF -> FAILURE, hex"4e487b71", 0x32 diff --git a/test/libsolidity/semanticTests/viaYul/array_storage_index_zeroed_test.sol b/test/libsolidity/semanticTests/viaYul/array_storage_index_zeroed_test.sol index b2e0cb54678b..26c0d8394e2a 100644 --- a/test/libsolidity/semanticTests/viaYul/array_storage_index_zeroed_test.sol +++ b/test/libsolidity/semanticTests/viaYul/array_storage_index_zeroed_test.sol @@ -54,18 +54,18 @@ contract C { // ---- // test_zeroed_indicies(uint256): 1 -> // test_zeroed_indicies(uint256): 5 -> -// gas irOptimized: 131197 -// gas legacy: 132367 -// gas legacyOptimized: 129586 +// gas irOptimized: 131192 +// gas legacy: 132331 +// gas legacyOptimized: 129514 // test_zeroed_indicies(uint256): 10 -> -// gas irOptimized: 174805 -// gas legacy: 177329 -// gas legacyOptimized: 172224 +// gas irOptimized: 174810 +// gas legacy: 177248 +// gas legacyOptimized: 172062 // test_zeroed_indicies(uint256): 15 -> -// gas irOptimized: 198055 -// gas legacy: 201954 -// gas legacyOptimized: 194604 +// gas irOptimized: 198070 +// gas legacy: 201828 +// gas legacyOptimized: 194352 // test_zeroed_indicies(uint256): 0xFF -> -// gas irOptimized: 6098185 -// gas legacy: 6163149 -// gas legacyOptimized: 6029474 +// gas irOptimized: 6098680 +// gas legacy: 6160863 +// gas legacyOptimized: 6024902 diff --git a/test/libsolidity/semanticTests/viaYul/array_storage_length_access.sol b/test/libsolidity/semanticTests/viaYul/array_storage_length_access.sol index c5af58449529..1c3f8410cd66 100644 --- a/test/libsolidity/semanticTests/viaYul/array_storage_length_access.sol +++ b/test/libsolidity/semanticTests/viaYul/array_storage_length_access.sol @@ -18,7 +18,7 @@ contract C { // gas legacy: 126722 // gas legacyOptimized: 107818 // set_get_length(uint256): 0xFFF -> 0xFFF -// gas irOptimized: 1217857 +// gas irOptimized: 1217851 // gas legacy: 1702119 // gas legacyOptimized: 1398420 // set_get_length(uint256): 0xFFFFF -> FAILURE # Out-of-gas # diff --git a/test/libsolidity/semanticTests/viaYul/array_storage_push_empty.sol b/test/libsolidity/semanticTests/viaYul/array_storage_push_empty.sol index 5c7c4cba8406..6e126a150766 100644 --- a/test/libsolidity/semanticTests/viaYul/array_storage_push_empty.sol +++ b/test/libsolidity/semanticTests/viaYul/array_storage_push_empty.sol @@ -13,13 +13,13 @@ contract C { // compileViaYul: also // ---- // pushEmpty(uint256): 128 -// gas irOptimized: 412570 -// gas legacy: 417287 -// gas legacyOptimized: 399048 +// gas irOptimized: 412561 +// gas legacy: 416903 +// gas legacyOptimized: 398280 // pushEmpty(uint256): 256 -// gas irOptimized: 702558 -// gas legacy: 715083 -// gas legacyOptimized: 688908 +// gas irOptimized: 702549 +// gas legacy: 714315 +// gas legacyOptimized: 687372 // pushEmpty(uint256): 38869 -> FAILURE # out-of-gas # // gas irOptimized: 100000000 // gas legacy: 100000000 diff --git a/test/libsolidity/semanticTests/viaYul/array_storage_push_empty_length_address.sol b/test/libsolidity/semanticTests/viaYul/array_storage_push_empty_length_address.sol index 5e5d1c962c7e..cb23435d1723 100644 --- a/test/libsolidity/semanticTests/viaYul/array_storage_push_empty_length_address.sol +++ b/test/libsolidity/semanticTests/viaYul/array_storage_push_empty_length_address.sol @@ -22,11 +22,11 @@ contract C { // gas legacy: 77730 // gas legacyOptimized: 77162 // set_get_length(uint256): 0xFF -> 0xFF -// gas irOptimized: 141805 +// gas irOptimized: 141799 // gas legacy: 678237 // gas legacyOptimized: 115104 // set_get_length(uint256): 0xFFF -> 0xFFF -// gas irOptimized: 1801672 +// gas irOptimized: 1801666 // gas legacy: 9873774 // gas legacyOptimized: 1398546 // set_get_length(uint256): 0xFFFFF -> FAILURE # Out-of-gas # diff --git a/test/libsolidity/semanticTests/viaYul/array_storage_push_pop.sol b/test/libsolidity/semanticTests/viaYul/array_storage_push_pop.sol index e802e3687b9a..25a2f5f9afc6 100644 --- a/test/libsolidity/semanticTests/viaYul/array_storage_push_pop.sol +++ b/test/libsolidity/semanticTests/viaYul/array_storage_push_pop.sol @@ -19,11 +19,11 @@ contract C { // gas legacy: 85822 // gas legacyOptimized: 83608 // set_get_length(uint256): 0xFF -> 0 -// gas irOptimized: 821881 +// gas irOptimized: 821875 // gas legacy: 810327 // gas legacyOptimized: 786258 // set_get_length(uint256): 0xFFF -> 0 -// gas irOptimized: 12841093 +// gas irOptimized: 12841087 // gas legacy: 12649059 // gas legacyOptimized: 12267870 // set_get_length(uint256): 0xFFFF -> FAILURE # Out-of-gas # diff --git a/test/libsolidity/semanticTests/viaYul/copy_struct_invalid_ir_bug.sol b/test/libsolidity/semanticTests/viaYul/copy_struct_invalid_ir_bug.sol index 05b7e668b481..f1a6f592b2a0 100644 --- a/test/libsolidity/semanticTests/viaYul/copy_struct_invalid_ir_bug.sol +++ b/test/libsolidity/semanticTests/viaYul/copy_struct_invalid_ir_bug.sol @@ -23,6 +23,6 @@ contract C { // compileViaYul: also // ---- // f() -> -// gas irOptimized: 112998 -// gas legacy: 112937 -// gas legacyOptimized: 112608 +// gas irOptimized: 112992 +// gas legacy: 112931 +// gas legacyOptimized: 112602 diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encode_convert_address_to_address_payable.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encode_convert_address_to_address_payable.sol new file mode 100644 index 000000000000..a4c823a8583c --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encode_convert_address_to_address_payable.sol @@ -0,0 +1,11 @@ +interface I { + function f(address payable) external; +} + +contract C { + function main() external view { + abi.encodeCall(I.f, (address(0))); + } +} +// ---- +// TypeError 5407: (136-148): Cannot implicitly convert component at position 0 from "address" to "address payable". diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encode_convert_function_pointer_to_different_function_pointer.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encode_convert_function_pointer_to_different_function_pointer.sol new file mode 100644 index 000000000000..7c570e29e06b --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encode_convert_function_pointer_to_different_function_pointer.sol @@ -0,0 +1,13 @@ +interface I { + function f(function (string calldata) external) external; +} + +contract C { + function g(string calldata) external {} + + function main() external view { + abi.encodeCall(I.f, (this.g)); + } +} +// ---- +// TypeError 5407: (201-209): Cannot implicitly convert component at position 0 from "function (string memory) external" to "function (string calldata) external". diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encode_convert_function_to_different_function.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encode_convert_function_to_different_function.sol new file mode 100644 index 000000000000..7a35bfa55320 --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encode_convert_function_to_different_function.sol @@ -0,0 +1,13 @@ +interface I { + function f(function (string calldata) external view returns (uint)) external; +} + +contract C { + function g(string memory) external {} + + function main() external view { + abi.encodeCall(I.f, (this.g)); + } +} +// ---- +// TypeError 5407: (219-227): Cannot implicitly convert component at position 0 from "function (string memory) external" to "function (string calldata) view external returns (uint256)". diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encode_convert_string_to_different_string.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encode_convert_string_to_different_string.sol new file mode 100644 index 000000000000..72efe4a07786 --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encode_convert_string_to_different_string.sol @@ -0,0 +1,12 @@ +interface I { + function f(string calldata) external; +} + +contract C { + string s; + function main() external view { + abi.encodeCall(I.f, (s)); + } +} +// ---- +// TypeError 5407: (150-153): Cannot implicitly convert component at position 0 from "string storage ref" to "string calldata". diff --git a/test/libsolidity/syntaxTests/bound/bound_to_struct.sol b/test/libsolidity/syntaxTests/bound/bound_to_struct.sol index 0e1cbddb87d2..59c8e2aa7def 100644 --- a/test/libsolidity/syntaxTests/bound/bound_to_struct.sol +++ b/test/libsolidity/syntaxTests/bound/bound_to_struct.sol @@ -7,4 +7,4 @@ contract C { using S for S; } // ---- -// TypeError 4357: (113-114): Library name expected. +// TypeError 4357: (113-114): Library name expected. If you want to attach a function, use '{...}'. diff --git a/test/libsolidity/syntaxTests/bound/interface_using_for.sol b/test/libsolidity/syntaxTests/bound/interface_using_for.sol index 727ff2c46ef4..41597101703d 100644 --- a/test/libsolidity/syntaxTests/bound/interface_using_for.sol +++ b/test/libsolidity/syntaxTests/bound/interface_using_for.sol @@ -7,4 +7,4 @@ interface I { function g() external; } // ---- -// TypeError 9088: (60-76): The "using for" directive is not allowed inside interfaces. +// SyntaxError 9088: (60-76): The "using for" directive is not allowed inside interfaces. diff --git a/test/libsolidity/syntaxTests/literals/ternary_operator_return_type_with_literal_arguments.sol b/test/libsolidity/syntaxTests/literals/ternary_operator_return_type_with_literal_arguments.sol new file mode 100644 index 000000000000..6a928c3addb4 --- /dev/null +++ b/test/libsolidity/syntaxTests/literals/ternary_operator_return_type_with_literal_arguments.sol @@ -0,0 +1,33 @@ +contract TestTernary +{ + function g() pure public + { + bool t = true; + bool f = false; + uint8 v255 = 255; + uint8 v63 = 63; + uint8 a; + + // Currently none of these should produce errors or warnings. + // The result of the operator is always a limited-precision integer, even if all arguments are literals. + + a = (t ? 63 : 255) + (f ? 63 : 255); + a = (t ? 0x3f : 0xff) + (f ? 0x3f : 0xff); + a = (t ? uint8(63) : 255) + (f ? 63 : uint8(255)); + a = (t ? v63 : 255) + (f ? 63 : v255); + + a = (true ? 63 : 255) + (false ? 63 : 255); + a = (true ? 0x3f : 0xff) + (false ? 0x3f : 0xff); + a = (true ? uint8(63) : 255) + (false ? 63 : uint8(255)); + a = (true ? v63 : 255) + (false ? 63 : v255); + + a = (t ? 63 : 255) - (f ? 63 : 255); + a = (t ? 63 : 255) * (f ? 63 : 255); + a = (t ? 63 : 255) / (f ? 63 : 255); + + a = (t ? (true ? 63 : 255) : (false ? 63 : 255)) + (f ? (t ? 63 : 255) : (f ? 63 : 255)); + a = uint8(t ? 63 : 255) + uint8(f ? 63 : 255); + + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/252_using_for_not_library.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/252_using_for_not_library.sol index 83839f368777..42de5ba411dc 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/252_using_for_not_library.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/252_using_for_not_library.sol @@ -3,4 +3,4 @@ contract C { using D for uint; } // ---- -// TypeError 4357: (38-39): Library name expected. +// TypeError 4357: (38-39): Library name expected. If you want to attach a function, use '{...}'. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/514_using_for_with_non_library.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/514_using_for_with_non_library.sol index ba141ce97003..940a3b071a83 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/514_using_for_with_non_library.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/514_using_for_with_non_library.sol @@ -7,4 +7,4 @@ library L { } } // ---- -// TypeError 4357: (120-121): Library name expected. +// TypeError 4357: (120-121): Library name expected. If you want to attach a function, use '{...}'. diff --git a/test/libsolidity/syntaxTests/specialFunctions/encodeCall_fail_args.sol b/test/libsolidity/syntaxTests/specialFunctions/encodeCall_fail_args.sol index a1c20f9bdeba..48372263f664 100644 --- a/test/libsolidity/syntaxTests/specialFunctions/encodeCall_fail_args.sol +++ b/test/libsolidity/syntaxTests/specialFunctions/encodeCall_fail_args.sol @@ -24,4 +24,4 @@ contract C { // TypeError 7788: (382-408): Expected 1 instead of 0 components for the tuple parameter. // TypeError 6219: (489-511): Expected two arguments: a function pointer followed by a tuple. // TypeError 7515: (597-628): Expected a tuple with 2 components instead of a single non-tuple parameter. -// TypeError 5407: (621-627): Cannot implicitly convert component at position 0 from "uint8[2]" to "int256". +// TypeError 5407: (621-627): Cannot implicitly convert component at position 0 from "uint8[2] memory" to "int256". diff --git a/test/libsolidity/syntaxTests/using/double_asterisk.sol b/test/libsolidity/syntaxTests/using/double_asterisk.sol new file mode 100644 index 000000000000..44cee5479778 --- /dev/null +++ b/test/libsolidity/syntaxTests/using/double_asterisk.sol @@ -0,0 +1,19 @@ +function id(uint x) pure returns (uint) { + return x; +} + +function zero(address) pure returns (address) { + return address(0); +} + +contract C { + using * for *; + function f(uint x) pure external returns (uint) { + return x.id(); + } + function g(address a) pure external returns (address) { + return a.zero(); + } +} +// ---- +// ParserError 2314: (156-157): Expected identifier but got '*' diff --git a/test/libsolidity/syntaxTests/using/file_level_inactive_after_import.sol b/test/libsolidity/syntaxTests/using/file_level_inactive_after_import.sol new file mode 100644 index 000000000000..219954238a1c --- /dev/null +++ b/test/libsolidity/syntaxTests/using/file_level_inactive_after_import.sol @@ -0,0 +1,22 @@ +==== Source: A ==== +function id(uint x) pure returns (uint) { + return x; +} +// we check that the effect of this directive is +// limited to this file. +using {id} for uint; + +function t() pure { + uint y = 2; + y = y.id(); +} + +==== Source: B ==== +import "A"; + +function f() pure { + uint y = 2; + y = y.id(); +} +// ---- +// TypeError 9582: (B:57-61): Member "id" not found or not visible after argument-dependent lookup in uint256. diff --git a/test/libsolidity/syntaxTests/using/free_functions_implicit_conversion.sol b/test/libsolidity/syntaxTests/using/free_functions_implicit_conversion.sol new file mode 100644 index 000000000000..9df5e9c2c1bc --- /dev/null +++ b/test/libsolidity/syntaxTests/using/free_functions_implicit_conversion.sol @@ -0,0 +1,6 @@ +function id(uint16 x) pure returns(uint16) { + return x; +} +contract C { + using {id} for uint8; +} diff --git a/test/libsolidity/syntaxTests/using/free_functions_implicit_conversion_err.sol b/test/libsolidity/syntaxTests/using/free_functions_implicit_conversion_err.sol new file mode 100644 index 000000000000..36f3f3032eff --- /dev/null +++ b/test/libsolidity/syntaxTests/using/free_functions_implicit_conversion_err.sol @@ -0,0 +1,8 @@ +function id(uint16 x) pure returns(uint16) { + return x; +} +contract C { + using {id} for uint256; +} +// ---- +// TypeError 3100: (85-87): The function "id" cannot be bound to the type "uint256" because the type cannot be implicitly converted to the first argument of the function ("uint16"). diff --git a/test/libsolidity/syntaxTests/using/free_functions_non_unique_err.sol b/test/libsolidity/syntaxTests/using/free_functions_non_unique_err.sol new file mode 100644 index 000000000000..7536dff07f76 --- /dev/null +++ b/test/libsolidity/syntaxTests/using/free_functions_non_unique_err.sol @@ -0,0 +1,12 @@ +function id(int8 x) pure returns(int8) { + return x; +} +function id(uint256 x) pure returns(uint256) { + return x; +} + +contract C { + using {id} for uint256; +} +// ---- +// DeclarationError 7920: (145-147): Identifier not found or not unique. diff --git a/test/libsolidity/syntaxTests/using/free_overloads.sol b/test/libsolidity/syntaxTests/using/free_overloads.sol new file mode 100644 index 000000000000..28a8e69ed1ce --- /dev/null +++ b/test/libsolidity/syntaxTests/using/free_overloads.sol @@ -0,0 +1,10 @@ +function f(uint8 x) pure returns (uint) { + return x; +} +function f(int8 storage x) pure returns (int) { + return x[0]; +} +using {f} for uint8; +using {f} for int; +// ---- +// DeclarationError 7920: (132-133): Identifier not found or not unique. diff --git a/test/libsolidity/syntaxTests/using/free_overloads_array.sol b/test/libsolidity/syntaxTests/using/free_overloads_array.sol new file mode 100644 index 000000000000..91b807397112 --- /dev/null +++ b/test/libsolidity/syntaxTests/using/free_overloads_array.sol @@ -0,0 +1,9 @@ +function f(uint x, uint[] y) pure returns (uint) { + return x; +} +function f(uint x, uint y) pure returns (int) { + return x; +} +using {f} for uint; +// ---- +// DeclarationError 7920: (138-139): Identifier not found or not unique. diff --git a/test/libsolidity/syntaxTests/using/free_reference_type.sol b/test/libsolidity/syntaxTests/using/free_reference_type.sol new file mode 100644 index 000000000000..833b78266e97 --- /dev/null +++ b/test/libsolidity/syntaxTests/using/free_reference_type.sol @@ -0,0 +1,11 @@ +function f(uint[] memory x) pure returns (uint) { + return x[0]; +} +function g(uint[] storage x) view returns (uint) { + return x[0]; +} +function h(uint[] calldata x) pure returns (uint) { + return x[0]; +} +using {f, g, h} for uint[]; +// ---- diff --git a/test/libsolidity/syntaxTests/using/global_and_local.sol b/test/libsolidity/syntaxTests/using/global_and_local.sol new file mode 100644 index 000000000000..7af04c0a602b --- /dev/null +++ b/test/libsolidity/syntaxTests/using/global_and_local.sol @@ -0,0 +1,21 @@ +==== Source: A ==== +using {f} for S global; +struct S { uint x; } +function gen() pure returns (S memory) {} +function f(S memory _x) pure returns (uint) { return _x.x; } +==== Source: B ==== +contract C { + using {fun} for S; + // Adds the same function again with the same name, + // so it's fine. + using {A.f} for S; + + function test() pure public + { + uint p = g().f(); + p = g().fun(); + } +} +import {gen as g, f as fun, S} from "A"; +import "A" as A; +// ---- \ No newline at end of file diff --git a/test/libsolidity/syntaxTests/using/global_for_asterisk.sol b/test/libsolidity/syntaxTests/using/global_for_asterisk.sol new file mode 100644 index 000000000000..b5f6d88272fb --- /dev/null +++ b/test/libsolidity/syntaxTests/using/global_for_asterisk.sol @@ -0,0 +1,5 @@ +using {f} for * global; +function f(uint) pure{} +// ---- +// SyntaxError 8118: (0-23): The type has to be specified explicitly at file level (cannot use '*'). +// SyntaxError 2854: (0-23): Can only globally bind functions to specific types. diff --git a/test/libsolidity/syntaxTests/using/global_for_non_user_defined.sol b/test/libsolidity/syntaxTests/using/global_for_non_user_defined.sol new file mode 100644 index 000000000000..051874abc9bc --- /dev/null +++ b/test/libsolidity/syntaxTests/using/global_for_non_user_defined.sol @@ -0,0 +1,4 @@ +using {f} for uint global; +function f(uint) pure{} +// ---- +// TypeError 8841: (0-26): Can only use "global" with user-defined types. diff --git a/test/libsolidity/syntaxTests/using/global_for_type_defined_elsewhere.sol b/test/libsolidity/syntaxTests/using/global_for_type_defined_elsewhere.sol new file mode 100644 index 000000000000..232ffafade9d --- /dev/null +++ b/test/libsolidity/syntaxTests/using/global_for_type_defined_elsewhere.sol @@ -0,0 +1,7 @@ +using {f} for L.S global; +function f(L.S memory) pure{} +library L { + struct S { uint x; } +} +// ---- +// TypeError 4117: (0-25): Can only use "global" with types defined in the same source unit at file level. diff --git a/test/libsolidity/syntaxTests/using/global_for_type_from_other_file.sol b/test/libsolidity/syntaxTests/using/global_for_type_from_other_file.sol new file mode 100644 index 000000000000..458a644e9a85 --- /dev/null +++ b/test/libsolidity/syntaxTests/using/global_for_type_from_other_file.sol @@ -0,0 +1,14 @@ +==== Source: A ==== +struct S { uint x; } +==== Source: B ==== + +using {f} for S global; +using {f} for A.S global; + +function f(S memory) pure{} + +import {S} from "A"; +import "A" as A; +// ---- +// TypeError 4117: (B:1-24): Can only use "global" with types defined in the same source unit at file level. +// TypeError 4117: (B:25-50): Can only use "global" with types defined in the same source unit at file level. diff --git a/test/libsolidity/syntaxTests/using/global_inside_contract.sol b/test/libsolidity/syntaxTests/using/global_inside_contract.sol new file mode 100644 index 000000000000..edaeea92231e --- /dev/null +++ b/test/libsolidity/syntaxTests/using/global_inside_contract.sol @@ -0,0 +1,7 @@ +contract C { + using {f} for uint global; +} +function f(uint) pure{} +// ---- +// SyntaxError 3367: (17-43): "global" can only be used at file level. +// TypeError 8841: (17-43): Can only use "global" with user-defined types. diff --git a/test/libsolidity/syntaxTests/using/global_local_clash.sol b/test/libsolidity/syntaxTests/using/global_local_clash.sol new file mode 100644 index 000000000000..1d149417f2ff --- /dev/null +++ b/test/libsolidity/syntaxTests/using/global_local_clash.sol @@ -0,0 +1,21 @@ +==== Source: A ==== +using {f} for S global; +struct S { uint x; } +function gen() pure returns (S memory) {} +function f(S memory _x) pure returns (uint) { return _x.x; } +function f1(S memory _x) pure returns (uint) { return _x.x + 1; } +==== Source: B ==== +contract C { + // Here, f points to f1, so we end up with two different functions + // bound as S.f + using {f} for S; + + function test() pure public + { + uint p = g().f(); + } +} +import {gen as g, f1 as f, S} from "A"; +import "A" as A; +// ---- +// TypeError 6675: (B:181-186): Member "f" not unique after argument-dependent lookup in struct S memory. diff --git a/test/libsolidity/syntaxTests/using/global_nonglobal.sol b/test/libsolidity/syntaxTests/using/global_nonglobal.sol new file mode 100644 index 000000000000..972a34a8d1b2 --- /dev/null +++ b/test/libsolidity/syntaxTests/using/global_nonglobal.sol @@ -0,0 +1,17 @@ +==== Source: A ==== +using {f} for S global; +using {g} for S; +struct S { uint x; } +function gen() pure returns (S memory) {} +function f(S memory _x) pure { _x.g(); } +function g(S memory _x) pure { } +==== Source: B ==== +import "A"; +function test() pure +{ + gen().f(); + gen().g(); +} + +// ---- +// TypeError 9582: (B:54-61): Member "g" not found or not visible after argument-dependent lookup in struct S memory. diff --git a/test/libsolidity/syntaxTests/using/global_working.sol b/test/libsolidity/syntaxTests/using/global_working.sol new file mode 100644 index 000000000000..9447202451fb --- /dev/null +++ b/test/libsolidity/syntaxTests/using/global_working.sol @@ -0,0 +1,15 @@ +==== Source: A ==== +using {f} for S global; +// this should not conflict +using {f} for S; +struct S { uint x; } +function gen() pure returns (S memory) {} +function f(S memory _x) pure returns (uint) { return _x.x; } +==== Source: B ==== +function test() pure +{ + uint p = g().f(); + p++; +} +import {gen as g} from "A"; +// ---- \ No newline at end of file diff --git a/test/libsolidity/syntaxTests/using/library_import_as.sol b/test/libsolidity/syntaxTests/using/library_import_as.sol new file mode 100644 index 000000000000..7c3fc2891da9 --- /dev/null +++ b/test/libsolidity/syntaxTests/using/library_import_as.sol @@ -0,0 +1,16 @@ +==== Source: A ==== +library L { + function id(uint x) pure internal returns (uint) { + return x; + } +} + +==== Source: B ==== +import {L as M} from "A"; + +contract C { + using M for uint; + function f(uint x) public pure returns (uint) { + return x.id(); + } +} diff --git a/test/libsolidity/syntaxTests/using/library_non_free_external_function_err.sol b/test/libsolidity/syntaxTests/using/library_non_free_external_function_err.sol new file mode 100644 index 000000000000..76d53cf90cf4 --- /dev/null +++ b/test/libsolidity/syntaxTests/using/library_non_free_external_function_err.sol @@ -0,0 +1,14 @@ +library L { + function id_ext(uint x) external returns(uint) { + return x; + } +} + +contract C { + using L.id_ext for uint; + function f(uint x) external { + x.id_ext(); + } +} +// ---- +// DeclarationError 7920: (115-123): Identifier not found or not unique. diff --git a/test/libsolidity/syntaxTests/using/library_non_free_function.sol b/test/libsolidity/syntaxTests/using/library_non_free_function.sol new file mode 100644 index 000000000000..2fdb471aba70 --- /dev/null +++ b/test/libsolidity/syntaxTests/using/library_non_free_function.sol @@ -0,0 +1,13 @@ +library L { + function id(uint x) internal pure returns(uint) { + return x; + } +} + +contract C { + using {L.id} for uint; + function f(uint x) external pure { + x.id(); + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/using/module_1.sol b/test/libsolidity/syntaxTests/using/module_1.sol new file mode 100644 index 000000000000..a2d3b9f992ac --- /dev/null +++ b/test/libsolidity/syntaxTests/using/module_1.sol @@ -0,0 +1,12 @@ +==== Source: A ==== +function id(uint x) pure returns (uint) { + return x; +} + +==== Source: B ==== +import "A" as M; +contract C { + using M for uint; +} +// ---- +// TypeError 4357: (B:40-41): Library name expected. If you want to attach a function, use '{...}'. diff --git a/test/libsolidity/syntaxTests/using/module_2.sol b/test/libsolidity/syntaxTests/using/module_2.sol new file mode 100644 index 000000000000..92420822250a --- /dev/null +++ b/test/libsolidity/syntaxTests/using/module_2.sol @@ -0,0 +1,14 @@ +==== Source: A ==== +function id(uint x) pure returns (uint) { + return x; +} + +==== Source: B ==== +import {id as Id} from "A"; + +contract C { + using { Id } for uint; + function f(uint x) public pure returns (uint) { + return x.Id(); + } +} diff --git a/test/libsolidity/syntaxTests/using/module_3.sol b/test/libsolidity/syntaxTests/using/module_3.sol new file mode 100644 index 000000000000..f017363e67cd --- /dev/null +++ b/test/libsolidity/syntaxTests/using/module_3.sol @@ -0,0 +1,14 @@ +==== Source: A ==== +function id(uint x) pure returns (uint) { + return x; +} + +==== Source: B ==== +import "A" as M; + +contract C { + using {M.id} for uint; + function f(uint x) public pure returns (uint) { + return x.id(); + } +} diff --git a/test/libsolidity/syntaxTests/using/module_identifier_not_found.sol b/test/libsolidity/syntaxTests/using/module_identifier_not_found.sol new file mode 100644 index 000000000000..ef1688b22915 --- /dev/null +++ b/test/libsolidity/syntaxTests/using/module_identifier_not_found.sol @@ -0,0 +1,13 @@ +==== Source: A ==== +function id(uint x) pure returns (uint) { + return x; +} + +==== Source: B ==== +import "A" as M; + +contract C { + using { id } for uint; +} +// ---- +// DeclarationError 7920: (B:43-45): Identifier not found or not unique. diff --git a/test/libsolidity/syntaxTests/using/using_contract_err.sol b/test/libsolidity/syntaxTests/using/using_contract_err.sol new file mode 100644 index 000000000000..e216e4cfc420 --- /dev/null +++ b/test/libsolidity/syntaxTests/using/using_contract_err.sol @@ -0,0 +1,13 @@ +contract C { + function f(uint) external { + } +} +interface I { + function f(uint) external; +} + +contract Test { + using C for uint; +} +// ---- +// TypeError 4357: (127-128): Library name expected. If you want to attach a function, use '{...}'. diff --git a/test/libsolidity/syntaxTests/using/using_empty_list_err.sol b/test/libsolidity/syntaxTests/using/using_empty_list_err.sol new file mode 100644 index 000000000000..b8b9cb9a7646 --- /dev/null +++ b/test/libsolidity/syntaxTests/using/using_empty_list_err.sol @@ -0,0 +1,5 @@ +contract C { + using {} for uint; +} +// ---- +// ParserError 2314: (24-25): Expected identifier but got '}' diff --git a/test/libsolidity/syntaxTests/using/using_empty_list_file_level.sol b/test/libsolidity/syntaxTests/using/using_empty_list_file_level.sol new file mode 100644 index 000000000000..b1dc8b706837 --- /dev/null +++ b/test/libsolidity/syntaxTests/using/using_empty_list_file_level.sol @@ -0,0 +1,3 @@ +using {} for uint; +// ---- +// ParserError 2314: (7-8): Expected identifier but got '}' diff --git a/test/libsolidity/syntaxTests/using/using_for_ast_file_level.sol b/test/libsolidity/syntaxTests/using/using_for_ast_file_level.sol new file mode 100644 index 000000000000..2b5d6a0dd63a --- /dev/null +++ b/test/libsolidity/syntaxTests/using/using_for_ast_file_level.sol @@ -0,0 +1,7 @@ +function id(uint x) pure returns (uint) { + return x; +} + +using {id} for *; +// ---- +// SyntaxError 8118: (59-76): The type has to be specified explicitly at file level (cannot use '*'). diff --git a/test/libsolidity/syntaxTests/using/using_free_functions.sol b/test/libsolidity/syntaxTests/using/using_free_functions.sol new file mode 100644 index 000000000000..5180cfd2012c --- /dev/null +++ b/test/libsolidity/syntaxTests/using/using_free_functions.sol @@ -0,0 +1,16 @@ +function id(uint x) pure returns (uint) { + return x; +} + +function zero(uint) pure returns (uint) { + return 0; +} +using {id} for uint; +contract C { + using {zero} for uint; + + function g(uint z) pure external { + z.zero(); + z.id(); + } +} diff --git a/test/libsolidity/syntaxTests/using/using_free_no_parameters_err.sol b/test/libsolidity/syntaxTests/using/using_free_no_parameters_err.sol new file mode 100644 index 000000000000..e03ba5d10dc0 --- /dev/null +++ b/test/libsolidity/syntaxTests/using/using_free_no_parameters_err.sol @@ -0,0 +1,7 @@ +function one() pure returns(uint) { + return 1; +} + +using {one} for uint; +// ---- +// TypeError 4731: (60-63): The function "one" does not have any parameters, and therefore cannot be bound to the type "uint256". diff --git a/test/libsolidity/syntaxTests/using/using_functions_with_ast.sol b/test/libsolidity/syntaxTests/using/using_functions_with_ast.sol new file mode 100644 index 000000000000..62f8e4736f9c --- /dev/null +++ b/test/libsolidity/syntaxTests/using/using_functions_with_ast.sol @@ -0,0 +1,7 @@ +function f(uint) {} + +contract C { + using {f} for *; +} +// ---- +// SyntaxError 3349: (38-54): The type has to be specified explicitly when attaching specific functions. diff --git a/test/libsolidity/syntaxTests/using/using_lhs_asterisk.sol b/test/libsolidity/syntaxTests/using/using_lhs_asterisk.sol new file mode 100644 index 000000000000..07b607004c2d --- /dev/null +++ b/test/libsolidity/syntaxTests/using/using_lhs_asterisk.sol @@ -0,0 +1,3 @@ +using * for uint; +// ---- +// ParserError 2314: (6-7): Expected identifier but got '*' diff --git a/test/libsolidity/syntaxTests/using/using_lhs_asterisk_contract.sol b/test/libsolidity/syntaxTests/using/using_lhs_asterisk_contract.sol new file mode 100644 index 000000000000..67eee5862e0e --- /dev/null +++ b/test/libsolidity/syntaxTests/using/using_lhs_asterisk_contract.sol @@ -0,0 +1,5 @@ +contract C { + using * for uint; +} +// ---- +// ParserError 2314: (23-24): Expected identifier but got '*' diff --git a/test/libsolidity/syntaxTests/using/using_library_ast_file_level.sol b/test/libsolidity/syntaxTests/using/using_library_ast_file_level.sol new file mode 100644 index 000000000000..dfc0b916e9df --- /dev/null +++ b/test/libsolidity/syntaxTests/using/using_library_ast_file_level.sol @@ -0,0 +1,4 @@ +library L { } +using L for *; +// ---- +// SyntaxError 8118: (14-28): The type has to be specified explicitly at file level (cannot use '*'). diff --git a/test/libsolidity/syntaxTests/using/using_library_file_level.sol b/test/libsolidity/syntaxTests/using/using_library_file_level.sol new file mode 100644 index 000000000000..c4de282c48a8 --- /dev/null +++ b/test/libsolidity/syntaxTests/using/using_library_file_level.sol @@ -0,0 +1,3 @@ +library L { } +using L for uint; +// ---- diff --git a/test/libsolidity/syntaxTests/using/using_non_free_function_err.sol b/test/libsolidity/syntaxTests/using/using_non_free_function_err.sol new file mode 100644 index 000000000000..df3b3f65faf3 --- /dev/null +++ b/test/libsolidity/syntaxTests/using/using_non_free_function_err.sol @@ -0,0 +1,9 @@ +contract C { + using {f, g} for uint; + + function f(uint) internal { } + function g(uint) public { } +} +// ---- +// TypeError 4167: (24-25): Only file-level functions and library functions can be bound to a type in a "using" statement +// TypeError 4167: (27-28): Only file-level functions and library functions can be bound to a type in a "using" statement diff --git a/test/libsolidity/syntaxTests/using/using_non_function.sol b/test/libsolidity/syntaxTests/using/using_non_function.sol new file mode 100644 index 000000000000..32d97345b670 --- /dev/null +++ b/test/libsolidity/syntaxTests/using/using_non_function.sol @@ -0,0 +1,6 @@ +contract C { + function() internal pure x; + using {x} for uint; +} +// ---- +// TypeError 8187: (56-57): Expected function name. diff --git a/test/libsolidity/util/BytesUtils.cpp b/test/libsolidity/util/BytesUtils.cpp index 49482a6c6ee6..f2a5db7af29a 100644 --- a/test/libsolidity/util/BytesUtils.cpp +++ b/test/libsolidity/util/BytesUtils.cpp @@ -220,7 +220,7 @@ string BytesUtils::formatString(bytes const& _bytes, size_t _cutOff) if (isPrint(static_cast(v))) os << v; else - os << "\\x" << toHex(v, HexCase::Lower); + os << "\\x" << util::toHex(v, HexCase::Lower); } } os << "\""; diff --git a/test/libsolidity/util/TestFileParser.cpp b/test/libsolidity/util/TestFileParser.cpp index dbaf52604d3c..11cfdbb86730 100644 --- a/test/libsolidity/util/TestFileParser.cpp +++ b/test/libsolidity/util/TestFileParser.cpp @@ -16,6 +16,9 @@ */ // SPDX-License-Identifier: GPL-3.0 + +#include + #include #include @@ -34,6 +37,7 @@ #include using namespace solidity; +using namespace solidity::util; using namespace solidity::frontend; using namespace solidity::frontend::test; using namespace std; @@ -763,7 +767,6 @@ string TestFileParser::Scanner::scanString() char TestFileParser::Scanner::scanHexPart() { auto toLower = [](char _c) -> char { return tolower(_c, locale::classic()); }; - auto isDigit = [](char _c) -> bool { return isdigit(_c, locale::classic()); }; advance(); // skip 'x' diff --git a/test/libsolidity/util/TestFunctionCall.cpp b/test/libsolidity/util/TestFunctionCall.cpp index 43805c8f9934..c51dbec97123 100644 --- a/test/libsolidity/util/TestFunctionCall.cpp +++ b/test/libsolidity/util/TestFunctionCall.cpp @@ -324,7 +324,7 @@ string TestFunctionCall::formatRawParameters( for (auto const c: param.rawString) // NOTE: Even though we have a toHex() overload specifically for uint8_t, the compiler // chooses the one for bytes if the second argument is omitted. - os << (c >= ' ' ? string(1, c) : "\\x" + toHex(static_cast(c), HexCase::Lower)); + os << (c >= ' ' ? string(1, c) : "\\x" + util::toHex(static_cast(c), HexCase::Lower)); if (¶m != &_params.back()) os << ", "; } diff --git a/test/libyul/EVMCodeTransformTest.cpp b/test/libyul/EVMCodeTransformTest.cpp index 8986acc1b09a..679493f35fc0 100644 --- a/test/libyul/EVMCodeTransformTest.cpp +++ b/test/libyul/EVMCodeTransformTest.cpp @@ -65,7 +65,7 @@ TestCase::TestResult EVMCodeTransformTest::run(ostream& _stream, string const& _ return TestResult::FatalError; } - evmasm::Assembly assembly; + evmasm::Assembly assembly{false, {}}; EthAssemblyAdapter adapter(assembly); EVMObjectCompiler::compile( *stack.parserResult(), diff --git a/test/libyul/KnowledgeBaseTest.cpp b/test/libyul/KnowledgeBaseTest.cpp index 03cc4cd8d5e1..ec2f0313d18e 100644 --- a/test/libyul/KnowledgeBaseTest.cpp +++ b/test/libyul/KnowledgeBaseTest.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -59,7 +58,7 @@ class KnowledgeBaseTest for (auto const& [name, expression]: m_ssaValues.values()) m_values[name].value = expression; - return KnowledgeBase(m_dialect, m_values); + return KnowledgeBase(m_dialect, [this](YulString _var) { return util::valueOrNullptr(m_values, _var); }); } EVMDialect m_dialect{EVMVersion{}, true}; diff --git a/test/libyul/YulOptimizerTestCommon.cpp b/test/libyul/YulOptimizerTestCommon.cpp index e7711f5866e1..60826665a0fc 100644 --- a/test/libyul/YulOptimizerTestCommon.cpp +++ b/test/libyul/YulOptimizerTestCommon.cpp @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -237,6 +238,15 @@ YulOptimizerTestCommon::YulOptimizerTestCommon( ForLoopInitRewriter::run(*m_context, *m_ast); UnusedAssignEliminator::run(*m_context, *m_ast); }}, + {"unusedStoreEliminator", [&]() { + disambiguate(); + ForLoopInitRewriter::run(*m_context, *m_ast); + ExpressionSplitter::run(*m_context, *m_ast); + SSATransform::run(*m_context, *m_ast); + UnusedStoreEliminator::run(*m_context, *m_ast); + SSAReverser::run(*m_context, *m_ast); + ExpressionJoiner::run(*m_context, *m_ast); + }}, {"equalStoreEliminator", [&]() { disambiguate(); FunctionHoister::run(*m_context, *m_ast); diff --git a/test/libyul/evmCodeTransform/pops_in_reverting_branch.yul b/test/libyul/evmCodeTransform/pops_in_reverting_branch.yul new file mode 100644 index 000000000000..78bf0a168268 --- /dev/null +++ b/test/libyul/evmCodeTransform/pops_in_reverting_branch.yul @@ -0,0 +1,41 @@ +object "main" { + code { + let a := calldataload(0) + let b := calldataload(32) + if calldataload(64) { + revert(0,0) + } + sstore(b, a) + } +} +// ==== +// stackOptimization: true +// ---- +// /* "":51:52 */ +// 0x00 +// /* "":38:53 */ +// calldataload +// /* "":81:83 */ +// 0x20 +// /* "":68:84 */ +// calldataload +// /* "":106:108 */ +// 0x40 +// /* "":93:109 */ +// calldataload +// /* "":90:139 */ +// tag_1 +// jumpi +// /* "":22:160 */ +// tag_2: +// /* "":145:157 */ +// sstore +// /* "":22:160 */ +// stop +// /* "":110:139 */ +// tag_1: +// /* "":130:131 */ +// 0x00 +// /* "":121:132 */ +// dup1 +// revert diff --git a/test/libyul/evmCodeTransform/stackReuse/if.yul b/test/libyul/evmCodeTransform/stackReuse/if.yul index cf0b2a044b0f..cee19ab93fdc 100644 --- a/test/libyul/evmCodeTransform/stackReuse/if.yul +++ b/test/libyul/evmCodeTransform/stackReuse/if.yul @@ -13,8 +13,6 @@ // jumpi // /* "":55:107 */ // tag_2: -// /* "":95:105 */ -// pop // /* "":104:105 */ // 0x03 // /* "":55:107 */ diff --git a/test/libyul/yulOptimizerTests/fullSuite/extcodelength.yul b/test/libyul/yulOptimizerTests/fullSuite/extcodelength.yul new file mode 100644 index 000000000000..436f5d5fafc4 --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSuite/extcodelength.yul @@ -0,0 +1,40 @@ +{ + let _1 := 0 + let value := calldataload(4) + if iszero(eq(value, and(value, sub(shl(160, 1), 1)))) { revert(_1, _1) } + let length := extcodesize(value) + let _2 := 0xffffffffffffffff + if gt(length, _2) { revert(0, 0) } + let _3 := not(31) + let memPtr := mload(64) + let newFreePtr := add(memPtr, and(add(and(add(length, 31), _3), 63), _3)) + if or(gt(newFreePtr, _2), lt(newFreePtr, memPtr)) { revert(0, 0) } + mstore(64, newFreePtr) + mstore(memPtr, length) + + // We aim to optimize this out. + extcodecopy(value, add(memPtr, 32), _1, length) + sstore(_1, mload(memPtr)) +} +// ==== +// EVMVersion: >byzantium +// ---- +// step: fullSuite +// +// { +// { +// let value := calldataload(4) +// if iszero(eq(value, and(value, sub(shl(160, 1), 1)))) { revert(0, 0) } +// let length := extcodesize(value) +// let _1 := 0xffffffffffffffff +// if gt(length, _1) { revert(0, 0) } +// let memPtr := mload(64) +// let _2 := not(31) +// let newFreePtr := add(memPtr, and(add(and(add(length, 31), _2), 63), _2)) +// if or(gt(newFreePtr, _1), lt(newFreePtr, memPtr)) { revert(0, 0) } +// mstore(64, newFreePtr) +// mstore(memPtr, length) +// extcodecopy(value, add(memPtr, 32), 0, length) +// sstore(0, mload(memPtr)) +// } +// } diff --git a/test/libyul/yulOptimizerTests/fullSuite/medium.yul b/test/libyul/yulOptimizerTests/fullSuite/medium.yul index 41b77c115710..9a6381d79913 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/medium.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/medium.yul @@ -23,13 +23,7 @@ // // { // { -// let p := mload(0x40) -// mstore(0x40, add(p, 0x20)) -// mstore(0x40, add(p, 96)) -// let p_1 := add(p, 128) -// mstore(p_1, 2) -// mstore(0x40, 0x20) -// sstore(0, p_1) +// sstore(0, add(mload(0x40), 128)) // sstore(1, 0x20) // } // } diff --git a/test/libyul/yulOptimizerTests/fullSuite/remove_redundant_assignments_in_switch.yul b/test/libyul/yulOptimizerTests/fullSuite/remove_redundant_assignments_in_switch.yul index a0ac5c36d292..31766132539b 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/remove_redundant_assignments_in_switch.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/remove_redundant_assignments_in_switch.yul @@ -15,6 +15,5 @@ // case 0 { } // case 1 { } // default { invalid() } -// mstore(1, 1) // } // } diff --git a/test/libyul/yulOptimizerTests/fullSuite/stack_compressor_msize.yul b/test/libyul/yulOptimizerTests/fullSuite/stack_compressor_msize.yul index 13683e8e6a67..75e2ff4c2010 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/stack_compressor_msize.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/stack_compressor_msize.yul @@ -52,9 +52,9 @@ // pop(keccak256(gcd(_3, _2), or(gt(not(gcd(_3, _2)), _1), _1))) // mstore(lt(or(gt(_1, or(or(gt(or(or(or(gt(or(gt(_6, _9), _1), _8), _7), _5), _1), _1), _4), _1)), _1), _1), _1) // sstore(not(gcd(_3, _2)), _1) -// sstore(0, 0) // sstore(2, _1) // extcodecopy(_1, msize(), _1, _1) +// sstore(0, 0) // sstore(3, _1) // } // function gcd(_a, _b) -> out diff --git a/test/libyul/yulOptimizerTests/fullSuite/static_array_slot_computation.yul b/test/libyul/yulOptimizerTests/fullSuite/static_array_slot_computation.yul index c5f4aa466c32..72c09d3dc37b 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/static_array_slot_computation.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/static_array_slot_computation.yul @@ -39,7 +39,6 @@ // mstore(4, 0x32) // revert(_1, 0x24) // } -// mstore(_1, _1) // sstore(0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56d, 0x05) // } // } diff --git a/test/libyul/yulOptimizerTests/fullSuite/storage.yul b/test/libyul/yulOptimizerTests/fullSuite/storage.yul index 7b3360847e18..a60b3d3486ea 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/storage.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/storage.yul @@ -8,7 +8,6 @@ // // { // { -// sstore(4, 5) // sstore(4, 3) // sstore(8, 3) // } diff --git a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner.yul b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner.yul index b7f0b4afbf80..6f82ab27a6d8 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner.yul @@ -20,7 +20,6 @@ // { // { // let out1, out2 := foo(sload(32)) -// sstore(0, out1) // sstore(0, out2) // let out1_1, out2_1 := foo(sload(8)) // } diff --git a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_loop.yul b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_loop.yul index ee648f80f994..7955ee12eaed 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_loop.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_loop.yul @@ -18,9 +18,9 @@ // { // { // f() -// sstore(0, 1) // f() // f() +// sstore(0, 1) // } // function f() // { diff --git a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_recursion.yul b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_recursion.yul index c3b75e84ee59..92d251cabe1a 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_recursion.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_recursion.yul @@ -18,7 +18,6 @@ // { // let x, y, z := f() // sstore(0, x) -// sstore(1, y) // sstore(1, z) // } // function f() -> x, y, z diff --git a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_return.yul b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_return.yul index 14f0137cb162..b066d998bafe 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_return.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_return.yul @@ -22,8 +22,6 @@ // { // { // let out1, out2 := foo(sload(32)) -// sstore(0, out1) -// sstore(0, out2) // sstore(0, 0) // let out1_1, out2_1 := foo(sload(8)) // } diff --git a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_simple.yul b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_simple.yul index 68620cc96b80..785840baa372 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_simple.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_simple.yul @@ -16,9 +16,9 @@ // { // { // f() -// sstore(0, 1) // f() // f() +// sstore(0, 1) // } // function f() // { diff --git a/test/libyul/yulOptimizerTests/stackCompressor/inlineInFunction.yul b/test/libyul/yulOptimizerTests/stackCompressor/inlineInFunction.yul index 35dfa5343d2d..a51c39f4f3b7 100644 --- a/test/libyul/yulOptimizerTests/stackCompressor/inlineInFunction.yul +++ b/test/libyul/yulOptimizerTests/stackCompressor/inlineInFunction.yul @@ -11,7 +11,6 @@ // step: stackCompressor // // { -// { let x := 8 } // function f() // { // mstore(calldataload(calldataload(9)), add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(calldataload(calldataload(9)), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)) diff --git a/test/libyul/yulOptimizerTests/unusedStoreEliminator/call_does_not_need_to_write.yul b/test/libyul/yulOptimizerTests/unusedStoreEliminator/call_does_not_need_to_write.yul new file mode 100644 index 000000000000..eeff779f85e0 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedStoreEliminator/call_does_not_need_to_write.yul @@ -0,0 +1,24 @@ +{ + mstore(0, 1) + let x := call( + 0, + 0, + 0, + 0, + 0, + 0, + 0x32 // length is only a max length, so there is no guarantee that the mstore above is overwritten. + ) + sstore(0, mload(0)) +} + +// ---- +// step: unusedStoreEliminator +// +// { +// { +// mstore(0, 1) +// let x := call(0, 0, 0, 0, 0, 0, 0x32) +// sstore(0, mload(0)) +// } +// } diff --git a/test/libyul/yulOptimizerTests/unusedStoreEliminator/covering_calldatacopy.yul b/test/libyul/yulOptimizerTests/unusedStoreEliminator/covering_calldatacopy.yul new file mode 100644 index 000000000000..7fd227089b83 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedStoreEliminator/covering_calldatacopy.yul @@ -0,0 +1,59 @@ +{ + let start := calldataload(0x10) + if calldataload(0) { + // not covered + mstore(add(start, 2), 7) + calldatacopy(start, 0, 0x20) + } + if calldataload(1) { + // covered + mstore(add(start, 2), 9) + calldatacopy(add(start, 1), 0, 0x21) + } + if calldataload(2) { + // covered + mstore8(add(start, 2), 7) + calldatacopy(start, 0, 3) + } + if calldataload(3) { + // not covered + mstore8(add(start, 3), 7) + calldatacopy(start, 0, 3) + } + sstore(0, keccak256(start, 0x40)) +} +// ---- +// step: unusedStoreEliminator +// +// { +// { +// let start := calldataload(0x10) +// if calldataload(0) +// { +// let _4 := 7 +// mstore(add(start, 2), _4) +// calldatacopy(start, 0, 0x20) +// } +// if calldataload(1) +// { +// let _11 := 9 +// mstore(add(start, 2), _11) +// let _14 := 0x21 +// let _15 := 0 +// calldatacopy(add(start, 1), _15, _14) +// } +// if calldataload(2) +// { +// let _20 := 7 +// mstore8(add(start, 2), _20) +// calldatacopy(start, 0, 3) +// } +// if calldataload(3) +// { +// let _27 := 7 +// mstore8(add(start, 3), _27) +// calldatacopy(start, 0, 3) +// } +// sstore(0, keccak256(start, 0x40)) +// } +// } diff --git a/test/libyul/yulOptimizerTests/unusedStoreEliminator/covering_calldatacopy_fixed.yul b/test/libyul/yulOptimizerTests/unusedStoreEliminator/covering_calldatacopy_fixed.yul new file mode 100644 index 000000000000..47e0b95fa3a3 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedStoreEliminator/covering_calldatacopy_fixed.yul @@ -0,0 +1,53 @@ +{ + if calldataload(0) { + // not covered + mstore(2, 7) + calldatacopy(0, 0, 0x20) + } + if calldataload(1) { + // covered + mstore(2, 9) + calldatacopy(1, 0, 0x21) + } + if calldataload(2) { + // covered + mstore8(2, 7) + calldatacopy(0, 0, 3) + } + if calldataload(3) { + // not covered + mstore8(3, 7) + calldatacopy(0, 0, 3) + } + sstore(0, keccak256(0, 0x40)) +} +// ---- +// step: unusedStoreEliminator +// +// { +// { +// if calldataload(0) +// { +// mstore(2, 7) +// calldatacopy(0, 0, 0x20) +// } +// if calldataload(1) +// { +// let _10 := 9 +// let _11 := 2 +// calldatacopy(1, 0, 0x21) +// } +// if calldataload(2) +// { +// let _17 := 7 +// let _18 := 2 +// calldatacopy(0, 0, 3) +// } +// if calldataload(3) +// { +// mstore8(3, 7) +// calldatacopy(0, 0, 3) +// } +// sstore(0, keccak256(0, 0x40)) +// } +// } diff --git a/test/libyul/yulOptimizerTests/unusedStoreEliminator/create.yul b/test/libyul/yulOptimizerTests/unusedStoreEliminator/create.yul new file mode 100644 index 000000000000..c3183d9ec83b --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedStoreEliminator/create.yul @@ -0,0 +1,17 @@ +{ + let x := 5 + sstore(x, 10) + pop(create(0, 0, 0)) + sstore(x, 20) +} +// ---- +// step: unusedStoreEliminator +// +// { +// { +// let x := 5 +// sstore(x, 10) +// pop(create(0, 0, 0)) +// sstore(x, 20) +// } +// } diff --git a/test/libyul/yulOptimizerTests/unusedStoreEliminator/create_inside_function.yul b/test/libyul/yulOptimizerTests/unusedStoreEliminator/create_inside_function.yul new file mode 100644 index 000000000000..782c68663b08 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedStoreEliminator/create_inside_function.yul @@ -0,0 +1,22 @@ +{ + let x := 5 + function f() { + pop(create(0, 0, 0)) + } + sstore(x, 10) + f() + sstore(x, 20) +} +// ---- +// step: unusedStoreEliminator +// +// { +// { +// let x := 5 +// sstore(x, 10) +// f() +// sstore(x, 20) +// } +// function f() +// { pop(create(0, 0, 0)) } +// } diff --git a/test/libyul/yulOptimizerTests/unusedStoreEliminator/function_end.yul b/test/libyul/yulOptimizerTests/unusedStoreEliminator/function_end.yul new file mode 100644 index 000000000000..cb69be363594 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedStoreEliminator/function_end.yul @@ -0,0 +1,20 @@ +{ + function f() { + let x := calldataload(2) + mstore(x, 2) + // This cannot be removed because we do not know what happens after the function. + mstore(x, 3) + } +} +// ---- +// step: unusedStoreEliminator +// +// { +// { } +// function f() +// { +// let x := calldataload(2) +// let _2 := 2 +// mstore(x, 3) +// } +// } diff --git a/test/libyul/yulOptimizerTests/unusedStoreEliminator/function_side_effects.yul b/test/libyul/yulOptimizerTests/unusedStoreEliminator/function_side_effects.yul new file mode 100644 index 000000000000..25f9355b3bb1 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedStoreEliminator/function_side_effects.yul @@ -0,0 +1,55 @@ +{ + function justStop() { return(0, 0) } + function justRevert() { revert(0, 0) } + + let x := 0 + let y := 1 + let a := 0x80 + let b := 7 + let c := 9 + switch calldataload(0) + case 0 + { + sstore(x, y) + mstore(a, b) + justStop() + sstore(x, y) + mstore(a, b) + } + case 1 + { + sstore(x, y) + mstore(a, b) + justRevert() + sstore(x, y) + mstore(a, b) + } +} +// ---- +// step: unusedStoreEliminator +// +// { +// { +// let x := 0 +// let y := 1 +// let a := 0x80 +// let b := 7 +// let c := 9 +// switch calldataload(0) +// case 0 { +// sstore(x, y) +// mstore(a, b) +// justStop() +// sstore(x, y) +// } +// case 1 { +// mstore(a, b) +// justRevert() +// sstore(x, y) +// } +// } +// function justStop() +// { return(0, 0) } +// function justRevert() +// { revert(0, 0) } +// } diff --git a/test/libyul/yulOptimizerTests/unusedStoreEliminator/function_side_effects_2.yul b/test/libyul/yulOptimizerTests/unusedStoreEliminator/function_side_effects_2.yul new file mode 100644 index 000000000000..843f7f6e9f52 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedStoreEliminator/function_side_effects_2.yul @@ -0,0 +1,28 @@ +{ + let x := 0 + let y := 1 + sstore(x, y) + f() + sstore(x, y) + function f() { + // prevent inlining + f() + return(0, 0) + } + } +// ---- +// step: unusedStoreEliminator +// +// { +// { +// let x := 0 +// let y := 1 +// f() +// sstore(x, y) +// } +// function f() +// { +// f() +// return(0, 0) +// } +// } diff --git a/test/libyul/yulOptimizerTests/unusedStoreEliminator/if_overwrite_all_branches.yul b/test/libyul/yulOptimizerTests/unusedStoreEliminator/if_overwrite_all_branches.yul new file mode 100644 index 000000000000..7054dc255464 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedStoreEliminator/if_overwrite_all_branches.yul @@ -0,0 +1,20 @@ +{ + let c := calldataload(0) + // This store will be overwritten in all branches and thus can be removed. + sstore(c, 1) + if c { + sstore(c, 2) + } + sstore(c, 3) +} +// ---- +// step: unusedStoreEliminator +// +// { +// { +// let c := calldataload(0) +// let _2 := 1 +// if c { let _3 := 2 } +// sstore(c, 3) +// } +// } diff --git a/test/libyul/yulOptimizerTests/unusedStoreEliminator/leave.yul b/test/libyul/yulOptimizerTests/unusedStoreEliminator/leave.yul new file mode 100644 index 000000000000..92a75155410b --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedStoreEliminator/leave.yul @@ -0,0 +1,23 @@ +{ + function f() { + mstore(0, 5) + if calldataload(0) { leave } + mstore(0x20, 5) + revert(0, 0) + } + f() +} +// ---- +// step: unusedStoreEliminator +// +// { +// { f() } +// function f() +// { +// mstore(0, 5) +// if calldataload(0) { leave } +// let _5 := 5 +// let _6 := 0x20 +// revert(0, 0) +// } +// } diff --git a/test/libyul/yulOptimizerTests/unusedStoreEliminator/memoryguard.yul b/test/libyul/yulOptimizerTests/unusedStoreEliminator/memoryguard.yul new file mode 100644 index 000000000000..466cd02e5331 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedStoreEliminator/memoryguard.yul @@ -0,0 +1,24 @@ +{ + mstore(0x40, memoryguard(100)) + let free_mem_ptr := mload(0x40) + // redundant + mstore(free_mem_ptr, 100) + // redundant + mstore8(add(free_mem_ptr, 31), 200) + mstore(free_mem_ptr, 300) + return(free_mem_ptr, add(free_mem_ptr, 100)) +} +// ---- +// step: unusedStoreEliminator +// +// { +// { +// mstore(0x40, memoryguard(100)) +// let free_mem_ptr := mload(0x40) +// let _4 := 100 +// let _5 := 200 +// mstore8(add(free_mem_ptr, 31), _5) +// mstore(free_mem_ptr, 300) +// return(free_mem_ptr, add(free_mem_ptr, 100)) +// } +// } diff --git a/test/libyul/yulOptimizerTests/unusedStoreEliminator/mload.yul b/test/libyul/yulOptimizerTests/unusedStoreEliminator/mload.yul new file mode 100644 index 000000000000..717332472c38 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedStoreEliminator/mload.yul @@ -0,0 +1,20 @@ +{ + let zero := 0 + mstore(zero, 5) + let x := mload(zero) + mstore(zero, 8) + let y := mload(zero) + sstore(zero, y) +} +// ---- +// step: unusedStoreEliminator +// +// { +// { +// let zero := 0 +// mstore(zero, 5) +// let x := mload(zero) +// mstore(zero, 8) +// sstore(zero, mload(zero)) +// } +// } diff --git a/test/libyul/yulOptimizerTests/unusedStoreEliminator/no_storage_inside_function.yul b/test/libyul/yulOptimizerTests/unusedStoreEliminator/no_storage_inside_function.yul new file mode 100644 index 000000000000..524b328e9e7e --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedStoreEliminator/no_storage_inside_function.yul @@ -0,0 +1,27 @@ +{ + function f() -> r { + r := mload(0x20) + } + let x := 5 + sstore(x, 10) // should be removed + mstore(0, 42) // could be removed, but will probably stay? + pop(f()) + sstore(x, 10) +} +// ---- +// step: unusedStoreEliminator +// +// { +// { +// let x := 5 +// let _2 := 10 +// mstore(0, 42) +// pop(f()) +// sstore(x, 10) +// } +// function f() -> r +// { +// r := mload(0x20) +// let r_7 := r +// } +// } diff --git a/test/libyul/yulOptimizerTests/unusedStoreEliminator/overflow.yul b/test/libyul/yulOptimizerTests/unusedStoreEliminator/overflow.yul new file mode 100644 index 000000000000..dda59873cb24 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedStoreEliminator/overflow.yul @@ -0,0 +1,18 @@ +{ + let x := 0 + + calldatacopy(0, 0, 115792089237316195423570985008687907853269984665640564039457584007913129639935) + mstore(x, 20) + return(0, 32) +} +// ---- +// step: unusedStoreEliminator +// +// { +// { +// let x := 0 +// calldatacopy(0, 0, 115792089237316195423570985008687907853269984665640564039457584007913129639935) +// mstore(x, 20) +// return(0, 32) +// } +// } diff --git a/test/libyul/yulOptimizerTests/unusedStoreEliminator/overlapping.yul b/test/libyul/yulOptimizerTests/unusedStoreEliminator/overlapping.yul new file mode 100644 index 000000000000..78179dc3eab9 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedStoreEliminator/overlapping.yul @@ -0,0 +1,21 @@ +{ + let _1 := 0 + if callvalue() { revert(_1, _1) } + mstore(_1, shl(224, 0x4e487b71)) + mstore(4, 0x32) + revert(_1, 0x24) +} +// ==== +// EVMVersion: >=constantinople +// ---- +// step: unusedStoreEliminator +// +// { +// { +// let _1 := 0 +// if callvalue() { revert(_1, _1) } +// mstore(_1, shl(224, 0x4e487b71)) +// mstore(4, 0x32) +// revert(_1, 0x24) +// } +// } diff --git a/test/libyul/yulOptimizerTests/unusedStoreEliminator/overlapping_small.yul b/test/libyul/yulOptimizerTests/unusedStoreEliminator/overlapping_small.yul new file mode 100644 index 000000000000..2950a04ce2fb --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedStoreEliminator/overlapping_small.yul @@ -0,0 +1,27 @@ +{ + let _1 := 0 + let _2 := callvalue() + let _3 := 0x4e487b71 + let _4 := 224 + let _5 := 7 + mstore(_1, _5) + let _6 := 0x32 + let _7 := 4 + mstore(_7, _6) + let _8 := 0x24 + revert(_1, _8) +} +// ---- +// step: unusedStoreEliminator +// +// { +// { +// let _1 := 0 +// let _2 := callvalue() +// let _3 := 0x4e487b71 +// let _4 := 224 +// mstore(_1, 7) +// mstore(4, 0x32) +// revert(_1, 0x24) +// } +// } diff --git a/test/libyul/yulOptimizerTests/unusedStoreEliminator/remove_before_revert.yul b/test/libyul/yulOptimizerTests/unusedStoreEliminator/remove_before_revert.yul new file mode 100644 index 000000000000..e7777964c20e --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedStoreEliminator/remove_before_revert.yul @@ -0,0 +1,21 @@ +{ + let c := calldataload(0) + mstore(c, 4) + if c { + sstore(c, 2) + } + let d := 0 + revert(d, d) +} +// ---- +// step: unusedStoreEliminator +// +// { +// { +// let c := calldataload(0) +// let _2 := 4 +// if c { let _3 := 2 } +// let d := 0 +// revert(d, d) +// } +// } diff --git a/test/libyul/yulOptimizerTests/unusedStoreEliminator/unaligned_access.yul b/test/libyul/yulOptimizerTests/unusedStoreEliminator/unaligned_access.yul new file mode 100644 index 000000000000..3bfd558fe08e --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedStoreEliminator/unaligned_access.yul @@ -0,0 +1,17 @@ +{ + let zero := 0 + mstore(zero, 0x1234) + mstore(4, 0x456) + revert(zero, 5) +} +// ---- +// step: unusedStoreEliminator +// +// { +// { +// let zero := 0 +// mstore(zero, 0x1234) +// mstore(4, 0x456) +// revert(zero, 5) +// } +// } diff --git a/test/libyul/yulOptimizerTests/unusedStoreEliminator/unknown_length2.yul b/test/libyul/yulOptimizerTests/unusedStoreEliminator/unknown_length2.yul new file mode 100644 index 000000000000..db5f060a634d --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedStoreEliminator/unknown_length2.yul @@ -0,0 +1,33 @@ +{ + let a + switch calldataload(0) + case 0 { a := calldataload(9) } + case 1 { a := calldataload(10) } + + calldatacopy(0x20, 0, a) + let x := mload(0) + sstore(0, x) +} +// ---- +// step: unusedStoreEliminator +// +// { +// { +// let a_9 +// let a := a_9 +// switch calldataload(0) +// case 0 { +// a := calldataload(9) +// let a_10 := a +// } +// case 1 { +// let a_12 := a +// a := calldataload(10) +// let a_11 := a +// } +// let a_13 := a +// let _5 := 0 +// let _6 := 0x20 +// sstore(0, mload(0)) +// } +// } diff --git a/test/libyul/yulOptimizerTests/unusedStoreEliminator/unrelated_relative.yul b/test/libyul/yulOptimizerTests/unusedStoreEliminator/unrelated_relative.yul new file mode 100644 index 000000000000..b0b42060f49c --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedStoreEliminator/unrelated_relative.yul @@ -0,0 +1,23 @@ +{ + let c := calldataload(0) + mstore(c, 4) + mstore(add(c, 0x20), 8) + sstore(0, mload(c)) + mstore(c, 9) + mstore(add(c, 0x20), 20) +} +// ---- +// step: unusedStoreEliminator +// +// { +// { +// let c := calldataload(0) +// mstore(c, 4) +// let _3 := 8 +// let _5 := add(c, 0x20) +// sstore(0, mload(c)) +// let _8 := 9 +// let _9 := 20 +// let _11 := add(c, 0x20) +// } +// } diff --git a/test/libyul/yulOptimizerTests/unusedStoreEliminator/write_before_recursion.yul b/test/libyul/yulOptimizerTests/unusedStoreEliminator/write_before_recursion.yul new file mode 100644 index 000000000000..855ae8325b7b --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedStoreEliminator/write_before_recursion.yul @@ -0,0 +1,27 @@ +{ + sstore(0, 1) + mstore(0, 2) + f() + function f() { + g() + } + function g() { + f() + } +} +// ---- +// step: unusedStoreEliminator +// +// { +// { +// let _1 := 1 +// let _2 := 0 +// let _3 := 2 +// let _4 := 0 +// f() +// } +// function f() +// { g() } +// function g() +// { f() } +// } diff --git a/test/libyul/yulStackLayout/complex.yul b/test/libyul/yulStackLayout/complex.yul index e521e6faa25d..604dca1f46e2 100644 --- a/test/libyul/yulStackLayout/complex.yul +++ b/test/libyul/yulStackLayout/complex.yul @@ -204,16 +204,16 @@ // // Block12 [label="\ // [ JUNK JUNK JUNK JUNK x JUNK ]\l\ -// [ 0x06 x ]\l\ +// [ JUNK JUNK JUNK JUNK JUNK JUNK 0x06 x ]\l\ // sstore\l\ -// [ ]\l\ -// [ 0x2a ]\l\ +// [ JUNK JUNK JUNK JUNK JUNK JUNK ]\l\ +// [ JUNK JUNK JUNK JUNK JUNK JUNK 0x2a ]\l\ // Assignment(c)\l\ -// [ c ]\l\ -// [ 0x00 0x00 ]\l\ +// [ JUNK JUNK JUNK JUNK JUNK JUNK c ]\l\ +// [ JUNK JUNK JUNK JUNK JUNK JUNK 0x00 0x00 ]\l\ // revert\l\ -// [ ]\l\ -// [ ]\l\ +// [ JUNK JUNK JUNK JUNK JUNK JUNK ]\l\ +// [ JUNK JUNK JUNK JUNK JUNK JUNK ]\l\ // "]; // Block12Exit [label="Terminated"]; // Block12 -> Block12Exit; @@ -254,10 +254,10 @@ // // Block16 [label="\ // [ JUNK JUNK JUNK JUNK JUNK ]\l\ -// [ 0x00 0x00 ]\l\ +// [ JUNK JUNK JUNK JUNK JUNK 0x00 0x00 ]\l\ // return\l\ -// [ ]\l\ -// [ ]\l\ +// [ JUNK JUNK JUNK JUNK JUNK ]\l\ +// [ JUNK JUNK JUNK JUNK JUNK ]\l\ // "]; // Block16Exit [label="Terminated"]; // Block16 -> Block16Exit; diff --git a/test/libyul/yulStackLayout/for.yul b/test/libyul/yulStackLayout/for.yul index fc0fbcdb7ea6..88aafad6b20a 100644 --- a/test/libyul/yulStackLayout/for.yul +++ b/test/libyul/yulStackLayout/for.yul @@ -49,10 +49,10 @@ // // Block2 [label="\ // [ JUNK ]\l\ -// [ 0x0506 0x06 ]\l\ +// [ JUNK 0x0506 0x06 ]\l\ // sstore\l\ -// [ ]\l\ -// [ ]\l\ +// [ JUNK ]\l\ +// [ JUNK ]\l\ // "]; // Block2Exit [label="MainExit"]; // Block2 -> Block2Exit; diff --git a/test/localeTest.sh b/test/localeTest.sh new file mode 100755 index 000000000000..58e2aad4d994 --- /dev/null +++ b/test/localeTest.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash + +#------------------------------------------------------------------------------ +# Script that tests that the compiler works correctly regardless of the locale +# setting. As a prerequisite, the following locales must be enabled system-wide: +# C, tr_TR.utf8, ja_JP.eucjp. +# +# Usage: +#