diff --git a/.circleci/config.yml b/.circleci/config.yml index 1b50f7583..65e7113a3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,16 +9,16 @@ version: 2.1 parameters: ubuntu-2004-docker-image: type: string - # solbuildpackpusher/solidity-buildpack-deps:ubuntu2004-10 - default: "solbuildpackpusher/solidity-buildpack-deps@sha256:e61939751ff9777307857361f712b581bfc8a8aaae75fab7b50febc764710587" + # solbuildpackpusher/solidity-buildpack-deps:ubuntu2004-11 + default: "solbuildpackpusher/solidity-buildpack-deps@sha256:9928dc357829e475e8729c62a1c2d495dbb41cb9fe4c4b115a5568be8e1ed69e" ubuntu-2004-clang-docker-image: type: string - # solbuildpackpusher/solidity-buildpack-deps:ubuntu2004.clang-10 - default: "solbuildpackpusher/solidity-buildpack-deps@sha256:0de8c68f084120b2a165406e3a0c2aab58b32f5b7182c2322245245f1d243b8d" + # solbuildpackpusher/solidity-buildpack-deps:ubuntu2004.clang-11 + default: "solbuildpackpusher/solidity-buildpack-deps@sha256:72fb9574c90e8ef908dce4c9dd9788ff4de708b504d970cd9146eed8911c313e" ubuntu-1604-clang-ossfuzz-docker-image: type: string - # solbuildpackpusher/solidity-buildpack-deps:ubuntu1604.clang.ossfuzz-15 - default: "solbuildpackpusher/solidity-buildpack-deps@sha256:87f1a57586eec194a6217ab624efc69d3d9af2f7ac8ca36497ad57488c2f08ae" + # solbuildpackpusher/solidity-buildpack-deps:ubuntu1604.clang.ossfuzz-16 + default: "solbuildpackpusher/solidity-buildpack-deps@sha256:fe54d8e5409827d43edb0dc8ad0d9e4232a675050ceb271c873b73e5ee267938" emscripten-docker-image: type: string # solbuildpackpusher/solidity-buildpack-deps:emscripten-9 diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..d50c44566 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +/docs/style-guide.rst @fulldecent diff --git a/Changelog.md b/Changelog.md index 073abe410..a6ce63a70 100644 --- a/Changelog.md +++ b/Changelog.md @@ -13,15 +13,15 @@ Breaking changes: ### 0.8.13 (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.12 (2022-02-16) Language Features: diff --git a/ReleaseChecklist.md b/ReleaseChecklist.md index 39a3d9a32..6d5008cb3 100644 --- a/ReleaseChecklist.md +++ b/ReleaseChecklist.md @@ -26,7 +26,11 @@ - [ ] Click the `PUBLISH RELEASE` button on the release page, creating the tag. - [ ] Wait for the CI runs on the tag itself. -### Download Binaries +### Upload Release Artifacts + - [ ] Switch to the tag that archives have to be created for. + - [ ] Create the ``prerelease.txt`` file: (``echo -n > prerelease.txt``). + - [ ] Run ``scripts/create_source_tarball.sh`` while being on the tag to create the source tarball. This will create the tarball in a directory called ``upload``. + - [ ] Take the tarball from the upload directory (its name should be ``solidity_x.x.x.tar.gz``, otherwise ``prerelease.txt`` was missing in the step before) and upload the source tarball to the release page. - [ ] Take the ``solc.exe`` binary from the ``b_win_release`` run of the released commit in circle-ci and add it to the release page as ``solc-windows.exe``. - [ ] Take the ``solc`` binary from the ``b_osx`` run of the released commit in circle-ci and add it to the release page as ``solc-macos``. - [ ] Take the ``solc`` binary from the ``b_ubu_static`` run of the released commit in circle-ci and add it to the release page as ``solc-static-linux``. diff --git a/docs/050-breaking-changes.rst b/docs/050-breaking-changes.rst index 90af86526..3f41ac860 100644 --- a/docs/050-breaking-changes.rst +++ b/docs/050-breaking-changes.rst @@ -89,8 +89,8 @@ For most of the topics the compiler will provide suggestions. * Explicit data location for all variables of struct, array or mapping types is now mandatory. This is also applied to function parameters and return - variables. For example, change ``uint[] x = m_x`` to ``uint[] storage x = - m_x``, and ``function f(uint[][] x)`` to ``function f(uint[][] memory x)`` + variables. For example, change ``uint[] x = z`` to ``uint[] storage x = + z``, and ``function f(uint[][] x)`` to ``function f(uint[][] memory x)`` where ``memory`` is the data location and might be replaced by ``storage`` or ``calldata`` accordingly. Note that ``external`` functions require parameters with a data location of ``calldata``. @@ -483,7 +483,7 @@ New version: return data; } - using address_make_payable for address; + using AddressMakePayable for address; // Data location for 'arr' must be specified function g(uint[] memory /* arr */, bytes8 x, OtherContract otherContract, address unknownContract) public payable { // 'otherContract.transfer' is not provided. @@ -500,7 +500,7 @@ New version: // 'address payable' should be used whenever possible. // To increase clarity, we suggest the use of a library for // the conversion (provided after the contract in this example). - address payable addr = unknownContract.make_payable(); + address payable addr = unknownContract.makePayable(); require(addr.send(1 ether)); // Since uint32 (4 bytes) is smaller than bytes8 (8 bytes), @@ -516,8 +516,8 @@ New version: // We can define a library for explicitly converting ``address`` // to ``address payable`` as a workaround. - library address_make_payable { - function make_payable(address x) internal pure returns (address payable) { + library AddressMakePayable { + function makePayable(address x) internal pure returns (address payable) { return address(uint160(x)); } } diff --git a/docs/assembly.rst b/docs/assembly.rst index c26a53e49..746da43c1 100644 --- a/docs/assembly.rst +++ b/docs/assembly.rst @@ -45,19 +45,19 @@ 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 o_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) // allocate output byte array - this could also be done without assembly - // by using o_code = new bytes(size) - o_code := mload(0x40) + // by using code = new bytes(size) + code := mload(0x40) // new "memory end" including padding - mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f)))) + mstore(0x40, add(code, and(add(add(size, 0x20), 0x1f), not(0x1f)))) // store length in memory - mstore(o_code, size) + mstore(code, size) // actually retrieve the code, this needs assembly - extcodecopy(_addr, add(o_code, 0x20), 0, size) + extcodecopy(_addr, add(code, 0x20), 0, size) } } } @@ -139,7 +139,7 @@ the variable will not point beyond ``calldatasize()`` is performed. For external function pointers the address and the function selector can be accessed using ``x.address`` and ``x.selector``. The selector consists of four right-aligned bytes. -Both values are can be assigned to. For example: +Both values can be assigned to. For example: .. code-block:: solidity :force: @@ -228,6 +228,11 @@ of their block is reached. Conventions in Solidity ----------------------- +.. _assembly-typed-variables: + +Values of Typed Variables +========================= + In contrast to EVM assembly, Solidity has types which are narrower than 256 bits, e.g. ``uint24``. For efficiency, most arithmetic operations ignore the fact that types can be shorter than 256 @@ -237,6 +242,11 @@ This means that if you access such a variable from within inline assembly, you might have to manually clean the higher-order bits first. +.. _assembly-memory-management: + +Memory Management +================= + Solidity manages memory in the following way. There is a "free memory pointer" at position ``0x40`` in memory. If you want to allocate memory, use the memory starting from where this pointer points at and update it. @@ -268,3 +278,99 @@ first slot of the array and followed by the array elements. Statically-sized memory arrays do not have a length field, but it might be added later to allow better convertibility between statically- and dynamically-sized arrays, so do not rely on this. + +Memory Safety +============= + +Without the use of inline assembly, the compiler can rely on memory to remain in a well-defined +state at all times. This is especially relevant for :ref:`the new code generation pipeline via Yul IR `: +this code generation path can move local variables from stack to memory to avoid stack-too-deep errors and +perform additional memory optimizations, if it can rely on certain assumptions about memory use. + +While we recommend to always respect Solidity's memory model, inline assembly allows you to use memory +in an incompatible way. Therefore, moving stack variables to memory and additional memory optimizations are, +by default, disabled in the presence of any inline assembly block that contains a memory operation or assigns +to solidity variables in memory. + +However, you can specifically annotate an assembly block to indicate that it in fact respects Solidity's memory +model as follows: + +.. code-block:: solidity + + assembly ("memory-safe") { + ... + } + +In particular, a memory-safe assembly block may only access the following memory ranges: + +- Memory allocated by yourself using a mechanism like the ``allocate`` function described above. +- Memory allocated by Solidity, e.g. memory within the bounds of a memory array you reference. +- The scratch space between memory offset 0 and 64 mentioned above. +- Temporary memory that is located *after* the value of the free memory pointer at the beginning of the assembly block, + i.e. memory that is "allocated" at the free memory pointer without updating the free memory pointer. + +Furthermore, if the assembly block assigns to Solidity variables in memory, you need to assure that accesses to +the Solidity variables only access these memory ranges. + +Since this is mainly about the optimizer, these restrictions still need to be followed, even if the assembly block +reverts or terminates. As an example, the following assembly snippet is not memory safe: + +.. code-block:: solidity + + assembly { + returndatacopy(0, 0, returndatasize()) + revert(0, returndatasize()) + } + +But the following is: + +.. code-block:: solidity + + assembly ("memory-safe") { + let p := mload(0x40) + returndatacopy(p, 0, returndatasize()) + revert(p, returndatasize()) + } + +Note that you do not need to update the free memory pointer if there is no following allocation, +but you can only use memory starting from the current offset given by the free memory pointer. + +If the memory operations use a length of zero, it is also fine to just use any offset (not only if it falls into the scratch space): + +.. code-block:: solidity + + assembly ("memory-safe") { + revert(0, 0) + } + +Note that not only memory operations in inline assembly itself can be memory-unsafe, but also assignments to +solidity variables of reference type in memory. For example the following is not memory-safe: + +.. code-block:: solidity + + bytes memory x; + assembly { + x := 0x40 + } + x[0x20] = 0x42; + +Inline assembly that neither involves any operations that access memory nor assigns to any solidity variables +in memory is automatically considered memory-safe and does not need to be annotated. + +.. warning:: + It is your responsibility to make sure that the assembly actually satisfies the memory model. If you annotate + an assembly block as memory-safe, but violate one of the memory assumptions, this **will** lead to incorrect and + undefined behaviour that cannot easily be discovered by testing. + +In case you are developing a library that is meant to be compatible across multiple versions +of solidity, you can use a special comment to annotate an assembly block as memory-safe: + +.. code-block:: solidity + + /// @solidity memory-safe-assembly + assembly { + ... + } + +Note that we will disallow the annotation via comment in a future breaking release, so if you are not concerned with +backwards-compatibility with older compiler versions, prefer using the dialect string. diff --git a/docs/contracts/functions.rst b/docs/contracts/functions.rst index 28eca096c..cc820d25e 100644 --- a/docs/contracts/functions.rst +++ b/docs/contracts/functions.rst @@ -102,10 +102,10 @@ two integers passed as function parameters, then you use something like: function arithmetic(uint _a, uint _b) public pure - returns (uint o_sum, uint o_product) + returns (uint sum, uint product) { - o_sum = _a + _b; - o_product = _a * _b; + sum = _a + _b; + product = _a * _b; } } @@ -129,7 +129,7 @@ statement: function arithmetic(uint _a, uint _b) public pure - returns (uint o_sum, uint o_product) + returns (uint sum, uint product) { return (_a + _b, _a * _b); } diff --git a/docs/contracts/using-for.rst b/docs/contracts/using-for.rst index 582409904..af6750f87 100644 --- a/docs/contracts/using-for.rst +++ b/docs/contracts/using-for.rst @@ -120,7 +120,7 @@ It is also possible to extend elementary types in that way: } Note that all external library calls are actual EVM function calls. This means that -if you pass memory or value types, a copy will be performed, even of the +if you pass memory or value types, a copy will be performed, even in case of the ``self`` variable. The only situation where no copy will be performed is when storage reference variables are used or when internal library functions are called. diff --git a/docs/grammar/SolidityLexer.g4 b/docs/grammar/SolidityLexer.g4 index 5a73be85f..653255ae3 100644 --- a/docs/grammar/SolidityLexer.g4 +++ b/docs/grammar/SolidityLexer.g4 @@ -251,6 +251,12 @@ mode AssemblyBlockMode; AssemblyDialect: '"evmasm"'; AssemblyLBrace: '{' -> popMode, pushMode(YulMode); +AssemblyFlagString: '"' DoubleQuotedStringCharacter+ '"'; + +AssemblyBlockLParen: '('; +AssemblyBlockRParen: ')'; +AssemblyBlockComma: ','; + AssemblyBlockWS: [ \t\r\n\u000C]+ -> skip ; AssemblyBlockCOMMENT: '/*' .*? '*/' -> channel(HIDDEN) ; AssemblyBlockLINE_COMMENT: '//' ~[\r\n]* -> channel(HIDDEN) ; diff --git a/docs/grammar/SolidityParser.g4 b/docs/grammar/SolidityParser.g4 index 110773fed..e41bb2ba9 100644 --- a/docs/grammar/SolidityParser.g4 +++ b/docs/grammar/SolidityParser.g4 @@ -476,7 +476,13 @@ revertStatement: Revert expression callArgumentList Semicolon; * The contents of an inline assembly block use a separate scanner/lexer, i.e. the set of keywords and * allowed identifiers is different inside an inline assembly block. */ -assemblyStatement: Assembly AssemblyDialect? AssemblyLBrace yulStatement* YulRBrace; +assemblyStatement: Assembly AssemblyDialect? assemblyFlags? AssemblyLBrace yulStatement* YulRBrace; + +/** + * Assembly flags. + * Comma-separated list of double-quoted strings as flags. + */ +assemblyFlags: AssemblyBlockLParen AssemblyFlagString (AssemblyBlockComma AssemblyFlagString)* AssemblyBlockRParen; //@doc:inline variableDeclarationList: variableDeclarations+=variableDeclaration (Comma variableDeclarations+=variableDeclaration)*; diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst index fa2fa34c1..94188a097 100644 --- a/docs/introduction-to-smart-contracts.rst +++ b/docs/introduction-to-smart-contracts.rst @@ -10,7 +10,7 @@ A Simple Smart Contract Let us begin with a basic example that sets the value of a variable and exposes it for other contracts to access. It is fine if you do not understand -everything right now, we will go into more detail later. +everything right now, we will go into more details later. Storage Example =============== diff --git a/docs/ir-breaking-changes.rst b/docs/ir-breaking-changes.rst index c1f6deb57..3fce53b3b 100644 --- a/docs/ir-breaking-changes.rst +++ b/docs/ir-breaking-changes.rst @@ -1,6 +1,8 @@ .. index: ir breaking changes +.. _ir-breaking-changes: + ********************************* Solidity IR-based Codegen Changes ********************************* diff --git a/docs/style-guide.rst b/docs/style-guide.rst index a3d3f69a5..3b76273cc 100644 --- a/docs/style-guide.rst +++ b/docs/style-guide.rst @@ -204,7 +204,7 @@ Yes: .. code-block:: solidity - thisIsALongNestedMapping[being][set][to_some_value] = someFunction( + thisIsALongNestedMapping[being][set][toSomeValue] = someFunction( argument1, argument2, argument3, @@ -215,7 +215,7 @@ No: .. code-block:: solidity - thisIsALongNestedMapping[being][set][to_some_value] = someFunction(argument1, + thisIsALongNestedMapping[being][set][toSomeValue] = someFunction(argument1, argument2, argument3, argument4); @@ -439,15 +439,15 @@ Yes: x = 1; y = 2; - long_variable = 3; + longVariable = 3; No: .. code-block:: solidity - x = 1; - y = 2; - long_variable = 3; + x = 1; + y = 2; + longVariable = 3; Don't include a whitespace in the receive and fallback functions: @@ -1092,12 +1092,10 @@ naming styles. * ``b`` (single lowercase letter) * ``B`` (single uppercase letter) * ``lowercase`` -* ``lower_case_with_underscores`` * ``UPPERCASE`` * ``UPPER_CASE_WITH_UNDERSCORES`` * ``CapitalizedWords`` (or CapWords) * ``mixedCase`` (differs from CapitalizedWords by initial lowercase character!) -* ``Capitalized_Words_With_Underscores`` .. note:: When using initialisms in CapWords, capitalize all the letters of the initialisms. Thus HTTPServerError is better than HttpServerError. When using initialisms in mixedCase, capitalize all the letters of the initialisms, except keep the first one lower case if it is the beginning of the name. Thus xmlHTTPRequest is better than XMLHTTPRequest. @@ -1256,7 +1254,7 @@ Enums, in the style of simple type declarations, should be named using the CapWo Avoiding Naming Collisions ========================== -* ``single_trailing_underscore_`` +* ``singleTrailingUnderscore_`` This convention is suggested when the desired name collides with that of a built-in or otherwise reserved name. diff --git a/docs/types/mapping-types.rst b/docs/types/mapping-types.rst index 18f3bf827..399523cf2 100644 --- a/docs/types/mapping-types.rst +++ b/docs/types/mapping-types.rst @@ -126,7 +126,7 @@ the ``sum`` function iterates over to sum all the values. :force: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >=0.6.8 <0.9.0; + pragma solidity ^0.8.8; struct IndexValue { uint keyIndex; uint value; } struct KeyFlag { uint key; bool deleted; } @@ -137,6 +137,8 @@ the ``sum`` function iterates over to sum all the values. uint size; } + type Iterator is uint; + library IterableMapping { function insert(itmap storage self, uint key, uint value) internal returns (bool replaced) { uint keyIndex = self.data[key].keyIndex; @@ -166,25 +168,29 @@ the ``sum`` function iterates over to sum all the values. return self.data[key].keyIndex > 0; } - function iterate_start(itmap storage self) internal view returns (uint keyIndex) { - return iterate_next(self, type(uint).max); + function iterateStart(itmap storage self) internal view returns (Iterator) { + return iteratorSkipDeleted(self, 0); } - function iterate_valid(itmap storage self, uint keyIndex) internal view returns (bool) { - return keyIndex < self.keys.length; + function iterateValid(itmap storage self, Iterator iterator) internal view returns (bool) { + return Iterator.unwrap(iterator) < self.keys.length; } - function iterate_next(itmap storage self, uint keyIndex) internal view returns (uint r_keyIndex) { - keyIndex++; - while (keyIndex < self.keys.length && self.keys[keyIndex].deleted) - keyIndex++; - return keyIndex; + function iterateNext(itmap storage self, Iterator iterator) internal view returns (Iterator) { + return iteratorSkipDeleted(self, Iterator.unwrap(iterator) + 1); } - function iterate_get(itmap storage self, uint keyIndex) internal view returns (uint key, uint value) { + function iterateGet(itmap storage self, Iterator iterator) internal view returns (uint key, uint value) { + uint keyIndex = Iterator.unwrap(iterator); key = self.keys[keyIndex].key; value = self.data[key].value; } + + function iteratorSkipDeleted(itmap storage self, uint keyIndex) private view returns (Iterator) { + while (keyIndex < self.keys.length && self.keys[keyIndex].deleted) + keyIndex++; + return Iterator.wrap(keyIndex); + } } // How to use it @@ -206,11 +212,11 @@ the ``sum`` function iterates over to sum all the values. // Computes the sum of all stored data. function sum() public view returns (uint s) { for ( - uint i = data.iterate_start(); - data.iterate_valid(i); - i = data.iterate_next(i) + Iterator i = data.iterateStart(); + data.iterateValid(i); + i = data.iterateNext(i) ) { - (, uint value) = data.iterate_get(i); + (, uint value) = data.iterateGet(i); s += value; } } diff --git a/docs/types/reference-types.rst b/docs/types/reference-types.rst index 014c49935..f595612c0 100644 --- a/docs/types/reference-types.rst +++ b/docs/types/reference-types.rst @@ -190,11 +190,11 @@ If you want to use string parameters or other types that are not implicitly conv contract C { string s = "Storage"; function f(bytes calldata bc, string memory sm, bytes16 b) public view { - string memory concat_string = string.concat(s, string(bc), "Literal", sm); - assert((bytes(s).length + bc.length + 7 + bytes(sm).length) == bytes(concat_string).length); + string memory concatString = string.concat(s, string(bc), "Literal", sm); + assert((bytes(s).length + bc.length + 7 + bytes(sm).length) == bytes(concatString).length); - bytes memory concat_bytes = bytes.concat(bytes(s), bc, bc[:2], "Literal", bytes(sm), b); - assert((bytes(s).length + bc.length + 2 + 7 + bytes(sm).length + b.length) == concat_bytes.length); + bytes memory concatBytes = bytes.concat(bytes(s), bc, bc[:2], "Literal", bytes(sm), b); + assert((bytes(s).length + bc.length + 2 + 7 + bytes(sm).length + b.length) == concatBytes.length); } } @@ -376,20 +376,20 @@ Array Members pragma solidity >=0.6.0 <0.9.0; contract ArrayContract { - uint[2**20] m_aLotOfIntegers; + uint[2**20] aLotOfIntegers; // Note that the following is not a pair of dynamic arrays but a // dynamic array of pairs (i.e. of fixed size arrays of length two). // Because of that, T[] is always a dynamic array of T, even if T // itself is an array. // Data location for all state variables is storage. - bool[2][] m_pairsOfFlags; + bool[2][] pairsOfFlags; // newPairs is stored in memory - the only possibility // for public contract function arguments function setAllFlagPairs(bool[2][] memory newPairs) public { // assignment to a storage array performs a copy of ``newPairs`` and - // replaces the complete array ``m_pairsOfFlags``. - m_pairsOfFlags = newPairs; + // replaces the complete array ``pairsOfFlags``. + pairsOfFlags = newPairs; } struct StructType { @@ -411,45 +411,45 @@ Array Members function setFlagPair(uint index, bool flagA, bool flagB) public { // access to a non-existing index will throw an exception - m_pairsOfFlags[index][0] = flagA; - m_pairsOfFlags[index][1] = flagB; + pairsOfFlags[index][0] = flagA; + pairsOfFlags[index][1] = flagB; } function changeFlagArraySize(uint newSize) public { // using push and pop is the only way to change the // length of an array - if (newSize < m_pairsOfFlags.length) { - while (m_pairsOfFlags.length > newSize) - m_pairsOfFlags.pop(); - } else if (newSize > m_pairsOfFlags.length) { - while (m_pairsOfFlags.length < newSize) - m_pairsOfFlags.push(); + if (newSize < pairsOfFlags.length) { + while (pairsOfFlags.length > newSize) + pairsOfFlags.pop(); + } else if (newSize > pairsOfFlags.length) { + while (pairsOfFlags.length < newSize) + pairsOfFlags.push(); } } function clear() public { // these clear the arrays completely - delete m_pairsOfFlags; - delete m_aLotOfIntegers; + delete pairsOfFlags; + delete aLotOfIntegers; // identical effect here - m_pairsOfFlags = new bool[2][](0); + pairsOfFlags = new bool[2][](0); } - bytes m_byteData; + bytes byteData; function byteArrays(bytes memory data) public { // byte arrays ("bytes") are different as they are stored without padding, // but can be treated identical to "uint8[]" - m_byteData = data; + byteData = data; for (uint i = 0; i < 7; i++) - m_byteData.push(); - m_byteData[3] = 0x08; - delete m_byteData[2]; + byteData.push(); + byteData[3] = 0x08; + delete byteData[2]; } function addFlag(bool[2] memory flag) public returns (uint) { - m_pairsOfFlags.push(flag); - return m_pairsOfFlags.length; + pairsOfFlags.push(flag); + return pairsOfFlags.length; } function createMemoryArray(uint size) public pure returns (bytes memory) { diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index 327912c26..5a3fe4881 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -409,12 +409,13 @@ Input Description "source1.sol": ["contract1"], "source2.sol": ["contract2", "contract3"] }, - // Choose whether division and modulo operations should be replaced by - // multiplication with slack variables. Default is `true`. - // Using `false` here is recommended if you are using the CHC engine + // Choose how division and modulo operations should be encoded. + // When using `false` they are replaced by multiplication with slack + // variables. This is the default. + // Using `true` here is recommended if you are using the CHC engine // and not using Spacer as the Horn solver (using Eldarica, for example). // See the Formal Verification section for a more detailed explanation of this option. - "divModWithSlacks": true, + "divModNoSlacks": false, // Choose which model checker engine to use: all (default), bmc, chc, none. "engine": "chc", // Choose which types of invariants should be reported to the user: contract, reentrancy. diff --git a/docs/yul.rst b/docs/yul.rst index 60a2da5b9..e4775ee4d 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -768,7 +768,7 @@ the ``dup`` and ``swap`` instructions as well as ``jump`` instructions, labels a +-------------------------+-----+---+-----------------------------------------------------------------+ | Instruction | | | Explanation | +=========================+=====+===+=================================================================+ -| stop() + `-` | F | stop execution, identical to return(0, 0) | +| stop() | `-` | F | stop execution, identical to return(0, 0) | +-------------------------+-----+---+-----------------------------------------------------------------+ | add(x, y) | | F | x + y | +-------------------------+-----+---+-----------------------------------------------------------------+ diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 12c7be230..55d23e283 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -397,26 +397,6 @@ AssemblyItem Assembly::newImmutableAssignment(string const& _identifier) return AssemblyItem{AssignImmutable, h}; } -Assembly& Assembly::optimise(bool _enable, EVMVersion _evmVersion, bool _isCreation, size_t _runs) -{ - OptimiserSettings settings; - settings.isCreation = _isCreation; - settings.runInliner = true; - settings.runJumpdestRemover = true; - settings.runPeephole = true; - if (_enable) - { - settings.runDeduplicate = true; - settings.runCSE = true; - settings.runConstantOptimiser = true; - } - settings.evmVersion = _evmVersion; - settings.expectedExecutionsPerDeployment = _runs; - optimise(settings); - return *this; -} - - Assembly& Assembly::optimise(OptimiserSettings const& _settings) { optimiseInternal(_settings, {}); diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index f768ffe31..97807e223 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -134,13 +134,6 @@ public: /// is optimised according to the settings in @a _settings. Assembly& optimise(OptimiserSettings const& _settings); - /// Modify (if @a _enable is set) and return the current assembly such that creation and - /// execution gas usage is optimised. @a _isCreation should be true for the top-level assembly. - /// @a _runs specifes an estimate on how often each opcode in this assembly will be executed, - /// i.e. use a small value to optimise for size and a large value to optimise for runtime. - /// If @a _enable is not set, will perform some simple peephole optimizations. - Assembly& optimise(bool _enable, langutil::EVMVersion _evmVersion, bool _isCreation, size_t _runs); - /// Create a text representation of the assembly. std::string assemblyString( langutil::DebugInfoSelection const& _debugInfoSelection = langutil::DebugInfoSelection::Default(), diff --git a/libevmasm/AssemblyItem.h b/libevmasm/AssemblyItem.h index 1cbfe768d..796a792e8 100644 --- a/libevmasm/AssemblyItem.h +++ b/libevmasm/AssemblyItem.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/libevmasm/CMakeLists.txt b/libevmasm/CMakeLists.txt index 4e392aadd..6563b2c0f 100644 --- a/libevmasm/CMakeLists.txt +++ b/libevmasm/CMakeLists.txt @@ -11,6 +11,8 @@ set(sources ConstantOptimiser.h ControlFlowGraph.cpp ControlFlowGraph.h + Disassemble.cpp + Disassemble.h Exceptions.h ExpressionClasses.cpp ExpressionClasses.h diff --git a/libevmasm/ConstantOptimiser.h b/libevmasm/ConstantOptimiser.h index d094bff73..ece28d249 100644 --- a/libevmasm/ConstantOptimiser.h +++ b/libevmasm/ConstantOptimiser.h @@ -26,6 +26,7 @@ #include +#include #include #include diff --git a/libevmasm/Disassemble.cpp b/libevmasm/Disassemble.cpp new file mode 100644 index 000000000..aa5b2820c --- /dev/null +++ b/libevmasm/Disassemble.cpp @@ -0,0 +1,76 @@ +/* + 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 + +using namespace std; +using namespace solidity; +using namespace solidity::util; +using namespace solidity::evmasm; + + +void solidity::evmasm::eachInstruction( + bytes const& _mem, + function const& _onInstruction +) +{ + for (auto it = _mem.begin(); it < _mem.end(); ++it) + { + Instruction const instr{*it}; + int additional = 0; + if (isValidInstruction(instr)) + additional = instructionInfo(instr).additional; + + u256 data{}; + + // fill the data with the additional data bytes from the instruction stream + while (additional > 0 && std::next(it) < _mem.end()) + { + data <<= 8; + data |= *++it; + --additional; + } + + // pad the remaining number of additional octets with zeros + data <<= 8 * additional; + + _onInstruction(instr, data); + } +} + +string solidity::evmasm::disassemble(bytes const& _mem, string const& _delimiter) +{ + stringstream ret; + eachInstruction(_mem, [&](Instruction _instr, u256 const& _data) { + if (!isValidInstruction(_instr)) + ret << "0x" << std::uppercase << std::hex << static_cast(_instr) << _delimiter; + else + { + InstructionInfo info = instructionInfo(_instr); + ret << info.name; + if (info.additional) + ret << " 0x" << std::uppercase << std::hex << _data; + ret << _delimiter; + } + }); + return ret.str(); +} diff --git a/libevmasm/Disassemble.h b/libevmasm/Disassemble.h new file mode 100644 index 000000000..cf194e24b --- /dev/null +++ b/libevmasm/Disassemble.h @@ -0,0 +1,38 @@ +/* + 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::evmasm +{ + +/// Iterate through EVM code and call a function on each instruction. +void eachInstruction(bytes const& _mem, std::function const& _onInstruction); + +/// Convert from EVM code to simple EVM assembly language. +std::string disassemble(bytes const& _mem, std::string const& _delimiter = " "); + +} diff --git a/libevmasm/Instruction.cpp b/libevmasm/Instruction.cpp index 7ce36c254..e2ce48b7f 100644 --- a/libevmasm/Instruction.cpp +++ b/libevmasm/Instruction.cpp @@ -22,10 +22,6 @@ #include -#include -#include -#include - using namespace std; using namespace solidity; using namespace solidity::util; @@ -325,53 +321,6 @@ static std::map const c_instructionInfo = { Instruction::SELFDESTRUCT, { "SELFDESTRUCT", 0, 1, 0, true, Tier::Special } } }; -void solidity::evmasm::eachInstruction( - bytes const& _mem, - function const& _onInstruction -) -{ - for (auto it = _mem.begin(); it < _mem.end(); ++it) - { - auto instr = Instruction(*it); - int additional = 0; - if (isValidInstruction(instr)) - additional = instructionInfo(instr).additional; - - u256 data; - - // fill the data with the additional data bytes from the instruction stream - while (additional > 0 && std::next(it) < _mem.end()) - { - data <<= 8; - data |= *++it; - --additional; - } - - // pad the remaining number of additional octets with zeros - data <<= 8 * additional; - - _onInstruction(instr, data); - } -} - -string solidity::evmasm::disassemble(bytes const& _mem, string const& _delimiter) -{ - stringstream ret; - eachInstruction(_mem, [&](Instruction _instr, u256 const& _data) { - if (!isValidInstruction(_instr)) - ret << "0x" << std::uppercase << std::hex << static_cast(_instr) << _delimiter; - else - { - InstructionInfo info = instructionInfo(_instr); - ret << info.name; - if (info.additional) - ret << " 0x" << std::uppercase << std::hex << _data; - ret << _delimiter; - } - }); - return ret.str(); -} - InstructionInfo solidity::evmasm::instructionInfo(Instruction _inst) { try @@ -380,7 +329,7 @@ InstructionInfo solidity::evmasm::instructionInfo(Instruction _inst) } catch (...) { - return InstructionInfo({"", 0, 0, 0, false, Tier::Invalid}); + return InstructionInfo({"(_inst)) + ">", 0, 0, 0, false, Tier::Invalid}); } } diff --git a/libevmasm/Instruction.h b/libevmasm/Instruction.h index ad6bc9796..52bda8bf1 100644 --- a/libevmasm/Instruction.h +++ b/libevmasm/Instruction.h @@ -25,8 +25,6 @@ #include #include #include -#include -#include namespace solidity::evmasm { @@ -217,25 +215,25 @@ inline bool isLogInstruction(Instruction _inst) /// @returns the number of PUSH Instruction _inst inline unsigned getPushNumber(Instruction _inst) { - return (uint8_t)_inst - unsigned(Instruction::PUSH1) + 1; + return static_cast(_inst) - unsigned(Instruction::PUSH1) + 1; } /// @returns the number of DUP Instruction _inst inline unsigned getDupNumber(Instruction _inst) { - return (uint8_t)_inst - unsigned(Instruction::DUP1) + 1; + return static_cast(_inst) - unsigned(Instruction::DUP1) + 1; } /// @returns the number of SWAP Instruction _inst inline unsigned getSwapNumber(Instruction _inst) { - return (uint8_t)_inst - unsigned(Instruction::SWAP1) + 1; + return static_cast(_inst) - unsigned(Instruction::SWAP1) + 1; } /// @returns the number of LOG Instruction _inst inline unsigned getLogNumber(Instruction _inst) { - return (uint8_t)_inst - unsigned(Instruction::LOG0); + return static_cast(_inst) - unsigned(Instruction::LOG0); } /// @returns the PUSH<_number> instruction @@ -266,7 +264,7 @@ inline Instruction logInstruction(unsigned _number) return Instruction(unsigned(Instruction::LOG0) + _number); } -enum class Tier : unsigned +enum class Tier { Zero = 0, // 0, Zero Base, // 2, Quick @@ -301,10 +299,4 @@ bool isValidInstruction(Instruction _inst); /// Convert from string mnemonic to Instruction type. extern const std::map c_instructions; -/// Iterate through EVM code and call a function on each instruction. -void eachInstruction(bytes const& _mem, std::function const& _onInstruction); - -/// Convert from EVM code to simple EVM assembly language. -std::string disassemble(bytes const& _mem, std::string const& _delimiter = " "); - } diff --git a/libevmasm/SemanticInformation.cpp b/libevmasm/SemanticInformation.cpp index 177208f0b..bda02b5e4 100644 --- a/libevmasm/SemanticInformation.cpp +++ b/libevmasm/SemanticInformation.cpp @@ -29,6 +29,125 @@ using namespace std; using namespace solidity; using namespace solidity::evmasm; +vector SemanticInformation::readWriteOperations(Instruction _instruction) +{ + switch (_instruction) + { + case Instruction::SSTORE: + case Instruction::SLOAD: + { + assertThrow(memory(_instruction) == Effect::None, OptimizerException, ""); + assertThrow(storage(_instruction) != Effect::None, OptimizerException, ""); + Operation op; + op.effect = storage(_instruction); + op.location = Location::Storage; + op.startParameter = 0; + // We know that exactly one slot is affected. + op.lengthConstant = 1; + return {op}; + } + case Instruction::MSTORE: + case Instruction::MSTORE8: + case Instruction::MLOAD: + { + assertThrow(memory(_instruction) != Effect::None, OptimizerException, ""); + assertThrow(storage(_instruction) == Effect::None, OptimizerException, ""); + Operation op; + op.effect = memory(_instruction); + op.location = Location::Memory; + op.startParameter = 0; + if (_instruction == Instruction::MSTORE || _instruction == Instruction::MLOAD) + op.lengthConstant = 32; + else if (_instruction == Instruction::MSTORE8) + op.lengthConstant = 1; + + return {op}; + } + case Instruction::REVERT: + case Instruction::RETURN: + case Instruction::KECCAK256: + case Instruction::LOG0: + case Instruction::LOG1: + case Instruction::LOG2: + case Instruction::LOG3: + case Instruction::LOG4: + { + assertThrow(storage(_instruction) == Effect::None, OptimizerException, ""); + assertThrow(memory(_instruction) == Effect::Read, OptimizerException, ""); + Operation op; + op.effect = memory(_instruction); + op.location = Location::Memory; + op.startParameter = 0; + op.lengthParameter = 1; + return {op}; + } + case Instruction::EXTCODECOPY: + { + assertThrow(memory(_instruction) == Effect::Write, OptimizerException, ""); + assertThrow(storage(_instruction) == Effect::None, OptimizerException, ""); + Operation op; + op.effect = memory(_instruction); + op.location = Location::Memory; + op.startParameter = 1; + op.lengthParameter = 3; + return {op}; + } + case Instruction::CODECOPY: + case Instruction::CALLDATACOPY: + case Instruction::RETURNDATACOPY: + { + assertThrow(memory(_instruction) == Effect::Write, OptimizerException, ""); + assertThrow(storage(_instruction) == Effect::None, OptimizerException, ""); + Operation op; + op.effect = memory(_instruction); + op.location = Location::Memory; + op.startParameter = 0; + op.lengthParameter = 2; + return {op}; + } + case Instruction::STATICCALL: + case Instruction::CALL: + case Instruction::CALLCODE: + case Instruction::DELEGATECALL: + { + size_t paramCount = static_cast(instructionInfo(_instruction).args); + vector operations{ + Operation{Location::Memory, Effect::Read, paramCount - 4, paramCount - 3, {}}, + Operation{Location::Storage, Effect::Read, {}, {}, {}} + }; + if (_instruction != Instruction::STATICCALL) + operations.emplace_back(Operation{Location::Storage, Effect::Write, {}, {}, {}}); + operations.emplace_back(Operation{ + Location::Memory, + Effect::Write, + paramCount - 2, + paramCount - 1, + {} + }); + return operations; + } + case Instruction::CREATE: + case Instruction::CREATE2: + return vector{ + Operation{ + Location::Memory, + Effect::Read, + 1, + 2, + {} + }, + Operation{Location::Storage, Effect::Read, {}, {}, {}}, + Operation{Location::Storage, Effect::Write, {}, {}, {}} + }; + case Instruction::MSIZE: + // This is just to satisfy the assert below. + return vector{}; + default: + assertThrow(storage(_instruction) == None && memory(_instruction) == None, AssemblyException, ""); + } + return {}; +} + bool SemanticInformation::breaksCSEAnalysisBlock(AssemblyItem const& _item, bool _msizeImportant) { switch (_item.type()) @@ -49,7 +168,7 @@ bool SemanticInformation::breaksCSEAnalysisBlock(AssemblyItem const& _item, bool case PushLibraryAddress: case PushImmutable: return false; - case Operation: + case evmasm::Operation: { if (isSwapInstruction(_item) || isDupInstruction(_item)) return false; @@ -79,7 +198,7 @@ bool SemanticInformation::breaksCSEAnalysisBlock(AssemblyItem const& _item, bool bool SemanticInformation::isCommutativeOperation(AssemblyItem const& _item) { - if (_item.type() != Operation) + if (_item.type() != evmasm::Operation) return false; switch (_item.instruction()) { @@ -97,14 +216,14 @@ bool SemanticInformation::isCommutativeOperation(AssemblyItem const& _item) bool SemanticInformation::isDupInstruction(AssemblyItem const& _item) { - if (_item.type() != Operation) + if (_item.type() != evmasm::Operation) return false; return evmasm::isDupInstruction(_item.instruction()); } bool SemanticInformation::isSwapInstruction(AssemblyItem const& _item) { - if (_item.type() != Operation) + if (_item.type() != evmasm::Operation) return false; return evmasm::isSwapInstruction(_item.instruction()); } @@ -116,7 +235,7 @@ bool SemanticInformation::isJumpInstruction(AssemblyItem const& _item) bool SemanticInformation::altersControlFlow(AssemblyItem const& _item) { - if (_item.type() != Operation) + if (_item.type() != evmasm::Operation) return false; switch (_item.instruction()) { @@ -166,7 +285,7 @@ bool SemanticInformation::isDeterministic(AssemblyItem const& _item) { assertThrow(_item.type() != VerbatimBytecode, AssemblyException, ""); - if (_item.type() != Operation) + if (_item.type() != evmasm::Operation) return true; switch (_item.instruction()) diff --git a/libevmasm/SemanticInformation.h b/libevmasm/SemanticInformation.h index 8ba2743c4..36aabd55f 100644 --- a/libevmasm/SemanticInformation.h +++ b/libevmasm/SemanticInformation.h @@ -26,6 +26,9 @@ #include +#include +#include + namespace solidity::evmasm { @@ -45,6 +48,32 @@ struct SemanticInformation Write }; + enum class Location { Storage, Memory }; + + /** + * Represents a read or write operation from or to one of the data locations. + */ + struct Operation + { + Location location; + Effect effect; + /// Start of affected area as an index into the parameters. + /// Unknown if not provided. + std::optional startParameter; + /// Length of the affected area as an index into the parameters (if this is an opcode). + /// Unknown if neither this nor lengthConstant is provided. + std::optional lengthParameter; + /// Length as a constant. + /// Unknown if neither this nor lengthArgument is provided. + std::optional lengthConstant; + }; + + /// @returns the sequence of read write operations performed by the instruction. + /// Order matters. + /// For external calls, there is just one unknown read and one unknown write operation, + /// event though there might be multiple. + static std::vector readWriteOperations(Instruction _instruction); + /// @returns true if the given items starts a new block for common subexpression analysis. /// @param _msizeImportant if false, consider an operation non-breaking if its only side-effect is that it modifies msize. static bool breaksCSEAnalysisBlock(AssemblyItem const& _item, bool _msizeImportant); diff --git a/libsolidity/analysis/DocStringTagParser.cpp b/libsolidity/analysis/DocStringTagParser.cpp index 137cdb409..1dc2711ef 100644 --- a/libsolidity/analysis/DocStringTagParser.cpp +++ b/libsolidity/analysis/DocStringTagParser.cpp @@ -30,6 +30,7 @@ #include #include +#include #include @@ -162,6 +163,81 @@ bool DocStringTagParser::visit(ErrorDefinition const& _error) return true; } +bool DocStringTagParser::visit(InlineAssembly const& _assembly) +{ + if (!_assembly.documentation()) + return true; + StructuredDocumentation documentation{-1, _assembly.location(), _assembly.documentation()}; + ErrorList errors; + ErrorReporter errorReporter{errors}; + auto docTags = DocStringParser{documentation, errorReporter}.parse(); + + if (!errors.empty()) + { + SecondarySourceLocation ssl; + for (auto const& error: errors) + if (error->comment()) + ssl.append( + *error->comment(), + _assembly.location() + ); + m_errorReporter.warning( + 7828_error, + _assembly.location(), + "Inline assembly has invalid NatSpec documentation.", + ssl + ); + } + + for (auto const& [tagName, tagValue]: docTags) + { + if (tagName == "solidity") + { + vector values; + boost::split(values, tagValue.content, isWhiteSpace); + + set valuesSeen; + set duplicates; + for (auto const& value: values | ranges::views::filter(not_fn(&string::empty))) + if (valuesSeen.insert(value).second) + { + if (value == "memory-safe-assembly") + { + if (_assembly.annotation().markedMemorySafe) + m_errorReporter.warning( + 8544_error, + _assembly.location(), + "Inline assembly marked as memory safe using both a NatSpec tag and an assembly flag. " + "If you are not concerned with backwards compatibility, only use the assembly flag, " + "otherwise only use the NatSpec tag." + ); + _assembly.annotation().markedMemorySafe = true; + } + else + m_errorReporter.warning( + 8787_error, + _assembly.location(), + "Unexpected value for @solidity tag in inline assembly: " + value + ); + } + else if (duplicates.insert(value).second) + m_errorReporter.warning( + 4377_error, + _assembly.location(), + "Value for @solidity tag in inline assembly specified multiple times: " + value + ); + } + else + m_errorReporter.warning( + 6269_error, + _assembly.location(), + "Unexpected NatSpec tag \"" + tagName + "\" with value \"" + tagValue.content + "\" in inline assembly." + ); + } + + return true; +} + void DocStringTagParser::checkParameters( CallableDeclaration const& _callable, StructurallyDocumented const& _node, diff --git a/libsolidity/analysis/DocStringTagParser.h b/libsolidity/analysis/DocStringTagParser.h index 84fde6c6c..248befcb8 100644 --- a/libsolidity/analysis/DocStringTagParser.h +++ b/libsolidity/analysis/DocStringTagParser.h @@ -48,6 +48,7 @@ private: bool visit(ModifierDefinition const& _modifier) override; bool visit(EventDefinition const& _event) override; bool visit(ErrorDefinition const& _error) override; + bool visit(InlineAssembly const& _assembly) override; void checkParameters( CallableDeclaration const& _callable, diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp index e47080cb4..589787a89 100644 --- a/libsolidity/analysis/SyntaxChecker.cpp +++ b/libsolidity/analysis/SyntaxChecker.cpp @@ -334,6 +334,27 @@ bool SyntaxChecker::visit(UnaryOperation const& _operation) bool SyntaxChecker::visit(InlineAssembly const& _inlineAssembly) { + if (_inlineAssembly.flags()) + for (auto flag: *_inlineAssembly.flags()) + { + if (*flag == "memory-safe") + { + if (_inlineAssembly.annotation().markedMemorySafe) + m_errorReporter.syntaxError( + 7026_error, + _inlineAssembly.location(), + "Inline assembly marked memory-safe multiple times." + ); + _inlineAssembly.annotation().markedMemorySafe = true; + } + else + m_errorReporter.warning( + 4430_error, + _inlineAssembly.location(), + "Unknown inline assembly flag: \"" + *flag + "\"" + ); + } + if (!m_useYulOptimizer) return false; diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 0bfa54f6e..ef82b8eab 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -763,6 +763,7 @@ void TypeChecker::endVisit(FunctionTypeName const& _funType) bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) { + bool lvalueAccessToMemoryVariable = false; // External references have already been resolved in a prior stage and stored in the annotation. // We run the resolve step again regardless. yul::ExternalIdentifierAccess::Resolver identifierAccess = [&]( @@ -780,6 +781,8 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) if (auto var = dynamic_cast(declaration)) { solAssert(var->type(), "Expected variable type!"); + if (_context == yul::IdentifierContext::LValue && var->type()->dataStoredIn(DataLocation::Memory)) + lvalueAccessToMemoryVariable = true; if (var->immutable()) { m_errorReporter.typeError(3773_error, nativeLocationOf(_identifier), "Assembly access to immutable variables is not supported."); @@ -967,8 +970,11 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) identifierAccess ); if (!analyzer.analyze(_inlineAssembly.operations())) - return false; - return true; + solAssert(m_errorReporter.hasErrors()); + _inlineAssembly.annotation().hasMemoryEffects = + lvalueAccessToMemoryVariable || + (analyzer.sideEffects().memory != yul::SideEffects::None); + return false; } bool TypeChecker::visit(IfStatement const& _ifStatement) diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp index 252210a12..3179a8eb7 100644 --- a/libsolidity/analysis/ViewPureChecker.cpp +++ b/libsolidity/analysis/ViewPureChecker.cpp @@ -256,10 +256,9 @@ void ViewPureChecker::reportMutability( m_errorReporter.typeError( 8961_error, _location, - "Function declared as " + + "Function cannot be declared as " + stateMutabilityToString(m_currentFunction->stateMutability()) + - ", but this expression (potentially) modifies the state and thus " - "requires non-payable (the default) or payable." + " because this expression (potentially) modifies the state." ); m_errors = true; } diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index c35c69c9d..4893c212f 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -1463,19 +1463,26 @@ public: SourceLocation const& _location, ASTPointer const& _docString, yul::Dialect const& _dialect, + ASTPointer>> _flags, std::shared_ptr _operations ): - Statement(_id, _location, _docString), m_dialect(_dialect), m_operations(std::move(_operations)) {} + Statement(_id, _location, _docString), + m_dialect(_dialect), + m_flags(move(_flags)), + m_operations(std::move(_operations)) + {} void accept(ASTVisitor& _visitor) override; void accept(ASTConstVisitor& _visitor) const override; yul::Dialect const& dialect() const { return m_dialect; } yul::Block const& operations() const { return *m_operations; } + ASTPointer>> const& flags() const { return m_flags; } InlineAssemblyAnnotation& annotation() const override; private: yul::Dialect const& m_dialect; + ASTPointer>> m_flags; std::shared_ptr m_operations; }; diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index 53931e426..0d6901ef2 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -220,6 +220,10 @@ struct InlineAssemblyAnnotation: StatementAnnotation std::map externalReferences; /// Information generated during analysis phase. std::shared_ptr analysisInfo; + /// 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; }; struct BlockAnnotation: StatementAnnotation, ScopableAnnotation diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 326cca43e..6b48797d1 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -493,24 +494,36 @@ bool ASTJsonConverter::visit(ModifierInvocation const& _node) bool ASTJsonConverter::visit(EventDefinition const& _node) { m_inEvent = true; - setJsonNode(_node, "EventDefinition", { + std::vector> _attributes = { make_pair("name", _node.name()), make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue), make_pair("parameters", toJson(_node.parameterList())), make_pair("anonymous", _node.isAnonymous()) - }); + }; + if (m_stackState >= CompilerStack::State::AnalysisPerformed) + _attributes.emplace_back( + make_pair( + "eventSelector", + toHex(u256(h256::Arith(util::keccak256(_node.functionType(true)->externalSignature())))) + )); + + setJsonNode(_node, "EventDefinition", std::move(_attributes)); return false; } bool ASTJsonConverter::visit(ErrorDefinition const& _node) { - setJsonNode(_node, "ErrorDefinition", { + std::vector> _attributes = { make_pair("name", _node.name()), make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue), make_pair("parameters", toJson(_node.parameterList())) - }); + }; + if (m_stackState >= CompilerStack::State::AnalysisPerformed) + _attributes.emplace_back(make_pair("errorSelector", _node.functionType(true)->externalIdentifierHex())); + + setJsonNode(_node, "ErrorDefinition", std::move(_attributes)); return false; } @@ -587,11 +600,23 @@ bool ASTJsonConverter::visit(InlineAssembly const& _node) for (Json::Value& it: externalReferences | ranges::views::values) externalReferencesJson.append(std::move(it)); - setJsonNode(_node, "InlineAssembly", { + std::vector> attributes = { make_pair("AST", Json::Value(yul::AsmJsonConverter(sourceIndexFromLocation(_node.location()))(_node.operations()))), make_pair("externalReferences", std::move(externalReferencesJson)), make_pair("evmVersion", dynamic_cast(_node.dialect()).evmVersion().name()) - }); + }; + + if (_node.flags()) + { + Json::Value flags(Json::arrayValue); + for (auto const& flag: *_node.flags()) + if (flag) + flags.append(*flag); + else + flags.append(Json::nullValue); + attributes.emplace_back(make_pair("flags", move(flags))); + } + setJsonNode(_node, "InlineAssembly", move(attributes)); return false; } diff --git a/libsolidity/ast/ASTJsonImporter.cpp b/libsolidity/ast/ASTJsonImporter.cpp index 2e69df93f..d71864f34 100644 --- a/libsolidity/ast/ASTJsonImporter.cpp +++ b/libsolidity/ast/ASTJsonImporter.cpp @@ -626,11 +626,24 @@ ASTPointer ASTJsonImporter::createInlineAssembly(Json::Value con astAssert(m_evmVersion == evmVersion, "Imported tree evm version differs from configured evm version!"); yul::Dialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(evmVersion.value()); + ASTPointer>> flags; + if (_node.isMember("flags")) + { + flags = make_shared>>(); + Json::Value const& flagsNode = _node["flags"]; + astAssert(flagsNode.isArray(), "Assembly flags must be an array."); + for (Json::ArrayIndex i = 0; i < flagsNode.size(); ++i) + { + astAssert(flagsNode[i].isString(), "Assembly flag must be a string."); + flags->emplace_back(make_shared(flagsNode[i].asString())); + } + } shared_ptr operations = make_shared(yul::AsmJsonImporter(m_sourceNames).createBlock(member(_node, "AST"))); return createASTNode( _node, nullOrASTString(_node, "documentation"), dialect, + move(flags), operations ); } diff --git a/libsolidity/codegen/ReturnInfo.cpp b/libsolidity/codegen/ReturnInfo.cpp index fd2ff451f..28518d9b2 100644 --- a/libsolidity/codegen/ReturnInfo.cpp +++ b/libsolidity/codegen/ReturnInfo.cpp @@ -54,4 +54,6 @@ ReturnInfo::ReturnInfo(EVMVersion const& _evmVersion, FunctionType const& _funct estimatedReturnSize += retType->decodingType()->calldataEncodedSize(); } } + if (dynamicReturnSize) + solAssert(estimatedReturnSize == 0); } diff --git a/libsolidity/codegen/ir/Common.cpp b/libsolidity/codegen/ir/Common.cpp index e75e5ef27..8f73f5733 100644 --- a/libsolidity/codegen/ir/Common.cpp +++ b/libsolidity/codegen/ir/Common.cpp @@ -41,6 +41,14 @@ YulArity YulArity::fromType(FunctionType const& _functionType) }; } +string IRNames::externalFunctionABIWrapper(Declaration const& _functionOrVarDecl) +{ + if (auto const* function = dynamic_cast(&_functionOrVarDecl)) + solAssert(!function->isConstructor()); + + return "external_fun_" + _functionOrVarDecl.name() + "_" + to_string(_functionOrVarDecl.id()); +} + string IRNames::function(FunctionDefinition const& _function) { if (_function.isConstructor()) diff --git a/libsolidity/codegen/ir/Common.h b/libsolidity/codegen/ir/Common.h index 3a860f8f1..2484ad809 100644 --- a/libsolidity/codegen/ir/Common.h +++ b/libsolidity/codegen/ir/Common.h @@ -49,6 +49,7 @@ struct YulArity struct IRNames { + static std::string externalFunctionABIWrapper(Declaration const& _functionOrVardecl); static std::string function(FunctionDefinition const& _function); static std::string function(VariableDeclaration const& _varDecl); static std::string modifierInvocation(ModifierInvocation const& _modifierInvocation); diff --git a/libsolidity/codegen/ir/IRGenerationContext.h b/libsolidity/codegen/ir/IRGenerationContext.h index cf01dc4f4..ea960bb70 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.h +++ b/libsolidity/codegen/ir/IRGenerationContext.h @@ -160,8 +160,8 @@ public: std::set& subObjectsCreated() { return m_subObjects; } - bool inlineAssemblySeen() const { return m_inlineAssemblySeen; } - void setInlineAssemblySeen() { m_inlineAssemblySeen = true; } + bool memoryUnsafeInlineAssemblySeen() const { return m_memoryUnsafeInlineAssemblySeen; } + void setMemoryUnsafeInlineAssemblySeen() { m_memoryUnsafeInlineAssemblySeen = true; } /// @returns the runtime ID to be used for the function in the dispatch routine /// and for internal function pointers. @@ -202,8 +202,8 @@ private: /// Whether to use checked or wrapping arithmetic. Arithmetic m_arithmetic = Arithmetic::Checked; - /// Flag indicating whether any inline assembly block was seen. - bool m_inlineAssemblySeen = false; + /// Flag indicating whether any memory-unsafe inline assembly block was seen. + bool m_memoryUnsafeInlineAssemblySeen = false; /// Function definitions queued for code generation. They're the Solidity functions whose calls /// were discovered by the IR generator during AST traversal. diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index e361ada47..cb187b424 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -213,8 +213,8 @@ string IRGenerator::generate( t("subObjects", subObjectSources(m_context.subObjectsCreated())); // This has to be called only after all other code generation for the creation object is complete. - bool creationInvolvesAssembly = m_context.inlineAssemblySeen(); - t("memoryInitCreation", memoryInit(!creationInvolvesAssembly)); + bool creationInvolvesMemoryUnsafeAssembly = m_context.memoryUnsafeInlineAssemblySeen(); + t("memoryInitCreation", memoryInit(!creationInvolvesMemoryUnsafeAssembly)); t("useSrcMapCreation", formatUseSrcMap(m_context)); resetContext(_contract, ExecutionContext::Deployed); @@ -239,8 +239,8 @@ string IRGenerator::generate( t("useSrcMapDeployed", formatUseSrcMap(m_context)); // This has to be called only after all other code generation for the deployed object is complete. - bool deployedInvolvesAssembly = m_context.inlineAssemblySeen(); - t("memoryInitDeployed", memoryInit(!deployedInvolvesAssembly)); + bool deployedInvolvesMemoryUnsafeAssembly = m_context.memoryUnsafeInlineAssemblySeen(); + t("memoryInitDeployed", memoryInit(!deployedInvolvesMemoryUnsafeAssembly)); solAssert(_contract.annotation().creationCallGraph->get() != nullptr, ""); solAssert(_contract.annotation().deployedCallGraph->get() != nullptr, ""); @@ -735,6 +735,44 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) }); } +string IRGenerator::generateExternalFunction(ContractDefinition const& _contract, FunctionType const& _functionType) +{ + string functionName = IRNames::externalFunctionABIWrapper(_functionType.declaration()); + return m_context.functionCollector().createFunction(functionName, [&](vector&, vector&) -> string { + Whiskers t(R"X( + + let := (4, calldatasize()) + let := () + let memPos := () + let memEnd := (memPos , ) + return(memPos, sub(memEnd, memPos)) + )X"); + t("callValueCheck", (_functionType.isPayable() || _contract.isLibrary()) ? "" : callValueCheck()); + + unsigned paramVars = make_shared(_functionType.parameterTypes())->sizeOnStack(); + unsigned retVars = make_shared(_functionType.returnParameterTypes())->sizeOnStack(); + + ABIFunctions abiFunctions(m_evmVersion, m_context.revertStrings(), m_context.functionCollector()); + t("abiDecode", abiFunctions.tupleDecoder(_functionType.parameterTypes())); + t("params", suffixedVariableNameList("param_", 0, paramVars)); + t("retParams", suffixedVariableNameList("ret_", 0, retVars)); + + if (FunctionDefinition const* funDef = dynamic_cast(&_functionType.declaration())) + { + solAssert(!funDef->isConstructor()); + t("function", m_context.enqueueFunctionForCodeGeneration(*funDef)); + } + else if (VariableDeclaration const* varDecl = dynamic_cast(&_functionType.declaration())) + t("function", generateGetter(*varDecl)); + else + solAssert(false, "Unexpected declaration for function!"); + + t("allocateUnbounded", m_utils.allocateUnboundedFunction()); + t("abiEncode", abiFunctions.tupleEncoder(_functionType.returnParameterTypes(), _functionType.returnParameterTypes(), _contract.isLibrary())); + return t.render(); + }); +} + string IRGenerator::generateInitialAssignment(VariableDeclaration const& _varDecl) { IRGeneratorForStatements generator(m_context, m_utils); @@ -976,12 +1014,7 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract) { // - - let := (4, calldatasize()) - let := () - let memPos := () - let memEnd := (memPos , ) - return(memPos, sub(memEnd, memPos)) + () } default {} @@ -1011,25 +1044,8 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract) "() }"; } templ["delegatecallCheck"] = delegatecallCheck; - templ["callValueCheck"] = (type->isPayable() || _contract.isLibrary()) ? "" : callValueCheck(); - unsigned paramVars = make_shared(type->parameterTypes())->sizeOnStack(); - unsigned retVars = make_shared(type->returnParameterTypes())->sizeOnStack(); - - ABIFunctions abiFunctions(m_evmVersion, m_context.revertStrings(), m_context.functionCollector()); - templ["abiDecode"] = abiFunctions.tupleDecoder(type->parameterTypes()); - templ["params"] = suffixedVariableNameList("param_", 0, paramVars); - templ["retParams"] = suffixedVariableNameList("ret_", 0, retVars); - - if (FunctionDefinition const* funDef = dynamic_cast(&type->declaration())) - templ["function"] = m_context.enqueueFunctionForCodeGeneration(*funDef); - else if (VariableDeclaration const* varDecl = dynamic_cast(&type->declaration())) - templ["function"] = generateGetter(*varDecl); - else - solAssert(false, "Unexpected declaration for function!"); - - templ["allocateUnbounded"] = m_utils.allocateUnboundedFunction(); - templ["abiEncode"] = abiFunctions.tupleEncoder(type->returnParameterTypes(), type->returnParameterTypes(), _contract.isLibrary()); + templ["externalFunction"] = generateExternalFunction(_contract, *type); } t("cases", functions); FunctionDefinition const* etherReceiver = _contract.receiveFunction(); diff --git a/libsolidity/codegen/ir/IRGenerator.h b/libsolidity/codegen/ir/IRGenerator.h index 126f90046..f89dc127a 100644 --- a/libsolidity/codegen/ir/IRGenerator.h +++ b/libsolidity/codegen/ir/IRGenerator.h @@ -102,6 +102,9 @@ private: /// Generates a getter for the given declaration and returns its name std::string generateGetter(VariableDeclaration const& _varDecl); + /// Generates the external part (ABI decoding and encoding) of a function or getter. + std::string generateExternalFunction(ContractDefinition const& _contract, FunctionType const& _functionType); + /// Generates code that assigns the initial value of the respective type. std::string generateInitialAssignment(VariableDeclaration const& _varDecl); diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 9fb73f021..3b977e9c8 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -2138,7 +2138,8 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm) { setLocation(_inlineAsm); - m_context.setInlineAssemblySeen(); + if (*_inlineAsm.annotation().hasMemoryEffects && !_inlineAsm.annotation().markedMemorySafe) + m_context.setMemoryUnsafeInlineAssemblySeen(); CopyTranslate bodyCopier{_inlineAsm.dialect(), m_context, _inlineAsm.annotation().externalReferences}; yul::Statement modified = bodyCopier(_inlineAsm.operations()); @@ -2505,6 +2506,8 @@ void IRGeneratorForStatements::appendExternalFunctionCall( appendCode() << "mstore(add(" << m_utils.allocateUnboundedFunction() << "() , " << to_string(returnInfo.estimatedReturnSize) << "), 0)\n"; } + // NOTE: When the expected size of returndata is static, we pass that in to the call opcode and it gets copied automatically. + // When it's dynamic, we get zero from estimatedReturnSize() instead and then we need an explicit returndatacopy(). Whiskers templ(R"( if iszero(extcodesize(
)) { () } @@ -2514,22 +2517,29 @@ void IRGeneratorForStatements::appendExternalFunctionCall( mstore(, ()) let := (add(, 4) ) - let := (,
, , , sub(, ), , ) + let := (,
, , , sub(, ), , ) if iszero() { () } let if { - - // copy dynamic return data out - returndatacopy(, 0, returndatasize()) - + + let := returndatasize() + returndatacopy(, 0, ) + + let := + + if gt(, returndatasize()) { + := returndatasize() + } + + // update freeMemoryPointer according to dynamic return size - (, ) + (, ) // decode return parameters from external try-call into retVars - := (, add(, )) + := (, add(, )) } )"); templ("revertNoCode", m_utils.revertReasonIfDebugFunction("Target contract does not contain code")); @@ -2558,21 +2568,18 @@ void IRGeneratorForStatements::appendExternalFunctionCall( templ("funSel", IRVariable(_functionCall.expression()).part("functionSelector").name()); templ("address", IRVariable(_functionCall.expression()).part("address").name()); - // Always use the actual return length, and not our calculated expected length, if returndatacopy is supported. - // This ensures it can catch badly formatted input from external calls. - if (m_context.evmVersion().supportsReturndata()) - templ("returnSize", "returndatasize()"); - else - templ("returnSize", to_string(returnInfo.estimatedReturnSize)); - - templ("reservedReturnSize", returnInfo.dynamicReturnSize ? "0" : to_string(returnInfo.estimatedReturnSize)); + if (returnInfo.dynamicReturnSize) + solAssert(m_context.evmVersion().supportsReturndata()); + templ("returnDataSizeVar", m_context.newYulVariable()); + templ("staticReturndataSize", to_string(returnInfo.estimatedReturnSize)); + templ("supportsReturnData", m_context.evmVersion().supportsReturndata()); string const retVars = IRVariable(_functionCall).commaSeparatedList(); templ("retVars", retVars); solAssert(retVars.empty() == returnInfo.returnTypes.empty()); templ("abiDecode", m_context.abiFunctions().tupleDecoder(returnInfo.returnTypes, true)); - templ("dynamicReturnSize", returnInfo.dynamicReturnSize); + templ("isReturndataSizeDynamic", returnInfo.dynamicReturnSize); templ("noTryCall", !_functionCall.annotation().tryCall); diff --git a/libsolidity/interface/FileReader.cpp b/libsolidity/interface/FileReader.cpp index e581c4a56..8300feb57 100644 --- a/libsolidity/interface/FileReader.cpp +++ b/libsolidity/interface/FileReader.cpp @@ -276,14 +276,8 @@ boost::filesystem::path FileReader::normalizeCLIPathForVFS( // If the path is on the same drive as the working dir, for portability we prefer not to // include the root name. Do this only for non-UNC paths - my experiments show that on Windows // when the working dir is an UNC path, / does not not actually refer to the root of the UNC path. - boost::filesystem::path normalizedRootPath = normalizedPath.root_path(); - if (!isUNCPath(normalizedPath)) - { - boost::filesystem::path workingDirRootPath = canonicalWorkDir.root_path(); - // Ignore drive letter case on Windows (C:\ <=> c:\). - if (boost::filesystem::equivalent(normalizedRootPath, workingDirRootPath)) - normalizedRootPath = "/"; - } + + boost::filesystem::path normalizedRootPath = normalizeCLIRootPathForVFS(normalizedPath, canonicalWorkDir); // lexically_normal() will not squash paths like "/../../" into "/". We have to do it manually. boost::filesystem::path dotDotPrefix = absoluteDotDotPrefix(normalizedPath); @@ -308,6 +302,27 @@ boost::filesystem::path FileReader::normalizeCLIPathForVFS( return normalizedPathNoDotDot; } +boost::filesystem::path FileReader::normalizeCLIRootPathForVFS( + boost::filesystem::path const& _path, + boost::filesystem::path const& _workDir +) +{ + solAssert(_workDir.is_absolute(), ""); + + boost::filesystem::path absolutePath = boost::filesystem::absolute(_path, _workDir); + boost::filesystem::path rootPath = absolutePath.root_path(); + boost::filesystem::path baseRootPath = _workDir.root_path(); + + if (isUNCPath(absolutePath)) + return rootPath; + + // Ignore drive letter case on Windows (C:\ <=> c:\). + if (boost::filesystem::equivalent(rootPath, baseRootPath)) + return "/"; + + return rootPath; +} + bool FileReader::isPathPrefix(boost::filesystem::path const& _prefix, boost::filesystem::path const& _path) { solAssert(!_prefix.empty() && !_path.empty(), ""); diff --git a/libsolidity/interface/FileReader.h b/libsolidity/interface/FileReader.h index 3892e9826..f05ce894d 100644 --- a/libsolidity/interface/FileReader.h +++ b/libsolidity/interface/FileReader.h @@ -115,6 +115,17 @@ public: SymlinkResolution _symlinkResolution = SymlinkResolution::Disabled ); + /// Normalizes a root path by excluding, in some cases, its root name. + /// The function is used for better portability, and intended to omit root name + /// if the path can be used without it. + /// @param _path Path to normalize the root path. + /// @param _workDir Current working directory path, must be absolute. + /// @returns a normalized root path. + static boost::filesystem::path normalizeCLIRootPathForVFS( + boost::filesystem::path const& _path, + boost::filesystem::path const& _workDir = boost::filesystem::current_path() + ); + /// @returns true if all the path components of @a _prefix are present at the beginning of @a _path. /// Both paths must be absolute (or have slash as root) and normalized (no . or .. segments, no /// multiple consecutive slashes). diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 75876d935..93ac20b03 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index fea062d01..b1d7e7cca 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -1321,13 +1321,28 @@ ASTPointer Parser::parseInlineAssembly(ASTPointer con advance(); } + ASTPointer>> flags; + if (m_scanner->currentToken() == Token::LParen) + { + flags = make_shared>>(); + do + { + advance(); + expectToken(Token::StringLiteral, false); + flags->emplace_back(make_shared(m_scanner->currentLiteral())); + advance(); + } + while (m_scanner->currentToken() == Token::Comma); + expectToken(Token::RParen); + } + yul::Parser asmParser(m_errorReporter, dialect); shared_ptr block = asmParser.parseInline(m_scanner); if (block == nullptr) BOOST_THROW_EXCEPTION(FatalError()); location.end = nativeLocationOf(*block).end; - return make_shared(nextID(), location, _docString, dialect, block); + return make_shared(nextID(), location, _docString, dialect, move(flags), block); } ASTPointer Parser::parseIfStatement(ASTPointer const& _docString) diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index 342d3d456..ea2bc37ce 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -309,6 +309,7 @@ vector AsmAnalyzer::operator()(FunctionCall const& _funCall) literalArguments = &f->literalArguments; validateInstructions(_funCall); + m_sideEffects += f->sideEffects; } else if (!m_currentScope->lookup(_funCall.functionName.name, GenericVisitor{ [&](Scope::Variable const&) diff --git a/libyul/AsmAnalysis.h b/libyul/AsmAnalysis.h index dc2770500..c71b4cbe3 100644 --- a/libyul/AsmAnalysis.h +++ b/libyul/AsmAnalysis.h @@ -94,6 +94,8 @@ public: void operator()(Leave const&) { } void operator()(Block const& _block); + /// @returns the worst side effects encountered during analysis (including within defined functions). + SideEffects const& sideEffects() const { return m_sideEffects; } private: /// Visits the expression, expects that it evaluates to exactly one value and /// returns the type. Reports errors on errors and returns the default type. @@ -128,6 +130,8 @@ private: /// Names of data objects to be referenced by builtin functions with literal arguments. std::set m_dataNames; ForLoop const* m_currentForLoop = nullptr; + /// Worst side effects encountered during analysis (including within defined functions). + SideEffects m_sideEffects; }; } diff --git a/libyul/backends/evm/EVMMetrics.h b/libyul/backends/evm/EVMMetrics.h index 19702b8f3..b67cb77cd 100644 --- a/libyul/backends/evm/EVMMetrics.h +++ b/libyul/backends/evm/EVMMetrics.h @@ -23,6 +23,7 @@ #include #include +#include #include namespace solidity::yul diff --git a/libyul/backends/evm/EVMObjectCompiler.cpp b/libyul/backends/evm/EVMObjectCompiler.cpp index bede32d17..c3c95d8bc 100644 --- a/libyul/backends/evm/EVMObjectCompiler.cpp +++ b/libyul/backends/evm/EVMObjectCompiler.cpp @@ -25,6 +25,8 @@ #include #include +#include + #include #include @@ -74,7 +76,22 @@ void EVMObjectCompiler::run(Object& _object, bool _optimize) OptimizedEVMCodeTransform::UseNamedLabels::ForFirstFunctionOfEachName ); if (!stackErrors.empty()) - BOOST_THROW_EXCEPTION(stackErrors.front()); + { + vector memoryGuardCalls = FunctionCallFinder::run( + *_object.code, + "memoryguard"_yulstring + ); + auto stackError = stackErrors.front(); + string msg = stackError.comment() ? *stackError.comment() : ""; + if (memoryGuardCalls.empty()) + msg += "\nNo memoryguard was present. " + "Consider using memory-safe assembly only and annotating it via " + "\"/// @solidity memory-safe-assembly\"."; + else + msg += "\nmemoryguard was present."; + stackError << util::errinfo_comment(msg); + BOOST_THROW_EXCEPTION(stackError); + } } else { diff --git a/libyul/optimiser/SimplificationRules.h b/libyul/optimiser/SimplificationRules.h index d4da4a2b0..77018bb38 100644 --- a/libyul/optimiser/SimplificationRules.h +++ b/libyul/optimiser/SimplificationRules.h @@ -27,6 +27,7 @@ #include #include +#include #include #include diff --git a/libyul/optimiser/UnusedStoreBase.cpp b/libyul/optimiser/UnusedStoreBase.cpp index 8e34d172f..de13a23cc 100644 --- a/libyul/optimiser/UnusedStoreBase.cpp +++ b/libyul/optimiser/UnusedStoreBase.cpp @@ -73,6 +73,7 @@ void UnusedStoreBase::operator()(FunctionDefinition const& _functionDefinition) { ScopedSaveAndRestore outerAssignments(m_stores, {}); ScopedSaveAndRestore forLoopInfo(m_forLoopInfo, {}); + ScopedSaveAndRestore forLoopNestingDepth(m_forLoopNestingDepth, 0); (*this)(_functionDefinition.body); diff --git a/scripts/bytecodecompare/storebytecode.sh b/scripts/bytecodecompare/storebytecode.sh index 3574fe6bf..2192960e4 100755 --- a/scripts/bytecodecompare/storebytecode.sh +++ b/scripts/bytecodecompare/storebytecode.sh @@ -1,10 +1,12 @@ #!/usr/bin/env bash #------------------------------------------------------------------------------ -# Script used for cross-platform comparison as part of the travis automation. -# Splits all test source code into multiple files, generates bytecode and -# uploads the bytecode into github.com/ethereum/solidity-test-bytecode where -# another travis job is triggered to do the actual comparison. +# Script used for cross-platform comparison of the bytecode generated by the compiler. +# Splits all test source code into multiple files, generates bytecode and metadata +# for each file and combines it into a single report.txt file. +# +# The script is meant to be executed in CI on all supported platforms. All generated +# reports must be identical for a given compiler version. # # ------------------------------------------------------------------------------ # This file is part of solidity. diff --git a/scripts/common.sh b/scripts/common.sh index 4a98c0072..7cb96ed02 100644 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -180,7 +180,7 @@ function diff_values shift shift - diff --color=auto --unified=0 <(echo "$value1") <(echo "$value2") "$@" + diff --unified=0 <(echo "$value1") <(echo "$value2") "$@" } function safe_kill diff --git a/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz b/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz index fb79ea946..bbc554e0f 100644 --- a/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz +++ b/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz @@ -22,7 +22,7 @@ # (c) 2016-2021 solidity contributors. #------------------------------------------------------------------------------ FROM gcr.io/oss-fuzz-base/base-clang:latest as base -LABEL version="15" +LABEL version="16" ARG DEBIAN_FRONTEND=noninteractive @@ -32,7 +32,7 @@ RUN apt-get update; \ software-properties-common \ ninja-build git wget \ libbz2-dev zlib1g-dev git curl uuid-dev \ - pkg-config openjdk-8-jdk liblzma-dev unzip mlton m4; \ + pkg-config openjdk-8-jdk liblzma-dev unzip mlton m4 jq; \ apt-get install -qy python3-pip; # Install cmake 3.21.2 (minimum requirement is cmake 3.10) diff --git a/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004 b/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004 index 3ecf9143a..6a047aa27 100644 --- a/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004 +++ b/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004 @@ -22,7 +22,7 @@ # (c) 2016-2019 solidity contributors. #------------------------------------------------------------------------------ FROM buildpack-deps:focal AS base -LABEL version="10" +LABEL version="11" ARG DEBIAN_FRONTEND=noninteractive @@ -37,7 +37,7 @@ RUN set -ex; \ cmake ninja-build \ libboost-filesystem-dev libboost-test-dev libboost-system-dev \ libboost-program-options-dev \ - libcvc4-dev libz3-static-dev z3-static \ + libcvc4-dev libz3-static-dev z3-static jq \ ; \ apt-get install -qy python3-pip python3-sphinx; \ pip3 install codecov; \ diff --git a/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004.clang b/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004.clang index d262fa5fa..853969ecd 100644 --- a/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004.clang +++ b/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004.clang @@ -22,7 +22,7 @@ # (c) 2016-2019 solidity contributors. #------------------------------------------------------------------------------ FROM buildpack-deps:focal AS base -LABEL version="10" +LABEL version="11" ARG DEBIAN_FRONTEND=noninteractive @@ -38,7 +38,7 @@ RUN set -ex; \ libboost-filesystem-dev libboost-test-dev libboost-system-dev \ libboost-program-options-dev \ clang \ - libz3-static-dev \ + libz3-static-dev jq \ ; \ rm -rf /var/lib/apt/lists/* diff --git a/scripts/fix_homebrew_paths_in_standalone_zip.py b/scripts/fix_homebrew_paths_in_standalone_zip.py deleted file mode 100755 index 43f26795c..000000000 --- a/scripts/fix_homebrew_paths_in_standalone_zip.py +++ /dev/null @@ -1,66 +0,0 @@ -# ------------------------------------------------------------------------------ -# This Python script is used within the OS X release process, to ensure -# that the standalone OS X ZIP files which we make are actually -# standalone, and not implicitly dependent on Homebrew installs for -# external libraries which we use. -# -# This implicit dependencies seem to show up only where we have -# external dependencies which are dependent on each other, and the -# path from one to another is an absolute path to "/usr/local/opt", -# the Homebrew install location. External dependencies which only -# depend on system libraries are fine. Our main applications seem -# to be fine. -# -# An example of a dependency which requires this fix-up at the time -# of writing is the following dependency edge: -# -# libjsonrpccpp-client.0.dylib -# -> /usr/local/opt/jsoncpp/lib/libjsoncpp.0.dylib -# -# See https://blogs.oracle.com/dipol/entry/dynamic_libraries_rpath_and_mac -# for a little overview of "install_name_tool" and "otool". -# -# ------------------------------------------------------------------------------ -# 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) 2016 solidity contributors. -# ----------------------------------------------------------------------------- - -import os -import subprocess -import sys - -def readDependencies(fname): - with subprocess.Popen(['otool', '-L', fname], stdout=subprocess.PIPE) as o: - for line in o.stdout: - if line[0] == '\t': - library = line.split(' ', 1)[0][1:] - if (library.startswith("/usr/local/lib") or - library.startswith("/usr/local/opt") or - library.startswith("/Users/") - ): - if os.path.basename(library) != os.path.basename(fname): - command = "install_name_tool -change " + \ - library + " @executable_path/./" + \ - os.path.basename(library) + " " + fname - print(command) - os.system("chmod +w " + fname) - os.system(command) - -root = sys.argv[1] -for (dirpath, dirnames, filenames) in os.walk(root): - for filename in filenames: - readDependencies(os.path.join(root, filename)) diff --git a/scripts/release.bat b/scripts/release.bat deleted file mode 100644 index a1a909ae0..000000000 --- a/scripts/release.bat +++ /dev/null @@ -1,38 +0,0 @@ -@ECHO OFF - -REM --------------------------------------------------------------------------- -REM Batch file for implementing release flow for solidity for Windows. -REM -REM The documentation for solidity is hosted at: -REM -REM https://docs.soliditylang.org -REM -REM --------------------------------------------------------------------------- -REM This file is part of solidity. -REM -REM solidity is free software: you can redistribute it and/or modify -REM it under the terms of the GNU General Public License as published by -REM the Free Software Foundation, either version 3 of the License, or -REM (at your option) any later version. -REM -REM solidity is distributed in the hope that it will be useful, -REM but WITHOUT ANY WARRANTY; without even the implied warranty of -REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -REM GNU General Public License for more details. -REM -REM You should have received a copy of the GNU General Public License -REM along with solidity. If not, see -REM -REM Copyright (c) 2016 solidity contributors. -REM --------------------------------------------------------------------------- - -set CONFIGURATION=%1 -set VERSION=%2 - -set "DLLS=MSVC_DLLS_NOT_FOUND" -FOR /d %%d IN ("C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Redist\MSVC\*" - "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Redist\MSVC\*") DO set "DLLS=%%d\x86\Microsoft.VC141.CRT\msvc*.dll" - -7z a solidity-windows.zip ^ - .\build\solc\%CONFIGURATION%\solc.exe .\build\test\%CONFIGURATION%\soltest.exe ^ - "%DLLS%" diff --git a/scripts/release.sh b/scripts/release.sh deleted file mode 100755 index 88aaa5fef..000000000 --- a/scripts/release.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env bash - -#------------------------------------------------------------------------------ -# Bash script implementing release flow for solidity for Linux and macOS. -# -# TODO - At the time of writing, we only have ZIPs working. Need to hook up -# support for Homebrew and PPAs. -# -# The documentation for solidity is hosted at: -# -# https://docs.soliditylang.org -# -# ------------------------------------------------------------------------------ -# 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) 2016 solidity contributors. -#------------------------------------------------------------------------------ - -ZIP_SUFFIX="$1" -ZIP_TEMP_DIR="$(pwd)/build/zip/" - -# There is an implicit assumption here that we HAVE to run from root directory. -REPO_ROOT=$(pwd) - -mkdir -p "$ZIP_TEMP_DIR" - -# Copy all the solidity executables into a temporary directory prior to ZIP creation - -cp "$REPO_ROOT/build/solc/solc" "$ZIP_TEMP_DIR" - -# For macOS, we run a fix-up script which alters all of the symbolic links within -# the executables and dynamic libraries such that the ZIP becomes self-contained, by -# revectoring all the dylib references to be relative to the directory containing the -# application, so that the ZIPs are self-contained, with the only external references -# being for kernel-level dylibs. - -if [[ "$OSTYPE" == "darwin"* ]]; then - python3 "$REPO_ROOT/scripts/fix_homebrew_paths_in_standalone_zip.py" "$ZIP_TEMP_DIR" -fi - -# And ZIP it all up, with a filename suffix passed in on the command-line. -mkdir -p "$REPO_ROOT/upload" -zip -j "$REPO_ROOT/upload/solidity-$ZIP_SUFFIX.zip" "$ZIP_TEMP_DIR/"* diff --git a/scripts/release_ppa.sh b/scripts/release_ppa.sh index 725649f80..fe1efda27 100755 --- a/scripts/release_ppa.sh +++ b/scripts/release_ppa.sh @@ -55,9 +55,9 @@ keyid=379F4801D622CDCF email=builds@ethereum.org packagename=solc -static_build_distribution=hirsute +static_build_distribution=impish -DISTRIBUTIONS="focal hirsute impish jammy" +DISTRIBUTIONS="focal impish jammy" if is_release then diff --git a/scripts/wasm-rebuild/docker-scripts/rebuild_current.sh b/scripts/wasm-rebuild/docker-scripts/rebuild_current.sh index 41e554139..fbe5a9d60 100755 --- a/scripts/wasm-rebuild/docker-scripts/rebuild_current.sh +++ b/scripts/wasm-rebuild/docker-scripts/rebuild_current.sh @@ -45,7 +45,7 @@ set +e if [ -e scripts/ci/build_emscripten.sh ]; then scripts/ci/build_emscripten.sh else - # The script used to be in scripts/ci/ in earlier versions. + # The script used to be in scripts/travis-emscripten/ in earlier versions. scripts/travis-emscripten/build_emscripten.sh fi diff --git a/scripts/wasm-rebuild/docker-scripts/rebuild_tags.sh b/scripts/wasm-rebuild/docker-scripts/rebuild_tags.sh index 6293d182b..9ef9caaa8 100755 --- a/scripts/wasm-rebuild/docker-scripts/rebuild_tags.sh +++ b/scripts/wasm-rebuild/docker-scripts/rebuild_tags.sh @@ -27,7 +27,7 @@ done SOLIDITY_REPO_URL="https://github.com/ethereum/solidity" SOLC_JS_REPO_URL="https://github.com/ethereum/solc-js" SOLC_JS_BRANCH=wasmRebuildTests -RELEASE_URL="https://raw.githubusercontent.com/ethereum/solc-bin/gh-pages/bin" +RELEASE_URL="https://binaries.soliditylang.org/bin" RELEASE_COMMIT_LIST_URL="$RELEASE_URL/list.txt" SCRIPTDIR=$(dirname "$0") @@ -196,6 +196,7 @@ cp scripts/bytecodecompare/storebytecode.sh /tmp # shellcheck disable=SC2016 sed -i -e 's/rm -rf "\$TMPDIR"/cp "\$TMPDIR"\/report.txt \/tmp\/report.txt ; rm -rf "\$TMPDIR"/' /tmp/storebytecode.sh sed -i -e 's/REPO_ROOT=.*/REPO_ROOT=\/src/' /tmp/storebytecode.sh +sed -i -e 's/git clone/git clone --branch '"${SOLC_JS_BRANCH}"'/' /tmp/storebytecode.sh export SOLC_EMSCRIPTEN="On" echo "Check out solc-js repository..." @@ -213,7 +214,9 @@ ln -sf /emsdk_portable/emscripten/bin/* /usr/local/bin rm -rf /src ln -sf /root/project /src +echo "Install dependencies and upgrade system packages." apt-get -qq update >/dev/null 2>&1 +apt-get -qq upgrade >/dev/null 2>&1 apt-get -qq install cmake >/dev/null 2>&1 echo "Create output directories." @@ -228,7 +231,6 @@ mkdir -p "${OUTPUTDIR}"/bin echo "Prepare solc-js." cd /root/solc-js npm install >/dev/null 2>&1 -npm run build >/dev/null 2>&1 echo "Install semver helper." npm install -g semver >/dev/null 2>&1 @@ -238,6 +240,7 @@ wget -q "${RELEASE_COMMIT_LIST_URL}" -O /tmp/release_commit_list.txt cd /src TAGS=$(git tag --list "${TAG_FILTER}" | tac) +echo "Matching tags: ${TAGS}" for TAG in ${TAGS}; do process_tag "${TAG}" done diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 02bbcfc3d..3b1f7947a 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -44,6 +44,7 @@ #include #include +#include #include #include diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1ca9c3328..255218c15 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -83,6 +83,8 @@ set(libsolidity_sources libsolidity/InlineAssembly.cpp libsolidity/LibSolc.cpp libsolidity/Metadata.cpp + libsolidity/MemoryGuardTest.cpp + libsolidity/MemoryGuardTest.h libsolidity/SemanticTest.cpp libsolidity/SemanticTest.h libsolidity/SemVerMatcher.cpp diff --git a/test/Common.h b/test/Common.h index f3ea9e6f4..e7e211d9e 100644 --- a/test/Common.h +++ b/test/Common.h @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -47,7 +48,7 @@ static constexpr auto heraFilename = "libhera.so"; static constexpr auto heraDownloadLink = "https://github.com/ewasm/hera/releases/download/v0.5.0/hera-0.5.0-linux-x86_64.tar.gz"; #endif -struct ConfigException : public util::Exception {}; +struct ConfigException: public util::Exception {}; struct CommonOptions { diff --git a/test/ExecutionFramework.cpp b/test/ExecutionFramework.cpp index 600bedbf5..bb46f108d 100644 --- a/test/ExecutionFramework.cpp +++ b/test/ExecutionFramework.cpp @@ -266,7 +266,7 @@ h160 ExecutionFramework::logAddress(size_t _logIdx) const bytes ExecutionFramework::logData(size_t _logIdx) const { - const auto& data = m_evmcHost->recorded_logs.at(_logIdx).data; + auto const& data = m_evmcHost->recorded_logs.at(_logIdx).data; // TODO: Return a copy of log data, because this is expected from REQUIRE_LOG_DATA(), // but reference type like string_view would be preferable. return {data.begin(), data.end()}; diff --git a/test/InteractiveTests.h b/test/InteractiveTests.h index d8f3ef07e..d359a815a 100644 --- a/test/InteractiveTests.h +++ b/test/InteractiveTests.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -74,6 +75,7 @@ Testsuite const g_interactiveTestsuites[] = { {"JSON ABI", "libsolidity", "ABIJson", false, false, &ABIJsonTest::create}, {"SMT Checker", "libsolidity", "smtCheckerTests", true, false, &SMTCheckerTest::create}, {"Gas Estimates", "libsolidity", "gasTests", false, false, &GasTest::create}, + {"Memory Guard Tests", "libsolidity", "memoryGuardTests", false, false, &MemoryGuardTest::create}, {"Ewasm Translation", "libyul", "ewasmTranslationTests", false, false, &yul::test::EwasmTranslationTest::create} }; diff --git a/test/cmdlineTests/constant_optimizer_yul/output b/test/cmdlineTests/constant_optimizer_yul/output index 328ac2544..2a769811a 100644 --- a/test/cmdlineTests/constant_optimizer_yul/output +++ b/test/cmdlineTests/constant_optimizer_yul/output @@ -11,14 +11,15 @@ object "C_12" { code { { /// @src 0:61:418 "contract C {..." - mstore(64, 128) + let _1 := memoryguard(0x80) + mstore(64, _1) if callvalue() { revert(0, 0) } /// @src 0:103:238 "assembly {..." sstore(0, shl(180, 1)) /// @src 0:61:418 "contract C {..." - let _1 := datasize("C_12_deployed") - codecopy(128, dataoffset("C_12_deployed"), _1) - return(128, _1) + let _2 := datasize("C_12_deployed") + codecopy(_1, dataoffset("C_12_deployed"), _2) + return(_1, _2) } } /// @use-src 0:"constant_optimizer_yul/input.sol" @@ -26,7 +27,7 @@ object "C_12" { code { { /// @src 0:61:418 "contract C {..." - mstore(64, 128) + 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 1b90e94a3..7775ff69c 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 @@ -108,12 +108,7 @@ object "C_6" { { // f() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - fun_f_5() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple__to__fromStack(memPos ) - return(memPos, sub(memEnd, memPos)) + external_fun_f_5() } default {} @@ -150,6 +145,17 @@ object "C_6" { } + function external_fun_f_5() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + fun_f_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { 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 86968e71b..35f680d92 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 @@ -108,12 +108,7 @@ object "C_6" { { // f() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - fun_f_5() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple__to__fromStack(memPos ) - return(memPos, sub(memEnd, memPos)) + external_fun_f_5() } default {} @@ -150,6 +145,17 @@ object "C_6" { } + function external_fun_f_5() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + fun_f_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { 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 6a87b0b46..93fad0421 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 @@ -101,12 +101,7 @@ object "C_6" { { // f() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - fun_f_5() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple__to__fromStack(memPos ) - return(memPos, sub(memEnd, memPos)) + external_fun_f_5() } default {} @@ -143,6 +138,17 @@ object "C_6" { } + function external_fun_f_5() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + fun_f_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { 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 ae3ee1735..82a74384e 100644 --- a/test/cmdlineTests/debug_info_in_yul_snippet_escaping/output +++ b/test/cmdlineTests/debug_info_in_yul_snippet_escaping/output @@ -158,12 +158,7 @@ object "D_27" { { // f() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - let ret_0 := fun_f_26() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0) - return(memPos, sub(memEnd, memPos)) + external_fun_f_26() } default {} @@ -238,6 +233,17 @@ object "D_27" { } + function external_fun_f_26() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + let ret_0 := fun_f_26() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0) + return(memPos, sub(memEnd, memPos)) + + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } @@ -484,7 +490,7 @@ object "D_27" { revert(pos, returndatasize()) } mstore(add(allocate_memory_array_string(), 32), "/*") - let memPtr := allocate_memory_array_string_480() + let memPtr := allocate_memory_array_string_546() mstore(add(memPtr, 32), 0x2f2a2a204073726320303a39363a313635202022636f6e74726163742044207b) mstore(add(memPtr, 64), shl(200, 0x2e2e2e22202a2f)) let memPos := mload(64) @@ -525,7 +531,7 @@ object "D_27" { memPtr := memPtr_1 mstore(memPtr_1, 2) } - function allocate_memory_array_string_480() -> memPtr + function allocate_memory_array_string_546() -> memPtr { let memPtr_1 := mload(64) let newFreePtr := add(memPtr_1, 96) diff --git a/test/cmdlineTests/exp_base_literal/output b/test/cmdlineTests/exp_base_literal/output index 77893da18..7b6e6e628 100644 --- a/test/cmdlineTests/exp_base_literal/output +++ b/test/cmdlineTests/exp_base_literal/output @@ -53,12 +53,7 @@ object "C_81" { { // f(uint256,uint256,uint256,uint256) - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - let param_0, param_1, param_2, param_3 := abi_decode_tuple_t_uint256t_uint256t_uint256t_uint256(4, calldatasize()) - let ret_0, ret_1, ret_2, ret_3 := fun_f_80(param_0, param_1, param_2, param_3) - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple_t_uint256_t_int256_t_uint256_t_uint256__to_t_uint256_t_int256_t_uint256_t_uint256__fromStack(memPos , ret_0, ret_1, ret_2, ret_3) - return(memPos, sub(memEnd, memPos)) + external_fun_f_80() } default {} @@ -160,6 +155,17 @@ object "C_81" { } + function external_fun_f_80() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0, param_1, param_2, param_3 := abi_decode_tuple_t_uint256t_uint256t_uint256t_uint256(4, calldatasize()) + let ret_0, ret_1, ret_2, ret_3 := fun_f_80(param_0, param_1, param_2, param_3) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple_t_uint256_t_int256_t_uint256_t_uint256__to_t_uint256_t_int256_t_uint256_t_uint256__fromStack(memPos , ret_0, ret_1, ret_2, ret_3) + return(memPos, sub(memEnd, memPos)) + + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } diff --git a/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/input.sol b/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/input.sol index aca9b3bef..67e1632e9 100644 --- a/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/input.sol +++ b/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/input.sol @@ -3,6 +3,6 @@ pragma solidity >=0.0.0; pragma abicoder v2; contract D { - constructor() { assembly {}} + constructor() { assembly { mstore(0,0) } } function f() public pure {} } diff --git a/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output b/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output index 34b72f8b8..d9b769a12 100644 --- a/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output +++ b/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output @@ -10,9 +10,12 @@ Optimized IR: object "D_12" { code { { - /// @src 0:82:161 "contract D {..." + /// @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) @@ -22,7 +25,7 @@ object "D_12" { object "D_12_deployed" { code { { - /// @src 0:82:161 "contract D {..." + /// @src 0:82:175 "contract D {..." let _1 := memoryguard(0x80) mstore(64, _1) if iszero(lt(calldatasize(), 4)) diff --git a/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/input.sol b/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/input.sol index e217f9cbb..26c0bfa98 100644 --- a/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/input.sol +++ b/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/input.sol @@ -4,6 +4,6 @@ pragma abicoder v2; contract D { function f() public pure { - assembly {} + assembly { mstore(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 cc95451e6..9a07c7861 100644 --- a/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/output +++ b/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/output @@ -10,7 +10,7 @@ Optimized IR: object "D_8" { code { { - /// @src 0:82:153 "contract D {..." + /// @src 0:82:166 "contract D {..." let _1 := memoryguard(0x80) mstore(64, _1) if callvalue() { revert(0, 0) } @@ -23,7 +23,7 @@ object "D_8" { object "D_8_deployed" { code { { - /// @src 0:82:153 "contract D {..." + /// @src 0:82:166 "contract D {..." mstore(64, 128) if iszero(lt(calldatasize(), 4)) { @@ -32,6 +32,8 @@ 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/name_simplifier/output b/test/cmdlineTests/name_simplifier/output index 57a4cb594..3dabe9c8d 100644 --- a/test/cmdlineTests/name_simplifier/output +++ b/test/cmdlineTests/name_simplifier/output @@ -50,7 +50,7 @@ object "C_59" { for { } lt(src, srcEnd) { src := add(src, _2) } { if slt(sub(calldatasize(), src), _2) { revert(_1, _1) } - let value := allocate_memory_1172() + let value := allocate_memory_1307() mstore(value, calldataload(src)) mstore(dst, value) dst := add(dst, _2) @@ -68,7 +68,7 @@ object "C_59" { mstore(4, 0x41) revert(0, 0x24) } - function allocate_memory_1172() -> memPtr + function allocate_memory_1307() -> memPtr { memPtr := mload(64) let newFreePtr := add(memPtr, 32) diff --git a/test/cmdlineTests/revert_strings/output b/test/cmdlineTests/revert_strings/output index d13f9f4e5..31b3db33b 100644 --- a/test/cmdlineTests/revert_strings/output +++ b/test/cmdlineTests/revert_strings/output @@ -68,12 +68,7 @@ object "C_15" { { // f(uint256[][],uint8) - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - let param_0, param_1 := abi_decode_tuple_t_array$_t_array$_t_uint256_$dyn_memory_ptr_$dyn_memory_ptrt_enum$_E_$3(4, calldatasize()) - fun_f_14(param_0, param_1) - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple__to__fromStack(memPos ) - return(memPos, sub(memEnd, memPos)) + external_fun_f_14() } default {} @@ -338,6 +333,17 @@ object "C_15" { } + function external_fun_f_14() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + let param_0, param_1 := abi_decode_tuple_t_array$_t_array$_t_uint256_$dyn_memory_ptr_$dyn_memory_ptrt_enum$_E_$3(4, calldatasize()) + fun_f_14(param_0, param_1) + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { let start := allocate_unbounded() 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 1c3999afc..238934a3f 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 @@ -78,195 +78,109 @@ stop sub_0: assembly { /* \"C\":79:428 contract C... */ mstore(0x40, 0x80) - jumpi(tag_8, iszero(lt(calldatasize, 0x04))) + jumpi(tag_7, iszero(lt(calldatasize, 0x04))) + tag_8: 0x00 dup1 revert - tag_8: + tag_7: 0x00 dup1 calldataload 0xe0 shr - dup1 + swap1 + dup2 0x26121ff0 eq - tag_10 + tag_9 jumpi + pop dup1 0x793816ec eq - tag_12 + tag_11 jumpi 0x9942ec6f eq - tag_14 + tag_13 jumpi - pop 0x00 dup1 revert - tag_14: - jumpi(tag_16, callvalue) + tag_13: + tag_8 + tag_3 + jump\t// in + tag_11: pop - tag_18 - calldatasize - tag_1 + tag_8 + tag_2 jump\t// in - tag_18: - tag_19 - /* \"C\":375:378 int */ - tag_20 - tag_6 - jump\t// in - tag_20: - /* \"C\":79:428 contract C... */ - mload(0x40) + tag_9: swap1 - dup2 - mstore - swap1 - dup2 - swap1 - 0x20 - dup3 - add - swap1 - jump - tag_19: - sub - swap1 - return - tag_16: + pop + jumpi(tag_19, callvalue) dup1 - revert - tag_12: - pop - jumpi(tag_16, callvalue) + add(calldatasize, not(0x03)) + slt tag_19 - swap1 - tag_24 - calldatasize - tag_1 - jump\t// in - tag_24: - sload - mload(0x40) - swap1 - dup2 - mstore - swap1 - dup2 - swap1 + jumpi + pop 0x20 - dup3 - add - swap1 - jump - tag_10: - pop - jumpi(tag_16, callvalue) - pop - tag_27 - calldatasize - tag_1 - jump\t// in - tag_27: - tag_19 - /* \"C\":279:298 constVar + immutVar */ - tag_20 /* \"C\":290:298 immutVar */ immutable(\"0xe4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10\") - /* \"C\":279:298 constVar + immutVar */ - tag_4 - jump\t// in - /* \"C\":79:428 contract C... */ - tag_1: - 0x00 - swap1 - not(0x03) - add - slt - tag_30 - jumpi - jump\t// out - tag_30: - pop - 0x00 - dup1 - revert - /* \"C\":117:119 41 */ - tag_3: - pop - mstore(0x00, shl(0xe0, 0x4e487b71)) - mstore(0x04, 0x11) - revert(0x00, 0x24) - tag_4: sub(shl(0xff, 0x01), 0x2a) + /* \"C\":117:119 41 */ dup2 sgt 0x01 and - tag_32 + tag_21 jumpi - tag_33: + /* \"C\":79:428 contract C... */ + tag_22: + mload(0x40) + /* \"C\":117:119 41 */ + swap1 0x29 add - swap1 - jump\t// out - tag_32: - tag_34 - tag_3 - jump\t// in - tag_34: - jump(tag_33) - tag_5: - 0x00 - dup2 - slt - dup1 - iszero - sub(shl(0xff, 0x01), 0x01) - dup4 - swap1 - sub - dup5 - sgt - and - tag_35 - jumpi - tag_36: - shl(0xff, 0x01) - dup3 - swap1 - sub - dup4 - slt - and - tag_37 - jumpi - add - swap1 - jump\t// out - tag_37: - tag_39 - tag_3 - jump\t// in - tag_39: - add - swap1 - jump\t// out - tag_35: - tag_40 - tag_3 - jump\t// in - tag_40: - jump(tag_36) - /* \"C\":304:341 modifier m()... */ - tag_6: /* \"C\":79:428 contract C... */ + dup2 + mstore + return + /* \"C\":117:119 41 */ + tag_21: + tag_23 + tag_4 + jump\t// in + tag_23: + jump(tag_22) + /* \"C\":79:428 contract C... */ + tag_19: + dup1 + revert + tag_2: + pop + jumpi(tag_8, callvalue) + jumpi(tag_8, slt(add(not(0x03), calldatasize), 0x00)) + 0x20 + sload(0x00) + mload(0x40) + swap1 + dup2 + mstore + return + tag_3: + pop + jumpi(tag_8, callvalue) 0x00 dup1 + add(calldatasize, not(0x03)) + slt + tag_19 + jumpi + dup1 sload /* \"C\":117:119 41 */ 0x01 @@ -275,11 +189,9 @@ sub_0: assembly { /* \"C\":79:428 contract C... */ dup2 eq - tag_41 + tag_32 jumpi - /* \"C\":304:341 modifier m()... */ - tag_42: - /* \"C\":79:428 contract C... */ + tag_33: add swap1 dup2 @@ -293,7 +205,7 @@ sub_0: assembly { 0x20 /* \"C\":403:407 this */ dup2 - /* \"C\":403:411 this.f() */ + /* \"C\":79:428 contract C... */ 0x04 /* \"C\":403:407 this */ dup2 @@ -304,113 +216,134 @@ sub_0: assembly { swap2 dup3 iszero - tag_43 + tag_34 jumpi dup1 swap3 - tag_45 + tag_36 jumpi - /* \"C\":304:341 modifier m()... */ - tag_46: + /* \"C\":79:428 contract C... */ + tag_37: /* \"C\":392:411 stateVar + this.f() */ pop pop - tag_47 - swap1 + tag_38 /* \"C\":392:422 stateVar + this.f() + immutVar */ - tag_48 + tag_39 /* \"C\":392:411 stateVar + this.f() */ - swap3 + swap2 + /* \"C\":79:428 contract C... */ + tag_40 + /* \"C\":392:411 stateVar + this.f() */ + swap4 tag_5 jump\t// in - tag_47: + tag_38: /* \"C\":414:422 immutVar */ immutable(\"0xe4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10\") /* \"C\":392:422 stateVar + this.f() + immutVar */ swap1 tag_5 jump\t// in - tag_48: - /* \"C\":304:341 modifier m()... */ - swap1 - jump\t// out - /* \"C\":403:411 this.f() */ - tag_45: + tag_39: /* \"C\":79:428 contract C... */ + mload(0x40) + swap1 + dup2 + mstore + swap1 + dup2 + swap1 + 0x20 + dup3 + add + swap1 + jump + tag_40: + sub + swap1 + return + /* \"C\":403:411 this.f() */ + tag_36: swap1 swap2 pop - /* \"C\":403:411 this.f() */ + 0x20 + swap1 returndatasize + dup3 + gt + tag_41 + jumpi + tag_42: /* \"C\":79:428 contract C... */ 0x1f + dup3 add not(0x1f) and - dup3 + dup4 add swap1 0xffffffffffffffff dup3 gt - dup4 + dup5 dup4 lt or - tag_49 + tag_43 jumpi pop - swap2 - /* \"C\":403:411 this.f() */ - tag_51 - /* \"C\":392:411 stateVar + this.f() */ - tag_47 - /* \"C\":79:428 contract C... */ swap3 + /* \"C\":403:411 this.f() */ + tag_45 /* \"C\":392:422 stateVar + this.f() + immutVar */ - tag_48 + tag_39 /* \"C\":79:428 contract C... */ - swap5 + swap4 + /* \"C\":392:411 stateVar + this.f() */ + tag_38 + /* \"C\":79:428 contract C... */ + swap4 + tag_40 + swap7 0x40 mstore /* \"C\":403:411 this.f() */ - returndatasize dup2 add swap1 - tag_7 + tag_6 jump\t// in - tag_51: - swap2 - dup2 - swap4 + tag_45: + swap3 pop - jump(tag_46) + swap3 + jump(tag_37) /* \"C\":79:428 contract C... */ - tag_49: + tag_43: shl(0xe0, 0x4e487b71) dup2 mstore - 0x41 - /* \"C\":403:411 this.f() */ - 0x04 - /* \"C\":79:428 contract C... */ - mstore + mstore(0x04, 0x41) 0x24 swap5 pop - /* \"C\":117:119 41 */ swap3 pop pop pop - /* \"C\":79:428 contract C... */ revert /* \"C\":403:411 this.f() */ - tag_43: - /* \"C\":79:428 contract C... */ - swap4 + tag_41: + returndatasize + swap2 pop + jump(tag_42) + tag_34: + /* \"C\":79:428 contract C... */ + swap3 pop pop pop @@ -423,13 +356,66 @@ sub_0: assembly { returndatasize swap1 revert - tag_41: + tag_32: + tag_46 + tag_4 + jump\t// in + tag_46: + jump(tag_33) + /* \"C\":117:119 41 */ + tag_4: + pop + /* \"C\":79:428 contract C... */ + shl(0xe0, 0x4e487b71) + /* \"C\":117:119 41 */ + 0x00 + mstore + mstore(0x04, 0x11) + revert(0x00, 0x24) + tag_5: + 0x00 + dup2 + slt + dup1 + iszero + sub(shl(0xff, 0x01), 0x01) + dup4 + swap1 + sub + dup5 + sgt + and + tag_47 + jumpi + tag_48: + shl(0xff, 0x01) + dup3 + swap1 + sub + dup4 + slt + and + tag_49 + jumpi + add + swap1 + jump\t// out + tag_49: + tag_51 + tag_4 + jump\t// in + tag_51: + add + swap1 + jump\t// out + tag_47: tag_52 - tag_3 + tag_4 jump\t// in tag_52: - jump(tag_42) - tag_7: + jump(tag_48) + /* \"C\":79:428 contract C... */ + tag_6: swap1 dup2 0x20 @@ -571,195 +557,109 @@ stop sub_0: assembly { /* \"D\":91:166 contract D is C(3)... */ mstore(0x40, 0x80) - jumpi(tag_8, iszero(lt(calldatasize, 0x04))) + jumpi(tag_7, iszero(lt(calldatasize, 0x04))) + tag_8: 0x00 dup1 revert - tag_8: + tag_7: 0x00 dup1 calldataload 0xe0 shr - dup1 + swap1 + dup2 0x26121ff0 eq - tag_10 + tag_9 jumpi + pop dup1 0x793816ec eq - tag_12 + tag_11 jumpi 0x9942ec6f eq - tag_14 + tag_13 jumpi - pop 0x00 dup1 revert - tag_14: - jumpi(tag_16, callvalue) + tag_13: + tag_8 + tag_3 + jump\t// in + tag_11: pop - tag_18 - calldatasize - tag_1 + tag_8 + tag_2 jump\t// in - tag_18: - tag_19 - /* \"C\":375:378 int */ - tag_20 - tag_6 - jump\t// in - tag_20: - /* \"D\":91:166 contract D is C(3)... */ - mload(0x40) + tag_9: swap1 - dup2 - mstore - swap1 - dup2 - swap1 - 0x20 - dup3 - add - swap1 - jump - tag_19: - sub - swap1 - return - tag_16: + pop + jumpi(tag_19, callvalue) dup1 - revert - tag_12: - pop - jumpi(tag_16, callvalue) + add(calldatasize, not(0x03)) + slt tag_19 - swap1 - tag_24 - calldatasize - tag_1 - jump\t// in - tag_24: - sload - mload(0x40) - swap1 - dup2 - mstore - swap1 - dup2 - swap1 + jumpi + pop 0x20 - dup3 - add - swap1 - jump - tag_10: - pop - jumpi(tag_16, callvalue) - pop - tag_27 - calldatasize - tag_1 - jump\t// in - tag_27: - tag_19 - /* \"C\":279:298 constVar + immutVar */ - tag_20 /* \"C\":290:298 immutVar */ immutable(\"0xe4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10\") - /* \"C\":279:298 constVar + immutVar */ - tag_4 - jump\t// in - /* \"D\":91:166 contract D is C(3)... */ - tag_1: - 0x00 - swap1 - not(0x03) - add - slt - tag_30 - jumpi - jump\t// out - tag_30: - pop - 0x00 - dup1 - revert - /* \"C\":117:119 41 */ - tag_3: - pop - mstore(0x00, shl(0xe0, 0x4e487b71)) - mstore(0x04, 0x11) - revert(0x00, 0x24) - tag_4: sub(shl(0xff, 0x01), 0x2a) + /* \"C\":117:119 41 */ dup2 sgt 0x01 and - tag_32 + tag_21 jumpi - tag_33: + /* \"D\":91:166 contract D is C(3)... */ + tag_22: + mload(0x40) + /* \"C\":117:119 41 */ + swap1 0x29 add - swap1 - jump\t// out - tag_32: - tag_34 - tag_3 - jump\t// in - tag_34: - jump(tag_33) - tag_5: - 0x00 - dup2 - slt - dup1 - iszero - sub(shl(0xff, 0x01), 0x01) - dup4 - swap1 - sub - dup5 - sgt - and - tag_35 - jumpi - tag_36: - shl(0xff, 0x01) - dup3 - swap1 - sub - dup4 - slt - and - tag_37 - jumpi - add - swap1 - jump\t// out - tag_37: - tag_39 - tag_3 - jump\t// in - tag_39: - add - swap1 - jump\t// out - tag_35: - tag_40 - tag_3 - jump\t// in - tag_40: - jump(tag_36) - /* \"C\":304:341 modifier m()... */ - tag_6: /* \"D\":91:166 contract D is C(3)... */ + dup2 + mstore + return + /* \"C\":117:119 41 */ + tag_21: + tag_23 + tag_4 + jump\t// in + tag_23: + jump(tag_22) + /* \"D\":91:166 contract D is C(3)... */ + tag_19: + dup1 + revert + tag_2: + pop + jumpi(tag_8, callvalue) + jumpi(tag_8, slt(add(not(0x03), calldatasize), 0x00)) + 0x20 + sload(0x00) + mload(0x40) + swap1 + dup2 + mstore + return + tag_3: + pop + jumpi(tag_8, callvalue) 0x00 dup1 + add(calldatasize, not(0x03)) + slt + tag_19 + jumpi + dup1 sload /* \"C\":117:119 41 */ 0x01 @@ -768,11 +668,9 @@ sub_0: assembly { /* \"D\":91:166 contract D is C(3)... */ dup2 eq - tag_41 + tag_32 jumpi - /* \"C\":304:341 modifier m()... */ - tag_42: - /* \"D\":91:166 contract D is C(3)... */ + tag_33: add swap1 dup2 @@ -786,7 +684,7 @@ sub_0: assembly { 0x20 /* \"C\":403:407 this */ dup2 - /* \"C\":403:411 this.f() */ + /* \"D\":91:166 contract D is C(3)... */ 0x04 /* \"C\":403:407 this */ dup2 @@ -797,113 +695,134 @@ sub_0: assembly { swap2 dup3 iszero - tag_43 + tag_34 jumpi dup1 swap3 - tag_45 + tag_36 jumpi - /* \"C\":304:341 modifier m()... */ - tag_46: + /* \"D\":91:166 contract D is C(3)... */ + tag_37: /* \"C\":392:411 stateVar + this.f() */ pop pop - tag_47 - swap1 + tag_38 /* \"C\":392:422 stateVar + this.f() + immutVar */ - tag_48 + tag_39 /* \"C\":392:411 stateVar + this.f() */ - swap3 + swap2 + /* \"D\":91:166 contract D is C(3)... */ + tag_40 + /* \"C\":392:411 stateVar + this.f() */ + swap4 tag_5 jump\t// in - tag_47: + tag_38: /* \"C\":414:422 immutVar */ immutable(\"0xe4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10\") /* \"C\":392:422 stateVar + this.f() + immutVar */ swap1 tag_5 jump\t// in - tag_48: - /* \"C\":304:341 modifier m()... */ - swap1 - jump\t// out - /* \"C\":403:411 this.f() */ - tag_45: + tag_39: /* \"D\":91:166 contract D is C(3)... */ + mload(0x40) + swap1 + dup2 + mstore + swap1 + dup2 + swap1 + 0x20 + dup3 + add + swap1 + jump + tag_40: + sub + swap1 + return + /* \"C\":403:411 this.f() */ + tag_36: swap1 swap2 pop - /* \"C\":403:411 this.f() */ + 0x20 + swap1 returndatasize + dup3 + gt + tag_41 + jumpi + tag_42: /* \"D\":91:166 contract D is C(3)... */ 0x1f + dup3 add not(0x1f) and - dup3 + dup4 add swap1 0xffffffffffffffff dup3 gt - dup4 + dup5 dup4 lt or - tag_49 + tag_43 jumpi pop - swap2 - /* \"C\":403:411 this.f() */ - tag_51 - /* \"C\":392:411 stateVar + this.f() */ - tag_47 - /* \"D\":91:166 contract D is C(3)... */ swap3 + /* \"C\":403:411 this.f() */ + tag_45 /* \"C\":392:422 stateVar + this.f() + immutVar */ - tag_48 + tag_39 /* \"D\":91:166 contract D is C(3)... */ - swap5 + swap4 + /* \"C\":392:411 stateVar + this.f() */ + tag_38 + /* \"D\":91:166 contract D is C(3)... */ + swap4 + tag_40 + swap7 0x40 mstore /* \"C\":403:411 this.f() */ - returndatasize dup2 add swap1 - tag_7 + tag_6 jump\t// in - tag_51: - swap2 - dup2 - swap4 + tag_45: + swap3 pop - jump(tag_46) + swap3 + jump(tag_37) /* \"D\":91:166 contract D is C(3)... */ - tag_49: + tag_43: shl(0xe0, 0x4e487b71) dup2 mstore - 0x41 - /* \"C\":403:411 this.f() */ - 0x04 - /* \"D\":91:166 contract D is C(3)... */ - mstore + mstore(0x04, 0x41) 0x24 swap5 pop - /* \"C\":117:119 41 */ swap3 pop pop pop - /* \"D\":91:166 contract D is C(3)... */ revert /* \"C\":403:411 this.f() */ - tag_43: - /* \"D\":91:166 contract D is C(3)... */ - swap4 + tag_41: + returndatasize + swap2 pop + jump(tag_42) + tag_34: + /* \"D\":91:166 contract D is C(3)... */ + swap3 pop pop pop @@ -916,13 +835,66 @@ sub_0: assembly { returndatasize swap1 revert - tag_41: + tag_32: + tag_46 + tag_4 + jump\t// in + tag_46: + jump(tag_33) + /* \"C\":117:119 41 */ + tag_4: + pop + /* \"D\":91:166 contract D is C(3)... */ + shl(0xe0, 0x4e487b71) + /* \"C\":117:119 41 */ + 0x00 + mstore + mstore(0x04, 0x11) + revert(0x00, 0x24) + tag_5: + 0x00 + dup2 + slt + dup1 + iszero + sub(shl(0xff, 0x01), 0x01) + dup4 + swap1 + sub + dup5 + sgt + and + tag_47 + jumpi + tag_48: + shl(0xff, 0x01) + dup3 + swap1 + sub + dup4 + slt + and + tag_49 + jumpi + add + swap1 + jump\t// out + tag_49: + tag_51 + tag_4 + jump\t// in + tag_51: + add + swap1 + jump\t// out + tag_47: tag_52 - tag_3 + tag_4 jump\t// in tag_52: - jump(tag_42) - tag_7: + jump(tag_48) + /* \"D\":91:166 contract D is C(3)... */ + tag_6: swap1 dup2 0x20 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 1fa8928e1..16236251d 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 @@ -114,12 +114,7 @@ object \"C_6\" { { // f() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - fun_f_5() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple__to__fromStack(memPos ) - return(memPos, sub(memEnd, memPos)) + external_fun_f_5() } default {} @@ -156,6 +151,17 @@ object \"C_6\" { } + function external_fun_f_5() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + fun_f_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { 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 e427b7fe1..d017c8e9c 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 @@ -114,12 +114,7 @@ object \"C_6\" { { // f() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - fun_f_5() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple__to__fromStack(memPos ) - return(memPos, sub(memEnd, memPos)) + external_fun_f_5() } default {} @@ -156,6 +151,17 @@ object \"C_6\" { } + function external_fun_f_5() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + fun_f_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { 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 e81f461d2..afe07fad9 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 @@ -107,12 +107,7 @@ object \"C_6\" { { // f() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - fun_f_5() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple__to__fromStack(memPos ) - return(memPos, sub(memEnd, memPos)) + external_fun_f_5() } default {} @@ -149,6 +144,17 @@ object \"C_6\" { } + function external_fun_f_5() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + fun_f_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { 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 2acd68ff7..f593301bc 100644 --- a/test/cmdlineTests/standard_debug_info_in_yul_location/output.json +++ b/test/cmdlineTests/standard_debug_info_in_yul_location/output.json @@ -172,48 +172,28 @@ object \"C_54\" { { // f() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - let ret_0 := fun_f_30() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0) - return(memPos, sub(memEnd, memPos)) + external_fun_f_30() } case 0x793816ec { // stateVar() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - let ret_0 := getter_fun_stateVar_10() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0) - return(memPos, sub(memEnd, memPos)) + external_fun_stateVar_10() } case 0x9942ec6f { // f2() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - let ret_0 := fun_f2_53() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0) - return(memPos, sub(memEnd, memPos)) + external_fun_f2_53() } case 0xa00b982b { // constVar() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - let ret_0 := getter_fun_constVar_5() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0) - return(memPos, sub(memEnd, memPos)) + external_fun_constVar_5() } default {} @@ -260,6 +240,17 @@ object \"C_54\" { } + function external_fun_f_30() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + let ret_0 := fun_f_30() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0) + return(memPos, sub(memEnd, memPos)) + + } + function shift_right_unsigned_dynamic(bits, value) -> newValue { newValue := @@ -292,6 +283,28 @@ object \"C_54\" { } /// @src 0:79:435 \"contract C...\" + function external_fun_stateVar_10() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + let ret_0 := getter_fun_stateVar_10() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0) + return(memPos, sub(memEnd, memPos)) + + } + + function external_fun_f2_53() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + let ret_0 := fun_f2_53() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0) + return(memPos, sub(memEnd, memPos)) + + } + function cleanup_t_rational_41_by_1(value) -> cleaned { cleaned := value } @@ -320,6 +333,17 @@ object \"C_54\" { } /// @src 0:79:435 \"contract C...\" + function external_fun_constVar_5() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + let ret_0 := getter_fun_constVar_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0) + return(memPos, sub(memEnd, memPos)) + + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } @@ -539,18 +563,24 @@ object \"C_54\" { let expr_47 if _12 { + let _13 := 32 + + if gt(_13, returndatasize()) { + _13 := returndatasize() + } + // update freeMemoryPointer according to dynamic return size - finalize_allocation(_10, returndatasize()) + finalize_allocation(_10, _13) // decode return parameters from external try-call into retVars - expr_47 := abi_decode_tuple_t_int256_fromMemory(_10, add(_10, returndatasize())) + expr_47 := abi_decode_tuple_t_int256_fromMemory(_10, add(_10, _13)) } /// @src 0:399:418 \"stateVar + this.f()\" let expr_48 := checked_add_t_int256(expr_44, expr_47) /// @src 0:421:429 \"immutVar\" - let _13 := loadimmutable(\"8\") - let expr_49 := _13 + let _14 := loadimmutable(\"8\") + let expr_49 := _14 /// @src 0:399:429 \"stateVar + this.f() + immutVar\" let expr_50 := checked_add_t_int256(expr_48, expr_49) @@ -638,62 +668,99 @@ object \"C_54\" { switch shr(224, calldataload(_1)) case 0x26121ff0 { if callvalue() { revert(_1, _1) } - abi_decode(calldatasize()) - let ret := /** @src 0:286:305 \"constVar + immutVar\" */ checked_add_int256_556(/** @src 0:297:305 \"immutVar\" */ loadimmutable(\"8\")) + if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } + /// @src 0:297:305 \"immutVar\" + let _2 := loadimmutable(\"8\") /// @src 0:79:435 \"contract C...\" + if and(1, sgt(_2, sub(shl(255, 1), 42))) { panic_error_0x11() } let memPos := mload(64) - return(memPos, sub(abi_encode_int256(memPos, ret), memPos)) - } - case 0x793816ec { - if callvalue() { revert(_1, _1) } - abi_decode(calldatasize()) - let ret_1 := sload(_1) - let memPos_1 := mload(64) - return(memPos_1, sub(abi_encode_int256(memPos_1, ret_1), memPos_1)) - } - case 0x9942ec6f { - if callvalue() { revert(_1, _1) } - abi_decode(calldatasize()) - let ret_2 := /** @src 0:382:385 \"int\" */ modifier_m() - /// @src 0:79:435 \"contract C...\" - let memPos_2 := mload(64) - return(memPos_2, sub(abi_encode_int256(memPos_2, ret_2), memPos_2)) - } - case 0xa00b982b { - if callvalue() { revert(_1, _1) } - abi_decode(calldatasize()) - let memPos_3 := mload(64) - return(memPos_3, sub(abi_encode_int256_555(memPos_3), memPos_3)) + mstore(memPos, add(/** @src 0:124:126 \"41\" */ 0x29, /** @src 0:79:435 \"contract C...\" */ _2)) + return(memPos, 32) } + case 0x793816ec { external_fun_stateVar() } + case 0x9942ec6f { external_fun_f2() } + case 0xa00b982b { external_fun_constVar() } } revert(0, 0) } - function abi_decode(dataEnd) - { - if slt(add(dataEnd, not(3)), 0) { revert(0, 0) } - } - function abi_encode_int256_555(headStart) -> tail - { - tail := add(headStart, 32) - mstore(headStart, /** @src 0:124:126 \"41\" */ 0x29) - } - /// @src 0:79:435 \"contract C...\" function abi_encode_int256(headStart, value0) -> tail { tail := add(headStart, 32) mstore(headStart, value0) } + function external_fun_stateVar() + { + if callvalue() { revert(0, 0) } + if slt(add(calldatasize(), not(3)), 0) { revert(0, 0) } + let _1 := sload(0) + let memPos := mload(64) + mstore(memPos, _1) + return(memPos, 32) + } + function external_fun_f2() + { + if callvalue() { revert(0, 0) } + let _1 := 0 + if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } + let _2 := sload(_1) + if eq(_2, sub(shl(255, 1), 1)) { panic_error_0x11() } + let ret := add(_2, 1) + sstore(_1, ret) + /// @src 0:410:418 \"this.f()\" + let _3 := /** @src 0:79:435 \"contract C...\" */ mload(64) + /// @src 0:410:418 \"this.f()\" + mstore(_3, /** @src 0:79:435 \"contract C...\" */ shl(228, 0x026121ff)) + /// @src 0:410:418 \"this.f()\" + let _4 := staticcall(gas(), /** @src 0:410:414 \"this\" */ address(), /** @src 0:410:418 \"this.f()\" */ _3, /** @src 0:79:435 \"contract C...\" */ 4, /** @src 0:410:418 \"this.f()\" */ _3, 32) + if iszero(_4) + { + /// @src 0:79:435 \"contract C...\" + let pos := mload(64) + returndatacopy(pos, _1, returndatasize()) + revert(pos, returndatasize()) + } + /// @src 0:410:418 \"this.f()\" + let expr := /** @src 0:79:435 \"contract C...\" */ _1 + /// @src 0:410:418 \"this.f()\" + if _4 + { + let _5 := 32 + if gt(_5, returndatasize()) { _5 := returndatasize() } + /// @src 0:79:435 \"contract C...\" + let newFreePtr := add(_3, and(add(_5, 31), not(31))) + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, _3)) + { + mstore(_1, shl(224, 0x4e487b71)) + mstore(4, 0x41) + revert(_1, 0x24) + } + mstore(64, newFreePtr) + /// @src 0:410:418 \"this.f()\" + expr := abi_decode_int256_fromMemory(_3, add(_3, _5)) + } + /// @src 0:399:418 \"stateVar + this.f()\" + let expr_1 := checked_add_int256(ret, expr) + /// @src 0:392:429 \"return stateVar + this.f() + immutVar\" + let var := /** @src 0:399:429 \"stateVar + this.f() + immutVar\" */ checked_add_int256(expr_1, /** @src 0:421:429 \"immutVar\" */ loadimmutable(\"8\")) + /// @src 0:79:435 \"contract C...\" + let memPos := mload(64) + return(memPos, sub(abi_encode_int256(memPos, var), memPos)) + } + function external_fun_constVar() + { + if callvalue() { revert(0, 0) } + if slt(add(calldatasize(), not(3)), 0) { revert(0, 0) } + let memPos := mload(64) + mstore(memPos, /** @src 0:124:126 \"41\" */ 0x29) + /// @src 0:79:435 \"contract C...\" + return(memPos, 32) + } function panic_error_0x11() { mstore(0, shl(224, 0x4e487b71)) mstore(4, 0x11) revert(0, 0x24) } - function checked_add_int256_556(y) -> sum - { - if and(1, sgt(y, sub(shl(255, 1), 42))) { panic_error_0x11() } - sum := add(/** @src 0:124:126 \"41\" */ 0x29, /** @src 0:79:435 \"contract C...\" */ y) - } function checked_add_int256(x, y) -> sum { let _1 := slt(x, 0) @@ -701,51 +768,6 @@ object \"C_54\" { if and(_1, slt(y, sub(shl(255, 1), x))) { panic_error_0x11() } sum := add(x, y) } - /// @ast-id 37 @src 0:311:348 \"modifier m()...\" - function modifier_m() -> _1 - { - /// @src 0:79:435 \"contract C...\" - let _2 := 0 - let _3 := sload(_2) - if eq(_3, sub(shl(255, 1), 1)) { panic_error_0x11() } - let ret := add(_3, 1) - sstore(_2, ret) - /// @src 0:410:418 \"this.f()\" - let _4 := /** @src 0:79:435 \"contract C...\" */ mload(64) - /// @src 0:410:418 \"this.f()\" - mstore(_4, /** @src 0:79:435 \"contract C...\" */ shl(228, 0x026121ff)) - /// @src 0:410:418 \"this.f()\" - let _5 := staticcall(gas(), /** @src 0:410:414 \"this\" */ address(), /** @src 0:410:418 \"this.f()\" */ _4, 4, _4, 32) - if iszero(_5) - { - /// @src 0:79:435 \"contract C...\" - let pos := mload(64) - returndatacopy(pos, _2, returndatasize()) - revert(pos, returndatasize()) - } - /// @src 0:410:418 \"this.f()\" - let expr := /** @src 0:79:435 \"contract C...\" */ _2 - /// @src 0:410:418 \"this.f()\" - if _5 - { - /// @src 0:79:435 \"contract C...\" - let newFreePtr := add(_4, and(add(/** @src 0:410:418 \"this.f()\" */ returndatasize(), /** @src 0:79:435 \"contract C...\" */ 31), not(31))) - if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, _4)) - { - mstore(_2, shl(224, 0x4e487b71)) - mstore(/** @src 0:410:418 \"this.f()\" */ 4, /** @src 0:79:435 \"contract C...\" */ 0x41) - revert(_2, 0x24) - } - mstore(64, newFreePtr) - /// @src 0:410:418 \"this.f()\" - expr := abi_decode_int256_fromMemory(_4, add(_4, returndatasize())) - } - /// @src 0:399:418 \"stateVar + this.f()\" - let expr_1 := checked_add_int256(ret, expr) - /// @src 0:343:344 \"_\" - _1 := /** @src 0:399:429 \"stateVar + this.f() + immutVar\" */ checked_add_int256(expr_1, /** @src 0:421:429 \"immutVar\" */ loadimmutable(\"8\")) - } - /// @src 0:79:435 \"contract C...\" function abi_decode_int256_fromMemory(headStart, dataEnd) -> value0 { if slt(sub(dataEnd, headStart), 32) { revert(0, 0) } @@ -997,48 +1019,28 @@ object \"D_72\" { { // f() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - let ret_0 := fun_f_30() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0) - return(memPos, sub(memEnd, memPos)) + external_fun_f_30() } case 0x793816ec { // stateVar() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - let ret_0 := getter_fun_stateVar_10() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0) - return(memPos, sub(memEnd, memPos)) + external_fun_stateVar_10() } case 0x9942ec6f { // f2() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - let ret_0 := fun_f2_53() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0) - return(memPos, sub(memEnd, memPos)) + external_fun_f2_53() } case 0xa00b982b { // constVar() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - let ret_0 := getter_fun_constVar_5() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0) - return(memPos, sub(memEnd, memPos)) + external_fun_constVar_5() } default {} @@ -1085,6 +1087,17 @@ object \"D_72\" { } + function external_fun_f_30() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + let ret_0 := fun_f_30() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0) + return(memPos, sub(memEnd, memPos)) + + } + function shift_right_unsigned_dynamic(bits, value) -> newValue { newValue := @@ -1117,6 +1130,28 @@ object \"D_72\" { } /// @src 1:91:166 \"contract D is C(3)...\" + function external_fun_stateVar_10() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + let ret_0 := getter_fun_stateVar_10() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0) + return(memPos, sub(memEnd, memPos)) + + } + + function external_fun_f2_53() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + let ret_0 := fun_f2_53() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0) + return(memPos, sub(memEnd, memPos)) + + } + function cleanup_t_rational_41_by_1(value) -> cleaned { cleaned := value } @@ -1145,6 +1180,17 @@ object \"D_72\" { } /// @src 1:91:166 \"contract D is C(3)...\" + function external_fun_constVar_5() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + let ret_0 := getter_fun_constVar_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0) + return(memPos, sub(memEnd, memPos)) + + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } @@ -1364,18 +1410,24 @@ object \"D_72\" { let expr_47 if _12 { + let _13 := 32 + + if gt(_13, returndatasize()) { + _13 := returndatasize() + } + // update freeMemoryPointer according to dynamic return size - finalize_allocation(_10, returndatasize()) + finalize_allocation(_10, _13) // decode return parameters from external try-call into retVars - expr_47 := abi_decode_tuple_t_int256_fromMemory(_10, add(_10, returndatasize())) + expr_47 := abi_decode_tuple_t_int256_fromMemory(_10, add(_10, _13)) } /// @src 0:399:418 \"stateVar + this.f()\" let expr_48 := checked_add_t_int256(expr_44, expr_47) /// @src 0:421:429 \"immutVar\" - let _13 := loadimmutable(\"8\") - let expr_49 := _13 + let _14 := loadimmutable(\"8\") + let expr_49 := _14 /// @src 0:399:429 \"stateVar + this.f() + immutVar\" let expr_50 := checked_add_t_int256(expr_48, expr_49) @@ -1471,62 +1523,99 @@ object \"D_72\" { switch shr(224, calldataload(_1)) case 0x26121ff0 { if callvalue() { revert(_1, _1) } - abi_decode(calldatasize()) - let ret := /** @src 0:286:305 \"constVar + immutVar\" */ checked_add_int256_556(/** @src 0:297:305 \"immutVar\" */ loadimmutable(\"8\")) + if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } + /// @src 0:297:305 \"immutVar\" + let _2 := loadimmutable(\"8\") /// @src 1:91:166 \"contract D is C(3)...\" + if and(1, sgt(_2, sub(shl(255, 1), 42))) { panic_error_0x11() } let memPos := mload(64) - return(memPos, sub(abi_encode_int256(memPos, ret), memPos)) - } - case 0x793816ec { - if callvalue() { revert(_1, _1) } - abi_decode(calldatasize()) - let ret_1 := sload(_1) - let memPos_1 := mload(64) - return(memPos_1, sub(abi_encode_int256(memPos_1, ret_1), memPos_1)) - } - case 0x9942ec6f { - if callvalue() { revert(_1, _1) } - abi_decode(calldatasize()) - let ret_2 := /** @src 0:382:385 \"int\" */ modifier_m() - /// @src 1:91:166 \"contract D is C(3)...\" - let memPos_2 := mload(64) - return(memPos_2, sub(abi_encode_int256(memPos_2, ret_2), memPos_2)) - } - case 0xa00b982b { - if callvalue() { revert(_1, _1) } - abi_decode(calldatasize()) - let memPos_3 := mload(64) - return(memPos_3, sub(abi_encode_int256_555(memPos_3), memPos_3)) + mstore(memPos, add(/** @src 0:124:126 \"41\" */ 0x29, /** @src 1:91:166 \"contract D is C(3)...\" */ _2)) + return(memPos, 32) } + case 0x793816ec { external_fun_stateVar() } + case 0x9942ec6f { external_fun_f2() } + case 0xa00b982b { external_fun_constVar() } } revert(0, 0) } - function abi_decode(dataEnd) - { - if slt(add(dataEnd, not(3)), 0) { revert(0, 0) } - } - function abi_encode_int256_555(headStart) -> tail - { - tail := add(headStart, 32) - mstore(headStart, /** @src 0:124:126 \"41\" */ 0x29) - } - /// @src 1:91:166 \"contract D is C(3)...\" function abi_encode_int256(headStart, value0) -> tail { tail := add(headStart, 32) mstore(headStart, value0) } + function external_fun_stateVar() + { + if callvalue() { revert(0, 0) } + if slt(add(calldatasize(), not(3)), 0) { revert(0, 0) } + let _1 := sload(0) + let memPos := mload(64) + mstore(memPos, _1) + return(memPos, 32) + } + function external_fun_f2() + { + if callvalue() { revert(0, 0) } + let _1 := 0 + if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } + let _2 := sload(_1) + if eq(_2, sub(shl(255, 1), 1)) { panic_error_0x11() } + let ret := add(_2, 1) + sstore(_1, ret) + /// @src 0:410:418 \"this.f()\" + let _3 := /** @src 1:91:166 \"contract D is C(3)...\" */ mload(64) + /// @src 0:410:418 \"this.f()\" + mstore(_3, /** @src 1:91:166 \"contract D is C(3)...\" */ shl(228, 0x026121ff)) + /// @src 0:410:418 \"this.f()\" + let _4 := staticcall(gas(), /** @src 0:410:414 \"this\" */ address(), /** @src 0:410:418 \"this.f()\" */ _3, /** @src 1:91:166 \"contract D is C(3)...\" */ 4, /** @src 0:410:418 \"this.f()\" */ _3, 32) + if iszero(_4) + { + /// @src 1:91:166 \"contract D is C(3)...\" + let pos := mload(64) + returndatacopy(pos, _1, returndatasize()) + revert(pos, returndatasize()) + } + /// @src 0:410:418 \"this.f()\" + let expr := /** @src 1:91:166 \"contract D is C(3)...\" */ _1 + /// @src 0:410:418 \"this.f()\" + if _4 + { + let _5 := 32 + if gt(_5, returndatasize()) { _5 := returndatasize() } + /// @src 1:91:166 \"contract D is C(3)...\" + let newFreePtr := add(_3, and(add(_5, 31), not(31))) + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, _3)) + { + mstore(_1, shl(224, 0x4e487b71)) + mstore(4, 0x41) + revert(_1, 0x24) + } + mstore(64, newFreePtr) + /// @src 0:410:418 \"this.f()\" + expr := abi_decode_int256_fromMemory(_3, add(_3, _5)) + } + /// @src 0:399:418 \"stateVar + this.f()\" + let expr_1 := checked_add_int256(ret, expr) + /// @src 0:392:429 \"return stateVar + this.f() + immutVar\" + let var := /** @src 0:399:429 \"stateVar + this.f() + immutVar\" */ checked_add_int256(expr_1, /** @src 0:421:429 \"immutVar\" */ loadimmutable(\"8\")) + /// @src 1:91:166 \"contract D is C(3)...\" + let memPos := mload(64) + return(memPos, sub(abi_encode_int256(memPos, var), memPos)) + } + function external_fun_constVar() + { + if callvalue() { revert(0, 0) } + if slt(add(calldatasize(), not(3)), 0) { revert(0, 0) } + let memPos := mload(64) + mstore(memPos, /** @src 0:124:126 \"41\" */ 0x29) + /// @src 1:91:166 \"contract D is C(3)...\" + return(memPos, 32) + } function panic_error_0x11() { mstore(0, shl(224, 0x4e487b71)) mstore(4, 0x11) revert(0, 0x24) } - function checked_add_int256_556(y) -> sum - { - if and(1, sgt(y, sub(shl(255, 1), 42))) { panic_error_0x11() } - sum := add(/** @src 0:124:126 \"41\" */ 0x29, /** @src 1:91:166 \"contract D is C(3)...\" */ y) - } function checked_add_int256(x, y) -> sum { let _1 := slt(x, 0) @@ -1534,51 +1623,6 @@ object \"D_72\" { if and(_1, slt(y, sub(shl(255, 1), x))) { panic_error_0x11() } sum := add(x, y) } - /// @ast-id 37 @src 0:311:348 \"modifier m()...\" - function modifier_m() -> _1 - { - /// @src 1:91:166 \"contract D is C(3)...\" - let _2 := 0 - let _3 := sload(_2) - if eq(_3, sub(shl(255, 1), 1)) { panic_error_0x11() } - let ret := add(_3, 1) - sstore(_2, ret) - /// @src 0:410:418 \"this.f()\" - let _4 := /** @src 1:91:166 \"contract D is C(3)...\" */ mload(64) - /// @src 0:410:418 \"this.f()\" - mstore(_4, /** @src 1:91:166 \"contract D is C(3)...\" */ shl(228, 0x026121ff)) - /// @src 0:410:418 \"this.f()\" - let _5 := staticcall(gas(), /** @src 0:410:414 \"this\" */ address(), /** @src 0:410:418 \"this.f()\" */ _4, 4, _4, 32) - if iszero(_5) - { - /// @src 1:91:166 \"contract D is C(3)...\" - let pos := mload(64) - returndatacopy(pos, _2, returndatasize()) - revert(pos, returndatasize()) - } - /// @src 0:410:418 \"this.f()\" - let expr := /** @src 1:91:166 \"contract D is C(3)...\" */ _2 - /// @src 0:410:418 \"this.f()\" - if _5 - { - /// @src 1:91:166 \"contract D is C(3)...\" - let newFreePtr := add(_4, and(add(/** @src 0:410:418 \"this.f()\" */ returndatasize(), /** @src 1:91:166 \"contract D is C(3)...\" */ 31), not(31))) - if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, _4)) - { - mstore(_2, shl(224, 0x4e487b71)) - mstore(/** @src 0:410:418 \"this.f()\" */ 4, /** @src 1:91:166 \"contract D is C(3)...\" */ 0x41) - revert(_2, 0x24) - } - mstore(64, newFreePtr) - /// @src 0:410:418 \"this.f()\" - expr := abi_decode_int256_fromMemory(_4, add(_4, returndatasize())) - } - /// @src 0:399:418 \"stateVar + this.f()\" - let expr_1 := checked_add_int256(ret, expr) - /// @src 0:343:344 \"_\" - _1 := /** @src 0:399:429 \"stateVar + this.f() + immutVar\" */ checked_add_int256(expr_1, /** @src 0:421:429 \"immutVar\" */ loadimmutable(\"8\")) - } - /// @src 1:91:166 \"contract D is C(3)...\" function abi_decode_int256_fromMemory(headStart, dataEnd) -> value0 { if slt(sub(dataEnd, headStart), 32) { revert(0, 0) } diff --git a/test/cmdlineTests/standard_irOptimized_requested/output.json b/test/cmdlineTests/standard_irOptimized_requested/output.json index c56849339..85b861602 100644 --- a/test/cmdlineTests/standard_irOptimized_requested/output.json +++ b/test/cmdlineTests/standard_irOptimized_requested/output.json @@ -34,17 +34,7 @@ object \"C_7\" { { let selector := shift_right_224_unsigned(calldataload(0)) switch selector - case 0x26121ff0 { - if callvalue() - { - revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() - } - abi_decode_tuple_(4, calldatasize()) - fun_f_6() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple__to__fromStack(memPos) - return(memPos, sub(memEnd, memPos)) - } + case 0x26121ff0 { external_fun_f_6() } default { } } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() @@ -65,6 +55,18 @@ object \"C_7\" { } function abi_encode_tuple__to__fromStack(headStart) -> tail { tail := add(headStart, 0) } + function external_fun_f_6() + { + if callvalue() + { + revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() + } + abi_decode_tuple_(4, calldatasize()) + fun_f_6() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos) + return(memPos, sub(memEnd, memPos)) + } function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } /// @ast-id 6 @src 0:92:119 \"function f() public pure {}\" diff --git a/test/cmdlineTests/standard_ir_requested/output.json b/test/cmdlineTests/standard_ir_requested/output.json index 59f07f768..1e7f8dec3 100644 --- a/test/cmdlineTests/standard_ir_requested/output.json +++ b/test/cmdlineTests/standard_ir_requested/output.json @@ -52,12 +52,7 @@ object \"C_7\" { { // f() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - fun_f_6() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple__to__fromStack(memPos ) - return(memPos, sub(memEnd, memPos)) + external_fun_f_6() } default {} @@ -94,6 +89,17 @@ object \"C_7\" { } + function external_fun_f_6() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + fun_f_6() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } diff --git a/test/cmdlineTests/standard_viair_requested/output.json b/test/cmdlineTests/standard_viair_requested/output.json index b72923f48..881a4bad4 100644 --- a/test/cmdlineTests/standard_viair_requested/output.json +++ b/test/cmdlineTests/standard_viair_requested/output.json @@ -121,12 +121,7 @@ object \"D_16\" { { // f() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - fun_f_15() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple__to__fromStack(memPos ) - return(memPos, sub(memEnd, memPos)) + external_fun_f_15() } default {} @@ -163,6 +158,17 @@ object \"D_16\" { } + function external_fun_f_15() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + fun_f_15() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } diff --git a/test/cmdlineTests/viair_abicoder_v1/output b/test/cmdlineTests/viair_abicoder_v1/output index cedda56dc..c71c535da 100644 --- a/test/cmdlineTests/viair_abicoder_v1/output +++ b/test/cmdlineTests/viair_abicoder_v1/output @@ -53,12 +53,7 @@ object "test_11" { { // f() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - let ret_0 := fun_f_10() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple_t_bool__to_t_bool__fromStack(memPos , ret_0) - return(memPos, sub(memEnd, memPos)) + external_fun_f_10() } default {} @@ -105,6 +100,17 @@ object "test_11" { } + function external_fun_f_10() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + let ret_0 := fun_f_10() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple_t_bool__to_t_bool__fromStack(memPos , ret_0) + return(memPos, sub(memEnd, memPos)) + + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } diff --git a/test/cmdlineTests/yul_optimizer_steps_nested_brackets/output b/test/cmdlineTests/yul_optimizer_steps_nested_brackets/output index cc67ca5bc..5b7c3fdb0 100644 --- a/test/cmdlineTests/yul_optimizer_steps_nested_brackets/output +++ b/test/cmdlineTests/yul_optimizer_steps_nested_brackets/output @@ -125,18 +125,7 @@ object "C_6" { if iszero(lt(calldatasize(), 4)) { let selector := shift_right_unsigned(calldataload(0)) - if eq(0x26121ff0, selector) - { - if callvalue() - { - revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() - } - abi_decode(4, calldatasize()) - fun_f() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple(memPos) - return(memPos, sub(memEnd, memPos)) - } + if eq(0x26121ff0, selector) { external_fun_f() } } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() } @@ -421,6 +410,18 @@ object "C_6" { let tail_86 := tail_1 tail := tail_1 } + function external_fun_f() + { + if callvalue() + { + revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() + } + abi_decode(4, calldatasize()) + fun_f() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple(memPos) + return(memPos, sub(memEnd, memPos)) + } function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } /// @ast-id 5 @src 0:74:101 "function f() public pure {}" diff --git a/test/cmdlineTests/yul_string_format_ascii/output.json b/test/cmdlineTests/yul_string_format_ascii/output.json index 2354929e4..46dd577eb 100644 --- a/test/cmdlineTests/yul_string_format_ascii/output.json +++ b/test/cmdlineTests/yul_string_format_ascii/output.json @@ -52,12 +52,7 @@ object \"C_11\" { { // f() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - let ret_0 := fun_f_10() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0) - return(memPos, sub(memEnd, memPos)) + external_fun_f_10() } default {} @@ -132,6 +127,17 @@ object \"C_11\" { } + function external_fun_f_10() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + let ret_0 := fun_f_10() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0) + return(memPos, sub(memEnd, memPos)) + + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json index 84e9ff271..0ffffa3a4 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json @@ -52,12 +52,7 @@ object \"C_11\" { { // f() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - let ret_0 := fun_f_10() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple_t_bytes32__to_t_bytes32__fromStack(memPos , ret_0) - return(memPos, sub(memEnd, memPos)) + external_fun_f_10() } default {} @@ -104,6 +99,17 @@ object \"C_11\" { } + function external_fun_f_10() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + let ret_0 := fun_f_10() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple_t_bytes32__to_t_bytes32__fromStack(memPos , ret_0) + return(memPos, sub(memEnd, memPos)) + + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } 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 716a1cc6e..1fb107015 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 @@ -52,12 +52,7 @@ object \"C_11\" { { // f() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - let ret_0 := fun_f_10() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0) - return(memPos, sub(memEnd, memPos)) + external_fun_f_10() } default {} @@ -104,6 +99,17 @@ object \"C_11\" { } + function external_fun_f_10() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + let ret_0 := fun_f_10() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0) + return(memPos, sub(memEnd, memPos)) + + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } diff --git a/test/cmdlineTests/yul_string_format_ascii_long/output.json b/test/cmdlineTests/yul_string_format_ascii_long/output.json index 1f52e103b..bf757e685 100644 --- a/test/cmdlineTests/yul_string_format_ascii_long/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_long/output.json @@ -52,12 +52,7 @@ object \"C_11\" { { // f() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - let ret_0 := fun_f_10() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0) - return(memPos, sub(memEnd, memPos)) + external_fun_f_10() } default {} @@ -132,6 +127,17 @@ object \"C_11\" { } + function external_fun_f_10() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + let ret_0 := fun_f_10() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0) + return(memPos, sub(memEnd, memPos)) + + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } diff --git a/test/cmdlineTests/yul_string_format_hex/output.json b/test/cmdlineTests/yul_string_format_hex/output.json index 04166a760..0ff492ce4 100644 --- a/test/cmdlineTests/yul_string_format_hex/output.json +++ b/test/cmdlineTests/yul_string_format_hex/output.json @@ -52,12 +52,7 @@ object \"C_11\" { { // f() - if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } - abi_decode_tuple_(4, calldatasize()) - let ret_0 := fun_f_10() - let memPos := allocate_unbounded() - let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0) - return(memPos, sub(memEnd, memPos)) + external_fun_f_10() } default {} @@ -104,6 +99,17 @@ object \"C_11\" { } + function external_fun_f_10() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + let ret_0 := fun_f_10() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0) + return(memPos, sub(memEnd, memPos)) + + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } diff --git a/test/externalTests/ens.sh b/test/externalTests/ens.sh index 734c5d8ae..e4edbf46c 100755 --- a/test/externalTests/ens.sh +++ b/test/externalTests/ens.sh @@ -48,7 +48,7 @@ function ens_test "${compile_only_presets[@]}" #ir-no-optimize # Compilation fails with "YulException: Variable var__945 is 1 slot(s) too deep inside the stack." #ir-optimize-evm-only # Compilation fails with "YulException: Variable var__945 is 1 slot(s) too deep inside the stack." - #ir-optimize-evm+yul # Compilation fails with "YulException: Variable _5 is 1 too deep in the stack [ _5 usr$i usr$h _7 usr$scratch usr$k usr$f _4 usr$len usr$j_2 RET _2 _1 var_data_mpos usr$totallen usr$x _12 ]" + ir-optimize-evm+yul # Needs memory-safe inline assembly patch legacy-optimize-evm-only legacy-optimize-evm+yul ) @@ -68,6 +68,8 @@ function ens_test replace_version_pragmas neutralize_packaged_contracts + find . -name "*.sol" -exec sed -i -e 's/^\(\s*\)\(assembly\)/\1\/\/\/ @solidity memory-safe-assembly\n\1\2/' '{}' \; + for preset in $SELECTED_PRESETS; do hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn store_benchmark_report hardhat ens "$repo" "$preset" diff --git a/test/externalTests/perpetual-pools.sh b/test/externalTests/perpetual-pools.sh index 8f90ed0b4..7e4289698 100755 --- a/test/externalTests/perpetual-pools.sh +++ b/test/externalTests/perpetual-pools.sh @@ -66,6 +66,11 @@ function perpetual_pools_test force_hardhat_unlimited_contract_size "$config_file" "$config_var" yarn install + # The project depends on @openzeppelin/hardhat-upgrades, which is currently not prepared + # for the parallel compilation introduced in Hardhat 2.9.0. + # TODO: Remove when https://github.com/OpenZeppelin/openzeppelin-upgrades/issues/528 is fixed. + yarn add hardhat@2.8.4 + replace_version_pragmas for preset in $SELECTED_PRESETS; do diff --git a/test/externalTests/trident.sh b/test/externalTests/trident.sh index 5e230560d..6c1f56fbb 100755 --- a/test/externalTests/trident.sh +++ b/test/externalTests/trident.sh @@ -56,7 +56,7 @@ function trident_test "${compile_only_presets[@]}" #ir-no-optimize # Compilation fails with: "YulException: Variable var_amount_165 is 9 slot(s) too deep inside the stack." #ir-optimize-evm-only # Compilation fails with: "YulException: Variable var_amount_165 is 9 slot(s) too deep inside the stack." - #ir-optimize-evm+yul # Compilation fails with: "YulException: Cannot swap Variable var_nearestTick with Variable _4: too deep in the stack by 4 slots" + ir-optimize-evm+yul # Needs memory-safe inline assembly patch legacy-no-optimize legacy-optimize-evm-only legacy-optimize-evm+yul @@ -87,6 +87,7 @@ function trident_test sed -i 's|uint32(-1)|type(uint32).max|g' contracts/flat/BentoBoxV1Flat.sol sed -i 's|IERC20(0)|IERC20(address(0))|g' contracts/flat/BentoBoxV1Flat.sol sed -i 's|IStrategy(0)|IStrategy(address(0))|g' contracts/flat/BentoBoxV1Flat.sol + find contracts -name "*.sol" -exec sed -i -e 's/^\(\s*\)\(assembly\)/\1\/\/\/ @solidity memory-safe-assembly\n\1\2/' '{}' \; # @sushiswap/core package contains contracts that get built with 0.6.12 and fail our compiler # version check. It's not used by tests so we can remove it. diff --git a/test/libevmasm/Assembler.cpp b/test/libevmasm/Assembler.cpp index c7f28f654..78e598bca 100644 --- a/test/libevmasm/Assembler.cpp +++ b/test/libevmasm/Assembler.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include diff --git a/test/libsolidity/ASTJSON/documentation.json b/test/libsolidity/ASTJSON/documentation.json index de512181f..f31382d3a 100644 --- a/test/libsolidity/ASTJSON/documentation.json +++ b/test/libsolidity/ASTJSON/documentation.json @@ -162,6 +162,7 @@ "src": "69:26:3", "text": "Some comment on Evt." }, + "eventSelector": "a69007916fc1145953e5a7032d7c3eab4b8e2f33ec59b0f71e732904eeede3a4", "id": 12, "name": "Evt", "nameLocation": "102:3:3", diff --git a/test/libsolidity/ASTJSON/event_definition.json b/test/libsolidity/ASTJSON/event_definition.json index 627fd13ba..0bb614c22 100644 --- a/test/libsolidity/ASTJSON/event_definition.json +++ b/test/libsolidity/ASTJSON/event_definition.json @@ -30,6 +30,7 @@ [ { "anonymous": false, + "eventSelector": "92bbf6e823a631f3c8e09b1c8df90f378fb56f7fbc9701827e1ff8aad7f6a028", "id": 2, "name": "E", "nameLocation": "19: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 new file mode 100644 index 000000000..e69de29bb diff --git a/test/libsolidity/ASTJSON/event_with_variables_of_internal_types.sol b/test/libsolidity/ASTJSON/event_with_variables_of_internal_types.sol new file mode 100644 index 000000000..a22910570 --- /dev/null +++ b/test/libsolidity/ASTJSON/event_with_variables_of_internal_types.sol @@ -0,0 +1,5 @@ +contract C { + event E(function() internal); +} + +// ---- diff --git a/test/libsolidity/ASTJSON/event_with_variables_of_internal_types_parseOnly.json b/test/libsolidity/ASTJSON/event_with_variables_of_internal_types_parseOnly.json new file mode 100644 index 000000000..0c90ee840 --- /dev/null +++ b/test/libsolidity/ASTJSON/event_with_variables_of_internal_types_parseOnly.json @@ -0,0 +1,78 @@ +{ + "absolutePath": "a", + "id": 8, + "nodeType": "SourceUnit", + "nodes": + [ + { + "abstract": false, + "baseContracts": [], + "contractDependencies": [], + "contractKind": "contract", + "id": 7, + "name": "C", + "nameLocation": "9:1:1", + "nodeType": "ContractDefinition", + "nodes": + [ + { + "anonymous": false, + "id": 6, + "name": "E", + "nameLocation": "23:1:1", + "nodeType": "EventDefinition", + "parameters": + { + "id": 5, + "nodeType": "ParameterList", + "parameters": + [ + { + "constant": false, + "id": 4, + "indexed": false, + "mutability": "mutable", + "name": "", + "nameLocation": "-1:-1:-1", + "nodeType": "VariableDeclaration", + "src": "25:20:1", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": {}, + "typeName": + { + "id": 3, + "nodeType": "FunctionTypeName", + "parameterTypes": + { + "id": 1, + "nodeType": "ParameterList", + "parameters": [], + "src": "33:2:1" + }, + "returnParameterTypes": + { + "id": 2, + "nodeType": "ParameterList", + "parameters": [], + "src": "44:0:1" + }, + "src": "25:20:1", + "stateMutability": "nonpayable", + "typeDescriptions": {}, + "visibility": "internal" + }, + "visibility": "internal" + } + ], + "src": "24:21:1" + }, + "src": "17:29:1" + } + ], + "src": "0:48:1", + "usedErrors": [] + } + ], + "src": "0:49:1" +} diff --git a/test/libsolidity/ASTJSON/used_errors.json b/test/libsolidity/ASTJSON/used_errors.json index a8ca24a28..a0e8e28ba 100644 --- a/test/libsolidity/ASTJSON/used_errors.json +++ b/test/libsolidity/ASTJSON/used_errors.json @@ -20,6 +20,7 @@ "nodes": [ { + "errorSelector": "c1599bd9", "id": 2, "name": "X", "nameLocation": "6:1:1", @@ -127,6 +128,7 @@ "nodes": [ { + "errorSelector": "2bc80f3a", "id": 11, "name": "T", "nameLocation": "63:1:1", @@ -145,7 +147,7 @@ { "id": 17, "nodeType": "Block", - "src": "97:8:1", + "src": "92:8:1", "statements": [ { @@ -160,7 +162,7 @@ "nodeType": "Identifier", "overloadedDeclarations": [], "referencedDeclaration": 9, - "src": "99:1:1", + "src": "94:1:1", "typeDescriptions": { "typeIdentifier": "t_function_internal_nonpayable$__$returns$__$", @@ -175,7 +177,7 @@ "lValueRequested": false, "names": [], "nodeType": "FunctionCall", - "src": "99:3:1", + "src": "94:3:1", "tryCall": false, "typeDescriptions": { @@ -185,7 +187,7 @@ }, "id": 16, "nodeType": "ExpressionStatement", - "src": "99:3:1" + "src": "94:3:1" } ] }, @@ -209,17 +211,17 @@ "id": 13, "nodeType": "ParameterList", "parameters": [], - "src": "97:0:1" + "src": "92:0:1" }, "scope": 19, - "src": "72:33:1", - "stateMutability": "pure", + "src": "72:28:1", + "stateMutability": "nonpayable", "virtual": false, "visibility": "public" } ], "scope": 20, - "src": "40:67:1", + "src": "40:62:1", "usedErrors": [ 2, @@ -227,5 +229,5 @@ ] } ], - "src": "0:108:1" + "src": "0:103:1" } diff --git a/test/libsolidity/ASTJSON/used_errors.sol b/test/libsolidity/ASTJSON/used_errors.sol index e891a20ee..ead3e2dcf 100644 --- a/test/libsolidity/ASTJSON/used_errors.sol +++ b/test/libsolidity/ASTJSON/used_errors.sol @@ -2,7 +2,7 @@ error X(); function f() { revert X(); } contract C { error T(); - function h() public pure { f(); } + function h() public { f(); } } // ---- diff --git a/test/libsolidity/ASTJSON/used_errors_parseOnly.json b/test/libsolidity/ASTJSON/used_errors_parseOnly.json index 162f441c4..58b476005 100644 --- a/test/libsolidity/ASTJSON/used_errors_parseOnly.json +++ b/test/libsolidity/ASTJSON/used_errors_parseOnly.json @@ -108,7 +108,7 @@ { "id": 17, "nodeType": "Block", - "src": "97:8:1", + "src": "92:8:1", "statements": [ { @@ -121,19 +121,19 @@ "name": "f", "nodeType": "Identifier", "overloadedDeclarations": [], - "src": "99:1:1", + "src": "94:1:1", "typeDescriptions": {} }, "id": 15, "names": [], "nodeType": "FunctionCall", - "src": "99:3:1", + "src": "94:3:1", "tryCall": false, "typeDescriptions": {} }, "id": 16, "nodeType": "ExpressionStatement", - "src": "99:3:1" + "src": "94:3:1" } ] }, @@ -156,17 +156,17 @@ "id": 13, "nodeType": "ParameterList", "parameters": [], - "src": "97:0:1" + "src": "92:0:1" }, - "src": "72:33:1", - "stateMutability": "pure", + "src": "72:28:1", + "stateMutability": "nonpayable", "virtual": false, "visibility": "public" } ], - "src": "40:67:1", + "src": "40:62:1", "usedErrors": [] } ], - "src": "0:108:1" + "src": "0:103:1" } diff --git a/test/libsolidity/MemoryGuardTest.cpp b/test/libsolidity/MemoryGuardTest.cpp new file mode 100644 index 000000000..b757e673f --- /dev/null +++ b/test/libsolidity/MemoryGuardTest.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 +#include +#include +#include + +using namespace std; +using namespace solidity; +using namespace solidity::util; +using namespace solidity::util::formatting; +using namespace solidity::langutil; +using namespace solidity::frontend; +using namespace solidity::frontend::test; +using namespace yul; + +TestCase::TestResult MemoryGuardTest::run(ostream& _stream, string const& _linePrefix, bool _formatted) +{ + compiler().reset(); + compiler().setSources(StringMap{{"", m_source}}); + compiler().setViaIR(true); + compiler().setOptimiserSettings(OptimiserSettings::none()); + if (!compiler().compile()) + return TestResult::FatalError; + + m_obtainedResult.clear(); + for (string contractName: compiler().contractNames()) + { + ErrorList errors; + auto [object, analysisInfo] = yul::test::parse( + compiler().yulIR(contractName), + EVMDialect::strictAssemblyForEVMObjects({}), + errors + ); + + if (!object || !analysisInfo || Error::containsErrors(errors)) + { + AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing IR." << endl; + return TestResult::FatalError; + } + + auto handleObject = [&](std::string const& _kind, Object const& _object) { + m_obtainedResult += contractName + "(" + _kind + ") " + (FunctionCallFinder::run( + *_object.code, + "memoryguard"_yulstring + ).empty() ? "false" : "true") + "\n"; + }; + handleObject("creation", *object); + size_t deployedIndex = object->subIndexByName.at( + YulString(IRNames::deployedObject(compiler().contractDefinition(contractName))) + ); + handleObject("runtime", dynamic_cast(*object->subObjects[deployedIndex])); + } + return checkResult(_stream, _linePrefix, _formatted); +} diff --git a/test/libsolidity/MemoryGuardTest.h b/test/libsolidity/MemoryGuardTest.h new file mode 100644 index 000000000..e2ca8a6e5 --- /dev/null +++ b/test/libsolidity/MemoryGuardTest.h @@ -0,0 +1,53 @@ +/* + 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 + +#include +#include +#include +#include + +namespace solidity::frontend::test +{ + +using solidity::test::SyntaxTestError; + +class MemoryGuardTest: public AnalysisFramework, public TestCase +{ +public: + static std::unique_ptr create(Config const& _config) + { + return std::make_unique(_config.filename); + } + MemoryGuardTest(std::string const& _filename): TestCase(_filename) + { + m_source = m_reader.source(); + m_expectation = m_reader.simpleExpectations(); + } + + TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false) override; +}; + +} diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp index 9c9d9a7e6..eb4102b15 100644 --- a/test/libsolidity/SolidityOptimizer.cpp +++ b/test/libsolidity/SolidityOptimizer.cpp @@ -25,6 +25,7 @@ #include #include +#include #include diff --git a/test/libsolidity/interface/FileReader.cpp b/test/libsolidity/interface/FileReader.cpp index 39355e536..ea85685fd 100644 --- a/test/libsolidity/interface/FileReader.cpp +++ b/test/libsolidity/interface/FileReader.cpp @@ -313,8 +313,9 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_not_resolve_symlinks_unless_r if (!createSymlinkIfSupportedByFilesystem(tempDir.path() / "abc", tempDir.path() / "sym", true)) return; - boost::filesystem::path expectedPrefixWithSymlinks = "/" / tempDir.path().relative_path(); - boost::filesystem::path expectedPrefixWithoutSymlinks = "/" / boost::filesystem::weakly_canonical(tempDir).relative_path(); + boost::filesystem::path expectedRootPath = FileReader::normalizeCLIRootPathForVFS(tempDir); + boost::filesystem::path expectedPrefixWithSymlinks = expectedRootPath / tempDir.path().relative_path(); + boost::filesystem::path expectedPrefixWithoutSymlinks = expectedRootPath / boost::filesystem::weakly_canonical(tempDir).relative_path(); BOOST_CHECK_EQUAL( FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol", SymlinkResolution::Disabled), diff --git a/test/libsolidity/memoryGuardTests/comment/constructor_safe_deploy_unsafe.sol b/test/libsolidity/memoryGuardTests/comment/constructor_safe_deploy_unsafe.sol new file mode 100644 index 000000000..2ab905ad8 --- /dev/null +++ b/test/libsolidity/memoryGuardTests/comment/constructor_safe_deploy_unsafe.sol @@ -0,0 +1,17 @@ +contract C { + constructor() { + uint256 x; + assembly { x := 0 } + f(); + } + function f() internal pure { + /// @solidity memory-safe-assembly + assembly { mstore(0, 0) } + } + function g() public pure { + assembly { mstore(0, 0) } + } +} +// ---- +// :C(creation) true +// :C(runtime) false diff --git a/test/libsolidity/memoryGuardTests/comment/constructor_unsafe_deploy_safe.sol b/test/libsolidity/memoryGuardTests/comment/constructor_unsafe_deploy_safe.sol new file mode 100644 index 000000000..12b7e772f --- /dev/null +++ b/test/libsolidity/memoryGuardTests/comment/constructor_unsafe_deploy_safe.sol @@ -0,0 +1,17 @@ +contract C { + constructor() { + uint256 x; + assembly { x := 0 } + f(); + } + function f() internal pure { + assembly { mstore(0, 0) } + } + function g() public pure { + /// @solidity memory-safe-assembly + assembly { mstore(0, 0) } + } +} +// ---- +// :C(creation) false +// :C(runtime) true diff --git a/test/libsolidity/memoryGuardTests/comment/free_function.sol b/test/libsolidity/memoryGuardTests/comment/free_function.sol new file mode 100644 index 000000000..a417189ed --- /dev/null +++ b/test/libsolidity/memoryGuardTests/comment/free_function.sol @@ -0,0 +1,29 @@ +function safe() pure returns (uint256 x) { + assembly { x := 42 } + /// @solidity memory-safe-assembly + assembly { mstore(0, 0) } +} +function unsafe() pure returns (uint256 x) { + assembly { pop(mload(0)) } +} +contract C { + constructor() { + unsafe(); + } + function f() public pure { + safe(); + } +} +contract D { + constructor() { + safe(); + } + function f() public pure { + unsafe(); + } +} +// ---- +// :C(creation) false +// :C(runtime) true +// :D(creation) true +// :D(runtime) false diff --git a/test/libsolidity/memoryGuardTests/comment/multi_annotation.sol b/test/libsolidity/memoryGuardTests/comment/multi_annotation.sol new file mode 100644 index 000000000..478546b83 --- /dev/null +++ b/test/libsolidity/memoryGuardTests/comment/multi_annotation.sol @@ -0,0 +1,17 @@ +contract C { + constructor() { + /// @solidity memory-safe-assembly a memory-safe-assembly + assembly { mstore(0, 0) } + } + function f() internal pure { + /// @solidity a memory-safe-assembly + assembly { mstore(0, 0) } + /// @solidity a + /// memory-safe-assembly + /// b + assembly { mstore(0, 0) } + } +} +// ---- +// :C(creation) true +// :C(runtime) true diff --git a/test/libsolidity/memoryGuardTests/comment/multiple_contracts.sol b/test/libsolidity/memoryGuardTests/comment/multiple_contracts.sol new file mode 100644 index 000000000..84d2cb453 --- /dev/null +++ b/test/libsolidity/memoryGuardTests/comment/multiple_contracts.sol @@ -0,0 +1,25 @@ +contract C { + constructor(uint256 x) { + assembly { x := 4 } + /// @solidity memory-safe-assembly + assembly { mstore(0, 0) } + } + function f() public pure { + assembly { mstore(0,0) } + } +} +contract D { + constructor() { + assembly { mstore(0,0) } + } + function f(uint256 x) public pure { + assembly { x := 4 } + /// @solidity memory-safe-assembly + assembly { mstore(0, 0) } + } +} +// ---- +// :C(creation) true +// :C(runtime) false +// :D(creation) false +// :D(runtime) true diff --git a/test/libsolidity/memoryGuardTests/comment/safe_and_unmarked_empty.sol b/test/libsolidity/memoryGuardTests/comment/safe_and_unmarked_empty.sol new file mode 100644 index 000000000..614201deb --- /dev/null +++ b/test/libsolidity/memoryGuardTests/comment/safe_and_unmarked_empty.sol @@ -0,0 +1,10 @@ +contract C { + function f() external pure { + /// @solidity memory-safe-assembly + assembly {} + assembly {} + } +} +// ---- +// :C(creation) true +// :C(runtime) true diff --git a/test/libsolidity/memoryGuardTests/comment/safe_and_unmarked_unsafe.sol b/test/libsolidity/memoryGuardTests/comment/safe_and_unmarked_unsafe.sol new file mode 100644 index 000000000..32d19993c --- /dev/null +++ b/test/libsolidity/memoryGuardTests/comment/safe_and_unmarked_unsafe.sol @@ -0,0 +1,10 @@ +contract C { + function f() external pure { + /// @solidity memory-safe-assembly + assembly {} + assembly { mstore(0,0) } + } +} +// ---- +// :C(creation) true +// :C(runtime) false diff --git a/test/libsolidity/memoryGuardTests/dialectString/constructor_safe_deploy_unsafe.sol b/test/libsolidity/memoryGuardTests/dialectString/constructor_safe_deploy_unsafe.sol new file mode 100644 index 000000000..8c5aa229d --- /dev/null +++ b/test/libsolidity/memoryGuardTests/dialectString/constructor_safe_deploy_unsafe.sol @@ -0,0 +1,17 @@ +contract C { + constructor() { + uint256 x; + assembly { x := 0 } + f(); + } + function f() internal pure { + assembly "evmasm" ("memory-safe") { mstore(0, 0) } + assembly ("memory-safe") { mstore(0, 0) } + } + function g() public pure { + assembly { mstore(0, 0) } + } +} +// ---- +// :C(creation) true +// :C(runtime) false diff --git a/test/libsolidity/memoryGuardTests/dialectString/constructor_unsafe_deploy_safe.sol b/test/libsolidity/memoryGuardTests/dialectString/constructor_unsafe_deploy_safe.sol new file mode 100644 index 000000000..595e25914 --- /dev/null +++ b/test/libsolidity/memoryGuardTests/dialectString/constructor_unsafe_deploy_safe.sol @@ -0,0 +1,16 @@ +contract C { + constructor() { + uint256 x; + assembly { x := 0 } + f(); + } + function f() internal pure { + assembly { mstore(0, 0) } + } + function g() public pure { + assembly "evmasm" ("memory-safe") { mstore(0, 0) } + } +} +// ---- +// :C(creation) false +// :C(runtime) true diff --git a/test/libsolidity/memoryGuardTests/dialectString/free_function.sol b/test/libsolidity/memoryGuardTests/dialectString/free_function.sol new file mode 100644 index 000000000..9e3d2a4b5 --- /dev/null +++ b/test/libsolidity/memoryGuardTests/dialectString/free_function.sol @@ -0,0 +1,28 @@ +function safe() pure returns (uint256 x) { + assembly { x := 42 } + assembly "evmasm" ("memory-safe") { mstore(0, 0) } +} +function unsafe() pure returns (uint256 x) { + assembly { pop(mload(0)) } +} +contract C { + constructor() { + unsafe(); + } + function f() public pure { + safe(); + } +} +contract D { + constructor() { + safe(); + } + function f() public pure { + unsafe(); + } +} +// ---- +// :C(creation) false +// :C(runtime) true +// :D(creation) true +// :D(runtime) false diff --git a/test/libsolidity/memoryGuardTests/dialectString/multiple_contracts.sol b/test/libsolidity/memoryGuardTests/dialectString/multiple_contracts.sol new file mode 100644 index 000000000..2ee227bc6 --- /dev/null +++ b/test/libsolidity/memoryGuardTests/dialectString/multiple_contracts.sol @@ -0,0 +1,23 @@ +contract C { + constructor(uint256 x) { + assembly { x := 4 } + assembly "evmasm" ("memory-safe") { mstore(0, 0) } + } + function f() public pure { + assembly { mstore(0,0) } + } +} +contract D { + constructor() { + assembly { mstore(0,0) } + } + function f(uint256 x) public pure { + assembly { x := 4 } + assembly ("memory-safe") { mstore(0, 0) } + } +} +// ---- +// :C(creation) true +// :C(runtime) false +// :D(creation) false +// :D(runtime) true diff --git a/test/libsolidity/memoryGuardTests/dialectString/safe_and_unmarked_empty.sol b/test/libsolidity/memoryGuardTests/dialectString/safe_and_unmarked_empty.sol new file mode 100644 index 000000000..ab653be97 --- /dev/null +++ b/test/libsolidity/memoryGuardTests/dialectString/safe_and_unmarked_empty.sol @@ -0,0 +1,9 @@ +contract C { + function f() external pure { + assembly "evmasm" ("memory-safe") {} + assembly {} + } +} +// ---- +// :C(creation) true +// :C(runtime) true diff --git a/test/libsolidity/memoryGuardTests/dialectString/safe_and_unmarked_unsafe.sol b/test/libsolidity/memoryGuardTests/dialectString/safe_and_unmarked_unsafe.sol new file mode 100644 index 000000000..8b865d5b8 --- /dev/null +++ b/test/libsolidity/memoryGuardTests/dialectString/safe_and_unmarked_unsafe.sol @@ -0,0 +1,9 @@ +contract C { + function f() external pure { + assembly "evmasm" ("memory-safe") {} + assembly { mstore(0,0) } + } +} +// ---- +// :C(creation) true +// :C(runtime) false diff --git a/test/libsolidity/memoryGuardTests/dialectString/stub.sol b/test/libsolidity/memoryGuardTests/dialectString/stub.sol new file mode 100644 index 000000000..65f6447c1 --- /dev/null +++ b/test/libsolidity/memoryGuardTests/dialectString/stub.sol @@ -0,0 +1,4 @@ +contract C {} +// ---- +// :C(creation) true +// :C(runtime) true diff --git a/test/libsolidity/memoryGuardTests/stub.sol b/test/libsolidity/memoryGuardTests/stub.sol new file mode 100644 index 000000000..65f6447c1 --- /dev/null +++ b/test/libsolidity/memoryGuardTests/stub.sol @@ -0,0 +1,4 @@ +contract C {} +// ---- +// :C(creation) true +// :C(runtime) true diff --git a/test/libsolidity/memoryGuardTests/unmarked_but_no_memory_access.sol b/test/libsolidity/memoryGuardTests/unmarked_but_no_memory_access.sol new file mode 100644 index 000000000..8af88d75d --- /dev/null +++ b/test/libsolidity/memoryGuardTests/unmarked_but_no_memory_access.sol @@ -0,0 +1,8 @@ +contract C { + function f(uint256 x, uint256 y) public pure returns (uint256 z){ + assembly { z := add(x, y) } + } +} +// ---- +// :C(creation) true +// :C(runtime) true diff --git a/test/libsolidity/memoryGuardTests/unmarked_with_memory_access.sol b/test/libsolidity/memoryGuardTests/unmarked_with_memory_access.sol new file mode 100644 index 000000000..88f826fdb --- /dev/null +++ b/test/libsolidity/memoryGuardTests/unmarked_with_memory_access.sol @@ -0,0 +1,8 @@ +contract C { + function f() public pure { + assembly { mstore(0,0) } + } +} +// ---- +// :C(creation) true +// :C(runtime) false diff --git a/test/libsolidity/memoryGuardTests/unmarked_with_memory_assignment.sol b/test/libsolidity/memoryGuardTests/unmarked_with_memory_assignment.sol new file mode 100644 index 000000000..c7519a65e --- /dev/null +++ b/test/libsolidity/memoryGuardTests/unmarked_with_memory_assignment.sol @@ -0,0 +1,11 @@ +contract C { + function f() public pure { + bytes memory x; + assembly { + x := 0 + } + } +} +// ---- +// :C(creation) true +// :C(runtime) false diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_calldata_slice.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_calldata_slice.sol index e54c39d32..c386cf3e8 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: 373483 +// gas irOptimized: 371919 // gas legacy: 418955 // gas legacyOptimized: 326783 // test_uint256() -> -// gas irOptimized: 524664 +// gas irOptimized: 523001 // gas legacy: 586784 // gas legacyOptimized: 451529 diff --git a/test/libsolidity/semanticTests/abiEncoderV1/struct/struct_storage_ptr.sol b/test/libsolidity/semanticTests/abiEncoderV1/struct/struct_storage_ptr.sol index 19d9b1b9a..cc1a182c9 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: 167446 +// gas irOptimized: 167696 // 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 53aeb8949..9deed97f1 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: 373483 +// gas irOptimized: 371919 // gas legacy: 418955 // gas legacyOptimized: 326783 // test_uint256() -> -// gas irOptimized: 524664 +// gas irOptimized: 523001 // gas legacy: 586784 // gas legacyOptimized: 451529 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2.sol b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2.sol index 3e9697698..82ece5f3f 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: 113361 +// gas irOptimized: 113299 // 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 953fa7945..eec062f56 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: 119931 +// gas irOptimized: 119919 // 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 11fccbb61..cf5958d45 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: 171964 +// gas irOptimized: 171842 // gas legacy: 141644 // gas legacyOptimized: 121532 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/storage_array_encoding.sol b/test/libsolidity/semanticTests/abiEncoderV2/storage_array_encoding.sol index 1f836bfaf..1f1e97720 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: 180925 +// gas irOptimized: 180931 // gas legacy: 184929 // gas legacyOptimized: 181504 // i(uint256[2][2]): 123, 124, 223, 224 -> 32, 128, 123, 124, 223, 224 -// gas irOptimized: 112535 +// gas irOptimized: 112539 // gas legacy: 115468 // gas legacyOptimized: 112988 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 e8d567059..7a2a06a2e 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: 189910 +// gas irOptimized: 189871 // gas legacy: 211149 // gas legacyOptimized: 206054 // data(uint256,uint256): 0x02, 0x02 -> 0x09 diff --git a/test/libsolidity/semanticTests/array/bytes_length_member.sol b/test/libsolidity/semanticTests/array/bytes_length_member.sol index bb4e21e16..aaf990ef6 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: 110433 +// gas irOptimized: 110439 // gas legacy: 110726 // gas legacyOptimized: 110567 // getLength() -> 68 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 2a401cd87..6c876286b 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: 650669 +// gas irOptimized: 650647 // gas legacy: 694515 // gas legacyOptimized: 694013 // retrieve() -> 9, 28, 9, 28, 4, 3, 32 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 4f7023250..1c030deba 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: 4652092 +// gas irOptimized: 4652058 // gas legacy: 4578341 // gas legacyOptimized: 4548354 // storageEmpty -> 1 // clear() -> 0, 0 -// gas irOptimized: 4483169 +// gas irOptimized: 4483175 // gas legacy: 4410769 // gas legacyOptimized: 4382531 // storageEmpty -> 1 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 202b3ad26..b4b392974 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: 111426 +// gas irOptimized: 111406 // gas legacy: 109278 // gas legacyOptimized: 109268 // getData2(uint256): 5 -> 10, 4 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 3cc9c9bd9..f3f3e8236 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 @@ -38,10 +38,10 @@ contract c { // compileViaYul: true // ---- // test1(uint256[][]): 0x20, 2, 0x40, 0x40, 2, 23, 42 -> 2, 65 -// gas irOptimized: 181308 +// gas irOptimized: 181298 // test2(uint256[][2]): 0x20, 0x40, 0x40, 2, 23, 42 -> 2, 65 -// gas irOptimized: 157901 +// gas irOptimized: 157936 // test3(uint256[2][]): 0x20, 2, 23, 42, 23, 42 -> 2, 65 -// gas irOptimized: 135108 +// gas irOptimized: 135098 // test4(uint256[2][2]): 23, 42, 23, 42 -> 65 -// gas irOptimized: 111428 +// gas irOptimized: 111362 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 826d48b2b..e8b460b4f 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 @@ -40,12 +40,12 @@ contract Test { // compileViaYul: also // ---- // test() -> 24 -// gas irOptimized: 227167 +// gas irOptimized: 227133 // gas legacy: 227133 // gas legacyOptimized: 226547 // test1() -> 3 // test2() -> 6 // test3() -> 24 -// gas irOptimized: 133621 +// gas irOptimized: 133597 // 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 8bd9ee42c..d872534cd 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: 104701 +// gas irOptimized: 104669 // gas legacy: 108725 // gas legacyOptimized: 102441 // 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 63236ed77..71399a281 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,7 +50,7 @@ contract C { // compileViaYul: also // ---- // copyExternalStorageArraysOfFunctionType() -> true -// gas irOptimized: 104372 +// gas irOptimized: 104342 // gas legacy: 108462 // gas legacyOptimized: 102174 // copyInternalArrayOfFunctionType() -> true diff --git a/test/libsolidity/semanticTests/array/copying/bytes_inside_mappings.sol b/test/libsolidity/semanticTests/array/copying/bytes_inside_mappings.sol index 809ef247d..ae2698551 100644 --- a/test/libsolidity/semanticTests/array/copying/bytes_inside_mappings.sol +++ b/test/libsolidity/semanticTests/array/copying/bytes_inside_mappings.sol @@ -7,11 +7,11 @@ contract c { // compileViaYul: also // ---- // set(uint256): 1, 2 -> true -// gas irOptimized: 110699 +// gas irOptimized: 110604 // gas legacy: 111091 // gas legacyOptimized: 110736 // set(uint256): 2, 2, 3, 4, 5 -> true -// gas irOptimized: 177659 +// gas irOptimized: 177564 // gas legacy: 178021 // gas legacyOptimized: 177666 // storageEmpty -> 0 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 ed0fe8f5f..72a837d1b 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,11 +37,11 @@ contract C { // compileViaYul: also // ---- // f() -> 0x40, 0x80, 6, 0x6162636465660000000000000000000000000000000000000000000000000000, 0x49, 0x3132333435363738393031323334353637383930313233343536373839303120, 0x3132333435363738393031323334353637383930313233343536373839303120, 0x3132333435363738390000000000000000000000000000000000000000000000 -// gas irOptimized: 179952 +// gas irOptimized: 179899 // gas legacy: 180694 // gas legacyOptimized: 180088 // g() -> 0x40, 0xc0, 0x49, 0x3132333435363738393031323334353637383930313233343536373839303120, 0x3132333435363738393031323334353637383930313233343536373839303120, 0x3132333435363738390000000000000000000000000000000000000000000000, 0x11, 0x3132333435363738393233343536373839000000000000000000000000000000 -// gas irOptimized: 107332 +// gas irOptimized: 107274 // gas legacy: 107895 // gas legacyOptimized: 107254 // h() -> 0x40, 0x60, 0x00, 0x00 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 6f019c77c..7550a9225 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: 124080 +// gas irOptimized: 124041 // 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 b8ec0d97f..8d8bd4d50 100644 --- a/test/libsolidity/semanticTests/array/copying/copy_removes_bytes_data.sol +++ b/test/libsolidity/semanticTests/array/copying/copy_removes_bytes_data.sol @@ -9,7 +9,7 @@ contract c { // compileViaYul: also // ---- // set(): 1, 2, 3, 4, 5 -> true -// gas irOptimized: 177417 +// gas irOptimized: 177390 // gas legacy: 177656 // gas legacyOptimized: 177496 // storageEmpty -> 0 diff --git a/test/libsolidity/semanticTests/array/copying/copying_bytes_multiassign.sol b/test/libsolidity/semanticTests/array/copying/copying_bytes_multiassign.sol index 3583a752d..7b2af9607 100644 --- a/test/libsolidity/semanticTests/array/copying/copying_bytes_multiassign.sol +++ b/test/libsolidity/semanticTests/array/copying/copying_bytes_multiassign.sol @@ -21,7 +21,7 @@ contract sender { // compileViaYul: also // ---- // (): 7 -> -// gas irOptimized: 110941 +// gas irOptimized: 110954 // gas legacy: 111082 // gas legacyOptimized: 111027 // val() -> 0 diff --git a/test/libsolidity/semanticTests/array/dynamic_array_cleanup.sol b/test/libsolidity/semanticTests/array/dynamic_array_cleanup.sol index 9f4be2119..019a3fca0 100644 --- a/test/libsolidity/semanticTests/array/dynamic_array_cleanup.sol +++ b/test/libsolidity/semanticTests/array/dynamic_array_cleanup.sol @@ -16,7 +16,7 @@ contract c { // ---- // storageEmpty -> 1 // fill() -> -// gas irOptimized: 519848 +// gas irOptimized: 519886 // gas legacy: 521773 // gas legacyOptimized: 517048 // 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 2587442d5..4ed8c050b 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: 104355 +// gas irOptimized: 111304 // 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 6aecbde32..cf310f86d 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: 122528 +// gas irOptimized: 122534 // 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 dd131f287..b09cb5812 100644 --- a/test/libsolidity/semanticTests/array/fixed_array_cleanup.sol +++ b/test/libsolidity/semanticTests/array/fixed_array_cleanup.sol @@ -13,7 +13,7 @@ contract c { // ---- // storageEmpty -> 1 // fill() -> -// gas irOptimized: 465585 +// gas irOptimized: 465544 // gas legacy: 471460 // gas legacyOptimized: 467520 // storageEmpty -> 0 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 3b0a73d00..fcf41823e 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: 130097 +// gas irOptimized: 130152 // gas legacy: 234943 // gas legacyOptimized: 132863 diff --git a/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol b/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol index ddead0503..07a054514 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: 132278 +// gas irOptimized: 129908 // 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 9c78c1207..73f9799d4 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: 290947 +// gas irOptimized: 298983 // gas legacy: 452172 // gas legacyOptimized: 285017 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 f6da6a398..7546a664b 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: 138785 +// gas irOptimized: 138732 // gas legacy: 145150 // gas legacyOptimized: 139171 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 8df809acd..761bf3ee3 100644 --- a/test/libsolidity/semanticTests/array/push/push_no_args_2d.sol +++ b/test/libsolidity/semanticTests/array/push/push_no_args_2d.sol @@ -29,14 +29,14 @@ contract C { // ---- // l() -> 0 // f(uint256,uint256): 42, 64 -> -// gas irOptimized: 112555 +// gas irOptimized: 112528 // gas legacy: 108234 // gas legacyOptimized: 102245 // l() -> 1 // ll(uint256): 0 -> 43 // a(uint256,uint256): 0, 42 -> 64 // f(uint256,uint256): 84, 128 -> -// gas irOptimized: 116427 +// gas irOptimized: 116400 // gas legacy: 107780 // gas legacyOptimized: 96331 // l() -> 2 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 defbf4149..830f25b02 100644 --- a/test/libsolidity/semanticTests/array/push/push_no_args_bytes.sol +++ b/test/libsolidity/semanticTests/array/push/push_no_args_bytes.sol @@ -23,7 +23,7 @@ contract C { // ---- // l() -> 0 // g(uint256): 70 -> -// gas irOptimized: 184507 +// gas irOptimized: 185936 // gas legacy: 184991 // gas legacyOptimized: 180608 // l() -> 70 diff --git a/test/libsolidity/semanticTests/array/reusing_memory.sol b/test/libsolidity/semanticTests/array/reusing_memory.sol index ee1a57b1e..ee91ce7f7 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: 113581 +// gas irOptimized: 113598 // 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 87067b77b..7773c6832 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,7 +11,7 @@ contract c { // compileViaYul: also // ---- // (): 1, 2, 3, 4, 5 -> -// gas irOptimized: 155178 +// gas irOptimized: 155181 // gas legacy: 155254 // gas legacyOptimized: 155217 // checkIfDataIsEmpty() -> false diff --git a/test/libsolidity/semanticTests/constructor/arrays_in_constructors.sol b/test/libsolidity/semanticTests/constructor/arrays_in_constructors.sol index 7885b24a3..cc303899a 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: 456668 +// gas irOptimized: 443960 // 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 434b926fc..ffe0fb8c2 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: 308497 +// gas irOptimized: 300804 // gas legacy: 428917 // gas legacyOptimized: 298128 diff --git a/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol b/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol index 6ee258bd6..2206fd351 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: 112563 +// gas irOptimized: 107175 // 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 ab90a0bb9..f6fab1092 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: 180731 +// gas irOptimized: 174905 // gas legacy: 221377 // gas legacyOptimized: 177671 // a() -> 1 diff --git a/test/libsolidity/semanticTests/constructor_inheritance_init_order.sol b/test/libsolidity/semanticTests/constructor_inheritance_init_order.sol index 41a050fc4..2518deb92 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: 122233 +// gas irOptimized: 122017 // 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 db58499ea..68506528b 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: 122233 +// gas irOptimized: 122017 // gas legacy: 135046 // gas legacyOptimized: 116176 // y() -> 42 diff --git a/test/libsolidity/semanticTests/constructor_with_params_diamond_inheritance.sol b/test/libsolidity/semanticTests/constructor_with_params_diamond_inheritance.sol index fe3c95b54..8f891116e 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: 159542 +// gas irOptimized: 160166 // gas legacy: 170665 // gas legacyOptimized: 145396 // i() -> 2 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 690f555dc..5ec47a4a9 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: 177344 +// gas irOptimized: 173672 // gas legacy: 250376 // gas legacyOptimized: 174522 // deposit(bytes32), 18 wei: 0x1234 -> diff --git a/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol b/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol index fc0b416fd..e6d6c478b 100644 --- a/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol +++ b/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol @@ -76,7 +76,7 @@ contract FixedFeeRegistrar is Registrar { // compileViaYul: also // ---- // constructor() -// gas irOptimized: 426283 +// gas irOptimized: 413485 // gas legacy: 936897 // gas legacyOptimized: 490983 // reserve(string), 69 ether: 0x20, 3, "abc" -> diff --git a/test/libsolidity/semanticTests/externalContracts/_base64/base64_inline_asm.sol b/test/libsolidity/semanticTests/externalContracts/_base64/base64_inline_asm.sol new file mode 100644 index 000000000..7df0c902d --- /dev/null +++ b/test/libsolidity/semanticTests/externalContracts/_base64/base64_inline_asm.sol @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Provides a set of functions to operate with Base64 strings. + */ +library InlineAsmBase64 { + /** + * @dev Base64 Encoding/Decoding Table + */ + string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + /** + * @dev Converts a `bytes` to its Bytes64 `string` representation. + */ + function encode(bytes memory data) internal pure returns (string memory) { + /** + * Inspired by OpenZepplin Base64 implementation + * https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2884/commits/157c32b65a15cb0b58257543643cafa1cebf883a + */ + if (data.length == 0) return ""; + + // Loads the table into memory + string memory table = _TABLE; + + // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter + // and split into 4 numbers of 6 bits. + // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up + // - `data.length + 2` -> Round up + // - `/ 3` -> Number of 3-bytes chunks + // - `4 *` -> 4 characters for each chunk + uint256 encodedLen = 4 * ((data.length + 2) / 3); + + // Add some extra buffer at the end required for the writing + string memory result = new string(encodedLen); + + assembly { + // Store the actual result length in memory + mstore(result, encodedLen) + + // Prepare the lookup table + let tablePtr := add(table, 1) + + // Prepare input pointer + let dataPtr := data + let endPtr := add(dataPtr, mload(data)) + + // Prepare result pointer, jump over length + let resultPtr := add(result, 32) + + // Run over the input, 3 bytes at a time + for { + + } lt(dataPtr, endPtr) { + + } { + // Advance 3 bytes + dataPtr := add(dataPtr, 3) + let input := mload(dataPtr) + + // To write each character, shift the 3 bytes (24 bits) chunk 4 + // times in blocks of 6 bits for each character (18, 12, 6, 0) + // and apply logical AND with 0x3F to extract the 6-bit group. + // Add the 6-bit group with the table ptr to index into the + // table and acquire the character to write. Finally, write + // the character to the result pointer. + + mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + } + + // When data `bytes` is not exactly 3 bytes long + // it is padded with `=` characters at the end + switch mod(mload(data), 3) + case 1 { + mstore8(sub(resultPtr, 1), 0x3d) + mstore8(sub(resultPtr, 2), 0x3d) + } + case 2 { + mstore8(sub(resultPtr, 1), 0x3d) + } + } + + return result; + } +} diff --git a/test/libsolidity/semanticTests/externalContracts/_base64/base64_no_inline_asm.sol b/test/libsolidity/semanticTests/externalContracts/_base64/base64_no_inline_asm.sol new file mode 100644 index 000000000..f54d2f925 --- /dev/null +++ b/test/libsolidity/semanticTests/externalContracts/_base64/base64_no_inline_asm.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Provides a set of functions to operate with Base64 strings. + */ +library NoAsmBase64 { + bytes private constant TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + function encode(bytes memory data) internal pure returns (string memory) { + if (data.length == 0) return ""; + + bytes memory table = TABLE; + bytes memory result = new bytes(4 * ((data.length + 2) / 3)); + uint256 resultPtr = 0; + + for (uint256 dataPtr = 0; dataPtr < data.length; dataPtr += 3) { + uint24 chunk = ( (uint24(uint8(data[dataPtr + 0])) << 16)) + + (dataPtr + 1 < data.length ? (uint24(uint8(data[dataPtr + 1])) << 8) : 0) + + (dataPtr + 2 < data.length ? (uint24(uint8(data[dataPtr + 2])) ) : 0); + + result[resultPtr++] = table[uint8(chunk >> 18) & 0x3f]; + result[resultPtr++] = table[uint8(chunk >> 12) & 0x3f]; + result[resultPtr++] = table[uint8(chunk >> 6) & 0x3f]; + result[resultPtr++] = table[uint8(chunk ) & 0x3f]; + } + + if (data.length % 3 == 1) { + result[--resultPtr] = 0x3d; + result[--resultPtr] = 0x3d; + } + else if (data.length % 3 == 2) { + result[--resultPtr] = 0x3d; + } + + return (string(result)); + } +} diff --git a/test/libsolidity/semanticTests/externalContracts/base64.sol b/test/libsolidity/semanticTests/externalContracts/base64.sol new file mode 100644 index 000000000..fd17c5d78 --- /dev/null +++ b/test/libsolidity/semanticTests/externalContracts/base64.sol @@ -0,0 +1,61 @@ +==== ExternalSource: _base64/base64_inline_asm.sol ==== +==== ExternalSource: _base64/base64_no_inline_asm.sol ==== +==== Source: base64.sol ==== + +import "_base64/base64_inline_asm.sol"; +import "_base64/base64_no_inline_asm.sol"; + +contract test { + function encode_inline_asm(bytes memory data) external pure returns (string memory) { + return InlineAsmBase64.encode(data); + } + + function encode_no_asm(bytes memory data) external pure returns (string memory) { + return NoAsmBase64.encode(data); + } + + function encode_inline_asm_large() external { + for (uint i = 0; i < 1000; i++) { + InlineAsmBase64.encode("foo"); + } + } + + function encode_no_asm_large() external { + for (uint i = 0; i < 1000; i++) { + NoAsmBase64.encode("foo"); + } + } +} +// Test cases derived from Base64 specification: RFC4648 +// https://datatracker.ietf.org/doc/html/rfc4648#section-10 +// +// ==== +// EVMVersion: >=constantinople +// compileViaYul: also +// ---- +// constructor() +// gas irOptimized: 450044 +// gas legacy: 766936 +// gas legacyOptimized: 543094 +// 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=" +// encode_inline_asm(bytes): 0x20, 3, "foo" -> 0x20, 4, "Zm9v" +// encode_inline_asm(bytes): 0x20, 4, "foob" -> 0x20, 8, "Zm9vYg==" +// encode_inline_asm(bytes): 0x20, 5, "fooba" -> 0x20, 8, "Zm9vYmE=" +// encode_inline_asm(bytes): 0x20, 6, "foobar" -> 0x20, 8, "Zm9vYmFy" +// encode_no_asm(bytes): 0x20, 0 -> 0x20, 0 +// encode_no_asm(bytes): 0x20, 1, "f" -> 0x20, 4, "Zg==" +// encode_no_asm(bytes): 0x20, 2, "fo" -> 0x20, 4, "Zm8=" +// encode_no_asm(bytes): 0x20, 3, "foo" -> 0x20, 4, "Zm9v" +// encode_no_asm(bytes): 0x20, 4, "foob" -> 0x20, 8, "Zm9vYg==" +// 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 +// encode_no_asm_large() +// gas irOptimized: 3335101 +// gas legacy: 4801077 +// gas legacyOptimized: 2929077 diff --git a/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol b/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol index 7f5799805..d98e73792 100644 --- a/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol +++ b/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol @@ -178,7 +178,7 @@ contract DepositContract is IDepositContract, ERC165 { // compileViaYul: also // ---- // constructor() -// gas irOptimized: 1557137 +// gas irOptimized: 1543359 // gas legacy: 2436584 // gas legacyOptimized: 1776483 // supportsInterface(bytes4): 0x0 -> 0 @@ -186,27 +186,27 @@ contract DepositContract is IDepositContract, ERC165 { // supportsInterface(bytes4): 0x01ffc9a700000000000000000000000000000000000000000000000000000000 -> true # ERC-165 id # // supportsInterface(bytes4): 0x8564090700000000000000000000000000000000000000000000000000000000 -> true # the deposit interface id # // get_deposit_root() -> 0xd70a234731285c6804c2a4f56711ddb8c82c99740f207854891028af34e27e5e -// gas irOptimized: 122169 +// gas irOptimized: 122135 // gas legacy: 150465 // gas legacyOptimized: 122798 // 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: 122169 +// gas irOptimized: 122135 // gas legacy: 150465 // gas legacyOptimized: 122798 // 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: 122148 +// gas irOptimized: 122114 // gas legacy: 150475 // gas legacyOptimized: 122811 // 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: 122148 +// gas irOptimized: 122114 // gas legacy: 150475 // gas legacyOptimized: 122811 // 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 9de7a30d8..56abe4a9d 100644 --- a/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol +++ b/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol @@ -50,7 +50,7 @@ contract test { // compileViaYul: also // ---- // constructor() -// gas irOptimized: 1924392 +// gas irOptimized: 1938339 // gas legacy: 2480887 // gas legacyOptimized: 1874490 // div(int256,int256): 3141592653589793238, 88714123 -> 35412542528203691288251815328 diff --git a/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol b/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol index 11001fffa..0488179f1 100644 --- a/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol +++ b/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol @@ -50,7 +50,7 @@ contract test { // compileViaYul: also // ---- // constructor() -// gas irOptimized: 1778342 +// gas irOptimized: 1792108 // gas legacy: 2250130 // gas legacyOptimized: 1746528 // div(uint256,uint256): 3141592653589793238, 88714123 -> 35412542528203691288251815328 diff --git a/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol b/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol index 763a8acda..45976217b 100644 --- a/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol +++ b/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol @@ -35,7 +35,7 @@ contract test { // compileViaYul: also // ---- // constructor() -// gas irOptimized: 465357 +// gas irOptimized: 465789 // gas legacy: 672749 // gas legacyOptimized: 479606 // prb_pi() -> 3141592656369545286 diff --git a/test/libsolidity/semanticTests/externalContracts/strings.sol b/test/libsolidity/semanticTests/externalContracts/strings.sol index 7c4028bb9..a16f884e8 100644 --- a/test/libsolidity/semanticTests/externalContracts/strings.sol +++ b/test/libsolidity/semanticTests/externalContracts/strings.sol @@ -51,7 +51,7 @@ contract test { // compileViaYul: also // ---- // constructor() -// gas irOptimized: 702619 +// gas irOptimized: 707330 // gas legacy: 1130761 // gas legacyOptimized: 750416 // toSlice(string): 0x20, 11, "hello world" -> 11, 0xa0 @@ -71,6 +71,6 @@ contract test { // gas legacy: 31621 // gas legacyOptimized: 27914 // benchmark(string,bytes32): 0x40, 0x0842021, 8, "solidity" -> 0x2020 -// gas irOptimized: 2040067 +// gas irOptimized: 2040045 // gas legacy: 4381235 // gas legacyOptimized: 2317529 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 2da7c2dd6..685d8a7de 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: 200295 +// gas irOptimized: 203967 // 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 0b0633c6d..a768a2836 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: 200458 +// gas irOptimized: 204130 // 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 942faa048..030aeaa10 100644 --- a/test/libsolidity/semanticTests/functionCall/external_call_to_nonexisting.sol +++ b/test/libsolidity/semanticTests/functionCall/external_call_to_nonexisting.sol @@ -25,7 +25,7 @@ contract C { // compileViaYul: also // ---- // constructor(), 1 ether -> -// gas irOptimized: 308423 +// gas irOptimized: 315341 // gas legacy: 465314 // gas legacyOptimized: 304481 // f(uint256): 0 -> 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 26faf248f..cfbf1bcc1 100644 --- a/test/libsolidity/semanticTests/functionCall/external_call_to_nonexisting_debugstrings.sol +++ b/test/libsolidity/semanticTests/functionCall/external_call_to_nonexisting_debugstrings.sol @@ -27,7 +27,7 @@ contract C { // revertStrings: debug // ---- // constructor(), 1 ether -> -// gas irOptimized: 448383 +// gas irOptimized: 452673 // gas legacy: 834272 // gas legacyOptimized: 510004 // f(uint256): 0 -> 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 54cd9f06a..2ebf8740d 100644 --- a/test/libsolidity/semanticTests/functionCall/failed_create.sol +++ b/test/libsolidity/semanticTests/functionCall/failed_create.sol @@ -18,7 +18,7 @@ contract C { // compileViaYul: also // ---- // constructor(), 20 wei -// gas irOptimized: 218775 +// gas irOptimized: 219285 // gas legacy: 294569 // gas legacyOptimized: 174699 // f(uint256): 20 -> 1370859564726510389319704988634906228201275401179 @@ -26,7 +26,7 @@ contract C { // f(uint256): 20 -> FAILURE // x() -> 1 // stack(uint256): 1023 -> FAILURE -// gas irOptimized: 296769 +// gas irOptimized: 314884 // gas legacy: 483942 // gas legacyOptimized: 298807 // x() -> 1 diff --git a/test/libsolidity/semanticTests/functionCall/gas_and_value_basic.sol b/test/libsolidity/semanticTests/functionCall/gas_and_value_basic.sol index b1d9299d8..4321753d6 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: 285350 +// gas irOptimized: 283040 // 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 9e2491ac1..2f89517b7 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: 285350 +// gas irOptimized: 283040 // 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 d3e2ba075..f1e2f1116 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: 111896 +// gas irOptimized: 111929 // gas legacy: 113806 // gas legacyOptimized: 111781 // get(uint8): 1 -> 21, 22, 42, 43 diff --git a/test/libsolidity/semanticTests/functionCall/return_size_bigger_than_expected.sol b/test/libsolidity/semanticTests/functionCall/return_size_bigger_than_expected.sol new file mode 100644 index 000000000..c7a1d12bf --- /dev/null +++ b/test/libsolidity/semanticTests/functionCall/return_size_bigger_than_expected.sol @@ -0,0 +1,31 @@ +interface ShortReturn { + function f() external pure returns (bytes32); +} +contract LongReturn { + function f() external pure returns (uint[20] memory) {} +} + +contract Test { + function test() public returns (uint) { + LongReturn longReturn = new LongReturn(); + uint freeMemoryBefore; + assembly { + freeMemoryBefore := mload(0x40) + } + + ShortReturn(address(longReturn)).f(); + + uint freeMemoryAfter; + + assembly { + freeMemoryAfter := mload(0x40) + } + + return freeMemoryAfter - freeMemoryBefore; + } +} +// ==== +// compileViaYul: true +// ---- +// test() -> 0x20 +// gas legacy: 131966 diff --git a/test/libsolidity/semanticTests/functionCall/return_size_shorter_than_expected.sol b/test/libsolidity/semanticTests/functionCall/return_size_shorter_than_expected.sol new file mode 100644 index 000000000..5f39b877e --- /dev/null +++ b/test/libsolidity/semanticTests/functionCall/return_size_shorter_than_expected.sol @@ -0,0 +1,32 @@ +interface LongReturn { + function f() external pure returns (uint[20] memory); +} +contract ShortReturn { + function f() external pure returns (bytes32) {} +} + +contract Test { + function test() public returns (uint) { + ShortReturn shortReturn = new ShortReturn(); + uint freeMemoryBefore; + assembly { + freeMemoryBefore := mload(0x40) + } + + LongReturn(address(shortReturn)).f(); + + uint freeMemoryAfter; + + assembly { + freeMemoryAfter := mload(0x40) + } + + return freeMemoryAfter - freeMemoryBefore; + } +} +// ==== +// EVMVersion: <=homestead +// compileViaYul: true +// ---- +// test() -> 0x0500 +// gas legacy: 131966 diff --git a/test/libsolidity/semanticTests/functionCall/return_size_shorter_than_expected_evm_version_after_homestead.sol b/test/libsolidity/semanticTests/functionCall/return_size_shorter_than_expected_evm_version_after_homestead.sol new file mode 100644 index 000000000..225832275 --- /dev/null +++ b/test/libsolidity/semanticTests/functionCall/return_size_shorter_than_expected_evm_version_after_homestead.sol @@ -0,0 +1,34 @@ +interface LongReturn { + function f() external pure returns (uint[20] memory); +} +contract ShortReturn { + function f() external pure returns (bytes32) {} +} + +contract Test { + function test() public returns (uint) { + ShortReturn shortReturn = new ShortReturn(); + uint freeMemoryBefore; + assembly { + freeMemoryBefore := mload(0x40) + } + + // This reverts. The external call succeeds but ABI decoding fails due to the returned + // `bytes32` being much shorter than the expected `uint[20]`. + LongReturn(address(shortReturn)).f(); + + uint freeMemoryAfter; + + assembly { + freeMemoryAfter := mload(0x40) + } + + return freeMemoryAfter - freeMemoryBefore; + } +} +// ==== +// EVMVersion: >homestead +// compileViaYul: true +// ---- +// test() -> FAILURE +// gas legacy: 131966 diff --git a/test/libsolidity/semanticTests/immutable/multi_creation.sol b/test/libsolidity/semanticTests/immutable/multi_creation.sol index 2f74c17f5..e834663d0 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: 127387 +// gas irOptimized: 127347 // 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 4fb3bf245..e065f3f01 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: 137184 +// gas irOptimized: 131042 // 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 46992694e..a15650992 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: 111781 +// gas irOptimized: 111794 // 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 b2f0f8a6b..e6f94bdcf 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: 288778 +// gas irOptimized: 284287 // 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 5af1e5cdc..8d37ed809 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: 184076 +// gas irOptimized: 188162 // 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 6b13ee09c..ac61fad71 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: 115822 +// gas irOptimized: 115874 // gas legacy: 135952 // gas legacyOptimized: 119643 diff --git a/test/libsolidity/semanticTests/libraries/using_library_mappings_public.sol b/test/libsolidity/semanticTests/libraries/using_library_mappings_public.sol index d85f90694..e8d22c279 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: 119757 +// gas irOptimized: 119561 // gas legacy: 124793 // gas legacyOptimized: 119694 diff --git a/test/libsolidity/semanticTests/libraries/using_library_mappings_return.sol b/test/libsolidity/semanticTests/libraries/using_library_mappings_return.sol index 9192fdfe3..86e7fa3d7 100644 --- a/test/libsolidity/semanticTests/libraries/using_library_mappings_return.sol +++ b/test/libsolidity/semanticTests/libraries/using_library_mappings_return.sol @@ -20,6 +20,6 @@ contract Test { // ---- // library: Lib // f() -> 1, 0, 0x2a, 0x17, 0, 0x63 -// gas irOptimized: 120471 +// gas irOptimized: 120572 // gas legacy: 125245 // gas legacyOptimized: 120153 diff --git a/test/libsolidity/semanticTests/libraries/using_library_structs.sol b/test/libsolidity/semanticTests/libraries/using_library_structs.sol index 4348c377c..116887fd5 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: 101869 +// gas irOptimized: 101820 // gas legacy: 101504 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 e8fe01687..4ce8b5149 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: 272947 +// gas irOptimized: 272413 // gas legacy: 422501 // gas legacyOptimized: 287472 diff --git a/test/libsolidity/semanticTests/smoke/constructor.sol b/test/libsolidity/semanticTests/smoke/constructor.sol index 7667c2443..a6e812e9a 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: 111723 +// gas irOptimized: 111699 // 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 d4dbffcb8..9abeb90aa 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: 119839 +// gas irOptimized: 115297 // 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 7b84033d8..6e65cd239 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: 203397 +// gas irOptimized: 203312 // 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 0d0aba8c8..c23a15ec0 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: 193980 +// gas irOptimized: 194005 // 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 7bbe495ce..258ff350b 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: 150618 +// gas irOptimized: 150545 // 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 12ec4ca18..5dd4d48a6 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: 111179 +// gas irOptimized: 111432 // 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 a677b5be8..6b5d1f022 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 @@ -25,7 +25,7 @@ contract c { // ---- // storageEmpty -> 1 // set(uint256,bytes,uint256): 12, 0x60, 13, 33, "12345678901234567890123456789012", "3" -> true -// gas irOptimized: 133752 +// gas irOptimized: 133728 // gas legacy: 134436 // gas legacyOptimized: 133879 // test(uint256): 32 -> "3" diff --git a/test/libsolidity/semanticTests/structs/struct_copy.sol b/test/libsolidity/semanticTests/structs/struct_copy.sol index f170dca3f..03a063bb8 100644 --- a/test/libsolidity/semanticTests/structs/struct_copy.sol +++ b/test/libsolidity/semanticTests/structs/struct_copy.sol @@ -38,12 +38,12 @@ contract c { // compileViaYul: also // ---- // set(uint256): 7 -> true -// gas irOptimized: 110119 +// gas irOptimized: 110051 // gas legacy: 110616 // gas legacyOptimized: 110006 // retrieve(uint256): 7 -> 1, 3, 4, 2 // copy(uint256,uint256): 7, 8 -> true -// gas irOptimized: 118698 +// gas irOptimized: 118597 // gas legacy: 119166 // gas legacyOptimized: 118622 // retrieve(uint256): 7 -> 1, 3, 4, 2 diff --git a/test/libsolidity/semanticTests/structs/struct_delete_storage_nested_small.sol b/test/libsolidity/semanticTests/structs/struct_delete_storage_nested_small.sol index bc18d3192..ded05d8d6 100644 --- a/test/libsolidity/semanticTests/structs/struct_delete_storage_nested_small.sol +++ b/test/libsolidity/semanticTests/structs/struct_delete_storage_nested_small.sol @@ -33,4 +33,4 @@ contract C { // compileViaYul: true // ---- // f() -> 0, 0, 0 -// gas irOptimized: 117289 +// gas irOptimized: 117403 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 e759520b4..44acf38e4 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: 121618 +// gas irOptimized: 121624 // gas legacy: 122132 // gas legacyOptimized: 121500 // g() -> diff --git a/test/libsolidity/semanticTests/structs/structs.sol b/test/libsolidity/semanticTests/structs/structs.sol index b56a2ec22..3356eac16 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: 134335 +// gas irOptimized: 134432 // 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 1927b2519..56ad74c54 100644 --- a/test/libsolidity/semanticTests/userDefinedValueType/calldata.sol +++ b/test/libsolidity/semanticTests/userDefinedValueType/calldata.sol @@ -51,7 +51,7 @@ contract C { // compileViaYul: also // ---- // test_f() -> true -// gas irOptimized: 122509 +// gas irOptimized: 122364 // gas legacy: 126168 // gas legacyOptimized: 123199 // test_g() -> true diff --git a/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol b/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol index 220d9d9a2..c2c5f3cdc 100644 --- a/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol +++ b/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol @@ -115,7 +115,7 @@ contract ERC20 { // ---- // constructor() // ~ emit Transfer(address,address,uint256): #0x00, #0x1212121212121212121212121212120000000012, 0x14 -// gas irOptimized: 447831 +// gas irOptimized: 423885 // gas legacy: 861559 // gas legacyOptimized: 420959 // totalSupply() -> 20 diff --git a/test/libsolidity/semanticTests/various/address_code.sol b/test/libsolidity/semanticTests/various/address_code.sol index 6072d5ac3..38e0fb13f 100644 --- a/test/libsolidity/semanticTests/various/address_code.sol +++ b/test/libsolidity/semanticTests/various/address_code.sol @@ -17,7 +17,7 @@ contract C { // compileViaYul: also // ---- // constructor() -> -// gas irOptimized: 199687 +// gas irOptimized: 199723 // gas legacy: 241124 // gas legacyOptimized: 155549 // initCode() -> 0x20, 0 diff --git a/test/libsolidity/semanticTests/various/destructuring_assignment.sol b/test/libsolidity/semanticTests/various/destructuring_assignment.sol index ee6f7690d..cc93152ea 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: 240685 +// gas irOptimized: 240691 // gas legacy: 240358 // gas legacyOptimized: 239682 diff --git a/test/libsolidity/semanticTests/various/erc20.sol b/test/libsolidity/semanticTests/various/erc20.sol index 64a3286a9..9ba4e3cb7 100644 --- a/test/libsolidity/semanticTests/various/erc20.sol +++ b/test/libsolidity/semanticTests/various/erc20.sol @@ -98,7 +98,7 @@ contract ERC20 { // ---- // constructor() // ~ emit Transfer(address,address,uint256): #0x00, #0x1212121212121212121212121212120000000012, 0x14 -// gas irOptimized: 443295 +// gas irOptimized: 419330 // gas legacy: 833310 // gas legacyOptimized: 416135 // totalSupply() -> 20 diff --git a/test/libsolidity/semanticTests/various/senders_balance.sol b/test/libsolidity/semanticTests/various/senders_balance.sol index 600e72e3e..1c456f1d4 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: 175261 +// gas irOptimized: 178933 // 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 cad181c8f..30a2d9f65 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: 178835 +// gas irOptimized: 178812 // gas legacy: 180762 // gas legacyOptimized: 179481 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 1950f7a4d..06faab882 100644 --- a/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure.sol +++ b/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure.sol @@ -42,6 +42,6 @@ contract D { // gas legacy: 98438801 // gas legacyOptimized: 98438594 // fpure() -> FAILURE -// gas irOptimized: 98438626 +// gas irOptimized: 98438625 // gas legacy: 98438801 // gas legacyOptimized: 98438595 diff --git a/test/libsolidity/semanticTests/various/swap_in_storage_overwrite.sol b/test/libsolidity/semanticTests/various/swap_in_storage_overwrite.sol index c8398b2bf..9b7a4306f 100644 --- a/test/libsolidity/semanticTests/various/swap_in_storage_overwrite.sol +++ b/test/libsolidity/semanticTests/various/swap_in_storage_overwrite.sol @@ -30,7 +30,7 @@ contract c { // x() -> 0, 0 // y() -> 0, 0 // set() -> -// gas irOptimized: 109733 +// gas irOptimized: 109713 // gas legacy: 109732 // gas legacyOptimized: 109682 // x() -> 1, 2 diff --git a/test/libsolidity/semanticTests/various/value_complex.sol b/test/libsolidity/semanticTests/various/value_complex.sol index bebf7557f..5d8bda5dd 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: 185891 +// gas irOptimized: 192113 // 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 9edd8061a..0b2b1735b 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: 187835 +// gas irOptimized: 194261 // 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 b603fb786..6ef403dcc 100644 --- a/test/libsolidity/semanticTests/viaYul/array_memory_index_access.sol +++ b/test/libsolidity/semanticTests/viaYul/array_memory_index_access.sol @@ -28,7 +28,7 @@ contract C { // index(uint256): 10 -> true // index(uint256): 20 -> true // index(uint256): 0xFF -> true -// gas irOptimized: 138441 +// gas irOptimized: 138410 // gas legacy: 248854 // gas legacyOptimized: 152638 // accessIndex(uint256,int256): 10, 1 -> 2 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 70e3a34d4..05b7e668b 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: 113142 +// gas irOptimized: 112998 // gas legacy: 112937 // gas legacyOptimized: 112608 diff --git a/test/libsolidity/smtCheckerTests/userTypes/multisource_module.sol b/test/libsolidity/smtCheckerTests/userTypes/multisource_module.sol index 491b8600d..846f3ab75 100644 --- a/test/libsolidity/smtCheckerTests/userTypes/multisource_module.sol +++ b/test/libsolidity/smtCheckerTests/userTypes/multisource_module.sol @@ -16,6 +16,7 @@ contract C { // ==== // SMTEngine: all // SMTIgnoreOS: macos +// SMTIgnoreCex: yes // ---- -// Warning 6328: (s2.sol:259-292): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.h()\n C.f(5) -- internal call\n C.f(5) -- internal call -// Warning 6328: (s2.sol:346-377): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.h()\n C.f(5) -- internal call\n C.f(5) -- internal call\n C.g(1) -- internal call\n C.g(1) -- internal call +// Warning 6328: (s2.sol:259-292): CHC: Assertion violation happens here. +// Warning 6328: (s2.sol:346-377): CHC: Assertion violation happens here. diff --git a/test/libsolidity/syntaxTests/freeFunctions/free_mutability.sol b/test/libsolidity/syntaxTests/freeFunctions/free_mutability.sol index dafa91ccb..9279ff1eb 100644 --- a/test/libsolidity/syntaxTests/freeFunctions/free_mutability.sol +++ b/test/libsolidity/syntaxTests/freeFunctions/free_mutability.sol @@ -5,4 +5,4 @@ function f() { function g(uint[] storage x) pure { x[0] = 1; } // ---- // Warning 2018: (0-39): Function state mutability can be restricted to pure -// TypeError 8961: (76-80): Function declared as pure, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. +// TypeError 8961: (76-80): Function cannot be declared as pure because this expression (potentially) modifies the state. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/assembly_dialect_duplicate_option.sol b/test/libsolidity/syntaxTests/inlineAssembly/assembly_dialect_duplicate_option.sol new file mode 100644 index 000000000..7e0672f65 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/assembly_dialect_duplicate_option.sol @@ -0,0 +1,5 @@ +function f() pure { + assembly "evmasm" ("memory-safe", "memory-safe") {} +} +// ---- +// SyntaxError 7026: (24-75): Inline assembly marked memory-safe multiple times. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/assembly_dialect_invalid_options.sol b/test/libsolidity/syntaxTests/inlineAssembly/assembly_dialect_invalid_options.sol new file mode 100644 index 000000000..44206c9ec --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/assembly_dialect_invalid_options.sol @@ -0,0 +1,8 @@ +function f() pure { + assembly "evmasm" ("a", "b", "c", "c") {} +} +// ---- +// Warning 4430: (24-65): Unknown inline assembly flag: "a" +// Warning 4430: (24-65): Unknown inline assembly flag: "b" +// Warning 4430: (24-65): Unknown inline assembly flag: "c" +// Warning 4430: (24-65): Unknown inline assembly flag: "c" diff --git a/test/libsolidity/syntaxTests/inlineAssembly/assembly_dialect_leading_space.sol b/test/libsolidity/syntaxTests/inlineAssembly/assembly_dialect_leading_space.sol new file mode 100644 index 000000000..1cf1e7fb9 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/assembly_dialect_leading_space.sol @@ -0,0 +1,5 @@ +function f() pure { + assembly " evmasm" {} +} +// ---- +// ParserError 4531: (33-42): Only "evmasm" supported. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/assembly_duplicate_option.sol b/test/libsolidity/syntaxTests/inlineAssembly/assembly_duplicate_option.sol new file mode 100644 index 000000000..69c503559 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/assembly_duplicate_option.sol @@ -0,0 +1,5 @@ +function f() pure { + assembly ("memory-safe", "memory-safe") {} +} +// ---- +// SyntaxError 7026: (24-66): Inline assembly marked memory-safe multiple times. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/assembly_empty_option_list.sol b/test/libsolidity/syntaxTests/inlineAssembly/assembly_empty_option_list.sol new file mode 100644 index 000000000..cae17320b --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/assembly_empty_option_list.sol @@ -0,0 +1,5 @@ +function f() pure { + assembly () {} +} +// ---- +// ParserError 2314: (34-35): Expected 'StringLiteral' but got ')' diff --git a/test/libsolidity/syntaxTests/inlineAssembly/assembly_empty_option_list_dialect.sol b/test/libsolidity/syntaxTests/inlineAssembly/assembly_empty_option_list_dialect.sol new file mode 100644 index 000000000..222e59b93 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/assembly_empty_option_list_dialect.sol @@ -0,0 +1,5 @@ +function f() pure { + assembly "evmasm" () {} +} +// ---- +// ParserError 2314: (43-44): Expected 'StringLiteral' but got ')' diff --git a/test/libsolidity/syntaxTests/inlineAssembly/assembly_flags_delimiter.sol b/test/libsolidity/syntaxTests/inlineAssembly/assembly_flags_delimiter.sol new file mode 100644 index 000000000..cd82f8aaa --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/assembly_flags_delimiter.sol @@ -0,0 +1,5 @@ +function f() pure { + assembly ("a" "b") {} +} +// ---- +// ParserError 2314: (35-38): Expected ')' but got 'StringLiteral' diff --git a/test/libsolidity/syntaxTests/inlineAssembly/assembly_invalid_options.sol b/test/libsolidity/syntaxTests/inlineAssembly/assembly_invalid_options.sol new file mode 100644 index 000000000..3364d793e --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/assembly_invalid_options.sol @@ -0,0 +1,8 @@ +function f() pure { + assembly ("a", "b", "c", "c") {} +} +// ---- +// Warning 4430: (24-56): Unknown inline assembly flag: "a" +// Warning 4430: (24-56): Unknown inline assembly flag: "b" +// Warning 4430: (24-56): Unknown inline assembly flag: "c" +// Warning 4430: (24-56): Unknown inline assembly flag: "c" diff --git a/test/libsolidity/syntaxTests/inlineAssembly/invalid_natspec.sol b/test/libsolidity/syntaxTests/inlineAssembly/invalid_natspec.sol new file mode 100644 index 000000000..d23eceeed --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/invalid_natspec.sol @@ -0,0 +1,14 @@ +contract C { + function f() public pure { + /// @test test + assembly {} + /// @solidity test + assembly {} + /// @param + assembly {} + } +} +// ---- +// Warning 6269: (60-71): Unexpected NatSpec tag "test" with value "test" in inline assembly. +// Warning 8787: (95-106): Unexpected value for @solidity tag in inline assembly: test +// Warning 7828: (122-133): Inline assembly has invalid NatSpec documentation. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/memory_safe_dialect_string_and_comment.sol b/test/libsolidity/syntaxTests/inlineAssembly/memory_safe_dialect_string_and_comment.sol new file mode 100644 index 000000000..9d0fd3e1c --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/memory_safe_dialect_string_and_comment.sol @@ -0,0 +1,7 @@ +function f() pure { + /// @solidity memory-safe-assembly + assembly "evmasm" ("memory-safe") { + } +} +// ---- +// Warning 8544: (63-104): Inline assembly marked as memory safe using both a NatSpec tag and an assembly flag. If you are not concerned with backwards compatibility, only use the assembly flag, otherwise only use the NatSpec tag. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/memory_safe_in_dialect_string.sol b/test/libsolidity/syntaxTests/inlineAssembly/memory_safe_in_dialect_string.sol new file mode 100644 index 000000000..c034f803d --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/memory_safe_in_dialect_string.sol @@ -0,0 +1,3 @@ +function f() pure { + assembly "evmasm" ("memory-safe") {} +} \ No newline at end of file diff --git a/test/libsolidity/syntaxTests/inlineAssembly/natspec_memory_safe.sol b/test/libsolidity/syntaxTests/inlineAssembly/natspec_memory_safe.sol new file mode 100644 index 000000000..b93b20318 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/natspec_memory_safe.sol @@ -0,0 +1,6 @@ +contract C { + function f() public pure { + // @solidity memory-safe-assembly + assembly {} + } +} \ No newline at end of file diff --git a/test/libsolidity/syntaxTests/inlineAssembly/natspec_multi.sol b/test/libsolidity/syntaxTests/inlineAssembly/natspec_multi.sol new file mode 100644 index 000000000..945d62b06 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/natspec_multi.sol @@ -0,0 +1,23 @@ +function f() pure { + /// @unrelated bogus-value + + /// @before bogus-value + /// + /// @solidity a memory-safe-assembly b c + /// d + /// @after bogus-value + assembly {} + /// @solidity memory-safe-assembly a a a + /// memory-safe-assembly + assembly {} +} +// ---- +// Warning 6269: (189-200): Unexpected NatSpec tag "after" with value "bogus-value" in inline assembly. +// Warning 6269: (189-200): Unexpected NatSpec tag "before" with value "bogus-value" in inline assembly. +// Warning 8787: (189-200): Unexpected value for @solidity tag in inline assembly: a +// Warning 8787: (189-200): Unexpected value for @solidity tag in inline assembly: b +// Warning 8787: (189-200): Unexpected value for @solidity tag in inline assembly: c +// Warning 8787: (189-200): Unexpected value for @solidity tag in inline assembly: d +// Warning 8787: (289-300): Unexpected value for @solidity tag in inline assembly: a +// Warning 4377: (289-300): Value for @solidity tag in inline assembly specified multiple times: a +// Warning 4377: (289-300): Value for @solidity tag in inline assembly specified multiple times: memory-safe-assembly diff --git a/test/libsolidity/syntaxTests/inlineAssembly/natspec_multi_swallowed.sol b/test/libsolidity/syntaxTests/inlineAssembly/natspec_multi_swallowed.sol new file mode 100644 index 000000000..74be1232d --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/natspec_multi_swallowed.sol @@ -0,0 +1,19 @@ +function f() pure { + /// @unrelated bogus-value + + /// @before + /// + /// @solidity a memory-safe-assembly b c + /// d + /// @after bogus-value + assembly {} + /// @solidity memory-safe-assembly a a a + /// memory-safe-assembly + assembly {} +} +// ---- +// Warning 6269: (177-188): Unexpected NatSpec tag "after" with value "bogus-value" in inline assembly. +// Warning 6269: (177-188): Unexpected NatSpec tag "before" with value "@solidity a memory-safe-assembly b c d" in inline assembly. +// Warning 8787: (277-288): Unexpected value for @solidity tag in inline assembly: a +// Warning 4377: (277-288): Value for @solidity tag in inline assembly specified multiple times: a +// Warning 4377: (277-288): Value for @solidity tag in inline assembly specified multiple times: memory-safe-assembly diff --git a/test/libsolidity/syntaxTests/multiSource/one_source.sol b/test/libsolidity/syntaxTests/multiSource/one_source.sol index 11ee49720..9c1d92eb5 100644 --- a/test/libsolidity/syntaxTests/multiSource/one_source.sol +++ b/test/libsolidity/syntaxTests/multiSource/one_source.sol @@ -4,4 +4,4 @@ contract A { function f() public pure { x = 42; } } // ---- -// TypeError 8961: (SourceName:53-54): Function declared as pure, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. +// TypeError 8961: (SourceName:53-54): Function cannot be declared as pure because this expression (potentially) modifies the state. diff --git a/test/libsolidity/syntaxTests/viewPureChecker/access_to_base_member_function.sol b/test/libsolidity/syntaxTests/viewPureChecker/access_to_base_member_function.sol index 1b5a7ae50..0f434c743 100644 --- a/test/libsolidity/syntaxTests/viewPureChecker/access_to_base_member_function.sol +++ b/test/libsolidity/syntaxTests/viewPureChecker/access_to_base_member_function.sol @@ -8,4 +8,4 @@ contract B is A { } } // ---- -// TypeError 8961: (100-105): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. +// TypeError 8961: (100-105): Function cannot be declared as view because this expression (potentially) modifies the state. diff --git a/test/libsolidity/syntaxTests/viewPureChecker/access_to_base_member_struct.sol b/test/libsolidity/syntaxTests/viewPureChecker/access_to_base_member_struct.sol index 612fbb745..13d0ed913 100644 --- a/test/libsolidity/syntaxTests/viewPureChecker/access_to_base_member_struct.sol +++ b/test/libsolidity/syntaxTests/viewPureChecker/access_to_base_member_struct.sol @@ -15,7 +15,7 @@ contract B is A { } } // ---- -// TypeError 8961: (107-110): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. -// TypeError 8961: (166-171): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. +// TypeError 8961: (107-110): Function cannot be declared as view because this expression (potentially) modifies the state. +// TypeError 8961: (166-171): Function cannot be declared as view because this expression (potentially) modifies the state. // TypeError 2527: (244-247): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view". // TypeError 2527: (244-249): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view". diff --git a/test/libsolidity/syntaxTests/viewPureChecker/access_to_base_members.sol b/test/libsolidity/syntaxTests/viewPureChecker/access_to_base_members.sol index e9dccaecd..1203d2c67 100644 --- a/test/libsolidity/syntaxTests/viewPureChecker/access_to_base_members.sol +++ b/test/libsolidity/syntaxTests/viewPureChecker/access_to_base_members.sol @@ -12,4 +12,4 @@ contract B is A { } // ---- // TypeError 2527: (107-110): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view". -// TypeError 8961: (157-160): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. +// TypeError 8961: (157-160): Function cannot be declared as view because this expression (potentially) modifies the state. diff --git a/test/libsolidity/syntaxTests/viewPureChecker/array/access_to_array_push_view.sol b/test/libsolidity/syntaxTests/viewPureChecker/array/access_to_array_push_view.sol index 3b7c19f5e..27ba16eaf 100644 --- a/test/libsolidity/syntaxTests/viewPureChecker/array/access_to_array_push_view.sol +++ b/test/libsolidity/syntaxTests/viewPureChecker/array/access_to_array_push_view.sol @@ -5,4 +5,4 @@ contract A { } } // ---- -// TypeError 8961: (88-96): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. +// TypeError 8961: (88-96): Function cannot be declared as view because this expression (potentially) modifies the state. diff --git a/test/libsolidity/syntaxTests/viewPureChecker/builtin_functions_view_fail.sol b/test/libsolidity/syntaxTests/viewPureChecker/builtin_functions_view_fail.sol index 000f5b009..76a05d8be 100644 --- a/test/libsolidity/syntaxTests/viewPureChecker/builtin_functions_view_fail.sol +++ b/test/libsolidity/syntaxTests/viewPureChecker/builtin_functions_view_fail.sol @@ -20,8 +20,8 @@ contract C { } } // ---- -// TypeError 8961: (52-77): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. -// TypeError 8961: (132-153): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. -// TypeError 8961: (201-228): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. -// TypeError 8961: (293-323): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. -// TypeError 8961: (414-436): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. +// TypeError 8961: (52-77): Function cannot be declared as view because this expression (potentially) modifies the state. +// TypeError 8961: (132-153): Function cannot be declared as view because this expression (potentially) modifies the state. +// TypeError 8961: (201-228): Function cannot be declared as view because this expression (potentially) modifies the state. +// TypeError 8961: (293-323): Function cannot be declared as view because this expression (potentially) modifies the state. +// TypeError 8961: (414-436): Function cannot be declared as view because this expression (potentially) modifies the state. diff --git a/test/libsolidity/syntaxTests/viewPureChecker/call_internal_functions_fail.sol b/test/libsolidity/syntaxTests/viewPureChecker/call_internal_functions_fail.sol index a47de539e..38762a34a 100644 --- a/test/libsolidity/syntaxTests/viewPureChecker/call_internal_functions_fail.sol +++ b/test/libsolidity/syntaxTests/viewPureChecker/call_internal_functions_fail.sol @@ -7,4 +7,4 @@ contract C { } // ---- // TypeError 2527: (56-59): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view". -// TypeError 8961: (130-133): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. +// TypeError 8961: (130-133): Function cannot be declared as view because this expression (potentially) modifies the state. diff --git a/test/libsolidity/syntaxTests/viewPureChecker/creation_view_fail.sol b/test/libsolidity/syntaxTests/viewPureChecker/creation_view_fail.sol index 643ba8b26..c934c9093 100644 --- a/test/libsolidity/syntaxTests/viewPureChecker/creation_view_fail.sol +++ b/test/libsolidity/syntaxTests/viewPureChecker/creation_view_fail.sol @@ -3,4 +3,4 @@ contract C { function f() public view { new D(); } } // ---- -// TypeError 8961: (58-65): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. +// TypeError 8961: (58-65): Function cannot be declared as view because this expression (potentially) modifies the state. diff --git a/test/libsolidity/syntaxTests/viewPureChecker/function_types_fail.sol b/test/libsolidity/syntaxTests/viewPureChecker/function_types_fail.sol index 47027331f..f0ad5efcc 100644 --- a/test/libsolidity/syntaxTests/viewPureChecker/function_types_fail.sol +++ b/test/libsolidity/syntaxTests/viewPureChecker/function_types_fail.sol @@ -13,6 +13,6 @@ contract C { } } // ---- -// TypeError 8961: (92-103): Function declared as pure, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. +// TypeError 8961: (92-103): Function cannot be declared as pure because this expression (potentially) modifies the state. // TypeError 2527: (193-202): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view". -// TypeError 8961: (289-300): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. +// TypeError 8961: (289-300): Function cannot be declared as view because this expression (potentially) modifies the state. diff --git a/test/libsolidity/syntaxTests/viewPureChecker/gas_with_call_nonpayable.sol b/test/libsolidity/syntaxTests/viewPureChecker/gas_with_call_nonpayable.sol index be8a5aeb8..65030cb30 100644 --- a/test/libsolidity/syntaxTests/viewPureChecker/gas_with_call_nonpayable.sol +++ b/test/libsolidity/syntaxTests/viewPureChecker/gas_with_call_nonpayable.sol @@ -8,5 +8,5 @@ contract C { } } // ---- -// TypeError 8961: (90-109): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. -// TypeError 8961: (180-197): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. +// TypeError 8961: (90-109): Function cannot be declared as view because this expression (potentially) modifies the state. +// TypeError 8961: (180-197): Function cannot be declared as view because this expression (potentially) modifies the state. diff --git a/test/libsolidity/syntaxTests/viewPureChecker/local_storage_variables_fail.sol b/test/libsolidity/syntaxTests/viewPureChecker/local_storage_variables_fail.sol index 774dd44e5..3b9054c41 100644 --- a/test/libsolidity/syntaxTests/viewPureChecker/local_storage_variables_fail.sol +++ b/test/libsolidity/syntaxTests/viewPureChecker/local_storage_variables_fail.sol @@ -12,4 +12,4 @@ contract C { } // ---- // TypeError 2527: (100-101): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view". -// TypeError 8961: (184-187): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. +// TypeError 8961: (184-187): Function cannot be declared as view because this expression (potentially) modifies the state. diff --git a/test/libsolidity/syntaxTests/viewPureChecker/modifiers_fail.sol b/test/libsolidity/syntaxTests/viewPureChecker/modifiers_fail.sol index 3c592844a..ad24e1827 100644 --- a/test/libsolidity/syntaxTests/viewPureChecker/modifiers_fail.sol +++ b/test/libsolidity/syntaxTests/viewPureChecker/modifiers_fail.sol @@ -9,4 +9,4 @@ contract C is D { } // ---- // TypeError 2527: (154-162): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view". -// TypeError 8961: (195-209): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. +// TypeError 8961: (195-209): Function cannot be declared as view because this expression (potentially) modifies the state. diff --git a/test/libsolidity/syntaxTests/viewPureChecker/value_with_call_nonpayable.sol b/test/libsolidity/syntaxTests/viewPureChecker/value_with_call_nonpayable.sol index af95cbe49..cfb41d320 100644 --- a/test/libsolidity/syntaxTests/viewPureChecker/value_with_call_nonpayable.sol +++ b/test/libsolidity/syntaxTests/viewPureChecker/value_with_call_nonpayable.sol @@ -8,5 +8,5 @@ contract C { } } // ---- -// TypeError 8961: (90-111): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. -// TypeError 8961: (182-201): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. +// TypeError 8961: (90-111): Function cannot be declared as view because this expression (potentially) modifies the state. +// TypeError 8961: (182-201): Function cannot be declared as view because this expression (potentially) modifies the state. diff --git a/test/libsolidity/syntaxTests/viewPureChecker/write_storage_fail.sol b/test/libsolidity/syntaxTests/viewPureChecker/write_storage_fail.sol index d6828aac6..c3875f411 100644 --- a/test/libsolidity/syntaxTests/viewPureChecker/write_storage_fail.sol +++ b/test/libsolidity/syntaxTests/viewPureChecker/write_storage_fail.sol @@ -3,4 +3,4 @@ contract C { function f() view public { x = 2; } } // ---- -// TypeError 8961: (56-57): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. +// TypeError 8961: (56-57): Function cannot be declared as view because this expression (potentially) modifies the state. diff --git a/test/libyul/ObjectCompilerTest.cpp b/test/libyul/ObjectCompilerTest.cpp index 256bced21..f22870952 100644 --- a/test/libyul/ObjectCompilerTest.cpp +++ b/test/libyul/ObjectCompilerTest.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include diff --git a/test/solc/CommandLineInterface.cpp b/test/solc/CommandLineInterface.cpp index cd6b9955b..499564ae8 100644 --- a/test/solc/CommandLineInterface.cpp +++ b/test/solc/CommandLineInterface.cpp @@ -178,8 +178,9 @@ BOOST_AUTO_TEST_CASE(cli_input) createFilesWithParentDirs({tempDir1.path() / "input1.sol"}); createFilesWithParentDirs({tempDir2.path() / "input2.sol"}); - boost::filesystem::path expectedDir1 = "/" / tempDir1.path().relative_path(); - boost::filesystem::path expectedDir2 = "/" / tempDir2.path().relative_path(); + boost::filesystem::path expectedRootPath = FileReader::normalizeCLIRootPathForVFS(tempDir1); + boost::filesystem::path expectedDir1 = expectedRootPath / tempDir1.path().relative_path(); + boost::filesystem::path expectedDir2 = expectedRootPath / tempDir2.path().relative_path(); soltestAssert(expectedDir1.is_absolute() || expectedDir1.root_path() == "/", ""); soltestAssert(expectedDir2.is_absolute() || expectedDir2.root_path() == "/", ""); @@ -221,7 +222,8 @@ BOOST_AUTO_TEST_CASE(cli_ignore_missing_some_files_exist) TemporaryDirectory tempDir2(TEST_CASE_NAME); createFilesWithParentDirs({tempDir1.path() / "input1.sol"}); - boost::filesystem::path expectedDir1 = "/" / tempDir1.path().relative_path(); + boost::filesystem::path expectedRootPath = FileReader::normalizeCLIRootPathForVFS(tempDir1); + boost::filesystem::path expectedDir1 = expectedRootPath / tempDir1.path().relative_path(); soltestAssert(expectedDir1.is_absolute() || expectedDir1.root_path() == "/", ""); // NOTE: Allowed paths should not be added for skipped files. diff --git a/test/tools/CMakeLists.txt b/test/tools/CMakeLists.txt index 18e3d4377..5971341ec 100644 --- a/test/tools/CMakeLists.txt +++ b/test/tools/CMakeLists.txt @@ -23,6 +23,7 @@ add_executable(isoltest ../libsolidity/util/TestFileParser.cpp ../libsolidity/util/TestFunctionCall.cpp ../libsolidity/GasTest.cpp + ../libsolidity/MemoryGuardTest.cpp ../libsolidity/SyntaxTest.cpp ../libsolidity/SemanticTest.cpp ../libsolidity/AnalysisFramework.cpp