aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.circleci/config.yml4
-rw-r--r--CMakeLists.txt11
-rw-r--r--Changelog.md19
-rw-r--r--docs/bugs_by_version.json4
-rw-r--r--docs/contracts.rst35
-rw-r--r--docs/contributing.rst4
-rw-r--r--docs/control-structures.rst27
-rw-r--r--docs/frequently-asked-questions.rst25
-rw-r--r--docs/index.rst1
-rw-r--r--docs/lll.rst21
-rw-r--r--docs/miscellaneous.rst23
-rw-r--r--docs/yul.rst6
-rw-r--r--libdevcore/CommonData.cpp2
-rw-r--r--libdevcore/Keccak256.cpp (renamed from libdevcore/SHA3.cpp)96
-rw-r--r--libdevcore/Keccak256.h (renamed from libdevcore/SHA3.h)8
-rw-r--r--libdevcore/SwarmHash.cpp2
-rw-r--r--libevmasm/Assembly.h2
-rw-r--r--libevmasm/CommonSubexpressionEliminator.cpp2
-rw-r--r--libevmasm/KnownState.cpp2
-rw-r--r--libevmasm/LinkerObject.cpp2
-rw-r--r--liblll/CodeFragment.cpp11
-rw-r--r--libsolc/CMakeLists.txt2
-rw-r--r--libsolc/libsolc.cpp228
-rw-r--r--libsolc/libsolc.h9
-rw-r--r--libsolidity/analysis/ControlFlowAnalyzer.cpp7
-rw-r--r--libsolidity/analysis/TypeChecker.cpp770
-rw-r--r--libsolidity/analysis/TypeChecker.h28
-rw-r--r--libsolidity/ast/AST.cpp2
-rw-r--r--libsolidity/ast/AST.h6
-rw-r--r--libsolidity/ast/Types.cpp2
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp2
-rw-r--r--libsolidity/formal/SMTChecker.cpp4
-rw-r--r--libsolidity/formal/SMTChecker.h5
-rw-r--r--libsolidity/interface/CompilerStack.cpp4
-rw-r--r--libsolidity/interface/GasEstimator.cpp2
-rw-r--r--libsolidity/interface/StandardCompiler.cpp2
-rw-r--r--libsolidity/parsing/Parser.cpp2
-rw-r--r--libsolidity/parsing/Scanner.h7
-rw-r--r--libyul/YulString.h87
-rw-r--r--libyul/optimiser/README.md2
-rw-r--r--libyul/optimiser/RedundantAssignEliminator.cpp73
-rw-r--r--libyul/optimiser/RedundantAssignEliminator.h11
-rw-r--r--libyul/optimiser/UnusedPruner.cpp10
-rw-r--r--libyul/optimiser/UnusedPruner.h6
-rwxr-xr-xscripts/bytecodecompare/storebytecode.sh20
-rwxr-xr-xscripts/check_style.sh7
-rw-r--r--test/CMakeLists.txt13
-rw-r--r--test/ExecutionFramework.h2
-rw-r--r--test/boostTest.cpp2
-rwxr-xr-xtest/cmdlineTests.sh2
-rwxr-xr-xtest/externalTests.sh13
-rw-r--r--test/liblll/Compiler.cpp956
-rw-r--r--test/liblll/EndToEndTest.cpp14
-rw-r--r--test/liblll/LLL_ENS.cpp (renamed from test/contracts/LLL_ENS.cpp)0
-rw-r--r--test/liblll/LLL_ERC20.cpp (renamed from test/contracts/LLL_ERC20.cpp)0
-rw-r--r--test/libsolidity/AnalysisFramework.cpp2
-rw-r--r--test/libsolidity/LibSolc.cpp143
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp2
-rw-r--r--test/libsolidity/SolidityTypes.cpp2
-rw-r--r--test/libsolidity/syntaxTests/controlFlow/storageReturn/unimplemented_internal.sol4
-rw-r--r--test/libsolidity/syntaxTests/controlFlow/storageReturn/unimplemented_library.sol4
-rw-r--r--test/libsolidity/syntaxTests/nameAndTypeResolution/102_duplicate_parameter_names_in_named_args.sol2
-rw-r--r--test/libsolidity/syntaxTests/nameAndTypeResolution/583_abi_encode_packed_with_rational_number_constant.sol5
-rw-r--r--test/libsolidity/syntaxTests/nameAndTypeResolution/584_abi_decode_with_tuple_of_other_than_types.sol5
-rw-r--r--test/libyul/Inliner.cpp6
-rw-r--r--test/libyul/YulOptimizerTest.cpp18
-rw-r--r--test/libyul/yulOptimizerTests/fullInliner/multi_fun_callback.yul13
-rw-r--r--test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul654
-rw-r--r--test/libyul/yulOptimizerTests/fullSuite/medium.yul4
-rw-r--r--test/libyul/yulOptimizerTests/splitJoin/control_flow.yul26
-rw-r--r--test/libyul/yulOptimizerTests/splitJoin/functions.yul30
-rw-r--r--test/libyul/yulOptimizerTests/splitJoin/smoke.yul5
-rw-r--r--test/libyul/yulOptimizerTests/unusedPruner/pop.yul8
-rw-r--r--test/libyul/yulOptimizerTests/varDeclPropagator/multi_assignment_vardecl.yul2
-rw-r--r--test/libyul/yulOptimizerTests/varDeclPropagator/simple1.yul2
-rw-r--r--test/tools/fuzzer.cpp2
76 files changed, 2161 insertions, 1385 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 4bb5e651..f1b49649 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -122,7 +122,7 @@ jobs:
- image: buildpack-deps:artful
environment:
TERM: xterm
- CMAKE_OPTIONS: -DCOVERAGE=ON
+ CMAKE_OPTIONS: -DCOVERAGE=OFF
steps:
- checkout
- run:
@@ -167,6 +167,7 @@ jobs:
TERM: xterm
CC: /usr/bin/clang-7
CXX: /usr/bin/clang++-7
+ CMAKE_OPTIONS: -DLLL=ON
steps:
- checkout
- run:
@@ -188,6 +189,7 @@ jobs:
xcode: "10.0.0"
environment:
TERM: xterm
+ CMAKE_OPTIONS: -DLLL=ON
steps:
- checkout
- run:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f2c84d20..86769672 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,12 +8,13 @@ include(EthPolicy)
eth_policy()
# project name and version should be set after cmake_policy CMP0048
-set(PROJECT_VERSION "0.5.0")
+set(PROJECT_VERSION "0.5.1")
project(solidity VERSION ${PROJECT_VERSION})
+option(LLL "Build LLL" OFF)
option(SOLC_LINK_STATIC "Link solc executable statically on supported platforms" OFF)
option(LLLC_LINK_STATIC "Link lllc executable statically on supported platforms" OFF)
-option(INSTALL_LLLC "Include lllc executable in installation" OFF)
+option(INSTALL_LLLC "Include lllc executable in installation" ${LLL})
# Setup cccache.
include(EthCcache)
@@ -50,8 +51,10 @@ add_subdirectory(libsolc)
if (NOT EMSCRIPTEN)
add_subdirectory(solc)
- add_subdirectory(liblll)
- add_subdirectory(lllc)
+ if (LLL)
+ add_subdirectory(liblll)
+ add_subdirectory(lllc)
+ endif()
endif()
if (TESTS AND NOT EMSCRIPTEN)
diff --git a/Changelog.md b/Changelog.md
index ff95a89a..b5e7eed8 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,4 +1,17 @@
-### 0.5.0 (unreleased)
+### 0.5.1 (unreleased)
+
+Language Features:
+
+
+Compiler Features:
+ * Build System: LLL is not built anymore by default. Must configure it with CMake as `-DLLL=ON`.
+
+
+Bugfixes:
+
+
+
+### 0.5.0 (2018-11-13)
How to update your code:
* Change every ``.call()`` to a ``.call("")`` and every ``.call(signature, a, b, c)`` to use ``.call(abi.encodeWithSignature(signature, a, b, c))`` (the last one only works for value types).
@@ -11,6 +24,8 @@ How to update your code:
Breaking Changes:
* ABI Encoder: Properly pad data from calldata (``msg.data`` and external function parameters). Use ``abi.encodePacked`` for unpadded encoding.
+ * C API (``libsolc`` / raw ``soljson.js``): Removed the ``version``, ``license``, ``compileSingle``, ``compileJSON``, ``compileJSONCallback`` methods
+ and replaced them with the ``solidity_license``, ``solidity_version`` and ``solidity_compile`` methods.
* Code Generator: Signed right shift uses proper arithmetic shift, i.e. rounding towards negative infinity. Warning: this may silently change the semantics of existing code!
* Code Generator: Revert at runtime if calldata is too short or points out of bounds. This is done inside the ``ABI decoder`` and therefore also applies to ``abi.decode()``.
* Code Generator: Use ``STATICCALL`` for ``pure`` and ``view`` functions. This was already the case in the experimental 0.5.0 mode.
@@ -91,7 +106,6 @@ Language Features:
Compiler Features:
* Build System: Support for Mojave version of macOS added.
- * C API (``libsolc``): Export the ``solidity_license``, ``solidity_version`` and ``solidity_compile`` methods.
* Code Generator: ``CREATE2`` instruction has been updated to match EIP1014 (aka "Skinny CREATE2"). It also is accepted as part of Constantinople.
* Code Generator: ``EXTCODEHASH`` instruction has been added based on EIP1052.
* Type Checker: Nicer error message when trying to reference overloaded identifiers in inline assembly.
@@ -111,6 +125,7 @@ Bugfixes:
* Code Generator: Properly handle negative number literals in ABIEncoderV2.
* Code Generator: Do not crash on using a length of zero for multidimensional fixed-size arrays.
* Commandline Interface: Correctly handle paths with backslashes on windows.
+ * Control Flow Analyzer: Ignore unimplemented functions when detecting uninitialized storage pointer returns.
* Fix NatSpec json output for `@notice` and `@dev` tags on contract definitions.
* Optimizer: Correctly estimate gas costs of constants for special cases.
* Optimizer: Fix simplification rule initialization bug that appeared on some emscripten platforms.
diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json
index 0318ac89..2631b286 100644
--- a/docs/bugs_by_version.json
+++ b/docs/bugs_by_version.json
@@ -608,5 +608,9 @@
"ConstantOptimizerSubtraction"
],
"released": "2017-01-31"
+ },
+ "0.5.0": {
+ "bugs": [],
+ "released": "2018-11-13"
}
} \ No newline at end of file
diff --git a/docs/contracts.rst b/docs/contracts.rst
index d4160eac..c1c51e56 100644
--- a/docs/contracts.rst
+++ b/docs/contracts.rst
@@ -50,7 +50,7 @@ This means that cyclic creation dependencies are impossible.
pragma solidity >=0.4.22 <0.6.0;
contract OwnedToken {
- // TokenCreator is a contract type that is defined below.
+ // `TokenCreator` is a contract type that is defined below.
// It is fine to reference it as long as it is not used
// to create a new contract.
TokenCreator creator;
@@ -61,14 +61,18 @@ This means that cyclic creation dependencies are impossible.
// creator and the assigned name.
constructor(bytes32 _name) public {
// State variables are accessed via their name
- // and not via e.g. this.owner. This also applies
- // to functions and especially in the constructors,
- // you can only call them like that ("internally"),
- // because the contract itself does not exist yet.
+ // and not via e.g. `this.owner`. Functions can
+ // be accessed directly or through `this.f`,
+ // but the latter provides an external view
+ // to the function. Especially in the constructor,
+ // you should not access functions externally,
+ // because the function does not exist yet.
+ // See the next section for details.
owner = msg.sender;
+
// We do an explicit type conversion from `address`
// to `TokenCreator` and assume that the type of
- // the calling contract is TokenCreator, there is
+ // the calling contract is `TokenCreator`, there is
// no real way to check that.
creator = TokenCreator(msg.sender);
name = _name;
@@ -86,10 +90,11 @@ This means that cyclic creation dependencies are impossible.
// Only the current owner can transfer the token.
if (msg.sender != owner) return;
- // We also want to ask the creator if the transfer
- // is fine. Note that this calls a function of the
- // contract defined below. If the call fails (e.g.
- // due to out-of-gas), the execution also fails here.
+ // We ask the creator contract if the transfer
+ // should proceed by using a function of the
+ // `TokenCreator` contract defined below. If
+ // the call fails (e.g. due to out-of-gas),
+ // the execution also fails here.
if (creator.isTokenTransferOK(owner, newOwner))
owner = newOwner;
}
@@ -100,8 +105,8 @@ This means that cyclic creation dependencies are impossible.
public
returns (OwnedToken tokenAddress)
{
- // Create a new Token contract and return its address.
- // From the JavaScript side, the return type is simply
+ // Create a new `Token` contract and return its address.
+ // From the JavaScript side, the return type is
// `address`, as this is the closest type available in
// the ABI.
return new OwnedToken(name);
@@ -113,12 +118,14 @@ This means that cyclic creation dependencies are impossible.
tokenAddress.changeName(name);
}
+ // Perform checks to determine if transferring a token to the
+ // `OwnedToken` contract should proceed
function isTokenTransferOK(address currentOwner, address newOwner)
public
pure
returns (bool ok)
{
- // Check some arbitrary condition.
+ // Check an arbitrary condition to see if transfer should proceed
return keccak256(abi.encodePacked(currentOwner, newOwner))[0] == 0x7f;
}
}
@@ -448,7 +455,7 @@ execution data (``msg.value`` or ``gasleft()``) or makes calls to external contr
that might have a side-effect on memory allocation are allowed, but those that
might have a side-effect on other memory objects are not. The built-in functions
``keccak256``, ``sha256``, ``ripemd160``, ``ecrecover``, ``addmod`` and ``mulmod``
-are allowed (even though they do call external contracts).
+are allowed (even though, with the exception of ``keccak256``, they do call external contracts).
The reason behind allowing side-effects on the memory allocator is that it
should be possible to construct complex objects like e.g. lookup-tables.
diff --git a/docs/contributing.rst b/docs/contributing.rst
index e626e5c0..11f95206 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -84,8 +84,8 @@ internally.
.. note ::
- Those working in a Windows environment wanting to run the above basic sets without aleth or libz3 in Git Bash, you would have to do: ``./build/test/RelWithDebInfo/soltest.exe -- --no-ipc --no-smt``.
- If you're running this in plain Command Prompt, use ``.\build\test\RelWithDebInfo\soltest.exe -- --no-ipc --no-smt``.
+ Those working in a Windows environment wanting to run the above basic sets without aleth or libz3 in Git Bash, you would have to do: ``./build/test/RelWithDebInfo/soltest.exe -- --no-ipc --no-smt``.
+ If you're running this in plain Command Prompt, use ``.\build\test\RelWithDebInfo\soltest.exe -- --no-ipc --no-smt``.
The option ``--no-smt`` disables the tests that require ``libz3`` and
``--no-ipc`` disables those that require ``aleth``.
diff --git a/docs/control-structures.rst b/docs/control-structures.rst
index 9da29d14..5e3b722b 100644
--- a/docs/control-structures.rst
+++ b/docs/control-structures.rst
@@ -2,7 +2,7 @@
Expressions and Control Structures
##################################
-.. index:: ! parameter, parameter;input, parameter;output
+.. index:: ! parameter, parameter;input, parameter;output, parameter;multiple
Input Parameters and Output Parameters
======================================
@@ -32,6 +32,8 @@ something like::
Input parameters can be used just as any other local variable
can be used, they can also be assigned to.
+.. index:: return array, return string, array, string, array of strings, dynamic array, variably sized array, return struct, struct
+
Output Parameters
-----------------
@@ -54,12 +56,21 @@ write::
}
The names of output parameters can be omitted.
-The output values can also be specified using ``return`` statements,
+The return values can be specified using ``return`` statements,
which are also capable of :ref:`returning multiple values<multi-return>`.
Return parameters can be used as any other local variable and they
are zero-initialized; if they are not explicitly
set, they stay zero.
+
+.. note::
+ You cannot return some types from non-internal functions, notably
+ multi-dimensional dynamic arrays and structs. If you enable the
+ new experimental ``ABIEncoderV2`` feature by adding ``pragma experimental
+ ABIEncoderV2;`` to your source file then more types are available, but
+ ``mapping`` types are still limited to inside a single contract and you
+ cannot transfer them.
+
.. index:: if, else, while, do/while, for, break, continue, return, switch, goto
Control Structures
@@ -120,8 +131,8 @@ External Function Calls
The expressions ``this.g(8);`` and ``c.g(2);`` (where ``c`` is a contract
instance) are also valid function calls, but this time, the function
will be called "externally", via a message call and not directly via jumps.
-Please note that function calls on ``this`` cannot be used in the constructor, as the
-actual contract has not been created yet.
+Please note that function calls on ``this`` cannot be used in the constructor,
+as the actual contract has not been created yet.
Functions of other contracts have to be called externally. For an external call,
all function arguments have to be copied to memory.
@@ -130,8 +141,10 @@ all function arguments have to be copied to memory.
A function call from one contract to another does not create its own transaction,
it is a message call as part of the overall transaction.
-When calling functions of other contracts, the amount of Wei sent with the call and
-the gas can be specified with special options ``.value()`` and ``.gas()``, respectively::
+When calling functions of other contracts, you can specify the amount of Wei or gas sent with the call with the special options ``.value()`` and ``.gas()``, respectively. Any Wei you send to the contract is added to the total balance of the contract:
+
+
+::
pragma solidity >=0.4.0 <0.6.0;
@@ -400,7 +413,7 @@ In any case, you will get a warning about the outer variable being shadowed.
}
}
-.. index:: ! exception, ! throw, ! assert, ! require, ! revert
+.. index:: ! exception, ! throw, ! assert, ! require, ! revert, ! errors
.. _assert-and-require:
diff --git a/docs/frequently-asked-questions.rst b/docs/frequently-asked-questions.rst
index 3e9a6aca..8b655b0d 100644
--- a/docs/frequently-asked-questions.rst
+++ b/docs/frequently-asked-questions.rst
@@ -38,11 +38,6 @@ has it (which includes `Remix <https://remix.ethereum.org/>`_), then
``contractname.kill.sendTransaction({from:eth.coinbase})``, just the same as my
examples.
-Can you return an array or a ``string`` from a solidity function call?
-======================================================================
-
-Yes. See `array_receiver_and_returner.sol <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/60_array_receiver_and_returner.sol>`_.
-
Is it possible to in-line initialize an array like so: ``string[] myarray = ["a", "b"];``
=========================================================================================
@@ -61,11 +56,6 @@ Example::
}
}
-Can a contract function return a ``struct``?
-============================================
-
-Yes, but only in ``internal`` function calls or if ``pragma experimental "ABIEncoderV2";`` is used.
-
If I return an ``enum``, I only get integer values in web3.js. How to get the named values?
===========================================================================================
@@ -103,15 +93,6 @@ How do structs work?
See `struct_and_for_loop_tester.sol <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/65_struct_and_for_loop_tester.sol>`_.
-How do for loops work?
-======================
-
-Very similar to JavaScript. Such as the following example:
-
-``for (uint i = 0; i < a.length; i ++) { a[i] = i; }``
-
-See `struct_and_for_loop_tester.sol <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/65_struct_and_for_loop_tester.sol>`_.
-
What are some examples of basic string manipulation (``substring``, ``indexOf``, ``charAt``, etc)?
==================================================================================================
@@ -292,12 +273,6 @@ In this example::
}
}
-Can a contract function accept a two-dimensional array?
-=======================================================
-
-If you want to pass two-dimensional arrays across non-internal functions,
-you most likely need to use ``pragma experimental "ABIEncoderV2";``.
-
What is the relationship between ``bytes32`` and ``string``? Why is it that ``bytes32 somevar = "stringliteral";`` works and what does the saved 32-byte hex value mean?
========================================================================================================================================================================
diff --git a/docs/index.rst b/docs/index.rst
index b60ea06d..17abf4b2 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -88,3 +88,4 @@ Contents
bugs.rst
contributing.rst
frequently-asked-questions.rst
+ lll.rst
diff --git a/docs/lll.rst b/docs/lll.rst
new file mode 100644
index 00000000..16be829e
--- /dev/null
+++ b/docs/lll.rst
@@ -0,0 +1,21 @@
+###
+LLL
+###
+
+.. _lll:
+
+LLL is a low-level language for the EVM with an s-expressions syntax.
+
+The Solidity repository contains an LLL compiler, which shares the assembler subsystem with Solidity.
+However, apart from maintaining that it still compiles, no other improvements are made to it.
+
+It is not built unless specifically requested:
+
+.. code-block:: bash
+
+ $ cmake -DLLL=ON ..
+ $ cmake --build .
+
+.. warning::
+
+ The LLL codebase is deprecated and will be removed from the Solidity repository in the future.
diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst
index 8cc52c8f..21978ded 100644
--- a/docs/miscellaneous.rst
+++ b/docs/miscellaneous.rst
@@ -32,6 +32,14 @@ Statically-sized variables (everything except mapping and dynamically-sized arra
``uint128, uint256, uint128``, as the former will only take up two slots of storage whereas the
latter will take up three.
+ .. note::
+ The layout of state variables in storage is considered to be part of the external interface
+ of Solidity due to the fact that storage pointers can be passed to libraries. This means that
+ any change to the rules outlined in this section is considered a breaking change
+ of the language and due to its critical nature should be considered very carefully before
+ being executed.
+
+
The elements of structs and arrays are stored after each other, just as if they were given explicitly.
Mappings and Dynamic Arrays
@@ -165,16 +173,16 @@ Different types have different rules for cleaning up invalid values:
.. index:: optimizer, common subexpression elimination, constant propagation
*************************
-Internals - The Optimizer
+Internals - The Optimiser
*************************
-The Solidity optimizer operates on assembly, so it can be and also is used by other languages. It splits the sequence of instructions into basic blocks at ``JUMPs`` and ``JUMPDESTs``. Inside these blocks, the instructions are analysed and every modification to the stack, to memory or storage is recorded as an expression which consists of an instruction and a list of arguments which are essentially pointers to other expressions. The main idea is now to find expressions that are always equal (on every input) and combine them into an expression class. The optimizer first tries to find each new expression in a list of already known expressions. If this does not work, the expression is simplified according to rules like ``constant + constant = sum_of_constants`` or ``X * 1 = X``. Since this is done recursively, we can also apply the latter rule if the second factor is a more complex expression where we know that it will always evaluate to one. Modifications to storage and memory locations have to erase knowledge about storage and memory locations which are not known to be different: If we first write to location x and then to location y and both are input variables, the second could overwrite the first, so we actually do not know what is stored at x after we wrote to y. On the other hand, if a simplification of the expression x - y evaluates to a non-zero constant, we know that we can keep our knowledge about what is stored at x.
+The Solidity optimiser operates on assembly so that other languages can use it. It splits the sequence of instructions into basic blocks at ``JUMPs`` and ``JUMPDESTs``. Inside these blocks, the optimiser analyses the instructions and records every modification to the stack, memory, or storage as an expression which consists of an instruction and a list of arguments which are pointers to other expressions. The optimiser uses a component called "CommonSubexpressionEliminator" that amongst other tasks, finds expressions that are always equal (on every input) and combines them into an expression class. The optimiser first tries to find each new expression in a list of already known expressions. If this does not work, it simplifies the expression according to rules like ``constant + constant = sum_of_constants`` or ``X * 1 = X``. Since this is a recursive process, we can also apply the latter rule if the second factor is a more complex expression where we know that it always evaluates to one. Modifications to storage and memory locations have to erase knowledge about storage and memory locations which are not known to be different. If we first write to location x and then to location y and both are input variables, the second could overwrite the first, so we do not know what is stored at x after we wrote to y. If simplification of the expression x - y evaluates to a non-zero constant, we know that we can keep our knowledge about what is stored at x.
-At the end of this process, we know which expressions have to be on the stack in the end and have a list of modifications to memory and storage. This information is stored together with the basic blocks and is used to link them. Furthermore, knowledge about the stack, storage and memory configuration is forwarded to the next block(s). If we know the targets of all ``JUMP`` and ``JUMPI`` instructions, we can build a complete control flow graph of the program. If there is only one target we do not know (this can happen as in principle, jump targets can be computed from inputs), we have to erase all knowledge about the input state of a block as it can be the target of the unknown ``JUMP``. If a ``JUMPI`` is found whose condition evaluates to a constant, it is transformed to an unconditional jump.
+After this process, we know which expressions have to be on the stack at the end, and have a list of modifications to memory and storage. This information is stored together with the basic blocks and is used to link them. Furthermore, knowledge about the stack, storage and memory configuration is forwarded to the next block(s). If we know the targets of all ``JUMP`` and ``JUMPI`` instructions, we can build a complete control flow graph of the program. If there is only one target we do not know (this can happen as in principle, jump targets can be computed from inputs), we have to erase all knowledge about the input state of a block as it can be the target of the unknown ``JUMP``. If the optimiser finds a ``JUMPI`` whose condition evaluates to a constant, it transforms it to an unconditional jump.
-As the last step, the code in each block is completely re-generated. A dependency graph is created from the expressions on the stack at the end of the block and every operation that is not part of this graph is essentially dropped. Now code is generated that applies the modifications to memory and storage in the order they were made in the original code (dropping modifications which were found not to be needed) and finally, generates all values that are required to be on the stack in the correct place.
+As the last step, the code in each block is re-generated. The optimiser creates a dependency graph from the expressions on the stack at the end of the block, and it drops every operation that is not part of this graph. It generates code that applies the modifications to memory and storage in the order they were made in the original code (dropping modifications which were found not to be needed). Finally, it generates all values that are required to be on the stack in the correct place.
-These steps are applied to each basic block and the newly generated code is used as replacement if it is smaller. If a basic block is split at a ``JUMPI`` and during the analysis, the condition evaluates to a constant, the ``JUMPI`` is replaced depending on the value of the constant, and thus code like
+These steps are applied to each basic block and the newly generated code is used as replacement if it is smaller. If a basic block is split at a ``JUMPI`` and during the analysis, the condition evaluates to a constant, the ``JUMPI`` is replaced depending on the value of the constant. Thus code like
::
@@ -185,15 +193,14 @@ These steps are applied to each basic block and the newly generated code is used
else
return 1;
-is simplified to code which can also be compiled from
+still simplifies to code which you can compile even though the instructions contained
+a jump in the beginning of the process:
::
data[7] = 9;
return 1;
-even though the instructions contained a jump in the beginning.
-
.. index:: source mappings
***************
diff --git a/docs/yul.rst b/docs/yul.rst
index 9e9fac8e..ea0a298b 100644
--- a/docs/yul.rst
+++ b/docs/yul.rst
@@ -369,10 +369,10 @@ The following functions must be available:
+---------------------------------------------+-----------------------------------------------------------------+
| gtu256(x:u256, y:u256) -> z:bool | true if x > y, false otherwise |
+---------------------------------------------+-----------------------------------------------------------------+
-| sltu256(x:s256, y:s256) -> z:bool | true if x < y, false otherwise |
+| lts256(x:s256, y:s256) -> z:bool | true if x < y, false otherwise |
| | (for signed numbers in two's complement) |
+---------------------------------------------+-----------------------------------------------------------------+
-| sgtu256(x:s256, y:s256) -> z:bool | true if x > y, false otherwise |
+| gts256(x:s256, y:s256) -> z:bool | true if x > y, false otherwise |
| | (for signed numbers in two's complement) |
+---------------------------------------------+-----------------------------------------------------------------+
| equ256(x:u256, y:u256) -> z:bool | true if x == y, false otherwise |
@@ -391,7 +391,7 @@ The following functions must be available:
+---------------------------------------------+-----------------------------------------------------------------+
| shru256(x:u256, y:u256) -> z:u256 | logical right shift of x by y |
+---------------------------------------------+-----------------------------------------------------------------+
-| saru256(x:u256, y:u256) -> z:u256 | arithmetic right shift of x by y |
+| sars256(x:s256, y:u256) -> z:u256 | arithmetic right shift of x by y |
+---------------------------------------------+-----------------------------------------------------------------+
| byte(n:u256, x:u256) -> v:u256 | nth byte of x, where the most significant byte is the 0th byte |
| | Cannot this be just replaced by and256(shr256(n, x), 0xff) and |
diff --git a/libdevcore/CommonData.cpp b/libdevcore/CommonData.cpp
index 91c60ffe..8d2639c9 100644
--- a/libdevcore/CommonData.cpp
+++ b/libdevcore/CommonData.cpp
@@ -22,7 +22,7 @@
#include <libdevcore/CommonData.h>
#include <libdevcore/Exceptions.h>
#include <libdevcore/Assertions.h>
-#include <libdevcore/SHA3.h>
+#include <libdevcore/Keccak256.h>
#include <boost/algorithm/string.hpp>
diff --git a/libdevcore/SHA3.cpp b/libdevcore/Keccak256.cpp
index e41a5e3b..7933fc7e 100644
--- a/libdevcore/SHA3.cpp
+++ b/libdevcore/Keccak256.cpp
@@ -19,7 +19,8 @@
* @date 2014
*/
-#include "SHA3.h"
+#include <libdevcore/Keccak256.h>
+
#include <cstdint>
#include <cstdio>
#include <cstdlib>
@@ -31,7 +32,7 @@ using namespace dev;
namespace dev
{
-namespace keccak
+namespace
{
/** libkeccak-tiny
@@ -43,26 +44,6 @@ namespace keccak
* but not liability.
*/
-#define decshake(bits) \
- int shake##bits(uint8_t*, size_t, const uint8_t*, size_t);
-
-#define decsha3(bits) \
- int sha3_##bits(uint8_t*, size_t, const uint8_t*, size_t);
-
-#define deckeccak(bits) \
- int keccak##bits(uint8_t*, size_t, const uint8_t*, size_t);
-
-decshake(128)
-decshake(256)
-decsha3(224)
-decsha3(256)
-decsha3(384)
-decsha3(512)
-deckeccak(224)
-deckeccak(256)
-deckeccak(384)
-deckeccak(512)
-
/******** The Keccak-f[1600] permutation ********/
/*** Constants. ***/
@@ -164,13 +145,15 @@ mkapply_sd(setout, dst[i] = src[i]) // setout
}
/** The sponge-based hash construction. **/
-static inline int hash(uint8_t* out, size_t outlen,
- const uint8_t* in, size_t inlen,
- size_t rate, uint8_t delim) {
- if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen))
- {
- return -1;
- }
+inline void hash(
+ uint8_t* out,
+ size_t outlen,
+ const uint8_t* in,
+ size_t inlen,
+ size_t rate,
+ uint8_t delim
+)
+{
uint8_t a[Plen] = {0};
// Absorb input.
foldP(in, inlen, xorin);
@@ -185,58 +168,19 @@ static inline int hash(uint8_t* out, size_t outlen,
foldP(out, outlen, setout);
setout(a, out, outlen);
memset(a, 0, 200);
- return 0;
}
-/*** Helper macros to define SHA3 and SHAKE instances. ***/
-#define defshake(bits) \
- int shake##bits(uint8_t* out, size_t outlen, \
- const uint8_t* in, size_t inlen) { \
- return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x1f); \
- }
-#define defsha3(bits) \
- int sha3_##bits(uint8_t* out, size_t outlen, \
- const uint8_t* in, size_t inlen) { \
- if (outlen > (bits/8)) { \
- return -1; \
- } \
- return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x06); \
- }
-#define defkeccak(bits) \
- int keccak##bits(uint8_t* out, size_t outlen, \
- const uint8_t* in, size_t inlen) { \
- if (outlen > (bits/8)) { \
- return -1; \
- } \
- return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \
- }
-
-/*** FIPS202 SHAKE VOFs ***/
-defshake(128)
-defshake(256)
-
-/*** FIPS202 SHA3 FOFs ***/
-defsha3(224)
-defsha3(256)
-defsha3(384)
-defsha3(512)
-
-/*** KECCAK FOFs ***/
-defkeccak(224)
-defkeccak(256)
-defkeccak(384)
-defkeccak(512)
-
}
-bool keccak256(bytesConstRef _input, bytesRef o_output)
+h256 keccak256(bytesConstRef _input)
{
- // FIXME: What with unaligned memory?
- if (o_output.size() != 32)
- return false;
- keccak::keccak256(o_output.data(), 32, _input.data(), _input.size());
-// keccak::keccak(ret.data(), 32, (uint64_t const*)_input.data(), _input.size());
- return true;
+ h256 output;
+ // Parameters used:
+ // The 0x01 is the specific padding for keccak (sha3 uses 0x06) and
+ // the way the round size (or window or whatever it was) is calculated.
+ // 200 - (256 / 4) is the "rate"
+ hash(output.data(), output.size, _input.data(), _input.size(), 200 - (256 / 4), 0x01);
+ return output;
}
}
diff --git a/libdevcore/SHA3.h b/libdevcore/Keccak256.h
index d1e2cc98..0d5f69bb 100644
--- a/libdevcore/SHA3.h
+++ b/libdevcore/Keccak256.h
@@ -30,14 +30,8 @@
namespace dev
{
-// Keccak-256 convenience routines.
-
-/// Calculate Keccak-256 hash of the given input and load it into the given output.
-/// @returns false if o_output.size() != 32.
-bool keccak256(bytesConstRef _input, bytesRef o_output);
-
/// Calculate Keccak-256 hash of the given input, returning as a 256-bit hash.
-inline h256 keccak256(bytesConstRef _input) { h256 ret; keccak256(_input, ret.ref()); return ret; }
+h256 keccak256(bytesConstRef _input);
/// Calculate Keccak-256 hash of the given input, returning as a 256-bit hash.
inline h256 keccak256(bytes const& _input) { return keccak256(bytesConstRef(&_input)); }
diff --git a/libdevcore/SwarmHash.cpp b/libdevcore/SwarmHash.cpp
index 1c718200..3b8d2f3e 100644
--- a/libdevcore/SwarmHash.cpp
+++ b/libdevcore/SwarmHash.cpp
@@ -19,7 +19,7 @@
#include <libdevcore/SwarmHash.h>
-#include <libdevcore/SHA3.h>
+#include <libdevcore/Keccak256.h>
using namespace std;
using namespace dev;
diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h
index 2a29874e..8ef36923 100644
--- a/libevmasm/Assembly.h
+++ b/libevmasm/Assembly.h
@@ -27,7 +27,7 @@
#include <libdevcore/Common.h>
#include <libdevcore/Assertions.h>
-#include <libdevcore/SHA3.h>
+#include <libdevcore/Keccak256.h>
#include <json/json.h>
diff --git a/libevmasm/CommonSubexpressionEliminator.cpp b/libevmasm/CommonSubexpressionEliminator.cpp
index 39485dd9..04926986 100644
--- a/libevmasm/CommonSubexpressionEliminator.cpp
+++ b/libevmasm/CommonSubexpressionEliminator.cpp
@@ -23,7 +23,7 @@
#include <functional>
#include <boost/range/adaptor/reversed.hpp>
-#include <libdevcore/SHA3.h>
+#include <libdevcore/Keccak256.h>
#include <libevmasm/CommonSubexpressionEliminator.h>
#include <libevmasm/AssemblyItem.h>
diff --git a/libevmasm/KnownState.cpp b/libevmasm/KnownState.cpp
index 7c593fc9..b6c1bcc9 100644
--- a/libevmasm/KnownState.cpp
+++ b/libevmasm/KnownState.cpp
@@ -23,7 +23,7 @@
#include "KnownState.h"
#include <functional>
-#include <libdevcore/SHA3.h>
+#include <libdevcore/Keccak256.h>
#include <libevmasm/AssemblyItem.h>
using namespace std;
diff --git a/libevmasm/LinkerObject.cpp b/libevmasm/LinkerObject.cpp
index a11f2378..6eec54ea 100644
--- a/libevmasm/LinkerObject.cpp
+++ b/libevmasm/LinkerObject.cpp
@@ -21,7 +21,7 @@
#include <libevmasm/LinkerObject.h>
#include <libdevcore/CommonData.h>
-#include <libdevcore/SHA3.h>
+#include <libdevcore/Keccak256.h>
using namespace dev;
using namespace dev::eth;
diff --git a/liblll/CodeFragment.cpp b/liblll/CodeFragment.cpp
index 85480119..f37cb8b9 100644
--- a/liblll/CodeFragment.cpp
+++ b/liblll/CodeFragment.cpp
@@ -45,6 +45,10 @@ using namespace dev::lll;
void CodeFragment::finalise(CompilerState const& _cs)
{
+ // NOTE: add this as a safeguard in case the user didn't issue an
+ // explicit stop at the end of the sequence
+ m_asm.append(Instruction::STOP);
+
if (_cs.usedAlloc && _cs.vars.size() && !m_finalised)
{
m_finalised = true;
@@ -232,7 +236,12 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
int c = 0;
for (auto const& i: _t)
if (c++)
- m_asm.append(CodeFragment(i, _s, m_readFile, true).m_asm);
+ {
+ auto fragment = CodeFragment(i, _s, m_readFile, true).m_asm;
+ if ((m_asm.deposit() + fragment.deposit()) < 0)
+ error<IncorrectParameterCount>("The assembly instruction resulted in stack underflow");
+ m_asm.append(fragment);
+ }
}
else if (us == "INCLUDE")
{
diff --git a/libsolc/CMakeLists.txt b/libsolc/CMakeLists.txt
index 63fc1a83..ed14e9fe 100644
--- a/libsolc/CMakeLists.txt
+++ b/libsolc/CMakeLists.txt
@@ -1,5 +1,5 @@
if (EMSCRIPTEN)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s EXPORTED_FUNCTIONS='[\"_solidity_license\",\"_solidity_version\",\"_solidity_compile\",\"_license\",\"_version\",\"_compileJSON\",\"_compileJSONMulti\",\"_compileJSONCallback\",\"_compileStandard\"]' -s RESERVED_FUNCTION_POINTERS=20")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s EXPORTED_FUNCTIONS='[\"_solidity_license\",\"_solidity_version\",\"_solidity_compile\"]' -s RESERVED_FUNCTION_POINTERS=20")
add_executable(soljson libsolc.cpp)
target_link_libraries(soljson PRIVATE solidity)
else()
diff --git a/libsolc/libsolc.cpp b/libsolc/libsolc.cpp
index 6931ed08..766e1c0c 100644
--- a/libsolc/libsolc.cpp
+++ b/libsolc/libsolc.cpp
@@ -17,7 +17,7 @@
/**
* @author Christian <c@ethdev.com>
* @date 2014
- * JSON interface for the solidity compiler to be used from Javascript.
+ * Public compiler API.
*/
#include <libsolc/libsolc.h>
@@ -72,193 +72,7 @@ ReadCallback::Callback wrapReadCallback(CStyleReadFileCallback _readCallback = n
return readCallback;
}
-/// Translates a gas value as a string to a JSON number or null
-Json::Value gasToJson(Json::Value const& _value)
-{
- if (_value.isObject())
- {
- Json::Value ret = Json::objectValue;
- for (auto const& sig: _value.getMemberNames())
- ret[sig] = gasToJson(_value[sig]);
- return ret;
- }
-
- if (_value == "infinite")
- return Json::Value(Json::nullValue);
-
- u256 value(_value.asString());
- if (value > std::numeric_limits<Json::LargestUInt>::max())
- return Json::Value(Json::nullValue);
- else
- return Json::Value(Json::LargestUInt(value));
-}
-
-Json::Value translateGasEstimates(Json::Value const& estimates)
-{
- Json::Value output(Json::objectValue);
-
- if (estimates["creation"].isObject())
- {
- Json::Value creation(Json::arrayValue);
- creation[0] = gasToJson(estimates["creation"]["executionCost"]);
- creation[1] = gasToJson(estimates["creation"]["codeDepositCost"]);
- output["creation"] = creation;
- }
- else
- output["creation"] = Json::objectValue;
- output["external"] = gasToJson(estimates.get("external", Json::objectValue));
- output["internal"] = gasToJson(estimates.get("internal", Json::objectValue));
-
- return output;
-}
-
-string compile(StringMap const& _sources, bool _optimize, CStyleReadFileCallback _readCallback)
-{
- /// create new JSON input format
- Json::Value input = Json::objectValue;
- input["language"] = "Solidity";
- input["sources"] = Json::objectValue;
- for (auto const& source: _sources)
- {
- input["sources"][source.first] = Json::objectValue;
- input["sources"][source.first]["content"] = source.second;
- }
- input["settings"] = Json::objectValue;
- input["settings"]["optimizer"] = Json::objectValue;
- input["settings"]["optimizer"]["enabled"] = _optimize;
- input["settings"]["optimizer"]["runs"] = 200;
-
- // Enable all SourceUnit-level outputs.
- input["settings"]["outputSelection"]["*"][""][0] = "*";
- // Enable all Contract-level outputs.
- input["settings"]["outputSelection"]["*"]["*"][0] = "*";
-
- StandardCompiler compiler(wrapReadCallback(_readCallback));
- Json::Value ret = compiler.compile(input);
-
- /// transform JSON to match the old format
- // {
- // "errors": [ "Error 1", "Error 2" ],
- // "sourceList": [ "sourcename1", "sourcename2" ],
- // "sources": {
- // "sourcename1": {
- // "AST": {}
- // }
- // },
- // "contracts": {
- // "Contract1": {
- // "interface": "[...abi...]",
- // "bytecode": "ff0011...",
- // "runtimeBytecode": "ff0011",
- // "opcodes": "PUSH 1 POP STOP",
- // "metadata": "{...metadata...}",
- // "functionHashes": {
- // "test(uint256)": "11ff2233"
- // },
- // "gasEstimates": {
- // "creation": [ 224, 42000 ],
- // "external": {
- // "11ff2233": null,
- // "3322ff11": 1234
- // },
- // "internal": {
- // }
- // },
- // "srcmap" = "0:1:2",
- // "srcmapRuntime" = "0:1:2",
- // "assembly" = {}
- // }
- // }
- // }
- Json::Value output = Json::objectValue;
-
- if (ret.isMember("errors"))
- {
- output["errors"] = Json::arrayValue;
- for (auto const& error: ret["errors"])
- output["errors"].append(
- !error["formattedMessage"].empty() ? error["formattedMessage"] : error["message"]
- );
- }
-
- output["sourceList"] = Json::arrayValue;
- for (auto const& source: _sources)
- output["sourceList"].append(source.first);
-
- if (ret.isMember("sources"))
- {
- output["sources"] = Json::objectValue;
- for (auto const& sourceName: ret["sources"].getMemberNames())
- {
- output["sources"][sourceName] = Json::objectValue;
- output["sources"][sourceName]["AST"] = ret["sources"][sourceName]["legacyAST"];
- }
- }
-
- if (ret.isMember("contracts"))
- {
- output["contracts"] = Json::objectValue;
- for (auto const& sourceName: ret["contracts"].getMemberNames())
- for (auto const& contractName: ret["contracts"][sourceName].getMemberNames())
- {
- Json::Value contractInput = ret["contracts"][sourceName][contractName];
- Json::Value contractOutput = Json::objectValue;
- contractOutput["interface"] = jsonCompactPrint(contractInput["abi"]);
- contractOutput["metadata"] = contractInput["metadata"];
- contractOutput["functionHashes"] = contractInput["evm"]["methodIdentifiers"];
- contractOutput["gasEstimates"] = translateGasEstimates(contractInput["evm"]["gasEstimates"]);
- contractOutput["assembly"] = contractInput["evm"]["legacyAssembly"];
- contractOutput["bytecode"] = contractInput["evm"]["bytecode"]["object"];
- contractOutput["opcodes"] = contractInput["evm"]["bytecode"]["opcodes"];
- contractOutput["srcmap"] = contractInput["evm"]["bytecode"]["sourceMap"];
- contractOutput["runtimeBytecode"] = contractInput["evm"]["deployedBytecode"]["object"];
- contractOutput["srcmapRuntime"] = contractInput["evm"]["deployedBytecode"]["sourceMap"];
- output["contracts"][sourceName + ":" + contractName] = contractOutput;
- }
- }
-
- try
- {
- return jsonCompactPrint(output);
- }
- catch (...)
- {
- return "{\"errors\":[\"Unknown error while generating JSON.\"]}";
- }
-}
-
-string compileMulti(string const& _input, bool _optimize, CStyleReadFileCallback _readCallback = nullptr)
-{
- string errors;
- Json::Value input;
- if (!jsonParseStrict(_input, input, &errors))
- {
- Json::Value jsonErrors(Json::arrayValue);
- jsonErrors.append("Error parsing input JSON: " + errors);
- Json::Value output(Json::objectValue);
- output["errors"] = jsonErrors;
- return jsonCompactPrint(output);
- }
- else
- {
- StringMap sources;
- Json::Value jsonSources = input["sources"];
- if (jsonSources.isObject())
- for (auto const& sourceName: jsonSources.getMemberNames())
- sources[sourceName] = jsonSources[sourceName].asString();
- return compile(sources, _optimize, _readCallback);
- }
-}
-
-string compileSingle(string const& _input, bool _optimize)
-{
- StringMap sources;
- sources[""] = _input;
- return compile(sources, _optimize, nullptr);
-}
-
-
-string compileStandardInternal(string const& _input, CStyleReadFileCallback _readCallback = nullptr)
+string compile(string const& _input, CStyleReadFileCallback _readCallback = nullptr)
{
StandardCompiler compiler(wrapReadCallback(_readCallback));
return compiler.compile(_input);
@@ -270,48 +84,18 @@ static string s_outputBuffer;
extern "C"
{
-extern char const* license() noexcept
+extern char const* solidity_license() noexcept
{
static string fullLicenseText = otherLicenses + licenseText;
return fullLicenseText.c_str();
}
-extern char const* version() noexcept
-{
- return VersionString.c_str();
-}
-extern char const* compileJSON(char const* _input, bool _optimize) noexcept
-{
- s_outputBuffer = compileSingle(_input, _optimize);
- return s_outputBuffer.c_str();
-}
-extern char const* compileJSONMulti(char const* _input, bool _optimize) noexcept
-{
- s_outputBuffer = compileMulti(_input, _optimize);
- return s_outputBuffer.c_str();
-}
-extern char const* compileJSONCallback(char const* _input, bool _optimize, CStyleReadFileCallback _readCallback) noexcept
-{
- s_outputBuffer = compileMulti(_input, _optimize, _readCallback);
- return s_outputBuffer.c_str();
-}
-extern char const* compileStandard(char const* _input, CStyleReadFileCallback _readCallback) noexcept
-{
- s_outputBuffer = compileStandardInternal(_input, _readCallback);
- return s_outputBuffer.c_str();
-}
-extern char const* solidity_license() noexcept
-{
- /// todo: make this the default or an alias
- return license();
-}
extern char const* solidity_version() noexcept
{
- /// todo: make this the default or an alias
- return version();
+ return VersionString.c_str();
}
extern char const* solidity_compile(char const* _input, CStyleReadFileCallback _readCallback) noexcept
{
- /// todo: make this the default or an alias
- return compileStandard(_input, _readCallback);
+ s_outputBuffer = compile(_input, _readCallback);
+ return s_outputBuffer.c_str();
}
}
diff --git a/libsolc/libsolc.h b/libsolc/libsolc.h
index e959b758..4b0ec639 100644
--- a/libsolc/libsolc.h
+++ b/libsolc/libsolc.h
@@ -17,7 +17,7 @@
/**
* @author Christian <c@ethdev.com>
* @date 2014
- * JSON interface for the solidity compiler to be used from Javascript.
+ * Public compiler API.
*/
#include <stdbool.h>
@@ -36,13 +36,6 @@ extern "C" {
/// heap-allocated and are free'd by the caller.
typedef void (*CStyleReadFileCallback)(char const* _path, char** o_contents, char** o_error);
-char const* license() SOLC_NOEXCEPT;
-char const* version() SOLC_NOEXCEPT;
-char const* compileJSON(char const* _input, bool _optimize) SOLC_NOEXCEPT;
-char const* compileJSONMulti(char const* _input, bool _optimize) SOLC_NOEXCEPT;
-char const* compileJSONCallback(char const* _input, bool _optimize, CStyleReadFileCallback _readCallback) SOLC_NOEXCEPT;
-char const* compileStandard(char const* _input, CStyleReadFileCallback _readCallback) SOLC_NOEXCEPT;
-
char const* solidity_license() SOLC_NOEXCEPT;
char const* solidity_version() SOLC_NOEXCEPT;
char const* solidity_compile(char const* _input, CStyleReadFileCallback _readCallback) SOLC_NOEXCEPT;
diff --git a/libsolidity/analysis/ControlFlowAnalyzer.cpp b/libsolidity/analysis/ControlFlowAnalyzer.cpp
index ab6569be..8a608552 100644
--- a/libsolidity/analysis/ControlFlowAnalyzer.cpp
+++ b/libsolidity/analysis/ControlFlowAnalyzer.cpp
@@ -28,8 +28,11 @@ bool ControlFlowAnalyzer::analyze(ASTNode const& _astRoot)
bool ControlFlowAnalyzer::visit(FunctionDefinition const& _function)
{
- auto const& functionFlow = m_cfg.functionFlow(_function);
- checkUnassignedStorageReturnValues(_function, functionFlow.entry, functionFlow.exit);
+ if (_function.isImplemented())
+ {
+ auto const& functionFlow = m_cfg.functionFlow(_function);
+ checkUnassignedStorageReturnValues(_function, functionFlow.entry, functionFlow.exit);
+ }
return false;
}
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 3774cf86..c5e6488b 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -582,7 +582,7 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
if (!actualType->fullEncodingType(false, _abiEncoderV2, false))
m_errorReporter.typeError(
typeArgument->location(),
- "Decoding type " + actualType->toString(false) + " not supported."
+ "Decoding type " + actualType->toString(false) + " not supported."
);
components.push_back(actualType);
}
@@ -1681,352 +1681,570 @@ void TypeChecker::endVisit(BinaryOperation const& _operation)
}
}
-bool TypeChecker::visit(FunctionCall const& _functionCall)
+TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
+ FunctionCall const& _functionCall
+)
{
- bool isPositionalCall = _functionCall.names().empty();
- vector<ASTPointer<Expression const>> arguments = _functionCall.arguments();
- vector<ASTPointer<ASTString>> const& argumentNames = _functionCall.names();
-
- bool isPure = true;
-
- // We need to check arguments' type first as they will be needed for overload resolution.
- shared_ptr<TypePointers> argumentTypes;
- if (isPositionalCall)
- argumentTypes = make_shared<TypePointers>();
- for (ASTPointer<Expression const> const& argument: arguments)
- {
- argument->accept(*this);
- if (!argument->annotation().isPure)
- isPure = false;
- // only store them for positional calls
- if (isPositionalCall)
- argumentTypes->push_back(type(*argument));
- }
- if (isPositionalCall)
- _functionCall.expression().annotation().argumentTypes = move(argumentTypes);
+ solAssert(_functionCall.annotation().kind == FunctionCallKind::TypeConversion, "");
+ TypePointer const& expressionType = type(_functionCall.expression());
- _functionCall.expression().accept(*this);
- TypePointer expressionType = type(_functionCall.expression());
+ vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments();
+ bool const isPositionalCall = _functionCall.names().empty();
- if (auto const* typeType = dynamic_cast<TypeType const*>(expressionType.get()))
- {
- if (typeType->actualType()->category() == Type::Category::Struct)
- _functionCall.annotation().kind = FunctionCallKind::StructConstructorCall;
- else
- _functionCall.annotation().kind = FunctionCallKind::TypeConversion;
-
- }
+ TypePointer resultType = dynamic_cast<TypeType const&>(*expressionType).actualType();
+ if (arguments.size() != 1)
+ m_errorReporter.typeError(
+ _functionCall.location(),
+ "Exactly one argument expected for explicit type conversion."
+ );
+ else if (!isPositionalCall)
+ m_errorReporter.typeError(
+ _functionCall.location(),
+ "Type conversion cannot allow named arguments."
+ );
else
- _functionCall.annotation().kind = FunctionCallKind::FunctionCall;
- solAssert(_functionCall.annotation().kind != FunctionCallKind::Unset, "");
-
- if (_functionCall.annotation().kind == FunctionCallKind::TypeConversion)
{
- TypeType const& t = dynamic_cast<TypeType const&>(*expressionType);
- TypePointer resultType = t.actualType();
- if (arguments.size() != 1)
- m_errorReporter.typeError(_functionCall.location(), "Exactly one argument expected for explicit type conversion.");
- else if (!isPositionalCall)
- m_errorReporter.typeError(_functionCall.location(), "Type conversion cannot allow named arguments.");
- else
+ TypePointer const& argType = type(*arguments.front());
+ // Resulting data location is memory unless we are converting from a reference
+ // type with a different data location.
+ // (data location cannot yet be specified for type conversions)
+ DataLocation dataLoc = DataLocation::Memory;
+ if (auto argRefType = dynamic_cast<ReferenceType const*>(argType.get()))
+ dataLoc = argRefType->location();
+ if (auto type = dynamic_cast<ReferenceType const*>(resultType.get()))
+ resultType = type->copyForLocation(dataLoc, type->isPointer());
+ if (argType->isExplicitlyConvertibleTo(*resultType))
{
- TypePointer const& argType = type(*arguments.front());
- // Resulting data location is memory unless we are converting from a reference
- // type with a different data location.
- // (data location cannot yet be specified for type conversions)
- DataLocation dataLoc = DataLocation::Memory;
- if (auto argRefType = dynamic_cast<ReferenceType const*>(argType.get()))
- dataLoc = argRefType->location();
- if (auto type = dynamic_cast<ReferenceType const*>(resultType.get()))
- resultType = type->copyForLocation(dataLoc, type->isPointer());
- if (argType->isExplicitlyConvertibleTo(*resultType))
- {
- if (auto argArrayType = dynamic_cast<ArrayType const*>(argType.get()))
- {
- auto resultArrayType = dynamic_cast<ArrayType const*>(resultType.get());
- solAssert(!!resultArrayType, "");
- solAssert(
- argArrayType->location() != DataLocation::Storage ||
- ((resultArrayType->isPointer() || (argArrayType->isByteArray() && resultArrayType->isByteArray())) &&
- resultArrayType->location() == DataLocation::Storage),
- "Invalid explicit conversion to storage type."
- );
- }
- }
- else
+ if (auto argArrayType = dynamic_cast<ArrayType const*>(argType.get()))
{
- if (resultType->category() == Type::Category::Contract && argType->category() == Type::Category::Address)
- {
- solAssert(dynamic_cast<ContractType const*>(resultType.get())->isPayable(), "");
- solAssert(dynamic_cast<AddressType const*>(argType.get())->stateMutability() < StateMutability::Payable, "");
- SecondarySourceLocation ssl;
- if (auto const* identifier = dynamic_cast<Identifier const*>(arguments.front().get()))
- if (auto const* variableDeclaration = dynamic_cast<VariableDeclaration const*>(identifier->annotation().referencedDeclaration))
- ssl.append("Did you mean to declare this variable as \"address payable\"?", variableDeclaration->location());
- m_errorReporter.typeError(
- _functionCall.location(), ssl,
- "Explicit type conversion not allowed from non-payable \"address\" to \"" +
- resultType->toString() +
- "\", which has a payable fallback function."
- );
- }
- else
- m_errorReporter.typeError(
- _functionCall.location(),
- "Explicit type conversion not allowed from \"" +
- argType->toString() +
- "\" to \"" +
- resultType->toString() +
- "\"."
- );
+ auto resultArrayType = dynamic_cast<ArrayType const*>(resultType.get());
+ solAssert(!!resultArrayType, "");
+ solAssert(
+ argArrayType->location() != DataLocation::Storage ||
+ (
+ (
+ resultArrayType->isPointer() ||
+ (argArrayType->isByteArray() && resultArrayType->isByteArray())
+ ) &&
+ resultArrayType->location() == DataLocation::Storage
+ ),
+ "Invalid explicit conversion to storage type."
+ );
}
- if (resultType->category() == Type::Category::Address)
+ }
+ else
+ {
+ if (
+ resultType->category() == Type::Category::Contract &&
+ argType->category() == Type::Category::Address
+ )
{
- bool payable = argType->isExplicitlyConvertibleTo(AddressType::addressPayable());
- resultType = make_shared<AddressType>(payable ? StateMutability::Payable : StateMutability::NonPayable);
+ solAssert(dynamic_cast<ContractType const*>(resultType.get())->isPayable(), "");
+ solAssert(
+ dynamic_cast<AddressType const*>(argType.get())->stateMutability() <
+ StateMutability::Payable,
+ ""
+ );
+ SecondarySourceLocation ssl;
+ if (
+ auto const* identifier = dynamic_cast<Identifier const*>(arguments.front().get())
+ )
+ if (
+ auto const* variableDeclaration = dynamic_cast<VariableDeclaration const*>(
+ identifier->annotation().referencedDeclaration
+ )
+ )
+ ssl.append(
+ "Did you mean to declare this variable as \"address payable\"?",
+ variableDeclaration->location()
+ );
+ m_errorReporter.typeError(
+ _functionCall.location(), ssl,
+ "Explicit type conversion not allowed from non-payable \"address\" to \"" +
+ resultType->toString() +
+ "\", which has a payable fallback function."
+ );
}
+ else
+ m_errorReporter.typeError(
+ _functionCall.location(),
+ "Explicit type conversion not allowed from \"" +
+ argType->toString() +
+ "\" to \"" +
+ resultType->toString() +
+ "\"."
+ );
+ }
+ if (resultType->category() == Type::Category::Address)
+ {
+ bool const payable = argType->isExplicitlyConvertibleTo(AddressType::addressPayable());
+ resultType = make_shared<AddressType>(
+ payable ? StateMutability::Payable : StateMutability::NonPayable
+ );
}
- _functionCall.annotation().type = resultType;
- _functionCall.annotation().isPure = isPure;
-
- return false;
}
+ return resultType;
+}
+void TypeChecker::typeCheckFunctionCall(
+ FunctionCall const& _functionCall,
+ FunctionTypePointer _functionType
+)
+{
// Actual function call or struct constructor call.
- FunctionTypePointer functionType;
+ solAssert(!!_functionType, "");
+ solAssert(_functionType->kind() != FunctionType::Kind::ABIDecode, "");
- /// For error message: Struct members that were removed during conversion to memory.
- set<string> membersRemovedForStructConstructor;
- if (_functionCall.annotation().kind == FunctionCallKind::StructConstructorCall)
+ // Check for unsupported use of bare static call
+ if (
+ _functionType->kind() == FunctionType::Kind::BareStaticCall &&
+ !m_evmVersion.hasStaticCall()
+ )
+ m_errorReporter.typeError(
+ _functionCall.location(),
+ "\"staticcall\" is not supported by the VM version."
+ );
+
+ // Check for deprecated function names
+ if (_functionType->kind() == FunctionType::Kind::KECCAK256)
{
- TypeType const& t = dynamic_cast<TypeType const&>(*expressionType);
- auto const& structType = dynamic_cast<StructType const&>(*t.actualType());
- functionType = structType.constructorType();
- membersRemovedForStructConstructor = structType.membersMissingInMemory();
- _functionCall.annotation().isPure = isPure;
+ if (auto functionName = dynamic_cast<Identifier const*>(&_functionCall.expression()))
+ if (functionName->name() == "sha3")
+ m_errorReporter.typeError(
+ _functionCall.location(),
+ "\"sha3\" has been deprecated in favour of \"keccak256\""
+ );
}
- else if ((functionType = dynamic_pointer_cast<FunctionType const>(expressionType)))
- _functionCall.annotation().isPure =
- isPure &&
- _functionCall.expression().annotation().isPure &&
- functionType->isPure();
-
- bool allowDynamicTypes = m_evmVersion.supportsReturndata();
- if (!functionType)
+ else if (_functionType->kind() == FunctionType::Kind::Selfdestruct)
{
- m_errorReporter.typeError(_functionCall.location(), "Type is not callable");
- _functionCall.annotation().type = make_shared<TupleType>();
- return false;
+ if (auto functionName = dynamic_cast<Identifier const*>(&_functionCall.expression()))
+ if (functionName->name() == "suicide")
+ m_errorReporter.typeError(
+ _functionCall.location(),
+ "\"suicide\" has been deprecated in favour of \"selfdestruct\""
+ );
}
- if (functionType->kind() == FunctionType::Kind::BareStaticCall && !m_evmVersion.hasStaticCall())
- m_errorReporter.typeError(_functionCall.location(), "\"staticcall\" is not supported by the VM version.");
+ // Check for event outside of emit statement
+ if (!m_insideEmitStatement && _functionType->kind() == FunctionType::Kind::Event)
+ m_errorReporter.typeError(
+ _functionCall.location(),
+ "Event invocations have to be prefixed by \"emit\"."
+ );
+
+ // Perform standard function call type checking
+ typeCheckFunctionGeneralChecks(_functionCall, _functionType);
+}
+
+void TypeChecker::typeCheckABIEncodeFunctions(
+ FunctionCall const& _functionCall,
+ FunctionTypePointer _functionType
+)
+{
+ solAssert(!!_functionType, "");
+ solAssert(
+ _functionType->kind() == FunctionType::Kind::ABIEncode ||
+ _functionType->kind() == FunctionType::Kind::ABIEncodePacked ||
+ _functionType->kind() == FunctionType::Kind::ABIEncodeWithSelector ||
+ _functionType->kind() == FunctionType::Kind::ABIEncodeWithSignature,
+ "ABI function has unexpected FunctionType::Kind."
+ );
+ solAssert(_functionType->takesArbitraryParameters(), "ABI functions should be variadic.");
- if (auto functionName = dynamic_cast<Identifier const*>(&_functionCall.expression()))
+ bool const isPacked = _functionType->kind() == FunctionType::Kind::ABIEncodePacked;
+ solAssert(_functionType->padArguments() != isPacked, "ABI function with unexpected padding");
+
+ bool const abiEncoderV2 = m_scope->sourceUnit().annotation().experimentalFeatures.count(
+ ExperimentalFeature::ABIEncoderV2
+ );
+
+ // Check for named arguments
+ if (!_functionCall.names().empty())
{
- if (functionName->name() == "sha3" && functionType->kind() == FunctionType::Kind::KECCAK256)
- m_errorReporter.typeError(_functionCall.location(), "\"sha3\" has been deprecated in favour of \"keccak256\"");
- else if (functionName->name() == "suicide" && functionType->kind() == FunctionType::Kind::Selfdestruct)
- m_errorReporter.typeError(_functionCall.location(), "\"suicide\" has been deprecated in favour of \"selfdestruct\"");
+ m_errorReporter.typeError(
+ _functionCall.location(),
+ "Named arguments cannot be used for functions that take arbitrary parameters."
+ );
+ return;
}
- if (!m_insideEmitStatement && functionType->kind() == FunctionType::Kind::Event)
- m_errorReporter.typeError(_functionCall.location(), "Event invocations have to be prefixed by \"emit\".");
- TypePointers parameterTypes = functionType->parameterTypes();
+ // Perform standard function call type checking
+ typeCheckFunctionGeneralChecks(_functionCall, _functionType);
- if (!functionType->padArguments())
+ // Check additional arguments for variadic functions
+ vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments();
+ for (size_t i = 0; i < arguments.size(); ++i)
{
- for (size_t i = 0; i < arguments.size(); ++i)
+ auto const& argType = type(*arguments[i]);
+
+ if (argType->category() == Type::Category::RationalNumber)
{
- auto const& argType = type(*arguments[i]);
- if (auto literal = dynamic_cast<RationalNumberType const*>(argType.get()))
+ if (!argType->mobileType())
{
- if (literal->mobileType())
- m_errorReporter.typeError(
- arguments[i]->location(),
- "Cannot perform packed encoding for a literal. Please convert it to an explicit type first."
- );
- else
- {
- /* If no mobile type is available an error will be raised elsewhere. */
- solAssert(m_errorReporter.hasErrors(), "");
- }
+ m_errorReporter.typeError(
+ arguments[i]->location(),
+ "Invalid rational number (too large or division by zero)."
+ );
+ continue;
+ }
+ else if (isPacked)
+ {
+ m_errorReporter.typeError(
+ arguments[i]->location(),
+ "Cannot perform packed encoding for a literal."
+ " Please convert it to an explicit type first."
+ );
+ continue;
}
}
+
+ if (!argType->fullEncodingType(false, abiEncoderV2, !_functionType->padArguments()))
+ m_errorReporter.typeError(
+ arguments[i]->location(),
+ "This type cannot be encoded."
+ );
}
+}
- bool const abiEncoderV2 = m_scope->sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2);
+void TypeChecker::typeCheckFunctionGeneralChecks(
+ FunctionCall const& _functionCall,
+ FunctionTypePointer _functionType
+)
+{
+ // Actual function call or struct constructor call.
- // Will be assigned to .type at the end (turning multi-elements into a tuple).
- TypePointers returnTypes =
- allowDynamicTypes ?
- functionType->returnParameterTypes() :
- functionType->returnParameterTypesWithoutDynamicTypes();
+ solAssert(!!_functionType, "");
+ solAssert(_functionType->kind() != FunctionType::Kind::ABIDecode, "");
- if (functionType->kind() == FunctionType::Kind::ABIDecode)
- returnTypes = typeCheckABIDecodeAndRetrieveReturnType(_functionCall, abiEncoderV2);
- else if (functionType->takesArbitraryParameters() && arguments.size() < parameterTypes.size())
- {
- solAssert(_functionCall.annotation().kind == FunctionCallKind::FunctionCall, "");
- m_errorReporter.typeError(
- _functionCall.location(),
- "Need at least " +
- toString(parameterTypes.size()) +
- " arguments for function call, but provided only " +
- toString(arguments.size()) +
- "."
- );
- }
- else if (!functionType->takesArbitraryParameters() && parameterTypes.size() != arguments.size())
+ bool const isPositionalCall = _functionCall.names().empty();
+ bool const isVariadic = _functionType->takesArbitraryParameters();
+
+ solAssert(
+ !isVariadic || _functionCall.annotation().kind == FunctionCallKind::FunctionCall,
+ "Struct constructor calls cannot be variadic."
+ );
+
+ TypePointers const& parameterTypes = _functionType->parameterTypes();
+ vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments();
+ vector<ASTPointer<ASTString>> const& argumentNames = _functionCall.names();
+
+ // Check number of passed in arguments
+ if (
+ arguments.size() < parameterTypes.size() ||
+ (!isVariadic && arguments.size() > parameterTypes.size())
+ )
{
- bool isStructConstructorCall = _functionCall.annotation().kind == FunctionCallKind::StructConstructorCall;
+ bool const isStructConstructorCall =
+ _functionCall.annotation().kind == FunctionCallKind::StructConstructorCall;
+
+ string msg;
+
+ if (isVariadic)
+ msg +=
+ "Need at least " +
+ toString(parameterTypes.size()) +
+ " arguments for " +
+ string(isStructConstructorCall ? "struct constructor" : "function call") +
+ ", but provided only " +
+ toString(arguments.size()) +
+ ".";
+ else
+ msg +=
+ "Wrong argument count for " +
+ string(isStructConstructorCall ? "struct constructor" : "function call") +
+ ": " +
+ toString(arguments.size()) +
+ " arguments given but " +
+ string(isVariadic ? "need at least " : "expected ") +
+ toString(parameterTypes.size()) +
+ ".";
- string msg =
- "Wrong argument count for " +
- string(isStructConstructorCall ? "struct constructor" : "function call") +
- ": " +
- toString(arguments.size()) +
- " arguments given but expected " +
- toString(parameterTypes.size()) +
- ".";
// Extend error message in case we try to construct a struct with mapping member.
- if (_functionCall.annotation().kind == FunctionCallKind::StructConstructorCall && !membersRemovedForStructConstructor.empty())
+ if (isStructConstructorCall)
{
- msg += " Members that have to be skipped in memory:";
- for (auto const& member: membersRemovedForStructConstructor)
- msg += " " + member;
+ /// For error message: Struct members that were removed during conversion to memory.
+ TypePointer const expressionType = type(_functionCall.expression());
+ TypeType const& t = dynamic_cast<TypeType const&>(*expressionType);
+ auto const& structType = dynamic_cast<StructType const&>(*t.actualType());
+ set<string> membersRemovedForStructConstructor = structType.membersMissingInMemory();
+
+ if (!membersRemovedForStructConstructor.empty())
+ {
+ msg += " Members that have to be skipped in memory:";
+ for (auto const& member: membersRemovedForStructConstructor)
+ msg += " " + member;
+ }
}
else if (
- functionType->kind() == FunctionType::Kind::BareCall ||
- functionType->kind() == FunctionType::Kind::BareCallCode ||
- functionType->kind() == FunctionType::Kind::BareDelegateCall ||
- functionType->kind() == FunctionType::Kind::BareStaticCall
+ _functionType->kind() == FunctionType::Kind::BareCall ||
+ _functionType->kind() == FunctionType::Kind::BareCallCode ||
+ _functionType->kind() == FunctionType::Kind::BareDelegateCall ||
+ _functionType->kind() == FunctionType::Kind::BareStaticCall
)
{
if (arguments.empty())
- msg += " This function requires a single bytes argument. Use \"\" as argument to provide empty calldata.";
+ msg +=
+ " This function requires a single bytes argument."
+ " Use \"\" as argument to provide empty calldata.";
else
- msg += " This function requires a single bytes argument. If all your arguments are value types, you can use abi.encode(...) to properly generate it.";
+ msg +=
+ " This function requires a single bytes argument."
+ " If all your arguments are value types, you can use"
+ " abi.encode(...) to properly generate it.";
}
else if (
- functionType->kind() == FunctionType::Kind::KECCAK256 ||
- functionType->kind() == FunctionType::Kind::SHA256 ||
- functionType->kind() == FunctionType::Kind::RIPEMD160
+ _functionType->kind() == FunctionType::Kind::KECCAK256 ||
+ _functionType->kind() == FunctionType::Kind::SHA256 ||
+ _functionType->kind() == FunctionType::Kind::RIPEMD160
)
msg +=
" This function requires a single bytes argument."
- " Use abi.encodePacked(...) to obtain the pre-0.5.0 behaviour"
- " or abi.encode(...) to use ABI encoding.";
+ " Use abi.encodePacked(...) to obtain the pre-0.5.0"
+ " behaviour or abi.encode(...) to use ABI encoding.";
m_errorReporter.typeError(_functionCall.location(), msg);
+ return;
}
- else if (isPositionalCall)
- {
- for (size_t i = 0; i < arguments.size(); ++i)
- {
- auto const& argType = type(*arguments[i]);
- if (functionType->takesArbitraryParameters() && i >= parameterTypes.size())
- {
- bool errored = false;
- if (auto t = dynamic_cast<RationalNumberType const*>(argType.get()))
- if (!t->mobileType())
- {
- m_errorReporter.typeError(arguments[i]->location(), "Invalid rational number (too large or division by zero).");
- errored = true;
- }
- if (!errored && !argType->fullEncodingType(false, abiEncoderV2, !functionType->padArguments()))
- m_errorReporter.typeError(arguments[i]->location(), "This type cannot be encoded.");
- }
- else if (!type(*arguments[i])->isImplicitlyConvertibleTo(*parameterTypes[i]))
- {
- string msg =
- "Invalid type for argument in function call. "
- "Invalid implicit conversion from " +
- type(*arguments[i])->toString() +
- " to " +
- parameterTypes[i]->toString() +
- " requested.";
- if (
- functionType->kind() == FunctionType::Kind::BareCall ||
- functionType->kind() == FunctionType::Kind::BareCallCode ||
- functionType->kind() == FunctionType::Kind::BareDelegateCall ||
- functionType->kind() == FunctionType::Kind::BareStaticCall
- )
- msg += " This function requires a single bytes argument. If all your arguments are value types, you can use abi.encode(...) to properly generate it.";
- else if (
- functionType->kind() == FunctionType::Kind::KECCAK256 ||
- functionType->kind() == FunctionType::Kind::SHA256 ||
- functionType->kind() == FunctionType::Kind::RIPEMD160
- )
- msg +=
- " This function requires a single bytes argument."
- " Use abi.encodePacked(...) to obtain the pre-0.5.0 behaviour"
- " or abi.encode(...) to use ABI encoding.";
- m_errorReporter.typeError(arguments[i]->location(), msg);
- }
- }
- }
+
+ // Parameter to argument map
+ std::vector<Expression const*> paramArgMap(parameterTypes.size());
+
+ // Map parameters to arguments - trivially for positional calls, less so for named calls
+ if (isPositionalCall)
+ for (size_t i = 0; i < paramArgMap.size(); ++i)
+ paramArgMap[i] = arguments[i].get();
else
{
- // call by named arguments
- auto const& parameterNames = functionType->parameterNames();
- if (functionType->takesArbitraryParameters())
+ auto const& parameterNames = _functionType->parameterNames();
+
+ // Check for expected number of named arguments
+ if (parameterNames.size() != argumentNames.size())
+ {
m_errorReporter.typeError(
_functionCall.location(),
- "Named arguments cannot be used for functions that take arbitrary parameters."
+ parameterNames.size() > argumentNames.size() ?
+ "Some argument names are missing." :
+ "Too many arguments."
);
- else if (parameterNames.size() > argumentNames.size())
- m_errorReporter.typeError(_functionCall.location(), "Some argument names are missing.");
- else if (parameterNames.size() < argumentNames.size())
- m_errorReporter.typeError(_functionCall.location(), "Too many arguments.");
- else
+ return;
+ }
+
+ // Check for duplicate argument names
{
- // check duplicate names
bool duplication = false;
for (size_t i = 0; i < argumentNames.size(); i++)
for (size_t j = i + 1; j < argumentNames.size(); j++)
if (*argumentNames[i] == *argumentNames[j])
{
duplication = true;
- m_errorReporter.typeError(arguments[i]->location(), "Duplicate named argument.");
+ m_errorReporter.typeError(
+ arguments[i]->location(),
+ "Duplicate named argument \"" + *argumentNames[i] + "\"."
+ );
}
+ if (duplication)
+ return;
+ }
+
+ // map parameter names to argument names
+ {
+ bool not_all_mapped = false;
- // check actual types
- if (!duplication)
- for (size_t i = 0; i < argumentNames.size(); i++)
+ for (size_t i = 0; i < paramArgMap.size(); i++)
+ {
+ size_t j;
+ for (j = 0; j < argumentNames.size(); j++)
+ if (parameterNames[i] == *argumentNames[j])
+ break;
+
+ if (j < argumentNames.size())
+ paramArgMap[i] = arguments[j].get();
+ else
{
- bool found = false;
- for (size_t j = 0; j < parameterNames.size(); j++)
- if (parameterNames[j] == *argumentNames[i])
- {
- found = true;
- // check type convertible
- if (!type(*arguments[i])->isImplicitlyConvertibleTo(*parameterTypes[j]))
- m_errorReporter.typeError(
- arguments[i]->location(),
- "Invalid type for argument in function call. "
- "Invalid implicit conversion from " +
- type(*arguments[i])->toString() +
- " to " +
- parameterTypes[i]->toString() +
- " requested."
- );
- break;
- }
-
- if (!found)
- m_errorReporter.typeError(
- _functionCall.location(),
- "Named argument \"" + *argumentNames[i] + "\" does not match function declaration."
- );
+ paramArgMap[i] = nullptr;
+ not_all_mapped = true;
+ m_errorReporter.typeError(
+ _functionCall.location(),
+ "Named argument \"" +
+ *argumentNames[i] +
+ "\" does not match function declaration."
+ );
}
+ }
+
+ if (not_all_mapped)
+ return;
}
}
- if (returnTypes.size() == 1)
- _functionCall.annotation().type = returnTypes.front();
- else
- _functionCall.annotation().type = make_shared<TupleType>(returnTypes);
+ // Check for compatible types between arguments and parameters
+ for (size_t i = 0; i < paramArgMap.size(); ++i)
+ {
+ solAssert(!!paramArgMap[i], "unmapped parameter");
+ if (!type(*paramArgMap[i])->isImplicitlyConvertibleTo(*parameterTypes[i]))
+ {
+ string msg =
+ "Invalid type for argument in function call. "
+ "Invalid implicit conversion from " +
+ type(*paramArgMap[i])->toString() +
+ " to " +
+ parameterTypes[i]->toString() +
+ " requested.";
+ if (
+ _functionType->kind() == FunctionType::Kind::BareCall ||
+ _functionType->kind() == FunctionType::Kind::BareCallCode ||
+ _functionType->kind() == FunctionType::Kind::BareDelegateCall ||
+ _functionType->kind() == FunctionType::Kind::BareStaticCall
+ )
+ msg +=
+ " This function requires a single bytes argument."
+ " If all your arguments are value types, you can"
+ " use abi.encode(...) to properly generate it.";
+ else if (
+ _functionType->kind() == FunctionType::Kind::KECCAK256 ||
+ _functionType->kind() == FunctionType::Kind::SHA256 ||
+ _functionType->kind() == FunctionType::Kind::RIPEMD160
+ )
+ msg +=
+ " This function requires a single bytes argument."
+ " Use abi.encodePacked(...) to obtain the pre-0.5.0"
+ " behaviour or abi.encode(...) to use ABI encoding.";
+ m_errorReporter.typeError(paramArgMap[i]->location(), msg);
+ }
+ }
+}
+
+bool TypeChecker::visit(FunctionCall const& _functionCall)
+{
+ vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments();
+ bool argumentsArePure = true;
+
+ // We need to check arguments' type first as they will be needed for overload resolution.
+ for (ASTPointer<Expression const> const& argument: arguments)
+ {
+ argument->accept(*this);
+ if (!argument->annotation().isPure)
+ argumentsArePure = false;
+ }
+
+ // For positional calls only, store argument types
+ if (_functionCall.names().empty())
+ {
+ shared_ptr<TypePointers> argumentTypes = make_shared<TypePointers>();
+ for (ASTPointer<Expression const> const& argument: arguments)
+ argumentTypes->push_back(type(*argument));
+ _functionCall.expression().annotation().argumentTypes = move(argumentTypes);
+ }
+
+ _functionCall.expression().accept(*this);
+
+ TypePointer const& expressionType = type(_functionCall.expression());
+
+ // Determine function call kind and function type for this FunctionCall node
+ FunctionCallAnnotation& funcCallAnno = _functionCall.annotation();
+ FunctionTypePointer functionType;
+
+ // Determine and assign function call kind, purity and function type for this FunctionCall node
+ switch (expressionType->category())
+ {
+ case Type::Category::Function:
+ functionType = dynamic_pointer_cast<FunctionType const>(expressionType);
+ funcCallAnno.kind = FunctionCallKind::FunctionCall;
+
+ // Purity for function calls also depends upon the callee and its FunctionType
+ funcCallAnno.isPure =
+ argumentsArePure &&
+ _functionCall.expression().annotation().isPure &&
+ functionType &&
+ functionType->isPure();
+
+ break;
+
+ case Type::Category::TypeType:
+ {
+ // Determine type for type conversion or struct construction expressions
+ TypePointer const& actualType = dynamic_cast<TypeType const&>(*expressionType).actualType();
+ solAssert(!!actualType, "");
+
+ if (actualType->category() == Type::Category::Struct)
+ {
+ functionType = dynamic_cast<StructType const&>(*actualType).constructorType();
+ funcCallAnno.kind = FunctionCallKind::StructConstructorCall;
+ funcCallAnno.isPure = argumentsArePure;
+ }
+ else
+ {
+ funcCallAnno.kind = FunctionCallKind::TypeConversion;
+ funcCallAnno.isPure = argumentsArePure;
+ }
+
+ break;
+ }
+
+ default:
+ m_errorReporter.typeError(_functionCall.location(), "Type is not callable");
+ funcCallAnno.kind = FunctionCallKind::Unset;
+ funcCallAnno.isPure = argumentsArePure;
+ break;
+ }
+
+ // Determine return types
+ switch (funcCallAnno.kind)
+ {
+ case FunctionCallKind::TypeConversion:
+ funcCallAnno.type = typeCheckTypeConversionAndRetrieveReturnType(_functionCall);
+ break;
+
+ case FunctionCallKind::StructConstructorCall: // fall-through
+ case FunctionCallKind::FunctionCall:
+ {
+ TypePointers returnTypes;
+
+ switch (functionType->kind())
+ {
+ case FunctionType::Kind::ABIDecode:
+ {
+ bool const abiEncoderV2 =
+ m_scope->sourceUnit().annotation().experimentalFeatures.count(
+ ExperimentalFeature::ABIEncoderV2
+ );
+ returnTypes = typeCheckABIDecodeAndRetrieveReturnType(_functionCall, abiEncoderV2);
+ break;
+ }
+ case FunctionType::Kind::ABIEncode:
+ case FunctionType::Kind::ABIEncodePacked:
+ case FunctionType::Kind::ABIEncodeWithSelector:
+ case FunctionType::Kind::ABIEncodeWithSignature:
+ {
+ typeCheckABIEncodeFunctions(_functionCall, functionType);
+ returnTypes = functionType->returnParameterTypes();
+ break;
+ }
+ default:
+ {
+ typeCheckFunctionCall(_functionCall, functionType);
+ returnTypes = m_evmVersion.supportsReturndata() ?
+ functionType->returnParameterTypes() :
+ functionType->returnParameterTypesWithoutDynamicTypes();
+ break;
+ }
+ }
+
+ funcCallAnno.type = returnTypes.size() == 1 ?
+ move(returnTypes.front()) :
+ make_shared<TupleType>(move(returnTypes));
+
+ break;
+ }
+
+ case FunctionCallKind::Unset: // fall-through
+ default:
+ // for non-callables, ensure error reported and annotate node to void function
+ solAssert(m_errorReporter.hasErrors(), "");
+ funcCallAnno.kind = FunctionCallKind::FunctionCall;
+ funcCallAnno.type = make_shared<TupleType>();
+ break;
+ }
return false;
}
diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h
index 6ea99ca2..c76fa466 100644
--- a/libsolidity/analysis/TypeChecker.h
+++ b/libsolidity/analysis/TypeChecker.h
@@ -94,7 +94,33 @@ private:
/// Performs type checks for ``abi.decode(bytes memory, (...))`` and returns the
/// vector of return types (which is basically the second argument) if successful. It returns
/// the empty vector on error.
- TypePointers typeCheckABIDecodeAndRetrieveReturnType(FunctionCall const& _functionCall, bool _abiEncoderV2);
+ TypePointers typeCheckABIDecodeAndRetrieveReturnType(
+ FunctionCall const& _functionCall,
+ bool _abiEncoderV2
+ );
+
+ /// Performs type checks and determines result types for type conversion FunctionCall nodes.
+ TypePointer typeCheckTypeConversionAndRetrieveReturnType(
+ FunctionCall const& _functionCall
+ );
+
+ /// Performs type checks on function call and struct ctor FunctionCall nodes (except for kind ABIDecode).
+ void typeCheckFunctionCall(
+ FunctionCall const& _functionCall,
+ FunctionTypePointer _functionType
+ );
+
+ /// Performs general number and type checks of arguments against function call and struct ctor FunctionCall node parameters.
+ void typeCheckFunctionGeneralChecks(
+ FunctionCall const& _functionCall,
+ FunctionTypePointer _functionType
+ );
+
+ /// Performs general checks and checks specific to ABI encode functions
+ void typeCheckABIEncodeFunctions(
+ FunctionCall const& _functionCall,
+ FunctionTypePointer _functionType
+ );
virtual void endVisit(InheritanceSpecifier const& _inheritance) override;
virtual void endVisit(UsingForDirective const& _usingFor) override;
diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp
index d9264230..3ae6bd6d 100644
--- a/libsolidity/ast/AST.cpp
+++ b/libsolidity/ast/AST.cpp
@@ -24,7 +24,7 @@
#include <libsolidity/ast/ASTVisitor.h>
#include <libsolidity/ast/AST_accept.h>
-#include <libdevcore/SHA3.h>
+#include <libdevcore/Keccak256.h>
#include <boost/algorithm/string.hpp>
diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h
index d819402e..4fd2bcb8 100644
--- a/libsolidity/ast/AST.h
+++ b/libsolidity/ast/AST.h
@@ -1191,11 +1191,11 @@ public:
Statement const& body() const { return *m_body; }
private:
- /// For statement's initialization expression. for(XXX; ; ). Can be empty
+ /// For statement's initialization expression. for (XXX; ; ). Can be empty
ASTPointer<Statement> m_initExpression;
- /// For statement's condition expression. for(; XXX ; ). Can be empty
+ /// For statement's condition expression. for (; XXX ; ). Can be empty
ASTPointer<Expression> m_condExpression;
- /// For statement's loop expression. for(;;XXX). Can be empty
+ /// For statement's loop expression. for (;;XXX). Can be empty
ASTPointer<ExpressionStatement> m_loopExpression;
/// The body of the loop
ASTPointer<Statement> m_body;
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index 6c3863e6..4b31d2e8 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -26,7 +26,7 @@
#include <libdevcore/CommonIO.h>
#include <libdevcore/CommonData.h>
-#include <libdevcore/SHA3.h>
+#include <libdevcore/Keccak256.h>
#include <libdevcore/UTF8.h>
#include <libdevcore/Algorithms.h>
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 63faddd3..bdf91fbf 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -25,7 +25,7 @@
#include <boost/range/adaptor/reversed.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <libdevcore/Common.h>
-#include <libdevcore/SHA3.h>
+#include <libdevcore/Keccak256.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/codegen/ExpressionCompiler.h>
#include <libsolidity/codegen/CompilerContext.h>
diff --git a/libsolidity/formal/SMTChecker.cpp b/libsolidity/formal/SMTChecker.cpp
index 51b310ae..cc580021 100644
--- a/libsolidity/formal/SMTChecker.cpp
+++ b/libsolidity/formal/SMTChecker.cpp
@@ -37,9 +37,10 @@ SMTChecker::SMTChecker(ErrorReporter& _errorReporter, ReadCallback::Callback con
{
}
-void SMTChecker::analyze(SourceUnit const& _source)
+void SMTChecker::analyze(SourceUnit const& _source, shared_ptr<Scanner> const& _scanner)
{
m_variableUsage = make_shared<VariableUsage>(_source);
+ m_scanner = _scanner;
if (_source.annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker))
_source.accept(*this);
}
@@ -753,6 +754,7 @@ void SMTChecker::checkCondition(
vector<string> expressionNames;
if (m_functionPath.size())
{
+ solAssert(m_scanner, "");
if (_additionalValue)
{
expressionsToEvaluate.emplace_back(*_additionalValue);
diff --git a/libsolidity/formal/SMTChecker.h b/libsolidity/formal/SMTChecker.h
index 376b73fd..a7f955dd 100644
--- a/libsolidity/formal/SMTChecker.h
+++ b/libsolidity/formal/SMTChecker.h
@@ -25,6 +25,8 @@
#include <libsolidity/interface/ReadFile.h>
+#include <libsolidity/parsing/Scanner.h>
+
#include <unordered_map>
#include <string>
#include <vector>
@@ -42,7 +44,7 @@ class SMTChecker: private ASTConstVisitor
public:
SMTChecker(ErrorReporter& _errorReporter, ReadCallback::Callback const& _readCallback);
- void analyze(SourceUnit const& _sources);
+ void analyze(SourceUnit const& _sources, std::shared_ptr<Scanner> const& _scanner);
private:
// TODO: Check that we do not have concurrent reads and writes to a variable,
@@ -193,6 +195,7 @@ private:
std::unordered_map<std::string, std::shared_ptr<SymbolicVariable>> m_specialVariables;
std::vector<smt::Expression> m_pathConditions;
ErrorReporter& m_errorReporter;
+ std::shared_ptr<Scanner> m_scanner;
/// Stores the current path of function calls.
std::vector<FunctionDefinition const*> m_functionPath;
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp
index 1f58245f..441c7897 100644
--- a/libsolidity/interface/CompilerStack.cpp
+++ b/libsolidity/interface/CompilerStack.cpp
@@ -47,6 +47,8 @@
#include <libevmasm/Exceptions.h>
+#include <libyul/YulString.h>
+
#include <libdevcore/SwarmHash.h>
#include <libdevcore/JSON.h>
@@ -282,7 +284,7 @@ bool CompilerStack::analyze()
{
SMTChecker smtChecker(m_errorReporter, m_smtQuery);
for (Source const* source: m_sourceOrder)
- smtChecker.analyze(*source->ast);
+ smtChecker.analyze(*source->ast, source->scanner);
}
}
catch(FatalError const&)
diff --git a/libsolidity/interface/GasEstimator.cpp b/libsolidity/interface/GasEstimator.cpp
index e70e23a2..1f20366e 100644
--- a/libsolidity/interface/GasEstimator.cpp
+++ b/libsolidity/interface/GasEstimator.cpp
@@ -24,7 +24,7 @@
#include <map>
#include <functional>
#include <memory>
-#include <libdevcore/SHA3.h>
+#include <libdevcore/Keccak256.h>
#include <libevmasm/ControlFlowGraph.h>
#include <libevmasm/KnownState.h>
#include <libevmasm/PathGasMeter.h>
diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp
index 8300e8db..c8b03a94 100644
--- a/libsolidity/interface/StandardCompiler.cpp
+++ b/libsolidity/interface/StandardCompiler.cpp
@@ -25,7 +25,7 @@
#include <libsolidity/ast/ASTJsonConverter.h>
#include <libevmasm/Instruction.h>
#include <libdevcore/JSON.h>
-#include <libdevcore/SHA3.h>
+#include <libdevcore/Keccak256.h>
#include <boost/algorithm/string.hpp>
diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp
index f99b9ea4..b17dad9a 100644
--- a/libsolidity/parsing/Parser.cpp
+++ b/libsolidity/parsing/Parser.cpp
@@ -1556,7 +1556,7 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
}
case Token::IllegalHex:
fatalParserError("Expected even number of hex-nibbles within double-quotes.");
- break;
+ break;
default:
if (TokenTraits::isElementaryTypeName(token))
{
diff --git a/libsolidity/parsing/Scanner.h b/libsolidity/parsing/Scanner.h
index 02e0553f..14eeb66e 100644
--- a/libsolidity/parsing/Scanner.h
+++ b/libsolidity/parsing/Scanner.h
@@ -162,6 +162,13 @@ public:
/// Do only use in error cases, they are quite expensive.
std::string lineAtPosition(int _position) const { return m_source.lineAtPosition(_position); }
std::tuple<int, int> translatePositionToLineColumn(int _position) const { return m_source.translatePositionToLineColumn(_position); }
+ std::string sourceAt(SourceLocation const& _location) const
+ {
+ solAssert(!_location.isEmpty(), "");
+ solAssert(m_sourceName && _location.sourceName, "");
+ solAssert(*m_sourceName == *_location.sourceName, "");
+ return m_source.source().substr(_location.start, _location.end - _location.start);
+ }
///@}
private:
diff --git a/libyul/YulString.h b/libyul/YulString.h
index ae01c83f..ad900a70 100644
--- a/libyul/YulString.h
+++ b/libyul/YulString.h
@@ -22,7 +22,7 @@
#include <boost/noncopyable.hpp>
-#include <map>
+#include <unordered_map>
#include <memory>
#include <vector>
#include <string>
@@ -32,64 +32,101 @@ namespace dev
namespace yul
{
+/// Repository for YulStrings.
+/// Owns the string data for all YulStrings, which can be referenced by a Handle.
+/// A Handle consists of an ID (that depends on the insertion order of YulStrings and is potentially
+/// non-deterministic) and a deterministic string hash.
class YulStringRepository: boost::noncopyable
{
public:
- YulStringRepository(): m_strings{std::make_shared<std::string>()}
+ struct Handle
{
- m_ids[std::string{}] = 0;
- }
+ size_t id;
+ std::uint64_t hash;
+ };
+ YulStringRepository():
+ m_strings{std::make_shared<std::string>()},
+ m_hashToID{std::make_pair(emptyHash(), 0)}
+ {}
static YulStringRepository& instance()
{
static YulStringRepository inst;
return inst;
}
- size_t stringToId(std::string const& _string)
+ Handle stringToHandle(std::string const& _string)
{
if (_string.empty())
- return 0;
- size_t& id = m_ids[_string];
- if (id == 0)
- {
- m_strings.emplace_back(std::make_shared<std::string>(_string));
- id = m_strings.size() - 1;
- }
- return id;
+ return { 0, emptyHash() };
+ std::uint64_t h = hash(_string);
+ auto range = m_hashToID.equal_range(h);
+ for (auto it = range.first; it != range.second; ++it)
+ if (*m_strings[it->second] == _string)
+ return Handle{it->second, h};
+ m_strings.emplace_back(std::make_shared<std::string>(_string));
+ size_t id = m_strings.size() - 1;
+ m_hashToID.emplace_hint(range.second, std::make_pair(h, id));
+ return Handle{id, h};
}
- std::string const& idToString(size_t _id) const
+ std::string const& idToString(size_t _id) const { return *m_strings.at(_id); }
+
+ static std::uint64_t hash(std::string const& v)
{
- return *m_strings.at(_id);
- }
+ // FNV hash - can be replaced by a better one, e.g. xxhash64
+ std::uint64_t hash = emptyHash();
+ for (auto c: v)
+ {
+ hash *= 1099511628211u;
+ hash ^= c;
+ }
+ return hash;
+ }
+ static constexpr std::uint64_t emptyHash() { return 14695981039346656037u; }
private:
std::vector<std::shared_ptr<std::string>> m_strings;
- std::map<std::string, size_t> m_ids;
+ std::unordered_multimap<std::uint64_t, size_t> m_hashToID;
};
+/// Wrapper around handles into the YulString repository.
+/// Equality of two YulStrings is determined by comparing their ID.
+/// The <-operator depends on the string hash and is not consistent
+/// with string comparisons (however, it is still deterministic).
class YulString
{
public:
YulString() = default;
- explicit YulString(std::string const& _s): m_id(YulStringRepository::instance().stringToId(_s)) {}
+ explicit YulString(std::string const& _s): m_handle(YulStringRepository::instance().stringToHandle(_s)) {}
YulString(YulString const&) = default;
YulString(YulString&&) = default;
YulString& operator=(YulString const&) = default;
YulString& operator=(YulString&&) = default;
/// This is not consistent with the string <-operator!
- bool operator<(YulString const& _other) const { return m_id < _other.m_id; }
- bool operator==(YulString const& _other) const { return m_id == _other.m_id; }
- bool operator!=(YulString const& _other) const { return m_id != _other.m_id; }
+ /// First compares the string hashes. If they are equal
+ /// it checks for identical IDs (only identical strings have
+ /// identical IDs and identical strings do not compare as "less").
+ /// If the hashes are identical and the strings are distinct, it
+ /// falls back to string comparison.
+ bool operator<(YulString const& _other) const
+ {
+ if (m_handle.hash < _other.m_handle.hash) return true;
+ if (_other.m_handle.hash < m_handle.hash) return false;
+ if (m_handle.id == _other.m_handle.id) return false;
+ return str() < _other.str();
+ }
+ /// Equality is determined based on the string ID.
+ bool operator==(YulString const& _other) const { return m_handle.id == _other.m_handle.id; }
+ bool operator!=(YulString const& _other) const { return m_handle.id != _other.m_handle.id; }
- bool empty() const { return m_id == 0; }
+ bool empty() const { return m_handle.id == 0; }
std::string const& str() const
{
- return YulStringRepository::instance().idToString(m_id);
+ return YulStringRepository::instance().idToString(m_handle.id);
}
private:
- /// ID of the string. Assumes that the empty string has ID zero.
- size_t m_id = 0;
+ /// Handle of the string. Assumes that the empty string has ID zero.
+ YulStringRepository::Handle m_handle{ 0, YulStringRepository::emptyHash() };
};
}
diff --git a/libyul/optimiser/README.md b/libyul/optimiser/README.md
index faef818b..c2575179 100644
--- a/libyul/optimiser/README.md
+++ b/libyul/optimiser/README.md
@@ -135,6 +135,8 @@ If there are two assignments to a variable where the first one is a movable expr
and the variable is not used between the two assignments (and the second is not inside
a loop or conditional, the first one is not inside), the first assignment is removed.
+This step also removes movable expression statements.
+
## Function Unifier
diff --git a/libyul/optimiser/RedundantAssignEliminator.cpp b/libyul/optimiser/RedundantAssignEliminator.cpp
index 775b7673..b7217074 100644
--- a/libyul/optimiser/RedundantAssignEliminator.cpp
+++ b/libyul/optimiser/RedundantAssignEliminator.cpp
@@ -96,9 +96,15 @@ void RedundantAssignEliminator::operator()(FunctionDefinition const& _functionDe
(*this)(_functionDefinition.body);
for (auto const& param: _functionDefinition.parameters)
+ {
changeUndecidedTo(param.name, State::Unused);
+ finalize(param.name);
+ }
for (auto const& retParam: _functionDefinition.returnVariables)
+ {
changeUndecidedTo(retParam.name, State::Used);
+ finalize(retParam.name);
+ }
}
void RedundantAssignEliminator::operator()(ForLoop const& _forLoop)
@@ -150,30 +156,48 @@ void RedundantAssignEliminator::run(Block& _ast)
RedundantAssignEliminator rae;
rae(_ast);
- std::set<Assignment const*> assignmentsToRemove;
- for (auto const& variables: rae.m_assignments)
- for (auto const& assignment: variables.second)
- {
- assertThrow(assignment.second != State::Undecided, OptimizerException, "");
- if (assignment.second == State::Unused && MovableChecker{*assignment.first->value}.movable())
- assignmentsToRemove.emplace(assignment.first);
- }
-
- AssignmentRemover remover{assignmentsToRemove};
+ AssignmentRemover remover{rae.m_assignmentsToRemove};
remover(_ast);
}
-void RedundantAssignEliminator::join(RedundantAssignEliminator& _other)
+template <class K, class V, class F>
+void joinMap(std::map<K, V>& _a, std::map<K, V>&& _b, F _conflictSolver)
{
- for (auto& var: _other.m_assignments)
- if (m_assignments.count(var.first))
+ // TODO Perhaps it is better to just create a sorted list
+ // and then use insert(begin, end)
+
+ auto ita = _a.begin();
+ auto aend = _a.end();
+ auto itb = _b.begin();
+ auto bend = _b.end();
+
+ for (; itb != bend; ++ita)
+ {
+ if (ita == aend)
+ ita = _a.insert(ita, std::move(*itb++));
+ else if (ita->first < itb->first)
+ continue;
+ else if (itb->first < ita->first)
+ ita = _a.insert(ita, std::move(*itb++));
+ else
{
- map<Assignment const*, State>& assignmentsHere = m_assignments[var.first];
- for (auto& assignment: var.second)
- assignmentsHere[assignment.first].join(assignment.second);
+ _conflictSolver(ita->second, std::move(itb->second));
+ ++itb;
}
- else
- m_assignments[var.first] = std::move(var.second);
+ }
+}
+
+void RedundantAssignEliminator::join(RedundantAssignEliminator& _other)
+{
+ m_assignmentsToRemove.insert(begin(_other.m_assignmentsToRemove), end(_other.m_assignmentsToRemove));
+
+ joinMap(m_assignments, std::move(_other.m_assignments), [](
+ map<Assignment const*, State>& _assignmentHere,
+ map<Assignment const*, State>&& _assignmentThere
+ )
+ {
+ return joinMap(_assignmentHere, std::move(_assignmentThere), State::join);
+ });
}
void RedundantAssignEliminator::changeUndecidedTo(YulString _variable, RedundantAssignEliminator::State _newState)
@@ -183,6 +207,19 @@ void RedundantAssignEliminator::changeUndecidedTo(YulString _variable, Redundant
assignment.second = _newState;
}
+void RedundantAssignEliminator::finalize(YulString _variable)
+{
+ for (auto& assignment: m_assignments[_variable])
+ {
+ assertThrow(assignment.second != State::Undecided, OptimizerException, "");
+ if (assignment.second == State{State::Unused} && MovableChecker{*assignment.first->value}.movable())
+ // TODO the only point where we actually need this
+ // to be a set is for the for loop
+ m_assignmentsToRemove.insert(assignment.first);
+ }
+ m_assignments.erase(_variable);
+}
+
void AssignmentRemover::operator()(Block& _block)
{
boost::range::remove_erase_if(_block.statements, [=](Statement const& _statement) -> bool {
diff --git a/libyul/optimiser/RedundantAssignEliminator.h b/libyul/optimiser/RedundantAssignEliminator.h
index 805a1f63..76106aae 100644
--- a/libyul/optimiser/RedundantAssignEliminator.h
+++ b/libyul/optimiser/RedundantAssignEliminator.h
@@ -127,10 +127,10 @@ private:
State(Value _value = Undecided): m_value(_value) {}
inline bool operator==(State _other) const { return m_value == _other.m_value; }
inline bool operator!=(State _other) const { return !operator==(_other); }
- inline void join(State const& _other)
+ static inline void join(State& _a, State const& _b)
{
// Using "max" works here because of the order of the values in the enum.
- m_value = Value(std::max(int(_other.m_value), int(m_value)));
+ _a.m_value = Value(std::max(int(_a.m_value), int(_b.m_value)));
}
private:
Value m_value = Undecided;
@@ -149,8 +149,12 @@ private:
}
~BlockScope()
{
+ // This should actually store all declared variables
+ // into a different mapping
for (auto const& var: m_rae.m_declaredVariables)
m_rae.changeUndecidedTo(var, State::Unused);
+ for (auto const& var: m_rae.m_declaredVariables)
+ m_rae.finalize(var);
swap(m_rae.m_declaredVariables, m_outerDeclaredVariables);
}
@@ -164,10 +168,13 @@ private:
/// Will destroy @a _other.
void join(RedundantAssignEliminator& _other);
void changeUndecidedTo(YulString _variable, State _newState);
+ void finalize(YulString _variable);
std::set<YulString> m_declaredVariables;
// TODO check that this does not cause nondeterminism!
+ // This could also be a pseudo-map from state to assignment.
std::map<YulString, std::map<Assignment const*, State>> m_assignments;
+ std::set<Assignment const*> m_assignmentsToRemove;
};
class AssignmentRemover: public ASTModifier
diff --git a/libyul/optimiser/UnusedPruner.cpp b/libyul/optimiser/UnusedPruner.cpp
index a7b32873..71e86798 100644
--- a/libyul/optimiser/UnusedPruner.cpp
+++ b/libyul/optimiser/UnusedPruner.cpp
@@ -85,6 +85,16 @@ void UnusedPruner::operator()(Block& _block)
}};
}
}
+ else if (statement.type() == typeid(ExpressionStatement))
+ {
+ ExpressionStatement& exprStmt = boost::get<ExpressionStatement>(statement);
+ if (MovableChecker(exprStmt.expression).movable())
+ {
+ // pop(x) should be movable!
+ subtractReferences(ReferencesCounter::countReferences(exprStmt.expression));
+ statement = Block{std::move(exprStmt.location), {}};
+ }
+ }
removeEmptyBlocks(_block);
diff --git a/libyul/optimiser/UnusedPruner.h b/libyul/optimiser/UnusedPruner.h
index 2dd74940..b5aea3dd 100644
--- a/libyul/optimiser/UnusedPruner.h
+++ b/libyul/optimiser/UnusedPruner.h
@@ -32,10 +32,8 @@ namespace yul
{
/**
- * Optimisation stage that removes unused variables and functions.
- *
- * TODO: Also remove intermediate variable assignments from movable expressions
- * which are not referenced until after the next assignment to the same variable.
+ * Optimisation stage that removes unused variables and functions and also
+ * removes movable expression statements.
*
* Note that this does not remove circular references.
*
diff --git a/scripts/bytecodecompare/storebytecode.sh b/scripts/bytecodecompare/storebytecode.sh
index 557e3275..ccf6e60e 100755
--- a/scripts/bytecodecompare/storebytecode.sh
+++ b/scripts/bytecodecompare/storebytecode.sh
@@ -40,14 +40,16 @@ TMPDIR=$(mktemp -d)
if [[ "$SOLC_EMSCRIPTEN" = "On" ]]
then
- cp "$REPO_ROOT/build/libsolc/soljson.js" .
- npm install solc
+ # npm install solc
+ git clone --depth 1 https://github.com/ethereum/solc-js.git solc-js
+ ( cd solc-js; npm install )
+ cp "$REPO_ROOT/build/libsolc/soljson.js" solc-js/
cat > solc <<EOF
#!/usr/bin/env node
var process = require('process')
var fs = require('fs')
-var compiler = require('solc/wrapper.js')(require('./soljson.js'))
+var compiler = require('./solc-js/wrapper.js')(require('./solc-js/soljson.js'))
for (var optimize of [false, true])
{
@@ -57,7 +59,15 @@ for (var optimize of [false, true])
{
var inputs = {}
inputs[filename] = fs.readFileSync(filename).toString()
- var result = compiler.compile({sources: inputs}, optimize)
+ var input = {
+ language: 'Solidity',
+ sources: inputs,
+ settings: {
+ optimizer: { enabled: optimize },
+ outputSelection: { '*': { '*': ['evm.bytecode.object', 'metadata'] } }
+ }
+ }
+ var result = JSON.parse(compiler.compile(JSON.stringify(input)))
if (!('contracts' in result) || Object.keys(result['contracts']).length === 0)
{
console.log(filename + ': ERROR')
@@ -66,7 +76,7 @@ for (var optimize of [false, true])
{
for (var contractName in result['contracts'])
{
- console.log(contractName + ' ' + result['contracts'][contractName].bytecode)
+ console.log(contractName + ' ' + result['contracts'][contractName].evm.bytecode.object)
console.log(contractName + ' ' + result['contracts'][contractName].metadata)
}
}
diff --git a/scripts/check_style.sh b/scripts/check_style.sh
index a8557a54..4f716d66 100755
--- a/scripts/check_style.sh
+++ b/scripts/check_style.sh
@@ -1,9 +1,9 @@
#!/usr/bin/env bash
-REPO_ROOT="$(dirname "$0")"/..
-
(
+REPO_ROOT="$(dirname "$0")"/..
cd $REPO_ROOT
+
WHITESPACE=$(git grep -n -I -E "^.*[[:space:]]+$" | grep -v "test/libsolidity/ASTJSON\|test/compilationTests/zeppelin/LICENSE")
if [[ "$WHITESPACE" != "" ]]
@@ -12,10 +12,7 @@ then
echo "$WHITESPACE" >&2
exit 1
fi
-)
-(
-cd $REPO_ROOT
FORMATERROR=$(
(
git grep -nIE "\<(if|for)\(" -- '*.h' '*.cpp'
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 91c1b200..3b674502 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -9,8 +9,10 @@ file(GLOB libevmasm_sources "libevmasm/*.cpp")
file(GLOB libevmasm_headers "libevmasm/*.h")
file(GLOB libyul_sources "libyul/*.cpp")
file(GLOB libyul_headers "libyul/*.h")
-file(GLOB liblll_sources "liblll/*.cpp")
-file(GLOB liblll_headers "liblll/*.h")
+if (LLL)
+ file(GLOB liblll_sources "liblll/*.cpp")
+ file(GLOB liblll_headers "liblll/*.h")
+endif()
file(GLOB libsolidity_sources "libsolidity/*.cpp")
file(GLOB libsolidity_headers "libsolidity/*.h")
@@ -22,7 +24,12 @@ add_executable(soltest ${sources} ${headers}
${liblll_sources} ${liblll_headers}
${libsolidity_sources} ${libsolidity_headers}
)
-target_link_libraries(soltest PRIVATE libsolc solidity lll evmasm devcore ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES})
+target_link_libraries(soltest PRIVATE libsolc solidity evmasm devcore ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES})
+
+if (LLL)
+ target_link_libraries(soltest PRIVATE lll)
+ target_compile_definitions(soltest PRIVATE HAVE_LLL=1)
+endif()
if (NOT Boost_USE_STATIC_LIBS)
target_compile_definitions(soltest PUBLIC -DBOOST_TEST_DYN_LINK)
diff --git a/test/ExecutionFramework.h b/test/ExecutionFramework.h
index e275147b..d6de95a3 100644
--- a/test/ExecutionFramework.h
+++ b/test/ExecutionFramework.h
@@ -28,7 +28,7 @@
#include <libsolidity/interface/EVMVersion.h>
#include <libdevcore/FixedHash.h>
-#include <libdevcore/SHA3.h>
+#include <libdevcore/Keccak256.h>
#include <functional>
diff --git a/test/boostTest.cpp b/test/boostTest.cpp
index 34eeaec9..5352ef85 100644
--- a/test/boostTest.cpp
+++ b/test/boostTest.cpp
@@ -160,9 +160,11 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] )
"SolidityAuctionRegistrar",
"SolidityFixedFeeRegistrar",
"SolidityWallet",
+#if HAVE_LLL
"LLLERC20",
"LLLENS",
"LLLEndToEndTest",
+#endif
"GasMeterTests",
"SolidityEndToEndTest",
"SolidityOptimizer"
diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh
index b0b545f3..4838d088 100755
--- a/test/cmdlineTests.sh
+++ b/test/cmdlineTests.sh
@@ -124,7 +124,7 @@ test_solc_file_input_failures() {
set -e
sed -i -e '/^Warning: This is a pre-release compiler version, please do not use it in production./d' "$stderr_path"
- sed -i -e 's/ \?Consider adding "pragma .*$//' "$stderr_path"
+ sed -i -e 's/ Consider adding "pragma .*$//' "$stderr_path"
if [[ $exitCode -eq 0 ]]; then
printError "Incorrect exit code. Expected failure (non-zero) but got success (0)."
diff --git a/test/externalTests.sh b/test/externalTests.sh
index 0168fb03..93581925 100755
--- a/test/externalTests.sh
+++ b/test/externalTests.sh
@@ -55,7 +55,16 @@ function test_truffle
cd "$DIR"
echo "Current commit hash: `git rev-parse HEAD`"
npm install
- find . -name soljson.js -exec cp "$SOLJSON" {} \;
+ # Replace solc package by master
+ for d in node_modules node_modules/truffle/node_modules
+ do
+ (
+ cd $d
+ rm -rf solc
+ git clone --depth 1 https://github.com/ethereum/solc-js.git solc
+ cp "$SOLJSON" solc/
+ )
+ done
if [ "$name" == "Zeppelin" -o "$name" == "Gnosis" ]; then
echo "Replaced fixed-version pragmas..."
# Replace fixed-version pragmas in Gnosis (part of Consensys best practice)
@@ -68,6 +77,8 @@ function test_truffle
rm "$assertsol"
wget https://raw.githubusercontent.com/trufflesuite/truffle-core/ef31bcaa15dbd9bd0f6a0070a5c63f271cde2dbc/lib/testing/Assert.sol -o "$assertsol"
fi
+ # Change "compileStandard" to "compile"
+ sed -i s/solc.compileStandard/solc.compile/ "node_modules/truffle/build/cli.bundled.js"
npm run test
)
rm -rf "$DIR"
diff --git a/test/liblll/Compiler.cpp b/test/liblll/Compiler.cpp
index a4394f54..27db45a5 100644
--- a/test/liblll/Compiler.cpp
+++ b/test/liblll/Compiler.cpp
@@ -147,215 +147,215 @@ BOOST_AUTO_TEST_CASE(disallowed_functional_asm_instructions)
BOOST_AUTO_TEST_CASE(valid_opcodes_functional)
{
vector<string> opcodes_bytecode {
- "00",
- "6000600001",
- "6000600002",
- "6000600003",
- "6000600004",
- "6000600005",
- "6000600006",
- "6000600007",
- "60006000600008",
- "60006000600009",
- "600060000a",
- "600060000b",
- "6000600010",
- "6000600011",
- "6000600012",
- "6000600013",
- "6000600014",
- "600015",
- "6000600016",
- "6000600017",
- "6000600018",
- "600019",
- "600060001a",
- "6000600020",
- "30",
- "600031",
- "32",
- "33",
- "34",
- "600035",
- "36",
- "60006000600037",
- "38",
- "60006000600039",
- "3a",
- "60003b",
- "60006000600060003c",
- "3d",
- "6000600060003e",
- "60003f",
- "600040",
- "41",
- "42",
- "43",
- "44",
- "45",
- "600050",
- "600051",
- "6000600052",
- "6000600053",
- "600054",
- "6000600055",
- "600056",
- "6000600057",
- "58",
- "59",
- "5a",
- "60ff",
- "61ffff",
- "62ffffff",
- "63ffffffff",
- "64ffffffffff",
- "65ffffffffffff",
- "66ffffffffffffff",
- "67ffffffffffffffff",
- "68ffffffffffffffffff",
- "69ffffffffffffffffffff",
- "6affffffffffffffffffffff",
- "6bffffffffffffffffffffffff",
- "6cffffffffffffffffffffffffff",
- "6dffffffffffffffffffffffffffff",
- "6effffffffffffffffffffffffffffff",
- "6fffffffffffffffffffffffffffffffff",
- "70ffffffffffffffffffffffffffffffffff",
- "71ffffffffffffffffffffffffffffffffffff",
- "72ffffffffffffffffffffffffffffffffffffff",
- "73ffffffffffffffffffffffffffffffffffffffff",
- "74ffffffffffffffffffffffffffffffffffffffffff",
- "75ffffffffffffffffffffffffffffffffffffffffffff",
- "76ffffffffffffffffffffffffffffffffffffffffffffff",
- "77ffffffffffffffffffffffffffffffffffffffffffffffff",
- "78ffffffffffffffffffffffffffffffffffffffffffffffffff",
- "79ffffffffffffffffffffffffffffffffffffffffffffffffffff",
- "7affffffffffffffffffffffffffffffffffffffffffffffffffffff",
- "7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
- "7cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
- "7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
- "7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
- "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
- "60006000a0",
- "600060006000a1",
- "6000600060006000a2",
- "60006000600060006000a3",
- "600060006000600060006000a4",
- "600060006000f0",
- "6000600060006000600060006000f1",
- "6000600060006000600060006000f2",
- "60006000f3",
- "600060006000600060006000f4",
- "600060006000600060006000fa",
- "60006000fd",
- "fe",
- "6000ff"
+ "0000",
+ "600060000100",
+ "600060000200",
+ "600060000300",
+ "600060000400",
+ "600060000500",
+ "600060000600",
+ "600060000700",
+ "6000600060000800",
+ "6000600060000900",
+ "600060000a00",
+ "600060000b00",
+ "600060001000",
+ "600060001100",
+ "600060001200",
+ "600060001300",
+ "600060001400",
+ "60001500",
+ "600060001600",
+ "600060001700",
+ "600060001800",
+ "60001900",
+ "600060001a00",
+ "600060002000",
+ "3000",
+ "60003100",
+ "3200",
+ "3300",
+ "3400",
+ "60003500",
+ "3600",
+ "6000600060003700",
+ "3800",
+ "6000600060003900",
+ "3a00",
+ "60003b00",
+ "60006000600060003c00",
+ "3d00",
+ "6000600060003e00",
+ "60003f00",
+ "60004000",
+ "4100",
+ "4200",
+ "4300",
+ "4400",
+ "4500",
+ "60005000",
+ "60005100",
+ "600060005200",
+ "600060005300",
+ "60005400",
+ "600060005500",
+ "60005600",
+ "600060005700",
+ "5800",
+ "5900",
+ "5a00",
+ "60ff00",
+ "61ffff00",
+ "62ffffff00",
+ "63ffffffff00",
+ "64ffffffffff00",
+ "65ffffffffffff00",
+ "66ffffffffffffff00",
+ "67ffffffffffffffff00",
+ "68ffffffffffffffffff00",
+ "69ffffffffffffffffffff00",
+ "6affffffffffffffffffffff00",
+ "6bffffffffffffffffffffffff00",
+ "6cffffffffffffffffffffffffff00",
+ "6dffffffffffffffffffffffffffff00",
+ "6effffffffffffffffffffffffffffff00",
+ "6fffffffffffffffffffffffffffffffff00",
+ "70ffffffffffffffffffffffffffffffffff00",
+ "71ffffffffffffffffffffffffffffffffffff00",
+ "72ffffffffffffffffffffffffffffffffffffff00",
+ "73ffffffffffffffffffffffffffffffffffffffff00",
+ "74ffffffffffffffffffffffffffffffffffffffffff00",
+ "75ffffffffffffffffffffffffffffffffffffffffffff00",
+ "76ffffffffffffffffffffffffffffffffffffffffffffff00",
+ "77ffffffffffffffffffffffffffffffffffffffffffffffff00",
+ "78ffffffffffffffffffffffffffffffffffffffffffffffffff00",
+ "79ffffffffffffffffffffffffffffffffffffffffffffffffffff00",
+ "7affffffffffffffffffffffffffffffffffffffffffffffffffffff00",
+ "7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff00",
+ "7cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00",
+ "7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00",
+ "7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00",
+ "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00",
+ "60006000a000",
+ "600060006000a100",
+ "6000600060006000a200",
+ "60006000600060006000a300",
+ "600060006000600060006000a400",
+ "600060006000f000",
+ "6000600060006000600060006000f100",
+ "6000600060006000600060006000f200",
+ "60006000f300",
+ "600060006000600060006000f400",
+ "600060006000600060006000fa00",
+ "60006000fd00",
+ "fe00",
+ "6000ff00"
};
vector<string> opcodes_lll {
- "{ (STOP) }",
- "{ (ADD 0 0) }",
- "{ (MUL 0 0) }",
- "{ (SUB 0 0) }",
- "{ (DIV 0 0) }",
- "{ (SDIV 0 0) }",
- "{ (MOD 0 0) }",
- "{ (SMOD 0 0) }",
- "{ (ADDMOD 0 0 0) }",
- "{ (MULMOD 0 0 0) }",
- "{ (EXP 0 0) }",
- "{ (SIGNEXTEND 0 0) }",
- "{ (LT 0 0) }",
- "{ (GT 0 0) }",
- "{ (SLT 0 0) }",
- "{ (SGT 0 0) }",
- "{ (EQ 0 0) }",
- "{ (ISZERO 0) }",
- "{ (AND 0 0) }",
- "{ (OR 0 0) }",
- "{ (XOR 0 0) }",
- "{ (NOT 0) }",
- "{ (BYTE 0 0) }",
- "{ (KECCAK256 0 0) }",
- "{ (ADDRESS) }",
- "{ (BALANCE 0) }",
- "{ (ORIGIN) }",
- "{ (CALLER) }",
- "{ (CALLVALUE) }",
- "{ (CALLDATALOAD 0) }",
- "{ (CALLDATASIZE) }",
- "{ (CALLDATACOPY 0 0 0) }",
- "{ (CODESIZE) }",
- "{ (CODECOPY 0 0 0) }",
- "{ (GASPRICE) }",
- "{ (EXTCODESIZE 0) }",
- "{ (EXTCODECOPY 0 0 0 0) }",
- "{ (RETURNDATASIZE) }",
- "{ (RETURNDATACOPY 0 0 0) }",
- "{ (EXTCODEHASH 0) }",
- "{ (BLOCKHASH 0) }",
- "{ (COINBASE) }",
- "{ (TIMESTAMP) }",
- "{ (NUMBER) }",
- "{ (DIFFICULTY) }",
- "{ (GASLIMIT) }",
- "{ (POP 0) }",
- "{ (MLOAD 0) }",
- "{ (MSTORE 0 0) }",
- "{ (MSTORE8 0 0) }",
- "{ (SLOAD 0) }",
- "{ (SSTORE 0 0) }",
- "{ (JUMP 0) }",
- "{ (JUMPI 0 0) }",
- "{ (PC) }",
- "{ (MSIZE) }",
- "{ (GAS) }",
- "{ 0xff }",
- "{ 0xffff }",
- "{ 0xffffff }",
- "{ 0xffffffff }",
- "{ 0xffffffffff }",
- "{ 0xffffffffffff }",
- "{ 0xffffffffffffff }",
- "{ 0xffffffffffffffff }",
- "{ 0xffffffffffffffffff }",
- "{ 0xffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffffffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffffffffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffffffffffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffffffffffffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff }",
- "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff }",
- "{ (LOG0 0 0) }",
- "{ (LOG1 0 0 0) }",
- "{ (LOG2 0 0 0 0) }",
- "{ (LOG3 0 0 0 0 0) }",
- "{ (LOG4 0 0 0 0 0 0) }",
- "{ (CREATE 0 0 0) }",
- "{ (CALL 0 0 0 0 0 0 0) }",
- "{ (CALLCODE 0 0 0 0 0 0 0) }",
- "{ (RETURN 0 0) }",
- "{ (DELEGATECALL 0 0 0 0 0 0) }",
- "{ (STATICCALL 0 0 0 0 0 0) }",
- "{ (REVERT 0 0) }",
- "{ (INVALID) }",
- "{ (SELFDESTRUCT 0) }"
+ "(STOP)",
+ "(ADD 0 0)",
+ "(MUL 0 0)",
+ "(SUB 0 0)",
+ "(DIV 0 0)",
+ "(SDIV 0 0)",
+ "(MOD 0 0)",
+ "(SMOD 0 0)",
+ "(ADDMOD 0 0 0)",
+ "(MULMOD 0 0 0)",
+ "(EXP 0 0)",
+ "(SIGNEXTEND 0 0)",
+ "(LT 0 0)",
+ "(GT 0 0)",
+ "(SLT 0 0)",
+ "(SGT 0 0)",
+ "(EQ 0 0)",
+ "(ISZERO 0)",
+ "(AND 0 0)",
+ "(OR 0 0)",
+ "(XOR 0 0)",
+ "(NOT 0)",
+ "(BYTE 0 0)",
+ "(KECCAK256 0 0)",
+ "(ADDRESS)",
+ "(BALANCE 0)",
+ "(ORIGIN)",
+ "(CALLER)",
+ "(CALLVALUE)",
+ "(CALLDATALOAD 0)",
+ "(CALLDATASIZE)",
+ "(CALLDATACOPY 0 0 0)",
+ "(CODESIZE)",
+ "(CODECOPY 0 0 0)",
+ "(GASPRICE)",
+ "(EXTCODESIZE 0)",
+ "(EXTCODECOPY 0 0 0 0)",
+ "(RETURNDATASIZE)",
+ "(RETURNDATACOPY 0 0 0)",
+ "(EXTCODEHASH 0)",
+ "(BLOCKHASH 0)",
+ "(COINBASE)",
+ "(TIMESTAMP)",
+ "(NUMBER)",
+ "(DIFFICULTY)",
+ "(GASLIMIT)",
+ "(POP 0)",
+ "(MLOAD 0)",
+ "(MSTORE 0 0)",
+ "(MSTORE8 0 0)",
+ "(SLOAD 0)",
+ "(SSTORE 0 0)",
+ "(JUMP 0)",
+ "(JUMPI 0 0)",
+ "(PC)",
+ "(MSIZE)",
+ "(GAS)",
+ "0xff",
+ "0xffff",
+ "0xffffff",
+ "0xffffffff",
+ "0xffffffffff",
+ "0xffffffffffff",
+ "0xffffffffffffff",
+ "0xffffffffffffffff",
+ "0xffffffffffffffffff",
+ "0xffffffffffffffffffff",
+ "0xffffffffffffffffffffff",
+ "0xffffffffffffffffffffffff",
+ "0xffffffffffffffffffffffffff",
+ "0xffffffffffffffffffffffffffff",
+ "0xffffffffffffffffffffffffffffff",
+ "0xffffffffffffffffffffffffffffffff",
+ "0xffffffffffffffffffffffffffffffffff",
+ "0xffffffffffffffffffffffffffffffffffff",
+ "0xffffffffffffffffffffffffffffffffffffff",
+ "0xffffffffffffffffffffffffffffffffffffffff",
+ "0xffffffffffffffffffffffffffffffffffffffffff",
+ "0xffffffffffffffffffffffffffffffffffffffffffff",
+ "0xffffffffffffffffffffffffffffffffffffffffffffff",
+ "0xffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0xffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0xffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0xffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "(LOG0 0 0)",
+ "(LOG1 0 0 0)",
+ "(LOG2 0 0 0 0)",
+ "(LOG3 0 0 0 0 0)",
+ "(LOG4 0 0 0 0 0 0)",
+ "(CREATE 0 0 0)",
+ "(CALL 0 0 0 0 0 0 0)",
+ "(CALLCODE 0 0 0 0 0 0 0)",
+ "(RETURN 0 0)",
+ "(DELEGATECALL 0 0 0 0 0 0)",
+ "(STATICCALL 0 0 0 0 0 0)",
+ "(REVERT 0 0)",
+ "(INVALID)",
+ "(SELFDESTRUCT 0)"
};
for (size_t i = 0; i < opcodes_bytecode.size(); i++)
@@ -372,281 +372,281 @@ BOOST_AUTO_TEST_CASE(valid_opcodes_functional)
BOOST_AUTO_TEST_CASE(valid_opcodes_asm)
{
vector<string> opcodes_bytecode {
- "00",
- "01",
- "02",
- "03",
- "04",
- "05",
- "06",
- "07",
- "08",
- "09",
- "0a",
- "0b",
- "10",
- "11",
- "12",
- "13",
- "14",
- "15",
- "16",
- "17",
- "18",
- "19",
- "1a",
- "20",
- "30",
- "31",
- "32",
- "33",
- "34",
- "35",
- "36",
- "37",
- "38",
- "39",
- "3a",
- "3b",
- "3c",
- "3d",
- "3e",
- "3f",
- "40",
- "41",
- "42",
- "43",
- "44",
- "45",
- "50",
- "51",
- "52",
- "53",
- "54",
- "55",
- "56",
- "57",
- "58",
- "59",
- "5a",
- "5b",
- "60ff",
- "61ffff",
- "62ffffff",
- "63ffffffff",
- "64ffffffffff",
- "65ffffffffffff",
- "66ffffffffffffff",
- "67ffffffffffffffff",
- "68ffffffffffffffffff",
- "69ffffffffffffffffffff",
- "6affffffffffffffffffffff",
- "6bffffffffffffffffffffffff",
- "6cffffffffffffffffffffffffff",
- "6dffffffffffffffffffffffffffff",
- "6effffffffffffffffffffffffffffff",
- "6fffffffffffffffffffffffffffffffff",
- "70ffffffffffffffffffffffffffffffffff",
- "71ffffffffffffffffffffffffffffffffffff",
- "72ffffffffffffffffffffffffffffffffffffff",
- "73ffffffffffffffffffffffffffffffffffffffff",
- "74ffffffffffffffffffffffffffffffffffffffffff",
- "75ffffffffffffffffffffffffffffffffffffffffffff",
- "76ffffffffffffffffffffffffffffffffffffffffffffff",
- "77ffffffffffffffffffffffffffffffffffffffffffffffff",
- "78ffffffffffffffffffffffffffffffffffffffffffffffffff",
- "79ffffffffffffffffffffffffffffffffffffffffffffffffffff",
- "7affffffffffffffffffffffffffffffffffffffffffffffffffffff",
- "7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
- "7cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
- "7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
- "7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
- "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
- "80",
- "81",
- "82",
- "83",
- "84",
- "85",
- "86",
- "87",
- "88",
- "89",
- "8a",
- "8b",
- "8c",
- "8d",
- "8e",
- "8f",
- "90",
- "91",
- "92",
- "93",
- "94",
- "95",
- "96",
- "97",
- "98",
- "99",
- "9a",
- "9b",
- "9c",
- "9d",
- "9e",
- "9f",
- "a0",
- "a1",
- "a2",
- "a3",
- "a4",
- "f0",
- "f1",
- "f2",
- "f3",
- "f4",
- "fa",
- "fd",
- "fe",
- "ff"
+ "0000",
+ "600060000100",
+ "600060000200",
+ "600060000300",
+ "600060000400",
+ "600060000500",
+ "600060000600",
+ "600060000700",
+ "6000600060000800",
+ "6000600060000900",
+ "600060000a00",
+ "600060000b00",
+ "600060001000",
+ "600060001100",
+ "600060001200",
+ "600060001300",
+ "600060001400",
+ "60001500",
+ "600060001600",
+ "600060001700",
+ "600060001800",
+ "60001900",
+ "600060001a00",
+ "600060002000",
+ "3000",
+ "60003100",
+ "3200",
+ "3300",
+ "3400",
+ "60003500",
+ "3600",
+ "6000600060003700",
+ "3800",
+ "6000600060003900",
+ "3a00",
+ "60003b00",
+ "60006000600060003c00",
+ "3d00",
+ "6000600060003e00",
+ "60003f00",
+ "4000",
+ "4100",
+ "4200",
+ "4300",
+ "4400",
+ "4500",
+ "60005000",
+ "60005100",
+ "600060005200",
+ "600060005300",
+ "60005400",
+ "600060005500",
+ "60005600",
+ "600060005700",
+ "5800",
+ "5900",
+ "5a00",
+ "5b00",
+ "60ff00",
+ "61ffff00",
+ "62ffffff00",
+ "63ffffffff00",
+ "64ffffffffff00",
+ "65ffffffffffff00",
+ "66ffffffffffffff00",
+ "67ffffffffffffffff00",
+ "68ffffffffffffffffff00",
+ "69ffffffffffffffffffff00",
+ "6affffffffffffffffffffff00",
+ "6bffffffffffffffffffffffff00",
+ "6cffffffffffffffffffffffffff00",
+ "6dffffffffffffffffffffffffffff00",
+ "6effffffffffffffffffffffffffffff00",
+ "6fffffffffffffffffffffffffffffffff00",
+ "70ffffffffffffffffffffffffffffffffff00",
+ "71ffffffffffffffffffffffffffffffffffff00",
+ "72ffffffffffffffffffffffffffffffffffffff00",
+ "73ffffffffffffffffffffffffffffffffffffffff00",
+ "74ffffffffffffffffffffffffffffffffffffffffff00",
+ "75ffffffffffffffffffffffffffffffffffffffffffff00",
+ "76ffffffffffffffffffffffffffffffffffffffffffffff00",
+ "77ffffffffffffffffffffffffffffffffffffffffffffffff00",
+ "78ffffffffffffffffffffffffffffffffffffffffffffffffff00",
+ "79ffffffffffffffffffffffffffffffffffffffffffffffffffff00",
+ "7affffffffffffffffffffffffffffffffffffffffffffffffffffff00",
+ "7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff00",
+ "7cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00",
+ "7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00",
+ "7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00",
+ "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00",
+ "60006000600060006000600060006000600060006000600060006000600060008000",
+ "60006000600060006000600060006000600060006000600060006000600060008100",
+ "60006000600060006000600060006000600060006000600060006000600060008200",
+ "60006000600060006000600060006000600060006000600060006000600060008300",
+ "60006000600060006000600060006000600060006000600060006000600060008400",
+ "60006000600060006000600060006000600060006000600060006000600060008500",
+ "60006000600060006000600060006000600060006000600060006000600060008600",
+ "60006000600060006000600060006000600060006000600060006000600060008700",
+ "60006000600060006000600060006000600060006000600060006000600060008800",
+ "60006000600060006000600060006000600060006000600060006000600060008900",
+ "60006000600060006000600060006000600060006000600060006000600060008a00",
+ "60006000600060006000600060006000600060006000600060006000600060008b00",
+ "60006000600060006000600060006000600060006000600060006000600060008c00",
+ "60006000600060006000600060006000600060006000600060006000600060008d00",
+ "60006000600060006000600060006000600060006000600060006000600060008e00",
+ "60006000600060006000600060006000600060006000600060006000600060008f00",
+ "60006000600060006000600060006000600060006000600060006000600060009000",
+ "60006000600060006000600060006000600060006000600060006000600060009100",
+ "60006000600060006000600060006000600060006000600060006000600060009200",
+ "60006000600060006000600060006000600060006000600060006000600060009300",
+ "60006000600060006000600060006000600060006000600060006000600060009400",
+ "60006000600060006000600060006000600060006000600060006000600060009500",
+ "60006000600060006000600060006000600060006000600060006000600060009600",
+ "60006000600060006000600060006000600060006000600060006000600060009700",
+ "60006000600060006000600060006000600060006000600060006000600060009800",
+ "60006000600060006000600060006000600060006000600060006000600060009900",
+ "60006000600060006000600060006000600060006000600060006000600060009a00",
+ "60006000600060006000600060006000600060006000600060006000600060009b00",
+ "60006000600060006000600060006000600060006000600060006000600060009c00",
+ "60006000600060006000600060006000600060006000600060006000600060009d00",
+ "60006000600060006000600060006000600060006000600060006000600060009e00",
+ "60006000600060006000600060006000600060006000600060006000600060009f00",
+ "60006000a000",
+ "600060006000a100",
+ "6000600060006000a200",
+ "60006000600060006000a300",
+ "600060006000600060006000a400",
+ "600060006000f000",
+ "600060006000600060006000f100",
+ "600060006000600060006000f200",
+ "60006000f300",
+ "60006000600060006000f400",
+ "60006000600060006000fa00",
+ "60006000fd00",
+ "fe00",
+ "6000ff00"
};
vector<string> opcodes_lll {
- "{ (asm STOP) }",
- "{ (asm ADD) }",
- "{ (asm MUL) }",
- "{ (asm SUB) }",
- "{ (asm DIV) }",
- "{ (asm SDIV ) }",
- "{ (asm MOD) }",
- "{ (asm SMOD) }",
- "{ (asm ADDMOD) }",
- "{ (asm MULMOD) }",
- "{ (asm EXP) }",
- "{ (asm SIGNEXTEND) }",
- "{ (asm LT) }",
- "{ (asm GT) }",
- "{ (asm SLT) }",
- "{ (asm SGT) }",
- "{ (asm EQ) }",
- "{ (asm ISZERO) }",
- "{ (asm AND) }",
- "{ (asm OR) }",
- "{ (asm XOR) }",
- "{ (asm NOT) }",
- "{ (asm BYTE) }",
- "{ (asm KECCAK256) }",
- "{ (asm ADDRESS) }",
- "{ (asm BALANCE) }",
- "{ (asm ORIGIN) }",
- "{ (asm CALLER) }",
- "{ (asm CALLVALUE) }",
- "{ (asm CALLDATALOAD) }",
- "{ (asm CALLDATASIZE) }",
- "{ (asm CALLDATACOPY) }",
- "{ (asm CODESIZE) }",
- "{ (asm CODECOPY) }",
- "{ (asm GASPRICE) }",
- "{ (asm EXTCODESIZE)}",
- "{ (asm EXTCODECOPY) }",
- "{ (asm RETURNDATASIZE) }",
- "{ (asm RETURNDATACOPY) }",
- "{ (asm EXTCODEHASH) }",
- "{ (asm BLOCKHASH) }",
- "{ (asm COINBASE) }",
- "{ (asm TIMESTAMP) }",
- "{ (asm NUMBER) }",
- "{ (asm DIFFICULTY) }",
- "{ (asm GASLIMIT) }",
- "{ (asm POP) }",
- "{ (asm MLOAD) }",
- "{ (asm MSTORE) }",
- "{ (asm MSTORE8) }",
- "{ (asm SLOAD) }",
- "{ (asm SSTORE) }",
- "{ (asm JUMP ) }",
- "{ (asm JUMPI ) }",
- "{ (asm PC) }",
- "{ (asm MSIZE) }",
- "{ (asm GAS) }",
- "{ (asm JUMPDEST) }",
- "{ (asm 0xff) }",
- "{ (asm 0xffff) }",
- "{ (asm 0xffffff) }",
- "{ (asm 0xffffffff) }",
- "{ (asm 0xffffffffff) }",
- "{ (asm 0xffffffffffff) }",
- "{ (asm 0xffffffffffffff) }",
- "{ (asm 0xffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffffffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
- "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
- "{ (asm DUP1) }",
- "{ (asm DUP2) }",
- "{ (asm DUP3) }",
- "{ (asm DUP4) }",
- "{ (asm DUP5) }",
- "{ (asm DUP6) }",
- "{ (asm DUP7) }",
- "{ (asm DUP8) }",
- "{ (asm DUP9) }",
- "{ (asm DUP10) }",
- "{ (asm DUP11) }",
- "{ (asm DUP12) }",
- "{ (asm DUP13) }",
- "{ (asm DUP14) }",
- "{ (asm DUP15) }",
- "{ (asm DUP16) }",
- "{ (asm SWAP1) }",
- "{ (asm SWAP2) }",
- "{ (asm SWAP3) }",
- "{ (asm SWAP4) }",
- "{ (asm SWAP5) }",
- "{ (asm SWAP6) }",
- "{ (asm SWAP7) }",
- "{ (asm SWAP8) }",
- "{ (asm SWAP9) }",
- "{ (asm SWAP10) }",
- "{ (asm SWAP11) }",
- "{ (asm SWAP12) }",
- "{ (asm SWAP13) }",
- "{ (asm SWAP14) }",
- "{ (asm SWAP15) }",
- "{ (asm SWAP16) }",
- "{ (asm LOG0) }",
- "{ (asm LOG1) }",
- "{ (asm LOG2) }",
- "{ (asm LOG3) }",
- "{ (asm LOG4) }",
- "{ (asm CREATE) }",
- "{ (asm CALL) }",
- "{ (asm CALLCODE) }",
- "{ (asm RETURN) }",
- "{ (asm DELEGATECALL) }",
- "{ (asm STATICCALL) }",
- "{ (asm REVERT) }",
- "{ (asm INVALID) }",
- "{ (asm SELFDESTRUCT) }"
+ "(asm STOP)",
+ "(asm 0 0 ADD)",
+ "(asm 0 0 MUL)",
+ "(asm 0 0 SUB)",
+ "(asm 0 0 DIV)",
+ "(asm 0 0 SDIV)",
+ "(asm 0 0 MOD)",
+ "(asm 0 0 SMOD)",
+ "(asm 0 0 0 ADDMOD)",
+ "(asm 0 0 0 MULMOD)",
+ "(asm 0 0 EXP)",
+ "(asm 0 0 SIGNEXTEND)",
+ "(asm 0 0 LT)",
+ "(asm 0 0 GT)",
+ "(asm 0 0 SLT)",
+ "(asm 0 0 SGT)",
+ "(asm 0 0 EQ)",
+ "(asm 0 ISZERO)",
+ "(asm 0 0 AND)",
+ "(asm 0 0 OR)",
+ "(asm 0 0 XOR)",
+ "(asm 0 NOT)",
+ "(asm 0 0 BYTE)",
+ "(asm 0 0 KECCAK256)",
+ "(asm ADDRESS)",
+ "(asm 0 BALANCE)",
+ "(asm ORIGIN)",
+ "(asm CALLER)",
+ "(asm CALLVALUE)",
+ "(asm 0 CALLDATALOAD)",
+ "(asm CALLDATASIZE)",
+ "(asm 0 0 0 CALLDATACOPY)",
+ "(asm CODESIZE)",
+ "(asm 0 0 0 CODECOPY)",
+ "(asm GASPRICE)",
+ "(asm 0 EXTCODESIZE)",
+ "(asm 0 0 0 0 EXTCODECOPY)",
+ "(asm RETURNDATASIZE)",
+ "(asm 0 0 0 RETURNDATACOPY)",
+ "(asm 0 EXTCODEHASH)",
+ "(asm BLOCKHASH)",
+ "(asm COINBASE)",
+ "(asm TIMESTAMP)",
+ "(asm NUMBER)",
+ "(asm DIFFICULTY)",
+ "(asm GASLIMIT)",
+ "(asm 0 POP)",
+ "(asm 0 MLOAD)",
+ "(asm 0 0 MSTORE)",
+ "(asm 0 0 MSTORE8)",
+ "(asm 0 SLOAD)",
+ "(asm 0 0 SSTORE)",
+ "(asm 0 JUMP)",
+ "(asm 0 0 JUMPI)",
+ "(asm PC)",
+ "(asm MSIZE)",
+ "(asm GAS)",
+ "(asm JUMPDEST)",
+ "(asm 0xff)",
+ "(asm 0xffff)",
+ "(asm 0xffffff)",
+ "(asm 0xffffffff)",
+ "(asm 0xffffffffff)",
+ "(asm 0xffffffffffff)",
+ "(asm 0xffffffffffffff)",
+ "(asm 0xffffffffffffffff)",
+ "(asm 0xffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffffffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffffffffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffffffffffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffffffffffffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffffffffffffffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)",
+ "(asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 DUP1)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 DUP2)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 DUP3)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 DUP4)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 DUP5)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 DUP6)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 DUP7)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 DUP8)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 DUP9)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 DUP10)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 DUP11)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 DUP12)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 DUP13)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 DUP14)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 DUP15)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 DUP16)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SWAP1)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SWAP2)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SWAP3)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SWAP4)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SWAP5)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SWAP6)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SWAP7)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SWAP8)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SWAP9)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SWAP10)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SWAP11)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SWAP12)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SWAP13)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SWAP14)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SWAP15)",
+ "(asm 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SWAP16)",
+ "(asm 0 0 LOG0)",
+ "(asm 0 0 0 LOG1)",
+ "(asm 0 0 0 0 LOG2)",
+ "(asm 0 0 0 0 0 LOG3)",
+ "(asm 0 0 0 0 0 0 LOG4)",
+ "(asm 0 0 0 CREATE)",
+ "(asm 0 0 0 0 0 0 CALL)",
+ "(asm 0 0 0 0 0 0 CALLCODE)",
+ "(asm 0 0 RETURN)",
+ "(asm 0 0 0 0 0 DELEGATECALL)",
+ "(asm 0 0 0 0 0 STATICCALL)",
+ "(asm 0 0 REVERT)",
+ "(asm INVALID)",
+ "(asm 0 SELFDESTRUCT)"
};
for (size_t i = 0; i < opcodes_bytecode.size(); i++)
diff --git a/test/liblll/EndToEndTest.cpp b/test/liblll/EndToEndTest.cpp
index ceaf450e..60aef7b0 100644
--- a/test/liblll/EndToEndTest.cpp
+++ b/test/liblll/EndToEndTest.cpp
@@ -986,6 +986,20 @@ BOOST_AUTO_TEST_CASE(shift_right)
BOOST_CHECK(callFallback() == encodeArgs(u256(256)));
}
+BOOST_AUTO_TEST_CASE(sub_assemblies)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (return (create 0 (returnlll (sstore 1 1)))))
+ )";
+ compileAndRun(sourceCode);
+ bytes ret = callFallback();
+ BOOST_REQUIRE(ret.size() == 32);
+ u256 rVal = u256(toHex(ret, 2, HexPrefix::Add));
+ BOOST_CHECK(rVal != 0);
+ BOOST_CHECK(rVal < u256("0x10000000000000000000000000000000000000000"));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/contracts/LLL_ENS.cpp b/test/liblll/LLL_ENS.cpp
index cfd6970c..cfd6970c 100644
--- a/test/contracts/LLL_ENS.cpp
+++ b/test/liblll/LLL_ENS.cpp
diff --git a/test/contracts/LLL_ERC20.cpp b/test/liblll/LLL_ERC20.cpp
index 6c6762dd..6c6762dd 100644
--- a/test/contracts/LLL_ERC20.cpp
+++ b/test/liblll/LLL_ERC20.cpp
diff --git a/test/libsolidity/AnalysisFramework.cpp b/test/libsolidity/AnalysisFramework.cpp
index 72b86767..ec98026c 100644
--- a/test/libsolidity/AnalysisFramework.cpp
+++ b/test/libsolidity/AnalysisFramework.cpp
@@ -29,7 +29,7 @@
#include <libsolidity/parsing/Scanner.h>
-#include <libdevcore/SHA3.h>
+#include <libdevcore/Keccak256.h>
#include <boost/test/unit_test.hpp>
diff --git a/test/libsolidity/LibSolc.cpp b/test/libsolidity/LibSolc.cpp
index 94fed7e8..09c08700 100644
--- a/test/libsolidity/LibSolc.cpp
+++ b/test/libsolidity/LibSolc.cpp
@@ -40,29 +40,9 @@ namespace test
namespace
{
-Json::Value compileSingle(string const& _input)
-{
- string output(compileJSON(_input.c_str(), dev::test::Options::get().optimize));
- Json::Value ret;
- BOOST_REQUIRE(jsonParseStrict(output, ret));
- return ret;
-}
-
-Json::Value compileMulti(string const& _input, bool _callback)
-{
- string output(
- _callback ?
- compileJSONCallback(_input.c_str(), dev::test::Options::get().optimize, nullptr) :
- compileJSONMulti(_input.c_str(), dev::test::Options::get().optimize)
- );
- Json::Value ret;
- BOOST_REQUIRE(jsonParseStrict(output, ret));
- return ret;
-}
-
Json::Value compile(string const& _input)
{
- string output(compileStandard(_input.c_str(), nullptr));
+ string output(solidity_compile(_input.c_str(), nullptr));
Json::Value ret;
BOOST_REQUIRE(jsonParseStrict(output, ret));
return ret;
@@ -74,113 +54,16 @@ BOOST_AUTO_TEST_SUITE(LibSolc)
BOOST_AUTO_TEST_CASE(read_version)
{
- string output(version());
+ string output(solidity_version());
BOOST_CHECK(output.find(VersionString) == 0);
}
BOOST_AUTO_TEST_CASE(read_license)
{
- string output(license());
+ string output(solidity_license());
BOOST_CHECK(output.find("GNU GENERAL PUBLIC LICENSE") != string::npos);
}
-BOOST_AUTO_TEST_CASE(basic_compilation)
-{
- char const* input = R"(
- {
- "sources": {
- "fileA": "contract A { }"
- }
- }
- )";
- Json::Value result = compileMulti(input, false);
- BOOST_CHECK(result.isObject());
-
- // Compare with compileJSONCallback
- BOOST_CHECK_EQUAL(
- dev::jsonCompactPrint(result),
- dev::jsonCompactPrint(compileMulti(input, true))
- );
-
- BOOST_CHECK(result["contracts"].isObject());
- BOOST_CHECK(result["contracts"]["fileA:A"].isObject());
- Json::Value contract = result["contracts"]["fileA:A"];
- BOOST_CHECK(contract.isObject());
- BOOST_CHECK(contract["interface"].isString());
- BOOST_CHECK_EQUAL(contract["interface"].asString(), "[]");
- BOOST_CHECK(contract["bytecode"].isString());
- BOOST_CHECK_EQUAL(
- dev::test::bytecodeSansMetadata(contract["bytecode"].asString()),
- "6080604052348015600f57600080fd5b50603580601d6000396000f3fe6080604052600080fdfe"
- );
- BOOST_CHECK(contract["runtimeBytecode"].isString());
- BOOST_CHECK_EQUAL(
- dev::test::bytecodeSansMetadata(contract["runtimeBytecode"].asString()),
- "6080604052600080fdfe"
- );
- BOOST_CHECK(contract["functionHashes"].isObject());
- BOOST_CHECK(contract["gasEstimates"].isObject());
- BOOST_CHECK_EQUAL(
- dev::jsonCompactPrint(contract["gasEstimates"]),
- "{\"creation\":[66,10600],\"external\":{},\"internal\":{}}"
- );
- BOOST_CHECK(contract["metadata"].isString());
- BOOST_CHECK(dev::test::isValidMetadata(contract["metadata"].asString()));
- BOOST_CHECK(result["sources"].isObject());
- BOOST_CHECK(result["sources"]["fileA"].isObject());
- BOOST_CHECK(result["sources"]["fileA"]["AST"].isObject());
- BOOST_CHECK_EQUAL(
- dev::jsonCompactPrint(result["sources"]["fileA"]["AST"]),
- "{\"attributes\":{\"absolutePath\":\"fileA\",\"exportedSymbols\":{\"A\":[1]}},"
- "\"children\":[{\"attributes\":{\"baseContracts\":[null],\"contractDependencies\":[null],"
- "\"contractKind\":\"contract\",\"documentation\":null,\"fullyImplemented\":true,\"linearizedBaseContracts\":[1],"
- "\"name\":\"A\",\"nodes\":[null],\"scope\":2},\"id\":1,\"name\":\"ContractDefinition\","
- "\"src\":\"0:14:0\"}],\"id\":2,\"name\":\"SourceUnit\",\"src\":\"0:14:0\"}"
- );
-}
-
-BOOST_AUTO_TEST_CASE(single_compilation)
-{
- Json::Value result = compileSingle("contract A { }");
- BOOST_CHECK(result.isObject());
-
- BOOST_CHECK(result["contracts"].isObject());
- BOOST_CHECK(result["contracts"][":A"].isObject());
- Json::Value contract = result["contracts"][":A"];
- BOOST_CHECK(contract.isObject());
- BOOST_CHECK(contract["interface"].isString());
- BOOST_CHECK_EQUAL(contract["interface"].asString(), "[]");
- BOOST_CHECK(contract["bytecode"].isString());
- BOOST_CHECK_EQUAL(
- dev::test::bytecodeSansMetadata(contract["bytecode"].asString()),
- "6080604052348015600f57600080fd5b50603580601d6000396000f3fe6080604052600080fdfe"
- );
- BOOST_CHECK(contract["runtimeBytecode"].isString());
- BOOST_CHECK_EQUAL(
- dev::test::bytecodeSansMetadata(contract["runtimeBytecode"].asString()),
- "6080604052600080fdfe"
- );
- BOOST_CHECK(contract["functionHashes"].isObject());
- BOOST_CHECK(contract["gasEstimates"].isObject());
- BOOST_CHECK_EQUAL(
- dev::jsonCompactPrint(contract["gasEstimates"]),
- "{\"creation\":[66,10600],\"external\":{},\"internal\":{}}"
- );
- BOOST_CHECK(contract["metadata"].isString());
- BOOST_CHECK(dev::test::isValidMetadata(contract["metadata"].asString()));
- BOOST_CHECK(result["sources"].isObject());
- BOOST_CHECK(result["sources"][""].isObject());
- BOOST_CHECK(result["sources"][""]["AST"].isObject());
- BOOST_CHECK_EQUAL(
- dev::jsonCompactPrint(result["sources"][""]["AST"]),
- "{\"attributes\":{\"absolutePath\":\"\",\"exportedSymbols\":{\"A\":[1]}},"
- "\"children\":[{\"attributes\":{\"baseContracts\":[null],\"contractDependencies\":[null],"
- "\"contractKind\":\"contract\",\"documentation\":null,\"fullyImplemented\":true,\"linearizedBaseContracts\":[1],"
- "\"name\":\"A\",\"nodes\":[null],\"scope\":2},\"id\":1,\"name\":\"ContractDefinition\","
- "\"src\":\"0:14:0\"}],\"id\":2,\"name\":\"SourceUnit\",\"src\":\"0:14:0\"}"
- );
-}
-
BOOST_AUTO_TEST_CASE(standard_compilation)
{
char const* input = R"(
@@ -201,26 +84,6 @@ BOOST_AUTO_TEST_CASE(standard_compilation)
BOOST_CHECK(result.isMember("contracts"));
}
-BOOST_AUTO_TEST_CASE(new_api)
-{
- char const* input = R"(
- {
- "language": "Solidity",
- "sources": {
- "fileA": {
- "content": "contract A { }"
- }
- }
- }
- )";
- BOOST_CHECK_EQUAL(string(version()), string(solidity_version()));
- BOOST_CHECK_EQUAL(string(license()), string(solidity_license()));
- BOOST_CHECK_EQUAL(
- string(compileStandard(input, nullptr)),
- string(solidity_compile(input, nullptr))
- );
-}
-
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index 640bf4d0..5ec010c7 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -26,7 +26,7 @@
#include <libsolidity/ast/AST.h>
-#include <libdevcore/SHA3.h>
+#include <libdevcore/Keccak256.h>
#include <boost/test/unit_test.hpp>
diff --git a/test/libsolidity/SolidityTypes.cpp b/test/libsolidity/SolidityTypes.cpp
index ee637261..6f9d4ce8 100644
--- a/test/libsolidity/SolidityTypes.cpp
+++ b/test/libsolidity/SolidityTypes.cpp
@@ -22,7 +22,7 @@
#include <libsolidity/ast/Types.h>
#include <libsolidity/ast/AST.h>
-#include <libdevcore/SHA3.h>
+#include <libdevcore/Keccak256.h>
#include <boost/test/unit_test.hpp>
using namespace std;
diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/unimplemented_internal.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/unimplemented_internal.sol
new file mode 100644
index 00000000..8bce0dd2
--- /dev/null
+++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/unimplemented_internal.sol
@@ -0,0 +1,4 @@
+contract C {
+ function f() internal returns(uint[] storage);
+ function g() internal returns(uint[] storage s);
+}
diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/unimplemented_library.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/unimplemented_library.sol
new file mode 100644
index 00000000..818b6a20
--- /dev/null
+++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/unimplemented_library.sol
@@ -0,0 +1,4 @@
+library L {
+ function f() public returns(uint[] storage);
+ function g() public returns(uint[] storage s);
+}
diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/102_duplicate_parameter_names_in_named_args.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/102_duplicate_parameter_names_in_named_args.sol
index fab4beff..88402fa3 100644
--- a/test/libsolidity/syntaxTests/nameAndTypeResolution/102_duplicate_parameter_names_in_named_args.sol
+++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/102_duplicate_parameter_names_in_named_args.sol
@@ -8,4 +8,4 @@ contract test {
}
// ----
// Warning: (31-37): This declaration shadows an existing declaration.
-// TypeError: (159-160): Duplicate named argument.
+// TypeError: (159-160): Duplicate named argument "a".
diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/583_abi_encode_packed_with_rational_number_constant.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/583_abi_encode_packed_with_rational_number_constant.sol
new file mode 100644
index 00000000..6be591f6
--- /dev/null
+++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/583_abi_encode_packed_with_rational_number_constant.sol
@@ -0,0 +1,5 @@
+contract C {
+ function f() pure public { abi.encodePacked(0/1); }
+}
+// ----
+// TypeError: (61-64): Cannot perform packed encoding for a literal. Please convert it to an explicit type first. \ No newline at end of file
diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/584_abi_decode_with_tuple_of_other_than_types.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/584_abi_decode_with_tuple_of_other_than_types.sol
new file mode 100644
index 00000000..c95eeb35
--- /dev/null
+++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/584_abi_decode_with_tuple_of_other_than_types.sol
@@ -0,0 +1,5 @@
+contract C {
+ function f() pure public { abi.decode("", (0)); }
+}
+// ----
+// TypeError: (60-61): Argument has to be a type name.
diff --git a/test/libyul/Inliner.cpp b/test/libyul/Inliner.cpp
index 4ed52b47..66810298 100644
--- a/test/libyul/Inliner.cpp
+++ b/test/libyul/Inliner.cpp
@@ -71,7 +71,7 @@ BOOST_AUTO_TEST_CASE(simple)
BOOST_CHECK_EQUAL(inlinableFunctions("{"
"function g(a:u256) -> b:u256 { b := a }"
"function f() -> x:u256 { x := g(2:u256) }"
- "}"), "f,g");
+ "}"), "g,f");
}
BOOST_AUTO_TEST_CASE(simple_inside_structures)
@@ -82,7 +82,7 @@ BOOST_AUTO_TEST_CASE(simple_inside_structures)
"function g(a:u256) -> b:u256 { b := a }"
"function f() -> x:u256 { x := g(2:u256) }"
"}"
- "}"), "f,g");
+ "}"), "g,f");
BOOST_CHECK_EQUAL(inlinableFunctions("{"
"for {"
"function g(a:u256) -> b:u256 { b := a }"
@@ -92,7 +92,7 @@ BOOST_AUTO_TEST_CASE(simple_inside_structures)
"{"
"function h() -> y:u256 { y := 2:u256 }"
"}"
- "}"), "f,g,h");
+ "}"), "h,g,f");
}
BOOST_AUTO_TEST_CASE(negative)
diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp
index d455c892..03cd6446 100644
--- a/test/libyul/YulOptimizerTest.cpp
+++ b/test/libyul/YulOptimizerTest.cpp
@@ -118,6 +118,19 @@ bool YulOptimizerTest::run(ostream& _stream, string const& _linePrefix, bool con
NameDispenser nameDispenser(*m_ast);
ExpressionSplitter{nameDispenser}(*m_ast);
}
+ else if (m_optimizerStep == "expressionJoiner")
+ {
+ disambiguate();
+ ExpressionJoiner::run(*m_ast);
+ }
+ else if (m_optimizerStep == "splitJoin")
+ {
+ disambiguate();
+ NameDispenser nameDispenser(*m_ast);
+ ExpressionSplitter{nameDispenser}(*m_ast);
+ ExpressionJoiner::run(*m_ast);
+ ExpressionJoiner::run(*m_ast);
+ }
else if (m_optimizerStep == "functionGrouper")
{
disambiguate();
@@ -175,11 +188,6 @@ bool YulOptimizerTest::run(ostream& _stream, string const& _linePrefix, bool con
disambiguate();
UnusedPruner::runUntilStabilised(*m_ast);
}
- else if (m_optimizerStep == "expressionJoiner")
- {
- disambiguate();
- ExpressionJoiner::run(*m_ast);\
- }
else if (m_optimizerStep == "ssaTransform")
{
disambiguate();
diff --git a/test/libyul/yulOptimizerTests/fullInliner/multi_fun_callback.yul b/test/libyul/yulOptimizerTests/fullInliner/multi_fun_callback.yul
index d09877de..19ac945e 100644
--- a/test/libyul/yulOptimizerTests/fullInliner/multi_fun_callback.yul
+++ b/test/libyul/yulOptimizerTests/fullInliner/multi_fun_callback.yul
@@ -41,18 +41,19 @@
// h_t := 2
// mstore(7, h_t)
// let g_x_1 := 10
-// f(1)
+// let g_f_x_8 := 1
+// mstore(0, g_f_x_8)
+// mstore(7, h())
+// g(10)
+// mstore(1, g_f_x_8)
// mstore(1, x)
// }
// function g(x_1)
// {
// let f_x_8 := 1
// mstore(0, f_x_8)
-// let f_h_t
-// f_h_t := 2
-// mstore(7, f_h_t)
-// let f_g_x_1 := 10
-// f(1)
+// mstore(7, h())
+// g(10)
// mstore(1, f_x_8)
// }
// function h() -> t
diff --git a/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul b/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul
new file mode 100644
index 00000000..a34da198
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul
@@ -0,0 +1,654 @@
+{
+ let x := abi_encode_t_array$_t_array$_t_contract$_C_$55_$3_memory_$dyn_memory_ptr_to_t_array$_t_array$_t_address_$3_memory_$dyn_memory_ptr(mload(0), 0x20)
+ let a, b, c, d := abi_decode_tuple_t_uint256t_uint256t_array$_t_uint256_$dyn_memory_ptrt_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(mload(0x20), mload(0x40))
+ sstore(a, b)
+ sstore(c, d)
+ sstore(0, x)
+
+ function abi_decode_t_address(offset, end) -> value
+ {
+ value := cleanup_revert_t_address(calldataload(offset))
+ }
+ function abi_decode_t_array$_t_address_$dyn_memory(offset, end) -> array
+ {
+ if iszero(slt(add(offset, 0x1f), end))
+ {
+ revert(0, 0)
+ }
+ let length := calldataload(offset)
+ array := allocateMemory(array_allocation_size_t_array$_t_address_$dyn_memory(length))
+ let dst := array
+ mstore(array, length)
+ offset := add(offset, 0x20)
+ dst := add(dst, 0x20)
+ let src := offset
+ if gt(add(src, mul(length, 0x20)), end)
+ {
+ revert(0, 0)
+ }
+ for {
+ let i := 0
+ }
+ lt(i, length)
+ {
+ i := add(i, 1)
+ }
+ {
+ let elementPos := src
+ mstore(dst, abi_decode_t_address(elementPos, end))
+ dst := add(dst, 0x20)
+ src := add(src, 0x20)
+ }
+ }
+ function abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(offset, end) -> array
+ {
+ if iszero(slt(add(offset, 0x1f), end))
+ {
+ revert(0, 0)
+ }
+ let length := calldataload(offset)
+ array := allocateMemory(array_allocation_size_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(length))
+ let dst := array
+ mstore(array, length)
+ offset := add(offset, 0x20)
+ dst := add(dst, 0x20)
+ let src := offset
+ if gt(add(src, mul(length, 0x40)), end)
+ {
+ revert(0, 0)
+ }
+ for {
+ let i := 0
+ }
+ lt(i, length)
+ {
+ i := add(i, 1)
+ }
+ {
+ let elementPos := src
+ mstore(dst, abi_decode_t_array$_t_uint256_$2_memory(elementPos, end))
+ dst := add(dst, 0x20)
+ src := add(src, 0x40)
+ }
+ }
+ function abi_decode_t_array$_t_uint256_$2_memory(offset, end) -> array
+ {
+ if iszero(slt(add(offset, 0x1f), end))
+ {
+ revert(0, 0)
+ }
+ let length := 0x2
+ array := allocateMemory(array_allocation_size_t_array$_t_uint256_$2_memory(length))
+ let dst := array
+ let src := offset
+ if gt(add(src, mul(length, 0x20)), end)
+ {
+ revert(0, 0)
+ }
+ for {
+ let i := 0
+ }
+ lt(i, length)
+ {
+ i := add(i, 1)
+ }
+ {
+ let elementPos := src
+ mstore(dst, abi_decode_t_uint256(elementPos, end))
+ dst := add(dst, 0x20)
+ src := add(src, 0x20)
+ }
+ }
+ function abi_decode_t_array$_t_uint256_$dyn_memory(offset, end) -> array
+ {
+ if iszero(slt(add(offset, 0x1f), end))
+ {
+ revert(0, 0)
+ }
+ let length := calldataload(offset)
+ array := allocateMemory(array_allocation_size_t_array$_t_uint256_$dyn_memory(length))
+ let dst := array
+ mstore(array, length)
+ offset := add(offset, 0x20)
+ dst := add(dst, 0x20)
+ let src := offset
+ if gt(add(src, mul(length, 0x20)), end)
+ {
+ revert(0, 0)
+ }
+ for {
+ let i := 0
+ }
+ lt(i, length)
+ {
+ i := add(i, 1)
+ }
+ {
+ let elementPos := src
+ mstore(dst, abi_decode_t_uint256(elementPos, end))
+ dst := add(dst, 0x20)
+ src := add(src, 0x20)
+ }
+ }
+ function abi_decode_t_array$_t_uint256_$dyn_memory_ptr(offset, end) -> array
+ {
+ if iszero(slt(add(offset, 0x1f), end))
+ {
+ revert(0, 0)
+ }
+ let length := calldataload(offset)
+ array := allocateMemory(array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr(length))
+ let dst := array
+ mstore(array, length)
+ offset := add(offset, 0x20)
+ dst := add(dst, 0x20)
+ let src := offset
+ if gt(add(src, mul(length, 0x20)), end)
+ {
+ revert(0, 0)
+ }
+ for {
+ let i := 0
+ }
+ lt(i, length)
+ {
+ i := add(i, 1)
+ }
+ {
+ let elementPos := src
+ mstore(dst, abi_decode_t_uint256(elementPos, end))
+ dst := add(dst, 0x20)
+ src := add(src, 0x20)
+ }
+ }
+ function abi_decode_t_contract$_C_$55(offset, end) -> value
+ {
+ value := cleanup_revert_t_contract$_C_$55(calldataload(offset))
+ }
+ function abi_decode_t_struct$_S_$11_memory_ptr(headStart, end) -> value
+ {
+ if slt(sub(end, headStart), 0x60)
+ {
+ revert(0, 0)
+ }
+ value := allocateMemory(0x60)
+ {
+ let offset := 0
+ mstore(add(value, 0x0), abi_decode_t_uint256(add(headStart, offset), end))
+ }
+ {
+ let offset := calldataload(add(headStart, 32))
+ if gt(offset, 0xffffffffffffffff)
+ {
+ revert(0, 0)
+ }
+ mstore(add(value, 0x20), abi_decode_t_array$_t_uint256_$dyn_memory(add(headStart, offset), end))
+ }
+ {
+ let offset := calldataload(add(headStart, 64))
+ if gt(offset, 0xffffffffffffffff)
+ {
+ revert(0, 0)
+ }
+ mstore(add(value, 0x40), abi_decode_t_array$_t_address_$dyn_memory(add(headStart, offset), end))
+ }
+ }
+ function abi_decode_t_uint256(offset, end) -> value
+ {
+ value := cleanup_revert_t_uint256(calldataload(offset))
+ }
+ function abi_decode_t_uint8(offset, end) -> value
+ {
+ value := cleanup_revert_t_uint8(calldataload(offset))
+ }
+ function abi_decode_tuple_t_contract$_C_$55t_uint8(headStart, dataEnd) -> value0, value1
+ {
+ if slt(sub(dataEnd, headStart), 64)
+ {
+ revert(0, 0)
+ }
+ {
+ let offset := 0
+ value0 := abi_decode_t_contract$_C_$55(add(headStart, offset), dataEnd)
+ }
+ {
+ let offset := 32
+ value1 := abi_decode_t_uint8(add(headStart, offset), dataEnd)
+ }
+ }
+ function abi_decode_tuple_t_struct$_S_$11_memory_ptrt_uint256(headStart, dataEnd) -> value0, value1
+ {
+ if slt(sub(dataEnd, headStart), 64)
+ {
+ revert(0, 0)
+ }
+ {
+ let offset := calldataload(add(headStart, 0))
+ if gt(offset, 0xffffffffffffffff)
+ {
+ revert(0, 0)
+ }
+ value0 := abi_decode_t_struct$_S_$11_memory_ptr(add(headStart, offset), dataEnd)
+ }
+ {
+ let offset := 32
+ value1 := abi_decode_t_uint256(add(headStart, offset), dataEnd)
+ }
+ }
+ function abi_decode_tuple_t_uint256t_uint256t_array$_t_uint256_$dyn_memory_ptrt_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(headStart, dataEnd) -> value0, value1, value2, value3
+ {
+ if slt(sub(dataEnd, headStart), 128)
+ {
+ revert(0, 0)
+ }
+ {
+ let offset := 0
+ value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd)
+ }
+ {
+ let offset := 32
+ value1 := abi_decode_t_uint256(add(headStart, offset), dataEnd)
+ }
+ {
+ let offset := calldataload(add(headStart, 64))
+ if gt(offset, 0xffffffffffffffff)
+ {
+ revert(0, 0)
+ }
+ value2 := abi_decode_t_array$_t_uint256_$dyn_memory_ptr(add(headStart, offset), dataEnd)
+ }
+ {
+ let offset := calldataload(add(headStart, 96))
+ if gt(offset, 0xffffffffffffffff)
+ {
+ revert(0, 0)
+ }
+ value3 := abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(add(headStart, offset), dataEnd)
+ }
+ }
+ function abi_encode_t_array$_t_array$_t_contract$_C_$55_$3_memory_$dyn_memory_ptr_to_t_array$_t_array$_t_address_$3_memory_$dyn_memory_ptr(value, pos) -> end
+ {
+ let length := array_length_t_array$_t_array$_t_contract$_C_$55_$3_memory_$dyn_memory_ptr(value)
+ mstore(pos, length)
+ pos := add(pos, 0x20)
+ let srcPtr := array_dataslot_t_array$_t_array$_t_contract$_C_$55_$3_memory_$dyn_memory_ptr(value)
+ for {
+ let i := 0
+ }
+ lt(i, length)
+ {
+ i := add(i, 1)
+ }
+ {
+ abi_encode_t_array$_t_contract$_C_$55_$3_memory_to_t_array$_t_address_$3_memory_ptr(mload(srcPtr), pos)
+ srcPtr := array_nextElement_t_array$_t_array$_t_contract$_C_$55_$3_memory_$dyn_memory_ptr(srcPtr)
+ pos := add(pos, 0x60)
+ }
+ end := pos
+ }
+ function abi_encode_t_array$_t_contract$_C_$55_$3_memory_to_t_array$_t_address_$3_memory_ptr(value, pos)
+ {
+ let length := array_length_t_array$_t_contract$_C_$55_$3_memory(value)
+ let srcPtr := array_dataslot_t_array$_t_contract$_C_$55_$3_memory(value)
+ for {
+ let i := 0
+ }
+ lt(i, length)
+ {
+ i := add(i, 1)
+ }
+ {
+ abi_encode_t_contract$_C_$55_to_t_address(mload(srcPtr), pos)
+ srcPtr := array_nextElement_t_array$_t_contract$_C_$55_$3_memory(srcPtr)
+ pos := add(pos, 0x20)
+ }
+ }
+ function abi_encode_t_bool_to_t_bool(value, pos)
+ {
+ mstore(pos, cleanup_assert_t_bool(value))
+ }
+ function abi_encode_t_contract$_C_$55_to_t_address(value, pos)
+ {
+ mstore(pos, convert_t_contract$_C_$55_to_t_address(value))
+ }
+ function abi_encode_t_uint16_to_t_uint16(value, pos)
+ {
+ mstore(pos, cleanup_assert_t_uint16(value))
+ }
+ function abi_encode_t_uint24_to_t_uint24(value, pos)
+ {
+ mstore(pos, cleanup_assert_t_uint24(value))
+ }
+ function abi_encode_tuple_t_bool__to_t_bool_(headStart, value0) -> tail
+ {
+ tail := add(headStart, 32)
+ abi_encode_t_bool_to_t_bool(value0, add(headStart, 0))
+ }
+ function abi_encode_tuple_t_uint16_t_uint24_t_array$_t_array$_t_contract$_C_$55_$3_memory_$dyn_memory_ptr__to_t_uint16_t_uint24_t_array$_t_array$_t_address_$3_memory_$dyn_memory_ptr_(headStart, value2, value1, value0) -> tail
+ {
+ tail := add(headStart, 96)
+ abi_encode_t_uint16_to_t_uint16(value0, add(headStart, 0))
+ abi_encode_t_uint24_to_t_uint24(value1, add(headStart, 32))
+ mstore(add(headStart, 64), sub(tail, headStart))
+ tail := abi_encode_t_array$_t_array$_t_contract$_C_$55_$3_memory_$dyn_memory_ptr_to_t_array$_t_array$_t_address_$3_memory_$dyn_memory_ptr(value2, tail)
+ }
+ function allocateMemory(size) -> memPtr
+ {
+ memPtr := mload(64)
+ let newFreePtr := add(memPtr, size)
+ if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr))
+ {
+ revert(0, 0)
+ }
+ mstore(64, newFreePtr)
+ }
+ function array_allocation_size_t_array$_t_address_$dyn_memory(length) -> size
+ {
+ if gt(length, 0xffffffffffffffff)
+ {
+ revert(0, 0)
+ }
+ size := mul(length, 0x20)
+ size := add(size, 0x20)
+ }
+ function array_allocation_size_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(length) -> size
+ {
+ if gt(length, 0xffffffffffffffff)
+ {
+ revert(0, 0)
+ }
+ size := mul(length, 0x20)
+ size := add(size, 0x20)
+ }
+ function array_allocation_size_t_array$_t_uint256_$2_memory(length) -> size
+ {
+ if gt(length, 0xffffffffffffffff)
+ {
+ revert(0, 0)
+ }
+ size := mul(length, 0x20)
+ }
+ function array_allocation_size_t_array$_t_uint256_$dyn_memory(length) -> size
+ {
+ if gt(length, 0xffffffffffffffff)
+ {
+ revert(0, 0)
+ }
+ size := mul(length, 0x20)
+ size := add(size, 0x20)
+ }
+ function array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr(length) -> size
+ {
+ if gt(length, 0xffffffffffffffff)
+ {
+ revert(0, 0)
+ }
+ size := mul(length, 0x20)
+ size := add(size, 0x20)
+ }
+ function array_dataslot_t_array$_t_array$_t_contract$_C_$55_$3_memory_$dyn_memory_ptr(memPtr) -> dataPtr
+ {
+ dataPtr := add(memPtr, 0x20)
+ }
+ function array_dataslot_t_array$_t_contract$_C_$55_$3_memory(memPtr) -> dataPtr
+ {
+ dataPtr := memPtr
+ }
+ function array_length_t_array$_t_array$_t_contract$_C_$55_$3_memory_$dyn_memory_ptr(value) -> length
+ {
+ length := mload(value)
+ }
+ function array_length_t_array$_t_contract$_C_$55_$3_memory(value) -> length
+ {
+ length := 0x3
+ }
+ function array_nextElement_t_array$_t_array$_t_contract$_C_$55_$3_memory_$dyn_memory_ptr(memPtr) -> nextPtr
+ {
+ nextPtr := add(memPtr, 0x20)
+ }
+ function array_nextElement_t_array$_t_contract$_C_$55_$3_memory(memPtr) -> nextPtr
+ {
+ nextPtr := add(memPtr, 0x20)
+ }
+ function cleanup_assert_t_address(value) -> cleaned
+ {
+ cleaned := cleanup_assert_t_uint160(value)
+ }
+ function cleanup_assert_t_bool(value) -> cleaned
+ {
+ cleaned := iszero(iszero(value))
+ }
+ function cleanup_assert_t_uint16(value) -> cleaned
+ {
+ cleaned := and(value, 0xFFFF)
+ }
+ function cleanup_assert_t_uint160(value) -> cleaned
+ {
+ cleaned := and(value, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
+ }
+ function cleanup_assert_t_uint24(value) -> cleaned
+ {
+ cleaned := and(value, 0xFFFFFF)
+ }
+ function cleanup_revert_t_address(value) -> cleaned
+ {
+ cleaned := cleanup_assert_t_uint160(value)
+ }
+ function cleanup_revert_t_contract$_C_$55(value) -> cleaned
+ {
+ cleaned := cleanup_assert_t_address(value)
+ }
+ function cleanup_revert_t_uint256(value) -> cleaned
+ {
+ cleaned := value
+ }
+ function cleanup_revert_t_uint8(value) -> cleaned
+ {
+ cleaned := and(value, 0xFF)
+ }
+ function convert_t_contract$_C_$55_to_t_address(value) -> converted
+ {
+ converted := convert_t_contract$_C_$55_to_t_uint160(value)
+ }
+ function convert_t_contract$_C_$55_to_t_uint160(value) -> converted
+ {
+ converted := cleanup_assert_t_uint160(value)
+ }
+}
+// ----
+// fullSuite
+// {
+// {
+// let _1 := 0x20
+// let _2 := 0
+// let _485 := mload(_2)
+// let abi_encode_pos := _1
+// let abi_encode_length_68 := mload(_485)
+// mstore(_1, abi_encode_length_68)
+// let abi_encode_pos_590 := 64
+// abi_encode_pos := abi_encode_pos_590
+// let abi_encode_srcPtr := add(_485, _1)
+// for {
+// let abi_encode_i_69 := _2
+// }
+// lt(abi_encode_i_69, abi_encode_length_68)
+// {
+// abi_encode_i_69 := add(abi_encode_i_69, 1)
+// }
+// {
+// let _931 := mload(abi_encode_srcPtr)
+// let abi_encode_pos_71_1037 := abi_encode_pos
+// let abi_encode_length_72_1038 := 0x3
+// let abi_encode_srcPtr_73_1039 := _931
+// for {
+// let abi_encode_i_74_1040 := _2
+// }
+// lt(abi_encode_i_74_1040, abi_encode_length_72_1038)
+// {
+// abi_encode_i_74_1040 := add(abi_encode_i_74_1040, 1)
+// }
+// {
+// mstore(abi_encode_pos_71_1037, and(mload(abi_encode_srcPtr_73_1039), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
+// abi_encode_srcPtr_73_1039 := add(abi_encode_srcPtr_73_1039, _1)
+// abi_encode_pos_71_1037 := add(abi_encode_pos_71_1037, _1)
+// }
+// abi_encode_srcPtr := add(abi_encode_srcPtr, _1)
+// abi_encode_pos := add(abi_encode_pos, 0x60)
+// }
+// let _933 := 0x40
+// let _487 := mload(_933)
+// let _488 := mload(_1)
+// let abi_decode_value0_60_618
+// let abi_decode_value0_60 := abi_decode_value0_60_618
+// let abi_decode_value1_61_619
+// let abi_decode_value1_61 := abi_decode_value1_61_619
+// let abi_decode_value2_620
+// let abi_decode_value2 := abi_decode_value2_620
+// let abi_decode_value3_621
+// let abi_decode_value3 := abi_decode_value3_621
+// if slt(sub(_487, _488), 128)
+// {
+// revert(_2, _2)
+// }
+// {
+// abi_decode_value0_60 := calldataload(_488)
+// }
+// {
+// abi_decode_value1_61 := calldataload(add(_488, 32))
+// }
+// {
+// let abi_decode_offset_64 := calldataload(add(_488, abi_encode_pos_590))
+// let _940 := 0xffffffffffffffff
+// if gt(abi_decode_offset_64, _940)
+// {
+// revert(_2, _2)
+// }
+// let _942 := add(_488, abi_decode_offset_64)
+// if iszero(slt(add(_942, 0x1f), _487))
+// {
+// revert(_2, _2)
+// }
+// let abi_decode_length_30_1046 := calldataload(_942)
+// if gt(abi_decode_length_30_1046, _940)
+// {
+// revert(_2, _2)
+// }
+// let abi_decode_array_allo__561 := mul(abi_decode_length_30_1046, _1)
+// let abi_decode_array_29_279_1047 := allocateMemory(add(abi_decode_array_allo__561, _1))
+// let abi_decode_dst_31_1048 := abi_decode_array_29_279_1047
+// mstore(abi_decode_array_29_279_1047, abi_decode_length_30_1046)
+// let abi_decode_offset_27_281_1049 := add(_942, _1)
+// abi_decode_dst_31_1048 := add(abi_decode_array_29_279_1047, _1)
+// let abi_decode_src_32_1050 := abi_decode_offset_27_281_1049
+// if gt(add(add(_942, abi_decode_array_allo__561), _1), _487)
+// {
+// revert(_2, _2)
+// }
+// for {
+// let abi_decode_i_33_1052 := _2
+// }
+// lt(abi_decode_i_33_1052, abi_decode_length_30_1046)
+// {
+// abi_decode_i_33_1052 := add(abi_decode_i_33_1052, 1)
+// }
+// {
+// mstore(abi_decode_dst_31_1048, calldataload(abi_decode_src_32_1050))
+// abi_decode_dst_31_1048 := add(abi_decode_dst_31_1048, _1)
+// abi_decode_src_32_1050 := add(abi_decode_src_32_1050, _1)
+// }
+// abi_decode_value2 := abi_decode_array_29_279_1047
+// }
+// {
+// let abi_decode_offset_65 := calldataload(add(_488, 96))
+// let _945 := 0xffffffffffffffff
+// if gt(abi_decode_offset_65, _945)
+// {
+// revert(_2, _2)
+// }
+// let _947 := add(_488, abi_decode_offset_65)
+// let abi_decode__489_1056 := 0x1f
+// if iszero(slt(add(_947, abi_decode__489_1056), _487))
+// {
+// revert(_2, _2)
+// }
+// let abi_decode_length_6_1058 := calldataload(_947)
+// if gt(abi_decode_length_6_1058, _945)
+// {
+// revert(_2, _2)
+// }
+// let abi_decode_array_5_254_1061 := allocateMemory(add(mul(abi_decode_length_6_1058, _1), _1))
+// let abi_decode_dst_7_1062 := abi_decode_array_5_254_1061
+// mstore(abi_decode_array_5_254_1061, abi_decode_length_6_1058)
+// let abi_decode_offset_3_256_1063 := add(_947, _1)
+// abi_decode_dst_7_1062 := add(abi_decode_array_5_254_1061, _1)
+// let abi_decode_src_8_1064 := abi_decode_offset_3_256_1063
+// if gt(add(add(_947, mul(abi_decode_length_6_1058, _933)), _1), _487)
+// {
+// revert(_2, _2)
+// }
+// for {
+// let abi_decode_i_9_1068 := _2
+// }
+// lt(abi_decode_i_9_1068, abi_decode_length_6_1058)
+// {
+// abi_decode_i_9_1068 := add(abi_decode_i_9_1068, 1)
+// }
+// {
+// if iszero(slt(add(abi_decode_src_8_1064, abi_decode__489_1056), _487))
+// {
+// revert(_2, _2)
+// }
+// let abi_decode_abi_decode_length_14_1069 := 0x2
+// if _2
+// {
+// revert(_2, _2)
+// }
+// let allocateMe_memPtr_315 := mload(abi_encode_pos_590)
+// let allocateMe_newFreePtr := add(allocateMe_memPtr_315, abi_encode_pos_590)
+// if or(gt(allocateMe_newFreePtr, _945), lt(allocateMe_newFreePtr, allocateMe_memPtr_315))
+// {
+// revert(_2, _2)
+// }
+// mstore(abi_encode_pos_590, allocateMe_newFreePtr)
+// let abi_decode_abi_decode_dst_15_1071 := allocateMe_memPtr_315
+// let abi_decode_abi_decode_src_16_1072 := abi_decode_src_8_1064
+// if gt(add(abi_decode_src_8_1064, abi_encode_pos_590), _487)
+// {
+// revert(_2, _2)
+// }
+// for {
+// let abi_decode_abi_decode_i_17_1073 := _2
+// }
+// lt(abi_decode_abi_decode_i_17_1073, abi_decode_abi_decode_length_14_1069)
+// {
+// abi_decode_abi_decode_i_17_1073 := add(abi_decode_abi_decode_i_17_1073, 1)
+// }
+// {
+// mstore(abi_decode_abi_decode_dst_15_1071, calldataload(abi_decode_abi_decode_src_16_1072))
+// abi_decode_abi_decode_dst_15_1071 := add(abi_decode_abi_decode_dst_15_1071, _1)
+// abi_decode_abi_decode_src_16_1072 := add(abi_decode_abi_decode_src_16_1072, _1)
+// }
+// mstore(abi_decode_dst_7_1062, allocateMe_memPtr_315)
+// abi_decode_dst_7_1062 := add(abi_decode_dst_7_1062, _1)
+// abi_decode_src_8_1064 := add(abi_decode_src_8_1064, _933)
+// }
+// abi_decode_value3 := abi_decode_array_5_254_1061
+// }
+// sstore(abi_decode_value0_60, abi_decode_value1_61)
+// sstore(abi_decode_value2, abi_decode_value3)
+// sstore(_2, abi_encode_pos)
+// }
+// function allocateMemory(size) -> memPtr
+// {
+// let _199 := 64
+// let memPtr_315 := mload(_199)
+// memPtr := memPtr_315
+// let newFreePtr := add(memPtr_315, size)
+// if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr_315))
+// {
+// let _204 := 0
+// revert(_204, _204)
+// }
+// mstore(_199, newFreePtr)
+// }
+// }
diff --git a/test/libyul/yulOptimizerTests/fullSuite/medium.yul b/test/libyul/yulOptimizerTests/fullSuite/medium.yul
index 47812fa8..deb02068 100644
--- a/test/libyul/yulOptimizerTests/fullSuite/medium.yul
+++ b/test/libyul/yulOptimizerTests/fullSuite/medium.yul
@@ -16,9 +16,7 @@
// {
// let _18 := 0x20
// let allocate__7 := 0x40
-// let allocate_p_12 := mload(allocate__7)
-// mstore(allocate__7, add(allocate_p_12, _18))
-// pop(allocate_p_12)
+// mstore(allocate__7, add(mload(allocate__7), _18))
// let allocate_p_12_31 := mload(allocate__7)
// mstore(allocate__7, add(allocate_p_12_31, allocate__7))
// mstore(add(allocate_p_12_31, 96), 2)
diff --git a/test/libyul/yulOptimizerTests/splitJoin/control_flow.yul b/test/libyul/yulOptimizerTests/splitJoin/control_flow.yul
new file mode 100644
index 00000000..ad609c74
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/splitJoin/control_flow.yul
@@ -0,0 +1,26 @@
+{
+ if mul(add(calldataload(0), 2), 3) {
+ for { let a := 2 } lt(a, mload(a)) { a := add(a, mul(a, 2)) } {
+ let b := mul(add(a, 2), 4)
+ sstore(b, mul(b, 2))
+ }
+ }
+}
+// ----
+// splitJoin
+// {
+// if mul(add(calldataload(0), 2), 3)
+// {
+// for {
+// let a := 2
+// }
+// lt(a, mload(a))
+// {
+// a := add(a, mul(a, 2))
+// }
+// {
+// let b := mul(add(a, 2), 4)
+// sstore(b, mul(b, 2))
+// }
+// }
+// }
diff --git a/test/libyul/yulOptimizerTests/splitJoin/functions.yul b/test/libyul/yulOptimizerTests/splitJoin/functions.yul
new file mode 100644
index 00000000..549fc550
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/splitJoin/functions.yul
@@ -0,0 +1,30 @@
+{
+ let x := f(0)
+ function f(y) -> r {
+ r := mload(mul(6, add(y, 0x20)))
+ }
+ for { let a := 2 } lt(a, mload(a)) { a := add(a, mul(a, 2)) } {
+ let b := mul(add(a, f(a)), 4)
+ sstore(b, mul(b, 2))
+ }
+}
+// ----
+// splitJoin
+// {
+// let x := f(0)
+// function f(y) -> r
+// {
+// r := mload(mul(6, add(y, 0x20)))
+// }
+// for {
+// let a := 2
+// }
+// lt(a, mload(a))
+// {
+// a := add(a, mul(a, 2))
+// }
+// {
+// let b := mul(add(a, f(a)), 4)
+// sstore(b, mul(b, 2))
+// }
+// }
diff --git a/test/libyul/yulOptimizerTests/splitJoin/smoke.yul b/test/libyul/yulOptimizerTests/splitJoin/smoke.yul
new file mode 100644
index 00000000..4b133029
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/splitJoin/smoke.yul
@@ -0,0 +1,5 @@
+{}
+// ----
+// splitJoin
+// {
+// }
diff --git a/test/libyul/yulOptimizerTests/unusedPruner/pop.yul b/test/libyul/yulOptimizerTests/unusedPruner/pop.yul
new file mode 100644
index 00000000..542070f9
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/unusedPruner/pop.yul
@@ -0,0 +1,8 @@
+{
+ let a := 1
+ pop(a)
+}
+// ----
+// unusedPruner
+// {
+// }
diff --git a/test/libyul/yulOptimizerTests/varDeclPropagator/multi_assignment_vardecl.yul b/test/libyul/yulOptimizerTests/varDeclPropagator/multi_assignment_vardecl.yul
index 4ac07031..ed8d33b4 100644
--- a/test/libyul/yulOptimizerTests/varDeclPropagator/multi_assignment_vardecl.yul
+++ b/test/libyul/yulOptimizerTests/varDeclPropagator/multi_assignment_vardecl.yul
@@ -1,6 +1,6 @@
{
function f() -> a, b, c {}
- let x, y, z
+ let x, y, z
z, x, y := f()
}
// ----
diff --git a/test/libyul/yulOptimizerTests/varDeclPropagator/simple1.yul b/test/libyul/yulOptimizerTests/varDeclPropagator/simple1.yul
index 117e0cc9..d8959040 100644
--- a/test/libyul/yulOptimizerTests/varDeclPropagator/simple1.yul
+++ b/test/libyul/yulOptimizerTests/varDeclPropagator/simple1.yul
@@ -1,5 +1,5 @@
{
- let f
+ let f
f := mload(0)
}
// ----
diff --git a/test/tools/fuzzer.cpp b/test/tools/fuzzer.cpp
index bb020f8c..8633454c 100644
--- a/test/tools/fuzzer.cpp
+++ b/test/tools/fuzzer.cpp
@@ -89,7 +89,7 @@ void testConstantOptimizer(string const& input)
void runCompiler(string input)
{
- string outputString(compileStandard(input.c_str(), nullptr));
+ string outputString(solidity_compile(input.c_str(), nullptr));
Json::Value output;
if (!jsonParseStrict(outputString, output))
{