diff --git a/.circleci/config.yml b/.circleci/config.yml index 65e7113a3..bcfc99cd7 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 fc7320c72..759f69a53 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 a6ce63a70..6badda517 100644 --- a/Changelog.md +++ b/Changelog.md @@ -10,18 +10,46 @@ Breaking changes: * General: The identifier ``basefee`` is a reserved identifier in Yul for all EVM versions. -### 0.8.13 (unreleased) +### 0.8.14 (unreleased) 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. Compiler Features: -* JSON-AST: Added selector field for errors and events. + 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: + * 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) Language Features: diff --git a/cmake/EthUtils.cmake b/cmake/EthUtils.cmake index fca41107e..44b92f4a0 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 746da43c1..0876229b1 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 0b72c05c7..9e24175b4 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 0aae3f1ac..7b9a7fc3d 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 86c81dbfb..1793ebd2f 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 b67068d63..e917cad7f 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 f1fd3b0b5..f574a5a6a 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 6e99a332b..27df4dde1 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 0d4c8e8c2..2445895e4 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 cc820d25e..890e8d177 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); } } @@ -363,7 +363,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. @@ -374,8 +374,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 @@ -398,7 +398,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. @@ -487,13 +487,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; } } @@ -507,12 +507,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; } } @@ -540,12 +540,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 b77feda0a..54817837c 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 a4581a15f..cc71cf64e 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 76bedba49..c40284b49 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 af6750f87..2c2817f15 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; - 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 insert(Data storage self, uint value) + 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/grammar/SolidityLexer.g4 b/docs/grammar/SolidityLexer.g4 index 653255ae3..9250835dd 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 e41bb2ba9..92718b975 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/index.rst b/docs/index.rst index 390ee0842..ff5b59c72 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -5,10 +5,8 @@ Solidity is an object-oriented, high-level language for implementing smart contracts. Smart contracts are programs which govern the behaviour of accounts within the Ethereum state. -Solidity is a `curly-bracket language `_. -It is influenced by C++, Python and JavaScript, and is designed to target the Ethereum Virtual Machine (EVM). -You can find more details about which languages Solidity has been inspired by in -the :doc:`language influences ` section. +Solidity is a `curly-bracket language `_ designed to target the Ethereum Virtual Machine (EVM). +It is influenced by C++, Python and JavaScript. You can find more details about which languages Solidity has been inspired by in the :doc:`language influences ` section. Solidity is statically typed, supports inheritance, libraries and complex user-defined types among other features. @@ -90,24 +88,25 @@ our `Gitter channel `_. Translations ------------ -Community volunteers help translate this documentation into several languages. -They have varying degrees of completeness and up-to-dateness. The English +Community contributors help translate this documentation into several languages. +Note that they have varying degrees of completeness and up-to-dateness. The English version stands as a reference. +You can switch between languages by clicking on the flyout menu in the bottom-left corner +and selecting the preferred language. + +* `French `_ +* `Indonesian `_ +* `Persian `_ +* `Japanese `_ +* `Korean `_ +* `Chinese `_ + .. note:: We recently set up a new GitHub organization and translation workflow to help streamline the community efforts. Please refer to the `translation guide `_ - for information on how to contribute to the community translations moving forward. - -* `French `_ (in progress) -* `Italian `_ (in progress) -* `Japanese `_ -* `Korean `_ (in progress) -* `Russian `_ (rather outdated) -* `Simplified Chinese `_ (in progress) -* `Spanish `_ -* `Turkish `_ (partial) + for information on how to start a new language or contribute to the community translations. Contents ======== diff --git a/docs/internals/layout_in_storage.rst b/docs/internals/layout_in_storage.rst index 4682d640c..599cd03d3 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 a7eff7346..1d6c214e5 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 94188a097..7adbfaedb 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 3fce53b3b..2b5905a96 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 921211248..729951142 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 c7e531c43..1a6568737 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); } } diff --git a/docs/smtchecker.rst b/docs/smtchecker.rst index 791659897..5093408a7 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 399523cf2..1c94b20ab 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 450963e11..be5f0d456 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 f595612c0..74b6daa7f 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 0d6a30cd6..8f1009407 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 5a3fe4881..ffe1aa624 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -297,7 +297,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 e4775ee4d..8a584db1d 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 55d23e283..6d7b97cc4 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 97807e223..11bc16662 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 @@ public: struct OptimiserSettings { - bool isCreation = false; bool runInliner = false; bool runJumpdestRemover = false; bool runPeephole = false; @@ -157,6 +156,8 @@ public: 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 @@ protected: 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/AssemblyItem.cpp b/libevmasm/AssemblyItem.cpp index eeeadb3ef..984058765 100644 --- a/libevmasm/AssemblyItem.cpp +++ b/libevmasm/AssemblyItem.cpp @@ -200,9 +200,7 @@ string AssemblyItem::toAssemblyText(Assembly const& _assembly) const case Operation: { assertThrow(isValidInstruction(instruction()), AssemblyException, "Invalid instruction."); - string name = instructionInfo(instruction()).name; - transform(name.begin(), name.end(), name.begin(), [](unsigned char _c) { return tolower(_c); }); - text = name; + text = util::toLower(instructionInfo(instruction()).name); break; } case Push: diff --git a/libevmasm/CommonSubexpressionEliminator.cpp b/libevmasm/CommonSubexpressionEliminator.cpp index 8a4e9f6e3..397d20f16 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 88e559719..51a5d74b2 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 @@ private: /// 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 8e4a09fcc..4e4a2c9d7 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 { -}; -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 -{ - static bool applyRule(AssemblyItems::const_iterator _in, std::back_insert_iterator _out) - { - return Method::applySimple(_in[0], _out); - } + static constexpr auto value = sizeof...(Args); }; -template +template struct SimplePeepholeOptimizerMethod { + template + static bool applyRule(AssemblyItems::const_iterator _in, back_insert_iterator _out, index_sequence) + { + return Method::applySimple(_in[Indices]..., _out); + } 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,36 @@ 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 DoubleSwap: SimplePeepholeOptimizerMethod { static size_t applySimple(AssemblyItem const& _s1, AssemblyItem const& _s2, std::back_insert_iterator) { @@ -148,7 +154,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 +169,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 +187,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 +213,7 @@ struct SwapComparison: SimplePeepholeOptimizerMethod }; /// Remove swapN after dupN -struct DupSwap: SimplePeepholeOptimizerMethod +struct DupSwap: SimplePeepholeOptimizerMethod { static size_t applySimple( AssemblyItem const& _dupN, @@ -230,7 +236,7 @@ struct DupSwap: SimplePeepholeOptimizerMethod }; -struct IsZeroIsZeroJumpI: SimplePeepholeOptimizerMethod +struct IsZeroIsZeroJumpI: SimplePeepholeOptimizerMethod { static size_t applySimple( AssemblyItem const& _iszero1, @@ -256,7 +262,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 +347,7 @@ struct JumpToNext: SimplePeepholeOptimizerMethod } }; -struct TagConjunctions: SimplePeepholeOptimizerMethod +struct TagConjunctions: SimplePeepholeOptimizerMethod { static bool applySimple( AssemblyItem const& _pushTag, @@ -317,7 +382,7 @@ struct TagConjunctions: SimplePeepholeOptimizerMethod } }; -struct TruthyAnd: SimplePeepholeOptimizerMethod +struct TruthyAnd: SimplePeepholeOptimizerMethod { static bool applySimple( AssemblyItem const& _push, @@ -394,8 +459,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(), 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 bda02b5e4..16c78541c 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/liblangutil/Token.cpp b/liblangutil/Token.cpp index 8bdaff1fd..d7620ef13 100644 --- a/liblangutil/Token.cpp +++ b/liblangutil/Token.cpp @@ -40,10 +40,13 @@ // You should have received a copy of the GNU General Public License // along with solidity. If not, see . -#include #include +#include +#include + #include + using namespace std; namespace solidity::langutil @@ -180,11 +183,11 @@ tuple fromIdentifierOrKeyword(string const& _ return ret; }; - auto positionM = find_if(_literal.begin(), _literal.end(), ::isdigit); + auto positionM = find_if(_literal.begin(), _literal.end(), util::isDigit); if (positionM != _literal.end()) { string baseType(_literal.begin(), positionM); - auto positionX = find_if_not(positionM, _literal.end(), ::isdigit); + auto positionX = find_if_not(positionM, _literal.end(), util::isDigit); int m = parseSize(positionM, positionX); Token keyword = keywordByName(baseType); if (keyword == Token::Bytes) @@ -208,7 +211,7 @@ tuple fromIdentifierOrKeyword(string const& _ positionM < positionX && positionX < _literal.end() && *positionX == 'x' && - all_of(positionX + 1, _literal.end(), ::isdigit) + all_of(positionX + 1, _literal.end(), util::isDigit) ) { int n = parseSize(positionX + 1, _literal.end()); if ( diff --git a/libsolc/CMakeLists.txt b/libsolc/CMakeLists.txt index 776b97ca5..fce54dd24 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 ff82cd9fb..3d2845463 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 0c64ac3b5..e80964ace 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 3de1ecca5..7c568b18e 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 9a44be57a..ae9c18a13 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 ba989972c..4fb210435 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 265237128..45da1b4f0 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 d08ee78b7..b5b973aa4 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 32927188f..38a192c22 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 589787a89..bdf138e20 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 ca36ed992..f221df09f 100644 --- a/libsolidity/analysis/SyntaxChecker.h +++ b/libsolidity/analysis/SyntaxChecker.h @@ -88,6 +88,9 @@ private: 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 ef82b8eab..c519f7bfe 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()) ); @@ -3635,12 +3641,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 969ee4394..2ef6b818b 100644 --- a/libsolidity/analysis/TypeChecker.h +++ b/libsolidity/analysis/TypeChecker.h @@ -125,6 +125,8 @@ private: 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 3179a8eb7..7483af892 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 dfbb2f747..b0abe8fd8 100644 --- a/libsolidity/analysis/ViewPureChecker.h +++ b/libsolidity/analysis/ViewPureChecker.h @@ -50,6 +50,8 @@ private: 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 2a7609de8..be6f2fe9b 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 4893c212f..4eba73c5d 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -630,9 +631,20 @@ private: }; /** - * `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 @@ public: 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 0d6901ef2..3497a2ea8 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 6b48797d1..4338cc64f 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 d71864f34..2f36cdead 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 3ed47d6f2..2b7ea7427 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 5b1a7d4e5..2bfbb8fe9 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 fa42c2dc6..6dab08f00 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 17b3c9fea..32ef5f4ea 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -33,7 +33,9 @@ #include #include #include +#include #include +#include #include #include @@ -330,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, @@ -362,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() + ); } } @@ -781,8 +816,8 @@ tuple RationalNumberType::parseRational(string const& _value) if (radixPoint != _value.end()) { if ( - !all_of(radixPoint + 1, _value.end(), ::isdigit) || - !all_of(_value.begin(), radixPoint, ::isdigit) + !all_of(radixPoint + 1, _value.end(), util::isDigit) || + !all_of(_value.begin(), radixPoint, util::isDigit) ) return make_tuple(false, rational(0)); @@ -2344,6 +2379,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()) @@ -2476,6 +2516,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; @@ -2544,6 +2589,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 9b030f65a..9b3080769 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -369,6 +369,10 @@ public: /// 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 @@ public: 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 @@ public: 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 @@ public: 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 700f53d1f..99b87e5a7 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 cd71d5a4d..a796ac60b 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -65,7 +65,7 @@ public: 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 5abc64636..d2c71e2af 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 e4ad4cf7e..21cb45e77 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 bd9252953..379e9818b 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 cb187b424..cb62cc292 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 3b977e9c8..9e48c811c 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -203,7 +203,7 @@ private: else solAssert(false); - if (isdigit(value.front())) + if (isDigit(value.front())) return yul::Literal{_identifier.debugData, yul::LiteralKind::Number, yul::YulString{value}, {}}; else return yul::Identifier{_identifier.debugData, yul::YulString{value}}; @@ -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 9e31d7fc9..58deaad4a 100644 --- a/libsolidity/formal/CHC.cpp +++ b/libsolidity/formal/CHC.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #ifdef HAVE_Z3_DLOPEN #include @@ -1497,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; @@ -1998,9 +1999,9 @@ map> CHC::summaryCalls(CHCSolverInterface::CexGraph c // Predicates that do not have a CALLID have a predicate id at the end of , // so the assertion below should still hold. auto beg = _s.data(); - while (beg != _s.data() + _s.size() && !isdigit(*beg)) ++beg; + while (beg != _s.data() + _s.size() && !isDigit(*beg)) ++beg; auto end = beg; - while (end != _s.data() + _s.size() && isdigit(*end)) ++end; + while (end != _s.data() + _s.size() && isDigit(*end)) ++end; solAssert(beg != end, "Expected to find numerical call or predicate id."); diff --git a/libsolidity/formal/Invariants.cpp b/libsolidity/formal/Invariants.cpp index 9dad0722c..10d342ed4 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 6e0eb4f3b..91513a00c 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 76342ba08..7cc978d28 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 fe84189be..84a80461d 100644 --- a/libsolidity/formal/SMTEncoder.h +++ b/libsolidity/formal/SMTEncoder.h @@ -136,6 +136,7 @@ protected: // 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 6612723d0..b1fd7978f 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 b9041c6bd..e40ff9245 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 7a8bc4ddb..de5bea137 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 c1f15a480..e5bc9b345 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -189,7 +189,7 @@ public: /// 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 @@ private: 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 @@ private: /// 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 e1c35e9ea..e233048c1 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 93ac20b03..31400ccad 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 000000000..26fb686db --- /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 000000000..453da3f15 --- /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 000000000..0da19aad3 --- /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 000000000..3ca1679be --- /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 fb704d819..671476ab0 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 a3ab37198..d2ad09367 100644 --- a/libsolidity/lsp/LanguageServer.h +++ b/libsolidity/lsp/LanguageServer.h @@ -57,6 +57,11 @@ public: /// @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 @@ private: 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 2d0b49517..82fe43909 100644 --- a/libsolidity/lsp/Transport.h +++ b/libsolidity/lsp/Transport.h @@ -69,7 +69,7 @@ private: { \ 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 000000000..624d1f150 --- /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 000000000..3594efba2 --- /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 b1d7e7cca..a1b49a81f 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/CommonData.cpp b/libsolutil/CommonData.cpp index a49f90491..437a090c2 100644 --- a/libsolutil/CommonData.cpp +++ b/libsolutil/CommonData.cpp @@ -20,11 +20,12 @@ * @date 2014 */ +#include #include #include -#include -#include #include +#include +#include #include @@ -154,9 +155,9 @@ string solidity::util::getChecksummedAddress(string const& _addr) char addressCharacter = s[i]; uint8_t nibble = hash[i / 2u] >> (4u * (1u - (i % 2u))) & 0xf; if (nibble >= 8) - ret += static_cast(toupper(addressCharacter)); + ret += toUpper(addressCharacter); else - ret += static_cast(tolower(addressCharacter)); + ret += toLower(addressCharacter); } return ret; } @@ -211,7 +212,7 @@ string solidity::util::escapeAndQuoteString(string const& _input) out += "\\r"; else if (c == '\t') out += "\\t"; - else if (!isprint(c, locale::classic())) + else if (!isPrint(c)) { ostringstream o; o << "\\x" << std::hex << setfill('0') << setw(2) << (unsigned)(unsigned char)(c); diff --git a/libsolutil/IpfsHash.cpp b/libsolutil/IpfsHash.cpp index a34ee035b..dbf411dc7 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/libsolutil/StringUtils.h b/libsolutil/StringUtils.h index 09aa30be9..7a48c296f 100644 --- a/libsolutil/StringUtils.h +++ b/libsolutil/StringUtils.h @@ -27,7 +27,9 @@ #include #include +#include #include +#include #include #include @@ -197,4 +199,47 @@ inline std::optional toUnsignedInt(std::string const& _value) } } +/// Converts parameter _c to its lowercase equivalent if c is an uppercase letter and has a lowercase equivalent. It uses the classic "C" locale semantics. +/// @param _c value to be converted +/// @return the converted value +inline char toLower(char _c) +{ + return tolower(_c, std::locale::classic()); +} + +/// Converts parameter _c to its uppercase equivalent if c is an lowercase letter and has a uppercase equivalent. It uses the classic "C" locale semantics. +/// @param _c value to be converted +/// @return the converted value +inline char toUpper(char _c) +{ + return toupper(_c, std::locale::classic()); +} + +/// Converts parameter _s to its lowercase equivalent. It uses the classic "C" locale semantics. +/// @param _s value to be converted +/// @return the converted value +inline std::string toLower(std::string _s) +{ + std::transform(_s.begin(), _s.end(), _s.begin(), [](char _c) { + return toLower(_c); + }); + return _s; +} + +/// Checks whether _c is a decimal digit character. It uses the classic "C" locale semantics. +/// @param _c character to be checked +/// @return true if _c is a decimal digit character, false otherwise +inline bool isDigit(char _c) +{ + return isdigit(_c, std::locale::classic()); +} + +// Checks if character is printable using classic "C" locale +/// @param _c character to be checked +/// @return true if _c is a printable character, false otherwise. +inline bool isPrint(char _c) +{ + return isprint(_c, std::locale::classic()); +} + } diff --git a/libyul/AST.h b/libyul/AST.h index 1c7b8e02a..71419d807 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 30ad58d77..3fefb9caf 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 fde673e3d..806f094fe 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 ed456ab53..cf68ff765 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 414d7d115..739dfd0e4 100644 --- a/libyul/backends/evm/AbstractAssembly.h +++ b/libyul/backends/evm/AbstractAssembly.h @@ -98,7 +98,7 @@ public: /// 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 6196697fc..8ca2076a0 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 df271bb8d..855d96fbd 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/EVMDialect.cpp b/libyul/backends/evm/EVMDialect.cpp index c45268fba..0b6855e3a 100644 --- a/libyul/backends/evm/EVMDialect.cpp +++ b/libyul/backends/evm/EVMDialect.cpp @@ -21,17 +21,17 @@ #include -#include +#include +#include +#include +#include #include -#include -#include +#include #include +#include +#include #include #include -#include -#include - -#include #include #include @@ -114,8 +114,7 @@ set createReservedIdentifiers() set reserved; for (auto const& instr: evmasm::c_instructions) { - string name = instr.first; - transform(name.begin(), name.end(), name.begin(), [](unsigned char _c) { return tolower(_c); }); + string name = toLower(instr.first); reserved.emplace(name); } reserved += vector{ @@ -134,8 +133,7 @@ map createBuiltins(langutil::EVMVersion _evmVe map builtins; for (auto const& instr: evmasm::c_instructions) { - string name = instr.first; - transform(name.begin(), name.end(), name.begin(), [](unsigned char _c) { return tolower(_c); }); + string name = toLower(instr.first); auto const opcode = instr.second; if ( diff --git a/libyul/backends/evm/EVMObjectCompiler.cpp b/libyul/backends/evm/EVMObjectCompiler.cpp index c3c95d8bc..4dbf5cc1a 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 1c41534b2..5d7b4cbf4 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 c11b375f6..87047ccbf 100644 --- a/libyul/backends/evm/EthAssemblyAdapter.h +++ b/libyul/backends/evm/EthAssemblyAdapter.h @@ -55,7 +55,7 @@ public: 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 62c0ad119..e26204201 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 b41d7f4a6..1103392ef 100644 --- a/libyul/backends/evm/NoOutputAssembly.h +++ b/libyul/backends/evm/NoOutputAssembly.h @@ -65,7 +65,7 @@ public: 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 50dcee5de..4f9a1e2a1 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 803e49354..34cac6d39 100644 --- a/libyul/backends/evm/StackLayoutGenerator.h +++ b/libyul/backends/evm/StackLayoutGenerator.h @@ -111,6 +111,9 @@ private: /// 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 16cdfd893..d25beb6bd 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 443a2a9be..cfd59d09a 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 af25cde59..65cdf31c3 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 deaa71f89..a8463360b 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 @@ public: 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 @@ protected: /// 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 dcba98ce4..542d8d50b 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 736ebe4b9..8c3a038f1 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 5b5c07dda..460f6707f 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 75e060eb1..999d0e312 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 @@ private: 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 550ca6fb3..abcfbaabb 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/Rematerialiser.cpp b/libyul/optimiser/Rematerialiser.cpp index f1597a7f2..6e00fcd8a 100644 --- a/libyul/optimiser/Rematerialiser.cpp +++ b/libyul/optimiser/Rematerialiser.cpp @@ -79,16 +79,15 @@ void Rematerialiser::visit(Expression& _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 +95,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 +116,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/SimplificationRules.cpp b/libyul/optimiser/SimplificationRules.cpp index 55c30d2f2..9d0144750 100644 --- a/libyul/optimiser/SimplificationRules.cpp +++ b/libyul/optimiser/SimplificationRules.cpp @@ -21,15 +21,16 @@ #include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include #include +#include using namespace std; using namespace solidity; @@ -40,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); @@ -137,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; @@ -147,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, ""); @@ -249,8 +250,7 @@ Expression Pattern::toExpression(shared_ptr const& _debugData) for (auto const& arg: m_arguments) arguments.emplace_back(arg.toExpression(_debugData)); - string name = instructionInfo(m_instruction).name; - transform(begin(name), end(name), begin(name), [](auto _c) { return tolower(_c); }); + string name = util::toLower(instructionInfo(m_instruction).name); return FunctionCall{_debugData, Identifier{_debugData, YulString{name}}, diff --git a/libyul/optimiser/SimplificationRules.h b/libyul/optimiser/SimplificationRules.h index 77018bb38..7444c47fb 100644 --- a/libyul/optimiser/SimplificationRules.h +++ b/libyul/optimiser/SimplificationRules.h @@ -62,7 +62,7 @@ public: 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 @@ public: 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 2deef5234..8b06d6625 100644 --- a/libyul/optimiser/StackCompressor.cpp +++ b/libyul/optimiser/StackCompressor.cpp @@ -67,7 +67,8 @@ public: 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]); + set const* ref = references(candidate); + cand[*cost * numRef].emplace_back(candidate, ref ? move(*ref) : set{}); } } return cand; @@ -80,11 +81,11 @@ public: 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_expressionCodeCost[varName] = CodeCost::codeCost(m_dialect, *value->value); } } } @@ -105,7 +106,7 @@ public: 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]; diff --git a/libyul/optimiser/StructuralSimplifier.cpp b/libyul/optimiser/StructuralSimplifier.cpp index 5b1ae2550..ca8f94239 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 3fd59efde..734b2e53a 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 @@ private: 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 0f2194061..181c9bdcb 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 000000000..343bd720a --- /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 000000000..dc3065e45 --- /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/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 3b1f7947a..2495bf2f4 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -464,7 +464,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); @@ -693,7 +693,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()) @@ -963,7 +963,7 @@ void CommandLineInterface::link() string foundPlaceholder(it, it + placeholderSize); if (librariesReplacements.count(foundPlaceholder)) { - string hexStr(toHex(librariesReplacements.at(foundPlaceholder).asBytes())); + string hexStr(util::toHex(librariesReplacements.at(foundPlaceholder).asBytes())); copy(hexStr.begin(), hexStr.end(), it); } else @@ -1017,8 +1017,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/CommandLineParser.cpp b/solc/CommandLineParser.cpp index beab340b4..8ae64032c 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 && @@ -331,17 +332,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. } @@ -406,15 +407,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 @@ -449,9 +450,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; @@ -555,19 +556,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(), @@ -625,12 +630,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." ) ; @@ -683,8 +688,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.") @@ -703,7 +708,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." ) ; @@ -713,7 +718,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." ) ( @@ -883,6 +888,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) @@ -988,11 +994,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(); } @@ -1233,7 +1239,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); @@ -1266,7 +1272,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 791e7f1c1..9723d5e06 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 ce69d20a7..50a6a8fc5 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 11f654281..5b66aea30 100644 --- a/test/CommonSyntaxTest.cpp +++ b/test/CommonSyntaxTest.cpp @@ -29,7 +29,6 @@ using namespace std; using namespace solidity; -using namespace solidity::util; using namespace solidity::util::formatting; using namespace solidity::langutil; using namespace solidity::frontend; @@ -43,10 +42,10 @@ namespace int parseUnsignedInteger(string::iterator& _it, string::iterator _end) { - 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"); @@ -207,14 +206,14 @@ vector CommonSyntaxTest::parseExpectations(istream& _stream) if (it == line.end()) continue; auto typeBegin = it; - while (it != line.end() && isalpha(*it)) + while (it != line.end() && isalpha(*it, locale::classic())) ++it; string errorType(typeBegin, it); 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(), ':'); @@ -227,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/TestCase.cpp b/test/TestCase.cpp index 93b209aba..32de68296 100644 --- a/test/TestCase.cpp +++ b/test/TestCase.cpp @@ -118,7 +118,7 @@ EVMVersionRestrictedTestCase::EVMVersionRestrictedTestCase(string const& _filena string comparator; size_t versionBegin = 0; for (auto character: versionString) - if (!isalpha(character)) + if (!isalpha(character, locale::classic())) { comparator += character; versionBegin++; diff --git a/test/TestCase.h b/test/TestCase.h index 5d4394b11..d63c88b48 100644 --- a/test/TestCase.h +++ b/test/TestCase.h @@ -90,7 +90,7 @@ protected: template static void skipWhitespace(IteratorType& _it, IteratorType _end) { - while (_it != _end && isspace(*_it)) + while (_it != _end && std::isspace(*_it, std::locale::classic())) ++_it; } diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index ded04178f..c8fef6a31 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 --ir-optimized" ) -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 2a769811a..9c7faa732 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 7775ff69c..af83c9f36 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 35f680d92..dc4ea45fd 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 93fad0421..b2ad57c30 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 82a74384e..04a354e2e 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 593d330f8..2f75f2bdd 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 7b6e6e628..24e5d29be 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 ab626e663..7b0bf90f1 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 495c82d5b..4e9c732b4 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": 145, "parameterSlots": 2, "returnSlots": 1 } diff --git a/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output b/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output index 330e208f4..84fd9d0bc 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 fbedf38db..5cacb6c16 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 d9b769a12..41f353269 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 9a07c7861..c406d4f7e 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 4abb046f6..8b89ea5b6 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 f5df14027..c308d737b 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 7816df4ec..89fa9901c 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 7816df4ec..89fa9901c 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 4dab68351..ec597c396 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 3dabe9c8d..219d76769 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 014a1178f..000000000 --- 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 8404525f8..bb0d0bf40 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 f6e7705c7..689e82ddb 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 31b3db33b..0f16ff9d0 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 238934a3f..3490a7342 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 16236251d..30895c160 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 d017c8e9c..6ee9874d3 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 afe07fad9..a32ee0580 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 f593301bc..a57dbdc35 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 85b861602..f91976411 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 1e7f8dec3..78e2aebce 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 881a4bad4..f08a5d302 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 671b8ffa7..63da252cd 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 b57bc9188..70122b9a7 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 0ce9fd2de..e7b1a6943 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 8203ee0a2..b8b5ff913 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 32a2a647a..0967ef424 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 42361097d..fe9bd66a6 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 32a2a647a..0967ef424 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 49aaa6a74..96903c452 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 45280c8a1..b4a9e3685 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 4071589cb..c4b5f6e0e 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 371a0816b..40fd18d2b 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 f041adaa8..1bc924d95 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 a4670cf26..8fa9f92ce 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 866361af4..c0001f382 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 62ebc300d..0879e4f21 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 c71c535da..1c4d6c90e 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 000000000..51e6fa519 --- /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 000000000..74549134a --- /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 000000000..1686e3ef7 --- /dev/null +++ b/test/cmdlineTests/viair_subobject_optimization/output @@ -0,0 +1,354 @@ + +======= 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 + pop + 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 1a5580b80..5331d83ac 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 4b388665c..51fdae924 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 07c602a4a..6088853e6 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 b95184440..6f4ba8390 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 a88ce164a..bb68a48fa 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 5b7c3fdb0..1e19c3a5c 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 46dd577eb..3ff8779ff 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 0ffffa3a4..a5aaa8633 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 1fb107015..4cb4408ca 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 bf757e685..e019e5c2f 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 0ff492ce4..a4e1b1463 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 014a1178f..000000000 --- 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 b3b46460b..2c4c6f76c 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 e4e1e3adf..9c68c8828 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 35e9661f3..b12c7dd0b 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 @@ -90,6 +89,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 b3b505051..39283bcd5 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 6b0915b6a..000000000 --- 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 82d1892f2..ccfc6cf5c 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 01bdb76f1..1d0a0dd86 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 4094c6936..ab79a8775 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 000000000..2961d0099 --- /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 78e598bca..3a3167816 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 c8bb93c41..44fbde927 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 22090ee29..9aec1e510 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 f7cc66cb5..28c9c8a20 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 85e06e90c..39e91de1c 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 aea5e54d0..41a18a1d0 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 412dd05a4..396efa0bf 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 af5071665..f5f554608 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 85dcb313f..f78699ef6 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 640c5b51c..c04d311b0 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 93e671c10..54d38b638 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 e69de29bb..000000000 diff --git a/test/libsolidity/ASTJSON/fail_after_parsing.sol b/test/libsolidity/ASTJSON/fail_after_parsing.sol new file mode 100644 index 000000000..b3b53a7c1 --- /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 000000000..a5c7669ef --- /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 cef79e70b..924f9cdb9 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 bed2742b2..176cea374 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 e47f24ad1..fd1d7637b 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 2f7145fda..0e2a56f84 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 3651a05fd..0f14102cc 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 e33388a07..df358ae36 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 e69de29bb..000000000 diff --git a/test/libsolidity/ASTJSON/not_existing_import.sol b/test/libsolidity/ASTJSON/not_existing_import.sol index 6353c7527..7251a02b8 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 0591a30cc..df51e49c6 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 0960bcde6..756998e43 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 decc215fe..88835788b 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 a0e8e28ba..f00336d20 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 ead3e2dcf..24c03982f 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 58b476005..b7500b445 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 b935b262b..c9052b0d7 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 be6e5288f..30e40252a 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 b4b016ac1..d704b4e81 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 82c6e7e18..14e2c2a8a 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 3365de589..648f3bbc3 100644 --- a/test/libsolidity/ASTJSONTest.h +++ b/test/libsolidity/ASTJSONTest.h @@ -89,7 +89,12 @@ private: 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 d37398637..9cbf73f84 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 1f07f177d..3c26f5a97 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 314d4283e..7509bed3c 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 f3921613f..7ff226a69 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 e0e02cf95..202addffa 100644 --- a/test/libsolidity/SolidityExecutionFramework.h +++ b/test/libsolidity/SolidityExecutionFramework.h @@ -75,11 +75,12 @@ public: /// 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 5f7b8d472..4fef140e8 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 eb4102b15..a1580fb53 100644 --- a/test/libsolidity/SolidityOptimizer.cpp +++ b/test/libsolidity/SolidityOptimizer.cpp @@ -98,8 +98,8 @@ public: 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 30477aa2e..7b67aeb44 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 000000000..675c1297c --- /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 000000000..b3df921fe --- /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 f4fb51e77..22efe6ca2 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 06f9bcbbf..07f4ab275 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 c386cf3e8..8503e5790 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 cc1a182c9..cfdecd7a0 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 9deed97f1..2710f202d 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 82ece5f3f..e1e2d0ab6 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 eec062f56..1a72e0888 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: 119911 // 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 cf5958d45..63ee9bd02 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 1f1e97720..5499c2594 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 b6c6ad5f0..027ae4e16 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 000000000..d19a457f9 --- /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 7a2a06a2e..8d1851c81 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 2c238a54b..b176c7e86 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 31879057a..f0b0d1bc0 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 aaf990ef6..b4e018e65 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 945de3cfe..2aa3d43f8 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: 142856 // 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 6c876286b..f80da3500 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 81607a264..04b3b8e84 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 1c030deba..92495b157 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 0e05c4ea8..88fed0d9b 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 cad3c9d49..bd45f49a9 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 b4b392974..f90d4b852 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 c865b8228..ad12cad12 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 db26b4d47..676736dc1 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 1daa061a5..5325e9cdf 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 c87f70244..68817ba4c 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 c39f80275..346b1c469 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 f3f3e8236..834f4d28c 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 e8b460b4f..e199d37bc 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 d872534cd..e358feaf7 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 71399a281..551ed4616 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 b3d950ffa..c4aa6ac4b 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 2fe271587..0c554a32f 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 ae2698551..26ad58f4c 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 87974f053..29a017e08 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 7c0b3bdbb..d15044005 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 72a837d1b..05f8bd2bf 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 b73f3dc44..41a5e9909 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 7550a9225..4c223d30c 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 8d8bd4d50..cf8023a2f 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 7b2af9607..09457bb74 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 3d4623b79..8908caa55 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 ec58360cd..c9c72543c 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 f94b442f3..35fd24fd8 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 ece6f7969..8f98822e7 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 556fb5a61..d9a50e73d 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 abcd72ee1..f954701d5 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 8072526ab..e107bd68a 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 149e8768d..f6208ea6f 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 82c8d6b6c..8d0f6358e 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 019a3fca0..01ba8dcfe 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 4ed8c050b..be8f6eff3 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 cf310f86d..5bbd9e207 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 b09cb5812..fba3119e1 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 fcf41823e..a19475f7b 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: 128110 +// 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 07a054514..3f66dca6f 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 73f9799d4..66e385812 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: 292702 +// 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 f2a98f993..3b066cfaa 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 4be29a15d..6ec59a75e 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 08a403174..06f3c6cc9 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 387d21872..227eb6afd 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 c911b1b7c..146a4dfc3 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 38c0c84d6..d5d004f5f 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 6d314fb27..fb05db350 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 a4be5ad90..05299ae55 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 7546a664b..a7b8d6d9d 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 78c817d44..c4f7cb44a 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 262ba724a..7c4bdcb9a 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 761bf3ee3..5b470e829 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 830f25b02..713c44ec1 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 ee91ce7f7..d2d09645d 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: 113398 // 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 7773c6832..b8dbff46a 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 cc303899a..82050efa2 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 ffe0fb8c2..2e0835c25 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: 295403 +// 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 1a93f53b3..31212c5e8 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: 286205 +// 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 2206fd351..701f4accb 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 f6fab1092..0c38107cc 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 3fdbb0785..9908b2386 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 2518deb92..4f9984503 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 68506528b..a583bd39f 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 cb6192774..ca4cf5a05 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 8f891116e..b8f4d42bb 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: 158225 // 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 3d90783f8..ede647d60 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 b5db5ca2b..dedffe232 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 f833ba37a..947e5ad9e 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 5ec47a4a9..36e5ee73c 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: 173316 // 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 d35db93c4..5d3ad5840 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 e6d6c478b..58087a3b5 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 fd17c5d78..7101af594 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 d98e73792..bcbf816ae 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: 1532125 +// 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 56abe4a9d..e45d3360e 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 0488179f1..c3fb5183b 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: 1783505 +// 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 45976217b..2152a38a0 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: 456094 +// 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 8f6b939fd..05b4ddb25 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 a16f884e8..ce582e7c9 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 685d8a7de..99167ee8e 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: 200649 // 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 a768a2836..7a44bf1b9 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: 200812 // 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 030aeaa10..7a29cc254 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: 304151 +// 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 cfbf1bcc1..2e9be2ff5 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 2ebf8740d..0a8b5a922 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: 214971 +// 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 4321753d6..ca2cf152e 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: 275142 // 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 2f89517b7..a08d75557 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: 275142 // 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 f1e2f1116..f422b43d9 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 617a6dec2..188052e75 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: 100480 // 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 e834663d0..c50acf2be 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: 126536 // 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 e065f3f01..4f3e8a3bd 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: 129602 // 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 a15650992..165ae909d 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: 102144 // 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 e6f94bdcf..95dd7c3d9 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: 280056 // 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 8d37ed809..3b1a485c1 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: 183976 // 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 ac61fad71..9cf5f65ff 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 e8d22c279..6304e12d8 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 116887fd5..1f1ac6eb0 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 000000000..22d61c6c5 --- /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 000000000..503f65680 --- /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 5374d2352..51b987c2c 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 4ce8b5149..aab46a9a4 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: 272431 // gas legacy: 422501 // gas legacyOptimized: 287472 diff --git a/test/libsolidity/semanticTests/smoke/constructor.sol b/test/libsolidity/semanticTests/smoke/constructor.sol index a6e812e9a..4e5a07e95 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: 109775 // 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 9abeb90aa..558e1ca90 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: 113738 // 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 6e65cd239..c5f2e7343 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 c23a15ec0..509fd29ed 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 258ff350b..876a7f6c8 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 5dd4d48a6..89f575577 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 6b5d1f022..f77156d64 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 03a063bb8..f7083c7a0 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 21757ea40..4305687b7 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 44acf38e4..bdb60b877 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 6f88df394..abc10d8aa 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 fe791a68d..6c317598b 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 3356eac16..412b71d39 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 56ad74c54..433470160 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 433d1969c..0305fd473 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 c2c5f3cdc..d65af8e8c 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 04e993682..b250bea87 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 000000000..493cfc29b --- /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 000000000..e522ff61b --- /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 000000000..bf71e4d44 --- /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 000000000..334b427e1 --- /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 000000000..d99e558fd --- /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 000000000..6102f5a70 --- /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 000000000..d648e88d1 --- /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 000000000..09d27db60 --- /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 000000000..7d7809d2a --- /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 000000000..e4bf286ee --- /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 000000000..747ed6bd0 --- /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 38e0fb13f..6f1fbe7a9 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: 194717 +// 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 57942979a..3d5a480e4 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: 101495 diff --git a/test/libsolidity/semanticTests/various/destructuring_assignment.sol b/test/libsolidity/semanticTests/various/destructuring_assignment.sol index cc93152ea..23b6c9e58 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 9ba4e3cb7..109a27578 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 1c456f1d4..344daf8d8 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: 175589 // 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 30a2d9f65..971d83407 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 06faab882..d2c520545 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: 98438622 // gas legacy: 98438801 // gas legacyOptimized: 98438594 // fpure() -> FAILURE -// gas irOptimized: 98438625 +// gas irOptimized: 98438622 // 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 5d8bda5dd..879e9d23c 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: 190491 // 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 0b2b1735b..0499c1b06 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: 192213 // 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 6ef403dcc..5bd5fe137 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 24d0e9f14..31cf4ad69 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 975130c51..ea64676a8 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 b2e0cb546..26c0d8394 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 c5af58449..1c3f8410c 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 5c7c4cba8..6e126a150 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 5e5d1c962..cb23435d1 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 e802e3687..25a2f5f9a 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 05b7e668b..f1a6f592b 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 000000000..a4c823a85 --- /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 000000000..7c570e29e --- /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 000000000..7a35bfa55 --- /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 000000000..72efe4a07 --- /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 0e1cbddb8..59c8e2aa7 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 727ff2c46..415971017 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 000000000..6a928c3ad --- /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 83839f368..42de5ba41 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 ba141ce97..940a3b071 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 a1c20f9bd..48372263f 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 000000000..44cee5479 --- /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 000000000..219954238 --- /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 000000000..9df5e9c2c --- /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 000000000..36f3f3032 --- /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 000000000..7536dff07 --- /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 000000000..28a8e69ed --- /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 000000000..91b807397 --- /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 000000000..833b78266 --- /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 000000000..7af04c0a6 --- /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 000000000..b5f6d8827 --- /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 000000000..051874abc --- /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 000000000..232ffafad --- /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 000000000..458a644e9 --- /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 000000000..edaeea922 --- /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 000000000..1d149417f --- /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 000000000..972a34a8d --- /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 000000000..944720245 --- /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 000000000..7c3fc2891 --- /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 000000000..76d53cf90 --- /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 000000000..2fdb471ab --- /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 000000000..a2d3b9f99 --- /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 000000000..924208222 --- /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 000000000..f017363e6 --- /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 000000000..ef1688b22 --- /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 000000000..e216e4cfc --- /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 000000000..b8b9cb9a7 --- /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 000000000..b1dc8b706 --- /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 000000000..2b5d6a0dd --- /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 000000000..5180cfd20 --- /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 000000000..e03ba5d10 --- /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 000000000..62f8e4736 --- /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 000000000..07b607004 --- /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 000000000..67eee5862 --- /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 000000000..dfc0b916e --- /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 000000000..c4de282c4 --- /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 000000000..df3b3f65f --- /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 000000000..32d97345b --- /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 f74b256d0..f2a5db7af 100644 --- a/test/libsolidity/util/BytesUtils.cpp +++ b/test/libsolidity/util/BytesUtils.cpp @@ -22,6 +22,7 @@ #include #include +#include #include @@ -216,10 +217,10 @@ string BytesUtils::formatString(bytes const& _bytes, size_t _cutOff) os << "\\n"; break; default: - if (isprint(v)) + 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 6652f704a..11cfdbb86 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; @@ -762,13 +766,15 @@ string TestFileParser::Scanner::scanString() // TODO: use fromHex() from CommonData char TestFileParser::Scanner::scanHexPart() { + auto toLower = [](char _c) -> char { return tolower(_c, locale::classic()); }; + advance(); // skip 'x' int value{}; - if (isdigit(current())) + if (isDigit(current())) value = current() - '0'; - else if (tolower(current()) >= 'a' && tolower(current()) <= 'f') - value = tolower(current()) - 'a' + 10; + else if (toLower(current()) >= 'a' && toLower(current()) <= 'f') + value = toLower(current()) - 'a' + 10; else BOOST_THROW_EXCEPTION(TestParserError("\\x used with no following hex digits.")); @@ -777,10 +783,10 @@ char TestFileParser::Scanner::scanHexPart() return static_cast(value); value <<= 4; - if (isdigit(current())) + if (isDigit(current())) value |= current() - '0'; - else if (tolower(current()) >= 'a' && tolower(current()) <= 'f') - value |= tolower(current()) - 'a' + 10; + else if (toLower(current()) >= 'a' && toLower(current()) <= 'f') + value |= toLower(current()) - 'a' + 10; advance(); diff --git a/test/libsolidity/util/TestFunctionCall.cpp b/test/libsolidity/util/TestFunctionCall.cpp index 43805c8f9..c51dbec97 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 8986acc1b..679493f35 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 03cc4cd8d..ec2f0313d 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 @@ protected: 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 e7711f586..60826665a 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 000000000..78bf0a168 --- /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 cf0b2a044..cee19ab93 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 000000000..436f5d5fa --- /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 41b77c115..9a6381d79 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 a0ac5c36d..317661325 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 13683e8e6..75e2ff4c2 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 c5f4aa466..72c09d3dc 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 7b3360847..a60b3d348 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 b7f0b4afb..6f82ab27a 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 ee648f80f..7955ee12e 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_loop.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_loop.yul @@ -18,9 +18,9 @@ // { // { // f() +// f() +// f() // sstore(0, 1) -// f() -// f() // } // function f() // { diff --git a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_recursion.yul b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_recursion.yul index c3b75e84e..92d251cab 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 14f0137cb..b066d998b 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 68620cc96..785840baa 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_simple.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_simple.yul @@ -16,9 +16,9 @@ // { // { // f() +// f() +// f() // sstore(0, 1) -// f() -// f() // } // function f() // { 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 000000000..eeff779f8 --- /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 000000000..7fd227089 --- /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 000000000..47e0b95fa --- /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 000000000..c3183d9ec --- /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 000000000..782c68663 --- /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 000000000..cb69be363 --- /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 000000000..25f9355b3 --- /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 000000000..843f7f6e9 --- /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 000000000..7054dc255 --- /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 000000000..92a751554 --- /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 000000000..466cd02e5 --- /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 000000000..717332472 --- /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 000000000..524b328e9 --- /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 000000000..dda59873c --- /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 000000000..78179dc3e --- /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 000000000..2950a04ce --- /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 000000000..e7777964c --- /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 000000000..3bfd558fe --- /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 000000000..db5f060a6 --- /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 000000000..b0b42060f --- /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 000000000..855ae8325 --- /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 e521e6faa..604dca1f4 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 fc0fbcdb7..88aafad6b 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 000000000..58e2aad4d --- /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: +#